Private
Public Access
1
0

initial incomplete version

This commit is contained in:
Sander Roosendaal
2018-11-27 17:49:02 +01:00
parent f403d1bf16
commit 8162b2fc45
10 changed files with 815 additions and 52 deletions

View File

@@ -1664,6 +1664,7 @@ class PlannedSession(models.Model):
('cycletarget','Total for a time period'),
('coursetest','OTW test over a course'),
('race','Virtual Race'),
('indoorrace','Indoor Virtual Race'),
)
sessionmodechoices = (
@@ -1772,7 +1773,7 @@ class PlannedSession(models.Model):
else:
self.sessionunit = 'None'
if self.sessiontype == 'test':
if self.sessiontype == 'test' or self.sessiontype == 'indoorrace':
if self.sessionmode not in ['distance','time']:
if self.sessionvalue < 100:
self.sessionmode = 'time'
@@ -1937,6 +1938,125 @@ def get_course_timezone(course):
return timezone_str
class IndoorVirtualRaceForm(ModelForm):
registration_closure = forms.SplitDateTimeField(widget=AdminSplitDateTime(),required=False)
evaluation_closure = forms.SplitDateTimeField(widget=AdminSplitDateTime(),required=True)
timezone = forms.ChoiceField(initial='UTC',
choices=[(x,x) for x in pytz.common_timezones],
label='Time Zone')
class Meta:
model = VirtualRace
fields = [
'name',
'startdate',
'start_time',
'enddate',
'end_time',
'timezone',
'sessionvalue',
'sessionunit',
'registration_form',
'registration_closure',
'evaluation_closure',
'comment',
'contact_phone',
'contact_email',
]
dateTimeOptions = {
'format': 'yyyy-mm-dd',
'autoclose': True,
}
widgets = {
'comment': forms.Textarea,
'startdate': AdminDateWidget(),
'enddate': AdminDateWidget(),
'start_time': AdminTimeWidget(),
'end_time': AdminTimeWidget(),
'registration_closure':AdminSplitDateTime(),
'evaluation_closure':AdminSplitDateTime(),
}
def __init__(self,*args,**kwargs):
super(IndoorVirtualRaceForm, self).__init__(*args, **kwargs)
self.fields['sessionunit'].choices = [('min','minutes'),('m','meters')]
def clean(self):
cd = self.cleaned_data
timezone_str = cd['timezone']
start_time = cd['start_time']
if start_time is None:
raise forms.ValidationError(
'Must have start time',
code='missing_yparam1'
)
start_date = cd['startdate']
startdatetime = datetime.datetime.combine(start_date,start_time)
startdatetime = pytz.timezone(timezone_str).localize(
startdatetime
)
end_time = cd['end_time']
if end_time is None:
raise forms.ValidationError(
'Must have end time',
code='missing endtime'
)
end_date = cd['enddate']
enddatetime = datetime.datetime.combine(end_date,end_time)
enddatetime = pytz.timezone(timezone_str).localize(
enddatetime
)
registration_closure = cd['registration_closure']
registration_form = cd['registration_form']
try:
evaluation_closure = cd['evaluation_closure']
except KeyError:
evaluation_closure = enddatetime+datetime.timedelta(days=1)
cd['evaluation_closure'] = evaluation_closure
if registration_form == 'manual':
try:
registration_closure = pytz.timezone(
timezone_str
).localize(
registration_closure.replace(tzinfo=None)
)
except AttributeError:
registration_closure = startdatetime
elif registration_form == 'windowstart':
registration_closure = startdatetime
elif registration_form == 'windowend':
registration_closure = enddatetime
else:
registration_closure = evaluation_closure
if registration_closure <= timezone.now():
raise forms.ValidationError("Registration Closure cannot be in the past")
if startdatetime > enddatetime:
raise forms.ValidationError("The Start of the Race Window should be before the End of the Race Window")
if cd['evaluation_closure'] <= enddatetime:
raise forms.ValidationError("Evaluation closure deadline should be after the Race Window closes")
if cd['evaluation_closure'] <= timezone.now():
raise forms.ValidationError("Evaluation closure cannot be in the past")
return cd
class VirtualRaceForm(ModelForm):
course = forms.ModelChoiceField(queryset = GeoCourse.objects, empty_label=None)
@@ -2309,6 +2429,54 @@ class VirtualRaceResult(models.Model):
s = self.sex,
)
# Virtual Race results (for keeping results when workouts are deleted)
class IndoorVirtualRaceResult(models.Model):
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otetypes)
userid = models.IntegerField(default=0)
teamname = models.CharField(max_length=80,verbose_name = 'Team Name',
blank=True,null=True)
username = models.CharField(max_length=150)
workoutid = models.IntegerField(null=True)
weightcategory = models.CharField(default="hwt",max_length=10,
choices=weightcategories,
verbose_name='Weight Category')
race = models.ForeignKey(VirtualRace)
duration = models.TimeField(default=datetime.time(1,0))
distance = models.IntegerField(default=0)
boatclass = models.CharField(choices=boatclasses,
max_length=40,
default='rower',
verbose_name = 'Ergometer Class')
coursecompleted = models.BooleanField(default=False)
sex = models.CharField(default="not specified",
max_length=30,
choices=sexcategories,
verbose_name='Gender')
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,
)
if self.teamname:
return u'Entry for {n} for "{r}" in {c} with {t} ({s})'.format(
n = name,
r = self.race,
t = self.teamname,
c = self.boatclass,
s = self.sex,
)
else:
return u'Entry for {n} for "{r}" in {c} ({s})'.format(
n = name,
r = self.race,
c = self.boatclass,
s = self.sex,
)
class CourseTestResult(models.Model):
userid = models.IntegerField(default=0)
@@ -2318,6 +2486,16 @@ class CourseTestResult(models.Model):
distance = models.IntegerField(default=0)
coursecompleted = models.BooleanField(default=False)
class IndoorVirtualRaceResultForm(ModelForm):
class Meta:
model = IndoorVirtualRaceResult
fields = ['teamname','weightcategory','boatclass','age']
def __init__(self, *args, **kwargs):
super(IndoorVirtualRaceResultForm, self).__init__(*args, **kwargs)
class VirtualRaceResultForm(ModelForm):
class Meta:
model = VirtualRaceResult

View File

@@ -225,6 +225,12 @@ otwtypes = (
'churchboat'
)
otetypes = (
'rower',
'dynamic',
'slides'
)
rowtypes = (
'water',
'rower',

View File

@@ -20,7 +20,7 @@ from rowers.models import (
Rower, Workout,Team,
GeoCourse, TrainingMicroCycle,TrainingMesoCycle,TrainingMacroCycle,
TrainingPlan,PlannedSession,VirtualRaceResult,CourseTestResult,
get_course_timezone
get_course_timezone, IndoorVirtualRaceResult
)
from rowers.courses import get_time_course
@@ -574,6 +574,56 @@ def update_plannedsession(ps,cd):
return 1,'Planned Session Updated'
def update_indoorvirtualrace(ps,cd):
for attr, value in cd.items():
if attr == 'comment':
value.replace("\r\n", "&#10");
value.replace("\n", "&#10");
setattr(ps, attr, value)
timezone_str = cd['timezone']
# correct times
startdatetime = datetime.combine(cd['startdate'],cd['start_time'])
enddatetime = datetime.combine(cd['enddate'],cd['end_time'])
startdatetime = pytz.timezone(timezone_str).localize(
startdatetime
)
enddatetime = pytz.timezone(timezone_str).localize(
enddatetime
)
ps.evaluation_closure = pytz.timezone(timezone_str).localize(
ps.evaluation_closure.replace(tzinfo=None)
)
registration_form = cd['registration_form']
registration_closure = cd['registration_closure']
if registration_form == 'manual':
try:
registration_closure = pytz.timezone(
timezone_str
).localize(
registration_closure.replace(tzinfo=None)
)
except AttributeError:
registration_closure = startdatetime
elif registration_form == 'windowstart':
registration_closure = startdatetime
elif registration_form == 'windowend':
registration_closure = enddatetime
else:
registration_closure = ps.evaluation_closure
ps.registration_closure = registration_closure
ps.timezone = timezone_str
ps.save()
return 1,'Virtual Race Updated'
def update_virtualrace(ps,cd):
for attr, value in cd.items():
if attr == 'comment':
@@ -708,6 +758,10 @@ def race_can_resubmit(r,race):
return False
def race_can_adddiscipline(r,race):
if race.sessiontype != 'race':
return False
records = VirtualRaceResult.objects.filter(
userid=r.id,
race=race)
@@ -813,6 +867,116 @@ def remove_rower_race(r,race,recordid=None):
return 1
# Low Level functions - to be called by higher level methods
def add_workout_indoorrace(ws,race,r,recordid=0):
result = 0
comments = []
errors = []
start_time = race.start_time
start_date = race.startdate
startdatetime = datetime.combine(start_date,start_time)
startdatetime = pytz.timezone(race.timezone).localize(
startdatetime
)
end_time = race.end_time
end_date = race.enddate
enddatetime = datetime.combine(end_date,end_time)
enddatetime = pytz.timezone(race.timezone).localize(
enddatetime
)
# check if all sessions have same date
dates = [w.date for w in ws]
if (not all(d == dates[0] for d in dates)) and race.sessiontype not in ['challenge','cycletarget']:
errors.append('For tests and training sessions, selected workouts must all be done on the same date')
return result,comments,errors,0
if len(ws)>1 and race.sessiontype == 'test':
errors.append('For tests, you can only attach one workout')
return result,comments,errors,0
ids = [w.id for w in ws]
ids = list(set(ids))
if len(ids)>1 and race.sessiontype in ['test','coursetest','race','indoorrace']:
errors.append('For tests, you can only attach one workout')
return result,comments,errors,0
username = r.user.first_name+' '+r.user.last_name
if r.birthdate:
age = calculate_age(r.birthdate)
else:
age = None
record = IndoorVirtualRaceResult.objects.get(
userid=r.id,
race=race,
id=recordid
)
records = IndoorVirtualRaceResult.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 race.sessionmode == 'distance':
if ws[0].distance != race.sessionvalue:
errors.append('Your workout did not have the correct distance')
return 0,comments, errors, 0
else:
record.distance = ws[0].distance
record.duration = ws[0].duration
else:
t = ws[0].duration
seconds = t.second+t.minute*60.+t.hour*3600.+t.microsecond/1.e6
if seconds != race.sessionvalue*60.:
errors.append('Your workout did not have the correct duration')
return 0, comments, errors, 0
else:
record.distance = ws[0].distance
record.duration = ws[0].duration
if ws[0].weightcategory != record.weightcategory:
errors.append('Your workout weight category did not match the weight category you registered')
return 0,comments, errors,0
# start adding sessions
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' % ws[0].id)
return result,comments,errors,0
if result>0:
for otherrecord in records:
otherrecord.workoutid = None
otherrecord.coursecompleted = False
otherrecord.save()
record.coursecompleted = True
record.workoutid = ws[0].id
record.save()
add_workouts_plannedsession(ws,race,r)
return result,comments,errors,0
def add_workout_race(ws,race,r,splitsecond=0,recordid=0):
result = 0
comments = []
@@ -895,7 +1059,6 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0):
if result>0:
for otherrecord in records:
print otherrecord
otherrecord.workoutid = None
otherrecord.coursecompleted = False
otherrecord.save()

View File

@@ -0,0 +1,61 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}New Virtual Race{% endblock %}
{% block main %}
<h1>New Indoor Virtual Race</h1>
<ul class="main-content">
<li class="grid_4">
<p>With this form, you can create a new virtual race. After you submit
the form, the race is created and will be visible to all users. From
that moment, only the site admin can delete the race
(admin@rowsandall.com). You can still edit the race until
the start of the race window.
</p>
</li>
<li class="grid_3">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<p>
<table>
{{ form.as_table }}
</table>
</p>
<p>
{% csrf_token %}
<input type="submit" value="Save">
</p>
</form>
</li>
<li class="grid_1">
<p>
<ul>
<li>All times are local times in the time zone you select</li>
<li>Adding a contact phone number and email is not mandatory, but we
strongly recommend it.</li>
<li>If your event has a registration closure deadline, participants
have to enter (and can withdraw) before the registration closure time.</li>
<li>Participants can submit results until the evaluation closure time.</li>
</ul>
</p>
</li>
</ul>
{% endblock %}
{% block scripts %}
{% endblock %}
{% block sidebar %}
{% include 'menu_racing.html' %}
{% endblock %}

View File

@@ -10,6 +10,11 @@
<i class="far fa-flag fa-fw"></i>&nbsp;New Race
</a>
</li>
<li id="indoor-new">
<a href="/rowers/virtualevent/createindoor">
<i class="far fa-flag fa-fw"></i>&nbsp;New Indoor Race
</a>
</li>
<li id="courses">
<a href="/rowers/list-courses">
<i class="fas fa-map-marked fa-fw"></i>&nbsp;Courses

View File

@@ -8,7 +8,8 @@
<th>Event</th>
<th>Country</th>
<th>Course</th>
<th>Distance</th>
<th></th>
<th></th>
<th>Click for Details</th>
</tr>
</thead>
@@ -26,7 +27,8 @@
<td><a href="/rowers/virtualevent/{{ race.id }}">{{ race.name }}</a></td>
<td>{{ race.course.country }}</td>
<td><a href="/rowers/courses/{{ race.course.id }}">{{ race.course.name }}</a></td>
<td>{{ race.sessionvalue }} m</td>
<td>{{ race.sessionvalue }}</td>
<td>{{ race.sessionunit }}</td>
<td>
{% if rower %}
{% if race|can_register:rower %}

View File

@@ -14,6 +14,7 @@
<h1>{{ race.name }}</h1>
<ul class="main-content">
{% if race.sessiontype == 'race' %}
<li class="grid_2">
<p>
<h2>Course</h2>
@@ -24,6 +25,7 @@
{{ coursescript|safe }}
</div>
</li>
{% endif %}
<li class="grid_2">
<div id="raceinfo">
<p>
@@ -32,11 +34,23 @@
<p>
<table class="listtable shortpadded" width="100%">
<tbody>
{% if race.sessiontype == 'race' %}
<tr>
<th>Course</th><td>{{ race.course }}</td>
</tr>
{% else %}
<tr>
<th>Distance</th><td>{{ race.sessionvalue }} m</td>
<th>Indoor Race</th><td>To be rowed on a Concept2 ergometer</td>
</tr>
<tr>
<th>Time Zone</th><td>{{ race.timezone }}</td>
</tr>
{% endif %}
<tr>
<th>
{{ race.sessionmode }} challenge
</th><td>{{ race.sessionvalue }} {{ race.sessionunit }}
</td>
</tr>
<tr>
<th>Registration closure</th>
@@ -81,38 +95,42 @@
{% for button in buttons %}
{% if button == 'registerbutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/register"
class="blue button">Register</a>
{% if race.sessiontype == 'race' %}
<a href="/rowers/virtualevent/{{ race.id }}/register">Register</a>
{% else %}
<a href="/rowers/virtualevent/{{ race.id }}/registerindoor">Register</a>
{% endif %}
</p>
{% endif %}
{% if button == 'submitbutton' %}
<a href="/rowers/virtualevent/{{ race.id }}/submit" class="blue button">Submit Result</a>
<a href="/rowers/virtualevent/{{ race.id }}/submit">Submit Result</a>
{% endif %}
{% if button == 'resubmitbutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/submit"
class="blue button">Submit New Result</a>
<a href="/rowers/virtualevent/{{ race.id }}/submit">Submit New Result</a>
</p>
{% endif %}
{% if button == 'withdrawbutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/withdraw"
class="blue button">Withdraw</a>
<a href="/rowers/virtualevent/{{ race.id }}/withdraw">Withdraw</a>
</p>
{% endif %}
{% if button == 'adddisciplinebutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/adddiscipline"
class="blue button">
<a href="/rowers/virtualevent/{{ race.id }}/adddiscipline">
Register New Boat
</a>
</p>
{% endif %}
{% if button == 'editbutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/edit"
class="blue button">Edit Race
{% if race.sessiontype == 'race' %}
<a href="/rowers/virtualevent/{{ race.id }}/edit">Edit Race
</a>
{% else %}
<a href="/rowers/virtualevent/{{ race.id }}/editindoor">Edit Race
</a>
{% endif %}
</p>
{% endif %}
{% endfor %}
@@ -135,8 +153,10 @@
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
{% if race.sessiontype == 'race' %}
<th>Class</th>
<th>Boat</th>
{% endif %}
<th>Time</th>
<th>Distance</th>
<th>Details</th>
@@ -153,8 +173,10 @@
<td>{{ result.age }}</td>
<td>{{ result.sex }}</td>
<td>{{ result.weightcategory }}</td>
{% if race.sessiontype == 'race' %}
<td>{{ result.boatclass }}</td>
<td>{{ result.boattype }}</td>
{% endif %}
<td>{{ result.duration |durationprint:"%H:%M:%S.%f" }}</td>
<td>{{ result.distance }} m</td>
<td>
@@ -170,8 +192,10 @@
<td>{{ result.age }}</td>
<td>{{ result.sex }}</td>
<td>{{ result.weightcategory }}</td>
{% if race.sessiontype == 'race' %}
<td>{{ result.boatclass }}</td>
<td>{{ result.boattype }}</td>
{% endif %}
<td>DNS</td>
</tr>
{% endfor %}
@@ -210,8 +234,10 @@
<tr>
<th>Name</th>
<th>Team Name</th>
{% if race.sessiontype == 'race' %}
<th>Class</th>
<th>Boat</th>
{% endif %}
<th>Age</th>
<th>Gender</th>
<th>Weight Category</th>
@@ -221,8 +247,10 @@
<tr>
<td>{{ record.username }}
<td>{{ record.teamname }}</td>
{% if race.sessiontype == 'race' %}
<td>{{ record.boatclass }}</td>
<td>{{ record.boattype }}</td>
{% endif %}
<td>{{ record.age }}</td>
<td>{{ record.sex }}</td>
<td>{{ record.weightcategory }}</td>
@@ -247,6 +275,14 @@
Virtual races are intended as an informal way to add a
competitive element to training and as a quick way to set
up and manage small regattas.
</p>
<p>
On the water races are rowed on the course shown. You cannot submit results rowed
on other bodies of water.
</p>
<p>
Indoor races are open for all, wherever you live. However, be aware of the
time zone for the race window.
</p>
<p>
As a rowsandall.com user, you can
@@ -271,6 +307,10 @@
you delete the respective workout or remove your account.
By registering, you agree with this and the race rules.
</p>
<p>
If you use a manually added workout for your indoor race result,
please attach a screenshot of the ergometer display for verification.
</p>
<p>
Virtual Racing on rowsandall.com is honors based. Please be a good
sport, submit real results rowed by you, and make sure you set the

View File

@@ -32,7 +32,7 @@
</p>
<p>
{% csrf_token %}
<input class="button green" type="submit" value="Save">
<input type="submit" value="Save">
</p>
</form>
</li>

View File

@@ -143,9 +143,12 @@ urlpatterns = [
url(r'^list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.workouts_view),
url(r'^virtualevents$',views.virtualevents_view),
url(r'^virtualevent/create$',views.virtualevent_create_view),
url(r'^virtualevent/createindoor$',views.indoorvirtualevent_create_view),
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+)/editindoor$',views.indoorvirtualevent_edit_view),
url(r'^virtualevent/(?P<id>\d+)/register$',views.virtualevent_register_view),
url(r'^virtualevent/(?P<id>\d+)/registerindoor$',views.indoorvirtualevent_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),

View File

@@ -90,7 +90,9 @@ from rowers.models import (
WorkoutComment,WorkoutCommentForm,RowerExportForm,
CalcAgePerformance,PowerTimeFitnessMetric,PlannedSessionForm,
PlannedSessionFormSmall,GeoCourseEditForm,VirtualRace,
VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm
VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm,
IndoorVirtualRaceResultForm,IndoorVirtualRaceResult,
IndoorVirtualRaceForm,
)
from rowers.models import (
FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement,BasePlannedSessionFormSet,
@@ -15765,7 +15767,8 @@ def virtualevents_view(request):
if country == 'All':
countries = VirtualRace.objects.order_by('country').values_list('country').distinct()
else:
countries = [country]
countries = [country,
'Indoor']
if regattatype == 'upcoming':
races1 = VirtualRace.objects.filter(
@@ -15836,12 +15839,16 @@ def virtualevent_view(request,id=0):
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
script,div = course_map(race.course)
if race.sessiontype == 'race':
script,div = course_map(race.course)
resultobj = VirtualRaceResult
else:
script = ''
div = ''
resultobj = IndoorVirtualRaceResult
records = resultobj.objects.filter(race=race)
records = VirtualRaceResult.objects.filter(
race=race
)
buttons = []
@@ -15881,7 +15888,10 @@ def virtualevent_view(request,id=0):
try:
boatclass = cd['boatclass']
except KeyError:
boatclass = [t for t in mytypes.otwtypes]
if race.sessiontype == 'race':
boatclass = [t for t in mytypes.otwtypes]
else:
boatclass = [t for t in mytypes.otetypes]
age_min = cd['age_min']
age_max = cd['age_max']
@@ -15891,35 +15901,46 @@ def virtualevent_view(request,id=0):
except KeyError:
weightcategory = ['hwt','lwt']
results = VirtualRaceResult.objects.filter(
race=race,
workoutid__isnull=False,
boatclass__in=boatclass,
boattype__in=boattype,
sex__in=sex,
weightcategory__in=weightcategory,
age__gte=age_min,
age__lte=age_max
).order_by("duration")
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = VirtualRaceResult.objects.filter(
if race.sessiontype == 'race':
results = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
workoutid__isnull=False,
boatclass__in=boatclass,
boattype__in=boattype,
sex__in=sex,
weightcategory__in=weightcategory,
age__gte=age_min,
age__lte=age_max
).order_by("duration")
else:
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
boatclass__in=boatclass,
sex__in=sex,
weightcategory__in=weightcategory,
age__gte=age_min,
age__lte=age_max
).order_by("duration","-distance")
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
boatclass__in=boatclass,
sex__in=sex,
weightcategory__in=weightcategory,
age__gte=age_min,
age__lte=age_max
)
else:
results = VirtualRaceResult.objects.filter(
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
).order_by("duration")
).order_by("duration","-distance")
if results:
form = RaceResultFilterForm(records=records)
@@ -15929,7 +15950,7 @@ def virtualevent_view(request,id=0):
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = VirtualRaceResult.objects.filter(
dns = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
)
@@ -16190,6 +16211,221 @@ def virtualevent_register_view(request,id=0):
})
@login_required()
def indoorvirtualevent_register_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_register(r,race):
messages.error(request,"You cannot register for this race")
url = reverse(virtualevent_view,
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
# we're still here
if request.method == 'POST':
# process form
form = IndoorVirtualRaceResultForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
teamname = cd['teamname']
weightcategory = cd['weightcategory']
age = cd['age']
boatclass = cd['boatclass']
sex = r.sex
if r.birthdate:
age = calculate_age(r.birthdate)
sex = r.sex
if sex == 'not specified':
sex = 'male'
record = IndoorVirtualRaceResult(
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),
boatclass=boatclass,
coursecompleted=False,
sex=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 = IndoorVirtualRaceResultForm(initial=initial)
return render(request,'virtualeventregister.html',
{
'form':form,
'race':race,
'userid':r.user.id,
})
@login_required()
def indoorvirtualevent_create_view(request):
r = getrower(request.user)
if request.method == 'POST':
racecreateform = IndoorVirtualRaceForm(request.POST)
if racecreateform.is_valid():
cd = racecreateform.cleaned_data
startdate = cd['startdate']
start_time = cd['start_time']
enddate = cd['enddate']
end_time = cd['end_time']
comment = cd['comment']
sessionunit = cd['sessionunit']
sessionvalue = cd['sessionvalue']
name = cd['name']
registration_form = cd['registration_form']
registration_closure = cd['registration_closure']
evaluation_closure = cd['evaluation_closure']
contact_phone = cd['contact_phone']
contact_email = cd['contact_email']
# correct times
timezone_str = cd['timezone']
startdatetime = datetime.datetime.combine(startdate,start_time)
enddatetime = datetime.datetime.combine(enddate,end_time)
startdatetime = pytz.timezone(timezone_str).localize(
startdatetime
)
enddatetime = pytz.timezone(timezone_str).localize(
enddatetime
)
evaluation_closure = pytz.timezone(timezone_str).localize(
evaluation_closure.replace(tzinfo=None)
)
if registration_form == 'manual':
try:
registration_closure = pytz.timezone(
timezone_str
).localize(
registration_closure.replace(tzinfo=None)
)
except AttributeError:
registration_closure = startdatetime
elif registration_form == 'windowstart':
registration_closure = startdatetime
elif registration_form == 'windowend':
registration_closure = enddatetime
else:
registration_closure = evaluation_closure
if sessionunit == 'min':
sessionmode = 'time'
else:
sessionmode = 'distance'
vs = VirtualRace(
name=name,
startdate=startdate,
preferreddate = startdate,
start_time = start_time,
enddate=enddate,
end_time=end_time,
comment=comment,
sessiontype = 'indoorrace',
sessionunit = sessionunit,
sessionmode = sessionmode,
sessionvalue = sessionvalue,
course=None,
timezone=timezone_str,
evaluation_closure=evaluation_closure,
registration_closure=registration_closure,
contact_phone=contact_phone,
contact_email=contact_email,
country = 'Indoor',
manager=request.user,
)
vs.save()
# create Site Announcement & Tweet
if settings.DEBUG:
dotweet = False
elif 'dev' in settings.SITE_URL:
dotweet = False
else:
dotweet = True
try:
sa = SiteAnnouncement(
announcement = "New Virtual Indoor Race on rowsandall.com: {name}".format(
name = name.encode('utf8'),
),
dotweet = dotweet
)
sa.save()
except UnicodeEncodeError:
sa = SiteAnnouncement(
announcement = "New Virtual Indoor Race on rowsandall.com: {name}".format(
name = name,
),
dotweet = dotweet
)
sa.save()
url = reverse(virtualevents_view)
return HttpResponseRedirect(url)
else:
racecreateform = IndoorVirtualRaceForm()
return render(request,'indoorvirtualeventcreate.html',
{
'form':racecreateform,
'rower':r,
'active':'nav-racing',
})
@login_required()
def virtualevent_create_view(request):
r = getrower(request.user)
@@ -16369,6 +16605,64 @@ def virtualevent_edit_view(request,id=0):
})
@login_required()
def indoorvirtualevent_edit_view(request,id=0):
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
if race.manager != request.user:
raise PermissionDenied("Access denied")
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
start_time = race.start_time
start_date = race.startdate
startdatetime = datetime.datetime.combine(start_date,start_time)
startdatetime = pytz.timezone(race.timezone).localize(
startdatetime
)
if timezone.now() > startdatetime:
messages.error(request,"You cannot edit a race after the start of the race window")
url = reverse(virtualevent_view,
kwargs={
'id':race.id,
})
if request.method == 'POST':
racecreateform = IndoorVirtualRaceForm(request.POST,instance=race)
if racecreateform.is_valid():
cd = racecreateform.cleaned_data
res, message = update_indoorvirtualrace(race,cd)
if res:
messages.info(request,message)
else:
messages.error(request,message)
url = reverse(virtualevent_view,
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
else:
racecreateform = IndoorVirtualRaceForm(instance=race)
return render(request,'virtualeventedit.html',
{
'form':racecreateform,
'rower':r,
'race':race,
})
@login_required()
def virtualevent_submit_result_view(request,id=0):
@@ -16391,7 +16685,12 @@ 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(
if race.sessiontype == 'race':
resultobj = VirtualRaceResult
else:
resultobj = IndoorVirtualRaceResult
records = resultobj.objects.filter(
userid = r.id,
race=race
)
@@ -16462,10 +16761,16 @@ def virtualevent_submit_result_view(request,id=0):
workouts = Workout.objects.filter(id=selectedworkout)
result,comments,errors,jobid = add_workout_race(
workouts,race,r,
splitsecond=splitsecond,recordid=recordid)
# if result:
if race.sessiontype == 'race':
result,comments,errors,jobid = add_workout_race(
workouts,race,r,
splitsecond=splitsecond,recordid=recordid)
else:
result,comments,errors,jobid = add_workout_indoorrace(
workouts,race,r,recordid=recordid)
# if result:
# for w in ws:
# remove_workout_plannedsession(w,race)
# delete_race_result(w,race)