From 1c40d31c9c76b3cfd4d2068aecd678ab78a5d34a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 28 Sep 2022 19:13:56 +0200 Subject: [PATCH 1/4] better totaltimetosec --- rowers/dataprep.py | 3 +++ rowers/tests/test_unit_tests.py | 21 ++++++++++++++- rowers/utils.py | 47 ++++++++++++++++++++++++++++++++- 3 files changed, 69 insertions(+), 2 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index a02c5ce3..9368c961 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1188,7 +1188,10 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', if workouttype in otetypes: dragfactor = row.dragfactor + t = datetime.datetime.strptime(duration, "%H:%M:%S.%f") + + delta = datetime.timedelta( hours=t.hour, minutes=t.minute, seconds=t.second) diff --git a/rowers/tests/test_unit_tests.py b/rowers/tests/test_unit_tests.py index 56cf7b56..1a8f6d27 100644 --- a/rowers/tests/test_unit_tests.py +++ b/rowers/tests/test_unit_tests.py @@ -5,7 +5,7 @@ from __future__ import unicode_literals from .statements import * from rowers.mytypes import rowtypes -from rowers.utils import allmonths,allsundays +from rowers.utils import allmonths,allsundays, totaltime_sec_to_string from rowers.models import update_records from django.db import transaction @@ -94,6 +94,25 @@ class OtherUnitTests(TestCase): # time zone should be US/Pacific self.assertTrue('US/Pacific' in str(startdate.tzinfo)) + def test_totaltime_sec_to_string(self): + results = ( + (0,"0:00"), + (120,"2:00"), + (3634.2,"1:00:34"), + ) + + for duration, expected in results: + self.assertEqual(totaltime_sec_to_string(duration, shorten=True), expected) + + results = ( + (0,"00:00:00.0"), + (120,"00:02:00.0"), + (3634.2,"01:00:34.2"), + ) + + for duration, expected in results: + self.assertEqual(totaltime_sec_to_string(duration, shorten=False), expected) + def test_summaryfromsplitdata(self): diff --git a/rowers/utils.py b/rowers/utils.py index 4f70f43b..7572d7f5 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -428,32 +428,77 @@ def wavg(group, avg_name, weight_name): except ZeroDivisionError: # pragma: no cover return d.mean() +from string import Formatter def totaltime_sec_to_string(totaltime, shorten=False): + if np.isnan(totaltime): + return '' + + fmt = '{H:02}:{M:02}:{S:02}.{t}' + if shorten: + fmt = '{H}:{M:02}:{S:02}' + if totaltime < 3600: + fmt = '{M}:{S:02}' + + remainder = int(totaltime) + tenths = totaltime-remainder + + f = Formatter() + desired_fields = [field_tuple[1] for field_tuple in f.parse(fmt)] + + possible_fields = ('D','H', 'M', 'S') + constants = {'D':86400, 'H': 3600, 'M': 60, 'S': 1} + values = {} + for field in possible_fields: + if field in desired_fields and field in constants: + values[field], remainder = divmod(remainder, constants[field]) + + values['t'] = round(10*tenths) + + return f.format(fmt, **values) + + +def totaltime_sec_to_string_old(totaltime, shorten=False): if np.isnan(totaltime): return '' hours = int(totaltime / 3600.) if hours > 23: # pragma: no cover message = 'Warning: The workout duration was longer than 23 hours. ' hours = 23 + elif hours < 0: + message = 'Warning: invalid workout duration' + hours = 0 minutes = int((totaltime - 3600. * hours) / 60.) if minutes > 59: # pragma: no cover minutes = 59 if not message: # pragma: no cover message = 'Warning: there is something wrong with the workout duration' + elif minutes < 0: + minutes = 0 + if not message: + message = 'Warning: invalid workout duration' seconds = int(totaltime - 3600. * hours - 60. * minutes) if seconds > 59: # pragma: no cover seconds = 59 if not message: # pragma: no cover message = 'Warning: there is something wrong with the workout duration' + elif seconds < 0: + seconds = 0 + if not message: + message = 'Warning: invalid workout duration' - tenths = int(10 * (totaltime - 3600. * hours - 60. * minutes - seconds)) + + tenths = round(10 * (totaltime - 3600. * hours - 60. * minutes - seconds)) if tenths > 9: # pragma: no cover tenths = 9 if not message: # pragma: no cover message = 'Warning: there is something wrong with the workout duration' + elif tenths < 0: + tenths = 0 + if not message: + message = 'Warning: invalid workout duration' duration = "" if not shorten: From 36f1c95c85087c8594866ea65b731aacdef478cb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 28 Sep 2022 21:06:32 +0200 Subject: [PATCH 2/4] fix --- rowers/dataprep.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 9368c961..c73012b6 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1189,11 +1189,11 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', dragfactor = row.dragfactor - t = datetime.datetime.strptime(duration, "%H:%M:%S.%f") + #t = datetime.datetime.strptime(duration, "%H:%M:%S.%f") delta = datetime.timedelta( - hours=t.hour, minutes=t.minute, seconds=t.second) + seconds=totaltime) workoutenddatetime = workoutstartdatetime+delta From 6026b1b9bb043329988144020e5c4544cdcfe502 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 29 Sep 2022 13:19:11 +0200 Subject: [PATCH 3/4] fix --- boatmovers/templates/faq.html | 1 - rowers/templates/instroke.html | 11 +--- rowers/templates/instroke_interactive.html | 11 +++- rowers/templates/menu_workout.html | 2 +- rowers/templatetags/rowerfilters.py | 17 +++--- rowers/views/workoutviews.py | 65 ++++++++++++++++------ 6 files changed, 69 insertions(+), 38 deletions(-) diff --git a/boatmovers/templates/faq.html b/boatmovers/templates/faq.html index eab7d37d..ad3e9de3 100644 --- a/boatmovers/templates/faq.html +++ b/boatmovers/templates/faq.html @@ -90,7 +90,6 @@ zien welk ploeglid bij Willem III roeit en welk ploeglid bij De Hoop.

  • Spaarne Lenterace
  • Dutch Masters Open (alleen uitslagen van races die zonder startverschil worden geroeid)
  • Cottwich
  • -
  • Eemhead
  • Tromp Boat Races
  • Novembervieren
  • diff --git a/rowers/templates/instroke.html b/rowers/templates/instroke.html index 3a39d61e..87c77905 100644 --- a/rowers/templates/instroke.html +++ b/rowers/templates/instroke.html @@ -8,7 +8,7 @@

    In Stroke Metrics

    • - {% if user.rower.rowerplan == 'basic' %} + {% if user.rower|is_basic %}

      This is a preview of the page with advanced functionality for Pro users. @@ -40,20 +40,15 @@

    • {% if instrokemetrics %} - {% for metric in instrokemetrics %}

      - {{ metric }} -

      - {% endfor %} -

      - NEW: Dynamic + Dynamic

      {% else %}

      Unfortunately, this workout doesn't have any in stroke metrics

      {% endif %}
    • - +
    diff --git a/rowers/templates/instroke_interactive.html b/rowers/templates/instroke_interactive.html index d22d2f4e..db6aaa5d 100644 --- a/rowers/templates/instroke_interactive.html +++ b/rowers/templates/instroke_interactive.html @@ -119,10 +119,15 @@ $( function() {

    In Stroke Metrics

      -
    • -

      This is an experimental prototype. It's behavior is not guaranteed. Response may be slow. -

    • + {% if user.rower|is_basic %} + +

      + This is a preview of the page with advanced functionality for Pro users. + See the About page for more information + and to sign up for Pro Membership +

      + {% endif %}
      {% csrf_token %} diff --git a/rowers/templates/menu_workout.html b/rowers/templates/menu_workout.html index da4f6a19..bba56d91 100644 --- a/rowers/templates/menu_workout.html +++ b/rowers/templates/menu_workout.html @@ -334,7 +334,7 @@ {% endif %} {% endif %}
    • - + In-Stroke Metrics diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index c967bd31..5faae199 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -26,7 +26,7 @@ from rowers.teams import coach_getcoachees from rowers import credits from rowers import c2stuff from rowers.c2stuff import c2_open -from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember, ispromember +from rowers.rower_rules import * from rowers.mytypes import ( otwtypes, adaptivetypes, sexcategories, weightcategories, workouttypes, workouttypes_icons) @@ -252,8 +252,11 @@ def nogoals(user): @register.filter def notfree(rower): - return rower.rowerplan not in ['basic', 'freecoach'] + return user_is_not_basic(rower.user) +@register.filter +def is_basic(rower): + return not user_is_not_basic(rower.user) def strfdelta(tdelta): minutes, seconds = divmod(tdelta.seconds, 60) @@ -606,12 +609,10 @@ def mayeditplan(obj, request): if obj.manager is not None: return request.user == obj.manager.user - rr = Rower.objects.get(user=request.user) # pragma: no cover - if is_coach_user(request.user, obj.rower) and rr.rowerplan not in ['basic', 'pro']: # pragma: no cover - mayedit = True - - return mayedit # pragma: no cover + if can_plan(request.user) and is_coach_user(request.user, obj.rower): + return True + return False @register.filter def iterrows(df): # pragma: no cover @@ -744,7 +745,7 @@ def openactions(user): def team_rowers(user): # pragma: no cover try: therower = Rower.objects.get(user=user) - if therower.rowerplan == 'basic': + if not user_is_not_basic(user): return [] teams = Team.objects.filter(manager=user) members = Rower.objects.filter( diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index d49c49bd..64feb930 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -2927,6 +2927,54 @@ def instroke_chart_interactive(request, id=0): form = InstrokeForm(choices=instrokemetrics) + breadcrumbs = [ + { + 'url': '/rowers/list-workouts/', + 'name': 'Workouts' + }, + { + 'url': get_workout_default_page(request, id), + 'name': w.name + }, + { + 'url': reverse('instroke_view', kwargs={'id': id}), + 'name': 'In-Stroke Metrics' + } + + ] + + if not instrokemetrics: + script = '' + div = 'No Instroke Metrics available for this workout' + spm_min = 15 + spm_max = 45 + ds = '' + dd = '' + activeminutesmin = 0 + activeminutesmax = int(rowdata.duration/60.) + maxminutes = activeminutesmax + + return render(request, + 'instroke_interactive.html', + { + 'workout': w, + 'rower': w.user, + 'active': 'nav-workouts', + 'breadcrumbs': breadcrumbs, + 'teams': get_my_teams(request.user), + 'instrokemetrics': instrokemetrics, + 'form':form, + 'the_script': script, + 'the_div': div, + 'spm_min': spm_min, + 'spm_max': spm_max, + 'ds': ds, + 'dd': dd, + 'activeminutesmin': activeminutesmin, + 'activeminutesmax': activeminutesmax, + 'maxminutes': maxminutes, + }) + script = '' div = get_call() @@ -2991,23 +3039,6 @@ def instroke_chart_interactive(request, id=0): id), promember=1, intervaldata=intervaldata) - - breadcrumbs = [ - { - 'url': '/rowers/list-workouts/', - 'name': 'Workouts' - }, - { - 'url': get_workout_default_page(request, id), - 'name': w.name - }, - { - 'url': reverse('instroke_view', kwargs={'id': id}), - 'name': 'In-Stroke Metrics' - } - - ] - if is_ajax: response = json.dumps({ 'script': script, From bcb26281e77339f9bd6f7a6824673f36e8cea1b0 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 2 Oct 2022 17:22:54 +0200 Subject: [PATCH 4/4] fix --- rowers/views/workoutviews.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 64feb930..a3155e52 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -2937,7 +2937,7 @@ def instroke_chart_interactive(request, id=0): 'name': w.name }, { - 'url': reverse('instroke_view', kwargs={'id': id}), + 'url': reverse('instroke_chart_interactive', kwargs={'id': id}), 'name': 'In-Stroke Metrics' }