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 %} -
- {{formset.management_form}} - {% crispy session_form %} - - {% for set in day.set_set.select_related %} - {% for exercise in set.exercise_bases %} - {% with value=exercise_list|get_item:exercise.id %} -
- -
-
-
{% translate "Amount" %}
-
{% translate "Unit" %}
-
{% translate "Weight" %}
-
{% translate "Unit" %}
-
{% translate "RiR" %}
-
- {% for form in value.forms %} - {% crispy form helper %} - {% endfor %} - {% endwith %} - {% endfor %} - {% endfor %} -
- -
-
-{% 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