Private
Public Access
1
0
Files
rowsandall/rowers/forms.py
2018-04-22 15:56:14 +02:00

772 lines
27 KiB
Python

from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from rowers.models import Workout,Rower,Team,PlannedSession
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.extras.widgets import SelectDateWidget
from django.utils import timezone,translation
from django.forms import ModelForm
import dataprep
import types
import datetime
from django.forms import formset_factory
from utils import landingpages
# login form
class LoginForm(forms.Form):
username = forms.CharField()
password = forms.CharField(widget=forms.PasswordInput())
# simple form for Contact page. Sends email to info@rowsandall.com
class EmailForm(forms.Form):
firstname = forms.CharField(max_length=255)
lastname = forms.CharField(max_length=255)
email = forms.EmailField()
subject = forms.CharField(max_length=255)
botcheck = forms.CharField(max_length=5)
message = forms.CharField()
# 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')
file = forms.FileField(required=False,
validators=[validate_kml])
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(CourseForm, self).__init__(*args, **kwargs)
# The form used for uploading files
class DocumentsForm(forms.Form):
title = forms.CharField(required=False)
file = forms.FileField(required=False,
validators=[validate_file_extension])
workouttype = forms.ChoiceField(required=True,
choices=Workout.workouttypes)
# initial='rower')
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','fileformat','offline']
def __init__(self, *args, **kwargs):
from django.forms.widgets import HiddenInput
super(DocumentsForm, self).__init__(*args, **kwargs)
# self.fields['offline'].widget = HiddenInput()
from utils import (
workflowleftpanel,workflowmiddlepanel,
defaultleft,defaultmiddle
)
# 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):
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):
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',
)
# 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')
landingpage = forms.ChoiceField(choices=nextpages,
initial='workout_edit_view',
label='After Upload, go to')
class Meta:
fields = ['make_plot','plottype','upload_toc2','makeprivate']
# 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')
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 PredictedPieceForm(forms.Form):
unitchoices = (
('t','minutes'),
('d','meters'),
)
pieceunit = forms.ChoiceField(required=True,choices=unitchoices,
initial='t',label='Unit')
value = forms.FloatField(initial=10,label='Value')
class Meta:
fields = ['value','pieceunit']
# On the Geeky side, to update stream information for river dwellers
class UpdateStreamForm(forms.Form):
unitchoices = (
('m','m/s'),
('f','foot/s'),
('k','knots'),
('p','pace difference (sec/500m)'),
)
dist1 = forms.FloatField(initial=0,label = 'Distance 1')
dist2 = forms.FloatField(initial=1000,label = 'Distance 2')
stream1 = forms.FloatField(initial=0,label = 'Stream velocity 1')
stream2 = forms.FloatField(initial=0,label = 'Stream velocity 2')
streamunit = forms.ChoiceField(required=True,
choices=unitchoices,
initial='m',
label='Unit')
class Meta:
fields = ['dist1','dist2','stream1', 'stream2','streamunit']
# add wind information to your workout
class UpdateWindForm(forms.Form):
unitchoices = (
('m','m/s'),
('k','knots'),
('b','beaufort'),
('kmh','km/h'),
('mph','miles/hour'),
)
dist1 = forms.FloatField(initial=0,label = 'Distance 1')
dist2 = forms.FloatField(initial=1000,label = 'Distance 2')
vwind1 = forms.FloatField(initial=0,required=False,label = 'Wind Speed 1')
vwind2 = forms.FloatField(initial=0,required=False,label = 'Wind Speed 2')
windunit = forms.ChoiceField(required=True,
choices=unitchoices,
initial='m',
label='Unit')
winddirection1 = forms.IntegerField(initial=0,required=False,
label = 'Wind Direction 1')
winddirection2 = forms.IntegerField(initial=0,required=False,
label = 'Wind Direction 2')
class Meta:
fields = ['dist1','dist2',
'vwind1','vwind2',
'windunit',
'winddirection1','winddirection2']
# 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(),
label='Start Date')
enddate = forms.DateField(
initial=timezone.now(),
widget=AdminDateWidget(),
label='End Date')
class Meta:
fields = ['startdate','enddate']
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 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 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")
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']):
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'),
)
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:
raise forms.ValidationError('Must be at least 16 years old to register')
sex = forms.ChoiceField(required=True,
choices=sexcategories,
initial='not specified',
label='Sex')
weightcategory = forms.ChoiceField(label='Weight Category',
choices=weightcategories)
# def __init__(self, *args, **kwargs):
# self.fields['sex'].initial = 'not specified'
# Time field supporting microseconds. Not used, I believe.
class MyTimeField(forms.TimeField):
def __init__(self, *args, **kwargs):
super(MyTimeField, self).__init__(*args, **kwargs)
supports_microseconds = True
# Form used to update interval stats
class IntervalUpdateForm(forms.Form):
def __init__(self, *args, **kwargs):
typechoices = (
(1,'single time'),
(2,'single distance'),
(3,'rest (time based)'),
(3,'rest (distance based)'),
(4,'work (time based)'),
(5,'work (distance based)'),
)
aantal = int(kwargs.pop('aantal'))
super(IntervalUpdateForm, self).__init__(*args, **kwargs)
for i in range(aantal):
self.fields['intervalt_%s' % i] = forms.DurationField(label='Time '+str(i+1))
self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1))
self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices,
required=True,
initial=4,
label = 'Type '+str(i+1))
self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;'
self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f')
boattypes = types.boattypes
workouttypes = types.workouttypes
ww = list(workouttypes)
ww.append(tuple(('all','All')))
workouttypes = tuple(ww)
# 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,
label='Water Boat Type',
initial = ['1x','2x','2-','4x','4-','8+'])
# 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,
label='Water Boat Type',
widget=forms.CheckboxSelectMultiple(),
initial = ['1x','2x','2-','4x','4-','8+'])
rower = forms.BooleanField(initial=True,required=False)
dynamic = forms.BooleanField(initial=True,required=False)
slides = forms.BooleanField(initial=True,required=False)
skierg = forms.BooleanField(initial=False,required=False)
paddle = forms.BooleanField(initial=False,required=False)
snow = forms.BooleanField(initial=False,required=False)
coastal = forms.BooleanField(initial=False,required=False)
other = forms.BooleanField(initial=False,required=False)
class WorkoutMultipleCompareForm(forms.Form):
workouts = forms.ModelMultipleChoiceField(queryset=Workout.objects.all(),
widget=forms.CheckboxSelectMultiple())
class PlannedSessionMultipleCloneForm(forms.Form):
plannedsessions = forms.ModelMultipleChoiceField(
queryset=PlannedSession.objects.all(),
widget=forms.CheckboxSelectMultiple(),
label='Planned Sessions'
)
from rowers.metrics import axlabels
formaxlabels = axlabels.copy()
formaxlabels.pop('None')
parchoices = list(sorted(formaxlabels.items(), key = lambda x:x[1]))
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')
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]))
from utils import palettes
palettechoices = tuple((p,p) for p in palettes.keys())
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)
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.ix[:,label].std() == 0:
try:
formaxlabels2.pop(label)
except KeyError:
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 WorkoutRaceSelectForm(forms.Form):
def __init__(self, workoutdata, *args, **kwargs):
super(WorkoutRaceSelectForm, self).__init__(*args, **kwargs)
self.fields['workouts'] = forms.ChoiceField(
label='Workouts',
choices = workoutdata['choices'],
initial=workoutdata['initial'],
widget=forms.RadioSelect,
)
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)
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()
from rowers.models import VirtualRace,GeoCourse
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:
countries = (('All','All'))
return countries
class VirtualRaceSelectForm(forms.Form):
regattatypechoices = (
('upcoming','Upcoming Races'),
('ongoing','Ongoing Races'),
('previous','Previous Races'),
('my','My Races'),
('all','All Races'),
)
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'
)