from rowers.plannedsessions import cratiocolors, checkscores from rowers.utils import allmonths from rowers.utils import allsundays from rowers.views.statements import * import rowers.garmin_stuff as gs from rowers import credits from json.decoder import JSONDecodeError from rowers.utils import step_to_string @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: {comment}'.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' _ = 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) _ = 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 _ = 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 _ = 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 Pro 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) for rower in team.rower.all(): add_rower_session(rower, 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 Pro plan", redirect_field_name=None) def template_share_view(request, id=0, userid=0): 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 Pro plan", redirect_field_name=None) def template_makeprivate_view(request, id=0, userid=0): 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 Pro 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 Pro 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 Pro 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 Pro 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 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 Pro 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: 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]) 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) 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 Pro 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) 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 is_coach(request.user) or is_coachtrial(request.user): 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) rowers = [therower] for ps in sps: if is_coach(request.user) or is_coachtrial(request.user): rowers += ps.rower.all() else: # pragma: no cover rowers += ps.rower.filter( team__in=rteams) 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, 'active': 'nav-plan', 'theteam': theteam, 'unmatchedworkouts': unmatchedworkouts, 'rower': getrower(request.user) } ) @login_required() def save_plan_yaml(request, userid=0): r = getrequestrower(request, userid=userid) startdate, enddate = get_dates_timeperiod(request) startdate = startdate.date() enddate = enddate.date() duration = (enddate-startdate).days+1 filename = 'myplan.yml' plan = { 'filename': filename, 'name': 'Training Plan', 'duration': duration, 'description': 'My Training Plan', } sps = get_sessions(r, startdate=startdate, enddate=enddate) trainingdays = [] # add sessions to days for i in range(duration): dd = startdate+timedelta(days=i) workouts = [] for ps in sps: if ps.preferreddate == dd: sessionsport = mytypes.fitmapping[ps.sessionsport].capitalize() if ps.steps: steps = ps.steps steps['filename'] = "" workouts.append(steps) else: # pragma: no cover if ps.sessionmode == 'distance': ps.interval_string = '{d}m'.format(d=ps.sessionvalue) elif ps.sessionmode == 'time': ps.interval_string = '{d}min'.format(d=ps.sessionvalue) elif ps.sessionmode == 'rScore': ps.approximate_duration = ps.sessionvalue ps.interval_string = '{d}min'.format(d=ps.sessionvalue) elif ps.sessionmode == 'TRIMP': ps.approximate_duration = int(ps.sessionvalue/2.) ps.interval_string = '{d}min'.format(d=int(ps.sessionvalue/2.)) ps.fitfile = '' ps.steps = None ps.save() ps_reload = PlannedSession.objects.get(id=ps.id) steps = ps_reload.steps steps['filename'] = "" steps['workoutName'] = ps.name workouts.append(steps) trainingdays.append({'order': i+1, 'workouts': workouts}) plan['trainingDays'] = trainingdays response = HttpResponse(yaml.dump(plan)) response['Content-Disposition'] = 'attachment; filename="training_plan_{u}_{d1}_{d2}.yml"'.format( u=request.user.username, d1=startdate.strftime("%Y%m%d"), d2=enddate.strftime("%Y%m%d"), ) response['Content-Type'] = 'application/octet-stream' return response @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 do_intervals_icu_sync = request.GET.get('icu_sync', False) 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() if do_intervals_icu_sync: # pragma: no cover integration = IntervalsIntegration(request.user) newids = integration.get_plannedsessions(kwargs={'newest':startdate.strftime('%Y-%m-%d'), 'oldest':enddate.strftime('%Y-%m-%d')}) for id in newids: messages.info(request, "Session {id} imported from ICU".format(id=id)) 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 row = { 'rscore': w.rscore, 'hrtss': w.hrtss, 'rpe': w.rpe, 'duration': w.duration, 'id': w.id } tss = dataprep.rscore_approx(row) totals['rscore'] += tss 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 if user_is_basic(request.user): 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 if ps.intervals_icu_id is None and do_intervals_icu_sync: # pragma: no cover intervals = IntervalsIntegration(request.user) result = intervals.plannedsession_create(ps) messages.info(request, "Session {id} synced to ICU".format(id=ps.id)) 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) 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 Pro 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() 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 ps.intervals_icu_id = None ps.rojabo_id = 0 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) for rower in team.rower.all(): add_rower_session(rower, 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 Pro 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 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() 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 Pro 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 steps = '' if ps.steps: # pragma: no cover d = ps.steps steps = ps_dict_get_description_html(d, short=False) 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, 'steps': steps, }) @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 Pro plan", redirect_field_name=None) def plannedsession_tointervals_view(request, id=0): r = getrequestplanrower(request) ps = get_object_or_404(PlannedSession, pk=id) intervals = IntervalsIntegration(request.user) result = intervals.plannedsession_create(ps) if not result: # pragma: no cover messages.error( request, 'You failed to export your session to Intervals') else: messages.info( request, 'Session is now on Intervals.') url = reverse(plannedsession_view, kwargs={'userid': r.user.id, 'id': ps.id, }) thenext = request.GET.get('next', url) # add ?startdate=startdate&enddate=enddate to url, with startdate ps.startdate and enddate ps.enddate startdate = ps.startdate.strftime('%Y-%m-%d') enddate = ps.enddate.strftime('%Y-%m-%d') url += '?startdate='+startdate+'&enddate='+enddate return HttpResponseRedirect(thenext) @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 Pro 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 += '?startdate='+startdatestring+'&enddate='+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 Pro 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 Pro 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, }) 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): 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) 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() _ = 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') # 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 = '' steps_intervals = '' if ps.steps: # pragma: no cover d = ps.steps steps = ps_dict_get_description_html(d, short=False) steps_intervals = ps.steps_intervals() 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, 'steps_intervals': steps_intervals, } ) class PlannedSessionDelete(DeleteView): model = PlannedSession template_name = 'plannedsessiondeleteconfirm.html' def post(self, request, *args, **kwargs): post_data = request.POST intervals_delete = post_data.get('intervals_delete', False) if not intervals_delete: # set intervals_icu_id of object to None self.object = self.get_object() self.object.intervals_icu_id = None self.object.save() return super(PlannedSessionDelete, self).post(request, *args, **kwargs) # 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) 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) workouts = nextday['workouts'] 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 paid plan 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) if not can_plan(request.user): messages.error( request, 'You must be on a paid plan to use free training plans') url = reverse('rower_view_instantplan', kwargs={ 'id': id, }) return HttpResponseRedirect(url) form = InstantPlanSelectForm(request.POST, targets=targets) byrscoreform = PlanByRscoreForm(request.POST) if byrscoreform.is_valid(): try: byrscore = byrscoreform.cleaned_data['byrscore'] except KeyError: byrscore = False else: byrscore = False if form.is_valid(): if plan.price > 0: # pragma: no cover _ = 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'] plan_past_days = form.cleaned_data['plan_past_days'] 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, ) if not plan_past_days: p.startdate = timezone.now().date() p.save() p.rowers.add(r) create_sessions_from_json(plansteps, r, startdate, r.user, planbyrscore=byrscore, plan=p, plan_past_days = plan_past_days, asynchronous=True) messages.info(request, 'Your Sessions have been added') url = reverse('plannedsessions_view') timeperiod = timezone.now().date().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) if request.user.is_superuser: byrscoreform = PlanByRscoreForm() else: byrscoreform = None else: # pragma: no cover form = None byrscoreform = 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, 'byrscoreform': byrscoreform, '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) # get and present available plans ips = InstantPlan.objects.filter(private=False) if not request.user.is_anonymous: ips2 = InstantPlan.objects.filter(owner=request.user) ips = ips | ips2 ips = ips.order_by("private", "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, 'breadcrumbs': breadcrumbs, }) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def rower_create_trainingplan(request, id=0): therower = getrequestrower(request, userid=id) 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, }) @csrf_exempt @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def stepadder(request, id=0): is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest' if not is_ajax: # pragma: no cover return JSONResponse( status=403, data={ 'status': 'false', 'message': 'this view cannot be accessed directly' } ) ps = get_object_or_404(PlannedSession, pk=id) is_save = request.GET.get('save',0) if request.method != 'POST': # pragma: no cover message = {'status': 'false', 'message': 'this view cannot be accessed through GET'} return JSONResponse(status=403, data=message) try: json_data = json.loads(request.body) post_data = json_data except (KeyError, JSONDecodeError): # pragma: no cover q = request.POST post_data = {k: q.getlist(k) if len( q.getlist(k)) > 1 else v for k, v in q.items()} # only allow local host hostt = request.get_host().split(':') if hostt[0] not in ['localhost', '127.0.0.1', 'dev.rowsandall.com', 'rowsandall.com', 'testserver']: # pragma: no cover message = {'status': 'false', 'message': 'permission denied for host '+hostt[0]} return JSONResponse(status=403, data=message) if ps.steps: filename = ps.steps.get('filename','') sport = ps.steps.get('sport','rowing') else: # pragma: no cover filename = '' sport = 'rowing' steps = { "filename": filename, "sport": sport, "steps": [] } for nr,id in enumerate(post_data): try: step = PlannedSessionStep.objects.get(id=int(id)) # add JSON d = step.asdict() d['stepId'] = nr steps['steps'].append(d) except PlannedSessionStep.DoesNotExist: # pragma: no cover pass if is_save: # pragma: no cover # save the darn thing ps.steps = steps ps.interval_string = '' ps.fitfile = None ps.save() return JSONResponse(status=200,data=post_data) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def stepdelete(request, id=0): step = get_object_or_404(PlannedSessionStep, pk=id) step.delete() backid = request.GET.get('id',0) if backid: # pragma: no cover url = reverse(stepeditor,kwargs={'id':backid}) else: url = reverse('plannedsessions_view') return HttpResponseRedirect(url) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def stepedit(request, id=0, psid=0): step = get_object_or_404(PlannedSessionStep, pk=id) try: ps = PlannedSession.objects.get(id=psid) except PlannedSession.DoesNotExist: # pragma: no cover ps = None form = StepEditorForm(instance=step) if request.method == 'POST': form = StepEditorForm(request.POST) if form.is_valid(): if ps: dd = step.asdict() dd.pop('stepId') for id,ss in enumerate(ps.steps['steps']): ee = ss.copy() ee.pop('stepId') if (dd == ee): # pragma: no cover ss['durationType'] = form.cleaned_data['durationtype'] ss['durationValue'] = form.cleaned_data['durationvalue'] ss['targetType'] = form.cleaned_data['targettype'] ss['targetValue'] = form.cleaned_data['targetvalue'] ss['targetValueLow']= form.cleaned_data['targetvaluelow'] ss['targetValueHigh'] = form.cleaned_data['targetvaluehigh'] ss['intensity'] = form.cleaned_data['intensity'] ss['wkt_step_name'] = form.cleaned_data['name'] ss['description'] = form.cleaned_data['description'] if form.cleaned_data['durationtype'] == 'Time': ss['durationValue'] = form.cleaned_data['durationvalue']*60000 elif form.cleaned_data['durationtype'] == 'Distance': ss['durationValue'] = form.cleaned_data['durationvalue']*100 ss['durationValue'] = int(ss['durationValue']) ps.fitfile = None ps.interval_string = "" ps.save() step.durationtype = form.cleaned_data['durationtype'] step.durationvalue = form.cleaned_data['durationvalue'] step.targettype = form.cleaned_data['targettype'] step.targetvalue = form.cleaned_data['targetvalue'] step.targetvaluelow = form.cleaned_data['targetvaluelow'] step.targetvaluehigh = form.cleaned_data['targetvaluehigh'] step.intensity = form.cleaned_data['intensity'] step.name = form.cleaned_data['name'] step.description = form.cleaned_data['description'] if step.durationtype == 'Time': # pragma: no cover step.durationvalue *= 60000 elif step.durationtype == 'Distance': # pragma: no cover step.durationvalue *= 100 step.save() if step.durationtype == 'Time': # pragma: no cover form.fields['durationvalue'].initial = step.durationvalue / 60000 elif step.durationtype == 'Distance': form.fields['durationvalue'].initial = step.durationvalue / 100 stepdescription = step_to_string(step.asdict(), short=False)[0] if request.method == 'POST': if 'stepsave_and_return' in request.POST: # pragma: no cover url = reverse('stepeditor',kwargs = {'id': ps.id}) return HttpResponseRedirect(url) breadcrumbs = [ { 'url': reverse('template_library_view'), 'name': 'Session Templates' }, { 'url': reverse('plannedsession_templateedit_view', kwargs={'id': ps.id}), 'name': ps.name }, { 'url': reverse('stepeditor', kwargs={'id':ps.id}), 'name': 'Edit Steps' }, { 'url': reverse('stepedit', kwargs={'psid': ps.id, 'id': step.id}), 'name': 'Edit Step' } ] return render(request,'stepedit.html', { 'step': step, 'stepdescription': stepdescription, 'form': form, 'ps': ps, 'breadcrumbs': breadcrumbs, }) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def stepeditor(request, id=0): ps = get_object_or_404(PlannedSession, pk=id) currentsteps = [] if ps.steps: for step in ps.steps['steps']: durationtype = step.get('durationType','') durationvalue = step.get('durationValue',0) targetvalue = step.get('targetValue',0) targettype = step.get('targetType','') targetvaluelow = step.get('targetValueLow',0) targetvaluehigh = step.get('targetValueHigh',0) intensity = step.get('intensity','Active') archived_steps = PlannedSessionStep.objects.filter( manager = request.user, durationtype = durationtype, durationvalue = durationvalue, targetvalue = targetvalue, targettype = targettype, targetvaluelow = targetvaluelow, targetvaluehigh = targetvaluehigh, intensity = intensity, ) if not archived_steps.count(): s = PlannedSessionStep( manager = request.user, durationtype = durationtype, durationvalue = durationvalue, targetvalue = targetvalue, targettype = targettype, targetvaluelow = targetvaluelow, targetvaluehigh = targetvaluehigh, intensity = intensity, name = step.get('wkt_step_name','Step') ) s.save() else: # pragma: no cover s = archived_steps[0] currentsteps.append(s) form = StepEditorForm() if request.method == 'POST': # pragma: no cover form = StepEditorForm(request.POST) if form.is_valid(): step = form.save(commit=False) step.manager = request.user step.save() steps = PlannedSessionStep.objects.filter( manager=request.user, durationtype__in=['Time','Distance','RepeatUntilStepsCmplt'] ).order_by( 'intensity','-durationvalue','durationtype', ) stepdescriptions = {} for step in steps: stepdescriptions[step.id] = step_to_string(step.asdict(), short=False)[0] breadcrumbs = [ { 'url': reverse('template_library_view'), 'name': 'Session Templates' }, { 'url': reverse('plannedsession_templateedit_view', kwargs={'id': ps.id}), 'name': ps.name }, { 'url': reverse('stepeditor', kwargs={'id': ps.id}), 'name': 'Edit Steps' } ] return render(request, 'stepeditor.html', { 'steps':steps, 'currentsteps': currentsteps, 'stepdescriptions': stepdescriptions, 'form':form, 'ps':ps, 'breadcrumbs': breadcrumbs, }) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro 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 post(self, request, *args, **kwargs): delete_sessions = request.POST.get('delete_sessions',0) delete_all_sessions = request.POST.get('delete_all_sessions',0) self.object = self.get_object() self.object.delete(delete_sessions=delete_sessions, delete_all_sessions=delete_all_sessions) return HttpResponseRedirect(self.get_success_url()) 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 Pro 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.is_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 Pro 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() _ = 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() _ = 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 Pro 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 Pro 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) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def currentweekplan_view(request): r = getrower(request.user) form = CurrentWeekJsonForm() if request.method == "POST": form = CurrentWeekJsonForm(request.POST) if form.is_valid(): secret = form.cleaned_data['secret'] plan = form.cleaned_data['plan'] delete_existing = form.cleaned_data['delete_existing'] post_data = { 'secret': secret, 'plan': plan, } url = "http://localhost:8898/current-week-plan/" response = requests.post(url, data=post_data) data = response.json() if response.status_code in [200,201]: if delete_existing: remove_this_week_sessions(r) create_next_week_from_json( data, r, startdate=timezone.now()-timezone.timedelta(days=timezone.now().weekday())) messages.info(request,"Your planned sessions were created") url = reverse("plannedsessions_view") return HttpResponseRedirect(url) active = 'nav-plan' breadcrumbs = [ { 'url': reverse('plannedsessions_view'), 'name': 'Sessions' }, { 'url': reverse('currentweekplan_view'), 'name': "Current week" }, ] return render(request, 'loadcurrentweek.html', {'rower': r, 'form': form, 'active': active, 'breadcrumbs': breadcrumbs}) @user_passes_test(can_plan, login_url="/rowers/paidplans", message="This functionality requires a Pro plan", redirect_field_name=None) def nextweekplan_view(request): r = getrower(request.user) fitness, fatigue = calculate_fitness(r) form = NextWeekJsonForm( initial={ 'fitness': round(fitness), 'fatigue': round(fatigue), } ) if request.method == "POST": form = NextWeekJsonForm(request.POST) if form.is_valid(): fitness = form.cleaned_data['fitness'] fatigue = form.cleaned_data['fatigue'] secret = form.cleaned_data['secret'] plan = form.cleaned_data['plan'] delete_existing = form.cleaned_data['delete_existing'] post_data = { 'fitness':fitness, 'fatigue':fatigue, 'plan': plan, 'secret': secret, } # post form.cleaned_data to localhost:8898/next-week-plan url = "http://localhost:8898/next-week-plan/" response = requests.post(url, data=post_data) if response.status_code in [200,201]: data = response.json() if delete_existing: remove_next_week_sessions(r) create_next_week_from_json(data, r) messages.info(request,"Your planned sessions were created") else: messages.error(request,"Unsuccessful") active = 'nav-plan' breadcrumbs = [ { 'url': reverse('plannedsessions_view'), 'name': 'Sessions' }, { 'url': reverse('nextweekplan_view'), 'name': "Next week" }, ] return render(request, 'loadnextweek.html', {'rower': r, 'form': form, 'active': active, 'breadcrumbs': breadcrumbs})