diff --git a/23099b58-7632-4d34-97e2-2f4890cf5773.tcx b/23099b58-7632-4d34-97e2-2f4890cf5773.tcx
new file mode 100644
index 00000000..e7df305a
--- /dev/null
+++ b/23099b58-7632-4d34-97e2-2f4890cf5773.tcx
@@ -0,0 +1,2523 @@
+
+
+
+
+ 2016-05-20T13:41:26.962390+00:00
+
+ 537
+ 2000
+ 118
+
+ 148
+
+
+ 156
+
+ Active
+ 21
+ Manual
+
+
+ <Element 'Notes' at 0x7f433c451b38>
+
+
+
+ rowsandall.com/rowingdata
+
+
+ rowingdata
+
+
+ 0
+ 75
+
+ Release
+
+ EN
+ 000-00000-00
+
+
diff --git a/requirements.txt b/requirements.txt
index 05616a35..00ed095f 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,215 +1,138 @@
-amqp==2.4.2
-apipkg==1.5
+amqp==2.5.2
+anytree==2.8.0
+apparmor==2.13.3
appdirs==1.4.3
-arcgis==1.6.0
-arrow==0.13.1
-asn1crypto==0.24.0
-atomicwrites==1.3.0
-attrs==19.1.0
+asn1crypto==1.3.0
+attrs==19.3.0
backcall==0.1.0
-beautifulsoup4==4.7.1
-billiard==3.6.0.0
+beautifulsoup4==4.8.2
+billiard==3.6.1.0
bleach==3.1.0
-bokeh==1.0.4
boto==2.49.0
-braintree==3.55.0
-cairocffi==1.0.2
+btrfsutil==1.1.1
+CacheControl==0.12.6
+case==1.5.3
+catfish==1.4.13
celery==4.3.0
-certifi==2019.3.9
-cffi==1.12.2
+ceph-volume==1.0.0
+cephfs==2.0.0
+cephfs-shell==0.0.1
+certifi==2019.11.28
+cffi==1.13.2
chardet==3.0.4
-Click==7.0
-cloudpickle==1.2.2
-colorama==0.4.1
-colorclass==2.2.0
-cookies==2.2.1
-coreapi==2.3.3
-coreschema==0.0.4
-coverage==4.5.3
-cryptography==2.6.1
+colorama==0.4.3
+contextlib2==0.6.0
+cryptography==2.8
cycler==0.10.0
-dask==2.6.0
-decorator==4.4.0
-defusedxml==0.5.0
-Django==2.1.7
-django-analytical==2.5.0
-django-async-messages==0.3.1
-django-braces==1.13.0
-django-classy-tags==0.8.0
-django-cookie-law==2.0.1
-django-cors-headers==2.5.2
-django-countries==5.3.3
-django-datetime-widget==0.9.3
-django-debug-toolbar==2.0
-django-extensions==2.1.6
-django-htmlmin==0.11.0
-django-leaflet==0.24.0
-django-mailbox==4.8.0
-django-oauth-toolkit==1.2.0
-django-oauth2-provider==0.2.6.1
-django-redis==4.10.0
-django-rest-framework==0.1.0
-django-rest-swagger==2.2.0
-django-rq==1.3.1
-django-rq-dashboard==0.3.3
-django-ses==0.8.10
-django-shell-plus==1.1.7
-django-social-share==1.3.2
-django-suit==0.2.26
-django-suit-rq==1.0.1
-django-tz-detect==0.2.9
-djangorestframework==3.9.2
+decorator==4.4.1
+defusedxml==0.6.0
+distlib==0.3.0
+distro==1.4.0
docopt==0.6.2
-docutils==0.14
entrypoints==0.3
-execnet==1.5.0
-factory-boy==2.11.1
-Faker==1.0.4
-fastparquet==0.3.2
-fitparse==1.1.0
-Flask==1.0.2
-fsspec==0.5.2
-future==0.17.1
-geocoder==1.38.1
-geos==0.2.1
-grpcio==1.26.0
-grpcio-tools==1.26.0
-holoviews==1.11.3
+gufw==19.10.0
html5lib==1.0.1
htmlmin==0.1.12
-HTMLParser==0.0.2
-httplib2==0.12.1
-hvplot==0.4.0
-icalendar==4.0.3
+httplib2==0.14.0
idna==2.8
-image==1.5.27
-importlib-resources==1.0.2
-ipykernel==5.1.0
-ipython==7.4.0
-ipython-genutils==0.2.0
-ipywidgets==7.4.2
-iso8601==0.1.12
-isodate==0.6.0
-itsdangerous==1.1.0
-itypes==1.1.0
-jedi==0.13.3
-jeepney==0.4
-Jinja2==2.10
-json5==0.8.5
-jsonschema==3.0.1
-jupyter==1.0.0
-jupyter-client==5.2.4
+importlib-metadata==1.4.0
+ipykernel==5.1.3
+ipython==7.11.1
+ipython-genutils==0.1.0
+ipywidgets==7.5.1
+Jade-Application-Kit==2.1.3
+jedi==0.15.1
+Jinja2==2.10.3
+jsonschema==3.2.0
+jupyter-client==5.3.4
jupyter-console==6.0.0
-jupyter-core==4.4.0
-jupyterlab==0.35.4
-jupyterlab-server==0.3.0
-keyring==18.0.0
-kiwisolver==1.0.1
-kombu==4.5.0
-llvmlite==0.30.0
-lxml==4.3.2
-Markdown==3.0.1
+jupyter-core==4.6.1
+keyutils==0.6
+kiwisolver==1.1.0
+kombu==4.6.7
+lensfun==0.3.2
+LibAppArmor==2.13.3
+lightdm-gtk-greeter-settings==1.2.2
+lockfile==0.12.2
+louis==3.12.0
+lxml==4.4.2
MarkupSafe==1.1.1
-matplotlib==3.0.3
-minify==0.1.4
-MiniMockTest==0.5
+matplotlib==3.1.2
+menulibre==2.2.1
mistune==0.8.4
-mock==2.0.0
-more-itertools==6.0.0
-mpld3==0.3
-mysqlclient==1.4.2.post1
-nbconvert==5.4.1
+more-itertools==8.1.0
+msgpack==0.6.2
+mugshot==0.4.2
+nbconvert==5.6.1
nbformat==4.4.0
-newrelic==5.2.1.129
nose==1.3.7
-nose-parameterized==0.6.0
-notebook==5.7.6
-numba==0.46.0
-numpy==1.16.2
-oauth2==1.9.0.post1
-oauthlib==3.0.1
-openapi-codec==1.3.2
-packaging==19.0
-pandas==0.24.2
+notebook==6.0.2
+npyscreen==4.10.5
+numpy==1.18.1
+openshot-qt==2.4.4
+ordered-set==3.1.1
+packaging==20.0
+pacman-mirrors==4.16.2
pandocfilters==1.4.2
-param==1.8.2
-parso==0.3.4
-pathspec==0.5.9
-pbr==5.1.3
-pexpect==4.6.0
+parso==0.5.2
+pep517==0.6.0
+pexpect==4.7.0
pickleshare==0.7.5
-Pillow==5.4.1
-pip-upgrader==1.4.6
-pluggy==0.9.0
-prometheus-client==0.6.0
-prompt-toolkit==2.0.9
-protobuf==3.11.1
-psycopg2==2.8.1
+Pillow==6.2.1
+pkgconfig==1.5.1
+pkginfo==1.5.0.1
+ply==3.11
+progress==1.5
+prometheus-client==0.7.1
+prompt-toolkit==3.0.2
+psutil==5.6.7
ptyprocess==0.6.0
-py==1.8.0
-pyarrow==0.15.0
+pycairo==1.18.2
pycparser==2.19
-Pygments==2.3.1
-pyparsing==2.3.1
-pyrsistent==0.14.11
-pyshp==2.1.0
-pytest==4.3.1
-pytest-django==3.4.8
-pytest-forked==1.0.2
-pytest-runner==4.4
-pytest-sugar==0.9.2
-pytest-xdist==1.27.0
-python-dateutil==2.8.0
-python-memcached==1.59
-python-twitter==3.5
-pytz==2018.9
-pyviz-comms==0.7.1
-pywin32-ctypes==0.2.0
-pywinpty==0.5.5
-PyYAML==5.1
-pyzmq==18.0.1
-qtconsole==4.4.3
-ratelim==0.1.6
-redis==3.2.1
-requests==2.21.0
-requests-oauthlib==1.2.0
-rowingdata==2.5.9
-rowingphysics==0.5.0
-rq==0.13.0
-rules==2.1
-scipy==1.2.1
-SecretStorage==3.1.1
+pycups==1.9.74
+pycurl==7.43.0.3
+Pygments==2.5.2
+PyGObject==3.34.0
+pymongo==3.10.1
+pyOpenSSL==19.1.0
+pyparsing==2.4.6
+PyQt5==5.14.1
+PyQt5-sip==12.7.0
+PyQtWebEngine==5.14.0
+Pyro4==4.77
+pyrsistent==0.15.7
+python-dateutil==2.8.1
+python-distutils-extra==2.39
+pytoml==0.1.21
+pytz==2019.3
+pyxdg==0.26
+PyYAML==5.3
+pyzmq==18.1.1
+rados==2.0.0
+rbd==2.0.0
+redis==3.3.11
+requests==2.22.0
+retrying==1.3.3
+rgw==2.0.0
+scipy==1.4.1
Send2Trash==1.5.0
-shell==1.0.1
-shortuuid==0.5.0
-simplejson==3.16.0
-six==1.12.0
-soupsieve==1.8
-SQLAlchemy==1.3.1
-sqlparse==0.3.0
-stravalib==0.10.2
-termcolor==1.1.0
-terminado==0.8.1
-terminaltables==3.1.0
-testpath==0.4.2
-text-unidecode==1.2
-thrift==0.11.0
-timezonefinder==4.0.1
-toolz==0.10.0
-tornado==6.0.1
-tqdm==4.31.1
-traitlets==4.3.2
-units==0.7
-uritemplate==3.0.0
-urllib3==1.24.1
-VerbalExpressions==0.0.2
+serpent==1.27
+six==1.13.0
+soupsieve==1.9.5
+SQLAlchemy==1.3.12
+team==1.0
+terminado==0.8.3
+testpath==0.4.4
+tornado==6.0.3
+traitlets==4.3.3
+udiskie==2.0.2
+ufw==0.36
+urllib3==1.25.7
vine==1.3.0
-wcwidth==0.1.7
+virtualenv==16.1.0
+wcwidth==0.1.8
webencodings==0.5.1
-Werkzeug==0.15.1
-widgetsnbextension==3.4.2
+widgetsnbextension==3.5.1
+wrapt==1.11.2
xlrd==1.2.0
-xmltodict==0.12.0
-yamjam==0.1.7
-yamllint==1.15.0
-yuicompressor==2.4.8
+zipp==0.6.0
diff --git a/rowers/models.py b/rowers/models.py
index d06ab70e..e412de4f 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -2301,6 +2301,35 @@ class PlannedSessionForm(ModelForm):
self.fields['sessiontype'].choices = regularsessiontypechoices
+class PlannedSessionTemplateForm(ModelForm):
+
+ class Meta:
+ model = PlannedSession
+ fields = [
+ 'name',
+ 'sessiontype',
+ 'sessionmode',
+ 'criterium',
+ 'sessionvalue',
+ 'sessionunit',
+ 'course',
+ 'comment',
+ ]
+
+ dateTimeOptions = {
+ 'format': 'yyyy-mm-dd',
+ 'autoclose': True,
+ }
+
+ widgets = {
+ 'comment': forms.Textarea,
+ }
+
+ def __init__(self,*args,**kwargs):
+ super(PlannedSessionTemplateForm, self).__init__(*args, **kwargs)
+ self.fields['course'].queryset = GeoCourse.objects.all().order_by("country","name")
+ self.fields['sessiontype'].choices = regularsessiontypechoices
+
def get_course_timezone(course):
polygons = GeoPolygon.objects.filter(course = course)
points = GeoPoint.objects.filter(polygon = polygons[0])
diff --git a/rowers/rower_rules.py b/rowers/rower_rules.py
index df9892e6..9a890920 100644
--- a/rowers/rower_rules.py
+++ b/rowers/rower_rules.py
@@ -98,6 +98,10 @@ def can_start_plantrial(user):
return user.rower.plantrialexpires == datetime.date(1970,1,1)
+@rules.predicate
+def is_staff(user):
+ return user.is_staff
+
@rules.predicate
def is_coach(user):
return user.rower.rowerplan in ['coach','freecoach']
@@ -302,7 +306,7 @@ def can_plan_user(user,rower):
rules.add_perm('rower.add_plan',can_plan_user) # replaces checkaccessplanuser
rules.add_perm('rower.is_coach',is_coach_user) # replaces checkaccessuser
rules.add_perm('rower.is_pro',ispromember)
-rules.add_perm('anonymous.is_coach',is_anonymous_or_coach)
+rules.add_perm('rower.is_staff',is_staff)
# WORKOUT permissions
diff --git a/rowers/templates/menuscript.html b/rowers/templates/menuscript.html
index 9ba9250f..16994896 100644
--- a/rowers/templates/menuscript.html
+++ b/rowers/templates/menuscript.html
@@ -33,3 +33,4 @@
});
});
+
diff --git a/rowers/templates/plannedsessioncreate.html b/rowers/templates/plannedsessioncreate.html
index 5c5f7ff1..38f29545 100644
--- a/rowers/templates/plannedsessioncreate.html
+++ b/rowers/templates/plannedsessioncreate.html
@@ -108,6 +108,7 @@
Name |
Value |
|
+ Edit |
Delete |
@@ -125,8 +126,11 @@
{{ ps.sessionvalue }} |
{{ ps.sessionunit }} |
+
+ Edit Template
+ |
- Delete
+ Delete
|
{% endfor %}
diff --git a/rowers/templates/plannedsessionteamcreate.html b/rowers/templates/plannedsessionteamcreate.html
index 2cba5493..55dabe13 100644
--- a/rowers/templates/plannedsessionteamcreate.html
+++ b/rowers/templates/plannedsessionteamcreate.html
@@ -115,6 +115,7 @@
Name |
Value |
|
+ Edit |
Delete |
@@ -132,6 +133,9 @@
{{ ps.sessionvalue }} |
{{ ps.sessionunit }} |
+
+ Edit Template
+ |
Delete
|
diff --git a/rowers/templates/plannedsessiontemplateedit.html b/rowers/templates/plannedsessiontemplateedit.html
new file mode 100644
index 00000000..34dde816
--- /dev/null
+++ b/rowers/templates/plannedsessiontemplateedit.html
@@ -0,0 +1,197 @@
+{% extends "newbase.html" %}
+{% load staticfiles %}
+{% load rowerfilters %}
+
+{% block title %}Update Template Session{% endblock %}
+
+{% block main %}
+Edit Session Template
+
+
+
+
+ -
+
{{ thesession.name }}
+
+
+
+ -
+
Templates
+
+ Click on session name to clone to current period
+
+
+
+
+ | Name |
+ Value |
+ |
+ Edit |
+ Delete |
+
+
+
+ {% for ps in sessiontemplates %}
+
+ |
+ {% if ps.name != '' %}
+ {{ ps.name }}
+ {% else %}
+ Unnamed Session
+ {% endif %}
+ |
+ {{ ps.sessionvalue }} |
+ {{ ps.sessionunit }} |
+
+ Edit Template
+ |
+
+ Delete
+ |
+
+ {% endfor %}
+
+
+
+
+
+{% endblock %}
+
+{% block sidebar %}
+{% include 'menu_plan.html' %}
+{% endblock %}
+
+
+{% block scripts %}
+
+
+
+{% endblock %}
diff --git a/rowers/templates/plannedsessionview.html b/rowers/templates/plannedsessionview.html
index a8d0ad65..e6e9666d 100644
--- a/rowers/templates/plannedsessionview.html
+++ b/rowers/templates/plannedsessionview.html
@@ -16,6 +16,8 @@
Edit Session
+ /
+ Save to template
{% endif %}
Session {{ psdict.name.1 }}
@@ -157,11 +159,11 @@
Course
{{ coursediv|safe }}
-
+
{{ coursescript|safe }}
{% endif %}
-
+
diff --git a/rowers/tests/viewnames.csv b/rowers/tests/viewnames.csv
index 1978647e..0d67bacc 100644
--- a/rowers/tests/viewnames.csv
+++ b/rowers/tests/viewnames.csv
@@ -1,312 +1,311 @@
-,id,view,function,anonymous,anonymous_response,own,own_response,own_nonperm,member,member_response,member_nonperm,coachee,coachee_response,coachee_nonperm,is_staff,userid,workoutid,dotest
-0,0,workouts_summaries_email_view,sends summary excel with workouts list and links to data to user,TRUE,302,basic,200,302,FALSE,403,403,FALSE,403,403,FALSE,FALSE,FALSE,TRUE
-1,1,rower_update_empower_view,updates old Empower Oarlock files (corrects Power bug),TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-2,2,agegroupcpview,needs age,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-3,4,ajax_agegrouprecords,gets age group records from C2 ,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-4,5,fitness_metric_view,updates a person's fitness metric,TRUE,302,basic,302,302,FALSE,403,302,FALSE,403,403,FALSE,FALSE,FALSE,TRUE
-5,6,agegrouprecordview,shows ergo age group records,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-6,7,workouts_view,workouts list,TRUE,302,basic,200,302,basic,200,403,coach,200,403,FALSE,TRUE,FALSE,TRUE
-7,8,virtualevents_view,virtual races list,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-8,9,virtualevent_create_view,create virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-9,10,indoorvirtualevent_create_view,create indoor virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-10,11,virtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-11,12,indoorvirtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-12,13,virtualevent_view,view virtual race,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-13,14,virtualevent_ranking_view,view ranking,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-14,15,virtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-15,16,indoorvirtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-16,17,virtualevent_register_view,register for race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-17,18,indoorvirtualevent_register_view,register for race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-18,19,virtualevent_addboat_view,add a new boat type,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-19,20,virtualevent_withdraw_view,withdraw,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-20,21,virtualevent_submit_result_view,submit a result,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,TRUE,FALSE
-21,22,virtualevent_disqualify_view,disqualify a racer,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE
-22,24,courses_view,see race courses,TRUE,200,FALSE,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-23,25,course_upload_view,upload a new course,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,TRUE
-24,26,addmanual_view,upload a manual workout,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,TRUE
-25,27,team_comparison_select,compare with a team member workout,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,TRUE,TRUE,TRUE
-26,28,workouts_join_view,join workouts,TRUE,302,pro,302,302,pro,403,403,coach,302,403,FALSE,TRUE,FALSE,TRUE
-27,29,workouts_join_select,select workouts to join,TRUE,404,pro,200,302,pro,403,403,coach,200,403,FALSE,TRUE,FALSE,TRUE
-28,30,user_boxplot_select,select boxplots,TRUE,302,pro,200,302,pro,403,403,coach,200,302,FALSE,TRUE,FALSE,TRUE
-29,31,analysis_new,front page for analysis section,TRUE,200,basic,200,302,FALSE,200,302,coach,200,302,FALSE,TRUE,FALSE,TRUE
-30,32,user_multiflex_select,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-31,33,session_jobs_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-32,34,session_jobs_status,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-33,35,kill_async_job,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-34,36,post_progress,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-35,37,graphs_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-36,38,fitnessmetric_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-37,39,rankings_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-38,40,rankings_view2,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-39,41,otwrankings_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-40,42,oterankings_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-41,43,cum_flex,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-42,44,analysis_view_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-43,47,cum_flex_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-44,48,histo,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-45,49,histo_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-46,51,cumstats,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-47,53,graph_show_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-48,54,GraphDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-49,55,get_thumbnails,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-50,56,otw_use_impeller,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-51,57,otw_use_gps,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-52,58,workout_toggle_ranking,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-53,59,team_workout_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-54,60,workout_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-55,61,workout_histo_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-56,62,workout_forcecurve_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-57,63,workout_unsubscribe_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-58,64,workout_comment_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-59,65,workout_tcxemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-60,66,workout_gpxemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-61,67,workout_csvemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-62,68,workout_csvtoadmin_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-63,69,workout_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-64,70,workout_map_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-65,71,workout_update_cp_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-66,72,instroke_chart,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-67,73,instroke_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-68,74,workout_stats_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-69,75,workout_data_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-70,76,workout_otwsetpower_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-71,77,workout_otwpowerplot_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-72,78,workout_wind_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-73,79,workout_uploadimage_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-74,80,virtualevent_compare_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-75,81,virtualevent_uploadimage_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-76,82,virtualevent_setlogo_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-77,83,logo_delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-78,84,workout_downloadwind_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-79,85,workout_downloadmetar_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-80,86,workout_stream_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-81,87,workout_summary_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-82,88,workout_summary_restore_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-83,89,workout_split_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-84,90,workout_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-85,91,workout_video_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-86,92,VideoDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-87,93,workout_video_view_mini,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-88,94,workout_video_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-89,95,list_videos,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-90,96,video_selectworkout,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-91,98,workout_fusion_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-92,99,workout_fusion_list,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-93,100,TemplateView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-94,103,workout_add_chart_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-95,112,WorkoutDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-96,113,workout_smoothenpace_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-97,114,workout_undo_smoothenpace_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-98,115,workout_c2import_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-99,120,workout_stravaimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-100,122,workout_getc2workout_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-101,124,workout_getimportview,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-102,125,workout_getstravaworkout_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-103,126,workout_getstravaworkout_next,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-104,127,workout_sporttracksimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-105,129,workout_getsporttracksworkout_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-106,130,workout_polarimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-107,132,workout_runkeeperimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-108,134,workout_underarmourimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-109,135,workout_c2_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-110,136,workout_strava_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-111,137,workout_recalcsummary_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-112,138,workout_sporttracks_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-113,139,workout_runkeeper_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-114,140,workout_underarmour_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-115,141,workout_tp_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-116,142,multi_compare_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-117,145,alerts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-118,147,AlertDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-119,148,alert_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-120,150,alert_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-121,152,alert_report_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-122,155,boxplot_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-123,157,boxplot_view_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-124,158,multiflex_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-125,160,multiflex_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-126,161,deactivate_user,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-127,162,remove_user,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-128,163,user_gdpr_confirm,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-129,165,user_gdpr_optin,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-130,167,rower_teams_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-131,168,rower_calcdps_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-132,169,rower_exportsettings_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-133,171,team_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-134,172,team_members_stats_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-135,173,team_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-136,174,team_leaveconfirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-137,175,team_leave_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-138,176,team_deleteconfirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-139,177,team_requestmembership_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-140,178,reject_revoke_coach_request,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-141,179,coach_drop_athlete_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-142,180,coach_drop_athlete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-143,181,athlete_drop_coach_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-144,182,athlete_drop_coach_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-145,184,reject_revoke_coach_offer,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-146,186,request_coaching_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-147,187,offer_coaching_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-148,188,coach_accept_coachrequest_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-149,189,rower_accept_coachoffer_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-150,190,team_delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-151,191,team_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-152,192,manager_member_drop_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-153,193,invitation_reject_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-154,194,invitation_revoke_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-155,195,rower_invitations_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-156,196,raise_500,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-157,198,request_revoke_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-158,199,request_reject_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-159,200,manager_requests_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-160,202,rower_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-161,204,rower_prefs_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-162,205,transactions_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-163,208,rower_c2_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-164,209,rower_polar_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-165,210,rower_revokeapp_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-166,211,rower_strava_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-167,212,rower_sporttracks_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-168,213,rower_underarmour_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-169,214,rower_tp_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-170,215,rower_runkeeper_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-171,216,rower_sporttracks_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-172,217,rower_underarmour_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-173,218,rower_tp_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-174,219,rower_c2_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-175,220,rower_favoritecharts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-176,222,workout_workflow_config2_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-177,224,workflow_default_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-178,225,sendmail,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-179,231,analysis_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-180,232,laboratory_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-181,233,errormessage_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-182,237,payment_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-183,238,upgrade_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-184,240,downgrade_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-185,241,billing_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-186,242,upgrade_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-187,243,downgrade_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-188,244,payment_completed_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-189,245,downgrade_completed_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-190,246,paidplans_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-191,247,plan_stop_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-192,248,plan_tobasic_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-193,249,checkouts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-194,250,upgrade_checkouts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-195,251,downgrade_checkouts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-196,252,planrequired_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-197,253,start_trial_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-198,254,start_plantrial_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-199,256,rower_register_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-200,257,freecoach_register_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-201,259,workout_workflow_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-202,260,workout_flexchart3_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-203,264,rower_process_testcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-204,265,rower_create_trainingplan,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-205,267,TrainingPlanDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-206,268,MicroCycleDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-207,269,MesoCycleDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-208,270,MacroCycleDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-209,271,rower_trainingplan_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-210,279,rower_trainingplan_execution_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-211,281,TrainingMacroCycleUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-212,282,TrainingMesoCycleUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-213,283,planmacrocyclebymonth,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-214,285,planmesocyclebyweek,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-215,287,TrainingMicroCycleUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-216,288,rower_delete_trainingtarget,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-217,289,TrainingPlanUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-218,290,TrainingTargetUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-219,291,strokedataform,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-220,292,plannedsession_teamcreate_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-221,296,plannedsession_teamedit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-222,298,plannedsession_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-223,300,plannedsession_multiclone_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-224,302,plannedsession_multicreate_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-225,305,plannedsession_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-226,306,plannedsession_totemplate_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-227,307,plannedsession_compare_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-228,310,plannedsession_clone_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-229,311,plannedsession_teamclone_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-230,313,plannedsession_detach_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-231,315,plannedsession_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-232,317,PlannedSessionDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-233,319,plannedsessions_manage_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-234,323,plannedsessions_coach_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-235,325,plannedsessions_coach_icsemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-236,326,plannedsessions_print_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-237,327,plannedsession_comment_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-238,330,plannedsessions_icsemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-239,332,plannedsessions_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE
-240,334,course_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-241,335,course_delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-242,336,course_kmldownload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-243,337,course_replace_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-244,338,course_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-245,339,course_map_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-246,341,c2listdebug_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-247,343,rower_process_callback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-248,344,rower_process_stravacallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-249,345,rower_process_sporttrackscallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-250,346,rower_process_underarmourcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-251,347,rower_process_polarcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-252,348,rower_process_runkeepercallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-253,349,rower_process_tpcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-254,350,rower_process_twittercallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-255,351,set_language,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-256,352,SetOffsetView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-257,353,stats,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-258,354,stats_json,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-259,355,jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-260,356,workers,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-261,357,worker_details,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-262,358,finished_jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-263,359,started_jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-264,360,deferred_jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-265,361,clear_queue,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-266,362,requeue_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-267,363,job_detail,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-268,364,delete_job,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-269,365,actions,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-270,366,requeue_job_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-271,367,enqueue_job,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-272,368,JavaScriptCatalog,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-273,369,serve,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-274,371,LoginView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-275,372,LogoutView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-276,373,PasswordChangeView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-277,374,PasswordChangeDoneView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-278,375,PasswordResetView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-279,376,PasswordResetDoneView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-280,377,PasswordResetConfirmView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-281,378,PasswordResetCompleteView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-282,386,index,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-283,387,login,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-284,388,logout,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-285,389,password_change,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-286,390,password_change_done,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-287,391,i18n_javascript,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-288,392,shortcut,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-289,393,changelist_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-290,394,add_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-291,395,autocomplete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-292,396,history_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-293,397,delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-294,398,change_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-295,399,RedirectView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-296,568,app_index,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-297,571,landingview,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-298,573,get_blog_posts,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-299,576,AuthorizationView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-300,577,TokenView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-301,578,WorkoutViewSet,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-302,582,RowerViewSet,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-303,586,FavoriteChartViewSet,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-304,590,APIRootView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-305,592,SwaggerSchemaView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-306,595,strokedatajson,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
-307,596,error500_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-308,603,failed_queue_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-309,604,failed_queue_empty,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE
-310,605,failed_job_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE
+,id,view,function,anonymous,anonymous_response,own,own_response,own_nonperm,member,member_response,member_nonperm,coachee,coachee_response,coachee_nonperm,is_staff,userid,workoutid,dotest,realtest
+0,0,workouts_summaries_email_view,sends summary excel with workouts list and links to data to user,TRUE,302,basic,200,302,FALSE,403,403,FALSE,403,403,FALSE,FALSE,FALSE,FALSE,TRUE
+1,1,rower_update_empower_view,updates old Empower Oarlock files (corrects Power bug),TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+2,2,agegroupcpview,needs age,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+3,4,ajax_agegrouprecords,gets age group records from C2 ,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+4,5,fitness_metric_view,updates a person's fitness metric,TRUE,302,basic,302,302,FALSE,403,302,FALSE,403,403,FALSE,FALSE,FALSE,FALSE,TRUE
+5,6,agegrouprecordview,shows ergo age group records,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+6,7,workouts_view,workouts list,TRUE,302,basic,200,302,basic,200,403,coach,200,403,FALSE,TRUE,FALSE,FALSE,TRUE
+7,8,virtualevents_view,virtual races list,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+8,9,virtualevent_create_view,create virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+9,10,indoorvirtualevent_create_view,create indoor virtual event,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+10,11,virtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+11,12,indoorvirtualevent_toggle_email_view,toggle email notifications,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+12,13,virtualevent_view,view virtual race,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+13,14,virtualevent_ranking_view,view ranking,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+14,15,virtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+15,16,indoorvirtualevent_edit_view,edit race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+16,17,virtualevent_register_view,register for race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+17,18,indoorvirtualevent_register_view,register for race,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+18,19,virtualevent_addboat_view,add a new boat type,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+19,20,virtualevent_withdraw_view,withdraw,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+20,21,virtualevent_submit_result_view,submit a result,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+21,22,virtualevent_disqualify_view,disqualify a racer,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+22,24,courses_view,see race courses,TRUE,200,FALSE,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+23,25,course_upload_view,upload a new course,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+24,26,addmanual_view,upload a manual workout,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+25,27,team_comparison_select,compare with a team member workout,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,TRUE,TRUE,FALSE,TRUE
+26,28,workouts_join_view,join workouts,TRUE,302,pro,302,302,pro,403,403,coach,302,403,FALSE,TRUE,FALSE,FALSE,TRUE
+27,29,workouts_join_select,select workouts to join,TRUE,404,pro,200,302,pro,403,403,coach,200,403,FALSE,TRUE,FALSE,FALSE,TRUE
+28,30,user_boxplot_select,select boxplots,TRUE,302,pro,200,302,pro,403,403,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+29,31,analysis_new,analysis front page,TRUE,302,pro,200,302,FALSE,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+30,32,user_multiflex_select,select multiflex data,TRUE,302,pro,200,302,FALSE,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+31,33,session_jobs_view,view jobs,TRUE,302,basic,200,302,FALSE,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+32,34,session_jobs_status,view jobs,TRUE,302,basic,200,302,FALSE,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+33,35,kill_async_job,kill job,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+34,36,post_progress,post progress,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+35,37,graphs_view,view charts,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+36,38,fitnessmetric_view,view fitness metric,TRUE,302,plan,200,302,plan,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+37,39,rankings_view,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+38,40,rankings_view2,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+39,41,otwrankings_view,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+40,42,oterankings_view,view ranking,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+41,43,cum_flex,flex all chart,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+42,44,analysis_view_data,redirects to analysis direct,TRUE,302,pro,302,302,pro,302,302,coach,302,302,FALSE,FALSE,FALSE,FALSE,TRUE
+43,47,cum_flex_data,flex all chart data (json),TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+44,48,histo,histogram view,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+45,49,histo_data,histogram data,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+46,51,cumstats,cumulative statistics,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+47,53,graph_show_view,show a chart,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+48,54,GraphDelete,delete a chart,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+49,55,get_thumbnails,get thumbnails,TRUE,403,basic,200,302,basic,403,403,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+50,56,otw_use_impeller,switch to impeller data,TRUE,403,basic,302,302,basic,403,302,coach,302,302,FALSE,FALSE,TRUE,FALSE,TRUE
+51,57,otw_use_gps,switch to GPS data,TRUE,403,basic,302,302,basic,403,302,coach,302,302,FALSE,FALSE,TRUE,FALSE,TRUE
+52,58,workout_toggle_ranking,toggle ranking,TRUE,302,basic,302,302,basic,403,302,coach,302,302,FALSE,FALSE,TRUE,FALSE,TRUE
+53,59,team_workout_upload_view,upload workout for team member,TRUE,302,coach,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+54,60,workout_upload_view,upload a workout,TRUE,302,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+55,61,workout_histo_view,histogram ,TRUE,302,basic,200,302,basic,403,403,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+56,62,workout_forcecurve_view,force curve,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+57,63,workout_unsubscribe_view,unsubscribe from comments,TRUE,302,basic,200,302,basic,200,302,basic,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+58,64,workout_comment_view,comment on workout,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+59,65,workout_tcxemail_view,download TCX file,TRUE,403,basic,200,302,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+60,66,workout_gpxemail_view,download GPX file,TRUE,403,basic,200,302,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+61,67,workout_csvemail_view,download CSV file,TRUE,403,basic,200,302,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+62,68,workout_csvtoadmin_view,send CSV to admin,TRUE,403,basic,200,200,basic,200,200,coach,200,200,TRUE,FALSE,TRUE,FALSE,TRUE
+63,69,workout_edit_view,Edit Workout,TRUE,403,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+64,70,workout_map_view,View workout Map,TRUE,302,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+65,71,workout_update_cp_view,Update CP data based on new workout,TRUE,403,pro,302,302,pro,403,403,coach,302,302,FALSE,FALSE,TRUE,FALSE,TRUE
+66,72,instroke_chart,View In-Stroke data chart,TRUE,302,pro,302,302,pro,403,403,coach,302,302,FALSE,FALSE,FALSE,FALSE,FALSE
+67,73,instroke_view,Create in stroke chart,TRUE,403,basic,200,302,basic,403,403,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+68,74,workout_stats_view,View Workout Stats,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+69,75,workout_data_view,shows the detailed data for a workout,TRUE,403,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+70,76,workout_otwsetpower_view,set weight and start offline OTW power calculations,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+71,77,workout_otwpowerplot_view,generates OTW power chart,TRUE,200,basic,200,200,basic,200,200,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+72,78,workout_wind_view,set wind,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+73,79,workout_uploadimage_view,upload image,TRUE,403,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+74,80,virtualevent_compare_view,compare workouts from a virtual event,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+75,81,virtualevent_uploadimage_view,upload image to virtual event,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+76,82,virtualevent_setlogo_view,set logo of virtual event,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+77,83,logo_delete_view,delete logo,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+78,84,workout_downloadwind_view,download Wind,TRUE,403,pro,302,302,pro,403,403,coach,302,403,FALSE,FALSE,TRUE,FALSE,FALSE
+79,85,workout_downloadmetar_view,download METAR,TRUE,403,pro,200,302,pro,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,FALSE
+80,86,workout_stream_view,edit stream (redirects as no data in test suite),TRUE,403,pro,200,302,pro,403,403,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+81,87,workout_summary_edit_view,edit workout summary,TRUE,403,basic,200,403,basic,403,403,coach,200,403,FALSE,FALSE,TRUE,FALSE,TRUE
+82,88,workout_summary_restore_view,restore workout summary,TRUE,403,basic,302,403,basic,403,403,coach,302,403,FALSE,FALSE,TRUE,FALSE,TRUE
+83,89,workout_split_view,split workout,TRUE,403,pro,200,302,pro,403,403,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+84,90,workout_view,view workout ,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+85,91,workout_video_create_view,add video ,TRUE,403,pro,200,302,pro,403,403,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+86,92,VideoDelete,delete video,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+87,93,workout_video_view_mini,minimal view,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+88,94,workout_video_view,"video view (not tested, no video in test suite)",TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+89,95,list_videos,list my videos,TRUE,302,pro,200,302,pro,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,TRUE
+90,96,video_selectworkout,select workout to create video,TRUE,302,pro,200,302,pro,403,403,coach,200,302,FALSE,TRUE,FALSE,FALSE,TRUE
+91,98,workout_fusion_view,needs to workouts,TRUE,403,pro,200,302,pro,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+92,99,workout_fusion_list,list workouts to fuse with,TRUE,302,pro,200,302,pro,403,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,TRUE
+94,103,workout_add_chart_view,add chart,TRUE,403,basic,302,403,basic,403,403,coach,302,403,FALSE,FALSE,TRUE,TRUE,FALSE
+95,112,WorkoutDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+96,113,workout_smoothenpace_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+97,114,workout_undo_smoothenpace_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+98,115,workout_c2import_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+99,120,workout_stravaimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+100,122,workout_getc2workout_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+101,124,workout_getimportview,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+102,125,workout_getstravaworkout_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+103,126,workout_getstravaworkout_next,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+104,127,workout_sporttracksimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+105,129,workout_getsporttracksworkout_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+106,130,workout_polarimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+107,132,workout_runkeeperimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+108,134,workout_underarmourimport_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+109,135,workout_c2_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+110,136,workout_strava_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+111,137,workout_recalcsummary_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+112,138,workout_sporttracks_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+113,139,workout_runkeeper_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+114,140,workout_underarmour_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+115,141,workout_tp_upload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+116,142,multi_compare_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+117,145,alerts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+118,147,AlertDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+119,148,alert_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+120,150,alert_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+121,152,alert_report_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+122,155,boxplot_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+123,157,boxplot_view_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+124,158,multiflex_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+125,160,multiflex_data,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+126,161,deactivate_user,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+127,162,remove_user,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+128,163,user_gdpr_confirm,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+129,165,user_gdpr_optin,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+130,167,rower_teams_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+131,168,rower_calcdps_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+132,169,rower_exportsettings_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+133,171,team_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+134,172,team_members_stats_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+135,173,team_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+136,174,team_leaveconfirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+137,175,team_leave_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+138,176,team_deleteconfirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+139,177,team_requestmembership_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+140,178,reject_revoke_coach_request,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+141,179,coach_drop_athlete_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+142,180,coach_drop_athlete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+143,181,athlete_drop_coach_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+144,182,athlete_drop_coach_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+145,184,reject_revoke_coach_offer,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+146,186,request_coaching_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+147,187,offer_coaching_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+148,188,coach_accept_coachrequest_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+149,189,rower_accept_coachoffer_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+150,190,team_delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+151,191,team_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+152,192,manager_member_drop_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+153,193,invitation_reject_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+154,194,invitation_revoke_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+155,195,rower_invitations_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+156,196,raise_500,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+157,198,request_revoke_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+158,199,request_reject_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+159,200,manager_requests_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+160,202,rower_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+161,204,rower_prefs_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+162,205,transactions_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+163,208,rower_c2_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+164,209,rower_polar_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+165,210,rower_revokeapp_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+166,211,rower_strava_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+167,212,rower_sporttracks_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+168,213,rower_underarmour_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+169,214,rower_tp_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+170,215,rower_runkeeper_authorize,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+171,216,rower_sporttracks_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+172,217,rower_underarmour_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+173,218,rower_tp_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+174,219,rower_c2_token_refresh,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+175,220,rower_favoritecharts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+176,222,workout_workflow_config2_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+177,224,workflow_default_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+178,225,sendmail,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+179,231,analysis_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+180,232,laboratory_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+181,233,errormessage_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+182,237,payment_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+183,238,upgrade_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+184,240,downgrade_confirm_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+185,241,billing_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+186,242,upgrade_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+187,243,downgrade_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+188,244,payment_completed_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+189,245,downgrade_completed_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+190,246,paidplans_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+191,247,plan_stop_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+192,248,plan_tobasic_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+193,249,checkouts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+194,250,upgrade_checkouts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+195,251,downgrade_checkouts_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+196,252,planrequired_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+197,253,start_trial_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+198,254,start_plantrial_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+199,256,rower_register_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+200,257,freecoach_register_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+201,259,workout_workflow_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+202,260,workout_flexchart3_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+203,264,rower_process_testcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+204,265,rower_create_trainingplan,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+205,267,TrainingPlanDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+206,268,MicroCycleDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+207,269,MesoCycleDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+208,270,MacroCycleDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+209,271,rower_trainingplan_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+210,279,rower_trainingplan_execution_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+211,281,TrainingMacroCycleUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+212,282,TrainingMesoCycleUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+213,283,planmacrocyclebymonth,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+214,285,planmesocyclebyweek,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+215,287,TrainingMicroCycleUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+216,288,rower_delete_trainingtarget,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+217,289,TrainingPlanUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+218,290,TrainingTargetUpdate,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+219,291,strokedataform,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+220,292,plannedsession_teamcreate_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+221,296,plannedsession_teamedit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+222,298,plannedsession_create_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+223,300,plannedsession_multiclone_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+224,302,plannedsession_multicreate_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+225,305,plannedsession_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+226,306,plannedsession_totemplate_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+227,307,plannedsession_compare_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+228,310,plannedsession_clone_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+229,311,plannedsession_teamclone_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+230,313,plannedsession_detach_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+231,315,plannedsession_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+232,317,PlannedSessionDelete,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+233,319,plannedsessions_manage_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+234,323,plannedsessions_coach_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+235,325,plannedsessions_coach_icsemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+236,326,plannedsessions_print_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+237,327,plannedsession_comment_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+238,330,plannedsessions_icsemail_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+239,332,plannedsessions_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,TRUE,FALSE,FALSE,FALSE
+240,334,course_edit_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+241,335,course_delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+242,336,course_kmldownload_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+243,337,course_replace_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+244,338,course_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+245,339,course_map_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+246,341,c2listdebug_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+247,343,rower_process_callback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+248,344,rower_process_stravacallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+249,345,rower_process_sporttrackscallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+250,346,rower_process_underarmourcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+251,347,rower_process_polarcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+252,348,rower_process_runkeepercallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+253,349,rower_process_tpcallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+254,350,rower_process_twittercallback,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+255,351,set_language,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+256,352,SetOffsetView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+257,353,stats,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+258,354,stats_json,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+259,355,jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+260,356,workers,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+261,357,worker_details,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+262,358,finished_jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+263,359,started_jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+264,360,deferred_jobs,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+265,361,clear_queue,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+266,362,requeue_all,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+267,363,job_detail,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+268,364,delete_job,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+269,365,actions,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+270,366,requeue_job_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+271,367,enqueue_job,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+272,368,JavaScriptCatalog,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+273,369,serve,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+274,371,LoginView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+275,372,LogoutView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+276,373,PasswordChangeView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+277,374,PasswordChangeDoneView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+278,375,PasswordResetView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+279,376,PasswordResetDoneView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+280,377,PasswordResetConfirmView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+281,378,PasswordResetCompleteView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+282,386,index,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+283,387,login,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+284,388,logout,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+285,389,password_change,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+286,390,password_change_done,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+287,391,i18n_javascript,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+288,392,shortcut,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+289,393,changelist_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+290,394,add_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+291,395,autocomplete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+292,396,history_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+293,397,delete_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+294,398,change_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+295,399,RedirectView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+296,568,app_index,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+297,571,landingview,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+298,573,get_blog_posts,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+299,576,AuthorizationView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+300,577,TokenView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+301,578,WorkoutViewSet,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+302,582,RowerViewSet,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+303,586,FavoriteChartViewSet,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+304,590,APIRootView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+305,592,SwaggerSchemaView,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+306,595,strokedatajson,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
+307,596,error500_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+308,603,failed_queue_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+309,604,failed_queue_empty,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,FALSE,FALSE,FALSE
+310,605,failed_job_view,,TRUE,200,basic,200,302,basic,200,302,coach,200,302,FALSE,FALSE,TRUE,FALSE,FALSE
diff --git a/rowers/urls.py b/rowers/urls.py
index dbae602e..d07c68e9 100644
--- a/rowers/urls.py
+++ b/rowers/urls.py
@@ -246,26 +246,27 @@ urlpatterns = [
re_path(r'^record-progress/(?P.*)/$',views.post_progress),
re_path(r'^record-progress/$',views.post_progress),
re_path(r'^list-graphs/$',views.graphs_view,name='graphs_view'),
+ re_path(r'^list-graphs/user/(?P\d+)/$',views.graphs_view,name='graphs_view'),
re_path(r'^fitness-progress/$',views.fitnessmetric_view,name='fitnessmetric_view'),
- re_path(r'^fitness-progress/user/(?P\d+)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
- re_path(r'^fitness-progress/user/(?P\d+)/(?P\w+.*)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
+ re_path(r'^fitness-progress/user/(?P\d+)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
+ re_path(r'^fitness-progress/user/(?P\d+)/(?P\w+.*)/$',views.fitnessmetric_view,name='fitnessmetric_view'),
# re_path(r'^ote-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view,name='rankings_view'),
- re_path(r'^ote-bests/user/(?P\d+)/$',views.rankings_view,name='rankings_view'),
+ re_path(r'^ote-bests/user/(?P\d+)/$',views.rankings_view,name='rankings_view'),
# re_path(r'^ote-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view,name='rankings_view'),
re_path(r'^ote-bests/$',views.rankings_view,name='rankings_view'),
- re_path(r'^(?P\d+)/ote-bests/$',views.rankings_view,name='rankings_view'),
+ re_path(r'^(?P\d+)/ote-bests/$',views.rankings_view,name='rankings_view'),
# re_path(r'^(?P\d+)/ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view2,name='rankings_view2'),
- re_path(r'^ote-bests2/user/(?P\d+)/$',views.rankings_view2,name='rankings_view2'),
+ re_path(r'^ote-bests2/user/(?P\d+)/$',views.rankings_view2,name='rankings_view2'),
# re_path(r'^ote-bests2/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.rankings_view2,name='rankings_view2'),
re_path(r'^ote-bests2/$',views.rankings_view2,name='rankings_view2'),
# re_path(r'^otw-bests/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwrankings_view,name='otwrankings_view'),
# re_path(r'^otw-bests/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.otwrankings_view,name='otwrankings_view'),
- re_path(r'^otw-bests/user/(?P\d+)/$',views.otwrankings_view,name='otwrankings_view'),
+ re_path(r'^otw-bests/user/(?P\d+)/$',views.otwrankings_view,name='otwrankings_view'),
re_path(r'^otw-bests/$',views.otwrankings_view,name='otwrankings_view'),
# re_path(r'^ote-ranking/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.oterankings_view,name='oterankings_view'),
# re_path(r'^ote-ranking/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.oterankings_view,name='oterankings_view'),
re_path(r'^ote-ranking/$',views.oterankings_view,name='oterankings_view'),
- re_path(r'^ote-ranking/user/(?P\d+)/$',views.oterankings_view,name='oterankings_view'),
+ re_path(r'^ote-ranking/user/(?P\d+)/$',views.oterankings_view,name='oterankings_view'),
# re_path(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/user/(?P\d+)/$',views.cum_flex,name='cum_flex'),
# re_path(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.cum_flex,name='cum_flex'),
re_path(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/$',views.cum_flex,name='cum_flex'),
@@ -273,7 +274,7 @@ urlpatterns = [
re_path(r'^flexall/user/(?P\d+)/$',views.cum_flex,name='cum_flex'),
re_path(r'^flexall/$',views.cum_flex,name='cum_flex'),
re_path(r'^flexalldata/$',views.cum_flex_data,name='cum_flex_data'),
- re_path(r'^histo/user/(?P\d+)/$',views.histo,name='histo'),
+ re_path(r'^histo/user/(?P\d+)/$',views.histo,name='histo'),
re_path(r'^histodata/$',views.histo_data,name='histo_data'),
# re_path(r'^histo/user/(?P\d+)/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$',views.histo,name='histo'),
re_path(r'^histo/$',views.histo,name='histo'),
@@ -356,6 +357,7 @@ urlpatterns = [
re_path(r'^video/(?P\w.+)/$',views.workout_video_view,
name='workout_video_view'),
re_path(r'^videos/',views.list_videos,name='list_videos'),
+ re_path(r'^add-video/user/(?P\d+)/$',views.video_selectworkout,name='video_selectworkout'),
re_path(r'^add-video/',views.video_selectworkout,name='video_selectworkout'),
# re_path(r'^workout/(?P\d+)/$',views.workout_view,name='workout_view'),
re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/$',views.workout_view,name='workout_view'),
@@ -450,7 +452,7 @@ urlpatterns = [
re_path(r'^user-multiflex-data/$',views.multiflex_data,name='multiflex_data'),
re_path(r'^me/deactivate/$',views.deactivate_user,name='deactivate_user'),
re_path(r'^me/delete/$',views.remove_user,name='remove_user'),
-# re_path(r'^survey/$',views.survey,name='survey'),
+ re_path(r'^survey/$',views.survey,name='survey'),
re_path(r'^me/gdpr-optin-confirm/?/$',views.user_gdpr_confirm,name='user_gdpr_confirm'),
re_path(r'^me/gdpr-optin-confirm/$',views.user_gdpr_confirm,name='user_gdpr_confirm'),
re_path(r'^me/gdpr-optin/?/$',views.user_gdpr_optin,name='user_gdpr_optin'),
@@ -667,6 +669,7 @@ urlpatterns = [
views.plannedsession_multicreate_view,
name='plannedsession_multicreate_view'),
re_path(r'^sessions/(?P\d+)/edit/$',views.plannedsession_edit_view),
+ re_path(r'^sessions/(?P\d+)/templateedit/',views.plannedsession_templateedit_view),
re_path(r'^sessions/(?P\d+)/maketemplate/$',views.plannedsession_totemplate_view),
re_path(r'^sessions/(?P\d+)/compare/$',
views.plannedsession_compare_view,
diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py
index be1190da..67392db8 100644
--- a/rowers/views/analysisviews.py
+++ b/rowers/views/analysisviews.py
@@ -730,7 +730,7 @@ def analysis_view_data(request,userid=0):
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
redirect_field_name=None)
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
-def histo(request,theuser=0,
+def histo(request,userid=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
deltadays=-1,
@@ -744,7 +744,7 @@ def histo(request,theuser=0,
'histoparam':'power'
}):
- r = getrequestrower(request,userid=theuser)
+ r = getrequestrower(request,userid=userid)
theuser = r.user
if 'histoparam' in request.session:
@@ -1335,13 +1335,13 @@ def planrequired_view(request):
@user_passes_test(isplanmember,login_url="/rowers/paidplans",
message="This functionality requires a Coach or Self-Coach plan",
redirect_field_name=None)
-@permission_required('rower.is_coach',fn=get_user_by_id,raise_exception=True)
-def fitnessmetric_view(request,id=0,mode='rower',
+@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
+def fitnessmetric_view(request,userid=0,mode='rower',
startdate=timezone.now()-timezone.timedelta(days=365),
enddate=timezone.now()):
- therower = getrequestrower(request,userid=id)
+ therower = getrequestrower(request,userid=userid)
theuser = therower.user
@@ -1391,7 +1391,8 @@ def fitnessmetric_view(request,id=0,mode='rower',
# Show ranking distances including predicted paces
@login_required()
-def rankings_view(request,theuser=0,
+@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
+def rankings_view(request,userid=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
deltadays=-1,
@@ -1412,25 +1413,25 @@ def rankings_view(request,theuser=0,
enddate = startdate
startdate = s
- if theuser == 0:
- theuser = request.user.id
+
promember=0
- if not request.user.is_anonymous:
- r = getrower(request.user)
- if r.birthdate:
- age = calculate_age(r.birthdate)
- worldclasspower = int(metrics.getagegrouprecord(
- age,
- sex=r.sex,
- weightcategory=r.weightcategory,
- ))
- else:
- worldclasspower = None
+ r = getrequestrower(request,userid=userid)
+ theuser = r.user.id
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
+ if r.birthdate:
+ age = calculate_age(r.birthdate)
+ worldclasspower = int(c2stuff.getagegrouprecord(
+ age,
+ sex=r.sex,
+ weightcategory=r.weightcategory,
+ ))
+ else:
+ worldclasspower = None
+
+ result = request.user.is_authenticated and ispromember(request.user)
+ if result:
+ promember=1
# get all indoor rows in date range
@@ -1741,7 +1742,8 @@ def ajax_agegrouprecords(request,
# Show ranking distances including predicted paces
@login_required()
-def rankings_view2(request,theuser=0,
+@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
+def rankings_view2(request,userid=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
deltadays=-1,
@@ -1762,83 +1764,84 @@ def rankings_view2(request,theuser=0,
enddate = startdate
startdate = s
- if theuser == 0:
- theuser = request.user.id
+ if userid == 0:
+ userid = request.user.id
else:
lastupdated = "01-01-1900"
promember=0
- if not request.user.is_anonymous:
- r = getrower(request.user)
+ r = getrequestrower(request,userid=userid)
+ theuser = r.user
+
+ wcdurations = []
+ wcpower = []
+
+ lastupdated = "01-01-1900"
+ userid = 0
+ if 'options' in request.session:
+ options = request.session['options']
+ try:
+ wcdurations = options['wcdurations']
+ wcpower = options['wcpower']
+ lastupdated = options['lastupdated']
+ except KeyError:
+ pass
+ try:
+ userid = options['userid']
+ except KeyError:
+ userid = 0
+ else:
+ options = {}
+
+
+
+ lastupdatedtime = arrow.get(lastupdated).timestamp
+ current_time = arrow.utcnow().timestamp
+
+ deltatime_seconds = current_time - lastupdatedtime
+ recalc = False
+ if str(userid) != str(theuser) or deltatime_seconds > 3600:
+ recalc = True
+ options['lastupdated'] = arrow.utcnow().isoformat()
+ else:
+ recalc = False
+
+ options['userid'] = theuser.id
+
+ if r.birthdate:
+ age = calculate_age(r.birthdate)
+ else:
+ worldclasspower = None
+ age = 0
+
+ agerecords = CalcAgePerformance.objects.filter(
+ age = age,
+ sex = r.sex,
+ weightcategory = r.weightcategory)
+
+ if len(agerecords) == 0:
+ recalc = True
+ wcpower = []
+ wcduration = []
+ else:
wcdurations = []
wcpower = []
+ for record in agerecords:
+ wcdurations.append(record.duration)
+ wcpower.append(record.power)
- lastupdated = "01-01-1900"
- userid = 0
- if 'options' in request.session:
- options = request.session['options']
- try:
- wcdurations = options['wcdurations']
- wcpower = options['wcpower']
- lastupdated = options['lastupdated']
- except KeyError:
- pass
- try:
- userid = options['userid']
- except KeyError:
- userid = 0
- else:
- options = {}
+ options['wcpower'] = wcpower
+ options['wcdurations'] = wcdurations
+ if theuser:
+ options['userid'] = theuser.id
+
+ request.session['options'] = options
-
- lastupdatedtime = arrow.get(lastupdated).timestamp
- current_time = arrow.utcnow().timestamp
-
- deltatime_seconds = current_time - lastupdatedtime
- recalc = False
- if str(userid) != str(theuser) or deltatime_seconds > 3600:
- recalc = True
- options['lastupdated'] = arrow.utcnow().isoformat()
- else:
- recalc = False
-
- options['userid'] = theuser
-
- if r.birthdate:
- age = calculate_age(r.birthdate)
- else:
- worldclasspower = None
- age = 0
-
- agerecords = CalcAgePerformance.objects.filter(
- age = age,
- sex = r.sex,
- weightcategory = r.weightcategory)
-
- if len(agerecords) == 0:
- recalc = True
- wcpower = []
- wcduration = []
- else:
- wcdurations = []
- wcpower = []
- for record in agerecords:
- wcdurations.append(record.duration)
- wcpower.append(record.power)
-
- options['wcpower'] = wcpower
- options['wcdurations'] = wcdurations
- if theuser:
- options['userid'] = theuser
-
- request.session['options'] = options
-
-
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
+ result = request.user.is_authenticated and ispromember(request.user)
+ if result:
+ promember=1
# get all indoor rows in date range
@@ -1887,10 +1890,7 @@ def rankings_view2(request,theuser=0,
r=0
- try:
- uu = User.objects.get(id=theuser)
- except User.DoesNotExist:
- uu = ''
+ uu = theuser
# test to fix bug
@@ -2155,7 +2155,7 @@ def rankings_view2(request,theuser=0,
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
redirect_field_name=None)
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
-def otwrankings_view(request,theuser=0,
+def otwrankings_view(request,userid=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
startdatestring="",
@@ -2178,22 +2178,10 @@ def otwrankings_view(request,theuser=0,
enddate = startdate
startdate = s
- if theuser == 0:
- if 'rowerid' in request.session:
- try:
- r = Rower.objects.get(id=request.session['rowerid'])
- theuser = r.user.id
- except Rower.DoesNotExist:
- theuser = request.user.id
- else:
- theuser = request.user.id
+ r = getrequestrower(request,userid=userid)
+ promember = True
- promember=0
- if not request.user.is_anonymous:
- r = Rower.objects.get(user=request.user)
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
+ theuser = r.user
# get all OTW rows in date range
@@ -2247,10 +2235,7 @@ def otwrankings_view(request,theuser=0,
- try:
- uu = User.objects.get(id=theuser)
- except User.DoesNotExist:
- uu = ''
+ uu = theuser
# test to fix bug
@@ -2561,7 +2546,7 @@ def otwcp_toadmin_view(request,theuser=0,
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
redirect_field_name=None)
@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
-def oterankings_view(request,theuser=0,
+def oterankings_view(request,userid=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
startdatestring="",
@@ -2584,23 +2569,11 @@ def oterankings_view(request,theuser=0,
enddate = startdate
startdate = s
- if theuser == 0:
- if 'rowerid' in request.session:
- try:
- r = Rower.objects.get(id=request.session['rowerid'])
- theuser = r.user.id
- except Rower.DoesNotExist:
- theuser = request.user.id
- else:
- theuser = request.user.id
+ r = getrequestrower(request,userid=userid)
+ theuser = r.user
promember=0
- if not request.user.is_anonymous:
- r = Rower.objects.get(user=request.user)
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
# get all OTW rows in date range
@@ -2674,10 +2647,8 @@ def oterankings_view(request,theuser=0,
raise Http404("Rower doesn't exist")
- try:
- uu = User.objects.get(id=theuser)
- except User.DoesNotExist:
- uu = ''
+ uu = theuser
+
# test to fix bug
diff --git a/rowers/views/exportviews.py b/rowers/views/exportviews.py
index afdfc7c9..b415696a 100644
--- a/rowers/views/exportviews.py
+++ b/rowers/views/exportviews.py
@@ -261,6 +261,7 @@ def workout_csvemail_view(request,id=0):
# Get Workout CSV file and send it to user's email address
@login_required()
+@permission_required('rower.is_staff',fn=get_user_by_userid,raise_exception=True)
def workout_csvtoadmin_view(request,id=0):
message = ""
r = getrower(request.user)
diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py
index 34a1f133..344f84ac 100644
--- a/rowers/views/paymentviews.py
+++ b/rowers/views/paymentviews.py
@@ -13,8 +13,8 @@ def paidplans_view(request):
else:
r = None
-
-
+
+
return render(request,
'paidplans.html',
{'rower':r})
@@ -24,7 +24,7 @@ def billing_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
@@ -42,7 +42,7 @@ def billing_view(request):
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
-
+
if billingaddressform.is_valid():
if planselectform.is_valid():
plan = planselectform.cleaned_data['plan']
@@ -58,7 +58,7 @@ def billing_view(request):
})
return HttpResponseRedirect(url)
-
+
else:
billingaddressform = RowerBillingAddressForm(instance=r)
planselectform = PlanSelectForm(paymentprocessor='braintree')
@@ -69,13 +69,13 @@ def billing_view(request):
'billingaddressform':billingaddressform,
'planselectform':planselectform,
})
-
+
@login_required()
def upgrade_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
@@ -93,7 +93,7 @@ def upgrade_view(request):
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
-
+
if planselectform.is_valid():
plan = planselectform.cleaned_data['plan']
if billingaddressform.is_valid():
@@ -102,7 +102,7 @@ def upgrade_view(request):
'planid':plan.id
})
return HttpResponseRedirect(url)
-
+
else:
billingaddressform = RowerBillingAddressForm(instance=r)
planselectform = PlanSelectForm(paymentprocessor='braintree',
@@ -114,13 +114,13 @@ def upgrade_view(request):
'billingaddressform':billingaddressform,
'planselectform':planselectform,
})
-
+
@login_required()
def downgrade_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
@@ -138,7 +138,7 @@ def downgrade_view(request):
for attr, value in cd.items():
setattr(r, attr, value)
r.save()
-
+
if planselectform.is_valid():
plan = planselectform.cleaned_data['plan']
@@ -150,14 +150,14 @@ def downgrade_view(request):
return HttpResponseRedirect(url)
else:
nextview = downgrade_confirm_view
-
+
if billingaddressform.is_valid():
url = reverse(nextview,
kwargs={
'planid':plan.id
})
return HttpResponseRedirect(url)
-
+
else:
billingaddressform = RowerBillingAddressForm(instance=r)
planselectform = PlanSelectForm(paymentprocessor='braintree',
@@ -169,17 +169,17 @@ def downgrade_view(request):
'billingaddressform':billingaddressform,
'planselectform':planselectform,
})
-
+
@login_required()
def plan_stop_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
subscriptions = []
-
+
if r.paymentprocessor != 'braintree' and r.paymenttype == 'recurring':
messages.error(request,'Automated payment processing is currently only available through BrainTree (by PayPal). You are currently on a recurring payment plan with PayPal. Contact the site administrator at support@rowsandall.com before you proceed')
@@ -189,7 +189,7 @@ def plan_stop_view(request):
except ProcessorCustomerError:
r.paymentprocessor = None
r.save()
-
+
return render(request,
@@ -203,7 +203,7 @@ def plan_tobasic_view(request,id=0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
if r.paidplan.paymentprocessor == 'braintree':
@@ -217,15 +217,15 @@ def plan_tobasic_view(request,id=0):
url = reverse(plan_stop_view)
return HttpResponseRedirect(url)
-
-
+
+
@login_required()
def upgrade_confirm_view(request,planid = 0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
try:
plan = PaidPlan.objects.get(id=planid)
except PaidPlan.DoesNotExist:
@@ -253,7 +253,7 @@ def downgrade_confirm_view(request,planid = 0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
try:
plan = PaidPlan.objects.get(id=planid)
except PaidPlan.DoesNotExist:
@@ -279,7 +279,7 @@ def payment_confirm_view(request,planid = 0):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
try:
plan = PaidPlan.objects.get(id=planid)
except PaidPlan.DoesNotExist:
@@ -350,13 +350,13 @@ def checkouts_view(request):
url = reverse(paidplans_view)
return HttpResponseRedirect(url)
-
+
@login_required()
def upgrade_checkouts_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
@@ -402,7 +402,7 @@ def downgrade_checkouts_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
@@ -450,7 +450,7 @@ def payment_completed_view(request):
amount = request.GET.get('amount',0)
-
+
r = request.user.rower
return render(request,
@@ -465,7 +465,7 @@ def downgrade_completed_view(request):
if not PAYMENT_PROCESSING_ON:
url = reverse('promembership')
return HttpResponseRedirect(url)
-
+
r = request.user.rower
return render(request,
@@ -480,7 +480,7 @@ def rower_register_view(request):
nextpage = request.GET.get('next','/rowers/list-workouts/')
if nextpage == '':
nextpage = '/rowers/list-workouts/'
-
+
if request.method == 'POST':
#form = RegistrationFormUniqueEmail(request.POST)
form = RegistrationFormSex(request.POST)
@@ -517,7 +517,7 @@ def rower_register_view(request):
timestr = strftime("%Y%m%d-%H%M%S")
f2 = f[:-7]+timestr+'.csv.gz'
copyfile(f,f2)
-
+
response = dataprep.new_workout_from_file(therower,f2,
title='New User Sample Data',
notes='This is an example workout to get you started')
@@ -527,17 +527,17 @@ def rower_register_view(request):
w.startdatetime = timezone.now()
w.date = timezone.now().date()
w.save()
-
+
# Create and send email
fullemail = first_name + " " + last_name + " " + "<" + email + ">"
subject = "Thank you for registering on rowsandall.com"
from_address = 'Sander Roosendaal '
d = {'first_name':theuser.first_name}
-
+
send_template_email(from_address,[fullemail],
subject,'registeremail.html',d)
-
+
subject2 = "New User"
message2 = "New user registered.\n"
@@ -550,7 +550,7 @@ def rower_register_view(request):
theuser = authenticate(username=username,password=password)
login(request,theuser)
-
+
return HttpResponseRedirect(nextpage)
# '/rowers/register/thankyou/')
@@ -572,7 +572,7 @@ def freecoach_register_view(request):
nextpage = request.GET.get('next','/rowers/me/teams/')
if nextpage == '':
nextpage = '/rowers/me/teams/'
-
+
if request.method == 'POST':
#form = RegistrationFormUniqueEmail(request.POST)
form = RegistrationFormSex(request.POST)
@@ -605,17 +605,17 @@ def freecoach_register_view(request):
# create default favorite charts
add_defaultfavorites(therower)
-
+
# Create and send email
fullemail = first_name + " " + last_name + " " + "<" + email + ">"
subject = "Thank you for registering on rowsandall.com"
from_address = 'Sander Roosendaal '
d = {'first_name':theuser.first_name}
-
+
send_template_email(from_address,[fullemail],
subject,'coachregisteremail.html',d)
-
+
subject2 = "New Free Coach"
message2 = "New Free Coach registered.\n"
@@ -628,7 +628,7 @@ def freecoach_register_view(request):
theuser = authenticate(username=username,password=password)
login(request,theuser)
-
+
return HttpResponseRedirect(nextpage)
else:
@@ -647,6 +647,7 @@ def freecoach_register_view(request):
'next':nextpage,})
@login_required()
+@permission_required('rower.is_staff',fn=get_user_by_userid,raise_exception=True)
def transactions_view(request):
if not request.user.is_staff:
raise PermissionDenied("Not Allowed")
@@ -662,7 +663,7 @@ def transactions_view(request):
response = HttpResponse(df.to_csv())
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
response['Content-Type'] = 'application/octet-stream'
-
+
return response
else:
@@ -673,4 +674,3 @@ def transactions_view(request):
{
'dateform':dateform
})
-
diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py
index 2548c41f..b5ec6dad 100644
--- a/rowers/views/planviews.py
+++ b/rowers/views/planviews.py
@@ -685,7 +685,9 @@ def plannedsession_teamcreate_view(request,
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
- return HttpResponseRedirect(url)
+ next = request.GET.get('next', url)
+
+ return HttpResponseRedirect(next)
else:
timeperiod = startdate.strftime('%Y-%m-%d')+'/'+enddate.strftime('%Y-%m-%d')
breadcrumbs = [
@@ -873,8 +875,8 @@ def plannedsession_teamedit_view(request,
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
-
- return HttpResponseRedirect(url)
+ next = request.GET.get('next', url)
+ return HttpResponseRedirect(next)
else:
sessioncreateform = PlannedSessionForm(instance=ps)
sessionteamselectform = PlannedSessionTeamForm(
@@ -1436,8 +1438,8 @@ def plannedsession_clone_view(request,id=0,userid=0):
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
-
- return HttpResponseRedirect(url)
+ next = request.GET.get('next', url)
+ return HttpResponseRedirect(next)
# Clone an existing planned session
# need clarity on cloning behavior time shift
@@ -1497,8 +1499,102 @@ def plannedsession_teamclone_view(request,id=0):
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
+ next = request.GET.get('next', url)
+ return HttpResponseRedirect(next)
+
+@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True)
+@user_passes_test(can_plan, login_url="/rowers/paidplans/",
+message="This functionality requires a Coach or Self-Coach plan",
+redirect_field_name=None)
+def plannedsession_templateedit_view(request,id=0):
+ r = getrequestrower(request)
+ startdate,enddate = get_dates_timeperiod(request)
+ try:
+ trainingplan = TrainingPlan.objects.filter(
+ startdate__lte = startdate,
+ rowers = r,
+ enddate__gte = enddate)[0]
+ except IndexError:
+ trainingplan = None
+
+ try:
+ ps = PlannedSession.objects.get(id=id)
+ except PlannedSession.DoesNotExist:
+ raise Http404("Planned Session does not exist")
+
+ if ps.manager != request.user:
+ raise PermissionDenied("You are not allowed to edit this planned session")
+
+ if ps.sessiontype in ['race','indoorrace']:
+ raise PermissionDenied("You are not allowed to edit this planned session because it is a race")
+
+ if not ps.is_template:
+ ps.pk = None
+ ps.id = None
+ ps.is_template = True
+ ps.startdate = datetime.date(1970,1,1)
+ ps.enddate = datetime.date(1970,1,1)
+ ps.team.clear()
+ ps.save()
+
+ sessioncreateform = PlannedSessionTemplateForm(instance=ps)
+
+ if request.method == 'POST':
+ sessioncreateform = PlannedSessionTemplateForm(request.POST,instance=ps)
+ if sessioncreateform.is_valid():
+ cd = sessioncreateform.cleaned_data
+ if cd['sessionunit'] == 'min':
+ cd['sessionmode'] = 'time'
+ elif cd['sessionunit'] in ['km','m']:
+ cd['sessionmode'] = 'distance'
+
+ res, message = update_plannedsession(ps,cd)
+
+ if res:
+ messages.info(request,message)
+ else:
+ messages.error(request,message)
+
+ url = reverse(plannedsession_templateedit_view,
+ kwargs = {
+ 'id':int(ps.id),
+ })
+
+ startdatestring = startdate.strftime('%Y-%m-%d')
+ enddatestring = enddate.strftime('%Y-%m-%d')
+ url += '?when='+startdatestring+'/'+enddatestring
+ next = request.GET.get('next', url)
+ return HttpResponseRedirect(next)
+
+ breadcrumbs = [
+ {
+ 'url': reverse(plannedsessions_view),
+ 'name': 'Sessions'
+ },
+ {
+ 'url':reverse(plannedsession_templateedit_view,
+ kwargs={
+ 'id':id,
+ }
+ ),
+ 'name': 'Edit'
+ }
+ ]
+
+ sessiontemplates = PlannedSession.objects.filter(manager=request.user,is_template=True)
+
+ return render(request,'plannedsessiontemplateedit.html',
+ {
+ 'teams':get_my_teams(request.user),
+ 'plan': trainingplan,
+ 'breadcrumbs': breadcrumbs,
+ 'form': sessioncreateform,
+ 'active':'nav-plan',
+ 'thesession': ps,
+ 'sessiontemplates': sessiontemplates,
+ 'rower': r,
+ })
- return HttpResponseRedirect(url)
@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True)
@user_passes_test(can_plan, login_url="/rowers/paidplans/",
@@ -1525,7 +1621,9 @@ def plannedsession_totemplate_view(request,id=0):
enddatestring = enddate.strftime('%Y-%m-%d')
url += '?when='+startdatestring+'/'+enddatestring
- return HttpResponseRedirect(url)
+ next = request.GET.get('next', url)
+
+ return HttpResponseRedirect(next)
# Edit an existing planned session
@permission_required('plannedsession.change_session',fn=get_session_by_pk,raise_exception=True)
@@ -1663,8 +1761,8 @@ def plannedsession_detach_view(request,id=0,psid=0):
remove_workout_plannedsession(w,ps)
url = reverse(plannedsession_view,kwargs={'id':psid})
-
- return HttpResponseRedirect(url)
+ next = request.GET.get('next', url)
+ return HttpResponseRedirect(next)
@login_required()
@permission_required('plannedsession.view_session',fn=get_session_by_pk,raise_exception=True)
@@ -1892,8 +1990,9 @@ class PlannedSessionDelete(DeleteView):
w.save()
url = reverse(plannedsessions_view)
+ next = self.request.GET.get('next',url)
- return url
+ return next
def get_object(self, *args, **kwargs):
obj = super(PlannedSessionDelete, self).get_object(*args, **kwargs)
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index 19deb0cf..e6a6e7e6 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -120,7 +120,7 @@ from rowers.models import (
WorkoutComment,WorkoutCommentForm,RowerExportForm,
CalcAgePerformance,
PowerTimeFitnessMetric,BlogPost,
- PlannedSessionForm,
+ PlannedSessionForm,PlannedSessionTemplateForm,
PlannedSessionFormSmall,GeoCourseEditForm,VirtualRace,
VirtualRaceForm,VirtualRaceResultForm,RowerImportExportForm,
IndoorVirtualRaceResultForm,IndoorVirtualRaceResult,
diff --git a/rowers/views/userviews.py b/rowers/views/userviews.py
index d3f4903d..d82f5b47 100644
--- a/rowers/views/userviews.py
+++ b/rowers/views/userviews.py
@@ -5,6 +5,31 @@ from __future__ import unicode_literals
from rowers.views.statements import *
+@login_required()
+def survey(request):
+
+ r = getrower(request.user)
+
+ surveyform = SurveyForm()
+
+ if request.method == 'POST':
+ form = SurveyForm(request.POST)
+ r.surveydone = True
+ r.surveydonedate = timezone.now()
+ r.save()
+
+ nexturl = request.GET.get('next')
+ return HttpResponseRedirect(nexturl)
+
+ context = {
+ 'teams':get_my_teams(request.user),
+ 'rower':r,
+ 'form':surveyform,
+ }
+
+
+ return render(request,'survey.html',context)
+
@login_required()
def start_trial_view(request):
r = getrower(request.user)
diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py
index 376f563e..a52d31e4 100644
--- a/rowers/views/workoutviews.py
+++ b/rowers/views/workoutviews.py
@@ -386,21 +386,18 @@ def workout_video_create_view(request,id=0):
@user_passes_test(ispromember,login_url="/rowers/paidplans/",
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
redirect_field_name=None)
+@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_forcecurve_view(request,id=0,workstrokesonly=False):
row = get_workout(id)
promember=0
mayedit=0
- if not request.user.is_anonymous:
- r = getrower(request.user)
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
- if request.user == row.user.user:
- mayedit=1
- if not promember:
- return HttpResponseRedirect("/rowers/about/")
+ r = getrequestrower(request)
+ promember = 1
+
+ if r == row.user:
+ mayedit = 1
if request.method == 'POST':
form = ForceCurveOptionsForm(request.POST)
@@ -503,21 +500,15 @@ def otw_use_gps(request,id=0):
# Show Stroke power histogram for a workout
@login_required()
+@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_histo_view(request,id=0):
w = get_workout(id)
+ r = getrequestrower(request)
+ promember = 1
- promember=0
mayedit=0
- if not request.user.is_anonymous:
- r = getrower(request.user)
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
- if request.user == w.user.user:
- mayedit=1
-
- if not promember:
- return HttpResponseRedirect("/rowers/about/")
+ if w.user == r:
+ mayedit = 1
res = interactive_histoall([w],'power',False)
script = res[0]
@@ -745,6 +736,7 @@ def fitness_metric_view(request,mode='rower',days=42):
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
+@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
@user_passes_test(ispromember,login_url="/rowers/paidplans",
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
redirect_field_name=None)
@@ -854,6 +846,7 @@ defaultoptions = {
@user_passes_test(ispromember, login_url="/rowers/paidplans",
message="This functionality requires a Pro plan or higher",
redirect_field_name=None)
+@permission_required('rower.is_coach',fn=get_user_by_userid,raise_exception=True)
def video_selectworkout(request,userid=0,teamid=0):
r = getrequestrower(request, userid=userid)
user = r.user
@@ -1975,17 +1968,15 @@ def workouts_view(request,message='',successmessage='',
@user_passes_test(ispromember,login_url="/rowers/paidplans",
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
redirect_field_name=None)
-def workout_fusion_list(request,id=0,message='',successmessage='',
+@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
+def workout_fusion_list(request,id=0,
startdatestring="",enddatestring="",
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now()):
- try:
- r = getrower(request.user)
- except Rower.DoesNotExist:
- raise Http404("User has no rower instance")
+ r = getrequestrower(request)
- u = User.objects.get(id=r.user.id)
+ u = r.user
if request.method == 'POST':
dateform = DateRangeForm(request.POST)
if dateform.is_valid():
@@ -2013,6 +2004,8 @@ def workout_fusion_list(request,id=0,message='',successmessage='',
if id:
theid = encoder.decode_hex(id)
+ w = get_workout(id)
+ r = w.user
workouts = Workout.objects.filter(user=r,
startdatetime__gte=startdate,
@@ -2042,8 +2035,6 @@ def workout_fusion_list(request,id=0,message='',successmessage='',
workouts = paginator.page(paginator.num_pages)
row = get_workout(id)
- messages.info(request,successmessage)
- messages.error(request,message)
breadcrumbs = [
{
@@ -2618,7 +2609,9 @@ def workout_stream_view(request,id=0,message="",successmessage=""):
rowdata = rdata(f1)
if rowdata == 0:
- return HttpResponse("Error: CSV Data File Not Found")
+ messages.info(request,"Error: CSV data file not found")
+ url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(row.id)})
+ return HttpResponseRedirect(url)
if request.method == 'POST':
# process form
@@ -3710,14 +3703,12 @@ def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
# r = getrower(u)
promember=0
- mayedit=0
- if not request.user.is_anonymous:
- r = getrower(request.user)
- result = request.user.is_authenticated and ispromember(request.user)
- if result:
- promember=1
- if request.user == w.user.user:
- mayedit=1
+ mayedit = 0
+ result = request.user.is_authenticated and ispromember(request.user)
+ if result:
+ promember=1
+ if request.user == w.user.user:
+ mayedit=1
# create interactive plot
res = interactive_otw_advanced_pace_chart(encoder.decode_hex(id),promember=promember)
@@ -5062,46 +5053,45 @@ def list_videos(request):
})
@login_required()
-def graphs_view(request):
+def graphs_view(request,userid=0):
request.session['referer'] = reverse('graphs_view')
+ r = getrequestrower(request,userid=userid)
+ workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
+ query = request.GET.get('q')
+ if query:
+ query_list = query.split()
+ workouts = workouts.filter(
+ reduce(operator.and_,
+ (Q(name__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()
+
+ g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
+
+
+ paginator = Paginator(g,8)
+ page = request.GET.get('page')
+
try:
- r = getrower(request.user)
- workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
- query = request.GET.get('q')
- if query:
- query_list = query.split()
- workouts = workouts.filter(
- reduce(operator.and_,
- (Q(name__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()
+ g = paginator.page(page)
+ except PageNotAnInteger:
+ g = paginator.page(1)
+ except EmptyPage:
+ g = paginator.page(paginator.num_pages)
- g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
-
-
- paginator = Paginator(g,8)
- page = request.GET.get('page')
-
- try:
- g = paginator.page(page)
- except PageNotAnInteger:
- g = paginator.page(1)
- except EmptyPage:
- g = paginator.page(paginator.num_pages)
-
- return render(request, 'list_graphs.html',
+ return render(request, 'list_graphs.html',
{'graphs': g,
'searchform':searchform,
'active':'nav-workouts',
'teams':get_my_teams(request.user),
+ 'rower':r,
})
- except Rower.DoesNotExist:
- raise Http404("User has no rower instance")
+
# Show the chart (png image)
def graph_show_view(request,id):