Private
Public Access
1
0

Merge branch 'release/v18.6.29'

This commit is contained in:
Sander Roosendaal
2022-10-02 17:23:06 +02:00
9 changed files with 140 additions and 42 deletions
-1
View File
@@ -90,7 +90,6 @@ zien welk ploeglid bij Willem III roeit en welk ploeglid bij De Hoop.</p>
<li>Spaarne Lenterace</li>
<li>Dutch Masters Open (alleen uitslagen van races die zonder startverschil worden geroeid)</li>
<li>Cottwich</li>
<li>Eemhead</li>
<li>Tromp Boat Races</li>
<li>Novembervieren</li>
</ul>
+5 -2
View File
@@ -1188,9 +1188,12 @@ 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")
#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
+3 -8
View File
@@ -8,7 +8,7 @@
<h1>In Stroke Metrics</h1>
<ul class="main-content">
<li class="grid_4">
{% if user.rower.rowerplan == 'basic' %}
{% if user.rower|is_basic %}
<p>
This is a preview of the page with advanced functionality for Pro users.
@@ -40,20 +40,15 @@
<li>
{% if instrokemetrics %}
{% for metric in instrokemetrics %}
<p>
<a href="/rowers/workout/{{ workout.id|encode }}/instroke/{{ metric }}/">{{ metric }}</a>
</p>
{% endfor %}
<p>
<a href="/rowers/workout/{{ workout.id|encode }}/instroke/interactive/">NEW: Dynamic</a>
<a href="/rowers/workout/{{ workout.id|encode }}/instroke/interactive/">Dynamic</a>
</p>
{% else %}
<p>Unfortunately, this workout doesn't have any in stroke metrics</p>
{% endif %}
</li>
</ul>
+8 -3
View File
@@ -119,10 +119,15 @@ $( function() {
<h1>In Stroke Metrics</h1>
<ul class="main-content">
<li class="grid_4">
<p>This is an experimental prototype. It's behavior is not guaranteed. Response may be slow.
</li>
<li class="grid_4" >
{% if user.rower|is_basic %}
<p>
This is a preview of the page with advanced functionality for Pro users.
See <a href="/rowers/about/">the About page</a> for more information
and to sign up for Pro Membership
</p>
{% endif %}
<form id="instrokeform" enctype="multipart/form-data" action="" method="post">
{% csrf_token %}
<table>
+1 -1
View File
@@ -334,7 +334,7 @@
{% endif %}
{% endif %}
<li id="advanced-instroke">
<a href="/rowers/workout/{{ workout.id|encode }}/instroke/">
<a href="/rowers/workout/{{ workout.id|encode }}/instroke/interactive/">
<i class="fas fa-search-plus fa-fw"></i>
In-Stroke Metrics
</a>
+9 -8
View File
@@ -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(
+20 -1
View File
@@ -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):
+46 -1
View File
@@ -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:
+48 -17
View File
@@ -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_chart_interactive', 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,