1946 lines
70 KiB
Python
1946 lines
70 KiB
Python
from rowers.utils import rankingdistances, rankingdurations
|
|
from rowers.utils import (
|
|
workflowleftpanel, workflowmiddlepanel,
|
|
defaultleft, defaultmiddle,
|
|
workout_name_element,
|
|
)
|
|
from rowers.utils import palettes
|
|
from time import strftime
|
|
from django import forms
|
|
from django.contrib.admin.widgets import FilteredSelectMultiple
|
|
from rowers.models import (
|
|
Workout, Rower, Team, PlannedSession, GeoCourse,
|
|
VirtualRace, VirtualRaceResult, IndoorVirtualRaceResult,
|
|
PaidPlan, InStrokeAnalysis, ForceCurveAnalysis
|
|
)
|
|
from rowers.rows import validate_file_extension, must_be_csv, validate_image_extension, validate_kml
|
|
from django.contrib.auth.forms import UserCreationForm
|
|
from django.contrib.auth.models import User
|
|
from django.contrib.admin.widgets import AdminDateWidget
|
|
from django.forms.widgets import SelectDateWidget, HiddenInput
|
|
from django_recaptcha.fields import ReCaptchaField
|
|
from django_recaptcha.widgets import ReCaptchaV3
|
|
|
|
from django.utils import timezone, translation
|
|
from django.forms import ModelForm, Select
|
|
import rowers.dataprep as dataprep
|
|
import rowers.mytypes as mytypes
|
|
import datetime
|
|
from django.forms import formset_factory
|
|
from rowers.utils import landingpages
|
|
from rowers.metrics import axes, metricsgroups, rowingmetrics
|
|
from rowers.metrics import axlabels
|
|
from rowers.rower_rules import user_is_not_basic
|
|
from rowers import models
|
|
|
|
formaxlabels = axlabels.copy()
|
|
formaxlabels.pop('None')
|
|
parchoices = list(sorted(formaxlabels.items(), key=lambda x: x[1]))
|
|
|
|
|
|
class SurveyForm(forms.Form):
|
|
surveydone = forms.ChoiceField(
|
|
required=True,
|
|
choices=(('YES', 'YES'), ('NO', 'NO')),
|
|
label='Will you take a 2 minute survey to help improve rowsandall?',
|
|
widget=forms.RadioSelect)
|
|
|
|
|
|
class FlexibleDecimalField(forms.DecimalField):
|
|
|
|
def to_python(self, value):
|
|
# check decimal symbol
|
|
comma_index = 0
|
|
dot_index = 0
|
|
try:
|
|
comma_index = value.index(',')
|
|
except ValueError:
|
|
pass
|
|
try:
|
|
dot_index = value.index('.')
|
|
except ValueError: # pragma: no cover
|
|
pass
|
|
if value:
|
|
if comma_index > dot_index: # pragma: no cover
|
|
value = value.replace('.', '').replace(',', '.')
|
|
return super(FlexibleDecimalField, self).to_python(value)
|
|
|
|
|
|
class ResampleForm(forms.Form):
|
|
resamplechoices = (
|
|
('overwrite', 'Overwrite Workout'),
|
|
('copy', 'Create a Duplicate Workout')
|
|
)
|
|
|
|
resamplechoice = forms.ChoiceField(
|
|
initial='copy', choices=resamplechoices, label='Copy behavior')
|
|
|
|
|
|
class TrainingZonesForm(forms.Form):
|
|
startdate = forms.DateField(
|
|
initial=timezone.now()-datetime.timedelta(days=42),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now(),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='End Date')
|
|
|
|
|
|
class InstantPlanSelectForm(forms.Form):
|
|
datechoices = (
|
|
('startdate', 'start date'),
|
|
('enddate', 'end date'),
|
|
('target', 'target')
|
|
)
|
|
name = forms.CharField(max_length=255, label='Plan Name', required=False)
|
|
startdate = forms.DateField(
|
|
initial=timezone.now(),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now()+datetime.timedelta(days=21),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='End Date')
|
|
target = forms.ChoiceField(required=False)
|
|
datechoice = forms.ChoiceField(choices=datechoices, initial='enddate', label='Plan by target, start or end date',
|
|
widget=forms.RadioSelect)
|
|
notes = forms.CharField(required=False,
|
|
max_length=200, label='Plan Notes',
|
|
widget=forms.Textarea)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
targets = kwargs.pop('targets', None)
|
|
instantplan = kwargs.pop('instantplan', None)
|
|
super(InstantPlanSelectForm, self).__init__(*args, **kwargs)
|
|
if targets:
|
|
targetchoices = [(x.id, x) for x in targets]
|
|
targetchoices.append((None, '---'))
|
|
self.fields['target'].choices = targetchoices
|
|
else:
|
|
datechoices = (
|
|
('startdate', 'start date'),
|
|
('enddate', 'end date'),
|
|
)
|
|
self.fields['datechoice'].choices = datechoices
|
|
self.fields['datechoice'].label = 'Plan by start or end date'
|
|
self.fields.pop('target')
|
|
if instantplan:
|
|
self.fields['enddate'].initial = timezone.now(
|
|
)+datetime.timedelta(days=instantplan.duration)
|
|
|
|
# Instroke Metrics interactive chart form
|
|
class InstrokeForm(forms.Form):
|
|
name = forms.CharField(initial="", max_length=200,required=False)
|
|
metric = forms.ChoiceField(label='metric',choices=(('a','a'),('b','b')))
|
|
individual_curves = forms.BooleanField(label='individual curves',initial=False,
|
|
required=False)
|
|
spm_min = forms.FloatField(initial=15,label='SPM Min',widget=HiddenInput)
|
|
spm_max = forms.FloatField(initial=45,label='SPM Max',widget=HiddenInput)
|
|
activeminutesmin = forms.FloatField(
|
|
required=False, initial=0, widget=forms.HiddenInput())
|
|
activeminutesmax = forms.FloatField(
|
|
required=False, initial=0, widget=forms.HiddenInput())
|
|
notes = forms.CharField(required=False,
|
|
max_length=200, label='Notes',
|
|
widget=forms.Textarea)
|
|
|
|
def __init__(self, *args, **kwargs): # pragma: no cover
|
|
choices = kwargs.pop('choices', [])
|
|
super(InstrokeForm, self).__init__(*args, **kwargs)
|
|
if len(choices) > 0:
|
|
choices = [(choice, choice) for choice in choices]
|
|
self.fields['metric'].choices = choices
|
|
self.fields['metric'].initial = choices[0]
|
|
|
|
|
|
# Video Analysis creation form
|
|
class VideoAnalysisCreateForm(forms.Form):
|
|
name = forms.CharField(
|
|
max_length=255, label='Analysis Name', required=False)
|
|
url = forms.CharField(max_length=255, required=True,
|
|
label='YouTube Video URL')
|
|
delay = forms.IntegerField(initial=0, label='Delay (seconds)')
|
|
|
|
|
|
def get_metricschoices(mode='water'):
|
|
modes = [mode, 'both', 'basic']
|
|
metricsdescriptions = {}
|
|
for m in metricsgroups:
|
|
metricsdescriptions[m] = m+' ('
|
|
for name, d in rowingmetrics:
|
|
if d['group'] == m and d['mode'] in modes:
|
|
metricsdescriptions[m] += d['verbose_name']+', '
|
|
metricsdescriptions[m] = metricsdescriptions[m][0:-2]+')'
|
|
|
|
metricsgroupschoices = ((m, metricsdescriptions[m]) for m in metricsgroups)
|
|
|
|
return metricsgroupschoices
|
|
|
|
|
|
class VideoAnalysisMetricsForm(forms.Form):
|
|
groups = forms.MultipleChoiceField(label='Metrics Groups',
|
|
choices=get_metricschoices(
|
|
mode='water'),
|
|
widget=forms.CheckboxSelectMultiple,)
|
|
|
|
class Meta:
|
|
mode = 'water'
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
mode = kwargs.pop('mode', 'water')
|
|
super(VideoAnalysisMetricsForm, self).__init__(*args, **kwargs)
|
|
self.fields['groups'].choices = get_metricschoices(mode=mode)
|
|
|
|
|
|
# BillingForm form
|
|
class BillingForm(forms.Form):
|
|
amount = FlexibleDecimalField(required=True, decimal_places=2,
|
|
max_digits=8)
|
|
plan = forms.IntegerField(widget=forms.HiddenInput())
|
|
payment_method_nonce = forms.CharField(max_length=255, required=True)
|
|
paymenttype = forms.CharField(max_length=255, required=True)
|
|
tac = forms.BooleanField(required=True, initial=False)
|
|
|
|
# TrainingPlanBillingForm form
|
|
|
|
|
|
class TrainingPlanBillingForm(forms.Form):
|
|
amount = FlexibleDecimalField(required=True, decimal_places=2,
|
|
max_digits=8)
|
|
plan = forms.IntegerField(widget=forms.HiddenInput())
|
|
payment_method_nonce = forms.CharField(max_length=255, required=True)
|
|
paymenttype = forms.CharField(max_length=255, required=True)
|
|
enddate = forms.DateField(widget=forms.HiddenInput)
|
|
name = forms.CharField(max_length=255, required=False)
|
|
notes = forms.CharField(max_length=255, required=False)
|
|
status = forms.CharField(max_length=255, required=True)
|
|
tac = forms.BooleanField(required=True, initial=False)
|
|
|
|
|
|
# login form
|
|
class LoginForm(forms.Form):
|
|
username = forms.CharField()
|
|
password = forms.CharField(widget=forms.PasswordInput())
|
|
|
|
# search form
|
|
|
|
|
|
class SearchForm(forms.Form):
|
|
q = forms.CharField(max_length=255, required=False,
|
|
widget=forms.TextInput(
|
|
attrs={'placeholder': 'keyword or leave empty'}),
|
|
label='Filter by Keyword')
|
|
|
|
|
|
# simple form for Contact page. Sends email to info@rowsandall.com
|
|
class EmailForm(forms.Form):
|
|
firstname = forms.CharField(max_length=255, label="First Name")
|
|
lastname = forms.CharField(max_length=255, required=False, label="Last Name")
|
|
email = forms.EmailField()
|
|
subject = forms.CharField(max_length=255)
|
|
message = forms.CharField(widget=forms.Textarea())
|
|
captcha = ReCaptchaField(widget=ReCaptchaV3(
|
|
attrs={
|
|
'required_score': 0.85,
|
|
}
|
|
))
|
|
|
|
|
|
disqualificationreasons = (
|
|
('noimage', 'No monitor screenshot or data evidence was included'),
|
|
('suspicious', 'The result is not plausible for the boat class or athlete gorup'),
|
|
('duplicate', 'Appears to be a duplicate entry'),
|
|
('other', 'Other Reason'),
|
|
)
|
|
|
|
disqualifiers = {}
|
|
for key, value in disqualificationreasons:
|
|
disqualifiers[key] = value
|
|
|
|
|
|
class DisqualificationForm(forms.Form):
|
|
|
|
reason = forms.ChoiceField(required=True,
|
|
choices=disqualificationreasons,
|
|
widget=forms.RadioSelect,)
|
|
|
|
message = forms.CharField(required=True, widget=forms.Textarea)
|
|
|
|
|
|
class HistorySelectForm(forms.Form):
|
|
typeselectchoices = [("All", "All")]
|
|
for wtype, verbose in mytypes.workouttypes_ordered.items():
|
|
typeselectchoices.append((wtype, verbose))
|
|
startdate = forms.DateField(
|
|
initial=timezone.now()-datetime.timedelta(days=15),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now(),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='End Date')
|
|
|
|
workouttype = forms.ChoiceField(initial='All', choices=typeselectchoices)
|
|
|
|
metricchoices = (
|
|
("time", "duration"),
|
|
("TRIMP", "trimp"),
|
|
("rScore", "rscore"),
|
|
("distance", "distance")
|
|
)
|
|
|
|
yaxis = forms.ChoiceField(
|
|
initial='time', choices=metricchoices, label="Measure by")
|
|
|
|
class Meta:
|
|
fields = ['startdate', 'enddate']
|
|
input_formats = ("%Y-%m-%d")
|
|
dateTimeOptions = {
|
|
'format': '%Y-%m-%d',
|
|
'autoclose': True,
|
|
}
|
|
|
|
|
|
class MetricsForm(forms.Form):
|
|
avghr = forms.IntegerField(required=False, label='Average Heart Rate')
|
|
avgpwr = forms.IntegerField(required=False, label='Average Power')
|
|
avgspm = forms.FloatField(required=False, label='Average SPM')
|
|
|
|
# Upload the CrewNerd Summary CSV
|
|
|
|
|
|
class CNsummaryForm(forms.Form):
|
|
file = forms.FileField(required=True, validators=[must_be_csv])
|
|
|
|
# The little window to type '4x2000m/500m' to update the workout summary
|
|
|
|
|
|
class SummaryStringForm(forms.Form):
|
|
intervalstring = forms.CharField(
|
|
max_length=255, label='Workout Description')
|
|
|
|
# little window to type a Team invitation code
|
|
|
|
|
|
class TeamInviteCodeForm(forms.Form):
|
|
code = forms.CharField(max_length=10, label='Team Code',
|
|
)
|
|
|
|
# Used for testing the POST API for StrokeData
|
|
|
|
|
|
class StrokeDataForm(forms.Form):
|
|
strokedata = forms.CharField(label='payload', widget=forms.Textarea)
|
|
|
|
# The form used for uploading images
|
|
|
|
|
|
class ImageForm(forms.Form):
|
|
file = forms.FileField(required=False,
|
|
validators=[validate_image_extension])
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
from django.forms.widgets import HiddenInput
|
|
super(ImageForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
# The form used for uploading images
|
|
class CourseForm(forms.Form):
|
|
name = forms.CharField(max_length=150, label='Course Name', required=False)
|
|
file = forms.FileField(required=False,
|
|
validators=[validate_kml])
|
|
notes = forms.CharField(required=False,
|
|
max_length=200, label='Course Notes',
|
|
widget=forms.Textarea)
|
|
country = forms.CharField(required=False, max_length=150, label='Country')
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
from django.forms.widgets import HiddenInput
|
|
super(CourseForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
class CourseConfirmForm(forms.Form):
|
|
BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))
|
|
doupdate = forms.TypedChoiceField(
|
|
initial=False,
|
|
coerce=lambda x: x == 'True', choices=((False, 'No'), (True, 'Yes')), widget=forms.RadioSelect,
|
|
label='Update Course with new markers?')
|
|
|
|
# The form used for uploading files
|
|
|
|
|
|
class StandardsForm(forms.Form):
|
|
name = forms.CharField(max_length=150, label='Course Name')
|
|
file = forms.FileField(required=False,
|
|
validators=[must_be_csv])
|
|
notes = forms.CharField(required=False,
|
|
max_length=200, label='Course Notes',
|
|
widget=forms.Textarea)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
from django.forms.widgets import HiddenInput
|
|
super(StandardsForm, self).__init__(*args, **kwargs)
|
|
|
|
# The form used for uploading files
|
|
|
|
|
|
class DocumentsForm(forms.Form):
|
|
rpechoices = models.rpechoices
|
|
rpechoices = tuple([(-1, '---')]+list(rpechoices))
|
|
title = forms.CharField(required=False)
|
|
file = forms.FileField(required=False,
|
|
validators=[validate_file_extension])
|
|
|
|
workouttype = forms.ChoiceField(required=True,
|
|
choices=Workout.workouttypes,
|
|
label='Workout Type')
|
|
|
|
boattype = forms.ChoiceField(required=True,
|
|
choices=mytypes.boattypes+mytypes.ergtypes,
|
|
label="Boat Type")
|
|
|
|
rpe = forms.ChoiceField(required=False,
|
|
choices=rpechoices,
|
|
label='Rate of Perceived Exertion', initial=-1)
|
|
|
|
notes = forms.CharField(required=False,
|
|
widget=forms.Textarea)
|
|
|
|
offline = forms.BooleanField(initial=False, required=False,
|
|
label='Process in Background')
|
|
|
|
class Meta:
|
|
fields = ['title', 'file', 'workouttype',
|
|
'boattype', 'fileformat', 'offline']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
from django.forms.widgets import HiddenInput
|
|
super(DocumentsForm, self).__init__(*args, **kwargs)
|
|
# self.fields['offline'].widget = HiddenInput()
|
|
|
|
|
|
# Form to change Workflow page layout
|
|
class WorkFlowLeftPanelForm(forms.Form):
|
|
panels = defaultleft
|
|
|
|
leftpanel = forms.MultipleChoiceField(
|
|
label='',
|
|
choices=workflowleftpanel,
|
|
initial=panels,
|
|
widget=FilteredSelectMultiple(
|
|
('elements'),
|
|
False
|
|
)
|
|
)
|
|
|
|
class Media:
|
|
css = {
|
|
'all': ['admin/css/widgets.css', ]
|
|
# 'css/uid-manage-form.css'],
|
|
}
|
|
js = ['/admin/jsi18n/']
|
|
|
|
def __init__(self, *args, **kwargs): # pragma: no cover
|
|
if 'instance' in kwargs:
|
|
r = kwargs.pop('instance')
|
|
panels = r.workflowleftpanel
|
|
self.base_fields['leftpanel'].initial = panels
|
|
else:
|
|
panels = defaultleft
|
|
|
|
super(WorkFlowLeftPanelForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
class WorkFlowMiddlePanelForm(forms.Form):
|
|
panels = defaultmiddle
|
|
|
|
middlepanel = forms.MultipleChoiceField(
|
|
label='',
|
|
choices=workflowmiddlepanel,
|
|
initial=panels,
|
|
widget=FilteredSelectMultiple(
|
|
('elements'),
|
|
False
|
|
)
|
|
)
|
|
|
|
class Media:
|
|
css = {
|
|
'all': ['admin/css/widgets.css', ]
|
|
# 'css/uid-manage-form.css'],
|
|
}
|
|
js = ['/admin/jsi18n/']
|
|
|
|
def __init__(self, *args, **kwargs): # pragma: no cover
|
|
if 'instance' in kwargs:
|
|
r = kwargs.pop('instance')
|
|
panels = r.workflowmiddlepanel
|
|
self.base_fields['middlepanel'].initial = panels
|
|
else:
|
|
panels = defaultmiddle
|
|
|
|
super(WorkFlowMiddlePanelForm, self).__init__(*args, **kwargs)
|
|
|
|
|
|
class WorkFlowLeftPanelElement(forms.Form):
|
|
panelchoices = tuple(list(workflowleftpanel)+[('None', 'None')])
|
|
|
|
panel = forms.ChoiceField(
|
|
label='',
|
|
choices=panelchoices,
|
|
initial='None',
|
|
)
|
|
|
|
|
|
class WorkFlowMiddlePanelElement(forms.Form):
|
|
panelchoices = tuple(list(workflowmiddlepanel)+[('None', 'None')])
|
|
|
|
panel = forms.ChoiceField(
|
|
label='',
|
|
choices=panelchoices,
|
|
initial='None',
|
|
)
|
|
|
|
class WorkoutNameTemplateElement(forms.Form):
|
|
templatechoices = tuple(list(workout_name_element)+[('None', 'None')])
|
|
|
|
element = forms.ChoiceField(
|
|
label='',
|
|
choices=templatechoices,
|
|
initial='None'
|
|
)
|
|
|
|
|
|
# The form to indicate additional actions to be performed immediately
|
|
# after a successful upload
|
|
|
|
nextpages = list(landingpages)
|
|
nextpages.append(('workout_upload_view', 'Upload Another File'))
|
|
nextpages = tuple(nextpages)
|
|
|
|
|
|
class LandingPageForm(forms.Form):
|
|
landingpage = forms.ChoiceField(choices=nextpages,
|
|
initial='workout_edit_view',
|
|
label='After Upload, go to')
|
|
|
|
|
|
class UploadOptionsForm(forms.Form):
|
|
plotchoices = (
|
|
('timeplot', 'Time Plot'),
|
|
('distanceplot', 'Distance Plot'),
|
|
('pieplot', 'Heart Rate Pie Chart'),
|
|
)
|
|
make_plot = forms.BooleanField(initial=False, required=False)
|
|
plottype = forms.ChoiceField(required=False,
|
|
choices=plotchoices,
|
|
initial='timeplot',
|
|
label='Plot Type')
|
|
upload_to_C2 = forms.BooleanField(initial=False, required=False,
|
|
label='Export to Concept2 logbook')
|
|
upload_to_Strava = forms.BooleanField(initial=False, required=False,
|
|
label='Export to Strava')
|
|
upload_to_SportTracks = forms.BooleanField(initial=False, required=False,
|
|
label='Export to SportTracks')
|
|
upload_to_RunKeeper = forms.BooleanField(initial=False, required=False,
|
|
label='Export to RunKeeper')
|
|
upload_to_MapMyFitness = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Export to MapMyFitness')
|
|
upload_to_TrainingPeaks = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Export to TrainingPeaks')
|
|
# do_physics = forms.BooleanField(initial=False,required=False,label='Power Estimate (OTW)')
|
|
makeprivate = forms.BooleanField(initial=False, required=False,
|
|
label='Make Workout Private')
|
|
|
|
submitrace = forms.ChoiceField(
|
|
label='Submit as challenge Result',
|
|
required=False)
|
|
|
|
landingpage = forms.ChoiceField(choices=nextpages,
|
|
initial='workout_edit_view',
|
|
label='After Upload, go to')
|
|
|
|
raceid = forms.IntegerField(initial=0, widget=HiddenInput())
|
|
|
|
class Meta:
|
|
fields = ['make_plot', 'plottype', 'upload_toc2', 'makeprivate']
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.request = kwargs.pop('request', None)
|
|
raceid = kwargs.pop('raceid', 0)
|
|
super(UploadOptionsForm, self).__init__(*args, **kwargs)
|
|
r = Rower.objects.get(user=self.request.user)
|
|
races = VirtualRace.objects.filter(
|
|
registration_closure__gt=timezone.now())
|
|
|
|
registrations = IndoorVirtualRaceResult.objects.filter(
|
|
race__in=races,
|
|
userid=r.id)
|
|
|
|
registrations2 = VirtualRaceResult.objects.filter(
|
|
race__in=races,
|
|
userid=r.id,
|
|
)
|
|
|
|
choices1 = [(r.id, str(r)) for r in registrations]
|
|
choices2 = [(r.id, str(r)) for r in registrations2]
|
|
choices3 = [(0, '---')]
|
|
|
|
noregistrations = []
|
|
for ra in VirtualRace.objects.filter(
|
|
registration_closure__gt=timezone.now(),
|
|
sessiontype='race'
|
|
): # pragma: no cover
|
|
rs = VirtualRaceResult.objects.filter(race=ra, userid=r.id)
|
|
if rs.count() == 0:
|
|
noregistrations.append((-ra.id, ra.name))
|
|
for ra in VirtualRace.objects.filter(
|
|
registration_closure__gt=timezone.now(),
|
|
sessiontype='indoorrace'
|
|
): # pragma: no cover
|
|
rs = IndoorVirtualRaceResult.objects.filter(race=ra, userid=r.id)
|
|
if rs.count() == 0:
|
|
noregistrations.append((-ra.id, ra.name))
|
|
|
|
choices = choices3+choices1+choices2+noregistrations
|
|
|
|
if int(raceid) in [r.id for r in races]: # pragma: no cover
|
|
therace = VirtualRace.objects.get(id=raceid)
|
|
self.fields['raceid'].initial = therace.id
|
|
if therace.sessiontype == 'race':
|
|
registrations = VirtualRaceResult.objects.filter(
|
|
race=therace, userid=r.id)
|
|
else:
|
|
registrations = IndoorVirtualRaceResult.objects.filter(
|
|
race=therace, userid=r.id)
|
|
|
|
if registrations.count() == 0:
|
|
race = VirtualRace.objects.get(id=raceid)
|
|
choices = [(-int(raceid), race.name)]
|
|
else:
|
|
choices = [(r.id, str(r)) for r in registrations]
|
|
choices = choices+[(0, '---')]
|
|
|
|
if races: # pragma: no cover
|
|
self.fields['submitrace'].choices = choices
|
|
else:
|
|
del self.fields['submitrace']
|
|
|
|
|
|
# The form to indicate additional actions to be performed immediately
|
|
# after a successful upload. This version allows the Team manager to select
|
|
# a team member
|
|
class TeamUploadOptionsForm(forms.Form):
|
|
plotchoices = (
|
|
('timeplot', 'Time Plot'),
|
|
('distanceplot', 'Distance Plot'),
|
|
('pieplot', 'Pie Chart'),
|
|
)
|
|
make_plot = forms.BooleanField(initial=False, required=False)
|
|
plottype = forms.ChoiceField(required=False,
|
|
choices=plotchoices,
|
|
initial='timeplot',
|
|
label='Plot Type')
|
|
|
|
upload_to_C2 = forms.BooleanField(initial=False, required=False,
|
|
label='Export to Concept2 logbook')
|
|
upload_to_Strava = forms.BooleanField(initial=False, required=False,
|
|
label='Export to Strava')
|
|
upload_to_SportTracks = forms.BooleanField(initial=False, required=False,
|
|
label='Export to SportTracks')
|
|
upload_to_RunKeeper = forms.BooleanField(initial=False, required=False,
|
|
label='Export to RunKeeper')
|
|
upload_to_MapMyFitness = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Export to MapMyFitness')
|
|
upload_to_TrainingPeaks = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Export to TrainingPeaks')
|
|
# do_physics = forms.BooleanField(initial=False,required=False,label='Power Estimate (OTW)')
|
|
makeprivate = forms.BooleanField(initial=False, required=False,
|
|
label='Make Workout Private')
|
|
|
|
class Meta:
|
|
fields = ['make_plot', 'plottype']
|
|
|
|
|
|
# This form is used on the Workout Split page
|
|
class WorkoutSplitForm(forms.Form):
|
|
splitchoices = (
|
|
('keep original', 'Keep Original'),
|
|
('keep first', 'Keep First Part'),
|
|
('keep second', 'Keep Second Part'),
|
|
('firstprivate', 'Set First Part Private'),
|
|
('secondprivate', 'Set Second Part Private'),
|
|
('originalprivate', 'Set Original Private'),
|
|
)
|
|
splittime = forms.TimeField(input_formats=['%H:%M:%S.%f',
|
|
'%H:%M:%S',
|
|
'%H:%M:%S',
|
|
'%M:%S.%f',
|
|
'%M:%S',
|
|
'%M'],
|
|
label='Split Time')
|
|
splitmode = forms.MultipleChoiceField(
|
|
initial=['keep original',
|
|
'keep first',
|
|
'keep second',
|
|
'firstprivate',
|
|
'secondprivate'],
|
|
label='Split Mode',
|
|
choices=splitchoices,
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
|
|
# This form is used on the Analysis page to add a custom distance/time
|
|
# trial and predict the pace
|
|
|
|
|
|
class OteWorkoutTypeForm(forms.Form):
|
|
choices = (
|
|
('rower', 'Indoor Rower'),
|
|
('dynamic', 'Dynamic Indoor Rower'),
|
|
('slides', 'Indoor Rower on Slides'),
|
|
)
|
|
|
|
workouttypes = forms.MultipleChoiceField(
|
|
required=True,
|
|
choices=choices,
|
|
label='Workout Types',
|
|
initial=[a for a, b in choices],
|
|
)
|
|
|
|
|
|
class PredictedPieceForm(forms.Form):
|
|
unitchoices = (
|
|
('t', 'minutes'),
|
|
('d', 'meters'),
|
|
)
|
|
|
|
rankingdistancechoices = []
|
|
rankingdurationchoices = []
|
|
for d in rankingdistances:
|
|
thetuple = (d, str(d)+' m')
|
|
rankingdistancechoices.append(thetuple)
|
|
|
|
for d in rankingdurations:
|
|
timestr = d.strftime("%H:%M:%S")
|
|
thetuple = (timestr, timestr)
|
|
rankingdurationchoices.append(thetuple)
|
|
|
|
trankingdistances = forms.MultipleChoiceField(
|
|
required=True,
|
|
choices=rankingdistancechoices, initial=rankingdistances,
|
|
label='Ranking Distances'
|
|
)
|
|
|
|
trankingdurations = forms.MultipleChoiceField(
|
|
required=True,
|
|
choices=rankingdurationchoices,
|
|
initial=[a for a, b in rankingdurationchoices],
|
|
label='Ranking Durations'
|
|
)
|
|
|
|
value = forms.FloatField(initial=10, label='Free ranking piece (minutes)')
|
|
pieceunit = forms.ChoiceField(required=True, choices=unitchoices,
|
|
initial='t', label='Unit')
|
|
|
|
class Meta:
|
|
fields = ['value', 'pieceunit']
|
|
|
|
|
|
class PredictedPieceFormNoDistance(forms.Form):
|
|
|
|
rankingdurationchoices = []
|
|
|
|
for d in rankingdurations:
|
|
timestr = d.strftime("%H:%M:%S")
|
|
thetuple = (timestr, timestr)
|
|
rankingdurationchoices.append(thetuple)
|
|
|
|
trankingdurations = forms.MultipleChoiceField(
|
|
required=True,
|
|
choices=rankingdurationchoices,
|
|
initial=[a for a, b in rankingdurationchoices],
|
|
label='Ranking Durations'
|
|
)
|
|
|
|
value = forms.FloatField(initial=10, label='Free ranking piece')
|
|
|
|
|
|
# Form to select a data range to show workouts from a certain time period
|
|
class DateRangeForm(forms.Form):
|
|
startdate = forms.DateField(
|
|
initial=timezone.now()-datetime.timedelta(days=365),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now(),
|
|
widget=AdminDateWidget(), # format='%Y-%m-%d'),
|
|
label='End Date')
|
|
|
|
class Meta:
|
|
fields = ['startdate', 'enddate']
|
|
input_formats = ("%Y-%m-%d")
|
|
dateTimeOptions = {
|
|
'format': '%Y-%m-%d',
|
|
'autoclose': True,
|
|
}
|
|
|
|
|
|
class FitnessMetricForm(forms.Form):
|
|
startdate = forms.DateField(
|
|
initial=timezone.now()-datetime.timedelta(days=365),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now(),
|
|
widget=AdminDateWidget(),
|
|
label='End Date')
|
|
|
|
modechoices = (
|
|
('rower', 'indoor rower'),
|
|
('water', 'on the water')
|
|
)
|
|
|
|
mode = forms.ChoiceField(required=True,
|
|
choices=modechoices,
|
|
initial='rower',
|
|
label='Workout Mode'
|
|
)
|
|
|
|
class Meta:
|
|
fields = ['startdate', 'enddate', 'mode']
|
|
|
|
|
|
class PerformanceManagerForm(forms.Form):
|
|
startdate = forms.DateField(
|
|
initial=timezone.now()-datetime.timedelta(days=365),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now(),
|
|
widget=AdminDateWidget(),
|
|
label='End Date')
|
|
|
|
metricchoices = (
|
|
('hrtss', 'Use Heart Rate Data'),
|
|
('rscore', 'Use Power and Heart Rate Data'),
|
|
)
|
|
|
|
metricchoice = forms.ChoiceField(
|
|
required=True,
|
|
choices=metricchoices,
|
|
initial='hrtss',
|
|
label='Data',
|
|
widget=forms.RadioSelect
|
|
)
|
|
|
|
dofatigue = forms.BooleanField(required=False, initial=False,
|
|
label='Fatigue')
|
|
|
|
doform = forms.BooleanField(required=False, initial=False,
|
|
label='Freshness')
|
|
|
|
|
|
class FitnessFitForm(forms.Form):
|
|
startdate = forms.DateField(
|
|
initial=timezone.now()-datetime.timedelta(days=365),
|
|
# widget=SelectDateWidget(years=range(1990,2050)),
|
|
widget=AdminDateWidget(),
|
|
label='Start Date')
|
|
enddate = forms.DateField(
|
|
initial=timezone.now(),
|
|
widget=AdminDateWidget(),
|
|
label='End Date')
|
|
|
|
modechoices = (
|
|
('rower', 'indoor rower'),
|
|
('water', 'on the water')
|
|
)
|
|
|
|
metricchoices = (
|
|
('trimp', 'TRIMP'),
|
|
('rscore', 'rScore')
|
|
)
|
|
|
|
modelchoices = (
|
|
('banister', 'Banister Impulse-Response model'),
|
|
('tsb', 'Coggan Training Stress Balance model'),
|
|
)
|
|
|
|
fitnesstest = forms.IntegerField(required=True, initial=20,
|
|
label='Test Duration (minutes)')
|
|
|
|
usegoldmedalstandard = forms.BooleanField(required=False, initial=False,
|
|
label='Use best performance against world class')
|
|
|
|
kfitness = forms.IntegerField(initial=42, required=True,
|
|
label='Fitness Time Constant (days)')
|
|
|
|
kfatigue = forms.IntegerField(initial=7, required=True,
|
|
label='Fatigue Time Constant (days)')
|
|
|
|
metricchoice = forms.ChoiceField(required=True,
|
|
choices=metricchoices,
|
|
initial='rscore',
|
|
label='Workload Metric')
|
|
|
|
modelchoice = forms.ChoiceField(required=True,
|
|
choices=modelchoices,
|
|
initial='tsb',
|
|
label='Model to use')
|
|
|
|
# temporary
|
|
k1 = forms.FloatField(required=True, initial=1.0,
|
|
label='k1')
|
|
k2 = forms.FloatField(required=True, initial=1.0,
|
|
label='k2')
|
|
p0 = forms.IntegerField(required=True, initial=100,
|
|
label='Unfit Performance')
|
|
|
|
mode = forms.ChoiceField(required=True,
|
|
choices=modechoices,
|
|
initial='rower',
|
|
label='Workout Mode'
|
|
)
|
|
|
|
class Meta:
|
|
fields = ['startdate', 'enddate', 'mode', 'fitnesstest',
|
|
'kfitness', 'kfatigue', 'metricchoice',
|
|
'k1', 'k2', 'p0']
|
|
|
|
|
|
class SessionDateShiftForm(forms.Form):
|
|
shiftstartdate = forms.DateField(
|
|
initial=timezone.now(),
|
|
widget=AdminDateWidget(),
|
|
label='Shift to start on')
|
|
|
|
class Meta:
|
|
fields = ['shiftstartdate']
|
|
|
|
# Form used to select workouts for the past N days
|
|
|
|
|
|
class DeltaDaysForm(forms.Form):
|
|
deltadays = forms.IntegerField(initial=7, required=False, label='')
|
|
|
|
class PlanByRscoreForm(forms.Form):
|
|
byrscore = forms.BooleanField(initial=False, required=False, label='plan by rScore')
|
|
|
|
class RegistrationForm(UserCreationForm):
|
|
"""
|
|
Form for registering a new user account.
|
|
Validates that the requested username is not already in use, and
|
|
requires the password to be entered twice to catch typos.
|
|
Subclasses should feel free to add any additional validation they
|
|
need, but should avoid defining a ``save()`` method -- the actual
|
|
saving of collected user data is delegated to the active
|
|
registration backend.
|
|
"""
|
|
required_css_class = 'required'
|
|
email = forms.EmailField(label="E-mail")
|
|
|
|
class Meta:
|
|
model = User
|
|
fields = ("username", "first_name", "last_name",
|
|
"email", "password1", "password2")
|
|
|
|
widgets = {
|
|
'username': forms.TextInput(attrs={'autocomplete': 'new-password'}),
|
|
'password1': forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
|
|
'password2': forms.PasswordInput(attrs={'autocomplete': 'new-password'}),
|
|
}
|
|
|
|
|
|
class RegistrationFormTermsOfService(RegistrationForm):
|
|
"""
|
|
Subclass of ``RegistrationForm`` which adds a required checkbox
|
|
for agreeing to a site's Terms of Service.
|
|
"""
|
|
tos = forms.BooleanField(widget=forms.CheckboxInput,
|
|
label='I have read and agree to the Terms of Service',
|
|
error_messages={'required': "You must agree to the terms to register"})
|
|
|
|
|
|
class RegistrationFormUniqueEmail(RegistrationFormTermsOfService):
|
|
"""
|
|
Subclass of ``RegistrationFormTermsOfService`` which enforces uniqueness of
|
|
email addresses.
|
|
"""
|
|
|
|
def clean_email(self):
|
|
"""
|
|
Validate that the supplied email address is unique for the
|
|
site.
|
|
"""
|
|
if User.objects.filter(email__iexact=self.cleaned_data['email']): # pragma: no cover
|
|
raise forms.ValidationError(
|
|
"This email address is already in use. Please supply a different email address.")
|
|
return self.cleaned_data['email']
|
|
|
|
|
|
class RegistrationFormSex(RegistrationFormUniqueEmail):
|
|
sexcategories = (
|
|
('female', 'female'),
|
|
('male', 'male'),
|
|
('not specified', 'not specified'),
|
|
)
|
|
|
|
weightcategories = (
|
|
('hwt', 'heavy-weight'),
|
|
('lwt', 'light-weight'),
|
|
)
|
|
|
|
adaptivecategories = mytypes.adaptivetypes
|
|
|
|
thisyear = timezone.now().year
|
|
|
|
birthdate = forms.DateTimeField(
|
|
widget=SelectDateWidget(years=range(1900, thisyear)),
|
|
initial=datetime.date(year=1970,
|
|
month=4,
|
|
day=15))
|
|
|
|
def clean_birthdate(self):
|
|
dob = self.cleaned_data['birthdate']
|
|
age = (timezone.now() - dob).days/365
|
|
if age < 16: # pragma: no cover
|
|
raise forms.ValidationError(
|
|
'Must be at least 16 years old to register')
|
|
return self.cleaned_data['birthdate']
|
|
|
|
sex = forms.ChoiceField(required=False,
|
|
choices=sexcategories,
|
|
initial='not specified',
|
|
label='Sex')
|
|
|
|
weightcategory = forms.ChoiceField(label='Weight Category',
|
|
choices=weightcategories, initial='hwt', required=False)
|
|
|
|
adaptiveclass = forms.ChoiceField(label='Adaptive Classification',
|
|
choices=adaptivecategories, initial='None', required=False)
|
|
|
|
|
|
class PowerIntervalUpdateForm(forms.Form):
|
|
selectorchoices = (
|
|
('power', 'Power'),
|
|
('pace', 'Pace'),
|
|
('work', 'Work per Stroke'),
|
|
('spm', 'Stroke Rate')
|
|
)
|
|
|
|
pace = forms.DurationField(required=False, label='Pace (/500m)')
|
|
power = forms.IntegerField(required=False, label='Power (W)')
|
|
work = forms.IntegerField(required=False, label='Work per Stroke (J)')
|
|
spm = forms.IntegerField(required=False, label='Stroke Rate')
|
|
selector = forms.ChoiceField(choices=selectorchoices,
|
|
required=True,
|
|
initial='power',
|
|
label='Use')
|
|
activeminutesmin = forms.IntegerField(
|
|
required=False, initial=0, widget=forms.HiddenInput())
|
|
activeminutesmax = forms.IntegerField(
|
|
required=False, initial=0, widget=forms.HiddenInput())
|
|
|
|
|
|
boattypes = mytypes.boattypes
|
|
ergtypes = mytypes.ergtypes
|
|
workouttypes = mytypes.workouttypes
|
|
ww = list(workouttypes)
|
|
ww.append(tuple(('all', 'All')))
|
|
workouttypes = tuple(ww)
|
|
|
|
|
|
class DataFrameColumnsForm(forms.Form):
|
|
cols = ['ftime', 'cumdist', 'fpace', 'spm',
|
|
'hr', 'grpower', 'driveenergy', 'drivelength', 'averageforce',
|
|
'peakforce', 'distance', 'drivespeed', 'workoutstate',
|
|
'catch', 'finish', 'peakforceangle', 'wash', 'slip', 'rhythm',
|
|
'effectiveangle', 'totalangle', 'distanceperstroke', 'velo']
|
|
|
|
colchoices = [
|
|
(c, c) for c in cols
|
|
]
|
|
|
|
cols = forms.MultipleChoiceField(choices=colchoices,
|
|
label='Table Columns')
|
|
|
|
|
|
class HistoForm(forms.Form):
|
|
includereststrokes = forms.BooleanField(
|
|
initial=False, label='Include Rest Strokes', required=False)
|
|
histoparam = forms.ChoiceField(choices=parchoices, initial='power',
|
|
label='Metric')
|
|
|
|
|
|
class AnalysisOptionsForm(forms.Form):
|
|
modality = forms.ChoiceField(choices=workouttypes,
|
|
label='Workout Type',
|
|
initial='all')
|
|
waterboattype = forms.MultipleChoiceField(choices=boattypes+ergtypes,
|
|
label='Water Boat Type',
|
|
initial=mytypes.waterboattype)
|
|
|
|
ranking = forms.BooleanField(label='Ranking Workouts Only',
|
|
initial=False,required=False)
|
|
|
|
|
|
# form to select modality and boat type for trend flex
|
|
class TrendFlexModalForm(forms.Form):
|
|
modality = forms.ChoiceField(choices=workouttypes,
|
|
label='Workout Type',
|
|
initial='all')
|
|
waterboattype = forms.MultipleChoiceField(choices=boattypes+ergtypes,
|
|
label='Water Boat Type',
|
|
initial=mytypes.waterboattype)
|
|
|
|
|
|
# This form sets options for the summary stats page
|
|
class StatsOptionsForm(forms.Form):
|
|
includereststrokes = forms.BooleanField(
|
|
initial=False, label='Include Rest Strokes', required=False)
|
|
|
|
water = forms.BooleanField(initial=False, required=False)
|
|
waterboattype = forms.MultipleChoiceField(choices=boattypes+ergtypes,
|
|
label='Water Boat Type',
|
|
widget=forms.CheckboxSelectMultiple(),
|
|
initial=mytypes.waterboattype)
|
|
|
|
def __init__(self, *args, **kwargs): # pragma: no cover
|
|
super(StatsOptionsForm, self).__init__(*args, **kwargs)
|
|
|
|
for type in mytypes.checktypes:
|
|
self.fields[type] = forms.BooleanField(
|
|
initial=True, required=False)
|
|
|
|
|
|
class PlanSelectForm(forms.Form):
|
|
plan = forms.ModelChoiceField(queryset=PaidPlan.objects.all(),
|
|
widget=forms.RadioSelect, required=True)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
paymentprocessor = kwargs.pop('paymentprocessor', None)
|
|
rower = kwargs.pop('rower', None)
|
|
includeall = kwargs.pop('includeall', False)
|
|
super(PlanSelectForm, self).__init__(*args, **kwargs)
|
|
self.fields['plan'].empty_label = None
|
|
if paymentprocessor:
|
|
self.fields['plan'].queryset = PaidPlan.objects.filter(
|
|
paymentprocessor=paymentprocessor,
|
|
active=True
|
|
).exclude(
|
|
shortname="basic"
|
|
).order_by(
|
|
"price", "shortname"
|
|
)
|
|
if rower and not includeall:
|
|
try:
|
|
amount = rower.paidplan.price
|
|
except AttributeError:
|
|
amount = 0
|
|
self.fields['plan'].queryset = PaidPlan.objects.filter(
|
|
paymentprocessor=rower.paymentprocessor,
|
|
active=True
|
|
).exclude(
|
|
price__lte=amount
|
|
).order_by(
|
|
"price", "shortname"
|
|
)
|
|
|
|
|
|
class CourseSelectForm(forms.Form):
|
|
course = forms.ModelChoiceField(queryset=GeoCourse.objects.filter())
|
|
|
|
def __init__(self, *args, **kwargs): # pragma: no cover
|
|
course = kwargs.pop('course', None)
|
|
manager = kwargs.pop('manager', None)
|
|
choices = kwargs.pop('choices', [])
|
|
super(CourseSelectForm, self).__init__(*args, **kwargs)
|
|
if len(choices) > 0:
|
|
self.fields['course'].queryset = GeoCourse.objects.filter(
|
|
id__in=[c.id for c in choices])
|
|
if course is not None:
|
|
d_min = 0.5*course.distance
|
|
d_max = 2*course.distance
|
|
country = course.country
|
|
countries = ['unknown', country]
|
|
|
|
self.fields['course'].queryset = self.fields['course'].queryset.filter(
|
|
distance__gt=d_min, distance__lt=d_max,
|
|
country__in=countries
|
|
).exclude(id=course.id)
|
|
if manager is not None:
|
|
self.fields['course'].queryset = self.fields['course'].queryset.filter(
|
|
manager=manager)
|
|
|
|
|
|
class WorkoutSingleSelectForm(forms.Form):
|
|
workout = forms.ModelChoiceField(
|
|
queryset=Workout.objects.filter(),
|
|
widget=forms.RadioSelect
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
workouts = kwargs.pop(
|
|
'workouts', Workout.objects.filter().order_by('-date'))
|
|
super(WorkoutSingleSelectForm, self).__init__(*args, **kwargs)
|
|
self.fields['workout'].queryset = workouts
|
|
|
|
|
|
class InStrokeMultipleCompareForm(forms.Form):
|
|
analyses = forms.ModelMultipleChoiceField(
|
|
queryset=InStrokeAnalysis.objects.all(),
|
|
widget=forms.CheckboxSelectMultiple()
|
|
)
|
|
|
|
class ForceCurveMultipleCompareForm(forms.Form):
|
|
analyses = forms.ModelMultipleChoiceField(
|
|
queryset=ForceCurveAnalysis.objects.all(),
|
|
widget=forms.CheckboxSelectMultiple()
|
|
)
|
|
|
|
bulkactions = (
|
|
('remove','remove'),
|
|
('export','export'),
|
|
('rower assign','rower assign'),
|
|
)
|
|
destinations = (
|
|
('C2','C2'),
|
|
('strava','strava'),
|
|
('sporttracks','sporttracks'),
|
|
('trainingpeaks','trainingpeaks')
|
|
)
|
|
|
|
class WorkoutBulkActions(forms.Form):
|
|
action = forms.ChoiceField(
|
|
choices=bulkactions, label='Action', required=True, initial='remove')
|
|
|
|
class ExportChoices(forms.Form):
|
|
destination = forms.ChoiceField(
|
|
choices=destinations, label='Destination', required=False, initial='strava'
|
|
)
|
|
|
|
class AssignChoices(forms.Form):
|
|
remove_workout = forms.BooleanField(initial=False, required=False)
|
|
rowers = forms.ModelMultipleChoiceField(label='Rowers', required=False,
|
|
queryset=Rower.objects.filter(), widget=forms.CheckboxSelectMultiple())
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(AssignChoices, self).__init__(*args, **kwargs)
|
|
self.fields['rowers'].queryset = Rower.objects.filter()
|
|
|
|
class WorkoutMultipleCompareForm(forms.Form):
|
|
workouts = forms.ModelMultipleChoiceField(
|
|
queryset=Workout.objects.filter(),
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(WorkoutMultipleCompareForm, self).__init__(*args, **kwargs)
|
|
self.fields['workouts'].queryset = Workout.objects.filter()
|
|
|
|
|
|
class PlannedSessionMultipleCloneForm(forms.Form):
|
|
plannedsessions = forms.ModelMultipleChoiceField(
|
|
queryset=PlannedSession.objects.all(),
|
|
widget=forms.CheckboxSelectMultiple(),
|
|
label='Planned Sessions'
|
|
)
|
|
|
|
|
|
grouplabels = axlabels.copy()
|
|
grouplabels['date'] = 'Date'
|
|
grouplabels['workoutid'] = 'Workout'
|
|
grouplabels.pop('None')
|
|
grouplabels.pop('time')
|
|
groupchoices = list(sorted(grouplabels.items(), key=lambda x: x[1]))
|
|
formaxlabelsmultiflex = formaxlabels.copy()
|
|
formaxlabelsmultiflex.pop('time')
|
|
formaxlabelsmultiflex.pop('distance')
|
|
formaxlabelsmultiflex['workoutid'] = 'Workout'
|
|
parchoicesmultiflex = list(
|
|
sorted(formaxlabelsmultiflex.items(), key=lambda x: x[1]))
|
|
|
|
|
|
palettechoices = tuple((p, p) for p in palettes.keys())
|
|
|
|
analysischoices = (
|
|
('boxplot', 'Box Chart'),
|
|
('trendflex', 'Trend Flex'),
|
|
('histo', 'Histogram'),
|
|
('flexall', 'Cumulative Flex Chart'),
|
|
('stats', 'Statistics'),
|
|
('compare', 'Compare'),
|
|
('cp', 'CP chart'),
|
|
)
|
|
|
|
|
|
class AnalysisChoiceForm(forms.Form):
|
|
axchoices = list(
|
|
(ax[0], ax[1]) for ax in axes if ax[0] not in ['cumdist', 'None']
|
|
)
|
|
axchoices = dict((x, y) for x, y in axchoices)
|
|
axchoices = list(sorted(axchoices.items(), key=lambda x: x[1]))
|
|
|
|
yaxchoices = list((ax[0], ax[1]) for ax in axes if ax[0]
|
|
not in ['cumdist', 'distance', 'time'])
|
|
yaxchoices = dict((x, y) for x, y in yaxchoices)
|
|
yaxchoices = list(sorted(yaxchoices.items(), key=lambda x: x[1]))
|
|
|
|
plotchoices = (
|
|
('line', 'Line Plot'),
|
|
('scatter', 'Scatter Plot'),
|
|
)
|
|
|
|
yaxchoices2 = list(
|
|
(ax[0], ax[1]) for ax in axes if ax[0] not in ['cumdist', 'distance', 'time']
|
|
)
|
|
yaxchoices2 = dict((x, y) for x, y in yaxchoices2)
|
|
yaxchoices2 = list(sorted(yaxchoices2.items(), key=lambda x: x[1]))
|
|
|
|
function = forms.ChoiceField(choices=analysischoices, initial='boxplot',
|
|
label='Analysis')
|
|
xaxis = forms.ChoiceField(
|
|
choices=axchoices, label='X-Axis', required=True, initial='spm')
|
|
yaxis1 = forms.ChoiceField(
|
|
choices=yaxchoices, label='Left Axis', required=True, initial='power')
|
|
yaxis2 = forms.ChoiceField(
|
|
choices=yaxchoices2, label='Right Axis', required=True, initial='None')
|
|
plottype = forms.ChoiceField(choices=plotchoices, initial='scatter')
|
|
|
|
plotfield = forms.ChoiceField(choices=parchoices, initial='spm',
|
|
label='Metric')
|
|
xparam = forms.ChoiceField(choices=parchoicesmultiflex,
|
|
initial='hr',
|
|
label='X axis')
|
|
yparam = forms.ChoiceField(choices=parchoicesmultiflex,
|
|
initial='pace',
|
|
label='Y axis')
|
|
|
|
groupby = forms.ChoiceField(choices=groupchoices, initial='spm',
|
|
label='Group By')
|
|
binsize = forms.FloatField(initial=1, required=False, label='Bin Size')
|
|
|
|
ploterrorbars = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Plot Error Bars')
|
|
|
|
palette = forms.ChoiceField(choices=palettechoices,
|
|
label='Color Scheme',
|
|
initial='monochrome_blue')
|
|
|
|
spmmin = forms.FloatField(initial=15,
|
|
required=False, label='Min SPM')
|
|
spmmax = forms.FloatField(initial=55,
|
|
required=False, label='Max SPM')
|
|
workmin = forms.FloatField(initial=0,
|
|
required=False, label='Min Work per Stroke')
|
|
workmax = forms.FloatField(initial=1500,
|
|
required=False, label='Max Work per Stroke')
|
|
|
|
cpfitchoices = (
|
|
('data', 'Fit to Selected Workouts'),
|
|
('automatic', 'Critical Power Rolling Data')
|
|
)
|
|
|
|
cpfit = forms.ChoiceField(choices=cpfitchoices,
|
|
label='Model Fit', initial='data', required=False)
|
|
|
|
cpoverlay = forms.BooleanField(initial=False,
|
|
label='Overlay Gold Medal Performance',
|
|
required=False)
|
|
piece = forms.IntegerField(initial=4, label='Ranking Piece (minutes)',
|
|
required=False)
|
|
|
|
includereststrokes = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Include Rest Strokes')
|
|
|
|
trendline = forms.BooleanField(initial=False, required=False,
|
|
label='Trend Line')
|
|
|
|
savedata = forms.BooleanField(initial=False, required=False,
|
|
label='Export data as CSV')
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(AnalysisChoiceForm, self).__init__(*args, **kwargs)
|
|
|
|
if 'initial' in kwargs and kwargs['initial']['function'] == 'compare':
|
|
self.fields['xaxis'].initial = 'time'
|
|
self.fields['yaxis1'].initial = 'hr'
|
|
self.fields['plottype'].initial = 'line'
|
|
|
|
|
|
class BoxPlotChoiceForm(forms.Form):
|
|
yparam = forms.ChoiceField(choices=parchoices, initial='spm',
|
|
label='Metric')
|
|
spmmin = forms.FloatField(initial=15,
|
|
required=False, label='Min SPM')
|
|
spmmax = forms.FloatField(initial=55,
|
|
required=False, label='Max SPM')
|
|
workmin = forms.FloatField(initial=0,
|
|
required=False, label='Min Work per Stroke')
|
|
workmax = forms.FloatField(initial=1500,
|
|
required=False, label='Max Work per Stroke')
|
|
|
|
includereststrokes = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Include Rest Strokes')
|
|
|
|
|
|
class MultiFlexChoiceForm(forms.Form):
|
|
xparam = forms.ChoiceField(choices=parchoicesmultiflex,
|
|
initial='hr',
|
|
label='X axis')
|
|
yparam = forms.ChoiceField(choices=parchoicesmultiflex,
|
|
initial='pace',
|
|
label='Y axis')
|
|
groupby = forms.ChoiceField(choices=groupchoices, initial='spm',
|
|
label='Group By')
|
|
binsize = forms.FloatField(initial=1, required=False, label='Bin Size')
|
|
spmmin = forms.FloatField(initial=15,
|
|
required=False, label='Min SPM')
|
|
spmmax = forms.FloatField(initial=55,
|
|
required=False, label='Max SPM')
|
|
workmin = forms.FloatField(initial=0,
|
|
required=False, label='Min Work per Stroke')
|
|
workmax = forms.FloatField(initial=1500,
|
|
required=False, label='Max Work per Stroke')
|
|
ploterrorbars = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Plot Error Bars')
|
|
includereststrokes = forms.BooleanField(initial=False,
|
|
required=False,
|
|
label='Include Rest Strokes')
|
|
palette = forms.ChoiceField(choices=palettechoices,
|
|
label='Color Scheme',
|
|
initial='monochrome_blue')
|
|
|
|
|
|
class ChartParamChoiceForm(forms.Form):
|
|
plotchoices = (
|
|
('line', 'Line Plot'),
|
|
('scatter', 'Scatter Plot'),
|
|
)
|
|
xparam = forms.ChoiceField(choices=parchoices, initial='distance')
|
|
yparam = forms.ChoiceField(choices=parchoices, initial='hr')
|
|
plottype = forms.ChoiceField(choices=plotchoices, initial='scatter')
|
|
teamid = forms.IntegerField(widget=forms.HiddenInput())
|
|
|
|
|
|
formaxlabels.pop('time')
|
|
metricchoices = list(sorted(formaxlabels.items(), key=lambda x: x[1]))
|
|
|
|
|
|
class WorkoutJoinParamForm(forms.Form):
|
|
workout_name = forms.CharField(required=True, initial='Joined Workout')
|
|
set_private = forms.BooleanField(initial=False, required=False)
|
|
killparents = forms.BooleanField(initial=False, required=False,
|
|
label='Delete original workouts')
|
|
|
|
|
|
class FusionMetricChoiceForm(ModelForm):
|
|
class Meta:
|
|
model = Workout
|
|
fields = []
|
|
|
|
posneg = (
|
|
('pos', 'Workout 2 starts after Workout 1'),
|
|
('neg', 'Workout 2 starts before Workout 1'),
|
|
)
|
|
columns = forms.MultipleChoiceField(choices=metricchoices,
|
|
initial=[],
|
|
widget=forms.CheckboxSelectMultiple())
|
|
posneg = forms.ChoiceField(choices=posneg, initial='pos')
|
|
offset = forms.DurationField(
|
|
label='Time Offset', initial=datetime.timedelta())
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(FusionMetricChoiceForm, self).__init__(*args, **kwargs)
|
|
formaxlabels2 = formaxlabels.copy()
|
|
# need to add code to remove "empty" fields
|
|
|
|
if self.instance.id is not None:
|
|
id = self.instance.id
|
|
df = dataprep.getrowdata_db(id=id)[0]
|
|
|
|
labeldict = {key: value for key,
|
|
value in self.fields['columns'].choices}
|
|
|
|
for label in labeldict:
|
|
if df.loc[:, label].std() == 0:
|
|
try:
|
|
formaxlabels2.pop(label)
|
|
except KeyError: # pragma: no cover
|
|
pass
|
|
|
|
metricchoices = list(
|
|
sorted(formaxlabels2.items(), key=lambda x: x[1]))
|
|
self.fields['columns'].choices = metricchoices
|
|
|
|
|
|
class PlannedSessionSelectForm(forms.Form):
|
|
|
|
def __init__(self, sessionchoices, *args, **kwargs):
|
|
initialsession = kwargs.pop('initialsession', None)
|
|
super(PlannedSessionSelectForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['plannedsession'] = forms.ChoiceField(
|
|
label='Sessions',
|
|
choices=sessionchoices,
|
|
widget=forms.RadioSelect,
|
|
initial=initialsession
|
|
)
|
|
|
|
|
|
class WorkoutSessionSelectForm(forms.Form):
|
|
|
|
def __init__(self, workoutdata, *args, **kwargs):
|
|
|
|
super(WorkoutSessionSelectForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['workouts'] = forms.MultipleChoiceField(
|
|
label='Workouts',
|
|
choices=workoutdata['choices'],
|
|
initial=workoutdata['initial'],
|
|
widget=forms.CheckboxSelectMultiple,
|
|
)
|
|
|
|
|
|
class RaceResultFilterForm(forms.Form):
|
|
boatclasses = (
|
|
type for type in mytypes.workouttypes if type[0] in mytypes.rowtypes)
|
|
boatclassinitial = [t for t in mytypes.rowtypes]
|
|
sexchoices = (
|
|
('female', 'Female'),
|
|
('male', 'Male'),
|
|
('mixed', 'Mixed'),
|
|
)
|
|
|
|
weightcategories = (
|
|
('hwt', 'heavy-weight'),
|
|
('lwt', 'light-weight'),
|
|
)
|
|
|
|
adaptivecategories = mytypes.adaptivetypes
|
|
|
|
sex = forms.MultipleChoiceField(
|
|
choices=sexchoices,
|
|
initial=['male', 'female', 'mixed'],
|
|
label='Gender',
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
boatclass = forms.MultipleChoiceField(
|
|
choices=boatclasses,
|
|
initial=boatclassinitial,
|
|
label='Boat/Erg Class',
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
boattype = forms.MultipleChoiceField(
|
|
choices=boattypes,
|
|
label='Boat Type',
|
|
initial=mytypes.waterboattype,
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
age_min = forms.IntegerField(label='Min Age', initial=16)
|
|
age_max = forms.IntegerField(label='Max Age', initial=100)
|
|
|
|
weightcategory = forms.MultipleChoiceField(
|
|
choices=weightcategories,
|
|
label='Weight Category',
|
|
initial=['hwt', 'lwt'],
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
adaptivecategory = forms.MultipleChoiceField(
|
|
choices=adaptivecategories,
|
|
label='Adaptive Class',
|
|
initial=['None', 'PR1', 'PR2', 'PR3', 'FES'],
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
entrycategory = forms.MultipleChoiceField(
|
|
choices=[],
|
|
label='Groups',
|
|
widget=forms.CheckboxSelectMultiple(),
|
|
required=False,
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
records = kwargs.pop('records', None)
|
|
groups = kwargs.pop('groups', None)
|
|
|
|
super(RaceResultFilterForm, self).__init__(*args, **kwargs)
|
|
|
|
if records:
|
|
# group
|
|
if groups: # pragma: no cover
|
|
thecategories = [record.entrycategory for record in records]
|
|
thecategories = list(set(thecategories))
|
|
if len(thecategories) <= 1:
|
|
del self.fields['entrycategory']
|
|
else:
|
|
categorychoices = []
|
|
for category in thecategories:
|
|
if category is not None:
|
|
categorychoices.append(
|
|
(category.id, category)
|
|
)
|
|
self.fields['entrycategory'].choices = categorychoices
|
|
self.fields['entrycategory'].initial = [cat[0]
|
|
for cat in categorychoices]
|
|
else:
|
|
del self.fields['entrycategory']
|
|
|
|
# sex
|
|
thesexes = [record.sex for record in records]
|
|
thesexes = list(set(thesexes))
|
|
|
|
if len(thesexes) <= 1:
|
|
del self.fields['sex']
|
|
else:
|
|
sexchoices = []
|
|
for choice in self.fields['sex'].choices:
|
|
if choice[0] in thesexes:
|
|
sexchoices.append(choice)
|
|
self.fields['sex'].choices = sexchoices
|
|
|
|
# boatclass
|
|
theboatclasses = [record.boatclass for record in records]
|
|
theboatclasses = list(set(theboatclasses))
|
|
|
|
if len(theboatclasses) <= 1:
|
|
del self.fields['boatclass']
|
|
else: # pragma: no cover
|
|
boatclasschoices = []
|
|
for choice in self.fields['boatclass'].choices:
|
|
if choice[0] in theboatclasses:
|
|
boatclasschoices.append(choice)
|
|
self.fields['boatclass'].choices = boatclasschoices
|
|
|
|
# boattype
|
|
try:
|
|
theboattypees = [record.boattype for record in records]
|
|
theboattypees = list(set(theboattypees))
|
|
except AttributeError: # pragma: no cover
|
|
theboattypees = []
|
|
|
|
if len(theboattypees) <= 1:
|
|
del self.fields['boattype']
|
|
else:
|
|
boattypechoices = []
|
|
for choice in self.fields['boattype'].choices:
|
|
if choice[0] in theboattypees:
|
|
boattypechoices.append(choice)
|
|
self.fields['boattype'].choices = boattypechoices
|
|
|
|
# weightcategory
|
|
theweightcategoryes = [record.weightcategory for record in records]
|
|
theweightcategoryes = list(set(theweightcategoryes))
|
|
|
|
if len(theweightcategoryes) <= 1:
|
|
del self.fields['weightcategory']
|
|
else: # pragma: no cover
|
|
weightcategorychoices = []
|
|
for choice in self.fields['weightcategory'].choices:
|
|
if choice[0] in theweightcategoryes:
|
|
weightcategorychoices.append(choice)
|
|
self.fields['weightcategory'].choices = weightcategorychoices
|
|
|
|
# adaptivecategory
|
|
theadaptivecategoryes = [
|
|
record.adaptiveclass for record in records]
|
|
theadaptivecategoryes = list(set(theadaptivecategoryes))
|
|
|
|
if len(theadaptivecategoryes) <= 1:
|
|
del self.fields['adaptivecategory']
|
|
else: # pragma: no cover
|
|
adaptivecategorychoices = []
|
|
for choice in self.fields['adaptivecategory'].choices:
|
|
if choice[0] in theadaptivecategoryes:
|
|
adaptivecategorychoices.append(choice)
|
|
self.fields['adaptivecategory'].choices = adaptivecategorychoices
|
|
|
|
|
|
class WorkoutRaceSelectForm(forms.Form):
|
|
# evaluate_after = forms.TimeField(
|
|
# input_formats=['%H:%M:%S.%f',
|
|
# '%H:%M:%S',
|
|
# '%H:%M:%S',
|
|
# '%M:%S.%f',
|
|
# '%M:%S',
|
|
# '%M'],
|
|
# label = 'Only Evaluate After:',
|
|
# required=False)
|
|
|
|
def __init__(self, workoutdata, entries, *args, **kwargs):
|
|
|
|
super(WorkoutRaceSelectForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['workouts'] = forms.ChoiceField(
|
|
label='Workouts',
|
|
choices=workoutdata['choices'],
|
|
initial=workoutdata['initial'],
|
|
widget=forms.RadioSelect,
|
|
)
|
|
|
|
self.fields['record'] = forms.ChoiceField(
|
|
label='Entry',
|
|
choices=entries['choices'],
|
|
initial=entries['initial'],
|
|
)
|
|
|
|
# self.fields['evaluate_after'] =
|
|
|
|
# form to send messages to team members
|
|
|
|
|
|
class TeamMessageForm(forms.Form):
|
|
message = forms.CharField(required=True,
|
|
initial='',
|
|
widget=forms.Textarea()
|
|
)
|
|
|
|
# Form to select team by rower
|
|
|
|
|
|
class RowerTeamForm(forms.Form):
|
|
team = forms.ModelChoiceField(
|
|
queryset=Team.objects.all(),
|
|
required=False,
|
|
)
|
|
|
|
def __init__(self, user, *args, **kwargs):
|
|
super(RowerTeamForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['team'].queryset = Team.objects.filter(manager=user)
|
|
|
|
|
|
class PlannedSessionTeamForm(forms.Form):
|
|
team = forms.ModelMultipleChoiceField(
|
|
queryset=Team.objects.all(),
|
|
required=False,
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
def __init__(self, user, *args, **kwargs):
|
|
super(PlannedSessionTeamForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['team'].queryset = Team.objects.filter(manager=user)
|
|
|
|
def clean(self):
|
|
if any(self.errors): # pragma: no cover
|
|
return
|
|
|
|
cd = self.cleaned_data
|
|
if not cd['team']:
|
|
raise forms.ValidationError(
|
|
'You must select at least one team'
|
|
)
|
|
|
|
return cd
|
|
|
|
|
|
class PlannedSessionTeamMemberForm(forms.Form):
|
|
members = forms.ModelMultipleChoiceField(
|
|
queryset=Rower.objects.all(),
|
|
widget=forms.CheckboxSelectMultiple())
|
|
|
|
def __init__(self, thesession, *args, **kwargs):
|
|
super(PlannedSessionTeamMemberForm, self).__init__(*args, **kwargs)
|
|
|
|
self.fields['members'].queryset = thesession.rower.all()
|
|
|
|
|
|
def get_countries():
|
|
try:
|
|
countries = VirtualRace.objects.order_by(
|
|
'country').values_list('country').distinct()
|
|
countries = tuple([(c[0], c[0]) for c in countries])
|
|
countries = countries+(('All', 'All'),)
|
|
except: # pragma: no cover
|
|
countries = (('All', 'All'))
|
|
return countries
|
|
|
|
|
|
class VirtualRaceSelectForm(forms.Form):
|
|
regattatypechoices = (
|
|
('upcoming', 'Upcoming Challenges'),
|
|
('ongoing', 'Ongoing Challenges'),
|
|
('previous', 'Previous Challenges'),
|
|
('my', 'My Challenges'),
|
|
('all', 'All Challenges'),
|
|
)
|
|
|
|
regattatype = forms.ChoiceField(
|
|
label='Type',
|
|
choices=regattatypechoices,
|
|
initial='upcoming',
|
|
)
|
|
|
|
country = forms.ChoiceField(
|
|
label='Country',
|
|
choices=get_countries()
|
|
)
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
super(VirtualRaceSelectForm, self).__init__(*args, **kwargs)
|
|
self.fields['country'] = forms.ChoiceField(
|
|
choices=get_countries(), initial='All'
|
|
)
|
|
|
|
|
|
class FlexOptionsForm(forms.Form):
|
|
includereststrokes = forms.BooleanField(initial=True, required=False,
|
|
label='Include Rest Strokes')
|
|
plotchoices = (
|
|
('line', 'Line Plot'),
|
|
('scatter', 'Scatter Plot'),
|
|
)
|
|
plottype = forms.ChoiceField(choices=plotchoices, initial='line',
|
|
label='Chart Type')
|
|
|
|
trendline = forms.BooleanField(initial=False, required=False,
|
|
label='Add Trend Line')
|
|
|
|
|
|
class ForceCurveOptionsForm(forms.Form):
|
|
includereststrokes = forms.BooleanField(initial=False, required=False,
|
|
label='Include Rest Strokes',
|
|
widget=forms.CheckboxInput(attrs={'class':'hidden'}))
|
|
|
|
spm_min = forms.FloatField(initial=15.0,label='SPM Min',widget=HiddenInput,required=False)
|
|
spm_max = forms.FloatField(initial=55.0,label='SPM Max',widget=HiddenInput,required=False)
|
|
dist_min = forms.IntegerField(initial=0,label='Dist Min',widget=HiddenInput,required=False)
|
|
dist_max = forms.IntegerField(initial=150000,label='Dist Max',widget=HiddenInput,required=False)
|
|
work_min = forms.IntegerField(initial=0,label='Work Min',widget=HiddenInput,required=False)
|
|
work_max = forms.IntegerField(initial=1500,label='Work Max',widget=HiddenInput,required=False)
|
|
|
|
notes = forms.CharField(initial="", label='notes', widget=HiddenInput, required=False)
|
|
|
|
name = forms.CharField(initial="", label='Name',required=False)
|
|
|
|
plotcircles = forms.BooleanField(initial=False,
|
|
widget=forms.CheckboxInput(attrs={'class':'hidden'}),
|
|
required=False)
|
|
plotlines = forms.BooleanField(initial=False,
|
|
widget=forms.CheckboxInput(attrs={'class':'hidden'}),
|
|
required=False)
|
|
|
|
|
|
axchoices = list(
|
|
(ax[0], ax[1]) for ax in axes if ax[0] not in ['cumdist', 'None']
|
|
)
|
|
axchoices = dict((x, y) for x, y in axchoices)
|
|
axchoices = list(sorted(axchoices.items(), key=lambda x: x[1]))
|
|
|
|
|
|
yaxchoices = list((ax[0], ax[1]) for ax in axes if ax[0]
|
|
not in ['cumdist', 'distance', 'time'])
|
|
yaxchoices = dict((x, y) for x, y in yaxchoices)
|
|
yaxchoices = list(sorted(yaxchoices.items(), key=lambda x: x[1]))
|
|
|
|
|
|
yaxchoices2 = list(
|
|
(ax[0], ax[1]) for ax in axes if ax[0] not in ['cumdist', 'distance', 'time']
|
|
)
|
|
yaxchoices2 = dict((x, y) for x, y in yaxchoices2)
|
|
yaxchoices2 = list(sorted(yaxchoices2.items(), key=lambda x: x[1]))
|
|
|
|
|
|
class StravaChartForm(forms.Form):
|
|
xaxischoices = (
|
|
('cumdist', 'Distance'),
|
|
('time', 'Time')
|
|
)
|
|
|
|
xaxis = forms.ChoiceField(
|
|
choices=xaxischoices, label='X-Axis', required=True)
|
|
|
|
yaxis1 = forms.ChoiceField(
|
|
choices=yaxchoices, label='First Chart', required=True)
|
|
yaxis2 = forms.ChoiceField(
|
|
choices=yaxchoices2, label='Second Chart', required=True)
|
|
|
|
yaxis3 = forms.ChoiceField(
|
|
choices=yaxchoices, label='Third Chart', required=True)
|
|
yaxis4 = forms.ChoiceField(
|
|
choices=yaxchoices2, label='Fourth Chart', required=True)
|
|
|
|
def __init__(self, request, *args, **kwargs):
|
|
super(StravaChartForm, self).__init__(*args, **kwargs)
|
|
|
|
rower = Rower.objects.get(user=request.user)
|
|
|
|
# axchoicespro = (
|
|
# ('', ax[1]) if ax[4] == 'pro' and ax[0] else (ax[0], ax[1]) for ax in axes
|
|
# )
|
|
|
|
axchoicesbasicx = []
|
|
axchoicesbasicy = []
|
|
|
|
for ax in axes:
|
|
if ax[4] != 'pro' and ax[0] != 'cumdist':
|
|
if ax[0] != 'None':
|
|
axchoicesbasicx.insert(0, (ax[0], ax[1]))
|
|
if ax[0] not in ['cumdist', 'distance', 'time']:
|
|
axchoicesbasicy.insert(0, (ax[0], ax[1]))
|
|
else:
|
|
if ax[0] != 'None':
|
|
axchoicesbasicx.insert(0, ('None', ax[1]+' (PRO)'))
|
|
if ax[0] not in ['cumdist', 'distance', 'time']:
|
|
axchoicesbasicy.insert(0, ('None', ax[1]+' (PRO)'))
|
|
|
|
if not user_is_not_basic(rower.user):
|
|
self.fields['xaxis'].choices = axchoicesbasicx
|
|
self.fields['yaxis1'].choices = axchoicesbasicy
|
|
self.fields['yaxis2'].choices = axchoicesbasicy
|
|
self.fields['yaxis3'].choices = axchoicesbasicy
|
|
self.fields['yaxis4'].choices = axchoicesbasicy
|
|
|
|
|
|
class FlexAxesForm(forms.Form):
|
|
|
|
xaxis = forms.ChoiceField(
|
|
choices=axchoices, label='X-Axis', required=True)
|
|
yaxis1 = forms.ChoiceField(
|
|
choices=yaxchoices, label='Left Axis', required=True)
|
|
yaxis2 = forms.ChoiceField(
|
|
choices=yaxchoices2, label='Right Axis', required=True)
|
|
|
|
def __init__(self, request, *args, **kwargs):
|
|
super(FlexAxesForm, self).__init__(*args, **kwargs)
|
|
|
|
rower = Rower.objects.get(user=request.user)
|
|
|
|
# axchoicespro = (
|
|
# ('', ax[1]) if ax[4] == 'pro' and ax[0] else (ax[0], ax[1]) for ax in axes
|
|
# )
|
|
|
|
axchoicesbasicx = []
|
|
axchoicesbasicy = []
|
|
|
|
for ax in axes:
|
|
if ax[4] != 'pro' and ax[0] != 'cumdist':
|
|
if ax[0] != 'None':
|
|
axchoicesbasicx.insert(0, (ax[0], ax[1]))
|
|
if ax[0] not in ['cumdist', 'distance', 'time']:
|
|
axchoicesbasicy.insert(0, (ax[0], ax[1]))
|
|
else:
|
|
if ax[0] != 'None':
|
|
axchoicesbasicx.insert(0, ('None', ax[1]+' (PRO)'))
|
|
if ax[0] not in ['cumdist', 'distance', 'time']:
|
|
axchoicesbasicy.insert(0, ('None', ax[1]+' (PRO)'))
|
|
|
|
if not user_is_not_basic(rower.user):
|
|
self.fields['xaxis'].choices = axchoicesbasicx
|
|
self.fields['yaxis1'].choices = axchoicesbasicy
|
|
self.fields['yaxis2'].choices = axchoicesbasicy
|