Merge branch 'feature/freecoach' into develop
This commit is contained in:
+13
-9
@@ -8,13 +8,13 @@ atomicwrites==1.3.0
|
||||
attrs==19.1.0
|
||||
backcall==0.1.0
|
||||
beautifulsoup4==4.7.1
|
||||
billiard==3.5.0.5
|
||||
billiard==3.6.0.0
|
||||
bleach==3.1.0
|
||||
bokeh==1.0.4
|
||||
boto==2.49.0
|
||||
braintree==3.51.0
|
||||
cairocffi==1.0.2
|
||||
celery==4.2.2
|
||||
celery==4.3.0
|
||||
certifi==2019.3.9
|
||||
cffi==1.12.2
|
||||
chardet==3.0.4
|
||||
@@ -46,9 +46,10 @@ django-leaflet==0.24.0
|
||||
django-mailbox==4.7.1
|
||||
django-oauth-toolkit==1.2.0
|
||||
django-oauth2-provider==0.2.6.1
|
||||
django-redis==4.10.0
|
||||
django-rest-framework==0.1.0
|
||||
django-rest-swagger==2.2.0
|
||||
django-rq==2.0
|
||||
django-rq==1.3.1
|
||||
django-rq-dashboard==0.3.3
|
||||
django-ses==0.8.10
|
||||
django-shell-plus==1.1.7
|
||||
@@ -66,7 +67,9 @@ Faker==1.0.4
|
||||
fitparse==1.1.0
|
||||
Flask==1.0.2
|
||||
future==0.17.1
|
||||
GDAL==2.3.3
|
||||
geocoder==1.38.1
|
||||
geos==0.2.1
|
||||
holoviews==1.11.3
|
||||
html5lib==1.0.1
|
||||
htmlmin==0.1.12
|
||||
@@ -96,7 +99,7 @@ jupyterlab==0.35.4
|
||||
jupyterlab-server==0.3.0
|
||||
keyring==18.0.0
|
||||
kiwisolver==1.0.1
|
||||
kombu==4.3.0
|
||||
kombu==4.5.0
|
||||
lxml==4.3.2
|
||||
Markdown==3.0.1
|
||||
MarkupSafe==1.1.1
|
||||
@@ -129,9 +132,9 @@ pip-upgrader==1.4.6
|
||||
pluggy==0.9.0
|
||||
prometheus-client==0.6.0
|
||||
prompt-toolkit==2.0.9
|
||||
psycopg2==2.8.1
|
||||
ptyprocess==0.6.0
|
||||
py==1.8.0
|
||||
pycairo==1.18.0
|
||||
pycparser==2.19
|
||||
Pygments==2.3.1
|
||||
pyparsing==2.3.1
|
||||
@@ -157,10 +160,9 @@ ratelim==0.1.6
|
||||
redis==3.2.1
|
||||
requests==2.21.0
|
||||
requests-oauthlib==1.2.0
|
||||
rowingdata==2.3.1
|
||||
rowingdata==2.3.8
|
||||
rowingphysics==0.5.0
|
||||
rq==1.0
|
||||
rq-dashboard==0.4.0
|
||||
rq==0.13.0
|
||||
scipy==1.2.1
|
||||
SecretStorage==3.1.1
|
||||
Send2Trash==1.5.0
|
||||
@@ -188,8 +190,10 @@ VerbalExpressions==0.0.2
|
||||
vine==1.3.0
|
||||
wcwidth==0.1.7
|
||||
webencodings==0.5.1
|
||||
Werkzeug==0.15.2
|
||||
Werkzeug==0.15.1
|
||||
widgetsnbextension==3.4.2
|
||||
winkerberos==0.7.0
|
||||
xlrd==1.2.0
|
||||
xmltodict==0.12.0
|
||||
yamjam==0.1.7
|
||||
yamllint==1.15.0
|
||||
|
||||
@@ -241,7 +241,6 @@ def create_subscription(rower,data):
|
||||
"payment_method_nonce": nonce_from_the_client
|
||||
})
|
||||
|
||||
|
||||
if result.is_success:
|
||||
payment_method_token = result.payment_method.token
|
||||
else:
|
||||
@@ -252,6 +251,7 @@ def create_subscription(rower,data):
|
||||
"plan_id": plan.external_id
|
||||
})
|
||||
|
||||
|
||||
if result.is_success:
|
||||
rower.paidplan = plan
|
||||
rower.planexpires = result.subscription.billing_period_end_date
|
||||
|
||||
+8
-5
@@ -3,6 +3,8 @@ from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
|
||||
# All the data preparation, data cleaning and data mangling should
|
||||
# be defined here
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
@@ -28,6 +30,7 @@ from pandas import DataFrame, Series
|
||||
from django.utils import timezone
|
||||
from django.utils.timezone import get_current_timezone
|
||||
from django_mailbox.models import Message,Mailbox,MessageAttachment
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from time import strftime
|
||||
import arrow
|
||||
@@ -1100,8 +1103,11 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
try:
|
||||
w.save()
|
||||
except ValidationError:
|
||||
w.startdatetime = timezone.now()
|
||||
w.save()
|
||||
try:
|
||||
w.startdatetime = timezone.now()
|
||||
w.save()
|
||||
except ValidationError:
|
||||
return (0,'Unable to create your workout')
|
||||
|
||||
if privacy == 'visible':
|
||||
ts = Team.objects.filter(rower=r)
|
||||
@@ -1189,7 +1195,6 @@ parsers = {
|
||||
}
|
||||
|
||||
def parsenonpainsled(fileformat,f2,summary):
|
||||
|
||||
try:
|
||||
row = parsers[fileformat](f2)
|
||||
hasrecognized = True
|
||||
@@ -1197,7 +1202,6 @@ def parsenonpainsled(fileformat,f2,summary):
|
||||
hasrecognized = False
|
||||
return None, hasrecognized, '', 'unknown'
|
||||
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
oarlength, inboard = get_empower_rigging(f2)
|
||||
@@ -1211,7 +1215,6 @@ def parsenonpainsled(fileformat,f2,summary):
|
||||
except ZeroDivisionError:
|
||||
summary = ''
|
||||
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
try:
|
||||
|
||||
+3
-3
@@ -632,16 +632,16 @@ class RegistrationFormSex(RegistrationFormUniqueEmail):
|
||||
raise forms.ValidationError('Must be at least 16 years old to register')
|
||||
return self.cleaned_data['birthdate']
|
||||
|
||||
sex = forms.ChoiceField(required=True,
|
||||
sex = forms.ChoiceField(required=False,
|
||||
choices=sexcategories,
|
||||
initial='not specified',
|
||||
label='Sex')
|
||||
|
||||
weightcategory = forms.ChoiceField(label='Weight Category',
|
||||
choices=weightcategories)
|
||||
choices=weightcategories,initial='hwt',required=False)
|
||||
|
||||
adaptiveclass = forms.ChoiceField(label='Adaptive Classification',
|
||||
choices=adaptivecategories)
|
||||
choices=adaptivecategories,initial='None',required=False)
|
||||
|
||||
# def __init__(self, *args, **kwargs):
|
||||
# self.fields['sex'].initial = 'not specified'
|
||||
|
||||
@@ -124,7 +124,7 @@ class RowerPlanMiddleWare(object):
|
||||
self.get_response = get_response
|
||||
|
||||
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.planexpires < timezone.now().date():
|
||||
messg = 'Your paid plan has expired. We have reset you to a free basic plan.'
|
||||
|
||||
+12
-4
@@ -601,7 +601,8 @@ plans = (
|
||||
('basic','basic'),
|
||||
('pro','pro'),
|
||||
('plan','plan'),
|
||||
('coach','coach')
|
||||
('coach','coach'),
|
||||
('freecoach','freecoach'),
|
||||
)
|
||||
|
||||
paymenttypes = (
|
||||
@@ -913,7 +914,7 @@ def check_teams_on_change(sender, **kwargs):
|
||||
team = Team.objects.get(id=id)
|
||||
if team.manager.rower.rowerplan not in ['coach']:
|
||||
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)
|
||||
@@ -1074,7 +1075,7 @@ def checkaccessplanuser(user,rower):
|
||||
r = Rower.objects.get(user=user)
|
||||
if rower == r:
|
||||
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':
|
||||
return user in team_managers
|
||||
else:
|
||||
@@ -2575,6 +2576,13 @@ class Workout(models.Model):
|
||||
choices=privacychoices)
|
||||
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
|
||||
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):
|
||||
|
||||
@@ -3263,7 +3271,7 @@ class AccountRowerForm(ModelForm):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(AccountRowerForm, self).__init__(*args, **kwargs)
|
||||
if self.instance.rowerplan != 'coach':
|
||||
if 'coach' not in self.instance.rowerplan:
|
||||
self.fields.pop('offercoaching')
|
||||
|
||||
|
||||
|
||||
@@ -465,12 +465,12 @@ def add_team_session(t,ps):
|
||||
def add_rower_session(r,ps):
|
||||
teams = Team.objects.filter(manager=ps.manager)
|
||||
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.save()
|
||||
|
||||
return 1
|
||||
elif ps.manager.rower == r:
|
||||
elif ps.manager.rower == r and r.rowerplan != 'freecoach':
|
||||
ps.rower.add(r)
|
||||
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.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')
|
||||
if manager.rower.rowerplan != 'coach':
|
||||
if manager.rower.rowerplan not in ('coach','freecoach'):
|
||||
ts = Team.objects.filter(manager=manager)
|
||||
if len(ts)>=1:
|
||||
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):
|
||||
if coach.mycoachgroup and coach.rowerplan == 'coach':
|
||||
if coach.mycoachgroup and coach.rowerplan in ('coach','freecoach'):
|
||||
return Rower.objects.filter(
|
||||
coachinggroups__in=[coach.mycoachgroup]
|
||||
).distinct().order_by("user__last_name","user__first_name")
|
||||
@@ -237,7 +237,7 @@ def create_coaching_request(coach,user):
|
||||
while code in codes:
|
||||
code = uuid.uuid4().hex[:10].upper()
|
||||
|
||||
if coach.rowerplan == 'coach':
|
||||
if 'coach' in coach.rowerplan:
|
||||
rekwest = CoachRequest(coach=coach,user=user,code=code)
|
||||
rekwest.save()
|
||||
|
||||
@@ -316,7 +316,7 @@ def create_coaching_offer(coach,user):
|
||||
while code in codes:
|
||||
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.save()
|
||||
|
||||
@@ -597,7 +597,7 @@ def process_request_code(manager,code):
|
||||
if rekwest.team.manager != manager:
|
||||
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:
|
||||
return (result,"The member couldn't be added")
|
||||
|
||||
@@ -622,7 +622,7 @@ def process_invite_code(user,code):
|
||||
return (0,'The invitation has expired')
|
||||
|
||||
t = invitation.team
|
||||
result = add_member(t.id,r)
|
||||
result, comment = add_member(t.id,r)
|
||||
if not result:
|
||||
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 %}
|
||||
@@ -120,8 +120,8 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Duration</th>
|
||||
<th> Power (upper)</th>
|
||||
<th> Power</th>
|
||||
<th> Power Estimate 1</th>
|
||||
<th> Power Estimate 2</th>
|
||||
<tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -178,6 +178,8 @@
|
||||
<td>
|
||||
{% if rower.rowerplan == 'coach' %}
|
||||
<h3>COACH ({{ rower.paymenttype }})</h3>
|
||||
{% elif rower.rowerplan == 'freecoach' %}
|
||||
<h3>Free COACH</h3>
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
@@ -248,6 +250,16 @@
|
||||
{% endif %}
|
||||
</button>
|
||||
</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' %}
|
||||
<td> </td>
|
||||
<td colspan="2">
|
||||
@@ -298,6 +310,14 @@
|
||||
can purchase upgrades to "Pro" and "Self-Coach" plans.
|
||||
</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
|
||||
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>
|
||||
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 button
|
||||
with your first name on it in the upper right corner of the opening page.
|
||||
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>
|
||||
|
||||
@@ -6,8 +6,36 @@
|
||||
|
||||
{% endblock %}
|
||||
{% block main %}
|
||||
<h1>New User Registration</h1>
|
||||
<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">
|
||||
<div id="registrationform">
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ from rowers.utils import calculate_age
|
||||
from rowers.models import (
|
||||
course_length,WorkoutComment,
|
||||
TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle,
|
||||
Rower,Workout,SiteAnnouncement
|
||||
Rower,Workout,SiteAnnouncement, TeamInvite, TeamRequest, CoachOffer,CoachRequest
|
||||
)
|
||||
from rowers.plannedsessions import (
|
||||
race_can_register, race_can_submit,race_rower_status
|
||||
@@ -51,6 +51,10 @@ def nogoals(user):
|
||||
date__gte=datetime.date.today())
|
||||
return len(targets)==0
|
||||
|
||||
@register.filter
|
||||
def notfree(rower):
|
||||
return rower.rowerplan not in ['basic','freecoach']
|
||||
|
||||
def strfdelta(tdelta):
|
||||
minutes,seconds = divmod(tdelta.seconds,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
@@ -327,7 +331,7 @@ def is_promember(user):
|
||||
@register.filter
|
||||
def is_manager(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
return r.rowerplan == 'coach'
|
||||
return 'coach' in r.rowerplan
|
||||
|
||||
from rowers.views import hasplannedsessions
|
||||
@register.filter
|
||||
@@ -385,13 +389,29 @@ def team_members(user):
|
||||
team__in=teams
|
||||
).distinct().order_by(
|
||||
"user__last_name","user__first_name"
|
||||
)
|
||||
).exclude(rowerplan='freecoach')
|
||||
return [rower.user for rower in members]
|
||||
except TypeError:
|
||||
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
|
||||
def team_rowers(user):
|
||||
try:
|
||||
@@ -401,7 +421,7 @@ def team_rowers(user):
|
||||
teams = Team.objects.filter(manager=user)
|
||||
members = Rower.objects.filter(team__in=teams).distinct().order_by(
|
||||
"user__last_name","user__last_name"
|
||||
)
|
||||
).exclude(rowerplan='freecoach')
|
||||
return members
|
||||
except TypeError:
|
||||
return []
|
||||
@@ -412,7 +432,10 @@ from rowers.teams import coach_getcoachees
|
||||
|
||||
@register.filter
|
||||
def coach_rowers(user):
|
||||
thelist = [user.rower]+[c for c in coach_getcoachees(user.rower)]
|
||||
if user.rower.rowerplan != 'freecoach':
|
||||
thelist = [user.rower]+[c for c in coach_getcoachees(user.rower)]
|
||||
else:
|
||||
thelist = [c for c in coach_getcoachees(user.rower)]
|
||||
return thelist
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,184 @@ from django.db import transaction
|
||||
import rowers.teams as teams
|
||||
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)
|
||||
class PermissionsBasicsTests(TestCase):
|
||||
def setUp(self):
|
||||
|
||||
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'^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'^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'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/workflow/$',views.workout_workflow_view,
|
||||
name='workout_workflow_view'),
|
||||
|
||||
@@ -566,6 +566,86 @@ def rower_register_view(request):
|
||||
{'form':form,
|
||||
'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()
|
||||
def transactions_view(request):
|
||||
if not request.user.is_staff:
|
||||
|
||||
@@ -632,7 +632,7 @@ def plannedsession_teamcreate_view(request,
|
||||
request.session['teams'] = [team.id for team in teams]
|
||||
for team in teams:
|
||||
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:
|
||||
add_rower_session(r,ps)
|
||||
|
||||
@@ -904,7 +904,7 @@ def plannedsessions_coach_view(request,
|
||||
else:
|
||||
theteam = False
|
||||
|
||||
if request.user.rower.rowerplan == 'coach':
|
||||
if 'coach' in request.user.rower.rowerplan:
|
||||
sps = get_sessions_manager(request.user,teamid=teamid,
|
||||
enddate=enddate,
|
||||
startdate=startdate)
|
||||
@@ -912,12 +912,16 @@ def plannedsessions_coach_view(request,
|
||||
rteams = therower.team.filter(viewing='allmembers')
|
||||
sps = get_sessions(therower,startdate=startdate,enddate=enddate)
|
||||
|
||||
rowers = [therower]
|
||||
if therower.rowerplan != 'freecoach':
|
||||
rowers = [therower]
|
||||
else:
|
||||
rowers = []
|
||||
|
||||
for ps in sps:
|
||||
if request.user.rower.rowerplan == 'coach':
|
||||
rowers += ps.rower.all()
|
||||
if 'coach' in request.user.rower.rowerplan:
|
||||
rowers += ps.rower.all().exclude(rowerplan='freecoach')
|
||||
else:
|
||||
rowers += ps.rower.filter(team__in=rteams)
|
||||
rowers += ps.rower.filter(team__in=rteams).exclude(rowerplan='freecoach')
|
||||
|
||||
rowers = list(set(rowers))
|
||||
|
||||
@@ -1569,7 +1573,7 @@ def plannedsession_view(request,id=0,userid=0):
|
||||
mm = Rower.objects.get(user=m)
|
||||
|
||||
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)
|
||||
members = Rower.objects.filter(team__in=teams).distinct()
|
||||
teamusers = [m.user for m in members]
|
||||
@@ -1808,6 +1812,10 @@ def rower_create_trainingplan(request,userid=0):
|
||||
name = targetform.cleaned_data['name']
|
||||
date = targetform.cleaned_data['date']
|
||||
notes = targetform.cleaned_data['notes']
|
||||
try:
|
||||
rowers = targetform.cleaned_data['rowers']
|
||||
except KeyError:
|
||||
rowers = [therower]
|
||||
|
||||
t = TrainingTarget(
|
||||
name=name,
|
||||
@@ -1817,7 +1825,8 @@ def rower_create_trainingplan(request,userid=0):
|
||||
|
||||
|
||||
t.save()
|
||||
t.rowers.add(therower)
|
||||
for athlete in rowers:
|
||||
t.rowers.add(athlete)
|
||||
t.save()
|
||||
|
||||
elif request.method == 'POST' and 'startdate' in request.POST:
|
||||
@@ -2589,7 +2598,7 @@ class TrainingPlanUpdate(UpdateView):
|
||||
obj = super(TrainingPlanUpdate, self).get_object(*args, **kwargs)
|
||||
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')
|
||||
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')
|
||||
|
||||
return obj
|
||||
|
||||
@@ -1009,7 +1009,7 @@ def iscoachmember(user):
|
||||
r = Rower(user=user)
|
||||
r.save()
|
||||
|
||||
result = user.is_authenticated and (r.rowerplan=='coach')
|
||||
result = user.is_authenticated and ('coach' in r.rowerplan)
|
||||
else:
|
||||
result = False
|
||||
|
||||
@@ -1025,7 +1025,7 @@ def cancreateteam(user):
|
||||
r = Rower(user=user)
|
||||
r.save()
|
||||
|
||||
if user.is_authenticated and (r.rowerplan=='coach'):
|
||||
if user.is_authenticated and ('coach' in r.rowerplan):
|
||||
return True
|
||||
elif user.is_athenticated() and r.rowerplan in ['plan','pro']:
|
||||
ts = Team.objects.filter(manager=user)
|
||||
@@ -1041,7 +1041,7 @@ def hasplannedsessions(user):
|
||||
r = Rower(user=user)
|
||||
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:
|
||||
result = user.is_authenticated and r.plantrialexpires >= datetime.date.today()
|
||||
else:
|
||||
|
||||
@@ -200,10 +200,10 @@ def rower_teams_view(request,message='',successmessage=''):
|
||||
|
||||
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 = [
|
||||
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 = [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=request.user
|
||||
).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:
|
||||
potentialathletes = []
|
||||
|
||||
@@ -437,7 +447,7 @@ def request_coaching_view(request,coachid):
|
||||
|
||||
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)
|
||||
if res:
|
||||
messages.info(request,text)
|
||||
|
||||
@@ -3842,6 +3842,9 @@ def workout_upload_view(request,
|
||||
is_ajax = True
|
||||
|
||||
r = getrower(request.user)
|
||||
if r.rowerplan == 'freecoach':
|
||||
url = reverse('team_workout_upload_view')
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
@@ -4295,7 +4298,14 @@ def team_workout_upload_view(request,message="",
|
||||
|
||||
rowerform = TeamInviteForm(request.POST)
|
||||
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()
|
||||
if form.is_valid():
|
||||
f = request.FILES['file']
|
||||
@@ -4420,9 +4430,20 @@ def team_workout_upload_view(request,message="",
|
||||
optionsform = TeamUploadOptionsForm(initial=uploadoptions)
|
||||
rowerform = TeamInviteForm()
|
||||
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',
|
||||
{'form':form,
|
||||
{'form':form,
|
||||
# 'teams':get_my_teams(request.user),
|
||||
'optionsform': optionsform,
|
||||
'active': 'nav-workouts',
|
||||
|
||||
@@ -161,7 +161,7 @@
|
||||
<a href="/rowers/me/preferences/" title="Profile">
|
||||
{% if user.rower.rowerplan == 'pro' %}
|
||||
<i class="fas fa-user-ninja "></i>
|
||||
{% elif user.rower.rowerplan == 'coach' %}
|
||||
{% elif 'coach' in user.rower.rowerplan %}
|
||||
<i class="fas fa-users "></i>
|
||||
{% elif user.rower.rowerplan == 'plan' %}
|
||||
<i class="fas fa-user-chart "></i>
|
||||
@@ -220,6 +220,9 @@
|
||||
<li id="nav-teams">
|
||||
<a href="/rowers/me/teams/">
|
||||
<i class="fas fa-bullhorn"></i> Groups
|
||||
{% if user.is_authenticated and user|openactions %}
|
||||
({{ user|openactions }})
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -234,7 +237,7 @@
|
||||
</p>
|
||||
</li>
|
||||
{% 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|date_dif|ddays < 4 %}
|
||||
<li class="grid_4">
|
||||
|
||||
@@ -169,7 +169,7 @@
|
||||
<a href="/rowers/me/preferences/" title="Profile">
|
||||
{% if user.rower.rowerplan == 'pro' %}
|
||||
<i class="fas fa-user-ninja "></i>
|
||||
{% elif user.rower.rowerplan == 'coach' %}
|
||||
{% elif 'coach' in user.rower.rowerplan %}
|
||||
<i class="fas fa-users "></i>
|
||||
{% elif user.rower.rowerplan == 'plan' %}
|
||||
<i class="fas fa-user-tie "></i>
|
||||
@@ -229,6 +229,9 @@
|
||||
<li id="nav-teams">
|
||||
<a href="/rowers/me/teams/">
|
||||
<i class="fas fa-bullhorn"></i> Groups
|
||||
{% if user.is_authenticated and user|openactions %}
|
||||
({{ user|openactions }})
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user