From 2ffd145bca272aa3afa92b67172407b9fce0fcad Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sat, 15 Dec 2018 14:18:48 +0100 Subject: [PATCH] added adaptive classes (not tested) --- rowers/admin.py | 2 +- rowers/dataprep.py | 13 +++++++++++-- rowers/forms.py | 27 ++++++++++++++++++++++++++- rowers/models.py | 37 +++++++++++++++++++++++++++++++++---- rowers/mytypes.py | 8 ++++++++ rowers/plannedsessions.py | 8 ++++++++ rowers/serializers.py | 1 + rowers/tests.py | 3 +++ rowers/views.py | 33 +++++++++++++++++++++++++++++++-- 9 files changed, 122 insertions(+), 10 deletions(-) diff --git a/rowers/admin.py b/rowers/admin.py index 8b2c0d74..1614ae88 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -23,7 +23,7 @@ class RowerInline(admin.StackedInline): {'fields':('rowerplan','paymenttype','planexpires','teamplanexpires','clubsize','protrialexpires','plantrialexpires',)}), ('Rower Settings', {'fields': - ('gdproptin','gdproptindate','weightcategory','sex','birthdate','getemailnotifications', + ('gdproptin','gdproptindate','weightcategory','sex','adaptiveclass','birthdate','getemailnotifications', 'getimportantemails','emailbounced','defaultlandingpage', 'defaulttimezone','showfavoritechartnotes')}), ('Rower Zones', diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 87029e4a..bf79d97a 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -140,6 +140,7 @@ def workout_summary_to_df( distances = [] durations = [] weightcategories = [] + adaptivetypes = [] weightvalues = [] notes = [] tcx_links = [] @@ -155,6 +156,7 @@ def workout_summary_to_df( distances.append(w.distance) durations.append(w.duration) weightcategories.append(w.weightcategory) + adaptivetypes.append(w.adaptiveclass) weightvalues.append(w.weightvalue) notes.append(w.notes) tcx_link = SITE_URL+'/rowers/workout/{id}/emailtcx'.format( @@ -177,6 +179,7 @@ def workout_summary_to_df( 'distance (m)':distances, 'duration ':durations, 'weight category':weightcategories, + 'adaptive classification':adaptivetypes, 'weight (kg)':weightvalues, 'notes':notes, 'Stroke Data TCX':tcx_links, @@ -742,7 +745,8 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower', avghr=None,avgpwr=None,avgspm=None, rankingpiece = False, duplicate=False, - title='Manual entry',notes='',weightcategory='hwt'): + title='Manual entry',notes='',weightcategory='hwt', + adaptiveclass='None'): if duration is not None: totalseconds = duration.hour*3600. @@ -832,6 +836,8 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower', dosmooth=False, workouttype=workouttype, consistencychecks=False, + weightcategory=weightcategory, + adaptiveclass=adaptiveclass, totaltime=totalseconds) return (id, message) @@ -841,6 +847,8 @@ from utils import totaltime_sec_to_string # Processes painsled CSV file to database def save_workout_database(f2, r, dosmooth=True, workouttype='rower', boattype='1x', + adaptiveclass='None', + weightcategory='hwt', dosummary=True, title='Workout', workoutsource='unknown', notes='', totaldist=0, totaltime=0, @@ -1046,7 +1054,8 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower', workouttype=workouttype, boattype=boattype, duration=duration, distance=totaldist, - weightcategory=r.weightcategory, + weightcategory=weightcategory, + adaptiveclass=adaptiveclass, starttime=workoutstarttime, duplicate=duplicate, workoutsource=workoutsource, diff --git a/rowers/forms.py b/rowers/forms.py index 05fc77a8..7f83f72d 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -575,6 +575,8 @@ class RegistrationFormSex(RegistrationFormUniqueEmail): ('lwt','light-weight'), ) + adaptivecategories = mytypes.adaptivetypes + thisyear = timezone.now().year birthdate = forms.DateTimeField( @@ -597,6 +599,9 @@ class RegistrationFormSex(RegistrationFormUniqueEmail): weightcategory = forms.ChoiceField(label='Weight Category', choices=weightcategories) + adaptiveclass = forms.ChoiceField(label='Adaptive Classification', + choices=adaptivecategories) + # def __init__(self, *args, **kwargs): # self.fields['sex'].initial = 'not specified' @@ -887,6 +892,7 @@ class RaceResultFilterForm(forms.Form): ('lwt','light-weight'), ) + adaptivecategories = mytypes.adaptivetypes sex = forms.MultipleChoiceField( choices=sexchoices, @@ -915,6 +921,12 @@ class RaceResultFilterForm(forms.Form): initial=['hwt','lwt'], widget=forms.CheckboxSelectMultiple()) + adaptivecategory = forms.MultipleChoiceField( + choices=adaptivecategories, + label='Adaptive Class', + initial=['None','PR1','PR2','PR3','FES'], + widget=forms.CheckboxSelectMultiple()) + def __init__(self, *args, **kwargs): if 'records' in kwargs: records = kwargs.pop('records',None) @@ -976,7 +988,20 @@ class RaceResultFilterForm(forms.Form): 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: + 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', diff --git a/rowers/models.py b/rowers/models.py index 4b1b0855..e48f252a 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -538,7 +538,7 @@ weightcategories = ( # Extension of User with rowing specific data class Rower(models.Model): - + adaptivetypes = mytypes.adaptivetypes stravatypes = ( ('Ride','Ride'), ('Kitesurf','Kitesurf'), @@ -593,6 +593,10 @@ class Rower(models.Model): max_length=30, choices=sexcategories) + adaptiveclass = models.CharField(choices=adaptivetypes,max_length=50, + default='None', + verbose_name='Adaptive Classification') + birthdate = models.DateField(null=True,blank=True) # Power Zone Data ftp = models.IntegerField(default=226,verbose_name="Functional Threshold Power") @@ -2256,6 +2260,7 @@ class Workout(models.Model): workouttypes = mytypes.workouttypes workoutsources = mytypes.workoutsources privacychoices = mytypes.privacychoices + adaptivetypes = mytypes.adaptivetypes user = models.ForeignKey(Rower) team = models.ManyToManyField(Team,blank=True) @@ -2270,6 +2275,9 @@ class Workout(models.Model): boattype = models.CharField(choices=boattypes,max_length=50, default='1x', verbose_name = 'Boat Type') + adaptiveclass = models.CharField(choices=adaptivetypes,max_length=50, + default='None', + verbose_name='Adaptive Classification') starttime = models.TimeField(blank=True,null=True) startdatetime = models.DateTimeField(blank=True,null=True) timezone = models.CharField(default='UTC', @@ -2426,6 +2434,9 @@ class VirtualRaceResult(models.Model): weightcategory = models.CharField(default="hwt",max_length=10, choices=weightcategories, verbose_name='Weight Category') + adaptiveclass = models.CharField(default="None",max_length=50, + choices=mytypes.adaptivetypes, + verbose_name="Adaptive Class") race = models.ForeignKey(VirtualRace) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) @@ -2482,6 +2493,9 @@ class IndoorVirtualRaceResult(models.Model): weightcategory = models.CharField(default="hwt",max_length=10, choices=weightcategories, verbose_name='Weight Category') + adaptiveclass = models.CharField(default="None",max_length=50, + choices=mytypes.adaptivetypes, + verbose_name="Adaptive Class") race = models.ForeignKey(VirtualRace) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) @@ -2533,7 +2547,7 @@ class CourseTestResult(models.Model): class IndoorVirtualRaceResultForm(ModelForm): class Meta: model = IndoorVirtualRaceResult - fields = ['teamname','weightcategory','boatclass','age'] + fields = ['teamname','weightcategory','boatclass','age','adaptiveclass'] def __init__(self, *args, **kwargs): @@ -2543,7 +2557,8 @@ class IndoorVirtualRaceResultForm(ModelForm): class VirtualRaceResultForm(ModelForm): class Meta: model = VirtualRaceResult - fields = ['teamname','weightcategory','boatclass','boattype','age'] + fields = ['teamname','weightcategory','boatclass','boattype', + 'age','adaptiveclass'] def __init__(self, *args, **kwargs): @@ -2683,7 +2698,20 @@ class WorkoutForm(ModelForm): # duration = forms.TimeInput(format='%H:%M:%S.%f') class Meta: model = Workout - fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece','duplicate','plannedsession'] + fields = ['name', + 'date', + 'starttime', + 'timezone', + 'duration', + 'distance', + 'workouttype', + 'boattype', + 'weightcategory', + 'adaptiveclass', + 'notes', + 'rankingpiece', + 'duplicate', + 'plannedsession'] widgets = { 'date': AdminDateWidget(), 'notes': forms.Textarea, @@ -2930,6 +2958,7 @@ class AccountRowerForm(ModelForm): class Meta: model = Rower fields = ['sex','birthdate','weightcategory', + 'adaptiveclass', 'getemailnotifications', 'getimportantemails', 'defaulttimezone','showfavoritechartnotes', diff --git a/rowers/mytypes.py b/rowers/mytypes.py index ad704756..662481a9 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -283,6 +283,14 @@ boattypes = ( ('8x+', '8x+ (octuple scull)'), ) +adaptivetypes = ( + ('None','None'), + ('PR1', 'PR1 (Arms and Shoulders)'), + ('PR2', 'PR2 (Trunk and Arms)'), + ('PR3', 'PR3 (Leg Trunk and Arms)'), + ('FES', 'FES (Functional Electrical Stimulation)'), + ) + waterboattype = [i[0] for i in boattypes] privacychoices = ( diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 1bf1ab8a..a4056bd1 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1025,6 +1025,10 @@ def add_workout_indoorrace(ws,race,r,recordid=0): errors.append('Your workout weight category did not match the weight category you registered') return 0,comments, errors,0 + if ws[0].adaptiveclass != record.adaptiveclass: + errors.append('Your adaptive classification did not match the registration') + return 0,comments, errors, 0 + # start adding sessions if ws[0].startdatetime>=startdatetime and ws[0].startdatetime<=enddatetime: ws[0].plannedsession = race @@ -1129,6 +1133,10 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): errors.append('Your workout weight category did not match the weight category you registered') return 0,comments, errors,0 + if ws[0].adaptiveclass != record.adaptiveclass: + errors.append('Your workout adaptive classification did not match the registration') + return 0,comments, errors,0 + # start adding sessions if ws[0].startdatetime>=startdatetime and ws[0].startdatetime<=enddatetime: ws[0].plannedsession = race diff --git a/rowers/serializers.py b/rowers/serializers.py index 3e94f954..3ecbdd49 100644 --- a/rowers/serializers.py +++ b/rowers/serializers.py @@ -79,6 +79,7 @@ class WorkoutSerializer(serializers.ModelSerializer): duration=validated_data['duration'], distance=validated_data['distance'], weightcategory=r.weightcategory, + adaptiveclass=r.adaptiveclass, starttime=validated_data['starttime'], csvfilename='', notes=validated_data['notes'], diff --git a/rowers/tests.py b/rowers/tests.py index c98ca1de..97358244 100644 --- a/rowers/tests.py +++ b/rowers/tests.py @@ -968,6 +968,7 @@ class NewUserRegistrationTest(TestCase): 'password2':'aapindewei2', 'tos':True, 'weightcategory':'hwt', + 'adaptiveclass': 'None', 'sex':'male', 'next':'/rowers/list-workouts', 'birthdate':datetime.datetime(year=1970,month=4,day=2) @@ -1161,6 +1162,7 @@ class DataTest(TestCase): 'distance':8000, 'notes':'Aap noot \n mies', 'weightcategory':'lwt', + 'adaptiveclass': 'PR1', 'workouttype':'water', 'boattype':'1x', 'private':False, @@ -1392,6 +1394,7 @@ class ViewTest(TestCase): 'duration':'1:00:00.5', 'distance':'15000', 'weightcategory':'hwt', + 'adaptiveclass':'PR1', 'workouttype':'rower', 'boattype':'1x', 'private':True, diff --git a/rowers/views.py b/rowers/views.py index d3d5803a..4a2630de 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -1045,6 +1045,7 @@ def rower_register_view(request): sex = form.cleaned_data['sex'] birthdate = form.cleaned_data['birthdate'] weightcategory = form.cleaned_data['weightcategory'] + adaptiveclass = form.cleaned_data['adaptiveclass'] nextpage = request.POST['next'] theuser = User.objects.create_user(username,password=password) theuser.first_name = first_name @@ -1053,7 +1054,8 @@ def rower_register_view(request): theuser.save() therower = Rower(user=theuser,sex=sex,birthdate=birthdate, - weightcategory=weightcategory) + weightcategory=weightcategory, + adaptiveclass=adaptiveclass) therower.save() @@ -3382,6 +3384,7 @@ def addmanual_view(request): workouttype = form.cleaned_data['workouttype'] duration = form.cleaned_data['duration'] weightcategory = form.cleaned_data['weightcategory'] + adaptiveclass = form.cleaned_data['adaptiveclass'] distance = form.cleaned_data['distance'] notes = form.cleaned_data['notes'] thetimezone = form.cleaned_data['timezone'] @@ -3431,6 +3434,7 @@ def addmanual_view(request): distance, duration,startdatetime, weightcategory=weightcategory, + adaptiveclass=adaptiveclass, avghr=avghr, rankingpiece=rankingpiece, avgpwr=avgpwr, @@ -3450,6 +3454,7 @@ def addmanual_view(request): w.rankingpiece = rankingpiece w.privacy = privacy w.weightcategory = weightcategory + w.adaptiveclass = adaptiveclass w.notes = notes w.plannedsession = ps w.name = name @@ -3567,7 +3572,8 @@ def rankings_view(request,theuser=0, worldclasspower = int(metrics.getagegrouprecord( age, sex=r.sex, - weightcategory=r.weightcategory + weightcategory=r.weightcategory, + adaptiveclass=r.adaptiveclass, )) else: worldclasspower = None @@ -10044,6 +10050,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): starttime = form.cleaned_data['starttime'] workouttype = form.cleaned_data['workouttype'] weightcategory = form.cleaned_data['weightcategory'] + adaptiveclass = form.cleaned_data['adaptiveclass'] duration = form.cleaned_data['duration'] distance = form.cleaned_data['distance'] private = form.cleaned_data['private'] @@ -10108,6 +10115,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""): row.startdatetime = startdatetime row.workouttype = workouttype row.weightcategory = weightcategory + row.adaptiveclass = adaptiveclass row.notes = notes row.duration = duration row.distance = distance @@ -13137,6 +13145,7 @@ def rower_edit_view(request,rowerid=0,userid=0,message=""): last_name = ucd['last_name'] email = ucd['email'] sex = cd['sex'] + adaptiveclass = cd['adaptiveclass'] defaultlandingpage = cd['defaultlandingpage'] weightcategory = cd['weightcategory'] birthdate = cd['birthdate'] @@ -13160,6 +13169,7 @@ def rower_edit_view(request,rowerid=0,userid=0,message=""): u.save() r.defaulttimezone=defaulttimezone r.weightcategory = weightcategory + r.adaptiveclass = adaptiveclass r.getemailnotifications = getemailnotifications r.getimportantemails = getimportantemails r.defaultlandingpage = defaultlandingpage @@ -13440,6 +13450,7 @@ def rower_prefs_view(request,userid=0,message=""): sex = cd['sex'] defaultlandingpage = cd['defaultlandingpage'] weightcategory = cd['weightcategory'] + adaptiveclass = cd['adaptiveclass'] birthdate = cd['birthdate'] showfavoritechartnotes = cd['showfavoritechartnotes'] getemailnotifications = cd['getemailnotifications'] @@ -13461,6 +13472,7 @@ def rower_prefs_view(request,userid=0,message=""): u.save() r.defaulttimezone=defaulttimezone r.weightcategory = weightcategory + r.adaptiveclass = adaptiveclass r.getemailnotifications = getemailnotifications r.getimportantemails = getimportantemails r.defaultlandingpage = defaultlandingpage @@ -16379,6 +16391,11 @@ def virtualevent_view(request,id=0): except KeyError: weightcategory = ['hwt','lwt'] + try: + adaptiveclass = cd['adaptiveclass'] + except KeyError: + adaptiveclass = ['None','PR1','PR2','PR3','FES'] + if race.sessiontype == 'race': results = resultobj.objects.filter( race=race, @@ -16387,6 +16404,7 @@ def virtualevent_view(request,id=0): boattype__in=boattype, sex__in=sex, weightcategory__in=weightcategory, + adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ).order_by("duration") @@ -16397,6 +16415,7 @@ def virtualevent_view(request,id=0): boatclass__in=boatclass, sex__in=sex, weightcategory__in=weightcategory, + adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ).order_by("duration","-distance") @@ -16411,6 +16430,7 @@ def virtualevent_view(request,id=0): boatclass__in=boatclass, sex__in=sex, weightcategory__in=weightcategory, + adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max ) @@ -16525,6 +16545,7 @@ def virtualevent_addboat_view(request,id=0): boattype = cd['boattype'] boatclass = cd['boatclass'] weightcategory = cd['weightcategory'] + adaptiveclass = cd['adaptiveclass'] age = cd['age'] mix = cd['mix'] @@ -16569,6 +16590,7 @@ def virtualevent_addboat_view(request,id=0): l = r.user.last_name ), weightcategory=weightcategory, + adaptiveclass=adaptiveclass, duration=datetime.time(0,0), boattype=boattype, boatclass=boatclass, @@ -16599,6 +16621,7 @@ def virtualevent_addboat_view(request,id=0): initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, + 'adaptiveclass': r.adaptiveclass, } form = VirtualRaceResultForm(initial=initial) @@ -16682,6 +16705,7 @@ def virtualevent_register_view(request,id=0): boattype = cd['boattype'] boatclass = cd['boatclass'] weightcategory = cd['weightcategory'] + adaptiveclass = cd['adaptiveclass'] age = cd['age'] mix = cd['mix'] @@ -16705,6 +16729,7 @@ def virtualevent_register_view(request,id=0): l = r.user.last_name ), weightcategory=weightcategory, + adaptiveclass=adaptiveclass, duration=datetime.time(0,0), boatclass=boatclass, boattype=boattype, @@ -16751,6 +16776,7 @@ def virtualevent_register_view(request,id=0): initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, + 'adaptiveclass': r.adaptiveclass, } form = VirtualRaceResultForm(initial=initial) @@ -16873,6 +16899,7 @@ def indoorvirtualevent_register_view(request,id=0): cd = form.cleaned_data teamname = cd['teamname'] weightcategory = cd['weightcategory'] + adaptiveclass = cd['adaptiveclass'] age = cd['age'] boatclass = cd['boatclass'] @@ -16894,6 +16921,7 @@ def indoorvirtualevent_register_view(request,id=0): l = r.user.last_name ), weightcategory=weightcategory, + adaptiveclass=adaptiveclass, duration=datetime.time(0,0), boatclass=boatclass, coursecompleted=False, @@ -16939,6 +16967,7 @@ def indoorvirtualevent_register_view(request,id=0): initial = { 'age': calculate_age(r.birthdate), 'weightcategory': r.weightcategory, + 'adaptiveclass': r.adaptiveclass, } form = IndoorVirtualRaceResultForm(initial=initial)