athlete edit permissions in place
This commit is contained in:
@@ -167,6 +167,11 @@ def update_subscription(rower,data,method='up'):
|
|||||||
l = rower.user.last_name,
|
l = rower.user.last_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if rower.paidplan != 'coach':
|
||||||
|
coachees = Rower.objects.filter(coach__in=[rower]).distinct()
|
||||||
|
for coachee in coachees:
|
||||||
|
coachee.coaches.remove(rower)
|
||||||
|
|
||||||
if method == 'up':
|
if method == 'up':
|
||||||
transactions = result.subscription.transactions
|
transactions = result.subscription.transactions
|
||||||
|
|
||||||
|
|||||||
@@ -340,6 +340,7 @@ class Team(models.Model):
|
|||||||
|
|
||||||
viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')
|
viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')
|
||||||
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __unicode__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
@@ -831,6 +832,7 @@ class Rower(models.Model):
|
|||||||
|
|
||||||
# Friends/Team
|
# Friends/Team
|
||||||
friends = models.ManyToManyField("self",blank=True)
|
friends = models.ManyToManyField("self",blank=True)
|
||||||
|
coaches = models.ManyToManyField("self",blank=True)
|
||||||
privacy = models.CharField(default='visible',max_length=30,
|
privacy = models.CharField(default='visible',max_length=30,
|
||||||
choices=privacychoices)
|
choices=privacychoices)
|
||||||
|
|
||||||
@@ -986,12 +988,12 @@ def checkworkoutuser(user,workout):
|
|||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
teams = workout.team.all()
|
coaches = user.rower.coaches.filter(rowerplan='coach')
|
||||||
if workout.user == r:
|
if workout.user == r:
|
||||||
return True
|
return True
|
||||||
elif teams:
|
elif coaches:
|
||||||
for team in teams:
|
for coach in coaches:
|
||||||
if user == team.manager and workout.privacy == 'visible':
|
if user.rower == coach and workout.privacy == 'visible':
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
@@ -1003,12 +1005,12 @@ def checkworkoutuser(user,workout):
|
|||||||
def checkaccessuser(user,rower):
|
def checkaccessuser(user,rower):
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
teams = Team.objects.filter(manager=user)
|
|
||||||
if rower == r:
|
if rower == r:
|
||||||
return True
|
return True
|
||||||
elif teams:
|
coaches = rower.coaches.filter(rowerplan='coach')
|
||||||
for team in teams:
|
if coaches:
|
||||||
if team in rower.team.all():
|
for coach in coaches:
|
||||||
|
if user.rower == coach:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|||||||
@@ -102,6 +102,11 @@ def remove_team(id):
|
|||||||
|
|
||||||
return (1,'Updated rower team expiry')
|
return (1,'Updated rower team expiry')
|
||||||
|
|
||||||
|
def add_coach(manager,rower):
|
||||||
|
rower.coaches.add(m)
|
||||||
|
|
||||||
|
return (1,"Added Coach")
|
||||||
|
|
||||||
def add_member(id,rower):
|
def add_member(id,rower):
|
||||||
t= Team.objects.get(id=id)
|
t= Team.objects.get(id=id)
|
||||||
try:
|
try:
|
||||||
@@ -415,6 +420,7 @@ def process_request_code(manager,code):
|
|||||||
if not result:
|
if not result:
|
||||||
return (result,"The member couldn't be added")
|
return (result,"The member couldn't be added")
|
||||||
|
|
||||||
|
|
||||||
send_request_accept_email(rekwest)
|
send_request_accept_email(rekwest)
|
||||||
|
|
||||||
|
|
||||||
@@ -439,6 +445,7 @@ def process_invite_code(user,code):
|
|||||||
if not result:
|
if not result:
|
||||||
return (result,"The member couldn't be added")
|
return (result,"The member couldn't be added")
|
||||||
|
|
||||||
|
|
||||||
send_invite_accept_email(invitation)
|
send_invite_accept_email(invitation)
|
||||||
invitation.delete()
|
invitation.delete()
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -376,6 +376,15 @@ def team_rowers(user):
|
|||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def coach_rowers(user):
|
||||||
|
try:
|
||||||
|
members = Rower.objects.filter(coaches__in=user.rower).distinct().order_by(
|
||||||
|
"user__last_name","user__last_name"
|
||||||
|
)
|
||||||
|
return members
|
||||||
|
except TypeError:
|
||||||
|
return []
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def verbosetimeperiod(timeperiod):
|
def verbosetimeperiod(timeperiod):
|
||||||
|
|||||||
@@ -455,9 +455,10 @@ class PermissionsViewTests(TestCase):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Coach can edit on behalf of athlete
|
## Coach can edit on behalf of athlete if permitted
|
||||||
def test_coach_edit_athlete_settings(self):
|
def test_coach_edit_athlete_settings(self):
|
||||||
self.rbasic.team.add(self.teamcoach)
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
self.rbasic.coaches.add(self.rcoach)
|
||||||
|
|
||||||
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||||
self.assertTrue(login)
|
self.assertTrue(login)
|
||||||
@@ -467,10 +468,22 @@ class PermissionsViewTests(TestCase):
|
|||||||
response = self.c.get(url)
|
response = self.c.get(url)
|
||||||
self.assertEqual(response.status_code,200)
|
self.assertEqual(response.status_code,200)
|
||||||
|
|
||||||
|
def test_coach_edit_athlete_settings_not(self):
|
||||||
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
|
||||||
|
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||||
|
self.assertTrue(login)
|
||||||
|
|
||||||
|
url = reverse('rower_prefs_view',kwargs={'userid':self.ubasic.id})
|
||||||
|
|
||||||
|
response = self.c.get(url)
|
||||||
|
self.assertEqual(response.status_code,403)
|
||||||
|
|
||||||
## Coach can run analytics for athlete
|
## Coach can run analytics for athlete
|
||||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
|
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
|
||||||
def test_coach_edit_athlete_analysis(self,mocked_df):
|
def test_coach_edit_athlete_analysis(self,mocked_df):
|
||||||
self.rbasic.team.add(self.teamcoach)
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
self.rbasic.coaches.add(self.rcoach)
|
||||||
|
|
||||||
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||||
self.assertTrue(login)
|
self.assertTrue(login)
|
||||||
@@ -486,12 +499,31 @@ class PermissionsViewTests(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(response.status_code,200)
|
self.assertEqual(response.status_code,200)
|
||||||
|
|
||||||
|
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
|
||||||
|
def test_coach_edit_athlete_analysis_not(self,mocked_df):
|
||||||
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
|
||||||
## Coach can upload on behalf of athlete
|
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||||
|
self.assertTrue(login)
|
||||||
|
|
||||||
|
|
||||||
|
url = reverse('cumstats',
|
||||||
|
kwargs={
|
||||||
|
'theuser':self.ubasic.id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.c.get(url)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code,403)
|
||||||
|
|
||||||
|
|
||||||
|
## Coach can upload on behalf of athlete - if team allows
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||||
def test_coach_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
def test_coach_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||||
self.rbasic.team.add(self.teamcoach)
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
self.rbasic.coaches.add(self.rcoach)
|
||||||
|
|
||||||
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||||
self.assertTrue(login)
|
self.assertTrue(login)
|
||||||
@@ -531,6 +563,50 @@ class PermissionsViewTests(TestCase):
|
|||||||
|
|
||||||
self.assertEqual(aantal2,aantal+1)
|
self.assertEqual(aantal2,aantal+1)
|
||||||
|
|
||||||
|
## Coach can upload on behalf of athlete - if team allows
|
||||||
|
@patch('rowers.dataprep.create_engine')
|
||||||
|
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
|
||||||
|
def test_coach_edit_athlete_uploadnot(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
|
||||||
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
|
||||||
|
login = self.c.login(username=self.ucoach.username, password=self.ucoachpassword)
|
||||||
|
self.assertTrue(login)
|
||||||
|
|
||||||
|
url = reverse('team_workout_upload_view')
|
||||||
|
|
||||||
|
aantal = len(Workout.objects.filter(user=self.rbasic))
|
||||||
|
|
||||||
|
response = self.c.get(url)
|
||||||
|
self.assertEqual(response.status_code,200)
|
||||||
|
|
||||||
|
filename = 'rowers/tests/testdata/testdata.csv'
|
||||||
|
f = open(filename,'rb')
|
||||||
|
file_data = {'file': f}
|
||||||
|
form_data = {
|
||||||
|
'title':'test',
|
||||||
|
'workouttype':'rower',
|
||||||
|
'boattype':'1x',
|
||||||
|
'notes':'aap noot mies',
|
||||||
|
'make_plot':False,
|
||||||
|
'upload_to_c2':False,
|
||||||
|
'plottype':'timeplot',
|
||||||
|
'file': f,
|
||||||
|
'user': self.ubasic.id
|
||||||
|
}
|
||||||
|
|
||||||
|
response = self.c.post(url, form_data, follow=True)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code,200)
|
||||||
|
|
||||||
|
self.assertRedirects(response,
|
||||||
|
expected_url = url,
|
||||||
|
status_code=302,target_status_code=200)
|
||||||
|
|
||||||
|
aantal2 = len(Workout.objects.filter(user=self.rbasic))
|
||||||
|
|
||||||
|
self.assertEqual(aantal2,aantal)
|
||||||
|
|
||||||
## Coach can edit athlete's workout
|
## Coach can edit athlete's workout
|
||||||
def test_coach_edit_athlete_workout(self):
|
def test_coach_edit_athlete_workout(self):
|
||||||
self.rbasic.team.add(self.teamcoach)
|
self.rbasic.team.add(self.teamcoach)
|
||||||
|
|||||||
@@ -405,6 +405,12 @@ def isprorower(r):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
def iscoach(m,r):
|
||||||
|
result = False
|
||||||
|
result = m in r.coaches
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
# Exponentially weighted moving average
|
# Exponentially weighted moving average
|
||||||
# Used for data smoothing of the jagged data obtained by Strava
|
# Used for data smoothing of the jagged data obtained by Strava
|
||||||
# See bitbucket issue 72
|
# See bitbucket issue 72
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ def team_requestmembership_view(request,teamid,userid):
|
|||||||
else:
|
else:
|
||||||
messages.error(request,text)
|
messages.error(request,text)
|
||||||
|
|
||||||
|
|
||||||
url = reverse('team_view',kwargs={
|
url = reverse('team_view',kwargs={
|
||||||
'id':int(teamid),
|
'id':int(teamid),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -4235,16 +4235,18 @@ def team_workout_upload_view(request,message="",
|
|||||||
|
|
||||||
rowerform = TeamInviteForm(request.POST)
|
rowerform = TeamInviteForm(request.POST)
|
||||||
rowerform.fields.pop('email')
|
rowerform.fields.pop('email')
|
||||||
rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
|
rowers = Rower.objects.filter(coaches__in=[request.user.rower]).distinct()
|
||||||
|
rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct()
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
f = request.FILES['file']
|
f = request.FILES['file']
|
||||||
res = handle_uploaded_file(f)
|
res = handle_uploaded_file(f)
|
||||||
t = form.cleaned_data['title']
|
t = form.cleaned_data['title']
|
||||||
offline = form.cleaned_data['offline']
|
offline = form.cleaned_data['offline']
|
||||||
boattype = form.cleaned_data['boattype']
|
boattype = form.cleaned_data['boattype']
|
||||||
|
workouttype = form.cleaned_data['workouttype']
|
||||||
if rowerform.is_valid():
|
if rowerform.is_valid():
|
||||||
u = rowerform.cleaned_data['user']
|
u = rowerform.cleaned_data['user']
|
||||||
if u:
|
if u and request.user.rower in u.rower.coaches.all():
|
||||||
r = getrower(u)
|
r = getrower(u)
|
||||||
else:
|
else:
|
||||||
message = 'Please select a rower'
|
message = 'Please select a rower'
|
||||||
|
|||||||
Reference in New Issue
Block a user