Merge branch 'release/v12.88'
This commit is contained in:
@@ -164,7 +164,7 @@ pytest-xdist==1.27.0
|
|||||||
python-dateutil==2.8.0
|
python-dateutil==2.8.0
|
||||||
python-memcached==1.59
|
python-memcached==1.59
|
||||||
python-twitter==3.5
|
python-twitter==3.5
|
||||||
pytz==2018.9
|
pytz==2020.1
|
||||||
pyviz-comms==0.7.1
|
pyviz-comms==0.7.1
|
||||||
pywin32-ctypes==0.2.0
|
pywin32-ctypes==0.2.0
|
||||||
pywinpty==0.5.5
|
pywinpty==0.5.5
|
||||||
@@ -173,9 +173,9 @@ pyzmq==18.0.1
|
|||||||
qtconsole==4.4.3
|
qtconsole==4.4.3
|
||||||
ratelim==0.1.6
|
ratelim==0.1.6
|
||||||
redis==3.2.1
|
redis==3.2.1
|
||||||
requests==2.21.0
|
requests==2.23.0
|
||||||
requests-oauthlib==1.2.0
|
requests-oauthlib==1.2.0
|
||||||
rowingdata==2.8.4
|
rowingdata==2.9.1
|
||||||
rowingphysics==0.5.0
|
rowingphysics==0.5.0
|
||||||
rq==0.13.0
|
rq==0.13.0
|
||||||
rules==2.1
|
rules==2.1
|
||||||
|
|||||||
@@ -381,6 +381,7 @@ def add_workouts_plannedsession(ws,ps,r):
|
|||||||
record.save()
|
record.save()
|
||||||
job = myqueue(queue,handle_check_race_course,w.csvfilename,
|
job = myqueue(queue,handle_check_race_course,w.csvfilename,
|
||||||
w.id,ps.course.id,record.id,
|
w.id,ps.course.id,record.id,
|
||||||
|
w.user.user.email,w.user.user.first_name,
|
||||||
mode='coursetest')
|
mode='coursetest')
|
||||||
else:
|
else:
|
||||||
errors.append('Workout %i did not match session dates' % w.id)
|
errors.append('Workout %i did not match session dates' % w.id)
|
||||||
@@ -659,6 +660,7 @@ def is_session_complete_ws(ws,ps):
|
|||||||
record.save()
|
record.save()
|
||||||
job = myqueue(queue,handle_check_race_course,ws[0].csvfilename,
|
job = myqueue(queue,handle_check_race_course,ws[0].csvfilename,
|
||||||
ws[0].id,ps.course.id,record.id,
|
ws[0].id,ps.course.id,record.id,
|
||||||
|
ws[0].user.user.email,ws[0].user.user.first_name,
|
||||||
mode='coursetest')
|
mode='coursetest')
|
||||||
|
|
||||||
return (0,'not done',None)
|
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.')
|
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,
|
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
|
referencespeed=record.referencespeed,coursedistance=race.course.distance
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,11 @@ siteurl = SITE_URL
|
|||||||
# testing task
|
# testing task
|
||||||
|
|
||||||
from rowers.emails import send_template_email
|
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
|
@app.task
|
||||||
def add(x, y):
|
def add(x, y):
|
||||||
@@ -342,7 +346,8 @@ def polygon_to_path(polygon,debug=True):
|
|||||||
@app.task(bind=True)
|
@app.task(bind=True)
|
||||||
def handle_check_race_course(self,
|
def handle_check_race_course(self,
|
||||||
f1,workoutid,courseid,
|
f1,workoutid,courseid,
|
||||||
recordid,**kwargs):
|
recordid,useremail,userfirstname,
|
||||||
|
**kwargs):
|
||||||
|
|
||||||
if 'debug' in kwargs:
|
if 'debug' in kwargs:
|
||||||
debug = kwargs['debug']
|
debug = kwargs['debug']
|
||||||
@@ -431,8 +436,19 @@ def handle_check_race_course(self,
|
|||||||
path = polygon_to_path(polygon,debug=debug)
|
path = polygon_to_path(polygon,debug=debug)
|
||||||
paths.append(path)
|
paths.append(path)
|
||||||
|
|
||||||
|
startsecond = 0
|
||||||
|
endsecond = rowdata['time'].max()
|
||||||
|
|
||||||
# check how many times went through start polygon
|
# 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 = []
|
cseconds = []
|
||||||
cmeters = []
|
cmeters = []
|
||||||
@@ -528,6 +544,39 @@ def handle_check_race_course(self,
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
else:
|
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 2
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
@@ -1118,6 +1167,29 @@ def handle_sendemail_raceregistration(
|
|||||||
|
|
||||||
return 1
|
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 <info@rowsandall.com>'
|
||||||
|
|
||||||
|
d = {
|
||||||
|
'username':username,
|
||||||
|
}
|
||||||
|
|
||||||
|
res = send_template_email(from_email,[useremail],
|
||||||
|
subject,
|
||||||
|
'trajectoryfailemail.html',
|
||||||
|
d,**kwargs)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def handle_sendemail_optout(
|
def handle_sendemail_optout(
|
||||||
useremail, username, registeredname, racename, raceid, **kwargs):
|
useremail, username, registeredname, racename, raceid, **kwargs):
|
||||||
|
|||||||
22
rowers/templates/trajectoryfailemail.html
Normal file
22
rowers/templates/trajectoryfailemail.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
{% extends "emailbase.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<p>Dear <strong>{{ username }}</strong>,</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
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!
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
If you feel that your course should have been valid, or in case
|
||||||
|
you have questions, please
|
||||||
|
contact me by reply to this email.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Best Regards, the Rowsandall Team
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
||||||
@@ -267,7 +267,7 @@
|
|||||||
<h2>Results</h2>
|
<h2>Results</h2>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% if results or dns %}
|
{% if results or dns or dnf %}
|
||||||
<p>
|
<p>
|
||||||
<table class="listtable shortpadded" width="100%">
|
<table class="listtable shortpadded" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -287,7 +287,7 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<th>Time<a href="?order_by=duration">▼</th>
|
<th>Time<a href="?order_by=duration">▼</th>
|
||||||
<th>Distance<a href="?order_by=-distance">▼</th>
|
<th>Distance<a href="?order_by=-distance">▼<a href="?order_by=distance">▲</th>
|
||||||
{% if race.coursestandards %}
|
{% if race.coursestandards %}
|
||||||
<th>Points<a href="?order_by=-points">▼</a></th>
|
<th>Points<a href="?order_by=-points">▼</a></th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -349,11 +349,16 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for result in dns %}
|
{% for result in dnf %}
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td>{{ result.username }}</td>
|
<td>{{ result.username }}</td>
|
||||||
<td>{{ result.teamname }}</td>
|
<td>{{ result.teamname }}</td>
|
||||||
|
{% if race.coursestandards %}
|
||||||
|
<td>{{ result.entrycategory }}</td>
|
||||||
|
<td>DNF</td>
|
||||||
|
<td>DNF</td>
|
||||||
|
{% else %}
|
||||||
<td>{{ result.age }}</td>
|
<td>{{ result.age }}</td>
|
||||||
<td>{{ result.sex }}</td>
|
<td>{{ result.sex }}</td>
|
||||||
<td>{{ result.weightcategory }}</td>
|
<td>{{ result.weightcategory }}</td>
|
||||||
@@ -368,6 +373,39 @@
|
|||||||
{% if race.sessiontype == 'race' %}
|
{% if race.sessiontype == 'race' %}
|
||||||
<td>{{ result.boattype }}</td>
|
<td>{{ result.boattype }}</td>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
|
<td>DNF</td>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/{{ result.workoutid|encode }}/view/entry/{{ result.id }}/">
|
||||||
|
Details</a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% for result in dns %}
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td>{{ result.username }}</td>
|
||||||
|
<td>{{ result.teamname }}</td>
|
||||||
|
{% if race.coursestandards %}
|
||||||
|
<td>{{ result.entrycategory }}</td>
|
||||||
|
<td>DNS</td>
|
||||||
|
<td>DNS</td>
|
||||||
|
{% else %}
|
||||||
|
<td>{{ result.age }}</td>
|
||||||
|
<td>{{ result.sex }}</td>
|
||||||
|
<td>{{ result.weightcategory }}</td>
|
||||||
|
<td>
|
||||||
|
{% if result.adaptiveclass == 'None' %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
{{ result.adaptiveclass }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ result.boatclass }}</td>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
|
<td>{{ result.boattype }}</td>
|
||||||
|
{% endif %}
|
||||||
|
{% endif %}
|
||||||
<td>DNS</td>
|
<td>DNS</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
<h2>Results</h2>
|
<h2>Results</h2>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% if results or dns %}
|
{% if results or dns or dnf %}
|
||||||
<p>
|
<p>
|
||||||
<table class="listtable shortpadded" width="100%">
|
<table class="listtable shortpadded" width="100%">
|
||||||
<thead>
|
<thead>
|
||||||
@@ -108,6 +108,32 @@
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% for result in dnf %}
|
||||||
|
<tr>
|
||||||
|
<td> </td>
|
||||||
|
<td>{{ result.username }}</td>
|
||||||
|
<td>{{ result.teamname }}</td>
|
||||||
|
<td>{{ result.age }}</td>
|
||||||
|
<td>{{ result.sex }}</td>
|
||||||
|
<td>{{ result.weightcategory }}</td>
|
||||||
|
<td>
|
||||||
|
{% if result.adaptiveclass == 'None' %}
|
||||||
|
|
||||||
|
{% else %}
|
||||||
|
{{ result.adaptiveclass }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ result.boatclass }}</td>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
|
<td>{{ result.boattype }}</td>
|
||||||
|
{% endif %}
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/{{ result.workoutid|encode }}/view/entry/{{ result.id }}/">
|
||||||
|
Details</a>
|
||||||
|
</td>
|
||||||
|
<td>DNF</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
{% for result in dns %}
|
{% for result in dns %}
|
||||||
<tr>
|
<tr>
|
||||||
<td> </td>
|
<td> </td>
|
||||||
|
|||||||
@@ -1956,7 +1956,9 @@ def plannedsession_view(request,id=0,userid=0):
|
|||||||
record.save()
|
record.save()
|
||||||
job = myqueue(queue,handle_check_race_course,
|
job = myqueue(queue,handle_check_race_course,
|
||||||
w.csvfilename,w.id,ps.course.id,
|
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
|
intsecs = 0
|
||||||
microsecs = 0
|
microsecs = 0
|
||||||
|
|||||||
@@ -1072,6 +1072,12 @@ def virtualevent_view(request,id=0):
|
|||||||
workoutid__isnull=True,
|
workoutid__isnull=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dnf = resultobj.objects.filter(
|
||||||
|
race=race,
|
||||||
|
workoutid__isnull=False,
|
||||||
|
coursecompleted=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if not request.user.is_anonymous:
|
if not request.user.is_anonymous:
|
||||||
if race_can_register(r,race):
|
if race_can_register(r,race):
|
||||||
@@ -1143,6 +1149,7 @@ def virtualevent_view(request,id=0):
|
|||||||
adaptiveclass__in=adaptiveclass,
|
adaptiveclass__in=adaptiveclass,
|
||||||
age__gte=age_min,
|
age__gte=age_min,
|
||||||
age__lte=age_max,
|
age__lte=age_max,
|
||||||
|
coursecompleted=True,
|
||||||
).order_by("duration")
|
).order_by("duration")
|
||||||
else:
|
else:
|
||||||
results = resultobj.objects.filter(
|
results = resultobj.objects.filter(
|
||||||
@@ -1154,6 +1161,7 @@ def virtualevent_view(request,id=0):
|
|||||||
adaptiveclass__in=adaptiveclass,
|
adaptiveclass__in=adaptiveclass,
|
||||||
age__gte=age_min,
|
age__gte=age_min,
|
||||||
age__lte=age_max,
|
age__lte=age_max,
|
||||||
|
coursecompleted=True,
|
||||||
).order_by("duration","-distance")
|
).order_by("duration","-distance")
|
||||||
|
|
||||||
if entrycategory is not None:
|
if entrycategory is not None:
|
||||||
@@ -1179,6 +1187,8 @@ def virtualevent_view(request,id=0):
|
|||||||
coursecompleted=True,
|
coursecompleted=True,
|
||||||
).order_by("duration","-distance")
|
).order_by("duration","-distance")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if results:
|
if results:
|
||||||
form = RaceResultFilterForm(records=records)
|
form = RaceResultFilterForm(records=records)
|
||||||
else:
|
else:
|
||||||
@@ -1221,6 +1231,7 @@ def virtualevent_view(request,id=0):
|
|||||||
'results':results,
|
'results':results,
|
||||||
'buttons':buttons,
|
'buttons':buttons,
|
||||||
'dns':dns,
|
'dns':dns,
|
||||||
|
'dnf':dnf,
|
||||||
'records':records,
|
'records':records,
|
||||||
'racelogo':racelogo,
|
'racelogo':racelogo,
|
||||||
'form':form,
|
'form':form,
|
||||||
@@ -1304,6 +1315,12 @@ def virtualevent_ranking_view(request,id=0):
|
|||||||
workoutid__isnull=True,
|
workoutid__isnull=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
dnf = resultobj.objects.filter(
|
||||||
|
race=race,
|
||||||
|
workoutid__isnull=False,
|
||||||
|
coursecompleted=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
if not request.user.is_anonymous:
|
if not request.user.is_anonymous:
|
||||||
if race_can_register(r,race):
|
if race_can_register(r,race):
|
||||||
|
|||||||
@@ -1511,7 +1511,6 @@ def virtualevent_mapcompare_view(request,id=0):
|
|||||||
results = VirtualRaceResult.objects.filter(
|
results = VirtualRaceResult.objects.filter(
|
||||||
race=race,
|
race=race,
|
||||||
workoutid__isnull=False,
|
workoutid__isnull=False,
|
||||||
coursecompleted=True,
|
|
||||||
).order_by("distance","duration")
|
).order_by("distance","duration")
|
||||||
|
|
||||||
workoutids = [result.workoutid for result in results]
|
workoutids = [result.workoutid for result in results]
|
||||||
|
|||||||
Reference in New Issue
Block a user