Merge branch 'release/v9.91'
This commit is contained in:
+13
-9
@@ -8,13 +8,13 @@ atomicwrites==1.3.0
|
|||||||
attrs==19.1.0
|
attrs==19.1.0
|
||||||
backcall==0.1.0
|
backcall==0.1.0
|
||||||
beautifulsoup4==4.7.1
|
beautifulsoup4==4.7.1
|
||||||
billiard==3.5.0.5
|
billiard==3.6.0.0
|
||||||
bleach==3.1.0
|
bleach==3.1.0
|
||||||
bokeh==1.0.4
|
bokeh==1.0.4
|
||||||
boto==2.49.0
|
boto==2.49.0
|
||||||
braintree==3.51.0
|
braintree==3.51.0
|
||||||
cairocffi==1.0.2
|
cairocffi==1.0.2
|
||||||
celery==4.2.2
|
celery==4.3.0
|
||||||
certifi==2019.3.9
|
certifi==2019.3.9
|
||||||
cffi==1.12.2
|
cffi==1.12.2
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
@@ -46,9 +46,10 @@ django-leaflet==0.24.0
|
|||||||
django-mailbox==4.7.1
|
django-mailbox==4.7.1
|
||||||
django-oauth-toolkit==1.2.0
|
django-oauth-toolkit==1.2.0
|
||||||
django-oauth2-provider==0.2.6.1
|
django-oauth2-provider==0.2.6.1
|
||||||
|
django-redis==4.10.0
|
||||||
django-rest-framework==0.1.0
|
django-rest-framework==0.1.0
|
||||||
django-rest-swagger==2.2.0
|
django-rest-swagger==2.2.0
|
||||||
django-rq==2.0
|
django-rq==1.3.1
|
||||||
django-rq-dashboard==0.3.3
|
django-rq-dashboard==0.3.3
|
||||||
django-ses==0.8.10
|
django-ses==0.8.10
|
||||||
django-shell-plus==1.1.7
|
django-shell-plus==1.1.7
|
||||||
@@ -66,7 +67,9 @@ Faker==1.0.4
|
|||||||
fitparse==1.1.0
|
fitparse==1.1.0
|
||||||
Flask==1.0.2
|
Flask==1.0.2
|
||||||
future==0.17.1
|
future==0.17.1
|
||||||
|
GDAL==2.3.3
|
||||||
geocoder==1.38.1
|
geocoder==1.38.1
|
||||||
|
geos==0.2.1
|
||||||
holoviews==1.11.3
|
holoviews==1.11.3
|
||||||
html5lib==1.0.1
|
html5lib==1.0.1
|
||||||
htmlmin==0.1.12
|
htmlmin==0.1.12
|
||||||
@@ -96,7 +99,7 @@ jupyterlab==0.35.4
|
|||||||
jupyterlab-server==0.3.0
|
jupyterlab-server==0.3.0
|
||||||
keyring==18.0.0
|
keyring==18.0.0
|
||||||
kiwisolver==1.0.1
|
kiwisolver==1.0.1
|
||||||
kombu==4.3.0
|
kombu==4.5.0
|
||||||
lxml==4.3.2
|
lxml==4.3.2
|
||||||
Markdown==3.0.1
|
Markdown==3.0.1
|
||||||
MarkupSafe==1.1.1
|
MarkupSafe==1.1.1
|
||||||
@@ -129,9 +132,9 @@ pip-upgrader==1.4.6
|
|||||||
pluggy==0.9.0
|
pluggy==0.9.0
|
||||||
prometheus-client==0.6.0
|
prometheus-client==0.6.0
|
||||||
prompt-toolkit==2.0.9
|
prompt-toolkit==2.0.9
|
||||||
|
psycopg2==2.8.1
|
||||||
ptyprocess==0.6.0
|
ptyprocess==0.6.0
|
||||||
py==1.8.0
|
py==1.8.0
|
||||||
pycairo==1.18.0
|
|
||||||
pycparser==2.19
|
pycparser==2.19
|
||||||
Pygments==2.3.1
|
Pygments==2.3.1
|
||||||
pyparsing==2.3.1
|
pyparsing==2.3.1
|
||||||
@@ -157,10 +160,9 @@ ratelim==0.1.6
|
|||||||
redis==3.2.1
|
redis==3.2.1
|
||||||
requests==2.21.0
|
requests==2.21.0
|
||||||
requests-oauthlib==1.2.0
|
requests-oauthlib==1.2.0
|
||||||
rowingdata==2.3.1
|
rowingdata==2.3.8
|
||||||
rowingphysics==0.5.0
|
rowingphysics==0.5.0
|
||||||
rq==1.0
|
rq==0.13.0
|
||||||
rq-dashboard==0.4.0
|
|
||||||
scipy==1.2.1
|
scipy==1.2.1
|
||||||
SecretStorage==3.1.1
|
SecretStorage==3.1.1
|
||||||
Send2Trash==1.5.0
|
Send2Trash==1.5.0
|
||||||
@@ -188,8 +190,10 @@ VerbalExpressions==0.0.2
|
|||||||
vine==1.3.0
|
vine==1.3.0
|
||||||
wcwidth==0.1.7
|
wcwidth==0.1.7
|
||||||
webencodings==0.5.1
|
webencodings==0.5.1
|
||||||
Werkzeug==0.15.2
|
Werkzeug==0.15.1
|
||||||
widgetsnbextension==3.4.2
|
widgetsnbextension==3.4.2
|
||||||
|
winkerberos==0.7.0
|
||||||
|
xlrd==1.2.0
|
||||||
xmltodict==0.12.0
|
xmltodict==0.12.0
|
||||||
yamjam==0.1.7
|
yamjam==0.1.7
|
||||||
yamllint==1.15.0
|
yamllint==1.15.0
|
||||||
|
|||||||
@@ -241,7 +241,6 @@ def create_subscription(rower,data):
|
|||||||
"payment_method_nonce": nonce_from_the_client
|
"payment_method_nonce": nonce_from_the_client
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
if result.is_success:
|
if result.is_success:
|
||||||
payment_method_token = result.payment_method.token
|
payment_method_token = result.payment_method.token
|
||||||
else:
|
else:
|
||||||
@@ -252,6 +251,7 @@ def create_subscription(rower,data):
|
|||||||
"plan_id": plan.external_id
|
"plan_id": plan.external_id
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
if result.is_success:
|
if result.is_success:
|
||||||
rower.paidplan = plan
|
rower.paidplan = plan
|
||||||
rower.planexpires = result.subscription.billing_period_end_date
|
rower.planexpires = result.subscription.billing_period_end_date
|
||||||
|
|||||||
+6
-3
@@ -3,6 +3,8 @@ from __future__ import division
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# All the data preparation, data cleaning and data mangling should
|
# All the data preparation, data cleaning and data mangling should
|
||||||
# be defined here
|
# be defined here
|
||||||
from __future__ import unicode_literals, absolute_import
|
from __future__ import unicode_literals, absolute_import
|
||||||
@@ -28,6 +30,7 @@ from pandas import DataFrame, Series
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.timezone import get_current_timezone
|
from django.utils.timezone import get_current_timezone
|
||||||
from django_mailbox.models import Message,Mailbox,MessageAttachment
|
from django_mailbox.models import Message,Mailbox,MessageAttachment
|
||||||
|
from django.core.exceptions import ValidationError
|
||||||
|
|
||||||
from time import strftime
|
from time import strftime
|
||||||
import arrow
|
import arrow
|
||||||
@@ -1100,8 +1103,11 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
try:
|
try:
|
||||||
w.save()
|
w.save()
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
|
try:
|
||||||
w.startdatetime = timezone.now()
|
w.startdatetime = timezone.now()
|
||||||
w.save()
|
w.save()
|
||||||
|
except ValidationError:
|
||||||
|
return (0,'Unable to create your workout')
|
||||||
|
|
||||||
if privacy == 'visible':
|
if privacy == 'visible':
|
||||||
ts = Team.objects.filter(rower=r)
|
ts = Team.objects.filter(rower=r)
|
||||||
@@ -1189,7 +1195,6 @@ parsers = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
def parsenonpainsled(fileformat,f2,summary):
|
def parsenonpainsled(fileformat,f2,summary):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
row = parsers[fileformat](f2)
|
row = parsers[fileformat](f2)
|
||||||
hasrecognized = True
|
hasrecognized = True
|
||||||
@@ -1197,7 +1202,6 @@ def parsenonpainsled(fileformat,f2,summary):
|
|||||||
hasrecognized = False
|
hasrecognized = False
|
||||||
return None, hasrecognized, '', 'unknown'
|
return None, hasrecognized, '', 'unknown'
|
||||||
|
|
||||||
|
|
||||||
# handle speed coach GPS 2
|
# handle speed coach GPS 2
|
||||||
if (fileformat == 'speedcoach2'):
|
if (fileformat == 'speedcoach2'):
|
||||||
oarlength, inboard = get_empower_rigging(f2)
|
oarlength, inboard = get_empower_rigging(f2)
|
||||||
@@ -1211,7 +1215,6 @@ def parsenonpainsled(fileformat,f2,summary):
|
|||||||
except ZeroDivisionError:
|
except ZeroDivisionError:
|
||||||
summary = ''
|
summary = ''
|
||||||
|
|
||||||
|
|
||||||
# handle FIT
|
# handle FIT
|
||||||
if (fileformat == 'fit'):
|
if (fileformat == 'fit'):
|
||||||
try:
|
try:
|
||||||
|
|||||||
+3
-3
@@ -632,16 +632,16 @@ class RegistrationFormSex(RegistrationFormUniqueEmail):
|
|||||||
raise forms.ValidationError('Must be at least 16 years old to register')
|
raise forms.ValidationError('Must be at least 16 years old to register')
|
||||||
return self.cleaned_data['birthdate']
|
return self.cleaned_data['birthdate']
|
||||||
|
|
||||||
sex = forms.ChoiceField(required=True,
|
sex = forms.ChoiceField(required=False,
|
||||||
choices=sexcategories,
|
choices=sexcategories,
|
||||||
initial='not specified',
|
initial='not specified',
|
||||||
label='Sex')
|
label='Sex')
|
||||||
|
|
||||||
weightcategory = forms.ChoiceField(label='Weight Category',
|
weightcategory = forms.ChoiceField(label='Weight Category',
|
||||||
choices=weightcategories)
|
choices=weightcategories,initial='hwt',required=False)
|
||||||
|
|
||||||
adaptiveclass = forms.ChoiceField(label='Adaptive Classification',
|
adaptiveclass = forms.ChoiceField(label='Adaptive Classification',
|
||||||
choices=adaptivecategories)
|
choices=adaptivecategories,initial='None',required=False)
|
||||||
|
|
||||||
# def __init__(self, *args, **kwargs):
|
# def __init__(self, *args, **kwargs):
|
||||||
# self.fields['sex'].initial = 'not specified'
|
# self.fields['sex'].initial = 'not specified'
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ class RowerPlanMiddleWare(object):
|
|||||||
self.get_response = get_response
|
self.get_response = get_response
|
||||||
|
|
||||||
def __call__(self, request):
|
def __call__(self, request):
|
||||||
if request.user.is_authenticated and request.user.rower.rowerplan != 'basic':
|
if request.user.is_authenticated and request.user.rower.rowerplan not in ['basic','freecoach']:
|
||||||
if request.user.rower.paymenttype == 'single':
|
if request.user.rower.paymenttype == 'single':
|
||||||
if request.user.rower.planexpires < timezone.now().date():
|
if request.user.rower.planexpires < timezone.now().date():
|
||||||
messg = 'Your paid plan has expired. We have reset you to a free basic plan.'
|
messg = 'Your paid plan has expired. We have reset you to a free basic plan.'
|
||||||
|
|||||||
+12
-4
@@ -601,7 +601,8 @@ plans = (
|
|||||||
('basic','basic'),
|
('basic','basic'),
|
||||||
('pro','pro'),
|
('pro','pro'),
|
||||||
('plan','plan'),
|
('plan','plan'),
|
||||||
('coach','coach')
|
('coach','coach'),
|
||||||
|
('freecoach','freecoach'),
|
||||||
)
|
)
|
||||||
|
|
||||||
paymenttypes = (
|
paymenttypes = (
|
||||||
@@ -913,7 +914,7 @@ def check_teams_on_change(sender, **kwargs):
|
|||||||
team = Team.objects.get(id=id)
|
team = Team.objects.get(id=id)
|
||||||
if team.manager.rower.rowerplan not in ['coach']:
|
if team.manager.rower.rowerplan not in ['coach']:
|
||||||
raise ValidationError(
|
raise ValidationError(
|
||||||
"You cannot join a team led by a Pro or Self-Coach user"
|
"You cannot join a team led by a Pro, Free Coach Plan or Self-Coach user"
|
||||||
)
|
)
|
||||||
|
|
||||||
m2m_changed.connect(check_teams_on_change, sender=Rower.team.through)
|
m2m_changed.connect(check_teams_on_change, sender=Rower.team.through)
|
||||||
@@ -1074,7 +1075,7 @@ def checkaccessplanuser(user,rower):
|
|||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
if rower == r:
|
if rower == r:
|
||||||
return True
|
return True
|
||||||
team_managers = [t.manager for t in rower.team.all() if t.manager.rower.rowerplan in ['plan','coach']]
|
team_managers = [t.manager for t in rower.team.all() if t.manager.rower.rowerplan in ['plan','coach','freecoach']]
|
||||||
if user.rower.rowerplan != 'basic':
|
if user.rower.rowerplan != 'basic':
|
||||||
return user in team_managers
|
return user in team_managers
|
||||||
else:
|
else:
|
||||||
@@ -2576,6 +2577,13 @@ class Workout(models.Model):
|
|||||||
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
|
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
|
||||||
duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout')
|
duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout')
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
user = self.user
|
||||||
|
if self.user.rowerplan == 'freecoach':
|
||||||
|
raise forms.ValidationError("Free Coach User cannot have any workouts")
|
||||||
|
|
||||||
|
super(Workout, self).save(*args, **kwargs)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
|
||||||
date = self.date
|
date = self.date
|
||||||
@@ -3263,7 +3271,7 @@ class AccountRowerForm(ModelForm):
|
|||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
super(AccountRowerForm, self).__init__(*args, **kwargs)
|
super(AccountRowerForm, self).__init__(*args, **kwargs)
|
||||||
if self.instance.rowerplan != 'coach':
|
if 'coach' not in self.instance.rowerplan:
|
||||||
self.fields.pop('offercoaching')
|
self.fields.pop('offercoaching')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -465,12 +465,12 @@ def add_team_session(t,ps):
|
|||||||
def add_rower_session(r,ps):
|
def add_rower_session(r,ps):
|
||||||
teams = Team.objects.filter(manager=ps.manager)
|
teams = Team.objects.filter(manager=ps.manager)
|
||||||
members = Rower.objects.filter(team__in=teams).distinct()
|
members = Rower.objects.filter(team__in=teams).distinct()
|
||||||
if r in members:
|
if r in members and r.rowerplan != 'freecoach':
|
||||||
ps.rower.add(r)
|
ps.rower.add(r)
|
||||||
ps.save()
|
ps.save()
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
elif ps.manager.rower == r:
|
elif ps.manager.rower == r and r.rowerplan != 'freecoach':
|
||||||
ps.rower.add(r)
|
ps.rower.add(r)
|
||||||
ps.save()
|
ps.save()
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -77,7 +77,7 @@ def create_team(name,manager,private='open',notes='',viewing='allmembers'):
|
|||||||
if manager.rower.rowerplan == 'basic':
|
if manager.rower.rowerplan == 'basic':
|
||||||
if manager.rower.protrialexpires < timezone.now().date() and manager.rower.plantrialexpires < timezone.now().date():
|
if manager.rower.protrialexpires < timezone.now().date() and manager.rower.plantrialexpires < timezone.now().date():
|
||||||
return (0,'You need to upgrade to a paid plan to establish a team')
|
return (0,'You need to upgrade to a paid plan to establish a team')
|
||||||
if manager.rower.rowerplan != 'coach':
|
if manager.rower.rowerplan not in ('coach','freecoach'):
|
||||||
ts = Team.objects.filter(manager=manager)
|
ts = Team.objects.filter(manager=manager)
|
||||||
if len(ts)>=1:
|
if len(ts)>=1:
|
||||||
return (0,'You need to upgrade to the Coach plan to have more than one team')
|
return (0,'You need to upgrade to the Coach plan to have more than one team')
|
||||||
@@ -180,7 +180,7 @@ def rower_get_coaches(rower):
|
|||||||
|
|
||||||
|
|
||||||
def coach_getcoachees(coach):
|
def coach_getcoachees(coach):
|
||||||
if coach.mycoachgroup and coach.rowerplan == 'coach':
|
if coach.mycoachgroup and coach.rowerplan in ('coach','freecoach'):
|
||||||
return Rower.objects.filter(
|
return Rower.objects.filter(
|
||||||
coachinggroups__in=[coach.mycoachgroup]
|
coachinggroups__in=[coach.mycoachgroup]
|
||||||
).distinct().order_by("user__last_name","user__first_name")
|
).distinct().order_by("user__last_name","user__first_name")
|
||||||
@@ -237,7 +237,7 @@ def create_coaching_request(coach,user):
|
|||||||
while code in codes:
|
while code in codes:
|
||||||
code = uuid.uuid4().hex[:10].upper()
|
code = uuid.uuid4().hex[:10].upper()
|
||||||
|
|
||||||
if coach.rowerplan == 'coach':
|
if 'coach' in coach.rowerplan:
|
||||||
rekwest = CoachRequest(coach=coach,user=user,code=code)
|
rekwest = CoachRequest(coach=coach,user=user,code=code)
|
||||||
rekwest.save()
|
rekwest.save()
|
||||||
|
|
||||||
@@ -316,7 +316,7 @@ def create_coaching_offer(coach,user):
|
|||||||
while code in codes:
|
while code in codes:
|
||||||
code = uuid.uuid4().hex[:10].upper()
|
code = uuid.uuid4().hex[:10].upper()
|
||||||
|
|
||||||
if coach.rowerplan == 'coach' and get_coach_club_size(coach)<coach.clubsize:
|
if 'coach' in coach.rowerplan and get_coach_club_size(coach)<coach.clubsize:
|
||||||
rekwest = CoachOffer(coach=coach,user=user,code=code)
|
rekwest = CoachOffer(coach=coach,user=user,code=code)
|
||||||
rekwest.save()
|
rekwest.save()
|
||||||
|
|
||||||
@@ -597,7 +597,7 @@ def process_request_code(manager,code):
|
|||||||
if rekwest.team.manager != manager:
|
if rekwest.team.manager != manager:
|
||||||
return (0,'You are not the manager of this team')
|
return (0,'You are not the manager of this team')
|
||||||
|
|
||||||
result = add_member(t.id,r)
|
result,comment = add_member(t.id,r)
|
||||||
if not result:
|
if not result:
|
||||||
return (result,"The member couldn't be added")
|
return (result,"The member couldn't be added")
|
||||||
|
|
||||||
@@ -622,7 +622,7 @@ def process_invite_code(user,code):
|
|||||||
return (0,'The invitation has expired')
|
return (0,'The invitation has expired')
|
||||||
|
|
||||||
t = invitation.team
|
t = invitation.team
|
||||||
result = add_member(t.id,r)
|
result, comment = add_member(t.id,r)
|
||||||
if not result:
|
if not result:
|
||||||
return (result,"The member couldn't be added")
|
return (result,"The member couldn't be added")
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{% extends "emailbase.html" %}
|
||||||
|
|
||||||
|
{% block body %}
|
||||||
|
<p>Dear <strong>{{ first_name }}</strong>,</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thank you for registering on rowsandall.com.
|
||||||
|
You can now login using the credentials you provided.
|
||||||
|
The first thing you should do is go to the
|
||||||
|
<a href="https://rowsandall.com/rowers/me/edit/">Settings page</a>
|
||||||
|
and make yourself familiar with the various options
|
||||||
|
available to personalize your experience on the website.
|
||||||
|
To get there, use the link in the email or click the user icon
|
||||||
|
in the upper right corner of the opening page.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As a new member on the free coach plan, you can start with your first training
|
||||||
|
group and invite athletes to join it.
|
||||||
|
For more information about training groups and managing athletes, please read
|
||||||
|
our explanation at
|
||||||
|
<a href="https://analytics.rowsandall.com/2019/02/24/managing-a-rowing-training-group-coaching-and-remote-coaching-on-rowsandall-com/">https://analytics.rowsandall.com/2019/02/24/managing-a-rowing-training-group-coaching-and-remote-coaching-on-rowsandall-com/</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
As long as you are on the free coach plan, you can only managing athletes who are
|
||||||
|
on one of the paid plans. To remove this limitation, upgrade to one of the paid
|
||||||
|
coaching plans:
|
||||||
|
<a href="https://rowsandall.com/rowers/paidplans">https://rowsandall.com/rowers/paidplans</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Oh, one more thing. The site is
|
||||||
|
developing fast. Bear with us. Don't hesitate to
|
||||||
|
contact me at info@rowsandall.com if anything is broken
|
||||||
|
or doesn't seem to work as advertised.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Best Regards, the Rowsandall Team
|
||||||
|
</p>
|
||||||
|
{% endblock %}
|
||||||
@@ -0,0 +1,79 @@
|
|||||||
|
{% extends "newbase.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% block title %}New Coach Registration{% endblock title %}
|
||||||
|
{% block meta %}
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
{% block main %}
|
||||||
|
<ul class="main-content">
|
||||||
|
<li class="grid_4">
|
||||||
|
<h1>New Coach Registration (free Coach Plan)</h1>
|
||||||
|
</li>
|
||||||
|
<li class="rounder grid_2">
|
||||||
|
<a href="/rowers/coachregister">
|
||||||
|
<h1>Register as a coach (free)</h1>
|
||||||
|
<p>Click here and fill out the form to start with a free Coach plan. This allows you
|
||||||
|
to manage up to 10 athletes (who have to be on the Pro plan). You cannot upload your own
|
||||||
|
workouts.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
From this free plan, you can upgrade to any of the paid plans, including coach plans for larger
|
||||||
|
athlete groups or rower plans for managing your own training plan and workouts.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="rounder grid_2">
|
||||||
|
<a href="/rowers/register">
|
||||||
|
<h1>Register as an athlete (free)</h1>
|
||||||
|
<p>Click here and fill out the form to start with a free Athlete plan. This allows you
|
||||||
|
to store and analyze your own workouts.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
From this free plan, you can upgrade to any of the paid plans, including
|
||||||
|
coach plans for managing larger athlete groups or rower plans for expanded
|
||||||
|
analytics.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
<div id="registrationform">
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<table width=100%>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
<a href="/rowers/legal/">Terms of Service</a>
|
||||||
|
<input type="hidden" name="next" value="{{ next }}"/>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="grid_2">
|
||||||
|
|
||||||
|
<p> To use rowsandall, you need to register and agree with the Terms of Service. </p>
|
||||||
|
<p> Registration is free. </p>
|
||||||
|
|
||||||
|
<p>Some of our advanced services only work if you give us your
|
||||||
|
(approximate) birth date, sex and weight category, with 72.5 kg the
|
||||||
|
bounday between heavies and lighties for men, and 59 kg for women.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>Also, we are restricting access to the site to 16 years and older
|
||||||
|
because of EU data protection regulations.</p>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock main %}
|
||||||
|
|
||||||
|
{% block sidebar %}
|
||||||
|
{% include 'menu_help.html' %}
|
||||||
|
{% endblock %}
|
||||||
@@ -1,6 +1,30 @@
|
|||||||
|
{% load leaflet_tags %}
|
||||||
|
{% load cookielaw_tags %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% load tz_detect %}
|
||||||
|
{% tz_detect %}
|
||||||
|
{% load analytical %}
|
||||||
|
{% block filters %}
|
||||||
|
{% endblock %}
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
<title>{% block title %}Rowsandall Rowing Data Analytics{% endblock %}</title>
|
||||||
|
{% block og_image %}
|
||||||
|
<meta property="og:image" content="https://rowsandall.com/static/img/logo_r.png" />
|
||||||
|
<meta property="og:image:secure_url" content="https://rowsandall.com/static/img/logo_r.png" />
|
||||||
|
{% endblock %}
|
||||||
|
<meta property="og:url" content="https://rowsandall.com{{ request.get_full_path }}" />
|
||||||
|
<meta property="fb:app_id" content="694685920739849" />
|
||||||
|
<meta property="og:title" content="{% block og_title %}Rowsandall{% endblock %}" />
|
||||||
|
<meta property="og:description" content="{% block og_description %}Rowsandall: Free Data and Analysis. For Rowers. By Rowers.{% endblock %}" />
|
||||||
|
<link rel="stylesheet" href="/static/css/resetnew.css" />
|
||||||
|
<link rel="stylesheet" href="/static/fontawesome/css/fontawesome.css">
|
||||||
|
<link rel="stylesheet" href="/static/fontawesome/css/all.css">
|
||||||
|
<link rel="stylesheet" href="/static/css/frontstyles.css">
|
||||||
|
<link rel="stylesheet" href="/static/css/text2.css" />
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
{% block image_src %}<link rel="image_src" href="static/img/logo7.png" />{% endblock %}
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<style>
|
<style>
|
||||||
body, html {
|
body, html {
|
||||||
@@ -10,6 +34,18 @@
|
|||||||
color: #777;
|
color: #777;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sticky {
|
||||||
|
position: fixed;
|
||||||
|
right: 0;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
padding: 5px;
|
||||||
|
z-index: 1;
|
||||||
|
height:65px;
|
||||||
|
width: 100%;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
.bgimg-1, .bgimg-2, .bgimg-3 {
|
.bgimg-1, .bgimg-2, .bgimg-3 {
|
||||||
position: relative;
|
position: relative;
|
||||||
opacity: 0.65;
|
opacity: 0.65;
|
||||||
@@ -26,12 +62,12 @@
|
|||||||
|
|
||||||
.bgimg-2 {
|
.bgimg-2 {
|
||||||
background-image: url("/static/img/MerijnSoeters-hr-8192.jpg");
|
background-image: url("/static/img/MerijnSoeters-hr-8192.jpg");
|
||||||
min-height: 400px;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.bgimg-3 {
|
.bgimg-3 {
|
||||||
background-image: url("/static/img/MerijnSoeters-hr-3282.jpg");
|
background-image: url("/static/img/MerijnSoeters-hr-3282.jpg");
|
||||||
min-height: 400px;
|
min-height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.caption {
|
.caption {
|
||||||
@@ -43,6 +79,36 @@
|
|||||||
color: #000;
|
color: #000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.register {
|
||||||
|
position: absolute;
|
||||||
|
opacity: 0.65;
|
||||||
|
top: 40%;
|
||||||
|
left: 0%;
|
||||||
|
text-align: center;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.signin {
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 5px;
|
||||||
|
right: 5px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: right;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.signin a {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
.caption span.border {
|
.caption span.border {
|
||||||
background-color: #111;
|
background-color: #111;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@@ -51,6 +117,13 @@
|
|||||||
letter-spacing: 10px;
|
letter-spacing: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.register .border {
|
||||||
|
background-color: #aaa;
|
||||||
|
color: #000;
|
||||||
|
padding: 18px;
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
letter-spacing: 5px;
|
letter-spacing: 5px;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
@@ -65,13 +138,40 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
{% analytical_head_bottom %}
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div class="sticky">
|
||||||
|
{% if not user.is_authenticated %}
|
||||||
|
<div class="signin">
|
||||||
|
<span><a href="/login/">Sign In </a></span>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<div class="signin">
|
||||||
|
<span><a href="/rowers/list-workouts/">Enter </a></span>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
<div class="logo">
|
||||||
|
<a href="/" title="Home">
|
||||||
|
<img src="/static/img/logo7.png"
|
||||||
|
alt="Rowsandall logo" height="55px">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<div class="bgimg-1">
|
<div class="bgimg-1">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<span class="border">SCROLL DOWN</span>
|
<span class="border">FREE DATA AND ANALYSIS. FOR ROWERS. BY ROWERS.</span>
|
||||||
</div>
|
</div>
|
||||||
|
{% if not user.is_authenticated %}
|
||||||
|
<div class="register">
|
||||||
|
<div class="border">
|
||||||
|
<p><a href="/rowers/register/">SIGN UP</a></p>
|
||||||
|
<p>Sign-up form goes here</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="color: #777;background-color:white;text-align:center;padding:50px 80px;text-align: justify;">
|
<div style="color: #777;background-color:white;text-align:center;padding:50px 80px;text-align: justify;">
|
||||||
@@ -96,33 +196,131 @@
|
|||||||
|
|
||||||
<div class="bgimg-2">
|
<div class="bgimg-2">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<span class="border" style="background-color:transparent;font-size:25px;color: #f7f7f7;">LESS HEIGHT</span>
|
<span class="border" style="background-color:transparent;font-size:25px;color:#000;">
|
||||||
|
For on-the-water and indoor rowing
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="position:relative;">
|
<div style="position:relative;">
|
||||||
<div style="color:#ddd;background-color:#282E34;text-align:center;padding:50px 80px;text-align: justify;">
|
<div style="color:#ddd;background-color:#282E34;text-align:center;padding:50px 80px;text-align: justify;">
|
||||||
<p>Some info goes here</p>
|
<h2>Testimonials</h2>
|
||||||
|
<p>"Check out @rowsandall as well - his site is really useful for dissecting rowing data, especially if you eventually get power/angles on the water - check out the articles in the blog - if you’re logging your ergs on C2logbook you can have a play dissecting the data" - Tom Carter</p>
|
||||||
|
<p>"Sander has made amazing tools for self-coaching or working with a coach."</p>
|
||||||
|
|
||||||
|
<p>“I just wanted to say that I absolutely love this website. I‘ve been
|
||||||
|
using my NK empower oarlock for about a month now, and I‘m really
|
||||||
|
excited to be able to better visualize my data.”</p>
|
||||||
|
<p> “I discovered rowsandall.com – which is brilliant.”</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bgimg-3">
|
<div class="bgimg-3">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<span class="border" style="background-color:transparent;font-size:25px;color: #f7f7f7;">SCROLL UP</span>
|
<span class="border">
|
||||||
|
Plan, execute, measure, adjust
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style="position:relative;">
|
<div style="position:relative;">
|
||||||
<div style="color:#ddd;background-color:#282E34;text-align:center;padding:50px 80px;text-align: justify;">
|
<div style="color:#ddd;background-color:#282E34;text-align:center;padding:50px 80px;text-align: justify;">
|
||||||
<p>Where does the login go?</p>
|
<h1>What we offer</h1>
|
||||||
|
|
||||||
|
<h2>Plan.</h2>
|
||||||
|
<p>We offer a fully integrated way for you or your coach to set up the goal you commit to, plan to
|
||||||
|
achieve it, and monitor plan versus execution based on time, distance, heart rate or power.</p>
|
||||||
|
|
||||||
|
<h2>Sync</h2>
|
||||||
|
<p>Maintain a consistent log for all your rowing (indoor and on the water) and sync your workouts
|
||||||
|
to popular tools as the Concept2 logbook, Strava, TrainingPeaks, SportTracks and others.</p>
|
||||||
|
|
||||||
|
<h2>Analyze</h2>
|
||||||
|
<p>Analyze your workouts with a consistent set of tools, developed by rowers for rowers.</p>
|
||||||
|
|
||||||
|
<h2>Compare</h2>
|
||||||
|
<p>Compare youre results between workouts and with other rowers in your team.</p>
|
||||||
|
|
||||||
|
<h2>Race</h2>
|
||||||
|
<p>Virtual regattas are an informal way to add a competitive element to your training
|
||||||
|
and can be used as a quick way to set up small regattas</p>
|
||||||
|
|
||||||
|
<h2>Coaching</h2>
|
||||||
|
<p>Rowsandall.com is the ideal platform for remote rowing coaching. As a coach, you can
|
||||||
|
easily manage your athletes, set up plans and monitor execution and technique</p>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bgimg-1">
|
<div class="bgimg-1">
|
||||||
<div class="caption">
|
<div class="caption">
|
||||||
<span class="border">COOL!</span>
|
<span class="border">Follow us on
|
||||||
|
<a href="https://twitter.com/rowsandall">
|
||||||
|
<i class="fab fa-twitter"></i>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.instagram.com/roosendaalsander/">
|
||||||
|
<i class="fab fa-instagram"></i>
|
||||||
|
</a>
|
||||||
|
<a href="https://analytics.rowsandall.com/">
|
||||||
|
<i class="fab fa-wordpress-simple"></i>
|
||||||
|
</a>
|
||||||
|
<a href="https://www.facebook.com/rowsandall">
|
||||||
|
<i class="fab fa-facebook"></i>
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<footer class="main-footer">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/help/">Help</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://analytics.rowsandall.com/">
|
||||||
|
Rowing Analytics Blog
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="https://www.facebook.com/rowsandall">
|
||||||
|
Rowing Data Facebook Group</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/email/">Contact</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/partners/">Partnering?</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/developers/">Developers Info</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/paidplans/">Paid Plans</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/legal/">Terms and Conditions</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="/rowers/legal/">Privacy Policy</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</footer>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -120,8 +120,8 @@
|
|||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th> Duration</th>
|
<th> Duration</th>
|
||||||
<th> Power (upper)</th>
|
<th> Power Estimate 1</th>
|
||||||
<th> Power</th>
|
<th> Power Estimate 2</th>
|
||||||
<tr>
|
<tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
|
|||||||
@@ -178,6 +178,8 @@
|
|||||||
<td>
|
<td>
|
||||||
{% if rower.rowerplan == 'coach' %}
|
{% if rower.rowerplan == 'coach' %}
|
||||||
<h3>COACH ({{ rower.paymenttype }})</h3>
|
<h3>COACH ({{ rower.paymenttype }})</h3>
|
||||||
|
{% elif rower.rowerplan == 'freecoach' %}
|
||||||
|
<h3>Free COACH</h3>
|
||||||
{% else %}
|
{% else %}
|
||||||
|
|
||||||
{% endif %}
|
{% endif %}
|
||||||
@@ -248,6 +250,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
|
{% elif rower and rower.rowerplan == 'freecoach' %}
|
||||||
|
<td colspan="3">
|
||||||
|
<button style="width:100%">
|
||||||
|
{% if user|existing_customer %}
|
||||||
|
<a href="/rowers/upgrade/">UPGRADE NOW</a>
|
||||||
|
{% else %}
|
||||||
|
<a href="/rowers/billing/">BUY NOW</a>
|
||||||
|
{% endif %}
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
{% elif rower and rower.rowerplan == 'pro' %}
|
{% elif rower and rower.rowerplan == 'pro' %}
|
||||||
<td> </td>
|
<td> </td>
|
||||||
<td colspan="2">
|
<td colspan="2">
|
||||||
@@ -298,6 +310,14 @@
|
|||||||
can purchase upgrades to "Pro" and "Self-Coach" plans.
|
can purchase upgrades to "Pro" and "Self-Coach" plans.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The Coach plans come in two versions: free and paid. On the free coach plan,
|
||||||
|
you can only have athletes who are on the PRO paid plans or higher, and you
|
||||||
|
cannot upload any workouts to your own account. On the paid
|
||||||
|
plans, your athletes can be on the free plan, and you have full access to the
|
||||||
|
site functionality for your own workouts and those of your athletes.
|
||||||
|
</p>
|
||||||
|
|
||||||
<p>If you would like to find a coach who helps you plan your training
|
<p>If you would like to find a coach who helps you plan your training
|
||||||
through rowsandall.com, contact me throught the contact form.</p>
|
through rowsandall.com, contact me throught the contact form.</p>
|
||||||
|
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
<a href="https://rowsandall.com/rowers/me/edit/">Settings page</a>
|
<a href="https://rowsandall.com/rowers/me/edit/">Settings page</a>
|
||||||
and make yourself familiar with the various options
|
and make yourself familiar with the various options
|
||||||
available to personalize your experience on the website.
|
available to personalize your experience on the website.
|
||||||
To get there, use the link in the email or click the button
|
To get there, use the link in the email or click the user icon
|
||||||
with your first name on it in the upper right corner of the opening page.
|
in the upper right corner of the opening page.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|||||||
@@ -6,8 +6,36 @@
|
|||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block main %}
|
{% block main %}
|
||||||
<h1>New User Registration</h1>
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
|
<li class="grid_4">
|
||||||
|
<h1>New User Registration</h1>
|
||||||
|
</li>
|
||||||
|
<li class="rounder grid_2">
|
||||||
|
<a href="/rowers/coachregister">
|
||||||
|
<h1>Register as a coach (free)</h1>
|
||||||
|
<p>Click here and fill out the form to start with a free Coach plan. This allows you
|
||||||
|
to manage up to 10 athletes (who have to be on the Pro plan). You cannot upload your own
|
||||||
|
workouts.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
From this free plan, you can upgrade to any of the paid plans, including coach plans for larger
|
||||||
|
athlete groups or rower plans for managing your own training plan and workouts.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li class="rounder grid_2">
|
||||||
|
<a href="/rowers/register">
|
||||||
|
<h1>Register as an athlete (free)</h1>
|
||||||
|
<p>Click here and fill out the form to start with a free Athlete plan. This allows you
|
||||||
|
to store and analyze your own workouts.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
From this free plan, you can upgrade to any of the paid plans, including
|
||||||
|
coach plans for managing larger athlete groups or rower plans for expanded
|
||||||
|
analytics.
|
||||||
|
</p>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
<li class="grid_2">
|
<li class="grid_2">
|
||||||
<div id="registrationform">
|
<div id="registrationform">
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from rowers.utils import calculate_age
|
|||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
course_length,WorkoutComment,
|
course_length,WorkoutComment,
|
||||||
TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle,
|
TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle,
|
||||||
Rower,Workout,SiteAnnouncement
|
Rower,Workout,SiteAnnouncement, TeamInvite, TeamRequest, CoachOffer,CoachRequest
|
||||||
)
|
)
|
||||||
from rowers.plannedsessions import (
|
from rowers.plannedsessions import (
|
||||||
race_can_register, race_can_submit,race_rower_status
|
race_can_register, race_can_submit,race_rower_status
|
||||||
@@ -51,6 +51,10 @@ def nogoals(user):
|
|||||||
date__gte=datetime.date.today())
|
date__gte=datetime.date.today())
|
||||||
return len(targets)==0
|
return len(targets)==0
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def notfree(rower):
|
||||||
|
return rower.rowerplan not in ['basic','freecoach']
|
||||||
|
|
||||||
def strfdelta(tdelta):
|
def strfdelta(tdelta):
|
||||||
minutes,seconds = divmod(tdelta.seconds,60)
|
minutes,seconds = divmod(tdelta.seconds,60)
|
||||||
tenths = int(tdelta.microseconds/1e5)
|
tenths = int(tdelta.microseconds/1e5)
|
||||||
@@ -327,7 +331,7 @@ def is_promember(user):
|
|||||||
@register.filter
|
@register.filter
|
||||||
def is_manager(user):
|
def is_manager(user):
|
||||||
r = Rower.objects.get(user=user)
|
r = Rower.objects.get(user=user)
|
||||||
return r.rowerplan == 'coach'
|
return 'coach' in r.rowerplan
|
||||||
|
|
||||||
from rowers.views import hasplannedsessions
|
from rowers.views import hasplannedsessions
|
||||||
@register.filter
|
@register.filter
|
||||||
@@ -385,13 +389,29 @@ def team_members(user):
|
|||||||
team__in=teams
|
team__in=teams
|
||||||
).distinct().order_by(
|
).distinct().order_by(
|
||||||
"user__last_name","user__first_name"
|
"user__last_name","user__first_name"
|
||||||
)
|
).exclude(rowerplan='freecoach')
|
||||||
return [rower.user for rower in members]
|
return [rower.user for rower in members]
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@register.filter
|
||||||
|
def openactions(user):
|
||||||
|
myteams = Team.objects.filter(manager=user)
|
||||||
|
|
||||||
|
invites = TeamInvite.objects.filter(user=user).count()
|
||||||
|
requests = TeamRequest.objects.filter(user=user).count()
|
||||||
|
myrequests = TeamRequest.objects.filter(team__in=myteams).count()
|
||||||
|
myinvites = TeamInvite.objects.filter(team__in=myteams).count()
|
||||||
|
mycoachoffers = CoachOffer.objects.filter(coach=user.rower).count()
|
||||||
|
coachoffers = CoachOffer.objects.filter(user=user).count()
|
||||||
|
mycoachrequests = CoachRequest.objects.filter(user=user).count()
|
||||||
|
coachrequests = CoachRequest.objects.filter(coach=user.rower).count()
|
||||||
|
|
||||||
|
return invites+requests+myrequests+myinvites+mycoachoffers+coachoffers+mycoachrequests+coachrequests
|
||||||
|
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def team_rowers(user):
|
def team_rowers(user):
|
||||||
try:
|
try:
|
||||||
@@ -401,7 +421,7 @@ def team_rowers(user):
|
|||||||
teams = Team.objects.filter(manager=user)
|
teams = Team.objects.filter(manager=user)
|
||||||
members = Rower.objects.filter(team__in=teams).distinct().order_by(
|
members = Rower.objects.filter(team__in=teams).distinct().order_by(
|
||||||
"user__last_name","user__last_name"
|
"user__last_name","user__last_name"
|
||||||
)
|
).exclude(rowerplan='freecoach')
|
||||||
return members
|
return members
|
||||||
except TypeError:
|
except TypeError:
|
||||||
return []
|
return []
|
||||||
@@ -412,7 +432,10 @@ from rowers.teams import coach_getcoachees
|
|||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def coach_rowers(user):
|
def coach_rowers(user):
|
||||||
|
if user.rower.rowerplan != 'freecoach':
|
||||||
thelist = [user.rower]+[c for c in coach_getcoachees(user.rower)]
|
thelist = [user.rower]+[c for c in coach_getcoachees(user.rower)]
|
||||||
|
else:
|
||||||
|
thelist = [c for c in coach_getcoachees(user.rower)]
|
||||||
return thelist
|
return thelist
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,183 @@ from django.db import transaction
|
|||||||
import rowers.teams as teams
|
import rowers.teams as teams
|
||||||
import rowers.plannedsessions as plannedsessions
|
import rowers.plannedsessions as plannedsessions
|
||||||
|
|
||||||
|
@override_settings(TESTING=True)
|
||||||
|
class PermissionsFreeCoach(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.c = Client()
|
||||||
|
## Users - Pro, Basic, Free Coach & Self Coach
|
||||||
|
|
||||||
|
self.ufreecoach = UserFactory(username='coachuser')
|
||||||
|
self.rfreecoach = Rower.objects.create(user=self.ufreecoach,
|
||||||
|
birthdate=faker.profile()['birthdate'],
|
||||||
|
gdproptin=True,gdproptindate=timezone.now(),
|
||||||
|
rowerplan='freecoach',clubsize=100)
|
||||||
|
|
||||||
|
self.coachinggroup = CoachingGroup.objects.create()
|
||||||
|
self.rfreecoach.mycoachgroup = self.coachinggroup
|
||||||
|
self.rfreecoach.save()
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.password = faker.word()
|
||||||
|
self.ufreecoach.set_password(self.password)
|
||||||
|
self.ufreecoach.save()
|
||||||
|
|
||||||
|
self.uplan = UserFactory(username='planuser')
|
||||||
|
self.rplan = Rower.objects.create(user=self.uplan,
|
||||||
|
birthdate=faker.profile()['birthdate'],
|
||||||
|
gdproptin=True,gdproptindate=timezone.now(),
|
||||||
|
rowerplan='plan')
|
||||||
|
|
||||||
|
self.uplan_workouts = WorkoutFactory.create_batch(5, user=self.rplan)
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.password = faker.word()
|
||||||
|
self.uplan.set_password(self.password)
|
||||||
|
self.uplan.save()
|
||||||
|
|
||||||
|
self.upro = UserFactory(username='prouser')
|
||||||
|
self.rpro = Rower.objects.create(user=self.upro,
|
||||||
|
birthdate=faker.profile()['birthdate'],
|
||||||
|
gdproptin=True,gdproptindate=timezone.now(),
|
||||||
|
rowerplan='pro')
|
||||||
|
|
||||||
|
self.upro_workouts = WorkoutFactory.create_batch(5, user=self.rpro)
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.password = faker.word()
|
||||||
|
self.upro.set_password(self.password)
|
||||||
|
self.upro.save()
|
||||||
|
|
||||||
|
self.uplan2 = UserFactory(username='planuser2')
|
||||||
|
self.rplan2 = Rower.objects.create(user=self.uplan2,
|
||||||
|
birthdate=faker.profile()['birthdate'],
|
||||||
|
gdproptin=True,gdproptindate=timezone.now(),
|
||||||
|
rowerplan='plan')
|
||||||
|
|
||||||
|
self.uplan2_workouts = WorkoutFactory.create_batch(5, user=self.rplan2)
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.password = faker.word()
|
||||||
|
self.uplan2.set_password(self.password)
|
||||||
|
self.uplan2.save()
|
||||||
|
|
||||||
|
self.upro2 = UserFactory(username='prouser2')
|
||||||
|
self.rpro2 = Rower.objects.create(user=self.upro2,
|
||||||
|
birthdate=faker.profile()['birthdate'],
|
||||||
|
gdproptin=True,gdproptindate=timezone.now(),
|
||||||
|
rowerplan='pro')
|
||||||
|
|
||||||
|
self.upro2_workouts = WorkoutFactory.create_batch(5, user=self.rpro2)
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.password = faker.word()
|
||||||
|
self.upro2.set_password(self.password)
|
||||||
|
self.upro2.save()
|
||||||
|
|
||||||
|
self.ubasic = UserFactory(username='basicuser')
|
||||||
|
self.rbasic = Rower.objects.create(user=self.ubasic,
|
||||||
|
birthdate=faker.profile()['birthdate'],
|
||||||
|
gdproptin=True,gdproptindate=timezone.now(),
|
||||||
|
rowerplan='basic')
|
||||||
|
|
||||||
|
self.ubasic_workouts = WorkoutFactory.create_batch(5, user=self.rbasic)
|
||||||
|
self.factory = RequestFactory()
|
||||||
|
self.ubasicpassword = faker.word()
|
||||||
|
self.ubasic.set_password(self.ubasicpassword)
|
||||||
|
self.ubasic.save()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## TeamFreeCoach
|
||||||
|
|
||||||
|
self.teamfreecoach = Team.objects.create(
|
||||||
|
name=faker.word()+'3',
|
||||||
|
notes=faker.text(),
|
||||||
|
manager=self.ufreecoach)
|
||||||
|
|
||||||
|
## Coach can have any number of groups
|
||||||
|
def test_coach_groupmanager(self):
|
||||||
|
team1 = Team.objects.create(
|
||||||
|
name = 'FirstTeam',
|
||||||
|
notes = faker.text(),
|
||||||
|
manager = self.ufreecoach,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(team1.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
team2 = Team.objects.create(
|
||||||
|
name = 'SecondTeam',
|
||||||
|
notes = faker.text(),
|
||||||
|
manager = self.ufreecoach,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(team2.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
|
||||||
|
team3 = Team.objects.create(
|
||||||
|
name = 'ThirdTeam',
|
||||||
|
notes = faker.text(),
|
||||||
|
manager = self.ufreecoach,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(team3.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Free coach can create more than one group
|
||||||
|
def test_plan_groupmanager(self):
|
||||||
|
team1 = Team.objects.create(
|
||||||
|
name = 'FirstTeam',
|
||||||
|
notes = faker.text(),
|
||||||
|
manager = self.ufreecoach,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(team1.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
team2 = Team.objects.create(
|
||||||
|
name = 'SecondTeam',
|
||||||
|
notes = faker.text(),
|
||||||
|
manager = self.ufreecoach,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(team2.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## Free Coach can create planned sessions and team planned sessions
|
||||||
|
## Self Coach and higher can create planned sessions and team planned sessions
|
||||||
|
def test_plan_create_session(self):
|
||||||
|
ps = PlannedSession.objects.create(
|
||||||
|
manager=self.ufreecoach,
|
||||||
|
name=faker.word(),
|
||||||
|
comment=faker.text()
|
||||||
|
)
|
||||||
|
self.assertEqual(ps.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
def test_coach_create_session(self):
|
||||||
|
ps = PlannedSession.objects.create(
|
||||||
|
manager=self.ufreecoach,
|
||||||
|
name=faker.word(),
|
||||||
|
comment=faker.text()
|
||||||
|
)
|
||||||
|
self.assertEqual(ps.manager,self.ufreecoach)
|
||||||
|
|
||||||
|
|
||||||
|
## Basic cannot join groups led by Free Coach
|
||||||
|
def test_add_basic_pro_or_plan(self):
|
||||||
|
with transaction.atomic():
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
self.rbasic.team.add(self.teamfreecoach)
|
||||||
|
|
||||||
|
|
||||||
|
## Free Coach user cannot have workouts
|
||||||
|
def test_add_workout_freecoach(self):
|
||||||
|
result = get_random_file(filename='rowers/tests/testdata/erg1.csv')
|
||||||
|
with transaction.atomic():
|
||||||
|
with self.assertRaises(ValidationError):
|
||||||
|
self.werg1 = WorkoutFactory(user=self.rfreecoach,
|
||||||
|
csvfilename=result['filename'],
|
||||||
|
starttime=result['starttime'],
|
||||||
|
startdatetime=result['startdatetime'],
|
||||||
|
duration=result['duration'],
|
||||||
|
distance=result['totaldist'],
|
||||||
|
workouttype = 'rower',
|
||||||
|
)
|
||||||
|
|
||||||
@override_settings(TESTING=True)
|
@override_settings(TESTING=True)
|
||||||
class PermissionsBasicsTests(TestCase):
|
class PermissionsBasicsTests(TestCase):
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -533,6 +533,7 @@ urlpatterns = [
|
|||||||
# re_path(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'),
|
# re_path(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'),
|
||||||
re_path(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
|
re_path(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
|
||||||
re_path(r'^register/$',views.rower_register_view,name='rower_register_view'),
|
re_path(r'^register/$',views.rower_register_view,name='rower_register_view'),
|
||||||
|
re_path(r'^coachregister/$',views.freecoach_register_view,name='freecoach_register_view'),
|
||||||
re_path(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
|
re_path(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
|
||||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/workflow/$',views.workout_workflow_view,
|
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/workflow/$',views.workout_workflow_view,
|
||||||
name='workout_workflow_view'),
|
name='workout_workflow_view'),
|
||||||
|
|||||||
@@ -566,6 +566,86 @@ def rower_register_view(request):
|
|||||||
{'form':form,
|
{'form':form,
|
||||||
'next':nextpage,})
|
'next':nextpage,})
|
||||||
|
|
||||||
|
# User registration
|
||||||
|
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)
|
||||||
|
if form.is_valid():
|
||||||
|
first_name = form.cleaned_data['first_name']
|
||||||
|
last_name = form.cleaned_data['last_name']
|
||||||
|
email = form.cleaned_data['email']
|
||||||
|
password = form.cleaned_data['password1']
|
||||||
|
username = form.cleaned_data['username']
|
||||||
|
sex = form.cleaned_data['sex']
|
||||||
|
birthdate = form.cleaned_data['birthdate']
|
||||||
|
weightcategory = form.cleaned_data['weightcategory']
|
||||||
|
adaptiveclass = form.cleaned_data['adaptiveclass']
|
||||||
|
nextpage = request.POST['next']
|
||||||
|
theuser = User.objects.create_user(username,password=password)
|
||||||
|
theuser.first_name = first_name
|
||||||
|
theuser.last_name = last_name
|
||||||
|
theuser.email = email
|
||||||
|
theuser.save()
|
||||||
|
|
||||||
|
birthdate = birthdate.replace(tzinfo=None)
|
||||||
|
|
||||||
|
therower = Rower(user=theuser,sex=sex,birthdate=birthdate,
|
||||||
|
weightcategory=weightcategory,
|
||||||
|
adaptiveclass=adaptiveclass,
|
||||||
|
rowerplan='freecoach',clubsize=10)
|
||||||
|
|
||||||
|
therower.save()
|
||||||
|
|
||||||
|
# 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 <info@rowsandall.com>'
|
||||||
|
|
||||||
|
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"
|
||||||
|
message2 += fullemail + "\n"
|
||||||
|
message2 += "User name: "+username
|
||||||
|
|
||||||
|
send_mail(subject2, message2,
|
||||||
|
'Rowsandall Server <info@rowsandall.com>',
|
||||||
|
['roosendaalsander@gmail.com'])
|
||||||
|
|
||||||
|
theuser = authenticate(username=username,password=password)
|
||||||
|
login(request,theuser)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(nextpage)
|
||||||
|
|
||||||
|
else:
|
||||||
|
return render(request,
|
||||||
|
"freecoach_registration_form.html",
|
||||||
|
{'form':form,
|
||||||
|
'next':nextpage,})
|
||||||
|
else:
|
||||||
|
form = RegistrationFormSex()
|
||||||
|
form.fields.pop('sex')
|
||||||
|
form.fields.pop('weightcategory')
|
||||||
|
form.fields.pop('adaptiveclass')
|
||||||
|
return render(request,
|
||||||
|
"freecoach_registration_form.html",
|
||||||
|
{'form':form,
|
||||||
|
'next':nextpage,})
|
||||||
|
|
||||||
@login_required()
|
@login_required()
|
||||||
def transactions_view(request):
|
def transactions_view(request):
|
||||||
if not request.user.is_staff:
|
if not request.user.is_staff:
|
||||||
|
|||||||
@@ -632,7 +632,7 @@ def plannedsession_teamcreate_view(request,
|
|||||||
request.session['teams'] = [team.id for team in teams]
|
request.session['teams'] = [team.id for team in teams]
|
||||||
for team in teams:
|
for team in teams:
|
||||||
add_team_session(team,ps)
|
add_team_session(team,ps)
|
||||||
rs = Rower.objects.filter(team__in=[team])
|
rs = Rower.objects.filter(team__in=[team]).exclude(rowerplan='freecoach')
|
||||||
for r in rs:
|
for r in rs:
|
||||||
add_rower_session(r,ps)
|
add_rower_session(r,ps)
|
||||||
|
|
||||||
@@ -904,7 +904,7 @@ def plannedsessions_coach_view(request,
|
|||||||
else:
|
else:
|
||||||
theteam = False
|
theteam = False
|
||||||
|
|
||||||
if request.user.rower.rowerplan == 'coach':
|
if 'coach' in request.user.rower.rowerplan:
|
||||||
sps = get_sessions_manager(request.user,teamid=teamid,
|
sps = get_sessions_manager(request.user,teamid=teamid,
|
||||||
enddate=enddate,
|
enddate=enddate,
|
||||||
startdate=startdate)
|
startdate=startdate)
|
||||||
@@ -912,12 +912,16 @@ def plannedsessions_coach_view(request,
|
|||||||
rteams = therower.team.filter(viewing='allmembers')
|
rteams = therower.team.filter(viewing='allmembers')
|
||||||
sps = get_sessions(therower,startdate=startdate,enddate=enddate)
|
sps = get_sessions(therower,startdate=startdate,enddate=enddate)
|
||||||
|
|
||||||
|
if therower.rowerplan != 'freecoach':
|
||||||
rowers = [therower]
|
rowers = [therower]
|
||||||
for ps in sps:
|
|
||||||
if request.user.rower.rowerplan == 'coach':
|
|
||||||
rowers += ps.rower.all()
|
|
||||||
else:
|
else:
|
||||||
rowers += ps.rower.filter(team__in=rteams)
|
rowers = []
|
||||||
|
|
||||||
|
for ps in sps:
|
||||||
|
if 'coach' in request.user.rower.rowerplan:
|
||||||
|
rowers += ps.rower.all().exclude(rowerplan='freecoach')
|
||||||
|
else:
|
||||||
|
rowers += ps.rower.filter(team__in=rteams).exclude(rowerplan='freecoach')
|
||||||
|
|
||||||
rowers = list(set(rowers))
|
rowers = list(set(rowers))
|
||||||
|
|
||||||
@@ -1569,7 +1573,7 @@ def plannedsession_view(request,id=0,userid=0):
|
|||||||
mm = Rower.objects.get(user=m)
|
mm = Rower.objects.get(user=m)
|
||||||
|
|
||||||
if ps.manager != request.user:
|
if ps.manager != request.user:
|
||||||
if r.rowerplan == 'coach' and r not in ps.rower.all():
|
if 'coach' in r.rowerplan and r not in ps.rower.all():
|
||||||
teams = Team.objects.filter(manager=request.user)
|
teams = Team.objects.filter(manager=request.user)
|
||||||
members = Rower.objects.filter(team__in=teams).distinct()
|
members = Rower.objects.filter(team__in=teams).distinct()
|
||||||
teamusers = [m.user for m in members]
|
teamusers = [m.user for m in members]
|
||||||
@@ -1808,6 +1812,10 @@ def rower_create_trainingplan(request,userid=0):
|
|||||||
name = targetform.cleaned_data['name']
|
name = targetform.cleaned_data['name']
|
||||||
date = targetform.cleaned_data['date']
|
date = targetform.cleaned_data['date']
|
||||||
notes = targetform.cleaned_data['notes']
|
notes = targetform.cleaned_data['notes']
|
||||||
|
try:
|
||||||
|
rowers = targetform.cleaned_data['rowers']
|
||||||
|
except KeyError:
|
||||||
|
rowers = [therower]
|
||||||
|
|
||||||
t = TrainingTarget(
|
t = TrainingTarget(
|
||||||
name=name,
|
name=name,
|
||||||
@@ -1817,7 +1825,8 @@ def rower_create_trainingplan(request,userid=0):
|
|||||||
|
|
||||||
|
|
||||||
t.save()
|
t.save()
|
||||||
t.rowers.add(therower)
|
for athlete in rowers:
|
||||||
|
t.rowers.add(athlete)
|
||||||
t.save()
|
t.save()
|
||||||
|
|
||||||
elif request.method == 'POST' and 'startdate' in request.POST:
|
elif request.method == 'POST' and 'startdate' in request.POST:
|
||||||
@@ -2589,7 +2598,7 @@ class TrainingPlanUpdate(UpdateView):
|
|||||||
obj = super(TrainingPlanUpdate, self).get_object(*args, **kwargs)
|
obj = super(TrainingPlanUpdate, self).get_object(*args, **kwargs)
|
||||||
if obj.manager is not None and self.request.user.rower != obj.manager:
|
if obj.manager is not None and self.request.user.rower != obj.manager:
|
||||||
raise PermissionDenied('You are not allowed to edit this training plan cycle')
|
raise PermissionDenied('You are not allowed to edit this training plan cycle')
|
||||||
if obj.manager.rowerplan not in ['coach','plan']:
|
if obj.manager.rowerplan not in ['coach','freecoach','plan']:
|
||||||
raise PermissionDenied('You are not allowed to edit this training plan')
|
raise PermissionDenied('You are not allowed to edit this training plan')
|
||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|||||||
@@ -1009,7 +1009,7 @@ def iscoachmember(user):
|
|||||||
r = Rower(user=user)
|
r = Rower(user=user)
|
||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
result = user.is_authenticated and (r.rowerplan=='coach')
|
result = user.is_authenticated and ('coach' in r.rowerplan)
|
||||||
else:
|
else:
|
||||||
result = False
|
result = False
|
||||||
|
|
||||||
@@ -1025,7 +1025,7 @@ def cancreateteam(user):
|
|||||||
r = Rower(user=user)
|
r = Rower(user=user)
|
||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
if user.is_authenticated and (r.rowerplan=='coach'):
|
if user.is_authenticated and ('coach' in r.rowerplan):
|
||||||
return True
|
return True
|
||||||
elif user.is_athenticated() and r.rowerplan in ['plan','pro']:
|
elif user.is_athenticated() and r.rowerplan in ['plan','pro']:
|
||||||
ts = Team.objects.filter(manager=user)
|
ts = Team.objects.filter(manager=user)
|
||||||
@@ -1041,7 +1041,7 @@ def hasplannedsessions(user):
|
|||||||
r = Rower(user=user)
|
r = Rower(user=user)
|
||||||
r.save()
|
r.save()
|
||||||
|
|
||||||
result = user.is_authenticated and (r.rowerplan=='coach' or r.rowerplan=='plan')
|
result = user.is_authenticated and (r.rowerplan=='coach' or r.rowerplan=='freecoach' or r.rowerplan=='plan')
|
||||||
if not result and r.plantrialexpires:
|
if not result and r.plantrialexpires:
|
||||||
result = user.is_authenticated and r.plantrialexpires >= datetime.date.today()
|
result = user.is_authenticated and r.plantrialexpires >= datetime.date.today()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -200,10 +200,10 @@ def rower_teams_view(request,message='',successmessage=''):
|
|||||||
|
|
||||||
coaches = teams.rower_get_coaches(r)
|
coaches = teams.rower_get_coaches(r)
|
||||||
|
|
||||||
potentialcoaches = [t.manager for t in memberteams if t.manager not in coaches and t.manager.rower.rowerplan == 'coach']
|
potentialcoaches = [t.manager for t in memberteams if t.manager not in coaches and 'coach' in t.manager.rower.rowerplan]
|
||||||
offercoaches = [
|
offercoaches = [
|
||||||
r.user for r in Rower.objects.filter(
|
r.user for r in Rower.objects.filter(
|
||||||
offercoaching=True,rowerplan='coach').exclude(user=request.user)
|
offercoaching=True,rowerplan__in='coach').exclude(user=request.user)
|
||||||
]
|
]
|
||||||
potentialcoaches = list(set(potentialcoaches+offercoaches))
|
potentialcoaches = list(set(potentialcoaches+offercoaches))
|
||||||
potentialcoaches = [c for c in potentialcoaches if c.rower not in invitedcoaches+coaches]
|
potentialcoaches = [c for c in potentialcoaches if c.rower not in invitedcoaches+coaches]
|
||||||
@@ -218,6 +218,16 @@ def rower_teams_view(request,message='',successmessage=''):
|
|||||||
user__in=invitedathletes).exclude(
|
user__in=invitedathletes).exclude(
|
||||||
user=request.user
|
user=request.user
|
||||||
).exclude(coachinggroups__in=[request.user.rower.mycoachgroup])
|
).exclude(coachinggroups__in=[request.user.rower.mycoachgroup])
|
||||||
|
elif request.user.rower.rowerplan == 'freecoach':
|
||||||
|
potentialathletes = Rower.objects.filter(
|
||||||
|
team__in=myteams).exclude(
|
||||||
|
user__in=invitedathletes).exclude(
|
||||||
|
user=request.user
|
||||||
|
).exclude(
|
||||||
|
coachinggroups__in=[request.user.rower.mycoachgroup]
|
||||||
|
).exclude(
|
||||||
|
rowerplan__in=['basic','freecoach']
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
potentialathletes = []
|
potentialathletes = []
|
||||||
|
|
||||||
@@ -437,7 +447,7 @@ def request_coaching_view(request,coachid):
|
|||||||
|
|
||||||
coach = User.objects.get(id=coachid).rower
|
coach = User.objects.get(id=coachid).rower
|
||||||
|
|
||||||
if coach.rowerplan == 'coach':
|
if 'coach' in coach.rowerplan:
|
||||||
res,text = teams.create_coaching_request(coach,request.user)
|
res,text = teams.create_coaching_request(coach,request.user)
|
||||||
if res:
|
if res:
|
||||||
messages.info(request,text)
|
messages.info(request,text)
|
||||||
|
|||||||
@@ -3842,6 +3842,9 @@ def workout_upload_view(request,
|
|||||||
is_ajax = True
|
is_ajax = True
|
||||||
|
|
||||||
r = getrower(request.user)
|
r = getrower(request.user)
|
||||||
|
if r.rowerplan == 'freecoach':
|
||||||
|
url = reverse('team_workout_upload_view')
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
breadcrumbs = [
|
breadcrumbs = [
|
||||||
{
|
{
|
||||||
@@ -4295,7 +4298,14 @@ def team_workout_upload_view(request,message="",
|
|||||||
|
|
||||||
rowerform = TeamInviteForm(request.POST)
|
rowerform = TeamInviteForm(request.POST)
|
||||||
rowerform.fields.pop('email')
|
rowerform.fields.pop('email')
|
||||||
rowers = Rower.objects.filter(coachinggroups__in=[r.mycoachgroup]).distinct()
|
rowers = Rower.objects.filter(
|
||||||
|
coachinggroups__in=[r.mycoachgroup]
|
||||||
|
).exclude(
|
||||||
|
rowerplan='freecoach'
|
||||||
|
).distinct()
|
||||||
|
if r.rowerplan == 'freecoach':
|
||||||
|
rowers = rowers.exclude(rowerplan='basic')
|
||||||
|
|
||||||
rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct()
|
rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct()
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
f = request.FILES['file']
|
f = request.FILES['file']
|
||||||
@@ -4420,7 +4430,18 @@ def team_workout_upload_view(request,message="",
|
|||||||
optionsform = TeamUploadOptionsForm(initial=uploadoptions)
|
optionsform = TeamUploadOptionsForm(initial=uploadoptions)
|
||||||
rowerform = TeamInviteForm()
|
rowerform = TeamInviteForm()
|
||||||
rowerform.fields.pop('email')
|
rowerform.fields.pop('email')
|
||||||
rowerform.fields['user'].queryset = User.objects.filter(rower__isnull=False,rower__team__in=myteams).distinct()
|
|
||||||
|
rowers = Rower.objects.filter(
|
||||||
|
coachinggroups__in=[r.mycoachgroup]
|
||||||
|
).exclude(
|
||||||
|
rowerplan='freecoach'
|
||||||
|
).distinct()
|
||||||
|
if r.rowerplan == 'freecoach':
|
||||||
|
rowers = rowers.exclude(rowerplan='basic')
|
||||||
|
|
||||||
|
rowerform.fields['user'].queryset = User.objects.filter(rower__in=rowers).distinct()
|
||||||
|
|
||||||
|
|
||||||
return render(request, 'team_document_form.html',
|
return render(request, 'team_document_form.html',
|
||||||
{'form':form,
|
{'form':form,
|
||||||
# 'teams':get_my_teams(request.user),
|
# 'teams':get_my_teams(request.user),
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ urlpatterns += [
|
|||||||
re_path(r'^admin/', admin.site.urls),
|
re_path(r'^admin/', admin.site.urls),
|
||||||
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework2')),
|
re_path(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework2')),
|
||||||
re_path(r'^$',rootview),
|
re_path(r'^$',rootview),
|
||||||
re_path(r'^landing$',landingview),
|
re_path(r'^landing/$',landingview),
|
||||||
re_path(r'^getblogs/$',rowersviews.get_blog_posts),
|
re_path(r'^getblogs/$',rowersviews.get_blog_posts),
|
||||||
re_path(r'^login/',
|
re_path(r'^login/',
|
||||||
# auth_views.LoginView,
|
# auth_views.LoginView,
|
||||||
|
|||||||
@@ -57,6 +57,7 @@
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font-size: 1.0em;
|
font-size: 1.0em;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
header ul {
|
header ul {
|
||||||
|
|||||||
@@ -143,7 +143,38 @@
|
|||||||
<!-- Container element -->
|
<!-- Container element -->
|
||||||
|
|
||||||
<body data-root="https://webapiv2.navionics.com/dist/webapi/images">
|
<body data-root="https://webapiv2.navionics.com/dist/webapi/images">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
<nav class="main-nav">
|
||||||
|
<ul>
|
||||||
|
<li id="nav-workouts">
|
||||||
|
<a href="/rowers/list-workouts/">
|
||||||
|
<i class="fas fa-clipboard-list"></i> Workouts
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li id="nav-racing">
|
||||||
|
<a href="/rowers/virtualevents/">
|
||||||
|
<i class="fas fa-flag-checkered"></i> Racing
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li id="nav-analysis">
|
||||||
|
<a href="/rowers/analysis/">
|
||||||
|
<i class="fas fa-analytics"></i> Analysis
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li id="nav-plan">
|
||||||
|
<a href="/rowers/sessions/">
|
||||||
|
<i class="fas fa-calendar-alt"></i> Plan
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li id="nav-teams">
|
||||||
|
<a href="/rowers/me/teams/">
|
||||||
|
<i class="fas fa-bullhorn"></i> Groups
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
{% endif %}
|
||||||
<div class="parallax">
|
<div class="parallax">
|
||||||
<p>Aap</p>
|
<p>Aap</p>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -161,7 +161,7 @@
|
|||||||
<a href="/rowers/me/preferences/" title="Profile">
|
<a href="/rowers/me/preferences/" title="Profile">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
<i class="fas fa-user-ninja "></i>
|
<i class="fas fa-user-ninja "></i>
|
||||||
{% elif user.rower.rowerplan == 'coach' %}
|
{% elif 'coach' in user.rower.rowerplan %}
|
||||||
<i class="fas fa-users "></i>
|
<i class="fas fa-users "></i>
|
||||||
{% elif user.rower.rowerplan == 'plan' %}
|
{% elif user.rower.rowerplan == 'plan' %}
|
||||||
<i class="fas fa-user-chart "></i>
|
<i class="fas fa-user-chart "></i>
|
||||||
@@ -220,6 +220,9 @@
|
|||||||
<li id="nav-teams">
|
<li id="nav-teams">
|
||||||
<a href="/rowers/me/teams/">
|
<a href="/rowers/me/teams/">
|
||||||
<i class="fas fa-bullhorn"></i> Groups
|
<i class="fas fa-bullhorn"></i> Groups
|
||||||
|
{% if user.is_authenticated and user|openactions %}
|
||||||
|
({{ user|openactions }})
|
||||||
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -234,7 +237,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if user.rower.planexpires and user.rower.rowerplan != 'basic' and user.rower.paymenttype == 'single'%}
|
{% if user.rower.planexpires and user.rower|notfree and user.rower.paymenttype == 'single'%}
|
||||||
{% if user.rower.planexpires|is_future_date %}
|
{% if user.rower.planexpires|is_future_date %}
|
||||||
{% if user.rower.planexpires|date_dif|ddays < 4 %}
|
{% if user.rower.planexpires|date_dif|ddays < 4 %}
|
||||||
<li class="grid_4">
|
<li class="grid_4">
|
||||||
|
|||||||
@@ -169,7 +169,7 @@
|
|||||||
<a href="/rowers/me/preferences/" title="Profile">
|
<a href="/rowers/me/preferences/" title="Profile">
|
||||||
{% if user.rower.rowerplan == 'pro' %}
|
{% if user.rower.rowerplan == 'pro' %}
|
||||||
<i class="fas fa-user-ninja "></i>
|
<i class="fas fa-user-ninja "></i>
|
||||||
{% elif user.rower.rowerplan == 'coach' %}
|
{% elif 'coach' in user.rower.rowerplan %}
|
||||||
<i class="fas fa-users "></i>
|
<i class="fas fa-users "></i>
|
||||||
{% elif user.rower.rowerplan == 'plan' %}
|
{% elif user.rower.rowerplan == 'plan' %}
|
||||||
<i class="fas fa-user-tie "></i>
|
<i class="fas fa-user-tie "></i>
|
||||||
@@ -229,6 +229,9 @@
|
|||||||
<li id="nav-teams">
|
<li id="nav-teams">
|
||||||
<a href="/rowers/me/teams/">
|
<a href="/rowers/me/teams/">
|
||||||
<i class="fas fa-bullhorn"></i> Groups
|
<i class="fas fa-bullhorn"></i> Groups
|
||||||
|
{% if user.is_authenticated and user|openactions %}
|
||||||
|
({{ user|openactions }})
|
||||||
|
{% endif %}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
Reference in New Issue
Block a user