From e4e5397e40062f393226a2b78118b8d291ec9d42 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 25 May 2020 21:48:22 +0200 Subject: [PATCH 01/22] First version --- rowers/models.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rowers/models.py b/rowers/models.py index f0659bf1..aa480b92 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -3790,3 +3790,20 @@ class ShareKey(models.Model): @property def expiration_date(self): return self.creation_date + datetime.timedelta(self.expiration_seconds) + +class StandardCollection(models.Model): + name = models.CharField(max_length=150) + +class CourseStandard(models.Model): + name = models.CharField(max_length=150) + coursedistance = models.IntegerField() + coursestandard = models.FloatField() # average boat speed + agemin = models.IntegerField(default=0) + agemax = models.IntegerField(default=120) + boatclass = models.CharField(max_length=150) # corresponds to workout workouttype + boattype = models.CharField(choices=boattypes,max_length=50,default='1x') + sex = models.CharField(max_length=150) + weightclass = models.CharField(max_length=150) + adaptiveclass = models.CharField(choices=mytypes.adaptivetypes,max_length=50,default="None") + skillclass = models.CharField(max_length=150) + standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) From 74ff1f98740bea1c3f18ae237066571e1290b62a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Mon, 25 May 2020 21:58:00 +0200 Subject: [PATCH 02/22] added coursestandards to virtualrace --- rowers/models.py | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index aa480b92..21861c49 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2194,7 +2194,22 @@ class PlannedSession(models.Model): from django.core.validators import RegexValidator,validate_email +class StandardCollection(models.Model): + name = models.CharField(max_length=150) +class CourseStandard(models.Model): + name = models.CharField(max_length=150) + coursedistance = models.IntegerField() + coursestandard = models.FloatField() # average boat speed + agemin = models.IntegerField(default=0) + agemax = models.IntegerField(default=120) + boatclass = models.CharField(max_length=150) # corresponds to workout workouttype + boattype = models.CharField(choices=mytypes.boattypes,max_length=50,default='1x') + sex = models.CharField(max_length=150) + weightclass = models.CharField(max_length=150) + adaptiveclass = models.CharField(choices=mytypes.adaptivetypes,max_length=50,default="None") + skillclass = models.CharField(max_length=150) + standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) registerchoices = ( ('windowstart','Start of challenge Window'), @@ -2233,6 +2248,8 @@ class VirtualRace(PlannedSession): contact_email = models.EmailField(max_length=254, validators=[validate_email],blank=True) + coursestandards = models.ForeignKey(StandardCollection,null=True,on_delete=models.SET_NULL) + def __str__(self): name = self.name @@ -3790,20 +3807,3 @@ class ShareKey(models.Model): @property def expiration_date(self): return self.creation_date + datetime.timedelta(self.expiration_seconds) - -class StandardCollection(models.Model): - name = models.CharField(max_length=150) - -class CourseStandard(models.Model): - name = models.CharField(max_length=150) - coursedistance = models.IntegerField() - coursestandard = models.FloatField() # average boat speed - agemin = models.IntegerField(default=0) - agemax = models.IntegerField(default=120) - boatclass = models.CharField(max_length=150) # corresponds to workout workouttype - boattype = models.CharField(choices=boattypes,max_length=50,default='1x') - sex = models.CharField(max_length=150) - weightclass = models.CharField(max_length=150) - adaptiveclass = models.CharField(choices=mytypes.adaptivetypes,max_length=50,default="None") - skillclass = models.CharField(max_length=150) - standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) From 0229dba4eebdbc2ff9dc920ee0bf55ff455e6122 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 08:04:55 +0200 Subject: [PATCH 03/22] bug fix --- rowers/dataprep.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 252e2bd9..b5712d7a 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1905,7 +1905,10 @@ def testdata(time, distance, pace, spm): def getrowdata_db(id=0, doclean=False, convertnewtons=True, checkefficiency=True): data = read_df_sql(id) - data['deltat'] = data['time'].diff() + try: + data['deltat'] = data['time'].diff() + except KeyError: + data = pd.DataFrame() if data.empty: rowdata, row = getrowdata(id=id) From 08c7562c514ad1b8f91b500fca4efac0db874582 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 10:56:23 +0200 Subject: [PATCH 04/22] more foundation work for scoring --- rowers/admin.py | 10 ++++- rowers/courseutils.py | 13 ++++-- rowers/models.py | 12 +++++ rowers/scoring.py | 102 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 rowers/scoring.py diff --git a/rowers/admin.py b/rowers/admin.py index f0db40e8..490fe9c3 100644 --- a/rowers/admin.py +++ b/rowers/admin.py @@ -11,7 +11,7 @@ from .models import ( Team,TeamInvite,TeamRequest, WorkoutComment,C2WorldClassAgePerformance,PlannedSession, GeoCourse,GeoPolygon,GeoPoint,VirtualRace,VirtualRaceResult, - PaidPlan,IndoorVirtualRaceResult,ShareKey + PaidPlan,IndoorVirtualRaceResult,ShareKey, CourseStandard,StandardCollection, ) # Register your models here so you can use them in the Admin module @@ -141,6 +141,12 @@ class IndoorVirtualRaceResultAdmin(admin.ModelAdmin): class PaidPlanAdmin(admin.ModelAdmin): list_display = ('name','shortname','price','paymenttype','paymentprocessor','external_id') +class StandardCollectionAdmin(admin.ModelAdmin): + list_display = ('name','manager') + +class CourseStandardAdmin(admin.ModelAdmin): + list_display = ('name','standardcollection') + admin.site.unregister(User) admin.site.register(User,UserAdmin) admin.site.register(Workout,WorkoutAdmin) @@ -160,3 +166,5 @@ admin.site.register(VirtualRaceResult, VirtualRaceResultAdmin) admin.site.register(IndoorVirtualRaceResult, IndoorVirtualRaceResultAdmin) admin.site.register(PaidPlan,PaidPlanAdmin) admin.site.register(ShareKey,ShareKeyAdmin) +admin.site.register(CourseStandard,CourseStandardAdmin) +admin.site.register(StandardCollection,StandardCollectionAdmin) diff --git a/rowers/courseutils.py b/rowers/courseutils.py index 39fda8bf..6ff83fc7 100644 --- a/rowers/courseutils.py +++ b/rowers/courseutils.py @@ -2,6 +2,11 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals + + + + + # low level methods def coordinate_in_path(latitude,longitude, p): @@ -18,12 +23,12 @@ def time_in_path(df,p,maxmin='max',getall=False): if df.empty: return 0 - + latitude = df.latitude longitude = df.longitude f = lambda x: coordinate_in_path(x['latitude'],x['longitude'],p) - + df['inpolygon'] = df.apply(f,axis=1) if maxmin=='max': @@ -40,7 +45,7 @@ def time_in_path(df,p,maxmin='max',getall=False): raise InvalidTrajectoryError("Trajectory doesn't go through path") - + return 0 @@ -64,7 +69,7 @@ def coursetime_paths(data,paths,finalmaxmin='min'): entrytime = data['time'].max() entrydistance = data['cum_dist'].max() coursecompleted = False - + # corner case - empty list of paths if len(paths) == 0: return 0,True diff --git a/rowers/models.py b/rowers/models.py index 21861c49..dcf75050 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2196,6 +2196,10 @@ from django.core.validators import RegexValidator,validate_email class StandardCollection(models.Model): name = models.CharField(max_length=150) + manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) + + def __str__(self): + return self.name class CourseStandard(models.Model): name = models.CharField(max_length=150) @@ -2211,6 +2215,14 @@ class CourseStandard(models.Model): skillclass = models.CharField(max_length=150) standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) + class Meta: + unique_together = ('name','sex','agemin', + 'agemax','boatclass','boattype','weightclass','adaptiveclass', + 'skillclass','standardcollection') + + def __str__(self): + return self.name + registerchoices = ( ('windowstart','Start of challenge Window'), ('windowend','End of challenge Window'), diff --git a/rowers/scoring.py b/rowers/scoring.py new file mode 100644 index 00000000..a4a6bd74 --- /dev/null +++ b/rowers/scoring.py @@ -0,0 +1,102 @@ +from rowers.models import StandardCollection,CourseStandard + +import pandas as pd +import arrow +import datetime + +def save_scoring(name,user,filename,id=0): + if id==0: + collection = StandardCollection(name=name,manager=user) + collection.save() + standards = CourseStandard.objects.filter(standardcollection=collection) + for standard in standards: + standard.delete() + else: + try: + collection = StandardCollection.objects.get(id=id) + collection.name = name + collection.save() + + except StandardCollection.DoesNotExist: + return 0 + + try: + df = pd.read_csv(filename) + except: + return 0 + + df = df.drop_duplicates(['Name']) + + for index, row in df.iterrows(): + try: + name = row['Name'] + except KeyError: + continue + + try: + coursedistance = row['CourseDistance'] + coursetime = row['CourseStandard'] + t = datetime.datetime.strptime(coursetime,'%M:%S.%f') + delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second,microseconds=t.microsecond) + seconds = delta.total_seconds() + + coursestandard = coursedistance/seconds + except KeyError: + continue + + try: + agemin = row['MinAge'] + agemax = row['MaxAge'] + agemin = int(agemin) + agemax = int(agemax) + except KeyError: + agemin = 0 + agemax = 120 + + try: + boatclass = row['BoatClass'] + except KeyError: + boatclass = 'water' + + try: + boattype = row['BoatType'] + except KeyError: + boattype = '1x' + + try: + sex = row['Gender'] + except KeyError: + sex = 'F' + + try: + weightclass = row['WeightClass'] + except KeyError: + weightclass = 'hwt' + + try: + adaptiveclass = row['AdaptiveClass'] + except KeyError: + adaptiveclass = None + + try: + skillclass = row['SkillClass'] + except KeyError: + skillclass = 'Open' + + # some testing + standard = CourseStandard( + name=name, + coursedistance=coursedistance, + coursestandard=coursestandard, + agemin=agemin, + agemax=agemax, + boatclass=boatclass, + boattype=boattype, + sex=sex, + weightclass=weightclass, + adaptiveclass=adaptiveclass, + skillclass=skillclass, + standardcollection = collection, + ) + + standard.save() From b953d2714b413706fea0668deb3aafda518b58fd Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 16:47:49 +0200 Subject: [PATCH 05/22] standards_view and standard_view --- rowers/models.py | 2 + rowers/scoring.py | 6 +- rowers/templates/list_standards.html | 84 ++++++++++++++++++++++++++++ rowers/templates/menu_racing.html | 5 ++ rowers/templates/standard_view.html | 72 ++++++++++++++++++++++++ rowers/urls.py | 2 + rowers/views/racesviews.py | 77 +++++++++++++++++++++++++ rowers/views/statements.py | 2 +- 8 files changed, 247 insertions(+), 3 deletions(-) create mode 100644 rowers/templates/list_standards.html create mode 100644 rowers/templates/standard_view.html diff --git a/rowers/models.py b/rowers/models.py index dcf75050..e57a9793 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2197,6 +2197,7 @@ from django.core.validators import RegexValidator,validate_email class StandardCollection(models.Model): name = models.CharField(max_length=150) manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) + notes = models.CharField(blank=True,null=True,max_length=1000) def __str__(self): return self.name @@ -2204,6 +2205,7 @@ class StandardCollection(models.Model): class CourseStandard(models.Model): name = models.CharField(max_length=150) coursedistance = models.IntegerField() + coursetime = models.CharField(max_length=100,default="") coursestandard = models.FloatField() # average boat speed agemin = models.IntegerField(default=0) agemax = models.IntegerField(default=120) diff --git a/rowers/scoring.py b/rowers/scoring.py index a4a6bd74..13ee7098 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -4,9 +4,9 @@ import pandas as pd import arrow import datetime -def save_scoring(name,user,filename,id=0): +def save_scoring(name,user,filename,id=0,notes=""): if id==0: - collection = StandardCollection(name=name,manager=user) + collection = StandardCollection(name=name,manager=user,notes=notes) collection.save() standards = CourseStandard.objects.filter(standardcollection=collection) for standard in standards: @@ -15,6 +15,7 @@ def save_scoring(name,user,filename,id=0): try: collection = StandardCollection.objects.get(id=id) collection.name = name + collection.notes = notes collection.save() except StandardCollection.DoesNotExist: @@ -88,6 +89,7 @@ def save_scoring(name,user,filename,id=0): name=name, coursedistance=coursedistance, coursestandard=coursestandard, + coursetime=coursetime, agemin=agemin, agemax=agemax, boatclass=boatclass, diff --git a/rowers/templates/list_standards.html b/rowers/templates/list_standards.html new file mode 100644 index 00000000..b99ac07f --- /dev/null +++ b/rowers/templates/list_standards.html @@ -0,0 +1,84 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Course Standards List{% endblock %} + +{% block scripts %} + +{% endblock %} + +{% block main %} + + + + +

Standards Collections

+ +
    +
  • + {% if standards %} +

    + + + + + + + + + {% for standard in standards %} + + + + + + + + {% endfor %} + +
    Name Maintainer
    {{ standard.name }} {{ standard.manager.first_name }} {{ standard.manager.last_name }} + {% if standard.manager == user %} + {{ standard.name }} + {% else %} + {{ standard.name }} + {% endif %} +
    +

    + {% else %} +

    No standards found

    + {% endif %} +
  • +
  • +

    +

    + {{ searchform }} + +
    +

    +

    + Add Standards +

    + +
  • + +
  • +

    How-to

    +

    + A set of Course Standard Times allows you to calculate a score for + each participant on how well they have done against the course + standard time for their category. This allows for comparison + and competition between the different categories. +

    +
  • +
+ {% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/templates/menu_racing.html b/rowers/templates/menu_racing.html index c1eb9178..a0a5d76b 100644 --- a/rowers/templates/menu_racing.html +++ b/rowers/templates/menu_racing.html @@ -131,6 +131,11 @@ {% endif %} +
  • + +  Course Time Standards + +
  • {% include 'menuscript.html' %} diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html new file mode 100644 index 00000000..2bc1a232 --- /dev/null +++ b/rowers/templates/standard_view.html @@ -0,0 +1,72 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% load leaflet_tags %} + +{% block meta %} +{% leaflet_js %} +{% leaflet_css %} +{% endblock %} + +{% block scripts %} +{% include "monitorjobs.html" %} +{% endblock %} + +{% block title %}{{ standard.name }} {% endblock %} +{% block og_title %}{{ standard.name }} {% endblock %} +{% block main %} + +

    {{ standard.name }}

    + +
      +
    • + + + + + + + + + + +
      Name{{ collection.name }}
      Manager{{ collection.manager.first_name }} {{ collection.manager.last_name }}
      Notes{{ collection.notes|linebreaks }}
      +
    • +
    • +

      Standard Times

      + + + + + + + + + + + + + {% for standard in standards %} + + + + + + + + + + + + + {% endfor %} +
      NameDistanceStandard TimeBoat ClassBoat TypeGenderWeight ClassAdaptive ClassSkill ClassMinimum/Maximum Age
      {{ standard.name }}{{ standard.coursedistance }}{{ standard.coursetime }}{{ standard.boatclass }}{{ standard.boattype }}{{ standard.sex }}{{ standard.weightclass }}{{ standard.adaptiveclass }}{{ standard.skillclass }}{{ standard.agemin }}/{{ standard.agemax }}
      +
    • +
    + +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index ad52fd3b..ea85a5ad 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -201,6 +201,7 @@ urlpatterns = [ views.virtualevent_results_download_view,name='virtualevent_results_download_view'), re_path(r'^list-workouts/$',views.workouts_view,name='workouts_view'), re_path(r'^list-courses/$',views.courses_view,name='courses_view'), + re_path(r'^list-standards/$',views.standards_view,name='standards_view'), re_path(r'^courses/upload/$',views.course_upload_view,name='course_upload_view'), re_path(r'^workout/addmanual/(?P\d+)$',views.addmanual_view,name='addmanual_view'), re_path(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'), @@ -752,6 +753,7 @@ urlpatterns = [ re_path(r'^courses/(?P\d+)/replace/$',views.course_replace_view, name='course_replace_view'), re_path(r'^courses/(?P\d+)/$',views.course_view,name='course_view'), + re_path(r'^standards/(?P\d+)/$',views.standard_view,name='standard_view'), re_path(r'^courses/(?P\d+)/map/$',views.course_map_view,name='course_map_view'), # URLS to be created re_path(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'), diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 606dbdb0..591458a5 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -35,6 +35,39 @@ def courses_view(request): 'rower':r, }) +# List Courses +def standards_view(request): + r = getrower(request.user) + + standards = StandardCollection.objects.all().order_by("name") + print(standards) + + # add search processing + query = request.GET.get('q') + if query: + query_list = query.split() + standards = StandardCollection.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() + + print(standards) + + return render(request,'list_standards.html', + {'standards':standards, + 'active':'nav-racing', + 'searchform':searchform, + 'rower':r, + }) + + # for ajax calls def course_map_view(request,id=0): @@ -249,6 +282,50 @@ def course_view(request,id=0): } ) +def standard_view(request,id=0): + try: + collection = StandardCollection.objects.get(id=id) + except StandardCollection.DoesNotExist: + return Http404("Standard Collection does not exist") + + r = getrower(request.user) + + orderby = request.GET.get('order_by') + + if orderby is not None: + standards = CourseStandard.objects.filter( + standardcollection=collection + ).order_by(orderby,"-coursestandard","agemax","agemin","sex","name") + else: + standards = CourseStandard.objects.filter( + standardcollection=collection + ).order_by("-coursestandard","agemax","agemin","sex","name") + + breadcrumbs = [ + { + 'url': reverse('virtualevents_view'), + 'name': 'Challenges' + }, + { + 'url': reverse(standards_view), + 'name': 'Standards' + }, + { + 'url': reverse(standard_view,kwargs={'id':collection.id}), + 'name': collection.name + }, + ] + + return render(request, 'standard_view.html', + { + 'active':'nav-racing', + 'breadcrumbs':breadcrumbs, + 'collection':collection, + 'standards':standards, + 'rower':r, + } + ) + @login_required() @permission_required('racelogo.delete_logo',fn=get_logo_by_pk,raise_exception=True) def logo_delete_view(request,id=0): diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 156919f9..29a68349 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -113,7 +113,7 @@ from rowers.models import ( RaceLogo,RowerBillingAddressForm,PaidPlan, AlertEditForm, ConditionEditForm, PlannedSessionComment,CoachRequest,CoachOffer, - VideoAnalysis,ShareKey, + VideoAnalysis,ShareKey,StandardCollection,CourseStandard, ) from rowers.models import ( RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm, From 496f265908c626ffc349d35639210b12e78d443b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 18:12:23 +0200 Subject: [PATCH 06/22] Course Times Standards CSV v1 working --- rowers/forms.py | 12 ++ rowers/scoring.py | 3 + rowers/templates/course_form.html | 29 +-- rowers/templates/standard_form.html | 265 ++++++++++++++++++++++++++++ rowers/urls.py | 1 + rowers/views/racesviews.py | 67 ++++++- rowers/views/statements.py | 2 +- 7 files changed, 362 insertions(+), 17 deletions(-) create mode 100644 rowers/templates/standard_form.html diff --git a/rowers/forms.py b/rowers/forms.py index bf7f79cd..f6305846 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -212,6 +212,18 @@ class CourseForm(forms.Form): from django.forms.widgets import HiddenInput super(CourseForm, self).__init__(*args, **kwargs) +# The form used for uploading images +class StandardsForm(forms.Form): + name = forms.CharField(max_length=150,label='Course Name') + file = forms.FileField(required=False, + validators=[must_be_csv]) + notes = forms.CharField(required=False, + max_length=200,label='Course Notes', + widget=forms.Textarea) + + def __init__(self, *args, **kwargs): + from django.forms.widgets import HiddenInput + super(StandardsForm, self).__init__(*args, **kwargs) # The form used for uploading files class DocumentsForm(forms.Form): diff --git a/rowers/scoring.py b/rowers/scoring.py index 13ee7098..f0093af6 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -5,6 +5,7 @@ import arrow import datetime def save_scoring(name,user,filename,id=0,notes=""): + print(notes) if id==0: collection = StandardCollection(name=name,manager=user,notes=notes) collection.save() @@ -102,3 +103,5 @@ def save_scoring(name,user,filename,id=0,notes=""): ) standard.save() + + return collection.id diff --git a/rowers/templates/course_form.html b/rowers/templates/course_form.html index fe6e1962..5a346104 100644 --- a/rowers/templates/course_form.html +++ b/rowers/templates/course_form.html @@ -30,7 +30,7 @@ Please correct the error{{ form.errors|pluralize }} below.

    {% endif %} - + {{ form.as_table }}
    @@ -71,13 +71,13 @@ if (!formdatasetok) { $("#id_dropregion").remove(); } - + if (formdatasetok) { - + $(document).ready(function() { var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val(); console.log("CSRF token",csrftoken); - + function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); @@ -95,11 +95,11 @@ $(window).on('dragenter', function() { $("#id_drop-files").css("background-color","#E9E9E4"); $("#id_dropregion").addClass("watermark").removeClass("invisible");}) - + $(window).on('dragleave', function() { $("#id_drop-files").css("background-color","#FFFFFF"); $("#id_dropregion").removeClass("watermark").addClass("invisible");}) - + var frm = $("#file_form"); if( window.FormData === undefined ) { @@ -108,7 +108,7 @@ } else { console.log('we have formdata'); } - + var data = new FormData(frm[0]); @@ -144,7 +144,7 @@ } } -}); +}); $('input').each(function( i ) { $(this).change(function() { @@ -159,7 +159,14 @@ console.log($(this).attr('name'),$(this).val()); }; });}); - + + $('textarea').each(function( i ) { + $(this).change(function() { + data.set($(this).attr('name'),$(this).val()); + console.log($(this).attr('name'),$(this).val()); + }); + }); + $('select').each(function( i ) { console.log($(this).attr('name'),$(this).val()); $(this).change(function() { @@ -200,7 +207,7 @@ console.log(result," reloading"); location.reload(); }; - } + } }); return false; }); @@ -236,7 +243,7 @@ $("#id_file").value = 0; return false; } - data.set("file",f); + data.set("file",f); // data.append("file",f); $("#id_file").replaceWith('
    '+files[0].name+'  X
    '); diff --git a/rowers/templates/standard_form.html b/rowers/templates/standard_form.html new file mode 100644 index 00000000..777c1857 --- /dev/null +++ b/rowers/templates/standard_form.html @@ -0,0 +1,265 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}File loading{% endblock %} + +{% block meta %} + + + +{% endblock %} + +{% block main %} +

    Upload Course Standard Times File

    + +
      +
    • +
      +

      Drag and drop files here

      +
      +
      +
      + {% if form.errors %} +

      + Please correct the error{{ form.errors|pluralize }} below. +

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

      + +

      +
      +
      +
    • +
    + + + + +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} + + +{% block scripts %} + + + + {% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index ea85a5ad..6304f2db 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -203,6 +203,7 @@ urlpatterns = [ re_path(r'^list-courses/$',views.courses_view,name='courses_view'), re_path(r'^list-standards/$',views.standards_view,name='standards_view'), re_path(r'^courses/upload/$',views.course_upload_view,name='course_upload_view'), + re_path(r'^standards/upload/$',views.standards_upload_view,name='standards_upload_view'), re_path(r'^workout/addmanual/(?P\d+)$',views.addmanual_view,name='addmanual_view'), re_path(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'), re_path(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 591458a5..27a98f43 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -5,6 +5,7 @@ from __future__ import unicode_literals from rowers.views.statements import * from rowsandall_app.settings import SITE_URL +from rowers.scoring import * # List Courses def courses_view(request): @@ -40,7 +41,6 @@ def standards_view(request): r = getrower(request.user) standards = StandardCollection.objects.all().order_by("name") - print(standards) # add search processing query = request.GET.get('q') @@ -49,8 +49,6 @@ def standards_view(request): standards = StandardCollection.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)) ) @@ -58,7 +56,6 @@ def standards_view(request): else: searchform = SearchForm() - print(standards) return render(request,'list_standards.html', {'standards':standards, @@ -464,7 +461,7 @@ def virtualevent_uploadimage_view(request,id=0): }) -# Image upload +# Course upload @login_required() def course_upload_view(request): is_ajax = False @@ -524,6 +521,66 @@ def course_upload_view(request): else: return {'result':0} +# Standards upload +@login_required() +def standards_upload_view(request,id=0): + is_ajax = False + if request.is_ajax(): + is_ajax = True + r = getrower(request.user) + + + if request.method == 'POST': + print(request.POST) + form = StandardsForm(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) + + id = save_scoring(name,request.user,path_and_filename,notes=notes,id=id) + print(notes) + + os.remove(path_and_filename) + + + + if id==0: + url = reverse(standards_view) + else: + url = reverse(standard_view,kwargs={'id':id}) + + if is_ajax: + return JSONResponse({'result':1,'url':url}) + + return HttpResponseRedirect(url) + + else: + messages.error(request,'Something went wrong - no file attached') + url = reverse(standards_upload_view) + if is_ajax: + return JSONResponse({'result':0,'url':0}) + + return HttpResponseRedirect(url) + else: + messages.error(request,'Form is not valid') + print(form.errors) + return render(request,'standard_form.html', + {'form':form, + }) + + else: + if not is_ajax: + form = StandardsForm() + return render(request,'standard_form.html', + {'form':form, + 'active':'nav-racing', + }) + return {'result':0} + def virtualevents_view(request): is_ajax = False diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 29a68349..2d6f0761 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -93,7 +93,7 @@ from rowers.forms import ( FitnessMetricForm,PredictedPieceFormNoDistance, EmailForm, RegistrationForm, RegistrationFormTermsOfService, RegistrationFormUniqueEmail,RegistrationFormSex, - CNsummaryForm,UpdateWindForm, + CNsummaryForm,UpdateWindForm,StandardsForm, UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm, FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm, TrendFlexModalForm,WorkoutSplitForm,WorkoutJoinParamForm, From 0eef902ccc708c49ddc9efa3dbc828bd74053421 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 18:21:56 +0200 Subject: [PATCH 07/22] Adding Course Update --- rowers/scoring.py | 1 - rowers/templates/standard_view.html | 3 +++ rowers/urls.py | 1 + rowers/views/racesviews.py | 4 +--- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rowers/scoring.py b/rowers/scoring.py index f0093af6..1156bc25 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -5,7 +5,6 @@ import arrow import datetime def save_scoring(name,user,filename,id=0,notes=""): - print(notes) if id==0: collection = StandardCollection(name=name,manager=user,notes=notes) collection.save() diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html index 2bc1a232..e42b4aad 100644 --- a/rowers/templates/standard_view.html +++ b/rowers/templates/standard_view.html @@ -32,6 +32,9 @@ +
  • +

    Update these Standard Times +

  • Standard Times

    \d+)/$',views.standards_upload_view,name='standards_upload_view'), re_path(r'^workout/addmanual/(?P\d+)$',views.addmanual_view,name='addmanual_view'), re_path(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'), re_path(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 27a98f43..700adfac 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -531,7 +531,6 @@ def standards_upload_view(request,id=0): if request.method == 'POST': - print(request.POST) form = StandardsForm(request.POST,request.FILES) if form.is_valid(): @@ -542,7 +541,7 @@ def standards_upload_view(request,id=0): filename,path_and_filename = handle_uploaded_file(f) id = save_scoring(name,request.user,path_and_filename,notes=notes,id=id) - print(notes) + os.remove(path_and_filename) @@ -567,7 +566,6 @@ def standards_upload_view(request,id=0): return HttpResponseRedirect(url) else: messages.error(request,'Form is not valid') - print(form.errors) return render(request,'standard_form.html', {'form':form, }) From 16ca9da117e4702aba14ff9c21bb831b795849ee Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 20:15:07 +0200 Subject: [PATCH 08/22] migration fixed --- rowers/migrations/0001_initial.py | 203 ++++++++++++++++++++---------- rowsandall_app/settings.py | 4 + 2 files changed, 143 insertions(+), 64 deletions(-) diff --git a/rowers/migrations/0001_initial.py b/rowers/migrations/0001_initial.py index 84b67e88..ee6b4a02 100644 --- a/rowers/migrations/0001_initial.py +++ b/rowers/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.7 on 2019-07-26 09:28 +# Generated by Django 2.1.7 on 2020-05-26 18:13 import datetime from django.conf import settings @@ -19,6 +19,28 @@ class Migration(migrations.Migration): ] operations = [ + migrations.CreateModel( + name='Alert', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, max_length=150, null=True, verbose_name='Alert Name')), + ('reststrokes', models.BooleanField(default=False, null=True, verbose_name='Include Rest Strokes')), + ('period', models.IntegerField(default=7, verbose_name='Reporting Period (days)')), + ('next_run', models.DateField(default=django.utils.timezone.now)), + ('emailalert', models.BooleanField(default=True, verbose_name='Send email alerts')), + ('workouttype', models.CharField(choices=[('water', 'Standard Racing Shell'), ('rower', 'Indoor Rower'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides'), ('coastal', 'Coastal'), ('c-boat', 'Dutch C boat'), ('churchboat', 'Finnish Church boat')], default='water', max_length=50, verbose_name='Exercise/Boat Class')), + ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50, verbose_name='Boat Type')), + ], + ), + migrations.CreateModel( + name='BlogPost', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('title', models.TextField(max_length=300)), + ('link', models.TextField(max_length=300)), + ('date', models.DateField()), + ], + ), migrations.CreateModel( name='C2WorldClassAgePerformance', fields=[ @@ -70,6 +92,34 @@ class Migration(migrations.Migration): ('code', models.CharField(max_length=150, unique=True)), ], ), + migrations.CreateModel( + name='Condition', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('metric', models.CharField(choices=[('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='Metric')), + ('value1', models.FloatField(default=0)), + ('value2', models.FloatField(blank=True, default=0, null=True)), + ('condition', models.CharField(choices=[('<', '<'), ('>', '>'), ('=', '='), ('between', 'between')], max_length=20, null=True)), + ], + ), + migrations.CreateModel( + name='CourseStandard', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(max_length=150)), + ('coursedistance', models.IntegerField()), + ('coursetime', models.CharField(default='', max_length=100)), + ('coursestandard', models.FloatField()), + ('agemin', models.IntegerField(default=0)), + ('agemax', models.IntegerField(default=120)), + ('boatclass', models.CharField(max_length=150)), + ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50)), + ('sex', models.CharField(max_length=150)), + ('weightclass', models.CharField(max_length=150)), + ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50)), + ('skillclass', models.CharField(max_length=150)), + ], + ), migrations.CreateModel( name='CourseTestResult', fields=[ @@ -122,9 +172,9 @@ class Migration(migrations.Migration): name='FavoriteChart', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('yparam1', models.CharField(choices=[('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distance', 'Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('powerhr', 'Power Heart Rate Efficiency (J/beat)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='Y1')), - ('yparam2', models.CharField(blank=True, choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distance', 'Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('powerhr', 'Power Heart Rate Efficiency (J/beat)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], default='None', max_length=50, verbose_name='Y2')), - ('xparam', models.CharField(choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distance', 'Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('powerhr', 'Power Heart Rate Efficiency (J/beat)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='X')), + ('yparam1', models.CharField(choices=[('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='Y1')), + ('yparam2', models.CharField(blank=True, choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], default='None', max_length=50, verbose_name='Y2')), + ('xparam', models.CharField(choices=[('None', ''), ('averageforce', 'Average Drive Force (N)'), ('forceratio', 'Average/Peak Force Ratio'), ('velo', 'Boat Speed (m/s)'), ('catch', 'Catch Angle (degrees)'), ('cumdist', 'Cumulative Distance (m)'), ('distanceperstroke', 'Distance per Stroke (m)'), ('totalangle', 'Drive Length (deg)'), ('drivelength', 'Drive Length (m)'), ('drivespeed', 'Drive Speed (m/s)'), ('effectiveangle', 'Effective Drive Length (deg)'), ('finish', 'Finish Angle (degrees)'), ('hr', 'Heart Rate (bpm)'), ('distance', 'Interval Distance (m)'), ('efficiency', 'OTW Efficiency (%)'), ('pace', 'Pace (/500m)'), ('peakforce', 'Peak Drive Force (N)'), ('peakforceangle', 'Peak Force Angle'), ('power', 'Power (W)'), ('slip', 'Slip (degrees)'), ('spm', 'Stroke Rate (spm)'), ('rhythm', 'Stroke Rhythm'), ('time', 'Time'), ('wash', 'Wash (degrees)'), ('driveenergy', 'Work Per Stroke (J)')], max_length=50, verbose_name='X')), ('plottype', models.CharField(choices=[('line', 'Line Chart'), ('scatter', 'Scatter Chart')], default='line', max_length=50, verbose_name='Chart Type')), ('workouttype', models.CharField(choices=[('ote', 'Erg/SkiErg'), ('otw', 'On The Water'), ('all', 'All'), ('strava', 'strava'), ('concept2', 'concept2'), ('sporttracks', 'sporttracks'), ('runkeeper', 'runkeeper'), ('mapmyfitness', 'mapmyfitness'), ('csv', 'painsled'), ('tcx', 'tcx'), ('rp', 'rowperfect'), ('mystery', 'mystery'), ('rowperfect3', 'rowperfect3'), ('ergdata', 'ergdata'), ('boatcoach', 'boatcoach'), ('boatcoachotw', 'boatcoachotw'), ('painsleddesktop', 'painsleddesktop'), ('speedcoach', 'speedcoach'), ('speedcoach2', 'speedcoach2'), ('ergstick', 'ergstick'), ('fit', 'fit'), ('unknown', 'unknown')], default='both', max_length=50, verbose_name='Workout Type')), ('reststrokes', models.BooleanField(default=True, verbose_name='Incl. Rest')), @@ -185,7 +235,7 @@ class Migration(migrations.Migration): ('coursecompleted', models.BooleanField(default=False)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30, verbose_name='Gender')), ('age', models.IntegerField(null=True)), - ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive race notifications by email')), + ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive challenge notifications by email')), ], ), migrations.CreateModel( @@ -207,11 +257,11 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(blank=True, max_length=150, verbose_name='Name')), - ('comment', models.TextField(blank=True, max_length=500)), + ('comment', models.TextField(blank=True, max_length=1000)), ('startdate', models.DateField(default=rowers.models.current_day, verbose_name='On or After')), ('enddate', models.DateField(default=rowers.models.a_week_from_now, verbose_name='On or Before')), ('preferreddate', models.DateField(default=rowers.models.a_week_from_now, verbose_name='Preferred Date')), - ('sessiontype', models.CharField(choices=[('session', 'Training Session'), ('challenge', 'Challenge'), ('test', 'Mandatory Test'), ('cycletarget', 'Total for a time period'), ('coursetest', 'OTW test over a course'), ('race', 'Virtual Race'), ('indoorrace', 'Indoor Virtual Race')], default='session', max_length=150, verbose_name='Session Type')), + ('sessiontype', models.CharField(choices=[('session', 'Training Session'), ('challenge', 'Challenge'), ('test', 'Mandatory Test'), ('cycletarget', 'Total for a time period'), ('coursetest', 'OTW test over a course'), ('race', 'Virtual challenge'), ('indoorrace', 'Indoor Virtual challenge')], default='session', max_length=150, verbose_name='Session Type')), ('sessionvalue', models.IntegerField(default=60, verbose_name='Value')), ('max_nr_of_workouts', models.IntegerField(default=0, verbose_name='Maximum number of workouts')), ('sessionunit', models.CharField(choices=[('min', 'minutes'), ('m', 'meters'), ('None', None)], default='min', max_length=150, verbose_name='Unit')), @@ -219,6 +269,7 @@ class Migration(migrations.Migration): ('verification', models.CharField(choices=[('none', 'None'), ('automatic', 'Automatic'), ('manual', 'Manual')], default='none', max_length=150)), ('sessionmode', models.CharField(choices=[('distance', 'Distance'), ('time', 'Time'), ('rScore', 'rScore'), ('TRIMP', 'TRIMP')], default='time', max_length=150, verbose_name='Session Mode')), ('hasranking', models.BooleanField(default=False)), + ('is_template', models.BooleanField(default=False)), ], ), migrations.CreateModel( @@ -240,7 +291,7 @@ class Migration(migrations.Migration): ('PowerFourMin', models.FloatField(default=0)), ('PowerTwoK', models.FloatField(default=0)), ('PowerOneHour', models.FloatField(default=0)), - ('workoutmode', models.CharField(choices=[('rower', 'Rower'), ('water', 'On the water')], default='rower', max_length=40)), + ('workoutmode', models.CharField(choices=[('rower', 'Rower'), ('water', 'On the water')], default='rower', max_length=41)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], options={ @@ -279,6 +330,8 @@ class Migration(migrations.Migration): ('offercoaching', models.BooleanField(default=False, verbose_name='Offer Remote Coaching')), ('gdproptin', models.BooleanField(default=False)), ('gdproptindate', models.DateTimeField(blank=True, null=True)), + ('surveydone', models.BooleanField(default=False)), + ('surveydonedate', models.DateTimeField(blank=True, null=True)), ('max', models.IntegerField(default=192, verbose_name='Max Heart Rate')), ('rest', models.IntegerField(default=48, verbose_name='Resting Heart Rate')), ('ut2', models.IntegerField(default=105, verbose_name='UT2 band lower HR')), @@ -346,14 +399,29 @@ class Migration(migrations.Migration): ('emailbounced', models.BooleanField(default=False, verbose_name='Email Address Bounced')), ('getimportantemails', models.BooleanField(default=True, verbose_name='Get Important Emails')), ('privacy', models.CharField(choices=[('visible', 'Visible'), ('hidden', 'Hidden')], default='visible', max_length=30)), - ('defaulttimezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100, verbose_name='Default Time Zone')), + ('defaulttimezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100, verbose_name='Default Time Zone')), ('showfavoritechartnotes', models.BooleanField(default=True, verbose_name='Show Notes for Favorite Charts')), + ('staticgrids', models.CharField(choices=[('none', None), ('both', 'both'), ('x', 'x'), ('y', 'y')], default='both', max_length=50, null=True, verbose_name='Chart Grid')), + ('slowpaceerg', models.DurationField(default=datetime.timedelta(0, 160), verbose_name='Slowest Erg Pace')), + ('fastpaceerg', models.DurationField(default=datetime.timedelta(0, 85), verbose_name='Fastest Erg Pace')), + ('slowpaceotw', models.DurationField(default=datetime.timedelta(0, 240), verbose_name='Slowest OTW Pace')), + ('fastpaceotw', models.DurationField(default=datetime.timedelta(0, 85), verbose_name='Fastest OTW Pace')), + ('autojoin', models.BooleanField(default=False, verbose_name='Auto Join Workout Segments')), ('coachinggroups', models.ManyToManyField(related_name='coaches', to='rowers.CoachingGroup')), ('friends', models.ManyToManyField(blank=True, related_name='_rower_friends_+', to='rowers.Rower')), ('mycoachgroup', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='coachingrole', to='rowers.CoachingGroup')), ('paidplan', models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.PaidPlan')), ], ), + migrations.CreateModel( + name='ShareKey', + fields=[ + ('location', models.TextField()), + ('token', models.CharField(max_length=40, primary_key=True, serialize=False)), + ('creation_date', models.DateTimeField(auto_now_add=True)), + ('expiration_seconds', models.BigIntegerField()), + ], + ), migrations.CreateModel( name='SiteAnnouncement', fields=[ @@ -366,55 +434,13 @@ class Migration(migrations.Migration): ], ), migrations.CreateModel( - name='StrokeData', + name='StandardCollection', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('workoutid', models.IntegerField(null=True)), - ('workoutstate', models.IntegerField(default=1, null=True)), - ('ftime', models.CharField(max_length=30)), - ('fpace', models.CharField(max_length=30)), - ('hr_ut2', models.IntegerField(null=True)), - ('hr_ut1', models.IntegerField(null=True)), - ('hr_at', models.IntegerField(null=True)), - ('hr_tr', models.IntegerField(null=True)), - ('hr_an', models.IntegerField(null=True)), - ('hr_max', models.IntegerField(null=True)), - ('hr_bottom', models.IntegerField(null=True)), - ('x_right', models.FloatField(null=True)), - ('ergpace', models.FloatField(null=True)), - ('nowindpace', models.FloatField(null=True)), - ('equivergpower', models.FloatField(null=True)), - ('fergpace', models.CharField(max_length=30)), - ('fnowindpace', models.CharField(max_length=30)), - ('time', models.FloatField(null=True, verbose_name='Time')), - ('hr', models.IntegerField(null=True, verbose_name='Heart Rate (bpm)')), - ('pace', models.FloatField(null=True, verbose_name='Pace (/500m)')), - ('velo', models.FloatField(default=0, null=True, verbose_name='Boat Speed (m/s)')), - ('powerhr', models.FloatField(null=True, verbose_name='Power Heart Rate Efficiency (J/beat)')), - ('spm', models.FloatField(null=True, verbose_name='Stroke Rate (spm)')), - ('driveenergy', models.FloatField(null=True, verbose_name='Work Per Stroke (J)')), - ('power', models.FloatField(null=True, verbose_name='Power (W)')), - ('averageforce', models.FloatField(null=True, verbose_name='Average Drive Force (N)')), - ('peakforce', models.FloatField(null=True, verbose_name='Peak Drive Force (N)')), - ('drivelength', models.FloatField(null=True, verbose_name='Drive Length (m)')), - ('forceratio', models.FloatField(null=True, verbose_name='Average/Peak Force Ratio')), - ('distance', models.FloatField(null=True, verbose_name='Distance (m)')), - ('cumdist', models.FloatField(null=True, verbose_name='Cumulative Distance (m)')), - ('drivespeed', models.FloatField(default=0, null=True, verbose_name='Drive Speed (m/s)')), - ('catch', models.FloatField(default=0, null=True, verbose_name='Catch Angle (degrees)')), - ('slip', models.FloatField(default=0, null=True, verbose_name='Slip (degrees)')), - ('finish', models.FloatField(default=0, null=True, verbose_name='Finish Angle (degrees)')), - ('wash', models.FloatField(default=0, null=True, verbose_name='Wash (degrees)')), - ('peakforceangle', models.FloatField(default=0, null=True, verbose_name='Peak Force Angle')), - ('totalangle', models.FloatField(default=0, null=True, verbose_name='Drive Length (deg)')), - ('effectiveangle', models.FloatField(default=0, null=True, verbose_name='Effective Drive Length (deg)')), - ('rhythm', models.FloatField(default=1.0, null=True, verbose_name='Stroke Rhythm')), - ('efficiency', models.FloatField(default=0, null=True, verbose_name='OTW Efficiency (%)')), - ('distanceperstroke', models.FloatField(default=0, null=True, verbose_name='Distance per Stroke (m)')), + ('name', models.CharField(max_length=150)), + ('notes', models.CharField(blank=True, max_length=1000, null=True)), + ('manager', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), ], - options={ - 'db_table': 'strokedata', - }, ), migrations.CreateModel( name='Team', @@ -527,6 +553,7 @@ class Migration(migrations.Migration): ('name', models.CharField(blank=True, max_length=150)), ('status', models.BooleanField(default=True, verbose_name='Active')), ('startdate', models.DateField(default=rowers.models.current_day)), + ('notes', models.CharField(blank=True, max_length=200, null=True, verbose_name='Plan Notes')), ('enddate', models.DateField(default=rowers.models.half_year_from_now)), ('manager', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='planmanager', to='rowers.Rower')), ('rowers', models.ManyToManyField(related_name='planathletes', to='rowers.Rower', verbose_name='Athletes')), @@ -543,6 +570,16 @@ class Migration(migrations.Migration): ('rowers', models.ManyToManyField(related_name='targetathletes', to='rowers.Rower', verbose_name='Athletes')), ], ), + migrations.CreateModel( + name='VideoAnalysis', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('name', models.CharField(blank=True, default='', max_length=150, null=True)), + ('video_id', models.CharField(default='', max_length=150)), + ('delay', models.IntegerField(default=0)), + ('metricsgroups', rowers.models.TemplateListField(default=['basic'])), + ], + ), migrations.CreateModel( name='VirtualRaceResult', fields=[ @@ -560,7 +597,9 @@ class Migration(migrations.Migration): ('coursecompleted', models.BooleanField(default=False)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30, verbose_name='Gender')), ('age', models.IntegerField(null=True)), - ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive race notifications by email')), + ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive challenge notifications by email')), + ('startsecond', models.FloatField(default=0)), + ('endsecond', models.FloatField(default=0)), ], ), migrations.CreateModel( @@ -573,7 +612,7 @@ class Migration(migrations.Migration): ('workoutsource', models.CharField(default='unknown', max_length=100)), ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50, verbose_name='Boat Type')), ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), - ('starttime', models.TimeField(blank=True, null=True)), + ('starttime', models.TimeField(default=datetime.time(12, 0))), ('startdatetime', models.DateTimeField(blank=True, null=True)), ('timezone', models.CharField(default='UTC', max_length=100)), ('distance', models.IntegerField(blank=True, default=0)), @@ -604,6 +643,7 @@ class Migration(migrations.Migration): ('privacy', models.CharField(choices=[('private', 'Private'), ('visible', 'Visible')], default='visible', max_length=30)), ('rankingpiece', models.BooleanField(default=False, verbose_name='Ranking Piece')), ('duplicate', models.BooleanField(default=False, verbose_name='Duplicate Workout')), + ('impeller', models.BooleanField(default=False, verbose_name='Impeller')), ], ), migrations.CreateModel( @@ -622,15 +662,16 @@ class Migration(migrations.Migration): name='VirtualRace', fields=[ ('plannedsession_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='rowers.PlannedSession')), - ('registration_form', models.CharField(choices=[('windowstart', 'Start of Race Window'), ('windowend', 'End of Race Window'), ('deadline', 'Evaluation Closure Deadline'), ('manual', 'Manual - select below')], default='windowstart', max_length=100, verbose_name='Registration Closure Quick Selector')), + ('registration_form', models.CharField(choices=[('windowstart', 'Start of challenge Window'), ('windowend', 'End of challenge Window'), ('deadline', 'Evaluation Closure Deadline'), ('manual', 'Manual - select below')], default='windowstart', max_length=100, verbose_name='Registration Closure Quick Selector')), ('registration_closure', models.DateTimeField(blank=True, null=True)), ('evaluation_closure', models.DateTimeField(blank=True, null=True)), ('start_time', models.TimeField(blank=True, null=True)), ('end_time', models.TimeField(blank=True, null=True)), ('country', models.CharField(blank=True, max_length=100)), - ('timezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Godthab', 'America/Godthab'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100)), + ('timezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100)), ('contact_phone', models.CharField(blank=True, max_length=17, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.", regex='^\\+?1?\\d{9,15}$')])), ('contact_email', models.EmailField(blank=True, max_length=254, validators=[django.core.validators.EmailValidator()])), + ('coursestandards', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.StandardCollection')), ], bases=('rowers.plannedsession',), ), @@ -649,6 +690,11 @@ class Migration(migrations.Migration): name='user', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Rower'), ), + migrations.AddField( + model_name='videoanalysis', + name='workout', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Workout'), + ), migrations.AddField( model_name='trainingplan', name='target', @@ -659,14 +705,10 @@ class Migration(migrations.Migration): name='plan', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.TrainingPlan'), ), - migrations.AlterIndexTogether( - name='strokedata', - index_together={('workoutid',)}, - ), migrations.AddField( model_name='rower', name='team', - field=models.ManyToManyField(blank=True, to='rowers.Team'), + field=models.ManyToManyField(blank=True, related_name='rower', to='rowers.Team'), ), migrations.AddField( model_name='rower', @@ -740,6 +782,11 @@ class Migration(migrations.Migration): name='plannedsession', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.PlannedSession'), ), + migrations.AddField( + model_name='coursestandard', + name='standardcollection', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.StandardCollection'), + ), migrations.AddField( model_name='coachrequest', name='coach', @@ -764,11 +811,35 @@ class Migration(migrations.Migration): name='c2worldclassageperformance', unique_together={('age', 'sex', 'weightcategory', 'distance')}, ), + migrations.AddField( + model_name='alert', + name='filter', + field=models.ManyToManyField(related_name='filters', to='rowers.Condition', verbose_name='Filters'), + ), + migrations.AddField( + model_name='alert', + name='manager', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL), + ), + migrations.AddField( + model_name='alert', + name='measured', + field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='measured', to='rowers.Condition', verbose_name='Measuring'), + ), + migrations.AddField( + model_name='alert', + name='rower', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Rower'), + ), migrations.AddField( model_name='virtualraceresult', name='race', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.VirtualRace'), ), + migrations.AlterUniqueTogether( + name='videoanalysis', + unique_together={('video_id', 'workout')}, + ), migrations.AddField( model_name='racelogo', name='race', @@ -779,4 +850,8 @@ class Migration(migrations.Migration): name='race', field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.VirtualRace'), ), + migrations.AlterUniqueTogether( + name='coursestandard', + unique_together={('name', 'sex', 'agemin', 'agemax', 'boatclass', 'boattype', 'weightclass', 'adaptiveclass', 'skillclass', 'standardcollection')}, + ), ] diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 75ee64e3..04a621a1 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -42,6 +42,10 @@ TESTING = False ALLOWED_HOSTS = CFG['allowed_hosts'] +OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = 'oauth2_provider.AccessToken' +OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application' +OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = 'oauth2_provider.RefreshToken' + # Application definition From 2a4991f7f7e44c149bd9db29b1f00d5da3cd4f14 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 20:17:43 +0200 Subject: [PATCH 09/22] fixed settings --- rowsandall_app/settings.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 75ee64e3..680f9615 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -42,7 +42,9 @@ TESTING = False ALLOWED_HOSTS = CFG['allowed_hosts'] - +OAUTH2_PROVIDER_ACCESS_TOKEN_MODEL = 'oauth2_provider.AccessToken' +OAUTH2_PROVIDER_APPLICATION_MODEL = 'oauth2_provider.Application' +OAUTH2_PROVIDER_REFRESH_TOKEN_MODEL = 'oauth2_provider.RefreshToken' # Application definition INSTALLED_APPS = [ From 66454b9ba2e2c26c64c7e8e586f5165b29ae188a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 20:55:50 +0200 Subject: [PATCH 10/22] adding Standard Times to events --- rowers/migrations/0001_initial.py | 2 +- rowers/models.py | 7 ++++++- rowers/templates/indoorvirtualeventcreate.html | 9 +++++++++ rowers/templates/virtualevent.html | 16 ++++++++++++++++ rowers/templates/virtualeventcreate.html | 9 +++++++++ rowers/views/racesviews.py | 16 +++++++++++++++- 6 files changed, 56 insertions(+), 3 deletions(-) diff --git a/rowers/migrations/0001_initial.py b/rowers/migrations/0001_initial.py index ee6b4a02..95afc7b0 100644 --- a/rowers/migrations/0001_initial.py +++ b/rowers/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.7 on 2020-05-26 18:13 +# Generated by Django 2.1.7 on 2020-05-26 18:20 import datetime from django.conf import settings diff --git a/rowers/models.py b/rowers/models.py index e57a9793..c84f98a9 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2262,7 +2262,8 @@ class VirtualRace(PlannedSession): contact_email = models.EmailField(max_length=254, validators=[validate_email],blank=True) - coursestandards = models.ForeignKey(StandardCollection,null=True,on_delete=models.SET_NULL) + coursestandards = models.ForeignKey(StandardCollection,null=True,on_delete=models.SET_NULL, + verbose_name='Standard Times') def __str__(self): @@ -2432,6 +2433,7 @@ class IndoorVirtualRaceForm(ModelForm): 'registration_closure', 'evaluation_closure', 'comment', + 'coursestandards', 'contact_phone', 'contact_email', ] @@ -2568,6 +2570,7 @@ class VirtualRaceForm(ModelForm): 'registration_closure', 'evaluation_closure', 'course', + 'coursestandards', 'comment', 'contact_phone', 'contact_email', @@ -2939,6 +2942,7 @@ class VirtualRaceResult(models.Model): race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) + points = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, max_length=40, default='water', @@ -3002,6 +3006,7 @@ class IndoorVirtualRaceResult(models.Model): race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) + points = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, max_length=40, default='rower', diff --git a/rowers/templates/indoorvirtualeventcreate.html b/rowers/templates/indoorvirtualeventcreate.html index 2fcc477b..8ec29004 100644 --- a/rowers/templates/indoorvirtualeventcreate.html +++ b/rowers/templates/indoorvirtualeventcreate.html @@ -55,6 +55,15 @@ If you require a screenshot of the PM monitor, do mention this in the comment.

    +

    + Standard Times are a way to compare results in a race category with + a course record or golden standard for that event. A point score is calculated + which compares the participant's result with the standard. This offers an + engaging way to compete on points across different categories, boat types, and skill + levels. + If you select a Standard Times set from the drop-down list, race categories will + be limited to those in the selected set of Standard Times. +

    diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index b3e1ff57..3589b469 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -104,6 +104,11 @@
    {% endif %} + {% if race.coursestandards %} + + + + {% endif %} {% endif %} {% endif %} - - + + {% if race.coursestandards %} - + {% endif %} diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index cbb09087..44cc7cc3 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1159,7 +1159,6 @@ def virtualevent_view(request,id=0): if entrycategory is not None: results = results.filter(entrycategory__in=entrycategory) - # to-do - add DNS dns = [] if timezone.now() > race.evaluation_closure: @@ -1198,6 +1197,10 @@ def virtualevent_view(request,id=0): } ] + orderby = request.GET.get('order_by') + if orderby is not None: + results = results.order_by(orderby) + racelogos = race.logos.all() if racelogos: From a6e5a0588a0f5f47bd86e3a67f1f4523dbe28ed7 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 28 May 2020 07:56:48 +0200 Subject: [PATCH 21/22] verbose names for boat class --- rowers/templates/standard_view.html | 2 +- rowers/templatetags/rowerfilters.py | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html index 8a92f859..222282e5 100644 --- a/rowers/templates/standard_view.html +++ b/rowers/templates/standard_view.html @@ -59,7 +59,7 @@ - + diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 9a2aab71..84b5c947 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -22,7 +22,9 @@ from rowers import c2stuff, runkeeperstuff from rowers.c2stuff import c2_open from rowers.runkeeperstuff import runkeeper_open from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember -from rowers.mytypes import otwtypes,adaptivetypes,sexcategories,weightcategories +from rowers.mytypes import ( + otwtypes,adaptivetypes,sexcategories,weightcategories,workouttypes, + ) from rowers.utils import NoTokenError import rowers.payments as payments @@ -49,6 +51,17 @@ def adaptive(s): return u +@register.filter +def boatclass(s): + u = s + + for e,v in workouttypes: + if e.lower() == u.lower(): + u = v + continue + + return u + @register.filter def sex(s): u = s From e5443602d13c1de2dafa6a91343663c2deb233a3 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 28 May 2020 08:10:26 +0200 Subject: [PATCH 22/22] small menu improvement --- rowers/templates/menu_racing.html | 4 +++- rowers/urls.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rowers/templates/menu_racing.html b/rowers/templates/menu_racing.html index a0a5d76b..8dd74087 100644 --- a/rowers/templates/menu_racing.html +++ b/rowers/templates/menu_racing.html @@ -55,12 +55,14 @@  Upload your Challenge result + {% if race.sessiontype != 'race' %}
  • - +  Enter Result
  • {% endif %} + {% endif %} {% if button == 'resubmitbutton' %}
  • Submit New Result diff --git a/rowers/urls.py b/rowers/urls.py index 3549c4a5..1997e73f 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -205,7 +205,7 @@ urlpatterns = [ re_path(r'^courses/upload/$',views.course_upload_view,name='course_upload_view'), re_path(r'^standards/upload/$',views.standards_upload_view,name='standards_upload_view'), re_path(r'^standards/upload/(?P\d+)/$',views.standards_upload_view,name='standards_upload_view'), - re_path(r'^workout/addmanual/(?P\d+)$',views.addmanual_view,name='addmanual_view'), + re_path(r'^workout/addmanual/(?P\d+)/$',views.addmanual_view,name='addmanual_view'), re_path(r'^workout/addmanual/$',views.addmanual_view,name='addmanual_view'), re_path(r'^team-compare-select/workout/(?P\d+)/team/(?P\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'), # re_path(r'^team-compare-select/team/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.team_comparison_select,name='team_comparison_select'),
  • Challenge Time Zone{{ race.timezone }}
    Standard Times{{ race.coursestandards }}
    {{ race.sessionmode }} challenge @@ -541,6 +546,17 @@ review and reject entries. If you are disqualified in this way, you will receive an email with the reason.

    + {% if race.coursestandards %} +

    + Standard Times are a way to compare results in a race category with + a course record or golden standard for that event. A point score is calculated + which compares the participant's result with the standard. This offers an + engaging way to compete on points across different categories, boat types, and skill + levels. + If you select a Standard Times set from the drop-down list, race categories will + be limited to those in the selected set of Standard Times. +

    + {% endif %} diff --git a/rowers/templates/virtualeventcreate.html b/rowers/templates/virtualeventcreate.html index c26e54c2..6bd65d53 100644 --- a/rowers/templates/virtualeventcreate.html +++ b/rowers/templates/virtualeventcreate.html @@ -49,6 +49,15 @@ is strongly recommended that you fill out a contact email or phone number.

    +

    + Standard Times are a way to compare results in a race category with + a course record or golden standard for that event. A point score is calculated + which compares the participant's result with the standard. This offers an + engaging way to compete on points across different categories, boat types, and skill + levels. + If you select a Standard Times set from the drop-down list, race categories will + be limited to those in the selected set of Standard Times. +

    diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 700adfac..95bf3eb0 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -529,6 +529,11 @@ def standards_upload_view(request,id=0): is_ajax = True r = getrower(request.user) + if id != 0: + collection = StandardCollection.objects.get(id=id) + if request.user != collection.manager: + raise PermissionDenied("You cannot change this set of time standards") + if request.method == 'POST': form = StandardsForm(request.POST,request.FILES) @@ -573,6 +578,12 @@ def standards_upload_view(request,id=0): else: if not is_ajax: form = StandardsForm() + if id != 0: + collection = StandardCollection.objects.get(id=id) + form = StandardsForm(initial={ + 'name':collection.name, + 'notes': collection.notes, + }) return render(request,'standard_form.html', {'form':form, 'active':'nav-racing', @@ -655,7 +666,6 @@ def virtualevents_view(request): country__in=countries ).order_by("startdate","start_time") else: - form = VirtualRaceSelectForm() if is_ajax: @@ -1938,6 +1948,7 @@ def indoorvirtualevent_create_view(request): evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] + coursestandards = cd['coursestandards'] # correct times @@ -1992,6 +2003,7 @@ def indoorvirtualevent_create_view(request): sessionvalue = sessionvalue, course=None, timezone=timezone_str, + coursestandards=coursestandards, evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, @@ -2078,6 +2090,7 @@ def virtualevent_create_view(request): evaluation_closure = cd['evaluation_closure'] contact_phone = cd['contact_phone'] contact_email = cd['contact_email'] + coursestandards = cd['coursestandards'] # correct times @@ -2129,6 +2142,7 @@ def virtualevent_create_view(request): evaluation_closure=evaluation_closure, registration_closure=registration_closure, contact_phone=contact_phone, + coursestandards=coursestandards, contact_email=contact_email, country = course.country, manager=request.user, From 5952e85694c0ed5ff8be3d210cf0efe91134a938 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 May 2020 22:21:04 +0200 Subject: [PATCH 11/22] registration form (not processing yet) --- rowers/models.py | 27 +++++++++++++++++++--- rowers/templates/virtualeventregister.html | 9 +++++++- rowers/views/racesviews.py | 22 +++++++++++++++--- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index c84f98a9..25a2ac34 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2939,6 +2939,8 @@ class VirtualRaceResult(models.Model): adaptiveclass = models.CharField(default="None",max_length=50, choices=mytypes.adaptivetypes, verbose_name="Adaptive Class") + skillclass = models.CharField(default="Open",max_length=50, + verbose_name="Skill Class") race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) @@ -2963,6 +2965,8 @@ class VirtualRaceResult(models.Model): startsecond = models.FloatField(default=0) endsecond = models.FloatField(default=0) + entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, + verbose_name='Field') def __str__(self): rr = Rower.objects.get(id=self.userid) @@ -3003,6 +3007,8 @@ class IndoorVirtualRaceResult(models.Model): adaptiveclass = models.CharField(default="None",max_length=50, choices=mytypes.adaptivetypes, verbose_name="Adaptive Class") + skillclass = models.CharField(default="Open",max_length=50, + verbose_name="Skill Class") race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) @@ -3020,6 +3026,8 @@ class IndoorVirtualRaceResult(models.Model): age = models.IntegerField(null=True) emailnotifications = models.BooleanField(default=True, verbose_name = 'Receive challenge notifications by email') + entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, + verbose_name='Category') def __str__(self): rr = Rower.objects.get(id=self.userid) @@ -3055,22 +3063,29 @@ class CourseTestResult(models.Model): class IndoorVirtualRaceResultForm(ModelForm): class Meta: model = IndoorVirtualRaceResult - fields = ['teamname','weightcategory','boatclass','age','adaptiveclass'] + fields = ['teamname','weightcategory','boatclass','age','adaptiveclass', + 'entrycategory'] def __init__(self, *args, **kwargs): + categories = kwargs.pop('categories') super(IndoorVirtualRaceResultForm, self).__init__(*args, **kwargs) - + if categories is not None: + self.fields['entrycategory'].queryset = categories + self.fields['entrycategory'].empty_label = None + else: + self.fields.pop('entrycategory') class VirtualRaceResultForm(ModelForm): class Meta: model = VirtualRaceResult fields = ['teamname','weightcategory','boatclass','boattype', - 'age','adaptiveclass'] + 'age','adaptiveclass','entrycategory'] def __init__(self, *args, **kwargs): boattypes = kwargs.pop('boattypes',None) + categories = kwargs.pop('categories',None) super(VirtualRaceResultForm, self).__init__(*args, **kwargs) if boattypes: @@ -3080,6 +3095,12 @@ class VirtualRaceResultForm(ModelForm): required=False, label='Mixed Gender') + if categories is not None: + self.fields['entrycategory'].queryset = categories + self.fields['entrycategory'].empty_label = None + else: + self.fields.pop('entrycategory') + from rowers.metrics import rowingmetrics strokedatafields = { diff --git a/rowers/templates/virtualeventregister.html b/rowers/templates/virtualeventregister.html index 5ed6c79a..4752256c 100644 --- a/rowers/templates/virtualeventregister.html +++ b/rowers/templates/virtualeventregister.html @@ -21,7 +21,7 @@ -

    If you are participating in a single, we will take the age and weight @@ -35,6 +35,13 @@ as a Male crew. Check the "Mixed gender" check box to register as a mixed gender crew (except for 1x where this check box does nothing).

    + {% if race.coursestandards %} +

    This race uses standard times and limits the race fields to those where + standard times exist. The "Field" form choice will overrule other selections you + make in the form (boat type, weight, etc) and your entry will be rejected + if the age and gender doesn't match. +

    + {% endif %}
    {{ form.as_table }} diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 95bf3eb0..db9aa416 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1529,7 +1529,13 @@ def virtualevent_addboat_view(request,id=0): 'adaptiveclass': r.adaptiveclass, } - form = VirtualRaceResultForm(initial=initial) + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + + form = VirtualRaceResultForm(initial=initial,categories=categories) breadcrumbs = [ { @@ -1684,7 +1690,12 @@ def virtualevent_register_view(request,id=0): 'adaptiveclass': r.adaptiveclass, } - form = VirtualRaceResultForm(initial=initial) + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + form = VirtualRaceResultForm(initial=initial,categories=categories) breadcrumbs = [ { @@ -1875,7 +1886,12 @@ def indoorvirtualevent_register_view(request,id=0): 'adaptiveclass': r.adaptiveclass, } - form = IndoorVirtualRaceResultForm(initial=initial) + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + form = IndoorVirtualRaceResultForm(initial=initial,categories=categories) breadcrumbs = [ { From 11685f31263ef452c1560267104faba876bad09a Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 27 May 2020 08:30:34 +0200 Subject: [PATCH 12/22] started registration form processing on OTW events - not working yet --- rowers/models.py | 7 ++++--- rowers/scoring.py | 4 ++-- rowers/views/racesviews.py | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 6 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 25a2ac34..53db424f 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2206,7 +2206,7 @@ class CourseStandard(models.Model): name = models.CharField(max_length=150) coursedistance = models.IntegerField() coursetime = models.CharField(max_length=100,default="") - coursestandard = models.FloatField() # average boat speed + referencespeed = models.FloatField() # average boat speed agemin = models.IntegerField(default=0) agemax = models.IntegerField(default=120) boatclass = models.CharField(max_length=150) # corresponds to workout workouttype @@ -2966,7 +2966,7 @@ class VirtualRaceResult(models.Model): startsecond = models.FloatField(default=0) endsecond = models.FloatField(default=0) entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, - verbose_name='Field') + verbose_name='Group') def __str__(self): rr = Rower.objects.get(id=self.userid) @@ -3012,6 +3012,7 @@ class IndoorVirtualRaceResult(models.Model): race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) + referencespeed = models.FloatField(default=5.0) points = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, max_length=40, @@ -3027,7 +3028,7 @@ class IndoorVirtualRaceResult(models.Model): emailnotifications = models.BooleanField(default=True, verbose_name = 'Receive challenge notifications by email') entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, - verbose_name='Category') + verbose_name='Group') def __str__(self): rr = Rower.objects.get(id=self.userid) diff --git a/rowers/scoring.py b/rowers/scoring.py index 1156bc25..89de6745 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -41,7 +41,7 @@ def save_scoring(name,user,filename,id=0,notes=""): delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second,microseconds=t.microsecond) seconds = delta.total_seconds() - coursestandard = coursedistance/seconds + referencespeed = coursedistance/seconds except KeyError: continue @@ -88,7 +88,7 @@ def save_scoring(name,user,filename,id=0,notes=""): standard = CourseStandard( name=name, coursedistance=coursedistance, - coursestandard=coursestandard, + referencespeed=referencespeed, coursetime=coursetime, agemin=agemin, agemax=agemax, diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index db9aa416..5124e421 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1631,6 +1631,40 @@ def virtualevent_register_view(request,id=0): if sex == 'not specified': sex = 'male' + + coursestandard = None + referencespeed = 5.0 + + if race.coursestandards is not None: + coursestandard = cd['entrycategory'] + referencespeed = coursestandard.referencespeed + boattype = coursestandard.boattype + boatclass = coursestandard.boatclass + weightcategory = coursestandard.weightcategory + adaptiveclass = coursestandard.adaptiveclass + skillclass = coursestandard.skillclass + + returnurl = reverse(virtualevent_register_view, + kwargs={'id':race.id}) + + if age < coursestandard.agemin: + messages.error(request,'You are younger than the minimum age for this group') + return HttpResponseRedirect(url) + + if age > coursestandard.agemax: + messages.error(request,'You are older than the maximum age for this group') + return HttpResponseRedirect(url) + + if sex == 'male' and coursestandard.sex != 'male': + messages.error(request,'Men are not allowed to enter this category') + return HttpResponseRedirect(url) + + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + messages.error(request,'Mixed crews are not allowed to enter this category') + return HttpResponseRedirect(url) + + + record = VirtualRaceResult( userid=r.id, teamname=teamname, @@ -1646,7 +1680,8 @@ def virtualevent_register_view(request,id=0): boattype=boattype, coursecompleted=False, sex=sex, - age=age + age=age, + entrycategory=coursestandard, ) record.save() From eb41a5f17fec77a5f152b00662cd785bf8fd0715 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 27 May 2020 09:22:09 +0200 Subject: [PATCH 13/22] some refinements --- rowers/scoring.py | 14 +++++++++++++- rowers/templates/virtualeventregister.html | 5 ++++- rowers/views/racesviews.py | 21 +++++++++++++-------- 3 files changed, 30 insertions(+), 10 deletions(-) diff --git a/rowers/scoring.py b/rowers/scoring.py index 89de6745..b196b8f5 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -66,16 +66,28 @@ def save_scoring(name,user,filename,id=0,notes=""): try: sex = row['Gender'] + if sex.lower() in ['m','men','male','open']: + sex = 'male' + elif sex.lower() in ['mix','mixed']: + sex = 'mixed' + else: + sex = 'female' except KeyError: - sex = 'F' + sex = 'female' try: weightclass = row['WeightClass'] + if weightclass.lower() in ['hwt','h','o','heavy','open']: + weightclass = 'hwt' + elif weightclass.lower() in ['lwt','l','light','lights','lighties']: + weightclass = 'lwt' except KeyError: weightclass = 'hwt' try: adaptiveclass = row['AdaptiveClass'] + if adaptiveclass.lower() in ['o','open','none','no']: + adaptiveclass = None except KeyError: adaptiveclass = None diff --git a/rowers/templates/virtualeventregister.html b/rowers/templates/virtualeventregister.html index 4752256c..20159a4e 100644 --- a/rowers/templates/virtualeventregister.html +++ b/rowers/templates/virtualeventregister.html @@ -36,11 +36,14 @@ mixed gender crew (except for 1x where this check box does nothing).

    {% if race.coursestandards %} -

    This race uses standard times and limits the race fields to those where +

    This race uses standard times and limits the race groups to those where standard times exist. The "Field" form choice will overrule other selections you make in the form (boat type, weight, etc) and your entry will be rejected if the age and gender doesn't match.

    +

    + You can check the valid race groups and standard times here. +

    {% endif %}
    diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 5124e421..9603465c 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -292,11 +292,11 @@ def standard_view(request,id=0): if orderby is not None: standards = CourseStandard.objects.filter( standardcollection=collection - ).order_by(orderby,"-coursestandard","agemax","agemin","sex","name") + ).order_by(orderby,"-referencespeed","agemax","agemin","sex","name") else: standards = CourseStandard.objects.filter( standardcollection=collection - ).order_by("-coursestandard","agemax","agemin","sex","name") + ).order_by("-referencespeed","agemax","agemin","sex","name") breadcrumbs = [ { @@ -1596,6 +1596,11 @@ def virtualevent_register_view(request,id=0): except VirtualRace.DoesNotExist: raise Http404("Virtual Challenge does not exist") + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + if not race_can_register(r,race): messages.error(request,"You cannot register for this race") @@ -1609,7 +1614,7 @@ def virtualevent_register_view(request,id=0): # we're still here if request.method == 'POST': # process form - form = VirtualRaceResultForm(request.POST) + form = VirtualRaceResultForm(request.POST,categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] @@ -1640,7 +1645,7 @@ def virtualevent_register_view(request,id=0): referencespeed = coursestandard.referencespeed boattype = coursestandard.boattype boatclass = coursestandard.boatclass - weightcategory = coursestandard.weightcategory + weightcategory = coursestandard.weightclass adaptiveclass = coursestandard.adaptiveclass skillclass = coursestandard.skillclass @@ -1649,19 +1654,19 @@ def virtualevent_register_view(request,id=0): if age < coursestandard.agemin: messages.error(request,'You are younger than the minimum age for this group') - return HttpResponseRedirect(url) + return HttpResponseRedirect(returnurl) if age > coursestandard.agemax: messages.error(request,'You are older than the maximum age for this group') - return HttpResponseRedirect(url) + return HttpResponseRedirect(returnurl) if sex == 'male' and coursestandard.sex != 'male': messages.error(request,'Men are not allowed to enter this category') - return HttpResponseRedirect(url) + return HttpResponseRedirect(returnurl) if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: messages.error(request,'Mixed crews are not allowed to enter this category') - return HttpResponseRedirect(url) + return HttpResponseRedirect(returnurl) From 8bfbb2bdf8a41620c58c8d9dd1874b98412eda3e Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 27 May 2020 13:16:51 +0200 Subject: [PATCH 14/22] better names for categories --- rowers/models.py | 21 +++++------------ rowers/mytypes.py | 12 +++++++++- rowers/scoring.py | 5 +++-- rowers/templates/standard_view.html | 6 ++--- rowers/templatetags/rowerfilters.py | 35 ++++++++++++++++++++++++++++- 5 files changed, 56 insertions(+), 23 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 53db424f..2eca5a37 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -243,15 +243,9 @@ def update_records(url=c2url,verbose=True): class CalcAgePerformance(models.Model): - weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) + weightcategories = mytypes.weightcategories - sexcategories = ( - ('male','male'), - ('female','female'), - ) + sexcategories = mytypes.sexcategories weightcategory = models.CharField(default="hwt", max_length=30, @@ -288,10 +282,7 @@ class PowerTimeFitnessMetric(models.Model): @python_2_unicode_compatible class C2WorldClassAgePerformance(models.Model): - weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) + weightcategories = mytypes.weightcategories sexcategories = ( ('male','male'), @@ -593,10 +584,8 @@ sexcategories = ( ('female','female'), ('not specified','not specified'), ) -weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), -) + +weightcategories = mytypes.weightcategories # Plan diff --git a/rowers/mytypes.py b/rowers/mytypes.py index c70ffbcc..294cb8bb 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -316,13 +316,23 @@ boattypes = ( ) adaptivetypes = ( - ('None','None'), + ('None','Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)'), ) +weightcategories = ( + ('hwt','open-weight'), + ('lwt','light-weight'), + ) + +sexcategories = ( + ('male','Open'), + ('female','Female'), + ) + waterboattype = [i[0] for i in boattypes] privacychoices = ( diff --git a/rowers/scoring.py b/rowers/scoring.py index b196b8f5..915a799b 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -84,12 +84,13 @@ def save_scoring(name,user,filename,id=0,notes=""): except KeyError: weightclass = 'hwt' + adaptiveclass = 'None' try: adaptiveclass = row['AdaptiveClass'] if adaptiveclass.lower() in ['o','open','none','no']: - adaptiveclass = None + adaptiveclass = 'None' except KeyError: - adaptiveclass = None + adaptiveclass = 'None' try: skillclass = row['SkillClass'] diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html index e42b4aad..c76f0f49 100644 --- a/rowers/templates/standard_view.html +++ b/rowers/templates/standard_view.html @@ -57,9 +57,9 @@ - - - + + + diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 4974bce7..9a2aab71 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -22,7 +22,7 @@ from rowers import c2stuff, runkeeperstuff from rowers.c2stuff import c2_open from rowers.runkeeperstuff import runkeeper_open from rowers.rower_rules import is_coach_user, is_workout_user, isplanmember,ispromember -from rowers.mytypes import otwtypes +from rowers.mytypes import otwtypes,adaptivetypes,sexcategories,weightcategories from rowers.utils import NoTokenError import rowers.payments as payments @@ -38,6 +38,39 @@ from django.template.defaultfilters import stringfilter from six import string_types +@register.filter +def adaptive(s): + u = s + + for e,v in adaptivetypes: + if e.lower() == u.lower(): + u = v + continue + + return u + +@register.filter +def sex(s): + u = s + + for e,v in sexcategories: + if e.lower() == u.lower(): + u = v + continue + + return u + +@register.filter +def weight(s): + u = s + + for e,v in weightcategories: + if e.lower() == u.lower(): + u = v + continue + + return u + @register.filter def sigdig(value, digits = 3): try: From 2ba9133a1dcb96136db47556203770ed47c3b192 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 27 May 2020 14:56:09 +0200 Subject: [PATCH 15/22] first result working --- rowers/models.py | 3 +- rowers/plannedsessions.py | 4 +- rowers/scoring.py | 18 ++++++++ rowers/tasks.py | 22 ++++++++-- rowers/templates/standard_form.html | 2 +- rowers/templates/virtualevent.html | 35 +++++++++++++--- rowers/views/racesviews.py | 7 +++- static/css/rowsandall2.css | 64 +++++++++++++++-------------- static/css/rowsandall2.min.css | 2 +- 9 files changed, 112 insertions(+), 45 deletions(-) diff --git a/rowers/models.py b/rowers/models.py index 2eca5a37..0b5ed03f 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2252,7 +2252,7 @@ class VirtualRace(PlannedSession): validators=[validate_email],blank=True) coursestandards = models.ForeignKey(StandardCollection,null=True,on_delete=models.SET_NULL, - verbose_name='Standard Times') + verbose_name='Standard Times',blank=True) def __str__(self): @@ -2954,6 +2954,7 @@ class VirtualRaceResult(models.Model): startsecond = models.FloatField(default=0) endsecond = models.FloatField(default=0) + referencespeed = models.FloatField(default=5.0) entrycategory = models.ForeignKey(CourseStandard,null=True,on_delete=models.SET_NULL, verbose_name='Group') diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 4c859b65..5201c279 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1514,6 +1514,7 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): return 0,comments,errors,0 if ws[0].workouttype != record.boatclass: + print(ws[0].workouttype,record.boatclass) errors.append('Your workout boat class is different than on your race registration') return 0,comments,errors,0 @@ -1551,7 +1552,8 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): comments.append('Workouts submitted to virtual events have to be public. We have changed the workout to a public workout.') job = myqueue(queue,handle_check_race_course,ws[0].csvfilename, - ws[0].id,race.course.id,record.id,splitsecond=splitsecond) + ws[0].id,race.course.id,record.id,splitsecond=splitsecond, + referencespeed=record.referencespeed) diff --git a/rowers/scoring.py b/rowers/scoring.py index 915a799b..38cba81a 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -17,6 +17,10 @@ def save_scoring(name,user,filename,id=0,notes=""): collection.name = name collection.notes = notes collection.save() + standards = CourseStandard.objects.filter(standardcollection=collection) + for standard in standards: + print(standard,collection) + standard.delete() except StandardCollection.DoesNotExist: return 0 @@ -56,6 +60,20 @@ def save_scoring(name,user,filename,id=0,notes=""): try: boatclass = row['BoatClass'] + if boatclass.lower() in ['standard','olympic','normal']: + boatclass = 'water' + elif boatclass.lower() in ['erg','c2','concept','static']: + boatclass = 'rower' + elif boatclass.lower() in ['dynamic']: + boatclass = 'dynamic' + elif boatclass.lower() in ['slides','slide','slider','sliders']: + boatclass = 'slides' + elif boatclass.lower() in ['c','c-boat']: + boatclass = 'c-boat' + elif boatclass.lower() in ['coastal','coast']: + boatclass = 'coastal' + elif boatclass.lower() in ['church','churchboat','finnish','finland']: + boatclass = 'churchboat' except KeyError: boatclass = 'water' diff --git a/rowers/tasks.py b/rowers/tasks.py index 71eca7bb..f2408632 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -353,6 +353,16 @@ def handle_check_race_course(self, else: splitsecond = 0 + if 'referencespeed' in kwargs: + referencespeed = kwargs['referencespeed'] + else: + referencespeed = 5.0 + + if 'coursedistance' in kwargs: + coursedistance = kwargs['coursedistance'] + else: + coursedistance = 0 + mode = 'race' if 'mode' in kwargs: mode = kwargs['mode'] @@ -479,22 +489,28 @@ def handle_check_race_course(self, else: coursecompleted = False - + points = 0 if coursecompleted: - query = 'UPDATE rowers_virtualraceresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond} WHERE id={recordid}'.format( + if coursedistance == 0: + coursedistance = coursemeters + velo = coursedistance/coursetimeseconds + points = int(100*(2.-referencespeed/velo)) + query = 'UPDATE rowers_virtualraceresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond}, points={points} WHERE id={recordid}'.format( recordid=recordid, duration=totaltime_sec_to_string(coursetimeseconds), distance=int(coursemeters), + points=points, workoutid=workoutid, startsecond=startsecond, endsecond=endsecond, ) if mode == 'coursetest': - query = 'UPDATE rowers_coursetestresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond} WHERE id={recordid}'.format( + query = 'UPDATE rowers_coursetestresult SET coursecompleted = 1, duration = "{duration}", distance = {distance}, workoutid = {workoutid}, startsecond = {startsecond}, endsecond = {endsecond}, points={points} WHERE id={recordid}'.format( recordid=recordid, duration=totaltime_sec_to_string(coursetimeseconds), distance=int(coursemeters), + points=points, workoutid=workoutid, startsecond=startsecond, endsecond=endsecond, diff --git a/rowers/templates/standard_form.html b/rowers/templates/standard_form.html index 777c1857..2e8c2314 100644 --- a/rowers/templates/standard_form.html +++ b/rowers/templates/standard_form.html @@ -187,7 +187,7 @@ $.ajax({ data: data, type: $(this).attr('method'), - url: '/rowers/standards/upload/', + url: window.location.pathname, contentType: false, processData: false, error: function(result) { diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 3589b469..cd8c6ccc 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -268,7 +268,9 @@ - + {% if race.coursestandards %} + + {% else %} @@ -276,8 +278,12 @@ {% if race.sessiontype == 'race' %} {% endif %} + {% endif %} + {% if race.coursestandards %} + + {% endif %} @@ -290,6 +296,9 @@ {{ result.username }} + {% if race.coursestandards %} + + {% else %} @@ -304,11 +313,17 @@ {% if race.sessiontype == 'race' %} {% endif %} + {% endif %} + {% if race.coursestandards %} + + {% endif %} + Details + + - {% if race.sessiontype == 'race' %} - - + {% if race.coursestandards %} + + {% else %} - + {% if race.sessiontype == 'race' %} + {% endif %} + + {% endif %} {% for record in records %} + {% if race.coursestandards %} + + + {% else %} {% if race.sessiontype == 'race' %} @@ -424,6 +446,7 @@ {{ record.adaptiveclass }} {% endif %} + {% endif %} {% if record.userid == rower.id and 'withdrawbutton' in buttons %}
    {{ standard.coursetime }} {{ standard.boatclass }} {{ standard.boattype }}{{ standard.sex }}{{ standard.weightclass }}{{ standard.adaptiveclass }}{{ standard.sex|sex }}{{ standard.weightclass|weight }}{{ standard.adaptiveclass|adaptive }} {{ standard.skillclass }} {{ standard.agemin }}/{{ standard.agemax }}
      Name Team Name Group     BoatTime DistancePointsDetails  
    {{ result.teamname }}{{ result.entrycategory }}{{ result.age }} {{ result.sex }} {{ result.weightcategory }}{{ result.boattype }}{{ result.duration |durationprint:"%H:%M:%S.%f" }} {{ result.distance }} m{{ result.points }} - Details {% if race.manager == request.user and not race|is_final %} @@ -394,22 +409,29 @@
    Name Team NameClassBoatGroupAgeClassBoatClass Age Gender Weight Category Adaptive
    {{ record.username }} {{ record.teamname }}{{ record.entrycategory }}{{ record.age }}{{ record.boatclass }}{{ record.boattype }} Withdraw diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 9603465c..f968306a 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -525,6 +525,7 @@ def course_upload_view(request): @login_required() def standards_upload_view(request,id=0): is_ajax = False + print(id,'aap') if request.is_ajax(): is_ajax = True r = getrower(request.user) @@ -573,6 +574,8 @@ def standards_upload_view(request,id=0): messages.error(request,'Form is not valid') return render(request,'standard_form.html', {'form':form, + 'active':'nav-racing', + 'id':id, }) else: @@ -587,6 +590,7 @@ def standards_upload_view(request,id=0): return render(request,'standard_form.html', {'form':form, 'active':'nav-racing', + 'id':id, }) return {'result':0} @@ -1127,8 +1131,6 @@ def virtualevent_view(request,id=0): else: form = None - - breadcrumbs = [ { 'url':reverse('virtualevents_view'), @@ -1687,6 +1689,7 @@ def virtualevent_register_view(request,id=0): sex=sex, age=age, entrycategory=coursestandard, + referencespeed=referencespeed, ) record.save() diff --git a/static/css/rowsandall2.css b/static/css/rowsandall2.css index f096204a..e4054cb8 100644 --- a/static/css/rowsandall2.css +++ b/static/css/rowsandall2.css @@ -50,7 +50,7 @@ } html { - font-size: 62.5%; + font-size: 62.5%; margin: 0px; height: 100%; width: 100%; @@ -96,13 +96,13 @@ cox { ------------------------------------------------------------------------------- */ -th { +th { font-weight: bold; align: left; } .listtable tbody tr:nth-of-type(even) { background-color: #DDD; } -.listtable thead th { +.listtable thead th { font-weight: bold; align: left; } @@ -112,6 +112,10 @@ th { .paddedtable td { padding: 1px 20px } +.shortpadded th { padding: 3px 3px } + +.paddedtable th { padding: 1px 20px } + .cortable { border-collapse: collapse; } @@ -124,12 +128,12 @@ th { th.rotate { /* Something you can count on */ - height: 120px; + height: 120px; white-space: nowrap; } th.rotate > div { - transform: + transform: /* Magic Numbers */ translate(28px, 91px) /* 45 is really 360 - 45 */ @@ -141,12 +145,12 @@ th.rotate > div > span { padding: 5px 5px; } -.fixtable table { +.fixtable table { table-layout: fixed; width: 60%; } -.message { +.message { border: 1px solid #000; background-color: #f88; font-weight: bold; @@ -172,7 +176,7 @@ th.rotate > div > span { background-color: #fee; } -.successmessage { +.successmessage { border: 1px solid #000; background-color: #8f8; color: #000; @@ -180,7 +184,7 @@ th.rotate > div > span { font-weight: bold; } -.deletelink { +.deletelink { border: 1px solid #000; background-color: #f88; color: #000; @@ -189,7 +193,7 @@ th.rotate > div > span { } .navbar { - border: 1px solid #666; + border: 1px solid #666; color: #000; @@ -199,7 +203,7 @@ th.rotate > div > span { text-align: center; } -.navbutton { +.navbutton { background-color: #ddd; -moz-border-radius: 15px; -webkit-border-radius: 15px; @@ -242,7 +246,7 @@ th.rotate > div > span { transition-delay:1s; } -.caption { +.caption { text-align: center; } @@ -263,7 +267,7 @@ th.rotate > div > span { font: 1.0em/1.2em sans-serif; text-decoration: none; display: block; - padding: .2em .5em .2em .5em; + padding: .2em .5em .2em .5em; zoom: 1; /* border-radius: .5em; */ /* -moz-border-radius: .5em; */ @@ -276,7 +280,7 @@ th.rotate > div > span { font: 1.0em/1.2em sans-serif; text-decoration: none; display: block; - padding: .2em .5em .2em .5em; + padding: .2em .5em .2em .5em; zoom: 1; /* border-radius: .5em; */ /* -moz-border-radius: .5em; */ @@ -304,7 +308,7 @@ th.rotate > div > span { } .dot:hover { - text-decoration: none; + text-decoration: none; } .rounder { @@ -345,9 +349,9 @@ th.rotate > div > span { -webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); -moz-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); - + line-height: 0; /* ensure no space between bottom */ - + } .vignet img { @@ -367,9 +371,9 @@ th.rotate > div > span { -webkit-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); -moz-box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); box-shadow: inset 0px 0px 85px rgba(0,0,0,0.4); - + line-height: 0; /* ensure no space between bottom */ - + } .vignet2 img { @@ -751,7 +755,7 @@ th.rotate > div > span { padding: 1em; text-align: left; line-height: 1.5em; - word-wrap: break-word; + word-wrap: break-word; } .talktext p{ /* remove webkit p margins */ @@ -776,7 +780,7 @@ th.rotate > div > span { /* paleblue */ .paleblue { -# padding: 8px; +# padding: 8px; background: aliceblue; box-shadow:inset 0px 0px 0px 6px #fff; -moz-box-shadow:inset 0px 0px 0px 6px #fff; @@ -948,7 +952,7 @@ th.rotate > div > span { .greenbar { - border: 1px solid #666; + border: 1px solid #666; color: #000; @@ -959,7 +963,7 @@ th.rotate > div > span { } -#footer { +#footer { text-align:center; } @@ -1016,21 +1020,21 @@ th.rotate > div > span { background-color: #3e8e41; } -.flexplot { +.flexplot { position: relative; z-index: 10; } -a.wh:link { +a.wh:link { color: #e9e9e9; } -a.wh:visited { +a.wh:visited { color: #e9e9e9; } -a.wh:hover { +a.wh:hover { color: #e9e9e9; } @@ -1067,7 +1071,7 @@ a.wh:hover { .icon-link a:hover, a:active, a:visited, a:link { /* color: #1c75bc; */ - text-decoration: none; + text-decoration: none; } @@ -1086,9 +1090,9 @@ a.wh:hover { } .mystyle { - font-size: 11pt; + font-size: 11pt; font-family: Arial; - border-collapse: collapse; + border-collapse: collapse; border: 1px solid silver; } diff --git a/static/css/rowsandall2.min.css b/static/css/rowsandall2.min.css index d995d025..ab482e51 100644 --- a/static/css/rowsandall2.min.css +++ b/static/css/rowsandall2.min.css @@ -1 +1 @@ -#main{background-color:transparent;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;min-height:759px;min-width:1024px;width:100%;height:auto}.one{background-image:url("/static/img/landing1.jpg")}.two{background-image:url("/static/img/landing1.jpg")}.three{background-image:url("/static/img/landing2.jpg")}.four{background-image:url("/static/img/landing8b.jpg")}.errorlist{color:red}.watermark{position:absolute;float:center;opacity:.25;font-size:3em;width:100%;top:50%;left:50%;transform:translateX(-25%) translateY(-50%);text-align:center;vertical-align:middle;z-index:1000}.invisible{display:none}html{font-size:62.5%;margin:0;height:100%;width:100%;min-height:100%}body{color:#333;font-size:1.2em;width:100%;min-height:100%;margin:0;box-sizing:border-box}.notyellow{font-size:1.2em;height:auto;padding:0}.yellow{color:#1c75bc;font-size:1.2em;height:auto;padding:0}cox{font-weight:normal;text-align:center;font-size:2em}th{font-weight:bold;align:left}.listtable tbody tr:nth-of-type(even){background-color:#DDD}.listtable thead th{font-weight:bold;align:left}.shortpadded td{padding:3px 3px}.paddedtable td{padding:1px 20px}.cortable{border-collapse:collapse}.cortable td{border:1px solid #999;text-align:center}th.rotate{height:120px;white-space:nowrap}th.rotate>div{transform:translate(28px,91px) rotate(315deg);width:30px}th.rotate>div>span{border-bottom:1px solid #ccc;padding:5px 5px}.fixtable table{table-layout:fixed;width:60%}.message{border:1px solid #000;background-color:#f88;font-weight:bold;color:#000;text-align:center}.midden{text-align:center}.poscor{background-color:#8f8}.weakposcor{background-color:#efe}.negcor{background-color:#f88}.weaknegcor{background-color:#fee}.successmessage{border:1px solid #000;background-color:#8f8;color:#000;text-align:center;font-weight:bold}.deletelink{border:1px solid #000;background-color:#f88;color:#000;text-align:center;font-weight:bold}.navbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#ddd;text-align:center}.navbutton{background-color:#ddd;-moz-border-radius:15px;-webkit-border-radius:15px;border:2px solid #666;padding:5px;text-align:center}.transparentbutton{padding:1px;text-align:center}.tooltip{position:relative;display:inline-block;color:#000}.tooltip a{color:black}.tooltip .tooltiptext{visibility:hidden;width:120px;background-color:#ff6;color:black;text-align:center;border-radius:6px;padding:5px 5px;position:absolute;z-index:999}.tooltip:hover .tooltiptext{visibility:visible;transition-delay:1s}.caption{text-align:center}.site-announcement-box{padding:.2em .5em .2em 0;width:100%;max-width:200px}@media only screen and (max-width:450px){.site-announcement-box{max-width:100%}}.site-announcement{font:1.0/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em .2em .5em;zoom:1;text-align:left;border:solid 1px #333}.site-announcement-white{font:1.0/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em .2em .5em;zoom:1;text-align:left;border:solid 1px #fff}.contentli{margin-left:30px;display:list-item;list-style-type:circle}.dot{border-radius:50%;display:block;text-align:center;width:25px;height:25px;border:solid 1px #333}.dot:hover{text-decoration:none}.rounder{border-radius:10px;display:block;overflow-x:hidden;border:solid 1px #333;padding:5px;margin:2px}.whiteborder{border:solid 2px #aaa}.frontitem{background-color:rgba(255,255,255,0.7);border:solid 1px wite;padding:5px;margin:5px;color:black}.frontitem label{color:black}.frontitem a{color:#1c75bc}.vignet{border-radius:50%;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);box-shadow:inset 0 0 85px rgba(0,0,0,0.4);line-height:0}.vignet img{position:relative;transform:scale(1.5);z-index:-1}.vignet2{border-radius:50%;width:200px;height:200px;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,0.4);box-shadow:inset 0 0 85px rgba(0,0,0,0.4);line-height:0}.vignet2 img{position:center;z-index:-1}.button{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;margin:0;padding:0;zoom:1;text-align:center}.button:active{position:relative;top:1px}.red{color:#faddde;border:solid 1px #980c10;background:#d81b21}.red:hover{background:#b61318}.red:active{color:#de898c}.green{color:#e8f0de;border:solid 1px #538312;background:#64991e}.green:hover{background:#538018}.green:active{color:#a9c08c}.lightgreen{background:#e2f0da;color:#fdffc;border:solid 1px #b2bfaa}.lightgreen:active{color:#f5faf2}.lightgreen:hover{background:#b2bfaa}.mediumgreen{background:#aad090;color:#fafff7;border:solid 1px #8db374}.mediumgreen:active{color:#d8e6cf}.mediumgreen:hover{background:#8db374}.purple{background:#8c1ec1;color:#e9ddf0;border:solid 1px #6b0f99}.purple:active{color:#cfa160}.purple:hover{background:#6b0f99}.violet{background:#c20d60;color:#f0dae5;border:solid 1px #99034e}.violet:active{color:#e595bd}.violet:hover{background:#99034e}.blue{color:#fae7e9;border:solid 1px #27aae2;background:#27aae2}.blue:hover{background:#1c74bb;border:solid 1px #27aae2}.blue:active{color:#fff}.leafletmap{padding:0;margin:0;display:grid;grid-gap:0}.orange{color:#fef4e9;border:solid 1px #da7c0c;background:#f78d1d}.orange:hover{background:#f47c20}.orange:active{color:#fcd3a5}.talk-bubble{margin:40px;display:inline-block;position:relative;width:200px;height:auto;background-color:lightyellow}.border{border:8px solid #666}.round{border-radius:30px;-webkit-border-radius:30px;-moz-border-radius:30px}.tri-right.border.left-top:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.left-top:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:0;bottom:auto;border:22px solid;border-color:lightyellow transparent transparent transparent}.tri-right.border.left-in:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:30px;bottom:auto;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.left-in:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:38px;bottom:auto;border:12px solid;border-color:lightyellow lightyellow transparent transparent}.tri-right.border.btm-left:before{content:' ';position:absolute;width:0;height:0;left:-8px;right:auto;top:auto;bottom:-40px;border:32px solid;border-color:transparent transparent transparent #666}.tri-right.btm-left:after{content:' ';position:absolute;width:0;height:0;left:0;right:auto;top:auto;bottom:-20px;border:22px solid;border-color:transparent transparent transparent lightyellow}.tri-right.border.btm-left-in:before{content:' ';position:absolute;width:0;height:0;left:30px;right:auto;top:auto;bottom:-40px;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.btm-left-in:after{content:' ';position:absolute;width:0;height:0;left:38px;right:auto;top:auto;bottom:-20px;border:12px solid;border-color:lightyellow transparent transparent lightyellow}.tri-right.border.btm-right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:30px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:38px;bottom:-20px;border:12px solid;border-color:lightyellow lightyellow transparent transparent}.tri-right.border.btm-right:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-8px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right:after{content:' ';position:absolute;width:0;height:0;left:auto;right:0;bottom:-20px;border:12px solid;border-color:lightyellow lightyellow transparent transparent}.tri-right.border.right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:30px;bottom:auto;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:38px;bottom:auto;border:12px solid;border-color:lightyellow transparent transparent lightyellow}.tri-right.border.right-top:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.right-top:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:0;bottom:auto;border:20px solid;border-color:lightyellow transparent transparent transparent}.talktext{padding:1em;text-align:left;line-height:1.5em;word-wrap:break-word}.talktext p{-webkit-margin-before:0;-webkit-margin-after:0}.drop-files{border:1px solid #000;color:#000}.palegreen{background:palegreen;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.paleblue{# padding:8px;background:aliceblue;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.lightsalmon{# padding:4px;background:lightsalmon;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.filler{background:darkgray;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.padded{padding:10px}.input{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;color:white;padding:.2em 0 .2em 0;zoom:1;border-radius:.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em;text-align:center}.blueicon{text-decoration:none;display:block;color:#1c75bc;padding:.2em 0 .2em 0;zoom:1}.bigrounded{-webkit-border-radius:2em;-moz-border-radius:2em;border-radius:2em;border:solid 1px white}.medium{font-size:1.2em}.small{font-size:1.0}.black{color:#d7d7d7;border:solid 1px #333;background:#333}.black:hover{background:#000}.black:active{color:#666}.gray{color:#e9e9e9;border:solid 1px #555;background:#6e6e6e}.gray:hover{background:#616161}.gray:active{color:#afafaf}.white{color:#606060;border:solid 1px #b7b7b7;background:#fff}.white:hover{background:#ededed}.white:active{color:#999}.bluetext{color:#27aae2}.rbluetext{color:#27aae1}.rdarkbluetext{color:#1c75bc}.rblue{color:#fae7e9;border:solid 1px #27aae1;background:#27aae1}.rblue:active{color:#fff}.rblue:hover{background:#1c75bc;border:solid 1px #27aae1}.rosy{color:#fae7e9;border:solid 1px #b73948;background:#da5867}.rosy:hover{background:#ba4b58}.rosy:active{color:#dca4ab}.pink{color:#feeef5;border:solid 1px #d2729e;background:#f895c2}.pink:hover{background:#d57ea5}.pink:active{color:#f3c3d9}.greenbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#8f8;text-align:center}#footer{text-align:center}.container_12,.container_16,.container_24{background-color:#fff;background-repeat:repeat-y}.dropbtn{color:white}.dropdown{position:relative;display:inline-block}.dropdown-content{display:none;position:absolute;min-width:160px;z-index:999}.dropdown-content a{text-decoration:none;display:block;z-index:999}.dropdown:hover .dropdown-content{display:block}.dropdown:hover .dropbtn{background-color:#3e8e41}.flexplot{position:relative;z-index:10}a.wh:link{color:#e9e9e9}a.wh:visited{color:#e9e9e9}a.wh:hover{color:#e9e9e9}.bk-canvas-map{overflow:hidden}.container{padding:5% 5%}.wrapwords{-ms-word-break:break-all;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.icon-link a{text-decoration:none}.icon-link a:hover,a:active,a:visited,a:link{text-decoration:none}.mapdiv{padding:0 !important}.mapdiv img{float:left !important;padding:0 !important}.paypalpix{width:auto !important;max-width:1px}.mystyle{font-size:11pt;font-family:Arial;border-collapse:collapse;border:1px solid silver}.pandastable tr{display:block}.pandastable th,.pandastable td{width:100px}.pandastable tbody{display:block;height:1200px;overflow:auto}.pandastable td,.pandastable th{padding:5px}.pandastable tr:nth-child(even){background:#e0e0e0}.pandastable tr:hover{background:silver;cursor:pointer}table.djangoform tbody>tr>th{vertical-align:top} \ No newline at end of file +#main{background-color:initial;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size:cover;min-height:759px;min-width:1024px;width:100%;height:auto}.one{background-image:url(/static/img/landing1.jpg)}.two{background-image:url(/static/img/landing1.jpg)}.three{background-image:url(/static/img/landing2.jpg)}.four{background-image:url(/static/img/landing8b.jpg)}.errorlist{color:red}.watermark{position:absolute;float:center;opacity:.25;font-size:3em;width:100%;top:50%;left:50%;transform:translateX(-25%)translateY(-50%);text-align:center;vertical-align:middle;z-index:1000}.invisible{display:none}html{font-size:62.5%;margin:0;height:100%;width:100%;min-height:100%}body{color:#333;font-size:1.2em;width:100%;min-height:100%;margin:0;box-sizing:border-box}.notyellow{font-size:1.2em;height:auto;padding:0}.yellow{color:#1c75bc;font-size:1.2em;height:auto;padding:0}cox{font-weight:400;text-align:center;font-size:2em}th{font-weight:700;align:left}.listtable tbody tr:nth-of-type(even){background-color:#ddd}.listtable thead th{font-weight:700;align:left}.shortpadded td{padding:3px}.paddedtable td{padding:1px 20px}.shortpadded th{padding:3px}.paddedtable th{padding:1px 20px}.cortable{border-collapse:collapse}.cortable td{border:1px solid #999;text-align:center}th.rotate{height:120px;white-space:nowrap}th.rotate>div{transform:translate(28px,91px)rotate(315deg);width:30px}th.rotate>div>span{border-bottom:1px solid #ccc;padding:5px}.fixtable table{table-layout:fixed;width:60%}.message{border:1px solid #000;background-color:#f88;font-weight:700;color:#000;text-align:center}.midden{text-align:center}.poscor{background-color:#8f8}.weakposcor{background-color:#efe}.negcor{background-color:#f88}.weaknegcor{background-color:#fee}.successmessage{border:1px solid #000;background-color:#8f8;color:#000;text-align:center;font-weight:700}.deletelink{border:1px solid #000;background-color:#f88;color:#000;text-align:center;font-weight:700}.navbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#ddd;text-align:center}.navbutton{background-color:#ddd;-moz-border-radius:15px;-webkit-border-radius:15px;border:2px solid #666;padding:5px;text-align:center}.transparentbutton{padding:1px;text-align:center}.tooltip{position:relative;display:inline-block;color:#000}.tooltip a{color:#000}.tooltip .tooltiptext{visibility:hidden;width:120px;background-color:#ff6;color:#000;text-align:center;border-radius:6px;padding:5px;position:absolute;z-index:999}.tooltip:hover .tooltiptext{visibility:visible;transition-delay:1s}.caption{text-align:center}.site-announcement-box{padding:.2em .5em .2em 0;width:100%;max-width:200px}@media only screen and (max-width:450px){.site-announcement-box{max-width:100%}}.site-announcement{font:1em/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em;zoom:1;text-align:left;border:solid 1px #333}.site-announcement-white{font:1em/1.2em sans-serif;text-decoration:none;display:block;padding:.2em .5em;zoom:1;text-align:left;border:solid 1px #fff}.contentli{margin-left:30px;display:list-item;list-style-type:circle}.dot{border-radius:50%;display:block;text-align:center;width:25px;height:25px;border:solid 1px #333}.dot:hover{text-decoration:none}.rounder{border-radius:10px;display:block;overflow-x:hidden;border:solid 1px #333;padding:5px;margin:2px}.whiteborder{border:solid 2px #aaa}.frontitem{background-color:rgba(255,255,255,.7);border:solid 1px wite;padding:5px;margin:5px;color:#000}.frontitem label{color:#000}.frontitem a{color:#1c75bc}.vignet{border-radius:50%;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,.4);box-shadow:inset 0 0 85px rgba(0,0,0,.4);line-height:0}.vignet img{position:relative;transform:scale(1.5);z-index:-1}.vignet2{border-radius:50%;width:200px;height:200px;display:block;overflow:hidden;padding:5px;margin:5px;-webkit-box-shadow:inset 0 0 85px rgba(0,0,0,.4);-moz-box-shadow:inset 0 0 85px rgba(0,0,0,.4);box-shadow:inset 0 0 85px rgba(0,0,0,.4);line-height:0}.vignet2 img{position:center;z-index:-1}.button{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;margin:0;padding:0;zoom:1;text-align:center}.button:active{position:relative;top:1px}.red{color:#faddde;border:solid 1px #980c10;background:#d81b21}.red:hover{background:#b61318}.red:active{color:#de898c}.green{color:#e8f0de;border:solid 1px #538312;background:#64991e}.green:hover{background:#538018}.green:active{color:#a9c08c}.lightgreen{background:#e2f0da;color:#fdffc;border:solid 1px #b2bfaa}.lightgreen:active{color:#f5faf2}.lightgreen:hover{background:#b2bfaa}.mediumgreen{background:#aad090;color:#fafff7;border:solid 1px #8db374}.mediumgreen:active{color:#d8e6cf}.mediumgreen:hover{background:#8db374}.purple{background:#8c1ec1;color:#e9ddf0;border:solid 1px #6b0f99}.purple:active{color:#cfa160}.purple:hover{background:#6b0f99}.violet{background:#c20d60;color:#f0dae5;border:solid 1px #99034e}.violet:active{color:#e595bd}.violet:hover{background:#99034e}.blue{color:#fae7e9;border:solid 1px #27aae2;background:#27aae2}.blue:hover{background:#1c74bb;border:solid 1px #27aae2}.blue:active{color:#fff}.leafletmap{padding:0;margin:0;display:grid;grid-gap:0}.orange{color:#fef4e9;border:solid 1px #da7c0c;background:#f78d1d}.orange:hover{background:#f47c20}.orange:active{color:#fcd3a5}.talk-bubble{margin:40px;display:inline-block;position:relative;width:200px;height:auto;background-color:#ffffe0}.border{border:8px solid #666}.round{border-radius:30px;-webkit-border-radius:30px;-moz-border-radius:30px}.tri-right.border.left-top:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.left-top:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:0;bottom:auto;border:22px solid;border-color:#ffffe0 transparent transparent transparent}.tri-right.border.left-in:before{content:' ';position:absolute;width:0;height:0;left:-40px;right:auto;top:30px;bottom:auto;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.left-in:after{content:' ';position:absolute;width:0;height:0;left:-20px;right:auto;top:38px;bottom:auto;border:12px solid;border-color:#ffffe0 #ffffe0 transparent transparent}.tri-right.border.btm-left:before{content:' ';position:absolute;width:0;height:0;left:-8px;right:auto;top:auto;bottom:-40px;border:32px solid;border-color:transparent transparent transparent #666}.tri-right.btm-left:after{content:' ';position:absolute;width:0;height:0;left:0;right:auto;top:auto;bottom:-20px;border:22px solid;border-color:transparent transparent transparent #ffffe0}.tri-right.border.btm-left-in:before{content:' ';position:absolute;width:0;height:0;left:30px;right:auto;top:auto;bottom:-40px;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.btm-left-in:after{content:' ';position:absolute;width:0;height:0;left:38px;right:auto;top:auto;bottom:-20px;border:12px solid;border-color:#ffffe0 transparent transparent #ffffe0}.tri-right.border.btm-right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:30px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:38px;bottom:-20px;border:12px solid;border-color:#ffffe0 #ffffe0 transparent transparent}.tri-right.border.btm-right:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-8px;bottom:-40px;border:20px solid;border-color:#666 #666 transparent transparent}.tri-right.btm-right:after{content:' ';position:absolute;width:0;height:0;left:auto;right:0;bottom:-20px;border:12px solid;border-color:#ffffe0 #ffffe0 transparent transparent}.tri-right.border.right-in:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:30px;bottom:auto;border:20px solid;border-color:#666 transparent transparent #666}.tri-right.right-in:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:38px;bottom:auto;border:12px solid;border-color:#ffffe0 transparent transparent #ffffe0}.tri-right.border.right-top:before{content:' ';position:absolute;width:0;height:0;left:auto;right:-40px;top:-8px;bottom:auto;border:32px solid;border-color:#666 transparent transparent transparent}.tri-right.right-top:after{content:' ';position:absolute;width:0;height:0;left:auto;right:-20px;top:0;bottom:auto;border:20px solid;border-color:#ffffe0 transparent transparent transparent}.talktext{padding:1em;text-align:left;line-height:1.5em;word-wrap:break-word}.talktext p{-webkit-margin-before:0;-webkit-margin-after:0}.drop-files{border:1px solid #000;color:#000}.palegreen{background:#98fb98;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.paleblue{# padding: 8px;background:#f0f8ff;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.lightsalmon{# padding: 4px;background:#ffa07a;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.filler{background:#a9a9a9;box-shadow:inset 0 0 0 6px #fff;-moz-box-shadow:inset 0 0 0 6px #fff;box-shadow:inset 0 0 0 6px #fff}.padded{padding:10px}.input{font:1.1em/1.5em sans-serif;text-decoration:none;display:block;color:#fff;padding:.2em 0;zoom:1;border-radius:.5em;-moz-border-radius:.5em;-webkit-border-radius:.5em;text-align:center}.blueicon{text-decoration:none;display:block;color:#1c75bc;padding:.2em 0;zoom:1}.bigrounded{-webkit-border-radius:2em;-moz-border-radius:2em;border-radius:2em;border:solid 1px #fff}.medium{font-size:1.2em}.small{font-size:1em}.black{color:#d7d7d7;border:solid 1px #333;background:#333}.black:hover{background:#000}.black:active{color:#666}.gray{color:#e9e9e9;border:solid 1px #555;background:#6e6e6e}.gray:hover{background:#616161}.gray:active{color:#afafaf}.white{color:#606060;border:solid 1px #b7b7b7;background:#fff}.white:hover{background:#ededed}.white:active{color:#999}.bluetext{color:#27aae2}.rbluetext{color:#27aae1}.rdarkbluetext{color:#1c75bc}.rblue{color:#fae7e9;border:solid 1px #27aae1;background:#27aae1}.rblue:active{color:#fff}.rblue:hover{background:#1c75bc;border:solid 1px #27aae1}.rosy{color:#fae7e9;border:solid 1px #b73948;background:#da5867}.rosy:hover{background:#ba4b58}.rosy:active{color:#dca4ab}.pink{color:#feeef5;border:solid 1px #d2729e;background:#f895c2}.pink:hover{background:#d57ea5}.pink:active{color:#f3c3d9}.greenbar{border:1px solid #666;color:#000;overflow:hidden;background-color:#8f8;text-align:center}#footer{text-align:center}.container_12,.container_16,.container_24{background-color:#fff;background-repeat:repeat-y}.container_12{}.dropbtn{color:#fff}.dropdown{position:relative;display:inline-block}.dropdown-content{display:none;position:absolute;min-width:160px;z-index:999}.dropdown-content a{text-decoration:none;display:block;z-index:999}.dropdown:hover .dropdown-content{display:block}.dropdown:hover .dropbtn{background-color:#3e8e41}.flexplot{position:relative;z-index:10}a.wh:link{color:#e9e9e9}a.wh:visited{color:#e9e9e9}a.wh:hover{color:#e9e9e9}.bk-canvas-map{overflow:hidden}.container{padding:5%}.wrapwords{-ms-word-break:break-all;word-break:break-all;word-break:break-word;-webkit-hyphens:auto;-moz-hyphens:auto;-ms-hyphens:auto;hyphens:auto}.icon-link a{text-decoration:none}.icon-link a:hover,a:active,a:visited,a:link{text-decoration:none}.mapdiv{padding:0!important}.mapdiv img{float:left!important;padding:0!important}.paypalpix{width:auto!important;max-width:1px}.mystyle{font-size:11pt;font-family:Arial;border-collapse:collapse;border:1px solid silver}.pandastable tr{display:block}.pandastable th,.pandastable td{width:100px}.pandastable tbody{display:block;height:1200px;overflow:auto}.pandastable td,.pandastable th{padding:5px}.pandastable tr:nth-child(even){background:#e0e0e0}.pandastable tr:hover{background:silver;cursor:pointer}table.djangoform tbody>tr>th{vertical-align:top} \ No newline at end of file From 7b6e2502fbda9f2570276cd941aad6fff04e22df Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 27 May 2020 15:28:36 +0200 Subject: [PATCH 16/22] adding categories to indoor races --- rowers/plannedsessions.py | 2 +- rowers/templates/virtualevent.html | 2 +- rowers/views/racesviews.py | 100 +++++++++++++++++++++++++++-- 3 files changed, 97 insertions(+), 7 deletions(-) diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 5201c279..f703e206 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1553,7 +1553,7 @@ def add_workout_race(ws,race,r,splitsecond=0,recordid=0): job = myqueue(queue,handle_check_race_course,ws[0].csvfilename, ws[0].id,race.course.id,record.id,splitsecond=splitsecond, - referencespeed=record.referencespeed) + referencespeed=record.referencespeed,coursedistance=race.course.distance) diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index cd8c6ccc..556ee5e4 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -459,7 +459,7 @@ {% endif %} {% for record in records %} - {% if record.userid == request.user.rower.id %} + {% if record.userid == request.user.rower.id and forloop.counter == 1 %} {% if race.sessiontype == 'race' %} {% if record.emailnotifications %} diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index f968306a..9bd0693a 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1422,6 +1422,12 @@ def virtualevent_addboat_view(request,id=0): except VirtualRace.DoesNotExist: raise Http404("Virtual Challenge does not exist") + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + + if not race_can_adddiscipline(r,race): messages.error(request,"You cannot register for this race") @@ -1445,7 +1451,7 @@ def virtualevent_addboat_view(request,id=0): # we're still here if request.method == 'POST': # process form - form = VirtualRaceResultForm(request.POST) + form = VirtualRaceResultForm(request.POST,categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] @@ -1467,7 +1473,7 @@ def virtualevent_addboat_view(request,id=0): if sex == 'not specified': sex = 'male' - if boattype in boattypes and boatclass in boatclasses: + if boattype in boattypes and boatclass in boatclasses and race.coursestandards is None: # check if different sexes therecords = records.filter( boattype=boattype, @@ -1488,6 +1494,49 @@ def virtualevent_addboat_view(request,id=0): return HttpResponseRedirect(url) + coursestandard = None + referencespeed = 5.0 + + if race.coursestandards is not None: + coursestandard = cd['entrycategory'] + thegroups = [record.entrycategory for record in records] + if coursestandard in thegroups: + messages.error(request,"You have already registered in that group") + url = reverse('virtualevent_view', + kwargs = { + 'id': race.id + } + ) + + return HttpResponseRedirect(url) + + referencespeed = coursestandard.referencespeed + boattype = coursestandard.boattype + boatclass = coursestandard.boatclass + weightcategory = coursestandard.weightclass + adaptiveclass = coursestandard.adaptiveclass + skillclass = coursestandard.skillclass + + returnurl = reverse(virtualevent_register_view, + kwargs={'id':race.id}) + + if age < coursestandard.agemin: + messages.error(request,'You are younger than the minimum age for this group') + return HttpResponseRedirect(returnurl) + + if age > coursestandard.agemax: + messages.error(request,'You are older than the maximum age for this group') + return HttpResponseRedirect(returnurl) + + if sex == 'male' and coursestandard.sex != 'male': + messages.error(request,'Men are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + messages.error(request,'Mixed crews are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + record = VirtualRaceResult( userid=r.id, teamname=teamname, @@ -1502,8 +1551,10 @@ def virtualevent_addboat_view(request,id=0): boattype=boattype, boatclass=boatclass, coursecompleted=False, + referencespeed=referencespeed, + entrycategory=coursestandard, sex=sex, - age=age + age=age, ) record.save() @@ -1840,6 +1891,11 @@ def indoorvirtualevent_register_view(request,id=0): except VirtualRace.DoesNotExist: raise Http404("Virtual Challenge does not exist") + categories = None + if race.coursestandards is not None: + categories = CourseStandard.objects.filter( + standardcollection=race.coursestandards).order_by("name") + if not race_can_register(r,race): messages.error(request,"You cannot register for this race") @@ -1853,7 +1909,7 @@ def indoorvirtualevent_register_view(request,id=0): # we're still here if request.method == 'POST': # process form - form = IndoorVirtualRaceResultForm(request.POST) + form = IndoorVirtualRaceResultForm(request.POST,categories=categories) if form.is_valid(): cd = form.cleaned_data teamname = cd['teamname'] @@ -1871,6 +1927,38 @@ def indoorvirtualevent_register_view(request,id=0): if sex == 'not specified': sex = 'male' + coursestandard = None + referencespeed = 5.0 + + if race.coursestandards is not None: + coursestandard = cd['entrycategory'] + referencespeed = coursestandard.referencespeed + boatclass = coursestandard.boatclass + weightcategory = coursestandard.weightclass + adaptiveclass = coursestandard.adaptiveclass + skillclass = coursestandard.skillclass + + returnurl = reverse(virtualevent_register_view, + kwargs={'id':race.id}) + + if age < coursestandard.agemin: + messages.error(request,'You are younger than the minimum age for this group') + return HttpResponseRedirect(returnurl) + + if age > coursestandard.agemax: + messages.error(request,'You are older than the maximum age for this group') + return HttpResponseRedirect(returnurl) + + if sex == 'male' and coursestandard.sex != 'male': + messages.error(request,'Men are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + if sex == 'mixed' and coursestandard.sex not in ['mixed','male']: + messages.error(request,'Mixed crews are not allowed to enter this category') + return HttpResponseRedirect(returnurl) + + + record = IndoorVirtualRaceResult( userid=r.id, teamname=teamname, @@ -1885,7 +1973,9 @@ def indoorvirtualevent_register_view(request,id=0): boatclass=boatclass, coursecompleted=False, sex=sex, - age=age + age=age, + entrycategory=coursestandard, + referencespeed=referencespeed ) record.save() From 7f402225b867a1191877bcf2049e77dd27f52587 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 28 May 2020 05:15:35 +0200 Subject: [PATCH 17/22] bug fix --- rowers/models.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rowers/models.py b/rowers/models.py index 0b5ed03f..a0a74a42 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -3059,7 +3059,7 @@ class IndoorVirtualRaceResultForm(ModelForm): def __init__(self, *args, **kwargs): - categories = kwargs.pop('categories') + categories = kwargs.pop('categories',None) super(IndoorVirtualRaceResultForm, self).__init__(*args, **kwargs) if categories is not None: self.fields['entrycategory'].queryset = categories From 98efddb8d7be50b893f6173417337a6191e15b86 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 28 May 2020 06:16:59 +0200 Subject: [PATCH 18/22] standards can be downloaded and deactivated --- rowers/migrations/0001_initial.py | 40 ++++++++------ rowers/models.py | 10 +++- rowers/scoring.py | 86 +++++++++++++++++++++-------- rowers/templates/standard_form.html | 13 ++++- rowers/templates/standard_view.html | 6 +- rowers/urls.py | 4 ++ rowers/views/racesviews.py | 50 ++++++++++++++++- 7 files changed, 163 insertions(+), 46 deletions(-) diff --git a/rowers/migrations/0001_initial.py b/rowers/migrations/0001_initial.py index 95afc7b0..5f0cdb04 100644 --- a/rowers/migrations/0001_initial.py +++ b/rowers/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.1.7 on 2020-05-26 18:20 +# Generated by Django 2.1.7 on 2020-05-28 03:31 import datetime from django.conf import settings @@ -45,7 +45,7 @@ class Migration(migrations.Migration): name='C2WorldClassAgePerformance', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female')], default='female', max_length=30)), ('age', models.IntegerField(default=19, verbose_name='Age')), ('distance', models.IntegerField(default=2000)), @@ -59,8 +59,8 @@ class Migration(migrations.Migration): name='CalcAgePerformance', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), - ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female')], default='female', max_length=30)), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), + ('sex', models.CharField(choices=[('male', 'Open'), ('female', 'Female')], default='female', max_length=30)), ('age', models.IntegerField(default=19, verbose_name='Age')), ('duration', models.FloatField(blank=True, default=1)), ('power', models.IntegerField(default=200)), @@ -109,14 +109,14 @@ class Migration(migrations.Migration): ('name', models.CharField(max_length=150)), ('coursedistance', models.IntegerField()), ('coursetime', models.CharField(default='', max_length=100)), - ('coursestandard', models.FloatField()), + ('referencespeed', models.FloatField()), ('agemin', models.IntegerField(default=0)), ('agemax', models.IntegerField(default=120)), ('boatclass', models.CharField(max_length=150)), ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50)), ('sex', models.CharField(max_length=150)), ('weightclass', models.CharField(max_length=150)), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50)), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50)), ('skillclass', models.CharField(max_length=150)), ], ), @@ -227,15 +227,19 @@ class Migration(migrations.Migration): ('teamname', models.CharField(blank=True, max_length=80, null=True, verbose_name='Team Name')), ('username', models.CharField(max_length=150)), ('workoutid', models.IntegerField(null=True)), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('skillclass', models.CharField(default='Open', max_length=50, verbose_name='Skill Class')), ('duration', models.TimeField(default=datetime.time(1, 0))), ('distance', models.IntegerField(default=0)), + ('referencespeed', models.FloatField(default=5.0)), + ('points', models.IntegerField(default=0)), ('boatclass', models.CharField(choices=[('rower', 'Indoor Rower'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides')], default='rower', max_length=40, verbose_name='Ergometer Class')), ('coursecompleted', models.BooleanField(default=False)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30, verbose_name='Gender')), ('age', models.IntegerField(null=True)), ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive challenge notifications by email')), + ('entrycategory', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.CourseStandard', verbose_name='Group')), ], ), migrations.CreateModel( @@ -340,9 +344,9 @@ class Migration(migrations.Migration): ('tr', models.IntegerField(default=167, verbose_name='TR band lower HR')), ('an', models.IntegerField(default=180, verbose_name='AN band lower HR')), ('hrftp', models.IntegerField(default=0, verbose_name='FTP heart rate')), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30)), ('sex', models.CharField(choices=[('male', 'male'), ('female', 'female'), ('not specified', 'not specified')], default='not specified', max_length=30)), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), ('birthdate', models.DateField(blank=True, null=True)), ('ftp', models.IntegerField(default=226, verbose_name='Functional Threshold Power')), ('p0', models.FloatField(default=1.0, verbose_name='CP p1')), @@ -588,10 +592,12 @@ class Migration(migrations.Migration): ('teamname', models.CharField(blank=True, max_length=80, null=True, verbose_name='Team Name')), ('username', models.CharField(max_length=150)), ('workoutid', models.IntegerField(null=True)), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Class')), + ('skillclass', models.CharField(default='Open', max_length=50, verbose_name='Skill Class')), ('duration', models.TimeField(default=datetime.time(1, 0))), ('distance', models.IntegerField(default=0)), + ('points', models.IntegerField(default=0)), ('boatclass', models.CharField(choices=[('water', 'Standard Racing Shell'), ('coastal', 'Coastal'), ('c-boat', 'Dutch C boat'), ('churchboat', 'Finnish Church boat')], default='water', max_length=40, verbose_name='Boat Class')), ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=40, verbose_name='Boat Type')), ('coursecompleted', models.BooleanField(default=False)), @@ -600,6 +606,8 @@ class Migration(migrations.Migration): ('emailnotifications', models.BooleanField(default=True, verbose_name='Receive challenge notifications by email')), ('startsecond', models.FloatField(default=0)), ('endsecond', models.FloatField(default=0)), + ('referencespeed', models.FloatField(default=5.0)), + ('entrycategory', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.CourseStandard', verbose_name='Group')), ], ), migrations.CreateModel( @@ -611,7 +619,7 @@ class Migration(migrations.Migration): ('workouttype', models.CharField(choices=[('water', 'Standard Racing Shell'), ('rower', 'Indoor Rower'), ('skierg', 'Ski Erg'), ('bikeerg', 'Bike Erg'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides'), ('paddle', 'Paddle Adapter'), ('snow', 'On-snow'), ('coastal', 'Coastal'), ('c-boat', 'Dutch C boat'), ('churchboat', 'Finnish Church boat'), ('Ride', 'Ride'), ('Bike', 'Bike'), ('Run', 'Run'), ('NordicSki', 'NordicSki'), ('Swim', 'Swim'), ('Hike', 'Hike'), ('Walk', 'Walk'), ('Canoeing', 'Canoeing'), ('Crossfit', 'Crossfit'), ('StandUpPaddling', 'StandUpPaddling'), ('IceSkate', 'IceSkate'), ('WeightTraining', 'WeightTraining'), ('InlineSkate', 'InlineSkate'), ('Kayaking', 'Kayaking'), ('Workout', 'Workout'), ('Yoga', 'Yoga'), ('other', 'Other')], max_length=50, verbose_name='Exercise/Boat Class')), ('workoutsource', models.CharField(default='unknown', max_length=100)), ('boattype', models.CharField(choices=[('1x', '1x (single)'), ('2x', '2x (double)'), ('2x+', '2x+ (coxed double)'), ('2-', '2- (pair)'), ('2+', '2+ (coxed pair)'), ('3x+', '3x+ (coxed triple)'), ('3x-', '3x- (triple)'), ('4x', '4x (quad)'), ('4x+', '4x+ (coxed quad)'), ('4-', '4- (four)'), ('4+', '4+ (coxed four)'), ('8+', '8+ (eight)'), ('8x+', '8x+ (octuple scull)')], default='1x', max_length=50, verbose_name='Boat Type')), - ('adaptiveclass', models.CharField(choices=[('None', 'None'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), + ('adaptiveclass', models.CharField(choices=[('None', 'Open'), ('PR1', 'PR1 (Arms and Shoulders)'), ('PR2', 'PR2 (Trunk and Arms)'), ('PR3', 'PR3 (Leg Trunk and Arms)'), ('FES', 'FES (Functional Electrical Stimulation)')], default='None', max_length=50, verbose_name='Adaptive Classification')), ('starttime', models.TimeField(default=datetime.time(12, 0))), ('startdatetime', models.DateTimeField(blank=True, null=True)), ('timezone', models.CharField(default='UTC', max_length=100)), @@ -624,7 +632,7 @@ class Migration(migrations.Migration): ('normp', models.IntegerField(blank=True, default=-1)), ('normv', models.FloatField(blank=True, default=-1)), ('normw', models.FloatField(blank=True, default=-1)), - ('weightcategory', models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), + ('weightcategory', models.CharField(choices=[('hwt', 'open-weight'), ('lwt', 'light-weight')], default='hwt', max_length=10, verbose_name='Weight Category')), ('weightvalue', models.FloatField(blank=True, default=80.0, verbose_name='Average Crew Weight (kg)')), ('csvfilename', models.CharField(blank=True, max_length=150)), ('uploadedtoc2', models.IntegerField(default=0)), @@ -671,7 +679,7 @@ class Migration(migrations.Migration): ('timezone', models.CharField(choices=[('Africa/Abidjan', 'Africa/Abidjan'), ('Africa/Accra', 'Africa/Accra'), ('Africa/Addis_Ababa', 'Africa/Addis_Ababa'), ('Africa/Algiers', 'Africa/Algiers'), ('Africa/Asmara', 'Africa/Asmara'), ('Africa/Bamako', 'Africa/Bamako'), ('Africa/Bangui', 'Africa/Bangui'), ('Africa/Banjul', 'Africa/Banjul'), ('Africa/Bissau', 'Africa/Bissau'), ('Africa/Blantyre', 'Africa/Blantyre'), ('Africa/Brazzaville', 'Africa/Brazzaville'), ('Africa/Bujumbura', 'Africa/Bujumbura'), ('Africa/Cairo', 'Africa/Cairo'), ('Africa/Casablanca', 'Africa/Casablanca'), ('Africa/Ceuta', 'Africa/Ceuta'), ('Africa/Conakry', 'Africa/Conakry'), ('Africa/Dakar', 'Africa/Dakar'), ('Africa/Dar_es_Salaam', 'Africa/Dar_es_Salaam'), ('Africa/Djibouti', 'Africa/Djibouti'), ('Africa/Douala', 'Africa/Douala'), ('Africa/El_Aaiun', 'Africa/El_Aaiun'), ('Africa/Freetown', 'Africa/Freetown'), ('Africa/Gaborone', 'Africa/Gaborone'), ('Africa/Harare', 'Africa/Harare'), ('Africa/Johannesburg', 'Africa/Johannesburg'), ('Africa/Juba', 'Africa/Juba'), ('Africa/Kampala', 'Africa/Kampala'), ('Africa/Khartoum', 'Africa/Khartoum'), ('Africa/Kigali', 'Africa/Kigali'), ('Africa/Kinshasa', 'Africa/Kinshasa'), ('Africa/Lagos', 'Africa/Lagos'), ('Africa/Libreville', 'Africa/Libreville'), ('Africa/Lome', 'Africa/Lome'), ('Africa/Luanda', 'Africa/Luanda'), ('Africa/Lubumbashi', 'Africa/Lubumbashi'), ('Africa/Lusaka', 'Africa/Lusaka'), ('Africa/Malabo', 'Africa/Malabo'), ('Africa/Maputo', 'Africa/Maputo'), ('Africa/Maseru', 'Africa/Maseru'), ('Africa/Mbabane', 'Africa/Mbabane'), ('Africa/Mogadishu', 'Africa/Mogadishu'), ('Africa/Monrovia', 'Africa/Monrovia'), ('Africa/Nairobi', 'Africa/Nairobi'), ('Africa/Ndjamena', 'Africa/Ndjamena'), ('Africa/Niamey', 'Africa/Niamey'), ('Africa/Nouakchott', 'Africa/Nouakchott'), ('Africa/Ouagadougou', 'Africa/Ouagadougou'), ('Africa/Porto-Novo', 'Africa/Porto-Novo'), ('Africa/Sao_Tome', 'Africa/Sao_Tome'), ('Africa/Tripoli', 'Africa/Tripoli'), ('Africa/Tunis', 'Africa/Tunis'), ('Africa/Windhoek', 'Africa/Windhoek'), ('America/Adak', 'America/Adak'), ('America/Anchorage', 'America/Anchorage'), ('America/Anguilla', 'America/Anguilla'), ('America/Antigua', 'America/Antigua'), ('America/Araguaina', 'America/Araguaina'), ('America/Argentina/Buenos_Aires', 'America/Argentina/Buenos_Aires'), ('America/Argentina/Catamarca', 'America/Argentina/Catamarca'), ('America/Argentina/Cordoba', 'America/Argentina/Cordoba'), ('America/Argentina/Jujuy', 'America/Argentina/Jujuy'), ('America/Argentina/La_Rioja', 'America/Argentina/La_Rioja'), ('America/Argentina/Mendoza', 'America/Argentina/Mendoza'), ('America/Argentina/Rio_Gallegos', 'America/Argentina/Rio_Gallegos'), ('America/Argentina/Salta', 'America/Argentina/Salta'), ('America/Argentina/San_Juan', 'America/Argentina/San_Juan'), ('America/Argentina/San_Luis', 'America/Argentina/San_Luis'), ('America/Argentina/Tucuman', 'America/Argentina/Tucuman'), ('America/Argentina/Ushuaia', 'America/Argentina/Ushuaia'), ('America/Aruba', 'America/Aruba'), ('America/Asuncion', 'America/Asuncion'), ('America/Atikokan', 'America/Atikokan'), ('America/Bahia', 'America/Bahia'), ('America/Bahia_Banderas', 'America/Bahia_Banderas'), ('America/Barbados', 'America/Barbados'), ('America/Belem', 'America/Belem'), ('America/Belize', 'America/Belize'), ('America/Blanc-Sablon', 'America/Blanc-Sablon'), ('America/Boa_Vista', 'America/Boa_Vista'), ('America/Bogota', 'America/Bogota'), ('America/Boise', 'America/Boise'), ('America/Cambridge_Bay', 'America/Cambridge_Bay'), ('America/Campo_Grande', 'America/Campo_Grande'), ('America/Cancun', 'America/Cancun'), ('America/Caracas', 'America/Caracas'), ('America/Cayenne', 'America/Cayenne'), ('America/Cayman', 'America/Cayman'), ('America/Chicago', 'America/Chicago'), ('America/Chihuahua', 'America/Chihuahua'), ('America/Costa_Rica', 'America/Costa_Rica'), ('America/Creston', 'America/Creston'), ('America/Cuiaba', 'America/Cuiaba'), ('America/Curacao', 'America/Curacao'), ('America/Danmarkshavn', 'America/Danmarkshavn'), ('America/Dawson', 'America/Dawson'), ('America/Dawson_Creek', 'America/Dawson_Creek'), ('America/Denver', 'America/Denver'), ('America/Detroit', 'America/Detroit'), ('America/Dominica', 'America/Dominica'), ('America/Edmonton', 'America/Edmonton'), ('America/Eirunepe', 'America/Eirunepe'), ('America/El_Salvador', 'America/El_Salvador'), ('America/Fort_Nelson', 'America/Fort_Nelson'), ('America/Fortaleza', 'America/Fortaleza'), ('America/Glace_Bay', 'America/Glace_Bay'), ('America/Goose_Bay', 'America/Goose_Bay'), ('America/Grand_Turk', 'America/Grand_Turk'), ('America/Grenada', 'America/Grenada'), ('America/Guadeloupe', 'America/Guadeloupe'), ('America/Guatemala', 'America/Guatemala'), ('America/Guayaquil', 'America/Guayaquil'), ('America/Guyana', 'America/Guyana'), ('America/Halifax', 'America/Halifax'), ('America/Havana', 'America/Havana'), ('America/Hermosillo', 'America/Hermosillo'), ('America/Indiana/Indianapolis', 'America/Indiana/Indianapolis'), ('America/Indiana/Knox', 'America/Indiana/Knox'), ('America/Indiana/Marengo', 'America/Indiana/Marengo'), ('America/Indiana/Petersburg', 'America/Indiana/Petersburg'), ('America/Indiana/Tell_City', 'America/Indiana/Tell_City'), ('America/Indiana/Vevay', 'America/Indiana/Vevay'), ('America/Indiana/Vincennes', 'America/Indiana/Vincennes'), ('America/Indiana/Winamac', 'America/Indiana/Winamac'), ('America/Inuvik', 'America/Inuvik'), ('America/Iqaluit', 'America/Iqaluit'), ('America/Jamaica', 'America/Jamaica'), ('America/Juneau', 'America/Juneau'), ('America/Kentucky/Louisville', 'America/Kentucky/Louisville'), ('America/Kentucky/Monticello', 'America/Kentucky/Monticello'), ('America/Kralendijk', 'America/Kralendijk'), ('America/La_Paz', 'America/La_Paz'), ('America/Lima', 'America/Lima'), ('America/Los_Angeles', 'America/Los_Angeles'), ('America/Lower_Princes', 'America/Lower_Princes'), ('America/Maceio', 'America/Maceio'), ('America/Managua', 'America/Managua'), ('America/Manaus', 'America/Manaus'), ('America/Marigot', 'America/Marigot'), ('America/Martinique', 'America/Martinique'), ('America/Matamoros', 'America/Matamoros'), ('America/Mazatlan', 'America/Mazatlan'), ('America/Menominee', 'America/Menominee'), ('America/Merida', 'America/Merida'), ('America/Metlakatla', 'America/Metlakatla'), ('America/Mexico_City', 'America/Mexico_City'), ('America/Miquelon', 'America/Miquelon'), ('America/Moncton', 'America/Moncton'), ('America/Monterrey', 'America/Monterrey'), ('America/Montevideo', 'America/Montevideo'), ('America/Montserrat', 'America/Montserrat'), ('America/Nassau', 'America/Nassau'), ('America/New_York', 'America/New_York'), ('America/Nipigon', 'America/Nipigon'), ('America/Nome', 'America/Nome'), ('America/Noronha', 'America/Noronha'), ('America/North_Dakota/Beulah', 'America/North_Dakota/Beulah'), ('America/North_Dakota/Center', 'America/North_Dakota/Center'), ('America/North_Dakota/New_Salem', 'America/North_Dakota/New_Salem'), ('America/Nuuk', 'America/Nuuk'), ('America/Ojinaga', 'America/Ojinaga'), ('America/Panama', 'America/Panama'), ('America/Pangnirtung', 'America/Pangnirtung'), ('America/Paramaribo', 'America/Paramaribo'), ('America/Phoenix', 'America/Phoenix'), ('America/Port-au-Prince', 'America/Port-au-Prince'), ('America/Port_of_Spain', 'America/Port_of_Spain'), ('America/Porto_Velho', 'America/Porto_Velho'), ('America/Puerto_Rico', 'America/Puerto_Rico'), ('America/Punta_Arenas', 'America/Punta_Arenas'), ('America/Rainy_River', 'America/Rainy_River'), ('America/Rankin_Inlet', 'America/Rankin_Inlet'), ('America/Recife', 'America/Recife'), ('America/Regina', 'America/Regina'), ('America/Resolute', 'America/Resolute'), ('America/Rio_Branco', 'America/Rio_Branco'), ('America/Santarem', 'America/Santarem'), ('America/Santiago', 'America/Santiago'), ('America/Santo_Domingo', 'America/Santo_Domingo'), ('America/Sao_Paulo', 'America/Sao_Paulo'), ('America/Scoresbysund', 'America/Scoresbysund'), ('America/Sitka', 'America/Sitka'), ('America/St_Barthelemy', 'America/St_Barthelemy'), ('America/St_Johns', 'America/St_Johns'), ('America/St_Kitts', 'America/St_Kitts'), ('America/St_Lucia', 'America/St_Lucia'), ('America/St_Thomas', 'America/St_Thomas'), ('America/St_Vincent', 'America/St_Vincent'), ('America/Swift_Current', 'America/Swift_Current'), ('America/Tegucigalpa', 'America/Tegucigalpa'), ('America/Thule', 'America/Thule'), ('America/Thunder_Bay', 'America/Thunder_Bay'), ('America/Tijuana', 'America/Tijuana'), ('America/Toronto', 'America/Toronto'), ('America/Tortola', 'America/Tortola'), ('America/Vancouver', 'America/Vancouver'), ('America/Whitehorse', 'America/Whitehorse'), ('America/Winnipeg', 'America/Winnipeg'), ('America/Yakutat', 'America/Yakutat'), ('America/Yellowknife', 'America/Yellowknife'), ('Antarctica/Casey', 'Antarctica/Casey'), ('Antarctica/Davis', 'Antarctica/Davis'), ('Antarctica/DumontDUrville', 'Antarctica/DumontDUrville'), ('Antarctica/Macquarie', 'Antarctica/Macquarie'), ('Antarctica/Mawson', 'Antarctica/Mawson'), ('Antarctica/McMurdo', 'Antarctica/McMurdo'), ('Antarctica/Palmer', 'Antarctica/Palmer'), ('Antarctica/Rothera', 'Antarctica/Rothera'), ('Antarctica/Syowa', 'Antarctica/Syowa'), ('Antarctica/Troll', 'Antarctica/Troll'), ('Antarctica/Vostok', 'Antarctica/Vostok'), ('Arctic/Longyearbyen', 'Arctic/Longyearbyen'), ('Asia/Aden', 'Asia/Aden'), ('Asia/Almaty', 'Asia/Almaty'), ('Asia/Amman', 'Asia/Amman'), ('Asia/Anadyr', 'Asia/Anadyr'), ('Asia/Aqtau', 'Asia/Aqtau'), ('Asia/Aqtobe', 'Asia/Aqtobe'), ('Asia/Ashgabat', 'Asia/Ashgabat'), ('Asia/Atyrau', 'Asia/Atyrau'), ('Asia/Baghdad', 'Asia/Baghdad'), ('Asia/Bahrain', 'Asia/Bahrain'), ('Asia/Baku', 'Asia/Baku'), ('Asia/Bangkok', 'Asia/Bangkok'), ('Asia/Barnaul', 'Asia/Barnaul'), ('Asia/Beirut', 'Asia/Beirut'), ('Asia/Bishkek', 'Asia/Bishkek'), ('Asia/Brunei', 'Asia/Brunei'), ('Asia/Chita', 'Asia/Chita'), ('Asia/Choibalsan', 'Asia/Choibalsan'), ('Asia/Colombo', 'Asia/Colombo'), ('Asia/Damascus', 'Asia/Damascus'), ('Asia/Dhaka', 'Asia/Dhaka'), ('Asia/Dili', 'Asia/Dili'), ('Asia/Dubai', 'Asia/Dubai'), ('Asia/Dushanbe', 'Asia/Dushanbe'), ('Asia/Famagusta', 'Asia/Famagusta'), ('Asia/Gaza', 'Asia/Gaza'), ('Asia/Hebron', 'Asia/Hebron'), ('Asia/Ho_Chi_Minh', 'Asia/Ho_Chi_Minh'), ('Asia/Hong_Kong', 'Asia/Hong_Kong'), ('Asia/Hovd', 'Asia/Hovd'), ('Asia/Irkutsk', 'Asia/Irkutsk'), ('Asia/Jakarta', 'Asia/Jakarta'), ('Asia/Jayapura', 'Asia/Jayapura'), ('Asia/Jerusalem', 'Asia/Jerusalem'), ('Asia/Kabul', 'Asia/Kabul'), ('Asia/Kamchatka', 'Asia/Kamchatka'), ('Asia/Karachi', 'Asia/Karachi'), ('Asia/Kathmandu', 'Asia/Kathmandu'), ('Asia/Khandyga', 'Asia/Khandyga'), ('Asia/Kolkata', 'Asia/Kolkata'), ('Asia/Krasnoyarsk', 'Asia/Krasnoyarsk'), ('Asia/Kuala_Lumpur', 'Asia/Kuala_Lumpur'), ('Asia/Kuching', 'Asia/Kuching'), ('Asia/Kuwait', 'Asia/Kuwait'), ('Asia/Macau', 'Asia/Macau'), ('Asia/Magadan', 'Asia/Magadan'), ('Asia/Makassar', 'Asia/Makassar'), ('Asia/Manila', 'Asia/Manila'), ('Asia/Muscat', 'Asia/Muscat'), ('Asia/Nicosia', 'Asia/Nicosia'), ('Asia/Novokuznetsk', 'Asia/Novokuznetsk'), ('Asia/Novosibirsk', 'Asia/Novosibirsk'), ('Asia/Omsk', 'Asia/Omsk'), ('Asia/Oral', 'Asia/Oral'), ('Asia/Phnom_Penh', 'Asia/Phnom_Penh'), ('Asia/Pontianak', 'Asia/Pontianak'), ('Asia/Pyongyang', 'Asia/Pyongyang'), ('Asia/Qatar', 'Asia/Qatar'), ('Asia/Qostanay', 'Asia/Qostanay'), ('Asia/Qyzylorda', 'Asia/Qyzylorda'), ('Asia/Riyadh', 'Asia/Riyadh'), ('Asia/Sakhalin', 'Asia/Sakhalin'), ('Asia/Samarkand', 'Asia/Samarkand'), ('Asia/Seoul', 'Asia/Seoul'), ('Asia/Shanghai', 'Asia/Shanghai'), ('Asia/Singapore', 'Asia/Singapore'), ('Asia/Srednekolymsk', 'Asia/Srednekolymsk'), ('Asia/Taipei', 'Asia/Taipei'), ('Asia/Tashkent', 'Asia/Tashkent'), ('Asia/Tbilisi', 'Asia/Tbilisi'), ('Asia/Tehran', 'Asia/Tehran'), ('Asia/Thimphu', 'Asia/Thimphu'), ('Asia/Tokyo', 'Asia/Tokyo'), ('Asia/Tomsk', 'Asia/Tomsk'), ('Asia/Ulaanbaatar', 'Asia/Ulaanbaatar'), ('Asia/Urumqi', 'Asia/Urumqi'), ('Asia/Ust-Nera', 'Asia/Ust-Nera'), ('Asia/Vientiane', 'Asia/Vientiane'), ('Asia/Vladivostok', 'Asia/Vladivostok'), ('Asia/Yakutsk', 'Asia/Yakutsk'), ('Asia/Yangon', 'Asia/Yangon'), ('Asia/Yekaterinburg', 'Asia/Yekaterinburg'), ('Asia/Yerevan', 'Asia/Yerevan'), ('Atlantic/Azores', 'Atlantic/Azores'), ('Atlantic/Bermuda', 'Atlantic/Bermuda'), ('Atlantic/Canary', 'Atlantic/Canary'), ('Atlantic/Cape_Verde', 'Atlantic/Cape_Verde'), ('Atlantic/Faroe', 'Atlantic/Faroe'), ('Atlantic/Madeira', 'Atlantic/Madeira'), ('Atlantic/Reykjavik', 'Atlantic/Reykjavik'), ('Atlantic/South_Georgia', 'Atlantic/South_Georgia'), ('Atlantic/St_Helena', 'Atlantic/St_Helena'), ('Atlantic/Stanley', 'Atlantic/Stanley'), ('Australia/Adelaide', 'Australia/Adelaide'), ('Australia/Brisbane', 'Australia/Brisbane'), ('Australia/Broken_Hill', 'Australia/Broken_Hill'), ('Australia/Currie', 'Australia/Currie'), ('Australia/Darwin', 'Australia/Darwin'), ('Australia/Eucla', 'Australia/Eucla'), ('Australia/Hobart', 'Australia/Hobart'), ('Australia/Lindeman', 'Australia/Lindeman'), ('Australia/Lord_Howe', 'Australia/Lord_Howe'), ('Australia/Melbourne', 'Australia/Melbourne'), ('Australia/Perth', 'Australia/Perth'), ('Australia/Sydney', 'Australia/Sydney'), ('Canada/Atlantic', 'Canada/Atlantic'), ('Canada/Central', 'Canada/Central'), ('Canada/Eastern', 'Canada/Eastern'), ('Canada/Mountain', 'Canada/Mountain'), ('Canada/Newfoundland', 'Canada/Newfoundland'), ('Canada/Pacific', 'Canada/Pacific'), ('Europe/Amsterdam', 'Europe/Amsterdam'), ('Europe/Andorra', 'Europe/Andorra'), ('Europe/Astrakhan', 'Europe/Astrakhan'), ('Europe/Athens', 'Europe/Athens'), ('Europe/Belgrade', 'Europe/Belgrade'), ('Europe/Berlin', 'Europe/Berlin'), ('Europe/Bratislava', 'Europe/Bratislava'), ('Europe/Brussels', 'Europe/Brussels'), ('Europe/Bucharest', 'Europe/Bucharest'), ('Europe/Budapest', 'Europe/Budapest'), ('Europe/Busingen', 'Europe/Busingen'), ('Europe/Chisinau', 'Europe/Chisinau'), ('Europe/Copenhagen', 'Europe/Copenhagen'), ('Europe/Dublin', 'Europe/Dublin'), ('Europe/Gibraltar', 'Europe/Gibraltar'), ('Europe/Guernsey', 'Europe/Guernsey'), ('Europe/Helsinki', 'Europe/Helsinki'), ('Europe/Isle_of_Man', 'Europe/Isle_of_Man'), ('Europe/Istanbul', 'Europe/Istanbul'), ('Europe/Jersey', 'Europe/Jersey'), ('Europe/Kaliningrad', 'Europe/Kaliningrad'), ('Europe/Kiev', 'Europe/Kiev'), ('Europe/Kirov', 'Europe/Kirov'), ('Europe/Lisbon', 'Europe/Lisbon'), ('Europe/Ljubljana', 'Europe/Ljubljana'), ('Europe/London', 'Europe/London'), ('Europe/Luxembourg', 'Europe/Luxembourg'), ('Europe/Madrid', 'Europe/Madrid'), ('Europe/Malta', 'Europe/Malta'), ('Europe/Mariehamn', 'Europe/Mariehamn'), ('Europe/Minsk', 'Europe/Minsk'), ('Europe/Monaco', 'Europe/Monaco'), ('Europe/Moscow', 'Europe/Moscow'), ('Europe/Oslo', 'Europe/Oslo'), ('Europe/Paris', 'Europe/Paris'), ('Europe/Podgorica', 'Europe/Podgorica'), ('Europe/Prague', 'Europe/Prague'), ('Europe/Riga', 'Europe/Riga'), ('Europe/Rome', 'Europe/Rome'), ('Europe/Samara', 'Europe/Samara'), ('Europe/San_Marino', 'Europe/San_Marino'), ('Europe/Sarajevo', 'Europe/Sarajevo'), ('Europe/Saratov', 'Europe/Saratov'), ('Europe/Simferopol', 'Europe/Simferopol'), ('Europe/Skopje', 'Europe/Skopje'), ('Europe/Sofia', 'Europe/Sofia'), ('Europe/Stockholm', 'Europe/Stockholm'), ('Europe/Tallinn', 'Europe/Tallinn'), ('Europe/Tirane', 'Europe/Tirane'), ('Europe/Ulyanovsk', 'Europe/Ulyanovsk'), ('Europe/Uzhgorod', 'Europe/Uzhgorod'), ('Europe/Vaduz', 'Europe/Vaduz'), ('Europe/Vatican', 'Europe/Vatican'), ('Europe/Vienna', 'Europe/Vienna'), ('Europe/Vilnius', 'Europe/Vilnius'), ('Europe/Volgograd', 'Europe/Volgograd'), ('Europe/Warsaw', 'Europe/Warsaw'), ('Europe/Zagreb', 'Europe/Zagreb'), ('Europe/Zaporozhye', 'Europe/Zaporozhye'), ('Europe/Zurich', 'Europe/Zurich'), ('GMT', 'GMT'), ('Indian/Antananarivo', 'Indian/Antananarivo'), ('Indian/Chagos', 'Indian/Chagos'), ('Indian/Christmas', 'Indian/Christmas'), ('Indian/Cocos', 'Indian/Cocos'), ('Indian/Comoro', 'Indian/Comoro'), ('Indian/Kerguelen', 'Indian/Kerguelen'), ('Indian/Mahe', 'Indian/Mahe'), ('Indian/Maldives', 'Indian/Maldives'), ('Indian/Mauritius', 'Indian/Mauritius'), ('Indian/Mayotte', 'Indian/Mayotte'), ('Indian/Reunion', 'Indian/Reunion'), ('Pacific/Apia', 'Pacific/Apia'), ('Pacific/Auckland', 'Pacific/Auckland'), ('Pacific/Bougainville', 'Pacific/Bougainville'), ('Pacific/Chatham', 'Pacific/Chatham'), ('Pacific/Chuuk', 'Pacific/Chuuk'), ('Pacific/Easter', 'Pacific/Easter'), ('Pacific/Efate', 'Pacific/Efate'), ('Pacific/Enderbury', 'Pacific/Enderbury'), ('Pacific/Fakaofo', 'Pacific/Fakaofo'), ('Pacific/Fiji', 'Pacific/Fiji'), ('Pacific/Funafuti', 'Pacific/Funafuti'), ('Pacific/Galapagos', 'Pacific/Galapagos'), ('Pacific/Gambier', 'Pacific/Gambier'), ('Pacific/Guadalcanal', 'Pacific/Guadalcanal'), ('Pacific/Guam', 'Pacific/Guam'), ('Pacific/Honolulu', 'Pacific/Honolulu'), ('Pacific/Kiritimati', 'Pacific/Kiritimati'), ('Pacific/Kosrae', 'Pacific/Kosrae'), ('Pacific/Kwajalein', 'Pacific/Kwajalein'), ('Pacific/Majuro', 'Pacific/Majuro'), ('Pacific/Marquesas', 'Pacific/Marquesas'), ('Pacific/Midway', 'Pacific/Midway'), ('Pacific/Nauru', 'Pacific/Nauru'), ('Pacific/Niue', 'Pacific/Niue'), ('Pacific/Norfolk', 'Pacific/Norfolk'), ('Pacific/Noumea', 'Pacific/Noumea'), ('Pacific/Pago_Pago', 'Pacific/Pago_Pago'), ('Pacific/Palau', 'Pacific/Palau'), ('Pacific/Pitcairn', 'Pacific/Pitcairn'), ('Pacific/Pohnpei', 'Pacific/Pohnpei'), ('Pacific/Port_Moresby', 'Pacific/Port_Moresby'), ('Pacific/Rarotonga', 'Pacific/Rarotonga'), ('Pacific/Saipan', 'Pacific/Saipan'), ('Pacific/Tahiti', 'Pacific/Tahiti'), ('Pacific/Tarawa', 'Pacific/Tarawa'), ('Pacific/Tongatapu', 'Pacific/Tongatapu'), ('Pacific/Wake', 'Pacific/Wake'), ('Pacific/Wallis', 'Pacific/Wallis'), ('US/Alaska', 'US/Alaska'), ('US/Arizona', 'US/Arizona'), ('US/Central', 'US/Central'), ('US/Eastern', 'US/Eastern'), ('US/Hawaii', 'US/Hawaii'), ('US/Mountain', 'US/Mountain'), ('US/Pacific', 'US/Pacific'), ('UTC', 'UTC')], default='UTC', max_length=100)), ('contact_phone', models.CharField(blank=True, max_length=17, validators=[django.core.validators.RegexValidator(message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.", regex='^\\+?1?\\d{9,15}$')])), ('contact_email', models.EmailField(blank=True, max_length=254, validators=[django.core.validators.EmailValidator()])), - ('coursestandards', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.StandardCollection')), + ('coursestandards', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='rowers.StandardCollection', verbose_name='Standard Times')), ], bases=('rowers.plannedsession',), ), @@ -852,6 +860,6 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='coursestandard', - unique_together={('name', 'sex', 'agemin', 'agemax', 'boatclass', 'boattype', 'weightclass', 'adaptiveclass', 'skillclass', 'standardcollection')}, + unique_together={('name', 'standardcollection')}, ), ] diff --git a/rowers/models.py b/rowers/models.py index a0a74a42..715e37c3 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2187,6 +2187,7 @@ class StandardCollection(models.Model): name = models.CharField(max_length=150) manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) notes = models.CharField(blank=True,null=True,max_length=1000) + active = models.BooleanField(default=True) def __str__(self): return self.name @@ -2207,9 +2208,10 @@ class CourseStandard(models.Model): standardcollection = models.ForeignKey(StandardCollection,on_delete=models.CASCADE) class Meta: - unique_together = ('name','sex','agemin', - 'agemax','boatclass','boattype','weightclass','adaptiveclass', - 'skillclass','standardcollection') + unique_together = ( + ('name','standardcollection') + ) + def __str__(self): return self.name @@ -2456,6 +2458,7 @@ class IndoorVirtualRaceForm(ModelForm): self.fields['sessionunit'].initial = 'm' if timezone: self.fields['timezone'].initial = timezone + self.fields['coursestandards'].queryset = StandardCollection.objects.filter(active=True) def clean(self): cd = self.cleaned_data @@ -2583,6 +2586,7 @@ class VirtualRaceForm(ModelForm): def __init__(self,*args,**kwargs): super(VirtualRaceForm, self).__init__(*args, **kwargs) self.fields['course'].queryset = GeoCourse.objects.all().order_by("country","name") + self.fields['coursestandards'].queryset = StandardCollection.objects.filter(active=True) def clean(self): diff --git a/rowers/scoring.py b/rowers/scoring.py index 38cba81a..8e24257b 100644 --- a/rowers/scoring.py +++ b/rowers/scoring.py @@ -1,4 +1,4 @@ -from rowers.models import StandardCollection,CourseStandard +from rowers.models import StandardCollection,CourseStandard, VirtualRaceResult,IndoorVirtualRaceResult import pandas as pd import arrow @@ -10,7 +10,8 @@ def save_scoring(name,user,filename,id=0,notes=""): collection.save() standards = CourseStandard.objects.filter(standardcollection=collection) for standard in standards: - standard.delete() + standards.delete() + else: try: collection = StandardCollection.objects.get(id=id) @@ -19,8 +20,11 @@ def save_scoring(name,user,filename,id=0,notes=""): collection.save() standards = CourseStandard.objects.filter(standardcollection=collection) for standard in standards: - print(standard,collection) - standard.delete() + records1 = VirtualRaceResult.objects.filter(entrycategory=standard) + records2 = IndoorVirtualRaceResult.objects.filter(entrycategory=standard) + if records1.count()+records2.count() == 0: + standard.delete() + except StandardCollection.DoesNotExist: return 0 @@ -30,6 +34,22 @@ def save_scoring(name,user,filename,id=0,notes=""): except: return 0 + df.rename( + columns={ + 'name':'Name', + 'agemax':'MaxAge', + 'agemin':'MinAge', + 'adaptiveclass':'AdaptiveClass', + 'coursedistance':'CourseDistance', + 'coursetime':'CourseStandard', + 'boatclass':'BoatClass', + 'boattype':'BoatType', + 'sex':'Gender', + 'weightclass':'WeightClass', + 'skillclass':'SkillClass', + }, + inplace=True) + df = df.drop_duplicates(['Name']) for index, row in df.iterrows(): @@ -60,9 +80,9 @@ def save_scoring(name,user,filename,id=0,notes=""): try: boatclass = row['BoatClass'] - if boatclass.lower() in ['standard','olympic','normal']: + if boatclass.lower() in ['standard','olympic','normal','water']: boatclass = 'water' - elif boatclass.lower() in ['erg','c2','concept','static']: + elif boatclass.lower() in ['erg','c2','concept','static','rower']: boatclass = 'rower' elif boatclass.lower() in ['dynamic']: boatclass = 'dynamic' @@ -115,23 +135,43 @@ def save_scoring(name,user,filename,id=0,notes=""): except KeyError: skillclass = 'Open' - # some testing - standard = CourseStandard( - name=name, - coursedistance=coursedistance, - referencespeed=referencespeed, - coursetime=coursetime, - agemin=agemin, - agemax=agemax, - boatclass=boatclass, - boattype=boattype, - sex=sex, - weightclass=weightclass, - adaptiveclass=adaptiveclass, - skillclass=skillclass, - standardcollection = collection, - ) + # finding existing standard + existingstandards = CourseStandard.objects.filter(name=name,standardcollection=collection) + #print(existingstandards,collection) + if existingstandards: + existingstandards.update( + name=name, + coursedistance=coursedistance, + referencespeed=referencespeed, + coursetime=coursetime, + agemin=agemin, + agemax=agemax, + boatclass=boatclass, + boattype=boattype, + sex=sex, + weightclass=weightclass, + adaptiveclass=adaptiveclass, + skillclass=skillclass, + standardcollection = collection, + ) + else: + #print('not') + standard = CourseStandard( + name=name, + coursedistance=coursedistance, + referencespeed=referencespeed, + coursetime=coursetime, + agemin=agemin, + agemax=agemax, + boatclass=boatclass, + boattype=boattype, + sex=sex, + weightclass=weightclass, + adaptiveclass=adaptiveclass, + skillclass=skillclass, + standardcollection = collection, + ) - standard.save() + standard.save() return collection.id diff --git a/rowers/templates/standard_form.html b/rowers/templates/standard_form.html index 2e8c2314..282ba443 100644 --- a/rowers/templates/standard_form.html +++ b/rowers/templates/standard_form.html @@ -21,7 +21,18 @@
    • -

      Drag and drop files here

      +

      Drag and drop files here. +

      +

      + If you're updating an existing set of standard times, + existing groups with challenge entries will be updated. New + groups will be created. All groups with challenge entries will + remain, even if you delete them from the CSV file. So, it + is not possible to remove groups if there have been starts in this group.

      +

      + If you want to still remove those groups, it is better to set the + existing set of standard times to inactive and upload a new one. +

      diff --git a/rowers/templates/standard_view.html b/rowers/templates/standard_view.html index c76f0f49..8a92f859 100644 --- a/rowers/templates/standard_view.html +++ b/rowers/templates/standard_view.html @@ -33,7 +33,11 @@
  • -

    Update these Standard Times + {% if request.user == collection.manager %} +

    Update these Standard Times

    +

    Deactivate this standard

    + {% endif %} +

    Download as CSV file

  • Standard Times

    diff --git a/rowers/urls.py b/rowers/urls.py index 4f387b5f..3549c4a5 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -756,6 +756,10 @@ urlpatterns = [ name='course_replace_view'), re_path(r'^courses/(?P\d+)/$',views.course_view,name='course_view'), re_path(r'^standards/(?P\d+)/$',views.standard_view,name='standard_view'), + re_path(r'^standards/(?P\d+)/download/$',views.standards_download_view, + name='standards_download_view'), + re_path(r'^standards/(?P\d+)/deactivate/$',views.standard_deactivate_view, + name='standard_decativate_view'), re_path(r'^courses/(?P\d+)/map/$',views.course_map_view,name='course_map_view'), # URLS to be created re_path(r'^help/$',TemplateView.as_view(template_name='help.html'), name='help'), diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 9bd0693a..2c0ac70c 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -40,7 +40,7 @@ def courses_view(request): def standards_view(request): r = getrower(request.user) - standards = StandardCollection.objects.all().order_by("name") + standards = StandardCollection.objects.filter(active=True).order_by("name") # add search processing query = request.GET.get('q') @@ -521,11 +521,57 @@ def course_upload_view(request): else: return {'result':0} +# Standards deactivate +@login_required() +def standard_deactivate_view(request,id=0): + is_ajax = False + if request.is_ajax(): + is_ajax = True + + r = getrower(request.user) + + try: + collection = StandardCollection.objects.get(id=id) + except StandardCollection.DoesNotExist: + raise Http404("Does not exist") + + if request.user != collection.manager: + raise PermissionDenied("You cannot change this set of time standards") + + collection.active = False + collection.save() + + url = reverse(standards_view) + + return HttpResponseRedirect(url) + +def standards_download_view(request,id=0): + try: + collection = StandardCollection.objects.get(id=id) + except StandardCollection.DoesNotExist: + raise Http404("Does not exist") + + filename = 'Standard Times {name} {id} {date}.csv'.format( + id=id, + name=collection.name, + date=timezone.now().strftime("%Y-%m-%d %H:%M:%S %Z") + ) + + standards = CourseStandard.objects.filter(standardcollection=collection) + df = pd.DataFrame.from_records(standards.values()) + + response = HttpResponse(df.to_csv()) + + response['Content-Disposition'] = 'attachment; filename="%s"' % filename + response['Content-Type'] = 'application/octet-stream' + + return response + + # Standards upload @login_required() def standards_upload_view(request,id=0): is_ajax = False - print(id,'aap') if request.is_ajax(): is_ajax = True r = getrower(request.user) From 691499351603805c65ae82900bc84c5be41474be Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 28 May 2020 06:49:13 +0200 Subject: [PATCH 19/22] filter form --- rowers/forms.py | 21 +++++++++++++++++ rowers/models.py | 27 ++++++++++++++++++++++ rowers/templates/virtualeventregister.html | 2 +- rowers/views/racesviews.py | 12 ++++++++-- 4 files changed, 59 insertions(+), 3 deletions(-) diff --git a/rowers/forms.py b/rowers/forms.py index f6305846..7110da87 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1230,6 +1230,12 @@ class RaceResultFilterForm(forms.Form): initial=['None','PR1','PR2','PR3','FES'], widget=forms.CheckboxSelectMultiple()) + entrycategory = forms.MultipleChoiceField( + choices = [], + label = 'Groups', + widget=forms.CheckboxSelectMultiple() + ) + def __init__(self, *args, **kwargs): if 'records' in kwargs: records = kwargs.pop('records',None) @@ -1237,6 +1243,21 @@ class RaceResultFilterForm(forms.Form): super(RaceResultFilterForm,self).__init__(*args,**kwargs) if records: + # group + thecategories = [record.entrycategory for record in records] + thecategories = list(set(thecategories)) + if len(thecategories) <= 1: + del self.fields['entrycategory'] + else: + categorychoices = [] + for category in thecategories: + if category is not None: + categorychoices.append( + (category.id,category) + ) + self.fields['entrycategory'].choices = categorychoices + self.fields['entrycategory'].initial = [cat[0] for cat in categorychoices] + # sex thesexes = [record.sex for record in records] thesexes = list(set(thesexes)) diff --git a/rowers/models.py b/rowers/models.py index 715e37c3..9f0e8d46 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -2969,6 +2969,14 @@ class VirtualRaceResult(models.Model): u2 = rr.user.last_name, ) if self.teamname: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g} with {t}'.format( + n = name, + r = self.race, + g = self.entrycategory, + t = self.teamname, + ) + return u'Entry for {n} for "{r}" in {c} {d} with {t} ({s})'.format( n = name, r = self.race, @@ -2978,6 +2986,12 @@ class VirtualRaceResult(models.Model): s = self.sex, ) else: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g}'.format( + n = name, + r = self.race, + g = self.entrycategory, + ) return u'Entry for {n} for "{r}" in {c} {d} ({s})'.format( n = name, r = self.race, @@ -3031,6 +3045,13 @@ class IndoorVirtualRaceResult(models.Model): u2 = rr.user.last_name, ) if self.teamname: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g} with {t}'.format( + n = name, + r = self.race, + g = self.entrycategory, + t = self.teamname, + ) return u'Entry for {n} for "{r}" on {c} with {t} ({s})'.format( n = name, r = self.race, @@ -3039,6 +3060,12 @@ class IndoorVirtualRaceResult(models.Model): s = self.sex, ) else: + if self.entrycategory: + return u'Entry for {n} for "{r}" in {g}'.format( + n = name, + r = self.race, + g = self.entrycategory, + ) return u'Entry for {n} for "{r}" on {c} ({s})'.format( n = name, r = self.race, diff --git a/rowers/templates/virtualeventregister.html b/rowers/templates/virtualeventregister.html index 20159a4e..6a925ac7 100644 --- a/rowers/templates/virtualeventregister.html +++ b/rowers/templates/virtualeventregister.html @@ -37,7 +37,7 @@

    {% if race.coursestandards %}

    This race uses standard times and limits the race groups to those where - standard times exist. The "Field" form choice will overrule other selections you + standard times exist. The "Group" form choice will overrule other selections you make in the form (boat type, weight, etc) and your entry will be rejected if the age and gender doesn't match.

    diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 2c0ac70c..cbb09087 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1127,6 +1127,11 @@ def virtualevent_view(request,id=0): except KeyError: adaptiveclass = ['None','PR1','PR2','PR3','FES'] + try: + entrycategory = cd['entrycategory'] + except KeyError: + entrycategory = None + if race.sessiontype == 'race': results = resultobj.objects.filter( race=race, @@ -1137,7 +1142,7 @@ def virtualevent_view(request,id=0): weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, - age__lte=age_max + age__lte=age_max, ).order_by("duration") else: results = resultobj.objects.filter( @@ -1148,9 +1153,12 @@ def virtualevent_view(request,id=0): weightcategory__in=weightcategory, adaptiveclass__in=adaptiveclass, age__gte=age_min, - age__lte=age_max + age__lte=age_max, ).order_by("duration","-distance") + if entrycategory is not None: + results = results.filter(entrycategory__in=entrycategory) + # to-do - add DNS dns = [] From 1c9d45a0263436f731bdf2d4851b97e171eb98b6 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 28 May 2020 07:53:32 +0200 Subject: [PATCH 20/22] ordering --- rowers/templates/virtualevent.html | 6 +++--- rowers/views/racesviews.py | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/rowers/templates/virtualevent.html b/rowers/templates/virtualevent.html index 556ee5e4..3e2297ce 100644 --- a/rowers/templates/virtualevent.html +++ b/rowers/templates/virtualevent.html @@ -279,10 +279,10 @@
  • BoatTimeDistanceTimeDistancePointsPointsDetails  {{ standard.name }} {{ standard.coursedistance }} {{ standard.coursetime }}{{ standard.boatclass }}{{ standard.boatclass|boatclass }} {{ standard.boattype }} {{ standard.sex|sex }} {{ standard.weightclass|weight }}