From 27c5e151145d0d22450e75f51dd10d267501acef Mon Sep 17 00:00:00 2001 From: Valentin Deniaud Date: Fri, 19 Apr 2019 17:57:44 +0200 Subject: [PATCH 3/4] delegate role permission checking to mellon if possible --- chrono/agendas/models.py | 33 +++++++++++++++++++++++---------- chrono/exceptions.py | 4 ++++ chrono/manager/views.py | 33 +++++++++++++++++++++------------ chrono/urls_utils.py | 7 +++++++ 4 files changed, 55 insertions(+), 22 deletions(-) create mode 100644 chrono/exceptions.py diff --git a/chrono/agendas/models.py b/chrono/agendas/models.py index 3eea87a..fd6a67e 100644 --- a/chrono/agendas/models.py +++ b/chrono/agendas/models.py @@ -35,7 +35,15 @@ from django.utils.translation import ugettext_lazy as _ from jsonfield import JSONField -from ..interval import Intervals +from chrono.exceptions import RoleNotInSession +from chrono.interval import Intervals + + +try: + from mellon.utils import user_has_role +except ImportError: + def user_has_role(request, role_id): + return request.user.groups.filter(id=role_id).exists() AGENDA_KINDS = ( @@ -93,17 +101,22 @@ class Agenda(models.Model): def get_absolute_url(self): return reverse('chrono-manager-agenda-view', kwargs={'pk': self.id}) - def can_be_managed(self, user): - if user.is_staff: + def can_be_managed(self, request): + if request.user.is_staff: return True - group_ids = [x.id for x in user.groups.all()] - return bool(self.edit_role_id in group_ids) + return user_has_role(request, self.edit_role_id) - def can_be_viewed(self, user): - if self.can_be_managed(user): - return True - group_ids = [x.id for x in user.groups.all()] - return bool(self.view_role_id in group_ids) + def can_be_viewed(self, request): + raised_exception = None + try: + if self.can_be_managed(request): + return True + except RoleNotInSession as e: + raised_exception = e + has_role = user_has_role(request, self.view_role_id) + if not has_role and raised_exception: + raise raised_exception + return has_role def get_base_meeting_duration(self): durations = [x.duration for x in MeetingType.objects.filter(agenda=self)] diff --git a/chrono/exceptions.py b/chrono/exceptions.py new file mode 100644 index 0000000..db54d4a --- /dev/null +++ b/chrono/exceptions.py @@ -0,0 +1,4 @@ +try: + from mellon.exceptions import RoleNotInSession +except ImportError: + RoleNotInSession = Exception diff --git a/chrono/manager/views.py b/chrono/manager/views.py index 80a59e4..081869d 100644 --- a/chrono/manager/views.py +++ b/chrono/manager/views.py @@ -35,6 +35,7 @@ from django.views.generic import (DetailView, CreateView, UpdateView, from chrono.agendas.models import (Agenda, Event, MeetingType, TimePeriod, Booking, Desk, TimePeriodException, ICSError, AgendaImportError) +from chrono.exceptions import RoleNotInSession from .forms import (AgendaAddForm, AgendaEditForm, EventForm, NewMeetingTypeForm, MeetingTypeForm, TimePeriodForm, ImportEventsForm, NewDeskForm, DeskForm, TimePeriodExceptionForm, @@ -130,7 +131,7 @@ class AgendaEditView(UpdateView): def get_object(self, queryset=None): obj = super(AgendaEditView, self).get_object(queryset=queryset) - if not obj.can_be_managed(self.request.user): + if not obj.can_be_managed(self.request): raise PermissionDenied() return obj @@ -176,7 +177,7 @@ class AgendaView(DetailView): agenda = Agenda.objects.get(id=kwargs.get('pk')) except Agenda.DoesNotExist: raise Http404() - if not agenda.can_be_viewed(self.request.user): + if not agenda.can_be_viewed(self.request): raise PermissionDenied() if agenda.kind == 'meetings': @@ -206,7 +207,7 @@ class AgendaDateView(object): self.agenda = get_object_or_404(Agenda, id=kwargs.get('pk')) if self.agenda.kind != 'meetings': raise Http404() - if not self.agenda.can_be_viewed(request.user): + if not self.agenda.can_be_viewed(request): raise PermissionDenied() # specify 6am time to get the expected timezone on daylight saving time @@ -443,7 +444,7 @@ class ManagedAgendaMixin(object): self.agenda = Agenda.objects.get(id=kwargs.get('pk')) except Agenda.DoesNotExist: raise Http404() - if not self.agenda.can_be_managed(request.user): + if not self.agenda.can_be_managed(request): raise PermissionDenied() return super(ManagedAgendaMixin, self).dispatch(request, *args, **kwargs) @@ -466,7 +467,7 @@ class ManagedAgendaSubobjectMixin(object): def dispatch(self, request, *args, **kwargs): self.agenda = self.get_object().agenda - if not self.agenda.can_be_managed(request.user): + if not self.agenda.can_be_managed(request): raise PermissionDenied() return super(ManagedAgendaSubobjectMixin, self).dispatch(request, *args, **kwargs) @@ -487,7 +488,7 @@ class ManagedDeskMixin(object): self.desk = Desk.objects.get(id=kwargs.get('pk')) except Desk.DoesNotExist: raise Http404() - if not self.desk.agenda.can_be_managed(request.user): + if not self.desk.agenda.can_be_managed(request): raise PermissionDenied() return super(ManagedDeskMixin, self).dispatch(request, *args, **kwargs) @@ -511,7 +512,7 @@ class ManagedDeskSubobjectMixin(object): def dispatch(self, request, *args, **kwargs): self.desk = self.get_object().desk - if not self.desk.agenda.can_be_managed(request.user): + if not self.desk.agenda.can_be_managed(request): raise PermissionDenied() return super(ManagedDeskSubobjectMixin, self).dispatch(request, *args, **kwargs) @@ -534,11 +535,19 @@ class AgendaSettings(ManagedAgendaMixin, DetailView): self.agenda = Agenda.objects.get(id=kwargs.get('pk')) except Agenda.DoesNotExist: raise Http404() - if not self.agenda.can_be_managed(request.user): - # "events" agendas settings page can be access by user with the - # view permission as there are no other "view" page for this type - # of agenda. - if self.agenda.kind != 'events' or not self.agenda.can_be_viewed(request.user): + # Do something different here as "events" agendas settings page can be + # access by user with the view permission as there are no other "view" + # page for this type of agenda. + raised_exception = None + try: + can_be_managed = self.agenda.can_be_managed(request) + except RoleNotInSession as e: + raised_exception = e + can_be_managed = False + if not can_be_managed: + if self.agenda.kind != 'events' or not self.agenda.can_be_viewed(request): + if raised_exception: + raise raised_exception raise PermissionDenied() return super(DetailView, self).dispatch(request, *args, **kwargs) diff --git a/chrono/urls_utils.py b/chrono/urls_utils.py index 2fc535d..0a9af17 100644 --- a/chrono/urls_utils.py +++ b/chrono/urls_utils.py @@ -23,6 +23,11 @@ from django.db.models import Q from .agendas.models import Agenda +try: + from mellon.utils import check_session_roles +except ImportError: + check_session_roles = None + class DecoratedURLPattern(RegexURLPattern): def resolve(self, *args, **kwargs): @@ -66,5 +71,7 @@ def manager_required(function=None, login_url=None): return False actual_decorator = user_passes_test(check_manager, login_url=login_url) if function: + if check_session_roles: + return check_session_roles(actual_decorator(function)) return actual_decorator(function) return actual_decorator -- 2.20.1