diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py index 40c63499..74709c9d 100644 --- a/rowers/rower_rules.py +++ b/rowers/rower_rules.py @@ -243,6 +243,10 @@ rules.add_perm('workout.view_workout',can_view_workout) # replaces checkworkoutu # check if user has view access to session @rules.predicate def can_view_session(user,session): + if session.sessiontype in ['race','indoorrace']: + return True + if user.is_anonymous: + return False # session manager can view session if user == session.manager: return True @@ -258,7 +262,20 @@ def can_view_session(user,session): return False +@rules.predicate +def can_change_session(user,session): + if user.is_anonymous: + return False + # session part of a race should not be changed through the session interface + if session.sessiontype in ['race','indoorrace']: + return False + if user == session.manager: + return True + + return False + rules.add_perm('plannedsession.view_session',can_view_session) +rules.add_perm('plannedsession.change_session',can_change_session) # checkaccessplanuser (models.py) # getrequestrower, getrequestplanrower diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index cb0ca2d2..60b02cbd 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -21,7 +21,7 @@ from rowers.plannedsessions import ( from rowers import c2stuff, runkeeperstuff from rowers.c2stuff import c2_open from rowers.runkeeperstuff import runkeeper_open -from rowers.rower_rules import is_coach_user, is_workout_user +from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember from rowers.mytypes import otwtypes from rowers.utils import NoTokenError @@ -430,7 +430,7 @@ def get_field_id(id,s,form): from rowers.models import Rower,Team,TrainingPlan,TrainingTarget -from rowers.views import ispromember + @register.filter def is_promember(user): return ispromember(user) @@ -440,10 +440,10 @@ def is_manager(user): r = Rower.objects.get(user=user) return 'coach' in r.rowerplan -from rowers.views import hasplannedsessions + @register.filter def is_planmember(user): - return hasplannedsessions(user) + return isplanmember(user) @register.filter def get_age(r): diff --git a/rowers/urls.py b/rowers/urls.py index b8924a1a..b8c65fb6 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -635,9 +635,9 @@ urlpatterns = [ re_path(r'^sessions/teamcreate/team/$', views.plannedsession_teamcreate_view, name='plannedsession_teamcreate_view'), - re_path(r'^sessions/teamedit/(?P\d+)/$',views.plannedsession_teamedit_view, + re_path(r'^sessions/teamedit/(?P\d+)/$',views.plannedsession_teamedit_view, name='plannedsession_teamedit_view'), - re_path(r'^sessions/teamedit/(?P\d+)/user/(?P\d+)/$', + re_path(r'^sessions/teamedit/(?P\d+)/user/(?P\d+)/$', views.plannedsession_teamedit_view, name='plannedsession_teamedit_view'), re_path(r'^sessions/create/$',views.plannedsession_create_view, diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 4cf62a9e..d7792db5 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -1329,7 +1329,7 @@ def planrequired_view(request): return HttpResponseRedirect(reverse('paidplans')) -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def fitnessmetric_view(request,id=0,mode='rower', diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index 5b7b76d1..c5c6d9ac 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -5,27 +5,11 @@ from __future__ import unicode_literals from rowers.views.statements import * -@login_required() +@login_required +@permission_required('plannedsession.view_session',fn=get_session_by_pk,raise_exception=True) def plannedsession_comment_view(request,id=0,userid=0): r = getrequestplanrower(request,userid=userid) - - try: - ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: - raise Http404("Planned Session does not exist") - - m = ps.manager - mm = Rower.objects.get(user=m) - - if ps.manager != request.user and ps.sessiontype not in ['race','indoorrace']: - if r.rowerplan == 'coach' and r not in ps.rower.all(): - teams = Team.objects.filter(manager=request.user) - members = Rower.objects.filter(team__in=teams).distinct() - teamusers = [m.user for m in members] - if ps.manager not in teamusers: - raise PermissionDenied("You do not have access to this session") - elif r not in ps.rower.all(): - raise PermissionDenied("You do not have access to this session") + ps = get_object_or_404(PlannedSession,pk=id) comments = PlannedSessionComment.objects.filter(plannedsession=ps).order_by("created") @@ -171,7 +155,7 @@ def plannedsession_comment_view(request,id=0,userid=0): }) # Cloning sessions -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_multiclone_view( @@ -322,7 +306,7 @@ def plannedsession_multiclone_view( ) # Individual user creates training for himself -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_create_view(request, @@ -477,7 +461,7 @@ def plannedsession_create_view(request, 'timeperiod':timeperiod, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_multicreate_view(request, @@ -613,7 +597,7 @@ def plannedsession_multicreate_view(request, return render(request,'plannedsession_multicreate.html',context) # Manager creates sessions for entire team -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_teamcreate_view(request, @@ -786,21 +770,16 @@ def plannedsession_teamcreate_view(request, }) # Manager edits sessions for entire team -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) +@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True) def plannedsession_teamedit_view(request, - sessionid=0,userid=0): + id=0,userid=0): r = getrequestplanrower(request,userid=userid) - - try: - ps = PlannedSession.objects.get(id=sessionid) - except PlannedSession.DoesNotExist: - raise Http404("This session doesn't exist") - if not ps.manager == request.user: - raise PermissionDenied("You are not the manager of this session") + ps = get_object_or_404(PlannedSession,pk=id) teams = Team.objects.filter(manager=request.user) teamchoices = [(team.id, team.name) for team in teams] @@ -1402,7 +1381,8 @@ def plannedsessions_manage_view(request,userid=0, # Clone an existing planned session # need clarity on cloning behavior time shift -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True) +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_clone_view(request,id=0,userid=0): @@ -1420,13 +1400,7 @@ def plannedsession_clone_view(request,id=0,userid=0): except IndexError: trainingplan = None - try: - ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: - raise Http404("Planned Session does not exist") - - if ps.manager != request.user: - raise PermissionDenied("You are not allowed to clone this planned session") + ps = get_object_or_404(PlannedSession,pk=id) rowers = ps.rower.all() teams = ps.team.all() @@ -1470,7 +1444,8 @@ def plannedsession_clone_view(request,id=0,userid=0): # Clone an existing planned session # need clarity on cloning behavior time shift -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True) +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_teamclone_view(request,id=0): @@ -1497,13 +1472,7 @@ def plannedsession_teamclone_view(request,id=0): except IndexError: trainingplan = None - try: - ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: - raise Http404("Planned Session does not exist") - - if ps.manager != request.user: - raise PermissionDenied("You are not allowed to clone this planned session") + ps = get_object_or_404(PlannedSession,pk=id) ps.pk = None @@ -1534,7 +1503,8 @@ def plannedsession_teamclone_view(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(hasplannedsessions, login_url="/rowers/paidplans/", +@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True) +@user_passes_test(isplanmember, login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_totemplate_view(request,id=0): @@ -1543,13 +1513,7 @@ def plannedsession_totemplate_view(request,id=0): startdate, enddate = get_dates_timeperiod(request) - try: - ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: - raise Http404("Planned Session does not exist") - - if ps.manager != request.user: - raise PermissionDenied("You can only store your own sessions as a template") + ps = get_object_or_404(PlannedSession,pk=id) ps.pk = None ps.id = None @@ -1567,7 +1531,8 @@ def plannedsession_totemplate_view(request,id=0): return HttpResponseRedirect(url) # Edit an existing planned session -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", +@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True) +@user_passes_test(isplanmember,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_edit_view(request,id=0,userid=0): @@ -1587,16 +1552,7 @@ def plannedsession_edit_view(request,id=0,userid=0): except IndexError: trainingplan = None - try: - ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: - raise Http404("Planned Session does not exist") - - if ps.manager != request.user: - raise PermissionDenied("You are not allowed to edit this planned session") - - if ps.sessiontype in ['race','indoorrace']: - raise PermissionDenied("You are not allowed to edit this planned session because it is a race") + ps = get_object_or_404(PlannedSession,pk=id) if ps.team.all() or ps.rower.all().count()>1: url = reverse(plannedsession_teamedit_view, @@ -1714,16 +1670,12 @@ def plannedsession_detach_view(request,id=0,psid=0): return HttpResponseRedirect(url) @login_required() +@permission_required('plannedsession.view_session',fn=get_session_by_pk,raise_exception=True) def plannedsession_view(request,id=0,userid=0): r = getrequestplanrower(request,userid=userid) - - - try: - ps = PlannedSession.objects.get(id=id) - except PlannedSession.DoesNotExist: - raise Http404("Planned Session does not exist") + ps = get_object_or_404(PlannedSession,pk=id) if ps.sessiontype in ['race','indoorrace']: url = reverse('virtualevent_view', @@ -1740,16 +1692,6 @@ def plannedsession_view(request,id=0,userid=0): m = ps.manager mm = Rower.objects.get(user=m) - if ps.manager != request.user: - if 'coach' in r.rowerplan and r not in ps.rower.all(): - teams = Team.objects.filter(manager=request.user) - members = Rower.objects.filter(team__in=teams).distinct() - teamusers = [m.user for m in members] - if ps.manager not in teamusers: - raise PermissionDenied("You do not have access to this session") - elif r not in ps.rower.all(): - raise PermissionDenied("You do not have access to this session") - resultsdict = get_session_metrics(ps) resultsdict = pd.DataFrame(resultsdict).transpose().to_dict() @@ -1965,7 +1907,7 @@ class PlannedSessionDelete(DeleteView): return obj -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_create_trainingplan(request,userid=0): @@ -2094,7 +2036,7 @@ def rower_create_trainingplan(request,userid=0): 'old_targets':old_targets, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_delete_trainingtarget(request,id=0): @@ -2114,7 +2056,7 @@ def rower_delete_trainingtarget(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_delete_trainingplan(request,id=0): @@ -2328,7 +2270,7 @@ class MacroCycleDelete(DeleteView): return obj -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_trainingplan_execution_view(request, @@ -2418,7 +2360,7 @@ def rower_trainingplan_execution_view(request, ) -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def rower_trainingplan_view(request, @@ -2841,7 +2783,7 @@ class TrainingTargetUpdate(UpdateView): from rowers.utils import allsundays -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def planmesocyclebyweek(request,id=0,userid=0): @@ -2896,7 +2838,7 @@ def planmesocyclebyweek(request,id=0,userid=0): from rowers.utils import allmonths -@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans", +@user_passes_test(isplanmember,login_url="/rowers/paidplans", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def planmacrocyclebymonth(request,id=0,userid=0): diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 5d3a969d..315f4df4 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -40,7 +40,7 @@ from rowers.opaque import encoder from rowers.rower_rules import ( ispromember,is_coach_user,is_team_member,is_rower_team_member, - is_workout_user + is_workout_user,isplanmember, ) from django.shortcuts import render @@ -289,7 +289,6 @@ def get_workout_by_opaqueid(request,id,**kwargs): pk = encoder.decode_hex(id) return get_object_or_404(Workout,pk=pk) - def get_session_by_pk(request,id): return get_object_or_404(PlannedSession,pk=id) @@ -1014,22 +1013,6 @@ def cancreateteam(user): if len(otherteams) >= 1: return False -# Check if a user can create planned sessions -def hasplannedsessions(user): - if not user.is_anonymous: - try: - r = Rower.objects.get(user=user) - except Rower.DoesNotExist: - r = Rower(user=user) - r.save() - - result = user.is_authenticated and (r.rowerplan=='coach' or r.rowerplan=='freecoach' or r.rowerplan=='plan') - if not result and r.plantrialexpires: - result = user.is_authenticated and r.plantrialexpires >= datetime.date.today() - else: - result = False - - return result from rowers.utils import ProcessorCustomerError