Merge branch 'release/v6.36'
This commit is contained in:
+5
-4
@@ -1586,9 +1586,9 @@ def rdata(file, rower=rrower()):
|
||||
try:
|
||||
res = rrdata(csvfile=file + '.gz', rower=rower)
|
||||
except IOError, IndexError:
|
||||
res = 0
|
||||
res = rrdata()
|
||||
except:
|
||||
res = 0
|
||||
res = rrdata()
|
||||
|
||||
return res
|
||||
|
||||
@@ -1637,7 +1637,7 @@ def getrowdata_db(id=0, doclean=False, convertnewtons=True):
|
||||
|
||||
if data.empty:
|
||||
rowdata, row = getrowdata(id=id)
|
||||
if rowdata:
|
||||
if not rowdata.empty:
|
||||
data = dataprep(rowdata.df, id=id, bands=True,
|
||||
barchart=True, otwpower=True)
|
||||
else:
|
||||
@@ -1645,7 +1645,8 @@ def getrowdata_db(id=0, doclean=False, convertnewtons=True):
|
||||
else:
|
||||
row = Workout.objects.get(id=id)
|
||||
|
||||
if data['efficiency'].mean() == 0 and data['power'].mean() != 0:
|
||||
|
||||
if not data.empty and data['efficiency'].mean() == 0 and data['power'].mean() != 0:
|
||||
data = add_efficiency(id=id)
|
||||
|
||||
if doclean:
|
||||
|
||||
+18
-18
@@ -42,8 +42,8 @@ def add_workouts_plannedsession(ws,ps,r):
|
||||
errors.append('For tests, you can only attach one workout')
|
||||
return result,comments,errors
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
wold = Workout.objects.filter(plannedsession=ps,user=r)
|
||||
ids = [w.id for w in wold] + [w.id for w in ws]
|
||||
ids = list(set(ids))
|
||||
@@ -51,7 +51,7 @@ def add_workouts_plannedsession(ws,ps,r):
|
||||
if len(ids)>1 and ps.sessiontype in ['test','coursetest']:
|
||||
errors.append('For tests, you can only attach one workout')
|
||||
return result,comments,errors
|
||||
|
||||
|
||||
# start adding sessions
|
||||
for w in ws:
|
||||
if w.date>=ps.startdate and w.date<=ps.enddate:
|
||||
@@ -63,7 +63,7 @@ def add_workouts_plannedsession(ws,ps,r):
|
||||
errors.append('Workout %i did not match session dates' % w.id)
|
||||
|
||||
return result,comments,errors
|
||||
|
||||
|
||||
|
||||
def remove_workout_plannedsession(w,ps):
|
||||
if w.plannedsession == ps:
|
||||
@@ -98,7 +98,7 @@ def get_session_metrics(ps):
|
||||
status = []
|
||||
|
||||
for r in rowers:
|
||||
rscorev = 0
|
||||
rscorev = 0
|
||||
trimpv = 0
|
||||
durationv = 0
|
||||
distancev = 0
|
||||
@@ -113,7 +113,7 @@ def get_session_metrics(ps):
|
||||
durationv += timefield_to_seconds_duration(w.duration)
|
||||
trimpv += dataprep.workout_trimp(w)
|
||||
rscorev += dataprep.workout_rscore(w)[0]
|
||||
|
||||
|
||||
ratio,statusv,completiondate = is_session_complete_ws(ws,ps)
|
||||
try:
|
||||
completedatev = completiondate.strftime('%Y-%m-%d')
|
||||
@@ -139,7 +139,7 @@ def get_session_metrics(ps):
|
||||
'rscore':rscore,
|
||||
'trimp':trimp,
|
||||
'completedate':completedate,
|
||||
'status':status,
|
||||
'status':status,
|
||||
}
|
||||
|
||||
return thedict
|
||||
@@ -154,7 +154,7 @@ def is_session_complete_ws(ws,ps):
|
||||
return ratio,status,None
|
||||
else:
|
||||
return 0,'not done',None
|
||||
|
||||
|
||||
value = ps.sessionvalue
|
||||
if ps.sessionunit == 'min':
|
||||
value *= 60.
|
||||
@@ -171,7 +171,7 @@ def is_session_complete_ws(ws,ps):
|
||||
cratiomin = 0.9167
|
||||
cratiomax = 1.0833
|
||||
|
||||
|
||||
|
||||
score = 0
|
||||
completiondate = None
|
||||
for w in ws:
|
||||
@@ -236,7 +236,7 @@ def is_session_complete_ws(ws,ps):
|
||||
else:
|
||||
if not completiondate:
|
||||
completiondate = ws.reverse()[0].date
|
||||
return ratio,'partial',completiondate
|
||||
return ratio,'partial',completiondate
|
||||
elif ps.sessiontype == 'coursetest':
|
||||
if ps.course:
|
||||
(
|
||||
@@ -274,19 +274,19 @@ def is_session_complete_ws(ws,ps):
|
||||
if not completiondate:
|
||||
completiondate = ws.reverse()[0].date
|
||||
return ratio,status,completiondate
|
||||
|
||||
|
||||
|
||||
def is_session_complete(r,ps):
|
||||
status = 'not done'
|
||||
|
||||
if r not in ps.rower.all():
|
||||
return 0,'not assigned',None
|
||||
|
||||
|
||||
ws = Workout.objects.filter(user=r,plannedsession=ps)
|
||||
|
||||
return is_session_complete_ws(ws,ps)
|
||||
|
||||
|
||||
|
||||
|
||||
def rank_results(ps):
|
||||
return 1
|
||||
|
||||
@@ -299,7 +299,7 @@ def add_team_session(t,ps):
|
||||
def add_rower_session(r,ps):
|
||||
ps.rower.add(r)
|
||||
ps.save()
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
def remove_team_session(t,ps):
|
||||
@@ -377,9 +377,9 @@ def get_sessions_manager(m,teamid=0,startdate=date.today(),
|
||||
startdate__lte=enddate,
|
||||
enddate__gte=startdate,
|
||||
).order_by("preferreddate","startdate","enddate")
|
||||
|
||||
|
||||
return sps
|
||||
|
||||
|
||||
def get_sessions(r,startdate=date.today(),
|
||||
enddate=date.today()+timezone.timedelta(+1000)):
|
||||
|
||||
@@ -388,7 +388,7 @@ def get_sessions(r,startdate=date.today(),
|
||||
startdate__lte=enddate,
|
||||
enddate__gte=startdate,
|
||||
).order_by("preferreddate","startdate","enddate")
|
||||
|
||||
|
||||
return sps
|
||||
|
||||
def get_workouts_session(r,ps):
|
||||
|
||||
+22
-1
@@ -21,6 +21,7 @@ class RowerSerializer(serializers.HyperlinkedModelSerializer):
|
||||
'tr',
|
||||
'an',
|
||||
'ftp',
|
||||
'sex',
|
||||
)
|
||||
|
||||
class FavoriteChartSerializer(serializers.ModelSerializer):
|
||||
@@ -52,6 +53,13 @@ class WorkoutSerializer(serializers.ModelSerializer):
|
||||
'maxhr',
|
||||
'notes',
|
||||
'summary',
|
||||
'boattype',
|
||||
'timezone',
|
||||
'forceunit',
|
||||
'inboard',
|
||||
'oarlength',
|
||||
'privacy',
|
||||
'rankingpiece'
|
||||
)
|
||||
|
||||
def create(self, validated_data):
|
||||
@@ -78,7 +86,13 @@ class WorkoutSerializer(serializers.ModelSerializer):
|
||||
summary=validated_data['summary'],
|
||||
averagehr=validated_data['averagehr'],
|
||||
maxhr=validated_data['maxhr'],
|
||||
startdatetime=rowdatetime)
|
||||
startdatetime=rowdatetime,
|
||||
timezone=validated_data['timezone'],
|
||||
forceunit=validated_data['forceunit'],
|
||||
inboard=validated_data['inboard'],
|
||||
oarlength=validated_data['oarlength'],
|
||||
privacy=validated_data['privacy'],
|
||||
rankingpiece=validated_data['rankingpiece'],)
|
||||
w.save()
|
||||
return w
|
||||
|
||||
@@ -104,6 +118,13 @@ class WorkoutSerializer(serializers.ModelSerializer):
|
||||
instance.averagehr=validated_data['averagehr']
|
||||
instance.maxhr=validated_data['maxhr']
|
||||
instance.startdatetime=rowdatetime
|
||||
instance.timezone=validated_data['timezone']
|
||||
instance.forceunit=validated_data['forceunit']
|
||||
instance.inboard=validated_data['inboard']
|
||||
instance.oarlength=validated_data['oarlength']
|
||||
instance.privacy=validated_data['privacy']
|
||||
instance.rankingpiece=validated_data['rankingpiece']
|
||||
|
||||
instance.save()
|
||||
return instance
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -132,17 +132,11 @@
|
||||
Developers of iOS or Android apps should contact me directly if
|
||||
this doesn't work for them. I can add exceptions.</p>
|
||||
|
||||
<p>The POST call must have content-type: <i>x-www-form-urlencoded</i>.
|
||||
I set it this way to support the handy testing utility mentioned
|
||||
belower. However,
|
||||
I really would like to support <i>application/json</i> but with the
|
||||
current framework I cannot support both at the same time. Expect
|
||||
changes. Write to me if you want to be notified of changes.</p>
|
||||
|
||||
<ul>
|
||||
<li>Authorization URL: <b>https://rowsandall.com/rowers/o/authorize</b></li>
|
||||
<li>Access Token request: <b>https://rowsandall.com/rowers/o/token/</b></li>
|
||||
<li>Access Token refresh: <b>https://rowsandall.com/rowers/o/token/</b></li>
|
||||
<li>Authorization URL: <b>https://{{ request.get_host }}/rowers/o/authorize</b></li>
|
||||
<li>Access Token request: <b>https://{{ request.get_host }}/rowers/o/token/</b></li>
|
||||
<li>Access Token refresh: <b>https://{{ request.get_host }}/rowers/o/token/</b></li>
|
||||
<li>Handy utility for testing: <b><a href="http://django-oauth-toolkit.herokuapp.com/consumer/">http://django-oauth-toolkit.herokuapp.com/consumer/</a></b></li>
|
||||
</ul>
|
||||
|
||||
@@ -169,7 +163,7 @@
|
||||
posted to:</p>
|
||||
|
||||
<ul>
|
||||
<li><b>https://rowsandall.com/rowers/api/workouts/{id}/strokedata</b></li>
|
||||
<li><b>https://{{ request.get_host }}/rowers/api/workouts/{id}/strokedata</b></li>
|
||||
</ul>
|
||||
|
||||
<p>The payload is application/json data and looks as follows:</p>
|
||||
@@ -203,6 +197,12 @@
|
||||
<li><b>peakdriveforce</b>: Peak handle force (lbs)</li>
|
||||
<li><b>lapidx</b>: Lap identifier</li>
|
||||
<li><b>hr</b>: Heart rate (beats per minute)</li>
|
||||
<li><b>wash</b>: Wash as defined per Empower oarlock (degrees)</li>
|
||||
<li><b>catch</b>: Catch angle per Empower oarlock (degrees)</li>
|
||||
<li><b>finish</b>: Finish angle per Empower oarlock (degrees)</li>
|
||||
<li><b>peakforceangle</b>: Peak Force Angle per Empower oarlock (degrees)</li>
|
||||
<li><b>slip</b>: Wash as defined per Empower oarlock (degrees)</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<p>Consistency checks will be done and the stroke data will be
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -69,7 +69,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 omega dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_rowers %}
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_rowers %}
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_rowers %}
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_rowers %}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_rowers %}
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</div>
|
||||
<div class="grid_2 suffix_2 omega dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ rower.user.first_name }} {{ rower.user.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for rower in user|team_rowers %}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block title %}Change Rower {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% if form.errors %}
|
||||
<p style="color: red;">
|
||||
@@ -11,7 +9,7 @@
|
||||
<div class="grid_12 alpha">
|
||||
<h1>Stroke Data for workout {{ id }}</h1>
|
||||
|
||||
<form enctype="multipart/form-data" action="/rowers/api/workouts/{{ id }}/strokedata" method="post">
|
||||
<form enctype="application/json" action="/rowers/api/workouts/{{ id }}/strokedata" method="post">
|
||||
<table>
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
{% if user.is_authenticated and user|is_manager %}
|
||||
<div class="grid_2 alpha dropdown">
|
||||
<button class="grid_2 alpha button green small dropbtn">
|
||||
Change Rower
|
||||
{{ theuser.first_name }} {{ theuser.last_name }}
|
||||
</button>
|
||||
<div class="dropdown-content">
|
||||
{% for member in user|team_members %}
|
||||
|
||||
+21
-5
@@ -11480,7 +11480,10 @@ def strokedatajson(request,id):
|
||||
df.index = df.index.astype(int)
|
||||
df.sort_index(inplace=True)
|
||||
# time, hr, pace, spm, power, drivelength, distance, drivespeed, dragfactor, strokerecoverytime, averagedriveforce, peakdriveforce, lapidx
|
||||
time = df['time']/1.e3
|
||||
try:
|
||||
time = df['time']/1.e3
|
||||
except KeyError:
|
||||
return HttpResponse("There must be time values",status=400)
|
||||
aantal = len(time)
|
||||
pace = df['pace']/1.e3
|
||||
if len(pace) != aantal:
|
||||
@@ -11505,14 +11508,20 @@ def strokedatajson(request,id):
|
||||
strokerecoverytime = trydf(df,aantal,'strokerecoverytime')
|
||||
averagedriveforce = trydf(df,aantal,'averagedriveforce')
|
||||
peakdriveforce = trydf(df,aantal,'peakdriveforce')
|
||||
wash = trydf(df,aantal,'wash')
|
||||
catch = trydf(df,aantal,'catch')
|
||||
finish = trydf(df,aantal,'finish')
|
||||
peakforceangle = trydf(df,aantal,'peakforceangle')
|
||||
driveenergy = trydf(df,aantal,'driveenergy')
|
||||
slip = trydf(df,aantal,'slip')
|
||||
lapidx = trydf(df,aantal,'lapidx')
|
||||
hr = trydf(df,aantal,'hr')
|
||||
|
||||
starttime = totimestamp(row.startdatetime)+time
|
||||
starttime = totimestamp(row.startdatetime)+time[0]
|
||||
unixtime = starttime+time
|
||||
|
||||
with open('media/apilog.log','a') as logfile:
|
||||
logfile.write(starttime+": ")
|
||||
logfile.write(str(starttime)+": ")
|
||||
logfile.write(request.user.username+"(POST) \r\n")
|
||||
|
||||
data = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||
@@ -11529,10 +11538,18 @@ def strokedatajson(request,id):
|
||||
' PeakDriveForce (lbs)':peakdriveforce,
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':time,
|
||||
'catch':catch,
|
||||
'slip':slip,
|
||||
'finish':finish,
|
||||
'wash':wash,
|
||||
'driveenergy':driveenergy,
|
||||
'peakforceangle':peakforceangle,
|
||||
})
|
||||
|
||||
# Following part should be replaced with dataprep.new_workout_from_df
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S")
|
||||
csvfilename ='media/Import_'+timestr+'.csv'
|
||||
|
||||
@@ -11541,7 +11558,6 @@ def strokedatajson(request,id):
|
||||
row.csvfilename = csvfilename
|
||||
row.save()
|
||||
|
||||
r = getrower(request.user)
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
|
||||
Reference in New Issue
Block a user