def test_get_video_embed_code(self):
        youtube_url = "https://youtube.com/watch?v=123"
        embed = logic.get_video_embed_code(youtube_url)
        self.assertEqual(
            embed,
            {
                "type": "youtube",
                "url": "https://youtube.com/embed/123",
                "id": "123",
            },
        )

        vimeo_url = "https://vimeo.com/123123"
        embed = logic.get_video_embed_code(vimeo_url)
        self.assertEqual(
            embed,
            {
                "type": "vimeo",
                "url": "https://player.vimeo.com/video/123123",
                "id": "123123",
            },
        )

        asciicinema_url = "https://asciinema.org/a/123"
        embed = logic.get_video_embed_code(asciicinema_url)
        self.assertEqual(
            embed,
            {
                "type": "asciinema",
                "url": "https://asciinema.org/a/123.js",
                "id": "123",
            },
        )
    def test_get_video_embed_code(self):
        youtube_url = "https://youtube.com/watch?v=123"
        embed = logic.get_video_embed_code(youtube_url)
        self.assertEqual(
            embed,
            {
                "type": "youtube",
                "url": "https://youtube.com/embed/123",
                "id": "123",
            },
        )

        vimeo_url = "https://vimeo.com/123123"
        embed = logic.get_video_embed_code(vimeo_url)
        self.assertEqual(
            embed,
            {
                "type": "vimeo",
                "url": "https://player.vimeo.com/video/123123",
                "id": "123123",
            },
        )

        asciicinema_url = "https://asciinema.org/a/123"
        embed = logic.get_video_embed_code(asciicinema_url)
        self.assertEqual(
            embed,
            {
                "type": "asciinema",
                "url": "https://asciinema.org/a/123.js",
                "id": "123",
            },
        )
示例#3
0
    def snap_details(snap_name):
        """
        A view to display the snap details page for specific snaps.

        This queries the snapcraft API (api.snapcraft.io) and passes
        some of the data through to the snap-details.html template,
        with appropriate sanitation.
        """

        error_info = {}
        status_code = 200

        try:
            details = api.get_snap_details(snap_name)
        except ApiTimeoutError as api_timeout_error:
            flask.abort(504, str(api_timeout_error))
        except ApiResponseDecodeError as api_response_decode_error:
            flask.abort(502, str(api_response_decode_error))
        except ApiResponseErrorList as api_response_error_list:
            if api_response_error_list.status_code == 404:
                flask.abort(404, "No snap named {}".format(snap_name))
            else:
                if api_response_error_list.errors:
                    error_messages = ", ".join(
                        api_response_error_list.errors.key())
                else:
                    error_messages = "An error occurred."
                flask.abort(502, error_messages)
        except ApiResponseError as api_response_error:
            flask.abort(502, str(api_response_error))
        except ApiCircuitBreaker:
            flask.abort(503)
        except ApiError as api_error:
            flask.abort(502, str(api_error))

        # When removing all the channel maps of an exsting snap the API,
        # responds that the snaps still exists with data.
        # Return a 404 if not channel maps, to avoid having a error.
        # For example: mir-kiosk-browser
        if not details.get("channel-map"):
            flask.abort(404, "No snap named {}".format(snap_name))

        formatted_paragraphs = logic.split_description_into_paragraphs(
            details["snap"]["description"])

        channel_maps_list = logic.convert_channel_maps(
            details.get("channel-map"))

        latest_channel = logic.get_last_updated_version(
            details.get("channel-map"))

        last_updated = latest_channel["created-at"]
        last_version = latest_channel["version"]
        binary_filesize = latest_channel["download"]["size"]

        country_metric_name = "weekly_installed_base_by_country_percent"
        os_metric_name = "weekly_installed_base_by_operating_system_normalized"

        webapp_config = flask.current_app.config.get("WEBAPP_CONFIG")

        if "STORE_QUERY" not in webapp_config:
            end = metrics_helper.get_last_metrics_processed_date()

            metrics_query_json = [
                metrics_helper.get_filter(
                    metric_name=country_metric_name,
                    snap_id=details["snap-id"],
                    start=end,
                    end=end,
                ),
                metrics_helper.get_filter(
                    metric_name=os_metric_name,
                    snap_id=details["snap-id"],
                    start=end,
                    end=end,
                ),
            ]

            try:
                metrics_response = api.get_public_metrics(
                    snap_name, metrics_query_json)
            except ApiError as api_error:
                status_code, error_info = _handle_errors(api_error)
                metrics_response = None

            os_metrics = None
            country_devices = None
            if metrics_response:
                oses = metrics_helper.find_metric(metrics_response,
                                                  os_metric_name)
                os_metrics = metrics.OsMetric(
                    name=oses["metric_name"],
                    series=oses["series"],
                    buckets=oses["buckets"],
                    status=oses["status"],
                )

                territories = metrics_helper.find_metric(
                    metrics_response, country_metric_name)
                country_devices = metrics.CountryDevices(
                    name=territories["metric_name"],
                    series=territories["series"],
                    buckets=territories["buckets"],
                    status=territories["status"],
                    private=False,
                )
        else:
            os_metrics = None
            country_devices = None

        # filter out banner and banner-icon images from screenshots
        screenshots = [
            m["url"] for m in details["snap"]["media"]
            if m["type"] == "screenshot" and "banner" not in m["url"]
        ]
        icons = [
            m["url"] for m in details["snap"]["media"] if m["type"] == "icon"
        ]

        videos = [
            logic.get_video_embed_code(m["url"])
            for m in details["snap"]["media"] if m["type"] == "video"
        ]

        # until default tracks are supported by the API we special case node
        # to use 10, rather then latest
        default_track = "10" if details["name"] == "node" else "latest"

        lowest_risk_available = logic.get_lowest_available_risk(
            channel_maps_list, default_track)

        confinement = logic.get_confinement(channel_maps_list, default_track,
                                            lowest_risk_available)

        last_version = logic.get_version(channel_maps_list, default_track,
                                         lowest_risk_available)

        is_users_snap = False
        if flask.session and "openid" in flask.session:
            if (flask.session.get("openid").get("nickname") == details["snap"]
                ["publisher"]["username"]):
                is_users_snap = True

        context = {
            # Data direct from details API
            "snap_title":
            details["snap"]["title"],
            "package_name":
            details["name"],
            "icon_url":
            icons[0] if icons else None,
            "version":
            last_version,
            "license":
            details["snap"]["license"],
            "publisher":
            details["snap"]["publisher"]["display-name"],
            "username":
            details["snap"]["publisher"]["username"],
            "screenshots":
            screenshots,
            "videos":
            videos,
            "prices":
            details["snap"]["prices"],
            "contact":
            details["snap"].get("contact"),
            "website":
            details["snap"].get("website"),
            "summary":
            details["snap"]["summary"],
            "description_paragraphs":
            formatted_paragraphs,
            "channel_map":
            channel_maps_list,
            "has_stable":
            logic.has_stable(channel_maps_list),
            "developer_validation":
            details["snap"]["publisher"]["validation"],
            "default_track":
            default_track,
            "lowest_risk_available":
            lowest_risk_available,
            "confinement":
            confinement,
            # Transformed API data
            "filesize":
            humanize.naturalsize(binary_filesize),
            "last_updated": (humanize.naturaldate(parser.parse(last_updated))),
            "last_updated_raw":
            last_updated,
            # Data from metrics API
            "countries":
            (country_devices.country_data if country_devices else None),
            "normalized_os":
            os_metrics.os if os_metrics else None,
            "is_users_snap":
            is_users_snap,
            # Context info
            "is_linux":
            ("Linux" in flask.request.headers.get("User-Agent", "")
             and "Android" not in flask.request.headers.get("User-Agent", "")),
            "error_info":
            error_info,
        }

        return (
            flask.render_template("store/snap-details.html", **context),
            status_code,
        )