diff --git a/qiita_db/artifact.py b/qiita_db/artifact.py index 8d14ea595..9bc553a53 100644 --- a/qiita_db/artifact.py +++ b/qiita_db/artifact.py @@ -571,6 +571,10 @@ def delete(cls, artifact_id): sql = "DELETE FROM qiita.study_artifact WHERE artifact_id = %s" qdb.sql_connection.TRN.add(sql, [artifact_id]) + # Detach the artifact from the analysis_artifact table + sql = "DELETE FROM qiita.analysis_artifact WHERE artifact_id = %s" + qdb.sql_connection.TRN.add(sql, [artifact_id]) + # Delete the row in the artifact table sql = "DELETE FROM qiita.artifact WHERE artifact_id = %s" qdb.sql_connection.TRN.add(sql, [artifact_id]) diff --git a/qiita_db/test/test_artifact.py b/qiita_db/test/test_artifact.py index a9173440e..89b13c661 100644 --- a/qiita_db/test/test_artifact.py +++ b/qiita_db/test/test_artifact.py @@ -919,6 +919,21 @@ def test_delete(self): with self.assertRaises(qdb.exceptions.QiitaDBUnknownIDError): qdb.artifact.Artifact(test.id) + # Analysis artifact + parameters = qdb.software.Parameters.from_default_params( + qdb.software.DefaultParameters(1), {'input_data': 1}) + test = qdb.artifact.Artifact.create( + self.filepaths_processed, "Demultiplexed", + parents=[qdb.artifact.Artifact(9)], + processing_parameters=parameters) + + self._clean_up_files.extend( + [join(uploads_fp, basename(fp)) for _, fp, _ in test.filepaths]) + qdb.artifact.Artifact.delete(test.id) + + with self.assertRaises(qdb.exceptions.QiitaDBUnknownIDError): + qdb.artifact.Artifact(test.id) + def test_delete_with_html(self): fd, html_fp = mkstemp(suffix=".html") close(fd) diff --git a/qiita_pet/handlers/analysis_handlers/base_handlers.py b/qiita_pet/handlers/analysis_handlers/base_handlers.py index cc23847eb..52c00a852 100644 --- a/qiita_pet/handlers/analysis_handlers/base_handlers.py +++ b/qiita_pet/handlers/analysis_handlers/base_handlers.py @@ -6,7 +6,10 @@ # The full license is in the file LICENSE, distributed with this software. # ----------------------------------------------------------------------------- +from json import loads + from tornado.web import authenticated +from moi import r_client from qiita_core.util import execute_as_transaction from qiita_core.qiita_settings import qiita_config @@ -29,16 +32,49 @@ def post(self): % (qiita_config.portal_dir, analysis.id)) +def analysis_description_handler_get_request(analysis_id, user): + """Returns the analysis information + + Parameters + ---------- + analysis_id : int + The analysis id + user : qiita_db.user.User + The user performing the request + """ + analysis = Analysis(analysis_id) + check_analysis_access(user, analysis) + + job_info = r_client.get("analysis_%s" % analysis.id) + alert_type = 'info' + alert_msg = '' + if job_info: + job_info = loads(job_info) + job_id = job_info['job_id'] + if job_id: + redis_info = loads(r_client.get(job_id)) + if redis_info['status_msg'] == 'running': + alert_msg = 'An artifact is being deleted from this analysis' + elif redis_info['return'] is not None: + alert_type = redis_info['return']['status'] + alert_msg = redis_info['return']['message'].replace( + '\n', '
') + + return {'analysis_name': analysis.name, + 'analysis_id': analysis.id, + 'analysis_description': analysis.description, + 'alert_type': alert_type, + 'alert_msg': alert_msg} + + class AnalysisDescriptionHandler(BaseHandler): @authenticated @execute_as_transaction def get(self, analysis_id): - analysis = Analysis(analysis_id) - check_analysis_access(self.current_user, analysis) + res = analysis_description_handler_get_request(analysis_id, + self.current_user) - self.render("analysis_description.html", analysis_name=analysis.name, - analysis_id=analysis_id, - analysis_description=analysis.description) + self.render("analysis_description.html", **res) def analyisis_graph_handler_get_request(analysis_id, user): diff --git a/qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py b/qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py index 9203f79dd..81810a045 100644 --- a/qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py +++ b/qiita_pet/handlers/analysis_handlers/tests/test_base_handlers.py @@ -7,20 +7,56 @@ # ----------------------------------------------------------------------------- from unittest import TestCase, main -from json import loads +from json import loads, dumps from tornado.web import HTTPError +from moi import r_client from qiita_core.util import qiita_test_checker from qiita_db.user import User from qiita_db.analysis import Analysis from qiita_pet.test.tornado_test_base import TestHandlerBase from qiita_pet.handlers.analysis_handlers.base_handlers import ( - analyisis_graph_handler_get_request) + analyisis_graph_handler_get_request, + analysis_description_handler_get_request) @qiita_test_checker() class TestBaseHandlersUtils(TestCase): + def tearDown(self): + r_client.flushdb() + + def test_analysis_description_handler_get_request(self): + obs = analysis_description_handler_get_request(1, User('test@foo.bar')) + exp = {'analysis_name': 'SomeAnalysis', + 'analysis_id': 1, + 'analysis_description': 'A test analysis', + 'alert_type': 'info', + 'alert_msg': ''} + self.assertEqual(obs, exp) + + r_client.set('analysis_1', dumps({'job_id': 'job_id'})) + r_client.set('job_id', dumps({'status_msg': 'running'})) + obs = analysis_description_handler_get_request(1, User('test@foo.bar')) + exp = {'analysis_name': 'SomeAnalysis', + 'analysis_id': 1, + 'analysis_description': 'A test analysis', + 'alert_type': 'info', + 'alert_msg': 'An artifact is being deleted from this analysis'} + self.assertEqual(obs, exp) + + r_client.set('job_id', dumps( + {'status_msg': 'Success', + 'return': {'status': 'danger', + 'message': 'Error deleting artifact'}})) + obs = analysis_description_handler_get_request(1, User('test@foo.bar')) + exp = {'analysis_name': 'SomeAnalysis', + 'analysis_id': 1, + 'analysis_description': 'A test analysis', + 'alert_type': 'danger', + 'alert_msg': 'Error deleting artifact'} + self.assertEqual(obs, exp) + def test_analyisis_graph_handler_get_request(self): obs = analyisis_graph_handler_get_request(1, User('test@foo.bar')) # The job id is randomly generated in the test environment. Gather diff --git a/qiita_pet/handlers/artifact_handlers/base_handlers.py b/qiita_pet/handlers/artifact_handlers/base_handlers.py index b93e75f89..3ba92e0ab 100644 --- a/qiita_pet/handlers/artifact_handlers/base_handlers.py +++ b/qiita_pet/handlers/artifact_handlers/base_handlers.py @@ -7,16 +7,24 @@ # ----------------------------------------------------------------------------- from os.path import basename +from json import dumps from tornado.web import authenticated +from moi import r_client from qiita_core.qiita_settings import qiita_config from qiita_pet.handlers.base_handlers import BaseHandler from qiita_pet.handlers.util import safe_execution from qiita_pet.exceptions import QiitaHTTPError +from qiita_ware.context import safe_submit +from qiita_ware.dispatchable import delete_artifact from qiita_db.artifact import Artifact from qiita_db.software import Command, Parameters from qiita_db.processing_job import ProcessingJob +from qiita_db.util import get_visibilities + + +PREP_TEMPLATE_KEY_FORMAT = 'prep_template_%s' def check_artifact_access(user, artifact): @@ -131,7 +139,7 @@ def artifact_summary_get_request(user, artifact_id): # If the artifact is part of an analysis, we don't require admin # approval, and the artifact can be made public only if all the # artifacts used to create the initial artifact set are public - if analysis.can_be_publicized: + if analysis.can_be_publicized and visibility != 'public': buttons.append(btn_base % ('make public', 'public', 'Make public')) else: @@ -145,13 +153,12 @@ def artifact_summary_get_request(user, artifact_id): buttons.append( btn_base % ('request approval for', 'awaiting_approval', 'Request approval')) - - elif user.level == 'admin' and visibility == 'awaiting_approval': - # The approve artifact button only appears if the user is an admin - # the artifact is waiting to be approvaed and the qiita config - # requires artifact approval - buttons.append(btn_base % ('approve', 'private', - 'Approve artifact')) + elif user.level == 'admin' and visibility == 'awaiting_approval': + # The approve artifact button only appears if the user is an + # admin the artifact is waiting to be approvaed and the qiita + # config requires artifact approval + buttons.append(btn_base % ('approve', 'private', + 'Approve artifact')) if visibility == 'private': # The make public button only appears if the artifact is private @@ -206,8 +213,7 @@ def artifact_summary_get_request(user, artifact_id): 'processing_jobs': processing_jobs, 'summary': summary, 'job': job_info, - 'errored_jobs': errored_jobs - } + 'errored_jobs': errored_jobs} def artifact_summary_post_request(user, artifact_id): @@ -311,6 +317,23 @@ def artifact_patch_request(user, artifact_id, req_op, req_path, req_value=None, if attribute == 'name': artifact.name = req_value return + elif attribute == 'visibility': + if req_value not in get_visibilities(): + raise QiitaHTTPError(400, 'Unknown visibility value: %s' + % req_value) + # Set the approval to private if needs approval and admin + if req_value == 'private': + if not qiita_config.require_approval: + artifact.visibility = 'private' + # Set the approval to private if approval not required + elif user.level == 'admin': + artifact.visibility = 'private' + # Trying to set approval without admin privileges + else: + raise QiitaHTTPError(403, 'User does not have permissions ' + 'to approve change') + else: + artifact.visibility = req_value else: # We don't understand the attribute so return an error raise QiitaHTTPError(404, 'Attribute "%s" not found. Please, ' @@ -320,7 +343,40 @@ def artifact_patch_request(user, artifact_id, req_op, req_path, req_value=None, 'supported operations: replace' % req_op) +def artifact_post_req(user, artifact_id): + """Deletes the artifact + + Parameters + ---------- + user : qiita_db.user.User + The user requesting the action + artifact_id : int + Id of the artifact being deleted + """ + artifact_id = int(artifact_id) + artifact = Artifact(artifact_id) + check_artifact_access(user, artifact) + + analysis = artifact.analysis + + if analysis: + # Do something when deleting in the analysis part to keep track of it + redis_key = "analysis_%s" % analysis.id + else: + pt_id = artifact.prep_templates[0].id + redis_key = PREP_TEMPLATE_KEY_FORMAT % pt_id + + job_id = safe_submit(user.id, delete_artifact, artifact_id) + r_client.set(redis_key, dumps({'job_id': job_id, 'is_qiita_job': False})) + + class ArtifactAJAX(BaseHandler): + @authenticated + def post(self, artifact_id): + with safe_execution(): + artifact_post_req(self.current_user, artifact_id) + self.finish() + @authenticated def patch(self, artifact_id): """Patches a prep template in the system 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 7c5473d35..41d181502 100644 --- a/qiita_pet/handlers/artifact_handlers/tests/test_base_handlers.py +++ b/qiita_pet/handlers/artifact_handlers/tests/test_base_handlers.py @@ -252,9 +252,10 @@ def test_artifact_summary_post_request(self): def test_artifact_patch_request(self): a = Artifact(1) + test_user = User('test@foo.bar') self.assertEqual(a.name, 'Raw data 1') - artifact_patch_request(User('test@foo.bar'), 1, 'replace', '/name/', + artifact_patch_request(test_user, 1, 'replace', '/name/', req_value='NEW_NAME') self.assertEqual(a.name, 'NEW_NAME') @@ -268,24 +269,44 @@ def test_artifact_patch_request(self): # Incorrect path parameter with self.assertRaises(QiitaHTTPError): - artifact_patch_request(User('test@foo.bar'), 1, 'replace', + artifact_patch_request(test_user, 1, 'replace', '/name/wrong/', req_value='NEW_NAME') # Missing value with self.assertRaises(QiitaHTTPError): - artifact_patch_request(User('test@foo.bar'), 1, 'replace', - '/name/') + artifact_patch_request(test_user, 1, 'replace', '/name/') # Wrong attribute with self.assertRaises(QiitaHTTPError): - artifact_patch_request(User('test@foo.bar'), 1, 'replace', + artifact_patch_request(test_user, 1, 'replace', '/wrong/', req_value='NEW_NAME') # Wrong operation with self.assertRaises(QiitaHTTPError): - artifact_patch_request(User('test@foo.bar'), 1, 'add', '/name/', + artifact_patch_request(test_user, 1, 'add', '/name/', req_value='NEW_NAME') + # Changing visibility + self.assertEqual(a.visibility, 'private') + artifact_patch_request(test_user, 1, 'replace', '/visibility/', + req_value='sandbox') + self.assertEqual(a.visibility, 'sandbox') + + # Admin can change to private + artifact_patch_request(User('admin@foo.bar'), 1, 'replace', + '/visibility/', req_value='private') + self.assertEqual(a.visibility, 'private') + + # Test user can't change to private + with self.assertRaises(QiitaHTTPError): + artifact_patch_request(test_user, 1, 'replace', '/visibility/', + req_value='private') + + # Unkown req value + with self.assertRaises(QiitaHTTPError): + artifact_patch_request(test_user, 1, 'replace', '/visibility/', + req_value='wrong') + class TestBaseHandlers(TestHandlerBase): def test_get_artifact_summary_ajax_handler(self): diff --git a/qiita_pet/templates/analysis_description.html b/qiita_pet/templates/analysis_description.html index ff2e628c0..df1d4949b 100644 --- a/qiita_pet/templates/analysis_description.html +++ b/qiita_pet/templates/analysis_description.html @@ -2,6 +2,29 @@ {% block head %}