From 046e1d2d079e1cfd5f7cb14eb09e1d3aa0acce58 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 20 Jun 2022 21:18:31 +0200 Subject: [PATCH 1/3] autosync works for coachees --- rowers/rower_rules.py | 5 +++++ rowers/tasks.py | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py index be51fcc8..b93d42ef 100644 --- a/rowers/rower_rules.py +++ b/rowers/rower_rules.py @@ -84,6 +84,11 @@ def user_is_not_basic(user): if user.rower.protrialexpires >= timezone.now().date(): return True # pragma: no cover + coaches = user.rower.get_coaches() + for coach in coaches: + if coach.rowerplan == 'coach': + return True + return False diff --git a/rowers/tasks.py b/rowers/tasks.py index d3d9f497..45f806ea 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -338,6 +338,12 @@ def handle_strava_sync(stravatoken, workoutid, filename, name, activity_type, de tb = traceback.format_exc() dologging('strava_fail.log', tb) failed = True + except stravalib.exc.TimeoutExceeded: + dologging('strava_fail.log', 'Strava upload failed for Workout {id} TimeOutExceeded'.format( + id=workoutid)) + tb = traceback.format_exc() + dologging('strava_fail.log', tb) + failed = True except JSONDecodeError: # pragma: no cover dologging('strava_fail.log', 'Strava upload failed for Workout {id} JSONDecodeError'.format( id=workoutid)) From 025999969587240ca4bec7168195b3fd28fb64e5 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 20 Jun 2022 21:27:53 +0200 Subject: [PATCH 2/3] fixing auto import for coachees --- rowers/management/commands/processemail.py | 8 ++++---- rowers/rower_rules.py | 4 ++++ rowers/tests/test_permissions.py | 5 ++++- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 591ab34c..55b4fc32 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -34,7 +34,7 @@ import rowers.stravastuff as stravastuff import rowers.nkstuff as nkstuff from rowers.opaque import encoder -from rowers.rower_rules import user_is_not_basic +from rowers.rower_rules import user_is_not_basic, user_is_coachee from rowers.utils import dologging # If you find a solution that does not need the two paths, please comment! @@ -90,7 +90,7 @@ class Command(BaseCommand): try: rowers = Rower.objects.filter(c2_auto_import=True) for r in rowers: # pragma: no cover - if user_is_not_basic(r.user): + if user_is_not_basic(r.user) or user_is_coachee(r.user): c2stuff.get_c2_workouts(r) except: # pragma: no cover exc_type, exc_value, exc_traceback = sys.exc_info() @@ -100,7 +100,7 @@ class Command(BaseCommand): try: rowers = Rower.objects.filter(rp3_auto_import=True) for r in rowers: # pragma: no cover - if user_is_not_basic(r.user): + if user_is_not_basic(r.user) or user_is_coachee(r.user): _ = rp3stuff.get_rp3_workouts(r) except: # pragma: no cover exc_type, exc_value, exc_traceback = sys.exc_info() @@ -111,7 +111,7 @@ class Command(BaseCommand): rowers = Rower.objects.filter(nk_auto_import=True) for r in rowers: # pragma: no cover dologging("nklog.log","NK Auto import set for rower {id}".format(id=r.user.id)) - if user_is_not_basic(r.user): + if user_is_not_basic(r.user) or user_is_coachee(r.user): dologging("nklog.log","User is not basic") _ = nkstuff.get_nk_workouts(r) except: # pragma: no cover diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py index b93d42ef..33724ef2 100644 --- a/rowers/rower_rules.py +++ b/rowers/rower_rules.py @@ -84,6 +84,10 @@ def user_is_not_basic(user): if user.rower.protrialexpires >= timezone.now().date(): return True # pragma: no cover + return False + +@rules.predicate +def user_is_coachee(user): coaches = user.rower.get_coaches() for coach in coaches: if coach.rowerplan == 'coach': diff --git a/rowers/tests/test_permissions.py b/rowers/tests/test_permissions.py index 5f4bcdd2..0f5a8c3e 100644 --- a/rowers/tests/test_permissions.py +++ b/rowers/tests/test_permissions.py @@ -13,7 +13,7 @@ from django.db import transaction import rowers.teams as teams import rowers.plannedsessions as plannedsessions -from rowers.rower_rules import is_coach_user +from rowers.rower_rules import is_coach_user, user_is_coachee @override_settings(TESTING=True) class PlanningPermissionsCoach(TestCase): @@ -94,6 +94,9 @@ class PlanningPermissionsCoach(TestCase): athletes = plan.rowers.all() self.assertTrue(self.rgroupmember in athletes) + def test_coachee_can_sync(self): + self.assertTrue(user_is_coachee(self.ucoachee)) + @override_settings(TESTING=True) class PermissionsFreeCoach(TestCase): From 7629183d6d4bde7a60d5f102c4a9cf202aa4b76a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 20 Jun 2022 21:48:23 +0200 Subject: [PATCH 3/3] added ranking selector --- rowers/forms.py | 3 +++ rowers/views/analysisviews.py | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/rowers/forms.py b/rowers/forms.py index 1b3793fb..fdb19df6 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1120,6 +1120,9 @@ class AnalysisOptionsForm(forms.Form): label='Water Boat Type', initial=mytypes.waterboattype) + ranking = forms.BooleanField(label='Ranking Workouts Only', + initial=False,required=False) + # form to select modality and boat type for trend flex class TrendFlexModalForm(forms.Form): diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 3f5e4729..7b46b5c9 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -19,7 +19,8 @@ defaultoptions = { 'includereststrokes': False, 'workouttypes': ['rower', 'dynamic', 'slides'], 'waterboattype': mytypes.waterboattype, - 'function': 'boxplot' + 'function': 'boxplot', + 'ranking': False, } @@ -72,6 +73,11 @@ def analysis_new(request, modalities = [m[0] for m in mytypes.workouttypes_ordered.items()] modality = 'all' + try: + ranking = options['ranking'] + except KeyError: + ranking = False + try: worldclass = options['cpoverlay'] except KeyError: @@ -109,6 +115,7 @@ def analysis_new(request, modality = optionsform.cleaned_data['modality'] waterboattype = optionsform.cleaned_data['waterboattype'] + ranking = optionsform.cleaned_data['ranking'] if modality == 'all': modalities = [m[0] for m in mytypes.workouttypes] else: # pragma: no cover @@ -118,6 +125,7 @@ def analysis_new(request, options['modalities'] = modalities options['waterboattype'] = waterboattype + options['ranking'] = ranking try: worldclass = options['cpoverlay'] except KeyError: @@ -173,17 +181,24 @@ def analysis_new(request, if b[0] not in waterboattype: # pragma: no cover negtypes.append(b[0]) + rankingtypes = [False,True] + if ranking: + rankingtypes = [True] + + if theteam is not None and (theteam.viewing == 'allmembers' or theteam.manager == request.user): # pragma: no cover workouts = Workout.objects.filter(team=theteam, startdatetime__gte=startdate, startdatetime__lte=enddate, workouttype__in=modalities, + rankingpiece__in=rankingtypes, ) elif theteam is not None and theteam.viewing == 'coachonly': # pragma: no cover workouts = Workout.objects.filter(team=theteam, user=r, startdatetime__gte=startdate, startdatetime__lte=enddate, workouttype__in=modalities, + rankingpiece__in=rankingtypes, ) elif thesession is not None: workouts = get_workouts_session(r, thesession) @@ -192,6 +207,7 @@ def analysis_new(request, startdatetime__gte=startdate, startdatetime__lte=enddate, workouttype__in=modalities, + rankingpiece__in=rankingtypes, ) if firstworkout: workouts = firstworkoutquery | workouts @@ -229,6 +245,7 @@ def analysis_new(request, optionsform = AnalysisOptionsForm(initial={ 'modality': modality, 'waterboattype': waterboattype, + 'ranking': ranking, }) if r.birthdate: