From 5d8b6f5cfdd7b0c65b6bdade2538cc3fb8e9c606 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 17:15:48 +0200 Subject: [PATCH 01/15] no longer require view_contact for recruitment This is a relic of a time when we had hoped that we could have model-level permissions for subject data, e.g. control access to contact data with `view_contact`. Nowadays we use contact data (especially name) all over the place, so checking for `view_contact` all the time would be essentially meaningless. --- castellum/recruitment/views.py | 5 +---- castellum/subjects/views.py | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/castellum/recruitment/views.py b/castellum/recruitment/views.py index 230b1fec0..7f984f4e4 100644 --- a/castellum/recruitment/views.py +++ b/castellum/recruitment/views.py @@ -291,10 +291,7 @@ class ContactView(ParticipationMixin, PermissionRequiredMixin, UpdateView): model = Participation form_class = ContactForm template_name = 'recruitment/contact.html' - permission_required = ( - 'contacts.view_contact', - 'recruitment.change_participation', - ) + permission_required = 'recruitment.change_participation' study_status = [Study.EXECUTION] def get_initial(self): diff --git a/castellum/subjects/views.py b/castellum/subjects/views.py index ad91483ce..3ad53a7c6 100644 --- a/castellum/subjects/views.py +++ b/castellum/subjects/views.py @@ -86,10 +86,7 @@ class SubjectSearchView(LoginRequiredMixin, FormView): can_recruit = ( has_privacy_level and can_access_study and - user.has_perms(( - 'contacts.view_contact', - 'recruitment.change_participation', - ), obj=participation.study) + user.has_perm('recruitment.change_participation', obj=participation.study) ) can_conduct = ( has_privacy_level and -- GitLab From fe16c8c8aced51283376b210ac3ecb7c24f3180a Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 16:43:14 +0200 Subject: [PATCH 02/15] add special export subject permission --- castellum/castellum_auth/fixtures/groups.json | 2 +- castellum/data_protection/views.py | 2 +- .../migrations/0017_refactor_permissions.py | 17 +++++++++++++++++ castellum/subjects/models.py | 3 +++ .../templates/subjects/subject_base.html | 4 ++-- castellum/subjects/views.py | 2 +- castellum/templates/index.html | 4 ++-- 7 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 castellum/subjects/migrations/0017_refactor_permissions.py diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index 2f0337072..0da318181 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -142,7 +142,7 @@ "participation" ], [ - "view_subject", + "export_subject", "subjects", "subject" ], diff --git a/castellum/data_protection/views.py b/castellum/data_protection/views.py index 9c241e979..a364bef49 100644 --- a/castellum/data_protection/views.py +++ b/castellum/data_protection/views.py @@ -29,7 +29,7 @@ from . import helpers class DataProtectionView(PermissionRequiredMixin, TemplateView): template_name = 'data_protection/index.html' permission_required = [ - 'subjects.view_subject', + 'subjects.export_subject', 'castellum_auth.privacy_level_2', ] limit_by = 10 diff --git a/castellum/subjects/migrations/0017_refactor_permissions.py b/castellum/subjects/migrations/0017_refactor_permissions.py new file mode 100644 index 000000000..ce2097dca --- /dev/null +++ b/castellum/subjects/migrations/0017_refactor_permissions.py @@ -0,0 +1,17 @@ +# Generated by Django 3.0.8 on 2020-07-21 16:34 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('subjects', '0016_consentdocument_is_deprecated'), + ] + + operations = [ + migrations.AlterModelOptions( + name='subject', + options={'permissions': [('export_subject', 'Can export all data related to a subject')], 'verbose_name': 'Subject'}, + ), + ] diff --git a/castellum/subjects/models.py b/castellum/subjects/models.py index 828b010c8..727bb3101 100644 --- a/castellum/subjects/models.py +++ b/castellum/subjects/models.py @@ -124,6 +124,9 @@ class Subject(TimeStampedModel): class Meta: verbose_name = _('Subject') + permissions = [ + ('export_subject', _('Can export all data related to a subject')), + ] def delete(self): self.contact.delete() diff --git a/castellum/subjects/templates/subjects/subject_base.html b/castellum/subjects/templates/subjects/subject_base.html index 0fa9babb5..eb16daa98 100644 --- a/castellum/subjects/templates/subjects/subject_base.html +++ b/castellum/subjects/templates/subjects/subject_base.html @@ -62,8 +62,8 @@ {% trans "Study Participations" %} - {% has_perm 'subjects.view_subject' user as can_view_subject %} - {% if can_view_subject %} + {% has_perm 'subjects.export_subject' user as can_export_subject %} + {% if can_export_subject %}
  • {{ participation.study }}
    - {% has_perm 'recruitment.view_participation_pseudonyms' user participation.study as can_view_participation_pseudonyms %} + {% has_perm 'recruitment.conduct_study' user participation.study as can_view_participation_pseudonyms %} {% if can_view_participation_pseudonyms %} {% if participation.status == participation.INVITED %} {% trans 'Go to execution' %} diff --git a/castellum/subjects/views.py b/castellum/subjects/views.py index 82f4d7750..3b8f3953f 100644 --- a/castellum/subjects/views.py +++ b/castellum/subjects/views.py @@ -92,9 +92,7 @@ class SubjectSearchView(LoginRequiredMixin, FormView): has_privacy_level and can_access_study and invited and - user.has_perm( - 'recruitment.view_participation_pseudonyms', obj=participation.study - ) + user.has_perm('recruitment.conduct_study', obj=participation.study) ) can_search = invited and user.has_perm('recruitment.search_execution') if can_recruit or can_conduct or can_search: @@ -334,7 +332,7 @@ class ParticipationListView(SubjectMixin, PermissionRequiredMixin, ListView): def is_permitted(self, study): return self.request.user.has_perm('studies.access_study', obj=study) and ( - self.request.user.has_perm('recruitment.view_participation_pseudonyms', obj=study) or + self.request.user.has_perm('recruitment.conduct_study', obj=study) or self.request.user.has_perm('recruitment.change_participation', obj=study) ) -- GitLab From 83125a066ab2c8e6e37b9fdb1fab04f06656a49d Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 16:38:42 +0200 Subject: [PATCH 04/15] combine recruitment permissions into a single one --- castellum/castellum_auth/fixtures/groups.json | 12 +------ castellum/recruitment/feeds.py | 6 ++-- .../migrations/0013_refactor_permissions.py | 2 +- castellum/recruitment/models/recruitment.py | 1 + .../recruitment/__recruitment_list.html | 33 ++++++++----------- .../templates/recruitment/recruitment.html | 15 ++++----- castellum/recruitment/views.py | 12 +++---- castellum/studies/models.py | 2 +- .../studies/templates/studies/study_list.html | 2 +- .../subjects/subject_participationlist.html | 4 +-- castellum/subjects/views.py | 8 ++--- 11 files changed, 38 insertions(+), 59 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index bf4c0532d..386db9a22 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -89,17 +89,7 @@ "contact" ], [ - "add_participation", - "recruitment", - "participation" - ], - [ - "change_participation", - "recruitment", - "participation" - ], - [ - "view_participation", + "recruit", "recruitment", "participation" ] diff --git a/castellum/recruitment/feeds.py b/castellum/recruitment/feeds.py index e08edc8e7..bd40dfb3a 100644 --- a/castellum/recruitment/feeds.py +++ b/castellum/recruitment/feeds.py @@ -32,7 +32,7 @@ from .models import Participation class FollowUpFeedForStudy(BaseFollowUpFeed): def get_object(self, request, *args, **kwargs): study = get_object_or_404(Study, pk=kwargs.get('study_pk'), status=Study.EXECUTION) - perms = ('recruitment.add_participation', 'studies.access_study') + perms = ('recruitment.recruit', 'studies.access_study') if not self.request.user.has_perms(perms, obj=study): raise PermissionDenied return study @@ -48,7 +48,7 @@ class FollowUpFeedForUser(BaseFollowUpFeed): return self.request.user def items(self, user): - perms = ('recruitment.add_participation', 'studies.access_study') + perms = ('recruitment.recruit', 'studies.access_study') for study in Study.objects.filter(status=Study.EXECUTION): if not user.has_perms(perms, obj=study): continue @@ -62,7 +62,7 @@ class FollowUpFeedForUser(BaseFollowUpFeed): class AppointmentFeed(BaseAppointmentFeed): def get_object(self, request, *args, **kwargs): study = get_object_or_404(Study, pk=kwargs['pk'], status=Study.EXECUTION) - perms = ('recruitment.view_participation', 'studies.access_study') + perms = ('recruitment.recruit', 'studies.access_study') if not self.request.user.has_perms(perms, obj=study): raise PermissionDenied return study diff --git a/castellum/recruitment/migrations/0013_refactor_permissions.py b/castellum/recruitment/migrations/0013_refactor_permissions.py index c9d7518e2..17fabefd5 100644 --- a/castellum/recruitment/migrations/0013_refactor_permissions.py +++ b/castellum/recruitment/migrations/0013_refactor_permissions.py @@ -12,6 +12,6 @@ class Migration(migrations.Migration): operations = [ migrations.AlterModelOptions( name='participation', - options={'permissions': (('conduct_study', 'Can conduct studies'), ('search_execution', 'Can search in execution')), 'verbose_name': 'Participation', 'verbose_name_plural': 'Participations'}, + options={'permissions': (('conduct_study', 'Can conduct studies'), ('search_execution', 'Can search in execution'), ('recruit', 'Can recruit')), 'verbose_name': 'Participation', 'verbose_name_plural': 'Participations'}, ), ] diff --git a/castellum/recruitment/models/recruitment.py b/castellum/recruitment/models/recruitment.py index 0299e5649..b1615b018 100644 --- a/castellum/recruitment/models/recruitment.py +++ b/castellum/recruitment/models/recruitment.py @@ -112,6 +112,7 @@ class Participation(models.Model): permissions = ( ('conduct_study', _('Can conduct studies')), ('search_execution', _('Can search in execution')), + ('recruit', _('Can recruit')), ) @property diff --git a/castellum/recruitment/templates/recruitment/__recruitment_list.html b/castellum/recruitment/templates/recruitment/__recruitment_list.html index c4829f22e..7a38b32a4 100644 --- a/castellum/recruitment/templates/recruitment/__recruitment_list.html +++ b/castellum/recruitment/templates/recruitment/__recruitment_list.html @@ -1,7 +1,6 @@ {% load i18n auth utils %}
      - {% has_perm 'recruitment.change_participation' user study as can_change_participation %} {% for participation, buckets, can_access in participations %}
    • {% if can_access %} @@ -78,17 +77,15 @@
    {% endif %} - {% if can_change_participation %} - - {% endif %} + {% else %}
    @@ -97,11 +94,9 @@
    - {% if can_change_participation %} - - {% endif %} + {% endif %}
  • {% empty %} @@ -109,8 +104,8 @@ {% if view.subtab == 'open' %} {% trans 'No one to contact for recruitment!' %} {% trans 'Currently, there are no open potential subjects.' %} - {% has_perm 'recruitment.add_participation' user study as can_add_participation %} - {% if can_add_participation %} + {% has_perm 'recruitment.recruit' user study as can_recruit %} + {% if can_recruit %} {% trans 'Please add a set of potential subjects using the Add button.' %} {% endif %} {% elif view.subtab == 'invited' %} diff --git a/castellum/recruitment/templates/recruitment/recruitment.html b/castellum/recruitment/templates/recruitment/recruitment.html index c7c70d9e4..a30861e17 100644 --- a/castellum/recruitment/templates/recruitment/recruitment.html +++ b/castellum/recruitment/templates/recruitment/recruitment.html @@ -59,14 +59,11 @@ {% if view.subtab == 'open' %} - {% has_perm 'recruitment.add_participation' user study as can_add_participation %} - {% if can_add_participation %} -
    -
    - {% csrf_token %} - -
    -
    - {% endif %} +
    +
    + {% csrf_token %} + +
    +
    {% endif %} {% endblock %} diff --git a/castellum/recruitment/views.py b/castellum/recruitment/views.py index dd6c8e300..c41b1b7d0 100644 --- a/castellum/recruitment/views.py +++ b/castellum/recruitment/views.py @@ -26,7 +26,6 @@ from collections import defaultdict from django.conf import settings from django.contrib import messages -from django.core.exceptions import PermissionDenied from django.core.mail import EmailMessage from django.core.mail import get_connection from django.shortcuts import redirect @@ -65,7 +64,7 @@ logger = logging.getLogger(__name__) class RecruitmentView(StudyMixin, PermissionRequiredMixin, ListView): model = Participation template_name = 'recruitment/recruitment.html' - permission_required = 'recruitment.view_participation' + permission_required = 'recruitment.recruit' study_status = [Study.EXECUTION] shown_status = [] tab = 'recruitment' @@ -217,9 +216,6 @@ class RecruitmentViewOpen(RecruitmentView): return added def post(self, request, *args, **kwargs): - if not request.user.has_perm('recruitment.add_participation', obj=self.study): - raise PermissionDenied - if self.study.min_subject_count == 0: messages.error(request, _( 'This study does not require participants. ' @@ -277,7 +273,7 @@ class RecruitmentViewOpen(RecruitmentView): class MailRecruitmentView(BaseMailRecruitmentView): - permission_required = 'recruitment.view_participation' + permission_required = 'recruitment.recruit' study_status = [Study.EXECUTION] participation_status = Participation.AWAITING_RESPONSE tab = 'mail' @@ -291,7 +287,7 @@ class ContactView(ParticipationMixin, PermissionRequiredMixin, UpdateView): model = Participation form_class = ContactForm template_name = 'recruitment/contact.html' - permission_required = 'recruitment.change_participation' + permission_required = 'recruitment.recruit' study_status = [Study.EXECUTION] def get_initial(self): @@ -416,7 +412,7 @@ class AdditionalInfoUpdateView(RecruitmentUpdateMixin, BaseAdditionalInfoUpdateV class CalendarView(StudyMixin, PermissionRequiredMixin, BaseCalendarView): model = Study - permission_required = 'recruitment.view_participation' + permission_required = 'recruitment.recruit' study_status = [Study.EXECUTION] nochrome = True feed = 'recruitment:calendar-feed' diff --git a/castellum/studies/models.py b/castellum/studies/models.py index 92c9327d8..90634e245 100644 --- a/castellum/studies/models.py +++ b/castellum/studies/models.py @@ -281,7 +281,7 @@ class Study(models.Model): def recruiters(self): recruiters = [] for user in self.members.all(): - if user.has_perm('recruitment.add_participation', obj=self): + if user.has_perm('recruitment.recruit', obj=self): recruiters.append(user) return recruiters diff --git a/castellum/studies/templates/studies/study_list.html b/castellum/studies/templates/studies/study_list.html index 2f65837f9..4edabadf2 100644 --- a/castellum/studies/templates/studies/study_list.html +++ b/castellum/studies/templates/studies/study_list.html @@ -77,7 +77,7 @@
    {% has_perm 'studies.access_study' user study as can_access %} {% if can_access and study.status == study.EXECUTION %} - {% has_perm 'recruitment.view_participation' user study as can_recruit %} + {% has_perm 'recruitment.recruit' user study as can_recruit %} {% if can_recruit %} {% trans 'Recruitment' %} {% endif %} diff --git a/castellum/subjects/templates/subjects/subject_participationlist.html b/castellum/subjects/templates/subjects/subject_participationlist.html index e5a3eff73..b0fc2ddbb 100644 --- a/castellum/subjects/templates/subjects/subject_participationlist.html +++ b/castellum/subjects/templates/subjects/subject_participationlist.html @@ -15,8 +15,8 @@ {% trans 'Go to execution' %} {% endif %} {% endif %} - {% has_perm 'recruitment.change_participation' user participation.study as can_change_participation %} - {% if can_change_participation %} + {% has_perm 'recruitment.recruit' user participation.study as can_recruit %} + {% if can_recruit %} {% if participation.status_open %} {% trans 'Contact' context 'verb' %} diff --git a/castellum/subjects/views.py b/castellum/subjects/views.py index 3b8f3953f..093d8978a 100644 --- a/castellum/subjects/views.py +++ b/castellum/subjects/views.py @@ -86,7 +86,7 @@ class SubjectSearchView(LoginRequiredMixin, FormView): can_recruit = ( has_privacy_level and can_access_study and - user.has_perm('recruitment.change_participation', obj=participation.study) + user.has_perm('recruitment.recruit', obj=participation.study) ) can_conduct = ( has_privacy_level and @@ -333,7 +333,7 @@ class ParticipationListView(SubjectMixin, PermissionRequiredMixin, ListView): def is_permitted(self, study): return self.request.user.has_perm('studies.access_study', obj=study) and ( self.request.user.has_perm('recruitment.conduct_study', obj=study) or - self.request.user.has_perm('recruitment.change_participation', obj=study) + self.request.user.has_perm('recruitment.recruit', obj=study) ) def get_queryset(self): @@ -381,7 +381,7 @@ class AddToStudyView(SubjectMixin, PermissionRequiredMixin, DetailView): tab = 'participations' def get_studies(self, subject): - perms = ('recruitment.add_participation', 'studies.access_study') + perms = ('recruitment.recruit', 'studies.access_study') studies = ( Study.objects .filter(status=Study.EXECUTION) @@ -409,7 +409,7 @@ class AddToStudyView(SubjectMixin, PermissionRequiredMixin, DetailView): self.object = self.get_object() study = get_object_or_404(Study, pk=request.POST['study'], status=Study.EXECUTION) - perms = ('recruitment.add_participation', 'studies.access_study') + perms = ('recruitment.recruit', 'studies.access_study') if not request.user.has_perms(perms, obj=study): raise PermissionDenied -- GitLab From 375d3d17a9ef97a8e5f6e443b1d70b23f722e8fe Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 16:51:14 +0200 Subject: [PATCH 05/15] use change_study instead of change_subjectfilter --- castellum/castellum_auth/fixtures/groups.json | 10 ----- .../studies/filtergroup_advanced.html | 43 ++++++++----------- .../study_recruitmentsettings_base.html | 21 ++++----- castellum/studies/views/members.py | 2 +- castellum/studies/views/subjectfilters.py | 12 +++--- 5 files changed, 35 insertions(+), 53 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index 386db9a22..2e0a18460 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -5,16 +5,6 @@ "fields": { "name": "Study coordinator", "permissions": [ - [ - "change_subjectfilter", - "recruitment", - "subjectfilter" - ], - [ - "view_subjectfilter", - "recruitment", - "subjectfilter" - ], [ "add_study", "studies", diff --git a/castellum/studies/templates/studies/filtergroup_advanced.html b/castellum/studies/templates/studies/filtergroup_advanced.html index 220518cb8..1dc498cdf 100644 --- a/castellum/studies/templates/studies/filtergroup_advanced.html +++ b/castellum/studies/templates/studies/filtergroup_advanced.html @@ -16,7 +16,6 @@
    - {% has_perm 'recruitment.change_subjectfilter' user study as can_change_subjectfilter %} {% for group in object_list %}
    @@ -45,35 +44,31 @@ {% endwith %}
    - {% if can_change_subjectfilter %} - {% if study.status != study.EDIT %} - {% trans "Duplicate" %} - {% trans "View" %} - {% trans "Delete" %} - {% else %} -
    - {% csrf_token %} - -
    - {% trans "Edit" %} - {% trans "Delete" %} - {% endif %} + {% if study.status != study.EDIT %} + {% trans "Duplicate" %} + {% trans "View" %} + {% trans "Delete" %} + {% else %} +
    + {% csrf_token %} + +
    + {% trans "Edit" %} + {% trans "Delete" %} {% endif %}
    {% endfor %} - {% if can_change_subjectfilter %} -
    - {% if study.status != study.EDIT %} - - {% else %} - {% csrf_token %} - - {% endif %} -
    - {% endif %} +
    + {% if study.status != study.EDIT %} + + {% else %} + {% csrf_token %} + + {% endif %} +
    {% endblock %} diff --git a/castellum/studies/templates/studies/study_recruitmentsettings_base.html b/castellum/studies/templates/studies/study_recruitmentsettings_base.html index 34a948739..8bd4b3f1f 100644 --- a/castellum/studies/templates/studies/study_recruitmentsettings_base.html +++ b/castellum/studies/templates/studies/study_recruitmentsettings_base.html @@ -9,18 +9,15 @@
    {% trans 'General' %} - {% has_perm 'recruitment.change_subjectfilter' user study as can_change_subjectfilter %} - {% if can_change_subjectfilter %} - {% has_privacy_level study.get_filter_max_privacy_level user as sufficient_privacy_level %} - {% if sufficient_privacy_level %} - - {% trans 'Filters' %} - - {% else %} - - {% endif %} + {% has_privacy_level study.get_filter_max_privacy_level user as sufficient_privacy_level %} + {% if sufficient_privacy_level %} + + {% trans 'Filters' %} + + {% else %} + {% endif %} {% trans 'Excluded studies' %} diff --git a/castellum/studies/views/members.py b/castellum/studies/views/members.py index e45612adf..eaf20546a 100644 --- a/castellum/studies/views/members.py +++ b/castellum/studies/views/members.py @@ -75,7 +75,7 @@ class StudyMembersView(StudyMixin, PermissionRequiredMixin, SingleObjectMixin, F max_privacy_level = self.object.get_filter_max_privacy_level() for user in self.object.members.all(): - if user.has_perm('recruitment.view_subjectfilter', obj=self.object): + if user.has_perm('studies.change_study', obj=self.object): if user.get_privacy_level() < max_privacy_level: yield user.username diff --git a/castellum/studies/views/subjectfilters.py b/castellum/studies/views/subjectfilters.py index bac575983..afae320c4 100644 --- a/castellum/studies/views/subjectfilters.py +++ b/castellum/studies/views/subjectfilters.py @@ -88,7 +88,7 @@ class FilterMixin(StudyMixin, PermissionRequiredMixin, CustomFilterMixin): class FilterGroupListView(FilterMixin, ListView): model = SubjectFilterGroup template_name = 'studies/filtergroup_advanced.html' - permission_required = 'recruitment.view_subjectfilter' + permission_required = 'studies.change_study' def get_queryset(self): qs = super().get_queryset() @@ -120,7 +120,7 @@ class FilterGroupListView(FilterMixin, ListView): class FilterGroupCreateView(FilterMixin, View): - permission_required = 'recruitment.change_subjectfilter' + permission_required = 'studies.change_study' study_status = [Study.EDIT] def post(self, *args, **kwargs): @@ -132,7 +132,7 @@ class FilterGroupUpdateView(FilterMixin, ReadonlyMixin, UpdateView): model = SubjectFilterGroup fields = [] template_name = "studies/filtergroup.html" - permission_required = 'recruitment.change_subjectfilter' + permission_required = 'studies.change_study' def get_object(self): return get_object_or_404(SubjectFilterGroup, study=self.study, pk=self.kwargs['pk']) @@ -175,7 +175,7 @@ class FilterGroupUpdateView(FilterMixin, ReadonlyMixin, UpdateView): def get_inaccessible_attributedescriptions(self): min_privacy_level = 2 for member in self.study.members.all(): - if member.has_perm('recruitment.view_subjectfilter', obj=self.study): + if member.has_perm('studies.change_study', obj=self.study): privacy_level = member.get_privacy_level(obj=self.study) if privacy_level < min_privacy_level: min_privacy_level = privacy_level @@ -214,7 +214,7 @@ class FilterGroupUpdateView(FilterMixin, ReadonlyMixin, UpdateView): class FilterGroupDeleteView(FilterMixin, DeleteView): model = SubjectFilterGroup template_name = 'studies/filtergroup_confirm_delete.html' - permission_required = 'recruitment.change_subjectfilter' + permission_required = 'studies.change_study' study_status = [Study.EDIT] def get_object(self): @@ -225,7 +225,7 @@ class FilterGroupDeleteView(FilterMixin, DeleteView): class FilterGroupDuplicateView(FilterMixin, View): - permission_required = 'recruitment.change_subjectfilter' + permission_required = 'studies.change_study' study_status = [Study.EDIT] def post(self, request, study_pk, pk): -- GitLab From e69246d530c983fd5942edf80fd2af6f368e5d06 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 17:09:45 +0200 Subject: [PATCH 06/15] use change_study instead of add_study --- castellum/castellum_auth/fixtures/groups.json | 5 ----- castellum/studies/templates/studies/study_base.html | 2 +- castellum/studies/templates/studies/study_list.html | 2 +- castellum/studies/views/studies.py | 4 ++-- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index 2e0a18460..dbdc817d0 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -5,11 +5,6 @@ "fields": { "name": "Study coordinator", "permissions": [ - [ - "add_study", - "studies", - "study" - ], [ "change_study", "studies", diff --git a/castellum/studies/templates/studies/study_base.html b/castellum/studies/templates/studies/study_base.html index 0b72b4205..48c9f6bb6 100644 --- a/castellum/studies/templates/studies/study_base.html +++ b/castellum/studies/templates/studies/study_base.html @@ -15,7 +15,7 @@

    {{ study|verbose_name:'contact_person' }}: {{ study.contact_person }}

    - {% has_perm 'studies.add_study' user as can_add_study %} + {% has_perm 'studies.change_study' user as can_add_study %} {% has_perm 'studies.access_study' user study as can_access_study %} {% has_perm 'studies.change_study' user study as can_change_study %} {% has_perm 'studies.delete_study' user study as can_delete_study %} diff --git a/castellum/studies/templates/studies/study_list.html b/castellum/studies/templates/studies/study_list.html index 4edabadf2..85d77cc56 100644 --- a/castellum/studies/templates/studies/study_list.html +++ b/castellum/studies/templates/studies/study_list.html @@ -117,7 +117,7 @@ {% endif %}
    - {% has_perm 'studies.add_study' user as can_add_study %} + {% has_perm 'studies.change_study' user as can_add_study %} {% if can_add_study %} {% get_enable_study_export as enable_export %} {% if enable_export %} diff --git a/castellum/studies/views/studies.py b/castellum/studies/views/studies.py index 58bb2241a..c81ef9d7c 100644 --- a/castellum/studies/views/studies.py +++ b/castellum/studies/views/studies.py @@ -154,7 +154,7 @@ class StudyCreateView(PermissionRequiredMixin, CreateView): 'min_subject_count', 'is_onetime_invitation', ] - permission_required = 'studies.add_study' + permission_required = 'studies.change_study' def form_valid(self, form): response = super().form_valid(form) @@ -295,7 +295,7 @@ class StudyFinishRecruitmentView(StudyMixin, PermissionRequiredMixin, View): class StudyImportView(PermissionRequiredMixin, FormView): - permission_required = 'studies.add_study' + permission_required = 'studies.change_study' template_name = 'studies/study_import.html' form_class = ImportForm -- GitLab From 5b30d059db3dd0ff76a269b857052a8cbfd18ad5 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 16:57:01 +0200 Subject: [PATCH 07/15] use change_subject instead of change_contact|attributeset --- castellum/castellum_auth/fixtures/groups.json | 10 ---------- castellum/contacts/mixins.py | 2 +- .../templates/execution/participation_detail.html | 12 ++---------- castellum/recruitment/mixins.py | 2 +- .../recruitment/templates/recruitment/contact.html | 10 +--------- .../subjects/templates/subjects/subject_base.html | 12 ++---------- 6 files changed, 7 insertions(+), 41 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index dbdc817d0..190f6fd8f 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -34,21 +34,11 @@ "contacts", "contact" ], - [ - "change_contact", - "contacts", - "contact" - ], [ "view_contact", "contacts", "contact" ], - [ - "change_attributeset", - "recruitment", - "attributeset" - ], [ "view_attributeset", "recruitment", diff --git a/castellum/contacts/mixins.py b/castellum/contacts/mixins.py index 59e36ce09..dab5a4243 100644 --- a/castellum/contacts/mixins.py +++ b/castellum/contacts/mixins.py @@ -30,7 +30,7 @@ from .models import Contact class BaseContactUpdateView(PermissionRequiredMixin, UpdateView): model = Contact form_class = ContactForm - permission_required = 'contacts.change_contact' + permission_required = 'subjects.change_subject' def get_form_kwargs(self): kwargs = super().get_form_kwargs() diff --git a/castellum/execution/templates/execution/participation_detail.html b/castellum/execution/templates/execution/participation_detail.html index 4f8350baa..6d034fe3d 100644 --- a/castellum/execution/templates/execution/participation_detail.html +++ b/castellum/execution/templates/execution/participation_detail.html @@ -41,23 +41,15 @@ {% endfor %} - {% has_perm 'contacts.change_contact' user study as can_change_contact %} - {% if can_change_contact %} + {% has_perm 'subjects.change_subject' user study as can_change_subject %} + {% if can_change_subject %} {% if not subject.contact.is_complete %} {% endif %} {% trans 'Edit contact data' %} - {% endif %} - - {% has_perm 'recruitment.change_attributeset' user study as can_change_attributeset %} - {% if can_change_attributeset %} {% trans 'Edit attributes' %} - {% endif %} - - {% has_perm 'subjects.change_subject' user study as can_change_subject %} - {% if can_change_subject %} {% if subject.consent.document.is_deprecated or subject.has_consent_from_before_full_age %} diff --git a/castellum/recruitment/mixins.py b/castellum/recruitment/mixins.py index 6a4ff7b0a..f83675348 100644 --- a/castellum/recruitment/mixins.py +++ b/castellum/recruitment/mixins.py @@ -113,7 +113,7 @@ class ParticipationMixin(StudyMixin, SubjectMixin): class BaseAttributeSetUpdateView(PermissionRequiredMixin, UpdateView): model = AttributeSet - permission_required = 'recruitment.change_attributeset' + permission_required = 'subjects.change_subject' def get_form_class(self): return AttributeSetForm.factory(self.request.user) diff --git a/castellum/recruitment/templates/recruitment/contact.html b/castellum/recruitment/templates/recruitment/contact.html index cdfee8be0..3697a4350 100644 --- a/castellum/recruitment/templates/recruitment/contact.html +++ b/castellum/recruitment/templates/recruitment/contact.html @@ -90,7 +90,7 @@ - {% has_perm 'contacts.change_contact' user study as can_change_contact %} + {% has_perm 'subjects.change_subject' user study as can_change_subject %} {% if can_change_contact %} {% if not subject.contact.is_complete %} @@ -98,15 +98,7 @@ {% endif %} {% trans 'Edit contact data' %} - {% endif %} - - {% has_perm 'recruitment.change_attributeset' user study as can_change_attributeset %} - {% if can_change_attributeset %} {% trans 'Edit attributes' %} - {% endif %} - - {% has_perm 'subjects.change_subject' user study as can_change_subject %} - {% if can_change_subject %} {% if subject.consent.document.is_deprecated or subject.has_consent_from_before_full_age %} diff --git a/castellum/subjects/templates/subjects/subject_base.html b/castellum/subjects/templates/subjects/subject_base.html index eb16daa98..8809ed0f6 100644 --- a/castellum/subjects/templates/subjects/subject_base.html +++ b/castellum/subjects/templates/subjects/subject_base.html @@ -22,8 +22,8 @@ - {% has_perm 'contacts.change_contact' user as can_change_contact %} - {% if can_change_contact %} + {% has_perm 'subjects.change_subject' user as can_change_subject %} + {% if can_change_subject %} - {% endif %} - - {% has_perm 'recruitment.change_attributeset' user as can_change_attributeset %} - {% if can_change_attributeset %} - {% endif %} - - {% has_perm 'subjects.change_subject' user as can_change_subject %} - {% if can_change_subject %}
    - {% has_perm 'recruitment.search_execution' user as can_search_execution %} - {% if can_search_execution %} + {% has_perm 'recruitment.view_current_appointments' user as can_view_current_appointments %} + {% if can_view_current_appointments %}
    diff --git a/tests/conftest.py b/tests/conftest.py index d1770abe7..99d9cb2c2 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -56,7 +56,7 @@ def create_user(group_name): user.user_permissions.add(Permission.objects.get(codename='privacy_level_1')) user.user_permissions.remove(Permission.objects.get(codename='privacy_level_2')) user.user_permissions.remove(Permission.objects.get(codename='access_study')) - user.user_permissions.remove(Permission.objects.get(codename='search_execution')) + user.user_permissions.remove(Permission.objects.get(codename='search_participations')) return user -- GitLab From d99397753eb58b99ed3cd5b88f74677fe3932a73 Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 17:10:55 +0200 Subject: [PATCH 12/15] rm unused add_attributeset --- castellum/castellum_auth/fixtures/groups.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index 9f1445888..3eb69a4e3 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -34,11 +34,6 @@ "subjects", "subject" ], - [ - "view_attributeset", - "recruitment", - "attributeset" - ], [ "change_subject", "subjects", -- GitLab From cada8da16661ae21d7eaccc75bef79715b93b65e Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Tue, 21 Jul 2020 18:24:44 +0200 Subject: [PATCH 13/15] add delete_subject permission check in data protection dashboard --- .../templates/data_protection/index.html | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/castellum/data_protection/templates/data_protection/index.html b/castellum/data_protection/templates/data_protection/index.html index deeab7994..ea0d1381f 100644 --- a/castellum/data_protection/templates/data_protection/index.html +++ b/castellum/data_protection/templates/data_protection/index.html @@ -1,5 +1,5 @@ {% extends "base_with_breadcrumbs.html" %} -{% load i18n %} +{% load i18n auth %} {% block title %}{% trans 'Data protection dashboard' %} · {{ block.super }}{% endblock %} @@ -11,12 +11,15 @@

    {% trans 'Export requested' %}

    {% include 'data_protection/__subject_list.html' with subjects=export_requested missing=export_requested_missing %} -

    {% trans 'To be deleted' %}

    - {% include 'data_protection/__subject_list.html' with subjects=to_be_deleted missing=to_be_deleted_missing %} + {% has_perm 'subjects.delete_subject' user as can_delete_subject %} + {% if can_delete_subject %} +

    {% trans 'To be deleted' %}

    + {% include 'data_protection/__subject_list.html' with subjects=to_be_deleted missing=to_be_deleted_missing %} -

    {% trans 'No legal basis' %}

    - {% include 'data_protection/__subject_list.html' with subjects=no_legal_basis missing=no_legal_basis_missing %} +

    {% trans 'No legal basis' %}

    + {% include 'data_protection/__subject_list.html' with subjects=no_legal_basis missing=no_legal_basis_missing %} -

    {% trans 'Unreachable' %}

    - {% include 'data_protection/__subject_list.html' with subjects=unreachable missing=unreachable_missing %} +

    {% trans 'Unreachable' %}

    + {% include 'data_protection/__subject_list.html' with subjects=unreachable missing=unreachable_missing %} + {% endif %} {% endblock %} -- GitLab From bc3fe3f0840a4817d1fd4c3d9d7c7dd31303b4fc Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Wed, 22 Jul 2020 11:05:03 +0200 Subject: [PATCH 14/15] rm conduct_study from data protection coordinator --- castellum/castellum_auth/fixtures/groups.json | 5 ----- tests/execution/views/test_views.py | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index 3eb69a4e3..7f87edd59 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -86,11 +86,6 @@ "subjects", "subject" ], - [ - "conduct_study", - "recruitment", - "participation" - ], [ "export_subject", "subjects", diff --git a/tests/execution/views/test_views.py b/tests/execution/views/test_views.py index e38c5ec8e..bbd309a2f 100644 --- a/tests/execution/views/test_views.py +++ b/tests/execution/views/test_views.py @@ -12,7 +12,7 @@ from castellum.studies.models import StudyMembership pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), pytest.param('subject_manager', marks=pytest.mark.xfail(strict=True)), - 'data_protection_coordinator', + pytest.param('data_protection_coordinator', marks=pytest.mark.xfail(strict=True)), ]) def test_study_detail_view(request, client, user_fixture, study_in_execution_status): user = request.getfixturevalue(user_fixture) @@ -31,7 +31,7 @@ def test_study_detail_view(request, client, user_fixture, study_in_execution_sta pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), pytest.param('subject_manager', marks=pytest.mark.xfail(strict=True)), - 'data_protection_coordinator', + pytest.param('data_protection_coordinator', marks=pytest.mark.xfail(strict=True)), ]) def test_participation_detail_view_invited( request, client, user_fixture, contact, study_in_execution_status -- GitLab From 6cb70eee203e34517f2a9a5e8c833b71d646acca Mon Sep 17 00:00:00 2001 From: Tobias Bengfort Date: Wed, 22 Jul 2020 11:05:12 +0200 Subject: [PATCH 15/15] rm view_subject from recruiter --- castellum/castellum_auth/fixtures/groups.json | 5 ----- tests/subjects/views/test_guardian_search_view.py | 2 +- tests/subjects/views/test_subject_search_view.py | 2 +- tests/subjects/views/test_views.py | 6 +++--- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/castellum/castellum_auth/fixtures/groups.json b/castellum/castellum_auth/fixtures/groups.json index 7f87edd59..bbbe6e544 100644 --- a/castellum/castellum_auth/fixtures/groups.json +++ b/castellum/castellum_auth/fixtures/groups.json @@ -48,11 +48,6 @@ "fields": { "name": "Recruiter", "permissions": [ - [ - "view_subject", - "subjects", - "subject" - ], [ "recruit", "recruitment", diff --git a/tests/subjects/views/test_guardian_search_view.py b/tests/subjects/views/test_guardian_search_view.py index 55c44e761..ddc751b70 100644 --- a/tests/subjects/views/test_guardian_search_view.py +++ b/tests/subjects/views/test_guardian_search_view.py @@ -6,7 +6,7 @@ from castellum.contacts.models import Contact @pytest.mark.parametrize('user_fixture', [ pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), - 'recruiter', + pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), 'subject_manager', 'data_protection_coordinator', ]) diff --git a/tests/subjects/views/test_subject_search_view.py b/tests/subjects/views/test_subject_search_view.py index 29cd98491..179ed0415 100644 --- a/tests/subjects/views/test_subject_search_view.py +++ b/tests/subjects/views/test_subject_search_view.py @@ -29,7 +29,7 @@ def test_with_parameters_200(client, user): @pytest.mark.parametrize('user_fixture', [ 'subject_manager', - 'recruiter', + pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), pytest.param('receptionist', marks=pytest.mark.xfail(strict=True)), pytest.param('study_conductor', marks=pytest.mark.xfail(strict=True)), pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), diff --git a/tests/subjects/views/test_views.py b/tests/subjects/views/test_views.py index 93d5db6a4..ddcaaa624 100644 --- a/tests/subjects/views/test_views.py +++ b/tests/subjects/views/test_views.py @@ -8,7 +8,7 @@ from castellum.contacts.models import Contact @pytest.mark.smoketest @pytest.mark.parametrize('user_fixture', [ pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), - 'recruiter', + pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), 'subject_manager', 'data_protection_coordinator', ]) @@ -114,7 +114,7 @@ def test_contact_200(request, client, user_fixture, contact): @pytest.mark.smoketest @pytest.mark.parametrize('user_fixture', [ pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), - 'recruiter', + pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), 'subject_manager', 'data_protection_coordinator', ]) @@ -191,7 +191,7 @@ def test_delete_post(client, user, contact): @pytest.mark.smoketest @pytest.mark.parametrize('user_fixture', [ pytest.param('study_coordinator', marks=pytest.mark.xfail(strict=True)), - 'recruiter', + pytest.param('recruiter', marks=pytest.mark.xfail(strict=True)), 'subject_manager', 'data_protection_coordinator', ]) -- GitLab