From 79afd29b190b8110b86e601b6e51a8be15758917 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 10 Jan 2020 08:06:18 +0100 Subject: [PATCH] rules first attempt --- rowers/models.py | 43 ++++++++++++++++++- rowers/permissions.py | 2 +- rowers/teams.py | 85 +++++++++++++++++++------------------- rowers/views/statements.py | 2 +- rowers/views/teamviews.py | 74 +++++++++++++++++---------------- rowsandall_app/settings.py | 2 + 6 files changed, 126 insertions(+), 82 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 6d9b7ac9..88b06f95 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -39,6 +39,9 @@ import pandas as pd from dateutil import parser import datetime +import rules +from rules.contrib.models import RulesModel + from rowers.rows import validate_file_extension from collections import OrderedDict from timezonefinder import TimezoneFinder @@ -53,6 +56,37 @@ from rowsandall_app.settings import ( TWEET_CONSUMER_SECRET, ) +# PERMISSIONS + +@rules.predicate +def is_team_manager(user,team): + print('aap') + return team.manager == user + +@rules.predicate +def is_team_member(user,team): + members = Rower.objects.filter(team__in=[team]) + return user in [member.user for member in members] + +@rules.predicate +def is_coach(user): + r = Rower.objects.get(user=user) + return r.rowerplan in ['coach','freecoach'] + +@rules.predicate +def can_view_team(user,team): + # user based + r = Rower.objects.get(user=user) + if r.rowerplan == 'basic' and team.manager.rower.rowerplan != 'coach': + return False + # team is public + if team.private == 'open': + return True + # team is private + return is_team_member(user,team) | is_team_manager(user,team) + +# END PERMISSIONS + tweetapi = twitter.Api(consumer_key=TWEET_CONSUMER_KEY, consumer_secret=TWEET_CONSUMER_SECRET, access_token_key=TWEET_ACCESS_TOKEN_KEY, @@ -331,7 +365,7 @@ def is_not_basic(user): # For future Team functionality @python_2_unicode_compatible -class Team(models.Model): +class Team(RulesModel): choices = ( ('private','private'), ('open','open'), @@ -350,6 +384,13 @@ class Team(models.Model): viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior') + class Meta: + rules_permissions = { + "add": is_coach, + "change": is_team_manager, + "delete": is_team_manager, + "view": can_view_team, + } def __str__(self): return self.name diff --git a/rowers/permissions.py b/rowers/permissions.py index 2d32add8..4950f910 100644 --- a/rowers/permissions.py +++ b/rowers/permissions.py @@ -22,7 +22,7 @@ class IsOwnerOrReadOnly(permissions.BasePermission): return obj.user == request.user class IsOwnerOrNot(permissions.BasePermission): - + def has_object_permission(self, request, view, obj): r = Rower.objects.get(user=request.user) return (obj.user == r) diff --git a/rowers/teams.py b/rowers/teams.py index 4c8ee0a4..2556cf21 100644 --- a/rowers/teams.py +++ b/rowers/teams.py @@ -23,7 +23,7 @@ queuehigh = django_rq.get_queue('low') from rowers.models import ( Rower, Workout, Team, TeamInvite,User,TeamRequest, CoachRequest, CoachOffer, - CoachingGroup + CoachingGroup,is_team_manager,is_team_member,is_coach ) from rowers.tasks import ( @@ -53,14 +53,15 @@ def handle_remove_workouts_team(ws,t): return 1 def handle_add_workouts_team(ws,t): - + for w in ws: w.team.add(t) return 1 def update_team(t,name,manager,private,notes,viewing): - if t.manager != manager: + + if not is_team_manager(t,manager): return (0,'You are not the manager of this team') try: t.name = name @@ -82,7 +83,7 @@ def create_team(name,manager,private='open',notes='',viewing='allmembers'): ts = Team.objects.filter(manager=manager) if len(ts)>=1: return (0,'You need to upgrade to the Coach plan to have more than one team') - + try: t = Team(name=name,manager=manager,notes=notes, private=private,viewing=viewing) @@ -116,7 +117,7 @@ def remove_team(id): def add_coach(coach,rower): # get coaching group - + coachgroup = coach.mycoachgroup if coachgroup is None: coachgroup = CoachingGroup(name=coach.user.first_name) @@ -126,7 +127,7 @@ def add_coach(coach,rower): if get_coach_club_size(coach) invitation.issuedate+timedelta(days=inviteduration): revoke_invite(invitation.team.manager,invitation.id) return (0,'The invitation has expired') - + t = invitation.team result, comment = add_member(t.id,r) if not result: @@ -698,7 +699,7 @@ def process_coachoffer_code(user,code): return result else: send_coachoffer_accepted_email(rekwest) - + rekwest.delete() return result @@ -732,7 +733,7 @@ def send_coachrequest_accepted_email(rekwest): res = myqueue(queuehigh, handle_sendemail_coachrequest_accepted, email,coachname,name) - + def send_coachoffer_accepted_email(rekwest): coachname = rekwest.coach.user.first_name + " " + rekwest.coach.user.last_name @@ -743,5 +744,3 @@ def send_coachoffer_accepted_email(rekwest): res = myqueue(queuehigh, handle_sendemail_coachoffer_accepted, coachemail,coachname,name) - - diff --git a/rowers/views/statements.py b/rowers/views/statements.py index aab50741..a14d41a4 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -240,7 +240,7 @@ from rq import Queue,cancel_job from django.core.cache import cache from django_mailbox.models import Message,Mailbox,MessageAttachment - +from rules.contrib.views import permission_required, objectgetter # Utility to get stroke data in a JSON response class JSONResponse(HttpResponse): diff --git a/rowers/views/teamviews.py b/rowers/views/teamviews.py index 36c6b85b..c767f0d0 100644 --- a/rowers/views/teamviews.py +++ b/rowers/views/teamviews.py @@ -6,7 +6,8 @@ from __future__ import unicode_literals from rowers.views.statements import * -@login_required() +#@login_required() +@permission_required('teams.view_team',fn=objectgetter(Team,'id')) def team_view(request,id=0,userid=0): ismember = 0 hasrequested = 0 @@ -16,25 +17,25 @@ def team_view(request,id=0,userid=0): teams.remove_expired_invites() - + try: t = Team.objects.get(id=id) except Team.DoesNotExist: raise Http404("Team doesn't exist") - if r.rowerplan == 'basic' and t.manager.rower.rowerplan != 'coach': - raise PermissionDenied("You need to be on a Paid Plan to see or join this team") + #if r.rowerplan == 'basic' and t.manager.rower.rowerplan != 'coach': + # raise PermissionDenied("You need to be on a Paid Plan to see or join this team") + - q = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct().exclude(rower__team__name=t.name) mygroups = [request.user.rower.mycoachgroup] q2 = User.objects.filter(rower__isnull=False,rower__coachinggroups__in=mygroups).distinct().exclude(rower__team__name=t.name) - + q = q | q2 - + if request.method == 'POST' and request.user == t.manager and 'email' in request.POST: inviteform = TeamInviteForm(request.POST) - + inviteform.fields['user'].queryset = q if inviteform.is_valid(): cd = inviteform.cleaned_data @@ -59,7 +60,7 @@ def team_view(request,id=0,userid=0): teams.send_team_message(t,message) messages.info(request,'Message was sent to all team members') groupmessageform = TeamMessageForm() - + elif request.user == t.manager: inviteform = TeamInviteForm() inviteform.fields['user'].queryset = q @@ -68,7 +69,7 @@ def team_view(request,id=0,userid=0): inviteform = '' groupmessageform = '' - + members = Rower.objects.filter(team=t).order_by('user__last_name','user__first_name') thisteammyrequests = TeamRequest.objects.filter(team=t,user=request.user) if len(thisteammyrequests): @@ -112,7 +113,7 @@ def team_leaveconfirm_view(request,id=0): raise Http404("Team doesn't exist") myteams, memberteams, otherteams = get_teams(request) - + breadcrumbs = [ { 'url':reverse(rower_teams_view), @@ -144,7 +145,7 @@ def rower_calcdps_view(request): ws = [(w.id,w.csvfilename) for w in Workout.objects.filter(user=r)] res = myqueue(queue,handle_updatedps,r.user.email,ws,debug=False, - emailbounced=r.emailbounced) + emailbounced=r.emailbounced) messages.info(request,"Your workouts are being updated in the background. You will receive email when this is done.") @@ -155,7 +156,7 @@ def rower_calcdps_view(request): def team_leave_view(request,id=0): r = getrower(request.user) teams.remove_member(id,r) - + url = reverse(rower_teams_view) response = HttpResponseRedirect(url) return response @@ -164,7 +165,7 @@ from rowers.forms import TeamInviteCodeForm def get_teams(request): r = Rower.objects.get(user=request.user) - + myteams = Team.objects.filter( manager=request.user).order_by('name') memberteams = Team.objects.filter( @@ -191,7 +192,7 @@ def rower_teams_view(request): messages.error(request,text) else: form = TeamInviteCodeForm() - + r = getrower(request.user) ts = Team.objects.filter(rower=r) @@ -208,7 +209,7 @@ def rower_teams_view(request): mycoachoffers = CoachOffer.objects.filter(coach=r) # user is invited (by coach) coachoffers = CoachOffer.objects.filter(user=r.user) - + # user requests a coach mycoachrequests = CoachRequest.objects.filter(user=r.user) # user is requested to coach @@ -230,7 +231,7 @@ def rower_teams_view(request): potentialcoaches = [c for c in potentialcoaches if c.rower not in invitedcoaches+coaches] potentialcoaches = [c for c in potentialcoaches if teams.get_coach_club_size(c.rower)