From 2a1129a603d50c7a9094d86018a9c55d56591cb7 Mon Sep 17 00:00:00 2001 From: Jose Navas Date: Thu, 1 Jun 2017 10:51:16 -0700 Subject: [PATCH] Arbitrary summary HTML (#2138) * fix #1505 * improving some GUI stuff * improving some GUI stuff - missing lines * addressing all comments * ready for review * fix #1987 * initial commit * requested changes * fix filter job list * Fixing server cert (#2051) * fix get_studies * flake8 * fix #503 * fix #2010 * fix #1913 * fix errors * addressing @josenavas comment * flake8 * fix #1010 * fix #1066 (#2058) * addressing @josenavas comments * fix #1961 * fix #1837 * Automatic jobs & new stats (#2057) * fix #814, fix #1636 * fixing error in test-env * fixing stats.html call * adding img * addressing @josenavas comments * rm for loops * addresssing @ElDeveloper comments * generalizing this functionality * fix #1816 * fix #1959 * addressing @josenavas comments * addressing @josenavas comments * fixing error * fixed? * addressing @josenavas comments * addressing @wasade comments * fix flake8 * generate biom and metadata release (#2066) * initial commit * adding portal * addressing @josenavas comments * pid -> qiita_artifact_id * addressing @josenavas comments * addressing @ElDeveloper comments * rm 50.sql * database changes to fix 969 * adding delete * addressing @josenavas comments * addressing @ElDeveloper comments * duh! * fix generate_biom_and_metadata_release (#2072) * fix generate_biom_and_metadata_release * addressing @ElDeveloper comment * Removing qiita ware code that will not be used anymore * Organizing the handlers and new analysis description page * fixing timestamp * rm formats * st -> pt * Connecting the analysis creation and making interface responsive * Addressing @antgonza's comments * Initial artifact GUI refactor * Removing unused code * moving to ISO 8601 - wow :'( * fix errors * addressing @wasade comments * Adding can_edit call to the analysis * Fixing artifact rest API since not all artifacts have study * Adding can_be_publicized call to analysis * Adding QiitaHTTPError to handle errors gracefully * Adding safe_execution contextmanager * Fixing typo * Adding qiita test checker * Adapting some artifact handlers * Abstracting the graph reloading and adding some documentation * Fixing typo * Fixing changing artifact visibility * Fixing delete * Fixing artifact deletion * Adding default parameters to the commands * Fixing processing page * Fixing variable name * fixing private/public studies * Changing bdiv metrics to single choice * sanbox-to-sandbox * flake8 * Fixing patch * fixing other issues * adding share documentation * psycopg2 <= 2.7 * psycopg2 < 2.7 * Various small fixes to be able to run tests on the plugins * Adding private module * Fixing processing job completion * Fixing patch 52 * Fixing call * Fixing complete * small fixes * Adding processing handlers * Fixing url and bug on processing job workflow * Adding the private script runner * Adding is_analysis column to the command * Adding retrieval of commands excluding analysis commands * Addressing bug on retrieving information from redis * Enabling the command register endpoint to provide if the command is analysis only * Addressing @antgonza's comments * Addressing @wasade's comments * Supporting multiple choice * Adding documentation * Modifying handler to pass allow_change_optionals * returning optional parameters * Addressing bug found by @antgonza * Enabling changing the default parameters * Adding correct class * Allowing user to change default parameters * Fixing bug with commands listing * Enabling arbitrary htmls in the summary * Addressing @wasade's comments * Addressing @antgonza's comment --- .../handlers/artifact_handlers/__init__.py | 6 ++- .../artifact_handlers/base_handlers.py | 33 +++++++++++++++-- .../tests/test_base_handlers.py | 37 +++++++++++++++++-- .../artifact_ajax/artifact_summary.html | 2 +- qiita_pet/webserver.py | 5 ++- 5 files changed, 71 insertions(+), 12 deletions(-) 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),