# Copyright (C) 2021-2024 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, cast
from django.http import HttpRequest, HttpResponse
from django.shortcuts import redirect, render
from swh.web.browse.browseurls import browse_route
from swh.web.browse.snapshot_context import (
browse_snapshot_directory,
get_snapshot_context,
)
from swh.web.utils import (
archive,
format_utc_iso_date,
parse_iso8601_date_to_utc,
redirect_to_new_route,
reverse,
)
from swh.web.utils.exc import BadInputExc
from swh.web.utils.origin_visits import get_origin_visits
[docs]
@browse_route(
r"origin/directory/",
view_name="browse-origin-directory",
)
def origin_directory_browse(request: HttpRequest) -> HttpResponse:
"""Django view for browsing the content of a directory associated
to an origin for a given visit.
The URL that points to it is :http:get:`/browse/origin/directory/`
"""
return browse_snapshot_directory(
request,
origin_url=request.GET.get("origin_url"),
snapshot_id=request.GET.get("snapshot"),
timestamp=request.GET.get("timestamp"),
path=request.GET.get("path"),
)
[docs]
@browse_route(
r"origin/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/directory/",
r"origin/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/directory/(?P<path>.+)/",
r"origin/(?P<origin_url>.+)/directory/(?P<path>.+)/",
r"origin/(?P<origin_url>.+)/directory/",
view_name="browse-origin-directory-legacy",
)
def origin_directory_browse_legacy(
request: HttpRequest,
origin_url: str,
timestamp: Optional[str] = None,
path: Optional[str] = None,
) -> HttpResponse:
"""Django view for browsing the content of a directory associated
to an origin for a given visit.
The URLs that point to it are
:http:get:`/browse/origin/(origin_url)/directory/[(path)/]` and
:http:get:`/browse/origin/(origin_url)/visit/(timestamp)/directory/[(path)/]`
"""
return browse_snapshot_directory(
request,
origin_url=origin_url,
snapshot_id=request.GET.get("snapshot"),
timestamp=timestamp,
path=path,
)
[docs]
@browse_route(
r"origin/content/",
view_name="browse-origin-content",
)
def origin_content_browse(request: HttpRequest) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/content` instead
Django view that produces an HTML display of a content
associated to an origin for a given visit.
The URL that points to it is :http:get:`/browse/origin/content/`
"""
return redirect_to_new_route(request, "browse-content")
[docs]
@browse_route(
r"origin/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/content/(?P<path>.+)/",
r"origin/(?P<origin_url>.+)/content/(?P<path>.+)/",
r"origin/(?P<origin_url>.+)/content/",
view_name="browse-origin-content-legacy",
)
def origin_content_browse_legacy(
request: HttpRequest,
origin_url: str,
path: Optional[str] = None,
timestamp: Optional[str] = None,
) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/content` instead
Django view that produces an HTML display of a content
associated to an origin for a given visit.
The URLs that point to it are
:http:get:`/browse/origin/(origin_url)/content/(path)/` and
:http:get:`/browse/origin/(origin_url)/visit/(timestamp)/content/(path)/`
"""
return redirect_to_new_route(request, "browse-content")
[docs]
@browse_route(
r"origin/log/",
view_name="browse-origin-log",
)
def origin_log_browse(request: HttpRequest) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/snapshot/log` instead
Django view that produces an HTML display of revisions history (aka
the commit log) associated to a software origin.
The URL that points to it is :http:get:`/browse/origin/log/`
"""
return redirect_to_new_route(request, "browse-snapshot-log")
[docs]
@browse_route(
r"origin/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/log/",
r"origin/(?P<origin_url>.+)/log/",
view_name="browse-origin-log-legacy",
)
def origin_log_browse_legacy(
request: HttpRequest, origin_url: str, timestamp: Optional[str] = None
) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/snapshot/log` instead
Django view that produces an HTML display of revisions history (aka
the commit log) associated to a software origin.
The URLs that point to it are
:http:get:`/browse/origin/(origin_url)/log/` and
:http:get:`/browse/origin/(origin_url)/visit/(timestamp)/log/`
"""
return redirect_to_new_route(
request,
"browse-snapshot-log",
)
[docs]
@browse_route(
r"origin/branches/",
view_name="browse-origin-branches",
)
def origin_branches_browse(request: HttpRequest) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/snapshot/branches` instead
Django view that produces an HTML display of the list of branches
associated to an origin for a given visit.
The URL that points to it is :http:get:`/browse/origin/branches/`
"""
return redirect_to_new_route(request, "browse-snapshot-branches")
[docs]
@browse_route(
r"origin/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/branches/",
r"origin/(?P<origin_url>.+)/branches/",
view_name="browse-origin-branches-legacy",
)
def origin_branches_browse_legacy(
request: HttpRequest, origin_url: str, timestamp: Optional[str] = None
) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/snapshot/branches` instead
Django view that produces an HTML display of the list of branches
associated to an origin for a given visit.
The URLs that point to it are
:http:get:`/browse/origin/(origin_url)/branches/` and
:http:get:`/browse/origin/(origin_url)/visit/(timestamp)/branches/`
"""
return redirect_to_new_route(request, "browse-snapshot-branches")
[docs]
@browse_route(
r"origin/releases/",
view_name="browse-origin-releases",
)
def origin_releases_browse(request: HttpRequest) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/snapshot/releases` instead
Django view that produces an HTML display of the list of releases
associated to an origin for a given visit.
The URL that points to it is :http:get:`/browse/origin/releases/`
"""
return redirect_to_new_route(request, "browse-snapshot-releases")
[docs]
@browse_route(
r"origin/(?P<origin_url>.+)/visit/(?P<timestamp>.+)/releases/",
r"origin/(?P<origin_url>.+)/releases/",
view_name="browse-origin-releases-legacy",
)
def origin_releases_browse_legacy(
request: HttpRequest, origin_url: str, timestamp: Optional[str] = None
) -> HttpResponse:
"""
This route is deprecated; use http:get:`/browse/snapshot/releases` instead
Django view that produces an HTML display of the list of releases
associated to an origin for a given visit.
The URLs that point to it are
:http:get:`/browse/origin/(origin_url)/releases/` and
:http:get:`/browse/origin/(origin_url)/visit/(timestamp)/releases/`
"""
return redirect_to_new_route(request, "browse-snapshot-releases")
def _origin_visits_browse(
request: HttpRequest, origin_url: Optional[str]
) -> HttpResponse:
if origin_url is None:
raise BadInputExc("An origin URL must be provided as query parameter.")
origin_info = archive.lookup_origin(origin_url)
origin_visits = cast(
List[Dict[str, Any]],
get_origin_visits(origin_info["url"], visit_type=request.GET.get("visit_type")),
)
snapshot_context = get_snapshot_context(
origin_url=origin_url, visit_type=request.GET.get("visit_type")
)
for i, visit in enumerate(origin_visits):
url_date = format_utc_iso_date(visit["date"], "%Y-%m-%dT%H:%M:%SZ")
visit["formatted_date"] = format_utc_iso_date(visit["date"])
query_params = {"origin_url": origin_url, "timestamp": url_date}
if i < len(origin_visits) - 1:
if visit["date"] == origin_visits[i + 1]["date"]:
query_params = {"origin_url": origin_url, "visit_id": visit["visit"]}
if i > 0:
if visit["date"] == origin_visits[i - 1]["date"]:
query_params = {"origin_url": origin_url, "visit_id": visit["visit"]}
snapshot = visit["snapshot"] if visit["snapshot"] else ""
visit["url"] = reverse(
"browse-origin-directory",
query_params=query_params,
)
if not snapshot:
visit["snapshot"] = ""
visit["date"] = parse_iso8601_date_to_utc(visit["date"]).timestamp()
heading = "Origin visits - %s" % origin_url
return render(
request,
"browse-origin-visits.html",
{
"heading": heading,
"swh_object_name": "Visits",
"swh_object_metadata": origin_info,
"origin_visits": origin_visits,
"origin_info": origin_info,
"snapshot_context": snapshot_context,
"vault_cooking": None,
"show_actions": False,
},
)
[docs]
@browse_route(r"origin/visits/", view_name="browse-origin-visits")
def origin_visits_browse(request: HttpRequest) -> HttpResponse:
"""Django view that produces an HTML display of visits reporting
for a given origin.
The URL that points to it is
:http:get:`/browse/origin/visits/`.
"""
return _origin_visits_browse(request, request.GET.get("origin_url"))
[docs]
@browse_route(
r"origin/(?P<origin_url>.+)/visits/", view_name="browse-origin-visits-legacy"
)
def origin_visits_browse_legacy(request: HttpRequest, origin_url: str) -> HttpResponse:
"""Django view that produces an HTML display of visits reporting
for a given origin.
The URL that points to it is
:http:get:`/browse/origin/(origin_url)/visits/`.
"""
return _origin_visits_browse(request, origin_url)
[docs]
@browse_route(r"origin/", view_name="browse-origin")
def origin_browse(request: HttpRequest) -> HttpResponse:
"""Django view that redirects to the display of the latest archived
snapshot for a given software origin.
"""
last_snapshot_url = reverse(
"browse-origin-directory",
query_params=request.GET,
)
return redirect(last_snapshot_url)
[docs]
@browse_route(r"origin/(?P<origin_url>.+)/", view_name="browse-origin-legacy")
def origin_browse_legacy(request: HttpRequest, origin_url: str) -> HttpResponse:
"""Django view that redirects to the display of the latest archived
snapshot for a given software origin.
"""
last_snapshot_url = reverse(
"browse-origin-directory",
query_params={"origin_url": origin_url, **request.GET},
)
return redirect(last_snapshot_url)