From 07acd1f192a09c424d6bef5521bc95f50963492c Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 22 Jan 2020 22:29:45 +0100 Subject: [PATCH] passing a few more tests, fixed some permissions bugs --- rowers/decorators.py | 4 +++ rowers/rower_rules.py | 16 +++++++++++ rowers/tests/.~lock.viewnames.csv# | 1 + rowers/tests/test_permissions2.py | 2 +- rowers/tests/viewnames.csv | 44 +++++++++++++++--------------- rowers/urls.py | 1 + rowers/views/racesviews.py | 1 - rowers/views/statements.py | 3 +- rowers/views/workoutviews.py | 17 ++++++++---- 9 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 rowers/tests/.~lock.viewnames.csv# diff --git a/rowers/decorators.py b/rowers/decorators.py index 4bd1c7a3..78dc7af6 100644 --- a/rowers/decorators.py +++ b/rowers/decorators.py @@ -4,6 +4,7 @@ from __future__ import print_function from __future__ import unicode_literals from django.contrib.auth.decorators import login_required,user_passes_test +from django.urls import reverse from django.http import HttpResponseRedirect from django.core.exceptions import PermissionDenied @@ -29,6 +30,9 @@ def user_passes_test(test_func, message=default_message,login_url=None,redirect_ def decorator(view_func): @wraps(view_func, assigned=available_attrs(view_func)) def _wrapped_view(request, *args, **kwargs): + if request.user.is_anonymous: + url = reverse('login')+'?next='+request.path + return HttpResponseRedirect(url) if not test_func(request.user): messages.error(request, message) return HttpResponseRedirect(login_url) diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py index dd78d76b..93bbdcd7 100644 --- a/rowers/rower_rules.py +++ b/rowers/rower_rules.py @@ -319,6 +319,22 @@ def is_workout_user(user,workout): return is_coach_user(user,workout.user.user) +# check if user is in same team as owner of workout +@rules.predicate +def is_workout_team(user,workout): + if user.is_anonymous: + return False + + try: + r = user.rower + except AttributeError: + return False + + if workout.user == r: + return True + + return is_rower_team_member(user,workout.user) + # check if user can see workout @rules.predicate def can_view_workout(user,workout): diff --git a/rowers/tests/.~lock.viewnames.csv# b/rowers/tests/.~lock.viewnames.csv# new file mode 100644 index 00000000..9775fe7e --- /dev/null +++ b/rowers/tests/.~lock.viewnames.csv# @@ -0,0 +1 @@ +,sander,sander-pc,22.01.2020 22:27,file:///home/sander/.config/libreoffice/4; \ No newline at end of file diff --git a/rowers/tests/test_permissions2.py b/rowers/tests/test_permissions2.py index bc2e6b36..f9ebb810 100644 --- a/rowers/tests/test_permissions2.py +++ b/rowers/tests/test_permissions2.py @@ -393,7 +393,7 @@ class PermissionsViewTests(TestCase): if notuser: falseurlstotest.append(url) elif permissions['userid']: - url = reverse(view,kwargs={'userid':thisuser['user'].id}) + url = reverse(view,kwargs={'userid':memberuser['user'].id}) urlstotest.append(url) url = reverse(view,kwargs={'userid':self.ustrange['user'].id}) diff --git a/rowers/tests/viewnames.csv b/rowers/tests/viewnames.csv index 23abc42c..12dca557 100644 --- a/rowers/tests/viewnames.csv +++ b/rowers/tests/viewnames.csv @@ -1,33 +1,33 @@ ,id,view,function,anonymous,anonymous_response,own,own_response,own_nonperm,member,member_response,member_nonperm,coachee,coachee_response,coachee_nonperm,is_staff,userid,workoutid,dotest -0,0,workouts_summaries_email_view,sends summary excel with workouts list and links to data to user,TRUE,302,basic,200,302,FALSE,404,404,FALSE,404,404,FALSE,FALSE,FALSE,TRUE +0,0,workouts_summaries_email_view,sends summary excel with workouts list and links to data to user,TRUE,302,basic,200,302,FALSE,403,403,FALSE,403,403,FALSE,FALSE,FALSE,TRUE 1,1,rower_update_empower_view,updates old Empower Oarlock files (corrects Power bug),TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE 2,2,agegroupcpview,needs age,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE 3,4,ajax_agegrouprecords,gets age group records from C2 ,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -4,5,fitness_metric_view,updates a person's fitness metric,TRUE,302,basic,302,302,FALSE,404,302,FALSE,404,404,FALSE,FALSE,FALSE,TRUE +4,5,fitness_metric_view,updates a person's fitness metric,TRUE,302,basic,302,302,FALSE,403,302,FALSE,403,403,FALSE,FALSE,FALSE,TRUE 5,6,agegrouprecordview,shows ergo age group records,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -6,7,workouts_view,workouts list,TRUE,302,basic,200,302,basic,200,404,coach,200,404,FALSE,TRUE,FALSE,TRUE +6,7,workouts_view,workouts list,TRUE,302,basic,200,302,basic,200,403,coach,200,403,FALSE,TRUE,FALSE,TRUE 7,8,virtualevents_view,virtual races list,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE 8,9,virtualevent_create_view,create virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE 9,10,indoorvirtualevent_create_view,create indoor virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -10,11,virtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -11,12,indoorvirtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -12,13,virtualevent_view,view virtual race,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -13,14,virtualevent_ranking_view,view ranking,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -14,15,virtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -15,16,indoorvirtualevent_edit_view,edit race,TRUE,303,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE -16,17,virtualevent_register_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -17,18,indoorvirtualevent_register_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -18,19,virtualevent_addboat_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -19,20,virtualevent_withdraw_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -20,21,virtualevent_submit_result_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE -21,22,virtualevent_disqualify_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -22,24,courses_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -23,25,course_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -24,26,addmanual_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -25,27,team_comparison_select,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,TRUE,FALSE -26,28,workouts_join_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE -27,29,workouts_join_select,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE -28,30,user_boxplot_select,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE +10,11,virtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +11,12,indoorvirtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +12,13,virtualevent_view,view virtual race,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +13,14,virtualevent_ranking_view,view ranking,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +14,15,virtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +15,16,indoorvirtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +16,17,virtualevent_register_view,register for race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +17,18,indoorvirtualevent_register_view,register for race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +18,19,virtualevent_addboat_view,add a new boat type,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +19,20,virtualevent_withdraw_view,withdraw,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +20,21,virtualevent_submit_result_view,submit a result,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,TRUE,FALSE +21,22,virtualevent_disqualify_view,disqualify a racer,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE +22,24,courses_view,see race courses,TRUE,200,FALSE,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE +23,25,course_upload_view,upload a new course,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE +24,26,addmanual_view,upload a manual workout,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,TRUE +25,27,team_comparison_select,compare with a team member workout,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,TRUE,TRUE,TRUE +26,28,workouts_join_view,join workouts,TRUE,302,pro,302,302,pro,403,403,coach,302,403,FALSE,TRUE,FALSE,TRUE +27,29,workouts_join_select,select workouts to join,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,TRUE,FALSE,TRUE +28,30,user_boxplot_select,select boxplots,TRUE,302,pro,200,302,pro,403,403,coach,200,302,FALSE,TRUE,FALSE,TRUE 29,31,analysis_new,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE 30,32,user_multiflex_select,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE 31,33,session_jobs_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE diff --git a/rowers/urls.py b/rowers/urls.py index 7ef0a425..dbae602e 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -220,6 +220,7 @@ urlpatterns = [ # re_path(r'^workouts-join-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select, # name='workouts_join_select'), re_path(r'^workouts-join/$',views.workouts_join_view,name='workouts_join_view'), + re_path(r'^workouts-join/user/(?P\d+)$',views.workouts_join_view,name='workouts_join_view'), re_path(r'^workouts-join-select/team/(?P\d+)/$',views.workouts_join_select,name='workouts_join_select'), # re_path(r'^workouts-join-select/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.workouts_join_select,name='workouts_join_select'), re_path(r'^workouts-join-select/$',views.workouts_join_select,name='workouts_join_select'), diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 358afddd..e9c7e3cf 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -7,7 +7,6 @@ from rowers.views.statements import * # List Courses -@login_required() def courses_view(request): r = getrower(request.user) diff --git a/rowers/views/statements.py b/rowers/views/statements.py index e6b43cb3..19deb0cf 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -45,7 +45,7 @@ from rowers.rower_rules import ( can_view_plan,can_change_plan,can_delete_plan, can_view_cycle,can_change_cycle,can_delete_cycle, can_add_workout_member,can_plan_user,is_paid_coach, - can_start_trial, can_start_plantrial,can_plan + can_start_trial, can_start_plantrial,can_plan,is_workout_team ) from django.shortcuts import render @@ -389,6 +389,7 @@ def getrequestrower(request,rowerid=0,userid=0,notpermanent=False): r = getrower(request.user) u = r.user + except Rower.DoesNotExist: raise Http404("Rower doesn't exist") diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index c4ac32c5..376f563e 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -797,8 +797,11 @@ def workout_recalcsummary_view(request,id=0): @user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality", redirect_field_name=None) -def workouts_join_view(request): +@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) +def workouts_join_view(request,userid=0): promember=0 + + r = getrequestrower(request,userid=userid) if not request.user.is_anonymous: r = getrower(request.user) result = request.user.is_authenticated and ispromember(request.user) @@ -1039,6 +1042,7 @@ def video_selectworkout(request,userid=0,teamid=0): }) +@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True) @user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality", redirect_field_name=None) @@ -1047,16 +1051,15 @@ def workouts_join_select(request, enddatestring="", message='', successmessage='', + userid=0, startdate=timezone.now()-datetime.timedelta(days=30), enddate=timezone.now()+datetime.timedelta(days=1), teamid=0): - try: - r = getrower(request.user) - except Rower.DoesNotExist: - raise Http404("Rower doesn't exist") + r = getrequestrower(request,userid=userid) + if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: @@ -1211,6 +1214,7 @@ def team_comparison_select(request, r = getrequestrower(request,userid=userid) requestrower = getrower(request.user) + request.session.pop('ps',None) if 'waterboattype' in request.session: @@ -1338,7 +1342,8 @@ def team_comparison_select(request, if id: firstworkout = get_workout(id) - if not is_workout_user(request.user,firstworkout): + if not is_workout_team(request.user,firstworkout): + raise PermissionDenied("You are not allowed to use this workout") firstworkoutquery = Workout.objects.filter(id=encoder.decode_hex(id))