Changeset View
Changeset View
Standalone View
Standalone View
swh/web/common/identifiers.py
# Copyright (C) 2020-2022 The Software Heritage developers | # Copyright (C) 2020-2022 The Software Heritage developers | ||||
# See the AUTHORS file at the top-level directory of this distribution | # See the AUTHORS file at the top-level directory of this distribution | ||||
# License: GNU Affero General Public License version 3, or any later version | # License: GNU Affero General Public License version 3, or any later version | ||||
# See top-level LICENSE file for more information | # See top-level LICENSE file for more information | ||||
from typing import Any, Dict, Iterable, List, Mapping, Optional | from typing import Any, Dict, Iterable, List, Mapping, Optional | ||||
from urllib.parse import quote, unquote | from urllib.parse import quote, unquote | ||||
from typing_extensions import TypedDict | from typing_extensions import TypedDict | ||||
from django.http import QueryDict | |||||
from swh.model.exceptions import ValidationError | from swh.model.exceptions import ValidationError | ||||
from swh.model.hashutil import hash_to_bytes, hash_to_hex | from swh.model.hashutil import hash_to_bytes, hash_to_hex | ||||
from swh.model.swhids import ObjectType, QualifiedSWHID | from swh.model.swhids import ObjectType, QualifiedSWHID | ||||
from swh.web.common import archive | from swh.web.common import archive | ||||
from swh.web.common.exc import BadInputExc | from swh.web.common.exc import BadInputExc | ||||
from swh.web.common.typing import ( | from swh.web.common.typing import ( | ||||
QueryParameters, | |||||
SnapshotContext, | SnapshotContext, | ||||
SWHIDContext, | SWHIDContext, | ||||
SWHIDInfo, | SWHIDInfo, | ||||
SWHObjectInfo, | SWHObjectInfo, | ||||
) | ) | ||||
from swh.web.common.utils import reverse | from swh.web.common.utils import reverse | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | class ResolvedSWHID(TypedDict): | ||||
"""parsed SWHID with context""" | """parsed SWHID with context""" | ||||
swhid_parsed: QualifiedSWHID | swhid_parsed: QualifiedSWHID | ||||
"""URL to browse object according to SWHID context""" | """URL to browse object according to SWHID context""" | ||||
browse_url: Optional[str] | browse_url: Optional[str] | ||||
def resolve_swhid( | def resolve_swhid( | ||||
swhid: str, query_params: Optional[QueryParameters] = None | swhid: str, query_params: Optional[Mapping[str, str]] = None | ||||
) -> ResolvedSWHID: | ) -> ResolvedSWHID: | ||||
""" | """ | ||||
Try to resolve a SoftWare Heritage persistent IDentifier into an url for | Try to resolve a SoftWare Heritage persistent IDentifier into an url for | ||||
browsing the targeted object. | browsing the targeted object. | ||||
Args: | Args: | ||||
swhid: a SoftWare Heritage persistent IDentifier | swhid: a SoftWare Heritage persistent IDentifier | ||||
query_params: optional dict filled with | query_params: optional dict filled with | ||||
query parameters to append to the browse url | query parameters to append to the browse url | ||||
Returns: | Returns: | ||||
a dict with the following keys: | a dict with the following keys: | ||||
* **swhid_parsed**: the parsed identifier | * **swhid_parsed**: the parsed identifier | ||||
* **browse_url**: the url for browsing the targeted object | * **browse_url**: the url for browsing the targeted object | ||||
""" | """ | ||||
swhid_parsed = get_swhid(swhid) | swhid_parsed = get_swhid(swhid) | ||||
object_type = swhid_parsed.object_type | object_type = swhid_parsed.object_type | ||||
object_id = swhid_parsed.object_id | object_id = swhid_parsed.object_id | ||||
browse_url = None | browse_url = None | ||||
url_args = {} | url_args = {} | ||||
query_dict = QueryDict("", mutable=True) | |||||
fragment = "" | fragment = "" | ||||
process_lines = object_type == ObjectType.CONTENT | process_lines = object_type == ObjectType.CONTENT | ||||
if query_params and len(query_params) > 0: | query_dict: Dict[str, str] = dict(query_params or {}) | ||||
vlorentz: is this still relevant? | |||||
Done Inline ActionsYes because query_params can be None and is defined as Mapping[str, str] (to fix mypy errors about Dict variance). We need to work with a Dict[str, str] in that function or mypy is not happy. However the call to sorted is redundant with what the reverse function does. anlambert: Yes because `query_params` can be `None` and is defined as `Mapping[str, str]` (to fix mypy… | |||||
Not Done Inline Actionsthen this: diff diff --git a/swh/web/common/identifiers.py b/swh/web/common/identifiers.py index b6e6cd4a..295a7592 100644 --- a/swh/web/common/identifiers.py +++ b/swh/web/common/identifiers.py @@ -106,13 +106,10 @@ def resolve_swhid( object_id = swhid_parsed.object_id browse_url = None url_args = {} - query_dict = {} fragment = "" process_lines = object_type == ObjectType.CONTENT - if query_params and len(query_params) > 0: - for k in query_params.keys(): - query_dict[k] = query_params[k] + query_dict: Dict[str, str] = dict(query_params or {}) if swhid_parsed.origin: origin_url = unquote(swhid_parsed.origin) vlorentz: then this:
```diff
diff --git a/swh/web/common/identifiers.py b/swh/web/common/identifiers.py… | |||||
Done Inline ActionsNice, thanks ! anlambert: Nice, thanks ! | |||||
for k in sorted(query_params.keys()): | |||||
query_dict[k] = str(query_params[k]) | |||||
if swhid_parsed.origin: | if swhid_parsed.origin: | ||||
origin_url = unquote(swhid_parsed.origin) | origin_url = unquote(swhid_parsed.origin) | ||||
origin_url = archive.lookup_origin({"url": origin_url})["url"] | origin_url = archive.lookup_origin({"url": origin_url})["url"] | ||||
query_dict["origin_url"] = origin_url | query_dict["origin_url"] = origin_url | ||||
if swhid_parsed.path and swhid_parsed.path != b"/": | if swhid_parsed.path and swhid_parsed.path != b"/": | ||||
query_dict["path"] = swhid_parsed.path.decode("utf8", errors="replace") | query_dict["path"] = swhid_parsed.path.decode("utf8", errors="replace") | ||||
Show All 16 Lines | if swhid_parsed.path and swhid_parsed.path != b"/": | ||||
if object_type == ObjectType.CONTENT: | if object_type == ObjectType.CONTENT: | ||||
if ( | if ( | ||||
not swhid_parsed.origin | not swhid_parsed.origin | ||||
and swhid_parsed.anchor.object_type != ObjectType.REVISION | and swhid_parsed.anchor.object_type != ObjectType.REVISION | ||||
): | ): | ||||
# when no origin or revision context, content objects need to have | # when no origin or revision context, content objects need to have | ||||
# their path prefixed by root directory id for breadcrumbs display | # their path prefixed by root directory id for breadcrumbs display | ||||
query_dict["path"] = hash_to_hex(directory) + query_dict["path"] | query_dict["path"] = hash_to_hex(directory) + query_dict["path"] | ||||
else: | elif query_dict["path"] is not None: | ||||
# remove leading slash from SWHID content path | # remove leading slash from SWHID content path | ||||
query_dict["path"] = str(query_dict["path"]).lstrip("/") | query_dict["path"] = query_dict["path"].lstrip("/") | ||||
elif object_type == ObjectType.DIRECTORY: | elif object_type == ObjectType.DIRECTORY and query_dict["path"] is not None: | ||||
object_id = directory | object_id = directory | ||||
# remove leading and trailing slashes from SWHID directory path | # remove leading and trailing slashes from SWHID directory path | ||||
query_dict["path"] = str(query_dict["path"]).strip("/") | query_dict["path"] = query_dict["path"].strip("/") | ||||
# snapshot context | # snapshot context | ||||
if swhid_parsed.visit: | if swhid_parsed.visit: | ||||
if swhid_parsed.visit.object_type != ObjectType.SNAPSHOT: | if swhid_parsed.visit.object_type != ObjectType.SNAPSHOT: | ||||
raise BadInputExc("Visit must be a snapshot SWHID.") | raise BadInputExc("Visit must be a snapshot SWHID.") | ||||
query_dict["snapshot"] = hash_to_hex(swhid_parsed.visit.object_id) | query_dict["snapshot"] = hash_to_hex(swhid_parsed.visit.object_id) | ||||
if swhid_parsed.anchor: | if swhid_parsed.anchor: | ||||
▲ Show 20 Lines • Show All 222 Lines • Show Last 20 Lines |
is this still relevant?