diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 52022e06..7bf213f7 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -188,7 +188,7 @@ class Command(BaseCommand): res = polarstuff.get_all_new_workouts(polar_available) # Concept2 - rowers = Rower.objects.filter(c2_auto_import=True) + rowers = Rower.objects.filter(c2_auto_import=True).exclude(rowerplan='basic') for r in rowers: c2stuff.get_c2_workouts(r) @@ -287,7 +287,7 @@ class Command(BaseCommand): message.delete() # Strava - rowers = Rower.objects.filter(strava_auto_import=True) + rowers = Rower.objects.filter(strava_auto_import=True).exclude(rowerplan='basic') for r in rowers: stravastuff.get_strava_workouts(r) diff --git a/rowers/models.py b/rowers/models.py index 93dcfa58..ac7b00d1 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1024,6 +1024,25 @@ def checkworkoutuser(user,workout): except Rower.DoesNotExist: return False +# Check if workout may be viewed by this user +def checkworkoutuserview(user,workout): + if user.is_anonymous(): + return False + try: + r = Rower.objects.get(user=user) + if workout.user == r: + return True + teams = workout.user.team.all() + + for team in teams: + if team in r.team.all(): + return True + return False + except Rower.DoesNotExist: + return False + + return False + def checkviewworkouts(user,rower): try: r = user.rower diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 756cf751..c8a2e2a8 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -473,13 +473,14 @@ def remove_rower_session(r,ps): return 1 -def get_dates_timeperiod(request,startdatestring='',enddatestring=''): +def get_dates_timeperiod(request,startdatestring='',enddatestring='', + defaulttimeperiod='thisweek'): # set start end date according timeperiod timeperiod = request.GET.get('when') if not timeperiod: - timeperiod = 'thisweek' + timeperiod = defaulttimeperiod startdatestring = request.GET.get('startdate') enddatestring = request.GET.get('enddate') @@ -536,6 +537,10 @@ def get_dates_timeperiod(request,startdatestring='',enddatestring=''): enddate = startdate+timezone.timedelta(days=32) enddate = enddate.replace(day=1) enddate = enddate-timezone.timedelta(days=1) + elif timeperiod=='lastyear': + today = date.today() + startdate = today-timezone.timedelta(days=365) + enddate = today+timezone.timedelta(days=1) elif daterangetester.match(timeperiod): tstartdatestring = daterangetester.match(timeperiod).group(1) tenddatestring = daterangetester.match(timeperiod).group(2) diff --git a/rowers/tasks.py b/rowers/tasks.py index cbf98d8d..efc0cf44 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -68,6 +68,7 @@ from rowers.dataprepnodjango import ( # create_strava_stroke_data_db ) +from rowers.opaque import encoder from django.core.mail import ( send_mail, @@ -1890,7 +1891,8 @@ def handle_sendemailnewresponse(first_name, last_name, if 'sessiontype' in kwargs: sessiontype=kwargs.pop('sessiontype') - commentlink = '/rowers/workout/{workoutid}/comment/'.format(workoutid=workoutid) + commentlink = '/rowers/workout/{workoutid}/comment/'.format( + workoutid=encoder.encode_hex(workoutid)) if 'commentlink' in kwargs: commentlink = kwargs.pop('commentlink') @@ -1940,7 +1942,8 @@ def handle_sendemailnewcomment(first_name, if 'sessiontype' in kwargs: sessiontype=kwargs.pop('sessiontype') - commentlink = '/rowers/workout/{workoutid}/comment/'.format(workoutid=workoutid) + commentlink = '/rowers/workout/{workoutid}/comment/'.format( + workoutid=encoder.encode_hex(workoutid)) if 'commentlink' in kwargs: commentlink = kwargs.pop('commentlink') @@ -1951,7 +1954,7 @@ def handle_sendemailnewcomment(first_name, 'comment':comment, 'workoutname':workoutname, 'siteurl':siteurl, - 'workoutid':workoutid, + 'workoutid':encoder.encode_hex(workoutid), 'sessiontype':sessiontype, 'commentlink':commentlink, } diff --git a/rowers/templates/list_workouts.html b/rowers/templates/list_workouts.html index bfac39a8..b4066432 100644 --- a/rowers/templates/list_workouts.html +++ b/rowers/templates/list_workouts.html @@ -129,7 +129,7 @@ {% if workouts.has_next %} {% if request.GET.q %} - + {% else %} - + @@ -216,7 +216,7 @@ {% if team %} {% if workout|may_edit:request %} - + {{ workout.user.user.first_name }} {{ workout.user.user.last_name }} @@ -245,18 +245,14 @@ - {% if workout|may_edit:request %} - {% else %} -   - {% endif %} - {% if workout.user.user == user or user == team.manager %} + {% if workout|may_edit:request %} diff --git a/rowers/templates/menu_plan.html b/rowers/templates/menu_plan.html index d6a448ec..7177f790 100644 --- a/rowers/templates/menu_plan.html +++ b/rowers/templates/menu_plan.html @@ -63,7 +63,7 @@
  • -  Add Team Session +  Add Group Session
  • diff --git a/rowers/templates/menu_workout.html b/rowers/templates/menu_workout.html index 84ff5c97..b87876bb 100644 --- a/rowers/templates/menu_workout.html +++ b/rowers/templates/menu_workout.html @@ -41,7 +41,7 @@
  • - +  Compare
  • diff --git a/rowers/templates/paidplans.html b/rowers/templates/paidplans.html index b091b9e5..fd5e4655 100644 --- a/rowers/templates/paidplans.html +++ b/rowers/templates/paidplans.html @@ -94,7 +94,14 @@ ✔ - Create Training plans, tests and challenges for yourself. Track your performance + Create and manage groups. +   + ✔ + ✔ + ✔ + + + Create Training plans, tests and challenges for yourself and your training group. Track your performance against plan.     @@ -110,14 +117,21 @@ ✔ - Create and manage teams. + Manage your athlete's workouts       ✔ - Manage your athlete's workouts + Run analytics for your athletes +   +   +   + ✔ + + + Change zone intensities and other workout related settings for your athletes       diff --git a/rowers/templates/plannedsessionsmanage.html b/rowers/templates/plannedsessionsmanage.html index 0e12facf..fa78f7b1 100644 --- a/rowers/templates/plannedsessionsmanage.html +++ b/rowers/templates/plannedsessionsmanage.html @@ -90,7 +90,7 @@
  • {% csrf_token %} - +
  • diff --git a/rowers/templates/plannedsessionview.html b/rowers/templates/plannedsessionview.html index ee840e64..f5aa1c88 100644 --- a/rowers/templates/plannedsessionview.html +++ b/rowers/templates/plannedsessionview.html @@ -96,6 +96,10 @@ {% endfor %} +

    + + Add, remove or change workouts for this session +

  • {{ rower.user.first_name }} {{ rower.user.last_name }}

    diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index 8e4fd953..5138566c 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -4,6 +4,11 @@ {% block main %}

    Import and Export Settings for {{ rower.user.first_name }} {{ rower.user.last_name }}

    + +{% if user.rower.rowerplan == 'basic' %} +The auto import and export settings only work on a paid plan. +{% endif %} + {% if form.errors %}

    Please correct the error{{ form.errors|pluralize }} below. diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 83269444..e44015eb 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -470,7 +470,7 @@ def userurl(path,member): userstring = 'user/%s/' % member.id # remove team - tpattern = re.compile('\/team\/\d+/') + tpattern = re.compile('team\/\d+/') if tpattern.search(path) is not None: path = tpattern.sub('',path) @@ -478,7 +478,7 @@ def userurl(path,member): replaced = pattern.sub(userstring,path) else: replaced = path+userstring - + return replaced @register.filter @@ -489,7 +489,7 @@ def teamurl(path,team): # remove user upattern = re.compile('\/user\/\d+/') if upattern.search(path) is not None: - path = upattern.sub('',path) + path = upattern.sub('/',path) if pattern.search(path) is not None: @@ -497,6 +497,7 @@ def teamurl(path,team): else: replaced = path+teamstring + return replaced @register.filter diff --git a/rowers/tests/test_permissions.py b/rowers/tests/test_permissions.py index a902d2fb..a84f7982 100644 --- a/rowers/tests/test_permissions.py +++ b/rowers/tests/test_permissions.py @@ -958,6 +958,31 @@ class PermissionsViewTests(TestCase): response = self.c.get(url) self.assertEqual(response.status_code,200) + + # stats + url = reverse('workout_view', + kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)} + ) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + # workflow + url = reverse('workout_workflow_view', + kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)} + ) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + # stats + url = reverse('workout_stats_view', + kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)} + ) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + ## Pro users (and higher) can join group led by other Pro (or higher) user def test_team_member_request_pro_pro(self): @@ -1416,8 +1441,7 @@ class PermissionsCoachingTests(TestCase): ## Basic users can subscribe to any race -# group related -## group members can see but not edit each other's workouts and charts +### ## group members can see but not edit each other's plans diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index 6bd4febc..c9b47c1d 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 e7e2305e..3f1ec013 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -367,6 +367,14 @@ def get_workout_permitted(user,id): return w +def get_workout_permittedview(user,id): + w = get_workout(id) + + if (checkworkoutuserview(user,w)==False): + raise PermissionDenied("Access denied") + + return w + def getvalue(data): perc = 0 total = 1 @@ -944,7 +952,9 @@ from rowers.utils import ( import rowers.datautils as datautils -from rowers.models import checkworkoutuser,checkaccessuser,checkviewworkouts +from rowers.models import ( + checkworkoutuser,checkaccessuser,checkviewworkouts,checkworkoutuserview + ) # Check if a user is a Coach member def iscoachmember(user): diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index b49af87d..73e01c79 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -590,7 +590,9 @@ def workouts_join_select(request, }) # Team comparison -@login_required() +@user_passes_test(ispromember,login_url='/rowers/paidplans/', + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def team_comparison_select(request, startdatestring="", enddatestring="", @@ -695,11 +697,6 @@ def team_comparison_select(request, except Team.DoesNotExist: theteam = 0 - if requestrower.rowerplan == 'basic' and theteam==0: - if requestrower.protrialexpires is None or requestrower.protrialexpires