diff --git a/smash/web/templates/subjects/confirm_delete.html b/smash/web/templates/subjects/confirm_delete.html new file mode 100644 index 0000000000000000000000000000000000000000..0cceb3e9550e58058c7106870efa24b68cc24cc9 --- /dev/null +++ b/smash/web/templates/subjects/confirm_delete.html @@ -0,0 +1,89 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/> + <style> + table, th, td { + border: 1px solid black; + border-collapse: collapse; + padding: 5px; + } + </style> +{% endblock styles %} + +{% block ui_active_tab %}'subjects'{% endblock ui_active_tab %} +{% block page_header %}Delete subject{% endblock page_header %} +{% block page_description %}{% endblock page_description %} + +{% block title %}{{ block.super }} - Delete subject{% endblock %} + +{% block breadcrumb %} + {% include "subjects/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + <div class="row"> + <div class="col-md-12"> + <div class="box box-success"> + <div class="box-header with-border"> + <h3 class="box-title">Confirm deletion</h3> + </div> + + <form action="" method="post" class="form-horizontal">{% csrf_token %} + <div class="box-body"> + <p>Are you sure you want to delete subject "{{ object }}"?</p> + <p>Other related elements will be removed too</p> + + <h4>Deletion Summary</h4> + <table> + <tr> + <th>Name</th> + <th>Amount</th> + </tr> + {% for model_name, object_count in model_count %} + <tr> + <td>{{ model_name|capfirst }}</td> + <td>{{ object_count }}</td> + </tr> + {% endfor %} + </table> + <h4>Deletion Tree</h4> + <p> + <ul> + {{ deletable_objects|unordered_list }} + </ul> + </p> + </div><!-- /.box-body --> + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-danger">Delete</button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.subjects' %}" + class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </form> + </div> + + </div> + </div> + + {% endblock %} + + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script> + +{% endblock scripts %} + + diff --git a/smash/web/templates/subjects/confirm_delete_study_subject.html b/smash/web/templates/subjects/confirm_delete_study_subject.html new file mode 100644 index 0000000000000000000000000000000000000000..927457de84334a0818ddffc007357dd32fc38375 --- /dev/null +++ b/smash/web/templates/subjects/confirm_delete_study_subject.html @@ -0,0 +1,89 @@ +{% extends "_base.html" %} +{% load static %} +{% load filters %} + +{% block styles %} + {{ block.super }} + <link rel="stylesheet" href="{% static 'AdminLTE/plugins/awesomplete/awesomplete.css' %}"/> + <style> + table, th, td { + border: 1px solid black; + border-collapse: collapse; + padding: 5px; + } + </style> +{% endblock styles %} + +{% block ui_active_tab %}'subjects'{% endblock ui_active_tab %} +{% block page_header %}Delete study subject{% endblock page_header %} +{% block page_description %}{% endblock page_description %} + +{% block title %}{{ block.super }} - Delete study subject{% endblock %} + +{% block breadcrumb %} + {% include "subjects/breadcrumb.html" %} +{% endblock breadcrumb %} + +{% block maincontent %} + + {% block content %} + <div class="row"> + <div class="col-md-12"> + <div class="box box-success"> + <div class="box-header with-border"> + <h3 class="box-title">Confirm deletion</h3> + </div> + + <form action="" method="post" class="form-horizontal">{% csrf_token %} + <div class="box-body"> + <p>Are you sure you want to delete study subject "{{ object }}" from study "{{object.study}}"?</p> + <p>Other related elements will be removed too</p> + + <h4>Deletion Summary</h4> + <table> + <tr> + <th>Name</th> + <th>Amount</th> + </tr> + {% for model_name, object_count in model_count %} + <tr> + <td>{{ model_name|capfirst }}</td> + <td>{{ object_count }}</td> + </tr> + {% endfor %} + </table> + <h4>Deletion Tree</h4> + <p> + <ul> + {{ deletable_objects|unordered_list }} + </ul> + </p> + </div><!-- /.box-body --> + <div class="box-footer"> + <div class="col-sm-6"> + <button type="submit" class="btn btn-block btn-danger">Delete</button> + </div> + <div class="col-sm-6"> + <a href="{% url 'web.views.subjects' %}" + class="btn btn-block btn-default">Cancel</a> + </div> + </div><!-- /.box-footer --> + </form> + </div> + + </div> + </div> + + {% endblock %} + + +{% endblock maincontent %} + +{% block scripts %} + {{ block.super }} + + <script src="{% static 'AdminLTE/plugins/awesomplete/awesomplete.min.js' %}"></script> + +{% endblock scripts %} + + diff --git a/smash/web/urls.py b/smash/web/urls.py index 7e5e12395e56808092604bb4e9d2284849f652d9..ce04e3b0b6fbcbf1101339161785ebafa384b049 100644 --- a/smash/web/urls.py +++ b/smash/web/urls.py @@ -90,6 +90,11 @@ urlpatterns = [ url(r'^subjects/subject_visit_details/(?P<id>\d+)$', views.subject.subject_visit_details, name='web.views.subject_visit_details'), url(r'^subjects/edit/(?P<id>\d+)$', views.subject.subject_edit, name='web.views.subject_edit'), + url(r'^subjects/(?P<pk>\d+)/delete$', views.subject.SubjectDeleteView.as_view(), + name='web.views.subject_delete'), + + url(r'^studysubjects/(?P<pk>\d+)/delete$', views.subject.StudySubjectDeleteView.as_view(), + name='web.views.study_subject_delete'), ######################### # RED CAP NOTIFICATIONS # diff --git a/smash/web/views/subject.py b/smash/web/views/subject.py index 2b0ddce56b84551a39bbfca87ad2d4bcc067c5e3..96730c2fc247bc6c3260fdefc4a7786e20e42e05 100644 --- a/smash/web/views/subject.py +++ b/smash/web/views/subject.py @@ -1,12 +1,17 @@ # coding=utf-8 import logging +from web.utils import get_deleted_objects +from django.db.models.deletion import Collector from django.contrib import messages from django.shortcuts import redirect, get_object_or_404 from ..utils import get_client_ip from web.decorators import PermissionDecorator from web.models.custom_data import CustomStudySubjectField from . import wrap_response +from django.views.generic import DeleteView +from . import WrappedView +from django.urls import reverse_lazy from ..forms import VisitDetailForm, SubjectAddForm, SubjectEditForm, StudySubjectAddForm, StudySubjectEditForm from ..models import StudySubject, MailTemplate, Worker, Study, Provenance, Subject from ..models.constants import GLOBAL_STUDY_ID, SUBJECT_TYPE_CHOICES, FILE_STORAGE @@ -54,6 +59,51 @@ def subject_add(request, study_id): return wrap_response(request, 'subjects/add.html', {'study_subject_form': study_subject_form, 'subject_form': subject_form}) +#delete subject (from all studies!) +class SubjectDeleteView(DeleteView, WrappedView): + model = Subject + success_url = reverse_lazy('web.views.subjects') + template_name = 'subjects/confirm_delete.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + deletable_objects, model_count, protected = get_deleted_objects([self.object]) + context['deletable_objects'] = deletable_objects + context['model_count'] = dict(model_count).items() + context['protected'] = protected + return context + + def delete(self, request, *args, **kwargs): + messages.success(request, "Subject deleted") + try: + return super(SubjectDeleteView, self).delete(request, *args, **kwargs) + except: + messages.add_message(request, messages.ERROR, 'There was a problem when deleting the subject. ' + 'Contact system administrator.') + return redirect('web.views.subjects') + +#delete subject from study +class StudySubjectDeleteView(DeleteView, WrappedView): + model = StudySubject + success_url = reverse_lazy('web.views.subjects') + template_name = 'subjects/confirm_delete_study_subject.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + deletable_objects, model_count, protected = get_deleted_objects([self.object]) + context['deletable_objects'] = deletable_objects + context['model_count'] = dict(model_count).items() + context['protected'] = protected + return context + + def delete(self, request, *args, **kwargs): + messages.success(request, "Study Subject deleted") + try: + return super(StudySubjectDeleteView, self).delete(request, *args, **kwargs) + except: + messages.add_message(request, messages.ERROR, 'There was a problem when deleting the Study Subject. ' + 'Contact system administrator.') + return redirect('web.views.subjects') def subject_no_visits(request): return subject_list(request, SUBJECT_LIST_NO_VISIT)