Merge branch 'release/v2.9'
This commit is contained in:
@@ -95,6 +95,15 @@ from scipy.signal import savgol_filter
|
|||||||
|
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
|
def get_workouts(ids,userid):
|
||||||
|
goodids = []
|
||||||
|
for id in ids:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
if int(w.user.user.id) == int(userid):
|
||||||
|
goodids.append(id)
|
||||||
|
|
||||||
|
return [Workout.objects.get(id=id) for id in goodids]
|
||||||
|
|
||||||
def filter_df(datadf,fieldname,value,largerthan=True):
|
def filter_df(datadf,fieldname,value,largerthan=True):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ from rowsandall_app.settings import DATABASES
|
|||||||
|
|
||||||
from utils import lbstoN
|
from utils import lbstoN
|
||||||
|
|
||||||
|
|
||||||
user = DATABASES['default']['USER']
|
user = DATABASES['default']['USER']
|
||||||
password = DATABASES['default']['PASSWORD']
|
password = DATABASES['default']['PASSWORD']
|
||||||
database_name = DATABASES['default']['NAME']
|
database_name = DATABASES['default']['NAME']
|
||||||
@@ -335,6 +336,7 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
|||||||
|
|
||||||
return (f2,summary,oarlength,inboard)
|
return (f2,summary,oarlength,inboard)
|
||||||
|
|
||||||
|
|
||||||
# Create new workout from file and store it in the database
|
# Create new workout from file and store it in the database
|
||||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||||
# Currently there is code duplication
|
# Currently there is code duplication
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ def getexpired():
|
|||||||
if r.planexpires < datetime.datetime.now().date():
|
if r.planexpires < datetime.datetime.now().date():
|
||||||
if r.rowerplan == 'pro' or r.rowerplan == 'coach':
|
if r.rowerplan == 'pro' or r.rowerplan == 'coach':
|
||||||
lijst.append(r)
|
lijst.append(r)
|
||||||
|
if r.teamplanexpires < datetime.datetime.now().date():
|
||||||
|
if r.rowerplan == 'pro' or r.rowerplan == 'coach':
|
||||||
|
lijst.append(r)
|
||||||
return lijst
|
return lijst
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -173,6 +173,7 @@ class Rower(models.Model):
|
|||||||
|
|
||||||
# Power Zone Data
|
# Power Zone Data
|
||||||
ftp = models.IntegerField(default=226,verbose_name="Functional Threshold Power")
|
ftp = models.IntegerField(default=226,verbose_name="Functional Threshold Power")
|
||||||
|
otwslack = models.IntegerField(default=0,verbose_name="OTW Power slack")
|
||||||
|
|
||||||
pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
|
pw_ut2 = models.IntegerField(default=124,verbose_name="UT2 Power")
|
||||||
pw_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
|
pw_ut1 = models.IntegerField(default=171,verbose_name="UT1 Power")
|
||||||
@@ -576,7 +577,7 @@ class AdvancedWorkoutForm(ModelForm):
|
|||||||
class RowerPowerForm(ModelForm):
|
class RowerPowerForm(ModelForm):
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rower
|
model = Rower
|
||||||
fields = ['ftp']
|
fields = ['ftp','otwslack']
|
||||||
|
|
||||||
# Form to set rower's Power zones, including test routines
|
# Form to set rower's Power zones, including test routines
|
||||||
# to enable consistency
|
# to enable consistency
|
||||||
|
|||||||
@@ -123,12 +123,10 @@ of a rowers technique.</p>
|
|||||||
|
|
||||||
|
|
||||||
<p>Click on the PayPal button to pay for your Premium membership.
|
<p>Click on the PayPal button to pay for your Premium membership.
|
||||||
It will be valid for one year with automatic renewal which you can stop at any time.
|
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.
|
||||||
|
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.
|
You will be taken to the secure PayPal payment site.
|
||||||
<ul>
|
|
||||||
<li>Please mention the username you are registered under in
|
|
||||||
"instructions to seller".</li>
|
|
||||||
</ul>
|
|
||||||
</p>
|
</p>
|
||||||
<p>After you do the payment, we will manually change your membership to
|
<p>After you do the payment, we will manually change your membership to
|
||||||
"Pro". Depending on our availability, this may take some time
|
"Pro". Depending on our availability, this may take some time
|
||||||
@@ -138,6 +136,10 @@ You will be taken to the secure PayPal payment site.
|
|||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
<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="cmd" value="_s-xclick">
|
||||||
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
|
<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.">
|
<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">
|
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -6,36 +6,50 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Available on C2 Logbook</h1>
|
<h1>Available on C2 Logbook</h1>
|
||||||
{% if workouts %}
|
|
||||||
<table width="70%" class="listtable">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th> Import </th>
|
|
||||||
<th> Date/Time </th>
|
|
||||||
<th> Duration </th>
|
|
||||||
<th> Total Distance</th>
|
|
||||||
<th> Type</th>
|
|
||||||
<th> Source</th>
|
|
||||||
<th> Comment</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for workout in workouts %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a href="/rowers/workout/c2import/{{ workout|lookup:'id' }}/">Import</a></td>
|
|
||||||
<td>{{ workout|lookup:'starttime' }}</td>
|
|
||||||
<td>{{ workout|lookup:'duration' }}</td>
|
|
||||||
<td>{{ workout|lookup:'distance' }}</td>
|
|
||||||
<td>{{ workout|lookup:'rowtype' }}</td>
|
|
||||||
<td>{{ workout|lookup:'source' }}</td>
|
|
||||||
<td>{{ workout|lookup:'comment' }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{% endfor %}
|
{% if workouts %}
|
||||||
</tbody>
|
<div class="grid_2 alpha ">
|
||||||
</table>
|
<a href="/rowers/workout/c2import/all/" class="button gray">Import all NEW</a>
|
||||||
{% else %}
|
</div>
|
||||||
<p> No workouts found </p>
|
<div class="grid_10 omega">
|
||||||
{% endif %}
|
<p>This imports all workouts that have not been imported to rowsandall.com.
|
||||||
|
The action may take a longer time to process, so please be patient. Click on Import in the list below to import an individual workout.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid_12 alpha">
|
||||||
|
<table width="70%" class="listtable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> Import </th>
|
||||||
|
<th> Date/Time </th>
|
||||||
|
<th> Duration </th>
|
||||||
|
<th> Total Distance</th>
|
||||||
|
<th> Type</th>
|
||||||
|
<th> Source</th>
|
||||||
|
<th> Comment</th>
|
||||||
|
<th> New</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for workout in workouts %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/c2import/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||||
|
<td>{{ workout|lookup:'starttime' }}</td>
|
||||||
|
<td>{{ workout|lookup:'duration' }}</td>
|
||||||
|
<td>{{ workout|lookup:'distance' }}</td>
|
||||||
|
<td>{{ workout|lookup:'rowtype' }}</td>
|
||||||
|
<td>{{ workout|lookup:'source' }}</td>
|
||||||
|
<td>{{ workout|lookup:'comment' }}</td>
|
||||||
|
<td>{{ workout|lookup:'new' }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p> No workouts found </p>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
|
||||||
|
{% extends "base.html" %}
|
||||||
|
{% block title %}About us{% endblock title %}
|
||||||
|
{% block content %}
|
||||||
|
<h2>PayPal Test Button</h2>
|
||||||
|
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
|
||||||
|
<p>This is a test page for testing the paypal functionality. Do not use it.</p>
|
||||||
|
|
||||||
|
<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
|
||||||
|
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>
|
||||||
|
<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.
|
||||||
|
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">
|
||||||
|
<form action="https://www.sandbox.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="JN7HNMTDBDARJ">
|
||||||
|
{% 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.sandbox.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
|
||||||
|
<img alt="" border="0" src="https://www.sandbox.paypal.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>After you do the payment, we will manually change your membership to
|
||||||
|
"Pro". Depending on our availability, this may take some time
|
||||||
|
(typically one working day). 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 Pro membership, 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>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock content %}
|
||||||
@@ -19,11 +19,10 @@ website. </p>
|
|||||||
<li>Power histogram</li>
|
<li>Power histogram</li>
|
||||||
</ul>
|
</ul>
|
||||||
</p>
|
</p>
|
||||||
<p>Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time.
|
<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.
|
||||||
|
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.
|
You will be taken to the secure PayPal payment site.
|
||||||
<ul>
|
|
||||||
<li>Please mention the username you are registered under in "instructions to seller".</li>
|
|
||||||
</ul>
|
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -31,6 +30,10 @@ You will be taken to the secure PayPal payment site.
|
|||||||
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
|
<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="cmd" value="_s-xclick">
|
||||||
<input type="hidden" name="hosted_button_id" value="964GLEXX3THAW">
|
<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.">
|
<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">
|
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
<div class="grid_6 alpha">
|
<div class="grid_6 alpha">
|
||||||
<p>
|
<p>
|
||||||
<h2>Heart Rate Zones</h2>
|
<h2>Heart Rate Zones</h2>
|
||||||
|
<p>Set your heart rate zones with this form.</p>
|
||||||
{% if form.errors %}
|
{% if form.errors %}
|
||||||
<p style="color: red;">
|
<p style="color: red;">
|
||||||
Please correct the error{{ form.errors|pluralize }} below.
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
@@ -27,6 +28,8 @@
|
|||||||
<div class="grid_6 omega">
|
<div class="grid_6 omega">
|
||||||
<p>
|
<p>
|
||||||
<h2>Power Zones</h2>
|
<h2>Power Zones</h2>
|
||||||
|
<p>The power zones are defined relative to power as measured by the
|
||||||
|
indoor rower.</p>
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
{% if powerzonesform.errors %}
|
{% if powerzonesform.errors %}
|
||||||
<p style="color: red;">
|
<p style="color: red;">
|
||||||
@@ -127,10 +130,15 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="grid_6 omega">
|
<div class="grid_6 omega">
|
||||||
<p>
|
<p>
|
||||||
<h2>Functional Threshold Power</h2>
|
<h2>Functional Threshold Power and OTW Slack</h2>
|
||||||
<p>Use this form to quickly change your zones based on the power of a
|
<p>Use this form to quickly change your zones based on the power of a
|
||||||
recent
|
recent
|
||||||
full out 60 minutes effort. It will update all zones defined above.</p>
|
full out 60 minutes effort on the ergometer.
|
||||||
|
It will update all zones defined above.</p>
|
||||||
|
<p>The OTW Power Slack is the percentage drop of your On-the-water
|
||||||
|
rowing power
|
||||||
|
vs the erg power. Typical values are around 15%. This will lower
|
||||||
|
the power zones for your OTW workouts.</p>
|
||||||
<form enctype="multipart/form-data" action="" method="post">
|
<form enctype="multipart/form-data" action="" method="post">
|
||||||
<table>
|
<table>
|
||||||
{{ powerform.as_table }}
|
{{ powerform.as_table }}
|
||||||
|
|||||||
@@ -6,34 +6,47 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Available on SportTracks</h1>
|
<h1>Available on SportTracks</h1>
|
||||||
{% if workouts %}
|
{% if workouts %}
|
||||||
<table width="70%" class="listtable">
|
<div class="grid_2 alpha ">
|
||||||
<thead>
|
<a href="/rowers/workout/sporttracksimport/all/" class="button gray">Import all NEW</a>
|
||||||
<tr>
|
</div>
|
||||||
<th> Import </th>
|
<div class="grid_10 omega">
|
||||||
<th> Name </th>
|
<p>This imports all workouts that have not been imported to rowsandall.com.
|
||||||
<th> Date/Time </th>
|
The action may take a longer time to process, so please be patient. Click on Import in the list below to import an individual workout.
|
||||||
<th> Duration </th>
|
</p>
|
||||||
<th> Total Distance</th>
|
</div>
|
||||||
<th> Type</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for workout in workouts %}
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<a href="/rowers/workout/sporttracksimport/{{ workout|lookup:'id' }}/">Import</a></td>
|
|
||||||
<td>{{ workout|lookup:'name' }}</td>
|
|
||||||
<td>{{ workout|lookup:'starttime' }}</td>
|
|
||||||
<td>{{ workout|lookup:'duration' }} </td>
|
|
||||||
<td>{{ workout|lookup:'distance' }} m</td>
|
|
||||||
<td>{{ workout|lookup:'type' }}</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{% endfor %}
|
<div class="grid_12 alpha">
|
||||||
</tbody>
|
<table width="70%" class="listtable">
|
||||||
</table>
|
<thead>
|
||||||
{% else %}
|
<tr>
|
||||||
<p> No workouts found </p>
|
<th> Import </th>
|
||||||
{% endif %}
|
<th> Name </th>
|
||||||
|
<th> Date/Time </th>
|
||||||
|
<th> Duration </th>
|
||||||
|
<th> Total Distance</th>
|
||||||
|
<th> Type</th>
|
||||||
|
<th> New</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for workout in workouts %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/sporttracksimport/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||||
|
<td>{{ workout|lookup:'name' }}</td>
|
||||||
|
<td>{{ workout|lookup:'starttime' }}</td>
|
||||||
|
<td>{{ workout|lookup:'duration' }} </td>
|
||||||
|
<td>{{ workout|lookup:'distance' }} m</td>
|
||||||
|
<td>{{ workout|lookup:'type' }}</td>
|
||||||
|
<td>{{ workout|lookup:'new' }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p> No workouts found </p>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -6,47 +6,47 @@
|
|||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Available on Strava</h1>
|
<h1>Available on Strava</h1>
|
||||||
{% if data %}
|
{% if workouts %}
|
||||||
<table width="70%" class="listtable">
|
<div class="grid_2 alpha ">
|
||||||
<thead>
|
<a href="/rowers/workout/stravaimport/all/" class="button gray">Import all NEW</a>
|
||||||
<tr>
|
</div>
|
||||||
<th> Import </th>
|
<div class="grid_10 omega">
|
||||||
<th> Duration </th>
|
<p>This imports all workouts that have not been imported to rowsandall.com.
|
||||||
<th> Type</th>
|
The action may take a longer time to process, so please be patient. Click on Import in the list below to import an individual workout.
|
||||||
<th> Date</th>
|
</p>
|
||||||
<th> Distance </th>
|
</div>
|
||||||
<th> Name</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for workout in data %}
|
|
||||||
<tr>
|
|
||||||
{% for key,value in workout.items %}
|
|
||||||
{% if key == "start_date" %}
|
|
||||||
<td>{{ value }}</td>
|
|
||||||
{% endif %}
|
|
||||||
{% if key == "name" %}
|
|
||||||
<td>{{ value }}</td>
|
|
||||||
{% endif %}
|
|
||||||
{% if key == "type" %}
|
|
||||||
<td>{{ value }}</td>
|
|
||||||
{% endif %}
|
|
||||||
{% if key == "distance" %}
|
|
||||||
<td>{{ value }}m</td>
|
|
||||||
{% endif %}
|
|
||||||
{% if key == "elapsed_time" %}
|
|
||||||
<td>{{ value }}</td>
|
|
||||||
{% endif %}
|
|
||||||
{% if key == "id" %}
|
|
||||||
<td><a href="/rowers/workout/stravaimport/{{ value }}/">Import</a></td>
|
|
||||||
{% endif %}
|
|
||||||
{% endfor %}
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
{% endfor %}
|
<div class="grid_12 alpha">
|
||||||
</tbody>
|
<table width="70%" class="listtable">
|
||||||
</table>
|
<thead>
|
||||||
{% else %}
|
<tr>
|
||||||
<p> No workouts found </p>
|
<th> Import </th>
|
||||||
{% endif %}
|
<th> Name</th>
|
||||||
|
<th> Date</th>
|
||||||
|
<th> Duration </th>
|
||||||
|
<th> Distance </th>
|
||||||
|
<th> Type</th>
|
||||||
|
<th> New</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for workout in workouts %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/stravaimport/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||||
|
<td>{{ workout|lookup:'name' }}</td>
|
||||||
|
<td>{{ workout|lookup:'starttime' }}</td>
|
||||||
|
<td>{{ workout|lookup:'duration' }} </td>
|
||||||
|
<td>{{ workout|lookup:'distance' }} m</td>
|
||||||
|
<td>{{ workout|lookup:'type' }}</td>
|
||||||
|
<td>{{ workout|lookup:'new' }}</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% else %}
|
||||||
|
<p> No workouts found </p>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|||||||
@@ -170,6 +170,7 @@ urlpatterns = [
|
|||||||
url(r'^workout/(?P<id>\d+)/comment$',views.workout_comment_view),
|
url(r'^workout/(?P<id>\d+)/comment$',views.workout_comment_view),
|
||||||
url(r'^workout/(?P<id>\d+)/emailtcx$',views.workout_tcxemail_view),
|
url(r'^workout/(?P<id>\d+)/emailtcx$',views.workout_tcxemail_view),
|
||||||
url(r'^workout/(?P<id>\d+)/emailcsv$',views.workout_csvemail_view),
|
url(r'^workout/(?P<id>\d+)/emailcsv$',views.workout_csvemail_view),
|
||||||
|
url(r'^workout/(?P<id>\d+)/csvtoadmin$',views.workout_csvtoadmin_view),
|
||||||
url(r'^workout/compare/(?P<id>\d+)/$',views.workout_comparison_list),
|
url(r'^workout/compare/(?P<id>\d+)/$',views.workout_comparison_list),
|
||||||
url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
|
url(r'^workout/compare2/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view),
|
||||||
url(r'^workout/compare/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\w+.*)$',views.workout_comparison_list),
|
url(r'^workout/compare/(?P<id>\d+)/(?P<startdatestring>\d+-\d+-\d+)/(?P<enddatestring>\w+.*)$',views.workout_comparison_list),
|
||||||
@@ -211,9 +212,12 @@ urlpatterns = [
|
|||||||
url(r'^workout/c2import/$',views.workout_c2import_view),
|
url(r'^workout/c2import/$',views.workout_c2import_view),
|
||||||
url(r'^workout/stravaimport/$',views.workout_stravaimport_view),
|
url(r'^workout/stravaimport/$',views.workout_stravaimport_view),
|
||||||
url(r'^workout/c2import/(?P<c2id>\d+)/$',views.workout_getc2workout_view),
|
url(r'^workout/c2import/(?P<c2id>\d+)/$',views.workout_getc2workout_view),
|
||||||
|
url(r'^workout/c2import/all/$',views.workout_getc2workout_all),
|
||||||
url(r'^workout/stravaimport/(?P<stravaid>\d+)/$',views.workout_getstravaworkout_view),
|
url(r'^workout/stravaimport/(?P<stravaid>\d+)/$',views.workout_getstravaworkout_view),
|
||||||
|
url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all),
|
||||||
url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view),
|
url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view),
|
||||||
url(r'^workout/sporttracksimport/(?P<sporttracksid>\d+)/$',views.workout_getsporttracksworkout_view),
|
url(r'^workout/sporttracksimport/(?P<sporttracksid>\d+)/$',views.workout_getsporttracksworkout_view),
|
||||||
|
url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all),
|
||||||
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view),
|
url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view),
|
||||||
url(r'^workout/runkeeperimport/(?P<runkeeperid>\d+)/$',views.workout_getrunkeeperworkout_view),
|
url(r'^workout/runkeeperimport/(?P<runkeeperid>\d+)/$',views.workout_getrunkeeperworkout_view),
|
||||||
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
|
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
|
||||||
@@ -274,6 +278,7 @@ urlpatterns = [
|
|||||||
url(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'),
|
url(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'),
|
||||||
url(r'^analysis', TemplateView.as_view(template_name='analysis.html'),name='analysis'),
|
url(r'^analysis', TemplateView.as_view(template_name='analysis.html'),name='analysis'),
|
||||||
url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'),
|
url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'),
|
||||||
|
url(r'^paypaltest', TemplateView.as_view(template_name='paypaltest.html'),name='paypaltest'),
|
||||||
url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
|
url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'),
|
||||||
url(r'^register$',views.rower_register_view),
|
url(r'^register$',views.rower_register_view),
|
||||||
url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
|
url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'),
|
||||||
|
|||||||
@@ -4,6 +4,21 @@ import numpy as np
|
|||||||
|
|
||||||
lbstoN = 4.44822
|
lbstoN = 4.44822
|
||||||
|
|
||||||
|
def uniqify(seq, idfun=None):
|
||||||
|
# order preserving
|
||||||
|
if idfun is None:
|
||||||
|
def idfun(x): return x
|
||||||
|
seen = {}
|
||||||
|
result = []
|
||||||
|
for item in seq:
|
||||||
|
marker = idfun(item)
|
||||||
|
# in old Python versions:
|
||||||
|
# if seen.has_key(marker)
|
||||||
|
# but in new ones:
|
||||||
|
if marker in seen: continue
|
||||||
|
seen[marker] = 1
|
||||||
|
result.append(item)
|
||||||
|
return result
|
||||||
|
|
||||||
def serialize_list(value,token=','):
|
def serialize_list(value,token=','):
|
||||||
assert(isinstance(value, list) or isinstance(value, tuple) or isinstance(value,np.ndarray))
|
assert(isinstance(value, list) or isinstance(value, tuple) or isinstance(value,np.ndarray))
|
||||||
|
|||||||
+286
-27
@@ -267,7 +267,7 @@ def splitstdata(lijst):
|
|||||||
|
|
||||||
return [np.array(t),np.array(latlong)]
|
return [np.array(t),np.array(latlong)]
|
||||||
|
|
||||||
from utils import geo_distance,serialize_list,deserialize_list
|
from utils import geo_distance,serialize_list,deserialize_list,uniqify
|
||||||
from rowers.models import checkworkoutuser
|
from rowers.models import checkworkoutuser
|
||||||
|
|
||||||
# Check if a user is a Coach member
|
# Check if a user is a Coach member
|
||||||
@@ -1150,6 +1150,41 @@ def workout_csvemail_view(request,id=0):
|
|||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
# Get Workout CSV file and send it to user's email address
|
||||||
|
@login_required()
|
||||||
|
def workout_csvtoadmin_view(request,id=0):
|
||||||
|
message = ""
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
try:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
raise Http404("Workout doesn't exist")
|
||||||
|
|
||||||
|
csvfile = w.csvfilename
|
||||||
|
if settings.DEBUG:
|
||||||
|
res = handle_sendemailcsv.delay(
|
||||||
|
'Sander',
|
||||||
|
'Roosendaal',
|
||||||
|
'roosendaalsander@gmail.com',csvfile)
|
||||||
|
|
||||||
|
else:
|
||||||
|
res = queuehigh.enqueue(
|
||||||
|
handle_sendemailcsv,
|
||||||
|
'Sander',
|
||||||
|
'Roosendaal',
|
||||||
|
'roosendaalsander@gmail.com',
|
||||||
|
csvfile)
|
||||||
|
|
||||||
|
successmessage = "The CSV file was sent to the site admin per email"
|
||||||
|
messages.info(request,successmessage)
|
||||||
|
url = reverse(workout_export_view,
|
||||||
|
kwargs = {
|
||||||
|
'id':str(w.id),
|
||||||
|
})
|
||||||
|
response = HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
# Send workout to TP
|
# Send workout to TP
|
||||||
@login_required()
|
@login_required()
|
||||||
def workout_tp_upload_view(request,id=0):
|
def workout_tp_upload_view(request,id=0):
|
||||||
@@ -1310,8 +1345,10 @@ def workout_c2_upload_view(request,id=0):
|
|||||||
except C2NoTokenError:
|
except C2NoTokenError:
|
||||||
return HttpResponseRedirect("/rowers/me/c2authorize/")
|
return HttpResponseRedirect("/rowers/me/c2authorize/")
|
||||||
|
|
||||||
if message:
|
if message and c2id <=0:
|
||||||
messages.error(request,message)
|
messages.error(request,message)
|
||||||
|
elif message:
|
||||||
|
messages.info(request,message)
|
||||||
|
|
||||||
|
|
||||||
url = reverse(workout_export_view,
|
url = reverse(workout_export_view,
|
||||||
@@ -1499,6 +1536,8 @@ def workout_sporttracks_upload_view(request,id=0):
|
|||||||
sporttracksid = sporttracksstuff.getidfromresponse(response)
|
sporttracksid = sporttracksstuff.getidfromresponse(response)
|
||||||
w.uploadedtosporttracks = sporttracksid
|
w.uploadedtosporttracks = sporttracksid
|
||||||
w.save()
|
w.save()
|
||||||
|
message = "Upload to SportTracks was successful"
|
||||||
|
messages.info(message)
|
||||||
url = "/rowers/workout/"+str(w.id)+"/export"
|
url = "/rowers/workout/"+str(w.id)+"/export"
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
@@ -3111,7 +3150,7 @@ def boxplot_view(request,userid=0,
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
return HttpResponse("Form is not valid")
|
return HttpResponse("Form is not valid")
|
||||||
if request.method == 'POST' and 'ids' in request.session:
|
elif request.method == 'POST' and 'ids' in request.session:
|
||||||
chartform = BoxPlotChoiceForm(request.POST)
|
chartform = BoxPlotChoiceForm(request.POST)
|
||||||
if chartform.is_valid():
|
if chartform.is_valid():
|
||||||
plotfield = chartform.cleaned_data['yparam']
|
plotfield = chartform.cleaned_data['yparam']
|
||||||
@@ -3124,7 +3163,18 @@ def boxplot_view(request,userid=0,
|
|||||||
workstrokesonly = not includereststrokes
|
workstrokesonly = not includereststrokes
|
||||||
ids = request.session['ids']
|
ids = request.session['ids']
|
||||||
request.session['ids'] = ids
|
request.session['ids'] = ids
|
||||||
workouts = [Workout.objects.get(id=id) for id in ids]
|
workouts = dataprep.get_workouts(ids,userid)
|
||||||
|
if not workouts:
|
||||||
|
message = 'Error: Workouts in session storage do not belong to this user.'
|
||||||
|
messages.error(request,message)
|
||||||
|
url = reverse(user_boxplot_select,
|
||||||
|
kwargs={
|
||||||
|
'userid':userid,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# workouts = [Workout.objects.get(id=id) for id in ids]
|
||||||
|
|
||||||
labeldict = {
|
labeldict = {
|
||||||
int(w.id): w.__unicode__() for w in workouts
|
int(w.id): w.__unicode__() for w in workouts
|
||||||
@@ -4344,6 +4394,10 @@ def cumstats(request,theuser=0,
|
|||||||
def workout_stats_view(request,id=0,message="",successmessage=""):
|
def workout_stats_view(request,id=0,message="",successmessage=""):
|
||||||
|
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
|
try:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
raise Http404("Workout doesn't exist")
|
||||||
|
|
||||||
workstrokesonly = True
|
workstrokesonly = True
|
||||||
if request.method == 'POST' and 'workstrokesonly' in request.POST:
|
if request.method == 'POST' and 'workstrokesonly' in request.POST:
|
||||||
@@ -4412,9 +4466,13 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
|||||||
pwr4 = datadf['power']**(4)
|
pwr4 = datadf['power']**(4)
|
||||||
normp = (pwr4.mean())**(0.25)
|
normp = (pwr4.mean())**(0.25)
|
||||||
if not np.isnan(normp):
|
if not np.isnan(normp):
|
||||||
intensityfactor = datadf['power'].mean()/float(r.ftp)
|
ftp = float(r.ftp)
|
||||||
intensityfactor = normp/float(r.ftp)
|
if w.workouttype == 'water':
|
||||||
tss = 100.*((duration*normp*intensityfactor)/(3600.*r.ftp))
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
|
intensityfactor = datadf['power'].mean()/float(ftp)
|
||||||
|
intensityfactor = normp/float(ftp)
|
||||||
|
tss = 100.*((duration*normp*intensityfactor)/(3600.*ftp))
|
||||||
|
|
||||||
if not np.isnan(tss):
|
if not np.isnan(tss):
|
||||||
otherstats['tss'] = {
|
otherstats['tss'] = {
|
||||||
@@ -5249,6 +5307,10 @@ def workout_add_otw_powerplot_view(request,id):
|
|||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
|
||||||
|
ftp = r.ftp
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
'hrut2':r.ut2,
|
'hrut2':r.ut2,
|
||||||
@@ -5256,7 +5318,7 @@ def workout_add_otw_powerplot_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5306,6 +5368,9 @@ def workout_add_piechart_view(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
@@ -5314,7 +5379,7 @@ def workout_add_piechart_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5364,6 +5429,9 @@ def workout_add_power_piechart_view(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
@@ -5372,7 +5440,7 @@ def workout_add_power_piechart_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5419,6 +5487,9 @@ def workout_add_timeplot_view(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
@@ -5427,7 +5498,7 @@ def workout_add_timeplot_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5476,6 +5547,9 @@ def workout_add_distanceplot_view(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
@@ -5484,7 +5558,7 @@ def workout_add_distanceplot_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5531,6 +5605,9 @@ def workout_add_distanceplot2_view(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
@@ -5539,7 +5616,7 @@ def workout_add_distanceplot2_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5588,6 +5665,9 @@ def workout_add_timeplot2_view(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
@@ -5596,7 +5676,7 @@ def workout_add_timeplot2_view(request,id):
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -5640,10 +5720,33 @@ def workout_stravaimport_view(request,message=""):
|
|||||||
url = reverse(workouts_view)
|
url = reverse(workouts_view)
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
data = res.json()
|
workouts = []
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
stravaids = [int(item['id']) for item in res.json()]
|
||||||
|
knownstravaids = uniqify([
|
||||||
|
w.uploadedtostrava for w in Workout.objects.filter(user=r)
|
||||||
|
])
|
||||||
|
newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids]
|
||||||
|
|
||||||
|
for item in res.json():
|
||||||
|
d = int(float(item['distance']))
|
||||||
|
i = item['id']
|
||||||
|
if i in knownstravaids:
|
||||||
|
nnn = ''
|
||||||
|
else:
|
||||||
|
nnn = 'NEW'
|
||||||
|
n = item['name']
|
||||||
|
ttot = str(datetime.timedelta(seconds=int(float(item['elapsed_time']))))
|
||||||
|
s = item['start_date']
|
||||||
|
r = item['type']
|
||||||
|
keys = ['id','distance','duration','starttime','type','name','new']
|
||||||
|
values = [i,d,ttot,s,r,n,nnn]
|
||||||
|
res = dict(zip(keys,values))
|
||||||
|
workouts.append(res)
|
||||||
|
|
||||||
|
|
||||||
return render(request,'strava_list_import.html',
|
return render(request,'strava_list_import.html',
|
||||||
{'data':data,
|
{'workouts':workouts,
|
||||||
'teams':get_my_teams(request.user),
|
'teams':get_my_teams(request.user),
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -5753,15 +5856,25 @@ def workout_sporttracksimport_view(request,message=""):
|
|||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
workouts = []
|
workouts = []
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
stids = [int(getidfromsturi(item['uri'])) for item in res.json()['items']]
|
||||||
|
knownstids = uniqify([
|
||||||
|
w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
|
||||||
|
])
|
||||||
|
newids = [stid for stid in stids if not stid in knownstids]
|
||||||
for item in res.json()['items']:
|
for item in res.json()['items']:
|
||||||
d = int(float(item['total_distance']))
|
d = int(float(item['total_distance']))
|
||||||
i = getidfromsturi(item['uri'])
|
i = int(getidfromsturi(item['uri']))
|
||||||
|
if i in knownstids:
|
||||||
|
nnn = ''
|
||||||
|
else:
|
||||||
|
nnn = 'NEW'
|
||||||
n = item['name']
|
n = item['name']
|
||||||
ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
|
ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
|
||||||
s = item['start_time']
|
s = item['start_time']
|
||||||
r = item['type']
|
r = item['type']
|
||||||
keys = ['id','distance','duration','starttime','type','name']
|
keys = ['id','distance','duration','starttime','type','name','new']
|
||||||
values = [i,d,ttot,s,r,n]
|
values = [i,d,ttot,s,r,n,nnn]
|
||||||
res = dict(zip(keys,values))
|
res = dict(zip(keys,values))
|
||||||
workouts.append(res)
|
workouts.append(res)
|
||||||
return render(request,'sporttracks_list_import.html',
|
return render(request,'sporttracks_list_import.html',
|
||||||
@@ -5813,6 +5926,57 @@ def c2listdebug_view(request,message=""):
|
|||||||
'teams':get_my_teams(request.user),
|
'teams':get_my_teams(request.user),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# Import all unknown workouts available on Concept2 logbook
|
||||||
|
@login_required()
|
||||||
|
def workout_getc2workout_all(request,message=""):
|
||||||
|
try:
|
||||||
|
thetoken = c2_open(request.user)
|
||||||
|
except C2NoTokenError:
|
||||||
|
return HttpResponseRedirect("/rowers/me/c2authorize/")
|
||||||
|
|
||||||
|
res = c2stuff.get_c2_workout_list(request.user)
|
||||||
|
|
||||||
|
if (res.status_code != 200):
|
||||||
|
message = "Something went wrong in workout_c2import_view (C2 token refresh)"
|
||||||
|
messages.error(request,message)
|
||||||
|
else:
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
c2ids = [item['id'] for item in res.json()['data']]
|
||||||
|
knownc2ids = uniqify([
|
||||||
|
w.uploadedtoc2 for w in Workout.objects.filter(user=r)
|
||||||
|
])
|
||||||
|
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
||||||
|
for c2id in newids:
|
||||||
|
res = c2stuff.get_c2_workout(request.user,c2id)
|
||||||
|
if (res.status_code == 200):
|
||||||
|
data = res.json()['data']
|
||||||
|
splitdata = None
|
||||||
|
if 'workout' in data:
|
||||||
|
if 'splits' in data['workout']:
|
||||||
|
splitdata = data['workout']['splits']
|
||||||
|
if 'intervals' in data['workout']:
|
||||||
|
splitdata = data['workout']['intervals']
|
||||||
|
|
||||||
|
# Check if workout has stroke data, and get the stroke data
|
||||||
|
if data['stroke_data']:
|
||||||
|
res2 = c2stuff.get_c2_workout_strokes(request.user,c2id)
|
||||||
|
# We have stroke data
|
||||||
|
if res2.status_code == 200:
|
||||||
|
strokedata = pd.DataFrame.from_dict(res2.json()['data'])
|
||||||
|
# create the workout
|
||||||
|
id,message = add_workout_from_strokedata(
|
||||||
|
request.user,c2id,data,strokedata,
|
||||||
|
source='c2')
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
w.uploadedtoc2=c2id
|
||||||
|
w.save()
|
||||||
|
if message:
|
||||||
|
messages.error(request,message)
|
||||||
|
|
||||||
|
url = reverse(workouts_view)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
# List of workouts available on Concept2 logbook - for import
|
# List of workouts available on Concept2 logbook - for import
|
||||||
@login_required()
|
@login_required()
|
||||||
def workout_c2import_view(request,message=""):
|
def workout_c2import_view(request,message=""):
|
||||||
@@ -5833,6 +5997,12 @@ def workout_c2import_view(request,message=""):
|
|||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
else:
|
else:
|
||||||
workouts = []
|
workouts = []
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
c2ids = [item['id'] for item in res.json()['data']]
|
||||||
|
knownc2ids = uniqify([
|
||||||
|
w.uploadedtoc2 for w in Workout.objects.filter(user=r)
|
||||||
|
])
|
||||||
|
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
||||||
for item in res.json()['data']:
|
for item in res.json()['data']:
|
||||||
d = item['distance']
|
d = item['distance']
|
||||||
i = item['id']
|
i = item['id']
|
||||||
@@ -5841,8 +6011,12 @@ def workout_c2import_view(request,message=""):
|
|||||||
r = item['type']
|
r = item['type']
|
||||||
s2 = item['source']
|
s2 = item['source']
|
||||||
c = item['comments']
|
c = item['comments']
|
||||||
keys = ['id','distance','duration','starttime','rowtype','source','comment']
|
if i in knownc2ids:
|
||||||
values = [i,d,ttot,s,r,s2,c]
|
nnn = ''
|
||||||
|
else:
|
||||||
|
nnn = 'NEW'
|
||||||
|
keys = ['id','distance','duration','starttime','rowtype','source','comment','new']
|
||||||
|
values = [i,d,ttot,s,r,s2,c,nnn]
|
||||||
res = dict(zip(keys,values))
|
res = dict(zip(keys,values))
|
||||||
workouts.append(res)
|
workouts.append(res)
|
||||||
|
|
||||||
@@ -5948,6 +6122,69 @@ def workout_getsporttracksworkout_view(request,sporttracksid):
|
|||||||
})
|
})
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# Imports all new workouts from SportTracks
|
||||||
|
@login_required()
|
||||||
|
def workout_getsporttracksworkout_all(request):
|
||||||
|
res = sporttracksstuff.get_sporttracks_workout_list(request.user)
|
||||||
|
if (res.status_code == 200):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
stids = [int(getidfromsturi(item['uri'])) for item in res.json()['items']]
|
||||||
|
knownstids = uniqify([
|
||||||
|
w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
|
||||||
|
])
|
||||||
|
newids = [stid for stid in stids if not stid in knownstids]
|
||||||
|
for sporttracksid in newids:
|
||||||
|
res = sporttracksstuff.get_sporttracks_workout(
|
||||||
|
request.user,sporttracksid)
|
||||||
|
data = res.json()
|
||||||
|
|
||||||
|
id,message = add_workout_from_stdata(request.user,sporttracksid,data)
|
||||||
|
if id==0:
|
||||||
|
messages.error(request,message)
|
||||||
|
|
||||||
|
else:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
w.uploadedtosporttracks=sporttracksid
|
||||||
|
w.save()
|
||||||
|
|
||||||
|
url = reverse(workouts_view)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
# Imports all new workouts from SportTracks
|
||||||
|
@login_required()
|
||||||
|
def workout_getstravaworkout_all(request):
|
||||||
|
res = stravastuff.get_strava_workout_list(request.user)
|
||||||
|
if (res.status_code == 200):
|
||||||
|
r = Rower.objects.get(user=request.user)
|
||||||
|
stravaids = [int(item['id']) for item in res.json()]
|
||||||
|
knownstravaids = uniqify([
|
||||||
|
w.uploadedtostrava for w in Workout.objects.filter(user=r)
|
||||||
|
])
|
||||||
|
newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids]
|
||||||
|
|
||||||
|
for stravaid in newids:
|
||||||
|
res = stravastuff.get_strava_workout(request.user,stravaid)
|
||||||
|
strokedata = res[1]
|
||||||
|
data = res[0]
|
||||||
|
|
||||||
|
id,message = add_workout_from_strokedata(request.user,stravaid,data,strokedata,
|
||||||
|
source='strava',
|
||||||
|
workoutsource='strava')
|
||||||
|
|
||||||
|
if id==0:
|
||||||
|
messages.error(request,message)
|
||||||
|
|
||||||
|
else:
|
||||||
|
w = Workout.objects.get(id=id)
|
||||||
|
w.uploadedtostrava=stravaid
|
||||||
|
w.save()
|
||||||
|
|
||||||
|
url = reverse(workouts_view)
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Imports a workout from Concept2
|
# Imports a workout from Concept2
|
||||||
@login_required()
|
@login_required()
|
||||||
def workout_getc2workout_view(request,c2id):
|
def workout_getc2workout_view(request,c2id):
|
||||||
@@ -6180,6 +6417,10 @@ def workout_upload_view(request,
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
'hrut2':r.ut2,
|
'hrut2':r.ut2,
|
||||||
@@ -6187,7 +6428,7 @@ def workout_upload_view(request,
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -6424,6 +6665,10 @@ def team_workout_upload_view(request,message="",
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if w.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
hrpwrdata = {
|
hrpwrdata = {
|
||||||
'hrmax':r.max,
|
'hrmax':r.max,
|
||||||
'hrut2':r.ut2,
|
'hrut2':r.ut2,
|
||||||
@@ -6431,7 +6676,7 @@ def team_workout_upload_view(request,message="",
|
|||||||
'hrat':r.at,
|
'hrat':r.at,
|
||||||
'hrtr':r.tr,
|
'hrtr':r.tr,
|
||||||
'hran':r.an,
|
'hran':r.an,
|
||||||
'ftp':r.ftp,
|
'ftp':ftp,
|
||||||
'powerperc':serialize_list(powerperc),
|
'powerperc':serialize_list(powerperc),
|
||||||
'powerzones':serialize_list(r.powerzones),
|
'powerzones':serialize_list(r.powerzones),
|
||||||
}
|
}
|
||||||
@@ -6633,9 +6878,13 @@ def workout_summary_restore_view(request,id,message="",successmessage=""):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if row.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||||
hrut1=r.ut1,hrat=r.at,
|
hrut1=r.ut1,hrat=r.at,
|
||||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
hrtr=r.tr,hran=r.an,ftp=ftp,
|
||||||
powerperc=powerperc,powerzones=r.powerzones)
|
powerperc=powerperc,powerzones=r.powerzones)
|
||||||
rowdata = rdata(f1,rower=rr)
|
rowdata = rdata(f1,rower=rr)
|
||||||
if rowdata == 0:
|
if rowdata == 0:
|
||||||
@@ -6744,9 +6993,13 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if row.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||||
hrut1=r.ut1,hrat=r.at,
|
hrut1=r.ut1,hrat=r.at,
|
||||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
hrtr=r.tr,hran=r.an,ftp=ftp,
|
||||||
powerperc=powerperc,powerzones=r.powerzones)
|
powerperc=powerperc,powerzones=r.powerzones)
|
||||||
rowdata = rdata(f1,rower=rr)
|
rowdata = rdata(f1,rower=rr)
|
||||||
if rowdata == 0:
|
if rowdata == 0:
|
||||||
@@ -7065,6 +7318,7 @@ def rower_edit_view(request,message=""):
|
|||||||
if powerform.is_valid():
|
if powerform.is_valid():
|
||||||
cd = powerform.cleaned_data
|
cd = powerform.cleaned_data
|
||||||
ftp = cd['ftp']
|
ftp = cd['ftp']
|
||||||
|
otwslack = cd['otwslack']
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(user=request.user)
|
r = Rower.objects.get(user=request.user)
|
||||||
powerfrac = 100*np.array([r.pw_ut2,
|
powerfrac = 100*np.array([r.pw_ut2,
|
||||||
@@ -7072,6 +7326,7 @@ def rower_edit_view(request,message=""):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
r.ftp = max(min(ftp,650),50)
|
r.ftp = max(min(ftp,650),50)
|
||||||
|
r.otwslack = max(min(otwslack,50),0)
|
||||||
ut2,ut1,at,tr,an = (r.ftp*powerfrac/100.).astype(int)
|
ut2,ut1,at,tr,an = (r.ftp*powerfrac/100.).astype(int)
|
||||||
r.pw_ut2 = ut2
|
r.pw_ut2 = ut2
|
||||||
r.pw_ut1 = ut1
|
r.pw_ut1 = ut1
|
||||||
@@ -7079,7 +7334,7 @@ def rower_edit_view(request,message=""):
|
|||||||
r.pw_tr = tr
|
r.pw_tr = tr
|
||||||
r.pw_an = an
|
r.pw_an = an
|
||||||
r.save()
|
r.save()
|
||||||
message = "Functional Threshold Value Changed"
|
message = "FTP and/or OTW slack values changed."
|
||||||
messages.info(request,message)
|
messages.info(request,message)
|
||||||
url = reverse(rower_edit_view)
|
url = reverse(rower_edit_view)
|
||||||
response = HttpResponseRedirect(url)
|
response = HttpResponseRedirect(url)
|
||||||
@@ -7428,9 +7683,13 @@ def strokedatajson(request,id):
|
|||||||
r.pw_at,
|
r.pw_at,
|
||||||
r.pw_tr,r.pw_an])/r.ftp
|
r.pw_tr,r.pw_an])/r.ftp
|
||||||
|
|
||||||
|
ftp = float(r.ftp)
|
||||||
|
if row.workouttype == 'water':
|
||||||
|
ftp = ftp*(100.-r.otwslack)/100.
|
||||||
|
|
||||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||||
hrut1=r.ut1,hrat=r.at,
|
hrut1=r.ut1,hrat=r.at,
|
||||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
hrtr=r.tr,hran=r.an,ftp=ftp,
|
||||||
powerperc=powerperc,powerzones=r.powerzones)
|
powerperc=powerperc,powerzones=r.powerzones)
|
||||||
rowdata = rdata(row.csvfilename,rower=rr).df
|
rowdata = rdata(row.csvfilename,rower=rr).df
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user