diff --git a/swh/web/browse/views/directory.py b/swh/web/browse/views/directory.py index 917ba6a4..bd38d5bf 100644 --- a/swh/web/browse/views/directory.py +++ b/swh/web/browse/views/directory.py @@ -1,177 +1,179 @@ -# 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 import os from django.http import HttpResponse from django.shortcuts import render, redirect from django.template.defaultfilters import filesizeformat import sentry_sdk 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.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 @browse_route(r'directory/(?P[0-9a-f]+)/', r'directory/(?P[0-9a-f]+)/(?P.+)/', view_name='browse-directory', checksum_args=['sha1_git']) def directory_browse(request, sha1_git, path=None): """Django view for browsing the content of a directory identified by its sha1_git value. The url that points to it is :http:get:`/browse/directory/(sha1_git)/[(path)/]` """ root_sha1_git = sha1_git try: if path: dir_info = service.lookup_directory_with_path(sha1_git, path) sha1_git = dir_info['target'] dirs, files = get_directory_entries(sha1_git) origin_url = request.GET.get('origin_url', None) if not origin_url: origin_url = request.GET.get('origin', None) snapshot_context = None if origin_url: try: snapshot_context = get_snapshot_context(origin_url=origin_url) except NotFoundExc: raw_dir_url = reverse('browse-directory', url_args={'sha1_git': sha1_git}) error_message = \ ('The Software Heritage archive has a directory ' '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 directory ' 'without origin information: %s' % (gen_link(origin_url), gen_link(raw_dir_url))) raise NotFoundExc(error_message) if snapshot_context: snapshot_context['visit_info'] = None except Exception as exc: return handle_view_exception(request, exc) path_info = gen_path_info(path) query_params = {'origin': origin_url} breadcrumbs = [] breadcrumbs.append({'name': root_sha1_git[:7], 'url': reverse('browse-directory', url_args={'sha1_git': root_sha1_git}, query_params=query_params)}) for pi in path_info: breadcrumbs.append({'name': pi['name'], 'url': reverse('browse-directory', url_args={'sha1_git': root_sha1_git, 'path': pi['path']}, query_params=query_params)}) path = '' if path is None else (path + '/') for d in dirs: if d['type'] == 'rev': d['url'] = reverse('browse-revision', url_args={'sha1_git': d['target']}, query_params=query_params) else: d['url'] = reverse('browse-directory', url_args={'sha1_git': root_sha1_git, 'path': path + d['name']}, query_params=query_params) sum_file_sizes = 0 readmes = {} for f in files: query_string = 'sha1_git:' + f['target'] f['url'] = reverse('browse-content', url_args={'query_string': query_string}, query_params={'path': root_sha1_git + '/' + path + f['name'], 'origin': origin_url}) if f['length'] is not None: sum_file_sizes += f['length'] f['length'] = filesizeformat(f['length']) if f['name'].lower().startswith('readme'): readmes[f['name']] = f['checksums']['sha1'] readme_name, readme_url, readme_html = get_readme_to_display(readmes) sum_file_sizes = filesizeformat(sum_file_sizes) dir_metadata = {"directory": sha1_git, "number of regular files": len(files), "number of subdirectories": len(dirs), "sum of regular file sizes": sum_file_sizes} vault_cooking = { 'directory_context': True, 'directory_id': sha1_git, 'revision_context': False, 'revision_id': None } - swh_ids = get_swh_persistent_ids([{'type': 'directory', - 'id': sha1_git}]) + swh_objects = [{'type': 'directory', 'id': sha1_git}] + + swh_ids = get_swh_persistent_ids( + swh_objects=swh_objects, snapshot_context=snapshot_context) heading = 'Directory - %s' % sha1_git if breadcrumbs: dir_path = '/'.join([bc['name'] for bc in breadcrumbs]) + '/' heading += ' - %s' % dir_path return render(request, 'browse/directory.html', {'heading': heading, 'swh_object_id': swh_ids[0]['swh_id'], 'swh_object_name': 'Directory', 'swh_object_metadata': dir_metadata, 'dirs': dirs, 'files': files, 'breadcrumbs': breadcrumbs, 'top_right_link': None, 'readme_name': readme_name, 'readme_url': readme_url, 'readme_html': readme_html, 'snapshot_context': snapshot_context, 'vault_cooking': vault_cooking, 'show_actions_menu': True, 'swh_ids': swh_ids}) -@browse_route(r'directory/resolve/content-path/(?P[0-9a-f]+)/(?P.+)/', # noqa +@browse_route(r'directory/resolve/content-path/(?P[0-9a-f]+)/(?P.+)/', # noqa view_name='browse-directory-resolve-content-path', checksum_args=['sha1_git']) def _directory_resolve_content_path(request, sha1_git, path): """ Internal endpoint redirecting to data url for a specific file path relative to a root directory. """ try: path = os.path.normpath(path) if not path.startswith('../'): dir_info = service.lookup_directory_with_path(sha1_git, path) if dir_info['type'] == 'file': sha1 = dir_info['checksums']['sha1'] data_url = reverse('browse-content-raw', url_args={'query_string': sha1}) return redirect(data_url) except Exception as exc: sentry_sdk.capture_exception(exc) return HttpResponse(status=404) diff --git a/swh/web/tests/browse/views/test_directory.py b/swh/web/tests/browse/views/test_directory.py index 05e478a3..78102b45 100644 --- a/swh/web/tests/browse/views/test_directory.py +++ b/swh/web/tests/browse/views/test_directory.py @@ -1,133 +1,146 @@ -# 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 import random from hypothesis import given from swh.web.common.utils import reverse, get_swh_persistent_id from swh.web.common.utils import gen_path_info from swh.web.tests.django_asserts import assert_contains, assert_template_used from swh.web.tests.strategies import ( directory, directory_with_subdirs, invalid_sha1, unknown_directory ) @given(directory()) def test_root_directory_view(client, archive_data, directory): _directory_view(client, directory, archive_data.directory_ls(directory)) @given(directory_with_subdirs()) def test_sub_directory_view(client, archive_data, directory): dir_content = archive_data.directory_ls(directory) subdir = random.choice([e for e in dir_content if e['type'] == 'dir']) subdir_content = archive_data.directory_ls(subdir['target']) _directory_view(client, directory, subdir_content, subdir['name']) @given(invalid_sha1(), unknown_directory()) def test_directory_request_errors(client, invalid_sha1, unknown_directory): dir_url = reverse('browse-directory', url_args={'sha1_git': invalid_sha1}) resp = client.get(dir_url) assert resp.status_code == 400 assert_template_used(resp, 'error.html') dir_url = reverse('browse-directory', url_args={'sha1_git': unknown_directory}) resp = client.get(dir_url) assert resp.status_code == 404 assert_template_used(resp, 'error.html') @given(directory()) def test_directory_uppercase(client, directory): url = reverse('browse-directory-uppercase-checksum', url_args={'sha1_git': directory.upper()}) resp = client.get(url) assert resp.status_code == 302 redirect_url = reverse('browse-directory', url_args={'sha1_git': directory}) assert resp['location'] == redirect_url +@given(directory()) +def test_permalink_box_context(client, tests_data, directory): + origin_url = random.choice(tests_data['origins'])['url'] + url = reverse('browse-directory', + url_args={'sha1_git': directory}, + query_params={'origin': origin_url}) + + resp = client.get(url) + + assert resp.status_code == 200 + assert_contains(resp, 'id="swh-id-option-origin-directory"') + + def _directory_view(client, root_directory_sha1, directory_entries, path=None): dirs = [e for e in directory_entries if e['type'] in ('dir', 'rev')] files = [e for e in directory_entries if e['type'] == 'file'] url_args = {'sha1_git': root_directory_sha1} if path: url_args['path'] = path url = reverse('browse-directory', url_args=url_args) root_dir_url = reverse('browse-directory', url_args={'sha1_git': root_directory_sha1}) resp = client.get(url) assert resp.status_code == 200 assert_template_used(resp, 'browse/directory.html') assert_contains(resp, '' + root_directory_sha1[:7] + '') assert_contains(resp, '', count=len(dirs)) assert_contains(resp, '', count=len(files)) for d in dirs: if d['type'] == 'rev': dir_url = reverse('browse-revision', url_args={'sha1_git': d['target']}) else: dir_path = d['name'] if path: dir_path = "%s/%s" % (path, d['name']) dir_url = reverse('browse-directory', url_args={'sha1_git': root_directory_sha1, 'path': dir_path}) assert_contains(resp, dir_url) for f in files: file_path = "%s/%s" % (root_directory_sha1, f['name']) if path: file_path = "%s/%s/%s" % (root_directory_sha1, path, f['name']) query_string = 'sha1_git:' + f['target'] file_url = reverse('browse-content', url_args={'query_string': query_string}, query_params={'path': file_path}) assert_contains(resp, file_url) path_info = gen_path_info(path) assert_contains(resp, '
  • ', count=len(path_info)+1) assert_contains(resp, '%s' % (root_dir_url, root_directory_sha1[:7])) for p in path_info: dir_url = reverse('browse-directory', url_args={'sha1_git': root_directory_sha1, 'path': p['path']}) assert_contains(resp, '%s' % (dir_url, p['name'])) assert_contains(resp, 'vault-cook-directory') swh_dir_id = get_swh_persistent_id( 'directory', directory_entries[0]['dir_id']) swh_dir_id_url = reverse('browse-swh-id', url_args={'swh_id': swh_dir_id}) assert_contains(resp, swh_dir_id) assert_contains(resp, swh_dir_id_url)