Changeset View
Changeset View
Standalone View
Standalone View
swh/web/misc/iframe.py
- This file was added.
# Copyright (C) 2021 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 | |||||
from typing import Any, Dict, List, Optional | |||||
from django.conf.urls import url | |||||
from django.shortcuts import render | |||||
from django.views.decorators.clickjacking import xframe_options_exempt | |||||
from swh.model.hashutil import hash_to_bytes | |||||
from swh.model.identifiers import ( | |||||
CONTENT, | |||||
DIRECTORY, | |||||
REVISION, | |||||
SNAPSHOT, | |||||
ObjectType, | |||||
QualifiedSWHID, | |||||
) | |||||
from swh.web.browse.snapshot_context import get_snapshot_context | |||||
from swh.web.browse.utils import ( | |||||
content_display_max_size, | |||||
get_directory_entries, | |||||
prepare_content_for_display, | |||||
request_content, | |||||
) | |||||
from swh.web.common import archive | |||||
from swh.web.common.exc import BadInputExc, NotFoundExc, http_status_code_message | |||||
from swh.web.common.identifiers import get_swhid, get_swhids_info | |||||
from swh.web.common.typing import SnapshotContext, SWHObjectInfo | |||||
from swh.web.common.utils import gen_path_info, reverse | |||||
def _get_content_rendering_data(cnt_swhid: QualifiedSWHID, path: str) -> Dict[str, Any]: | |||||
content_data = request_content(f"sha1_git:{cnt_swhid.object_id.hex()}") | |||||
content = None | |||||
language = None | |||||
mimetype = None | |||||
if content_data.get("raw_data") is not None: | |||||
content_display_data = prepare_content_for_display( | |||||
content_data["raw_data"], content_data["mimetype"], path | |||||
) | |||||
content = content_display_data["content_data"] | |||||
language = content_display_data["language"] | |||||
mimetype = content_display_data["mimetype"] | |||||
return { | |||||
"content": content, | |||||
"content_size": content_data.get("length"), | |||||
"max_content_size": content_display_max_size, | |||||
"filename": path.split("/")[-1], | |||||
"encoding": content_data.get("encoding"), | |||||
"mimetype": mimetype, | |||||
"language": language, | |||||
} | |||||
def _get_directory_rendering_data( | |||||
dir_swhid: QualifiedSWHID, focus_swhid: QualifiedSWHID, path: str, | |||||
) -> Dict[str, Any]: | |||||
dirs, files = get_directory_entries(dir_swhid.object_id.hex()) | |||||
for d in dirs: | |||||
if d["type"] == "rev": | |||||
d["url"] = None | |||||
else: | |||||
dir_swhid = QualifiedSWHID( | |||||
object_type=ObjectType.DIRECTORY, | |||||
object_id=hash_to_bytes(d["target"]), | |||||
origin=dir_swhid.origin, | |||||
visit=dir_swhid.visit, | |||||
anchor=dir_swhid.anchor, | |||||
path=(path or "/") + d["name"] + "/", | |||||
) | |||||
d["url"] = reverse( | |||||
"swhid-iframe", | |||||
url_args={"swhid": str(dir_swhid)}, | |||||
query_params={"focus_swhid": str(focus_swhid)}, | |||||
) | |||||
for f in files: | |||||
object_id = hash_to_bytes(f["target"]) | |||||
cnt_swhid = QualifiedSWHID( | |||||
object_type=ObjectType.CONTENT, | |||||
object_id=object_id, | |||||
origin=dir_swhid.origin, | |||||
visit=dir_swhid.visit, | |||||
anchor=dir_swhid.anchor, | |||||
path=(path or "/") + f["name"], | |||||
lines=(focus_swhid.lines if object_id == focus_swhid.object_id else None), | |||||
) | |||||
f["url"] = reverse( | |||||
"swhid-iframe", | |||||
url_args={"swhid": str(cnt_swhid)}, | |||||
query_params={"focus_swhid": str(focus_swhid)}, | |||||
) | |||||
return {"dirs": dirs, "files": files} | |||||
def _get_breacrumbs_data( | |||||
swhid: QualifiedSWHID, | |||||
focus_swhid: QualifiedSWHID, | |||||
path: str, | |||||
snapshot_context: Optional[SnapshotContext] = None, | |||||
) -> List[Dict[str, Any]]: | |||||
breadcrumbs = [] | |||||
filename = None | |||||
# strip any leading or trailing slash from path qualifier of SWHID | |||||
if path and path[0] == "/": | |||||
path = path[1:] | |||||
if path and path[-1] == "/": | |||||
path = path[:-1] | |||||
if swhid.object_type == ObjectType.CONTENT: | |||||
split_path = path.split("/") | |||||
filename = split_path[-1] | |||||
path = path[: -len(filename)] | |||||
path_info = gen_path_info(path) if path != "/" else [] | |||||
root_dir = None | |||||
if snapshot_context and snapshot_context["root_directory"]: | |||||
root_dir = snapshot_context["root_directory"] | |||||
elif focus_swhid.object_type == ObjectType.DIRECTORY: | |||||
root_dir = focus_swhid.object_id.hex() | |||||
if root_dir: | |||||
root_dir_swhid = QualifiedSWHID( | |||||
object_type=ObjectType.DIRECTORY, | |||||
object_id=hash_to_bytes(root_dir), | |||||
origin=swhid.origin, | |||||
visit=swhid.visit, | |||||
anchor=swhid.anchor, | |||||
) | |||||
breadcrumbs.append( | |||||
{ | |||||
"name": root_dir[:7], | |||||
"object_id": root_dir_swhid.object_id.hex(), | |||||
"path": "/", | |||||
"url": reverse( | |||||
"swhid-iframe", | |||||
url_args={"swhid": str(root_dir_swhid)}, | |||||
query_params={"focus_swhid": focus_swhid}, | |||||
), | |||||
} | |||||
) | |||||
for pi in path_info: | |||||
dir_info = archive.lookup_directory_with_path(root_dir, pi["path"]) | |||||
dir_swhid = QualifiedSWHID( | |||||
object_type=ObjectType.DIRECTORY, | |||||
object_id=hash_to_bytes(dir_info["target"]), | |||||
origin=swhid.origin, | |||||
visit=swhid.visit, | |||||
anchor=swhid.anchor, | |||||
path="/" + pi["path"] + "/", | |||||
) | |||||
breadcrumbs.append( | |||||
{ | |||||
"name": pi["name"], | |||||
"object_id": dir_swhid.object_id.hex(), | |||||
"path": dir_swhid.path.decode("utf-8") if dir_swhid.path else "", | |||||
"url": reverse( | |||||
"swhid-iframe", | |||||
url_args={"swhid": str(dir_swhid)}, | |||||
query_params={"focus_swhid": focus_swhid}, | |||||
), | |||||
} | |||||
) | |||||
if filename: | |||||
breadcrumbs.append( | |||||
{ | |||||
"name": filename, | |||||
"object_id": swhid.object_id.hex(), | |||||
"path": path, | |||||
"url": "", | |||||
} | |||||
) | |||||
return breadcrumbs | |||||
@xframe_options_exempt | |||||
def swhid_iframe(request, swhid: str): | |||||
"""Django view that can be embedded in an iframe to display objects archived | |||||
by Software Heritage (currently contents and directories) in a minimalist | |||||
Web UI. | |||||
""" | |||||
focus_swhid = request.GET.get("focus_swhid", swhid) | |||||
parsed_swhid = None | |||||
view_data = {} | |||||
breadcrumbs = [] | |||||
swh_objects = [] | |||||
snapshot_context = None | |||||
swhids_info_extra_context = {} | |||||
try: | |||||
parsed_swhid = get_swhid(swhid) | |||||
parsed_focus_swhid = get_swhid(focus_swhid) | |||||
path = parsed_swhid.path.decode("utf-8") if parsed_swhid.path else "" | |||||
snapshot_context = None | |||||
revision_id = None | |||||
if ( | |||||
parsed_swhid.anchor | |||||
and parsed_swhid.anchor.object_type == ObjectType.REVISION | |||||
): | |||||
revision_id = parsed_swhid.anchor.object_id.hex() | |||||
if parsed_swhid.origin or parsed_swhid.visit: | |||||
snapshot_context = get_snapshot_context( | |||||
origin_url=parsed_swhid.origin, | |||||
snapshot_id=parsed_swhid.visit.object_id.hex() | |||||
if parsed_swhid.visit | |||||
else None, | |||||
revision_id=revision_id, | |||||
) | |||||
error_info: Dict[str, Any] = {"status_code": 200, "description": ""} | |||||
if parsed_swhid and parsed_swhid.object_type == ObjectType.CONTENT: | |||||
view_data = _get_content_rendering_data(parsed_swhid, path) | |||||
swh_objects.append( | |||||
SWHObjectInfo( | |||||
object_type=CONTENT, object_id=parsed_swhid.object_id.hex() | |||||
) | |||||
) | |||||
elif parsed_swhid and parsed_swhid.object_type == ObjectType.DIRECTORY: | |||||
view_data = _get_directory_rendering_data( | |||||
parsed_swhid, parsed_focus_swhid, path | |||||
) | |||||
swh_objects.append( | |||||
SWHObjectInfo( | |||||
object_type=DIRECTORY, object_id=parsed_swhid.object_id.hex() | |||||
) | |||||
) | |||||
elif parsed_swhid: | |||||
error_info = { | |||||
"status_code": 400, | |||||
"description": ( | |||||
f"Objects of type {parsed_swhid.object_type} are not supported" | |||||
), | |||||
} | |||||
swhids_info_extra_context["path"] = path | |||||
if parsed_swhid and view_data: | |||||
breadcrumbs = _get_breacrumbs_data( | |||||
parsed_swhid, parsed_focus_swhid, path, snapshot_context | |||||
) | |||||
if parsed_swhid.object_type == ObjectType.CONTENT and len(breadcrumbs) > 1: | |||||
swh_objects.append( | |||||
SWHObjectInfo( | |||||
object_type=DIRECTORY, object_id=breadcrumbs[-2]["object_id"] | |||||
) | |||||
) | |||||
swhids_info_extra_context["path"] = breadcrumbs[-2]["path"] | |||||
swhids_info_extra_context["filename"] = breadcrumbs[-1]["name"] | |||||
if snapshot_context: | |||||
swh_objects.append( | |||||
SWHObjectInfo( | |||||
object_type=REVISION, | |||||
object_id=snapshot_context["revision_id"] or "", | |||||
) | |||||
) | |||||
swh_objects.append( | |||||
SWHObjectInfo( | |||||
object_type=SNAPSHOT, | |||||
object_id=snapshot_context["snapshot_id"] or "", | |||||
) | |||||
) | |||||
except BadInputExc as e: | |||||
error_info = {"status_code": 400, "description": f"BadInputExc: {str(e)}"} | |||||
except NotFoundExc as e: | |||||
error_info = {"status_code": 404, "description": f"NotFoundExc: {str(e)}"} | |||||
except Exception as e: | |||||
error_info = {"status_code": 500, "description": str(e)} | |||||
return render( | |||||
request, | |||||
"misc/iframe.html", | |||||
{ | |||||
**view_data, | |||||
"iframe_mode": True, | |||||
"object_type": parsed_swhid.object_type.value if parsed_swhid else None, | |||||
"lines": parsed_swhid.lines if parsed_swhid else None, | |||||
"breadcrumbs": breadcrumbs, | |||||
"swhid": swhid, | |||||
"focus_swhid": focus_swhid, | |||||
"error_code": error_info["status_code"], | |||||
"error_message": http_status_code_message.get(error_info["status_code"]), | |||||
"error_description": error_info["description"], | |||||
"snapshot_context": None, | |||||
"swhids_info": get_swhids_info( | |||||
swh_objects, snapshot_context, swhids_info_extra_context | |||||
), | |||||
}, | |||||
status=error_info["status_code"], | |||||
) | |||||
urlpatterns = [ | |||||
url( | |||||
r"^embed/(?P<swhid>swh:[0-9]+:[a-z]+:[0-9a-f]+.*)$", | |||||
swhid_iframe, | |||||
name="swhid-iframe", | |||||
), | |||||
] |