Private
Public Access
1
0

Merge branch 'release/v8.56'

This commit is contained in:
Sander Roosendaal
2018-11-26 21:05:53 +01:00
18 changed files with 168 additions and 19 deletions
+1
View File
@@ -32,6 +32,7 @@ oauth_data = {
'expirydatename': 'tokenexpirydate', 'expirydatename': 'tokenexpirydate',
'bearer_auth': True, 'bearer_auth': True,
'base_url': "https://log.concept2.com/oauth/access_token", 'base_url': "https://log.concept2.com/oauth/access_token",
'scope':'write',
} }
+4 -1
View File
@@ -1251,7 +1251,10 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
data.to_sql('strokedata',engine,if_exists='append',index=False) data.to_sql('strokedata',engine,if_exists='append',index=False)
except: except:
data.drop(columns=['rhythm'],inplace=True) data.drop(columns=['rhythm'],inplace=True)
data.to_sql('strokedata',engine,if_exists='append',index=False) try:
data.to_sql('strokedata',engine,if_exists='append',index=False)
except:
pass
conn.close() conn.close()
engine.dispose() engine.dispose()
+3 -1
View File
@@ -216,6 +216,8 @@ def imports_get_token(
if 'grant_type' in oauth_data: if 'grant_type' in oauth_data:
if oauth_data['grant_type']: if oauth_data['grant_type']:
post_data['grant_type'] = oauth_data['grant_type'] post_data['grant_type'] = oauth_data['grant_type']
if 'strava' in oauth_data['autorization_uri']:
post_data['grant_type'] = "authorization_code"
else: else:
grant_type = post_data.pop('grant_type',None) grant_type = post_data.pop('grant_type',None)
@@ -265,7 +267,7 @@ def imports_make_authorization_url(oauth_data):
params = {"client_id": oauth_data['client_id'], params = {"client_id": oauth_data['client_id'],
"response_type": "code", "response_type": "code",
"redirect_uri": oauth_data['redirect_uri'], "redirect_uri": oauth_data['redirect_uri'],
"scope":"write", "scope":oauth_data['scope'],
"state":state} "state":state}
+18 -2
View File
@@ -2091,7 +2091,8 @@ class Workout(models.Model):
user = models.ForeignKey(Rower) user = models.ForeignKey(Rower)
team = models.ManyToManyField(Team,blank=True) team = models.ManyToManyField(Team,blank=True)
plannedsession = models.ForeignKey(PlannedSession, blank=True,null=True) plannedsession = models.ForeignKey(PlannedSession, blank=True,null=True,
verbose_name='Session')
name = models.CharField(max_length=150,blank=True,null=True) name = models.CharField(max_length=150,blank=True,null=True)
date = models.DateField() date = models.DateField()
workouttype = models.CharField(choices=workouttypes,max_length=50, workouttype = models.CharField(choices=workouttypes,max_length=50,
@@ -2452,7 +2453,7 @@ class WorkoutForm(ModelForm):
# duration = forms.TimeInput(format='%H:%M:%S.%f') # duration = forms.TimeInput(format='%H:%M:%S.%f')
class Meta: class Meta:
model = Workout model = Workout
fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece','duplicate'] fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece','duplicate','plannedsession']
widgets = { widgets = {
'date': AdminDateWidget(), 'date': AdminDateWidget(),
'notes': forms.Textarea, 'notes': forms.Textarea,
@@ -2475,6 +2476,21 @@ class WorkoutForm(ModelForm):
else: else:
self.fields['private'].initial = True self.fields['private'].initial = True
workout = self.instance
sps = PlannedSession.objects.filter(
rower__in=[workout.user],
startdate__lte=workout.date,
enddate__gte=workout.date,
).order_by("preferreddate","startdate","enddate").exclude(
sessiontype='race')
if not sps:
del self.fields['plannedsession']
else:
self.fields['plannedsession'].queryset = sps
else:
del self.fields['plannedsession']
# Used for the rowing physics calculations # Used for the rowing physics calculations
class AdvancedWorkoutForm(ModelForm): class AdvancedWorkoutForm(ModelForm):
quick_calc = forms.BooleanField(initial=True,required=False) quick_calc = forms.BooleanField(initial=True,required=False)
+2 -1
View File
@@ -19,7 +19,8 @@ oauth_data = {
'expirydatename': None, 'expirydatename': None,
'bearer_auth': True, 'bearer_auth': True,
'base_url': "https://runkeeper.com/apps/token", 'base_url': "https://runkeeper.com/apps/token",
'headers': {'user-agent': 'sanderroosendaal'} 'headers': {'user-agent': 'sanderroosendaal'},
'scope':'write',
} }
+1
View File
@@ -20,6 +20,7 @@ oauth_data = {
'expirydatename': 'sporttrackstokenexpirydate', 'expirydatename': 'sporttrackstokenexpirydate',
'bearer_auth': False, 'bearer_auth': False,
'base_url': "https://api.sporttracks.mobi/oauth2/token", 'base_url': "https://api.sporttracks.mobi/oauth2/token",
'scope':'write',
} }
# Checks if user has SportTracks token, renews them if they are expired # Checks if user has SportTracks token, renews them if they are expired
+8
View File
@@ -33,6 +33,12 @@ except ImportError:
from rowers.imports import * from rowers.imports import *
headers = {'Accept': 'application/json',
'Api-Key': STRAVA_CLIENT_ID,
'Content-Type': 'application/json',
'user-agent': 'sanderroosendaal'}
oauth_data = { oauth_data = {
'client_id': STRAVA_CLIENT_ID, 'client_id': STRAVA_CLIENT_ID,
'client_secret': STRAVA_CLIENT_SECRET, 'client_secret': STRAVA_CLIENT_SECRET,
@@ -45,6 +51,8 @@ oauth_data = {
'bearer_auth': True, 'bearer_auth': True,
'base_url': "https://www.strava.com/oauth/token", 'base_url': "https://www.strava.com/oauth/token",
'grant_type': 'refresh_token', 'grant_type': 'refresh_token',
'headers': headers,
'scope':'activity:write,activity:read_all',
} }
+19
View File
@@ -610,6 +610,7 @@ def handle_calctrimp(id,
intensityfactor = normp/float(ftp) intensityfactor = normp/float(ftp)
tss = 100.*((duration*normp*intensityfactor)/(3600.*ftp)) tss = 100.*((duration*normp*intensityfactor)/(3600.*ftp))
if sex == 'male': if sex == 'male':
f = 1.92 f = 1.92
else: else:
@@ -646,6 +647,24 @@ def handle_calctrimp(id,
if not np.isfinite(normw): if not np.isfinite(normw):
normw = 0 normw = 0
try:
dum = int(tss)
except ValueError:
tss = 0
try:
dum = int(normp)
except ValueError:
normp = 0
try:
dump = int(trimp)
except ValueError:
trimp = 0
try:
dump = int(hrtss)
except ValueError:
hrtss = 0
query = 'UPDATE rowers_workout SET rscore = {tss}, normp = {normp}, trimp={trimp}, hrtss={hrtss}, normv={normv}, normw={normw} WHERE id={id}'.format( query = 'UPDATE rowers_workout SET rscore = {tss}, normp = {normp}, trimp={trimp}, hrtss={hrtss}, normv={normv}, normw={normw} WHERE id={id}'.format(
tss = int(tss), tss = int(tss),
normp = int(normp), normp = int(normp),
+7 -2
View File
@@ -5,13 +5,18 @@
{% block title %}GDPR Opt-In{% endblock %} {% block title %}GDPR Opt-In{% endblock %}
{% block main %} {% block main %}
<p>
We know you are eager to start using rowsandall.com, but we must
ask you to read and agree with the below first.
</p>
<h2>GDPR Opt-In</h2> <h2>GDPR Opt-In</h2>
<p> <p>
<b> <b>
To comply with the European Union General Data Protection Regulation, To comply with the European Union General Data Protection Regulation,
we need to record your consent to use personal data on this website. we need to record your consent to use personal data on this website.
Please take some time to review our data policies. If you agree and Please take some time to review our data policies. If you agree and
opt in, click the green button at the bottom to be taken to the site. opt in, click the "opt in" button at the bottom to be taken to the site.
If you do not agree, please use the red button to delete your If you do not agree, please use the red button to delete your
account. This will irreversibly delete all your data on rowsandall.com account. This will irreversibly delete all your data on rowsandall.com
and remove your account. and remove your account.
@@ -32,7 +37,7 @@
</p> </p>
<p> <p>
<a class="button gray small" href="/rowers/me/gdpr-optin-confirm/?next={{ next }}">Opt in and continue</a> <a class="button green small" href="/rowers/me/gdpr-optin-confirm/?next={{ next }}">Opt in and continue</a>
</p> </p>
<p> <p>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block scripts %} {% block scripts %}
<script> <script>
setTimeout("location.reload(true);",60000); setTimeout("location.reload(true);",180000);
</script> </script>
<script <script
type='text/javascript' type='text/javascript'
+1 -1
View File
@@ -57,7 +57,7 @@
<li> <li>
<a href={{ request.path|userurl:member }}> <a href={{ request.path|userurl:member }}>
<i class="fas fa-user fa-fw"></i> <i class="fas fa-user fa-fw"></i>
{% if member == rower.user and team.id == 0 %} {% if member == rower.user and not team %}
&bull; &bull;
{% else %} {% else %}
&nbsp; &nbsp;
+11 -1
View File
@@ -9,7 +9,7 @@
Please correct the error{{ form.errors|pluralize }} below. Please correct the error{{ form.errors|pluralize }} below.
</p> </p>
{% endif %} {% endif %}
<p>
<form enctype="multipart/form-data" action="" method="post"> <form enctype="multipart/form-data" action="" method="post">
<table> <table>
{{ form.as_table }} {{ form.as_table }}
@@ -17,6 +17,16 @@
{% csrf_token %} {% csrf_token %}
<input class="button green" type="submit" value="Save"> <input class="button green" type="submit" value="Save">
</form> </form>
</p>
<p>Click on one of the icons below to connect to the service of your
choice or to renew the authorization</p>
<p><a href="/rowers/me/stravaauthorize/"><img src="/static/img/ConnectWithStrava.png" alt="connect with strava" width="120"></a></p>
<p><a href="/rowers/me/c2authorize/"><img src="/static/img/blueC2logo.png" alt="connect with Concept2" width="120"></a></p>
<p><a href="/rowers/me/sporttracksauthorize/"><img src="/static/img/sporttracks-button.png" alt="connect with SportTracks" width="120"></a></p>
<p><a href="/rowers/me/runkeeperauthorize/"><img src="/static/img/rk-logo.png" alt="connect with RunKeeper" width="120"></a></p>
<p><a href="/rowers/me/underarmourauthorize/"><img src="/static/img/UAbtn.png" alt="connect with Under Armour" width="120"></a></p>
<p><a href="/rowers/me/polarauthorize/"><img src="/static/img/Polar_connectwith_btn_white.png"
alt="connect with Polar" width="130"></a></p>
+12 -1
View File
@@ -41,6 +41,17 @@ $('#id_workouttype').change();
{% block main %} {% block main %}
<p>
{% if workout|previousworkout:rower.user %}
<a href="/rowers/workout/{{ workout|previousworkout:rower.user }}/edit"
title="Jump to preceding workout"><em>Previous</em></a>&nbsp;
{% endif %}
{% if workout|nextworkout:rower.user %}
<a href="/rowers/workout/{{ workout|nextworkout:rower.user }}/edit"
title="Jump to following workout"><em>Next</em></a>
{% endif %}
</p>
<h1>Edit Workout {{ workout.name }}</h1> <h1>Edit Workout {{ workout.name }}</h1>
<ul class="main-content"> <ul class="main-content">
<li class="grid_4"> <li class="grid_4">
@@ -94,7 +105,7 @@ $('#id_workouttype').change();
{{ form.as_table }} {{ form.as_table }}
</table> </table>
{% csrf_token %} {% csrf_token %}
<input class="button green" type="submit" value="Save"> <input type="submit" value="Save">
</form> </form>
</li> </li>
<li class="grid_2"> <li class="grid_2">
+50 -1
View File
@@ -11,7 +11,7 @@ from rowers.utils import calculate_age
from rowers.models import ( from rowers.models import (
course_length,WorkoutComment, course_length,WorkoutComment,
TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle, TrainingMacroCycle,TrainingMesoCycle, TrainingMicroCycle,
Rower Rower,Workout
) )
from rowers.plannedsessions import ( from rowers.plannedsessions import (
race_can_register, race_can_submit,race_rower_status race_can_register, race_can_submit,race_rower_status
@@ -464,4 +464,53 @@ def micromacroid(id):
return str(theid) return str(theid)
@register.filter
def nextworkout(workout,user):
if user.rower == workout.user:
ws = Workout.objects.filter(
startdatetime__gte=workout.startdatetime,
user=workout.user
).order_by(
"startdatetime"
).exclude(id=workout.id)
else:
ws = Workout.objects.filter(
startdatetime__gte=workout.startdatetime,
user=workout.user,privacy='visible'
).order_by(
"startdatetime"
).exclude(id=workout.id)
if ws:
return ws[0].id
else:
return 0
@register.filter
def previousworkout(workout,user):
if user.rower == workout.user:
ws = Workout.objects.filter(
startdatetime__lte=workout.startdatetime,
user=workout.user
).order_by(
"-startdatetime"
).exclude(id=workout.id)
else:
ws = Workout.objects.filter(
startdatetime__lte=workout.startdatetime,
user=workout.user,privacy='visible'
).order_by(
"-startdatetime"
).exclude(id=workout.id)
if ws:
return ws[0].id
else:
return 0
+1
View File
@@ -34,6 +34,7 @@ oauth_data = {
'expirydatename': 'tptokenexpirydate', 'expirydatename': 'tptokenexpirydate',
'bearer_auth': False, 'bearer_auth': False,
'base_url': "https://oauth.trainingpeaks.com/oauth/token", 'base_url': "https://oauth.trainingpeaks.com/oauth/token",
'scope':'write',
} }
+1
View File
@@ -17,6 +17,7 @@ oauth_data = {
'expirydatename': 'underarmourtokenexpirydate', 'expirydatename': 'underarmourtokenexpirydate',
'bearer_auth': True, 'bearer_auth': True,
'base_url': "https://api.ua.com/v7.1/oauth2/access_token/", 'base_url': "https://api.ua.com/v7.1/oauth2/access_token/",
'scope':'write',
} }
# Checks if user has UnderArmour token, renews them if they are expired # Checks if user has UnderArmour token, renews them if they are expired
+2
View File
@@ -357,7 +357,9 @@ urlpatterns = [
url(r'^me/deactivate$',views.deactivate_user), url(r'^me/deactivate$',views.deactivate_user),
url(r'^me/delete$',views.remove_user), url(r'^me/delete$',views.remove_user),
url(r'^me/gdpr-optin-confirm/?$',views.user_gdpr_confirm), url(r'^me/gdpr-optin-confirm/?$',views.user_gdpr_confirm),
url(r'^me/gdpr-optin-confirm/$',views.user_gdpr_confirm),
url(r'^me/gdpr-optin/?$',views.user_gdpr_optin), url(r'^me/gdpr-optin/?$',views.user_gdpr_optin),
url(r'^me/gdpr-optin/$',views.user_gdpr_optin),
url(r'^me/teams/$',views.rower_teams_view), url(r'^me/teams/$',views.rower_teams_view),
url(r'^me/calcdps/$',views.rower_calcdps_view), url(r'^me/calcdps/$',views.rower_calcdps_view),
url(r'^me/exportsettings/$',views.rower_exportsettings_view), url(r'^me/exportsettings/$',views.rower_exportsettings_view),
+24 -5
View File
@@ -208,6 +208,7 @@ from django.core.cache import cache
from django_mailbox.models import Message,Mailbox,MessageAttachment from django_mailbox.models import Message,Mailbox,MessageAttachment
# Utility to get stroke data in a JSON response # Utility to get stroke data in a JSON response
class JSONResponse(HttpResponse): class JSONResponse(HttpResponse):
def __init__(self, data, **kwargs): def __init__(self, data, **kwargs):
@@ -2069,7 +2070,7 @@ def rower_strava_authorize(request):
params = {"client_id": STRAVA_CLIENT_ID, params = {"client_id": STRAVA_CLIENT_ID,
"response_type": "code", "response_type": "code",
"redirect_uri": STRAVA_REDIRECT_URI, "redirect_uri": STRAVA_REDIRECT_URI,
"scope": "write"} "scope": "activity:write,activity:read_all"}
url = "https://www.strava.com/oauth/authorize?"+ urllib.urlencode(params) url = "https://www.strava.com/oauth/authorize?"+ urllib.urlencode(params)
@@ -2407,6 +2408,7 @@ def rower_process_polarcallback(request):
def rower_process_stravacallback(request): def rower_process_stravacallback(request):
try: try:
code = request.GET['code'] code = request.GET['code']
scope = request.GET['scope']
except MultiValueDictKeyError: except MultiValueDictKeyError:
try: try:
message = request.GET['error'] message = request.GET['error']
@@ -3369,6 +3371,11 @@ def addmanual_view(request):
avghr = metricsform.cleaned_data['avghr'] avghr = metricsform.cleaned_data['avghr']
avgpwr = metricsform.cleaned_data['avgpwr'] avgpwr = metricsform.cleaned_data['avgpwr']
avgspm = metricsform.cleaned_data['avgspm'] avgspm = metricsform.cleaned_data['avgspm']
try:
ps = form.cleaned_data['plannedsession']
except KeyError:
ps = None
try: try:
boattype = request.POST['boattype'] boattype = request.POST['boattype']
except KeyError: except KeyError:
@@ -3426,10 +3433,14 @@ def addmanual_view(request):
w.privacy = privacy w.privacy = privacy
w.weightcategory = weightcategory w.weightcategory = weightcategory
w.notes = notes w.notes = notes
w.plannedsession = ps
w.name = name w.name = name
w.workouttype = workouttype w.workouttype = workouttype
w.boattype = boattype w.boattype = boattype
w.save() w.save()
if ps:
add_workouts_plannedsession([w],ps,w.user)
messages.info(request,'New workout created') messages.info(request,'New workout created')
else: else:
return render(request,'manualadd.html', return render(request,'manualadd.html',
@@ -6079,10 +6090,7 @@ def multiflex_data(request,userid=0,
yerror = groups.std()[yparam] yerror = groups.std()[yparam]
groupsize = groups.count()[xparam] groupsize = groups.count()[xparam]
print groupsize.sum(),groupsize.mean()
mask = groupsize <= min([0.01*groupsize.sum(),0.2*groupsize.mean()]) mask = groupsize <= min([0.01*groupsize.sum(),0.2*groupsize.mean()])
print '--------------------------'
xvalues.loc[mask] = np.nan xvalues.loc[mask] = np.nan
yvalues.loc[mask] = np.nan yvalues.loc[mask] = np.nan
@@ -9956,7 +9964,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
if request.method == 'POST': if request.method == 'POST':
# Form was submitted # Form was submitted
form = WorkoutForm(request.POST) form = WorkoutForm(request.POST,instance=row)
if form.is_valid(): if form.is_valid():
# Get values from form # Get values from form
name = form.cleaned_data['name'] name = form.cleaned_data['name']
@@ -9970,6 +9978,11 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
notes = form.cleaned_data['notes'] notes = form.cleaned_data['notes']
thetimezone = form.cleaned_data['timezone'] thetimezone = form.cleaned_data['timezone']
try:
ps = form.cleaned_data['plannedsession']
except KeyError:
ps = None
try: try:
boattype = request.POST['boattype'] boattype = request.POST['boattype']
except KeyError: except KeyError:
@@ -10031,10 +10044,16 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
row.privacy = privacy row.privacy = privacy
row.rankingpiece = rankingpiece row.rankingpiece = rankingpiece
row.timezone = thetimezone row.timezone = thetimezone
row.plannedsession = ps
try: try:
row.save() row.save()
except IntegrityError: except IntegrityError:
pass pass
if ps:
add_workouts_plannedsession([row],ps,row.user)
# change data in csv file # change data in csv file
r = rdata(row.csvfilename) r = rdata(row.csvfilename)