diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py index e5646ac9..5f5979bc 100644 --- a/rowers/c2stuff.py +++ b/rowers/c2stuff.py @@ -7,7 +7,7 @@ from rowers.imports import * import datetime from requests import Request, Session -from rowers.types import otwtypes +from rowers.mytypes import otwtypes from iso8601 import ParseError from rowsandall_app.settings import ( diff --git a/rowers/dataprep.py b/rowers/dataprep.py index a23f3eda..70537eeb 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -74,7 +74,7 @@ queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('default') from rowsandall_app.settings import SITE_URL -from rowers.types import otwtypes +from rowers.mytypes import otwtypes from rowers.database import * diff --git a/rowers/decorators.py b/rowers/decorators.py new file mode 100644 index 00000000..3d356dd2 --- /dev/null +++ b/rowers/decorators.py @@ -0,0 +1,46 @@ +from django.contrib.auth.decorators import login_required,user_passes_test + +from django.http import HttpResponseRedirect +from django.core.exceptions import PermissionDenied +from django.utils.decorators import available_attrs +from django.contrib import messages + +try: + from functools import wraps +except ImportError: + from django.utils.functional import wraps + + +REDIRECT_FIELD_NAME = None + +default_message = "Please log in, in order to see the requested page." + +def user_passes_test(test_func, message=default_message,login_url=None,redirect_field_name=None): + """ + Decorator for views that checks that the user passes the given test, + setting a message in case of no success. The test should be a callable + that takes the user object and returns True if the user passes. + """ + def decorator(view_func): + @wraps(view_func, assigned=available_attrs(view_func)) + def _wrapped_view(request, *args, **kwargs): + if not test_func(request.user): + messages.error(request, message) + return HttpResponseRedirect(login_url) + return view_func(request, *args, **kwargs) + return _wrapped_view + return decorator + +def login_required_message(function=None, message=default_message): + """ + Decorator for views that checks that the user is logged in, redirecting + to the log-in page if necessary. + """ + actual_decorator = user_passes_test( + lambda u: u.is_authenticated(), + message=message, + ) + if function: + return actual_decorator(function) + return actual_decorator + diff --git a/rowers/forms.py b/rowers/forms.py index 834494fb..d9d6e39b 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -9,7 +9,7 @@ from django.forms.extras.widgets import SelectDateWidget from django.utils import timezone,translation from django.forms import ModelForm, Select import dataprep -import types +import mytypes import datetime from django.forms import formset_factory from utils import landingpages @@ -83,7 +83,7 @@ class DocumentsForm(forms.Form): choices=Workout.workouttypes) boattype = forms.ChoiceField(required=True, - choices=types.boattypes, + choices=mytypes.boattypes, label = "Boat Type") @@ -589,8 +589,8 @@ class IntervalUpdateForm(forms.Form): self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;' self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f') -boattypes = types.boattypes -workouttypes = types.workouttypes +boattypes = mytypes.boattypes +workouttypes = mytypes.workouttypes ww = list(workouttypes) ww.append(tuple(('all','All'))) workouttypes = tuple(ww) @@ -616,7 +616,7 @@ class TrendFlexModalForm(forms.Form): initial='all') waterboattype = forms.MultipleChoiceField(choices=boattypes, label='Water Boat Type', - initial = types.waterboattype) + initial = mytypes.waterboattype) rankingonly = forms.BooleanField(initial=False, label='Only Ranking Pieces', required=False) @@ -631,14 +631,14 @@ class StatsOptionsForm(forms.Form): waterboattype = forms.MultipleChoiceField(choices=boattypes, label='Water Boat Type', widget=forms.CheckboxSelectMultiple(), - initial = types.waterboattype) + initial = mytypes.waterboattype) def __init__(self, *args, **kwargs): super(StatsOptionsForm, self).__init__(*args,**kwargs) - for type in types.checktypes: + for type in mytypes.checktypes: self.fields[type] = forms.BooleanField(initial=True,required=False) @@ -807,8 +807,8 @@ class WorkoutSessionSelectForm(forms.Form): class RaceResultFilterForm(forms.Form): - boatclasses = (type for type in types.workouttypes if type[0] in types.otwtypes) - boatclassinitial = [t for t in types.otwtypes] + boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otwtypes) + boatclassinitial = [t for t in mytypes.otwtypes] sexchoices = ( ('female','Female'), ('male','Male'), @@ -836,7 +836,7 @@ class RaceResultFilterForm(forms.Form): boattype = forms.MultipleChoiceField( choices=boattypes, label='Boat Type', - initial=types.waterboattype, + initial=mytypes.waterboattype, widget=forms.CheckboxSelectMultiple()) age_min = forms.IntegerField(label='Min Age',initial=16) diff --git a/rowers/imports.py b/rowers/imports.py index c1e150cc..70f765c0 100644 --- a/rowers/imports.py +++ b/rowers/imports.py @@ -38,7 +38,7 @@ from django.contrib.auth.decorators import login_required from rowingdata import rowingdata, make_cumvalues import pandas as pd from rowers.models import Rower,Workout,checkworkoutuser -from rowers import types +from rowers import mytypes from rowsandall_app.settings import ( C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, diff --git a/rowers/middleware.py b/rowers/middleware.py index 495ad436..9a44b7fe 100644 --- a/rowers/middleware.py +++ b/rowers/middleware.py @@ -5,7 +5,7 @@ from utils import myqueue import django_rq queue = django_rq.get_queue('default') from rowers.tasks import handle_updatefitnessmetric -from rowers.types import otwtypes +from rowers.mytypes import otwtypes def getrower(user): try: diff --git a/rowers/models.py b/rowers/models.py index ffdb668e..4d968e96 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -34,7 +34,7 @@ from rowers.rows import validate_file_extension from collections import OrderedDict from timezonefinder import TimezoneFinder -import types +import mytypes from matplotlib import path from rowsandall_app.settings import ( @@ -1990,13 +1990,13 @@ class PlannedSessionFormSmall(ModelForm): 'manager': forms.HiddenInput(), } -boattypes = types.boattypes +boattypes = mytypes.boattypes # Workout class Workout(models.Model): - workouttypes = types.workouttypes - workoutsources = types.workoutsources - privacychoices = types.privacychoices + workouttypes = mytypes.workouttypes + workoutsources = mytypes.workoutsources + privacychoices = mytypes.privacychoices user = models.ForeignKey(Rower) team = models.ManyToManyField(Team,blank=True) @@ -2121,7 +2121,7 @@ def auto_delete_strokedata_on_delete(sender, instance, **kwargs): # Virtual Race results (for keeping results when workouts are deleted) class VirtualRaceResult(models.Model): - boatclasses = (type for type in types.workouttypes if type[0] in types.otwtypes) + boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otwtypes) userid = models.IntegerField(default=0) teamname = models.CharField(max_length=80,verbose_name = 'Team Name', blank=True,null=True) diff --git a/rowers/types.py b/rowers/mytypes.py similarity index 100% rename from rowers/types.py rename to rowers/mytypes.py diff --git a/rowers/templates/analysis.html b/rowers/templates/analysis.html index 121e38ef..8fd8ef83 100644 --- a/rowers/templates/analysis.html +++ b/rowers/templates/analysis.html @@ -37,11 +37,7 @@
  • Power Histogram

    - {% if user|is_promember %} - {% else %} - - {% endif %}
    Power Histogram
    @@ -52,11 +48,7 @@
  • Statistics

    - {% if user|is_promember %}
    - {% else %} - - {% endif %}
    Statistics
    @@ -67,11 +59,7 @@
  • Box Chart

    - {% if user|is_promember %}
    - {% else %} - - {% endif %}
    Box Chart
    @@ -83,11 +71,7 @@
  • OTW Critical Power

    - {% if user|is_promember %}
    - {% else %} - - {% endif %}
    OTW Critical Power
    @@ -98,11 +82,7 @@
  • OTE Critical Power

    - {% if user|is_promember %}
    - {% else %} - - {% endif %}
    OTE Critical Power
    @@ -114,11 +94,7 @@
  • Trend Flex

    - {% if user|is_promember %}
    - {% else %} - - {% endif %}
    Trend Flex
    @@ -130,11 +106,7 @@
  • Power Progress

    - {% if user|is_planmember %}
    - {% else %} - - {% endif %}
    Power Progress
    diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 38cfc83d..9456bded 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -20,7 +20,7 @@ from rowers import c2stuff, runkeeperstuff from rowers.c2stuff import c2_open from rowers.runkeeperstuff import runkeeper_open -from rowers.types import otwtypes +from rowers.mytypes import otwtypes from rowers.utils import NoTokenError def strfdelta(tdelta): diff --git a/rowers/uploads.py b/rowers/uploads.py index d871d870..676e481c 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -26,7 +26,7 @@ queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') -from types import workouttypes,boattypes,otwtypes +from mytypes import workouttypes,boattypes,otwtypes try: from cStringIO import StringIO diff --git a/rowers/urls.py b/rowers/urls.py index 59b9f769..cf4ff1fd 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -397,6 +397,7 @@ urlpatterns = [ url(r'^analysis/$', views.analysis_view,name='analysis'), url(r'^laboratory/$', views.laboratory_view,name='laboratory'), url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'), + url(r'^planrequired',views.planrequired_view), url(r'^starttrial$',views.start_trial_view), url(r'^startplantrial$',views.start_plantrial_view), # url(r'^planmembership', TemplateView.as_view(template_name='planmembership.html'),name='planmembership'), diff --git a/rowers/views.py b/rowers/views.py index de0a49d6..846ff465 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -98,7 +98,8 @@ import rowers.uploads as uploads from django.forms.formsets import formset_factory from django.forms import modelformset_factory import StringIO -from django.contrib.auth.decorators import login_required,user_passes_test +from django.contrib.auth.decorators import login_required #,user_passes_test +from rowers.decorators import user_passes_test from time import strftime,strptime,mktime,time,daylight import os,sys import datetime @@ -161,7 +162,7 @@ from scipy.signal import savgol_filter from django.shortcuts import render_to_response from Cookie import SimpleCookie from shutil import copyfile,move -import types +import mytypes from rowingdata import rower as rrower from rowingdata import main as rmain from rowingdata import rowingdata as rrdata @@ -630,7 +631,7 @@ def get_thumbnails(request,id): aantalcomments = len(comments) workouttype = 'ote' - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: workouttype = 'otw' try: @@ -2475,7 +2476,7 @@ def cum_flex_data( 'includereststrokes':False, 'rankingonly':False, 'modality':'all', - 'waterboattype':types.waterboattype, + 'waterboattype':mytypes.waterboattype, 'theuser':0, 'xparam':'spm', 'yparam1':'power', @@ -2504,7 +2505,7 @@ def cum_flex_data( enddatestring = keyvalue_get_default('enddatestring',options,def_options) if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] @@ -2579,7 +2580,7 @@ def histo_data( 'includereststrokes':False, 'rankingonly':False, 'modality':'all', - 'waterboattype':types.waterboattype, + 'waterboattype':mytypes.waterboattype, 'theuser':0, 'enddatestring':'', 'startdatestring':'', @@ -2602,7 +2603,7 @@ def histo_data( enddatestring = keyvalue_get_default('enddatestring',options,def_options) if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] @@ -2679,8 +2680,8 @@ def cum_flex(request,theuser=0, enddatestring="", options={ 'includereststrokes':False, - 'workouttypes':[i[0] for i in types.workouttypes], - 'waterboattype':types.waterboattype, + 'workouttypes':[i[0] for i in mytypes.workouttypes], + 'waterboattype':mytypes.waterboattype, 'rankingonly':False, }): @@ -2691,7 +2692,7 @@ def cum_flex(request,theuser=0, if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if 'rankingonly' in request.session: @@ -2706,7 +2707,7 @@ def cum_flex(request,theuser=0, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' @@ -2723,7 +2724,7 @@ def cum_flex(request,theuser=0, workstrokesonly = not includereststrokes - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if startdatestring != "": @@ -2757,12 +2758,12 @@ def cum_flex(request,theuser=0, waterboattype = modalityform.cleaned_data['waterboattype'] rankingonly = modalityform.cleaned_data['rankingonly'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] request.session['modalities'] = modalities @@ -2799,7 +2800,7 @@ def cum_flex(request,theuser=0, flexaxesform = FlexAxesForm(request,initial=initial) negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -2861,7 +2862,13 @@ def cum_flex(request,theuser=0, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", +def planrequired_view(request): + messages.info(request,"This functionality requires Coach or Self-Coach membership") + + return render(request,'promembership.html') + +@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", + message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def fitnessmetric_view(request,id=0,mode='rower', startdate=timezone.now()-timezone.timedelta(days=365), @@ -2904,6 +2911,7 @@ def fitnessmetric_view(request,id=0,mode='rower', # Show the EMpower Oarlock generated Stroke Profile @user_passes_test(ispromember,login_url="/rowers/promembership/", + message="This functionality requires a Pro plan or higher", redirect_field_name=None) def workout_forcecurve_view(request,id=0,workstrokesonly=False): row = get_workout(id) @@ -3034,7 +3042,9 @@ def workout_histo_view(request,id=0): # Histogram for a date/time range -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def histo(request,theuser=0, startdate=timezone.now()-datetime.timedelta(days=365), enddate=timezone.now(), @@ -3043,8 +3053,8 @@ def histo(request,theuser=0, enddatestring="", options={ 'includereststrokes':False, - 'workouttypes':[i[0] for i in types.workouttypes], - 'waterboattype':types.waterboattype, + 'workouttypes':[i[0] for i in mytypes.workouttypes], + 'waterboattype':mytypes.waterboattype, 'rankingonly': False, }): @@ -3054,7 +3064,7 @@ def histo(request,theuser=0, if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if 'rankingonly' in request.session: @@ -3069,7 +3079,7 @@ def histo(request,theuser=0, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' @@ -3086,7 +3096,7 @@ def histo(request,theuser=0, workstrokesonly = not includereststrokes - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if startdatestring != "": @@ -3119,12 +3129,12 @@ def histo(request,theuser=0, waterboattype = modalityform.cleaned_data['waterboattype'] rankingonly = modalityform.cleaned_data['rankingonly'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] request.session['modalities'] = modalities @@ -3151,7 +3161,7 @@ def histo(request,theuser=0, ) negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -4090,7 +4100,9 @@ def rankings_view2(request,theuser=0, 'teams':get_my_teams(request.user), }) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_update_cp_view(request,id=0): row = get_workout(id) @@ -4108,7 +4120,7 @@ def workout_update_cp_view(request,id=0): dataprep.runcpupdate(r) - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: url = reverse(otwrankings_view) else: url = reverse(oterankings_view) @@ -4116,7 +4128,9 @@ def workout_update_cp_view(request,id=0): return HttpResponseRedirect(url) # Show ranking distances including predicted paces -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def otwrankings_view(request,theuser=0, startdate=timezone.now()-datetime.timedelta(days=365), enddate=timezone.now(), @@ -4519,7 +4533,9 @@ def otwcp_toadmin_view(request,theuser=0, return response # Show ranking distances including predicted paces -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def oterankings_view(request,theuser=0, startdate=timezone.now()-datetime.timedelta(days=365), enddate=timezone.now(), @@ -4950,7 +4966,9 @@ def workout_setprivate_view(request,id, return HttpResponseRedirect(url) # Joining workout -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workouts_join_view(request): promember=0 if not request.user.is_anonymous(): @@ -4994,7 +5012,9 @@ def workouts_join_view(request): url = reverse(workouts_join_select) return HttpResponseRedirect(url) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workouts_join_select(request, startdatestring="", enddatestring="", @@ -5013,7 +5033,7 @@ def workouts_join_select(request, if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if 'modalities' in request.session: @@ -5023,7 +5043,7 @@ def workouts_join_select(request, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' if request.method == 'POST' and 'daterange' in request.POST: @@ -5048,19 +5068,19 @@ def workouts_join_select(request, modality = modalityform.cleaned_data['modality'] waterboattype = modalityform.cleaned_data['waterboattype'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] request.session['modalities'] = modalities request.session['waterboattype'] = waterboattype negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -5166,7 +5186,7 @@ def team_comparison_select(request, if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if 'rankingonly' in request.session: rankingonly = request.session['rankingonly'] @@ -5180,7 +5200,7 @@ def team_comparison_select(request, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' if request.method == 'POST': @@ -5198,12 +5218,12 @@ def team_comparison_select(request, modality = modalityform.cleaned_data['modality'] waterboattype = modalityform.cleaned_data['waterboattype'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] if 'rankingonly' in modalityform.cleaned_data: @@ -5228,7 +5248,7 @@ def team_comparison_select(request, negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -5451,7 +5471,9 @@ def multi_compare_view(request): return HttpResponseRedirect(url) # Multi Flex Chart with Grouping -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def user_multiflex_select(request, startdatestring="", enddatestring="", @@ -5494,7 +5516,7 @@ def user_multiflex_select(request, waterboattype = request.session['waterboattype'] else: - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if 'rankingonly' in request.session: rankingonly = request.session['rankingonly'] @@ -5509,7 +5531,7 @@ def user_multiflex_select(request, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' if request.method == 'POST': @@ -5527,12 +5549,12 @@ def user_multiflex_select(request, waterboattype = modalityform.cleaned_data['waterboattype'] rankingonly = modalityform.cleaned_data['rankingonly'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] request.session['modalities'] = modalities @@ -5561,7 +5583,7 @@ def user_multiflex_select(request, negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -5649,7 +5671,9 @@ def user_multiflex_select(request, 'teams':get_my_teams(request.user), }) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def multiflex_data(request,userid=0, options={ 'includereststrokes':False, @@ -5880,7 +5904,9 @@ def multiflex_data(request,userid=0, }) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def multiflex_view(request,userid=0, options={ 'includereststrokes':False, @@ -6045,7 +6071,9 @@ def multiflex_view(request,userid=0, # Box plots -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def user_boxplot_select(request, startdatestring="", enddatestring="", @@ -6056,7 +6084,7 @@ def user_boxplot_select(request, options={ 'includereststrokes':False, 'workouttypes':['rower','dynamic','slides'], - 'waterboattype':types.waterboattype, + 'waterboattype':mytypes.waterboattype, 'rankingonly':False, }, userid=0): @@ -6093,7 +6121,7 @@ def user_boxplot_select(request, workstrokesonly = not includereststrokes - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if startdatestring != "": @@ -6122,11 +6150,11 @@ def user_boxplot_select(request, modality = optionsform.cleaned_data['modality'] waterboattype = optionsform.cleaned_data['waterboattype'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] if 'rankingonly' in optionsform.cleaned_data: @@ -6149,14 +6177,14 @@ def user_boxplot_select(request, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -6176,7 +6204,7 @@ def user_boxplot_select(request, startdate = s negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -6188,7 +6216,7 @@ def user_boxplot_select(request, ).order_by( "-date", "-starttime" ).exclude(boattype__in=negtypes) - # workouttypes = [w for w in workouttypes if w not in types.otwtypes] + # workouttypes = [w for w in workouttypes if w not in mytypes.otwtypes] if rankingonly: workouts = [w for w in workouts if w.rankingpiece] @@ -6247,7 +6275,9 @@ def user_boxplot_select(request, 'teams':get_my_teams(request.user), }) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def boxplot_view_data(request,userid=0, options={ 'includereststrokes':False, @@ -6344,7 +6374,9 @@ def boxplot_view_data(request,userid=0, "div":div, }) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def boxplot_view(request,userid=0, options={ 'includereststrokes':False, @@ -6645,7 +6677,9 @@ def workouts_view(request,message='',successmessage='', # List of workouts to compare a selected workout to -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_comparison_list(request,id=0,message='',successmessage='', startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), @@ -6725,7 +6759,9 @@ def workout_comparison_list(request,id=0,message='',successmessage='', # List of workouts to compare a selected workout to -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_fusion_list(request,id=0,message='',successmessage='', startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), @@ -6917,7 +6953,9 @@ def workout_view(request,id=0): # Resets stroke data to raw data (pace) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_undo_smoothenpace_view( request,id=0,message="",successmessage="" ): @@ -6954,7 +6992,9 @@ def workout_undo_smoothenpace_view( # Data smoothing of pace data -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_smoothenpace_view(request,id=0,message="",successmessage=""): row = get_workout(id) @@ -7003,7 +7043,9 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""): return HttpResponseRedirect(url) # Process CrewNerd Summary CSV and update summary -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): row = get_workout(id) r = getrower(request.user) @@ -7078,7 +7120,9 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): 'id':row.id}) # Get weather for given location and date/time -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership", + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def workout_downloadwind_view(request,id=0, airportcode=None, message="",successmessage=""): @@ -7144,7 +7188,7 @@ def workout_downloadwind_view(request,id=0, return response # Get weather for given location and date/time -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_downloadmetar_view(request,id=0, airportcode=None, message="",successmessage=""): @@ -7211,7 +7255,7 @@ def workout_downloadmetar_view(request,id=0, # Show form to update wind data -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_wind_view(request,id=0,message="",successmessage=""): row = get_workout(id) r = getrower(request.user) @@ -7347,7 +7391,7 @@ def workout_wind_view(request,id=0,message="",successmessage=""): # Show form to update River stream data (for river dwellers) -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_stream_view(request,id=0,message="",successmessage=""): row = get_workout(id) r = getrower(request.user) @@ -7668,7 +7712,7 @@ def workout_geeky_view(request,id=0,message="",successmessage=""): messages.error(request,message) messages.info(request,successmessage) - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: return render(request, 'otwgeeky.html', {'workout':row, @@ -7742,7 +7786,7 @@ def instroke_chart(request,id=0,metric=''): return HttpResponseRedirect(url) # Cumulative stats page -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def cumstats(request,theuser=0, startdate=timezone.now()-datetime.timedelta(days=30), enddate=timezone.now(), @@ -7752,7 +7796,7 @@ def cumstats(request,theuser=0, options={ 'includereststrokes':False, 'workouttypes':['rower','dynamic','slides'], - 'waterboattype':types.waterboattype, + 'waterboattype':mytypes.waterboattype, 'rankingonly':False, }): @@ -7762,7 +7806,7 @@ def cumstats(request,theuser=0, if 'waterboattype' in request.session: waterboattype = request.session['waterboattype'] else: - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if 'rankingonly' in request.session: @@ -7777,7 +7821,7 @@ def cumstats(request,theuser=0, else: modality = modalities[0] else: - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] modality = 'all' @@ -7794,7 +7838,7 @@ def cumstats(request,theuser=0, workstrokesonly = not includereststrokes - waterboattype = types.waterboattype + waterboattype = mytypes.waterboattype if startdatestring != "": @@ -7829,12 +7873,12 @@ def cumstats(request,theuser=0, waterboattype = modalityform.cleaned_data['waterboattype'] rankingonly = modalityform.cleaned_data['rankingonly'] if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] if modality != 'water': - waterboattype = [b[0] for b in types.boattypes] + waterboattype = [b[0] for b in mytypes.boattypes] request.session['modalities'] = modalities @@ -7861,7 +7905,7 @@ def cumstats(request,theuser=0, ) negtypes = [] - for b in types.boattypes: + for b in mytypes.boattypes: if b[0] not in waterboattype: negtypes.append(b[0]) @@ -7887,7 +7931,7 @@ def cumstats(request,theuser=0, if modality == 'all': - modalities = [m[0] for m in types.workouttypes] + modalities = [m[0] for m in mytypes.workouttypes] else: modalities = [modality] @@ -8347,7 +8391,7 @@ def workout_advanced_view(request,id=0,message="",successmessage=""): messages.info(request,successmessage) - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: return render(request, 'advancedotw.html', {'workout':row, @@ -8620,7 +8664,7 @@ def workout_workflow_view(request,id): aantalcomments = len(comments) workouttype = 'ote' - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: workouttype = 'otw' try: @@ -8730,7 +8774,7 @@ def workout_flexchart3_view(request,*args,**kwargs): mayedit=1 workouttype = 'ote' - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: workouttype = 'otw' try: @@ -8904,7 +8948,7 @@ def workout_flexchart3_view(request,*args,**kwargs): noylist = ["time","distance"] axchoicesbasic.pop("cumdist") - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: for name,d in rowingmetrics: if d['mode'] == 'erg': axchoicespro.pop(name) @@ -11507,7 +11551,7 @@ def workout_summary_restore_view(request,id,message="",successmessage=""): r.pw_tr,r.pw_an])/r.ftp ftp = float(r.ftp) - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: ftp = ftp*(100.-r.otwslack)/100. rr = rrower(hrmax=r.max,hrut2=r.ut2, @@ -11542,7 +11586,7 @@ def workout_summary_restore_view(request,id,message="",successmessage=""): return HttpResponseRedirect(url) # Split a workout -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_split_view(request,id=id): row = get_workout_permitted(request.user,id) @@ -11633,7 +11677,7 @@ def workout_split_view(request,id=id): # Fuse two workouts -@user_passes_test(ispromember,login_url="/rowers/promembership",redirect_field_name=None) +@user_passes_test(ispromember,login_url="/rowers/promembership",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def workout_fusion_view(request,id1=0,id2=1): r = getrower(request.user) @@ -11746,7 +11790,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" r.pw_tr,r.pw_an])/r.ftp ftp = float(r.ftp) - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: ftp = ftp*(100.-r.otwslack)/100. rr = rrower(hrmax=r.max,hrut2=r.ut2, @@ -13038,7 +13082,7 @@ def strokedatajson(request,id): r.pw_tr,r.pw_an])/r.ftp ftp = float(r.ftp) - if row.workouttype in types.otwtypes: + if row.workouttype in mytypes.otwtypes: ftp = ftp*(100.-r.otwslack)/100. rr = rrower(hrmax=r.max,hrut2=r.ut2, @@ -13755,6 +13799,7 @@ def agegrouprecordview(request,sex='male',weightcategory='hwt', # Cloning sessions @user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", + message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_multiclone_view( request, @@ -13867,6 +13912,7 @@ def plannedsession_multiclone_view( # Individual user creates training for himself @user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", + message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_create_view(request, userid=0): @@ -14000,6 +14046,7 @@ def plannedsession_create_view(request, }) @user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", + message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_multicreate_view(request, teamid=0,userid=0,extrasessions=0): @@ -14709,6 +14756,7 @@ def plannedsessions_manage_view(request,userid=0, # Clone an existing planned session # need clarity on cloning behavior time shift @user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", + message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_clone_view(request,id=0,userid=0): @@ -14772,6 +14820,7 @@ def plannedsession_clone_view(request,id=0,userid=0): # Edit an existing planned session @user_passes_test(hasplannedsessions,login_url="/rowers/promembership/", + message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_edit_view(request,id=0,userid=0): @@ -15281,12 +15330,12 @@ def virtualevent_view(request,id=0): try: boattype = cd['boattype'] except KeyError: - boattype = types.waterboattype + boattype = mytypes.waterboattype try: boatclass = cd['boatclass'] except KeyError: - boatclass = [t for t in types.otwtypes] + boatclass = [t for t in mytypes.otwtypes] age_min = cd['age_min'] age_max = cd['age_max'] @@ -15403,7 +15452,7 @@ def virtualevent_addboat_view(request,id=0): boattypes = [record.boattype for record in records] boatclasses = [record.boatclass for record in records] - allowedboats = tuple([ type for type in types.boattypes if type[0] not in boattypes] ) + allowedboats = tuple([ type for type in mytypes.boattypes if type[0] not in boattypes] ) # we're still here @@ -15908,7 +15957,9 @@ def virtualevent_submit_result_view(request,id=0): 'w_form':w_form, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", redirect_field_name=None) +@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", + message="This functionality requires a Coach or Self-Coach plan", + redirect_field_name=None) def rower_create_trainingplan(request,userid=0): therower = getrequestrower(request,userid=userid) @@ -15979,7 +16030,9 @@ def rower_create_trainingplan(request,userid=0): 'targetform':targetform, }) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", redirect_field_name=None) +@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", + message="This functionality requires a Coach or Self-Coach plan", + redirect_field_name=None) def rower_delete_trainingtarget(request,id=0): try: target = TrainingTarget.objects.get(id=id) @@ -15997,7 +16050,9 @@ def rower_delete_trainingtarget(request,id=0): return HttpResponseRedirect(url) -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", redirect_field_name=None) +@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", + message="This functionality requires a Coach or Self-Coach plan", + redirect_field_name=None) def rower_delete_trainingplan(request,id=0): try: plan = TrainingPlan.objects.get(id=id) @@ -16224,6 +16279,7 @@ class WorkoutDelete(DeleteView): ] mayedit=0 + promember=0 if not self.request.user.is_anonymous(): r = getrower(self.request.user) result = self.request.user.is_authenticated() and ispromember(self.request.user) @@ -16306,7 +16362,9 @@ class MacroCycleDelete(DeleteView): return obj -@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", redirect_field_name=None) +@user_passes_test(hasplannedsessions,login_url="/rowers/promembership", + message="This functionality requires a Coach or Self-Coach plan", + redirect_field_name=None) def rower_trainingplan_view(request, id=0, userid=0,