diff --git a/swh/web/ui/tests/test_renderers.py b/swh/web/ui/tests/test_renderers.py index b22ae942f..b7a83ca73 100644 --- a/swh/web/ui/tests/test_renderers.py +++ b/swh/web/ui/tests/test_renderers.py @@ -1,231 +1,239 @@ # Copyright (C) 2015 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 json import unittest import yaml from flask_api.mediatypes import MediaType from nose.tools import istest from unittest.mock import patch from swh.web.ui import renderers class RendererTestCase(unittest.TestCase): @patch('swh.web.ui.renderers.request') @istest def swh_filter_renderer_do_nothing(self, mock_request): # given mock_request.args = {} swh_filter_renderer = renderers.SWHFilterEnricher() input_data = {'a': 'some-data'} # when actual_data = swh_filter_renderer.filter_by_fields(input_data) # then self.assertEquals(actual_data, input_data) @patch('swh.web.ui.renderers.utils') @patch('swh.web.ui.renderers.request') @istest def swh_filter_renderer_do_filter(self, mock_request, mock_utils): # given mock_request.args = {'fields': 'a,c'} mock_utils.filter_field_keys.return_value = {'a': 'some-data'} swh_filter_renderer = renderers.SWHFilterEnricher() input_data = {'a': 'some-data', 'b': 'some-other-data'} # when actual_data = swh_filter_renderer.filter_by_fields(input_data) # then self.assertEquals(actual_data, {'a': 'some-data'}) mock_utils.filter_field_keys.assert_called_once_with(input_data, {'a', 'c'}) @patch('swh.web.ui.renderers.request') @istest def yaml_renderer_without_filter(self, mock_request): # given mock_request.args = {} yaml_renderer = renderers.YAMLRenderer() input_data = {'target': 'sha1-dir', 'type': 'dir', 'dir-id': 'dir-id-sha1-git'} expected_data = input_data # when actual_data = yaml_renderer.render(input_data, 'application/yaml') # then self.assertEqual(yaml.load(actual_data), expected_data) @patch('swh.web.ui.renderers.request') @istest def yaml_renderer(self, mock_request): # given mock_request.args = {'fields': 'type,target'} yaml_renderer = renderers.YAMLRenderer() input_data = {'target': 'sha1-dir', 'type': 'dir', 'dir-id': 'dir-id-sha1-git'} expected_data = {'target': 'sha1-dir', 'type': 'dir'} # when actual_data = yaml_renderer.render(input_data, 'application/yaml') # then self.assertEqual(yaml.load(actual_data), expected_data) @patch('swh.web.ui.renderers.request') @istest def json_renderer_basic(self, mock_request): # given mock_request.args = {} json_renderer = renderers.SWHJSONRenderer() input_data = {'target': 'sha1-dir', 'type': 'dir', 'dir-id': 'dir-id-sha1-git'} expected_data = input_data # when actual_data = json_renderer.render(input_data, MediaType( 'application/json')) # then self.assertEqual(json.loads(actual_data), expected_data) @patch('swh.web.ui.renderers.request') @istest def json_renderer_basic_with_filter(self, mock_request): # given mock_request.args = {'fields': 'target'} json_renderer = renderers.SWHJSONRenderer() input_data = {'target': 'sha1-dir', 'type': 'dir', 'dir-id': 'dir-id-sha1-git'} expected_data = {'target': 'sha1-dir'} # when actual_data = json_renderer.render(input_data, MediaType( 'application/json')) # then self.assertEqual(json.loads(actual_data), expected_data) @patch('swh.web.ui.renderers.request') @istest def json_renderer_basic_with_filter_and_jsonp(self, mock_request): # given mock_request.args = {'fields': 'target', 'callback': 'jsonpfn'} json_renderer = renderers.SWHJSONRenderer() input_data = {'target': 'sha1-dir', 'type': 'dir', 'dir-id': 'dir-id-sha1-git'} # when actual_data = json_renderer.render(input_data, MediaType( 'application/json')) # then self.assertEqual(actual_data, 'jsonpfn({"target": "sha1-dir"})') @patch('swh.web.ui.renderers.request') @istest def jsonp_enricher_basic_with_filter_and_jsonp(self, mock_request): # given mock_request.args = {'callback': 'jsonpfn'} jsonp_enricher = renderers.JSONPEnricher() # when actual_output = jsonp_enricher.enrich_with_jsonp({'output': 'test'}) # then self.assertEqual(actual_output, "jsonpfn({'output': 'test'})") @patch('swh.web.ui.renderers.request') @istest def jsonp_enricher_do_nothing(self, mock_request): # given mock_request.args = {} jsonp_enricher = renderers.JSONPEnricher() # when actual_output = jsonp_enricher.enrich_with_jsonp({'output': 'test'}) # then self.assertEqual(actual_output, {'output': 'test'}) @istest def urlize_api_links(self): # update api link with html links content with links content = '{"url": "/api/1/abc/"}' expected_content = '{"url": "/api/1/abc/"}' self.assertEquals(renderers.urlize_api_links(content), expected_content) # update /browse link with html links content with links content = '{"url": "/browse/def/"}' expected_content = '{"url": "' \ '/browse/def/"}' self.assertEquals(renderers.urlize_api_links(content), expected_content) # will do nothing since it's not an api url other_content = '{"url": "/something/api/1/other"}' self.assertEquals(renderers.urlize_api_links(other_content), other_content) + @istest + def revision_id_from_url(self): + url = ('/browse/revision/9ba4bcb645898d562498ea66a0df958ef0e7a68c/' + 'prev/9ba4bcb645898d562498ea66a0df958ef0e7aaaa/') + + expected_id = '9ba4bcb645898d562498ea66a0df958ef0e7a68c' + self.assertEqual(renderers.revision_id_from_url(url), expected_id) + @istest def safe_docstring_display(self): # update api link with html links content with links docstring = """

Show all revisions (~git log) starting from sha1_git. The first element returned is the given sha1_git.

Args: sha1_git: the revision's hash

Returns: Information on the revision if found.

Raises: BadInputExc in case of unknown algo_hash or bad hash NotFoundExc if the revision is not found.

Example: blah

""" expected_docstring = """

Show all revisions (~git log) starting from sha1_git. The first element returned is the given sha1_git.

Args:

   sha1_git: the revision's hash

Returns:

   Information on the revision if found.

Raises:

   BadInputExc in case of unknown algo_hash or bad hash NotFoundExc if the revision is not found.

Example:

   blah

""" self.assertEquals(renderers.safe_docstring_display(docstring), expected_docstring) diff --git a/swh/web/ui/tests/views/test_browse.py b/swh/web/ui/tests/views/test_browse.py index e08ce4896..930909e11 100644 --- a/swh/web/ui/tests/views/test_browse.py +++ b/swh/web/ui/tests/views/test_browse.py @@ -1,1710 +1,1730 @@ # Copyright (C) 2015 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 nose.tools import istest from unittest.mock import patch from swh.web.ui.exc import BadInputExc, NotFoundExc from .. import test_app class FileMock(): def __init__(self, filename): self.filename = filename class SearchView(test_app.SWHViewTestCase): render_template = False + @patch('swh.web.ui.apidoc.APIUrls') + @istest + def browse_api_doc(self, mock_api_urls): + # given + endpoints = { + '/a/doc/endpoint/': 'relevant documentation', + '/some/other/endpoint/': 'more docstrings'} + mock_api_urls.apidoc_routes = endpoints + + # when + rv = self.client.get('/api/1/doc/') + + # then + self.assertEquals(rv.status_code, 200) + self.assertIsNotNone( + self.get_context_variable('doc_routes'), + sorted(endpoints.items()) + ) + self.assert_template_used('api.html') + @istest def search_default(self): # when rv = self.client.get('/search/') self.assertEqual(rv.status_code, 200) self.assertEqual(self.get_context_variable('message'), '') self.assertEqual(self.get_context_variable('search_res'), None) self.assert_template_used('search.html') @patch('swh.web.ui.views.browse.api') @istest def search_get_query_hash_not_found(self, mock_api): # given mock_api.api_search.return_value = { 'search_res': [{ 'filename': None, 'sha1': 'sha1:456', 'found': False}], 'search_stats': {'nbfiles': 1, 'pct': 100}} # when rv = self.client.get('/search/?q=sha1:456') self.assertEqual(rv.status_code, 200) self.assertEqual(self.get_context_variable('message'), '') self.assertEqual(self.get_context_variable('search_res'), [ {'filename': None, 'sha1': 'sha1:456', 'found': False}]) self.assert_template_used('search.html') mock_api.api_search.assert_called_once_with('sha1:456') @patch('swh.web.ui.views.browse.api') @istest def search_get_query_hash_bad_input(self, mock_api): # given mock_api.api_search.side_effect = BadInputExc('error msg') # when rv = self.client.get('/search/?q=sha1_git:789') self.assertEqual(rv.status_code, 200) self.assertEqual(self.get_context_variable('message'), 'error msg') self.assertEqual(self.get_context_variable('search_res'), None) self.assert_template_used('search.html') mock_api.api_search.assert_called_once_with('sha1_git:789') @patch('swh.web.ui.views.browse.api') @istest def search_get_query_hash_found(self, mock_api): # given mock_api.api_search.return_value = { 'search_res': [{ 'filename': None, 'sha1': 'sha1:123', 'found': True}], 'search_stats': {'nbfiles': 1, 'pct': 100}} # when rv = self.client.get('/search/?q=sha1:123') self.assertEqual(rv.status_code, 200) self.assertEqual(self.get_context_variable('message'), '') self.assertEqual(len(self.get_context_variable('search_res')), 1) resp = self.get_context_variable('search_res')[0] self.assertTrue(resp is not None) self.assertEqual(resp['sha1'], 'sha1:123') self.assertEqual(resp['found'], True) self.assert_template_used('search.html') mock_api.api_search.assert_called_once_with('sha1:123') @patch('swh.web.ui.views.browse.request') @patch('swh.web.ui.views.browse.api') @istest def search_post_hashes_bad_input(self, mock_api, mock_request): # given mock_request.form = {'a': ['456caf10e9535160d90e874b45aa426de762f19f'], 'b': ['745bab676c8f3cec8016e0c39ea61cf57e518865']} mock_request.method = 'POST' mock_api.api_search.side_effect = BadInputExc( 'error bad input') # when (mock_request completes the post request) rv = self.client.post('/search/') # then self.assertEqual(rv.status_code, 200) self.assertEqual(self.get_context_variable('search_stats'), {'nbfiles': 0, 'pct': 0}) self.assertEqual(self.get_context_variable('search_res'), None) self.assertEqual(self.get_context_variable('message'), 'error bad input') self.assert_template_used('search.html') @patch('swh.web.ui.views.browse.request') @patch('swh.web.ui.views.browse.api') @istest def search_post_hashes_none(self, mock_api, mock_request): # given mock_request.form = {'a': ['456caf10e9535160d90e874b45aa426de762f19f'], 'b': ['745bab676c8f3cec8016e0c39ea61cf57e518865']} mock_request.method = 'POST' mock_api.api_search.return_value = { 'search_stats': {'nbfiles': 2, 'pct': 0}, 'search_res': [{'filename': 'a', 'sha1': '456caf10e9535160d90e874b45aa426de762f19f', 'found': False}, {'filename': 'b', 'sha1': '745bab676c8f3cec8016e0c39ea61cf57e518865', 'found': False}]} # when (mock_request completes the post request) rv = self.client.post('/search/') # then self.assertEqual(rv.status_code, 200) self.assertIsNotNone(self.get_context_variable('search_res')) self.assertTrue(self.get_context_variable('search_stats') is not None) self.assertEqual(len(self.get_context_variable('search_res')), 2) stats = self.get_context_variable('search_stats') self.assertEqual(stats['nbfiles'], 2) self.assertEqual(stats['pct'], 0) a, b = self.get_context_variable('search_res') self.assertEqual(a['found'], False) self.assertEqual(b['found'], False) self.assertEqual(self.get_context_variable('message'), '') self.assert_template_used('search.html') @patch('swh.web.ui.views.browse.request') @patch('swh.web.ui.views.browse.api') @istest def search_post_hashes_some(self, mock_api, mock_request): # given mock_request.form = {'a': '456caf10e9535160d90e874b45aa426de762f19f', 'b': '745bab676c8f3cec8016e0c39ea61cf57e518865'} mock_request.method = 'POST' mock_api.api_search.return_value = { 'search_stats': {'nbfiles': 2, 'pct': 50}, 'search_res': [{'filename': 'a', 'sha1': '456caf10e9535160d90e874b45aa426de762f19f', 'found': False}, {'filename': 'b', 'sha1': '745bab676c8f3cec8016e0c39ea61cf57e518865', 'found': True}]} # when (mock_request completes the post request) rv = self.client.post('/search/') # then self.assertEqual(rv.status_code, 200) self.assertIsNotNone(self.get_context_variable('search_res')) self.assertEqual(len(self.get_context_variable('search_res')), 2) self.assertTrue(self.get_context_variable('search_stats') is not None) stats = self.get_context_variable('search_stats') self.assertEqual(stats['nbfiles'], 2) self.assertEqual(stats['pct'], 50) self.assertEqual(self.get_context_variable('message'), '') a, b = self.get_context_variable('search_res') self.assertEqual(a['found'], False) self.assertEqual(b['found'], True) self.assert_template_used('search.html') class ContentView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_content_ko_not_found(self, mock_api): # given mock_api.api_content_metadata.side_effect = NotFoundExc( 'Not found!') # when rv = self.client.get('/browse/content/sha1:sha1-hash/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content.html') self.assertEqual(self.get_context_variable('message'), 'Not found!') self.assertIsNone(self.get_context_variable('content')) mock_api.api_content_metadata.assert_called_once_with( 'sha1:sha1-hash') @patch('swh.web.ui.views.browse.api') @istest def browse_content_ko_bad_input(self, mock_api): # given mock_api.api_content_metadata.side_effect = BadInputExc( 'Bad input!') # when rv = self.client.get('/browse/content/sha1:sha1-hash/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content.html') self.assertEqual(self.get_context_variable('message'), 'Bad input!') self.assertIsNone(self.get_context_variable('content')) mock_api.api_content_metadata.assert_called_once_with( 'sha1:sha1-hash') @patch('swh.web.ui.views.browse.service') @patch('swh.web.ui.views.browse.api') @istest def browse_content(self, mock_api, mock_service): # given stub_content = {'sha1': 'sha1_hash'} mock_api.api_content_metadata.return_value = stub_content mock_service.lookup_content_raw.return_value = {'data': b'blah'} expected_content = {'sha1': 'sha1_hash', 'data': 'blah'} # when rv = self.client.get('/browse/content/sha1:sha1-hash/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content.html') self.assertIsNone(self.get_context_variable('message')) self.assertEqual(self.get_context_variable('content'), expected_content) mock_service.lookup_content_raw.assert_called_once_with( 'sha1:sha1-hash') mock_api.api_content_metadata.assert_called_once_with( 'sha1:sha1-hash') @patch('swh.web.ui.views.browse.redirect') @patch('swh.web.ui.views.browse.url_for') @istest def browse_content_raw(self, mock_urlfor, mock_redirect): # given stub_content_raw = b'some-data' mock_urlfor.return_value = '/api/content/sha1:sha1-hash/raw/' mock_redirect.return_value = stub_content_raw # when rv = self.client.get('/browse/content/sha1:sha1-hash/raw/') self.assertEqual(rv.status_code, 200) self.assertEqual(rv.data, stub_content_raw) mock_urlfor.assert_called_once_with('api_content_raw', q='sha1:sha1-hash') mock_redirect.assert_called_once_with( '/api/content/sha1:sha1-hash/raw/') class DirectoryView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_directory_ko_bad_input(self, mock_api): # given mock_api.api_directory.side_effect = BadInputExc( 'Invalid hash') # when rv = self.client.get('/browse/directory/sha2-invalid/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('directory.html') self.assertEqual(self.get_context_variable('message'), 'Invalid hash') self.assertEqual(self.get_context_variable('files'), []) mock_api.api_directory.assert_called_once_with( 'sha2-invalid') @patch('swh.web.ui.views.browse.api') @istest def browse_directory_empty_result(self, mock_api): # given mock_api.api_directory.return_value = [] # when rv = self.client.get('/browse/directory/some-sha1/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('directory.html') self.assertEqual(self.get_context_variable('message'), 'Listing for directory some-sha1:') self.assertEqual(self.get_context_variable('files'), []) mock_api.api_directory.assert_called_once_with( 'some-sha1') @patch('swh.web.ui.views.browse.service') @patch('swh.web.ui.views.browse.api') @istest def browse_directory_relative_file(self, mock_api, mock_service): # given stub_entry = { 'sha256': '240', 'type': 'file' } mock_service.lookup_directory_with_path.return_value = stub_entry stub_file = { 'sha1_git': '123', 'sha1': '456', 'status': 'visible', 'data_url': '/api/1/content/890', 'length': 42, 'ctime': 'Thu, 01 Oct 2015 12:13:53 GMT', 'target': 'file.txt', 'sha256': '148' } mock_api.api_content_metadata.return_value = stub_file mock_service.lookup_content_raw.return_value = { 'data': 'this is my file'} # when rv = self.client.get('/browse/directory/sha1/path/to/file/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content.html') self.assertIsNotNone(self.get_context_variable('content')) content = self.get_context_variable('content') # change caused by call to prepare_data_for_view self.assertEqual(content['data_url'], '/browse/content/890') self.assertEqual(content['data'], 'this is my file') mock_api.api_content_metadata.assert_called_once_with('sha256:240') mock_service.lookup_content_raw.assert_called_once_with('sha256:240') @patch('swh.web.ui.views.browse.service') @patch('swh.web.ui.views.browse.api') @istest def browse_directory_relative_dir(self, mock_api, mock_service): # given mock_service.lookup_directory_with_path.return_value = { 'sha256': '240', 'target': 'abcd', 'type': 'dir' } stub_directory_ls = [ {'type': 'dir', 'target': '123', 'name': 'some-dir-name'}, {'type': 'file', 'sha1': '654', 'name': 'some-filename'}, {'type': 'dir', 'target': '987', 'name': 'some-other-dirname'} ] mock_api.api_directory.return_value = stub_directory_ls # when rv = self.client.get('/browse/directory/sha1/path/to/dir/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('directory.html') self.assertIsNotNone(self.get_context_variable('files')) self.assertEqual(len(self.get_context_variable('files')), len(stub_directory_ls)) mock_api.api_directory.assert_called_once_with('abcd') @patch('swh.web.ui.views.browse.service') @patch('swh.web.ui.views.browse.api') @istest def browse_directory_relative_not_found(self, mock_api, mock_service): # given mock_service.lookup_directory_with_path.side_effect = NotFoundExc( 'Directory entry not found.') # when rv = self.client.get('/browse/directory/some-sha1/some/path/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('directory.html') self.assertEqual(self.get_context_variable('message'), 'Directory entry not found.') @patch('swh.web.ui.views.browse.api') @patch('swh.web.ui.views.browse.utils') @istest def browse_directory(self, mock_utils, mock_api): # given stub_directory_ls = [ {'type': 'dir', 'target': '123', 'name': 'some-dir-name'}, {'type': 'file', 'sha1': '654', 'name': 'some-filename'}, {'type': 'dir', 'target': '987', 'name': 'some-other-dirname'} ] mock_api.api_directory.return_value = stub_directory_ls stub_directory_map = [ {'link': '/path/to/url/dir/123', 'name': 'some-dir-name'}, {'link': '/path/to/url/file/654', 'name': 'some-filename'}, {'link': '/path/to/url/dir/987', 'name': 'some-other-dirname'} ] mock_utils.prepare_data_for_view.return_value = stub_directory_map # when rv = self.client.get('/browse/directory/some-sha1/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('directory.html') self.assertEqual(self.get_context_variable('message'), 'Listing for directory some-sha1:') self.assertEqual(self.get_context_variable('files'), stub_directory_map) mock_api.api_directory.assert_called_once_with( 'some-sha1') mock_utils.prepare_data_for_view.assert_called_once_with( stub_directory_ls) class ContentWithOriginView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') # @istest def browse_content_with_origin_content_ko_not_found(self, mock_api): # given mock_api.api_content_checksum_to_origin.side_effect = NotFoundExc( 'Not found!') # when rv = self.client.get('/browse/content/sha256:some-sha256/origin/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content-with-origin.html') self.assertEqual(self.get_context_variable('message'), 'Not found!') mock_api.api_content_checksum_to_origin.assert_called_once_with( 'sha256:some-sha256') @patch('swh.web.ui.views.browse.api') # @istest def browse_content_with_origin_ko_bad_input(self, mock_api): # given mock_api.api_content_checksum_to_origin.side_effect = BadInputExc( 'Invalid hash') # when rv = self.client.get('/browse/content/sha256:some-sha256/origin/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content-with-origin.html') self.assertEqual( self.get_context_variable('message'), 'Invalid hash') mock_api.api_content_checksum_to_origin.assert_called_once_with( 'sha256:some-sha256') @patch('swh.web.ui.views.browse.api') # @istest def browse_content_with_origin(self, mock_api): # given mock_api.api_content_checksum_to_origin.return_value = { 'origin_type': 'ftp', 'origin_url': '/some/url', 'revision': 'revision-hash', 'branch': 'master', 'path': '/path/to', } # when rv = self.client.get('/browse/content/sha256:some-sha256/origin/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('content-with-origin.html') self.assertEqual( self.get_context_variable('message'), "The content with hash sha256:some-sha256 has been seen on " + "origin with type 'ftp'\n" + "at url '/some/url'. The revision was identified at " + "'revision-hash' on branch 'master'.\n" + "The file's path referenced was '/path/to'.") mock_api.api_content_checksum_to_origin.assert_called_once_with( 'sha256:some-sha256') class OriginView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_origin_ko_not_found(self, mock_api): # given mock_api.api_origin.side_effect = NotFoundExc('Not found!') # when rv = self.client.get('/browse/origin/1/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('origin.html') self.assertEqual(self.get_context_variable('origin_id'), 1) self.assertEqual( self.get_context_variable('message'), 'Not found!') mock_api.api_origin.assert_called_once_with(1) @patch('swh.web.ui.views.browse.api') @istest def browse_origin_ko_bad_input(self, mock_api): # given mock_api.api_origin.side_effect = BadInputExc('wrong input') # when rv = self.client.get('/browse/origin/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('origin.html') self.assertEqual(self.get_context_variable('origin_id'), 426) mock_api.api_origin.assert_called_once_with(426) @patch('swh.web.ui.views.browse.api') @patch('swh.web.ui.views.browse.url_for') @istest def browse_origin_found(self, mock_url_for, mock_api): # given def url_for_test(fn, **args): if fn == 'browse_revision_with_origin': return '/browse/revision/origin/%s/' % args['origin_id'] elif fn == 'api_origin_visits': return '/api/1/stat/visits/%s/' % args['origin_id'] mock_url_for.side_effect = url_for_test mock_origin = {'type': 'git', 'lister': None, 'project': None, 'url': 'rsync://some/url', 'id': 426} mock_api.api_origin.return_value = mock_origin # when rv = self.client.get('/browse/origin/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('origin.html') self.assertEqual(self.get_context_variable('origin_id'), 426) self.assertEqual(self.get_context_variable('origin'), mock_origin) self.assertEqual(self.get_context_variable('browse_url'), '/browse/revision/origin/426/') self.assertEqual(self.get_context_variable('visit_url'), '/api/1/stat/visits/426/') mock_api.api_origin.assert_called_once_with(426) class PersonView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_person_ko_not_found(self, mock_api): # given mock_api.api_person.side_effect = NotFoundExc('not found') # when rv = self.client.get('/browse/person/1/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('person.html') self.assertEqual(self.get_context_variable('person_id'), 1) self.assertEqual( self.get_context_variable('message'), 'not found') mock_api.api_person.assert_called_once_with(1) @patch('swh.web.ui.views.browse.api') @istest def browse_person_ko_bad_input(self, mock_api): # given mock_api.api_person.side_effect = BadInputExc('wrong input') # when rv = self.client.get('/browse/person/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('person.html') self.assertEqual(self.get_context_variable('person_id'), 426) mock_api.api_person.assert_called_once_with(426) @patch('swh.web.ui.views.browse.api') @istest def browse_person(self, mock_api): # given mock_person = {'type': 'git', 'lister': None, 'project': None, 'url': 'rsync://some/url', 'id': 426} mock_api.api_person.return_value = mock_person # when rv = self.client.get('/browse/person/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('person.html') self.assertEqual(self.get_context_variable('person_id'), 426) self.assertEqual(self.get_context_variable('person'), mock_person) mock_api.api_person.assert_called_once_with(426) class ReleaseView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_release_ko_not_found(self, mock_api): # given mock_api.api_release.side_effect = NotFoundExc('not found!') # when rv = self.client.get('/browse/release/1/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('release.html') self.assertEqual(self.get_context_variable('sha1_git'), '1') self.assertEqual( self.get_context_variable('message'), 'not found!') mock_api.api_release.assert_called_once_with('1') @patch('swh.web.ui.views.browse.api') @istest def browse_release_ko_bad_input(self, mock_api): # given mock_api.api_release.side_effect = BadInputExc('wrong input') # when rv = self.client.get('/browse/release/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('release.html') self.assertEqual(self.get_context_variable('sha1_git'), '426') mock_api.api_release.assert_called_once_with('426') @patch('swh.web.ui.views.browse.api') @istest def browse_release(self, mock_api): # given self.maxDiff = None mock_release = { "date": "Sun, 05 Jul 2015 18:02:06 GMT", "id": "1e951912027ea6873da6985b91e50c47f645ae1a", "target": "d770e558e21961ad6cfdf0ff7df0eb5d7d4f0754", "target_url": '/browse/revision/d770e558e21961ad6cfdf0ff7df0' 'eb5d7d4f0754/', "synthetic": False, "target_type": "revision", "author": { "email": "torvalds@linux-foundation.org", "name": "Linus Torvalds" }, "message": "Linux 4.2-rc1\n", "name": "v4.2-rc1" } mock_api.api_release.return_value = mock_release expected_release = { "date": "Sun, 05 Jul 2015 18:02:06 GMT", "id": "1e951912027ea6873da6985b91e50c47f645ae1a", "target_url": '/browse/revision/d770e558e21961ad6cfdf0ff7df0' 'eb5d7d4f0754/', "target": 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754', "synthetic": False, "target_type": "revision", "author": { "email": "torvalds@linux-foundation.org", "name": "Linus Torvalds" }, "message": "Linux 4.2-rc1\n", "name": "v4.2-rc1" } # when rv = self.client.get('/browse/release/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('release.html') self.assertEqual(self.get_context_variable('sha1_git'), '426') self.assertEqual(self.get_context_variable('release'), expected_release) mock_api.api_release.assert_called_once_with('426') class RevisionView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_revision_ko_not_found(self, mock_api): # given mock_api.api_revision.side_effect = NotFoundExc('Not found!') # when rv = self.client.get('/browse/revision/1/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('sha1_git'), '1') self.assertEqual( self.get_context_variable('message'), 'Not found!') self.assertIsNone(self.get_context_variable('revision')) mock_api.api_revision.assert_called_once_with('1', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_ko_bad_input(self, mock_api): # given mock_api.api_revision.side_effect = BadInputExc('wrong input!') # when rv = self.client.get('/browse/revision/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('sha1_git'), '426') self.assertEqual( self.get_context_variable('message'), 'wrong input!') self.assertIsNone(self.get_context_variable('revision')) mock_api.api_revision.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision(self, mock_api): # given stub_revision = { 'id': 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754', 'date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'committer': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'committer_date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'type': 'git', 'author': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'message': 'Linux 4.2-rc1\n', 'synthetic': False, 'directory_url': '/api/1/directory/' '2a1dbabeed4dcf1f4a4c441993b2ffc9d972780b/', 'parent_url': [ '/api/1/revision/a585d2b738bfa26326b3f1f40f0f1eda0c067ccf/' ], } mock_api.api_revision.return_value = stub_revision expected_revision = { 'id': 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754', 'date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'committer': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'committer_date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'type': 'git', 'author': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'message': 'Linux 4.2-rc1\n', 'synthetic': False, 'parent_url': [ '/browse/revision/a585d2b738bfa26326b3f1f40f0f1eda0c067ccf/' ], 'directory_url': '/browse/directory/2a1dbabeed4dcf1f4a4c441993b2f' 'fc9d972780b/', } # when rv = self.client.get('/browse/revision/426/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('sha1_git'), '426') self.assertEqual(self.get_context_variable('revision'), expected_revision) self.assertIsNone(self.get_context_variable('message')) mock_api.api_revision.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_raw_message(self, mock_api): # given sha1 = 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754' # when rv = self.client.get('/browse/revision/' 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754/raw/') self.assertRedirects( rv, '/api/1/revision/%s/raw/' % sha1) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_log_ko_not_found(self, mock_api): # given mock_api.api_revision_log.side_effect = NotFoundExc('Not found!') # when rv = self.client.get('/browse/revision/sha1/log/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-log.html') self.assertEqual(self.get_context_variable('sha1_git'), 'sha1') self.assertEqual( self.get_context_variable('message'), 'Not found!') self.assertEqual(self.get_context_variable('revisions'), []) mock_api.api_revision_log.assert_called_once_with('sha1', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_log_ko_bad_input(self, mock_api): # given mock_api.api_revision_log.side_effect = BadInputExc('wrong input!') # when rv = self.client.get('/browse/revision/426/log/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-log.html') self.assertEqual(self.get_context_variable('sha1_git'), '426') self.assertEqual( self.get_context_variable('message'), 'wrong input!') self.assertEqual(self.get_context_variable('revisions'), []) mock_api.api_revision_log.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_log(self, mock_api): # given stub_revisions = { 'revisions': [{ 'id': 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754', 'date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'committer': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'committer_date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'type': 'git', 'author': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'message': 'Linux 4.2-rc1\n', 'synthetic': False, 'directory_url': '/api/1/directory/' '2a1dbabeed4dcf1f4a4c441993b2ffc9d972780b/', 'parent_url': [ '/api/1/revision/a585d2b738bfa26326b3f1f40f0f1eda0c067ccf/' ], }], 'next_revs_url': '/api/1/revision/1234/log/' } mock_api.api_revision_log.return_value = stub_revisions # when rv = self.client.get('/browse/revision/426/log/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-log.html') self.assertEqual(self.get_context_variable('sha1_git'), '426') self.assertTrue( isinstance(self.get_context_variable('revisions'), map)) self.assertEqual( self.get_context_variable('next_revs_url'), '/browse/revision/1234/log/') self.assertIsNone(self.get_context_variable('message')) mock_api.api_revision_log.assert_called_once_with('426', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_log_by_ko_not_found(self, mock_api): # given mock_api.api_revision_log_by.side_effect = NotFoundExc('Not found!') # when rv = self.client.get('/browse/revision/origin/9/log/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-log.html') self.assertEqual(self.get_context_variable('origin_id'), 9) self.assertEqual( self.get_context_variable('message'), 'Not found!') self.assertEqual(self.get_context_variable('revisions'), []) mock_api.api_revision_log_by.assert_called_once_with( 9, 'refs/heads/master', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_log_by_ko_bad_input(self, mock_api): # given mock_api.api_revision_log.side_effect = BadInputExc('wrong input!') # when rv = self.client.get('/browse/revision/abcd/log/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-log.html') self.assertEqual(self.get_context_variable('sha1_git'), 'abcd') self.assertEqual( self.get_context_variable('message'), 'wrong input!') self.assertEqual(self.get_context_variable('revisions'), []) mock_api.api_revision_log.assert_called_once_with('abcd', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_log_by(self, mock_api): # given stub_revisions = [{ 'id': 'd770e558e21961ad6cfdf0ff7df0eb5d7d4f0754', 'date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'committer': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'committer_date': 'Sun, 05 Jul 2015 18:01:52 GMT', 'type': 'git', 'author': { 'email': 'torvalds@linux-foundation.org', 'name': 'Linus Torvalds' }, 'message': 'Linux 4.2-rc1\n', 'synthetic': False, 'directory_url': '/api/1/directory/' '2a1dbabeed4dcf1f4a4c441993b2ffc9d972780b/', 'parent_url': [ '/api/1/revision/a585d2b738bfa26326b3f1f40f0f1eda0c067ccf/' ], }] mock_api.api_revision_log_by.return_value = stub_revisions # when rv = self.client.get('/browse/revision/origin/2/log/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-log.html') self.assertEqual(self.get_context_variable('origin_id'), 2) self.assertTrue( isinstance(self.get_context_variable('revisions'), map)) self.assertIsNone(self.get_context_variable('message')) mock_api.api_revision_log_by.assert_called_once_with( 2, 'refs/heads/master', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_ko_not_found(self, mock_api): # given mock_api.api_revision_history.side_effect = NotFoundExc( 'Not found') # when rv = self.client.get('/browse/revision/1/history/2/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('sha1_git_root'), '1') self.assertEqual(self.get_context_variable('sha1_git'), '2') self.assertEqual( self.get_context_variable('message'), 'Not found') mock_api.api_revision_history.assert_called_once_with( '1', '2') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_ko_bad_input(self, mock_api): # given mock_api.api_revision_history.side_effect = BadInputExc( 'Input incorrect') # when rv = self.client.get('/browse/revision/321/history/654/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('sha1_git_root'), '321') self.assertEqual(self.get_context_variable('sha1_git'), '654') self.assertEqual( self.get_context_variable('message'), 'Input incorrect') mock_api.api_revision_history.assert_called_once_with( '321', '654') @istest def browse_revision_history_ok_same_sha1(self): # when rv = self.client.get('/browse/revision/10/history/10/') # then self.assertEqual(rv.status_code, 302) @patch('swh.web.ui.views.browse.utils') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history(self, mock_api, mock_utils): # given stub_revision = {'id': 'some-rev'} mock_api.api_revision_history.return_value = stub_revision expected_revision = { 'id': 'some-rev-id', 'author': {'name': 'foo', 'email': 'bar'}, 'committer': {'name': 'foo', 'email': 'bar'} } mock_utils.prepare_data_for_view.return_value = expected_revision # when rv = self.client.get('/browse/revision/426/history/789/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('sha1_git_root'), '426') self.assertEqual(self.get_context_variable('sha1_git'), '789') self.assertEqual(self.get_context_variable('revision'), expected_revision) mock_api.api_revision_history.assert_called_once_with( '426', '789') mock_utils.prepare_data_for_view.assert_called_once_with(stub_revision) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory_ko_not_found(self, mock_api): # given mock_api.api_revision_directory.side_effect = NotFoundExc('Not found!') # when rv = self.client.get('/browse/revision/1/directory/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('sha1_git'), '1') self.assertEqual(self.get_context_variable('path'), '.') self.assertIsNone(self.get_context_variable('result')) self.assertEqual( self.get_context_variable('message'), "Not found!") mock_api.api_revision_directory.assert_called_once_with( '1', None, with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory_ko_bad_input(self, mock_api): # given mock_api.api_revision_directory.side_effect = BadInputExc('Bad input!') # when rv = self.client.get('/browse/revision/10/directory/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('sha1_git'), '10') self.assertEqual(self.get_context_variable('path'), '.') self.assertIsNone(self.get_context_variable('result')) self.assertEqual( self.get_context_variable('message'), "Bad input!") mock_api.api_revision_directory.assert_called_once_with( '10', None, with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory(self, mock_api): # given stub_result0 = { 'type': 'dir', 'revision': '100', 'content': [ { 'id': 'some-result', 'type': 'file', 'name': 'blah', }, { 'id': 'some-other-result', 'type': 'dir', 'name': 'foo', } ] } mock_api.api_revision_directory.return_value = stub_result0 stub_result1 = { 'type': 'dir', 'revision': '100', 'content': [ { 'id': 'some-result', 'type': 'file', 'name': 'blah', }, { 'id': 'some-other-result', 'type': 'dir', 'name': 'foo', } ] } # when rv = self.client.get('/browse/revision/100/directory/some/path/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('sha1_git'), '100') self.assertEqual(self.get_context_variable('revision'), '100') self.assertEqual(self.get_context_variable('path'), 'some/path') self.assertIsNone(self.get_context_variable('message')) self.assertEqual(self.get_context_variable('result'), stub_result1) mock_api.api_revision_directory.assert_called_once_with( '100', 'some/path', with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_directory_ko_not_found(self, mock_api): # given mock_api.api_revision_history_directory.side_effect = NotFoundExc( 'not found') # when rv = self.client.get('/browse/revision/123/history/456/directory/a/b/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('sha1_git_root'), '123') self.assertEqual(self.get_context_variable('sha1_git'), '456') self.assertEqual(self.get_context_variable('path'), 'a/b') self.assertEqual(self.get_context_variable('message'), 'not found') self.assertIsNone(self.get_context_variable('result')) mock_api.api_revision_history_directory.assert_called_once_with( '123', '456', 'a/b', with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_directory_ko_bad_input(self, mock_api): # given mock_api.api_revision_history_directory.side_effect = BadInputExc( 'bad input') # when rv = self.client.get('/browse/revision/123/history/456/directory/a/c/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('sha1_git_root'), '123') self.assertEqual(self.get_context_variable('sha1_git'), '456') self.assertEqual(self.get_context_variable('path'), 'a/c') self.assertEqual(self.get_context_variable('message'), 'bad input') self.assertIsNone(self.get_context_variable('result')) mock_api.api_revision_history_directory.assert_called_once_with( '123', '456', 'a/c', with_data=True) @patch('swh.web.ui.views.browse.service') @istest def browse_revision_history_directory_ok_no_trailing_slash_so_redirect( self, mock_service): # when rv = self.client.get('/browse/revision/1/history/2/directory/path/to') # then self.assertEqual(rv.status_code, 301) @patch('swh.web.ui.views.browse.service') @istest def browse_revision_history_directory_ok_same_sha1_redirects( self, mock_service): # when rv = self.client.get('/browse/revision/1/history/1/directory/path/to') # then self.assertEqual(rv.status_code, 301) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_directory(self, mock_api): # given stub_result0 = { 'type': 'dir', 'revision': '1000', 'content': [{ 'id': 'some-result', 'type': 'file', 'name': 'blah' }] } mock_api.api_revision_history_directory.return_value = stub_result0 stub_result1 = { 'type': 'dir', 'revision': '1000', 'content': [{ 'id': 'some-result', 'type': 'file', 'name': 'blah' }] } # when rv = self.client.get('/browse/revision/100/history/999/directory/' 'path/to/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('sha1_git_root'), '100') self.assertEqual(self.get_context_variable('sha1_git'), '999') self.assertEqual(self.get_context_variable('revision'), '1000') self.assertEqual(self.get_context_variable('path'), 'path/to') self.assertIsNone(self.get_context_variable('message')) self.assertEqual(self.get_context_variable('result'), stub_result1) mock_api.api_revision_history_directory.assert_called_once_with( '100', '999', 'path/to', with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_through_origin_ko_bad_input(self, mock_api): # given mock_api.api_revision_history_through_origin.side_effect = BadInputExc( 'Problem input.') # noqa # when rv = self.client.get('/browse/revision/origin/99' '/history/123/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertIsNone(self.get_context_variable('revision')) self.assertEqual(self.get_context_variable('message'), 'Problem input.') mock_api.api_revision_history_through_origin.assert_called_once_with( 99, 'refs/heads/master', None, '123') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_through_origin_ko_not_found(self, mock_api): # given mock_api.api_revision_history_through_origin.side_effect = NotFoundExc( 'Not found.') # when rv = self.client.get('/browse/revision/origin/999/' 'branch/dev/history/123/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertIsNone(self.get_context_variable('revision')) self.assertEqual(self.get_context_variable('message'), 'Not found.') mock_api.api_revision_history_through_origin.assert_called_once_with( 999, 'dev', None, '123') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_through_origin_ko_other_error(self, mock_api): # given mock_api.api_revision_history_through_origin.side_effect = ValueError( 'Other Error.') # when rv = self.client.get('/browse/revision/origin/438' '/branch/scratch' '/ts/2016' '/history/789/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertIsNone(self.get_context_variable('revision')) self.assertEqual(self.get_context_variable('message'), 'Other Error.') mock_api.api_revision_history_through_origin.assert_called_once_with( 438, 'scratch', '2016', '789') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_history_through_origin(self, mock_api): # given stub_rev = { 'id': 'some-id', 'author': {}, 'committer': {} } mock_api.api_revision_history_through_origin.return_value = stub_rev # when rv = self.client.get('/browse/revision/origin/99/history/123/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('revision'), stub_rev) self.assertIsNone(self.get_context_variable('message')) mock_api.api_revision_history_through_origin.assert_called_once_with( 99, 'refs/heads/master', None, '123') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_with_origin_ko_not_found(self, mock_api): # given mock_api.api_revision_with_origin.side_effect = NotFoundExc( 'Not found') # when rv = self.client.get('/browse/revision/origin/1/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertIsNone(self.get_context_variable('revision')) self.assertEqual(self.get_context_variable('message'), 'Not found') mock_api.api_revision_with_origin.assert_called_once_with( 1, 'refs/heads/master', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_with_origin_ko_bad_input(self, mock_api): # given mock_api.api_revision_with_origin.side_effect = BadInputExc( 'Bad Input') # when rv = self.client.get('/browse/revision/origin/1000/branch/dev/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertIsNone(self.get_context_variable('revision')) self.assertEqual(self.get_context_variable('message'), 'Bad Input') mock_api.api_revision_with_origin.assert_called_once_with( 1000, 'dev', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_with_origin_ko_other(self, mock_api): # given mock_api.api_revision_with_origin.side_effect = ValueError( 'Other') # when rv = self.client.get('/browse/revision/origin/1999' '/branch/scratch/master' '/ts/1990-01-10/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertIsNone(self.get_context_variable('revision')) self.assertEqual(self.get_context_variable('message'), 'Other') mock_api.api_revision_with_origin.assert_called_once_with( 1999, 'scratch/master', '1990-01-10') @patch('swh.web.ui.views.browse.api') @istest def browse_revision_with_origin(self, mock_api): # given stub_rev = {'id': 'some-id', 'author': {}, 'committer': {}} mock_api.api_revision_with_origin.return_value = stub_rev # when rv = self.client.get('/browse/revision/origin/1/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision.html') self.assertEqual(self.get_context_variable('revision'), stub_rev) self.assertIsNone(self.get_context_variable('message')) mock_api.api_revision_with_origin.assert_called_once_with( 1, 'refs/heads/master', None) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory_through_origin_ko_not_found(self, mock_api): # given mock_api.api_directory_through_revision_origin.side_effect = BadInputExc( # noqa 'this is not the robot you are looking for') # when rv = self.client.get('/browse/revision/origin/2' '/directory/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertIsNone(self.get_context_variable('result')) self.assertEqual(self.get_context_variable('message'), 'this is not the robot you are looking for') mock_api.api_directory_through_revision_origin.assert_called_once_with( # noqa 2, 'refs/heads/master', None, None, with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory_through_origin_ko_bad_input(self, mock_api): # given mock_api.api_directory_through_revision_origin.side_effect = BadInputExc( # noqa 'Bad Robot') # when rv = self.client.get('/browse/revision/origin/2' '/directory/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertIsNone(self.get_context_variable('result')) self.assertEqual(self.get_context_variable('message'), 'Bad Robot') mock_api.api_directory_through_revision_origin.assert_called_once_with( 2, 'refs/heads/master', None, None, with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory_through_origin_ko_other(self, mock_api): # given mock_api.api_directory_through_revision_origin.side_effect = ValueError( # noqa 'Other bad stuff') # when rv = self.client.get('/browse/revision/origin/2' '/directory/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertIsNone(self.get_context_variable('result')) self.assertEqual(self.get_context_variable('message'), 'Other bad stuff') mock_api.api_directory_through_revision_origin.assert_called_once_with( 2, 'refs/heads/master', None, None, with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_revision_directory_through_origin(self, mock_api): # given stub_res = {'id': 'some-id', 'revision': 'some-rev-id', 'type': 'dir', 'content': 'some-content'} mock_api.api_directory_through_revision_origin.return_value = stub_res # when rv = self.client.get('/browse/revision/origin/2' '/branch/dev' '/ts/2013-20-20 10:02' '/directory/some/file/') self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('result'), stub_res) self.assertIsNone(self.get_context_variable('message')) mock_api.api_directory_through_revision_origin.assert_called_once_with( 2, 'dev', '2013-20-20 10:02', 'some/file', with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_directory_through_revision_with_origin_history_ko_not_found( self, mock_api): mock_api.api_directory_through_revision_with_origin_history.side_effect = NotFoundExc( # noqa 'Not found!') # when rv = self.client.get('/browse/revision/origin/987' '/history/sha1git' '/directory/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertIsNone(self.get_context_variable('result')) self.assertEqual(self.get_context_variable('message'), 'Not found!') self.assertEqual(self.get_context_variable('path'), '.') mock_api.api_directory_through_revision_with_origin_history.assert_called_once_with( # noqa 987, 'refs/heads/master', None, 'sha1git', None, with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_directory_through_revision_with_origin_history_ko_bad_input( self, mock_api): mock_api.api_directory_through_revision_with_origin_history.side_effect = BadInputExc( # noqa 'Bad input! Bleh!') # when rv = self.client.get('/browse/revision/origin/798' '/branch/refs/heads/dev' '/ts/2012-11-11' '/history/1234' '/directory/some/path/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertIsNone(self.get_context_variable('result')) self.assertEqual(self.get_context_variable('message'), 'Bad input! Bleh!') self.assertEqual(self.get_context_variable('path'), 'some/path') mock_api.api_directory_through_revision_with_origin_history.assert_called_once_with( # noqa 798, 'refs/heads/dev', '2012-11-11', '1234', 'some/path', with_data=True) @patch('swh.web.ui.views.browse.api') @istest def browse_directory_through_revision_with_origin_history( self, mock_api): stub_dir = {'type': 'dir', 'content': [], 'revision': 'specific-rev-id'} mock_api.api_directory_through_revision_with_origin_history.return_value = stub_dir # noqa # when rv = self.client.get('/browse/revision/origin/101010' '/ts/1955-11-12' '/history/54628' '/directory/emacs-24.5/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('revision-directory.html') self.assertEqual(self.get_context_variable('result'), stub_dir) self.assertIsNone(self.get_context_variable('message')) self.assertEqual(self.get_context_variable('path'), 'emacs-24.5') mock_api.api_directory_through_revision_with_origin_history.assert_called_once_with( # noqa 101010, 'refs/heads/master', '1955-11-12', '54628', 'emacs-24.5', with_data=True) class EntityView(test_app.SWHViewTestCase): render_template = False @patch('swh.web.ui.views.browse.api') @istest def browse_entity_ko_not_found(self, mock_api): # given mock_api.api_entity_by_uuid.side_effect = NotFoundExc('Not found!') # when rv = self.client.get('/browse/entity/' '5f4d4c51-498a-4e28-88b3-b3e4e8396cba/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('entity.html') self.assertEqual(self.get_context_variable('entities'), []) self.assertEqual(self.get_context_variable('message'), 'Not found!') mock_api.api_entity_by_uuid.assert_called_once_with( '5f4d4c51-498a-4e28-88b3-b3e4e8396cba') @patch('swh.web.ui.views.browse.api') @istest def browse_entity_ko_bad_input(self, mock_api): # given mock_api.api_entity_by_uuid.side_effect = BadInputExc('wrong input!') # when rv = self.client.get('/browse/entity/blah-blah-uuid/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('entity.html') self.assertEqual(self.get_context_variable('entities'), []) self.assertEqual(self.get_context_variable('message'), 'wrong input!') mock_api.api_entity_by_uuid.assert_called_once_with( 'blah-blah-uuid') @patch('swh.web.ui.views.browse.api') @istest def browse_entity(self, mock_api): # given stub_entities = [ {'id': '5f4d4c51-5a9b-4e28-88b3-b3e4e8396cba'}] mock_api.api_entity_by_uuid.return_value = stub_entities # when rv = self.client.get('/browse/entity/' '5f4d4c51-5a9b-4e28-88b3-b3e4e8396cba/') # then self.assertEqual(rv.status_code, 200) self.assert_template_used('entity.html') self.assertEqual(self.get_context_variable('entities'), stub_entities) self.assertIsNone(self.get_context_variable('message')) mock_api.api_entity_by_uuid.assert_called_once_with( '5f4d4c51-5a9b-4e28-88b3-b3e4e8396cba') diff --git a/swh/web/ui/views/browse.py b/swh/web/ui/views/browse.py index 95e1da18a..f6e03d18f 100644 --- a/swh/web/ui/views/browse.py +++ b/swh/web/ui/views/browse.py @@ -1,846 +1,859 @@ # Copyright (C) 2015 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 encodings.aliases import aliases from flask import render_template, request, url_for, redirect from flask.ext.api.decorators import set_renderers from flask.ext.api.renderers import HTMLRenderer from swh.core.hashutil import ALGORITHMS -from .. import service, utils +from .. import service, utils, apidoc from ..exc import BadInputExc, NotFoundExc from ..main import app from . import api hash_filter_keys = ALGORITHMS +@app.route('/api/1/doc/') +@set_renderers(HTMLRenderer) +def api_doc(): + """Render the API's documentation. + """ + routes = apidoc.APIUrls.get_app_endpoints() + # Return a list of routes with consistent ordering + env = { + 'doc_routes': sorted(routes.items()) + } + return render_template('api.html', **env) + + @app.route('/search/', methods=['GET', 'POST']) @set_renderers(HTMLRenderer) def search(): """Search for hashes in swh-storage. One form to submit either: - hash query to look up in swh storage - file hashes calculated client-side to be queried in swh storage - both Returns: dict representing data to look for in swh storage. The following keys are returned: - search_stats: {'nbfiles': X, 'pct': Y} the number of total queried files and percentage of files not in storage respectively - responses: array of {'filename': X, 'sha1': Y, 'found': Z} - messages: General messages. TODO: Batch-process with all checksums, not just sha1 """ env = {'search_res': None, 'search_stats': None, 'message': []} search_stats = {'nbfiles': 0, 'pct': 0} search_res = None message = '' # Get with a single hash request if request.method == 'GET': data = request.args q = data.get('q') if q: try: search = api.api_search(q) search_res = search['search_res'] search_stats = search['search_stats'] except BadInputExc as e: message = str(e) # Post form submission with many hash requests elif request.method == 'POST': try: search = api.api_search(None) search_res = search['search_res'] search_stats = search['search_stats'] except BadInputExc as e: message = str(e) env['search_stats'] = search_stats env['search_res'] = search_res env['message'] = message return render_template('search.html', **env) @app.route('/browse/content//') @set_renderers(HTMLRenderer) def browse_content(q): """Given a hash and a checksum, display the content's meta-data. Args: q is of the form algo_hash:hash with algo_hash in (sha1, sha1_git, sha256) Returns: Information on one possible origin for such content. Raises: BadInputExc in case of unknown algo_hash or bad hash NotFoundExc if the content is not found. """ env = {'q': q, 'message': None, 'content': None} encoding = request.args.get('encoding', 'utf8') if encoding not in aliases: env['message'] = 'Encoding %s not supported.' \ 'Supported Encodings: %s' % ( encoding, list(aliases.keys())) return render_template('content.html', **env) try: content = api.api_content_metadata(q) content_raw = service.lookup_content_raw(q) if content_raw: content['data'] = content_raw['data'] env['content'] = utils.prepare_data_for_view(content, encoding=encoding) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('content.html', **env) @app.route('/browse/content//raw/') def browse_content_raw(q): """Given a hash and a checksum, display the content's raw data. Args: q is of the form algo_hash:hash with algo_hash in (sha1, sha1_git, sha256) Returns: Information on one possible origin for such content. Raises: BadInputExc in case of unknown algo_hash or bad hash NotFoundExc if the content is not found. """ return redirect(url_for('api_content_raw', q=q)) def _origin_seen(q, data): """Given an origin, compute a message string with the right information. Args: origin: a dictionary with keys: - origin: a dictionary with type and url keys - occurrence: a dictionary with a validity range Returns: Message as a string """ origin_type = data['origin_type'] origin_url = data['origin_url'] revision = data['revision'] branch = data['branch'] path = data['path'] return """The content with hash %s has been seen on origin with type '%s' at url '%s'. The revision was identified at '%s' on branch '%s'. The file's path referenced was '%s'.""" % (q, origin_type, origin_url, revision, branch, path) # @app.route('/browse/content//origin/') @set_renderers(HTMLRenderer) def browse_content_with_origin(q): """Show content information. Args: - q: query string of the form with `algo_hash` in sha1, sha1_git, sha256. This means that several different URLs (at least one per HASH_ALGO) will point to the same content sha: the sha with 'hash' format Returns: The content's information at for a given checksum. """ env = {'q': q} try: origin = api.api_content_checksum_to_origin(q) message = _origin_seen(q, origin) except (NotFoundExc, BadInputExc) as e: message = str(e) env['message'] = message return render_template('content-with-origin.html', **env) @app.route('/browse/directory//') @app.route('/browse/directory///') @set_renderers(HTMLRenderer) def browse_directory(sha1_git, path=None): """Show directory information. Args: - sha1_git: the directory's sha1 git identifier. If path is set, the base directory for the relative path to the entry - path: the path to the requested entry, relative to the directory pointed by sha1_git Returns: The content's information at sha1_git, or at sha1_git/path if path is set. """ env = {'sha1_git': sha1_git, 'files': []} try: if path: env['message'] = ('Listing for directory with path %s from %s:' % (path, sha1_git)) dir_or_file = service.lookup_directory_with_path( sha1_git, path) if dir_or_file['type'] == 'file': fsha = 'sha256:%s' % dir_or_file['sha256'] content = api.api_content_metadata(fsha) content_raw = service.lookup_content_raw(fsha) if content_raw: # FIXME: currently assuming utf8 encoding content['data'] = content_raw['data'] env['content'] = utils.prepare_data_for_view( content, encoding='utf-8') return render_template('content.html', **env) else: directory_files = api.api_directory(dir_or_file['target']) env['files'] = utils.prepare_data_for_view(directory_files) else: env['message'] = "Listing for directory %s:" % sha1_git directory_files = api.api_directory(sha1_git) env['files'] = utils.prepare_data_for_view(directory_files) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('directory.html', **env) @app.route('/browse/origin//') @set_renderers(HTMLRenderer) def browse_origin(origin_id): """Browse origin with id id. """ browse_url = url_for('browse_revision_with_origin', origin_id=origin_id) visit_url = url_for('api_origin_visits', origin_id=origin_id) env = {'browse_url': browse_url, 'visit_url': visit_url, 'origin_id': origin_id, 'origin': None} try: env['origin'] = api.api_origin(origin_id) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('origin.html', **env) @app.route('/browse/person//') @set_renderers(HTMLRenderer) def browse_person(person_id): """Browse person with id id. """ env = {'person_id': person_id, 'person': None, 'message': None} try: env['person'] = api.api_person(person_id) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('person.html', **env) @app.route('/browse/release//') @set_renderers(HTMLRenderer) def browse_release(sha1_git): """Browse release with sha1_git. """ env = {'sha1_git': sha1_git, 'message': None, 'release': None} try: rel = api.api_release(sha1_git) env['release'] = utils.prepare_data_for_view(rel) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('release.html', **env) @app.route('/browse/revision//') @app.route('/browse/revision//prev//') @set_renderers(HTMLRenderer) def browse_revision(sha1_git, prev_sha1s=None): """Browse the revision with git SHA1 sha1_git_cur, while optionally keeping the context from which we came as a list of previous (i.e. later) revisions' sha1s. Args: sha1_git: the requested revision's sha1_git. prev_sha1s: an optional string of /-separated sha1s representing our context, ordered by descending revision date. Returns: Information about revision of git SHA1 sha1_git_cur, with relevant URLS pointing to the context augmented with sha1_git_cur. Example: GET /browse/revision/ """ env = {'sha1_git': sha1_git, 'message': None, 'revision': None} try: rev = api.api_revision(sha1_git, prev_sha1s) env['revision'] = utils.prepare_data_for_view(rev) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('revision.html', **env) @app.route('/browse/revision//raw/') def browse_revision_raw_message(sha1_git): """Given a sha1_git, display the corresponding revision's raw message. """ return redirect(url_for('api_revision_raw_message', sha1_git=sha1_git)) @app.route('/browse/revision//log/') @app.route('/browse/revision//prev//log/') @set_renderers(HTMLRenderer) def browse_revision_log(sha1_git, prev_sha1s=None): """Browse revision with sha1_git's log. If the navigation path through the commit tree is specified, we intersect the earliest revision's log with the revisions the user browsed through - ie the path taken to the specified revision. Args: sha1_git: the current revision's SHA1_git checksum prev_sha1s: optionally, the path through which we want log information """ env = {'sha1_git': sha1_git, 'sha1_url': '/browse/revision/%s/' % sha1_git, 'message': None, 'revisions': []} try: revision_data = api.api_revision_log(sha1_git, prev_sha1s) revisions = revision_data['revisions'] next_revs_url = revision_data['next_revs_url'] env['revisions'] = map(utils.prepare_data_for_view, revisions) env['next_revs_url'] = utils.prepare_data_for_view(next_revs_url) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('revision-log.html', **env) @app.route('/browse/revision' '/origin//log/') @app.route('/browse/revision' '/origin/' '/branch//log/') @app.route('/browse/revision' '/origin/' '/branch/' '/ts//log/') @app.route('/browse/revision' '/origin/' '/ts//log/') @set_renderers(HTMLRenderer) def browse_revision_log_by(origin_id, branch_name='refs/heads/master', timestamp=None): """Browse the revision described by origin, branch name and timestamp's log Args: origin_id: the revision's origin branch_name: the revision's branch timestamp: the requested timeframe for the revision Returns: The revision log of the described revision as a list of revisions if it is found. """ env = {'sha1_git': None, 'origin_id': origin_id, 'origin_url': '/browse/origin/%d/' % origin_id, 'branch_name': branch_name, 'timestamp': timestamp, 'message': None, 'revisions': []} try: revisions = api.api_revision_log_by( origin_id, branch_name, timestamp) env['revisions'] = map(utils.prepare_data_for_view, revisions) except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('revision-log.html', **env) @app.route('/browse/revision//prev//') @set_renderers(HTMLRenderer) def browse_with_rev_context(sha1_git_cur, sha1s): """Browse the revision with git SHA1 sha1_git_cur, while keeping the context from which we came as a list of previous (i.e. later) revisions' sha1s. Args: sha1_git_cur: the requested revision's sha1_git. sha1s: a string of /-separated sha1s representing our context, ordered by descending revision date. Returns: Information about revision of git SHA1 sha1_git_cur, with relevant URLS pointing to the context augmented with sha1_git_cur. Example: GET /browse/revision/ """ env = {'sha1_git': sha1_git_cur, 'message': None, 'revision': None} try: revision = api.api_revision( sha1_git_cur, sha1s) env['revision'] = utils.prepare_data_for_view(revision) except (BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision.html', **env) @app.route('/browse/revision//history//') @set_renderers(HTMLRenderer) def browse_revision_history(sha1_git_root, sha1_git): """Display information about revision sha1_git, limited to the sub-graph of all transitive parents of sha1_git_root. In other words, sha1_git is an ancestor of sha1_git_root. Args: sha1_git_root: latest revision of the browsed history. sha1_git: one of sha1_git_root's ancestors. limit: optional query parameter to limit the revisions log (default to 100). For now, note that this limit could impede the transitivity conclusion about sha1_git not being an ancestor of sha1_git_root (even if it is). Returns: Information on sha1_git if it is an ancestor of sha1_git_root including children leading to sha1_git_root. """ env = {'sha1_git_root': sha1_git_root, 'sha1_git': sha1_git, 'message': None, 'keys': [], 'revision': None} if sha1_git == sha1_git_root: return redirect(url_for('browse_revision', sha1_git=sha1_git)) try: revision = api.api_revision_history(sha1_git_root, sha1_git) env['revision'] = utils.prepare_data_for_view(revision) except (BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision.html', **env) @app.route('/browse/revision//directory/') @app.route('/browse/revision//directory//') @set_renderers(HTMLRenderer) def browse_revision_directory(sha1_git, path=None): """Browse directory from revision with sha1_git. """ env = { 'sha1_git': sha1_git, 'path': '.' if not path else path, 'message': None, 'result': None } encoding = request.args.get('encoding', 'utf8') if encoding not in aliases: env['message'] = 'Encoding %s not supported.' \ 'Supported Encodings: %s' % ( encoding, list(aliases.keys())) return render_template('revision-directory.html', **env) try: result = api.api_revision_directory(sha1_git, path, with_data=True) result['content'] = utils.prepare_data_for_view(result['content'], encoding=encoding) env['revision'] = result['revision'] env['result'] = result except (BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision-directory.html', **env) @app.route('/browse/revision/' '/history/' '/directory/') @app.route('/browse/revision/' '/history/' '/directory//') @set_renderers(HTMLRenderer) def browse_revision_history_directory(sha1_git_root, sha1_git, path=None): """Return information about directory pointed to by the revision defined as: revision sha1_git, limited to the sub-graph of all transitive parents of sha1_git_root. Args: sha1_git_root: latest revision of the browsed history. sha1_git: one of sha1_git_root's ancestors. path: optional directory pointed to by that revision. limit: optional query parameter to limit the revisions log (default to 100). For now, note that this limit could impede the transitivity conclusion about sha1_git not being an ancestor of sha1_git_root (even if it is). Returns: Information on the directory pointed to by that revision. Raises: BadInputExc in case of unknown algo_hash or bad hash. NotFoundExc if either revision is not found or if sha1_git is not an ancestor of sha1_git_root or the path referenced does not exist """ env = { 'sha1_git_root': sha1_git_root, 'sha1_git': sha1_git, 'path': '.' if not path else path, 'message': None, 'result': None } encoding = request.args.get('encoding', 'utf8') if encoding not in aliases: env['message'] = 'Encoding %s not supported.' \ 'Supported Encodings: %s' % ( encoding, list(aliases.keys())) return render_template('revision-directory.html', **env) if sha1_git == sha1_git_root: return redirect(url_for('browse_revision_directory', sha1_git=sha1_git, path=path, encoding=encoding), code=301) try: result = api.api_revision_history_directory(sha1_git_root, sha1_git, path, with_data=True) env['revision'] = result['revision'] env['content'] = utils.prepare_data_for_view(result['content'], encoding=encoding) env['result'] = result except (BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision-directory.html', **env) @app.route('/browse/revision' '/origin/' '/history/' '/directory/') @app.route('/browse/revision' '/origin/' '/history/' '/directory//') @app.route('/browse/revision' '/origin/' '/branch/' '/history/' '/directory/') @app.route('/browse/revision' '/origin/' '/branch/' '/history/' '/directory//') @app.route('/browse/revision' '/origin/' '/ts/' '/history/' '/directory/') @app.route('/browse/revision' '/origin/' '/ts/' '/history/' '/directory//') @app.route('/browse/revision' '/origin/' '/branch/' '/ts/' '/history/' '/directory/') @app.route('/browse/revision' '/origin/' '/branch/' '/ts/' '/history/' '/directory//') @set_renderers(HTMLRenderer) def browse_directory_through_revision_with_origin_history( origin_id, branch_name="refs/heads/master", ts=None, sha1_git=None, path=None): env = { 'origin_id': origin_id, 'branch_name': branch_name, 'ts': ts, 'sha1_git': sha1_git, 'path': '.' if not path else path, 'message': None, 'result': None } encoding = request.args.get('encoding', 'utf8') if encoding not in aliases: env['message'] = (('Encoding %s not supported.' 'Supported Encodings: %s') % ( encoding, list(aliases.keys()))) return render_template('revision-directory.html', **env) try: result = api.api_directory_through_revision_with_origin_history( origin_id, branch_name, ts, sha1_git, path, with_data=True) env['revision'] = result['revision'] env['content'] = utils.prepare_data_for_view(result['content'], encoding=encoding) env['result'] = result except (BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision-directory.html', **env) @app.route('/browse/revision' '/origin/') @app.route('/browse/revision' '/origin//') @app.route('/browse/revision' '/origin/' '/branch//') @app.route('/browse/revision' '/origin/' '/branch/' '/ts//') @app.route('/browse/revision' '/origin/' '/ts//') @set_renderers(HTMLRenderer) def browse_revision_with_origin(origin_id, branch_name="refs/heads/master", ts=None): """Instead of having to specify a (root) revision by SHA1_GIT, users might want to specify a place and a time. In SWH a "place" is an origin; a "time" is a timestamp at which some place has been observed by SWH crawlers. Args: origin_id: origin's identifier (default to 1). branch_name: the optional branch for the given origin (default to master). timestamp: optional timestamp (default to the nearest time crawl of timestamp). Returns: Information on the revision if found. Raises: BadInputExc in case of unknown algo_hash or bad hash. NotFoundExc if the revision is not found. """ env = {'message': None, 'revision': None} try: revision = api.api_revision_with_origin(origin_id, branch_name, ts) env['revision'] = utils.prepare_data_for_view(revision) except (ValueError, NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('revision.html', **env) @app.route('/browse/revision' '/origin/' '/history//') @app.route('/browse/revision' '/origin/' '/branch/' '/history//') @app.route('/browse/revision' '/origin/' '/branch/' '/ts/' '/history//') @set_renderers(HTMLRenderer) def browse_revision_history_through_origin(origin_id, branch_name='refs/heads/master', ts=None, sha1_git=None): """Return information about revision sha1_git, limited to the sub-graph of all transitive parents of the revision root identified by (origin_id, branch_name, ts). Given sha1_git_root such root revision's identifier, in other words, sha1_git is an ancestor of sha1_git_root. Args: origin_id: origin's identifier (default to 1). branch_name: the optional branch for the given origin (default to master). timestamp: optional timestamp (default to the nearest time crawl of timestamp). sha1_git: one of sha1_git_root's ancestors. limit: optional query parameter to limit the revisions log (default to 100). For now, note that this limit could impede the transitivity conclusion about sha1_git not being an ancestor of sha1_git_root (even if it is). Returns: Information on sha1_git if it is an ancestor of sha1_git_root including children leading to sha1_git_root. """ env = {'message': None, 'revision': None} try: revision = api.api_revision_history_through_origin( origin_id, branch_name, ts, sha1_git) env['revision'] = utils.prepare_data_for_view(revision) except (ValueError, BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision.html', **env) @app.route('/browse/revision' '/origin/' '/directory/') @app.route('/browse/revision' '/origin/' '/directory/') @app.route('/browse/revision' '/origin/' '/branch/' '/directory/') @app.route('/browse/revision' '/origin/' '/branch/' '/directory//') @app.route('/browse/revision' '/origin/' '/branch/' '/ts/' '/directory/') @app.route('/browse/revision' '/origin/' '/branch/' '/ts/' '/directory//') @set_renderers(HTMLRenderer) def browse_revision_directory_through_origin(origin_id, branch_name='refs/heads/master', ts=None, path=None): env = {'message': None, 'origin_id': origin_id, 'ts': ts, 'path': '.' if not path else path, 'result': None} encoding = request.args.get('encoding', 'utf8') if encoding not in aliases: env['message'] = 'Encoding %s not supported.' \ 'Supported Encodings: %s' % ( encoding, list(aliases.keys())) return render_template('revision-directory.html', **env) try: result = api.api_directory_through_revision_origin( origin_id, branch_name, ts, path, with_data=True) result['content'] = utils.prepare_data_for_view(result['content'], encoding=encoding) env['revision'] = result['revision'] env['result'] = result except (ValueError, BadInputExc, NotFoundExc) as e: env['message'] = str(e) return render_template('revision-directory.html', **env) @app.route('/browse/entity/') @app.route('/browse/entity//') @set_renderers(HTMLRenderer) def browse_entity(uuid): env = {'entities': [], 'message': None} try: entities = api.api_entity_by_uuid(uuid) env['entities'] = entities except (NotFoundExc, BadInputExc) as e: env['message'] = str(e) return render_template('entity.html', **env)