diff --git a/qiita_db/study.py b/qiita_db/study.py index 4163200f4..4f0ff3e5b 100644 --- a/qiita_db/study.py +++ b/qiita_db/study.py @@ -107,6 +107,7 @@ from .util import (check_required_columns, check_table_cols, convert_to_id, get_environmental_packages, get_table_cols, infer_status) from .sql_connection import SQLConnectionHandler +from .util import exists_table class Study(QiitaObject): @@ -347,6 +348,68 @@ def create(cls, owner, title, efo, info, investigation=None): return cls(study_id) + @classmethod + def delete(cls, id_): + r"""Deletes the study from the database + + Parameters + ---------- + id_ : integer + The object identifier + + Raises + ------ + QiitaDBError + If the sample_(id_) table exists means a sample template exists + """ + cls._check_subclass() + + # checking that the id_ exists + cls(id_) + + conn_handler = SQLConnectionHandler() + if exists_table('sample_%d' % id_, conn_handler): + raise QiitaDBError('Study "%s" cannot be erased because it has a ' + 'sample template' % cls(id_).title) + + queue = "delete_study_%d" % id_ + conn_handler.create_queue(queue) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.study_sample_columns WHERE study_id = %s", + (id_, )) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.study_experimental_factor WHERE study_id = %s", + (id_, )) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.study_pmid WHERE study_id = %s", (id_, )) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.study_environmental_package WHERE study_id = " + "%s", (id_, )) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.study_users WHERE study_id = %s", (id_, )) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.investigation_study WHERE study_id = " + "%s", (id_, )) + + conn_handler.add_to_queue( + queue, + "DELETE FROM qiita.study WHERE study_id = %s", (id_, )) + + conn_handler.execute_queue(queue) + + # --- Attributes --- @property def title(self): diff --git a/qiita_db/test/test_study.py b/qiita_db/test/test_study.py index adef0aaa4..a235c3cce 100644 --- a/qiita_db/test/test_study.py +++ b/qiita_db/test/test_study.py @@ -11,7 +11,9 @@ from qiita_db.user import User from qiita_db.data import RawData from qiita_db.util import convert_to_id -from qiita_db.exceptions import QiitaDBColumnError, QiitaDBStatusError +from qiita_db.exceptions import ( + QiitaDBColumnError, QiitaDBStatusError, QiitaDBError, + QiitaDBUnknownIDError) # ----------------------------------------------------------------------------- # Copyright (c) 2014--, The Qiita Development Team. @@ -438,6 +440,18 @@ def test_create_unknown_db_col(self): Study.create(User('test@foo.bar'), "Fried Chicken Microbiome", [1], self.info) + def test_delete(self): + title = "Fried chicken microbiome" + study = Study.create(User('test@foo.bar'), title, [1], self.info) + study.delete(study.id) + self.assertFalse(study.exists(title)) + + with self.assertRaises(QiitaDBError): + Study.delete(1) + + with self.assertRaises(QiitaDBUnknownIDError): + Study.delete(41) + def test_retrieve_title(self): self.assertEqual(self.study.title, 'Identification of the Microbiomes' ' for Cannabis Soils') diff --git a/qiita_pet/handlers/study_handlers/description_handlers.py b/qiita_pet/handlers/study_handlers/description_handlers.py index 00e2c8716..0f68c63e8 100644 --- a/qiita_pet/handlers/study_handlers/description_handlers.py +++ b/qiita_pet/handlers/study_handlers/description_handlers.py @@ -29,6 +29,8 @@ QiitaDBDuplicateHeaderError, QiitaDBError) from qiita_pet.handlers.base_handlers import BaseHandler from qiita_pet.handlers.util import check_access +from qiita_pet.handlers.study_handlers.listing_handlers import ( + ListStudiesHandler) html_error_message = "An error occurred %s %s
%s" @@ -640,6 +642,38 @@ def display_template(self, study, user, msg, msg_level, full_access, sub_tab=sub_tab, prep_tab=prep_tab) + def delete_study(self, study, user, callback): + """Delete study + + Parameters + ---------- + study : Study + The current study object + user : User + The current user object + callback : function + The callback function to call with the results once the processing + is done and it fails + """ + study_id = study.id + study_title = study.title + + try: + Study.delete(study_id) + + # redirecting to list but also passing messages + # we need to change the request.method to GET + self.request.method = 'GET' + ListStudiesHandler(self.application, self.request)._execute( + [t(self.request) for t in self.application.transforms], + message=('Study "%s" has been deleted' % study_title), + msg_level='success') + except Exception as e: + msg = "Couldn't remove study %d: %s" % (study_id, str(e)) + msg_level = "danger" + + callback((msg, msg_level, 'study_information_tab', None, None)) + def delete_sample_template(self, study, user, callback): """Delete sample template @@ -808,6 +842,7 @@ def post(self, study_id): request_approval=self.request_approval, make_sandbox=self.make_sandbox, update_investigation_type=self.update_investigation_type, + delete_study=self.delete_study, delete_sample_template=self.delete_sample_template, delete_raw_data=self.delete_raw_data, delete_prep_template=self.delete_prep_template, diff --git a/qiita_pet/handlers/study_handlers/listing_handlers.py b/qiita_pet/handlers/study_handlers/listing_handlers.py index 5816b71bc..682563070 100644 --- a/qiita_pet/handlers/study_handlers/listing_handlers.py +++ b/qiita_pet/handlers/study_handlers/listing_handlers.py @@ -123,13 +123,16 @@ def _check_owner(user, study): class ListStudiesHandler(BaseHandler): @authenticated @coroutine - def get(self): + def get(self, message="", msg_level=None): all_emails_except_current = yield Task(self._get_all_emails) all_emails_except_current.remove(self.current_user.id) avail_meta = SampleTemplate.metadata_headers() +\ get_table_cols("study") - self.render('list_studies.html', availmeta=avail_meta, - all_emails_except_current=all_emails_except_current) + self.render('list_studies.html', + availmeta=avail_meta, + all_emails_except_current=all_emails_except_current, + message=message, + msg_level=msg_level) def _get_all_emails(self, callback): callback(list(User.iter())) diff --git a/qiita_pet/templates/study_description.html b/qiita_pet/templates/study_description.html index cbd5ce8a0..20f39ba01 100644 --- a/qiita_pet/templates/study_description.html +++ b/qiita_pet/templates/study_description.html @@ -184,6 +184,36 @@ form.submit(); } +function validate_delete_study_text() { + if ($("#study-alias").val() == "{{study_alias}}") { + $('#delete-study-button').prop('disabled', false); + } else { + $('#delete-study-button').prop('disabled', true); + } +} + +function delete_study() { + if ($("#study-alias").val() != "{{study_alias}}") { + alert("The added name doesn't match the study alias"); + return false; + } + if (confirm('Are you sure you want to delete "{{study_title}}"?')) { + var form = $("
") + .attr("action", window.location.href) + .attr("method", "post") + .append($("") + .attr("type", "hidden") + .attr("name", "study_id") + .attr("value", {{study.id}})) + .append($("") + .attr("type", "hidden") + .attr("name", "action") + .attr("value", "delete_study")); + $("body").append(form); + form.submit(); + } +} + function delete_sample_template() { sample_template_id = {{study.sample_template}}; if (confirm('Are you sure you want to delete sample template ID: ' + sample_template_id + '?')) { @@ -548,6 +578,7 @@

{{study_alias}}

Edit {% end %} Upload + Delete-study @@ -580,4 +611,24 @@

{{study_alias}}

{% end %} + + + {% end %} diff --git a/qiita_pet/test/test_study_handlers.py b/qiita_pet/test/test_study_handlers.py index 438523d4d..1c6536a87 100644 --- a/qiita_pet/test/test_study_handlers.py +++ b/qiita_pet/test/test_study_handlers.py @@ -385,6 +385,15 @@ class TestEBISubmitHandler(TestHandlerBase): class TestDelete(TestHandlerBase): database = True + def test_delete_study(self): + response = self.post('/study/description/1', + {'study_id': 1, + 'action': 'delete_study'}) + self.assertEqual(response.code, 200) + + # checking that the action was sent + self.assertIn("Couldn't remove study", response.body) + def test_delete_sample_template(self): response = self.post('/study/description/1', {'sample_template_id': 1,