diff --git a/rowers/models.py b/rowers/models.py index fd3d419a..d06ab70e 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -941,6 +941,7 @@ class CoachOffer(models.Model): from django.db.models.signals import m2m_changed + def check_teams_on_change(sender, **kwargs): instance = kwargs.pop('instance', None) action = kwargs.pop('action', None) @@ -1282,6 +1283,18 @@ class TrainingTarget(models.Model): return stri +def check_trainingtarget_on_change(sender,**kwargs): + instance = kwargs.pop('instance',None) + action = kwargs.pop('action',None) + pk_set = kwargs.pop('pk_set',None) + if action == 'pre_add': + for id in pk_set: + rower = Rower.objects.get(id=id) + if not can_plan_user(instance.manager.user,rower): + raise ValidationError("You cannot add this rower. Not your coachee") + +m2m_changed.connect(check_trainingtarget_on_change, sender=TrainingTarget.rowers.through) + class TrainingTargetForm(ModelForm): class Meta: model = TrainingTarget @@ -1356,6 +1369,8 @@ class TrainingPlan(models.Model): "Basic user cannot have a training plan" ) + + if self.enddate < self.startdate: startdate = self.startdate enddate = self.enddate @@ -1365,6 +1380,13 @@ class TrainingPlan(models.Model): if not self.enddate <= self.startdate: super(TrainingPlan,self).save(*args, **kwargs) + # only add athletes that are allowed to be added + for rower in self.rowers.all(): + if can_plan_user(manager.user,rower): + self.rowers.add(rower) + else: + self.rowers.remove(rower) + if self.status: otherplans = TrainingPlan.objects.filter( status=True).exclude( @@ -1401,6 +1423,18 @@ class TrainingPlan(models.Model): else: createmacrofillers(self) +def check_trainingplan_on_change(sender, **kwargs): + instance = kwargs.pop('instance',None) + action = kwargs.pop('action',None) + pk_set = kwargs.pop('pk_set',None) + if action == 'pre_add': + for id in pk_set: + rower = Rower.objects.get(id=id) + if not can_plan_user(instance.manager.user,rower): + raise ValidationError("You cannot add this rower. Not your coachee") + +m2m_changed.connect(check_trainingplan_on_change, sender=TrainingPlan.rowers.through) + class TrainingPlanForm(ModelForm): class Meta: diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py index 27b81814..f8edd93f 100644 --- a/rowers/rower_rules.py +++ b/rowers/rower_rules.py @@ -72,7 +72,7 @@ USER permissions """ -# not tested +# used in can_plan_user @rules.predicate def user_is_not_basic(user): if user.rower.rowerplan != 'basic': @@ -156,7 +156,7 @@ def can_add_team(user): @rules.predicate def can_add_plan(user): - return isplanmember(user) + return isplanmember(user) or is_coach(user) @rules.predicate def can_add_workout(user): @@ -189,7 +189,6 @@ def can_add_session(user): # User / Coach relationships (Rower object) -# not tested @rules.predicate def can_plan(user): return user.rower.rowerplan in ['plan','coach','freecoach'] @@ -197,6 +196,9 @@ def can_plan(user): # checks if rower is coach of user @rules.predicate def is_coach_user(usercoach,userrower): + if not is_coach(usercoach): + return False + if usercoach == userrower: return True @@ -221,8 +223,7 @@ def is_rower_team_member(user,rower): if user.rower == rower: return True - # below not tested - teams = user.rower.team.all() + teams = rower.team.all() for team in teams: if team.private == 'open': @@ -247,22 +248,30 @@ def can_add_workout_member(user,rower): # check if user can plan for the rower @rules.predicate def can_plan_user(user,rower): - if not isplanmember(user): + # user must have planning permission + if not can_plan(user): return False - try: - r = user.rower - except AttributeError: - return False - - if rower == r: + # if has planning permission, can always plan for himself + if rower == user.rower: return True - # below not tested - team_managers = [t.manager for t in rower.team.all() and can_plan(t.manager)] - if user_is_not_basic(user): + teams = user.rower.get_managed_teams() + # free coach, plan etc cannot plan for basic + if not is_paid_coach(user) and user_is_not_basic(user): + for t in teams: + if rower in t.rower.all(): + return True + + return user in team_managers + # paying coach can plan for all kinds of rowers + if is_paid_coach(user): + for t in teams: + if rower in t.rower.all(): + return True + return False rules.add_perm('rower.add_plan',can_plan_user) # replaces checkaccessplanuser diff --git a/rowers/tests/test_permissions.py b/rowers/tests/test_permissions.py index b638c9d7..fafe1e8b 100644 --- a/rowers/tests/test_permissions.py +++ b/rowers/tests/test_permissions.py @@ -15,6 +15,86 @@ import rowers.teams as teams import rowers.plannedsessions as plannedsessions from rowers.rower_rules import is_coach_user +@override_settings(TESTING=True) +class PlanningPermissionsCoach(TestCase): + def setUp(self): + self.c = Client() + + self.ucoach = UserFactory() + self.rcoach = Rower.objects.create( + user=self.ucoach, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='coach', + clubsize=10, + ) + self.ucoachpassword = faker.word() + self.ucoach.set_password(self.ucoachpassword) + self.ucoach.save() + + self.ucoachee = UserFactory() + self.rcoachee = Rower.objects.create( + user=self.ucoachee, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='basic' + ) + + self.coachgroup = CoachingGroup.objects.create(name=self.ucoach.first_name) + self.rcoach.mycoachgroup = self.coachgroup + self.rcoach.save() + + self.team = Team.objects.create( + name=faker.word()+'3', + notes=faker.text(), + manager=self.ucoach) + + # coachee is in coach's team + self.rcoachee.team.add(self.team) + + # coachee is coached by coach + self.rcoachee.coachinggroups.add(self.rcoach.mycoachgroup) + self.rcoachee.save() + + self.ugroupmember = UserFactory() + self.rgroupmember = Rower.objects.create( + user=self.ugroupmember, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='basic' + ) + + # groupmember is in coach's team (but not coached) + self.rgroupmember.team.add(self.team) + + + # def test_target(self): + + def test_trainingplan(self): + plan = TrainingPlan( + name='test plan', + manager=self.ucoach.rower, + ) + plan.save() + + # can add self and coachee + plan.rowers.add(self.ucoach.rower) + plan.rowers.add(self.ucoachee.rower) + + # test 1 + athletes = plan.rowers.all() + self.assertTrue(self.ucoach.rower in athletes) + self.assertTrue(self.ucoachee.rower in athletes) + + # can add groupmember if not basic + plan.rowers.add(self.rgroupmember) + athletes = plan.rowers.all() + self.assertTrue(self.rgroupmember in athletes) + + @override_settings(TESTING=True) class PermissionsFreeCoach(TestCase): def setUp(self): @@ -884,6 +964,37 @@ class PermissionsViewTests(TestCase): response = self.c.get(url) self.assertEqual(response.status_code,403) + ## Coach can see list of workouts of athlete + def test_coach_athlete_workout_list(self): + self.rbasic.team.add(self.teamcoach) + print(self.rbasic.team.all()) + print(self.teamcoach) + + login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword) + self.assertTrue(login) + + url = reverse('workouts_view', + kwargs={'rowerid':self.rbasic.id}) + + + + response = self.c.get(url) + print(url,response.status_code) + self.assertEqual(response.status_code,200) + + url = reverse('workouts_view', + kwargs={'userid':self.ubasic.id}) + + response = self.c.get(url) + print(url,response.status_code) + self.assertEqual(response.status_code,200) + + url = reverse('workouts_view') + + response = self.c.get(url) + print(url,response.status_code) + self.assertEqual(response.status_code,200) + ## Self coach can create one group ## Self coach cannot create more than one group def test_plan_groups_create(self): diff --git a/rowers/tests/test_plans.py b/rowers/tests/test_plans.py index 613478da..b593a8d7 100644 --- a/rowers/tests/test_plans.py +++ b/rowers/tests/test_plans.py @@ -5,7 +5,17 @@ from __future__ import unicode_literals #from __future__ import print_function from .statements import * -nu = datetime.datetime.now() +nu = datetime.datetime.now()self.ucoach = UserFactory() +self.rcoach = Rower.objects.create( + user=self.ucoach, + birthdate=faker.profile()['birthdate'], + gdproptin=True,surveydone=True, + gdproptindate=timezone.now(), + rowerplan='coach' +) +self.ucoachpassword = faker.word() +self.uchoach.set_password(self.ucoachpassword) +self.ucoach.save() from rowers.utils import allmonths,allsundays import rowers.plannedsessions as plannedsessions @@ -125,7 +135,6 @@ class TrainingPlanTest(TestCase): for url in urls: if 'planbyweeks' in url and not tested: - print(url) response = self.c.get(url,follow=True) self.assertEqual(response.status_code,200) tested = True