Beispiel #1
0
    def test_parse_single_fences(self):
        """Code (text blocks inside  ` pairs)"""
        markdown = "`code block`"
        result = parse_markdown_description(markdown)
        expected_result = "<p><code>code block</code></p>\n"

        self.assertEqual(result, expected_result)
Beispiel #2
0
    def test_parse_text(self):
        """Text conversion works"""
        markdown = "text"
        result = parse_markdown_description(markdown)
        expected_result = "<p>text</p>\n"

        self.assertEqual(result, expected_result)
Beispiel #3
0
    def test_parse_triple_fences(self):
        """Code (text blocks inside  ``` pairs)"""
        markdown = "```code block```"
        result = parse_markdown_description(markdown)
        expected_result = "<p>```code block```</p>\n"

        self.assertEqual(result, expected_result)
Beispiel #4
0
    def test_parse_paragraph_merging(self):
        """Paragraph merging (consecutive lines are joined)"""
        markdown = "this is\n a paragraph"
        result = parse_markdown_description(markdown)
        expected_result = "<p>this is\n a paragraph</p>\n"

        self.assertEqual(result, expected_result)
Beispiel #5
0
    def test_parse_paragraph(self):
        """Paragraphs"""
        markdown = "paragraph 1\n\n paragraph 2"
        result = parse_markdown_description(markdown)
        expected_result = "<p>paragraph 1</p>\n<p>paragraph 2</p>\n"

        self.assertEqual(result, expected_result)
Beispiel #6
0
    def test_parse_italics(self):
        """Italics (_foo_)"""
        markdown = "_text_"
        result = parse_markdown_description(markdown)
        expected_result = "<p><em>text</em></p>\n"

        self.assertEqual(result, expected_result)
Beispiel #7
0
    def test_parse_code_line(self):
        """Code (text blocks inside `)"""
        markdown = "`code line`"
        result = parse_markdown_description(markdown)
        expected_result = "<p><code>code line</code></p>\n"

        self.assertEqual(result, expected_result)
Beispiel #8
0
    def test_parse_image_link(self):
        """Image link is converted into a simple link"""
        markdown = "![image](link.png)"
        result = parse_markdown_description(markdown)
        expected_result = "<p>" + markdown + "</p>\n"

        self.assertEqual(result, expected_result)
Beispiel #9
0
    def test_parse_title(self):
        """Title conversion shouldn't work"""
        markdown = "# title"
        result = parse_markdown_description(markdown)
        expected_result = "<p># title</p>\n"

        self.assertEqual(result, expected_result)
Beispiel #10
0
    def test_parse_code_block_single_line(self):
        """Code with three space indentation"""
        markdown = "   code"
        result = parse_markdown_description(markdown)
        expected_result = "<pre><code>code\n</code></pre>\n"

        self.assertEqual(result, expected_result)
Beispiel #11
0
    def test_parse_bold(self):
        """Bold (**foo**)"""
        markdown = "**text**"
        result = parse_markdown_description(markdown)
        expected_result = "<p><strong>text</strong></p>\n"

        self.assertEqual(result, expected_result)
Beispiel #12
0
    def test_parse_urls(self):
        """Literal URLs auto-link https://foo.bar"""
        markdown = "https://toto.space"
        result = parse_markdown_description(markdown)
        expected_result = (
            '<p><a href="https://toto.space">https://toto.space</a></p>\n')

        self.assertEqual(result, expected_result)
Beispiel #13
0
    def test_parse_list_ordered(self):
        """Lists (* Foo)"""
        markdown = "1. item \n2. item \n3. item \n"
        result = parse_markdown_description(markdown)
        expected_result = (
            "<ol>\n<li>item </li>\n<li>item </li>\n<li>item </li>\n</ol>\n")

        self.assertEqual(result, expected_result)
Beispiel #14
0
    def test_parse_list_special_char(self):
        """Lists (• Foo)"""
        markdown = "• item \n• item \n• item \n"
        result = parse_markdown_description(markdown)
        expected_result = (
            "<ul>\n<li>item </li>\n<li>item </li>\n<li>item </li>\n</ul>\n")

        self.assertEqual(result, expected_result)
Beispiel #15
0
    def test_parse_urls_title(self):
        """URLs with title [title for the link](https://foo.bar)"""
        markdown = "[toto](https://toto.space)"
        result = parse_markdown_description(markdown)
        expected_result = (
            "<p>"
            '[toto](<a href="https://toto.space">https://toto.space</a>)'
            "</p>\n")

        self.assertEqual(result, expected_result)
Beispiel #16
0
def post_preview(snap_name):
    try:
        snap_details = publisher_api.get_snap_info(snap_name, flask.session)
    except StoreApiResponseErrorList as api_response_error_list:
        if api_response_error_list.status_code == 404:
            return flask.abort(404, "No snap named {}".format(snap_name))
        else:
            return _handle_error_list(api_response_error_list.errors)
    except (StoreApiError, ApiError) as api_error:
        return _handle_error(api_error)

    context = {
        "publisher": snap_details["publisher"]["display-name"],
        "username": snap_details["publisher"]["username"],
        "developer_validation": snap_details["publisher"]["validation"],
    }

    state = loads(flask.request.form["state"])

    for item in state:
        if item == "description":
            context[item] = parse_markdown_description(
                bleach.clean(state[item], tags=[]))
        else:
            context[item] = state[item]

    context["is_preview"] = True
    context["package_name"] = context["snap_name"]
    context["snap_title"] = context["title"]
    context["appliances"] = []

    # Images
    icons = get_icon(context["images"])
    context["screenshots"] = filter_screenshots(context["images"])
    context["icon_url"] = icons[0] if icons else None
    context["video"] = get_video(context["images"])

    # Channel map
    context["channel_map"] = []
    context["default_track"] = "latest"
    context["lowest_risk_available"] = "stable"
    context["version"] = "test"
    context["has_stable"] = True

    # metadata
    context["last_updated"] = "Preview"
    context["filesize"] = "1mb"

    # maps
    context["countries"] = preview_data.get_countries()
    context["normalized_os"] = preview_data.get_normalised_oses()

    return flask.render_template("store/snap-details.html", **context)
Beispiel #17
0
def post_preview(snap_name):
    try:
        snap_details = api.get_snap_info(snap_name, flask.session)
    except ApiResponseErrorList as api_response_error_list:
        if api_response_error_list.status_code == 404:
            return flask.abort(404, "No snap named {}".format(snap_name))
        else:
            return _handle_error_list(api_response_error_list.errors)
    except ApiError as api_error:
        return _handle_errors(api_error)

    context = {
        "publisher": snap_details["publisher"]["display-name"],
        "username": snap_details["publisher"]["username"],
        "developer_validation": snap_details["publisher"]["validation"],
    }

    state = loads(flask.request.form["state"])

    for item in state:
        if item == "description":
            context[item] = parse_markdown_description(
                bleach.clean(state[item])
            )
        else:
            context[item] = state[item]

    context["is_preview"] = True
    context["package_name"] = context["snap_name"]
    context["snap_title"] = context["title"]

    # Images
    icons = get_icon(context["images"])
    context["screenshots"] = filter_screenshots(context["images"])
    context["icon_url"] = icons[0] if icons else None
    context["videos"] = get_videos(context["images"])

    # Channel map
    context["default_track"] = "latest"
    context["lowest_risk_available"] = "stable"
    context["version"] = "test"
    context["has_stable"] = True

    # metadata
    context["last_updated"] = "Preview"
    context["filesize"] = "1mb"

    # maps
    context["countries"] = preview_data.get_countries()
    context["normalized_os"] = preview_data.get_normalised_oses()

    return flask.render_template("store/snap-details.html", **context)
    def _get_context_snap_details(snap_name):
        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))

        clean_description = bleach.clean(details["snap"]["description"])
        formatted_description = parse_markdown_description(clean_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"]

        # filter out banner and banner-icon images from screenshots
        screenshots = logic.filter_screenshots(details["snap"]["media"])

        icons = logic.get_icon(details["snap"]["media"])

        videos = logic.get_videos(details["snap"]["media"])

        # until default tracks are supported by the API we special case node
        # to use 10, rather then latest
        default_track = helpers.get_default_track(details["name"])

        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

        # build list of categories of a snap
        categories = logic.get_snap_categories(details["snap"]["categories"])

        context = {
            "snap-id": details.get("snap-id"),
            # Data direct from details API
            "snap_title": details["snap"]["title"],
            "package_name": details["name"],
            "categories": categories,
            "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": formatted_description,
            "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": logic.convert_date(last_updated),
            "last_updated_raw": last_updated,
            "is_users_snap": is_users_snap,
        }

        return context
    def _get_context_snap_details(snap_name):
        try:
            details = api.get_item_details(snap_name, api_version=2)
        except StoreApiTimeoutError as api_timeout_error:
            flask.abort(504, str(api_timeout_error))
        except StoreApiResponseDecodeError as api_response_decode_error:
            flask.abort(502, str(api_response_decode_error))
        except StoreApiResponseErrorList 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 StoreApiResponseError as api_response_error:
            flask.abort(502, str(api_response_error))
        except StoreApiCircuitBreaker:
            flask.abort(503)
        except (StoreApiError, ApiError) as api_error:
            flask.abort(502, str(api_error))

        # When removing all the channel maps of an existing 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))

        clean_description = bleach.clean(details["snap"]["description"],
                                         tags=[])
        formatted_description = parse_markdown_description(clean_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"]

        # filter out banner and banner-icon images from screenshots
        screenshots = logic.filter_screenshots(details["snap"]["media"])

        icons = logic.get_icon(details["snap"]["media"])

        publisher_info = helpers.get_yaml(
            "{}{}.yaml".format(
                flask.current_app.config["CONTENT_DIRECTORY"]
                ["PUBLISHER_PAGES"],
                details["snap"]["publisher"]["username"],
            ),
            typ="safe",
        )

        publisher_snaps = helpers.get_yaml(
            "{}{}-snaps.yaml".format(
                flask.current_app.config["CONTENT_DIRECTORY"]
                ["PUBLISHER_PAGES"],
                details["snap"]["publisher"]["username"],
            ),
            typ="safe",
        )

        publisher_featured_snaps = None

        if publisher_info:
            publisher_featured_snaps = publisher_info.get("featured_snaps")
            publisher_snaps = logic.get_n_random_snaps(
                publisher_snaps["snaps"], 4)

        videos = logic.get_videos(details["snap"]["media"])

        # until default tracks are supported by the API we special case node
        # to use 10, rather then latest
        default_track = helpers.get_default_track(details["name"])
        if not default_track:
            default_track = (details.get("default-track")
                             if details.get("default-track") 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 authentication.is_authenticated(flask.session):
            if (flask.session.get("openid").get("nickname")
                    == details["snap"]["publisher"]["username"]
                ) or ("user_shared_snaps" in flask.session
                      and snap_name in flask.session.get("user_shared_snaps")):
                is_users_snap = True

        # build list of categories of a snap
        categories = logic.get_snap_categories(details["snap"]["categories"])

        developer = logic.get_snap_developer(details["name"])

        context = {
            "snap-id": details.get("snap-id"),
            # Data direct from details API
            "snap_title": details["snap"]["title"],
            "package_name": details["name"],
            "categories": categories,
            "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,
            "publisher_snaps": publisher_snaps,
            "publisher_featured_snaps": publisher_featured_snaps,
            "has_publisher_page": publisher_info is not None,
            "prices": details["snap"]["prices"],
            "contact": details["snap"].get("contact"),
            "website": details["snap"].get("website"),
            "summary": details["snap"]["summary"],
            "description": formatted_description,
            "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,
            "trending": details["snap"]["trending"],
            # Transformed API data
            "filesize": humanize.naturalsize(binary_filesize),
            "last_updated": logic.convert_date(last_updated),
            "last_updated_raw": last_updated,
            "is_users_snap": is_users_snap,
            "unlisted": details["snap"]["unlisted"],
            "developer": developer,
            # TODO: This is horrible and hacky
            "appliances": {
                "adguard-home": "adguard",
                "mosquitto": "mosquitto",
                "nextcloud": "nextcloud",
                "plexmediaserver": "plex",
                "openhab": "openhab",
            },
        }

        return context
Beispiel #20
0
    def _get_context_snap_details(snap_name):
        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))

        clean_description = bleach.clean(details["snap"]["description"],
                                         tags=[])
        formatted_description = parse_markdown_description(clean_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"]

        # filter out banner and banner-icon images from screenshots
        screenshots = logic.filter_screenshots(details["snap"]["media"])

        icons = logic.get_icon(details["snap"]["media"])

        videos = logic.get_videos(details["snap"]["media"])

        # until default tracks are supported by the API we special case node
        # to use 10, rather then latest
        default_track = helpers.get_default_track(details["name"])

        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

        # build list of categories of a snap
        categories = logic.get_snap_categories(details["snap"]["categories"])

        context = {
            "snap-id": details.get("snap-id"),
            # Data direct from details API
            "snap_title": details["snap"]["title"],
            "package_name": details["name"],
            "categories": categories,
            "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": formatted_description,
            "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": logic.convert_date(last_updated),
            "last_updated_raw": last_updated,
            "is_users_snap": is_users_snap,
        }

        return context