Merge branch 'feature/indoor' into develop
This commit is contained in:
@@ -45,6 +45,8 @@ env = Environment(loader = FileSystemLoader(["rowers/templates"]))
|
|||||||
|
|
||||||
from django.contrib.staticfiles import finders
|
from django.contrib.staticfiles import finders
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def textify(html):
|
def textify(html):
|
||||||
# Remove html tags and continuous whitespaces
|
# Remove html tags and continuous whitespaces
|
||||||
text_only = re.sub('[ \t]+', ' ', strip_tags(html))
|
text_only = re.sub('[ \t]+', ' ', strip_tags(html))
|
||||||
|
|||||||
@@ -30,6 +30,24 @@ class EmailForm(forms.Form):
|
|||||||
botcheck = forms.CharField(max_length=5)
|
botcheck = forms.CharField(max_length=5)
|
||||||
message = forms.CharField()
|
message = forms.CharField()
|
||||||
|
|
||||||
|
disqualificationreasons = (
|
||||||
|
('noimage','You did not attach a monitor screenshot or other photographic evidence as required'),
|
||||||
|
('suspicious','We doubt that you rowed this in the right boat class or type'),
|
||||||
|
('duplicate','This result looks like a duplicate entry'),
|
||||||
|
('other','Other Reason'),
|
||||||
|
)
|
||||||
|
|
||||||
|
disqualifiers = {}
|
||||||
|
for key, value in disqualificationreasons:
|
||||||
|
disqualifiers[key] = value
|
||||||
|
|
||||||
|
class DisqualificationForm(forms.Form):
|
||||||
|
|
||||||
|
reason = forms.ChoiceField(required=True,
|
||||||
|
choices=disqualificationreasons,
|
||||||
|
widget = forms.RadioSelect,)
|
||||||
|
|
||||||
|
message = forms.CharField(required=True,widget=forms.Textarea)
|
||||||
|
|
||||||
class MetricsForm(forms.Form):
|
class MetricsForm(forms.Form):
|
||||||
avghr = forms.IntegerField(required=False,label='Average Heart Rate')
|
avghr = forms.IntegerField(required=False,label='Average Heart Rate')
|
||||||
@@ -892,8 +910,11 @@ class RaceResultFilterForm(forms.Form):
|
|||||||
self.fields['boatclass'].choices = boatclasschoices
|
self.fields['boatclass'].choices = boatclasschoices
|
||||||
|
|
||||||
# boattype
|
# boattype
|
||||||
|
try:
|
||||||
theboattypees = [record.boattype for record in records]
|
theboattypees = [record.boattype for record in records]
|
||||||
theboattypees = list(set(theboattypees))
|
theboattypees = list(set(theboattypees))
|
||||||
|
except AttributeError:
|
||||||
|
theboattypees = []
|
||||||
|
|
||||||
if len(theboattypees)<= 1:
|
if len(theboattypees)<= 1:
|
||||||
del self.fields['boattype']
|
del self.fields['boattype']
|
||||||
|
|||||||
+179
-1
@@ -1664,6 +1664,7 @@ class PlannedSession(models.Model):
|
|||||||
('cycletarget','Total for a time period'),
|
('cycletarget','Total for a time period'),
|
||||||
('coursetest','OTW test over a course'),
|
('coursetest','OTW test over a course'),
|
||||||
('race','Virtual Race'),
|
('race','Virtual Race'),
|
||||||
|
('indoorrace','Indoor Virtual Race'),
|
||||||
)
|
)
|
||||||
|
|
||||||
sessionmodechoices = (
|
sessionmodechoices = (
|
||||||
@@ -1772,7 +1773,7 @@ class PlannedSession(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.sessionunit = 'None'
|
self.sessionunit = 'None'
|
||||||
|
|
||||||
if self.sessiontype == 'test':
|
if self.sessiontype == 'test' or self.sessiontype == 'indoorrace':
|
||||||
if self.sessionmode not in ['distance','time']:
|
if self.sessionmode not in ['distance','time']:
|
||||||
if self.sessionvalue < 100:
|
if self.sessionvalue < 100:
|
||||||
self.sessionmode = 'time'
|
self.sessionmode = 'time'
|
||||||
@@ -1937,6 +1938,125 @@ def get_course_timezone(course):
|
|||||||
|
|
||||||
return timezone_str
|
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):
|
class VirtualRaceForm(ModelForm):
|
||||||
course = forms.ModelChoiceField(queryset = GeoCourse.objects, empty_label=None)
|
course = forms.ModelChoiceField(queryset = GeoCourse.objects, empty_label=None)
|
||||||
@@ -2309,6 +2429,54 @@ class VirtualRaceResult(models.Model):
|
|||||||
s = self.sex,
|
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}" on {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}" on {c} ({s})'.format(
|
||||||
|
n = name,
|
||||||
|
r = self.race,
|
||||||
|
c = self.boatclass,
|
||||||
|
s = self.sex,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CourseTestResult(models.Model):
|
class CourseTestResult(models.Model):
|
||||||
userid = models.IntegerField(default=0)
|
userid = models.IntegerField(default=0)
|
||||||
@@ -2318,6 +2486,16 @@ class CourseTestResult(models.Model):
|
|||||||
distance = models.IntegerField(default=0)
|
distance = models.IntegerField(default=0)
|
||||||
coursecompleted = models.BooleanField(default=False)
|
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 VirtualRaceResultForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualRaceResult
|
model = VirtualRaceResult
|
||||||
|
|||||||
@@ -225,6 +225,12 @@ otwtypes = (
|
|||||||
'churchboat'
|
'churchboat'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
otetypes = (
|
||||||
|
'rower',
|
||||||
|
'dynamic',
|
||||||
|
'slides'
|
||||||
|
)
|
||||||
|
|
||||||
rowtypes = (
|
rowtypes = (
|
||||||
'water',
|
'water',
|
||||||
'rower',
|
'rower',
|
||||||
|
|||||||
+184
-6
@@ -20,7 +20,7 @@ from rowers.models import (
|
|||||||
Rower, Workout,Team,
|
Rower, Workout,Team,
|
||||||
GeoCourse, TrainingMicroCycle,TrainingMesoCycle,TrainingMacroCycle,
|
GeoCourse, TrainingMicroCycle,TrainingMesoCycle,TrainingMacroCycle,
|
||||||
TrainingPlan,PlannedSession,VirtualRaceResult,CourseTestResult,
|
TrainingPlan,PlannedSession,VirtualRaceResult,CourseTestResult,
|
||||||
get_course_timezone
|
get_course_timezone, IndoorVirtualRaceResult
|
||||||
)
|
)
|
||||||
|
|
||||||
from rowers.courses import get_time_course
|
from rowers.courses import get_time_course
|
||||||
@@ -574,6 +574,56 @@ def update_plannedsession(ps,cd):
|
|||||||
|
|
||||||
return 1,'Planned Session Updated'
|
return 1,'Planned Session Updated'
|
||||||
|
|
||||||
|
def update_indoorvirtualrace(ps,cd):
|
||||||
|
for attr, value in cd.items():
|
||||||
|
if attr == 'comment':
|
||||||
|
value.replace("\r\n", "
");
|
||||||
|
value.replace("\n", "
");
|
||||||
|
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):
|
def update_virtualrace(ps,cd):
|
||||||
for attr, value in cd.items():
|
for attr, value in cd.items():
|
||||||
if attr == 'comment':
|
if attr == 'comment':
|
||||||
@@ -631,7 +681,12 @@ def race_rower_status(r,race):
|
|||||||
has_registered = False
|
has_registered = False
|
||||||
is_complete = False
|
is_complete = False
|
||||||
|
|
||||||
vs = VirtualRaceResult.objects.filter(userid=r.id,race=race)
|
if race.sessiontype == 'race':
|
||||||
|
resultobj = VirtualRaceResult
|
||||||
|
else:
|
||||||
|
resultobj = IndoorVirtualRaceResult
|
||||||
|
|
||||||
|
vs = IndoorVirtualRaceResult.objects.filter(userid=r.id,race=race)
|
||||||
if vs:
|
if vs:
|
||||||
has_registered = True
|
has_registered = True
|
||||||
is_complete = vs[0].coursecompleted
|
is_complete = vs[0].coursecompleted
|
||||||
@@ -708,6 +763,10 @@ def race_can_resubmit(r,race):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def race_can_adddiscipline(r,race):
|
def race_can_adddiscipline(r,race):
|
||||||
|
|
||||||
|
if race.sessiontype != 'race':
|
||||||
|
return False
|
||||||
|
|
||||||
records = VirtualRaceResult.objects.filter(
|
records = VirtualRaceResult.objects.filter(
|
||||||
userid=r.id,
|
userid=r.id,
|
||||||
race=race)
|
race=race)
|
||||||
@@ -766,7 +825,12 @@ def race_can_withdraw(r,race):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
def race_can_register(r,race):
|
def race_can_register(r,race):
|
||||||
records = VirtualRaceResult.objects.filter(
|
if race.sessiontype == 'race':
|
||||||
|
recordobj = VirtualRaceResult
|
||||||
|
else:
|
||||||
|
recordobj = IndoorVirtualRaceResult
|
||||||
|
|
||||||
|
records = recordobj.objects.filter(
|
||||||
userid=r.id,
|
userid=r.id,
|
||||||
race=race)
|
race=race)
|
||||||
|
|
||||||
@@ -798,13 +862,18 @@ def add_rower_race(r,race):
|
|||||||
def remove_rower_race(r,race,recordid=None):
|
def remove_rower_race(r,race,recordid=None):
|
||||||
race.rower.remove(r)
|
race.rower.remove(r)
|
||||||
|
|
||||||
|
if race.sessiontype == 'race':
|
||||||
|
recordobj = VirtualRaceResult
|
||||||
|
else:
|
||||||
|
recordobj = IndoorVirtualRaceResult
|
||||||
|
|
||||||
if recordid:
|
if recordid:
|
||||||
records = VirtualRaceResult.objects.filter(userid=r.id,
|
records = recordobj.objects.filter(userid=r.id,
|
||||||
workoutid__isnull=True,
|
workoutid__isnull=True,
|
||||||
race=race,
|
race=race,
|
||||||
id=recordid)
|
id=recordid)
|
||||||
else:
|
else:
|
||||||
records = VirtualRaceResult.objects.filter(userid=r.id,
|
records = recordobj.objects.filter(userid=r.id,
|
||||||
workoutid__isnull=True,
|
workoutid__isnull=True,
|
||||||
race=race,)
|
race=race,)
|
||||||
for r in records:
|
for r in records:
|
||||||
@@ -813,6 +882,116 @@ def remove_rower_race(r,race,recordid=None):
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
# Low Level functions - to be called by higher level methods
|
# 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):
|
def add_workout_race(ws,race,r,splitsecond=0,recordid=0):
|
||||||
result = 0
|
result = 0
|
||||||
comments = []
|
comments = []
|
||||||
@@ -895,7 +1074,6 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0):
|
|||||||
|
|
||||||
if result>0:
|
if result>0:
|
||||||
for otherrecord in records:
|
for otherrecord in records:
|
||||||
print otherrecord
|
|
||||||
otherrecord.workoutid = None
|
otherrecord.workoutid = None
|
||||||
otherrecord.coursecompleted = False
|
otherrecord.coursecompleted = False
|
||||||
otherrecord.save()
|
otherrecord.save()
|
||||||
|
|||||||
@@ -41,6 +41,22 @@ from django.utils.html import strip_tags
|
|||||||
|
|
||||||
from utils import deserialize_list,ewmovingaverage,wavg
|
from utils import deserialize_list,ewmovingaverage,wavg
|
||||||
|
|
||||||
|
from HTMLParser import HTMLParser
|
||||||
|
class MLStripper(HTMLParser):
|
||||||
|
def __init__(self):
|
||||||
|
self.reset()
|
||||||
|
self.fed = []
|
||||||
|
def handle_data(self, d):
|
||||||
|
self.fed.append(d)
|
||||||
|
def get_data(self):
|
||||||
|
return ''.join(self.fed)
|
||||||
|
|
||||||
|
def strip_tags(html):
|
||||||
|
s = MLStripper()
|
||||||
|
s.feed(html)
|
||||||
|
return s.get_data()
|
||||||
|
|
||||||
|
|
||||||
from rowers.dataprepnodjango import (
|
from rowers.dataprepnodjango import (
|
||||||
update_strokedata, new_workout_from_file,
|
update_strokedata, new_workout_from_file,
|
||||||
getsmallrowdata_db, updatecpdata_sql,
|
getsmallrowdata_db, updatecpdata_sql,
|
||||||
@@ -721,6 +737,35 @@ def handle_updatedps(useremail, workoutids, debug=False,**kwargs):
|
|||||||
|
|
||||||
# send email when a breakthrough workout is uploaded
|
# send email when a breakthrough workout is uploaded
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def handle_send_disqualification_email(
|
||||||
|
useremail,username,reason,message, racename, **kwargs):
|
||||||
|
|
||||||
|
if 'debug' in kwargs:
|
||||||
|
debug = kwargs['debug']
|
||||||
|
else:
|
||||||
|
debug = True
|
||||||
|
|
||||||
|
subject = "Your result for {n} has been disqualified on rowsandall.com".format(
|
||||||
|
n = racename
|
||||||
|
)
|
||||||
|
|
||||||
|
from_email = 'Rowsandall <support@rowsandall.com>'
|
||||||
|
|
||||||
|
d = {
|
||||||
|
'username':username,
|
||||||
|
'reason':reason,
|
||||||
|
'message': strip_tags(message),
|
||||||
|
'racename':racename,
|
||||||
|
}
|
||||||
|
|
||||||
|
res = send_template_email(from_email,[useremail],
|
||||||
|
subject,
|
||||||
|
'disqualificationemail.html',
|
||||||
|
d,**kwargs)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def handle_sendemail_expired(useremail,userfirstname,userlastname,expireddate,
|
def handle_sendemail_expired(useremail,userfirstname,userlastname,expireddate,
|
||||||
**kwargs):
|
**kwargs):
|
||||||
|
|||||||
@@ -0,0 +1,138 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% block scripts %}
|
||||||
|
{% include "monitorjobs.html" %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block title %}{{ workout.name }} {% endblock %}
|
||||||
|
{% block og_title %}{{ workout.name }} {% endblock %}
|
||||||
|
{% block description %}{{ workout.name }}
|
||||||
|
{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %}
|
||||||
|
{% block og_description %}{{ workout.name }}
|
||||||
|
{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %}
|
||||||
|
{% if graphs1 %}
|
||||||
|
{% endif %}
|
||||||
|
{% for graph in graphs1 %}
|
||||||
|
{% block og_image %}
|
||||||
|
{% if graphs1 %}
|
||||||
|
{% for graph in graphs %}
|
||||||
|
<meta property="og:image" content="http://rowsandall.com/{{ graph.filename |spacetohtml }}" />
|
||||||
|
<meta property="og:image:secure_url" content="https://rowsandall.com/{{ graph.filename |spacetohtml }}" />
|
||||||
|
<meta property="og:image:width" content="{{ graph.width }}" />
|
||||||
|
<meta property="og:image:height" content="{{ graph.height }}" />
|
||||||
|
{% endfor %}
|
||||||
|
{% else %}
|
||||||
|
<meta property="og:image" content="http://rowsandall.com/static/img/logo_r.png" />
|
||||||
|
<meta property="og:image:secure_url" content="https://rowsandall.com/static/img/logo_r.png" />
|
||||||
|
{% endif %}
|
||||||
|
{% endblock %}
|
||||||
|
{% block image_src %}
|
||||||
|
{% for graph in graphs %}
|
||||||
|
<link rel="image_src" href="/{{ graph.filename |spacetohtml }}" />
|
||||||
|
{% endfor %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
{% block main %}
|
||||||
|
|
||||||
|
<h1>Do you want to disqualify this result?</h1>
|
||||||
|
<ul class="main-content">
|
||||||
|
<li class="grid_4">
|
||||||
|
<p>
|
||||||
|
Before you reject this race result, please carefully review it
|
||||||
|
using the information below. If you still want to reject the entry,
|
||||||
|
scroll down to the rejection form.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
<table width=100%>
|
||||||
|
<tr>
|
||||||
|
<th>Rower:</th><td>{{ record.username }}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<tr>
|
||||||
|
<th>Name:</th><td>{{ workout.name }}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<tr>
|
||||||
|
<th>Date:</th><td>{{ workout.date }}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>Time:</th><td>{{ workout.starttime }}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>Distance:</th><td>{{ workout.distance }}m</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>Type:</th><td>{{ workout.workouttype }}</td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>Weight Category:</th><td>{{ workout.weightcategory }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
<h1>Workout Summary</h1>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<pre>
|
||||||
|
{{ workout.summary }}
|
||||||
|
</pre>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
{% for graph in graphs %}
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/graph/{{ graph.id }}/">
|
||||||
|
<img src="/{{ graph.filename }}"
|
||||||
|
onerror="this.src='/static/img/rowingtimer.gif'"
|
||||||
|
alt="{{ graph.filename }}" width="120" height="100">
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
{% if mapdiv %}
|
||||||
|
<li class="grid_2">
|
||||||
|
<div class="mapdiv">
|
||||||
|
|
||||||
|
{{ mapdiv|safe }}
|
||||||
|
|
||||||
|
|
||||||
|
{{ mapscript|safe }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
<li class="grid_2">
|
||||||
|
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||||
|
<script async="true" type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ interactiveplot |safe }}
|
||||||
|
|
||||||
|
{{ the_div|safe }}
|
||||||
|
|
||||||
|
</li>
|
||||||
|
<li class="grid_4">
|
||||||
|
<h1>
|
||||||
|
Yes, I want to reject this entry
|
||||||
|
</h1>
|
||||||
|
<p>
|
||||||
|
Please select a reason and add a comment (mandatory).
|
||||||
|
Pressing 'Reject' disqualifies the submitted result.
|
||||||
|
An email will be sent to the rower. There is no "undo".
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<form enctype="multipart/form-date" action="" method="post">
|
||||||
|
<table>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
{% csrf_token %}
|
||||||
|
<input type="submit" value="Reject">
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_racing.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
{% extends "emailbase.html" %}
|
||||||
|
{% block body %}
|
||||||
|
<p>Dear <strong>{{ username }}</strong>,</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Unfortunately, the result that you have submitted
|
||||||
|
for the virtual race {{ racename }}
|
||||||
|
has been rejected by the race organizer.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The reason for the rejection was: <i>{{ reason }}</i>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The race organizer added the following explanation:
|
||||||
|
<p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<i>{{ message }}</i>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The decision to reject your result is the sole responsibility of
|
||||||
|
the race organizer. If you disagree with the decision, please do contact
|
||||||
|
him or her.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You are still registered for the race and can submit a result.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Best Regards, the Rowsandall Team
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
{% 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>
|
||||||
|
<p>All times are local times in the time zone you select</p>
|
||||||
|
<p>Adding a contact phone number and email is not mandatory, but we
|
||||||
|
strongly recommend it.</p>
|
||||||
|
<p>If your event has a registration closure deadline, participants
|
||||||
|
have to enter (and can withdraw) before the registration closure time.</p>
|
||||||
|
<p>Participants can submit results until the evaluation closure time.</p>
|
||||||
|
<p>Until one hour after evaluation closure time, the race organizer
|
||||||
|
can review and reject submitted results ("disqualification"). If
|
||||||
|
you as the race organizer intend to use this functionality, it
|
||||||
|
is strongly recommended that you fill out a contact email or phone
|
||||||
|
number.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If you require a screenshot of the PM monitor, do mention this
|
||||||
|
in the comment.
|
||||||
|
</p>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block scripts %}
|
||||||
|
{% endblock %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_racing.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -10,6 +10,11 @@
|
|||||||
<i class="far fa-flag fa-fw"></i> New Race
|
<i class="far fa-flag fa-fw"></i> New Race
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li id="indoor-new">
|
||||||
|
<a href="/rowers/virtualevent/createindoor">
|
||||||
|
<i class="far fa-flag fa-fw"></i> New Indoor Race
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li id="courses">
|
<li id="courses">
|
||||||
<a href="/rowers/list-courses">
|
<a href="/rowers/list-courses">
|
||||||
<i class="fas fa-map-marked fa-fw"></i> Courses
|
<i class="fas fa-map-marked fa-fw"></i> Courses
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
<th>Event</th>
|
<th>Event</th>
|
||||||
<th>Country</th>
|
<th>Country</th>
|
||||||
<th>Course</th>
|
<th>Course</th>
|
||||||
<th>Distance</th>
|
<th></th>
|
||||||
|
<th></th>
|
||||||
<th>Click for Details</th>
|
<th>Click for Details</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@@ -26,7 +27,8 @@
|
|||||||
<td><a href="/rowers/virtualevent/{{ race.id }}">{{ race.name }}</a></td>
|
<td><a href="/rowers/virtualevent/{{ race.id }}">{{ race.name }}</a></td>
|
||||||
<td>{{ race.course.country }}</td>
|
<td>{{ race.course.country }}</td>
|
||||||
<td><a href="/rowers/courses/{{ race.course.id }}">{{ race.course.name }}</a></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>
|
<td>
|
||||||
{% if rower %}
|
{% if rower %}
|
||||||
{% if race|can_register:rower %}
|
{% if race|can_register:rower %}
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
<h1>{{ race.name }}</h1>
|
<h1>{{ race.name }}</h1>
|
||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
<h2>Course</h2>
|
<h2>Course</h2>
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
{{ coursescript|safe }}
|
{{ coursescript|safe }}
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
{% endif %}
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<div id="raceinfo">
|
<div id="raceinfo">
|
||||||
<p>
|
<p>
|
||||||
@@ -32,11 +34,23 @@
|
|||||||
<p>
|
<p>
|
||||||
<table class="listtable shortpadded" width="100%">
|
<table class="listtable shortpadded" width="100%">
|
||||||
<tbody>
|
<tbody>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<tr>
|
<tr>
|
||||||
<th>Course</th><td>{{ race.course }}</td>
|
<th>Course</th><td>{{ race.course }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
{% else %}
|
||||||
<tr>
|
<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>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Registration closure</th>
|
<th>Registration closure</th>
|
||||||
@@ -81,38 +95,42 @@
|
|||||||
{% for button in buttons %}
|
{% for button in buttons %}
|
||||||
{% if button == 'registerbutton' %}
|
{% if button == 'registerbutton' %}
|
||||||
<p>
|
<p>
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/register"
|
{% if race.sessiontype == 'race' %}
|
||||||
class="blue button">Register</a>
|
<a href="/rowers/virtualevent/{{ race.id }}/register">Register</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/rowers/virtualevent/{{ race.id }}/registerindoor">Register</a>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if button == 'submitbutton' %}
|
{% 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 %}
|
{% endif %}
|
||||||
{% if button == 'resubmitbutton' %}
|
{% if button == 'resubmitbutton' %}
|
||||||
<p>
|
<p>
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/submit"
|
<a href="/rowers/virtualevent/{{ race.id }}/submit">Submit New Result</a>
|
||||||
class="blue button">Submit New Result</a>
|
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if button == 'withdrawbutton' %}
|
{% if button == 'withdrawbutton' %}
|
||||||
<p>
|
<p>
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/withdraw"
|
<a href="/rowers/virtualevent/{{ race.id }}/withdraw">Withdraw</a>
|
||||||
class="blue button">Withdraw</a>
|
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if button == 'adddisciplinebutton' %}
|
{% if button == 'adddisciplinebutton' %}
|
||||||
<p>
|
<p>
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/adddiscipline"
|
<a href="/rowers/virtualevent/{{ race.id }}/adddiscipline">
|
||||||
class="blue button">
|
|
||||||
Register New Boat
|
Register New Boat
|
||||||
</a>
|
</a>
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if button == 'editbutton' %}
|
{% if button == 'editbutton' %}
|
||||||
<p>
|
<p>
|
||||||
<a href="/rowers/virtualevent/{{ race.id }}/edit"
|
{% if race.sessiontype == 'race' %}
|
||||||
class="blue button">Edit Race
|
<a href="/rowers/virtualevent/{{ race.id }}/edit">Edit Race
|
||||||
</a>
|
</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/rowers/virtualevent/{{ race.id }}/editindoor">Edit Race
|
||||||
|
</a>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -122,7 +140,11 @@
|
|||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<div id="results">
|
<div id="results">
|
||||||
<p>
|
<p>
|
||||||
|
{% if race|is_final %}
|
||||||
|
<h2>Final Results</h2>
|
||||||
|
{% else %}
|
||||||
<h2>Results</h2>
|
<h2>Results</h2>
|
||||||
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% if results or dns %}
|
{% if results or dns %}
|
||||||
@@ -135,11 +157,14 @@
|
|||||||
<th> </th>
|
<th> </th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
<th> </th>
|
<th> </th>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<th>Class</th>
|
<th>Class</th>
|
||||||
<th>Boat</th>
|
<th>Boat</th>
|
||||||
|
{% endif %}
|
||||||
<th>Time</th>
|
<th>Time</th>
|
||||||
<th>Distance</th>
|
<th>Distance</th>
|
||||||
<th>Details</th>
|
<th>Details</th>
|
||||||
|
<th> </th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@@ -153,13 +178,24 @@
|
|||||||
<td>{{ result.age }}</td>
|
<td>{{ result.age }}</td>
|
||||||
<td>{{ result.sex }}</td>
|
<td>{{ result.sex }}</td>
|
||||||
<td>{{ result.weightcategory }}</td>
|
<td>{{ result.weightcategory }}</td>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<td>{{ result.boatclass }}</td>
|
<td>{{ result.boatclass }}</td>
|
||||||
<td>{{ result.boattype }}</td>
|
<td>{{ result.boattype }}</td>
|
||||||
|
{% endif %}
|
||||||
<td>{{ result.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
<td>{{ result.duration |durationprint:"%H:%M:%S.%f" }}</td>
|
||||||
<td>{{ result.distance }} m</td>
|
<td>{{ result.distance }} m</td>
|
||||||
<td>
|
<td>
|
||||||
<a href="/rowers/workout/{{ result.workoutid }}">
|
<a href="/rowers/workout/{{ result.workoutid }}">
|
||||||
Details</a></td>
|
Details</a></td>
|
||||||
|
<td>
|
||||||
|
{% if race.manager == request.user and not race|is_final %}
|
||||||
|
<a href="/rowers/virtualevent/{{ race.id }}/disqualify/{{ result.id }}/">
|
||||||
|
Disqualify
|
||||||
|
</a>
|
||||||
|
{% else %}
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% for result in dns %}
|
{% for result in dns %}
|
||||||
@@ -170,8 +206,10 @@
|
|||||||
<td>{{ result.age }}</td>
|
<td>{{ result.age }}</td>
|
||||||
<td>{{ result.sex }}</td>
|
<td>{{ result.sex }}</td>
|
||||||
<td>{{ result.weightcategory }}</td>
|
<td>{{ result.weightcategory }}</td>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<td>{{ result.boatclass }}</td>
|
<td>{{ result.boatclass }}</td>
|
||||||
<td>{{ result.boattype }}</td>
|
<td>{{ result.boattype }}</td>
|
||||||
|
{% endif %}
|
||||||
<td>DNS</td>
|
<td>DNS</td>
|
||||||
</tr>
|
</tr>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
@@ -210,8 +248,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
<th>Team Name</th>
|
<th>Team Name</th>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<th>Class</th>
|
<th>Class</th>
|
||||||
<th>Boat</th>
|
<th>Boat</th>
|
||||||
|
{% endif %}
|
||||||
<th>Age</th>
|
<th>Age</th>
|
||||||
<th>Gender</th>
|
<th>Gender</th>
|
||||||
<th>Weight Category</th>
|
<th>Weight Category</th>
|
||||||
@@ -221,8 +261,10 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<td>{{ record.username }}
|
<td>{{ record.username }}
|
||||||
<td>{{ record.teamname }}</td>
|
<td>{{ record.teamname }}</td>
|
||||||
|
{% if race.sessiontype == 'race' %}
|
||||||
<td>{{ record.boatclass }}</td>
|
<td>{{ record.boatclass }}</td>
|
||||||
<td>{{ record.boattype }}</td>
|
<td>{{ record.boattype }}</td>
|
||||||
|
{% endif %}
|
||||||
<td>{{ record.age }}</td>
|
<td>{{ record.age }}</td>
|
||||||
<td>{{ record.sex }}</td>
|
<td>{{ record.sex }}</td>
|
||||||
<td>{{ record.weightcategory }}</td>
|
<td>{{ record.weightcategory }}</td>
|
||||||
@@ -247,6 +289,16 @@
|
|||||||
Virtual races are intended as an informal way to add a
|
Virtual races are intended as an informal way to add a
|
||||||
competitive element to training and as a quick way to set
|
competitive element to training and as a quick way to set
|
||||||
up and manage small regattas.
|
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>
|
||||||
<p>
|
<p>
|
||||||
As a rowsandall.com user, you can
|
As a rowsandall.com user, you can
|
||||||
@@ -271,6 +323,10 @@
|
|||||||
you delete the respective workout or remove your account.
|
you delete the respective workout or remove your account.
|
||||||
By registering, you agree with this and the race rules.
|
By registering, you agree with this and the race rules.
|
||||||
</p>
|
</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>
|
<p>
|
||||||
Virtual Racing on rowsandall.com is honors based. Please be a good
|
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
|
sport, submit real results rowed by you, and make sure you set the
|
||||||
@@ -285,6 +341,11 @@
|
|||||||
Individual participants are entirely responsible for their
|
Individual participants are entirely responsible for their
|
||||||
safety while participating in a virtual race.
|
safety while participating in a virtual race.
|
||||||
</p>
|
</p>
|
||||||
|
<p>
|
||||||
|
Until the evaluation closure time, the race organizer can
|
||||||
|
review and reject entries. If you are disqualified in this
|
||||||
|
way, you will receive an email with the reason.
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -32,20 +32,22 @@
|
|||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<input class="button green" type="submit" value="Save">
|
<input type="submit" value="Save">
|
||||||
</p>
|
</p>
|
||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_1">
|
<li class="grid_1">
|
||||||
<p>
|
<p>All times are local times in the race course time zone</p>
|
||||||
<ul>
|
<p>Adding a contact phone number and email is not mandatory, but we
|
||||||
<li>All times are local times in the race course time zone</li>
|
strongly recommend it.</p>
|
||||||
<li>Adding a contact phone number and email is not mandatory, but we
|
<p>If your event has a registration closure deadline, participants
|
||||||
strongly recommend it.</li>
|
have to enter (and can withdraw) before the registration closure time.</p>
|
||||||
<li>If your event has a registration closure deadline, participants
|
<p>Participants can submit results until the evaluation closure time.</p>
|
||||||
have to enter (and can withdraw) before the registration closure time.</li>
|
<p>Until one hour after evaluation closure time, the race organizer
|
||||||
<li>Participants can submit results until the evaluation closure time.</li>
|
can review and reject submitted results ("disqualification"). If
|
||||||
</ul>
|
you as the race organizer intend to use this functionality, it
|
||||||
|
is strongly recommended that you fill out a contact email or phone
|
||||||
|
number.
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -370,6 +370,14 @@ def is_past_due(self):
|
|||||||
def is_not_past_due(self):
|
def is_not_past_due(self):
|
||||||
return datetime.date.today() <= self.date
|
return datetime.date.today() <= self.date
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def is_closed(race):
|
||||||
|
return race.evaluation_closure < timezone.now()
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def is_final(race):
|
||||||
|
return race.evaluation_closure < timezone.now()-datetime.timedelta(hours=1)
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def userurl(path,member):
|
def userurl(path,member):
|
||||||
pattern = re.compile('user\/\d+')
|
pattern = re.compile('user\/\d+')
|
||||||
|
|||||||
@@ -143,14 +143,19 @@ urlpatterns = [
|
|||||||
url(r'^list-workouts/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\d+-\d+-\d+)$',views.workouts_view),
|
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'^virtualevents$',views.virtualevents_view),
|
||||||
url(r'^virtualevent/create$',views.virtualevent_create_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+)$',views.virtualevent_view),
|
||||||
url(r'^virtualevent/(?P<id>\d+)/edit$',views.virtualevent_edit_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+)/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+)/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/(?P<recordid>\d+)$',views.virtualevent_withdraw_view),
|
||||||
url(r'^virtualevent/(?P<id>\d+)/withdraw$',views.virtualevent_withdraw_view),
|
url(r'^virtualevent/(?P<id>\d+)/withdraw$',views.virtualevent_withdraw_view),
|
||||||
url(r'^virtualevent/(?P<id>\d+)/submit$',
|
url(r'^virtualevent/(?P<id>\d+)/submit$',
|
||||||
views.virtualevent_submit_result_view),
|
views.virtualevent_submit_result_view),
|
||||||
|
url(r'^virtualevent/(?P<raceid>\d+)/disqualify/(?P<recordid>\d+)/',
|
||||||
|
views.virtualevent_disqualify_view),
|
||||||
url(r'^list-workouts/$',views.workouts_view),
|
url(r'^list-workouts/$',views.workouts_view),
|
||||||
url(r'^list-courses/$',views.courses_view),
|
url(r'^list-courses/$',views.courses_view),
|
||||||
url(r'^courses/upload$',views.course_upload_view),
|
url(r'^courses/upload$',views.course_upload_view),
|
||||||
|
|||||||
+610
-13
@@ -49,7 +49,8 @@ from rowers.forms import (
|
|||||||
VirtualRaceSelectForm,WorkoutRaceSelectForm,CourseSelectForm,
|
VirtualRaceSelectForm,WorkoutRaceSelectForm,CourseSelectForm,
|
||||||
RaceResultFilterForm,PowerIntervalUpdateForm,FlexAxesForm,
|
RaceResultFilterForm,PowerIntervalUpdateForm,FlexAxesForm,
|
||||||
FlexOptionsForm,DataFrameColumnsForm,OteWorkoutTypeForm,
|
FlexOptionsForm,DataFrameColumnsForm,OteWorkoutTypeForm,
|
||||||
MetricsForm,
|
MetricsForm,DisqualificationForm,disqualificationreasons,
|
||||||
|
disqualifiers
|
||||||
)
|
)
|
||||||
from django.core.urlresolvers import reverse, reverse_lazy
|
from django.core.urlresolvers import reverse, reverse_lazy
|
||||||
|
|
||||||
@@ -90,7 +91,9 @@ from rowers.models import (
|
|||||||
WorkoutComment,WorkoutCommentForm,RowerExportForm,
|
WorkoutComment,WorkoutCommentForm,RowerExportForm,
|
||||||
CalcAgePerformance,PowerTimeFitnessMetric,PlannedSessionForm,
|
CalcAgePerformance,PowerTimeFitnessMetric,PlannedSessionForm,
|
||||||
PlannedSessionFormSmall,GeoCourseEditForm,VirtualRace,
|
PlannedSessionFormSmall,GeoCourseEditForm,VirtualRace,
|
||||||
VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm
|
VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm,
|
||||||
|
IndoorVirtualRaceResultForm,IndoorVirtualRaceResult,
|
||||||
|
IndoorVirtualRaceForm,
|
||||||
)
|
)
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement,BasePlannedSessionFormSet,
|
FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement,BasePlannedSessionFormSet,
|
||||||
@@ -154,6 +157,7 @@ from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,
|
|||||||
from rowers.tasks import (
|
from rowers.tasks import (
|
||||||
handle_sendemail_unrecognized,handle_sendemailnewcomment,
|
handle_sendemail_unrecognized,handle_sendemailnewcomment,
|
||||||
handle_sendemailsummary,
|
handle_sendemailsummary,
|
||||||
|
handle_send_disqualification_email,
|
||||||
handle_sendemailfile,
|
handle_sendemailfile,
|
||||||
handle_sendemailkml,
|
handle_sendemailkml,
|
||||||
handle_sendemailnewresponse, handle_updatedps,
|
handle_sendemailnewresponse, handle_updatedps,
|
||||||
@@ -15765,7 +15769,8 @@ def virtualevents_view(request):
|
|||||||
if country == 'All':
|
if country == 'All':
|
||||||
countries = VirtualRace.objects.order_by('country').values_list('country').distinct()
|
countries = VirtualRace.objects.order_by('country').values_list('country').distinct()
|
||||||
else:
|
else:
|
||||||
countries = [country]
|
countries = [country,
|
||||||
|
'Indoor']
|
||||||
|
|
||||||
if regattatype == 'upcoming':
|
if regattatype == 'upcoming':
|
||||||
races1 = VirtualRace.objects.filter(
|
races1 = VirtualRace.objects.filter(
|
||||||
@@ -15813,14 +15818,146 @@ def virtualevents_view(request):
|
|||||||
'rower':r,
|
'rower':r,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
return render(request,'virtualevents.html',
|
return render(request,'virtualevents.html',
|
||||||
{ 'races':races,
|
{ 'races':races,
|
||||||
'form':form,
|
'form':form,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'active':'nav-racing',
|
'active':'nav-racing',
|
||||||
'rower':r,
|
'rower':r,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@login_required()
|
||||||
|
def virtualevent_disqualify_view(request,raceid=0,recordid=0):
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
|
||||||
|
try:
|
||||||
|
race = VirtualRace.objects.get(id=raceid)
|
||||||
|
except VirtualRace.DoesNotExist:
|
||||||
|
raise Http404("Virtual Race does not exist")
|
||||||
|
|
||||||
|
if r.user != race.manager:
|
||||||
|
raise PermissionDenied("Access denied")
|
||||||
|
|
||||||
|
if race.sessiontype == 'race':
|
||||||
|
recordobj = VirtualRaceResult
|
||||||
|
else:
|
||||||
|
recordobj = IndoorVirtualRaceResult
|
||||||
|
|
||||||
|
# datum moet voor race evaluation date zijn (ook in template controleren)
|
||||||
|
|
||||||
|
try:
|
||||||
|
record = recordobj.objects.get(id=recordid)
|
||||||
|
except recordobj.DoesNotExist:
|
||||||
|
messages.error(request,"We couldn't find the record")
|
||||||
|
|
||||||
|
if timezone.now() > race.evaluation_closure+datetime.timedelta(hours=1):
|
||||||
|
messages.error(request,"The evaluation is already closed and the results are official")
|
||||||
|
url = reverse(virtualevent_view,kwargs={'id':raceid})
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = DisqualificationForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
message = form.cleaned_data['message']
|
||||||
|
reason = form.cleaned_data['reason']
|
||||||
|
disqualifier = disqualifiers[reason]
|
||||||
|
|
||||||
|
u = User.objects.get(id=record.userid)
|
||||||
|
name = record.username
|
||||||
|
|
||||||
|
job = myqueue(queue,handle_send_disqualification_email,
|
||||||
|
u.email, name,
|
||||||
|
disqualifier,message,race.name)
|
||||||
|
|
||||||
|
messages.info(request,"We have invalidated the result for: "+str(record))
|
||||||
|
|
||||||
|
record.coursecompleted = False
|
||||||
|
record.save()
|
||||||
|
|
||||||
|
url = reverse(virtualevent_view,kwargs={'id':raceid})
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
else:
|
||||||
|
form = DisqualificationForm(request.POST)
|
||||||
|
|
||||||
|
workout = Workout.objects.get(id=record.workoutid)
|
||||||
|
|
||||||
|
g = GraphImage.objects.filter(workout=workout).order_by("-creationdatetime")
|
||||||
|
for i in g:
|
||||||
|
try:
|
||||||
|
width,height = Image.open(i.filename).size
|
||||||
|
i.width = width
|
||||||
|
i.height = height
|
||||||
|
i.save()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
script, div = interactive_chart(record.workoutid)
|
||||||
|
|
||||||
|
f1 = workout.csvfilename
|
||||||
|
rowdata = rdata(f1)
|
||||||
|
hascoordinates = 1
|
||||||
|
if rowdata != 0:
|
||||||
|
try:
|
||||||
|
latitude = rowdata.df[' latitude']
|
||||||
|
if not latitude.std():
|
||||||
|
hascoordinates = 0
|
||||||
|
except KeyError, AttributeError:
|
||||||
|
hascoordinates = 0
|
||||||
|
else:
|
||||||
|
hascoordinates = 0
|
||||||
|
|
||||||
|
if hascoordinates:
|
||||||
|
mapscript, mapdiv = leaflet_chart(rowdata.df[' latitude'],
|
||||||
|
rowdata.df[' longitude'],
|
||||||
|
workout.name)
|
||||||
|
else:
|
||||||
|
mapscript = ""
|
||||||
|
mapdiv = ""
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_disqualify_view,
|
||||||
|
kwargs={'raceid':raceid,
|
||||||
|
'recordid':recordid}),
|
||||||
|
'name': 'Disqualify Entry'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
return render(request,"disqualification_view.html",
|
||||||
|
{'workout':workout,
|
||||||
|
'active':'nav-racing',
|
||||||
|
'graphs':g,
|
||||||
|
'interactiveplot':script,
|
||||||
|
'the_div':div,
|
||||||
|
'mapscript':mapscript,
|
||||||
|
'mapdiv':mapdiv,
|
||||||
|
'form':form,
|
||||||
|
'race':race,
|
||||||
|
'record':record,
|
||||||
|
})
|
||||||
|
|
||||||
def virtualevent_view(request,id=0):
|
def virtualevent_view(request,id=0):
|
||||||
|
|
||||||
results = []
|
results = []
|
||||||
@@ -15836,12 +15973,16 @@ def virtualevent_view(request,id=0):
|
|||||||
except VirtualRace.DoesNotExist:
|
except VirtualRace.DoesNotExist:
|
||||||
raise Http404("Virtual Race does not exist")
|
raise Http404("Virtual Race does not exist")
|
||||||
|
|
||||||
|
if race.sessiontype == 'race':
|
||||||
script,div = course_map(race.course)
|
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 = []
|
buttons = []
|
||||||
|
|
||||||
@@ -15881,7 +16022,10 @@ def virtualevent_view(request,id=0):
|
|||||||
try:
|
try:
|
||||||
boatclass = cd['boatclass']
|
boatclass = cd['boatclass']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
if race.sessiontype == 'race':
|
||||||
boatclass = [t for t in mytypes.otwtypes]
|
boatclass = [t for t in mytypes.otwtypes]
|
||||||
|
else:
|
||||||
|
boatclass = [t for t in mytypes.otetypes]
|
||||||
|
|
||||||
age_min = cd['age_min']
|
age_min = cd['age_min']
|
||||||
age_max = cd['age_max']
|
age_max = cd['age_max']
|
||||||
@@ -15891,7 +16035,8 @@ def virtualevent_view(request,id=0):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
weightcategory = ['hwt','lwt']
|
weightcategory = ['hwt','lwt']
|
||||||
|
|
||||||
results = VirtualRaceResult.objects.filter(
|
if race.sessiontype == 'race':
|
||||||
|
results = resultobj.objects.filter(
|
||||||
race=race,
|
race=race,
|
||||||
workoutid__isnull=False,
|
workoutid__isnull=False,
|
||||||
boatclass__in=boatclass,
|
boatclass__in=boatclass,
|
||||||
@@ -15901,25 +16046,36 @@ def virtualevent_view(request,id=0):
|
|||||||
age__gte=age_min,
|
age__gte=age_min,
|
||||||
age__lte=age_max
|
age__lte=age_max
|
||||||
).order_by("duration")
|
).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
|
# to-do - add DNS
|
||||||
dns = []
|
dns = []
|
||||||
if timezone.now() > race.evaluation_closure:
|
if timezone.now() > race.evaluation_closure:
|
||||||
dns = VirtualRaceResult.objects.filter(
|
dns = resultobj.objects.filter(
|
||||||
race=race,
|
race=race,
|
||||||
workoutid__isnull=True,
|
workoutid__isnull=True,
|
||||||
boatclass__in=boatclass,
|
boatclass__in=boatclass,
|
||||||
boattype__in=boattype,
|
|
||||||
sex__in=sex,
|
sex__in=sex,
|
||||||
weightcategory__in=weightcategory,
|
weightcategory__in=weightcategory,
|
||||||
age__gte=age_min,
|
age__gte=age_min,
|
||||||
age__lte=age_max
|
age__lte=age_max
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
results = VirtualRaceResult.objects.filter(
|
results = resultobj.objects.filter(
|
||||||
race=race,
|
race=race,
|
||||||
workoutid__isnull=False,
|
workoutid__isnull=False,
|
||||||
).order_by("duration")
|
coursecompleted=True,
|
||||||
|
).order_by("duration","-distance")
|
||||||
|
|
||||||
if results:
|
if results:
|
||||||
form = RaceResultFilterForm(records=records)
|
form = RaceResultFilterForm(records=records)
|
||||||
@@ -15929,18 +16085,32 @@ def virtualevent_view(request,id=0):
|
|||||||
# to-do - add DNS
|
# to-do - add DNS
|
||||||
dns = []
|
dns = []
|
||||||
if timezone.now() > race.evaluation_closure:
|
if timezone.now() > race.evaluation_closure:
|
||||||
dns = VirtualRaceResult.objects.filter(
|
dns = resultobj.objects.filter(
|
||||||
race=race,
|
race=race,
|
||||||
workoutid__isnull=True,
|
workoutid__isnull=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render(request,'virtualevent.html',
|
return render(request,'virtualevent.html',
|
||||||
{
|
{
|
||||||
'coursescript':script,
|
'coursescript':script,
|
||||||
'coursediv':div,
|
'coursediv':div,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'race':race,
|
'race':race,
|
||||||
'rower':r,
|
'rower':r,
|
||||||
'results':results,
|
'results':results,
|
||||||
@@ -16089,9 +16259,31 @@ def virtualevent_addboat_view(request,id=0):
|
|||||||
|
|
||||||
form = VirtualRaceResultForm(initial=initial)
|
form = VirtualRaceResultForm(initial=initial)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': reverse(virtualevent_addboat_view,
|
||||||
|
kwargs = {'id':race.id}
|
||||||
|
),
|
||||||
|
'name': 'Add Discipline'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return render(request,'virtualeventregister.html',
|
return render(request,'virtualeventregister.html',
|
||||||
{
|
{
|
||||||
'form':form,
|
'form':form,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'race':race,
|
'race':race,
|
||||||
'userid':r.user.id,
|
'userid':r.user.id,
|
||||||
'active': 'nav-racing',
|
'active': 'nav-racing',
|
||||||
@@ -16182,14 +16374,281 @@ def virtualevent_register_view(request,id=0):
|
|||||||
|
|
||||||
form = VirtualRaceResultForm(initial=initial)
|
form = VirtualRaceResultForm(initial=initial)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': reverse(virtualevent_register_view,
|
||||||
|
kwargs = {'id':race.id}
|
||||||
|
),
|
||||||
|
'name': 'Register'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return render(request,'virtualeventregister.html',
|
||||||
|
{
|
||||||
|
'form':form,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
|
'race':race,
|
||||||
|
'userid':r.user.id,
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': reverse(indoorvirtualevent_register_view,
|
||||||
|
kwargs = {'id':race.id}
|
||||||
|
),
|
||||||
|
'name': 'Register'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
return render(request,'virtualeventregister.html',
|
return render(request,'virtualeventregister.html',
|
||||||
{
|
{
|
||||||
'form':form,
|
'form':form,
|
||||||
'race':race,
|
'race':race,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'userid':r.user.id,
|
'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()
|
||||||
|
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(indoorvirtualevent_create_view,
|
||||||
|
),
|
||||||
|
'name': 'New Indoor Virtual Regatta'
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
return render(request,'indoorvirtualeventcreate.html',
|
||||||
|
{
|
||||||
|
'form':racecreateform,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
|
'rower':r,
|
||||||
|
'active':'nav-racing',
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def virtualevent_create_view(request):
|
def virtualevent_create_view(request):
|
||||||
r = getrower(request.user)
|
r = getrower(request.user)
|
||||||
@@ -16304,9 +16763,21 @@ def virtualevent_create_view(request):
|
|||||||
racecreateform = VirtualRaceForm()
|
racecreateform = VirtualRaceForm()
|
||||||
|
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_create_view,
|
||||||
|
),
|
||||||
|
'name': 'New Virtual Regatta'
|
||||||
|
},
|
||||||
|
]
|
||||||
return render(request,'virtualeventcreate.html',
|
return render(request,'virtualeventcreate.html',
|
||||||
{
|
{
|
||||||
'form':racecreateform,
|
'form':racecreateform,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'rower':r,
|
'rower':r,
|
||||||
'active':'nav-racing',
|
'active':'nav-racing',
|
||||||
|
|
||||||
@@ -16360,15 +16831,111 @@ def virtualevent_edit_view(request,id=0):
|
|||||||
|
|
||||||
racecreateform = VirtualRaceForm(instance=race)
|
racecreateform = VirtualRaceForm(instance=race)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': reverse(virtualevent_edit_view,
|
||||||
|
kwargs = {'id':race.id}
|
||||||
|
),
|
||||||
|
'name': 'Edit'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
return render(request,'virtualeventedit.html',
|
return render(request,'virtualeventedit.html',
|
||||||
{
|
{
|
||||||
'form':racecreateform,
|
'form':racecreateform,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'rower':r,
|
'rower':r,
|
||||||
'race':race,
|
'race':race,
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@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)
|
||||||
|
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': reverse(indoorvirtualevent_edit_view,
|
||||||
|
kwargs = {'id':race.id}
|
||||||
|
),
|
||||||
|
'name': 'Edit'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return render(request,'virtualeventedit.html',
|
||||||
|
{
|
||||||
|
'form':racecreateform,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
|
'rower':r,
|
||||||
|
'race':race,
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def virtualevent_submit_result_view(request,id=0):
|
def virtualevent_submit_result_view(request,id=0):
|
||||||
|
|
||||||
@@ -16391,7 +16958,12 @@ def virtualevent_submit_result_view(request,id=0):
|
|||||||
|
|
||||||
can_submit = race_can_submit(r,race) or race_can_resubmit(r,race)
|
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,
|
userid = r.id,
|
||||||
race=race
|
race=race
|
||||||
)
|
)
|
||||||
@@ -16462,9 +17034,15 @@ def virtualevent_submit_result_view(request,id=0):
|
|||||||
|
|
||||||
workouts = Workout.objects.filter(id=selectedworkout)
|
workouts = Workout.objects.filter(id=selectedworkout)
|
||||||
|
|
||||||
|
if race.sessiontype == 'race':
|
||||||
result,comments,errors,jobid = add_workout_race(
|
result,comments,errors,jobid = add_workout_race(
|
||||||
workouts,race,r,
|
workouts,race,r,
|
||||||
splitsecond=splitsecond,recordid=recordid)
|
splitsecond=splitsecond,recordid=recordid)
|
||||||
|
else:
|
||||||
|
result,comments,errors,jobid = add_workout_indoorrace(
|
||||||
|
workouts,race,r,recordid=recordid)
|
||||||
|
|
||||||
|
|
||||||
# if result:
|
# if result:
|
||||||
# for w in ws:
|
# for w in ws:
|
||||||
# remove_workout_plannedsession(w,race)
|
# remove_workout_plannedsession(w,race)
|
||||||
@@ -16494,10 +17072,29 @@ def virtualevent_submit_result_view(request,id=0):
|
|||||||
else:
|
else:
|
||||||
w_form = WorkoutRaceSelectForm(workoutdata,entries)
|
w_form = WorkoutRaceSelectForm(workoutdata,entries)
|
||||||
|
|
||||||
|
breadcrumbs = [
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevents_view),
|
||||||
|
'name': 'Racing'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url':reverse(virtualevent_view,
|
||||||
|
kwargs={'id':race.id}
|
||||||
|
),
|
||||||
|
'name': race.name
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'url': reverse(virtualevent_submit_result_view,
|
||||||
|
kwargs = {'id':race.id}
|
||||||
|
),
|
||||||
|
'name': 'Submit Result'
|
||||||
|
}
|
||||||
|
]
|
||||||
return render(request,'race_submit.html',
|
return render(request,'race_submit.html',
|
||||||
{
|
{
|
||||||
'race':race,
|
'race':race,
|
||||||
'workouts':ws,
|
'workouts':ws,
|
||||||
|
'breadcrumbs':breadcrumbs,
|
||||||
'active':'nav-racing',
|
'active':'nav-racing',
|
||||||
'rower':r,
|
'rower':r,
|
||||||
'w_form':w_form,
|
'w_form':w_form,
|
||||||
|
|||||||
Reference in New Issue
Block a user