Private
Public Access
1
0

Merge branch 'release/v8.27'

This commit is contained in:
Sander Roosendaal
2018-10-28 16:47:20 +01:00
15 changed files with 447 additions and 132 deletions

View File

@@ -846,7 +846,8 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
pass
return new_workout_from_df(r, newdf,
title=title,boattype=boattype,
workouttype=workouttype)
workouttype=workouttype,
workoutsource=workoutsource)
try:
checks = row.check_consistency()
allchecks = 1
@@ -1178,6 +1179,7 @@ def handle_nonpainsled(f2, fileformat, summary=''):
def new_workout_from_file(r, f2,
workouttype='rower',
workoutsource=None,
title='Workout',
boattype='1x',
makeprivate=False,
@@ -1272,13 +1274,16 @@ def new_workout_from_file(r, f2,
dosummary = (fileformat != 'fit' and 'speedcoach2' not in fileformat)
dosummary = dosummary or summary == ''
if workoutsource is None:
workoutsource = fileformat
id, message = save_workout_database(
f2, r,
workouttype=workouttype,
boattype=boattype,
makeprivate=makeprivate,
dosummary=dosummary,
workoutsource=fileformat,
workoutsource=workoutsource,
summary=summary,
inboard=inboard, oarlength=oarlength,
title=title
@@ -1389,6 +1394,7 @@ def split_workout(r, parent, splitsecond, splitmode):
def new_workout_from_df(r, df,
title='New Workout',
workoutsource='unknown',
boattype='1x',
workouttype='rower',
parent=None,
@@ -1403,7 +1409,7 @@ def new_workout_from_df(r, df,
oarlength = parent.oarlength
inboard = parent.inboard
workoutsource = parent.workoutsource
workouttype = parent.workouttype
boattype = parent.boattype
notes = parent.notes
@@ -1451,6 +1457,7 @@ def new_workout_from_df(r, df,
workouttype=workouttype,
boattype=boattype,
title=title,
workoutsource=workoutsource,
notes=notes,
oarlength=oarlength,
inboard=inboard,

View File

@@ -298,6 +298,7 @@ def add_c2_stroke_data_db(strokedata,workoutid,starttimeunix,csvfilename,
def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
dosummary=True,title='Workout',
notes='',totaldist=0,totaltime=0,
workoutsource='unknown',
summary='',
makeprivate=False,
oarlength=2.89,inboard=0.88):
@@ -430,15 +431,16 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
w = Workout(user=r,name=title,date=workoutdate,
workouttype=workouttype,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=f2,notes=notes,summary=summary,
maxhr=maxhr,averagehr=averagehr,
startdatetime=workoutstartdatetime,
inboard=inboard,oarlength=oarlength,
privacy=privacy)
workouttype=workouttype,
workoutsource=workoutsource,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=f2,notes=notes,summary=summary,
maxhr=maxhr,averagehr=averagehr,
startdatetime=workoutstartdatetime,
inboard=inboard,oarlength=oarlength,
privacy=privacy)
w.save()

View File

@@ -751,11 +751,14 @@ parchoicesx = list(sorted(favchartlabelsx.items(), key = lambda x:x[1]))
# Saving a chart as a favorite chart
class FavoriteChart(models.Model):
workouttypechoices = (
workouttypechoices = [
('ote','Erg/SkiErg'),
('otw','On The Water'),
('both','both')
)
('all','All')
]
for workoutsource in mytypes.workoutsources:
workouttypechoices.append(workoutsource)
plottypes = (
('line','Line Chart'),
@@ -771,6 +774,7 @@ class FavoriteChart(models.Model):
workouttype = models.CharField(max_length=50,choices=workouttypechoices,
default='both',
verbose_name='Workout Type')
reststrokes = models.BooleanField(default=True,verbose_name="Incl. Rest")
notes = models.CharField(max_length=300,verbose_name='Chart Notes',
default='Flex Chart Notes',blank=True)
@@ -930,7 +934,8 @@ def a_week_from_now():
# models related to training planning - draft
# Do we need a separate class TestTarget?
class TrainingTarget(models.Model):
rower = models.ForeignKey(Rower)
rower = models.ForeignKey(Rower,related_name='targetathlete')
manager = models.ForeignKey(Rower,related_name='targetmanager',null=True)
name = models.CharField(max_length=150,blank=True)
date = models.DateField(
default=half_year_from_now)
@@ -978,7 +983,8 @@ class TrainingTargetForm(ModelForm):
class TrainingPlan(models.Model):
rower = models.ForeignKey(Rower)
rower = models.ForeignKey(Rower,related_name='planathlete')
manager = models.ForeignKey(Rower,related_name='planmanager',null=True)
name = models.CharField(max_length=150,blank=True)
target = models.ForeignKey(TrainingTarget,blank=True,null=True)
startdate = models.DateField(default=timezone.now)

View File

@@ -30,14 +30,14 @@ workoutsources = (
('mapmyfitness','mapmyfitness'),
('csv','painsled'),
('tcx','tcx'),
('rp','rp'),
('rp','rowperfect'),
('mystery','mystery'),
('tcxnohr','tcx (no HR)'),
# ('tcxnohr','tcx (no HR)'),
('rowperfect3','rowperfect3'),
('ergdata','ergdata'),
('boatcoach','boatcoach'),
('boatcoachotw','boatcoachotw'),
('bcmike','boatcoach (develop)'),
# ('bcmike','boatcoach (develop)'),
('painsleddesktop','painsleddesktop'),
('speedcoach','speedcoach'),
('speedcoach2','speedcoach2'),
@@ -52,6 +52,7 @@ boattypes = (
('2-', '2- (pair)'),
('2+', '2+ (coxed pair)'),
('3x+','3x+ (coxed triple)'),
('3x-','3x- (triple)'),
('4x', '4x (quad)'),
('4x+', '4x+ (coxed quad)'),
('4-', '4- (four)'),

View File

@@ -41,13 +41,11 @@
<i class="fal fa-table fa-fw"></i>&nbsp;Statistics
</a>
</li>
<!--
<li id="compare">
<a href="/rowers/multi-compare">
<i class="fas fa-balance-scale fa-fw"></i>&nbsp;Compare
<li id="compare">
<a href="/rowers/multi-compare/workout/{{ workout.id }}">
<i class="fas fa-balance-scale fa-fw"></i>&nbsp;Compare
</a>
</li>
-->
</li>
{% if user.is_authenticated and workout|may_edit:request %}
<li id="chart-image">
<a href="/rowers/workout/{{ workout.id }}/image">

View File

@@ -100,7 +100,7 @@
<td> {{ actualvalue|lookup:ps.id }}</td>
<td> {{ ps.sessionunit }} </td>
{% if completeness|lookup:ps.id == 'partial' %}
<td style="color:darkgray"><i> {{ completiondate|lookup:ps.id|date:"Y-m-d" }}</i></td>
<td style="color:darkgray"><em> {{ completiondate|lookup:ps.id|date:"Y-m-d" }}</em></td>
{% else %}
<td> {{ completiondate|lookup:ps.id|date:"Y-m-d" }}</td>
{% endif %}

View File

@@ -83,6 +83,31 @@
your workouts. That makes it easy to search.
</p>
</li>
<li class="grid_2">
<form enctype="multipart/form-data"
action="/rowers/team-compare-select/team/{{ team.id }}"
method="post">
<table>
{{ dateform.as_table }}
</table>
<table>
{{ modalityform.as_table }}
</table>
{% csrf_token %}
<p>
<input name='modalityform' class="button green" type="submit" value="Filter">
</p>
</form>
</li>
<li class="grid_2">
<form id="searchform" action=""
method="get" accept-charset="utf-8">
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
<button class="button blue small" type="submit">
Search
</button>
</form>
</li>
<li class="grid_2 maxheight">
{% if workouts %}
<form enctype="multipart/form-data" action="/rowers/multi-compare" method="post">
@@ -109,42 +134,6 @@
</p>
</form>
</li>
<li class="grid_2">
{% if team %}
<form enctype="multipart/form-data"
action="/rowers/team-compare-select/team/{{ team.id }}"
method="post">
{% else %}
<form enctype="multipart/form-data"
action="/rowers/team-compare-select/"
method="post">
{% endif %}
<table>
{{ dateform.as_table }}
</table>
<table>
{{ modalityform.as_table }}
</table>
{% csrf_token %}
<p>
<input name='modalityform' class="button green" type="submit" value="Submit">
</p>
</form>
</li>
<li class="grid_2">
{% if team %}
<form id="searchform" action=""
method="get" accept-charset="utf-8">
{% else %}
<form id="searchform" action="/rowers/team-compare-select/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
method="get" accept-charset="utf-8">
{% endif %}
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
<button class="button blue small" type="submit">
Search
</button>
</form>
</li>
</ul>
{% endblock %}

View File

@@ -12,14 +12,16 @@
The training plan target is: {{ plan.target.name }} on {{ plan.target.date }}.
{% endif %}
</p>
{% if plan|mayeditplan:request %}
<p><a href="/rowers/editplan/{{ plan.id }}">Edit the plan</a></p>
{% endif %}
<h2>Plan Macro, Meso and Micro Cycles</h2>
<ul class="cd-accordion-menu animated">
<!-- Start Macrocycle For Loop -->
{% for key, macrocycle in cycles.items %}
<li class="has-children" id="macros">
<li class="has-kids" id="macros">
<input type="checkbox" name="macro-selector" id="macro-selector-{{ macrocycle.0.id }}">
<label for="macro-selector-{{ macrocycle.0.id }}">Macro Cycle {{ macrocycle.0.name }} ({{ macrocycle.0.startdate }} - {{ macrocycle.0.enddate }})</label>
<ul>
@@ -39,10 +41,12 @@
</tr>
<tr>
<td colspan="4">
{% if macrocycle.0|mayeditplan:request %}
<a href="/rowers/macrocycle/{{ macrocycle.0.id }}/">edit</a>
/
<a href="/rowers/deletemacrocycle/{{ macrocycle.0.id }}/">delete</a>
/
{% endif %}
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
</td>
</tr>
@@ -95,10 +99,16 @@
</tr>
<tr>
<td colspan="4">
{% if macrocycle.0|mayeditplan:request %}
<a href="/rowers/macrocycle/{{ macrocycle.0.id }}/">edit</a>
/
<a href="/rowers/deletemacrocycle/{{ macrocycle.0.id }}/">delete</a>
/
<a href="/rowers/macrocycle/{{ macrocycle.0.id }}/planbymonths/user/{{ rower.user.id }}">
Replan by Months
</a>
/
{% endif %}
<a href='/rowers/sessions/{{ macrocycle.0.startdate|date:"Y-m-d" }}/{{ macrocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
</td>
</tr>
@@ -117,7 +127,7 @@
</div>
{% endif %}
</li>
<li class="has-children" id="mesos">
<li class="has-kids" id="mesos">
<input type="checkbox" name="meso-selector" id="meso-selector-{{ macrocycle.0.id }}">
<label for="meso-selector-{{ macrocycle.0.id }}">Meso Cycles</label>
<ul>
@@ -140,10 +150,12 @@
</tr>
<tr>
<td colspan="4">
{% if mesocycle.0|mayeditplan:request %}
<a href="/rowers/mesocycle/{{ mesocycle.0.id }}/">edit</a>
/
<a href="/rowers/deletemesocycle/{{ mesocycle.0.id }}/">delete</a>
/
{% endif %}
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
</td>
</tr>
@@ -197,10 +209,16 @@
</tr>
<tr>
<td colspan="4">
{% if mesocycle.0|mayeditplan:request %}
<a href="/rowers/mesocycle/{{ mesocycle.0.id }}/">edit</a>
/
<a href="/rowers/deletemesocycle/{{ mesocycle.0.id }}/">delete</a>
/
<a href="/rowers/mesocycle/{{ mesocycle.0.id }}/planbyweeks/user/{{ rower.user.id }}">
Replan by Weeks
</a>
/
{% endif %}
<a href='/rowers/sessions/{{ mesocycle.0.startdate|date:"Y-m-d" }}/{{ mesocycle.0.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
</td>
</tr>
@@ -219,7 +237,7 @@
</div>
{% endif %}
</li>
<li class="has-children" id="micros">
<li class="has-kids" id="micros">
<input type="checkbox" name="micro-selector"
id="micro-selector-{{ macrocycle.0.id }}-{{ mesocycle.0.id }}">
<label
@@ -247,10 +265,12 @@
</tr>
<tr>
<td colspan="4">
{% if microcycle|mayeditplan:request %}
<a href="/rowers/microcycle/{{ microcycle.id }}/">edit</a>
/
<a href="/rowers/deletemicrocycle/{{ microcycle.id }}/">delete</a>
/
{% endif %}
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
</td>
</tr>
@@ -306,10 +326,12 @@
</tr>
<tr>
<td colspan="4">
{% if microcycle|mayeditplan:request %}
<a href="/rowers/microcycle/{{ microcycle.id }}">edit</a>
/
<a href="/rowers/deletemicrocycle/{{ microcycle.id }}">delete</a>
/
{% endif %}
<a href='/rowers/sessions/{{ microcycle.startdate|date:"Y-m-d" }}/{{ microcycle.enddate|date:"Y-m-d" }}/user/{{ rower.user.id }}'>sessions</a>
</td>
</tr>

View File

@@ -74,7 +74,9 @@ $('#id_workouttype').change();
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr><tr>
<th>Public link to this workout</th>
<th>Source:</th><td>{{ workout.workoutsource }}</td>
</tr><tr>
<th>Public link to this workout:</th>
<td>
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
</td>

View File

@@ -10,7 +10,8 @@ register = template.Library()
from rowers.utils import calculate_age
from rowers.models import (
course_length,WorkoutComment,
TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle
TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle,
Rower
)
from rowers.plannedsessions import (
race_can_register, race_can_submit,race_rower_status
@@ -19,7 +20,7 @@ from rowers.plannedsessions import (
from rowers import c2stuff, runkeeperstuff
from rowers.c2stuff import c2_open
from rowers.runkeeperstuff import runkeeper_open
from rowers.models import checkaccessuser
from rowers.mytypes import otwtypes
from rowers.utils import NoTokenError
@@ -182,6 +183,29 @@ def may_edit(workout,request):
return mayedit
@register.filter
def mayeditplan(obj,request):
if obj is None:
return False
if hasattr(obj,'plan'):
return mayeditplan(obj.plan,request)
if hasattr(obj,'manager'):
if obj.manager is not None:
return request.user == obj.manager.user
rr = Rower.objects.get(user=request.user)
if checkaccessuser(request.user,obj.rower) and rr.rowerplan not in ['basic','pro']:
mayedit = True
return mayedit
@register.filter(name='times')
def times(number):
return range(number)

View File

@@ -1046,6 +1046,7 @@ boattype: 4x
a = MessageAttachment(message=m,document=a2[6:])
a.save()
def tearDown(self):
for filename in os.listdir('media/mailbox_attachments'):
path = os.path.join('media/mailbox_attachments/',filename)
@@ -2137,6 +2138,7 @@ class URLTests(TestCase):
'/rowers/sessions/teamcreate/',
'/rowers/sessions/user/1',
'/rowers/team-compare-select/',
'/rowers/team-compare-select/workout/1',
'/rowers/team-compare-select/2016-01-01/2016-12-31',
'/rowers/test-job/2',
'/rowers/test-job2/2',

View File

@@ -26,7 +26,7 @@ queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from mytypes import workouttypes,boattypes,otwtypes
from mytypes import workouttypes,boattypes,otwtypes,workoutsources
try:
from cStringIO import StringIO
@@ -49,6 +49,18 @@ def cleanbody(body):
return body
sources = [s for s,name in workoutsources]
def matchsource(line):
results = []
for s in sources:
testert = '^source.*(%s)' % s
tester = re.compile(testert)
if tester.match(line.lower()):
return group(1)
# currently only matches one chart
def matchchart(line):
results = []
@@ -147,6 +159,14 @@ def getprivateoptions_body2(uploadoptions,body):
return uploadoptions
def getworkoutsources(uploadoptions,body):
for line in body.splitlines():
workoutsource = matchsource(line)
if workoutsource:
uploadoptions['workoutsource'] = workoutsource
return uploadoptions
def getplotoptions_body2(uploadoptions,body):
for line in body.splitlines():
chart = matchchart(line)
@@ -241,6 +261,17 @@ def getboattype(uploadoptions,value,key):
return uploadoptions
def getsource(uploadoptions,value,key):
workoutsource = 'unknown'
for type,verb in workoutsources:
if value == type:
workoutsource = type
if value == verb:
workoutsource = type
uploadoptions[key] = workoutsource
return uploadoptions
def getboolean(uploadoptions,value,key):
b = True
@@ -273,6 +304,8 @@ def upload_options(body):
uploadoptions = gettype(uploadoptions,value,'workouttype')
if 'boat' in lowkey:
uploadoptions = getboattype(uploadoptions,value,'boattype')
if 'source' in lowkey:
uploadoptions = getsource(uploadoptions,value,'workoutsource')
except AttributeError:
#pass
raise yaml.YAMLError
@@ -283,6 +316,7 @@ def upload_options(body):
uploadoptions = getprivateoptions_body2(uploadoptions,body)
typeoptions = gettypeoptions_body2(uploadoptions,body)
uploadoptions = getstravaid(uploadoptions,body)
uploadoptions = getworkoutsources(uploadoptions,body)
except IOError:
pm = exc.problem_mark
strpm = str(pm)
@@ -377,6 +411,13 @@ def set_workouttype(w,options):
return 1
def set_workoutsource(w,options):
try:
w.workoutsource = options['workoutsource']
w.save()
except KeyError:
pass
def make_private(w,options):
if 'makeprivate' in options and options['makeprivate']:
w.privacy = 'hidden'

View File

@@ -156,8 +156,13 @@ urlpatterns = [
url(r'^courses/upload$',views.course_upload_view),
url(r'^addmanual/$',views.addmanual_view),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/team/(?P<teamid>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.team_comparison_select),
url(r'^team-compare-select/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.team_comparison_select),
url(r'^team-compare-select/workout/(?P<id>\d+)/$',views.team_comparison_select),
url(r'^team-compare-select/team/(?P<teamid>\d+)$',views.team_comparison_select),
url(r'^team-compare-select/$',views.team_comparison_select),
url(r'^workouts-join-select/team/(?P<teamid>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.workouts_join_select),
url(r'^workouts-join$',views.workouts_join_view),
@@ -328,6 +333,7 @@ urlpatterns = [
url(r'^workout/(?P<id>\d+)/runkeeperuploadw/$',views.workout_runkeeper_upload_view),
url(r'^workout/(?P<id>\d+)/underarmouruploadw/$',views.workout_underarmour_upload_view),
url(r'^workout/(?P<id>\d+)/tpuploadw/$',views.workout_tp_upload_view),
url(r'^multi-compare/workout/(?P<id>\d+)$',views.multi_compare_view),
url(r'^multi-compare$',views.multi_compare_view),
url(r'^user-boxplot/user/(?P<userid>\d+)$',views.boxplot_view),
url(r'^user-boxplot$',views.boxplot_view),
@@ -435,6 +441,10 @@ urlpatterns = [
name='macrocycle_update_view'),
url(r'^mesocycle/(?P<pk>\d+)/$',views.TrainingMesoCycleUpdate.as_view(),
name='mesocycle_update_view'),
url(r'^macrocycle/(?P<id>\d+)/planbymonths/$',views.planmacrocyclebymonth),
url(r'^macrocycle/(?P<id>\d+)/planbymonths/user/(?P<userid>\d+)/$',views.planmacrocyclebymonth),
url(r'^mesocycle/(?P<id>\d+)/planbyweeks/$',views.planmesocyclebyweek),
url(r'^mesocycle/(?P<id>\d+)/planbyweeks/user/(?P<userid>\d+)/$',views.planmesocyclebyweek),
url(r'^microcycle/(?P<pk>\d+)/$',views.TrainingMicroCycleUpdate.as_view(),
name='microcycle_update_view'),
url(r'^deletetarget/(?P<id>\d+)/$',views.rower_delete_trainingtarget),

View File

@@ -3019,7 +3019,7 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_forcecurve_view,kwargs={'id':id}),
@@ -3089,7 +3089,7 @@ def workout_histo_view(request,id=0):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_histo_view,kwargs={'id':id}),
@@ -5250,6 +5250,7 @@ def team_comparison_select(request,
successmessage='',
startdate=timezone.now()-datetime.timedelta(days=30),
enddate=timezone.now(),
id=0,
teamid=0):
try:
@@ -5371,7 +5372,7 @@ def team_comparison_select(request,
if rankingonly:
workouts = [w for w in workouts if w.rankingpiece]
query = request.GET.get('q')
if query:
query_list = query.split()
@@ -5382,8 +5383,22 @@ def team_comparison_select(request,
(Q(notes__icontains=q) for q in query_list))
)
if id:
firstworkout = get_workout(id)
if not checkworkoutuser(request.user,firstworkout):
raise PermissionDenied("You are not allowed to sue this workout")
firstworkoutquery = Workout.objects.filter(id=id)
workouts = firstworkoutquery | workouts
else:
firstworkout = None
form = WorkoutMultipleCompareForm()
form.fields["workouts"].queryset = workouts
if id:
form.fields["workouts"].initial = [firstworkout]
if theteam:
theid = theteam.id
@@ -5396,20 +5411,38 @@ def team_comparison_select(request,
messages.error(request,message)
r = getrower(request.user)
breadcrumbs = [
{
'url':'/rowers/list-workouts',
'name':'Workouts'
},
{
'url':reverse(team_comparison_select,kwargs={'teamid':teamid}),
'name': 'Compare Select'
},
if id:
breadcrumbs = [
{
'url':'/rowers/list-workouts',
'name':'Workouts'
},
{
'url':get_workout_default_page(request,id),
'name': str(id)
},
{
'url':reverse(team_comparison_select,kwargs={'id':id,'teamid':teamid}),
'name':'Compare Select'
},
]
else:
breadcrumbs = [
{
'url':'/rowers/list-workouts',
'name':'Workouts'
},
{
'url':reverse(team_comparison_select,kwargs={'teamid':teamid}),
'name': 'Compare Select'
},
]
return render(request, 'team_compare_select.html',
{'workouts': workouts,
'workout':firstworkout,
'dateform':dateform,
'startdate':startdate,
'enddate':enddate,
@@ -5426,7 +5459,7 @@ def team_comparison_select(request,
# Team comparison
@login_required()
def multi_compare_view(request):
def multi_compare_view(request,id=0):
promember=0
if not request.user.is_anonymous():
r = getrower(request.user)
@@ -5542,7 +5575,10 @@ def multi_compare_view(request):
})
else:
url = reverse(workouts_view)
url = reverse(team_comparison_select,
kwargs={
'id':id,
'teamid':0})
return HttpResponseRedirect(url)
# Multi Flex Chart with Grouping
@@ -6908,7 +6944,7 @@ def workout_fusion_list(request,id=0,message='',successmessage='',
},
{
'url':get_workout_default_page(request,row.id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_fusion_list,kwargs={'id':id}),
@@ -7131,7 +7167,7 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_crewnerd_summary_view,kwargs={'id':id}),
@@ -7341,7 +7377,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_wind_view,kwargs={'id':id}),
@@ -7529,7 +7565,7 @@ def workout_stream_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_stream_view,kwargs={'id':id}),
@@ -7661,7 +7697,7 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_otwsetpower_view,kwargs={'id':id}),
@@ -7701,7 +7737,7 @@ def instroke_view(request,id=0):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(instroke_view,kwargs={'id':id}),
@@ -8179,7 +8215,7 @@ def workout_data_view(request, id=0):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_data_view,kwargs={'id':id}),
@@ -8275,7 +8311,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_stats_view,kwargs={'id':id}),
@@ -8719,6 +8755,34 @@ def workout_workflow_config2_view(request,userid=0):
})
def getfavorites(r,row):
workouttype = 'ote'
if row.workouttype in mytypes.otwtypes:
workouttype = 'otw'
matchworkouttypes = [workouttype,'all']
workoutsource = row.workoutsource
if 'speedcoach2' in row.workoutsource:
workoutsource = 'speedcoach2'
try:
favorites = FavoriteChart.objects.filter(user=r,
workouttype__in=matchworkouttypes).order_by("id")
favorites2 = FavoriteChart.objects.filter(user=r,
workouttype__in=[workoutsource]).order_by("id")
favorites = favorites | favorites2
maxfav = len(favorites)-1
except:
favorites = None
maxfav = 0
return favorites,maxfav
# Workflow View
@login_required()
def workout_workflow_view(request,id):
@@ -8738,17 +8802,8 @@ def workout_workflow_view(request,id):
aantalcomments = len(comments)
workouttype = 'ote'
if row.workouttype in mytypes.otwtypes:
workouttype = 'otw'
try:
favorites = FavoriteChart.objects.filter(user=r,
workouttype__in=[workouttype,'both']).order_by("id")
maxfav = len(favorites)-1
except:
favorites = None
maxfav = 0
favorites,maxfav = getfavorites(r,row)
charts = get_call()
@@ -8791,7 +8846,7 @@ def workout_workflow_view(request,id):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_workflow_view,kwargs={'id':id}),
@@ -8853,13 +8908,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
if row.workouttype in mytypes.otwtypes:
workouttype = 'otw'
try:
favorites = FavoriteChart.objects.filter(user=r,
workouttype__in=[workouttype,'both']).order_by("id")
maxfav = len(favorites)-1
except:
favorites = None
maxfav = 0
favorites,maxfav = getfavorites(r,row)
# check if favoritenr is not out of range
if favorites:
@@ -8968,7 +9017,6 @@ def workout_flexchart3_view(request,*args,**kwargs):
else:
print flexaxesform.errors
print xparam,yparam1,yparam2
if not promember:
for name,d in rowingmetrics:
@@ -9086,7 +9134,7 @@ def workout_flexchart3_view(request,*args,**kwargs):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_flexchart3_view,kwargs=kwargs),
@@ -9180,7 +9228,7 @@ def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_otwpowerplot_view,kwargs={'id':id}),
@@ -9407,7 +9455,7 @@ def workout_comment_view(request,id=0):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_comment_view,kwargs={'id':id}),
@@ -9827,7 +9875,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
},
{
'url':get_workout_default_page(request,id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_edit_view,kwargs={'id':id}),
@@ -9869,7 +9917,7 @@ def workout_map_view(request,id=0):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_map_view,kwargs={'id':id}),
@@ -9943,7 +9991,7 @@ def workout_uploadimage_view(request,id):
},
{
'url':get_workout_default_page(request,id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(workout_uploadimage_view,kwargs={'id':id}),
@@ -10926,6 +10974,11 @@ def workout_upload_view(request,
except KeyError:
boattype = '1x'
try:
workoutsource = uploadoptions['workoutsource']
except KeyError:
workoutsource = None
try:
plottype = uploadoptions['plottype']
except KeyError:
@@ -11039,6 +11092,7 @@ def workout_upload_view(request,
id,message,f2 = dataprep.new_workout_from_file(
r,f2,
workouttype=workouttype,
workoutsource=workoutsource,
boattype=boattype,
makeprivate=makeprivate,
title = t,
@@ -11583,7 +11637,7 @@ def graph_show_view(request,id):
},
{
'url':get_workout_default_page(request,w.id),
'name': str(w.id)
'name': w.name
},
{
'url':reverse(graph_show_view,kwargs={'id':id}),
@@ -11675,7 +11729,7 @@ def workout_split_view(request,id=id):
},
{
'url':get_workout_default_page(request,row.id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(graph_show_view,kwargs={'id':id}),
@@ -11846,7 +11900,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
},
{
'url':get_workout_default_page(request,row.id),
'name': str(row.id)
'name': row.name
},
{
'url':reverse(workout_summary_edit_view,kwargs={'id':id}),
@@ -16040,6 +16094,7 @@ def rower_create_trainingplan(request,userid=0):
therower = getrequestrower(request,userid=userid)
theuser = therower.user
themanager = getrower(request.user)
if request.method == 'POST' and 'date' in request.POST:
targetform = TrainingTargetForm(request.POST)
@@ -16051,6 +16106,7 @@ def rower_create_trainingplan(request,userid=0):
t = TrainingTarget(rower=therower,
name=name,
date=date,
manager=themanager,
notes=notes)
t.save()
@@ -16067,6 +16123,7 @@ def rower_create_trainingplan(request,userid=0):
name=name,
rower=therower,
target=target,
manager=themanager,
startdate=startdate,
enddate=enddate,
)
@@ -16115,7 +16172,7 @@ def rower_delete_trainingtarget(request,id=0):
except TrainingPlan.DoesNotExist:
raise Http404("Training Plan Does Not Exist")
if checkaccessuser(request.user,target.rower):
if checkaccessuser(request.user,target.manager):
target.delete()
messages.info(request,"We have deleted the training target")
else:
@@ -16135,7 +16192,7 @@ def rower_delete_trainingplan(request,id=0):
except TrainingPlan.DoesNotExist:
raise Http404("Training Plan Does Not Exist")
if checkaccessuser(request.user,plan.rower):
if checkaccessuser(request.user,plan.manager):
plan.delete()
messages.info(request,"We have deleted the training plan")
else:
@@ -16152,7 +16209,7 @@ class TrainingPlanDelete(DeleteView):
def get_object(self, *args, **kwargs):
obj = super(TrainingPlanDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.rower):
if not checkaccessuser(self.request.user,obj.manager):
raise PermissionDenied('You are not allowed to delete this training plan')
return obj
@@ -16218,7 +16275,7 @@ class MicroCycleDelete(DeleteView):
def get_object(self, *args, **kwargs):
obj = super(MicroCycleDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.plan.plan.rower):
if not checkaccessuser(self.request.user,obj.plan.plan.plan.manager):
raise PermissionDenied('You are not allowed to delete this training plan cycle')
return obj
@@ -16279,7 +16336,8 @@ class MesoCycleDelete(DeleteView):
def get_object(self, *args, **kwargs):
obj = super(MesoCycleDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.plan.rower):
if not checkaccessuser(self.request.user,obj.plan.plan.manager):
raise PermissionDenied('You are not allowed to delete this training plan cycle')
return obj
@@ -16432,15 +16490,12 @@ class MacroCycleDelete(DeleteView):
def get_object(self, *args, **kwargs):
obj = super(MacroCycleDelete, self).get_object(*args, **kwargs)
if not checkaccessuser(self.request.user,obj.plan.rower):
if not checkaccessuser(self.request.user,obj.plan.manager):
raise PermissionDenied('You are not allowed to delete this training plan cycle')
return obj
@user_passes_test(hasplannedsessions,login_url="/rowers/promembership",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def rower_trainingplan_view(request,
id=0,
userid=0,
@@ -16676,6 +16731,9 @@ class TrainingMacroCycleUpdate(UpdateView):
def get_object(self, *args, **kwargs):
obj = super(TrainingMacroCycleUpdate, self).get_object(*args, **kwargs)
if obj.plan.manager is not None and self.request.user.rower != obj.plan.manager:
raise PermissionDenied('You are not allowed to edit this training plan cycle')
if not checkaccessuser(self.request.user,obj.plan.rower):
raise PermissionDenied('You are not allowed to edit this training plan cycle')
else:
@@ -16748,6 +16806,9 @@ class TrainingMesoCycleUpdate(UpdateView):
def get_object(self, *args, **kwargs):
obj = super(TrainingMesoCycleUpdate, self).get_object(*args, **kwargs)
r = obj.plan.plan.rower
if obj.plan.plan.manager is not None and self.request.user.rower != obj.plan.plan.manager:
raise PermissionDenied('You are not allowed to edit this training plan cycle')
if not checkaccessuser(self.request.user,r):
raise PermissionDenied('You are not allowed to edit this training plan cycle')
else:
@@ -16826,6 +16887,9 @@ class TrainingMicroCycleUpdate(UpdateView):
def get_object(self, *args, **kwargs):
obj = super(TrainingMicroCycleUpdate, self).get_object(*args, **kwargs)
r = obj.plan.plan.plan.rower
if obj.plan.plan.plan.manager is not None and self.request.user.rower != obj.plan.plan.plan.manager:
raise PermissionDenied('You are not allowed to edit this training plan cycle')
if not checkaccessuser(self.request.user,r):
raise PermissionDenied('You are not allowed to edit this training plan cycle')
else:
@@ -16840,6 +16904,41 @@ class TrainingPlanUpdate(UpdateView):
template_name = 'trainingplan_edit.html'
form_class = TrainingPlanForm
# extra parameters
def get_context_data(self, **kwargs):
context = super(TrainingPlanUpdate, self).get_context_data(**kwargs)
if 'userid' in kwargs:
userid = kwargs['userid']
else:
userid=0
breadcrumbs = [
{
'url':reverse(plannedsessions_view,
kwargs={'userid':userid}),
'name': 'Plan'
},
{
'url':reverse(rower_trainingplan_view,
kwargs={'userid':userid,
'id':self.object.id}),
'name': self.object.name
},
{
'url':reverse('trainingplan_update_view',
kwargs={'pk':self.object.pk}),
'name': 'Edit'
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request,userid=userid)
return context
def get_success_url(self):
return reverse(rower_create_trainingplan)
@@ -16847,11 +16946,16 @@ class TrainingPlanUpdate(UpdateView):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
plan = form.save()
plan.manager = self.request.user.rower
plan.save()
macrocyclecheckdates(plan)
return super(TrainingPlanUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingPlanUpdate, self).get_object(*args, **kwargs)
if obj.manager is not None and self.request.user.rower != obj.manager.user:
raise PermissionDenied('You are not allowed to edit this training plan cycle')
if not checkaccessuser(self.request.user,obj.rower):
raise PermissionDenied('You are not allowed to edit this training plan cycle')
return obj
@@ -16872,7 +16976,114 @@ class TrainingTargetUpdate(UpdateView):
def get_object(self, *args, **kwargs):
obj = super(TrainingTargetUpdate, self).get_object(*args, **kwargs)
if obj.manager is not None and self.request.user.rower != obj.manager.user:
raise PermissionDenied('You are not allowed to edit this training plan cycle')
if not checkaccessuser(self.request.user,obj.rower):
raise PermissionDenied('You are not allowed to edit this training plan target')
return obj
def allsundays(startdate,enddate):
d = startdate
d += timedelta(days = 6 - d.weekday()) # first Sunday
while d<enddate:
yield d
d += timedelta(days=7)
@user_passes_test(hasplannedsessions,login_url="/rowers/promembership",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def planmesocyclebyweek(request,id=0,userid=0):
try:
cycle = TrainingMesoCycle.objects.get(id=id)
except TrainingMesoCycle.DoesNotExist:
raise Http404("Training Cycle does not exist")
if not checkaccessuser(request.user,cycle.plan.plan.manager):
raise PermissionDenied("You are not allowed to do this")
micros = TrainingMicroCycle.objects.filter(plan=cycle)
for m in micros:
m.delete()
cycle.type = 'userdefined'
cycle.save()
#we're still here. We have permission
sundays = [s for s in allsundays(cycle.startdate,cycle.enddate)]
for i in range(len(sundays)-1):
monday = sundays[i]+timedelta(days=1)
nextsunday = sundays[i+1]
if i == 0 and monday > cycle.startdate:
monday = cycle.startdate
if nextsunday < cycle.enddate and i == len(sundays)-2:
nextsunday = cycle.enddate
micro = TrainingMicroCycle(startdate = monday,
enddate = nextsunday,
plan = cycle,
name = 'Week %s' % sundays[i+1].isocalendar()[1],
type = 'userdefined')
micro.save()
micros = TrainingMicroCycle.objects.filter(plan=cycle)
url = reverse(rower_trainingplan_view,
kwargs = {'userid':str(userid),
'id':str(cycle.plan.plan.id),
'thismicroid':str(micros[0].id)})
return HttpResponseRedirect(url)
def allmonths(startdate,enddate):
d = startdate
while d<enddate:
yield d
d = datetime.date(d.year+(d.month / 12),((d.month % 12) + 1),1)
@user_passes_test(hasplannedsessions,login_url="/rowers/promembership",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def planmacrocyclebymonth(request,id=0,userid=0):
try:
cycle = TrainingMacroCycle.objects.get(id=id)
except TrainingMacroCycle.DoesNotExist:
raise Http404("Training Cycle does not exist")
if not checkaccessuser(request.user,cycle.plan.manager):
raise PermissionDenied("You are not allowed to do this")
mesos = TrainingMesoCycle.objects.filter(plan=cycle)
for m in mesos:
m.delete()
cycle.type = 'userdefined'
cycle.save()
#we're still here. We have permission
monthstarts = [d for d in allmonths(cycle.startdate,cycle.enddate)]
monthstarts.append(cycle.enddate)
for i in range(len(monthstarts)-1):
firstday = monthstarts[i]
lastday = monthstarts[i+1]-timedelta(days=1)
if lastday < cycle.enddate and i == len(monthstarts)-2:
lastday = cycle.enddate
meso = TrainingMesoCycle(startdate = firstday,
enddate = lastday,
plan = cycle,
name = '%s' % firstday.strftime("%B"),
type = 'userdefined')
meso.save()
mesos = TrainingMesoCycle.objects.filter(plan=cycle)
url = reverse(rower_trainingplan_view,
kwargs = {'userid':str(userid),
'id':str(cycle.plan.id),
'thismesoid':str(mesos[0].id)})
return HttpResponseRedirect(url)

View File

@@ -149,7 +149,7 @@
</li>
{% if user.is_authenticated %}
<li>
<a href="/rowers/me/edit" title="Profile">
<a href="/rowers/me/preferences" title="Profile">
{% if user.rower.rowerplan == 'pro' %}
<i class="fas fa-user-ninja "></i>
{% elif user.rower.rowerplan == 'coach' %}