diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 62aaeff9..1a48c7ab 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -940,7 +940,7 @@ def email_submit_race(r,race,workoutid): result = add_rower_race(r,race) otherrecords = IndoorVirtualRaceResult.objects.filter( - race = race).exclude(userid = r.id) + race = race) for otherrecord in otherrecords: @@ -978,7 +978,7 @@ def email_submit_race(r,race,workoutid): if result: otherrecords = IndoorVirtualRaceResult.objects.filter( - race = race).exclude(userid = r.id) + race = race) for otherrecord in otherrecords: otheruser = Rower.objects.get(id=otherrecord.userid) diff --git a/rowers/templates/virtualeventranking.html b/rowers/templates/virtualeventranking.html new file mode 100644 index 00000000..dac83880 --- /dev/null +++ b/rowers/templates/virtualeventranking.html @@ -0,0 +1,503 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Virtual Race{% endblock %} + +{% block scripts %} +{% include "monitorjobs.html" %} + +{% endblock %} + +{% block og_title %}{{ race.name }}{% endblock %} +{% block description %}Virtual Rowing Race {{ race.name }}{% endblock %} + +{% if racelogo %} +{% block og_image %} + + + + +{% endblock %} +{% block image_src %} + +{% endblock %} +{% endif %} + +{% block main %} + + +

{{ race.name }}

+ + +
    +
  • +
    +

    + {% if race|is_final %} +

    Final Results

    + {% else %} +

    Results

    + {% endif %} +

    + {% if results or dns %} +

    + + + + + + + + + + + + {% if race.sessiontype == 'race' %} + + {% endif %} + + + + + + + + {% for result in results %} + + + + + + + + + + {% if race.sessiontype == 'race' %} + + {% endif %} + + + + + + {% endfor %} + {% for result in dns %} + + + + + + + + + + {% if race.sessiontype == 'race' %} + + {% endif %} + + + {% endfor %} + +
     NameTeam Name    ClassBoatTimeDistanceDetails 
    {{ forloop.counter }} + + {{ result.username }}{{ result.teamname }}{{ result.age }}{{ result.sex }}{{ result.weightcategory }} + {% if result.adaptiveclass == 'None' %} +   + {% else %} + {{ result.adaptiveclass }} + {% endif %} + {{ result.boatclass }}{{ result.boattype }}{{ result.duration |durationprint:"%H:%M:%S.%f" }}{{ result.distance }} m + + Details + {% if race.manager == request.user and not race|is_final %} + + Disqualify + + {% else %} +   + {% endif %} +
     {{ result.username }}{{ result.teamname }}{{ result.age }}{{ result.sex }}{{ result.weightcategory }} + {% if result.adaptiveclass == 'None' %} +   + {% else %} + {{ result.adaptiveclass }} + {% endif %} + {{ result.boatclass }}{{ result.boattype }}DNS
    +

    +

    + Compare Results +

    + {% else %} +

    + No results yet +

    + {% endif %} +
    +
  • + {% if form %} +
  • + +

    +

    Filter Results

    +

    +

    + +

    + + {{ form.as_table }} +
    + + {% csrf_token %} + +

    +
  • + {% endif %} + {% if racelogo %} +
  • + {{ racelogo.filename }} + {% if race.manager == request.user %} + Edit Image + {% endif %} +
  • + {% endif %} + {% if race.sessiontype == 'race' %} +
  • +

    +

    Course

    +

    +
    + {{ coursediv|safe }} + + {{ coursescript|safe }} +
    +
  • + {% endif %} +
  • +
    +

    +

    Race Information

    +

    +

    + + + {% if race.sessiontype == 'race' %} + + + + {% else %} + + + + + + + {% endif %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Course{{ race.course }}
    Indoor RaceTo be rowed on a Concept2 ergometer
    Time Zone{{ race.timezone }}
    + {{ race.sessionmode }} challenge + {{ race.sessionvalue }} {{ race.sessionunit }} +
    Registration closure{{ race.registration_closure }}
    Date{{ race.startdate }}
    Race Window{{ race.startdate }} {{ race.start_time }} to {{ race.enddate }} {{ race.end_time }}
    Results Submission Deadline{{ race.evaluation_closure }}
    Organizer{{ race.manager.first_name }} {{ race.manager.last_name }}
    Contact Email{{ race.contact_email }}
    Contact Phone{{ race.contact_phone }}
    Comment{{ race.comment|linebreaks }}
    +

    +
    +
  • +
  • +
    + {% if request.user.is_anonymous %} +

    + Registered users of rowsandall.com can participate in this event. Participation is free, unless specified differently in the race comment above. + {% if race.sessiontype == 'race' %} +

    Register

    + {% else %} +

    Register

    + {% endif %} +

    + {% else %} +

    + See race rules below. Participation to this race is free, + unless specified differently in the race comment above. +

    +

    + {% for button in buttons %} + {% if button == 'registerbutton' %} +

    + {% if race.sessiontype == 'race' %} +

    Register

    + {% else %} +

    Register

    + {% endif %} +

    + {% endif %} + {% if button == 'submitbutton' %} + + + + + + + + + + {% if race.sessiontype == 'indoorrace' %} + + + + + {% endif %} +
    + Submit Workout + + Submit a workout that is already on the site as your race result +
    + Upload your race result + + Upload a new workout to the site and submit it as a result. You + need a workout data file. +
    + Enter your race result manually + + If you don't have a data file, enter the results + manually. If you have a photo of the monitor with the + result, it is recommended to add this to the workout. +
    + {% endif %} + {% if button == 'resubmitbutton' %} +

    + Submit New Result +

    + {% endif %} + {% if button == 'withdrawbutton' %} +

    + Withdraw +

    + {% endif %} + {% if button == 'adddisciplinebutton' %} +

    + + Register New Boat + +

    + {% endif %} + {% if button == 'editbutton' %} +

    + {% if race.sessiontype == 'race' %} + Edit Race + + {% else %} + Edit Race + + {% endif %} +

    + {% endif %} + {% endfor %} + {% endif %} +
    +
  • +
  • +
    + {% if records %} +

    Registered Competitors

    + + + + + + {% if race.sessiontype == 'race' %} + + + {% else %} + + {% endif %} + + + + + + + {% for record in records %} + + + + {% if race.sessiontype == 'race' %} + + {% endif %} + + + + + {% if record.userid == rower.id and 'withdrawbutton' in buttons %} + + {% endif %} + + {% endfor %} + +
    NameTeam NameClassBoatClassAgeGenderWeight CategoryAdaptive
    {{ record.username }} + {{ record.teamname }}{{ record.boatclass }}{{ record.boattype }}{{ record.age }}{{ record.sex }}{{ record.weightcategory }} + {% if record.adaptiveclass == 'None' %} +   + {% else %} + {{ record.adaptiveclass }} + {% endif %} + + Withdraw +
    + {% endif %} +
    + {% for record in records %} + {% if record.userid == request.user.rower.id %} + {% if race.sessiontype == 'race' %} + {% if record.emailnotifications %} + + Unsubscribe from race notifications by email + + {% else %} + + Subscribe to race notifications by email + + {% endif %} + {% else %} + {% if record.emailnotifications %} + + Unsubscribe from race notifications by email + + {% else %} + + Subscribe to race notifications by email + + {% endif %} + {% endif %} + {% endif %} + {% endfor %} +
  • +
  • +
    +

    +

    Rules

    +

    +

    + Virtual races are intended as an informal way to add a + competitive element to training and as a quick way to set + up and manage small regattas. +

    +

    + On the water races are rowed on the course shown. + You cannot submit results rowed + on other bodies of water. +

    +

    + Indoor races are open for all, wherever you live. + However, be aware of the + time zone for the race window. +

    +

    + As a rowsandall.com user, you can + register to take part in this event. Please note the registration + deadline. You must register before this deadline. + You can always withdraw from participating before the registration + deadline or the start of the race window, whichever is earlier. +

    +

    + After the start of the race window and before the submission deadline, + you can submit results by linking the race to one of your uploaded + workouts. The workout start time must be within the race window + and your course must pass through the blue polygons on the course + map (in the right order), for your result to be valid. +

    +

    + The results table has a link to a page where details of your workout + are shown. +

    +

    + Race results are stored permanently and are not deleted when + you delete the respective workout or remove your account. + By registering, you agree with this and the race rules. +

    +

    + If you use a manually added workout for your indoor race result, + please attach a screenshot of the ergometer display for verification. +

    +

    + 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 + boat type correctly. For (future functionality) age and gender + corrected times, please be sure your gender and birth date are set + correctly in your user settings. +

    +

    + Virtual races are intended as an informal way to add a + competitive element to training. Virtual races are not + refereed or staffed to provide for participants safety. + Individual participants are entirely responsible for their + safety while participating in a virtual race. +

    +

    + 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. +

    +
    +
  • +
+ +

+

+ Share +
+

+ Tweet + {% else %} + data-text="@rowsandall #rowingdata Participate in Indoor Rowing virtual race '{{ race.name }}'">Tweet +{% endif %} +

+ + +

+ + +{% if not racelogo and race.manager == request.user %} +Add Race Logo +{% endif %} +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index 5201c511..216dabaf 100644 Binary files a/rowers/tests/testdata/testdata.csv.gz and b/rowers/tests/testdata/testdata.csv.gz differ diff --git a/rowers/tests/testdata/testdata.tcx b/rowers/tests/testdata/testdata.tcx index 09a7a0bc..2b309e36 100644 --- a/rowers/tests/testdata/testdata.tcx +++ b/rowers/tests/testdata/testdata.tcx @@ -2502,7 +2502,7 @@ - <Element 'Notes' at 0x153817f0> + <Element 'Notes' at 0x134fa7b8> diff --git a/rowers/urls.py b/rowers/urls.py index ef652679..3972e842 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -149,6 +149,7 @@ urlpatterns = [ url(r'^indoorraceregistration/togglenotification/(?P\d+)/$', views.indoorvirtualevent_toggle_email_view), url(r'^virtualevent/(?P\d+)/$',views.virtualevent_view), + url(r'^virtualevent/(?P\d+)/ranking$',views.virtualevent_ranking_view), url(r'^virtualevent/(?P\d+)/edit/$',views.virtualevent_edit_view), url(r'^virtualevent/(?P\d+)/editindoor/$',views.indoorvirtualevent_edit_view), url(r'^virtualevent/(?P\d+)/register/$',views.virtualevent_register_view), diff --git a/rowers/views.py b/rowers/views.py index 9ca1329c..d92f71dd 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -16128,6 +16128,186 @@ def virtualevent_view(request,id=0): 'active':'nav-racing', }) +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)