From cad9e6ab77eecefc85825d3bcee4bd9788a1cedb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 7 Apr 2022 16:29:11 +0200 Subject: [PATCH] everything working, --- rowers/models.py | 27 ++- .../templates/plannedsessiontemplateedit.html | 9 + rowers/templates/stepedit.html | 38 ++++ rowers/templates/stepeditor.html | 96 ++++++++-- rowers/urls.py | 6 + rowers/views/planviews.py | 177 +++++++++++++++++- static/css/rowsandall2.css | 2 +- 7 files changed, 324 insertions(+), 31 deletions(-) create mode 100644 rowers/templates/stepedit.html diff --git a/rowers/models.py b/rowers/models.py index 06364051..ef789caa 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2414,7 +2414,7 @@ class PlannedSessionStep(models.Model): manager = models.ForeignKey(User, null=True, on_delete=models.CASCADE) name = models.TextField(default='',max_length=200, blank=True, null=True) type = models.TextField(default='',max_length=200, blank=True, null=True) - durationvalue = models.IntegerField(default=0) + durationvalue = models.FloatField(default=0) durationtype = models.TextField(default='',max_length=200, blank=True, null=True, choices=durationtypes) targetvalue = models.IntegerField(default=0) @@ -2435,6 +2435,8 @@ class PlannedSessionStep(models.Model): elif self.intensity == "Rest": self.color = 'add8e6' + self.durationvalue = int(self.durationvalue) + super(PlannedSessionStep, self).save(*args, **kwargs) def asdict(self): @@ -2442,7 +2444,10 @@ class PlannedSessionStep(models.Model): 'wkt_step_name': self.name, 'durationType': self.durationtype, 'durationValue': self.durationvalue, + 'targetType': self.targettype, 'targetValue': self.targetvalue, + 'targetValueLow': self.targetvaluelow, + 'targetValueHigh': self.targetvaluehigh, 'description': self.description, 'stepId': self.pk, 'intensity': self.intensity, @@ -2458,13 +2463,33 @@ class StepEditorForm(ModelForm): #'type', 'durationtype', 'durationvalue', + 'targettype', + 'targetvalue', + 'targetvaluelow', + 'targetvaluehigh', 'intensity', + 'description', ] widgets = { 'name': forms.Textarea(attrs={'rows':1, 'cols':50}), } + def __init__(self, *args, **kwargs): + super(StepEditorForm, self).__init__(*args, **kwargs) + if self.instance.durationtype == 'Time': + self.initial['durationvalue'] = self.instance.durationvalue / 60000 + elif self.instance.durationtype == 'Distance': + form.initial['durationvalue'] = self.instance.durationvalue / 100 + + def save(self, *args, **kwargs): + # conversions + if self.instance.durationtype == 'Time': + self.instance.durationvalue *= 60000 + elif self.instance.durationtype == 'Distance': + self.instance.durationvalue *= 100 + return super(StepEditorForm, self).save(*args, **kwargs) + class PlannedSession(models.Model): diff --git a/rowers/templates/plannedsessiontemplateedit.html b/rowers/templates/plannedsessiontemplateedit.html index d3c15a01..303d47cf 100644 --- a/rowers/templates/plannedsessiontemplateedit.html +++ b/rowers/templates/plannedsessiontemplateedit.html @@ -35,6 +35,15 @@ +
  • + {% if steps %} +

    Steps

    +

    {{ steps|safe }}

    +

    + Edit Steps (experimental) +

    + {% endif %} +
  • {% endblock %} diff --git a/rowers/templates/stepedit.html b/rowers/templates/stepedit.html new file mode 100644 index 00000000..1e6a0530 --- /dev/null +++ b/rowers/templates/stepedit.html @@ -0,0 +1,38 @@ +{% extends "newbase.html" %} +{% load static %} +{% load rowerfilters %} + +{% block title %}Rowsandall Training Plans{% endblock %} + + +{% block main %} +

    Edit {{ step.name }}

    +
      +
    • +

      + WARNING: This is experimental functionality which may not behave as you + expect. Does not work on smartphones. +

      +
    • +
    • +

      Step Description

      + {{ stepdescription }} +
    • +
    • +

      Add new step

      +
      + + {{ form.as_table }} +
      + {% csrf_token %} + + +
      +
    • +
    +{% endblock %} + + +{% block sidebar %} +{% include 'menu_plan.html' %} +{% endblock %} diff --git a/rowers/templates/stepeditor.html b/rowers/templates/stepeditor.html index ecfee243..ec64d60d 100644 --- a/rowers/templates/stepeditor.html +++ b/rowers/templates/stepeditor.html @@ -19,14 +19,47 @@

    Training Steps for {{ ps.name }}

    +

    +

    + + +
    +

    +{% for step in currentsteps %} +
    + + {{ step.name }} + + + + + + + + + + + +
    +{% endfor %}

    Library

    {% for step in steps %} -
    -
    +
    + {{ step.name }} -
    + + + + + + + + + + +
    {% endfor %}
    @@ -57,18 +90,16 @@ {% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index 049e6bb6..49cfa865 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -875,6 +875,12 @@ urlpatterns = [ views.rower_create_trainingplan, name='rower_create_trainingplan'), re_path(r'^plans/$', views.rower_select_instantplan, name='rower_select_instantplan'), + re_path(r'^plans/step/(?P\d+)/edit/$', + views.stepedit, name='stepedit'), + re_path(r'^plans/step/(?P\d+)/edit/(?P\d+)/$', + views.stepedit, name='stepedit'), + re_path(r'^plans/step/(?P\d+)/delete/$', + views.stepdelete, name='stepdelete'), re_path(r'^plans/stepeditor/$', views.stepeditor, name='stepeditor'), re_path(r'^plans/stepeditor/(?P\d+)/$', diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index 6612e01f..3012334a 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -2005,6 +2005,12 @@ def plannedsession_templateedit_view(request, id=0): 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), @@ -2015,6 +2021,7 @@ def plannedsession_templateedit_view(request, id=0): 'thesession': ps, 'sessiontemplates': sessiontemplates, 'rower': r, + 'steps': steps, }) @@ -2975,6 +2982,8 @@ def stepadder(request, id=0): ) ps = get_object_or_404(PlannedSession, pk=id) + is_save = request.GET.get('save',0) + if request.method != 'POST': message = {'status': 'false', 'message': 'this view cannot be accessed through GET'} @@ -2996,27 +3005,159 @@ def stepadder(request, id=0): return JSONResponse(status=403, data=message) steps = { - "filename": "", + "filename": ps.steps['filename'], + "sport": ps.steps['sport'], + "steps": [] } - for id in post_data: + + for nr,id in enumerate(post_data): try: step = PlannedSessionStep.objects.get(id=int(id)) - print(step.name) # add JSON + d = step.asdict() + d['stepId'] = nr + steps['steps'].append(d) except PlannedSessionStep.DoesNotExist: - print('fail') pass + if is_save: + # 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 Coach or Self-Coach 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') + + url = reverse(stepeditor,kwargs={'id':backid}) + + return HttpResponseRedirect(url) + +@user_passes_test(can_plan, login_url="/rowers/paidplans", + message="This functionality requires a Coach or Self-Coach plan", + redirect_field_name=None) +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: + 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): + 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': + step.durationvalue *= 60000 + elif step.durationtype == 'Distance': + step.durationvalue *= 100 + + step.save() + + + if step.durationtype == 'Time': + 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: + 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 Coach or Self-Coach 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']: - print(step) durationtype = step.get('durationType','') durationvalue = step.get('durationValue',0) targetvalue = step.get('targetValue',0) @@ -3034,8 +3175,8 @@ def stepeditor(request, id=0): targetvaluelow = targetvaluelow, targetvaluehigh = targetvaluehigh, intensity = intensity, - ).count() - if not archived_steps and durationvalue != 0: + ) + if not archived_steps.count() and durationvalue != 0: s = PlannedSessionStep( manager = request.user, durationtype = durationtype, @@ -3048,7 +3189,9 @@ def stepeditor(request, id=0): name = step.get('wkt_step_name','Step') ) s.save() - ps.steps = {} + else: + s = archived_steps[0] + currentsteps.append(s) form = StepEditorForm() @@ -3069,16 +3212,30 @@ def stepeditor(request, id=0): for step in steps: stepdescriptions[step.id] = step_to_string(step.asdict(), short=False)[0] - print(stepdescriptions) - print(steps) + 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", diff --git a/static/css/rowsandall2.css b/static/css/rowsandall2.css index da382d2c..bd6c9752 100644 --- a/static/css/rowsandall2.css +++ b/static/css/rowsandall2.css @@ -357,7 +357,7 @@ th.rotate > div > span { position: relative; overflow: hidden; background: #878787; - color: white; + /* color: white; */ padding: 10px; padding-bottom: 40px; }