From f044f276af103221bdbf6fb77f07d106ffe1f323 Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Tue, 28 Jun 2022 14:49:26 +0200 Subject: [PATCH] agendas: add management role for shared custody (#66671) --- .../migrations/0131_sharedcustodysettings.py | 36 +++++++++++++++++++ chrono/agendas/models.py | 19 ++++++++++ chrono/manager/forms.py | 11 ++++++ .../templates/chrono/manager_home.html | 3 ++ chrono/manager/urls.py | 5 +++ chrono/manager/views.py | 28 ++++++++++++++- chrono/settings.py | 2 ++ tests/manager/test_shared_custody_agenda.py | 32 +++++++++++++++++ tests/settings.py | 2 ++ 9 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 chrono/agendas/migrations/0131_sharedcustodysettings.py diff --git a/chrono/agendas/migrations/0131_sharedcustodysettings.py b/chrono/agendas/migrations/0131_sharedcustodysettings.py new file mode 100644 index 00000000..0ae519d8 --- /dev/null +++ b/chrono/agendas/migrations/0131_sharedcustodysettings.py @@ -0,0 +1,36 @@ +# Generated by Django 2.2.26 on 2022-06-27 16:02 + +import django.db.models.deletion +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '0011_update_proxy_permissions'), + ('agendas', '0130_event_date_range_constraint'), + ] + + operations = [ + migrations.CreateModel( + name='SharedCustodySettings', + fields=[ + ( + 'id', + models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + ( + 'management_role', + models.ForeignKey( + blank=True, + default=None, + null=True, + on_delete=django.db.models.deletion.SET_NULL, + related_name='+', + to='auth.Group', + verbose_name='Management role', + ), + ), + ], + ), + ] diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py index 424931ec..73b2501a 100644 --- a/chrono/agendas/models.py +++ b/chrono/agendas/models.py @@ -3487,3 +3487,22 @@ class SharedCustodyPeriod(models.Model): date_format(self.date_end, 'SHORT_DATE_FORMAT'), ) return '%s, %s' % (self.guardian, exc_repr) + + +class SharedCustodySettings(models.Model): + management_role = models.ForeignKey( + Group, + blank=True, + null=True, + default=None, + related_name='+', + verbose_name=_('Management role'), + on_delete=models.SET_NULL, + ) + + @classmethod + def get_singleton(cls): + try: + return cls.objects.get() + except cls.DoesNotExist: + return cls() diff --git a/chrono/manager/forms.py b/chrono/manager/forms.py index dfb7e6a9..21410f5a 100644 --- a/chrono/manager/forms.py +++ b/chrono/manager/forms.py @@ -57,6 +57,7 @@ from chrono.agendas.models import ( SharedCustodyHolidayRule, SharedCustodyPeriod, SharedCustodyRule, + SharedCustodySettings, Subscription, TimePeriod, TimePeriodException, @@ -1550,3 +1551,13 @@ class SharedCustodyPeriodForm(forms.ModelForm): self.add_error('date_end', _('End date must be greater than start date.')) return cleaned_data + + +class SharedCustodySettingsForm(forms.ModelForm): + management_role = forms.ModelChoiceField( + label=_('Management role'), required=False, queryset=Group.objects.all().order_by('name') + ) + + class Meta: + model = SharedCustodySettings + fields = '__all__' diff --git a/chrono/manager/templates/chrono/manager_home.html b/chrono/manager/templates/chrono/manager_home.html index 78ea9796..5d356746 100644 --- a/chrono/manager/templates/chrono/manager_home.html +++ b/chrono/manager/templates/chrono/manager_home.html @@ -12,6 +12,9 @@
  • {% trans 'Export' %}
  • {% trans 'Events types' %}
  • {% trans 'Check types' %}
  • + {% if shared_custody_enabled %} +
  • {% trans 'Shared custody' %}
  • + {% endif %} {% endif %} {% if has_access_to_unavailability_calendars %}
  • {% trans 'Unavailability calendars' %}
  • diff --git a/chrono/manager/urls.py b/chrono/manager/urls.py index 8e999ea5..49634127 100644 --- a/chrono/manager/urls.py +++ b/chrono/manager/urls.py @@ -400,6 +400,11 @@ urlpatterns = [ views.agenda_import_events_sample_csv, name='chrono-manager-sample-events-csv', ), + url( + r'^shared-custody/settings/$', + views.shared_custody_settings, + name='chrono-manager-shared-custody-settings', + ), url( r'^shared-custody/(?P\d+)/$', views.shared_custody_agenda_view, diff --git a/chrono/manager/views.py b/chrono/manager/views.py index 282abd49..0f4ad4fc 100644 --- a/chrono/manager/views.py +++ b/chrono/manager/views.py @@ -26,6 +26,7 @@ from operator import attrgetter import requests from dateutil.relativedelta import MO, relativedelta +from django.conf import settings from django.contrib import messages from django.core.exceptions import PermissionDenied from django.db import IntegrityError, transaction @@ -80,6 +81,7 @@ from chrono.agendas.models import ( SharedCustodyHolidayRule, SharedCustodyPeriod, SharedCustodyRule, + SharedCustodySettings, TimePeriod, TimePeriodException, TimePeriodExceptionSource, @@ -122,6 +124,7 @@ from .forms import ( SharedCustodyHolidayRuleForm, SharedCustodyPeriodForm, SharedCustodyRuleForm, + SharedCustodySettingsForm, SubscriptionCheckFilterSet, TimePeriodAddForm, TimePeriodExceptionForm, @@ -163,6 +166,7 @@ class HomepageView(ListView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['has_access_to_unavailability_calendars'] = self.has_access_to_unavailability_calendars() + context['shared_custody_enabled'] = settings.SHARED_CUSTODY_ENABLED return context def get(self, request, *args, **kwargs): @@ -3685,7 +3689,10 @@ class SharedCustodyAgendaMixin: return super().dispatch(request, *args, **kwargs) def check_permissions(self, user): - return user.is_staff + if user.is_staff: + return True + management_role = SharedCustodySettings.get_singleton().management_role + return bool(management_role in user.groups.all()) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) @@ -3863,6 +3870,25 @@ class SharedCustodyAgendaDeletePeriodView(SharedCustodyAgendaMixin, DeleteView): shared_custody_agenda_delete_period = SharedCustodyAgendaDeletePeriodView.as_view() +class SharedCustodySettingsView(UpdateView): + title = _('Shared custody settings') + template_name = 'chrono/manager_agenda_form.html' + form_class = SharedCustodySettingsForm + model = SharedCustodySettings + success_url = reverse_lazy('chrono-manager-homepage') + + def dispatch(self, request, *args, **kwargs): + if not request.user.is_staff: + raise PermissionDenied() + return super().dispatch(request, *args, **kwargs) + + def get_object(self): + return SharedCustodySettings.get_singleton() + + +shared_custody_settings = SharedCustodySettingsView.as_view() + + def menu_json(request): if not request.user.is_staff: homepage_view = HomepageView(request=request) diff --git a/chrono/settings.py b/chrono/settings.py index 0ffd2406..2c118413 100644 --- a/chrono/settings.py +++ b/chrono/settings.py @@ -195,6 +195,8 @@ SMS_SENDER = '' REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'chrono.api.utils.exception_handler'} +SHARED_CUSTODY_ENABLED = False + local_settings_file = os.environ.get( 'CHRONO_SETTINGS_FILE', os.path.join(os.path.dirname(__file__), 'local_settings.py') ) diff --git a/tests/manager/test_shared_custody_agenda.py b/tests/manager/test_shared_custody_agenda.py index b2ab2a54..97723cae 100644 --- a/tests/manager/test_shared_custody_agenda.py +++ b/tests/manager/test_shared_custody_agenda.py @@ -286,3 +286,35 @@ def test_shared_custody_agenda_holiday_rules(app, admin_user): resp = app.get('/manage/shared-custody/%s/2022/12/' % agenda.pk) assert 'John Doe (Vacances de Noël)' in resp.text + + +def test_shared_custody_settings_feature_flag(app, admin_user, settings): + settings.SHARED_CUSTODY_ENABLED = False + app = login(app) + resp = app.get('/manage/') + assert 'Shared custody' not in resp.text + + settings.SHARED_CUSTODY_ENABLED = True + resp = app.get('/manage/') + assert 'Shared custody' in resp.text + + +def test_shared_custody_settings_management_role(app, admin_user, manager_user): + father = Person.objects.create(user_external_id='father_id', first_name='John', last_name='Doe') + mother = Person.objects.create(user_external_id='mother_id', first_name='Jane', last_name='Doe') + agenda = SharedCustodyAgenda.objects.create(first_guardian=father, second_guardian=mother) + + app = login(app, username='manager', password='manager') + app.get('/manage/shared-custody/%s/settings/' % agenda.pk, status=403) + + app.reset() + app = login(app) + resp = app.get('/manage/') + resp = resp.click('Shared custody') + resp.form['management_role'] = manager_user.groups.all()[0].pk + resp.form.submit() + + app.reset() + app = login(app, username='manager', password='manager') + resp = app.get('/manage/shared-custody/%s/settings/' % agenda.pk) + assert 'Custody agenda of John Doe and Jane Doe' in resp.text diff --git a/tests/settings.py b/tests/settings.py index c7257967..52a56b75 100644 --- a/tests/settings.py +++ b/tests/settings.py @@ -34,3 +34,5 @@ LEGACY_URLS_MAPPING = {'old.org': 'new.org'} EXCEPTIONS_SOURCES = {} SITE_BASE_URL = 'https://example.com' + +SHARED_CUSTODY_ENABLED = True