diff --git a/qiita_pet/handlers/artifact_handlers/__init__.py b/qiita_pet/handlers/artifact_handlers/__init__.py index 707499994..f99d723bc 100644 --- a/qiita_pet/handlers/artifact_handlers/__init__.py +++ b/qiita_pet/handlers/artifact_handlers/__init__.py @@ -6,7 +6,9 @@ # The full license is in the file LICENSE, distributed with this software. # ----------------------------------------------------------------------------- -from .base_handlers import ArtifactSummaryAJAX, ArtifactAJAX +from .base_handlers import (ArtifactSummaryAJAX, ArtifactAJAX, + ArtifactSummaryHandler) from .process_handlers import ProcessArtifactHandler -__all__ = ['ArtifactSummaryAJAX', 'ArtifactAJAX', 'ProcessArtifactHandler'] +__all__ = ['ArtifactSummaryAJAX', 'ArtifactAJAX', 'ArtifactSummaryHandler', + 'ProcessArtifactHandler'] diff --git a/qiita_pet/handlers/artifact_handlers/base_handlers.py b/qiita_pet/handlers/artifact_handlers/base_handlers.py index 3ba92e0ab..7a415a10e 100644 --- a/qiita_pet/handlers/artifact_handlers/base_handlers.py +++ b/qiita_pet/handlers/artifact_handlers/base_handlers.py @@ -6,10 +6,10 @@ # The full license is in the file LICENSE, distributed with this software. # ----------------------------------------------------------------------------- -from os.path import basename +from os.path import basename, relpath from json import dumps -from tornado.web import authenticated +from tornado.web import authenticated, StaticFileHandler from moi import r_client from qiita_core.qiita_settings import qiita_config @@ -108,8 +108,12 @@ def artifact_summary_get_request(user, artifact_id): # Check if the HTML summary exists if summary: - with open(summary[1]) as f: - summary = f.read() + # Magic number 1: If the artifact has a summary, the call + # artifact.html_summary_fp returns a tuple with 2 elements. The first + # element is the filepath id, while the second one is the actual + # actual filepath. We are only interested on the actual filepath, + # hence the 1 value. + summary = relpath(summary[1], qiita_config.base_data_dir) else: # Check if the summary is being generated command = Command.get_html_generator(artifact.artifact_type) @@ -394,3 +398,24 @@ def patch(self, artifact_id): req_path, req_value, req_from) self.finish() + + +class ArtifactSummaryHandler(StaticFileHandler, BaseHandler): + def validate_absolute_path(self, root, absolute_path): + """Overrides StaticFileHandler's method to include authentication""" + user = self.current_user + + # Magic number 1, the path structure for the summaries is + # root/ARTIFACTDIR/artifact_id/FILE. We are interested in the + # artifact_id. root is removed by relpath, so the second element of the + # list is the artifact id + artifact_id = relpath(absolute_path, root).split('/')[1] + + # This call will check if the user has access to the artifact or not, + # taking into account admin privileges. If not it will raise a 403 + # which will be handled correctly by tornado + check_artifact_access(user, Artifact(artifact_id)) + + # If we reach this point the user has access to the file - return it + return super(ArtifactSummaryHandler, self).validate_absolute_path( + root, absolute_path) diff --git a/qiita_pet/handlers/artifact_handlers/tests/test_base_handlers.py b/qiita_pet/handlers/artifact_handlers/tests/test_base_handlers.py index 41d181502..337b02614 100644 --- a/qiita_pet/handlers/artifact_handlers/tests/test_base_handlers.py +++ b/qiita_pet/handlers/artifact_handlers/tests/test_base_handlers.py @@ -9,11 +9,12 @@ from unittest import TestCase, main from tempfile import mkstemp from os import close, remove -from os.path import basename, exists +from os.path import basename, exists, relpath from tornado.web import HTTPError from qiita_core.util import qiita_test_checker +from qiita_db.util import get_db_files_base_dir from qiita_db.user import User from qiita_db.artifact import Artifact from qiita_db.processing_job import ProcessingJob @@ -134,6 +135,8 @@ def test_artifact_summary_get_request(self): exp_files.append( (a.html_summary_fp[0], '%s (html summary)' % basename(a.html_summary_fp[1]))) + exp_summary_path = relpath( + a.html_summary_fp[1], get_db_files_base_dir()) obs = artifact_summary_get_request(user, 1) exp = {'name': 'Raw data 1', 'artifact_id': 1, @@ -150,7 +153,7 @@ def test_artifact_summary_get_request(self): 'sandbox'), 'processing_parameters': {}, 'files': exp_files, - 'summary': 'HTML TEST - not important\n', + 'summary': exp_summary_path, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': []} @@ -171,7 +174,7 @@ def test_artifact_summary_get_request(self): 'buttons': '', 'processing_parameters': {}, 'files': [], - 'summary': 'HTML TEST - not important\n', + 'summary': exp_summary_path, 'job': None, 'processing_jobs': exp_p_jobs, 'errored_jobs': []} @@ -228,7 +231,7 @@ def test_artifact_summary_get_request(self): 'editable': True, 'buttons': '', 'processing_parameters': {}, - 'files': [(22, 'biom_table.biom (biom)')], + 'files': [(27, 'biom_table.biom (biom)')], 'summary': None, 'job': None, 'processing_jobs': [], @@ -309,6 +312,16 @@ def test_artifact_patch_request(self): class TestBaseHandlers(TestHandlerBase): + def setUp(self): + super(TestBaseHandlers, self).setUp() + self._files_to_remove = [] + + def tearDown(self): + super(TestBaseHandlers, self).tearDown() + for fp in self._files_to_remove: + if exists(fp): + remove(fp) + def test_get_artifact_summary_ajax_handler(self): response = self.get('/artifact/1/summary/') self.assertEqual(response.code, 200) @@ -322,6 +335,22 @@ def test_patch_artifact_ajax_handler(self): self.assertEqual(a.name, 'NEW_NAME') a.name = 'Raw data 1' + def test_get_artifact_summary_handler(self): + a = Artifact(1) + # Add a summary to the artifact + fd, fp = mkstemp(suffix=".html") + close(fd) + with open(fp, 'w') as f: + f.write('HTML TEST - not important\n') + a = Artifact(1) + a.html_summary_fp = fp + self._files_to_remove.extend([fp, a.html_summary_fp[1]]) + + summary = relpath(a.html_summary_fp[1], get_db_files_base_dir()) + response = self.get('/artifact/html_summary/%s' % summary) + self.assertEqual(response.code, 200) + self.assertEqual(response.body, 'HTML TEST - not important\n') + if __name__ == '__main__': main() diff --git a/qiita_pet/templates/artifact_ajax/artifact_summary.html b/qiita_pet/templates/artifact_ajax/artifact_summary.html index bb333dd4e..0162d7df1 100644 --- a/qiita_pet/templates/artifact_ajax/artifact_summary.html +++ b/qiita_pet/templates/artifact_ajax/artifact_summary.html @@ -144,7 +144,7 @@

{% if summary is not None %} - {% raw summary %} + {% elif job is not None %} Job {{ job[0] }}: {{ job[1] }} {{ job[2] }} {% else %} diff --git a/qiita_pet/webserver.py b/qiita_pet/webserver.py index 551b346b7..2e75d8096 100644 --- a/qiita_pet/webserver.py +++ b/qiita_pet/webserver.py @@ -34,7 +34,8 @@ PrepTemplateSummaryAJAX, WorkflowHandler, WorkflowRunHandler, JobAJAX, AutocompleteHandler) from qiita_pet.handlers.artifact_handlers import ( - ArtifactSummaryAJAX, ArtifactAJAX, ProcessArtifactHandler) + ArtifactSummaryAJAX, ArtifactAJAX, ArtifactSummaryHandler, + ProcessArtifactHandler) from qiita_pet.handlers.websocket_handlers import ( MessageHandler, SelectedSocketHandler, SelectSamplesHandler) from qiita_pet.handlers.logger_handlers import LogEntryViewerHandler @@ -129,6 +130,8 @@ def __init__(self): # Artifact handlers (r"/artifact/graph/", ArtifactGraphAJAX), (r"/artifact/(.*)/summary/", ArtifactSummaryAJAX), + (r"/artifact/html_summary/(.*)", ArtifactSummaryHandler, + {"path": qiita_config.base_data_dir}), (r"/artifact/(.*)/process/", ProcessArtifactHandler), (r"/artifact/(.*)/", ArtifactAJAX), (r"/prep_template/", PrepTemplateHandler),