diff --git a/swh/web/browse/views/release.py b/swh/web/browse/views/release.py index c7fe01f6..f8ceb6af 100644 --- a/swh/web/browse/views/release.py +++ b/swh/web/browse/views/release.py @@ -1,186 +1,210 @@ # Copyright (C) 2017-2019 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 django.shortcuts import render import sentry_sdk from swh.web.common import service 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.utils import ( gen_revision_link, get_snapshot_context, gen_link, gen_snapshot_link, get_swh_persistent_ids, gen_directory_link, gen_content_link, gen_release_link, gen_person_mail_link ) @browse_route(r'release/(?P[0-9a-f]+)/', view_name='browse-release', checksum_args=['sha1_git']) def release_browse(request, sha1_git): """ Django view that produces an HTML display of a release identified by its id. The url that points to it is :http:get:`/browse/release/(sha1_git)/`. """ try: release = service.lookup_release(sha1_git) snapshot_context = None origin_info = None snapshot_id = request.GET.get('snapshot_id', None) origin_url = request.GET.get('origin_url', None) if not origin_url: origin_url = request.GET.get('origin', None) timestamp = request.GET.get('timestamp', None) visit_id = request.GET.get('visit_id', None) if origin_url: try: snapshot_context = get_snapshot_context( snapshot_id, origin_url, timestamp, visit_id) except NotFoundExc: raw_rel_url = reverse('browse-release', url_args={'sha1_git': sha1_git}) error_message = \ ('The Software Heritage archive has a release ' 'with the hash you provided but the origin ' 'mentioned in your request appears broken: %s. ' 'Please check the URL and try again.\n\n' 'Nevertheless, you can still browse the release ' 'without origin information: %s' % (gen_link(origin_url), gen_link(raw_rel_url))) raise NotFoundExc(error_message) origin_info = snapshot_context['origin_info'] elif snapshot_id: snapshot_context = get_snapshot_context(snapshot_id) except Exception as exc: return handle_view_exception(request, exc) release_data = {} release_data['author'] = 'None' if release['author']: release_data['author'] = gen_person_mail_link(release['author']) release_data['date'] = format_utc_iso_date(release['date']) release_data['release'] = sha1_git release_data['name'] = release['name'] release_data['synthetic'] = release['synthetic'] release_data['target'] = release['target'] release_data['target type'] = release['target_type'] if snapshot_context: if release['target_type'] == 'revision': release_data['context-independent target'] = \ gen_revision_link(release['target']) elif release['target_type'] == 'content': release_data['context-independent target'] = \ gen_content_link(release['target']) elif release['target_type'] == 'directory': release_data['context-independent target'] = \ gen_directory_link(release['target']) elif release['target_type'] == 'release': release_data['context-independent target'] = \ gen_release_link(release['target']) release_note_lines = [] if release['message']: release_note_lines = release['message'].split('\n') vault_cooking = None + rev_directory = None target_link = None if release['target_type'] == 'revision': target_link = gen_revision_link(release['target'], snapshot_context=snapshot_context, link_text=None, link_attrs=None) try: revision = service.lookup_revision(release['target']) + rev_directory = revision['directory'] vault_cooking = { 'directory_context': True, - 'directory_id': revision['directory'], + 'directory_id': rev_directory, 'revision_context': True, 'revision_id': release['target'] } except Exception as exc: sentry_sdk.capture_exception(exc) elif release['target_type'] == 'directory': target_link = gen_directory_link(release['target'], snapshot_context=snapshot_context, link_text=None, link_attrs=None) try: - revision = service.lookup_directory(release['target']) + # check directory exists + service.lookup_directory(release['target']) vault_cooking = { 'directory_context': True, - 'directory_id': revision['directory'], + 'directory_id': release['target'], 'revision_context': False, 'revision_id': None } except Exception as exc: sentry_sdk.capture_exception(exc) elif release['target_type'] == 'content': target_link = gen_content_link(release['target'], snapshot_context=snapshot_context, link_text=None, link_attrs=None) elif release['target_type'] == 'release': target_link = gen_release_link(release['target'], snapshot_context=snapshot_context, link_text=None, link_attrs=None) + rev_directory_url = None + if rev_directory is not None: + if origin_info: + rev_directory_url = reverse( + 'browse-origin-directory', + url_args={'origin_url': origin_info['url']}, + query_params={'release': release['name']}) + elif snapshot_id: + rev_directory_url = reverse( + 'browse-snapshot-directory', + url_args={'snapshot_id': snapshot_id}, + query_params={'release': release['name']}) + else: + rev_directory_url = reverse( + 'browse-directory', + url_args={'sha1_git': rev_directory}) + + directory_link = None + if rev_directory_url is not None: + directory_link = gen_link(rev_directory_url, rev_directory) + release['directory_link'] = directory_link release['target_link'] = target_link if snapshot_context: release_data['snapshot'] = snapshot_context['snapshot_id'] if origin_info: release_data['context-independent release'] = \ gen_release_link(release['id']) release_data['origin url'] = gen_link(origin_info['url'], origin_info['url']) browse_snapshot_link = \ gen_snapshot_link(snapshot_context['snapshot_id']) release_data['context-independent snapshot'] = browse_snapshot_link swh_objects = [{'type': 'release', 'id': sha1_git}] if snapshot_context: snapshot_id = snapshot_context['snapshot_id'] if snapshot_id: swh_objects.append({'type': 'snapshot', 'id': snapshot_id}) swh_ids = get_swh_persistent_ids(swh_objects, snapshot_context) note_header = 'None' if len(release_note_lines) > 0: note_header = release_note_lines[0] release['note_header'] = note_header release['note_body'] = '\n'.join(release_note_lines[1:]) heading = 'Release - %s' % release['name'] if snapshot_context: context_found = 'snapshot: %s' % snapshot_context['snapshot_id'] if origin_info: context_found = 'origin: %s' % origin_info['url'] heading += ' - %s' % context_found return render(request, 'browse/release.html', {'heading': heading, 'swh_object_id': swh_ids[0]['swh_id'], 'swh_object_name': 'Release', 'swh_object_metadata': release_data, 'release': release, 'snapshot_context': snapshot_context, 'show_actions_menu': True, 'breadcrumbs': None, 'vault_cooking': vault_cooking, 'top_right_link': None, 'swh_ids': swh_ids}) diff --git a/swh/web/templates/browse/release.html b/swh/web/templates/browse/release.html index 54edf7e5..e98ae8e7 100644 --- a/swh/web/templates/browse/release.html +++ b/swh/web/templates/browse/release.html @@ -1,25 +1,30 @@ {% extends "./browse.html" %} {% comment %} Copyright (C) 2017-2019 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 {% endcomment %} {% load swh_templatetags %} {% block swh-browse-content %} {% include "includes/top-navigation.html" %}
Release {{ swh_object_metadata.name }} created by {{ swh_object_metadata.author }} on {{ swh_object_metadata.date }}
 
{{ release.note_header }}
{{ release.note_body }}
Target: {{ release.target_link}} + {% if release.directory_link %} +
+ Directory: + {{ release.directory_link}} + {% endif %}
{% endblock %} diff --git a/swh/web/tests/browse/views/test_release.py b/swh/web/tests/browse/views/test_release.py index 7f33c2b3..e85d1888 100644 --- a/swh/web/tests/browse/views/test_release.py +++ b/swh/web/tests/browse/views/test_release.py @@ -1,104 +1,117 @@ # Copyright (C) 2018-2019 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 import random from hypothesis import given from swh.web.common.utils import ( reverse, format_utc_iso_date, get_swh_persistent_id ) from swh.web.tests.django_asserts import assert_contains, assert_template_used from swh.web.tests.strategies import ( release, origin_with_releases, unknown_release ) @given(release()) def test_release_browse(client, archive_data, release): url = reverse('browse-release', url_args={'sha1_git': release}) release_data = archive_data.release_get(release) resp = client.get(url) - _release_browse_checks(resp, release_data) + _release_browse_checks(resp, release_data, archive_data) @given(origin_with_releases()) def test_release_browse_with_origin(client, archive_data, origin): snapshot = archive_data.snapshot_get_latest(origin['url']) release = random.choice([b for b in snapshot['branches'].values() if b['target_type'] == 'release']) url = reverse('browse-release', url_args={'sha1_git': release['target']}, query_params={'origin': origin['url']}) release_data = archive_data.release_get(release['target']) resp = client.get(url) - _release_browse_checks(resp, release_data, origin) + _release_browse_checks(resp, release_data, archive_data, origin) @given(unknown_release()) def test_release_browse_not_found(client, archive_data, unknown_release): url = reverse('browse-release', url_args={'sha1_git': unknown_release}) resp = client.get(url) assert resp.status_code == 404 assert_template_used(resp, 'error.html') err_msg = 'Release with sha1_git %s not found' % unknown_release assert_contains(resp, err_msg, status_code=404) @given(release()) def test_release_uppercase(client, release): url = reverse('browse-release-uppercase-checksum', url_args={'sha1_git': release.upper()}) resp = client.get(url) assert resp.status_code == 302 redirect_url = reverse('browse-release', url_args={'sha1_git': release}) assert resp['location'] == redirect_url -def _release_browse_checks(resp, release_data, origin_info=None): +def _release_browse_checks(resp, release_data, archive_data, origin_info=None): query_params = {} if origin_info: query_params['origin'] = origin_info['url'] release_id = release_data['id'] release_name = release_data['name'] author_name = release_data['author']['name'] release_date = release_data['date'] message = release_data['message'] target_type = release_data['target_type'] target = release_data['target'] target_url = reverse('browse-revision', url_args={'sha1_git': target}, query_params=query_params) message_lines = message.split('\n') assert resp.status_code == 200 assert_template_used(resp, 'browse/release.html') assert_contains(resp, author_name) assert_contains(resp, format_utc_iso_date(release_date)) assert_contains(resp, '
%s
%s' % (message_lines[0] or 'None', '\n'.join(message_lines[1:]))) assert_contains(resp, release_id) assert_contains(resp, release_name) assert_contains(resp, target_type) assert_contains(resp, '%s' % (target_url, target)) swh_rel_id = get_swh_persistent_id('release', release_id) swh_rel_id_url = reverse('browse-swh-id', url_args={'swh_id': swh_rel_id}) assert_contains(resp, swh_rel_id) assert_contains(resp, swh_rel_id_url) + + if release_data['target_type'] == 'revision': + if origin_info: + directory_url = reverse( + 'browse-origin-directory', + url_args={'origin_url': origin_info['url']}, + query_params={'release': release_data['name']}) + else: + rev = archive_data.revision_get(release_data['target']) + directory_url = reverse( + 'browse-directory', + url_args={'sha1_git': rev['directory']}) + assert_contains(resp, directory_url)