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