diff --git a/requirements.txt b/requirements.txt index d08e1fed..8aba5f9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -164,7 +164,7 @@ pytest-xdist==1.27.0 python-dateutil==2.8.0 python-memcached==1.59 python-twitter==3.5 -pytz==2018.9 +pytz==2020.1 pyviz-comms==0.7.1 pywin32-ctypes==0.2.0 pywinpty==0.5.5 @@ -173,9 +173,9 @@ pyzmq==18.0.1 qtconsole==4.4.3 ratelim==0.1.6 redis==3.2.1 -requests==2.21.0 +requests==2.23.0 requests-oauthlib==1.2.0 -rowingdata==2.8.4 +rowingdata==2.9.1 rowingphysics==0.5.0 rq==0.13.0 rules==2.1 diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 02df37f3..d8936ca3 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -381,6 +381,7 @@ def add_workouts_plannedsession(ws,ps,r): record.save() job = myqueue(queue,handle_check_race_course,w.csvfilename, w.id,ps.course.id,record.id, + w.user.user.email,w.user.user.first_name, mode='coursetest') else: errors.append('Workout %i did not match session dates' % w.id) @@ -659,6 +660,7 @@ def is_session_complete_ws(ws,ps): record.save() job = myqueue(queue,handle_check_race_course,ws[0].csvfilename, ws[0].id,ps.course.id,record.id, + ws[0].user.user.email,ws[0].user.user.first_name, mode='coursetest') return (0,'not done',None) @@ -1575,7 +1577,9 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): comments.append('Workouts submitted to virtual events have to be public. We have changed the workout to a public workout.') job = myqueue(queue,handle_check_race_course,ws[0].csvfilename, - ws[0].id,race.course.id,record.id,splitsecond=splitsecond, + ws[0].id,race.course.id,record.id, + ws[0].user.user.email,ws[0].user.user.first_name, + splitsecond=splitsecond, referencespeed=record.referencespeed,coursedistance=race.course.distance ) diff --git a/rowers/tasks.py b/rowers/tasks.py index fcd7bc62..2a5365fc 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -119,7 +119,11 @@ siteurl = SITE_URL # testing task from rowers.emails import send_template_email -from rowers.courseutils import coursetime_paths, coursetime_first, time_in_path +from rowers.courseutils import ( + coursetime_paths, coursetime_first, time_in_path, + InvalidTrajectoryError + ) + @app.task def add(x, y): @@ -342,7 +346,8 @@ def polygon_to_path(polygon,debug=True): @app.task(bind=True) def handle_check_race_course(self, f1,workoutid,courseid, - recordid,**kwargs): + recordid,useremail,userfirstname, + **kwargs): if 'debug' in kwargs: debug = kwargs['debug'] @@ -431,8 +436,19 @@ def handle_check_race_course(self, path = polygon_to_path(polygon,debug=debug) paths.append(path) + startsecond = 0 + endsecond = rowdata['time'].max() + # check how many times went through start polygon - entrytimes,entrydistances = time_in_path(rowdata,paths[0],maxmin='max',getall=True) + try: + entrytimes,entrydistances = time_in_path(rowdata,paths[0],maxmin='max',getall=True) + except InvalidTrajectoryError: + entrytimes = [] + entrydistances = [] + coursecompleted = False + coursemeters = 0 + coursetimeseconds = 0 + cseconds = [] cmeters = [] @@ -528,6 +544,39 @@ def handle_check_race_course(self, return 1 else: + query = 'UPDATE rowers_virtualraceresult SET coursecompleted = 0, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond}, points={points} WHERE id={recordid}'.format( + recordid=recordid, + duration=totaltime_sec_to_string(0), + distance=0, + points=0.0, + workoutid=workoutid, + startsecond=startsecond, + endsecond=endsecond, + ) + + if mode == 'coursetest': + query = 'UPDATE rowers_coursetestresult SET coursecompleted = 0, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond}, points={points} WHERE id={recordid}'.format( + recordid=recordid, + duration=totaltime_sec_to_string(0), + distance=0, + points=0, + workoutid=workoutid, + startsecond=startsecond, + endsecond=endsecond, + ) + + + with engine.connect() as conn, conn.begin(): + result = conn.execute(query) + + conn.close() + engine.dispose() + + # send email + handle_sendemail_coursefail( + useremail,userfirstname, + ) + return 2 return 0 @@ -1118,6 +1167,29 @@ def handle_sendemail_raceregistration( return 1 +def handle_sendemail_coursefail( + useremail, username, **kwargs): + + if 'debug' in kwargs: + debug = kwargs['debug'] + else: + debug = True + + subject = "The validation of your course has failed" + + from_email = 'Rowsandall ' + + d = { + 'username':username, + } + + res = send_template_email(from_email,[useremail], + subject, + 'trajectoryfailemail.html', + d,**kwargs) + + return 1 + @app.task def handle_sendemail_optout( useremail, username, registeredname, racename, raceid, **kwargs): diff --git a/rowers/templates/trajectoryfailemail.html b/rowers/templates/trajectoryfailemail.html new file mode 100644 index 00000000..3022682b --- /dev/null +++ b/rowers/templates/trajectoryfailemail.html @@ -0,0 +1,22 @@ +{% extends "emailbase.html" %} +{% block body %} +

Dear {{ username }},

+ +

+ Unfortunately, the course you took did not go through all gates for + the virtual challenge. + You can check your course versus the gates by clicking on Details + in your challenge result. + Of course, you can always submit a new row! +

+ +

+ If you feel that your course should have been valid, or in case + you have questions, please + contact me by reply to this email. +

+ +

+ Best Regards, the Rowsandall Team +

+{% endblock %} diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 90685498..26d16084 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -267,7 +267,7 @@

Results

{% endif %}

- {% if results or dns %} + {% if results or dns or dnf %}

@@ -287,7 +287,7 @@ {% endif %} {% endif %} - + {% if race.coursestandards %} {% endif %} @@ -349,11 +349,16 @@ {% endfor %} - {% for result in dns %} + {% for result in dnf %} + {% if race.coursestandards %} + + + + {% else %} @@ -368,6 +373,39 @@ {% if race.sessiontype == 'race' %} {% endif %} + {% endif %} + + + + {% endfor %} + {% for result in dns %} + + + + + {% if race.coursestandards %} + + + + {% else %} + + + + + + {% if race.sessiontype == 'race' %} + + {% endif %} + {% endif %} {% endfor %} diff --git a/rowers/templates/virtualeventranking.html b/rowers/templates/virtualeventranking.html index 42bb6299..9053c269 100644 --- a/rowers/templates/virtualeventranking.html +++ b/rowers/templates/virtualeventranking.html @@ -48,7 +48,7 @@

Results

{% endif %}

- {% if results or dns %} + {% if results or dns or dnf %}

TimeDistanceDistancePoints
  {{ result.username }} {{ result.teamname }}{{ result.entrycategory }}DNFDNF{{ result.age }} {{ result.sex }} {{ result.weightcategory }}{{ result.boattype }}DNF + + Details +
 {{ result.username }}{{ result.teamname }}{{ result.entrycategory }}DNSDNS{{ result.age }}{{ result.sex }}{{ result.weightcategory }} + {% if result.adaptiveclass == 'None' %} +   + {% else %} + {{ result.adaptiveclass }} + {% endif %} + {{ result.boatclass }}{{ result.boattype }}DNS
@@ -108,6 +108,32 @@ {% endfor %} + {% for result in dnf %} + + + + + + + + + + {% if race.sessiontype == 'race' %} + + {% endif %} + + + + {% endfor %} {% for result in dns %} diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index f596d83a..f30b51b9 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -1956,7 +1956,9 @@ def plannedsession_view(request,id=0,userid=0): record.save() job = myqueue(queue,handle_check_race_course, w.csvfilename,w.id,ps.course.id, - record.id,mode='coursetest') + record.id, + w.user.user.email,w.user.user.first_name, + mode='coursetest') intsecs = 0 microsecs = 0 diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 1f6f4a33..7d2e2dcf 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1072,6 +1072,12 @@ def virtualevent_view(request,id=0): workoutid__isnull=True, ) + dnf = resultobj.objects.filter( + race=race, + workoutid__isnull=False, + coursecompleted=False, + ) + if not request.user.is_anonymous: if race_can_register(r,race): @@ -1143,6 +1149,7 @@ def virtualevent_view(request,id=0): adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max, + coursecompleted=True, ).order_by("duration") else: results = resultobj.objects.filter( @@ -1154,6 +1161,7 @@ def virtualevent_view(request,id=0): adaptiveclass__in=adaptiveclass, age__gte=age_min, age__lte=age_max, + coursecompleted=True, ).order_by("duration","-distance") if entrycategory is not None: @@ -1179,6 +1187,8 @@ def virtualevent_view(request,id=0): coursecompleted=True, ).order_by("duration","-distance") + + if results: form = RaceResultFilterForm(records=records) else: @@ -1221,6 +1231,7 @@ def virtualevent_view(request,id=0): 'results':results, 'buttons':buttons, 'dns':dns, + 'dnf':dnf, 'records':records, 'racelogo':racelogo, 'form':form, @@ -1304,6 +1315,12 @@ def virtualevent_ranking_view(request,id=0): workoutid__isnull=True, ) + dnf = resultobj.objects.filter( + race=race, + workoutid__isnull=False, + coursecompleted=False, + ) + if not request.user.is_anonymous: if race_can_register(r,race): diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index a407d0e2..43bea2b4 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -1511,7 +1511,6 @@ def virtualevent_mapcompare_view(request,id=0): results = VirtualRaceResult.objects.filter( race=race, workoutid__isnull=False, - coursecompleted=True, ).order_by("distance","duration") workoutids = [result.workoutid for result in results]
 {{ result.username }}{{ result.teamname }}{{ result.age }}{{ result.sex }}{{ result.weightcategory }} + {% if result.adaptiveclass == 'None' %} +   + {% else %} + {{ result.adaptiveclass }} + {% endif %} + {{ result.boatclass }}{{ result.boattype }} + + Details + DNF