diff --git a/rowers/models.py b/rowers/models.py
index 7f7d5300..b261d323 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -346,8 +346,9 @@ class Team(models.Model):
def save(self, *args, **kwargs):
manager = self.manager
if manager.rower.rowerplan == 'basic':
- raise ValidationError(
- "Basic user cannot be team manager"
+ if manager.rower.protrialexpires < datetime.date.today() and manager.rower.plantrialexpires < datetime.date.today():
+ raise ValidationError(
+ "Basic user cannot be team manager"
)
if manager.rower.rowerplan in ['plan','pro']:
@@ -695,8 +696,8 @@ class Rower(models.Model):
planexpires = models.DateField(default=current_day)
teamplanexpires = models.DateField(default=current_day)
clubsize = models.IntegerField(default=0)
- protrialexpires = models.DateField(blank=True,null=True)
- plantrialexpires = models.DateField(blank=True,null=True)
+ protrialexpires = models.DateField(default=datetime.date(1970,1,1))
+ plantrialexpires = models.DateField(default=datetime.date(1970,1,1))
# Privacy Data
@@ -875,11 +876,12 @@ def check_teams_on_change(sender, **kwargs):
action = kwargs.pop('action', None)
pk_set = kwargs.pop('pk_set',None)
if action == 'pre_add' and instance.rowerplan=='basic':
- for id in pk_set:
- team = Team.objects.get(id=id)
- if team.manager.rower.rowerplan not in ['coach']:
- raise ValidationError(
- "You cannot join a team led by a Pro or Self-Coach user"
+ if instance.protrialexpires < datetime.date.today() and instance.plantrialexpires < datetime.date.today():
+ for id in pk_set:
+ team = Team.objects.get(id=id)
+ if team.manager.rower.rowerplan not in ['coach']:
+ raise ValidationError(
+ "You cannot join a team led by a Pro or Self-Coach user"
)
m2m_changed.connect(check_teams_on_change, sender=Rower.team.through)
@@ -1905,9 +1907,10 @@ class PlannedSession(models.Model):
manager = self.manager
if self.sessiontype not in ['race','indoorrace']:
if manager.rower.rowerplan in ['basic','pro']:
- raise ValidationError(
- "Basic user cannot be team manager"
- )
+ if manager.rower.plantrialexpires < timezone.now().date():
+ raise ValidationError(
+ "You must be a Self-Coach user or higher to create a planned session"
+ )
# sort units
diff --git a/rowers/teams.py b/rowers/teams.py
index 6bdbf566..b6a7bfc2 100644
--- a/rowers/teams.py
+++ b/rowers/teams.py
@@ -61,6 +61,14 @@ def update_team(t,name,manager,private,notes,viewing):
def create_team(name,manager,private='open',notes='',viewing='allmembers'):
# needs some error testing
+ if manager.rower.rowerplan == 'basic':
+ if manager.rower.protrialexpires < timezone.now().date() and manager.rower.plantrialexpires < timezone.now().date():
+ return (0,'You need to upgrade to a paid plan to establish a team')
+ elif manager.rower.rowerplan != 'coach':
+ 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)
@@ -77,17 +85,18 @@ def remove_team(id):
send_team_delete_mail(t,r)
return t.delete()
-def set_teamplanexpires(rower):
- ts = Team.objects.filter(rower=rower)
+#def set_teamplanexpires(rower):
+# ts = Team.objects.filter(rower=rower)
- texp = datetime.date(timezone.now())
+# texp = datetime.date(timezone.now())
- for t in ts:
- mr = Rower.objects.get(user=t.manager)
- if mr.teamplanexpires > texp:
- rower.teamplanexpires = mr.teamplanexpires
+# for t in ts:
+# print t.name
+# mr = Rower.objects.get(user=t.manager)
+# if mr.teamplanexpires > texp:
+# rower.teamplanexpires = mr.teamplanexpires
- t.save()
+# t.save()
return (1,'Updated rower team expiry')
@@ -99,7 +108,7 @@ def add_member(id,rower):
res = handle_add_workouts_team(ws,t)
- set_teamplanexpires(rower)
+# set_teamplanexpires(rower)
return (id,'Member added')
@@ -111,7 +120,7 @@ def remove_member(id,rower):
res = handle_remove_workouts_team(ws,t)
- set_teamplanexpires(rower)
+# set_teamplanexpires(rower)
return (id,'Member removed')
def mgr_remove_member(id,manager,rower):
diff --git a/rowers/templates/teams.html b/rowers/templates/teams.html
index 7db3247f..2f5a4396 100644
--- a/rowers/templates/teams.html
+++ b/rowers/templates/teams.html
@@ -56,7 +56,6 @@
{% endif %}
- {% if user.rower.rowerplan == 'coach' %}
Teams I manage
Number of members: {{ clubsize }}
@@ -85,7 +84,6 @@
{% endif %}
New Team
- {% endif %}
{% if invites or requests or myrequests or myinvites %}
Invitations and Requests
diff --git a/rowers/tests/test_permissions.py b/rowers/tests/test_permissions.py
index 8c6e2618..408cf6ff 100644
--- a/rowers/tests/test_permissions.py
+++ b/rowers/tests/test_permissions.py
@@ -112,7 +112,7 @@ class PermissionsBasicsTests(TestCase):
## Low level
## Coach can have any number of groups
- def test_plan_groupmanager(self):
+ def test_coach_groupmanager(self):
team1 = Team.objects.create(
name = 'FirstTeam',
notes = faker.text(),
@@ -131,7 +131,7 @@ class PermissionsBasicsTests(TestCase):
team3 = Team.objects.create(
- name = 'SecondTeam',
+ name = 'ThirdTeam',
notes = faker.text(),
manager = self.ucoach,
)
@@ -447,8 +447,6 @@ class PermissionsViewTests(TestCase):
'name': faker.word(),
}
- print 'posting to sessions/create'
-
form = PlannedSessionForm(post_data)
self.assertTrue(form.is_valid())
@@ -545,7 +543,7 @@ class PermissionsViewTests(TestCase):
)
response = self.c.get(url)
- self.assertEqual(response.status_code,200)
+ self.assertEqual(response.status_code,403)
## Self coach can create one group
## Self coach cannot create more than one group
@@ -629,7 +627,6 @@ class PermissionsViewTests(TestCase):
'name': faker.word(),
}
- print 'posting to sessions/create'
form = PlannedSessionForm(post_data)
self.assertTrue(form.is_valid())
@@ -641,7 +638,7 @@ class PermissionsViewTests(TestCase):
## Self Coach cannot edit on behalf of athlete
def test_plan_edit_athlete_settings(self):
- self.rbasic.team.add(self.teamplan)
+ self.rpro.team.add(self.teamplan)
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
self.assertTrue(login)
@@ -649,12 +646,12 @@ class PermissionsViewTests(TestCase):
url = reverse('rower_prefs_view',kwargs={'userid':self.ubasic.id})
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
## Self Coach cannot run analytics on behalf of athlete
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
def test_plan_edit_athlete_analysis(self,mocked_df):
- self.rbasic.team.add(self.teamplan)
+ self.rpro.team.add(self.teamplan)
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
self.assertTrue(login)
@@ -668,13 +665,13 @@ class PermissionsViewTests(TestCase):
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
## Self Coach cannot upload on behalf of athlete
@patch('rowers.dataprep.create_engine')
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
def test_plan_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
- self.rbasic.team.add(self.teamplan)
+ self.rpro.team.add(self.teamplan)
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
self.assertTrue(login)
@@ -682,7 +679,7 @@ class PermissionsViewTests(TestCase):
url = reverse('team_workout_upload_view')
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
## Pro can have one group
@@ -763,7 +760,7 @@ class PermissionsViewTests(TestCase):
## Pro cannot edit on behalf of athlete
def test_pro_edit_athlete_settings(self):
- self.rbasic.team.add(self.teampro)
+ self.rpro.team.add(self.teampro)
login = self.c.login(username=self.upro2.username, password=self.upro2password)
self.assertTrue(login)
@@ -771,12 +768,12 @@ class PermissionsViewTests(TestCase):
url = reverse('rower_prefs_view',kwargs={'userid':self.ubasic.id})
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
## Pro cannot run analytics on behalf of athlete
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
def test_pro_edit_athlete_analysis(self,mocked_df):
- self.rbasic.team.add(self.teampro)
+ self.rpro.team.add(self.teampro)
login = self.c.login(username=self.upro2.username, password=self.upro2password)
self.assertTrue(login)
@@ -790,40 +787,45 @@ class PermissionsViewTests(TestCase):
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
## Self Coach cannot upload on behalf of athlete
@patch('rowers.dataprep.create_engine')
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
def test_plan_edit_athlete_upload(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
- self.rbasic.team.add(self.teamplan)
+ self.rpro.team.add(self.teamplan)
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
self.assertTrue(login)
url = reverse('team_workout_upload_view')
- response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ response = self.c.get(url,follow=True)
+ self.assertEqual(response.status_code,200)
+
+ expected_url = reverse('paidplans')
+ self.assertRedirects(response,
+ expected_url = expected_url,
+ status_code=302,target_status_code=200)
## Pro users can see team members' workout, but not edit
- def test_coach_edit_athlete_workout(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
- self.rbasic.team.add(self.proplan)
- self.rpro2.team.add(self.proplan)
+ def test_pro_edit_athlete_workout(self):
+ self.rpro.team.add(self.teampro)
+ self.rpro2.team.add(self.teampro)
login = self.c.login(username=self.upro2.username, password=self.upro2password)
self.assertTrue(login)
url = reverse('workout_edit_view',
- kwargs={'id':encoder.encode_hex(self.ubasic_workouts[0].id)}
+ kwargs={'id':encoder.encode_hex(self.upro_workouts[0].id)}
)
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
url = reverse('workout_view',
- kwargs={'id':encoder.encode_hex(self.ubasic_workouts[0].id)}
+ kwargs={'id':encoder.encode_hex(self.upro_workouts[0].id)}
)
response = self.c.get(url)
@@ -831,8 +833,8 @@ class PermissionsViewTests(TestCase):
## Self Coach users can see team members' workout, but not edit
- def test_coach_edit_athlete_workout(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
- self.rbasic.team.add(self.teamplan)
+ def test_plan_edit_athlete_workout(self):
+ self.rpro.team.add(self.teamplan)
login = self.c.login(username=self.uplan2.username, password=self.uplan2password)
self.assertTrue(login)
@@ -842,7 +844,7 @@ class PermissionsViewTests(TestCase):
)
response = self.c.get(url)
- self.assertEqual(response.status_code,200)
+ self.assertEqual(response.status_code,403)
url = reverse('workout_view',
kwargs={'id':encoder.encode_hex(self.ubasic_workouts[0].id)}
@@ -853,9 +855,9 @@ class PermissionsViewTests(TestCase):
## Basic users can see team members' workout, but not edit
- def test_basic_edit_athlete_workout(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
- self.rbasic.team.add(self.teamplan)
- self.rplan2.team.add(self.teamplan)
+ def test_basic_edit_athlete_workout(self):
+ self.rbasic.team.add(self.teamcoach)
+ self.rplan2.team.add(self.teamcoach)
login = self.c.login(username=self.ubasic.username, password=self.ubasicpassword)
self.assertTrue(login)
@@ -865,7 +867,7 @@ class PermissionsViewTests(TestCase):
)
response = self.c.get(url)
- self.assertEqual(response.status_code,404)
+ self.assertEqual(response.status_code,403)
url = reverse('workout_view',
kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)}
@@ -902,7 +904,7 @@ class PermissionsViewTests(TestCase):
url = reverse('team_requestmembership_view',
kwargs = {
'teamid':self.teampro.id,
- 'userid':self.upro.id
+ 'userid':self.ubasic.id
})
response = self.c.get(url,follow=True)
@@ -913,3 +915,8 @@ class PermissionsViewTests(TestCase):
expected_url = expected_url,
status_code=302,target_status_code=200)
+# Race related
+
+## Basic and Pro users can create races
+
+## Basic users can subscribe to any race
diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz
index 3c6cc8df..a3190522 100644
Binary files a/rowers/tests/testdata/testdata.csv.gz and b/rowers/tests/testdata/testdata.csv.gz differ
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index 69a5c1a2..7dff9589 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -928,6 +928,23 @@ def iscoachmember(user):
return result
+def cancreateteam(user):
+ if user.is_anonymous():
+ return False
+
+ try:
+ r = Rower.objects.get(user=user)
+ except Rower.DoesNotExist:
+ r = Rower(user=user)
+ r.save()
+
+ if user.is_authenticated() and (r.rowerplan=='coach'):
+ return True
+ elif user.is_athenticated() and r.rowerplan in ['plan','pro']:
+ ts = Team.objects.filter(manager=user)
+ if len(otherteams) >= 1:
+ return False
+
# Check if a user can create planned sessions
def hasplannedsessions(user):
if not user.is_anonymous():
diff --git a/rowers/views/teamviews.py b/rowers/views/teamviews.py
index a248c24b..54c8736e 100644
--- a/rowers/views/teamviews.py
+++ b/rowers/views/teamviews.py
@@ -254,6 +254,15 @@ def team_requestmembership_view(request,teamid,userid):
t = Team.objects.get(id=teamid)
except Team.DoesNotExist:
raise Http404("Team doesn't exist")
+
+ r = getrequestrower(request,userid=userid)
+
+ if t.manager.rower.rowerplan in ['plan','pro'] and r.rowerplan == 'basic':
+ messages.error(request,
+ "You have to be on a paid plan (Pro or higher) to join this team. As a basic user you can only join teams managed by users on the Coach plan.")
+
+ url = reverse('paidplans')
+ return HttpResponseRedirect(url)
res,text = teams.create_request(t,userid)
if res:
@@ -395,8 +404,19 @@ def team_edit_view(request,id=0):
'team':t,
})
-@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
+#@user_passes_test(cancreateteam,login_url="/rowers/paidplans",redirect_field_name=None)
+@login_required()
def team_create_view(request):
+ r = getrequestrower(request)
+
+ if r.rowerplan == 'basic':
+ if r.protrialexpires < timezone.now().date() and r.plantrialexpires < timezone.now().date():
+ messages.error(request,"You must upgrade to Pro or higher to create teams/training groups")
+ url = reverse('paidplans')
+ return HttpResponseRedirect(url)
+
+
+
if request.method == 'POST':
teamcreateform = TeamForm(request.POST)
if teamcreateform.is_valid():
@@ -408,6 +428,12 @@ def team_create_view(request):
viewing = cd['viewing']
res,message=teams.create_team(name,manager,private,notes,
viewing)
+
+ if not res:
+ messages.error(request,message)
+ url = reverse('paidplans')
+ return HttpResponseRedirect(url)
+
url = reverse('rower_teams_view')
response = HttpResponseRedirect(url)
return response
@@ -438,7 +464,7 @@ def team_create_view(request):
'breadcrumbs':breadcrumbs,
})
-@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
+@login_required()
def team_deleteconfirm_view(request,id):
r = getrower(request.user)
try:
@@ -474,7 +500,7 @@ def team_deleteconfirm_view(request,id):
'active':'nav-teams',
})
-@user_passes_test(iscoachmember,login_url="/rowers/paidplans",redirect_field_name=None)
+@login_required()
def team_delete_view(request,id):
r = getrower(request.user)
try: