Private
Public Access
1
0
This commit is contained in:
2024-07-26 16:31:29 +02:00
parent 4968ed5550
commit 2dea905b3c
5 changed files with 262 additions and 33 deletions

197
rowers/session_utils.py Normal file
View File

@@ -0,0 +1,197 @@
from django.utils import timezone
from rowers.models import Workout, VirtualRaceResult, CourseTestResult
def timefield_to_seconds_duration(t):
duration = t.hour*3600.
duration += t.minute * 60.
duration += t.second
duration += t.microsecond/1.e6
return duration
def is_session_complete_ws(ws, ps):
ws = ws.order_by("date")
if ws.count() == 0:
today = timezone.now()
if today.date() > ps.enddate:
verdict = 'missed'
ratio = 0
return ratio, verdict, None
else:
return 0, 'not done', None
value = ps.sessionvalue
if ps.sessionunit == 'min':
value *= 60.
elif ps.sessionunit == 'km': # pragma: no cover
value *= 1000.
cratiomin = 1
# cratiomax = 1
cratios = {
'better than nothing': 0,
'partial': 0.6,
'on target': 0.8,
'over target': 1.2,
'way over target': 1.5
}
if ps.criterium == 'none':
if ps.sessiontype == 'session':
cratiomin = 0.8
# cratiomax = 1.2
else:
cratios['on target'] = 0.9167
cratios['over target'] = 1.0833
cratiomin = 0.9167
# cratiomax = 1.0833
score = 0
completiondate = None
for w in ws:
if ps.sessionmode == 'distance':
score += w.distance
elif ps.sessionmode == 'time':
durationseconds = timefield_to_seconds_duration(w.duration)
score += durationseconds
elif ps.sessionmode == 'TRIMP':
score += w.trimp
elif ps.sessionmode == 'rScore':
score += wrscore
if not completiondate and score >= cratiomin*value:
completiondate = w.date
try:
ratio = score/float(int(value))
except ZeroDivisionError: # pragma: no cover
ratio = 0
verdict = 'better than nothing'
if ps.sessiontype in ['session', 'cycletarget']:
if ps.criterium == 'exact':
if ratio == 1.0:
return ratio, 'on target', completiondate
else:
if not completiondate: # pragma: no cover
completiondate = ws.reverse()[0].date
return ratio, 'partial', completiondate
elif ps.criterium == 'minimum': # pragma: no cover
if ratio >= 1.0:
return ratio, 'on target', completiondate
else:
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio, 'partial', completiondate
else:
thevalue = 0
for key, value in cratios.items():
if ratio > value and value > thevalue:
verdict = key
thevalue = value
completiondate = ws.reverse()[0].date
return ratio, verdict, completiondate
elif ps.sessiontype == 'test':
if ratio == 1.0:
return ratio, 'on target', completiondate
else:
return ratio, 'partial', completiondate
elif ps.sessiontype == 'challenge':
if ps.criterium == 'exact':
if ratio == 1.0:
return ratio, 'on target', completiondate
else:
return ratio, 'partial', completiondate
elif ps.criterium == 'minimum': # pragma: no cover
if ratio > 1.0:
return ratio, 'on target', completiondate
else:
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio, 'partial', completiondate
else:
if not completiondate: # pragma: no cover
completiondate = ws.reverse()[0].date
return ratio, 'partial', completiondate
elif ps.sessiontype == 'race': # pragma: no cover
vs = VirtualRaceResult.objects.filter(race=ps)
wids = [w.id for w in ws]
for record in vs:
if record.workoutid in wids:
if record.coursecompleted:
ratio = record.distance/ps.sessionvalue
return ratio, 'on target', completiondate
else:
ratio = record.distance/ps.sessionvalue
return ratio, 'partial', completiondate
return (0, 'partial', None)
elif ps.sessiontype in ['fastest_time', 'fastest_distance']: # pragma: no cover
vs = CourseTestResult.objects.filter(
plannedsession=ps, userid=ws[0].user.user.id)
completiondate = ws.reverse()[0].date
wids = [w.id for w in ws]
for record in vs:
if record.workoutid in wids:
if record.coursecompleted:
ratio = 1
return ratio, 'on target', completiondate
else:
return 0, 'partial', completiondate
if ws:
record = CourseTestResult(
userid=ws[0].user.id,
plannedsession=ps,
workoutid=ws[0].id,
duration=dt.time(0, 0),
coursecompleted=False
)
record.save()
return (0, 'not done', None)
elif ps.sessiontype == 'coursetest': # pragma: no cover
vs = CourseTestResult.objects.filter(plannedsession=ps)
wids = [w.id for w in ws]
for record in vs:
if record.workoutid in wids:
if record.coursecompleted:
ratio = record.distance/float(ps.sessionvalue)
return ratio, 'on target', completiondate
else:
ratio = record.distance/float(ps.sessionvalue)
return ratio, 'partial', completiondate
# we're still here - no record, need to create one
if ws:
record = CourseTestResult(
userid=ws[0].user.id,
plannedsession=ps,
workoutid=ws[0].id,
duration=dt.time(0, 0),
coursecompleted=False,
)
record.save()
_ = myqueue(queue, handle_check_race_course, ws[0].csvfilename,
ws[0].id, ps.course.id, record.id,
ws[0].user.user.email, ws[0].user.user.first_name,
mode='coursetest')
return (0, 'not done', None)
else: # pragma: no cover
if not completiondate:
completiondate = ws.reverse()[0].date
return ratio, verdict, completiondate
def is_session_complete(r, ps):
if r not in ps.rower.all(): # pragma: no cover
return 0, 'not assigned', None
ws = Workout.objects.filter(user=r, plannedsession=ps)
return is_session_complete_ws(ws, ps)

View File

@@ -17,7 +17,7 @@ from rowers.models import (
VirtualRaceResult, CourseTestResult, Rower,
GraphImage
)
from rowers.session_utils import is_session_complete
import math
from rowers.courseutils import (
coursetime_paths, coursetime_first, time_in_path,
@@ -441,6 +441,52 @@ def uploadactivity(access_token, filename, description='',
return 0, 0, 0, 0 # pragma: no cover
@app.task
def send_session_stats(user, debug=False, **kwargs):
ws = Workout.objects.filter(plannedsession__isnull=False)
results = []
for w in ws:
ps = w.plannedsession
r = w.user
ratio, status, cdate = is_session_complete(r, ps)
d = {
'date':w.date,
'session_id':ps.id,
'session_name':ps.name,
'complete': ratio,
'status': status,
'rscore': w.rscore,
'duration': w.duration,
}
results.append(d)
df = pd.DataFrame(results)
code = str(uuid4())
filename = code+'.csv'
df.to_csv(filename)
subject = "Session Stats"
from_email = 'Rowsandall <info@rowsandall.com>'
useremail = user.email
_ = send_template_email(
from_email, [useremail],
subject,
'sessionstats.html',
d,
attach_file=filename,
)
os.remove(filename)
return 1
@app.task
def check_tp_workout_id(workout, location, attempts=5, debug=False, **kwargs): # pragma: no cover

View File

@@ -0,0 +1,11 @@
{% extends "emailbase.html" %}
{% block body %}
<p>
Attached the requested stats.
</p>
<p>
Best Regards, the Rowsandall Team
</p>
{% endblock %}

Binary file not shown.

View File

@@ -2,6 +2,7 @@
from rowers.views.statements import *
from rowers.interactiveplots import sleep
from rowers.plannedsessions import is_session_complete
from rowers.tasks import send_session_stats
from rq import Queue
from redis import Redis
@@ -61,41 +62,15 @@ def sessions_stats(request):
if not request.user.is_staff: # pragma: no cover
raise PermissionDenied("Not Allowed")
ws = Workout.objects.filter(plannedsession__isnull=False)
myqueue(queuelow,
send_session_stats,
request.user)
results = []
r = getrower(request.user)
url = reverse('workouts_view')
for w in ws:
ps = w.plannedsession
r = w.user
ratio, status, cdate = is_session_complete(r, ps)
d = {
'date':w.date,
'session_id':ps.id,
'session_name':ps.name,
'complete': ratio,
'status': status,
'rscore': w.rscore,
'duration': w.duration,
}
results.append(d)
return HttpResponseRedirect(url)
df = pd.DataFrame(results)
code = str(uuid4())
filename = code+'.csv'
df.to_csv(filename)
with open(filename,'r') as f:
response = HttpResponse(f)
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response['Content-Type'] = 'application/octet-stream'
os.remove(filename)
return response
@login_required()