diff --git a/wger/manager/forms.py b/wger/manager/forms.py
index e72133764..0894d3b34 100644
--- a/wger/manager/forms.py
+++ b/wger/manager/forms.py
@@ -13,19 +13,17 @@
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
-"""
-This file contains forms used in the application
-"""
+
+# Third Party
+from crispy_forms.helper import FormHelper
+from crispy_forms.layout import Submit
# Django
from django.forms import (
BooleanField,
CharField,
ChoiceField,
- DecimalField,
Form,
- IntegerField,
- ModelChoiceField,
ModelForm,
ModelMultipleChoiceField,
widgets,
@@ -35,27 +33,8 @@
gettext_lazy,
)
-# Third Party
-from crispy_forms.helper import FormHelper
-from crispy_forms.layout import (
- Column,
- Layout,
- Row,
- Submit,
-)
-
# wger
-from wger.core.models import (
- RepetitionUnit,
- WeightUnit,
-)
-from wger.exercises.models import Exercise
-from wger.manager.consts import RIR_OPTIONS
-from wger.manager.models import (
- Workout,
- WorkoutLog,
- WorkoutSession,
-)
+from wger.manager.models import Workout
class WorkoutForm(ModelForm):
@@ -98,123 +77,6 @@ def clean(self, value):
return sorted(qs, key=lambda x: int_list.index(x.pk))
-class WorkoutLogForm(ModelForm):
- """
- Helper form for a WorkoutLog.
-
- These fields are re-defined here only to make them optional. Otherwise
- all the entries in the formset would be required, which is not really what
- we want. This form is one prime candidate to rework with some modern JS
- framework, there is a ton of ugly logic like this just to make it work.
- """
-
- repetition_unit = ModelChoiceField(
- queryset=RepetitionUnit.objects.all(),
- label=_('Unit'),
- required=False,
- )
- weight_unit = ModelChoiceField(
- queryset=WeightUnit.objects.all(),
- label=_('Unit'),
- required=False,
- )
- exercise_base = ModelChoiceField(
- queryset=Exercise.objects.all(),
- label=_('Exercise'),
- required=False,
- )
- reps = IntegerField(
- label=_('Repetitions'),
- required=False,
- )
- weight = DecimalField(
- label=_('Weight'),
- initial=0,
- required=False,
- )
- rir = ChoiceField(
- label=_('RiR'),
- choices=RIR_OPTIONS,
- required=False,
- )
-
- class Meta:
- model = WorkoutLog
- exclude = ('workout',)
-
-
-class WorkoutLogFormHelper(FormHelper):
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.form_method = 'post'
- self.layout = Layout(
- 'id',
- Row(
- Column('reps', css_class='col-2'),
- Column('repetition_unit', css_class='col-3'),
- Column('weight', css_class='col-2'),
- Column('weight_unit', css_class='col-3'),
- Column('rir', css_class='col-2'),
- css_class='form-row',
- ),
- )
- self.form_show_labels = False
- self.form_tag = False
- self.disable_csrf = True
- self.render_required_fields = True
-
-
-class HelperWorkoutSessionForm(ModelForm):
- """
- A helper form used in the workout log view
- """
-
- class Meta:
- model = WorkoutSession
- exclude = ('user', 'workout')
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
- self.helper = FormHelper()
- self.helper.layout = Layout(
- Row(
- Column('date', css_class='col-6'),
- Column('impression', css_class='col-6'),
- css_class='form-row',
- ),
- 'notes',
- Row(
- Column('time_start', css_class='col-6'),
- Column('time_end', css_class='col-6'),
- css_class='form-row',
- ),
- )
- self.helper.form_tag = False
-
-
-class WorkoutSessionForm(ModelForm):
- """
- Workout Session form
- """
-
- class Meta:
- model = WorkoutSession
- exclude = ('user', 'workout', 'date')
-
- def __init__(self, *args, **kwargs):
- super(WorkoutSessionForm, self).__init__(*args, **kwargs)
- self.helper = FormHelper()
- self.helper.layout = Layout(
- 'impression',
- 'notes',
- Row(
- Column('time_start', css_class='col-6'),
- Column('time_end', css_class='col-6'),
- css_class='form-row',
- ),
- )
-
-
class WorkoutScheduleDownloadForm(Form):
"""
Form for the workout schedule download
diff --git a/wger/manager/helpers.py b/wger/manager/helpers.py
index ba1fde058..8a77e0262 100644
--- a/wger/manager/helpers.py
+++ b/wger/manager/helpers.py
@@ -23,10 +23,7 @@
from reportlab.lib import colors
from reportlab.lib.units import cm
from reportlab.platypus import (
- Image,
KeepTogether,
- ListFlowable,
- ListItem,
Paragraph,
Table,
)
@@ -76,11 +73,13 @@ def render_workout_day(
set_count = 1
day_markers.append(len(data))
- data.append([
- Paragraph(
- f'{_("Rest day") if day_data.day.is_rest else day_data.day.name}',
- styleSheet['SubHeader'],
- )]
+ data.append(
+ [
+ Paragraph(
+ f'{_("Rest day") if day_data.day.is_rest else day_data.day.name}',
+ styleSheet['SubHeader'],
+ )
+ ]
)
# Note: the _('Date') will be on the 3rd cell, but since we make a span
@@ -92,7 +91,6 @@ def render_workout_day(
exercise_start = len(data)
slot_count = 0
for slot in day_data.slots_display_mode:
-
slot_count += 1
group_exercise_marker[slot_count] = {'start': len(data), 'end': len(data)}
diff --git a/wger/manager/signals.py b/wger/manager/signals.py
index a84878923..0da1d1bf1 100644
--- a/wger/manager/signals.py
+++ b/wger/manager/signals.py
@@ -101,7 +101,8 @@ def update_cache_rir_config(sender, instance: RiRConfig, **kwargs):
def update_cache_log(sender, instance: WorkoutLog, **kwargs):
- reset_routine_cache(instance.routine)
+ if instance.routine:
+ reset_routine_cache(instance.routine)
post_save.connect(update_activity_cache, sender=WorkoutSession)
diff --git a/wger/manager/templates/log/add.html b/wger/manager/templates/log/add.html
deleted file mode 100644
index fd8184e9c..000000000
--- a/wger/manager/templates/log/add.html
+++ /dev/null
@@ -1,79 +0,0 @@
-{% extends "base.html" %}
-{% load i18n static wger_extras django_bootstrap_breadcrumbs crispy_forms_tags %}
-
-
-{# #}
-{# Breadcrumbs #}
-{# #}
-{% block breadcrumbs %}
- {{ block.super }}
-
- {% breadcrumb day.training day.training %}
- {% breadcrumb "Weight log" "manager:log:log" day.training_id %}
- {% breadcrumb "New weight log" "manager:log:log" day.training_id %}
-{% endblock %}
-
-
-{# #}
-{# Title #}
-{# #}
-{% block title %}{% translate "New weight log" %} – {{day.description}}{% endblock %}
-
-
-{# #}
-{# Header #}
-{# #}
-{% block header %}
-
-{% endblock %}
-
-
-{# #}
-{# Content #}
-{# #}
-{% block content %}
-
-{% endblock %}
-
-
-{# #}
-{# Side bar #}
-{# #}
-{% block sidebar %}
-{% translate "Info" %}
-{% blocktranslate %}A new workout session (impression, notes, time) will
-be created if there isn't already one for the selected date. If there is, it
-will simply be edited. Weight entries are always added.{% endblocktranslate %}
-{% endblock %}
diff --git a/wger/manager/urls.py b/wger/manager/urls.py
index 78f40ee8f..f83bd0782 100644
--- a/wger/manager/urls.py
+++ b/wger/manager/urls.py
@@ -17,7 +17,6 @@
# Django
from django.conf.urls import include
-from django.contrib.auth.decorators import login_required
from django.urls import (
path,
re_path,
@@ -27,13 +26,11 @@
from wger.core.views.react import ReactView
from wger.manager.views import (
ical,
- log,
pdf,
routine,
schedule,
schedule_step,
workout,
- workout_session,
)
# sub patterns for workout logs
@@ -43,16 +40,6 @@
ReactView.as_view(login_required=True),
name='log',
),
- path(
- '/edit', # JS
- log.WorkoutLogUpdateView.as_view(),
- name='edit',
- ),
- path(
- '/delete',
- log.WorkoutLogDeleteView.as_view(),
- name='delete',
- ),
]
# sub patterns for templates
@@ -146,25 +133,6 @@
),
]
-# sub patterns for workout sessions
-patterns_session = [
- re_path(
- r'^(?P\d+)/add/(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})$',
- workout_session.WorkoutSessionAddView.as_view(),
- name='add',
- ),
- path(
- '/edit',
- workout_session.WorkoutSessionUpdateView.as_view(),
- name='edit',
- ),
- re_path(
- r'^(?P\d+)/delete/(?Psession|logs)?$',
- workout_session.WorkoutSessionDeleteView.as_view(),
- name='delete',
- ),
-]
-
# sub patterns for schedules
patterns_schedule = [
path(
@@ -272,9 +240,8 @@
path('', include((patterns_workout, 'workout'), namespace='workout')),
path('', include((patterns_routine, 'routine'), namespace='routine')),
path('template/', include((patterns_templates, 'template'), namespace='template')),
- path('/day/', include((patterns_days, 'day'), namespace='template')),
+ path('/day/', include((patterns_days, 'day'), namespace='day')),
path('log/', include((patterns_log, 'log'), namespace='log')),
- path('session/', include((patterns_session, 'session'), namespace='session')),
path('schedule/', include((patterns_schedule, 'schedule'), namespace='schedule')),
path('schedule/step/', include((patterns_step, 'step'), namespace='step')),
]
diff --git a/wger/manager/views/log.py b/wger/manager/views/log.py
deleted file mode 100644
index ec8816158..000000000
--- a/wger/manager/views/log.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# This file is part of wger Workout Manager.
-#
-# wger Workout Manager is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# wger Workout Manager is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-
-# Standard Library
-import logging
-
-# Django
-from django.contrib.auth.mixins import LoginRequiredMixin
-from django.shortcuts import render
-from django.urls import reverse
-from django.utils.translation import gettext_lazy
-from django.views.generic import (
- DeleteView,
- UpdateView,
-)
-
-# wger
-from wger.manager.forms import WorkoutLogForm
-from wger.manager.models import WorkoutLog
-from wger.utils.generic_views import (
- WgerDeleteMixin,
- WgerFormMixin,
-)
-
-
-logger = logging.getLogger(__name__)
-
-
-# ************************
-# Log functions
-# ************************
-class WorkoutLogUpdateView(WgerFormMixin, UpdateView, LoginRequiredMixin):
- """
- Generic view to edit an existing workout log weight entry
- """
-
- model = WorkoutLog
- form_class = WorkoutLogForm
-
- def get_success_url(self):
- return reverse('manager:workout:view', kwargs={'pk': self.object.workout_id})
-
-
-class WorkoutLogDeleteView(WgerDeleteMixin, DeleteView, LoginRequiredMixin):
- """
- Delete a workout log
- """
-
- model = WorkoutLog
- title = gettext_lazy('Delete workout log')
-
- def get_success_url(self):
- return reverse('manager:workout:view', kwargs={'pk': self.object.workout_id})
-
-
-def add(request, pk):
- """
- Add a new workout log
- """
-
- context = {}
-
- return render(request, 'log/add.html', context)
diff --git a/wger/manager/views/schedule.py b/wger/manager/views/schedule.py
index ee7c1231f..fe7b0e526 100644
--- a/wger/manager/views/schedule.py
+++ b/wger/manager/views/schedule.py
@@ -70,6 +70,7 @@
styleSheet,
)
+
logger = logging.getLogger(__name__)
diff --git a/wger/manager/views/workout_session.py b/wger/manager/views/workout_session.py
deleted file mode 100644
index f17a9f9a4..000000000
--- a/wger/manager/views/workout_session.py
+++ /dev/null
@@ -1,159 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# This file is part of wger Workout Manager.
-#
-# wger Workout Manager is free software: you can redistribute it and/or modify
-# it under the terms of the GNU Affero General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# wger Workout Manager is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU Affero General Public License
-
-# Standard Library
-import datetime
-import logging
-
-# Django
-from django.contrib.auth.mixins import LoginRequiredMixin
-from django.http import (
- HttpResponseBadRequest,
- HttpResponseForbidden,
-)
-from django.urls import (
- reverse,
- reverse_lazy,
-)
-from django.utils.translation import (
- gettext as _,
- gettext_lazy,
-)
-from django.views.generic import (
- CreateView,
- DeleteView,
- UpdateView,
-)
-
-# wger
-from wger.manager.forms import WorkoutSessionForm
-from wger.manager.models import (
- Workout,
- WorkoutLog,
- WorkoutSession,
-)
-from wger.utils.generic_views import (
- WgerDeleteMixin,
- WgerFormMixin,
-)
-
-
-logger = logging.getLogger(__name__)
-"""
-Workout session
-"""
-
-
-class WorkoutSessionUpdateView(WgerFormMixin, LoginRequiredMixin, UpdateView):
- """
- Generic view to edit an existing workout session entry
- """
-
- model = WorkoutSession
- form_class = WorkoutSessionForm
-
- def get_context_data(self, **kwargs):
- context = super(WorkoutSessionUpdateView, self).get_context_data(**kwargs)
- context['title'] = _('Edit workout impression for {0}').format(self.object.date)
-
- return context
-
- def get_success_url(self):
- return reverse('manager:workout:calendar')
-
-
-class WorkoutSessionAddView(WgerFormMixin, LoginRequiredMixin, CreateView):
- """
- Generic view to add a new workout session entry
- """
-
- model = WorkoutSession
- form_class = WorkoutSessionForm
-
- def get_date(self):
- """
- Returns a date object from the URL parameters or None if no date
- could be created
- """
- try:
- date = datetime.date(
- int(self.kwargs['year']),
- int(self.kwargs['month']),
- int(self.kwargs['day']),
- )
- except ValueError:
- date = None
-
- return date
-
- def dispatch(self, request, *args, **kwargs):
- """
- Check for ownership
- """
- workout = Workout.objects.get(pk=kwargs['workout_pk'])
- if workout.get_owner_object().user != request.user:
- return HttpResponseForbidden()
-
- if not self.get_date():
- return HttpResponseBadRequest('You need to use a valid date')
-
- return super(WorkoutSessionAddView, self).dispatch(request, *args, **kwargs)
-
- def get_context_data(self, **kwargs):
- context = super(WorkoutSessionAddView, self).get_context_data(**kwargs)
- context['title'] = _('New workout impression for the {0}'.format(self.get_date()))
- return context
-
- def get_success_url(self):
- return reverse('manager:workout:calendar')
-
- def form_valid(self, form):
- """
- Set the workout and the user
- """
-
- workout = Workout.objects.get(pk=self.kwargs['workout_pk'])
- form.instance.workout = workout
- form.instance.user = self.request.user
- form.instance.date = self.get_date()
- return super(WorkoutSessionAddView, self).form_valid(form)
-
-
-class WorkoutSessionDeleteView(WgerDeleteMixin, LoginRequiredMixin, DeleteView):
- """
- Generic view to delete a workout routine
- """
-
- model = WorkoutSession
- success_url = reverse_lazy('manager:routine:overview')
- messages = gettext_lazy('Successfully deleted')
-
- def form_valid(self, form):
- """
- Delete the workout session and, if wished, all associated weight logs as well
- """
- if self.kwargs.get('logs') == 'logs':
- WorkoutLog.objects.filter(user=self.request.user, date=self.get_object().date).delete()
-
- return super().form_valid(form)
-
- def get_context_data(self, **kwargs):
- logs = '' if not self.kwargs.get('logs') else self.kwargs['logs']
- context = super(WorkoutSessionDeleteView, self).get_context_data(**kwargs)
- context['title'] = _('Delete {0}?').format(self.object)
- if logs == 'logs':
- self.delete_message_extra = _('This will delete all weight logs for this day as well.')
- return context