Private
Public Access
1
0

attach workouts to sessions version 0

This commit is contained in:
Sander Roosendaal
2018-02-07 16:37:03 +01:00
parent d3448c66f1
commit 91d59dfc28
13 changed files with 483 additions and 61 deletions

View File

@@ -602,3 +602,29 @@ class FusionMetricChoiceForm(ModelForm):
metricchoices = list(sorted(formaxlabels2.items(), key = lambda x:x[1]))
self.fields['columns'].choices = metricchoices
class PlannedSessionSelectForm(forms.Form):
def __init__(self, sessionchoices, *args, **kwargs):
super(PlannedSessionSelectForm, self).__init__(*args,**kwargs)
self.fields['plannedsession'] = forms.ChoiceField(
label='Sessions',
choices = sessionchoices,
widget = forms.RadioSelect,
)
class WorkoutSessionSelectForm(forms.Form):
def __init__(self, workoutdata, *args, **kwargs):
super(WorkoutSessionSelectForm, self).__init__(*args, **kwargs)
self.fields['workouts'] = forms.MultipleChoiceField(
label='Workouts',
choices = workoutdata['choices'],
initial=workoutdata['initial'],
widget = forms.CheckboxSelectMultiple,
)

View File

@@ -855,10 +855,6 @@ class PlannedSession(models.Model):
choices=verificationchoices
)
# 0 = incomplete, 1 = complete, >1 = partial (details could
# be defined later)
sessioncompleted = models.IntegerField(default=0)
team = models.ManyToManyField(Team,blank=True)
rower = models.ManyToManyField(Rower,blank=True)

View File

@@ -26,14 +26,28 @@ import numpy as np
import dataprep
# Low Level functions - to be called by higher level methods
# dummies for now
def add_workouts_plannedsession(ws,ps):
for w in ws:
w.plannedsession = ps
w.save()
result = 0
comments = []
errors = []
return 1
# check if all sessions have same date
dates = [w.date for w in ws]
if (not all(d == dates[0] for d in dates)) and ps.sessiontype != 'challenge':
errors.append('For tests and training sessions, selected workouts must all be done on the same date')
return result,comments,errors
# start adding sessions
for w in ws:
if w.date>=ps.startdate and w.date<=ps.enddate:
w.plannedsession = ps
w.save()
result += 1
comments.append('Attached workout %i to session' % w.id)
else:
errors.append('Workout %i did not match session dates' % w.id)
return result,comments,errors
def remove_workout_plannedsession(w,ps):
@@ -57,8 +71,20 @@ def timefield_to_seconds_duration(t):
return duration
def is_session_complete(ps):
ws = Workout.objects.filter(plannedsession=ps)
def is_session_complete(r,ps):
status = 'not done'
ws = Workout.objects.filter(user=r,plannedsession=ps)
if len(ws)==0:
today = date.today()
if today > ps.enddate:
status = 'missed'
ratio = 0
return ratio,status
else:
return 0,'not done'
score = 0
for w in ws:
if ps.sessionmode == 'distance':
@@ -73,13 +99,56 @@ def is_session_complete(ps):
rscore = dataprep.workout_rscore(w)
score += rscore
ratio = score/float(ps.value)
value = ps.sessionvalue
if ps.sessionunit == 'min':
value *= 60.
elif ps.sessionunit == 'km':
value *= 1000.
if ratio>0.8 and ratio<1.2:
return True
print score,value,ps.sessionvalue,ps.sessionunit
ratio = score/float(value)
return False
status = 'partial'
if ps.sessiontype == 'training':
if ps.sessioncriterium == 'exact':
if ratio == 1.0:
return ratio,'completed'
else:
return ratio,'partial'
elif ps.sessioncriterium == 'minimum':
if ratio > 1.0:
return ratio,'completed'
else:
return ratio,'partial'
else:
if ratio>0.8 and ratio<1.2:
return ratio,'completed'
else:
return ratio,'partial'
elif ps.sessiontype == 'test':
if ratio==1.0:
return ratio,'completed'
else:
return ratio,'partial'
elif ps.sessiontype == 'challenge':
if ps.sessioncriterium == 'exact':
if ratio == 1.0:
return ratio,'completed'
else:
return ratio,'partial'
elif ps.sessioncriterium == 'minimum':
if ratio > 1.0:
return ratio,'completed'
else:
return ratio,'partial'
else:
return ratio,'partial'
else:
return ratio,status
def rank_results(ps):
return 1
@@ -105,17 +174,58 @@ def remove_rower_session(r,ps):
return 1
def get_dates_timeperiod(timeperiod):
# set start end date according timeperiod
if timeperiod=='today':
startdate=date.today()
enddate=date.today()
elif timeperiod=='tomorrow':
startdate=date.today()+timezone.timedelta(days=1)
enddate=date.today()+timezone.timedelta(days=1)
elif timeperiod=='thisweek':
today = date.today()
startdate = date.today()-timezone.timedelta(days=today.weekday())
enddate = startdate+timezone.timedelta(days=6)
elif timeperiod=='thismonth':
today = date.today()
startdate = today.replace(day=1)
enddate = startdate+timezone.timedelta(days=32)
enddate = enddate.replace(day=1)
enddate = enddate-timezone.timedelta(days=1)
elif timeperiod=='lastweek':
today = date.today()
enddate = today-timezone.timedelta(days=today.weekday())-timezone.timedelta(days=1)
startdate = enddate-timezone.timedelta(days=6)
elif timeperiod=='lastmonth':
today = date.today()
startdate = today.replace(day=1)
startdate = startdate-timezone.timedelta(days=3)
startdate = startdate.replace(day=1)
enddate = startdate+timezone.timedelta(days=32)
enddate = enddate.replace(day=1)
enddate = enddate-timezone.timedelta(days=1)
else:
startdate = date.today()
enddate = date.today()
return startdate,enddate
def get_sessions(r,startdate=date.today(),
enddate=date.today()+timezone.timedelta(+1000)):
sps = PlannedSession.objects.filter(
rower__in=[r],
startdate__gte=startdate,
enddate__lte=enddate,
startdate__lte=enddate,
enddate__gte=startdate,
).order_by("startdate","enddate")
return sps
def get_workouts_session(r,ps):
ws = Workout.objects.filter(user=r,plannedsession=ps)
return ws
def update_plannedsession(ps,cd):
for attr, value in cd.items():
setattr(ps, attr, value)

View File

@@ -0,0 +1 @@
e408191@CZ27LT9RCGN72.19768:1517816528

View File

@@ -30,7 +30,7 @@
<p>
Click on session name to view
</p>
<table class="listtable shortpadded">
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>After</th>

View File

@@ -21,7 +21,10 @@
{{ form.as_table }}
</table>
{% csrf_token %}
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
<div class="grid_1 prefix_3 alpha">
<a class="red button small" href="/rowers/sessions/{{ thesession.id }}/deleteconfirm">Delete</a>
</div>
<div id="formbutton" class="grid_1 suffix_1 omega">
<input class="button green" type="submit" value="Submit">
</div>
</div>
@@ -30,7 +33,7 @@
<p>
Click on session name to view
</p>
<table class="listtable shortpadded">
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>After</th>

View File

@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Planned Sessions{% endblock %}
@@ -36,8 +37,10 @@
</div>
</div>
<div class="grid_12 alpha">
{% if plannedsessions %}
<p>
Click on session name to view
Click on session name to view, edit to change the session and on the
traffic light symbol to add workouts to the session
</p>
<table width="80%" class="listtable shortpadded">
<thead>
@@ -45,10 +48,11 @@
<th>After</th>
<th>Before</th>
<th>Name</th>
<th>Edit</th>
<th>Value</th>
<th>&nbsp;</th>
<th>Type</th>
<th>Done</th>
<th>Status</th>
<th>
</tr>
</thead>
@@ -66,13 +70,37 @@
href="/rowers/sessions/{{ ps.id }}">Unnamed Session</a>
{% endif %}
</td>
<td>
{% if ps.manager == request.user %}
<a class="small"
href="/rowers/sessions/{{ ps.id }}/edit">Edit</a>
{% else %}
&nbsp;
{% endif %}
</td>
<td> {{ ps.sessionvalue }} </td>
<td> {{ ps.sessionunit }} </td>
<td> {{ ps.sessiontype }} </td>
<td>
{% if completeness|lookup:ps.id == 'not done' %}
<a class="white dot" href="/rowers/sessions/manage/{{ timeperiod }}/rower/{{ rower.id }}">&nbsp;</a>
{% elif completeness|lookup:ps.id == 'completed' %}
<a class="green dot" href="/rowers/sessions/manage/{{ timeperiod }}/rower/{{ rower.id }}">&nbsp;</a>
{% elif completeness|lookup:ps.id == 'partial' %}
<a class="orange dot" href="/rowers/sessions/manage/{{ timeperiod }}/rower/{{ rower.id }}">&nbsp;</a>
{% else %}
<a class="red dot" href="/rowers/sessions/manage/{{ timeperiod }}/rower/{{ rower.id }}">&nbsp;</a>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
You have no planned workouts for this period. Planned workouts are created
by your coach if you are part of a team. You can create your own
planned workouts by purchasing the "Coach" or "Self-Coach" plans.
{% endif %}
</div>

View File

@@ -0,0 +1,74 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Planned Sessions{% endblock %}
{% block content %}
<div class="grid_12 alpha">
{% include "planningbuttons.html" %}
</div>
<div class="grid_6 alpha">
<h1>Manage Plan Execution for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
</div>
<div id="timeperiod" class="grid_2 dropdown">
<button class="grid_2 alpha button gray small dropbtn">Time Period</button>
<div class="dropdown-content">
<a class="button gray small alpha"
href="/rowers/sessions/manage/today/rower/{{ rower.id }}">
Today
</a>
<a class="button gray small alpha"
href="/rowers/sessions/manage/thisweek/rower/{{ rower.id }}">
This Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/manage/thismonth/rower/{{ rower.id }}">
This Month
</a>
<a class="button gray small alpha"
href="/rowers/sessions/manage/lastweek/rower/{{ rower.id }}">
Last Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/manage/lastmonth/rower/{{ rower.id }}">
Last Month
</a>
</div>
</div>
<div class="grid_12 alpha">
<p>Select one session on the left, and one or more workouts on the right
to match the workouts to the session. For tests and training sessions,
the selected workouts must be done on the same date. For all sessions,
the workout dates must be between the start and end date for the
session.
</p>
<p>
If you select a workout that has already been matched to another session,
it will change to match this session.
</p>
<p>
We will make this form smarter in the near future.
</p>
</div>
<form id="session_form" action="/rowers/sessions/manage/{{ timeperiod }}/rower/{{ rower.id }}"
method="post">
<div class="grid_12 alpha">
<div class="grid_6 alpha">
{{ ps_form.as_table}}
</div>
<div class="grid_6 omega">
{{ w_form.as_table}}
</div>
</div>
<div class="grid_2 prefix_2 suffix_8">
{% csrf_token %}
<input class="button green" type="submit" value="Submit">
</div>
</form>
</form>
{% endblock %}

View File

@@ -1,5 +1,6 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Planned Session{% endblock %}
@@ -10,7 +11,7 @@
</div>
<div id="left" class="grid_6 alpha">
<h1>Session {{ psdict.name.1 }}</h1>
<table class="listtable shortpadded">
<table class="listtable shortpadded" width="80%">
{% for attr in attrs %}
{% for key,value in psdict.items %}
{% if key == attr %}
@@ -21,9 +22,36 @@
{% endfor %}
{% endfor %}
</table>
<h1>Result</h1>
<p>Status: {{ status }}</p>
<p>Percentage complete: {{ ratio }} </p>
</div>
<div id="right" class="grid_6 omega">
<p>&nbsp;</p>
<h1>Workouts attached</h1>
<table class="listtable shortpadded" width="80%">
<thead>
<tr>
<th>Date</th>
<th>Name</th>
<th>Distance</th>
<th>Duration</th>
</tr>
</thead>
<tbody>
{% for workout in workouts %}
<tr>
<td> {{ workout.date|date:"Y-m-d" }} </td>
<td>
<a href={% url manager.defaultlandingpage id=workout.id %}>
{{ workout.name }}
</a>
</td>
<td> {{ workout.distance }}m</td>
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
</tr>
{% endfor %}
</tbody>
</table>
</div>

View File

@@ -0,0 +1,48 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Planned Sessions{% endblock %}
{% block content %}
<div class="grid_12 alpha">
{% include "planningbuttons.html" %}
</div>
<div class="grid_6 alpha">
<h1>Plan for {{ rower.user.first_name }} {{ rower.user.last_name }}</h1>
</div>
<div id="timeperiod" class="grid_2 dropdown">
<button class="grid_2 alpha button gray small dropbtn">Time Period</button>
<div class="dropdown-content">
<a class="button gray small alpha"
href="/rowers/sessions/today/rower/{{ rower.id }}">
Today
</a>
<a class="button gray small alpha"
href="/rowers/sessions/thisweek/rower/{{ rower.id }}">
This Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/thismonth/rower/{{ rower.id }}">
This Month
</a>
<a class="button gray small alpha"
href="/rowers/sessions/lastweek/rower/{{ rower.id }}">
Last Week
</a>
<a class="button gray small alpha"
href="/rowers/sessions/lastmonth/rower/{{ rower.id }}">
Last Month
</a>
</div>
</div>
<div class="grid_12 alpha">
<p>
Click on session name to view
</p>
</div>
</form>
{% endblock %}

View File

@@ -401,6 +401,14 @@ urlpatterns = [
url(r'^sessions/(?P<id>\d+)$',views.plannedsession_view),
url(r'^sessions/(?P<id>\d+)/deleteconfirm$',views.plannedsession_deleteconfirm_view),
url(r'^sessions/(?P<id>\d+)/delete$',views.plannedsession_delete_view),
url(r'^sessions/manage/?$',
views.plannedsessions_manage_view),
url(r'^sessions/manage/rower/(?P<rowerid>\d+)$',
views.plannedsessions_manage_view),
url(r'^sessions/manage/(?P<timeperiod>[\w\ ]+.*)/rower/(?P<rowerid>\d+)$',
views.plannedsessions_manage_view),
url(r'^sessions/manage/(?P<timeperiod>[\w\ ]+.*)$',
views.plannedsessions_manage_view),
url(r'^sessions/?$',views.plannedsessions_view),
url(r'^sessions/rower/(?P<rowerid>\d+)$',views.plannedsessions_view),
url(r'^sessions/(?P<timeperiod>[\w\ ]+.*)/rower/(?P<rowerid>\d+)$',views.plannedsessions_view),

View File

@@ -30,7 +30,7 @@ from rowers.forms import (
LoginForm,DocumentsForm,UploadOptionsForm,ImageForm,
TeamUploadOptionsForm,WorkFlowLeftPanelForm,WorkFlowMiddlePanelForm,
WorkFlowLeftPanelElement,WorkFlowMiddlePanelElement,
LandingPageForm,
LandingPageForm,PlannedSessionSelectForm,WorkoutSessionSelectForm
)
from django.core.urlresolvers import reverse
from django.core.exceptions import PermissionDenied
@@ -606,6 +606,7 @@ def rowhascoordinates(row):
if rowdata != 0:
try:
latitude = rowdata.df[' latitude']
if not latitude.std():
hascoordinates = 0
except KeyError,AttributeError:
@@ -11765,48 +11766,110 @@ def plannedsessions_view(request,timeperiod='today',rowerid=0):
if not checkaccessuser(request.user,r):
raise Http404("You don't have access to this plan")
# set start end date according timeperiod
if timeperiod=='today':
startdate=datetime.date.today()
enddate=datetime.date.today()
elif timeperiod=='tomorrow':
startdate=datetime.date.today()+timezone.timedelta(days=1)
enddate=datetime.date.today()+timezone.timedelta(days=1)
elif timeperiod=='thisweek':
today = datetime.date.today()
startdate = datetime.date.today()-timezone.timedelta(days=today.weekday())
enddate = startdate+timezone.timedelta(weeks=1)
elif timeperiod=='thismonth':
today = datetime.date.today()
startdate = today.replace(day=1)
enddate = startdate+timezone.timedelta(days=32)
enddate = enddate.replace(day=1)
elif timeperiod=='lastweek':
today = datetime.date.today()
enddate = today-timezone.timedelta(days=today.weekday())
startdate = enddate-timezone.timedelta(days=7)
elif timeperiod=='lastmonth':
today = datetime.date.today()
startdate = today.replace(day=1)
startdate = startdate-timezone.timedelta(days=3)
startdate = startdate.replace(day=1)
enddate = startdate+timezone.timedelta(days=32)
enddate = enddate.replace(day=1)
else:
startdate = datetime.date.today()
enddate = datetime.date.today()
startdate,enddate = get_dates_timeperiod(timeperiod)
sps = get_sessions(r,startdate=startdate,enddate=enddate)
completeness = {}
for ps in sps:
ratio,status = is_session_complete(r,ps)
completeness[ps.id] = status
return render(request,'plannedsessions.html',
{
'teams':get_my_teams(request.user),
'plannedsessions':sps,
'rower':r,
'timeperiod':timeperiod,
'completeness':completeness,
})
@login_required()
def plannedsessions_manage_view(request,timeperiod='today',rowerid=0):
if rowerid==0:
r = getrower(request.user)
else:
try:
r = Rower.objects.get(id=rowerid)
except Rower.DoesNotExist:
raise Http404("This rower doesn't exist")
if not checkaccessuser(request.user,r):
raise Http404("You don't have access to this plan")
startdate,enddate = get_dates_timeperiod(timeperiod)
sps = get_sessions(r,startdate=startdate,enddate=enddate)
ws = Workout.objects.filter(
user=r,date__gte=startdate,
date__lte=enddate
).order_by(
"date","id"
)
plannedsessionstuple = []
for ps in sps:
sessiontpl = (ps.id,ps.__unicode__())
plannedsessionstuple.append(sessiontpl)
plannedsessionstuple = tuple(plannedsessionstuple)
workoutdata = {}
workoutdata['initial'] = []
choices = []
for w in ws:
wtpl = (w.id, w.__unicode__())
choices.append(wtpl)
workoutdata['choices'] = tuple(choices)
if request.method == 'POST':
ps_form = PlannedSessionSelectForm(plannedsessionstuple,request.POST)
w_form = WorkoutSessionSelectForm(workoutdata,request.POST)
if ps_form.is_valid():
ps = PlannedSession.objects.get(id=ps_form.cleaned_data['plannedsession'])
if w_form.is_valid():
selectedworkouts = w_form.cleaned_data['workouts']
else:
selectedworkouts = []
if selectedworkouts:
workouts = Workout.objects.filter(user=r,id__in=selectedworkouts)
for w in ws:
if w.id not in selectedworkouts:
remove_workout_plannedsession(w,ps)
result,comments,errors = add_workouts_plannedsession(workouts,ps)
for c in comments:
messages.info(request,c)
for er in errors:
messages.error(request,er)
ps_form = PlannedSessionSelectForm(plannedsessionstuple)
w_form = WorkoutSessionSelectForm(workoutdata=workoutdata)
return render(request,'plannedsessionsmanage.html',
{
'teams':get_my_teams(request.user),
'plannedsessions':sps,
'workouts':ws,
'timeperiod':timeperiod,
'rower':r,
'ps_form':ps_form,
'w_form':w_form,
})
# Edit an existing planned session
@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/",
@@ -11864,9 +11927,14 @@ def plannedsession_edit_view(request,id=0):
@login_required()
def plannedsession_view(request,id=0):
def plannedsession_view(request,id=0,rowerid=0):
r = getrower(request.user)
m = getrower(request.user)
if not rowerid:
r = m
else:
r = Rower.objects.get(id=rowerid)
try:
ps = PlannedSession.objects.get(id=id)
@@ -11879,13 +11947,27 @@ def plannedsession_view(request,id=0):
psdict = my_dict_from_instance(ps,PlannedSession)
ws = get_workouts_session(r,ps)
ratio,status = is_session_complete(r,ps)
print ratio
ratio = int(100.*ratio)
return render(request,'plannedsessionview.html',
{
'psdict': psdict,
'attrs':[
'name','startdate','enddate','sessiontype',
]
'sessionvalue','sessionunit'
],
'workouts': ws,
'manager':m,
'rower':r,
'ratio':ratio,
'status':status
}
)
@@ -11902,6 +11984,11 @@ def plannedsession_delete_view(request,id=0):
if ps.manager != request.user:
raise Http404("You are not allowed to delete this planned session")
ws = Workout.objects.filter(plannedsession=ps)
for w in ws:
w.plannedsession=None
w.save()
ps.delete()
url = reverse(plannedsessions_view)