From 6a9b61bef3057bd6382ffbe599be066362994559 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 19 Apr 2018 13:28:12 +0200 Subject: [PATCH] register and withdraw done --- rowers/models.py | 37 ++++++++-- rowers/plannedsessions.py | 107 ++++++++++++++++++++++++++++- rowers/templates/virtualevent.html | 66 +++++++++++++++++- rowers/urls.py | 2 + rowers/views.py | 71 +++++++++++++++++-- 5 files changed, 270 insertions(+), 13 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index dade1028..20b86584 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -422,6 +422,12 @@ def course_length(course): return int(totaldist) +sexcategories = ( + ('male','male'), + ('female','female'), + ('not specified','not specified'), +) + # Extension of User with rowing specific data class Rower(models.Model): weightcategories = ( @@ -429,11 +435,6 @@ class Rower(models.Model): ('lwt','light-weight'), ) - sexcategories = ( - ('male','male'), - ('female','female'), - ('not specified','not specified'), - ) stravatypes = ( ('Ride','Ride'), @@ -1066,6 +1067,10 @@ class VirtualRace(PlannedSession): end_time = models.TimeField(blank=True,null=True) country = models.CharField(max_length=100,blank=True) + timezone = models.CharField(default='UTC', + choices=timezones, + max_length=100) + phone_regex = RegexValidator( regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed." @@ -1087,6 +1092,8 @@ class VirtualRace(PlannedSession): ) return stri + + # Date input utility class DateInput(forms.DateInput): @@ -1199,12 +1206,12 @@ class PlannedSessionFormSmall(ModelForm): 'manager': forms.HiddenInput(), } +boattypes = types.boattypes # Workout class Workout(models.Model): workouttypes = types.workouttypes workoutsources = types.workoutsources - boattypes = types.boattypes privacychoices = types.privacychoices user = models.ForeignKey(Rower) @@ -1317,6 +1324,24 @@ def auto_delete_strokedata_on_delete(sender, instance, **kwargs): conn.close() engine.dispose() +# Virtual Race results (for keeping results when workouts are deleted) +class VirtualRaceResult(models.Model): + user = models.ForeignKey(Rower) + username = models.CharField(max_length=150) + workout = models.ForeignKey(Workout) + race = models.ForeignKey(VirtualRace) + duration = models.TimeField(default=3600) + boattype = models.CharField(choices=boattypes,max_length=40, + default='1x', + verbose_name = 'Boat Type' + ) + + sex = models.CharField(default="not specified", + max_length=30, + choices=sexcategories, + verbose_name='Gender') + + from rowers.metrics import rowingmetrics strokedatafields = { diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index f4c58ad5..7aa5f311 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -477,6 +477,7 @@ def update_virtualrace(ps,cd): ps.registration_closure.replace(tzinfo=None) ) + ps.timezone = timezone_str ps.save() @@ -488,6 +489,110 @@ def race_rower_status(r,race): is_complete = is_session_complete_ws(ws,race)[1] - has_registered = r in race.rower + has_registered = r in race.rower.all() return is_complete,has_registered + + +def race_can_submit(r,race): + if r not in race.rower.all(): + return False + + start_time = race.start_time + start_date = race.startdate + startdatetime = datetime.combine(start_date,start_time) + startdatetime = pytz.timezone(race.timezone).localize( + startdatetime + ) + evaluation_closure = race.evaluation_closure + + + if timezone.now() > startdatetime and timezone.now() < evaluation_closure: + is_complete,has_registered = race_rower_status(r,race) + if is_complete == 'not done': + return True + else: + return False + else: + return False + + return False + +def race_can_resubmit(r,race): + if r not in race.rower.all(): + return False + + start_time = race.start_time + start_date = race.startdate + startdatetime = datetime.combine(start_date,start_time) + startdatetime = pytz.timezone(race.timezone).localize( + startdatetime + ) + evaluation_closure = race.evaluation_closure + + + if timezone.now() > startdatetime and timezone.now() < evaluation_closure: + is_complete,has_registered = race_rower_status(r,race) + if is_complete in ['partial','completed']: + return True + else: + return False + else: + return False + + return False + +def race_can_withdraw(r,race): + if r not in race.rower.all(): + return False + + start_time = race.start_time + start_date = race.startdate + startdatetime = datetime.combine(start_date,start_time) + startdatetime = pytz.timezone(race.timezone).localize( + startdatetime + ) + + registration_closure = race.registration_closure + if registration_closure is not None and registration_closure != '': + if timezone.now() > registration_closure: + return False + elif timezone.now() > startdatetime: + return False + elif timezone.now() > startdatetime: + return False + + return True + +def race_can_register(r,race): + if r in race.rower.all(): + return False + + start_time = race.start_time + start_date = race.startdate + startdatetime = datetime.combine(start_date,start_time) + startdatetime = pytz.timezone(race.timezone).localize( + startdatetime + ) + + registration_closure = race.registration_closure + if registration_closure is not None and registration_closure != '': + if timezone.now() > registration_closure: + return False + elif timezone.now() > startdatetime: + return False + elif timezone.now() > startdatetime: + return False + + return True + +def add_rower_race(r,race): + race.rower.add(r) + race.save() + + return 1 + +def remove_rower_race(r,race): + race.rower.remove(r) + + return 1 diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 3c50175a..7f7f32d1 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -29,6 +29,12 @@ Course{{ race.course }} + {% if race.has_registration %} + + Registration closure + {{ race.registration_closure }} + + {% endif %} Date{{ race.startdate }} @@ -55,9 +61,31 @@

+ {% if request.user.is_anonymous %}

- hier komen de registratieknoppen en zo + Registered users of rowsandall.com can participate in this event.

+ {% else %} +

+ See race rules below. +

+

+ {% for button in buttons %} + {% if button == 'registerbutton' %} + Register + {% endif %} + {% if button == 'submitbutton' %} + Submit Result + {% endif %} + {% if button == 'resubmitbutton' %} + Submit New Result + {% endif %} + {% if button == 'withdrawbutton' %} + Withdraw + {% endif %} + {% endfor %} +

+ {% endif %}

Results

@@ -65,6 +93,42 @@ No results yet

+
+

Rules

+

+ As a rowsandall.com user, you can + register to take part in this event. + If the race organizer has set a registration deadline, you must + register before the deadline. Otherwise, it is sufficient to + register before the start of the race window. + You can always withdraw from participating before the registration + deadline or the start of the race window, if no registration + deadline was set. +

+

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

+

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

+

Course

diff --git a/rowers/urls.py b/rowers/urls.py index 8baf56d0..c28fbbc7 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -147,6 +147,8 @@ urlpatterns = [ url(r'^virtualevent/create$',views.virtualevent_create_view), url(r'^virtualevent/(?P\d+)$',views.virtualevent_view), url(r'^virtualevent/(?P\d+)/edit$',views.virtualevent_edit_view), + url(r'^virtualevent/(?P\d+)/register$',views.virtualevent_register_view), + url(r'^virtualevent/(?P\d+)/withdraw$',views.virtualevent_withdraw_view), url(r'^list-workouts/$',views.workouts_view), url(r'^list-courses/$',views.courses_view), url(r'^courses/upload$',views.course_upload_view), diff --git a/rowers/views.py b/rowers/views.py index b65ba078..320ac3e3 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -13376,7 +13376,10 @@ def virtualevents_view(request): ) def virtualevent_view(request,id=0): - r = getrower(request.user) + if not request.user.is_anonymous(): + r = getrower(request.user) + else: + r = None try: race = VirtualRace.objects.get(id=id) @@ -13384,7 +13387,21 @@ def virtualevent_view(request,id=0): raise Http404("Virtual Race does not exist") script,div = course_map(race.course) - is_complete,has_registered = race_rower_status(r,race) + + buttons = [] + + if not request.user.is_anonymous(): + if race_can_register(r,race): + buttons += ['registerbutton'] + + if race_can_submit(r,race): + buttons += ['submitbutton'] + + if race_can_resubmit(r,race): + buttons += ['resubmitbutton'] + + if race_can_withdraw(r,race): + buttons += ['withdrawbutton'] return render(request,'virtualevent.html', @@ -13392,11 +13409,54 @@ def virtualevent_view(request,id=0): 'coursescript':script, 'coursediv':div, 'race':race, - 'rower':r - 'has_registered':has_registered, - 'has_rowed':is_complete, + 'rower':r, + 'buttons':buttons, }) +@login_required() +def virtualevent_withdraw_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 race_can_withdraw(r,race): + remove_rower_race(r,race) + 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_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 race_can_register(r,race): + add_rower_race(r,race) + messages.info(request, + "You have successfully registered for this race. Good luck!") + else: + messages.error(request,"You cannot register for this race") + + url = reverse(virtualevent_view, + kwargs = { + 'id':race.id + }) + + return HttpResponseRedirect(url) + @login_required() def virtualevent_create_view(request): r = getrower(request.user) @@ -13451,6 +13511,7 @@ def virtualevent_create_view(request): course=geocourse, comment=comment, sessiontype = 'coursetest', + timezone=timezone_str, has_registration=has_registration, evaluation_closure=evaluation_closure, registration_closure=registration_closure,