Private
Public Access
1
0
Files
rowsandall/rowers/views/planviews.py
Sander Roosendaal 8af7ac8af4 commit
2022-02-15 08:05:12 +01:00

3795 lines
125 KiB
Python

from __future__ import absolute_import
from rowers.plannedsessions import cratiocolors, checkscores
from rowers.utils import allmonths
from rowers.utils import allsundays
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from rowers.views.statements import *
from rowingdata import trainingparser
import json
from taggit.models import Tag
import rowers.garmin_stuff as gs
from rowers import credits
@login_required
@permission_required('plannedsession.view_session', fn=get_session_by_pk, raise_exception=True)
def plannedsession_comment_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
ps = get_object_or_404(PlannedSession, pk=id)
comments = PlannedSessionComment.objects.filter(
plannedsession=ps).order_by("created")
if request.method == 'POST':
manager = ps.manager
form = PlannedSessionCommentForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
comment = cd['comment']
comment = bleach.clean(comment)
try:
if isinstance(comment, unicode): # pragma: no cover
comment = comment.encode('utf8')
elif isinstance(comment, str): # pragma: no cover
comment = comment.decode('utf8')
except:
pass
notification = cd['notification']
c = PlannedSessionComment(plannedsession=ps, user=request.user, comment=comment,
notification=notification)
c.save()
url = reverse('plannedsession_comment_view',
kwargs={
'id': id
})
message = '{name} says: <a href="{url}">{comment}</a>'.format(
name=request.user.first_name,
comment=comment,
url=url,
)
if request.user != manager: # pragma: no cover
a_messages.info(r.user, message.encode('ascii', 'ignore'))
sessiontype = 'training session'
if ps.sessiontype == 'race': # pragma: no cover
sessiontype = 'online virtual race'
elif ps.sessiontype == 'indoorrace': # pragma: no cover
sessiontype = 'indoor online virtual race'
res = myqueue(queuehigh,
handle_sendemailnewcomment, r.user.first_name,
r.user.last_name,
r.user.email,
request.user.first_name,
request.user.last_name,
comment, ps.name, ps.id,
emailbounced=r.emailbounced,
sessiontype=sessiontype,
commentlink=url
)
commenters = {oc.user for oc in comments if oc.notification}
if ps.sessiontype == 'race': # pragma: no cover
registrations = VirtualRaceResult.objects.filter(
race__id=ps.id,
emailnotifications=True)
ids = [rg.userid for rg in registrations]
rwrs = Rower.objects.filter(id__in=ids)
rowers = {u.user for u in rwrs}
elif ps.sessiontype == 'indoorrace': # pragma: no cover
registrations = IndoorVirtualRaceResult.objects.filter(
race__id=ps.id,
emailnotifications=True)
ids = [rg.userid for rg in registrations]
rwrs = Rower.objects.filter(id__in=ids)
rowers = {u.user for u in rwrs}
else:
rowers = {r.user for r in ps.rower.all()}
commenters = set(list(commenters)+list(rowers))
for u in commenters:
try:
a_messages.info(u, message)
except ValueError: # pragma: no cover
pass
if u != request.user and u != r.user: # pragma: no cover
ocr = Rower.objects.get(user=u)
res = myqueue(queue,
handle_sendemailnewresponse,
u.first_name,
u.last_name,
u.email,
request.user.first_name,
request.user.last_name,
comment,
ps.name,
ps.id,
c.id,
emailbounced=ocr.emailbounced,
sessiontype=sessiontype,
commentlink=url
)
if ps.sessiontype in ['race', 'indoorrace']: # pragma: no cover
followers = VirtualRaceFollower.objects.filter(race__id=ps.id)
for follower in followers:
othername = ''
if follower.user:
othername = follower.user.first_name+' '+follower.user.last_name
email = follower.emailaddress
res = myqueue(queue,
handle_sendemailnewresponse,
othername, '', email,
request.user.first_name,
request.user.last_name,
comment,
ps.name, ps.id, c.id,
emailbounced=False,
sessiontype=sessiontype,
commentlink=url,
)
url = reverse('plannedsession_comment_view', kwargs={'id': ps.id})
return HttpResponseRedirect(url)
form = WorkoutCommentForm()
rower = getrower(request.user)
if ps.sessiontype in ['race', 'indoorrace']: # pragma: no cover
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Races'
},
{
'url': reverse('virtualevent_view', kwargs={'id': ps.id}),
'name': ps.name
},
{
'url': reverse('plannedsession_comment_view', kwargs={'id': ps.id}),
'name': 'Comments'
}
]
active = 'nav-racing'
else:
breadcrumbs = [
{
'url': reverse('plannedsessions_view'),
'name': 'Sessions'
},
{
'url': reverse('plannedsession_view', kwargs={'id': ps.id}),
'name': ps.name
},
{
'url': reverse('plannedsession_comment_view', kwargs={'id': ps.id}),
'name': 'Comments'
}
]
active = 'nav-plan'
return render(request,
'plannedsession_comments.html',
{'plannedsession': ps,
'rower': rower,
'breadcrumbs': breadcrumbs,
'active': active,
'comments': comments,
'form': form,
})
@login_required
@permission_required('virtualevent.change_race', fn=get_session_by_pk, raise_exception=True)
def plannedsession_message_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
ps = get_object_or_404(PlannedSession, pk=id)
userform = VirtualRaceAthleteForm(instance=ps)
if request.method == 'POST':
userform = VirtualRaceAthleteForm(request.POST, instance=ps)
if userform.is_valid():
subject = userform.cleaned_data['subject']
message = userform.cleaned_data['message']
rowers = userform.cleaned_data['rower']
for participant in rowers:
rowername = participant.user.first_name
fromemail = ps.manager.email
job = myqueue(
queue,
handle_send_template_email,
'virtualracemessage.html',
participant.user.email,
fromemail,
rowername,
subject,
message,
)
url = reverse('plannedsession_view', kwargs={'id': ps.id})
if ps.sessiontype in ['race', 'indoorrace']: # pragma: no cover
url = reverse('virtualevent_view', kwargs={'id': ps.id})
return HttpResponseRedirect(url)
if ps.sessiontype in ['race', 'indoorrace']: # pragma: no cover
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Races'
},
{
'url': reverse('virtualevent_view', kwargs={'id': ps.id}),
'name': ps.name
},
{
'url': reverse('plannedsession_comment_view', kwargs={'id': ps.id}),
'name': 'Comments'
}
]
active = 'nav-racing'
else:
breadcrumbs = [
{
'url': reverse('plannedsessions_view'),
'name': 'Sessions'
},
{
'url': reverse('plannedsession_view', kwargs={'id': ps.id}),
'name': ps.name
},
{
'url': reverse('plannedsession_comment_view', kwargs={'id': ps.id}),
'name': 'Comments'
}
]
active = 'nav-plan'
return render(request,
'plannedsession_message.html',
{'plannedsession': ps,
'rower': r,
'breadcrumbs': breadcrumbs,
'active': active,
'userform': userform,
})
# Cloning sessions
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_multiclone_view(
request,
userid=0,):
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
teamid = get_team(request)
if request.method == 'POST' and 'daterange' in request.POST: # pragma: no cover
dateform = DateRangeForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
request.session['startdate'] = startdatestring
request.session['enddate'] = enddatestring
else:
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
if request.method == 'POST' and 'plannedsessions' in request.POST:
form = PlannedSessionMultipleCloneForm(request.POST)
dateshiftform = SessionDateShiftForm(request.POST)
if form.is_valid() and dateshiftform.is_valid():
cd = form.cleaned_data
sps = cd['plannedsessions']
std = min([ps.startdate for ps in sps])
shiftstartdate = dateshiftform.cleaned_data['shiftstartdate']
delta = shiftstartdate-std
lastdate = shiftstartdate
for ps in sps:
rowers = ps.rower.all()
teams = ps.team.all()
ps.pk = None
ps.startdate += delta
ps.preferreddate += delta
ps.enddate += delta
if ps.enddate > lastdate:
lastdate = ps.enddate
ps.fitfile = None
ps.save()
for rower in rowers:
add_rower_session(rower, ps)
for team in teams:
add_team_session(team, ps)
startdatestring = shiftstartdate.strftime('%Y-%m-%d')
enddatestring = lastdate.strftime('%Y-%m-%d')
url = reverse(plannedsessions_view,
kwargs={
'userid': r.user.id,
})
url += '?when='+startdatestring+'/'+enddatestring
return HttpResponseRedirect(url)
sps = PlannedSession.objects.filter(
manager=request.user,
rower__in=[r],
is_template=False,
startdate__lte=enddate,
enddate__gte=startdate).order_by(
"startdate", "preferreddate", "enddate").exclude(
sessiontype='race')
if teamid: # pragma: no cover
sps = sps.filter(team__in=[teamid])
try:
team = Team.objects.get(id=teamid)
if team.manager != request.user:
team = None
except Team.DoesNotExist:
team = None
else:
team = None
query = request.GET.get('q')
if query: # pragma: no cover
query_list = query.split()
sps = sps.filter(
reduce(operator.and_,
(Q(name__icontains=q) for q in query_list)) |
reduce(operator.and_,
(Q(comment__icontains=q) for q in query_list))
)
form = PlannedSessionMultipleCloneForm()
form.fields["plannedsessions"].queryset = sps
dateshiftform = SessionDateShiftForm()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsession_multiclone_view),
'name': 'Clone Multiple Sessions'
}
]
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
if Team.objects.filter(manager=request.user).count() >= 1:
teamform = RowerTeamForm(request.user)
if teamid: # pragma: no cover
teamform = RowerTeamForm(request.user, initial={'team': teamid})
else:
teamform = None
return render(request, 'plannedsessions_multiclone_select.html',
{'plannedsessions': sps,
'breadcrumbs': breadcrumbs,
'plan': trainingplan,
'dateform': dateform,
'startdate': startdate,
'enddate': enddate,
'form': form,
'dateshiftform': dateshiftform,
'rower': r,
'active': 'nav-plan',
'timeperiod': timeperiod,
'team': team,
'teamform': teamform,
}
)
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def template_share_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
ps = get_object_or_404(PlannedSession, pk=id)
if ps.can_be_shared:
ps.is_public = True
ps.save()
else: # pragma: no cover
messages.error(
request, 'This planned session comes from a third party and cannot be shared')
return HttpResponseRedirect(reverse(template_library_view))
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def template_makeprivate_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
ps = get_object_or_404(PlannedSession, pk=id)
ps.is_public = False
ps.save()
return HttpResponseRedirect(reverse(template_library_view))
# Manage Template sessions (library)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def template_library_view(request, userid=0):
r = getrequestplanrower(request, userid=userid)
templates = PlannedSession.objects.filter(
manager=request.user, is_template=True)
templates2 = PlannedSession.objects.filter(
is_template=True, is_public=True)
templates = templates | templates2
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
alltags = []
for t in templates:
tags = t.tags.all()
for tag in tags:
alltags.append(tag)
alltags = uniqify(alltags)
tag = request.GET.get('tag')
if tag: # pragma: no cover
tags = [tag]
templates = templates.filter(tags__name__in=tags).distinct()
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(template_library_view),
'name': 'Session Library',
}
]
return render(request, 'templatelibrary.html',
{
'teams': get_my_teams(request.user),
'breadcrumbs': breadcrumbs,
'templates': templates,
'plan': trainingplan,
'rower': r,
'active': 'nav-plan',
'alltags': alltags,
}
)
# Individual user creates training for himself
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_create_view(request,
userid=0,
startdatestring='',
enddatestring=''):
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request, startdatestring=startdatestring,
enddatestring=enddatestring)
startdate = startdate.date()
enddate = enddate.date()
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST, request.FILES)
if sessioncreateform.is_valid():
ps = sessioncreateform.save(commit=False)
ps.manager = request.user
ps.save()
add_rower_session(r, ps)
request.session['fstartdate'] = str(arrow.get(ps.startdate))
request.session['fenddate'] = str(arrow.get(ps.enddate))
request.session['fprefdate'] = str(arrow.get(ps.preferreddate))
url = reverse(plannedsessions_view, kwargs={
'userid': userid,
})
if '_continue' in request.POST: # pragma: no cover
url = reverse('plannedsession_edit_view', kwargs={
'id': ps.id,
})
elif '_addanother' in request.POST: # pragma: no cover
url = reverse('plannedsession_create_view',
kwargs={'userid': userid})
url = url+'?when='+timeperiod
return HttpResponseRedirect(url)
else:
if 'fstartdate' in request.session: # pragma: no cover
try:
fstartdate = arrow.get(request.session['fstartdate']).date()
except KeyError:
fstartdate = timezone.now().date()
if fstartdate < startdate:
fstartdate = startdate
try:
fenddate = arrow.get(request.session['fenddate']).date()
except KeyError:
fenddate = timezone.now().date()
if fenddate > enddate:
fenddate = enddate
try:
fprefdate = arrow.get(request.session['fprefdate']).date()
except KeyError:
fprefdate = timezone.now().date()
if fprefdate < startdate:
fprefdate = startdate
if fprefdate > enddate:
fprefdate = enddate
forminitial = {
'startdate': fstartdate,
'enddate': fenddate,
'preferreddate': fprefdate
}
else:
try:
preferreddate = startdate.date()
except AttributeError:
preferreddate = startdate
if preferreddate < timezone.now().date(): # pragma: no cover
preferreddate = timezone.now().date()
try:
enddate = enddate.date()
except AttributeError:
pass
if preferreddate > enddate: # pragma: no cover
preferreddate = enddate
forminitial = {
'startdate': startdate,
'enddate': enddate,
'preferreddate': preferreddate,
}
sessioncreateform = PlannedSessionForm(initial=forminitial)
if request.GET.get('startdate') or request.GET.get('when'):
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
sps = get_sessions(r, startdate=startdate, enddate=enddate).exclude(
sessiontype='race')
sessiontemplates = PlannedSession.objects.filter(
manager=request.user,
is_template=True).order_by("name")
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True, is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
sessiontemplates = sessiontemplates.order_by("name")
alltags = []
for t in sessiontemplates: # pragma: no cover
tags = t.tags.all()
for tag in tags:
alltags.append(tag)
alltags = uniqify(alltags)
tag = request.GET.get('tag')
if tag: # pragma: no cover
tags = [tag]
sessiontemplates = sessiontemplates.filter(
tags__name__in=tags).distinct()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsessions_view)+'?when='+timeperiod,
'name': timeperiod,
},
{
'url': reverse(plannedsession_create_view),
'name': 'Add Session'
}
]
return render(request, 'plannedsessioncreate.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'dateform': dateform,
'breadcrumbs': breadcrumbs,
'form': sessioncreateform,
'active': 'nav-plan',
'plannedsessions': sps,
'sessiontemplates': sessiontemplates,
'rower': r,
'timeperiod': timeperiod,
'alltags': alltags,
})
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_createtemplate_view(request,
userid=0,
):
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
if request.method == 'POST':
sessioncreateform = PlannedSessionTemplateForm(
request.POST, request.FILES)
if sessioncreateform.is_valid():
ps = sessioncreateform.save(commit=False)
ps.manager = request.user
ps.is_template = True
ps.save()
sessioncreateform.save_m2m()
add_rower_session(r, ps)
url = reverse('template_library_view')
if '_continue' in request.POST: # pragma: no cover
url = reverse('plannedsession_templateedit_view', kwargs={
'id': ps.id,
})
elif '_addanother' in request.POST: # pragma: no cover
url = reverse('plannedsession_createtemplate_view')
return HttpResponseRedirect(url)
else:
sessioncreateform = PlannedSessionTemplateForm()
sessiontemplates = PlannedSession.objects.filter(
manager=request.user,
is_template=True).order_by("name")
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True, is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
sessiontemplates = sessiontemplates.order_by("name")
alltags = []
for t in sessiontemplates: # pragma: no cover
tags = t.tags.all()
for tag in tags:
alltags.append(tag)
alltags = uniqify(alltags)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Sessions'
},
{
'url': reverse('template_library_view'),
'name': 'Session Library'
},
{
'url': reverse(plannedsession_createtemplate_view),
'name': 'Create Library Session'
}
]
return render(request, 'plannedsessiontemplatecreate.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'form': sessioncreateform,
'breadcrumbs': breadcrumbs,
'active': 'nav-plan',
'rower': r,
'alltags': alltags,
})
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_multicreate_view(request,
teamid=0, userid=0, extrasessions=0):
extrasessions = int(extrasessions)
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
teamid = get_team(request)
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
m = Rower.objects.get(user=request.user)
qset = PlannedSession.objects.filter(
rower__in=[r],
manager=request.user,
startdate__lte=enddate,
enddate__gte=startdate,
).order_by("startdate", "preferreddate", "enddate").exclude(
sessiontype='race')
if teamid: # pragma: no cover
qset = qset.filter(team__in=[teamid])
try:
team = Team.objects.get(id=teamid)
if team.manager != request.user:
team = None
except Team.DoesNotExist:
team = None
else:
team = None
initial = {
'startdate': startdate,
'enddate': enddate,
'sessionvalue': 60,
'manager': request.user,
'name': 'NEW SESSION'
}
initials = [initial for i in range(extrasessions)]
PlannedSessionFormSet = modelformset_factory(
PlannedSession,
form=PlannedSessionFormSmall,
can_delete=True,
extra=extrasessions,
)
if request.method == "POST":
ps_formset = PlannedSessionFormSet(queryset=qset,
data=request.POST)
if ps_formset.is_valid(): # pragma: no cover
instances = ps_formset.save(commit=False)
for ps in instances:
ps.save()
add_rower_session(r, ps)
if team: # pragma: no cover
add_team_session(team, ps)
messages.info(
request, "Saved changes for Planned Session "+str(ps))
for obj in ps_formset.deleted_objects: # pragma: no cover
messages.info(request, "Deleted Planned Session "+str(obj))
obj.delete()
url = reverse(plannedsession_multicreate_view,
kwargs={
'userid': r.user.id,
}
)
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
if team: # pragma: no cover
url += '&team={teamid}'.format(teamid=team.id)
return HttpResponseRedirect(url)
ps_formset = PlannedSessionFormSet(queryset=qset,
initial=initials)
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsession_multicreate_view),
'name': 'Plan MicroCycle'
}
]
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate
})
if Team.objects.filter(manager=request.user).count() >= 1:
teamform = RowerTeamForm(request.user)
if teamid: # pragma: no cover
teamform = RowerTeamForm(request.user, initial={'team': teamid})
else:
teamform = None
context = {
'ps_formset': ps_formset,
'breadcrumbs': breadcrumbs,
'rower': r,
'active': 'nav-plan',
'dateform': dateform,
'teamform': teamform,
'plan': trainingplan,
'timeperiod': timeperiod,
'teams': get_my_teams(request.user),
'extrasessions': extrasessions+1,
'team': team,
}
return render(request, 'plannedsession_multicreate.html', context)
# Manager creates sessions for entire team
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_teamcreate_view(request,
teamid=0, userid=0):
therower = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
teams = Team.objects.filter(manager=request.user)
if teams.count() > 0:
teamchoices = [(team.id, team.name) for team in teams]
teaminitial = [str(teams[0].id)]
else:
messages.info(
request, "You have no teams established yet. We are redirecting you to the Team Management page.")
url = reverse('rower_teams_view')
return HttpResponseRedirect(url)
trainingplan = None
sps = []
for team in teams:
res = get_sessions_manager(
request.user, startdate=startdate, enddate=enddate)
sps += res
sps = list(set(sps))
ids = [ps.id for ps in sps]
sps = PlannedSession.objects.filter(id__in=ids).order_by(
"preferreddate", "startdate", "enddate")
sessiontemplates = PlannedSession.objects.filter(
manager=request.user, is_template=True)
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True, is_public=True)
sessiontemplates = sessiontemplates | sessiontemplates2
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(request.POST, request.FILES)
sessionteamselectform = PlannedSessionTeamForm(
request.user, request.POST
)
if sessioncreateform.is_valid() and sessionteamselectform.is_valid():
cd = sessioncreateform.cleaned_data
ps = sessioncreateform.save(commit=False)
ps.manager = request.user
ps.save()
cd = sessionteamselectform.cleaned_data
teams = cd['team']
request.session['teams'] = [team.id for team in teams]
for team in teams:
add_team_session(team, ps)
rs = Rower.objects.filter(
team__in=[team]).exclude(rowerplan='freecoach')
for r in rs:
add_rower_session(r, ps)
url = reverse(plannedsessions_view, kwargs={
'userid': userid,
})
if '_continue' in request.POST: # pragma: no cover
url = reverse('plannedsession_edit_view', kwargs={
'id': ps.id,
})
elif '_addanother' in request.POST: # pragma: no cover
url = reverse('plannedsession_teamcreate_view',
kwargs={'userid': userid})
url = url+'?when='+timeperiod
return HttpResponseRedirect(url)
#url = reverse(plannedsession_teamcreate_view)
#startdatestring = startdate.strftime('%Y-%m-%d')
#enddatestring = enddate.strftime('%Y-%m-%d')
#url += '?when='+startdatestring+'/'+enddatestring
#next = request.GET.get('next', url)
# return HttpResponseRedirect(next)
else: # pragma: no cover
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsessions_view)+'?when='+timeperiod,
'name': timeperiod,
},
{
'url': reverse(plannedsession_teamcreate_view),
'name': 'Add Team Session'
}
]
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
return render(request, 'plannedsessionteamcreate.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'breadcrumbs': breadcrumbs,
'form': sessioncreateform,
'sessiontemplates': sessiontemplates,
'teamform': sessionteamselectform,
'timeperiod': timeperiod,
'plannedsessions': sps,
'rower': therower,
'active': 'nav-plan'
})
else:
initial = {
'startdate': startdate,
'enddate': enddate,
'preferreddate': startdate,
}
if 'teams' in request.session: # pragma: no cover
teams = request.session['teams']
theteams = Team.objects.filter(id__in=teams)
initialteam = {
'team': theteams
}
else:
initialteam = {}
sessioncreateform = PlannedSessionForm(initial=initial)
sessionteamselectform = PlannedSessionTeamForm(
request.user, initial=initialteam
)
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsessions_view)+'?when='+timeperiod,
'name': timeperiod,
},
{
'url': reverse(plannedsession_teamcreate_view),
'name': 'Add Team Session'
}
]
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
return render(request, 'plannedsessionteamcreate.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'dateform': dateform,
'breadcrumbs': breadcrumbs,
'form': sessioncreateform,
'sessiontemplates': sessiontemplates,
'teamform': sessionteamselectform,
'timeperiod': timeperiod,
'plannedsessions': sps,
'rower': therower,
'active': 'nav-plan'
})
# Manager edits sessions for entire team
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
def plannedsession_teamedit_view(request,
id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
ps = get_object_or_404(PlannedSession, pk=id)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
teams = Team.objects.filter(manager=request.user)
teamchoices = [(team.id, team.name) for team in teams]
teaminitial = ps.team.all()
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError: # pragma: no cover
trainingplan = None
sps = []
rowers = []
for team in teams:
res = get_sessions_manager(
request.user, startdate=startdate, enddate=enddate)
sps += res
rowers += Rower.objects.filter(team__in=[team])
rowers = list(set(rowers))
sps = list(set(sps))
ids = [pps.id for pps in sps]
sps = PlannedSession.objects.filter(id__in=ids).order_by(
"preferreddate", "startdate", "enddate")
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(
request.POST, request.FILES, instance=ps)
sessionteamselectform = PlannedSessionTeamForm(
request.user, request.POST
)
sessionrowerform = PlannedSessionTeamMemberForm(ps, request.POST)
if sessioncreateform.is_valid():
cd = sessioncreateform.cleaned_data
if cd['sessionunit'] == 'min': # pragma: no cover
cd['sessionmode'] = 'time'
elif cd['sessionunit'] in ['km', 'm']:
cd['sessionmode'] = 'distance'
res, message = update_plannedsession(ps, cd)
if res:
messages.info(request, message)
else: # pragma: no cover
messages.error(request, message)
# some logic when to add all selected rowers
if sessionteamselectform.is_valid():
cd = sessionteamselectform.cleaned_data
selectedteams = cd['team']
for team in teams:
if team in selectedteams:
add_team_session(team, ps)
rs = Rower.objects.filter(team__in=[team])
for r in rs:
add_rower_session(r, ps)
else: # pragma: no cover
remove_team_session(team, ps)
else: # pragma: no cover
selectedteams = []
for team in teams:
remove_team_session(team, ps)
if sessionrowerform.is_valid():
cd = sessionrowerform.cleaned_data
selectedrowers = cd['members']
for r in rowers:
if r in selectedrowers:
add_rower_session(r, ps)
else:
remove_rower_session(r, ps)
for t in selectedteams:
if t in r.team.all():
add_rower_session(r, ps)
url = reverse('plannedsessions_view')
if "_continue" in request.POST: # pragma: no cover
url = reverse(plannedsession_edit_view,
kwargs={
'id': int(ps.id),
'userid': r.user.id,
})
url = url+'?when='+timeperiod
return HttpResponseRedirect(url)
else:
sessioncreateform = PlannedSessionForm(instance=ps)
sessionteamselectform = PlannedSessionTeamForm(
request.user
)
sessionteamselectform.fields['team'].initial = teaminitial
sessionrowerform = PlannedSessionTeamMemberForm(
ps
)
sessionrowerform.fields['members'].initial = ps.rower.all()
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsessions_view)+'?when='+timeperiod,
'name': timeperiod,
},
{
'url': reverse(plannedsession_view,
kwargs={
'userid': userid,
'id': id,
}
),
'name': ps.id
},
{
'url': reverse(plannedsession_teamedit_view,
kwargs={
'userid': userid,
'id': id,
}),
'name': 'Edit'
}
]
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
return render(request, 'plannedsessionteamedit.html',
{
'plannedsession': ps,
'plan': trainingplan,
'dateform': dateform,
'breadcrumbs': breadcrumbs,
'rower': r,
'active': 'nav-plan',
'teams': get_my_teams(request.user),
'form': sessioncreateform,
'teamform': sessionteamselectform,
'rowersform': sessionrowerform,
'timeperiod': timeperiod,
'plannedsessions': sps,
})
# @user_passes_test(iscoachmember,login_url="/rowers/paidplans/",
# redirect_field_name=None)
@login_required()
def plannedsessions_coach_view(request,
teamid=0, userid=0):
therower = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
trainingplan = None
if teamid != 0: # pragma: no cover
try:
theteam = Team.objects.get(id=teamid)
except Team.DoesNotExist:
theteam = False
else:
theteam = False
if 'coach' in request.user.rower.rowerplan:
sps = get_sessions_manager(request.user, teamid=teamid,
enddate=enddate,
startdate=startdate)
else:
rteams = therower.team.filter(viewing='allmembers')
sps = get_sessions(therower, startdate=startdate, enddate=enddate)
if therower.rowerplan != 'freecoach':
rowers = [therower]
else: # pragma: no cover
rowers = []
for ps in sps:
if 'coach' in request.user.rower.rowerplan:
rowers += ps.rower.all().exclude(rowerplan='freecoach')
else: # pragma: no cover
rowers += ps.rower.filter(
team__in=rteams).exclude(rowerplan='freecoach')
rowers = list(set(rowers))
statusdict = []
for ps in sps:
rowerstatus = {}
rowercolor = {}
for r in rowers:
ratio, status, completiondate = is_session_complete(r, ps)
rowerstatus[r.id] = status
rowercolor[r.id] = cratiocolors[status]
sessiondict = {
'id': ps.id,
'results': rowerstatus,
'name': ps.name,
'startdate': ps.startdate,
'color': rowercolor,
'preferreddate': ps.preferreddate,
'enddate': ps.enddate,
}
statusdict.append(sessiondict)
unmatchedworkouts = []
for r in rowers:
unmatchedworkouts += Workout.objects.filter(
user=r,
plannedsession=None,
date__gte=startdate, date__lte=enddate)
myteams = Team.objects.filter(manager=request.user)
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
{
'url': reverse(plannedsessions_coach_view),
'name': 'Coach View'
}
]
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
ttemplate = 'plannedsessionscoach.html'
if len(rowers) > 5 and len(rowers) > len(sps): # pragma: no cover
ttemplate = 'plannedsessionscoach2.html'
return render(request, ttemplate,
{
'myteams': myteams,
'plannedsessions': sps,
'breadcrumbs': breadcrumbs,
'plan': trainingplan,
'statusdict': statusdict,
'dateform': dateform,
'timeperiod': timeperiod,
'rowers': rowers,
'rower': therower,
'active': 'nav-plan',
'theteam': theteam,
'unmatchedworkouts': unmatchedworkouts,
'rower': getrower(request.user)
}
)
@login_required()
def plannedsessions_view(request,
userid=0, startdatestring='', enddatestring=''):
try:
r = getrequestplanrower(request, userid=userid)
except PermissionDenied: # pragma: no cover
r = request.user.rower
if startdatestring: # pragma: no cover
try:
startdate = iso8601.parse_date(startdatestring)
except ParseError:
pass
if enddatestring: # pragma: no cover
try:
enddate = iso8601.parse_date(enddatestring)
except ParseError:
pass
startdate, enddate = get_dates_timeperiod(
request,
startdatestring=startdatestring,
enddatestring=enddatestring,
rower=r)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate
)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r, startdate=startdate, enddate=enddate)
completeness = {}
actualvalue = {}
completiondate = {}
sessioncolor = {}
totals = {
'trimp': 0,
'rscore': 0,
'distance': 0,
'time': 0,
'plannedtime': 0,
'planneddistance': 0,
'plannedtrimp': 0,
'plannedrscore': 0,
'actualtime': 0,
'actualdistance': 0,
'actualtrimp': 0,
'actualrscore': 0,
}
ws = Workout.objects.filter(
user=r,
date__gte=startdate,
date__lte=enddate,
)
for w in ws:
thetrimp, hrtss = dataprep.workout_trimp(w)
totals['trimp'] += thetrimp
tss = dataprep.workout_rscore(w)[0]
if not np.isnan(tss) and tss != 0:
totals['rscore'] += tss
elif tss == 0:
totals['rscore'] += hrtss
tss = hrtss
totals['distance'] += w.distance
totals['time'] += timefield_to_seconds_duration(w.duration)
if w.plannedsession: # pragma: no cover
if w.plannedsession.sessionmode == 'distance':
totals['actualdistance'] += w.distance
elif w.plannedsession.sessionmode == 'time':
totals['actualtime'] += timefield_to_seconds_duration(
w.duration)
elif w.plannedsession.sessionmode == 'rScore':
totals['actualrscore'] += tss
elif w.plannedsession.sessionmode == 'TRIMP':
totals['actualtrimp'] += thetrimp
if not sps and request.user.rower.rowerplan == 'basic': # pragma: no cover
messages.error(request,
"You must purchase Coach or Self-coach plans or be part of a team to get planned sessions")
for ps in sps:
ratio, status, cdate = is_session_complete(r, ps)
actualvalue[ps.id] = int(ps.sessionvalue*ratio)
completeness[ps.id] = status
sessioncolor[ps.id] = cratiocolors[status]
ws = Workout.objects.filter(user=r, plannedsession=ps)
completiondate[ps.id] = cdate
if ps.steps:
sdict, totalmeters, totalseconds, totalrscore = ps_dict_order(
ps.steps, rower=r)
totals['planneddistance'] += int(totalmeters)
totals['plannedtime'] += int(totalseconds)/60.
totals['plannedrscore'] += int(totalrscore)
totals['plannedtrimp'] += int(totalrscore)*2
else:
if ps.sessionmode == 'distance':
totals['planneddistance'] += ps.sessionvalue
else:
totals['planneddistance'] += ps.approximate_distance
if ps.sessionmode == 'time':
totals['plannedtime'] += ps.sessionvalue
else:
totals['plannedtime'] += ps.approximate_duration
if ps.sessionmode == 'rScore': # pragma: no cover
totals['plannedrscore'] += ps.sessionvalue
else:
totals['plannedrscore'] += ps.approximate_rscore
if ps.sessionmode == 'TRIMP': # pragma: no cover
totals['plannedtrimp'] += ps.sessionvalue
else:
totals['plannedtrimp'] += ps.approximate_rscore*2
totals['time'] = int(totals['time']/60.)
totals['actualtime'] = int(totals['actualtime']/60.)
totals['plannedtime'] = int(totals['plannedtime'])
unmatchedworkouts = Workout.objects.filter(
user=r,
plannedsession=None,
date__gte=startdate,
date__lte=enddate
)
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Planned Sessions'
},
]
initial = {
'startdate': startdate,
'enddate': enddate,
}
dateform = DateRangeForm(initial=initial)
return render(request, 'plannedsessions.html',
{
'teams': get_my_teams(request.user),
'breadcrumbs': breadcrumbs,
'plannedsessions': sps,
'plan': trainingplan,
'active': 'nav-plan',
'dateform': dateform,
'totals': totals,
'rower': r,
'timeperiod': timeperiod,
'completeness': completeness,
'sessioncolor': sessioncolor,
'actualvalue': actualvalue,
'completiondate': completiondate,
'unmatchedworkouts': unmatchedworkouts,
})
@allow_shares
# @login_required()
def plannedsessions_print_view(request, userid=0, startdatestring='', enddatestring=''):
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request, startdatestring=startdatestring,
enddatestring=enddatestring)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r, startdate=startdate, enddate=enddate)
completeness = {}
actualvalue = {}
completiondate = {}
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
return render(request, 'plannedsessions_print.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'plannedsessions': sps,
'rower': r,
'active': 'nav-plan',
'startdate': startdate,
'enddate': enddate,
'timeperiod': timeperiod,
})
@login_required()
@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True)
def plannedsessions_manage_view(request, userid=0,
initialsession=0):
is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
r = getrequestrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
sps = get_sessions(r, startdate=startdate, enddate=enddate)
if initialsession == 0:
try:
initialsession = sps[0].id
except IndexError:
initialsession = 0
if initialsession:
try:
ps0 = PlannedSession.objects.get(id=initialsession)
except PlannedSession.DoesNotExist:
ps0 = None
else:
ps0 = None
ws = Workout.objects.filter(
user=r, date__gte=startdate,
date__lte=enddate
).order_by(
"-date", "-startdatetime", "-id"
)
initialworkouts = [w.id for w in Workout.objects.filter(
user=r, plannedsession=ps0)]
linkedworkouts = []
for w in ws:
if w.plannedsession is not None: # pragma: no cover
linkedworkouts.append(w.id)
plannedsessionstuple = []
for ps in sps:
sessiontpl = (ps.id, ps.__str__())
plannedsessionstuple.append(sessiontpl)
plannedsessionstuple = tuple(plannedsessionstuple)
workoutdata = {}
workoutdata['initial'] = []
choices = []
for w in ws:
wtpl = (w.id, w.__str__())
choices.append(wtpl)
if w.id in initialworkouts:
workoutdata['initial'].append(w.id)
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: # pragma: no cover
selectedworkouts = []
if len(selectedworkouts) == 0: # pragma: no cover
for w in ws:
remove_workout_plannedsession(w, ps)
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, r)
for c in comments:
messages.info(request, c)
for er in errors: # pragma: no cover
messages.error(request, er)
ps_form = PlannedSessionSelectForm(plannedsessionstuple,
initialsession=initialsession)
w_form = WorkoutSessionSelectForm(workoutdata=workoutdata)
if is_ajax: # pragma: no cover
ajax_workouts = []
for id, name in workoutdata['choices']:
ininitial = id in initialworkouts
inlinked = id in linkedworkouts
ajax_workouts.append((id, name, ininitial, inlinked))
ajax_response = {
'workouts': ajax_workouts,
'plannedsessionstuple': plannedsessionstuple,
}
return JSONResponse(ajax_response)
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Plan'
},
{
'url': reverse(plannedsessions_manage_view,
kwargs={
'userid': userid,
'initialsession': initialsession,
}
),
'name': 'Link Sessions to Workouts'
},
]
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
return render(request, 'plannedsessionsmanage.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'dateform': dateform,
'plannedsessions': sps,
'workouts': ws,
'active': 'nav-plan',
'breadcrumbs': breadcrumbs,
'timeperiod': timeperiod,
'rower': r,
'ps_form': ps_form,
'w_form': w_form,
})
# Clone an existing planned session
# need clarity on cloning behavior time shift
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_clone_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError: # pragma: no cover
trainingplan = None
ps = get_object_or_404(PlannedSession, pk=id)
rowers = ps.rower.all()
teams = ps.team.all()
ps.pk = None
ps.id = None
if not ps.is_template:
ps.name += ' (copy)'
ps.is_template = False
deltadays = ps.preferreddate-ps.startdate
ps.startdate = startdate
ps.enddate = enddate
ps.preferreddate = ps.startdate+deltadays
ps.fitfile = None
ps.save()
if rowers:
for rower in rowers:
add_rower_session(rower, ps)
else: # pragma: no cover
add_rower_session(r, ps)
for team in teams:
add_team_session(team, ps)
url = reverse(plannedsession_edit_view,
kwargs={
'id': ps.id,
'userid': r.user.id,
}
)
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
next = request.GET.get('next', url)
return HttpResponseRedirect(next)
# Clone an existing planned session
# need clarity on cloning behavior time shift
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_teamclone_view(request, id=0):
r = getrequestplanrower(request)
teams = Team.objects.filter(manager=request.user)
if teams.count() > 0: # pragma: no cover
teamchoices = [(team.id, team.name) for team in teams]
teaminitial = [str(teams[0].id)]
else: # pragma: no cover
messages.info(
request, "You have no teams established yet. We are redirecting you to the Team Management page.")
url = reverse('rower_teams_view')
return HttpResponseRedirect(url)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError: # pragma: no cover
trainingplan = None
ps = get_object_or_404(PlannedSession, pk=id)
ps.pk = None
ps.id = None
if not ps.is_template:
ps.name += ' (copy)'
ps.is_template = False
ps.fitfile = None
deltadays = ps.preferreddate-ps.startdate
ps.startdate = startdate
ps.enddate = enddate
ps.preferreddate = startdate+deltadays
ps.save()
url = reverse(plannedsession_teamedit_view,
kwargs={
'id': ps.id,
'userid': r.user.id,
}
)
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
next = request.GET.get('next', url)
return HttpResponseRedirect(next)
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_templateedit_view(request, id=0):
r = getrequestrower(request)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
try:
ps = PlannedSession.objects.get(id=id)
except PlannedSession.DoesNotExist: # pragma: no cover
raise Http404("Planned Session does not exist")
if ps.manager != request.user: # pragma: no cover
raise PermissionDenied(
"You are not allowed to edit this planned session")
if ps.sessiontype in ['race', 'indoorrace']: # pragma: no cover
raise PermissionDenied(
"You are not allowed to edit this planned session because it is a race")
if not ps.is_template: # pragma: no cover
ps.pk = None
ps.id = None
ps.is_template = True
ps.startdate = datetime.date(1970, 1, 1)
ps.enddate = datetime.date(1970, 1, 1)
ps.team.clear()
ps.fitfile = None
ps.save()
sessioncreateform = PlannedSessionTemplateForm(instance=ps)
if request.method == 'POST':
sessioncreateform = PlannedSessionTemplateForm(
request.POST, instance=ps)
if sessioncreateform.is_valid():
cd = sessioncreateform.cleaned_data
if cd['sessionunit'] == 'min':
cd['sessionmode'] = 'time'
elif cd['sessionunit'] in ['km', 'm']: # pragma: no cover
cd['sessionmode'] = 'distance'
obj = sessioncreateform.save(commit=False)
obj.save()
sessioncreateform.save_m2m()
res, message = update_plannedsession(ps, cd)
# sessioncreateform.save_m2m()
if res:
messages.info(request, message)
else: # pragma: no cover
messages.error(request, message)
url = reverse('template_library_view')
if '_continue' in request.POST: # pragma: no cover
url = reverse('plannedsession_templateedit_view', kwargs={
'id': ps.id,
})
return HttpResponseRedirect(url)
breadcrumbs = [
{
'url': reverse(plannedsessions_view),
'name': 'Sessions'
},
{
'url': reverse('template_library_view'),
'name': 'Library',
},
{
'url': reverse(plannedsession_templateedit_view,
kwargs={
'id': id,
}
),
'name': 'Edit Session'
}
]
sessiontemplates = PlannedSession.objects.filter(
manager=request.user, is_template=True)
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True, is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
return render(request, 'plannedsessiontemplateedit.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'breadcrumbs': breadcrumbs,
'form': sessioncreateform,
'active': 'nav-plan',
'thesession': ps,
'sessiontemplates': sessiontemplates,
'rower': r,
})
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_togarmin_view(request, id=0):
r = getrequestplanrower(request)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
ps = get_object_or_404(PlannedSession, pk=id)
result = gs.garmin_session_create(ps, r.user)
if not result: # pragma: no cover
messages.error(
request, 'You failed to export your session to Garmin Connect') # pragma: no cover
else: # pragma: no cover
messages.info(
request, 'Session is now on Garmin Connect. Sync your Garmin watch')
url = reverse(plannedsession_view, kwargs={'userid': r.user.id,
'id': ps.id, })
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
next = request.GET.get('next', url)
return HttpResponseRedirect(next)
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_totemplate_view(request, id=0):
r = getrequestplanrower(request)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
ps = get_object_or_404(PlannedSession, pk=id)
ps.pk = None
ps.id = None
ps.is_template = True
ps.fitfile = None
ps.startdate = datetime.date(1970, 1, 1)
ps.enddate = datetime.date(1970, 1, 1)
ps.save()
url = reverse(plannedsession_create_view, kwargs={'userid': r.user.id})
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
next = request.GET.get('next', url)
return HttpResponseRedirect(next)
# Edit an existing planned session
@permission_required('plannedsession.change_session', fn=get_session_by_pk, raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
def plannedsession_edit_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError: # pragma: no cover
trainingplan = None
ps = get_object_or_404(PlannedSession, pk=id)
if ps.team.all() or ps.rower.all().count() > 1:
url = reverse(plannedsession_teamedit_view,
kwargs={
'id': id,
})
url = url+"?when="+timeperiod
return HttpResponseRedirect(url)
if request.method == 'POST':
sessioncreateform = PlannedSessionForm(
request.POST, request.FILES, instance=ps)
if sessioncreateform.is_valid():
cd = sessioncreateform.cleaned_data
if cd['sessionunit'] == 'min': # pragma: no cover
cd['sessionmode'] = 'time'
elif cd['sessionunit'] in ['km', 'm']:
cd['sessionmode'] = 'distance'
res, message = update_plannedsession(ps, cd)
if res:
messages.info(request, message)
else: # pragma: no cover
messages.error(request, message)
url = reverse('plannedsessions_view')
if "_continue" in request.POST: # pragma: no cover
url = reverse(plannedsession_edit_view,
kwargs={
'id': int(ps.id),
'userid': r.user.id,
})
startdatestring = startdate.strftime('%Y-%m-%d')
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+timeperiod
return HttpResponseRedirect(url)
else:
sessioncreateform = PlannedSessionForm(instance=ps)
sps = get_sessions(r, startdate=startdate, enddate=enddate)
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Sessions'
},
{
'url': reverse(plannedsessions_view)+'?when='+timeperiod,
'name': timeperiod,
},
{
'url': reverse(plannedsession_view,
kwargs={
'userid': userid,
'id': id,
}
),
'name': ps.id
},
{
'url': reverse(plannedsession_edit_view,
kwargs={
'userid': userid,
'id': id,
}
),
'name': 'Edit'
}
]
sessiontemplates = PlannedSession.objects.filter(
manager=request.user, is_template=True)
sessiontemplates2 = PlannedSession.objects.filter(
is_template=True, is_public=True
).order_by("name")
sessiontemplates = sessiontemplates | sessiontemplates2
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
return render(request, 'plannedsessionedit.html',
{
'teams': get_my_teams(request.user),
'plan': trainingplan,
'breadcrumbs': breadcrumbs,
'form': sessioncreateform,
'active': 'nav-plan',
'plannedsessions': sps,
'thesession': ps,
'dateform': dateform,
'sessiontemplates': sessiontemplates,
'rower': r,
'timeperiod': timeperiod,
})
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
def plannedsession_detach_view(request, id=0, psid=0):
r = getrequestrower(request)
ps = get_object_or_404(PlannedSession, pk=psid)
w = get_workout(id)
remove_workout_plannedsession(w, ps)
url = reverse(plannedsession_view, kwargs={'id': psid})
next = request.GET.get('next', url)
return HttpResponseRedirect(next)
@login_required()
@permission_required('plannedsession.view_session', fn=get_session_by_pk, raise_exception=True)
def plannedsession_view(request, id=0, userid=0):
r = getrequestplanrower(request, userid=userid)
ps = get_object_or_404(PlannedSession, pk=id)
if ps.steps is not None: # pragma: no cover
jsons = ps.steps
else:
jsons = {}
try: # pragma: no cover
r = VirtualRace.objects.get(id=ps.id)
url = reverse('virtualevent_view',
kwargs={'id': ps.id}
)
return HttpResponseRedirect(url)
except VirtualRace.DoesNotExist:
pass
if ps.course: # pragma: no cover
coursescript, coursediv = course_map(ps.course)
else:
coursescript = ''
coursediv = ''
m = ps.manager
mm = Rower.objects.get(user=m)
resultsdict = get_session_metrics(ps)
resultsdict = pd.DataFrame(resultsdict).transpose().to_dict()
psdict = my_dict_from_instance(ps, PlannedSession)
ws = get_workouts_session(r, ps)
ratio, status, completiondate = is_session_complete(r, ps)
ratio = int(100.*ratio)
# ranking for test
ranking = []
if ps.sessiontype in ['test', 'coursetest']:
if ps.sessionmode == 'distance':
rankws = Workout.objects.filter(
plannedsession=ps).order_by("duration")
else:
rankws = Workout.objects.filter(
plannedsession=ps).order_by("-distance")
for w in rankws:
dd = w.duration
dddelta = datetime.timedelta(hours=dd.hour,
minutes=dd.minute,
seconds=dd.second,
microseconds=dd.microsecond)
wdict = {
'name': w.user.user.first_name+' '+w.user.user.last_name,
'date': w.date,
'distance': w.distance,
'time': dddelta,
'type': w.workouttype,
'coursecompleted': True,
'sessionresult': 0,
'workoutid': w.id,
}
if ps.sessiontype == 'coursetest': # pragma: no cover
vs = CourseTestResult.objects.filter(plannedsession=ps,
workoutid=w.id)
if vs:
for record in vs:
if record.workoutid == w.id:
coursemeters = record.distance
coursecompleted = record.coursecompleted
t = record.duration
wdict['time'] = datetime.timedelta(
hours=t.hour,
seconds=t.second,
minutes=t.minute,
microseconds=t.microsecond
)
wdict['distance'] = int(round(coursemeters))
wdict['coursecompleted'] = coursecompleted
wdict['sessionresult'] = record.id
else:
record = CourseTestResult(
userid=w.user.id,
workoutid=w.id,
plannedsession=ps,
duration=w.duration,
coursecompleted=False,
)
record.save()
job = myqueue(queue, handle_check_race_course,
w.csvfilename, w.id, ps.course.id,
record.id,
w.user.user.email, w.user.user.first_name,
mode='coursetest')
intsecs = 0
microsecs = 0
# taking workout duration plus 1 minute penalty
wdict['time'] = datetime.timedelta(
hours=w.duration.hour,
minutes=w.duration.minute,
seconds=w.duration.second,
)
wdict['distance'] = ps.course.distance
wdict['coursecompleted'] = False
ranking.append(wdict)
if ps.sessiontype == 'coursetest': # pragma: no cover
ranking = sorted(ranking, key=lambda k: k['time'])
if ps.sessiontype == 'fastest_distance': # pragma: no cover
vs = CourseTestResult.objects.filter(plannedsession=ps)
if vs:
for record in vs:
userid = record.userid
uu = User.objects.get(id=userid)
try:
w = Workout.objects.get(id=record.workoutid)
wdict = {
'name': uu.first_name+' '+uu.last_name,
'date': w.date,
'distance': record.distance,
'type': w.workouttype,
'workoutid': w.id,
'coursecompleted': True,
'sessionresult': record.id
}
coursecompleted = record.coursecompleted
t = record.duration
wdict['time'] = datetime.timedelta(
hours=t.hour,
seconds=t.second,
minutes=t.minute,
microseconds=t.microsecond
)
wdict['coursecompleted'] = coursecompleted
ranking.append(wdict)
except Workout.DoesNotExist:
pass
ranking = sorted(ranking, key=lambda k: k['time'])
if ps.sessiontype == 'fastest_time': # pragma: no cover
vs = CourseTestResult.objects.filter(plannedsession=ps)
if vs:
for record in vs:
userid = record.userid
uu = User.objects.get(id=userid)
w = Workout.objects.get(id=record.workoutid)
wdict = {
'name': uu.first_name+' '+uu.last_name,
'date': w.date,
'distance': record.distance,
'type': w.workouttype,
'workoutid': w.id,
'coursecompleted': True,
'sessionresult': record.id,
}
coursecompleted = record.coursecompleted
t = record.duration
wdict['time'] = datetime.timedelta(
hours=t.hour,
seconds=t.second,
minutes=t.minute,
microseconds=t.microsecond
)
wdict['coursecompleted'] = coursecompleted
ranking.append(wdict)
ranking = sorted(ranking, key=lambda k: -k['distance'])
# if coursetest, need to reorder the ranking
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
rowers=r,
enddate__gte=enddate)[0]
except IndexError:
trainingplan = None
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Plan'
},
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Sessions'
},
{
'url': reverse(plannedsession_view,
kwargs={
'userid': userid,
'id': id,
}
),
'name': ps.id
}
]
comments = PlannedSessionComment.objects.filter(
plannedsession=ps).order_by("created")
steps = ''
if ps.steps: # pragma: no cover
d = ps.steps
steps = ps_dict_get_description_html(d, short=False)
return render(request, 'plannedsessionview.html',
{
'psdict': psdict,
'attrs': [
'name', 'startdate', 'enddate', 'preferreddate',
'sessionsport',
'sessiontype',
'sessionmode', 'criterium',
'sessionvalue', 'sessionunit',
'approximate_distance', 'approximate_duration',
'approximate_rscore',
'comment',
],
'workouts': ws,
'active': 'nav-plan',
'breadcrumbs': breadcrumbs,
'manager': mm,
'rower': r,
'ratio': ratio,
'plan': trainingplan,
'status': status,
'results': resultsdict,
'plannedsession': ps,
'timeperiod': timeperiod,
'ranking': ranking,
'coursescript': coursescript,
'coursediv': coursediv,
'comments': comments,
'steps': steps,
}
)
class PlannedSessionDelete(DeleteView):
model = PlannedSession
template_name = 'plannedsessiondeleteconfirm.html'
# extra parameters
def get_context_data(self, **kwargs):
context = super(PlannedSessionDelete, self).get_context_data(**kwargs)
if 'userid' in kwargs: # pragma: no cover
userid = kwargs['userid']
else:
userid = 0
context['active'] = 'nav-plan'
context['rower'] = getrequestrower(self.request, userid=userid)
context['ps'] = self.object
psdict = my_dict_from_instance(self.object, PlannedSession)
context['psdict'] = psdict
context['attrs'] = ['name', 'startdate', 'enddate', 'sessiontype']
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Plan'
},
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Sessions'
},
{
'url': reverse(plannedsession_view,
kwargs={
'userid': userid,
'id': self.object.pk,
}
),
'name': self.object.pk
},
{
'url': reverse('plannedsession_delete_view',
kwargs={'pk': self.object.pk}),
'name': 'Delete'
}
]
context['breadcrumbs'] = breadcrumbs
return context
def get_success_url(self):
ws = Workout.objects.filter(plannedsession=self.object)
for w in ws: # pragma: no cover
w.plannedsession = None
w.save()
url = reverse(plannedsessions_view)
next = self.request.GET.get('next', url)
return next
def get_object(self, *args, **kwargs):
obj = super(PlannedSessionDelete, self).get_object(*args, **kwargs)
if not can_delete_session(self.request.user, obj): # pragma: no cover
raise PermissionDenied(
'You are not allowed to delete this planned session')
return obj
def rower_view_instantplan(request, id='', userid=0):
r = getrequestrower(request, userid=userid)
if not id: # pragma: no cover
raise Http404("Plan does not exist")
plan = InstantPlan.objects.get(uuid=id)
try:
discountedprice = credits.discounted(plan.price, r)
except AttributeError: # pragma: no cover
discountedprice = plan.price
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: # pragma: no cover
messages.error(
request, "Could not connect to the training plan server")
return HttpResponseRedirect(reverse('rower_select_instantplan'))
plansteps = response.json()
trainingdays = plansteps['trainingDays']
trainingdays2 = []
nextday = trainingdays.pop(0)
for i in range(plansteps['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': []
}
)
targets = TrainingTarget.objects.filter(
rowers=r,
date__gte=timezone.now(),
).order_by("-date")
if request.method == 'POST' and not request.user.is_anonymous:
if not can_plan(request.user) and plan.price == 0: # pragma: no cover
messages.error(
request, 'You must be on a <a href="/rowers/paidplans">paid plan</a> to use free training plans')
url = reverse('rower_view_instantplan', kwargs={
'id': id,
})
return HttpResponseRedirect(url)
# check if plan is free or credits are sufficient
if plan.price > 0: # pragma: no cover
if plan.price > r.eurocredits:
messages.error(
request, 'You did not have enough credit to purchase this plan')
url = reverse('rower_view_instantplan', kwargs={
'id': id,
})
return HttpResponseRedirect(url)
form = InstantPlanSelectForm(request.POST, targets=targets)
if form.is_valid():
if plan.price > 0: # pragma: no cover
eurocredits = credits.withdraw(plan.price, r)
plansteps = response.json()
name = form.cleaned_data['name']
try:
targetid = form.cleaned_data['target']
if targetid != '': # pragma: no cover
target = TrainingTarget.objects.get(id=int(targetid))
else:
target = None
except KeyError: # pragma: no cover
try:
targetid = request.POST['target']
if targetid != '':
target = TrainingTarget.objects.get(id=int(targetid))
else:
target = None
except KeyError:
target = None
enddate = form.cleaned_data['enddate']
startdate = form.cleaned_data['startdate']
notes = form.cleaned_data['notes']
datechoice = form.cleaned_data['datechoice']
status = True
if target and datechoice == 'target': # pragma: no cover
enddate = target.date
startdate = enddate-datetime.timedelta(days=plan.duration)
elif datechoice == 'startdate':
enddate = startdate+datetime.timedelta(days=plan.duration)
else: # pragma: no cover
startdate = enddate-datetime.timedelta(days=plan.duration)
p = TrainingPlan(
name=name,
target=target,
manager=r,
startdate=startdate,
enddate=enddate, status=status,
notes=notes,
)
p.save()
p.rowers.add(r)
create_sessions_from_json(plansteps, r, startdate, r.user)
messages.info(request, 'Your Sessions have been added')
url = reverse('plannedsessions_view')
timeperiod = startdate.strftime(
'%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
url = url+'?when='+timeperiod
return HttpResponseRedirect(url)
elif not request.user.is_anonymous:
tz = pytz.timezone(r.defaulttimezone)
nowdate = timezone.now().astimezone(tz)
initial = {
'datechoice': 'startdate',
'startdate': nowdate,
'enddate': nowdate+datetime.timedelta(days=21)
}
form = InstantPlanSelectForm(
targets=targets, instantplan=plan, initial=initial)
else: # pragma: no cover
form = None
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,
'breadcrumbs': breadcrumbs,
'form': form,
})
@login_required()
def remove_groupsession_view(request, id=0):
r = getrequestrower(request)
ps = get_object_or_404(PlannedSession, pk=id)
res = remove_rower_session(r, ps)
if res:
messages.info(request, "We have removed you from this group session")
else: # pragma: no cover
messages.error(
request, "For some reason we could not remove you from this group session")
url = reverse('plannedsessions_view')
return HttpResponseRedirect(url)
@login_required()
def add_instantplan_view(request):
if not request.user.is_staff: # pragma: no cover
raise PermissionDenied("Not Allowed")
r = request.user.rower
if request.method == 'POST': # pragma: no cover
form = InstantPlanForm(request.POST, request.FILES)
if form.is_valid():
ip = form.save(commit=False)
ip.owner = r.user
ip.save()
url = reverse(rower_select_instantplan)
return HttpResponseRedirect(url)
else:
form = InstantPlanForm()
breadcrumbs = [
{
'url': reverse('plannedsessions_view'),
'name': 'Sessions'
},
{
'url': reverse(rower_create_trainingplan),
'name': 'Manage Plans and Targets'
},
{
'url': reverse('rower_select_instantplan'),
'name': 'Select Existing Plans'
},
{
'url': reverse(add_instantplan_view),
'name': 'Add New Instant Plan'
}
]
return render(request, 'add_instantplan.html',
{
'form': form,
'rower': r,
'active': 'nav-plan',
'breadcrumbs': breadcrumbs,
}
)
def rower_select_instantplan(request, id=0):
r = getrequestrower(request, userid=id)
themanager = getrower(request.user)
# get and present available plans
ips = InstantPlan.objects.all().order_by(
"name", "sessionsperweek", "hoursperweek", "duration", "id")
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',
'plans': ips,
})
@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_create_trainingplan(request, id=0):
therower = getrequestrower(request, userid=id)
theuser = therower.user
themanager = getrower(request.user)
if request.method == 'POST' and 'date' in request.POST:
targetform = TrainingTargetForm(request.POST, user=request.user)
if targetform.is_valid():
name = targetform.cleaned_data['name']
date = targetform.cleaned_data['date']
notes = targetform.cleaned_data['notes']
try:
rowers = targetform.cleaned_data['rowers']
except KeyError:
rowers = [therower]
t = TrainingTarget(
name=name,
date=date,
manager=themanager,
notes=notes)
t.save()
for athlete in rowers:
t.rowers.add(athlete)
t.save()
elif request.method == 'POST' and 'startdate' in request.POST:
form = TrainingPlanForm(request.POST, user=request.user)
if form.is_valid():
name = form.cleaned_data['name']
try:
target = form.cleaned_data['target']
except KeyError:
try:
targetid = request.POST['target']
if targetid != '':
target = TrainingTarget.objects.get(id=int(targetid))
else: # pragma: no cover
target = None
except KeyError: # pragma: no cover
target = None
startdate = form.cleaned_data['startdate']
status = form.cleaned_data['status']
enddate = form.cleaned_data['enddate']
notes = form.cleaned_data['notes']
try:
athletes = form.cleaned_data['rowers']
except KeyError:
athletes = [therower]
p = TrainingPlan(
name=name,
target=target,
manager=themanager,
startdate=startdate,
enddate=enddate, status=status,
notes=notes,
)
p.save()
for athlete in athletes:
if can_plan_user(request.user, athlete):
p.rowers.add(athlete)
targets = TrainingTarget.objects.filter(
rowers=therower,
date__gte=timezone.now(),
).order_by("date")
old_targets = TrainingTarget.objects.filter(
rowers=therower,
date__lt=timezone.now(),
).order_by("-date")
targetform = TrainingTargetForm(user=request.user)
plans = TrainingPlan.objects.filter(rowers=therower).order_by("-startdate")
plans_to_deactivate = TrainingPlan.objects.filter(
rowers=therower,
enddate__lt=timezone.now(),
status=True,
).order_by("-startdate")
for p in plans_to_deactivate: # pragma: no cover
p.status = False
p.save()
form = TrainingPlanForm(targets=targets,
initial={'status': False, 'rowers': [therower]},
user=request.user)
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': id}),
'name': 'Plan'
},
{
'url': reverse(rower_create_trainingplan,
kwargs={'id': id}),
'name': 'Manage Plans and Targets'
}
]
return render(request, 'trainingplan_create.html',
{
'form': form,
'rower': therower,
'breadcrumbs': breadcrumbs,
'plans': plans,
'active': 'nav-plan',
'targets': targets,
'targetform': targetform,
'old_targets': old_targets,
})
@user_passes_test(can_plan, login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
@permission_required('target.delete_target', fn=get_target_by_pk, raise_exception=True)
def rower_delete_trainingtarget(request, id=0):
target = get_object_or_404(TrainingTarget, pk=id)
target.delete()
url = reverse(rower_create_trainingplan)
return HttpResponseRedirect(url)
class TrainingPlanDelete(DeleteView):
model = TrainingPlan
template_name = 'trainingplan_delete.html'
success_url = reverse_lazy(rower_create_trainingplan)
def get_object(self, *args, **kwargs):
obj = super(TrainingPlanDelete, self).get_object(*args, **kwargs)
if not can_delete_plan(self.request.user, obj): # pragma: no cover
raise PermissionDenied(
'You are not allowed to delete this training plan')
return obj
class MicroCycleDelete(DeleteView): # pragma: no cover
model = TrainingMicroCycle
template_name = 'trainingplan_delete.html'
# extra parameters
def get_context_data(self, **kwargs):
context = super(MicroCycleDelete, 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.plan.plan.plan.id}),
'name': self.object.plan.plan.plan.name
},
{
'url': reverse('macrocycle_update_view',
kwargs={'pk': self.object.plan.plan.pk}),
'name': self.object.plan.plan.name
},
{
'url': reverse('mesocycle_update_view',
kwargs={'pk': self.object.plan.pk}),
'name': self.object.plan.name
},
{
'url': reverse('microcycle_update_view',
kwargs={'pk': self.object.pk}),
'name': self.object.name
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request, userid=userid)
return context
def get_success_url(self):
plan = self.object.plan.plan.plan
createmacrofillers(plan)
thismesoid = self.object.plan.pk
return reverse(rower_trainingplan_view,
kwargs={
'id': plan.id,
'thismesoid': thismesoid
})
def get_object(self, *args, **kwargs):
obj = super(MicroCycleDelete, self).get_object(*args, **kwargs)
if not can_delete_cycle(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to delete this training plan cycle')
return obj
class MesoCycleDelete(DeleteView): # pragma: no cover
model = TrainingMesoCycle
template_name = 'trainingplan_delete.html'
# extra parameters
def get_context_data(self, **kwargs):
context = super(MesoCycleDelete, 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.plan.plan.id}),
'name': self.object.plan.plan.name
},
{
'url': reverse('macrocycle_update_view',
kwargs={'pk': self.object.plan.pk}),
'name': self.object.plan.name
},
{
'url': reverse('mesocycle_update_view',
kwargs={'pk': self.object.pk}),
'name': self.object.name
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request, userid=userid)
return context
def get_success_url(self):
plan = self.object.plan.plan
thismacroid = self.object.plan.pk
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs={
'id': plan.id,
'thismacroid': thismacroid,
})
def get_object(self, *args, **kwargs):
obj = super(MesoCycleDelete, self).get_object(*args, **kwargs)
if not can_delete_cycle(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to delete this training plan cycle')
return obj
class MacroCycleDelete(DeleteView): # pragma: no cover
model = TrainingMacroCycle
template_name = 'trainingplan_delete.html'
# extra parameters
def get_context_data(self, **kwargs):
context = super(MacroCycleDelete, 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.plan.id}),
'name': self.object.plan.name
},
{
'url': reverse('macrocycle_update_view',
kwargs={'pk': self.object.pk}),
'name': self.object.name
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request, userid=userid)
return context
def get_success_url(self):
plan = self.object.plan
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs={
'id': plan.id
})
def get_object(self, *args, **kwargs):
obj = super(MacroCycleDelete, self).get_object(*args, **kwargs)
if not can_delete_cycle(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to delete this training plan cycle')
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_trainingplan_execution_view(request,
id=0,
userid=0):
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
r = getrequestrower(request, userid=userid)
if int(id) > 0:
try:
plan = TrainingPlan.objects.get(id=id)
except TrainingPlan.DoesNotExist: # pragma: no cover
raise Http404("Training Plan Does Not Exist")
if not is_coach_user(request.user, plan.manager.user): # pragma: no cover
if request.user.rower not in plan.rowers.all():
raise PermissionDenied("Access denied")
if not startdate or not enddate: # pragma: no cover
if int(id) > 0:
startdate = plan.startdate
enddate = plan.enddate
else:
startdate, enddate = get_dates_timeperiod(request)
else:
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
if int(id) > 0:
data, message = get_execution_report(r, startdate, enddate, plan=plan)
else: # pragma: no cover
data, message = get_execution_report(r, startdate, enddate)
if not data.empty:
script, div = interactive_planchart(data, startdate, enddate)
else: # pragma: no cover
script = ''
div = ''
messages.error(request, 'The plan does not cover this time range')
if int(id):
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Plan'
},
{
'url': reverse(rower_trainingplan_view,
kwargs={'userid': userid,
'id': id}),
'name': plan.name
},
{
'url': reverse(rower_trainingplan_execution_view,
kwargs={'userid': userid,
'id': id}),
'name': 'Execution'
}
]
else: # pragma: no cover
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Plan'
},
{
'url': reverse(rower_trainingplan_execution_view,
kwargs={'userid': userid,
'id': id}),
'name': 'Execution'
}
]
return render(request, 'trainingplan_chart.html',
{
'todays_date': timezone.now().date(),
'active': 'nav-plan',
'breadcrumbs': breadcrumbs,
'rower': r,
'the_script': script,
'the_div': div
}
)
# @user_passes_test(can_plan,login_url="/rowers/paidplans",
# message="This functionality requires a Coach or Self-Coach plan",
# redirect_field_name=None)
@login_required()
@permission_required('plan.view_plan', fn=get_plan_by_pk, raise_exception=True)
def rower_trainingplan_view(request,
id=0,
userid=0,
thismicroid=0,
thismacroid=0,
thismesoid=0):
startdate, enddate = get_dates_timeperiod(request)
startdate = startdate.date()
enddate = enddate.date()
plan = get_object_or_404(TrainingPlan, pk=id)
r = getrequestrower(request, userid=userid)
createmacrofillers(plan)
macrocycles = TrainingMacroCycle.objects.filter(
plan=plan,
type='userdefined').order_by("startdate")
checkscores(r, macrocycles)
createmacrofillers(plan)
macrocycles = TrainingMacroCycle.objects.filter(
plan=plan).order_by("startdate")
count = 0
cycles = {}
for m in macrocycles:
createmesofillers(m)
mesocycles = TrainingMesoCycle.objects.filter(
plan=m).order_by("startdate")
mesos = {}
count2 = 0
for me in mesocycles:
createmicrofillers(me)
microcycles = TrainingMicroCycle.objects.filter(
plan=me).order_by("startdate")
mesos[count2] = (me, microcycles)
count2 += 1
cycles[count] = (m, mesos)
count += 1
breadcrumbs = [
{
'url': reverse(plannedsessions_view,
kwargs={'userid': userid}),
'name': 'Plan'
},
{
'url': reverse(rower_trainingplan_view,
kwargs={'userid': userid,
'id': id}),
'name': plan.name
}
]
if not thismicroid and not thismacroid and not thismesoid:
try:
thismicro = get_todays_micro(plan, thedate=startdate)
thismicroid = thismicro.pk
except AttributeError: # pragma: no cover
thismicroid = None
return render(request, 'trainingplan.html',
{
'plan': plan,
'todays_date': timezone.now().date(),
'active': 'nav-plan',
'breadcrumbs': breadcrumbs,
'rower': r,
'cycles': cycles,
'thismicroid': thismicroid,
'thismacroid': thismacroid,
'thismesoid': thismesoid,
}
)
class TrainingMacroCycleUpdate(UpdateView): # pragma: no cover
model = TrainingMacroCycle
template_name = 'trainingplan_edit.html'
form_class = TrainingMacroCycleForm
# extra parameters
def get_context_data(self, **kwargs):
context = super(TrainingMacroCycleUpdate,
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.plan.id}),
'name': self.object.plan.name
},
{
'url': reverse('macrocycle_update_view',
kwargs={'pk': self.object.pk}),
'name': self.object.name
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request, userid=userid)
return context
def get_success_url(self):
plan = self.object.plan
createmacrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs={
'id': plan.id,
'thismacroid': self.object.id,
}
)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
macrocycle = form.save()
mesocyclecheckdates(macrocycle)
return super(TrainingMacroCycleUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingMacroCycleUpdate, self).get_object(*args, **kwargs)
if not can_change_cycle(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to edit this training plan cycle')
else:
obj.type = 'userdefined'
obj.save()
return obj
class TrainingMesoCycleUpdate(UpdateView): # pragma: no cover
model = TrainingMesoCycle
template_name = 'trainingplan_edit.html'
form_class = TrainingMesoCycleForm
# extra parameters
def get_context_data(self, **kwargs):
context = super(TrainingMesoCycleUpdate,
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.plan.plan.id}),
'name': self.object.plan.plan.name
},
{
'url': reverse('macrocycle_update_view',
kwargs={'pk': self.object.plan.pk}),
'name': self.object.plan.name
},
{
'url': reverse('mesocycle_update_view',
kwargs={'pk': self.object.pk}),
'name': self.object.name
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request, userid=userid)
return context
def get_success_url(self):
plan = self.object.plan
createmesofillers(plan)
return reverse(rower_trainingplan_view,
kwargs={
'id': plan.plan.id,
'thismesoid': self.object.id,
}
)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
mesocycle = form.save()
microcyclecheckdates(mesocycle)
return super(TrainingMesoCycleUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingMesoCycleUpdate, self).get_object(*args, **kwargs)
if not can_change_cycle(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to edit this training plan cycle')
else:
obj.type = 'userdefined'
obj.save()
obj.plan.type = 'userdefined'
obj.plan.save()
return obj
class TrainingMicroCycleUpdate(UpdateView): # pragma: no cover
model = TrainingMicroCycle
template_name = 'trainingplan_edit.html'
form_class = TrainingMicroCycleForm
# extra parameters
def get_context_data(self, **kwargs):
context = super(TrainingMicroCycleUpdate,
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.plan.plan.plan.id}),
'name': self.object.plan.plan.plan.name
},
{
'url': reverse('macrocycle_update_view',
kwargs={'pk': self.object.plan.plan.pk}),
'name': self.object.plan.plan.name
},
{
'url': reverse('mesocycle_update_view',
kwargs={'pk': self.object.plan.pk}),
'name': self.object.plan.name
},
{
'url': reverse('microcycle_update_view',
kwargs={'pk': self.object.pk}),
'name': self.object.name
}
]
context['active'] = 'nav-plan'
context['breadcrumbs'] = breadcrumbs
context['rower'] = getrequestrower(self.request, userid=userid)
return context
def get_success_url(self):
plan = self.object.plan
createmicrofillers(plan)
return reverse(rower_trainingplan_view,
kwargs={
'id': plan.plan.plan.id,
'thismicroid': self.object.pk
}
)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
microcycle = form.save()
return super(TrainingMicroCycleUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingMicroCycleUpdate, self).get_object(*args, **kwargs)
if not can_change_cycle(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to edit this training plan cycle')
else:
obj.type = 'userdefined'
obj.save()
obj.plan.type = 'userdefined'
obj.plan.save()
return obj
class TrainingPlanUpdate(UpdateView): # pragma: no cover
model = TrainingPlan
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)
def form_valid(self, form):
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 not can_change_plan(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to edit this training plan cycle')
return obj
class TrainingTargetUpdate(UpdateView): # pragma: no cover
model = TrainingTarget
template_name = 'trainingplan_edit.html'
form_class = TrainingTargetForm
# extra parameters
def get_context_data(self, **kwargs):
context = super(TrainingTargetUpdate, 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('trainingtarget_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)
def form_valid(self, form):
form.instance.user = self.request.user
form.instance.post_date = datetime.datetime.now()
target = form.save()
return super(TrainingTargetUpdate, self).form_valid(form)
def get_object(self, *args, **kwargs):
obj = super(TrainingTargetUpdate, self).get_object(*args, **kwargs)
if not can_change_target(self.request.user, obj):
raise PermissionDenied(
'You are not allowed to edit this training plan cycle')
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)
@permission_required('cycle.change_cycle', fn=get_meso_by_pk, raise_exception=True)
def planmesocyclebyweek(request, id=0, userid=0): # pragma: no cover
cycle = get_object_or_404(TrainingMesoCycle, pk=id)
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)]
if sundays and sundays[-1] < cycle.enddate:
sundays = sundays+[cycle.enddate]
elif not sundays:
sundays = [cycle.enddate]
for i in range(len(sundays)):
if i == 0:
monday = cycle.startdate
else:
monday = sundays[i]-timedelta(days=6)
if monday < cycle.startdate:
monday = cycle.startdate
nextsunday = sundays[i]
micro = TrainingMicroCycle(startdate=monday,
enddate=nextsunday,
plan=cycle,
name='Week %s' % monday.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)
@user_passes_test(can_plan, login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
@permission_required('cycle.change_cycle', fn=get_macro_by_pk, raise_exception=True)
def planmacrocyclebymonth(request, id=0, userid=0): # pragma: no cover
cycle = get_object_or_404(TrainingMacroCycle, pk=id)
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)