diff --git a/castellum/contacts/models.py b/castellum/contacts/models.py index afb831efda6216199f3b1625f07071f4c7405fb4..dede59e86771ef148084e7681d64931b2471306a 100644 --- a/castellum/contacts/models.py +++ b/castellum/contacts/models.py @@ -204,7 +204,7 @@ class Contact(TimeStampedModel): return super().save(*args, **kwargs) def get_absolute_url(self): - return reverse('subjects:detail', args=[self.subject.pk]) + return reverse('subjects:detail', args=[self.subject.pk, self.subject.slug]) class Address(models.Model): diff --git a/castellum/data_protection/management/commands/notify_to_be_deleted.py b/castellum/data_protection/management/commands/notify_to_be_deleted.py index ddd69ef211c8c134bcdd7cf7d812f6f1d376af42..01f05fd369a42f01489031cb2eaaabd25396320f 100644 --- a/castellum/data_protection/management/commands/notify_to_be_deleted.py +++ b/castellum/data_protection/management/commands/notify_to_be_deleted.py @@ -37,7 +37,7 @@ def subjects_notify(subjects, base_url): subject.save() count += 1 - url = base_url + reverse('subjects:detail', args=[subject.pk]) + url = base_url + reverse('subjects:detail', args=[subject.pk, subject.slug]) send_mail( settings.CASTELLUM_DELETE_SUBJECT_NOTIFICATION_SUBJECT, settings.CASTELLUM_DELETE_SUBJECT_NOTIFICATION_BODY.format(url=url), diff --git a/castellum/data_protection/templates/data_protection/__subject_list.html b/castellum/data_protection/templates/data_protection/__subject_list.html index 772073bb34f8bd8382bed759f345f818bc2cb90f..c363f83a5d23a3a51523d9721daa12aa83241cd1 100644 --- a/castellum/data_protection/templates/data_protection/__subject_list.html +++ b/castellum/data_protection/templates/data_protection/__subject_list.html @@ -15,7 +15,7 @@ {% endif %}
- {% trans 'Details' %} + {% trans 'Details' %}
{% empty %} diff --git a/castellum/recruitment/models/attributesets.py b/castellum/recruitment/models/attributesets.py index 0e6d2d0676a9b4da169afeda1ea8abc3e45a7c6d..e69017941f25294bf4a15cca4050f17249c5f7ef 100644 --- a/castellum/recruitment/models/attributesets.py +++ b/castellum/recruitment/models/attributesets.py @@ -95,7 +95,7 @@ class AttributeSet(TimeStampedModel): verbose_name_plural = _('Attribute sets') def get_absolute_url(self): - return reverse('subjects:detail', args=[self.subject.pk]) + return reverse('subjects:detail', args=[self.subject.pk, self.subject.slug]) def get_data(self): qs = AttributeDescription.objects.all() diff --git a/castellum/recruitment/templates/recruitment/participation_confirm_delete.html b/castellum/recruitment/templates/recruitment/participation_confirm_delete.html index a0c086aecaad7ec4a3fc6c879b2fe3b509674d11..020b4a80e5ee506987ef60ae8fc35a8a9e470290 100644 --- a/castellum/recruitment/templates/recruitment/participation_confirm_delete.html +++ b/castellum/recruitment/templates/recruitment/participation_confirm_delete.html @@ -15,7 +15,7 @@ {% trans "I have made sure that all external data related to this study participation has been destroyed" %}
- {% trans 'Cancel' %} + {% trans 'Cancel' %}
diff --git a/castellum/recruitment/views.py b/castellum/recruitment/views.py index 09d1a8dbd1031b7ab41873751dd06aeaf24b0c2d..8c6cf3ca5dec9fdb0a8469e771d1b62fb85f0099 100644 --- a/castellum/recruitment/views.py +++ b/castellum/recruitment/views.py @@ -317,7 +317,8 @@ class ContactView(ParticipationMixin, PermissionRequiredMixin, UpdateView): def get_success_url(self): context = self.request.GET.get('context') if context == 'subjects:participation-list': - return reverse(context, args=[self.object.subject.pk]) + subject = self.object.subject + return reverse(context, args=[subject.pk, subject.slug]) else: return reverse('recruitment:recruitment-open', args=[self.object.study.pk]) diff --git a/castellum/subjects/migrations/0018_subject_slug.py b/castellum/subjects/migrations/0018_subject_slug.py new file mode 100644 index 0000000000000000000000000000000000000000..0532698ccb1149359c93ae18df63de087b946769 --- /dev/null +++ b/castellum/subjects/migrations/0018_subject_slug.py @@ -0,0 +1,19 @@ +# Generated by Django 3.0.8 on 2020-08-04 11:23 + +import castellum.subjects.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('subjects', '0017_refactor_permissions'), + ] + + operations = [ + migrations.AddField( + model_name='subject', + name='slug', + field=models.CharField(default=castellum.subjects.models.generate_slug, max_length=6, verbose_name='Slug'), + ), + ] diff --git a/castellum/subjects/mixins.py b/castellum/subjects/mixins.py index d0be11792c13f664f19dda6a3e5c0915aa3371c1..ffba589fb26459967c2492b73f5c766488fbca99 100644 --- a/castellum/subjects/mixins.py +++ b/castellum/subjects/mixins.py @@ -76,7 +76,7 @@ class BaseDataProtectionUpdateView(PermissionRequiredMixin, UpdateView): if settings.CASTELLUM_DELETE_NOTIFICATION_TO: old = Subject.objects.get(pk=self.object.pk) if self.object.export_requested and not old.export_requested: - rel = reverse('subjects:detail', args=[self.object.pk]) + rel = reverse('subjects:detail', args=[self.object.pk, self.object.slug]) url = self.request.build_absolute_uri(rel) self.object.to_be_deleted_notified = send_mail( @@ -87,7 +87,7 @@ class BaseDataProtectionUpdateView(PermissionRequiredMixin, UpdateView): ) if self.object.to_be_deleted and not self.object.to_be_deleted_notified: - rel = reverse('subjects:detail', args=[self.object.pk]) + rel = reverse('subjects:detail', args=[self.object.pk, self.object.slug]) url = self.request.build_absolute_uri(rel) self.object.to_be_deleted_notified = send_mail( diff --git a/castellum/subjects/models.py b/castellum/subjects/models.py index 727bb310192dc2183b9d9ac50aa750958211f7f6..eefcf3df3fe9064018225732f9e24d9c612d05bd 100644 --- a/castellum/subjects/models.py +++ b/castellum/subjects/models.py @@ -24,6 +24,7 @@ import datetime from django.conf import settings from django.db import models from django.utils import timezone +from django.utils.crypto import get_random_string from django.utils.functional import cached_property from django.utils.translation import gettext_lazy as _ @@ -34,6 +35,10 @@ from castellum.utils.fields import RestrictedFileField from castellum.utils.models import TimeStampedModel +def generate_slug(): + return get_random_string(6) + + class TimeSlot(models.Model): hour = models.PositiveSmallIntegerField(_('hour')) @@ -73,6 +78,8 @@ class SubjectManager(models.Manager): class Subject(TimeStampedModel): + slug = models.CharField(_('Slug'), max_length=6, default=generate_slug) + privacy_level = models.PositiveIntegerField( _('Privacy level'), default=0, diff --git a/castellum/subjects/templates/subjects/maintenance_attributes.html b/castellum/subjects/templates/subjects/maintenance_attributes.html index 4c05e74df985aaf84fcaa5e8669ae7f090acba14..639b6694bdd0c06190c9564c6bae79abae61131b 100644 --- a/castellum/subjects/templates/subjects/maintenance_attributes.html +++ b/castellum/subjects/templates/subjects/maintenance_attributes.html @@ -22,7 +22,7 @@
{% if can_access %} - {% trans 'Details' %} + {% trans 'Details' %} {% else %} {% endif %} diff --git a/castellum/subjects/templates/subjects/maintenance_consent.html b/castellum/subjects/templates/subjects/maintenance_consent.html index 3ded9176299a106b76a6f959fd0b08e87bda8a5e..49888e8b32c64b6fcf1ee450252307a5ca65688f 100644 --- a/castellum/subjects/templates/subjects/maintenance_consent.html +++ b/castellum/subjects/templates/subjects/maintenance_consent.html @@ -17,7 +17,7 @@
{% if can_access %} - {% trans 'Details' %} + {% trans 'Details' %} {% else %} {% endif %} diff --git a/castellum/subjects/templates/subjects/maintenance_contact.html b/castellum/subjects/templates/subjects/maintenance_contact.html index 52e8863897f0f41c674b59026671215a47bb0039..c75a739146e77ccd6a60254f27239345cbe8e3a3 100644 --- a/castellum/subjects/templates/subjects/maintenance_contact.html +++ b/castellum/subjects/templates/subjects/maintenance_contact.html @@ -17,7 +17,7 @@
{% if can_access %} - {% trans 'Details' %} + {% trans 'Details' %} {% else %} {% endif %} diff --git a/castellum/subjects/templates/subjects/maintenance_showup.html b/castellum/subjects/templates/subjects/maintenance_showup.html index 98cc4f0fbc8c74d990976f1906663f84f4a433bd..db0fdea10b97b19905023f029552b3391af57b8a 100644 --- a/castellum/subjects/templates/subjects/maintenance_showup.html +++ b/castellum/subjects/templates/subjects/maintenance_showup.html @@ -17,7 +17,7 @@
{% if can_access %} - {% trans 'Details' %} + {% trans 'Details' %} {% else %} {% endif %} diff --git a/castellum/subjects/templates/subjects/maintenance_waiting.html b/castellum/subjects/templates/subjects/maintenance_waiting.html index f393eea06d155cab6cd590b85594efa428cc6677..bb757e5ff1e852deb3728ea9286492a8459f80e1 100644 --- a/castellum/subjects/templates/subjects/maintenance_waiting.html +++ b/castellum/subjects/templates/subjects/maintenance_waiting.html @@ -17,7 +17,7 @@
{% if can_access %} - {% trans 'Details' %} + {% trans 'Details' %} {% else %} {% endif %} diff --git a/castellum/subjects/templates/subjects/subject_base.html b/castellum/subjects/templates/subjects/subject_base.html index 8809ed0f6a1921d9acd628a7fd6f5d3509c8682a..74d882d5302cda33562bc3e4269d638c481831c5 100644 --- a/castellum/subjects/templates/subjects/subject_base.html +++ b/castellum/subjects/templates/subjects/subject_base.html @@ -3,7 +3,7 @@ {% block breadcrumbs %} {{ block.super }} - + {% endblock %} {% block header %} @@ -14,7 +14,7 @@
@@ -49,7 +49,7 @@ {% endif %}
- {% trans 'Cancel' %} + {% trans 'Cancel' %}
diff --git a/castellum/subjects/templates/subjects/subject_detail.html b/castellum/subjects/templates/subjects/subject_detail.html index 7455f4d83498d758cd9dd5d134c65dd335c73371..2b3ca7ca791f73941a54fd5576817f087e64322a 100644 --- a/castellum/subjects/templates/subjects/subject_detail.html +++ b/castellum/subjects/templates/subjects/subject_detail.html @@ -17,7 +17,7 @@ {% for c in subject.contact.guardians.all %} {% has_privacy_level c.subject.privacy_level user as can_access %} {% if can_access %} - {{ c }}{% if not forloop.last %},{% endif %} + {{ c }}{% if not forloop.last %},{% endif %} {% else %} {% trans '(access denied)' %}{% if not forloop.last %},{% endif %} {% endif %} @@ -31,7 +31,7 @@ {% for c in subject.contact.guardian_of.all %} {% has_privacy_level c.subject.privacy_level user as can_access %} {% if can_access %} - {{ c }}{% if not forloop.last %},{% endif %} + {{ c }}{% if not forloop.last %},{% endif %} {% else %} {% trans '(access denied)' %}{% if not forloop.last %},{% endif %} {% endif %} @@ -70,7 +70,7 @@ {% if subject.has_legal_basis %} {{ subject|display:'has_consent_or_waiting' }} {% else %} - {% url 'subjects:data-protection' subject.pk as url %} + {% url 'subjects:data-protection' subject.pk subject.slug as url %} {% blocktrans with url=url %}If applicable, set consent status.{% endblocktrans %} {% endif %} @@ -83,7 +83,7 @@ {% if subject.has_legal_basis %} {{ subject|display:'has_study_consent' }} {% else %} - {% url 'subjects:add-to-study' subject.pk as url %} + {% url 'subjects:add-to-study' subject.pk subject.slug as url %} {% blocktrans with url=url %}If applicable, add to a study.{% endblocktrans %} {% endif %} @@ -104,7 +104,7 @@ {% if coverletter_exists %}
- {% trans 'Download cover letter' %} + {% trans 'Download cover letter' %}
{% endif %} {% endblock %} diff --git a/castellum/subjects/templates/subjects/subject_participationlist.html b/castellum/subjects/templates/subjects/subject_participationlist.html index b0fc2ddbb24f1d0257e745e2bd489c5414aa7e5f..0e76fec61a459c66a7d404a22dbdd0dd5b54a71a 100644 --- a/castellum/subjects/templates/subjects/subject_participationlist.html +++ b/castellum/subjects/templates/subjects/subject_participationlist.html @@ -46,10 +46,10 @@
- {% trans 'Add to study' %} + {% trans 'Add to study' %} {% has_perm 'subjects.change_subject' user as can_change_subject %} {% if can_change_subject %} - {% trans 'Add to finished study' %} + {% trans 'Add to finished study' %} {% endif %}
{% endblock %} diff --git a/castellum/subjects/templates/subjects/subject_search.html b/castellum/subjects/templates/subjects/subject_search.html index eac611f904959dd920b77b7aac4cae0176c3d156..f6a9610e55e784ab5f70c8462245e76102caebb5 100644 --- a/castellum/subjects/templates/subjects/subject_search.html +++ b/castellum/subjects/templates/subjects/subject_search.html @@ -79,7 +79,7 @@
{% if can_view_subject %} {% if can_access %} - {% trans 'Details' %} + {% trans 'Details' %} {% else %} {% endif %} diff --git a/castellum/subjects/urls.py b/castellum/subjects/urls.py index 194e66bd88cdb44498a537d672d084e31a03c39f..c194eb8e9d99d0f21edba2b98d42a9132273b3c4 100644 --- a/castellum/subjects/urls.py +++ b/castellum/subjects/urls.py @@ -45,27 +45,35 @@ from .views import SubjectSearchView app_name = 'subjects' urlpatterns = [ path('', SubjectSearchView.as_view(), name='index'), - path('/', SubjectDetailView.as_view(), name='detail'), - path('/delete/', SubjectDeleteView.as_view(), name='delete'), - path('/export/', SubjectExportView.as_view(), name='export'), - path('/contact/', ContactUpdateView.as_view(), name='contact'), - path('/attributes/', AttributeSetUpdateView.as_view(), name='attributeset'), - path('/data-protection/', DataProtectionUpdateView.as_view(), name='data-protection'), - path('/additional-info/', AdditionalInfoUpdateView.as_view(), name='additional-info'), - path('/coverletter.docx', CoverletterView.as_view(), name='coverletter'), + path('//', SubjectDetailView.as_view(), name='detail'), + path('//delete/', SubjectDeleteView.as_view(), name='delete'), + path('//export/', SubjectExportView.as_view(), name='export'), + path('//contact/', ContactUpdateView.as_view(), name='contact'), + path('//attributes/', AttributeSetUpdateView.as_view(), name='attributeset'), path( - '/participations/', + '//data-protection/', + DataProtectionUpdateView.as_view(), + name='data-protection', + ), + path( + '//additional-info/', + AdditionalInfoUpdateView.as_view(), + name='additional-info', + ), + path('//coverletter.docx', CoverletterView.as_view(), name='coverletter'), + path( + '//participations/', ParticipationListView.as_view(), name='participation-list', ), - path('/participations/add/', AddToStudyView.as_view(), name='add-to-study'), + path('//participations/add/', AddToStudyView.as_view(), name='add-to-study'), path( - '/participations/add-finished/', + '//participations/add-finished/', AddToFinishedStudyView.as_view(), name='add-to-finished-study', ), path( - '/participations//delete/', + '//participations//delete/', ParticipationDeleteView.as_view(), name='participation-delete', ), diff --git a/castellum/subjects/views.py b/castellum/subjects/views.py index aa15b9f7a645a62e34b3dcfa3fc46c2e2c55a575..50f9e596f9042adbeef683380ac79b15ad4f87f5 100644 --- a/castellum/subjects/views.py +++ b/castellum/subjects/views.py @@ -158,7 +158,7 @@ class SubjectSearchView(LoginRequiredMixin, FormView): monitoring_logger.info('SubjectData update: {} by {}'.format( contact.subject_id, self.request.user.pk )) - return redirect('subjects:detail', pk=contact.subject.pk) + return redirect('subjects:detail', pk=contact.subject.pk, slug=contact.subject.slug) else: messages.error(request, _( 'Both first and last name must be provided in order to create a subject!' @@ -171,6 +171,7 @@ class SubjectSearchView(LoginRequiredMixin, FormView): class SubjectDetailView(SubjectMixin, PermissionRequiredMixin, DetailView): model = Subject + query_pk_and_slug = True permission_required = 'subjects.view_subject' template_name = 'subjects/subject_detail.html' tab = 'detail' @@ -196,6 +197,7 @@ class SubjectDetailView(SubjectMixin, PermissionRequiredMixin, DetailView): class SubjectDeleteView(SubjectMixin, PermissionRequiredMixin, DeleteView): model = Subject + query_pk_and_slug = True permission_required = 'subjects.delete_subject' tab = 'delete' @@ -227,6 +229,7 @@ class SubjectDeleteView(SubjectMixin, PermissionRequiredMixin, DeleteView): class SubjectExportView(SubjectMixin, PermissionRequiredMixin, DetailView): model = Subject + query_pk_and_slug = True template_name = 'subjects/subject_export.html' permission_required = 'subjects.export_subject' tab = 'export' @@ -267,10 +270,12 @@ class SubjectExportView(SubjectMixin, PermissionRequiredMixin, DetailView): else: self.object.export_requested = datetime.date.today() self.object.save() - return redirect('subjects:export', self.object.pk) + return redirect('subjects:export', self.object.pk, self.object.slug) class SubjectUpdateMixin(SubjectMixin): + query_pk_and_slug = True + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['base_template'] = 'subjects/subject_base.html' @@ -285,39 +290,39 @@ class DataProtectionUpdateView(SubjectUpdateMixin, BaseDataProtectionUpdateView) tab = 'data-protection' def get_success_url(self): - return reverse('subjects:data-protection', args=[self.object.pk]) + return reverse('subjects:data-protection', args=[self.subject.pk, self.subject.slug]) class AdditionalInfoUpdateView(SubjectUpdateMixin, BaseAdditionalInfoUpdateView): tab = 'additional-info' def get_success_url(self): - return reverse('subjects:additional-info', args=[self.object.pk]) + return reverse('subjects:additional-info', args=[self.subject.pk, self.subject.slug]) class ContactUpdateView(SubjectUpdateMixin, BaseContactUpdateView): tab = 'contact' def get_object(self): - subject = get_object_or_404(Subject, pk=self.kwargs['pk']) + subject = get_object_or_404(Subject, pk=self.kwargs['pk'], slug=self.kwargs['slug']) return subject.contact def get_success_url(self): - return reverse('subjects:contact', args=[self.object.subject.pk]) + return reverse('subjects:contact', args=[self.subject.pk, self.subject.slug]) class AttributeSetUpdateView(SubjectUpdateMixin, BaseAttributeSetUpdateView): tab = 'attributeset' def get_object(self): - subject = get_object_or_404(Subject, pk=self.kwargs['pk']) + subject = get_object_or_404(Subject, pk=self.kwargs['pk'], slug=self.kwargs['slug']) attributeset, __ = AttributeSet.objects.get_or_create( subject=subject, defaults={'data': {}} ) return attributeset def get_success_url(self): - return reverse('subjects:attributeset', args=[self.object.subject.pk]) + return reverse('subjects:attributeset', args=[self.subject.pk, self.subject.slug]) class ParticipationListView(SubjectMixin, PermissionRequiredMixin, ListView): @@ -328,7 +333,7 @@ class ParticipationListView(SubjectMixin, PermissionRequiredMixin, ListView): @cached_property def subject(self): - return get_object_or_404(Subject, pk=self.kwargs['pk']) + return get_object_or_404(Subject, pk=self.kwargs['pk'], slug=self.kwargs['slug']) def is_permitted(self, study): return self.request.user.has_perm('studies.access_study', obj=study) and ( @@ -359,12 +364,13 @@ class ParticipationDeleteView(SubjectMixin, PermissionRequiredMixin, DeleteView) permission_required = ['studies.access_study', 'subjects.delete_subject'] def get_object(self): - return get_object_or_404( - Participation, pk=self.kwargs['pk'], subject_id=self.kwargs['subject_pk'] + subject = get_object_or_404( + Subject, pk=self.kwargs['subject_pk'], slug=self.kwargs['subject_slug'] ) + return get_object_or_404(Participation, pk=self.kwargs['pk'], subject=subject) def get_success_url(self): - return reverse('subjects:delete', args=[self.subject.pk]) + return reverse('subjects:delete', args=[self.subject.pk, self.subject.slug]) def delete(self, request, *args, **kwargs): self.object = self.get_object() @@ -376,6 +382,7 @@ class ParticipationDeleteView(SubjectMixin, PermissionRequiredMixin, DeleteView) class AddToStudyView(SubjectMixin, PermissionRequiredMixin, DetailView): model = Subject + query_pk_and_slug = True template_name = 'subjects/subject_add_to_study.html' permission_required = 'subjects.view_subject' tab = 'participations' @@ -448,7 +455,7 @@ class AddToFinishedStudyView(SubjectMixin, PermissionRequiredMixin, DetailView): subject=self.object, study=study, status=Participation.INVITED ) - return redirect('subjects:participation-list', self.object.pk) + return redirect('subjects:participation-list', self.subject.pk, self.subject.slug) class GuardianSearchView(PermissionRequiredMixin, SubjectSearchView): @@ -630,6 +637,7 @@ class MaintenanceShowupView(BaseMaintenanceView): class CoverletterView(SubjectMixin, PermissionRequiredMixin, SingleObjectMixin, View): model = Subject + query_pk_and_slug = True permission_required = 'subjects.view_subject' def get_data(self): diff --git a/tests/subjects/views/test_attributeset_view.py b/tests/subjects/views/test_attributeset_view.py index 480e519a0e118fff8f511782475792e75ee15c4c..2eb354955e59d7ed00a8d5217c72946d6fa55cf4 100644 --- a/tests/subjects/views/test_attributeset_view.py +++ b/tests/subjects/views/test_attributeset_view.py @@ -10,7 +10,7 @@ import pytest def test_update_200(request, client, user_fixture, attributeset, attribute_description): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/attributes/'.format(attributeset.subject.pk) + url = '/subjects/{}/{}/attributes/'.format(attributeset.subject.pk, attributeset.subject.slug) response = client.get(url) assert response.status_code == 200 assert attribute_description.label.encode(response.charset) in response.content @@ -18,7 +18,7 @@ def test_update_200(request, client, user_fixture, attributeset, attribute_descr def test_update_post(client, user, attributeset, attribute_description): client.force_login(user) - url = '/subjects/{}/attributes/'.format(attributeset.subject.pk) + url = '/subjects/{}/{}/attributes/'.format(attributeset.subject.pk, attributeset.subject.slug) response = client.post(url, { 'd1': 1, 'd2': 'de', @@ -37,7 +37,7 @@ def test_update_blocked(client, user, attributeset, attribute_description): attribute_description.save() client.force_login(user) - url = '/subjects/{}/attributes/'.format(attributeset.subject.pk) + url = '/subjects/{}/{}/attributes/'.format(attributeset.subject.pk, attributeset.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -51,7 +51,7 @@ def test_update_blocked_post(client, user, attributeset, attribute_description): attributeset.save() client.force_login(user) - url = '/subjects/{}/attributes/'.format(attributeset.subject.pk) + url = '/subjects/{}/{}/attributes/'.format(attributeset.subject.pk, attributeset.subject.slug) response = client.post(url, { 'd1': 1, 'd2': 'de', diff --git a/tests/subjects/views/test_subject_studies_view.py b/tests/subjects/views/test_subject_studies_view.py index ed9595fe41ef5bbb12958dbe476bbb76bc18cc49..9537bd3aa6699ef8e1b21372eafe0c00e6a21f2e 100644 --- a/tests/subjects/views/test_subject_studies_view.py +++ b/tests/subjects/views/test_subject_studies_view.py @@ -3,14 +3,18 @@ import pytest def test_200_without_attributeset(client, user, contact): client.force_login(user) - response = client.get('/subjects/{}/participations/add/'.format(contact.subject.pk)) + response = client.get('/subjects/{}/{}/participations/add/'.format( + contact.subject.pk, contact.subject.slug + )) assert response.status_code == 200 assert b'No attributes provided' in response.content def test_200_with_attributeset(client, user, contact, attributeset): client.force_login(user) - response = client.get('/subjects/{}/participations/add/'.format(contact.subject.pk)) + response = client.get('/subjects/{}/{}/participations/add/'.format( + contact.subject.pk, contact.subject.slug + )) assert response.status_code == 200 assert b'No matching studies found' in response.content @@ -19,7 +23,9 @@ def test_200_with_attributeset_and_study( client, member, contact, attributeset, study_in_execution_status ): client.force_login(member) - response = client.get('/subjects/{}/participations/add/'.format(contact.subject.pk)) + response = client.get('/subjects/{}/{}/participations/add/'.format( + contact.subject.pk, contact.subject.slug + )) assert response.status_code == 200 assert b'No attributes provided' not in response.content assert b'No matching studies found' not in response.content @@ -28,5 +34,7 @@ def test_200_with_attributeset_and_study( @pytest.mark.smoketest def test_finished_200(client, member, contact): client.force_login(member) - response = client.get('/subjects/{}/participations/add-finished/'.format(contact.subject.pk)) + response = client.get('/subjects/{}/{}/participations/add-finished/'.format( + contact.subject.pk, contact.subject.slug + )) assert response.status_code == 200 diff --git a/tests/subjects/views/test_views.py b/tests/subjects/views/test_views.py index ddcaaa6247e7ee1fcf4a0cc42b1e6fff93997cc7..f482157700628b73d8128803c69c1f86f088e307 100644 --- a/tests/subjects/views/test_views.py +++ b/tests/subjects/views/test_views.py @@ -15,7 +15,7 @@ from castellum.contacts.models import Contact def test_detail_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/'.format(contact.subject.pk) + url = '/subjects/{}/{}/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -23,7 +23,7 @@ def test_detail_200(request, client, user_fixture, contact): @pytest.mark.smoketest def test_detail_with_attributeset_200(client, user, contact, attributeset): client.force_login(user) - url = '/subjects/{}/'.format(contact.subject.pk) + url = '/subjects/{}/{}/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -38,7 +38,7 @@ def test_detail_with_attributeset_200(client, user, contact, attributeset): def test_data_protection_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/data-protection/'.format(contact.subject.pk) + url = '/subjects/{}/{}/data-protection/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -47,7 +47,7 @@ def test_data_protection_post_valid(client, user, contact): client.force_login(user) assert contact.subject.privacy_level == 0 - url = '/subjects/{}/data-protection/'.format(contact.subject.pk) + url = '/subjects/{}/{}/data-protection/'.format(contact.subject.pk, contact.subject.slug) response = client.post(url, { 'privacy_level': 1, }) @@ -60,7 +60,7 @@ def test_data_protection_post_valid(client, user, contact): def test_data_protection_post_invalid_privacy_level(client, user, contact): client.force_login(user) - url = '/subjects/{}/data-protection/'.format(contact.subject.pk) + url = '/subjects/{}/{}/data-protection/'.format(contact.subject.pk, contact.subject.slug) response = client.post(url, { 'privacy_level': 2, }) @@ -71,7 +71,7 @@ def test_data_protection_post_invalid_privacy_level(client, user, contact): def test_data_protection_post_invalid_to_be_deleted_consent(client, user, contact): client.force_login(user) - url = '/subjects/{}/data-protection/'.format(contact.subject.pk) + url = '/subjects/{}/{}/data-protection/'.format(contact.subject.pk, contact.subject.slug) response = client.post(url, { 'privacy_level': 1, 'to_be_deleted': 'on', @@ -91,7 +91,7 @@ def test_data_protection_post_invalid_to_be_deleted_consent(client, user, contac def test_additional_info_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/additional-info/'.format(contact.subject.pk) + url = '/subjects/{}/{}/additional-info/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -106,7 +106,7 @@ def test_additional_info_200(request, client, user_fixture, contact): def test_contact_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/contact/'.format(contact.subject.pk) + url = '/subjects/{}/{}/contact/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -118,10 +118,12 @@ def test_contact_200(request, client, user_fixture, contact): 'subject_manager', 'data_protection_coordinator', ]) -def test_partcipation_list_200(request, client, user_fixture, participation): +def test_participation_list_200(request, client, user_fixture, participation): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/participations/'.format(participation.subject.pk) + url = '/subjects/{}/{}/participations/'.format( + participation.subject.pk, participation.subject.slug + ) response = client.get(url) assert response.status_code == 200 @@ -136,7 +138,7 @@ def test_partcipation_list_200(request, client, user_fixture, participation): def test_export_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/export/'.format(contact.subject.pk) + url = '/subjects/{}/{}/export/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -146,7 +148,7 @@ def test_export_requested(client, user, contact): contact.subject.save() client.force_login(user) - url = '/subjects/{}/export/'.format(contact.subject.pk) + url = '/subjects/{}/{}/export/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 @@ -155,7 +157,7 @@ def test_export_requested(client, user, contact): def test_export_post(client, user, contact): client.force_login(user) - url = '/subjects/{}/export/'.format(contact.subject.pk) + url = '/subjects/{}/{}/export/'.format(contact.subject.pk, contact.subject.slug) client.post(url) del contact.__dict__['subject'] # clear cached_property @@ -176,14 +178,14 @@ def test_export_post(client, user, contact): def test_delete_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/delete/'.format(contact.subject.pk) + url = '/subjects/{}/{}/delete/'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200 def test_delete_post(client, user, contact): client.force_login(user) - url = '/subjects/{}/delete/'.format(contact.subject.pk) + url = '/subjects/{}/{}/delete/'.format(contact.subject.pk, contact.subject.slug) client.post(url) assert not Contact.objects.filter(pk=contact.pk).exists() @@ -198,6 +200,6 @@ def test_delete_post(client, user, contact): def test_coverletter_200(request, client, user_fixture, contact): user = request.getfixturevalue(user_fixture) client.force_login(user) - url = '/subjects/{}/coverletter.docx'.format(contact.subject.pk) + url = '/subjects/{}/{}/coverletter.docx'.format(contact.subject.pk, contact.subject.slug) response = client.get(url) assert response.status_code == 200