Skip to content

Commit 4bed8a5

Browse files
committed
Merge pull request #1068 from antgonza/delete-study
Delete study
2 parents 3b51c0d + 53b5b93 commit 4bed8a5

File tree

6 files changed

+179
-4
lines changed

6 files changed

+179
-4
lines changed

qiita_db/study.py

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
from .util import (check_required_columns, check_table_cols, convert_to_id,
108108
get_environmental_packages, get_table_cols, infer_status)
109109
from .sql_connection import SQLConnectionHandler
110+
from .util import exists_table
110111

111112

112113
class Study(QiitaObject):
@@ -347,6 +348,68 @@ def create(cls, owner, title, efo, info, investigation=None):
347348

348349
return cls(study_id)
349350

351+
@classmethod
352+
def delete(cls, id_):
353+
r"""Deletes the study from the database
354+
355+
Parameters
356+
----------
357+
id_ : integer
358+
The object identifier
359+
360+
Raises
361+
------
362+
QiitaDBError
363+
If the sample_(id_) table exists means a sample template exists
364+
"""
365+
cls._check_subclass()
366+
367+
# checking that the id_ exists
368+
cls(id_)
369+
370+
conn_handler = SQLConnectionHandler()
371+
if exists_table('sample_%d' % id_, conn_handler):
372+
raise QiitaDBError('Study "%s" cannot be erased because it has a '
373+
'sample template' % cls(id_).title)
374+
375+
queue = "delete_study_%d" % id_
376+
conn_handler.create_queue(queue)
377+
378+
conn_handler.add_to_queue(
379+
queue,
380+
"DELETE FROM qiita.study_sample_columns WHERE study_id = %s",
381+
(id_, ))
382+
383+
conn_handler.add_to_queue(
384+
queue,
385+
"DELETE FROM qiita.study_experimental_factor WHERE study_id = %s",
386+
(id_, ))
387+
388+
conn_handler.add_to_queue(
389+
queue,
390+
"DELETE FROM qiita.study_pmid WHERE study_id = %s", (id_, ))
391+
392+
conn_handler.add_to_queue(
393+
queue,
394+
"DELETE FROM qiita.study_environmental_package WHERE study_id = "
395+
"%s", (id_, ))
396+
397+
conn_handler.add_to_queue(
398+
queue,
399+
"DELETE FROM qiita.study_users WHERE study_id = %s", (id_, ))
400+
401+
conn_handler.add_to_queue(
402+
queue,
403+
"DELETE FROM qiita.investigation_study WHERE study_id = "
404+
"%s", (id_, ))
405+
406+
conn_handler.add_to_queue(
407+
queue,
408+
"DELETE FROM qiita.study WHERE study_id = %s", (id_, ))
409+
410+
conn_handler.execute_queue(queue)
411+
412+
350413
# --- Attributes ---
351414
@property
352415
def title(self):

qiita_db/test/test_study.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
from qiita_db.user import User
1212
from qiita_db.data import RawData
1313
from qiita_db.util import convert_to_id
14-
from qiita_db.exceptions import QiitaDBColumnError, QiitaDBStatusError
14+
from qiita_db.exceptions import (
15+
QiitaDBColumnError, QiitaDBStatusError, QiitaDBError,
16+
QiitaDBUnknownIDError)
1517

1618
# -----------------------------------------------------------------------------
1719
# Copyright (c) 2014--, The Qiita Development Team.
@@ -438,6 +440,18 @@ def test_create_unknown_db_col(self):
438440
Study.create(User('test@foo.bar'), "Fried Chicken Microbiome",
439441
[1], self.info)
440442

443+
def test_delete(self):
444+
title = "Fried chicken microbiome"
445+
study = Study.create(User('test@foo.bar'), title, [1], self.info)
446+
study.delete(study.id)
447+
self.assertFalse(study.exists(title))
448+
449+
with self.assertRaises(QiitaDBError):
450+
Study.delete(1)
451+
452+
with self.assertRaises(QiitaDBUnknownIDError):
453+
Study.delete(41)
454+
441455
def test_retrieve_title(self):
442456
self.assertEqual(self.study.title, 'Identification of the Microbiomes'
443457
' for Cannabis Soils')

qiita_pet/handlers/study_handlers/description_handlers.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
QiitaDBDuplicateHeaderError, QiitaDBError)
3030
from qiita_pet.handlers.base_handlers import BaseHandler
3131
from qiita_pet.handlers.util import check_access
32+
from qiita_pet.handlers.study_handlers.listing_handlers import (
33+
ListStudiesHandler)
3234

3335
html_error_message = "<b>An error occurred %s %s</b></br>%s"
3436

@@ -640,6 +642,38 @@ def display_template(self, study, user, msg, msg_level, full_access,
640642
sub_tab=sub_tab,
641643
prep_tab=prep_tab)
642644

645+
def delete_study(self, study, user, callback):
646+
"""Delete study
647+
648+
Parameters
649+
----------
650+
study : Study
651+
The current study object
652+
user : User
653+
The current user object
654+
callback : function
655+
The callback function to call with the results once the processing
656+
is done and it fails
657+
"""
658+
study_id = study.id
659+
study_title = study.title
660+
661+
try:
662+
Study.delete(study_id)
663+
664+
# redirecting to list but also passing messages
665+
# we need to change the request.method to GET
666+
self.request.method = 'GET'
667+
ListStudiesHandler(self.application, self.request)._execute(
668+
[t(self.request) for t in self.application.transforms],
669+
message=('Study "%s" has been deleted' % study_title),
670+
msg_level='success')
671+
except Exception as e:
672+
msg = "Couldn't remove study %d: %s" % (study_id, str(e))
673+
msg_level = "danger"
674+
675+
callback((msg, msg_level, 'study_information_tab', None, None))
676+
643677
def delete_sample_template(self, study, user, callback):
644678
"""Delete sample template
645679
@@ -808,6 +842,7 @@ def post(self, study_id):
808842
request_approval=self.request_approval,
809843
make_sandbox=self.make_sandbox,
810844
update_investigation_type=self.update_investigation_type,
845+
delete_study=self.delete_study,
811846
delete_sample_template=self.delete_sample_template,
812847
delete_raw_data=self.delete_raw_data,
813848
delete_prep_template=self.delete_prep_template,

qiita_pet/handlers/study_handlers/listing_handlers.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,16 @@ def _check_owner(user, study):
123123
class ListStudiesHandler(BaseHandler):
124124
@authenticated
125125
@coroutine
126-
def get(self):
126+
def get(self, message="", msg_level=None):
127127
all_emails_except_current = yield Task(self._get_all_emails)
128128
all_emails_except_current.remove(self.current_user.id)
129129
avail_meta = SampleTemplate.metadata_headers() +\
130130
get_table_cols("study")
131-
self.render('list_studies.html', availmeta=avail_meta,
132-
all_emails_except_current=all_emails_except_current)
131+
self.render('list_studies.html',
132+
availmeta=avail_meta,
133+
all_emails_except_current=all_emails_except_current,
134+
message=message,
135+
msg_level=msg_level)
133136

134137
def _get_all_emails(self, callback):
135138
callback(list(User.iter()))

qiita_pet/templates/study_description.html

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,36 @@
184184
form.submit();
185185
}
186186

187+
function validate_delete_study_text() {
188+
if ($("#study-alias").val() == "{{study_alias}}") {
189+
$('#delete-study-button').prop('disabled', false);
190+
} else {
191+
$('#delete-study-button').prop('disabled', true);
192+
}
193+
}
194+
195+
function delete_study() {
196+
if ($("#study-alias").val() != "{{study_alias}}") {
197+
alert("The added name doesn't match the study alias");
198+
return false;
199+
}
200+
if (confirm('Are you sure you want to delete "{{study_title}}"?')) {
201+
var form = $("<form>")
202+
.attr("action", window.location.href)
203+
.attr("method", "post")
204+
.append($("<input>")
205+
.attr("type", "hidden")
206+
.attr("name", "study_id")
207+
.attr("value", {{study.id}}))
208+
.append($("<input>")
209+
.attr("type", "hidden")
210+
.attr("name", "action")
211+
.attr("value", "delete_study"));
212+
$("body").append(form);
213+
form.submit();
214+
}
215+
}
216+
187217
function delete_sample_template() {
188218
sample_template_id = {{study.sample_template}};
189219
if (confirm('Are you sure you want to delete sample template ID: ' + sample_template_id + '?')) {
@@ -548,6 +578,7 @@ <h2><i>{{study_alias}}</i></h2>
548578
<a class="btn btn-default glyphicon glyphicon-edit" href="/study/edit/{{study.id}}" title="Edit the study information" style="margin:5px; word-spacing: -10px;"> Edit</a>
549579
{% end %}
550580
<a href="/study/upload/{{study.id}}" class="btn btn-default glyphicon glyphicon-upload" title="Upload study files" style="margin:5px; word-spacing: -10px;"> Upload</a>
581+
<a class="btn btn-danger glyphicon glyphicon-trash" style="display: inline-block;" data-toggle="modal" data-target="#delete-study"> Delete-study</a>
551582
</td>
552583
</tr>
553584
</table>
@@ -580,4 +611,24 @@ <h2><i>{{study_alias}}</i></h2>
580611
{% end %}
581612
</div>
582613

614+
615+
<div class="modal fade delete-study" tabindex="-1" role="dialog" id="delete-study">
616+
<div class="modal-dialog modal-sm">
617+
<div class="modal-content">
618+
<div class="modal-header">
619+
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
620+
<h3>Deleting:<br/></h3><h4>{{study_title}}</h4>
621+
</div>
622+
<div class="modal-body">
623+
You will only be able to delete a study that has no data associated with it.
624+
</div>
625+
<div class="modal-footer">
626+
To continue you need to write the alias name of the study:
627+
<input type="text" name="study-alias" id="study-alias" onkeyup="validate_delete_study_text();">
628+
<button class="btn btn-danger glyphicon glyphicon-trash" onclick="delete_study();" id="delete-study-button" disabled></button>
629+
</div>
630+
</div>
631+
</div>
632+
</div>
633+
583634
{% end %}

qiita_pet/test/test_study_handlers.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,15 @@ class TestEBISubmitHandler(TestHandlerBase):
385385
class TestDelete(TestHandlerBase):
386386
database = True
387387

388+
def test_delete_study(self):
389+
response = self.post('/study/description/1',
390+
{'study_id': 1,
391+
'action': 'delete_study'})
392+
self.assertEqual(response.code, 200)
393+
394+
# checking that the action was sent
395+
self.assertIn("Couldn't remove study", response.body)
396+
388397
def test_delete_sample_template(self):
389398
response = self.post('/study/description/1',
390399
{'sample_template_id': 1,

0 commit comments

Comments
 (0)