Private
Public Access
1
0

Merge branch 'release/v15.7.0'

This commit is contained in:
Sander Roosendaal
2021-03-10 11:10:00 +01:00
8 changed files with 207 additions and 3 deletions

View File

@@ -184,7 +184,7 @@ ratelim==0.1.6
redis==3.5.3 redis==3.5.3
requests==2.23.0 requests==2.23.0
requests-oauthlib==1.2.0 requests-oauthlib==1.2.0
rowingdata==3.1.8 rowingdata==3.2.7
rowingphysics==0.5.0 rowingphysics==0.5.0
rq==0.13.0 rq==0.13.0
rules==2.1 rules==2.1

View File

@@ -1531,6 +1531,15 @@ class TrainingTargetForm(ModelForm):
).distinct().order_by("user__last_name","user__first_name") ).distinct().order_by("user__last_name","user__first_name")
class InstantPlan(models.Model):
uuid = models.UUIDField(primary_key=False,editable=True,default=uuid.uuid4)
owner = models.ForeignKey(User,on_delete=models.SET_NULL,null=True)
name = models.CharField(max_length=150,blank=True)
goal = models.CharField(max_length=150,blank=True)
description = models.TextField(max_length=300,blank=True)
duration = models.IntegerField(default=6)
target = models.TextField(max_length=300,blank=True)
hoursperweek = models.IntegerField(default=4)
@python_2_unicode_compatible @python_2_unicode_compatible

View File

@@ -30,6 +30,8 @@ import pandas as pd
from rowingdata import rowingdata as rrdata from rowingdata import rowingdata as rrdata
from rowingdata import rower as rrower from rowingdata import rower as rrower
from rowers.opaque import encoder
def to_pace(pace): def to_pace(pace):
minutes, seconds = divmod(pace,60) minutes, seconds = divmod(pace,60)
seconds, rest = divmod(seconds, 1) seconds, rest = divmod(seconds, 1)
@@ -455,7 +457,7 @@ def add_workouts_plannedsession(ws,ps,r):
w.plannedsession = ps w.plannedsession = ps
w.save() w.save()
result += 1 result += 1
comments.append('Attached workout %i to session' % w.id) comments.append('Attached workout %s to session' % encoder.encode_hex(w.id))
if ps.sessiontype == 'coursetest': if ps.sessiontype == 'coursetest':
record = CourseTestResult( record = CourseTestResult(
userid=w.user.id, userid=w.user.id,

View File

@@ -0,0 +1,43 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}{{ plan.name }}{% endblock %}
{% block main %}
<h1>{{ plan.name }}</h1>
<ul class="main-content">
<li class="grid_4">
<table width="100%" class="listtable">
<thead>
<tr>
<th>Week</th>
<th>Day</th>
<th>Workouts</th>
</tr>
</thead>
<tbody>
{% for day in trainingdays %}
<tr>
<td>{{ day.week }}</td>
<td>{{ day.order }}</td>
<td>
{% for workout in day.workouts %}
<h3>{{ workout.workoutName }}</h3>
{{ workout|steptostring|safe }}
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</li>
</ul>
{% endblock %}
{% block sidebar %}
{% include 'menu_plan.html' %}
{% endblock %}

View File

@@ -0,0 +1,24 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Rowsandall Training Plans{% endblock %}
{% block main %}
<h1>Training Plans</h1>
<ul class="main-content">
{% for plan in trainingdict %}
<li>
<p><a href="/rowers/plans/{{ plan.ID }}">{{ plan.name }}</a></p>
<p>{{ plan.plan|lookup:"duration"}}</p>
</li>
{% endfor %}
</ul>
{% endblock %}
{% block sidebar %}
{% include 'menu_plan.html' %}
{% endblock %}

View File

@@ -26,12 +26,13 @@ from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispr
from rowers.mytypes import ( from rowers.mytypes import (
otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes, otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes,
) )
from rowers.utils import NoTokenError from rowers.utils import NoTokenError, step_to_string
import rowers.payments as payments import rowers.payments as payments
from rowers.opaque import encoder from rowers.opaque import encoder
from rowers.plannedsessions import ps_dict_get_description_html
import arrow import arrow
@@ -70,6 +71,11 @@ favanalysisicons = {
'cp':'fa-user-chart', 'cp':'fa-user-chart',
} }
@register.filter
def steptostring(steps):
res = ps_dict_get_description_html(steps)
return res
# for verbose version of fav analysis # for verbose version of fav analysis
@register.filter @register.filter
def verbose(s): def verbose(s):

View File

@@ -740,6 +740,9 @@ urlpatterns = [
re_path(r'^test\_callback',views.rower_process_testcallback,name='rower_process_testcallback'), re_path(r'^test\_callback',views.rower_process_testcallback,name='rower_process_testcallback'),
re_path(r'^createplan/$',views.rower_create_trainingplan,name='rower_create_trainingplan'), re_path(r'^createplan/$',views.rower_create_trainingplan,name='rower_create_trainingplan'),
re_path(r'^createplan/user/(?P<id>\d+)/$',views.rower_create_trainingplan,name='rower_create_trainingplan'), re_path(r'^createplan/user/(?P<id>\d+)/$',views.rower_create_trainingplan,name='rower_create_trainingplan'),
re_path(r'^plans/$', views.rower_select_instantplan, name='rower_select_instantplan'),
re_path(r'^plans/(?P<id>[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12})/$',
views.rower_view_instantplan, name='rower_view_instantplan'),
re_path(r'^deleteplan/(?P<pk>\d+)/$',login_required( re_path(r'^deleteplan/(?P<pk>\d+)/$',login_required(
views.TrainingPlanDelete.as_view()),name='trainingplan_delete_view'), views.TrainingPlanDelete.as_view()),name='trainingplan_delete_view'),
re_path(r'^deletemicrocycle/(?P<pk>\d+)/$',login_required( re_path(r'^deletemicrocycle/(?P<pk>\d+)/$',login_required(

View File

@@ -2425,6 +2425,123 @@ class PlannedSessionDelete(DeleteView):
return obj return obj
@user_passes_test(can_plan,login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def rower_view_instantplan(request,id='',userid=0):
r = getrequestrower(request,userid=userid)
if not id:
raise Http404("Plan does not exist")
authorizationstring = 'Bearer '+settings.WORKOUTS_FIT_TOKEN
url = settings.WORKOUTS_FIT_URL+"/trainingplan/"+id
headers = {'Authorization':authorizationstring}
response = requests.get(url=url,headers=headers)
if response.status_code != 200:
messages.error(request,"Could not connect to the training plan server")
return HttpResponseRedirect(reverse('rower_select_instantplan'))
plan = response.json()
trainingdays = plan['plan']['trainingDays']
trainingdays2 = []
nextday = trainingdays.pop(0)
for i in range(plan['plan']['duration']):
if nextday['order'] == i+1:
nextday['week'] = (divmod(i,7)[0])+1
trainingdays2.append(nextday)
try:
nextday = trainingdays.pop(0)
except IndexError:
continue
else:
trainingdays2.append(
{
'order':i+1,
'week': (divmod(i,7)[0])+1,
'workouts':[]
}
)
breadcrumbs = [
{
'url':reverse('plannedsessions_view'),
'name': 'Sessions'
},
{
'url':reverse(rower_create_trainingplan,
kwargs={'id':userid}),
'name': 'Manage Plans and Targets'
},
{
'url':reverse('rower_select_instantplan'),
'name': 'Select Existing Plans'
},
{
'url':reverse('rower_view_instantplan',kwargs={
'id':id,
# 'userid':userid,
}),
'name':plan['name']
}
]
return render(request,
'instantplan.html',
{
'rower':r,
'active':'nav-plan',
'plan':plan,
'trainingdays':trainingdays2,
})
@user_passes_test(can_plan,login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def rower_select_instantplan(request,id=0):
r = getrequestrower(request,userid=id)
themanager = getrower(request.user)
# get and present available plans
authorizationstring = 'Bearer '+settings.WORKOUTS_FIT_TOKEN
url = settings.WORKOUTS_FIT_URL+"/trainingplan/"
headers = {'Authorization':authorizationstring}
trainingdict = {}
response = requests.get(url=url, headers=headers)
if response.status_code != 200:
messages.error(request,"Could not connect to the training plan server")
else:
trainingdict = response.json()['plans']
breadcrumbs = [
{
'url':reverse('plannedsessions_view'),
'name': 'Sessions'
},
{
'url':reverse(rower_create_trainingplan,
kwargs={'id':id}),
'name': 'Manage Plans and Targets'
},
{
'url':reverse('rower_select_instantplan'),
'name': 'Select Existing Plans'
}
]
return render(request,
'instantplans.html',
{
'rower':r,
'active':'nav-plan',
'trainingdict':trainingdict,
})
@user_passes_test(can_plan,login_url="/rowers/paidplans", @user_passes_test(can_plan,login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan", message="This functionality requires a Coach or Self-Coach plan",