Merge branch 'release/v5.96'
This commit is contained in:
+3
-50
@@ -18,6 +18,7 @@ import pandas as pd
|
||||
import numpy as np
|
||||
|
||||
import dataprep
|
||||
from rowers.utils import geo_distance
|
||||
|
||||
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
|
||||
|
||||
@@ -25,6 +26,8 @@ ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
|
||||
from rowers.models import (
|
||||
Rower, Workout,
|
||||
GeoPoint,GeoPolygon, GeoCourse,
|
||||
course_length,course_coord_center,course_coord_maxmin,
|
||||
polygon_coord_center
|
||||
)
|
||||
|
||||
# low level methods
|
||||
@@ -35,56 +38,6 @@ class InvalidTrajectoryError(Exception):
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
|
||||
def polygon_coord_center(polygon):
|
||||
|
||||
points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
|
||||
|
||||
latitudes = pd.Series([p.latitude for p in points])
|
||||
longitudes = pd.Series([p.longitude for p in points])
|
||||
|
||||
return latitudes.mean(), longitudes.mean()
|
||||
|
||||
def course_coord_center(course):
|
||||
|
||||
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
|
||||
for p in polygons:
|
||||
latitude,longitude = polygon_coord_center(p)
|
||||
latitudes.append(latitude)
|
||||
longitudes.append(longitude)
|
||||
|
||||
latitude = pd.Series(latitudes).median()
|
||||
longitude = pd.Series(longitudes).median()
|
||||
|
||||
coordinates = pd.DataFrame({
|
||||
'latitude':latitudes,
|
||||
'longitude':longitudes,
|
||||
})
|
||||
|
||||
return latitude,longitude,coordinates
|
||||
|
||||
def course_coord_maxmin(course):
|
||||
|
||||
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
|
||||
for p in polygons:
|
||||
latitude,longitude = polygon_coord_center(p)
|
||||
latitudes.append(latitude)
|
||||
longitudes.append(longitude)
|
||||
|
||||
lat_min = pd.Series(latitudes).min()
|
||||
lat_max = pd.Series(latitudes).max()
|
||||
long_min = pd.Series(longitudes).min()
|
||||
long_max = pd.Series(longitudes).max()
|
||||
|
||||
|
||||
return lat_min,lat_max,long_min,long_max
|
||||
|
||||
def polygon_to_path(polygon):
|
||||
points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
|
||||
|
||||
+80
-3
@@ -350,6 +350,79 @@ from utils import (
|
||||
defaultleft,defaultmiddle,landingpages
|
||||
)
|
||||
|
||||
from utils import geo_distance
|
||||
|
||||
def polygon_coord_center(polygon):
|
||||
|
||||
points = GeoPoint.objects.filter(polygon=polygon).order_by("order_in_poly")
|
||||
|
||||
latitudes = pd.Series([p.latitude for p in points])
|
||||
longitudes = pd.Series([p.longitude for p in points])
|
||||
|
||||
return latitudes.mean(), longitudes.mean()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def course_coord_center(course):
|
||||
|
||||
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
|
||||
for p in polygons:
|
||||
latitude,longitude = polygon_coord_center(p)
|
||||
latitudes.append(latitude)
|
||||
longitudes.append(longitude)
|
||||
|
||||
latitude = pd.Series(latitudes).median()
|
||||
longitude = pd.Series(longitudes).median()
|
||||
|
||||
coordinates = pd.DataFrame({
|
||||
'latitude':latitudes,
|
||||
'longitude':longitudes,
|
||||
})
|
||||
|
||||
return latitude,longitude,coordinates
|
||||
|
||||
def course_coord_maxmin(course):
|
||||
|
||||
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
|
||||
|
||||
latitudes = []
|
||||
longitudes = []
|
||||
|
||||
for p in polygons:
|
||||
latitude,longitude = polygon_coord_center(p)
|
||||
latitudes.append(latitude)
|
||||
longitudes.append(longitude)
|
||||
|
||||
lat_min = pd.Series(latitudes).min()
|
||||
lat_max = pd.Series(latitudes).max()
|
||||
long_min = pd.Series(longitudes).min()
|
||||
long_max = pd.Series(longitudes).max()
|
||||
|
||||
|
||||
return lat_min,lat_max,long_min,long_max
|
||||
|
||||
|
||||
def course_length(course):
|
||||
polygons = GeoPolygon.objects.filter(course=course).order_by("order_in_course")
|
||||
|
||||
totaldist = 0
|
||||
for i in range(len(polygons)-1):
|
||||
latitude1,longitude1 = polygon_coord_center(polygons[i])
|
||||
latitude2,longitude2 = polygon_coord_center(polygons[i+1])
|
||||
|
||||
dist = geo_distance(latitude1,longitude1,
|
||||
latitude2,longitude2,)
|
||||
|
||||
totaldist += 1000.*dist[0]
|
||||
|
||||
return int(totaldist)
|
||||
|
||||
# Extension of User with rowing specific data
|
||||
class Rower(models.Model):
|
||||
weightcategories = (
|
||||
@@ -677,7 +750,7 @@ class GeoCourse(models.Model):
|
||||
class GeoCourseEditForm(ModelForm):
|
||||
class Meta:
|
||||
model = GeoCourse
|
||||
fields = ['name','notes']
|
||||
fields = ['name','country','notes']
|
||||
|
||||
widgets = {
|
||||
'notes': forms.Textarea,
|
||||
@@ -941,6 +1014,11 @@ class PlannedSession(models.Model):
|
||||
self.sessionmode = 'distance'
|
||||
self.sessionunit = 'm'
|
||||
self.criterium = 'none'
|
||||
if self.course == None:
|
||||
self.course = GeoCourse.objects.all()[0]
|
||||
self.sessionvalue = course_length(self.course)
|
||||
elif self.sessiontype != 'coursetest':
|
||||
self.course = None
|
||||
|
||||
super(PlannedSession,self).save(*args, **kwargs)
|
||||
|
||||
@@ -977,8 +1055,7 @@ class PlannedSessionForm(ModelForm):
|
||||
|
||||
def __init__(self,*args,**kwargs):
|
||||
super(PlannedSessionForm, self).__init__(*args, **kwargs)
|
||||
if self.instance.sessiontype != 'coursetest':
|
||||
del self.fields['course']
|
||||
self.fields['course'].queryset = GeoCourse.objects.all().order_by("country","name")
|
||||
|
||||
class PlannedSessionFormSmall(ModelForm):
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ def get_dates_timeperiod(timeperiod):
|
||||
elif timeperiod=='nextweek':
|
||||
today = date.today()
|
||||
enddate = today-timezone.timedelta(days=today.weekday())-timezone.timedelta(days=1)+timezone.timedelta(days=7)
|
||||
startdate = enddate-timezone.timedelta(days=13)
|
||||
startdate = enddate-timezone.timedelta(days=6)
|
||||
elif timeperiod=='lastmonth':
|
||||
today = date.today()
|
||||
startdate = today.replace(day=1)
|
||||
|
||||
@@ -9,19 +9,22 @@
|
||||
<p>You have arrived at this page, because you tried to create a
|
||||
training plan for yourself.</p>
|
||||
|
||||
<p>Currently, training planning is restricted to "coach" members with
|
||||
"team" functionality.</p>
|
||||
<p>This option is restricted to rowers on our "Self-Coach" plan or
|
||||
coaches on our "Coach" plan.</p>
|
||||
|
||||
<p>If you are interested in becoming a coach and planning sessions
|
||||
for a group of rowers on rowsandall.com, contact me through the contact
|
||||
form.
|
||||
<p>On the "Self-Coach" plan, you can plan your own sessions.</p>
|
||||
|
||||
<p>On the "Coach" plan, you can establish teams, see workouts done by
|
||||
athletes on your team, and plan individual and group sessions for 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>
|
||||
|
||||
<p>For self-coached rowers who would like to add the training planning
|
||||
functionality, we will soon establish a "Self-Coach" plan, which will enable you to do so.</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@@ -34,15 +37,15 @@
|
||||
|
||||
<p>
|
||||
<ul>
|
||||
<li>Create Planned Sessions (trainings, tests, challenges) for yourself
|
||||
<li><b>Implemented:</b>Create Planned Sessions (trainings, tests, challenges) for yourself
|
||||
and for your team members (coach plan)</li>
|
||||
<li>Track your performance against plan.
|
||||
<li><b>Implemented:</b>Track your performance against plan.
|
||||
Match workouts to planned sessions.
|
||||
Get feedback on plan adherence.</li>
|
||||
<li>Track your teams performance against plan. See how well each
|
||||
<li><b>Implemented:</b>Track your teams performance against plan. See how well each
|
||||
of your team members adhere to their (team or personalized) plan.</li>
|
||||
<li>See test outcomes ranked by performance.</li>
|
||||
<li>Attach courses to your OTW tests. This advanced functionality
|
||||
<li><b>Implemented:</b>See test outcomes ranked by performance.</li>
|
||||
<li><b>Implemented:</b>Attach courses to your OTW tests. This advanced functionality
|
||||
allows you, for example, to assign "Row the 6km from bridge A to
|
||||
bridge B on Saturday" to your team members. The resulting workout
|
||||
tracks will be evaluated against the course, and you will receive
|
||||
@@ -52,6 +55,65 @@
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
<div class="grid_12">
|
||||
<h1>Subscriptions</h1>
|
||||
<div class="grid_6 alpha">
|
||||
<h2>Recurring Payment</h2>
|
||||
<p>You need a Paypal account for this</p>
|
||||
<p>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
|
||||
<table>
|
||||
<tr><td><input type="hidden" name="on0" value="Plans">Plans</td></tr><tr><td><select name="os0">
|
||||
<option value="Pro Membership">Pro Membership : €15.00 EUR - yearly</option>
|
||||
<option value="Self-Coach Membership">Self-Coach Membership : €75.00 EUR - yearly</option>
|
||||
<option value="Coach 4 athletes or less">Coach 4 athletes or less : €90.00 EUR - yearly</option>
|
||||
<option value="Coach 4-10 athletes">Coach 4-10 athletes : €200.00 EUR - yearly</option>
|
||||
<option value="Coach more than 10 athletes">Coach more than 10 athletes : €450.00 EUR - yearly</option>
|
||||
</select> </td></tr>
|
||||
<tr><td><input type="hidden" name="on1" value="Your User Name">Your User Name</td></tr><tr><td><input type="text" name="os1" maxlength="200"></td></tr>
|
||||
</table>
|
||||
<input type="hidden" name="currency_code" value="EUR">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
</p>
|
||||
|
||||
<h2>One Year Subscription</h2>
|
||||
<p>Only a credit card needed. Will not automatically renew</p>
|
||||
|
||||
<p><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="2YB32HQTF96QW">
|
||||
<table>
|
||||
<tr><td><input type="hidden" name="on0" value="Plans">Plans</td></tr><tr><td><select name="os0">
|
||||
<option value="Pro Membership">Pro Membership €20.00 EUR</option>
|
||||
<option value="Self-Coach Membership">Self-Coach Membership €90.00 EUR</option>
|
||||
<option value="Coach - 4 athletes or less">Coach - 4 athletes or less €120.00 EUR</option>
|
||||
<option value="Coach - 4-10 athletes">Coach - 4-10 athletes €250.00 EUR</option>
|
||||
<option value="Coach - more than 10 athletes">Coach - more than 10 athletes €500.00 EUR</option>
|
||||
</select> </td></tr>
|
||||
<tr><td><input type="hidden" name="on1" value="Your User Name">Your User Name</td></tr><tr><td><input type="text" name="os1" maxlength="200"></td></tr>
|
||||
</table>
|
||||
<input type="hidden" name="currency_code" value="EUR">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||
</form>
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid_6 omega">
|
||||
<h2>Payment Processing</h2>
|
||||
<p>After you do the payment, we will manually change your membership to
|
||||
the selected plan. Depending on our availability, this may take some time
|
||||
(typically one working day). If you upgrade or downgrade, we will stop the recurring payment
|
||||
for the plan you were on before the change.
|
||||
Don't hesitate to contact us
|
||||
if you have any questions at this stage.</p>
|
||||
|
||||
<p>If, for any reason, you are not happy with your membership plan, please let me know through the contact form. I will contact you as soon as possible to discuss how we can make things better.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
@@ -145,6 +145,10 @@
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
$("td #id_course").hide();
|
||||
$("th label[for='id_course']").hide();
|
||||
|
||||
$("td #id_sessionmode").change(function() {
|
||||
|
||||
if (this.value == 'TRIMP') {
|
||||
@@ -179,6 +183,20 @@
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For Mandatory Tests, only distance or time are allowed.</p><p>For Mandatory Tests, the only criterium is 'Exactly'</p>");
|
||||
}
|
||||
if (this.value == 'coursetest') {
|
||||
$("th label[for='id_course']").show();
|
||||
$("td #id_course").show();
|
||||
$("td #id_criterium").prop("value","none");
|
||||
$("td #id_sessionmode").prop("value","distance");
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For OTW Tests, only distance is allowed.</p><p>The exact value is not relevant because it is calculated from the course.</p>");
|
||||
}
|
||||
|
||||
if (this.value != 'coursetest') {
|
||||
$("th label[for='id_course']").hide();
|
||||
$("td #id_course").hide();
|
||||
}
|
||||
|
||||
if (this.value == 'challenge') {
|
||||
$("td #id_criterium").prop("value","minimum");
|
||||
$('#id_guidance').html("<p>For Challenges, the default criterium is 'At Least'</p>");
|
||||
|
||||
@@ -144,6 +144,19 @@
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
var o = $("td #id_sessiontype").find(":selected").val();
|
||||
|
||||
if (o != 'coursetest') {
|
||||
$("td #id_course").hide();
|
||||
$("th label[for='id_course']").hide();
|
||||
} else {
|
||||
$("td #id_course").show();
|
||||
$("th label[for='id_course']").show();
|
||||
|
||||
}
|
||||
|
||||
|
||||
$("td #id_sessionmode").change(function() {
|
||||
|
||||
if (this.value == 'TRIMP') {
|
||||
@@ -178,6 +191,22 @@
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For Mandatory Tests, only distance or time are allowed.</p><p>For Mandatory Tests, the only criterium is 'Exactly'</p>");
|
||||
}
|
||||
|
||||
if (this.value == 'coursetest') {
|
||||
$("th label[for='id_course']").show();
|
||||
$("td #id_course").show();
|
||||
$("td #id_criterium").prop("value","none");
|
||||
$("td #id_sessionmode").prop("value","distance");
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For OTW Tests, only distance is allowed.</p><p>The exact value is not relevant because it is calculated from the course.</p>");
|
||||
}
|
||||
|
||||
if (this.value != 'coursetest') {
|
||||
$("th label[for='id_course']").hide();
|
||||
$("td #id_course").hide();
|
||||
}
|
||||
|
||||
|
||||
if (this.value == 'challenge') {
|
||||
$("td #id_criterium").prop("value","minimum");
|
||||
$('#id_guidance').html("<p>For Challenges, the default criterium is 'At Least'</p>");
|
||||
|
||||
@@ -137,6 +137,9 @@
|
||||
|
||||
|
||||
$(document).ready(function(){
|
||||
$("td #id_course").hide();
|
||||
$("th label[for='id_course']").hide();
|
||||
|
||||
$("td #id_sessionmode").change(function() {
|
||||
|
||||
if (this.value == 'TRIMP') {
|
||||
@@ -171,6 +174,22 @@
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For Mandatory Tests, only distance or time are allowed.</p><p>For Mandatory Tests, the only criterium is 'Exactly'</p>");
|
||||
}
|
||||
|
||||
if (this.value == 'coursetest') {
|
||||
$("th label[for='id_course']").show();
|
||||
$("td #id_course").show();
|
||||
$("td #id_criterium").prop("value","none");
|
||||
$("td #id_sessionmode").prop("value","distance");
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For OTW Tests, only distance is allowed.</p><p>The exact value is not relevant because it is calculated from the course.</p>");
|
||||
}
|
||||
|
||||
if (this.value != 'coursetest') {
|
||||
$("th label[for='id_course']").hide();
|
||||
$("td #id_course").hide();
|
||||
}
|
||||
|
||||
|
||||
if (this.value == 'challenge') {
|
||||
$("td #id_criterium").prop("value","minimum");
|
||||
$('#id_guidance').html("<p>For Challenges, the default criterium is 'At Least'</p>");
|
||||
|
||||
@@ -152,6 +152,19 @@
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script>
|
||||
$(document).ready(function(){
|
||||
|
||||
var o = $("td #id_sessiontype").find(":selected").val();
|
||||
|
||||
if (o != 'coursetest') {
|
||||
$("td #id_course").hide();
|
||||
$("th label[for='id_course']").hide();
|
||||
} else {
|
||||
$("td #id_course").show();
|
||||
$("th label[for='id_course']").show();
|
||||
|
||||
}
|
||||
|
||||
|
||||
$("td #id_sessionmode").change(function() {
|
||||
|
||||
if (this.value == 'TRIMP') {
|
||||
@@ -186,6 +199,22 @@
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For Mandatory Tests, only distance or time are allowed.</p><p>For Mandatory Tests, the only criterium is 'Exactly'</p>");
|
||||
}
|
||||
|
||||
if (this.value == 'coursetest') {
|
||||
$("th label[for='id_course']").show();
|
||||
$("td #id_course").show();
|
||||
$("td #id_criterium").prop("value","none");
|
||||
$("td #id_sessionmode").prop("value","distance");
|
||||
$("td #id_sessionunit").prop("value","m");
|
||||
$('#id_guidance').html("<p>Set mode to distance. For OTW Tests, only distance is allowed.</p><p>The exact value is not relevant because it is calculated from the course.</p>");
|
||||
}
|
||||
|
||||
if (this.value != 'coursetest') {
|
||||
$("th label[for='id_course']").hide();
|
||||
$("td #id_course").hide();
|
||||
}
|
||||
|
||||
|
||||
if (this.value == 'challenge') {
|
||||
$("td #id_criterium").prop("value","minimum");
|
||||
$('#id_guidance').html("<p>For Challenges, the default criterium is 'At Least'</p>");
|
||||
|
||||
@@ -8,24 +8,131 @@
|
||||
<h2>Pro Membership</h2>
|
||||
|
||||
<p>Donations are welcome to keep this web site going. To help cover the hosting
|
||||
costs, I have created a <q>Pro</q> membership option (for only 15 EURO per year). Once I process your
|
||||
costs, I have created several paid plans offering advanced functionality.
|
||||
Once I process your
|
||||
donation, I will give you access to some <q>special</q> features on this
|
||||
website. </p>
|
||||
|
||||
<p>Currently, the Pro membership will give you the following extra functionality (and more will follow):
|
||||
<ul>
|
||||
<li>More stroke metrics plots</li>
|
||||
<li>Power curves for OTW rowing</li>
|
||||
<li>Add weather information to OTW rowing sessions</li>
|
||||
<li>Power histogram</li>
|
||||
</ul>
|
||||
<p>The following table gives an overview of the different plans. As we are
|
||||
constantly developing new functionality, the table might be slightly outdated. Don't
|
||||
hesitate to contact us. </p>
|
||||
|
||||
<p>The Pro membership is open for a free 14 day trial</p>
|
||||
|
||||
<p>
|
||||
<table class="listtable paddedtable" width="80%">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> </th>
|
||||
<th>BASIC</th>
|
||||
<th>PRO</th>
|
||||
<th>SELF-COACH</th>
|
||||
<th>COACH</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Basic rowing metrics (spm, time, distance, heart rate, power)</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Import, Export, Synchronization and download of all your data</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Heart rate and power zones</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ranking Pieces, Stroke Analysis</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Advanced Analysis (Critical Power, Stats, Box Chart, Trend Flex)</td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Compare Workouts</td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Empower Stroke Profile</td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sensor Fusion, Split Workout, In-stroke metrics</td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Create Training plans, tests and challenges for yourself. Track your performance
|
||||
against plan.</td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Create Training plans, tests and challenges for your athletes. Track their performance
|
||||
against plan. </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Create and manage teams.</a>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Manage your athlete's workouts</a>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td> </td>
|
||||
<td>✔</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</p>
|
||||
<p>Click on the PayPal button to pay for your Pro membership. Before you pay, please <a href="/rowers/register">register</a> for the free Basic membership and log in.
|
||||
In this way, your user name will be added to the payment details.
|
||||
|
||||
<p>The Coach plan functionality listed is available to the coach only. Individual athletes
|
||||
can purchase upgrades to Pro membership.
|
||||
</p>
|
||||
<p>Click on the PayPal button to pay for your Pro membership. Before you pay, please <a href="/rowers/register">register</a> for the free Basic membership and add your user name to the form.
|
||||
Your payment will be valid for one year with automatic renewal which you can stop at any time.
|
||||
You will be taken to the secure PayPal payment site.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid_6 omega">
|
||||
{% if user.rower.rowerplan == 'basic' and user.rower.protrialexpires|date_dif == 1 %}
|
||||
<h2>Free Trial</h2>
|
||||
<p>
|
||||
You qualify for a 14 day free trial. No credit card needed.
|
||||
Try out Pro membership for two weeks. Click the button below to
|
||||
@@ -34,30 +141,51 @@ You will be taken to the secure PayPal payment site.
|
||||
</p>
|
||||
<div class="grid_6"><p><a class="button green small" href="/rowers/starttrial">Yes, I want to try Pro membership for 14 days for free. No strings attached.</a></p></div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="grid_6 omega">
|
||||
<h2>Recurring Payment</h2>
|
||||
<p>You need a Paypal account for this</p>
|
||||
<p><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<p>
|
||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
|
||||
{% if user.is_authenticated %}
|
||||
<input type="hidden" name="os0" value="{{ user }}">
|
||||
<input type="hidden" name="on0" value="username">
|
||||
{% endif %}
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online.">
|
||||
<table>
|
||||
<tr><td><input type="hidden" name="on0" value="Plans">Plans</td></tr><tr><td><select name="os0">
|
||||
<option value="Pro Membership">Pro Membership : €15.00 EUR - yearly</option>
|
||||
<option value="Self-Coach Membership">Self-Coach Membership : €75.00 EUR - yearly</option>
|
||||
<option value="Coach 4 athletes or less">Coach 4 athletes or less : €90.00 EUR - yearly</option>
|
||||
<option value="Coach 4-10 athletes">Coach 4-10 athletes : €200.00 EUR - yearly</option>
|
||||
<option value="Coach more than 10 athletes">Coach more than 10 athletes : €450.00 EUR - yearly</option>
|
||||
</select> </td></tr>
|
||||
<tr><td><input type="hidden" name="on1" value="Your User Name">Your User Name</td></tr><tr><td><input type="text" name="os1" maxlength="200"></td></tr>
|
||||
</table>
|
||||
<input type="hidden" name="currency_code" value="EUR">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_subscribeCC_LG_global.gif" border="0" name="submit" alt="PayPal – The safer, easier way to pay online!">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||
</form></p>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
<h2>One Year Subscription</h2>
|
||||
<p>Only a credit card needed. Will not automatically renew</p>
|
||||
|
||||
<p><form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
||||
<input type="hidden" name="cmd" value="_s-xclick">
|
||||
<input type="hidden" name="hosted_button_id" value="2YB32HQTF96QW">
|
||||
<table>
|
||||
<tr><td><input type="hidden" name="on0" value="Plans">Plans</td></tr><tr><td><select name="os0">
|
||||
<option value="Pro Membership">Pro Membership €20.00 EUR</option>
|
||||
<option value="Self-Coach Membership">Self-Coach Membership €90.00 EUR</option>
|
||||
<option value="Coach - 4 athletes or less">Coach - 4 athletes or less €120.00 EUR</option>
|
||||
<option value="Coach - 4-10 athletes">Coach - 4-10 athletes €250.00 EUR</option>
|
||||
<option value="Coach - more than 10 athletes">Coach - more than 10 athletes €500.00 EUR</option>
|
||||
</select> </td></tr>
|
||||
<tr><td><input type="hidden" name="on1" value="Your User Name">Your User Name</td></tr><tr><td><input type="text" name="os1" maxlength="200"></td></tr>
|
||||
</table>
|
||||
<input type="hidden" name="currency_code" value="EUR">
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/i/btn/btn_buynowCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
|
||||
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||
</form></p>
|
||||
</form>
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Payment Processing</h2>
|
||||
<p>After you do the payment, we will manually change your membership to
|
||||
|
||||
+5
-4
@@ -224,13 +224,13 @@ def geo_distance(lat1,lon1,lat2,lon2):
|
||||
dlon = lon2 - lon1
|
||||
dlat = lat2 - lat1
|
||||
|
||||
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
|
||||
c = 2 * atan2(sqrt(a), sqrt(1 - a))
|
||||
a = math.sin(dlat / 2)**2 + math.cos(lat1) * math.cos(lat2) * math.sin(dlon / 2)**2
|
||||
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
|
||||
|
||||
distance = R * c
|
||||
|
||||
tc1 = atan2(sin(lon2-lon1)*cos(lat2),
|
||||
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))
|
||||
tc1 = math.atan2(math.sin(lon2-lon1)*math.cos(lat2),
|
||||
math.cos(lat1)*math.sin(lat2)-math.sin(lat1)*math.cos(lat2)*math.cos(lon2-lon1))
|
||||
|
||||
tc1 = tc1 % (2*pi)
|
||||
|
||||
@@ -239,6 +239,7 @@ def geo_distance(lat1,lon1,lat2,lon2):
|
||||
return [distance,bearing]
|
||||
|
||||
|
||||
|
||||
def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
|
||||
pwr = abs(p0)/(1+(delta/abs(p2)))
|
||||
pwr += abs(p1)/(1+(delta/abs(p3)))
|
||||
|
||||
+14
-1
@@ -8462,6 +8462,7 @@ def course_edit_view(request,id=0):
|
||||
form = GeoCourseEditForm(request.POST)
|
||||
if form.is_valid():
|
||||
name = form.cleaned_data['name']
|
||||
country = form.cleaned_data['country']
|
||||
notes = form.cleaned_data['notes']
|
||||
if isinstance(name,unicode):
|
||||
name = name.encode('utf8')
|
||||
@@ -8469,6 +8470,7 @@ def course_edit_view(request,id=0):
|
||||
name = name.decode('utf8')
|
||||
|
||||
course.name = name
|
||||
course.country = country
|
||||
course.notes = notes
|
||||
course.save()
|
||||
|
||||
@@ -11882,6 +11884,7 @@ def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0):
|
||||
sessionvalue = cd['sessionvalue']
|
||||
sessionunit = cd['sessionunit']
|
||||
comment = cd['comment']
|
||||
course = cd['course']
|
||||
name = cd['name']
|
||||
|
||||
if sessionunit == 'min':
|
||||
@@ -11893,6 +11896,7 @@ def plannedsession_create_view(request,timeperiod='thisweek',rowerid=0):
|
||||
name=name,
|
||||
startdate=startdate,
|
||||
enddate=enddate,
|
||||
course=course,
|
||||
sessiontype=sessiontype,
|
||||
sessionmode=sessionmode,
|
||||
sessionvalue=sessionvalue,
|
||||
@@ -12074,6 +12078,7 @@ def plannedsession_teamcreate_view(request,timeperiod='thisweek',
|
||||
sessionvalue = cd['sessionvalue']
|
||||
sessionunit = cd['sessionunit']
|
||||
comment = cd['comment']
|
||||
course = cd['course']
|
||||
name = cd['name']
|
||||
|
||||
if sessionunit == 'min':
|
||||
@@ -12091,6 +12096,7 @@ def plannedsession_teamcreate_view(request,timeperiod='thisweek',
|
||||
sessionunit=sessionunit,
|
||||
comment=comment,
|
||||
criterium=criterium,
|
||||
course=course,
|
||||
manager=request.user)
|
||||
|
||||
ps.save()
|
||||
@@ -12632,7 +12638,14 @@ def plannedsession_view(request,id=0,rowerid=0,
|
||||
coursescript = ''
|
||||
coursediv = ''
|
||||
|
||||
if ps.manager != request.user and r not in ps.rower.all():
|
||||
if ps.manager != request.user:
|
||||
if r.rowerplan == 'coach':
|
||||
teams = Team.objects.filter(manager=request.user)
|
||||
members = Rower.objects.filter(team__in=teams).distinct()
|
||||
teamusers = [m.user for m in members]
|
||||
if ps.manager not in teamusers:
|
||||
raise PermissionDenied("You do not have access to this session")
|
||||
elif r not in ps.rower.all():
|
||||
raise PermissionDenied("You do not have access to this session")
|
||||
|
||||
resultsdict = get_session_metrics(ps)
|
||||
|
||||
Reference in New Issue
Block a user