Private
Public Access
1
0

Merge branch 'release/v6.76'

This commit is contained in:
Sander Roosendaal
2018-06-01 15:17:07 +02:00
11 changed files with 347 additions and 92 deletions
+5 -1
View File
@@ -33,7 +33,7 @@ from rowers.models import (
)
from utils import geo_distance
from rowers.courseutils import coursetime_paths, coursetime_first
from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path
@@ -199,12 +199,16 @@ def get_time_course(ws,course):
rowdata = rowdata.resample('100ms',on='dt').mean()
rowdata = rowdata.interpolate()
# create path
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
paths = []
for polygon in polygons:
path = polygon_to_path(polygon)
paths.append(path)
(
coursetimeseconds,
coursemeters,
+5 -2
View File
@@ -10,7 +10,7 @@ class InvalidTrajectoryError(Exception):
def __str__(self):
return repr(self.value)
def time_in_path(df,p,maxmin='max'):
def time_in_path(df,p,maxmin='max',getall=False):
if df.empty:
return 0
@@ -29,7 +29,10 @@ def time_in_path(df,p,maxmin='max'):
if len(df[b==2]):
return df[b==2]['time'].min(),df[b==2]['cum_dist'].min()
if getall:
return df[b==2]['time'],df[b==2]['cum_dist']
else:
return df[b==2]['time'].min(),df[b==2]['cum_dist'].min()
raise InvalidTrajectoryError("Trajectory doesn't go through path")
+16 -10
View File
@@ -699,17 +699,17 @@ class WorkoutSessionSelectForm(forms.Form):
)
class WorkoutRaceSelectForm(forms.Form):
evaluate_after = forms.TimeField(
input_formats=['%H:%M:%S.%f',
'%H:%M:%S',
'%H:%M:%S',
'%M:%S.%f',
'%M:%S',
'%M'],
label = 'Only Evaluate After:',
required=False)
# evaluate_after = forms.TimeField(
# input_formats=['%H:%M:%S.%f',
# '%H:%M:%S',
# '%H:%M:%S',
# '%M:%S.%f',
# '%M:%S',
# '%M'],
# label = 'Only Evaluate After:',
# required=False)
def __init__(self, workoutdata, *args, **kwargs):
def __init__(self, workoutdata,entries, *args, **kwargs):
super(WorkoutRaceSelectForm, self).__init__(*args, **kwargs)
@@ -720,6 +720,12 @@ class WorkoutRaceSelectForm(forms.Form):
widget=forms.RadioSelect,
)
self.fields['record'] = forms.ChoiceField(
label = 'Entry',
choices = entries['choices'],
initial = entries['initial'],
)
# self.fields['evaluate_after'] =
class PlannedSessionTeamForm(forms.Form):
+20
View File
@@ -1587,6 +1587,19 @@ class VirtualRaceResult(models.Model):
age = models.IntegerField(null=True)
def __unicode__(self):
rr = Rower.objects.get(id=self.userid)
name = '{u1} {u2}'.format(
u1 = rr.user.first_name,
u2 = rr.user.last_name,
)
return u'Entry for {n} for "{r}" in {d}'.format(
n = name,
r = self.race,
d = self.boattype,
)
class CourseTestResult(models.Model):
userid = models.IntegerField(default=0)
workoutid = models.IntegerField(null=True)
@@ -1601,6 +1614,13 @@ class VirtualRaceResultForm(ModelForm):
fields = ['teamname','weightcategory','boattype','age']
def __init__(self, *args, **kwargs):
boattypes = kwargs.pop('boattypes',None)
super(VirtualRaceResultForm, self).__init__(*args, **kwargs)
if boattypes:
self.fields['boattype'].choices = boattypes
from rowers.metrics import rowingmetrics
strokedatafields = {
+83 -20
View File
@@ -630,7 +630,12 @@ def race_can_submit(r,race):
return False
def race_can_resubmit(r,race):
if r not in race.rower.all():
records = VirtualRaceResult.objects.filter(
userid=r.id,
race=race)
if not records:
return False
start_time = race.start_time
@@ -651,8 +656,44 @@ def race_can_resubmit(r,race):
return False
def race_can_adddiscipline(r,race):
records = VirtualRaceResult.objects.filter(
userid=r.id,
race=race)
if not records:
return False
start_time = race.start_time
start_date = race.startdate
startdatetime = datetime.combine(start_date,start_time)
startdatetime = pytz.timezone(race.timezone).localize(
startdatetime
)
evaluation_closure = race.evaluation_closure
if timezone.now() < evaluation_closure:
is_complete,has_registered = race_rower_status(r,race)
if has_registered:
return True
else:
return False
else:
return False
return False
def race_can_withdraw(r,race):
if r not in race.rower.all():
records = VirtualRaceResult.objects.filter(
userid=r.id,
race=race
)
if not records:
return False
start_time = race.start_time
@@ -674,7 +715,11 @@ def race_can_withdraw(r,race):
return True
def race_can_register(r,race):
if r in race.rower.all():
records = VirtualRaceResult.objects.filter(
userid=r.id,
race=race)
if records:
return False
start_time = race.start_time
@@ -699,20 +744,25 @@ def add_rower_race(r,race):
return 1
def remove_rower_race(r,race):
def remove_rower_race(r,race,recordid=None):
race.rower.remove(r)
records = VirtualRaceResult.objects.filter(userid=r.id,
workoutid__isnull=True,
race=race)
if recordid:
records = VirtualRaceResult.objects.filter(userid=r.id,
workoutid__isnull=True,
race=race,
id=recordid)
else:
records = VirtualRaceResult.objects.filter(userid=r.id,
workoutid__isnull=True,
race=race,)
for r in records:
r.delete()
return 1
# Low Level functions - to be called by higher level methods
def add_workout_race(ws,race,r,splitsecond=0):
def add_workout_race(ws,race,r,splitsecond=0,recordid=0):
result = 0
comments = []
errors = []
@@ -758,12 +808,21 @@ def add_workout_race(ws,race,r,splitsecond=0):
else:
age = None
records = VirtualRaceResult.objects.filter(
record = VirtualRaceResult.objects.get(
userid=r.id,
race=race
race=race,
id=recordid
)
record = records[0]
records = VirtualRaceResult.objects.filter(
userid=r.id,
race=race,
workoutid = ws[0].id
)
if not record:
errors.append("Couldn't find this entry")
return result,comments,errors,0
if ws[0].boattype != record.boattype:
errors.append('Your workout boat type did not match the boat type you registered')
@@ -774,17 +833,21 @@ def add_workout_race(ws,race,r,splitsecond=0):
return 0,comments, errors,0
# start adding sessions
for w in ws:
if w.startdatetime>=startdatetime and w.startdatetime<=enddatetime:
w.plannedsession = race
w.save()
result += 1
if ws[0].startdatetime>=startdatetime and ws[0].startdatetime<=enddatetime:
ws[0].plannedsession = race
ws[0].save()
result += 1
else:
errors.append('Workout %i did not match the race window' % w.id)
return result,comments,errors,0
else:
errors.append('Workout %i did not match the race window' % ws[0].id)
return result,comments,errors,0
if result>0:
for otherrecord in records:
print otherrecord
otherrecord.workoutid = None
otherrecord.coursecompleted = False
otherrecord.save()
job = myqueue(queue,handle_check_race_course,ws[0].csvfilename,
ws[0].id,race.course.id,record.id,splitsecond=splitsecond)
+49 -14
View File
@@ -70,7 +70,7 @@ siteurl = SITE_URL
# testing task
from rowers.emails import send_template_email
from rowers.courseutils import coursetime_paths, coursetime_first
from rowers.courseutils import coursetime_paths, coursetime_first, time_in_path
@app.task
def add(x, y):
@@ -276,21 +276,56 @@ def handle_check_race_course(self,
path = polygon_to_path(polygon,debug=debug)
paths.append(path)
(
coursetimeseconds,
coursemeters,
coursecompleted,
# check how many times went through start polygon
entrytimes,entrydistances = time_in_path(rowdata,paths[0],maxmin='max',getall=True)
) = coursetime_paths(rowdata,paths)
(
coursetimefirst,
coursemetersfirst,
firstcompleted
) = coursetime_first(
rowdata,paths)
cseconds = []
cmeters = []
ccomplete = []
for startt in entrytimes:
rowdata2 = rowdata[rowdata['time']>(startt-10.)]
(
coursetimeseconds,
coursemeters,
coursecompleted,
) = coursetime_paths(rowdata2,paths)
(
coursetimefirst,
coursemetersfirst,
firstcompleted
) = coursetime_first(
rowdata2,paths)
coursetimeseconds = coursetimeseconds-coursetimefirst
coursemeters = coursemeters-coursemetersfirst
cseconds.append(coursetimeseconds)
cmeters.append(coursemeters)
ccomplete.append(coursecompleted)
records = pd.DataFrame({
'coursetimeseconds':cseconds,
'coursecompleted': ccomplete,
'coursemeters': cmeters
})
records = records[records['coursecompleted'] == True]
if len(records):
coursecompleted = True
mintime = records['coursetimeseconds'].min()
coursetimeseconds = records[records['coursetimeseconds'] == mintime]['coursetimeseconds'].min()
coursemeters = records[records['coursetimeseconds'] == mintime]['coursemeters'].min()
else:
coursecompleted = False
coursetimeseconds = coursetimeseconds-coursetimefirst
coursemeters = coursemeters-coursemetersfirst
if coursecompleted:
query = 'UPDATE rowers_virtualraceresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid} WHERE id={recordid}'.format(
+1
View File
@@ -92,6 +92,7 @@ When the site is down, this is the appropriate channel to look for apologies, up
602 00 Brno<br />
Czech Republic<br />
IČ: 070 48 572<br />
DIČ: CZ 070 48 572<br />
Datová schránka: 7897syr<br />
Email: <a href="mailto:info@rowsandall.com">info@rowsandall.com</a><br />
The company is registered in the business register at the
-19
View File
@@ -27,7 +27,6 @@
<form id="race_submit_form"
method="post">
<div class="grid_12 alpha">
<div class="grid_6 alpha">
<p>Select one of the following workouts that you rowed within the race window</p>
<table width="100%">
<tr>
@@ -42,24 +41,6 @@
{% endfor %}
</tr>
</table>
</div>
<div class="grid_6 omega">
<p>The "Only Evaluate After" field allows you to tell the site to
discard the first N minutes fo the workout. This is useful if you
paddled through the start polygon as part of your warming up.
Fill out the
time at which you want to start the evaluation, or leave empty to
evaluate the entire workout. </p>
<p>Use any of the following formats:
<ul>
<li>H:MM:SS.d, e.g. 1:45:00.0 for one hour and 45 minutes</li>
<li>H:MM:SS, e.g. 1:45:00 for one hour and 45 minutes</li>
<li>MM:SS.d, e.g. 30:00.0 for thirty minutes</li>
<li>MM, e.g. 30 for thirty minutes</li>
</ul>
</p>
</div>
</div>
<div class="grid_2 prefix_2 suffix_8">
{% csrf_token %}
+8
View File
@@ -83,6 +83,9 @@
{% if button == 'withdrawbutton' %}
<a href="/rowers/virtualevent/{{ race.id }}/withdraw" class="button gray small grid_2">Withdraw</a>
{% endif %}
{% if button == 'adddisciplinebutton' %}
<a href="/rowers/virtualevent/{{ race.id }}/adddiscipline" class="button gray small grid_2">Register New Boat</a>
{% endif %}
{% if button == 'editbutton' %}
<a href="/rowers/virtualevent/{{ race.id }}/edit" class="button gray small grid_2">Edit Race</a>
{% endif %}
@@ -167,6 +170,11 @@
<td>{{ record.boattype }}</td>
<td>{{ record.age }}</td>
<td>{{ record.weightcategory }}</td>
{% if record.userid == rower.id %}
<td>
<a href="/rowers/virtualevent/{{ race.id }}/withdraw/{{ record.id }}" >Withdraw</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
+2
View File
@@ -149,6 +149,8 @@ urlpatterns = [
url(r'^virtualevent/(?P<id>\d+)$',views.virtualevent_view),
url(r'^virtualevent/(?P<id>\d+)/edit$',views.virtualevent_edit_view),
url(r'^virtualevent/(?P<id>\d+)/register$',views.virtualevent_register_view),
url(r'^virtualevent/(?P<id>\d+)/adddiscipline$',views.virtualevent_addboat_view),
url(r'^virtualevent/(?P<id>\d+)/withdraw/(?P<recordid>\d+)$',views.virtualevent_withdraw_view),
url(r'^virtualevent/(?P<id>\d+)/withdraw$',views.virtualevent_withdraw_view),
url(r'^virtualevent/(?P<id>\d+)/submit$',
views.virtualevent_submit_result_view),
+155 -23
View File
@@ -13440,6 +13440,9 @@ def virtualevent_view(request,id=0):
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
@@ -13485,7 +13488,7 @@ def virtualevent_view(request,id=0):
})
@login_required()
def virtualevent_withdraw_view(request,id=0):
def virtualevent_withdraw_view(request,id=0,recordid=None):
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
@@ -13493,7 +13496,7 @@ def virtualevent_withdraw_view(request,id=0):
raise Http404("Virtual Race does not exist")
if race_can_withdraw(r,race):
remove_rower_race(r,race)
remove_rower_race(r,race,recordid=recordid)
messages.info(request,
"You have successfully withdrawn from this race.")
else:
@@ -13506,6 +13509,106 @@ def virtualevent_withdraw_view(request,id=0):
return HttpResponseRedirect(url)
@login_required()
def virtualevent_addboat_view(request,id=0):
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
if not race_can_adddiscipline(r,race):
messages.error(request,"You cannot register for this race")
url = reverse(virtualevent_view,
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
records = VirtualRaceResult.objects.filter(
userid = r.id,
race = race
)
boattypes = [record.boattype for record in records]
allowedboats = tuple([ type for type in types.boattypes if type[0] not in boattypes] )
# we're still here
if request.method == 'POST':
# process form
form = VirtualRaceResultForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
teamname = cd['teamname']
boattype = cd['boattype']
weightcategory = cd['weightcategory']
age = cd['age']
if boattype == '1x' and r.birthdate:
age = calculate_age(r.birthdate)
if boattype in boattypes:
messages.error(request,"You have already registered in that boat type")
url = reverse(virtualevent_view,
kwargs = {
'id': race.id
}
)
return HttpResponseRedirect(url)
record = VirtualRaceResult(
userid=r.id,
teamname=teamname,
race=race,
username = u'{f} {l}'.format(
f = r.user.first_name,
l = r.user.last_name
),
weightcategory=weightcategory,
duration=datetime.time(0,0),
boattype=boattype,
coursecompleted=False,
sex=r.sex,
age=age
)
record.save()
add_rower_race(r,race)
messages.info(
request,
"You have successfully registered for this race. Good luck!"
)
url = reverse(virtualevent_view,
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
else:
initial = {
'age': calculate_age(r.birthdate),
'weightcategory': r.weightcategory,
}
form = VirtualRaceResultForm(initial=initial,boattypes=allowedboats)
return render(request,'virtualeventregister.html',
{
'form':form,
'race':race,
'rowerid':r.id,
})
@login_required()
def virtualevent_register_view(request,id=0):
r = getrower(request.user)
@@ -13672,15 +13775,27 @@ def virtualevent_create_view(request):
dotweet = False
else:
dotweet = True
sa = SiteAnnouncement(
announcement = "New Virtual Race on rowsandall.com: {name} on course {course}".format(
name = name,
course = course.name.encode('utf8')
try:
sa = SiteAnnouncement(
announcement = "New Virtual Race on rowsandall.com: {name} on course {course}".format(
name = name.encode('utf8'),
course = course.name.encode('utf8')
),
dotweet = dotweet
dotweet = dotweet
)
sa.save()
sa.save()
except UnicodeEncodeError:
sa = SiteAnnouncement(
announcement = "New Virtual Race on rowsandall.com: {name} on course {course}".format(
name = name,
course = str(course.name.encode('utf8','ignore'))
),
dotweet = dotweet
)
sa.save()
url = reverse(virtualevents_view)
return HttpResponseRedirect(url)
@@ -13775,6 +13890,21 @@ def virtualevent_submit_result_view(request,id=0):
can_submit = race_can_submit(r,race) or race_can_resubmit(r,race)
records = VirtualRaceResult.objects.filter(
userid = r.id,
race=race
)
entrychoices = []
for record in records:
rtpl = (record.id, record.__unicode__())
entrychoices.append(rtpl)
entries = {}
entries['choices'] = entrychoices
entries['initial'] = [records[0].id]
if not can_submit:
messages.error(request,'You cannot submit a result to this race')
url = reverse(virtualevent_view,
@@ -13808,18 +13938,20 @@ def virtualevent_submit_result_view(request,id=0):
workoutdata['choices'] = tuple(choices)
if request.method == 'POST':
w_form = WorkoutRaceSelectForm(workoutdata,request.POST)
w_form = WorkoutRaceSelectForm(workoutdata,entries,request.POST)
if w_form.is_valid():
selectedworkout = w_form.cleaned_data['workouts']
splittime = w_form.cleaned_data['evaluate_after']
if splittime is not None:
splitsecond = splittime.hour*3600
splitsecond += splittime.minute*60
splitsecond += splittime.second
splitsecond += splittime.microsecond/1.e6
else:
splitsecond = 0
splitsecond = 0
recordid = w_form.cleaned_data['record']
# splittime = w_form.cleaned_data['evaluate_after']
# if splittime is not None:
# splitsecond = splittime.hour*3600
# splitsecond += splittime.minute*60
# splitsecond += splittime.second
# splitsecond += splittime.microsecond/1.e6
# else:
# splitsecond = 0
else:
selectedworkout = None
@@ -13831,11 +13963,11 @@ def virtualevent_submit_result_view(request,id=0):
result,comments,errors,jobid = add_workout_race(
workouts,race,r,
splitsecond=splitsecond)
if result:
for w in ws:
remove_workout_plannedsession(w,race)
delete_race_result(w,race)
splitsecond=splitsecond,recordid=recordid)
# if result:
# for w in ws:
# remove_workout_plannedsession(w,race)
# delete_race_result(w,race)
for c in comments:
messages.info(request,c)
@@ -13859,7 +13991,7 @@ def virtualevent_submit_result_view(request,id=0):
return HttpResponseRedirect(url)
else:
w_form = WorkoutRaceSelectForm(workoutdata=workoutdata)
w_form = WorkoutRaceSelectForm(workoutdata,entries)
return render(request,'race_submit.html',
{