Private
Public Access
1
0
Files
rowsandall/rowers/views/racesviews.py
2019-03-22 10:59:49 +01:00

2287 lines
68 KiB
Python

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from rowers.views.statements import *
# List Courses
@login_required()
def courses_view(request):
r = getrower(request.user)
courses = GeoCourse.objects.all().order_by("country","name")
# add search processing
query = request.GET.get('q')
if query:
query_list = query.split()
courses = GeoCourse.objects.filter(
reduce(operator.and_,
(Q(name__icontains=q) for q in query_list)) |
reduce(operator.and_,
(Q(country__icontains=q) for q in query_list)) |
reduce(operator.and_,
(Q(notes__icontains=q) for q in query_list))
)
searchform = SearchForm(initial={'q':query})
else:
searchform = SearchForm()
return render(request,'list_courses.html',
{'courses':courses,
'active':'nav-racing',
'searchform':searchform,
'rower':r,
})
# for ajax calls
def course_map_view(request,id=0):
try:
course = GeoCourse.objects.get(id=id)
except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist")
script,div = course_map(course)
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url': reverse(courses_view),
'name': 'Courses'
},
{
'url': reverse(course_view,kwargs={'id':course.id}),
'name': course.name
},
{
'url': reverse(course_map_view,kwargs={'id':course.id}),
'name': 'Map'
}
]
r = getrower(request.user)
return render(request,
'coursemap.html',
{
'mapdiv':div,
'course':course,
'mapscript':script,
'active':'nav-racing',
'rower':r,
'breadcrumbs':breadcrumbs,
})
@login_required()
def course_replace_view(request,id=0):
try:
course = GeoCourse.objects.get(id=id)
except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist")
r = getrower(request.user)
if course.manager != r:
raise PermissionDenied("Access denied")
thecourses = GeoCourse.objects.filter(manager=r).exclude(id=id)
if request.method == 'POST':
form = CourseSelectForm(request.POST)
if form.is_valid():
course2 = form.cleaned_data['course']
res = courses.replacecourse(course,course2)
url = reverse(course_view,
kwargs = {
'id':course2.id
})
return HttpResponseRedirect(url)
else:
form = CourseSelectForm()
form.fields["course"].queryset = thecourses
script,div = course_map(course)
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url': reverse(courses_view),
'name': 'Courses'
},
{
'url': reverse(course_view,kwargs={'id':course.id}),
'name': course.name
},
{
'url': reverse(course_replace_view,kwargs={'id':course.id}),
'name': 'Replace Markers'
}
]
return render(request,
'course_replace.html',
{'course':course,
'active':'nav-racing',
'breadcrumbs':breadcrumbs,
'rower':r,
'mapdiv':div,
'mapscript':script,
'form':form})
@login_required()
def course_delete_view(request,id=0):
try:
course = GeoCourse.objects.get(id=id)
except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist")
r = getrower(request.user)
if course.manager != r:
raise PermissionDenied("Access denied")
ps = PlannedSession.objects.filter(course=course)
nosessions = len(ps) == 0
if nosessions:
course.delete()
url = reverse(courses_view)
return HttpResponseRedirect(url)
@login_required()
def course_edit_view(request,id=0):
try:
course = GeoCourse.objects.get(id=id)
except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist")
r = getrower(request.user)
if course.manager != r:
raise PermissionDenied("Access denied")
ps = PlannedSession.objects.filter(course=course)
nosessions = len(ps) == 0
script,div = course_map(course)
if request.method == 'POST':
form = GeoCourseEditForm(request.POST)
if form.is_valid():
name = form.cleaned_data['name']
country = form.cleaned_data['country']
notes = form.cleaned_data['notes']
course.name = name
course.country = country
course.notes = notes
course.save()
form = GeoCourseEditForm(instance=course)
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url': reverse(courses_view),
'name': 'Courses'
},
{
'url': reverse(course_view,kwargs={'id':course.id}),
'name': course.name
},
{
'url': reverse(course_edit_view,kwargs={'id':course.id}),
'name': 'Edit'
}
]
return render(request, 'course_edit_view.html',
{
'course':course,
'active':'nav-racing',
'breadcrumbs':breadcrumbs,
'mapscript':script,
'mapdiv':div,
'nosessions':nosessions,
'rower':r,
'form':form,
}
)
@login_required()
def course_view(request,id=0):
try:
course = GeoCourse.objects.get(id=id)
except GeoCourse.DoesNotExist:
return Http404("Course doesn't exist")
r = getrower(request.user)
script,div = course_map(course)
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url': reverse(courses_view),
'name': 'Courses'
},
{
'url': reverse(course_view,kwargs={'id':course.id}),
'name': course.name
},
]
return render(request, 'course_view.html',
{
'active':'nav-racing',
'breadcrumbs':breadcrumbs,
'course':course,
'mapscript':script,
'mapdiv':div,
'nosessions':False,
'rower':r,
}
)
@login_required()
def logo_delete_view(request,id=0):
try:
logo = RaceLogo.objects.get(id=id)
except RaceLogo.DoesNotExist:
raise Http404("Logo doesn't exist")
if logo.user == request.user:
logo.delete()
messages.info(request,"Logo Deleted")
url = reverse('virtualevents_view')
return HttpResponseRedirect(url)
@login_required()
def virtualevent_setlogo_view(request,id=0,logoid=0):
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Race doesn't exist")
try:
logo = RaceLogo.objects.get(id=logoid)
except RaceLogo.DoesNotExist:
raise Http404("Logo doesn't exist")
if logo.user == request.user and race.manager == request.user:
otherlogos = race.logos.all()
for otherlogo in otherlogos:
otherlogo.race.remove(race)
logo.race.add(race)
logo.save()
else:
message = "You do not own this race or this image"
messages.error(request,message)
url = reverse('virtualevent_view',
kwargs={'id':id})
return HttpResponseRedirect(url)
# Image upload to virtual event
@login_required()
def virtualevent_uploadimage_view(request,id=0):
is_ajax = False
if request.is_ajax():
is_ajax = True
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Race doesn't exist")
logos = RaceLogo.objects.filter(user=request.user).order_by("-creationdatetime")
breadcrumbs = [
{
'url': reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url': reverse('virtualevent_view',kwargs={'id':id}),
'name': race.name
},
{
'url': reverse(virtualevent_uploadimage_view,
kwargs={'id':id}),
'name': 'Add Image'
}
]
if request.method == 'POST':
if len(logos) >= 6:
messages.error(request,"You cannot have more than 6 logos")
url = reverse(virtualevent_imageupload_view,
kwargs={'id':id})
return HttpResponseRedirect(url)
form = ImageForm(request.POST, request.FILES)
if form.is_valid():
f = form.cleaned_data['file']
if f is not None:
filename, path_and_filename = handle_uploaded_image(f)
try:
width, height = Image.open(path_and_filename).size
except:
message = "Not a valid image"
messages.error(request,message)
os.remove(path_and_filename)
url = reverse(virtualevent_image_view,
kwargs={'id':id})
if is_ajax:
return JSONResponse({'result':0, 'url':0})
else:
return HttpResponseRedirect(url)
otherlogos = race.logos.all()
for logo in otherlogos:
logo.race.remove(race)
logo = RaceLogo(user = request.user,
creationdatetime=timezone.now(),
filename = path_and_filename,
width=width, height=height)
logo.save()
logo.race.add(race)
logo.save()
url = reverse('virtualevent_view',
kwargs={'id':id})
if is_ajax:
return JSONResponse({'result':1, 'url':url})
else:
return HttpResponseRedirect(url)
else:
messages.error(request,"Something went wrong - no file attached")
url = reverse(virtualevent_uploadimage_view,
kwargs = {'id':id})
if is_ajax:
return JSONResponse({'result':0,'url':1})
else:
return HttpResponseRedirect(url)
else:
form = ImageForm()
if is_ajax:
return {'result':0}
return render(request,'logo_form.html',
{'form':form,
'rower':r,
'logos':logos,
'active':'nav-racing',
'breadcrumbs':breadcrumbs,
'race':race,
})
# Image upload
@login_required()
def course_upload_view(request):
is_ajax = False
if request.is_ajax():
is_ajax = True
r = getrower(request.user)
if request.method == 'POST':
form = CourseForm(request.POST,request.FILES)
if form.is_valid():
f = form.cleaned_data['file']
name = form.cleaned_data['name']
notes = form.cleaned_data['notes']
if f is not None:
filename,path_and_filename = handle_uploaded_file(f)
cs = courses.kmltocourse(path_and_filename)
for course in cs:
cname = name+' - '+course['name']
cnotes = notes+'\n\n'+course['description']
polygons = course['polygons']
course = courses.createcourse(r,cname,polygons,notes=cnotes)
os.remove(path_and_filename)
url = reverse(courses_view)
if is_ajax:
return JSONResponse({'result':1,'url':url})
else:
return HttpResponseRedirect(url)
else:
messages.error(request,'Something went wrong - no file attached')
url = reverse(course_upload_view)
if is_ajax:
return JSONResponse({'result':0,'url':0})
else:
return HttpResponseRedirect(url)
else:
messages.error(request,'Form is not valid')
return render(request,'course_form.html',
{'form':form,
})
else:
if not is_ajax:
form = CourseForm()
return render(request,'course_form.html',
{'form':form,
'active':'nav-racing',
})
else:
return {'result':0}
def virtualevents_view(request):
is_ajax = False
if request.is_ajax():
is_ajax = True
# default races
races1 = VirtualRace.objects.filter(
startdate__gte=datetime.date.today(),
)
races2 = VirtualRace.objects.filter(
startdate__lte=datetime.date.today(),
evaluation_closure__gte=timezone.now()-datetime.timedelta(days=3),
)
races = (races1 | races2).order_by("startdate","start_time")
if not request.user.is_anonymous:
r = getrower(request.user)
else:
r = None
if request.method == 'POST':
# process form
form = VirtualRaceSelectForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
country = cd['country']
regattatype = cd['regattatype']
if country == 'All':
countries = VirtualRace.objects.order_by('country').values_list('country').distinct()
else:
countries = [country,
'Indoor']
if regattatype == 'upcoming':
races1 = VirtualRace.objects.filter(
startdate__gte=datetime.date.today(),
country__in=countries
)
races2 = VirtualRace.objects.filter(
startdate__lte=datetime.date.today(),
evaluation_closure__gte=timezone.now(),
country__in=countries
)
races = (races1 | races2).order_by("startdate","start_time")
elif regattatype == 'previous':
races = VirtualRace.objects.filter(
evaluation_closure__lt=timezone.now(),
country__in=countries
).order_by("-startdate","-start_time")
elif regattatype == 'ongoing':
races = VirtualRace.objects.filter(
startdate__lte=datetime.date.today(),
evaluation_closure__gte=timezone.now(),
country__in=countries
).order_by("startdate","start_time")
elif regattatype == 'my':
mysessions = get_my_session_ids(r)
races = VirtualRace.objects.filter(
id__in=mysessions,
country__in=countries
).order_by("startdate","start_time")
elif regattatype == 'all':
races = VirtualRace.objects.filter(
country__in=countries
).order_by("startdate","start_time")
else:
form = VirtualRaceSelectForm()
if is_ajax:
return render(request,'racelist.html',
{ 'races':races,
'rower':r,
})
breadcrumbs = [
{
'url':reverse('virtualevents_view'),
'name': 'Racing'
},
]
return render(request,'virtualevents.html',
{ 'races':races,
'form':form,
'breadcrumbs':breadcrumbs,
'active':'nav-racing',
'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]
r = Rower.objects.get(id=record.userid)
name = record.username
job = myqueue(queue,handle_send_disqualification_email,
r.user.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'
},
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,"disqualification_view.html",
{'workout':workout,
'active':'nav-racing',
'graphs':g,
'buttons':buttons,
'interactiveplot':script,
'the_div':div,
'mapscript':mapscript,
'mapdiv':mapdiv,
'form':form,
'race':race,
'record':record,
})
def virtualevent_view(request,id=0):
results = []
if not request.user.is_anonymous:
r = getrower(request.user)
else:
r = None
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
if race.sessiontype == 'race':
script,div = course_map(race.course)
resultobj = VirtualRaceResult
else:
script = ''
div = ''
resultobj = IndoorVirtualRaceResult
records = resultobj.objects.filter(race=race)
buttons = []
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
)
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
if request.method == 'POST':
form = RaceResultFilterForm(request.POST,records=records)
if form.is_valid():
cd = form.cleaned_data
try:
sex = cd['sex']
except KeyError:
sex = ['female','male','mixed']
try:
boattype = cd['boattype']
except KeyError:
boattype = mytypes.waterboattype
try:
boatclass = cd['boatclass']
except KeyError:
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']
try:
weightcategory = cd['weightcategory']
except KeyError:
weightcategory = ['hwt','lwt']
try:
adaptiveclass = cd['adaptiveclass']
except KeyError:
adaptiveclass = ['None','PR1','PR2','PR3','FES']
if race.sessiontype == 'race':
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
boatclass__in=boatclass,
boattype__in=boattype,
sex__in=sex,
weightcategory__in=weightcategory,
adaptiveclass__in=adaptiveclass,
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,
adaptiveclass__in=adaptiveclass,
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,
adaptiveclass__in=adaptiveclass,
age__gte=age_min,
age__lte=age_max
)
else:
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
coursecompleted=True,
).order_by("duration","-distance")
if results:
form = RaceResultFilterForm(records=records)
else:
form = None
breadcrumbs = [
{
'url':reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url':reverse('virtualevent_view',
kwargs={'id':race.id}
),
'name': race.name
}
]
racelogos = race.logos.all()
if racelogos:
racelogo = racelogos[0]
else:
racelogo = None
comments = PlannedSessionComment.objects.filter(plannedsession=race).order_by("created")
return render(request,'virtualevent.html',
{
'coursescript':script,
'coursediv':div,
'breadcrumbs':breadcrumbs,
'race':race,
'rower':r,
'results':results,
'buttons':buttons,
'dns':dns,
'records':records,
'racelogo':racelogo,
'form':form,
'active':'nav-racing',
'comments':comments
})
def virtualevent_ranking_view(request,id=0):
results = []
if not request.user.is_anonymous:
r = getrower(request.user)
else:
r = None
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
if race.sessiontype == 'race':
script,div = course_map(race.course)
resultobj = VirtualRaceResult
else:
script = ''
div = ''
resultobj = IndoorVirtualRaceResult
records = resultobj.objects.filter(race=race)
buttons = []
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
)
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
if request.method == 'POST':
form = RaceResultFilterForm(request.POST,records=records)
if form.is_valid():
cd = form.cleaned_data
try:
sex = cd['sex']
except KeyError:
sex = ['female','male','mixed']
try:
boattype = cd['boattype']
except KeyError:
boattype = mytypes.waterboattype
try:
boatclass = cd['boatclass']
except KeyError:
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']
try:
weightcategory = cd['weightcategory']
except KeyError:
weightcategory = ['hwt','lwt']
try:
adaptiveclass = cd['adaptiveclass']
except KeyError:
adaptiveclass = ['None','PR1','PR2','PR3','FES']
if race.sessiontype == 'race':
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
boatclass__in=boatclass,
boattype__in=boattype,
sex__in=sex,
weightcategory__in=weightcategory,
adaptiveclass__in=adaptiveclass,
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,
adaptiveclass__in=adaptiveclass,
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,
adaptiveclass__in=adaptiveclass,
age__gte=age_min,
age__lte=age_max
)
else:
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
coursecompleted=True,
).order_by("duration","-distance")
if results:
form = RaceResultFilterForm(records=records)
else:
form = None
breadcrumbs = [
{
'url':reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url':reverse('virtualevent_view',
kwargs={'id':race.id}
),
'name': race.name
}
]
racelogos = race.logos.all()
if racelogos:
racelogo = racelogos[0]
else:
racelogo = None
return render(request,'virtualeventranking.html',
{
'coursescript':script,
'coursediv':div,
'breadcrumbs':breadcrumbs,
'race':race,
'rower':r,
'results':results,
'buttons':buttons,
'dns':dns,
'records':records,
'racelogo':racelogo,
'form':form,
'active':'nav-racing',
})
@login_required()
def virtualevent_withdraw_view(request,id=0,recordid=None):
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
if race_can_withdraw(r,race):
remove_rower_race(r,race,recordid=recordid)
messages.info(request,
"You have successfully withdrawn from this race.")
else:
messages.error(request,"You cannot withdraw from this race")
url = reverse('virtualevent_view',
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
@login_required()
def virtualevent_addboat_view(request,id=0):
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
if not race_can_adddiscipline(r,race):
messages.error(request,"You cannot register for this race")
url = reverse('virtualevent_view',
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
records = VirtualRaceResult.objects.filter(
userid = r.id,
race = race
)
boattypes = [record.boattype for record in records]
boatclasses = [record.boatclass for record in records]
allowedboats = tuple([ type for type in mytypes.boattypes if type[0] not in boattypes] )
# we're still here
if request.method == 'POST':
# process form
form = VirtualRaceResultForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
teamname = cd['teamname']
boattype = cd['boattype']
boatclass = cd['boatclass']
weightcategory = cd['weightcategory']
adaptiveclass = cd['adaptiveclass']
age = cd['age']
mix = cd['mix']
sex = r.sex
if mix:
sex = 'mixed'
if boattype == '1x' and r.birthdate:
age = calculate_age(r.birthdate)
sex = r.sex
if sex == 'not specified':
sex = 'male'
if boattype in boattypes and boatclass in boatclasses:
# check if different sexes
therecords = records.filter(
boattype=boattype,
boatclass=boatclass)
thesexes = [record.sex for record in therecords]
if sex in thesexes:
messages.error(
request,
"You have already registered in that boat class/type"
)
url = reverse('virtualevent_view',
kwargs = {
'id': race.id
}
)
return HttpResponseRedirect(url)
record = VirtualRaceResult(
userid=r.id,
teamname=teamname,
race=race,
username = u'{f} {l}'.format(
f = r.user.first_name,
l = r.user.last_name
),
weightcategory=weightcategory,
adaptiveclass=adaptiveclass,
duration=datetime.time(0,0),
boattype=boattype,
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,
'adaptiveclass': r.adaptiveclass,
}
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'
}
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,'virtualeventregister.html',
{
'form':form,
'buttons':buttons,
'breadcrumbs':breadcrumbs,
'race':race,
'userid':r.user.id,
'active': 'nav-racing',
})
@login_required()
def virtualevent_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 = VirtualRaceResultForm(request.POST)
if form.is_valid():
cd = form.cleaned_data
teamname = cd['teamname']
boattype = cd['boattype']
boatclass = cd['boatclass']
weightcategory = cd['weightcategory']
adaptiveclass = cd['adaptiveclass']
age = cd['age']
mix = cd['mix']
sex = r.sex
if mix:
sex = 'mixed'
if boattype == '1x' and r.birthdate:
age = calculate_age(r.birthdate)
sex = r.sex
if sex == 'not specified':
sex = 'male'
record = VirtualRaceResult(
userid=r.id,
teamname=teamname,
race=race,
username = u'{f} {l}'.format(
f = r.user.first_name,
l = r.user.last_name
),
weightcategory=weightcategory,
adaptiveclass=adaptiveclass,
duration=datetime.time(0,0),
boatclass=boatclass,
boattype=boattype,
coursecompleted=False,
sex=sex,
age=age
)
record.save()
add_rower_race(r,race)
otherrecords = IndoorVirtualRaceResult.objects.filter(
race = race).exclude(userid = r.id)
for otherrecord in otherrecords:
otheruser = Rower.objects.get(id=otherrecord.userid)
othername = otheruser.user.first_name+' '+otheruser.user.last_name
registeredname = r.user.first_name+' '+r.user.last_name
if otherrecord.emailnotifications:
job = myqueue(
queue,
handle_sendemail_raceregistration,
otheruser.user.email, othername,
registeredname,
race.name,
race.id
)
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,
'adaptiveclass': r.adaptiveclass,
}
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'
}
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,'virtualeventregister.html',
{
'form':form,
'buttons':buttons,
'breadcrumbs':breadcrumbs,
'race':race,
'userid':r.user.id,
})
@login_required()
def virtualevent_toggle_email_view(request,id=0):
r = getrower(request.user)
race = VirtualRace.objects.get(id=id)
records = VirtualRaceResult.objects.filter(userid=r.id,race=race)
if True in [record.emailnotifications for record in records]:
newsetting = False
else:
newsetting = True
for record in records:
record.emailnotifications = newsetting
record.save()
url = reverse('virtualevent_view',
kwargs={'id':race.id})
return HttpResponseRedirect(url)
@login_required()
def indoorvirtualevent_toggle_email_view(request,id=0):
r = getrower(request.user)
race = VirtualRace.objects.get(id=id)
records = IndoorVirtualRaceResult.objects.filter(userid=r.id,
race=race)
if True in [record.emailnotifications for record in records]:
newsetting = False
else:
newsetting = True
for record in records:
record.emailnotifications = newsetting
record.save()
url = reverse('virtualevent_view',
kwargs={'id':race.id})
return HttpResponseRedirect(url)
@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']
adaptiveclass = cd['adaptiveclass']
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,
adaptiveclass=adaptiveclass,
duration=datetime.time(0,0),
boatclass=boatclass,
coursecompleted=False,
sex=sex,
age=age
)
record.save()
add_rower_race(r,race)
otherrecords = IndoorVirtualRaceResult.objects.filter(
race = race).exclude(userid = r.id)
for otherrecord in otherrecords:
otheruser = Rower.objects.get(id=otherrecord.userid)
othername = otheruser.user.first_name+' '+otheruser.user.last_name
registeredname = r.user.first_name+' '+r.user.last_name
if otherrecord.emailnotifications:
job = myqueue(
queue,
handle_sendemail_raceregistration,
otheruser.user.email, othername,
registeredname,
race.name,
race.id
)
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,
'adaptiveclass': r.adaptiveclass,
}
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'
}
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,'virtualeventregister.html',
{
'form':form,
'buttons':buttons,
'race':race,
'breadcrumbs':breadcrumbs,
'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 or settings.TESTING:
dotweet = False
elif 'dev' in settings.SITE_URL:
dotweet = False
else:
dotweet = True
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(timezone=r.defaulttimezone)
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()
def virtualevent_create_view(request):
r = getrower(request.user)
if request.method == 'POST':
racecreateform = VirtualRaceForm(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']
course = cd['course']
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
geocourse = GeoCourse.objects.get(id= course.id)
timezone_str = get_course_timezone(geocourse)
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
vs = VirtualRace(
name=name,
startdate=startdate,
preferreddate = startdate,
start_time = start_time,
enddate=enddate,
end_time=end_time,
course=geocourse,
comment=comment,
sessiontype = 'race',
timezone=timezone_str,
evaluation_closure=evaluation_closure,
registration_closure=registration_closure,
contact_phone=contact_phone,
contact_email=contact_email,
country = course.country,
manager=request.user,
)
vs.save()
# create Site Announcement & Tweet
if settings.DEBUG or settings.TESTING:
dotweet = False
elif 'dev' in settings.SITE_URL:
dotweet = False
else:
dotweet = True
sa = SiteAnnouncement(
announcement = "New Virtual Race on rowsandall.com: {name} on course {course}".format(
name = name,
course = course.name,
),
dotweet = dotweet
)
sa.save()
url = reverse('virtualevents_view')
return HttpResponseRedirect(url)
else:
racecreateform = VirtualRaceForm()
breadcrumbs = [
{
'url':reverse('virtualevents_view'),
'name': 'Racing'
},
{
'url':reverse(virtualevent_create_view,
),
'name': 'New Virtual Regatta'
},
]
return render(request,'virtualeventcreate.html',
{
'form':racecreateform,
'breadcrumbs':breadcrumbs,
'rower':r,
'active':'nav-racing',
})
@login_required()
def virtualevent_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 = VirtualRaceForm(request.POST,instance=race)
if racecreateform.is_valid():
cd = racecreateform.cleaned_data
res, message = update_virtualrace(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 = 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'
}
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,'virtualeventedit.html',
{
'form':racecreateform,
'breadcrumbs':breadcrumbs,
'buttons':buttons,
'rower':r,
'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'
}
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,'virtualeventedit.html',
{
'form':racecreateform,
'buttons':buttons,
'breadcrumbs':breadcrumbs,
'rower':r,
'race':race,
})
@login_required()
def virtualevent_submit_result_view(request,id=0,workoutid=0):
r = getrower(request.user)
try:
race = VirtualRace.objects.get(id=id)
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)
end_time = race.end_time
end_date = race.enddate
enddatetime = datetime.datetime.combine(end_date, end_time)
enddatetime = pytz.timezone(race.timezone).localize(enddatetime)
can_submit = race_can_submit(r,race) or race_can_resubmit(r,race)
if race.sessiontype == 'race':
resultobj = VirtualRaceResult
else:
resultobj = IndoorVirtualRaceResult
records = resultobj.objects.filter(
userid = r.id,
race=race
)
entrychoices = []
for record in records:
rtpl = (record.id, record.__str__())
entrychoices.append(rtpl)
entries = {}
entries['choices'] = entrychoices
entries['initial'] = [records[0].id]
if not can_submit:
messages.error(request,'You cannot submit a result to this race')
url = reverse('virtualevent_view',
kwargs = {
'id':id
}
)
return HttpResponseRedirect(url)
ws = Workout.objects.filter(
user=r,
workouttype__in=mytypes.rowtypes,
startdatetime__gte=startdatetime,
startdatetime__lte=enddatetime,
).order_by("date","startdatetime","id")
if not ws:
messages.info(
request,
'You have no workouts executed during the race window. Please upload a result or enter it manually.'
)
url = reverse('virtualevent_view',
kwargs = {
'id':id
})
return HttpResponseRedirect(url)
initialworkouts = [w.id for w in Workout.objects.filter(
user=r,plannedsession=race
)]
workoutdata = {}
workoutdata['initial'] = []
choices = []
for w in ws:
wtpl = (w.id, w.__str__())
choices.append(wtpl)
if w.id in initialworkouts:
workoutdata['initial'].append(w.id)
workoutdata['choices'] = tuple(choices)
if request.method == 'POST':
w_form = WorkoutRaceSelectForm(workoutdata,entries,request.POST)
if w_form.is_valid():
selectedworkout = w_form.cleaned_data['workouts']
splitsecond = 0
recordid = w_form.cleaned_data['record']
else:
selectedworkout = None
if selectedworkout is not None:
workouts = Workout.objects.filter(id=selectedworkout)
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)
for c in comments:
messages.info(request,c)
for er in errors:
messages.error(request,er)
if jobid:
try:
request.session['async_tasks'] += [(jobid,'submit_race')]
except KeyError:
request.session['async_tasks'] = [(jobid,'submit_race')]
messages.info(request,"We are evaluating your result. The page will reload when we're done. Your result will show up if you adhered to the course")
if result:
otherrecords = resultobj.objects.filter(
race = race).exclude(userid = r.id)
if not jobid:
messages.info(request,"Result submitted successfully.")
for otherrecord in otherrecords:
otheruser = Rower.objects.get(id=otherrecord.userid)
othername = otheruser.user.first_name+' '+otheruser.user.last_name
registeredname = r.user.first_name+' '+r.user.last_name
if otherrecord.emailnotifications:
job = myqueue(
queue,
handle_sendemail_racesubmission,
otheruser.user.email, othername,
registeredname,
race.name,
race.id
)
# redirect to race page
url = reverse('virtualevent_view',
kwargs = {
'id':race.id
})
return HttpResponseRedirect(url)
else:
if workoutid:
workoutdata['initial'] = encoder.decode_hex(workoutid)
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'
}
]
buttons = []
if not request.user.is_anonymous:
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
return render(request,'race_submit.html',
{
'race':race,
'buttons':buttons,
'workouts':ws,
'breadcrumbs':breadcrumbs,
'active':'nav-racing',
'rower':r,
'w_form':w_form,
})