From ba0b351130f876ee8662b312d7fa7ef25e16d251 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 21 Jun 2020 12:48:24 +0200 Subject: [PATCH 1/3] working submission --- requirements.txt | 8 +++- rowers/forms.py | 29 ++++++++------ rowers/plannedsessions.py | 5 ++- rowers/views/workoutviews.py | 76 ++++++++++++++++++++++++++++-------- 4 files changed, 86 insertions(+), 32 deletions(-) diff --git a/requirements.txt b/requirements.txt index a237c95a..25b00df6 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,6 +12,8 @@ billiard==3.6.0.0 bleach==3.1.0 bokeh==1.0.4 boto==2.49.0 +boto3==1.14.7 +botocore==1.17.7 braintree==3.55.0 cairocffi==1.0.2 celery==4.3.0 @@ -53,7 +55,7 @@ django-rest-framework==0.1.0 django-rest-swagger==2.2.0 django-rq==1.3.1 django-rq-dashboard==0.3.3 -django-ses==0.8.10 +django-ses==1.0.0 django-shell-plus==1.1.7 django-social-share==1.3.2 django-suit==0.2.26 @@ -96,6 +98,7 @@ itypes==1.1.0 jedi==0.13.3 jeepney==0.4 Jinja2==2.10 +jmespath==0.10.0 json5==0.8.5 jsonschema==3.0.1 jupyter==1.0.0 @@ -125,7 +128,7 @@ newrelic==5.2.1.129 nose==1.3.7 nose-parameterized==0.6.0 notebook==5.7.6 -numba==0.46.0 +numba==0.50.0 numpy==1.18.5 oauth2==1.9.0.post1 oauthlib==3.0.1 @@ -179,6 +182,7 @@ rowingdata==2.9.1 rowingphysics==0.5.0 rq==0.13.0 rules==2.1 +s3transfer==0.3.3 scipy==1.2.1 SecretStorage==3.1.1 Send2Trash==1.5.0 diff --git a/rowers/forms.py b/rowers/forms.py index 3dc3a222..42987cb4 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -124,7 +124,7 @@ class EmailForm(forms.Form): subject = forms.CharField(max_length=255) message = forms.CharField(widget=forms.Textarea()) - + disqualificationreasons = ( ('noimage','No monitor screenshot or data evidence was included'), @@ -386,7 +386,7 @@ class UploadOptionsForm(forms.Form): makeprivate = forms.BooleanField(initial=False,required=False, label='Make Workout Private') - submitrace = forms.ModelChoiceField(queryset=VirtualRace.objects.all(), + submitrace = forms.ChoiceField( label='Submit as challenge Result', required=False) @@ -404,6 +404,7 @@ class UploadOptionsForm(forms.Form): 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) @@ -413,25 +414,27 @@ class UploadOptionsForm(forms.Form): userid = r.id, ) - raceids = [r.race.id for r in registrations] - raceids2 = [r.race.id for r in registrations2] + choices1 = [(r.id,str(r)) for r in registrations] + choices2 = [(r.id,str(r)) for r in registrations2] + choices3 = [(0,'---')] - raceids = raceids+raceids2 + choices = choices3+choices1+choices2 - races = VirtualRace.objects.filter( - id__in=raceids - ) + if int(raceid) in [r.id for r in races]: + therace = VirtualRace.objects.get(id=raceid) + if therace.sessiontype == 'race': + registrations = VirtualRaceResult.objects.filter(race=therace,userid=r.id) + else: + registrations = IndoorVirtualRaceResult.objects.filter(race=therace,userid=r.id) + choices = [(r.id,str(r)) for r in registrations] + choices = [(0,'---')]+choices if races: - self.fields['submitrace'].queryset = races + self.fields['submitrace'].choices = choices else: del self.fields['submitrace'] - if int(raceid) in raceids: - self.fields['submitrace'].initial = VirtualRace.objects.get(id=raceid) - - # The form to indicate additional actions to be performed immediately # after a successful upload. This version allows the Team manager to select diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index a9be6a3e..674b5fe8 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1343,6 +1343,7 @@ def remove_rower_race(r,race,recordid=None): # Low Level functions - to be called by higher level methods def add_workout_indoorrace(ws,race,r,recordid=0): + print('aap') result = 0 comments = [] errors = [] @@ -1402,6 +1403,8 @@ def add_workout_indoorrace(ws,race,r,recordid=0): workoutid = ws[0].id ) + print(record,records) + if not record: errors.append("Couldn't find this entry") return result,comments,errors,0 @@ -1471,7 +1474,7 @@ def add_workout_indoorrace(ws,race,r,recordid=0): return result,comments,errors,0 -def add_workout_race(ws,race,r,splitsecond=0,recordid=0): +def add_workout_race(ws,race,r,splitsecond=0,recordid=0,doregister=False): result = 0 comments = [] errors = [] diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 43bea2b4..79b8f1ea 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4909,7 +4909,7 @@ def workout_upload_view(request, notes = form.cleaned_data['notes'] offline = form.cleaned_data['offline'] - race = None + registrationid = 0 if optionsform.is_valid(): make_plot = optionsform.cleaned_data['make_plot'] plottype = optionsform.cleaned_data['plottype'] @@ -4923,9 +4923,9 @@ def workout_upload_view(request, landingpage = optionsform.cleaned_data['landingpage'] try: - race = optionsform.cleaned_data['submitrace'] + registrationid = optionsform.cleaned_data['submitrace'] except KeyError: - race = None + registrationid = 0 uploadoptions = { 'makeprivate':makeprivate, @@ -5113,17 +5113,60 @@ def workout_upload_view(request, else: messages.error(request,message) - if race and race_can_submit(r,race): - if race.sessiontype == 'indoorrace': - records = IndoorVirtualRaceResult.objects.filter( - race=race, - userid=r.id + if int(registrationid) < 0: + race = VirtualRace.Objects.get(id=-int(registrationid)) + if race.sessiontype == 'race': + race = registrations[0].race + result,comments,errors,jobid = add_workout_race( + [w], race,r, + ) + if result: + messages.info( + request, + "We have submitted your workout to the race") + + for c in comments: + messages.info(request,c) + for er in errors: + messages.error(request,er) + elif race.sessiontype == 'indoorrace': + race = registrations[0].race + result,comments,errors,jobid = add_workout_indoorrace( + [w],race,r, ) - if records: + if result: + messages.info( + request, + "We have submitted your workout to the race") + for c in comments: + messages.info(request,c) + for er in errors: + messages.error(request,er) + + if int(registrationid)>0: + races = VirtualRace.objects.filter( + registration_closure__gt=timezone.now() + ) + registrations = IndoorVirtualRaceResult.objects.filter( + race__in = races, + id=registrationid, + userid = r.id, + ) + registrations2 = VirtualRaceResult.objects.filter( + race__in = races, + id=registrationid, + userid=r.id, + ) + + if int(registrationid) in [r.id for r in registrations]: + # indoor race + registrations = registrations.filter(id=registrationid) + if registrations: + race = registrations[0].race result,comments,errors,jobid = add_workout_indoorrace( - [w],race,r,recordid=records[0].id + [w],race,r,recordid=registrations[0].id ) if result: @@ -5135,15 +5178,15 @@ def workout_upload_view(request, messages.info(request,c) for er in errors: messages.error(request,er) - if race.sessiontype == 'race': - records = VirtualRaceResult.objects.filter( - race=race,userid=r.id - ) - if records: + if int(registrationid) in [r.id for r in registrations2]: + # race + registrations = registrations2.filter(id=registrationid) + if registrations: + race = registrations[0].race result,comments,errors,jobid = add_workout_race( - [w], race,r,recordid=records[0].id + [w], race,r,recordid=registrations[0].id ) if result: messages.info( @@ -5156,6 +5199,7 @@ def workout_upload_view(request, messages.error(request,er) + if landingpage != 'workout_upload_view': url = reverse(landingpage, kwargs = { From add55993ba33350ebc37b3fe75a624cf8b5f2bfb Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 21 Jun 2020 14:49:09 +0200 Subject: [PATCH 2/3] form initial now has better default initial --- rowers/forms.py | 12 +++++- rowers/models.py | 4 +- rowers/plannedsessions.py | 76 +++++++++++++++++++++++++++++++++++--- rowers/views/racesviews.py | 40 ++++++++++++++++---- 4 files changed, 116 insertions(+), 16 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index 42987cb4..694962b5 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -418,7 +418,17 @@ class UploadOptionsForm(forms.Form): choices2 = [(r.id,str(r)) for r in registrations2] choices3 = [(0,'---')] - choices = choices3+choices1+choices2 + noregistrations = [] + for ra in VirtualRace.objects.filter(registration_closure__gt=timezone.now(),sessiontype='race'): + 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'): + 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]: therace = VirtualRace.objects.get(id=raceid) diff --git a/rowers/models.py b/rowers/models.py index 4a8adafb..8e9ed3f8 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2648,7 +2648,7 @@ class VirtualRaceForm(ModelForm): except KeyError: registration_closure = enddatetime+datetime.timedelta(days=1) cd['registration_closure'] = registration_closure - + registration_form = cd['registration_form'] try: @@ -3124,6 +3124,8 @@ class CourseTestResult(models.Model): distance = models.IntegerField(default=0) coursecompleted = models.BooleanField(default=False) + + class IndoorVirtualRaceResultForm(ModelForm): class Meta: model = IndoorVirtualRaceResult diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 674b5fe8..93206cbe 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -45,7 +45,7 @@ from rowers.models import ( GeoCourse, TrainingMicroCycle,TrainingMesoCycle,TrainingMacroCycle, TrainingPlan,PlannedSession,VirtualRaceResult,CourseTestResult, get_course_timezone, IndoorVirtualRaceResult,VirtualRace,createmacrofillers, - createmesofillers,createmicrofillers, + createmesofillers,createmicrofillers,CourseStandard, ) from rowers.courses import get_time_course @@ -1341,9 +1341,70 @@ def remove_rower_race(r,race,recordid=None): return 1 +def default_class(r,w,race): + if r.birthdate: + age = calculate_age(r.birthdate) + else: + age = 25 + + sex = r.sex + if sex=='not specified': + sex='male' + + if w is not None: + boatclass = w.workouttype + boattype = w.boattype + + adaptiveclass = w.adaptiveclass + weightclass = w.weightcategory + else: + if race.sessiontype == 'race': + boatclass = 'water' + else: + boatclass = 'rower' + boattype = '1x' + adaptiveclass = 'None' + weightclass = 'hwt' + + if race.coursestandards: + standards = CourseStandard.objects.filter( + agemin__lt=age,agemax__gt=age, + boatclass=boatclass, + adaptiveclass=adaptiveclass, + boattype=boattype, + weightclass=weightclass + ).order_by("agemax","-agemin","boattype") + + + if standards.count()==0: + # omit weight + standards = CourseStandard.objects.filter(agemin__lt=age,agemax__gt=age, + boatclass=boatclass, + adaptiveclass=adaptiveclass, + boattype=boattype, + ) + if standards.count()==0: + standards = CourseStandard.objects.filter(agemin__lt=age,agemax__gt=age, + boattype=boattype) + if standards.count()==0: + standards = CourseStandard.objects.filter(agemin__lt=age,agemax__gt=age) + + if standards.count()==0: + # boolean, boattype, boatclass, adaptiveclass, weightclass, sex, coursestandard, + return False,'1x','water',None,'hwt','male',None + + if standards.count()>0: + # find optimum standard + s = standards[0] + return True,s.boattype,s.boatclass,s.adaptiveclass,s.weightclass,s.sex,s + + # No Course Standard + return True,boattype,boatclass,adaptiveclass,weightclass,sex,None + + + # Low Level functions - to be called by higher level methods -def add_workout_indoorrace(ws,race,r,recordid=0): - print('aap') +def add_workout_indoorrace(ws,race,r,recordid=0,doregister=False): result = 0 comments = [] errors = [] @@ -1403,11 +1464,14 @@ def add_workout_indoorrace(ws,race,r,recordid=0): workoutid = ws[0].id ) - print(record,records) - if not record: + + if not record and not doregister: errors.append("Couldn't find this entry") return result,comments,errors,0 + elif not record: + pass + if race.sessionmode == 'distance': if ws[0].distance != race.sessionvalue: @@ -1532,7 +1596,7 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0,doregister=False): workoutid = ws[0].id ) - if not record: + if not record and not doregister: errors.append("Couldn't find this entry") return result,comments,errors,0 diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index c0369e00..c2148ac0 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1499,6 +1499,7 @@ def virtualevent_addboat_view(request,id=0): raise Http404("Virtual Challenge does not exist") categories = None + hasinitial,boattype,boatclass,adaptiveclass,weightclass,sex,initialcategory = default_class(r,None,race) if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") @@ -1700,11 +1701,22 @@ def virtualevent_addboat_view(request,id=0): return HttpResponseRedirect(url) else: - initial = { - 'age': calculate_age(r.birthdate), - 'weightcategory': r.weightcategory, - 'adaptiveclass': r.adaptiveclass, + if hasinitial: + initial = { + 'age': calculate_age(r.birthdate), + 'boattype':boattype, + 'boatclass':boatclass, + 'adaptiveclass':adaptiveclass, + 'weightclass':weightclass, + 'sex':sex, + 'entrycategory':initialcategory, } + else: + initial = { + 'age': calculate_age(r.birthdate), + 'weightcategory': r.weightcategory, + 'adaptiveclass': r.adaptiveclass, + } categories = None if race.coursestandards is not None: @@ -1774,6 +1786,7 @@ def virtualevent_register_view(request,id=0): raise Http404("Virtual Challenge does not exist") categories = None + hasinitial,boattype,boatclass,adaptiveclass,weightclass,sex,initialcategory = default_class(r,None,race) if race.coursestandards is not None: categories = CourseStandard.objects.filter( standardcollection=race.coursestandards).order_by("name") @@ -1937,11 +1950,22 @@ def virtualevent_register_view(request,id=0): return HttpResponseRedirect(url) else: - initial = { - 'age': calculate_age(r.birthdate), - 'weightcategory': r.weightcategory, - 'adaptiveclass': r.adaptiveclass, + if hasinitial: + initial = { + 'age': calculate_age(r.birthdate), + 'boattype':boattype, + 'boatclass':boatclass, + 'adaptiveclass':adaptiveclass, + 'weightclass':weightclass, + 'sex':sex, + 'entrycategory':initialcategory, } + else: + initial = { + 'age': calculate_age(r.birthdate), + 'weightcategory': r.weightcategory, + 'adaptiveclass': r.adaptiveclass, + } categories = None if race.coursestandards is not None: From 37f977a187fffb5a1adfa2ad27d31f1b6baef7dc Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Sun, 21 Jun 2020 16:27:41 +0200 Subject: [PATCH 3/3] seems to be complete now --- rowers/forms.py | 8 ++- rowers/plannedsessions.py | 81 +++++++++++++++++++++++------- rowers/templates/virtualevent.html | 3 ++ rowers/views/racesviews.py | 24 +++++++++ rowers/views/workoutviews.py | 16 +++--- 5 files changed, 106 insertions(+), 26 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index 694962b5..d3b23329 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -437,8 +437,12 @@ class UploadOptionsForm(forms.Form): else: registrations = IndoorVirtualRaceResult.objects.filter(race=therace,userid=r.id) - choices = [(r.id,str(r)) for r in registrations] - choices = [(0,'---')]+choices + 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: self.fields['submitrace'].choices = choices diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 93206cbe..92166a78 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1041,8 +1041,8 @@ def race_can_edit(r,race): return False def race_can_submit(r,race): - if r not in race.rower.all(): - return False + #if r not in race.rower.all(): + # return False start_time = race.start_time start_date = race.startdate @@ -1451,12 +1451,34 @@ def add_workout_indoorrace(ws,race,r,recordid=0,doregister=False): else: age = None - record = IndoorVirtualRaceResult.objects.get( - userid=r.id, - race=race, - id=recordid - ) - + try: + record = IndoorVirtualRaceResult.objects.get( + userid=r.id, + race=race, + id=recordid + ) + except IndoorVirtualRaceResult.DoesNotExist: + if doregister: + hasinitial,boattype,boatclass,adaptiveclass,weightclass,sex,initialcategory = default_class(r,ws[0],race) + if hasinitial: + record = IndoorVirtualRaceResult( + userid = r.id, + username = r.user.first_name+' '+r.user.last_name, + weightcategory=weightclass, + adaptiveclass=adaptiveclass, + race=race, + boatclass=boatclass, + sex=sex, + age = age, + entrycategory=initialcategory, + ) + record.save() + else: + errors.append("Unable to find a suitable start category") + return result,comments,errors,0 + else: + errors.append("Couldn't find this entry") + return result,comments,errors,0 records = IndoorVirtualRaceResult.objects.filter( userid=r.id, @@ -1466,11 +1488,8 @@ def add_workout_indoorrace(ws,race,r,recordid=0,doregister=False): - if not record and not doregister: - errors.append("Couldn't find this entry") - return result,comments,errors,0 - elif not record: - pass + + if race.sessionmode == 'distance': @@ -1584,11 +1603,35 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0,doregister=False): else: age = None - record = VirtualRaceResult.objects.get( - userid=r.id, - race=race, - id=recordid - ) + try: + record = VirtualRaceResult.objects.get( + userid=r.id, + race=race, + id=recordid + ) + except VirtualRaceResult.DoesNotExist: + if doregister: + hasinitial,boattype,boatclass,adaptiveclass,weightclass,sex,initialcategory = default_class(r,ws[0],race) + if hasinitial: + record = VirtualRaceResult( + userid = r.id, + username = r.user.first_name+' '+r.user.last_name, + weightcategory=weightclass, + adaptiveclass=adaptiveclass, + race=race, + boatclass=boatclass, + boattype=boattype, + sex=sex, + age = age, + entrycategory=initialcategory, + ) + record.save() + else: + errors.append("Unable to find a suitable start category") + return result,comments,errors,0 + else: + errors.append("Couldn't find this entry") + return result,comments,errors,0 records = VirtualRaceResult.objects.filter( userid=r.id, @@ -1656,6 +1699,8 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0,doregister=False): referencespeed=record.referencespeed,coursedistance=race.course.distance ) + comments.append('We are now checking adherence to the race course. This may take a few minutes to complete') + add_workouts_plannedsession(ws,race,r) diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 26d16084..6decfc0c 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -163,6 +163,7 @@ Registered users of rowsandall.com can participate in this challenge. Participation is free, unless specified differently in the race comment above. {% if race.sessiontype == 'race' %} + Register to let others know you plan to do this challenge:

Register

{% else %}

Register

@@ -183,6 +184,8 @@ {% for button in buttons %} {% if button == 'registerbutton' %}

+ Register to let others know you plan to do this challenge. This also give you the option to + select your entry category: {% if race.sessiontype == 'race' %}

Register

{% else %} diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index c2148ac0..93df6047 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -746,6 +746,7 @@ def virtualevent_disqualify_view(request,id=0,recordid=0): r = getrower(request.user) race = get_object_or_404(VirtualRace,pk=id) + raceid = race.id if race.sessiontype == 'race': @@ -2810,6 +2811,29 @@ def virtualevent_submit_result_view(request,id=0,workoutid=0): race=race ) + if records.count() == 0: + hasinitial,boattype,boatclass,adaptiveclass,weightclass,sex,initialcategory = default_class(r,None,race) + if not hasinitial: + messages.error(request,"Sorry, you have to register first") + url = reverse('virtualevent_view', + kwargs = { + 'id':id, + }) + return HttpResponseRedirect(url) + record = resultobj( + userid = r.id, + username = r.user.first_name+' '+r.user.last_name, + weightcategory=weightclass, + adaptiveclass=adaptiveclass, + race=race, + boatclass=boatclass, + sex=sex, + age=calculate_age(r.birthdate), + entrycategory=initialcategory, + ) + record.save() + records = [record] + entrychoices = [] diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 79b8f1ea..914064b0 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -5114,11 +5114,10 @@ def workout_upload_view(request, messages.error(request,message) if int(registrationid) < 0: - race = VirtualRace.Objects.get(id=-int(registrationid)) + race = VirtualRace.objects.get(id=-int(registrationid)) if race.sessiontype == 'race': - race = registrations[0].race result,comments,errors,jobid = add_workout_race( - [w], race,r, + [w], race,r,doregister=True, ) if result: messages.info( @@ -5130,9 +5129,8 @@ def workout_upload_view(request, for er in errors: messages.error(request,er) elif race.sessiontype == 'indoorrace': - race = registrations[0].race result,comments,errors,jobid = add_workout_indoorrace( - [w],race,r, + [w],race,r,doregister=True, ) if result: @@ -5200,11 +5198,17 @@ def workout_upload_view(request, - if landingpage != 'workout_upload_view': + if registrationid != 0: + url = reverse('virtualevent_view', + kwargs = { + 'id':race.id, + }) + elif landingpage != 'workout_upload_view': url = reverse(landingpage, kwargs = { 'id':encoder.encode_hex(w.id), }) + else: url = reverse(landingpage)