diff --git a/swh/web/browse/views/utils/snapshot_context.py b/swh/web/browse/snapshot_context.py rename from swh/web/browse/views/utils/snapshot_context.py rename to swh/web/browse/snapshot_context.py --- a/swh/web/browse/views/utils/snapshot_context.py +++ b/swh/web/browse/snapshot_context.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2019 The Software Heritage developers +# Copyright (C) 2017-2020 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -8,15 +8,15 @@ # Its purpose is to factorize code for the views reachable from the # /origin/.* and /snapshot/.* endpoints. +from typing import Any, Dict + from django.shortcuts import render from django.template.defaultfilters import filesizeformat from django.utils.html import escape import sentry_sdk -from swh.model.identifiers import snapshot_identifier - +from swh.model.identifiers import snapshot_identifier, persistent_identifier from swh.web.browse.utils import ( - get_snapshot_context, get_directory_entries, gen_directory_link, gen_revision_link, @@ -29,12 +29,14 @@ gen_release_link, get_readme_to_display, get_swh_persistent_ids, + get_origin_visit_snapshot, + get_snapshot_content, gen_snapshot_link, process_snapshot_branches, ) - from swh.web.common import service, highlightjs from swh.web.common.exc import handle_view_exception, NotFoundExc +from swh.web.common.origin_visits import get_origin_visit from swh.web.common.utils import ( reverse, gen_path_info, @@ -45,6 +47,136 @@ _empty_snapshot_id = snapshot_identifier({"branches": {}}) +def get_snapshot_context( + snapshot_id=None, origin_url=None, timestamp=None, visit_id=None +) -> Dict[str, Any]: + """ + Utility function to compute relevant information when navigating + the archive in a snapshot context. The snapshot is either + referenced by its id or it will be retrieved from an origin visit. + + Args: + snapshot_id (str): hexadecimal representation of a snapshot identifier, + all other parameters will be ignored if it is provided + origin_url (str): the origin_url + (e.g. https://github.com/(user)/(repo)/) + timestamp (str): a datetime string for retrieving the closest + visit of the origin + visit_id (int): optional visit id for disambiguation in case + of several visits with the same timestamp + + Returns: + A dict with the following entries: + * origin_info: dict containing origin information + * visit_info: dict containing visit information + * branches: the list of branches for the origin found + during the visit + * releases: the list of releases for the origin found + during the visit + * origin_browse_url: the url to browse the origin + * origin_branches_url: the url to browse the origin branches + * origin_releases_url': the url to browse the origin releases + * origin_visit_url: the url to browse the snapshot of the origin + found during the visit + * url_args: dict containing url arguments to use when browsing in + the context of the origin and its visit + + Raises: + swh.web.common.exc.NotFoundExc: if no snapshot is found for the visit + of an origin. + """ + origin_info = None + visit_info = None + url_args = None + query_params = {} + branches = [] + releases = [] + browse_url = None + visit_url = None + branches_url = None + releases_url = None + swh_type = "snapshot" + if origin_url: + swh_type = "origin" + origin_info = service.lookup_origin({"url": origin_url}) + + visit_info = get_origin_visit(origin_info, timestamp, visit_id, snapshot_id) + fmt_date = format_utc_iso_date(visit_info["date"]) + visit_info["fmt_date"] = fmt_date + snapshot_id = visit_info["snapshot"] + + if not snapshot_id: + raise NotFoundExc( + "No snapshot associated to the visit of origin " + "%s on %s" % (escape(origin_url), fmt_date) + ) + + # provided timestamp is not necessarily equals to the one + # of the retrieved visit, so get the exact one in order + # use it in the urls generated below + if timestamp: + timestamp = visit_info["date"] + + branches, releases = get_origin_visit_snapshot( + origin_info, timestamp, visit_id, snapshot_id + ) + + url_args = {"origin_url": origin_info["url"]} + + query_params = {"visit_id": visit_id} + + browse_url = reverse("browse-origin-visits", url_args=url_args) + + if timestamp: + url_args["timestamp"] = format_utc_iso_date(timestamp, "%Y-%m-%dT%H:%M:%S") + visit_url = reverse( + "browse-origin-directory", url_args=url_args, query_params=query_params + ) + visit_info["url"] = visit_url + + branches_url = reverse( + "browse-origin-branches", url_args=url_args, query_params=query_params + ) + + releases_url = reverse( + "browse-origin-releases", url_args=url_args, query_params=query_params + ) + elif snapshot_id: + branches, releases = get_snapshot_content(snapshot_id) + url_args = {"snapshot_id": snapshot_id} + browse_url = reverse("browse-snapshot", url_args=url_args) + branches_url = reverse("browse-snapshot-branches", url_args=url_args) + + releases_url = reverse("browse-snapshot-releases", url_args=url_args) + + releases = list(reversed(releases)) + + snapshot_sizes = service.lookup_snapshot_sizes(snapshot_id) + + is_empty = sum(snapshot_sizes.values()) == 0 + + swh_snp_id = persistent_identifier("snapshot", snapshot_id) + + return { + "swh_type": swh_type, + "swh_object_id": swh_snp_id, + "snapshot_id": snapshot_id, + "snapshot_sizes": snapshot_sizes, + "is_empty": is_empty, + "origin_info": origin_info, + "visit_info": visit_info, + "branches": branches, + "releases": releases, + "branch": None, + "release": None, + "browse_url": browse_url, + "branches_url": branches_url, + "releases_url": releases_url, + "url_args": url_args, + "query_params": query_params, + } + + def _get_branch(branches, branch_name, snapshot_id): """ Utility function to get a specific branch from a branches list. diff --git a/swh/web/browse/utils.py b/swh/web/browse/utils.py --- a/swh/web/browse/utils.py +++ b/swh/web/browse/utils.py @@ -16,9 +16,8 @@ from django.utils.html import escape import sentry_sdk -from swh.model.identifiers import persistent_identifier from swh.web.common import highlightjs, service -from swh.web.common.exc import NotFoundExc, http_status_code_message +from swh.web.common.exc import http_status_code_message from swh.web.common.identifiers import get_swh_persistent_id from swh.web.common.origin_visits import get_origin_visit from swh.web.common.utils import ( @@ -885,136 +884,6 @@ return revision_log_data -def get_snapshot_context( - snapshot_id=None, origin_url=None, timestamp=None, visit_id=None -): - """ - Utility function to compute relevant information when navigating - the archive in a snapshot context. The snapshot is either - referenced by its id or it will be retrieved from an origin visit. - - Args: - snapshot_id (str): hexadecimal representation of a snapshot identifier, - all other parameters will be ignored if it is provided - origin_url (str): the origin_url - (e.g. https://github.com/(user)/(repo)/) - timestamp (str): a datetime string for retrieving the closest - visit of the origin - visit_id (int): optional visit id for disambiguation in case - of several visits with the same timestamp - - Returns: - A dict with the following entries: - * origin_info: dict containing origin information - * visit_info: dict containing visit information - * branches: the list of branches for the origin found - during the visit - * releases: the list of releases for the origin found - during the visit - * origin_browse_url: the url to browse the origin - * origin_branches_url: the url to browse the origin branches - * origin_releases_url': the url to browse the origin releases - * origin_visit_url: the url to browse the snapshot of the origin - found during the visit - * url_args: dict containing url arguments to use when browsing in - the context of the origin and its visit - - Raises: - swh.web.common.exc.NotFoundExc: if no snapshot is found for the visit - of an origin. - """ - origin_info = None - visit_info = None - url_args = None - query_params = {} - branches = [] - releases = [] - browse_url = None - visit_url = None - branches_url = None - releases_url = None - swh_type = "snapshot" - if origin_url: - swh_type = "origin" - origin_info = service.lookup_origin({"url": origin_url}) - - visit_info = get_origin_visit(origin_info, timestamp, visit_id, snapshot_id) - fmt_date = format_utc_iso_date(visit_info["date"]) - visit_info["fmt_date"] = fmt_date - snapshot_id = visit_info["snapshot"] - - if not snapshot_id: - raise NotFoundExc( - "No snapshot associated to the visit of origin " - "%s on %s" % (escape(origin_url), fmt_date) - ) - - # provided timestamp is not necessarily equals to the one - # of the retrieved visit, so get the exact one in order - # use it in the urls generated below - if timestamp: - timestamp = visit_info["date"] - - branches, releases = get_origin_visit_snapshot( - origin_info, timestamp, visit_id, snapshot_id - ) - - url_args = {"origin_url": origin_info["url"]} - - query_params = {"visit_id": visit_id} - - browse_url = reverse("browse-origin-visits", url_args=url_args) - - if timestamp: - url_args["timestamp"] = format_utc_iso_date(timestamp, "%Y-%m-%dT%H:%M:%S") - visit_url = reverse( - "browse-origin-directory", url_args=url_args, query_params=query_params - ) - visit_info["url"] = visit_url - - branches_url = reverse( - "browse-origin-branches", url_args=url_args, query_params=query_params - ) - - releases_url = reverse( - "browse-origin-releases", url_args=url_args, query_params=query_params - ) - elif snapshot_id: - branches, releases = get_snapshot_content(snapshot_id) - url_args = {"snapshot_id": snapshot_id} - browse_url = reverse("browse-snapshot", url_args=url_args) - branches_url = reverse("browse-snapshot-branches", url_args=url_args) - - releases_url = reverse("browse-snapshot-releases", url_args=url_args) - - releases = list(reversed(releases)) - - snapshot_sizes = service.lookup_snapshot_sizes(snapshot_id) - - is_empty = sum(snapshot_sizes.values()) == 0 - - swh_snp_id = persistent_identifier("snapshot", snapshot_id) - - return { - "swh_type": swh_type, - "swh_object_id": swh_snp_id, - "snapshot_id": snapshot_id, - "snapshot_sizes": snapshot_sizes, - "is_empty": is_empty, - "origin_info": origin_info, - "visit_info": visit_info, - "branches": branches, - "releases": releases, - "branch": None, - "release": None, - "browse_url": browse_url, - "branches_url": branches_url, - "releases_url": releases_url, - "url_args": url_args, - "query_params": query_params, - } - - # list of common readme names ordered by preference # (lower indices have higher priority) _common_readme_names = [ diff --git a/swh/web/browse/views/content.py b/swh/web/browse/views/content.py --- a/swh/web/browse/views/content.py +++ b/swh/web/browse/views/content.py @@ -18,11 +18,11 @@ from swh.web.common import query, service, highlightjs from swh.web.common.utils import reverse, gen_path_info, swh_object_icons from swh.web.common.exc import NotFoundExc, handle_view_exception +from swh.web.browse.snapshot_context import get_snapshot_context from swh.web.browse.utils import ( request_content, prepare_content_for_display, content_display_max_size, - get_snapshot_context, get_swh_persistent_ids, gen_link, gen_directory_link, diff --git a/swh/web/browse/views/directory.py b/swh/web/browse/views/directory.py --- a/swh/web/browse/views/directory.py +++ b/swh/web/browse/views/directory.py @@ -13,14 +13,15 @@ from swh.web.common import service from swh.web.common.utils import reverse, gen_path_info from swh.web.common.exc import handle_view_exception, NotFoundExc +from swh.web.browse.snapshot_context import get_snapshot_context from swh.web.browse.utils import ( get_directory_entries, - get_snapshot_context, get_readme_to_display, get_swh_persistent_ids, gen_link, ) + from swh.web.browse.browseurls import browse_route diff --git a/swh/web/browse/views/origin.py b/swh/web/browse/views/origin.py --- a/swh/web/browse/views/origin.py +++ b/swh/web/browse/views/origin.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017-2019 The Software Heritage developers +# Copyright (C) 2017-2020 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -9,10 +9,9 @@ from swh.web.common.origin_visits import get_origin_visits from swh.web.common.utils import reverse, format_utc_iso_date, parse_timestamp from swh.web.common.exc import handle_view_exception -from swh.web.browse.utils import get_snapshot_context +from swh.web.browse.snapshot_context import get_snapshot_context from swh.web.browse.browseurls import browse_route - -from .utils.snapshot_context import ( +from swh.web.browse.snapshot_context import ( browse_snapshot_directory, browse_snapshot_content, browse_snapshot_log, diff --git a/swh/web/browse/views/release.py b/swh/web/browse/views/release.py --- a/swh/web/browse/views/release.py +++ b/swh/web/browse/views/release.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017-2019 The Software Heritage developers +# Copyright (C) 2017-2020 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -10,9 +10,9 @@ from swh.web.common.utils import reverse, format_utc_iso_date from swh.web.common.exc import NotFoundExc, handle_view_exception from swh.web.browse.browseurls import browse_route +from swh.web.browse.snapshot_context import get_snapshot_context from swh.web.browse.utils import ( gen_revision_link, - get_snapshot_context, gen_link, gen_snapshot_link, get_swh_persistent_ids, diff --git a/swh/web/browse/views/revision.py b/swh/web/browse/views/revision.py --- a/swh/web/browse/views/revision.py +++ b/swh/web/browse/views/revision.py @@ -1,4 +1,4 @@ -# Copyright (C) 2017-2019 The Software Heritage developers +# Copyright (C) 2017-2020 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -23,11 +23,11 @@ ) from swh.web.common.exc import NotFoundExc, handle_view_exception from swh.web.browse.browseurls import browse_route +from swh.web.browse.snapshot_context import get_snapshot_context from swh.web.browse.utils import ( gen_link, gen_revision_link, gen_revision_url, - get_snapshot_context, get_revision_log_url, get_directory_entries, gen_directory_link, diff --git a/swh/web/browse/views/snapshot.py b/swh/web/browse/views/snapshot.py --- a/swh/web/browse/views/snapshot.py +++ b/swh/web/browse/views/snapshot.py @@ -1,4 +1,4 @@ -# Copyright (C) 2018-2019 The Software Heritage developers +# Copyright (C) 2018-2020 The Software Heritage developers # See the AUTHORS file at the top-level directory of this distribution # License: GNU Affero General Public License version 3, or any later version # See top-level LICENSE file for more information @@ -7,15 +7,14 @@ from django.shortcuts import redirect from swh.web.browse.browseurls import browse_route -from swh.web.common.utils import reverse - -from .utils.snapshot_context import ( +from swh.web.browse.snapshot_context import ( browse_snapshot_directory, browse_snapshot_content, browse_snapshot_log, browse_snapshot_branches, browse_snapshot_releases, ) +from swh.web.common.utils import reverse @browse_route( diff --git a/swh/web/browse/views/utils/__init__.py b/swh/web/browse/views/utils/__init__.py deleted file mode 100644 diff --git a/swh/web/tests/browse/views/test_origin.py b/swh/web/tests/browse/views/test_origin.py --- a/swh/web/tests/browse/views/test_origin.py +++ b/swh/web/tests/browse/views/test_origin.py @@ -443,19 +443,16 @@ def test_origin_request_errors(client, archive_data, mocker): - mock_snapshot_service = mocker.patch( - "swh.web.browse.views.utils.snapshot_context.service" - ) + mock_snapshot_service = mocker.patch("swh.web.browse.snapshot_context.service") mock_origin_service = mocker.patch("swh.web.browse.views.origin.service") - mock_utils_service = mocker.patch("swh.web.browse.utils.service") mock_get_origin_visit_snapshot = mocker.patch( - "swh.web.browse.utils.get_origin_visit_snapshot" + "swh.web.browse.snapshot_context.get_origin_visit_snapshot" ) mock_get_origin_visits = mocker.patch( "swh.web.common.origin_visits.get_origin_visits" ) mock_request_content = mocker.patch( - "swh.web.browse.views.utils.snapshot_context.request_content" + "swh.web.browse.snapshot_context.request_content" ) mock_origin_service.lookup_origin.side_effect = NotFoundExc("origin not found") url = reverse("browse-origin-visits", url_args={"origin_url": "bar"}) @@ -512,17 +509,21 @@ ], [], ) + mock_utils_service = mocker.patch("swh.web.browse.snapshot_context.service") mock_utils_service.lookup_snapshot_sizes.return_value = { "revision": 1, "release": 0, } - mock_lookup_directory = mock_utils_service.lookup_directory + + mock_utils_service2 = mocker.patch("swh.web.browse.utils.service") + mock_lookup_directory = mock_utils_service2.lookup_directory mock_lookup_directory.side_effect = NotFoundExc("Directory not found") url = reverse("browse-origin-directory", url_args={"origin_url": "bar"}) resp = client.get(url) assert resp.status_code == 404 assert_template_used(resp, "error.html") assert_contains(resp, "Directory not found", status_code=404) + assert mock_lookup_directory.called mock_origin_service.lookup_origin.side_effect = None mock_origin_service.lookup_origin.return_value = { @@ -610,7 +611,7 @@ assert_contains(resp, "Content not found", status_code=404) mock_get_snapshot_context = mocker.patch( - "swh.web.browse.views.utils.snapshot_context.get_snapshot_context" + "swh.web.browse.snapshot_context.get_snapshot_context" ) mock_get_snapshot_context.side_effect = NotFoundExc("Snapshot not found") @@ -622,9 +623,9 @@ def test_origin_empty_snapshot(client, mocker): - mock_utils_service = mocker.patch("swh.web.browse.utils.service") + mock_utils_service = mocker.patch("swh.web.browse.snapshot_context.service") mock_get_origin_visit_snapshot = mocker.patch( - "swh.web.browse.utils.get_origin_visit_snapshot" + "swh.web.browse.snapshot_context.get_origin_visit_snapshot" ) mock_get_origin_visits = mocker.patch( "swh.web.common.origin_visits.get_origin_visits" @@ -1084,9 +1085,7 @@ When a snapshot contains a branch or a release alias, pagination links in the branches / releases view should be displayed. """ - mocker.patch( - "swh.web.browse.views.utils.snapshot_context.PER_PAGE", len(revisions) / 2 - ) + mocker.patch("swh.web.browse.snapshot_context.PER_PAGE", len(revisions) / 2) snp_dict = {"branches": {}, "id": hash_to_bytes(random_sha1())} for i in range(len(revisions)): branch = "".join(random.choices(string.ascii_lowercase, k=8))