diff --git a/requirements.txt b/requirements.txt
index d7f1e8b0..4b13966d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -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
diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py
index c7238887..184cc58e 100644
--- a/rowers/braintreestuff.py
+++ b/rowers/braintreestuff.py
@@ -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
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index f4a20ba2..89266aba 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -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:
diff --git a/rowers/forms.py b/rowers/forms.py
index fcc54568..3c3cef2d 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -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'
diff --git a/rowers/middleware.py b/rowers/middleware.py
index d2fbd425..c1b968f2 100644
--- a/rowers/middleware.py
+++ b/rowers/middleware.py
@@ -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.'
diff --git a/rowers/models.py b/rowers/models.py
index f124ac36..7f50af9f 100644
--- a/rowers/models.py
+++ b/rowers/models.py
@@ -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')
diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py
index d62b50eb..34642a46 100644
--- a/rowers/plannedsessions.py
+++ b/rowers/plannedsessions.py
@@ -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()
diff --git a/rowers/teams.py b/rowers/teams.py
index 3dc3f310..7be8d03a 100644
--- a/rowers/teams.py
+++ b/rowers/teams.py
@@ -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)
+ 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 + Settings page + 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. +
+ ++ 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 + https://analytics.rowsandall.com/2019/02/24/managing-a-rowing-training-group-coaching-and-remote-coaching-on-rowsandall-com/. +
+ ++ 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: + https://rowsandall.com/rowers/paidplans +
+ ++ 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. +
+ ++ Best Regards, the Rowsandall Team +
+{% endblock %} diff --git a/rowers/templates/freecoach_registration_form.html b/rowers/templates/freecoach_registration_form.html new file mode 100644 index 00000000..0c1f6a5d --- /dev/null +++ b/rowers/templates/freecoach_registration_form.html @@ -0,0 +1,79 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} +{% block title %}New Coach Registration{% endblock title %} +{% block meta %} + +{% endblock %} +{% block main %} +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. +
++ 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. +
+ +Click here and fill out the form to start with a free Athlete plan. This allows you + to store and analyze your own workouts. +
++ 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. +
+ ++ Please correct the error{{ form.errors|pluralize }} below. +
+ {% endif %} + + +To use rowsandall, you need to register and agree with the Terms of Service.
+Registration is free.
+ +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. +
+ +Also, we are restricting access to the site to 16 years and older + because of EU data protection regulations.
+
+
+ Sign-up form goes here
+Some info goes here
+"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
+"Sander has made amazing tools for self-coaching or working with a coach."
+ +“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.”
+“I discovered rowsandall.com – which is brilliant.”
Where does the login go?
+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.
+ +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.
+ +Analyze your workouts with a consistent set of tools, developed by rowers for rowers.
+ +Compare youre results between workouts and with other rowers in your team.
+ +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
+ +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
++ 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. +
+If you would like to find a coach who helps you plan your training through rowsandall.com, contact me throught the contact form.
diff --git a/rowers/templates/registeremail.html b/rowers/templates/registeremail.html index 20c81907..267358b3 100644 --- a/rowers/templates/registeremail.html +++ b/rowers/templates/registeremail.html @@ -10,8 +10,8 @@ Settings page 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.diff --git a/rowers/templates/registration_form.html b/rowers/templates/registration_form.html index 6ddf9632..7408e158 100644 --- a/rowers/templates/registration_form.html +++ b/rowers/templates/registration_form.html @@ -6,8 +6,36 @@ {% endblock %} {% block main %} -
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. +
++ 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. +
+ +Click here and fill out the form to start with a free Athlete plan. This allows you + to store and analyze your own workouts. +
++ 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. +
+ +Aap