Private
Public Access
1
0

Merge branch 'feature/restapi' into develop

This commit is contained in:
Sander Roosendaal
2016-11-27 13:27:34 +01:00
15 changed files with 955 additions and 5025 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -8,6 +8,31 @@ from pandas import DataFrame,Series
import pandas as pd
import numpy as np
import itertools
from django.conf import settings
from sqlalchemy import create_engine
import sqlalchemy as sa
user = settings.DATABASES['default']['USER']
password = settings.DATABASES['default']['PASSWORD']
database_name = settings.DATABASES['default']['NAME']
host = settings.DATABASES['default']['HOST']
port = settings.DATABASES['default']['PORT']
database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
user=user,
password=password,
database_name=database_name,
host=host,
port=port,
)
if settings.DEBUG or user=='':
# database_url = 'sqlite:///db.sqlite3'
database_url = 'sqlite:///'+database_name
engine = create_engine(database_url, echo=False)
from scipy.signal import savgol_filter
@@ -59,6 +84,55 @@ def rdata(file,rower=rrower()):
return res
def delete_strokedata(id):
query = sa.text('DELETE FROM strokedata WHERE workoutid={id};'.format(
id=id,
))
with engine.connect() as conn, conn.begin():
try:
result = conn.execute(query)
except:
print "Database Locked"
def testdata(time,distance,pace,spm):
t1 = np.issubdtype(time,np.number)
t2 = np.issubdtype(distance,np.number)
t3 = np.issubdtype(pace,np.number)
t4 = np.issubdtype(spm,np.number)
return t1 and t2 and t3 and t4
def getrowdata_db(id=0):
data = read_df_sql(id)
data['pace'] = data['pace']/1.0e6
data['ergpace'] = data['ergpace']/1.0e6
data['nowindpace'] = data['nowindpace']/1.0e6
data['time'] = data['time']/1.0e6
data['x_right'] = data['x_right']/1.0e6
if data.empty:
rowdata,row = getrowdata(id=id)
if rowdata:
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
else:
data = pd.DataFrame() # returning empty dataframe
else:
row = Workout.objects.get(id=id)
return data,row
def getsmallrowdata_db(columns,ids=[]):
prepmultipledata(ids)
data = read_cols_df_sql(ids,columns)
for column in columns:
if column == 'time':
data['time'] = data['time']/1.0e6
if column == 'pace':
data['pace'] = data['pace']/1.0e6
if column == 'pace':
data['pace'] = data['pace']/1.0e6
return data
def getrowdata(id=0):
# check if valid ID exists (workout exists)
@@ -80,6 +154,56 @@ def getrowdata(id=0):
return rowdata,row
def prepmultipledata(ids,verbose=False):
query = sa.text('SELECT DISTINCT workoutid FROM strokedata')
with engine.connect() as conn, conn.begin():
res = conn.execute(query)
res = list(itertools.chain.from_iterable(res.fetchall()))
res = list(set(ids)-set(res))
for id in res:
rowdata,row = getrowdata(id=id)
if verbose:
print id
if rowdata:
data = dataprep(rowdata.df,id=id,bands=True,barchart=True,otwpower=True)
return res
def read_cols_df_sql(ids,columns):
columns = list(columns)+['distance','spm']
columns = [x for x in columns if x != 'None']
columns = list(set(columns))
cls = ''
for column in columns:
cls += column+', '
cls = cls[:-2]
if len(ids) == 0:
query = sa.text('SELECT {columns} FROM strokedata WHERE workoutid=0'.format(
columns = cls,
))
elif len(ids) == 1:
query = sa.text('SELECT {columns} FROM strokedata WHERE workoutid={id}'.format(
id = ids[0],
columns = cls,
))
else:
query = sa.text('SELECT {columns} FROM strokedata WHERE workoutid IN {ids}'.format(
columns = cls,
ids = tuple(ids),
))
df = pd.read_sql_query(query,engine)
return df
def read_df_sql(id):
df = pd.read_sql_query(sa.text('SELECT * FROM strokedata WHERE workoutid={id}'.format(
id=id)), engine)
return df
def smalldataprep(therows,xparam,yparam1,yparam2):
df = pd.DataFrame()
@@ -110,8 +234,7 @@ def smalldataprep(therows,xparam,yparam1,yparam2):
return df
def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False):
def dataprep(rowdatadf,id=0,bands=False,barchart=False,otwpower=False):
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
t = rowdatadf.ix[:,'TimeStamp (sec)']
t = pd.Series(t-rowdatadf.ix[0,'TimeStamp (sec)'])
@@ -127,8 +250,11 @@ def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False):
power = rowdatadf.ix[:,' Power (watts)']
averageforce = rowdatadf.ix[:,' AverageDriveForce (lbs)']
drivelength = rowdatadf.ix[:,' DriveLength (meters)']
try:
workoutstate = rowdatadf.ix[:,' WorkoutState']
except KeyError:
workoutstate = 0*hr
peakforce = rowdatadf.ix[:,' PeakDriveForce (lbs)']
forceratio = averageforce/peakforce
@@ -175,6 +301,7 @@ def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False):
fpace = nicepaceformat(p2),
driveenergy=driveenergy,
power=power,
workoutstate=workoutstate,
averageforce=averageforce,
drivelength=drivelength,
peakforce=peakforce,
@@ -228,5 +355,11 @@ def dataprep(rowdatadf,bands=False,barchart=False,otwpower=False):
data = data.replace([-np.inf,np.inf],np.nan)
data = data.fillna(method='ffill')
# write data if id given
if id != 0:
data['workoutid'] = id
with engine.connect() as conn, conn.begin():
data.to_sql('strokedata',engine,if_exists='append',index=False)
return data

View File

@@ -27,6 +27,10 @@ class CNsummaryForm(forms.Form):
class SummaryStringForm(forms.Form):
intervalstring = forms.CharField(max_length=255,label='Workout Description')
class StrokeDataForm(forms.Form):
strokedata = forms.CharField(label='payload',
widget=forms.Textarea)
class DocumentsForm(forms.Form):
filetypechoices = (
('csv' , 'Painsled iOS CSV'),

View File

@@ -70,14 +70,14 @@ from rowers.dataprep import timedeltaconv
def interactive_histoall(theworkouts):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata)
histopwr = histodata(therows)
ids = [w.id for w in theworkouts]
rowdata = dataprep.getsmallrowdata_db(['power'],ids=ids)
histopwr = rowdata['power'].values
if len(histopwr) == 0:
return "","CSV file not found","",""
# throw out nans
histopwr = histopwr[~np.isinf(histopwr)]
histopwr = histopwr[histopwr > 25]
@@ -496,18 +496,15 @@ def interactive_chart(id=0,promember=0):
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
rowdata,row = dataprep.getrowdata(id=id)
if rowdata == 0:
datadf,row = dataprep.getrowdata_db(id=id)
if datadf.empty:
return "","CSV Data File Not Found"
datadf = dataprep.dataprep(rowdata.df)
source = ColumnDataSource(
datadf
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
plot_width=400,
plot_height=400,
@@ -554,10 +551,10 @@ def interactive_chart(id=0,promember=0):
hover.mode = 'mouse'
plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)}
plot.extra_y_ranges = {"hrax": Range1d(start=100,end=200)}
plot.line('time','hr',source=source,color="red",
y_range_name="hr", legend="Heart Rate")
plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right')
y_range_name="hrax", legend="Heart Rate")
plot.add_layout(LinearAxis(y_range_name="hrax",axis_label="HR"),'right')
plot.legend.location = "bottom_right"
@@ -570,8 +567,10 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
yparam1='power',
yparam2='spm'):
datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
# datadf = dataprep.smalldataprep(theworkouts,xparam,yparam1,yparam2)
ids = [w.id for w in theworkouts]
datadf = dataprep.getsmallrowdata_db([xparam,yparam1,yparam2],ids=ids)
axlabels = {
'time': 'Time',
'distance': 'Distance (m)',
@@ -666,6 +665,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
else:
datadf['yname2'] = yparam1
source = ColumnDataSource(
datadf
)
@@ -678,7 +678,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
@@ -862,384 +862,6 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
return [script,div,js_resources,css_resources]
def interactive_cum_flex_chart(theworkouts,promember=0,
xparam='spm',
yparam1='power',
yparam2='hr',
):
therows = []
for workout in theworkouts:
f1 = workout.csvfilename
rowdata = rdata(f1)
if rowdata != 0:
therows.append(rowdata.df)
datadf = pd.concat(therows)
axlabels = {
'time': 'Time',
'distance': 'Distance (m)',
'hr': 'Heart Rate (bpm)',
'spm': 'Stroke Rate (spm)',
'pace': 'Pace (/500m)',
'power': 'Power (Watt)',
'averageforce': 'Average Drive Force (lbs)',
'drivelength': 'Drive Length (m)',
'peakforce': 'Peak Drive Force (lbs)',
'forceratio': 'Average/Peak Drive Force Ratio',
'driveenergy': 'Work per Stroke (J)',
'drivespeed': 'Drive Speed (m/s)',
'None': '',
}
yparamname1 = axlabels[yparam1]
yparamname2 = axlabels[yparam2]
yaxminima = {
'hr':100,
'spm':15,
'pace': 1.0e3*210,
'power': 0,
'averageforce': 0,
'peakforce': 0,
'forceratio':0,
'drivelength':0.5,
'driveenergy': 0,
'drivespeed': 0,
}
yaxmaxima = {
'hr':200,
'spm':45,
'pace':1.0e3*90,
'power': 600,
'averageforce':200,
'peakforce':400,
'forceratio':1,
'drivelength':2.0,
'driveenergy': 1000,
'drivespeed':4,
}
datadf = dataprep.dataprep(datadf)
if yparam1 != 'pace' and yparam1 != 'time':
datadf = datadf[datadf[yparam1] > 0]
elif yparam1 == 'time':
datadf = datadf[datadf['timesecs'] > 0]
else:
datadf = datadf[datadf['pseconds']>0]
if xparam != 'time' and xparam != 'pace':
datadf = datadf[datadf[xparam] > 0]
elif xparam == 'time':
datadf = datadf[datadf['timesecs']>0]
else:
datadf = datadf[datadf['pseconds']>0]
if yparam2 != 'None':
datadf = datadf[datadf[yparam2] > 0]
# check if dataframe not empty
if datadf.empty:
return ['','<p>No non-zero data in selection</p>','','']
datadf['x1'] = datadf.ix[:,xparam]
tseconds = datadf.ix[:,'timesecs']
datadf['y1'] = datadf.ix[:,yparam1]
if yparam2 != 'None':
datadf['y2'] = datadf.ix[:,yparam2]
else:
datadf['y2'] = datadf['y1']
if xparam=='time':
xaxmax = tseconds.max()
xaxmin = tseconds.min()
xaxmax = 1.0e3*xaxmax
xaxmin = 1.0e3*xaxmin
elif xparam=='distance':
xaxmax = datadf['x1'].max()
xaxmin = datadf['x1'].min()
else:
xaxmax = yaxmaxima[xparam]
xaxmin = yaxminima[xparam]
# average values
if xparam != 'time':
x1mean = datadf['x1'].mean()
else:
x1mean = 0
y1mean = datadf['y1'].mean()
y2mean = datadf['y2'].mean()
if xparam != 'time':
xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.)
else:
xvals = pd.Series(np.arange(100))
x_axis_type = 'linear'
y_axis_type = 'linear'
if xparam == 'time':
x_axis_type = 'datetime'
if yparam1 == 'pace':
y_axis_type = 'datetime'
y1mean = datadf.ix[:,'pseconds'].mean()
datadf['xname'] = xparam
datadf['yname1'] = yparam1
if yparam2 != 'None':
datadf['yname2'] = yparam2
else:
datadf['yname2'] = yparam1
source = ColumnDataSource(
datadf
)
source2 = ColumnDataSource(
datadf.copy()
)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
tools=TOOLS,
toolbar_location="above",
toolbar_sticky=False)
x1means = Span(location=x1mean,dimension='height',line_color='green',
line_dash=[6,6], line_width=2)
y1means = Span(location=y1mean,dimension='width',line_color='blue',
line_dash=[6,6],line_width=2)
y2means = y1means
xlabel = Label(x=370,y=130,x_units='screen',y_units='screen',
text=xparam+": {x1mean:6.2f}".format(x1mean=x1mean),
background_fill_alpha=.7,
text_color='green',
)
if (xparam != 'time') and (xparam != 'distance'):
plot.add_layout(x1means)
plot.add_layout(xlabel)
plot.add_layout(y1means)
y1label = Label(x=370,y=100,x_units='screen',y_units='screen',
text=yparam1+": {y1mean:6.2f}".format(y1mean=y1mean),
background_fill_alpha=.7,
text_color='blue',
)
if yparam1 != 'time' and yparam1 != 'pace':
plot.add_layout(y1label)
y2label = y1label
plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None,
legend=yparamname1,
)
plot.xaxis.axis_label = axlabels[xparam]
plot.yaxis.axis_label = axlabels[yparam1]
yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1])
plot.y_range = yrange1
if (xparam != 'time') and (xparam != 'distance'):
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
plot.x_range = xrange1
if xparam == 'time':
xrange1 = Range1d(start=xaxmin,end=xaxmax)
plot.x_range = xrange1
plot.xaxis[0].formatter = DatetimeTickFormatter(
hours = ["%H"],
minutes = ["%M"],
seconds = ["%S"],
days = ["0"],
months = [""],
years = [""]
)
if yparam1 == 'pace':
plot.yaxis[0].formatter = DatetimeTickFormatter(
seconds = ["%S"],
minutes = ["%M"]
)
if yparam2 != 'None':
yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2])
plot.extra_y_ranges = {"yax2": yrange2}
plot.circle('x1','y2',color="red",y_range_name="yax2",
legend=yparamname2,
source=source2,fill_alpha=0.3,line_color=None)
plot.add_layout(LinearAxis(y_range_name="yax2",
axis_label=axlabels[yparam2]),'right')
y2means = Span(location=y2mean,dimension='width',line_color='red',
line_dash=[6,6],line_width=2,y_range_name="yax2")
plot.add_layout(y2means)
y2label = Label(x=370,y=70,x_units='screen',y_units='screen',
text=yparam2+": {y2mean:6.2f}".format(y2mean=y2mean),
background_fill_alpha=.7,
text_color='red',
)
if yparam2 != 'pace' and yparam2 != 'time':
plot.add_layout(y2label)
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Time','@ftime'),
('Pace','@fpace'),
('HR','@hr{int}'),
('SPM','@spm{1.1}'),
('Power','@power{int}'),
])
hover.mode = 'mouse'
callback = CustomJS(args = dict(source=source,source2=source2,
x1means=x1means,
y1means=y1means,
y1label=y1label,
y2label=y2label,
xlabel=xlabel,
y2means=y2means), code="""
var data = source.data
var data2 = source2.data
var x1 = data['x1']
var y1 = data['y1']
var y2 = data['y2']
var spm1 = data['spm']
var time1 = data['time']
var pace1 = data['pace']
var hr1 = data['hr']
var distance1 = data['distance']
var power1 = data['power']
var xname = data['xname'][0]
var yname1 = data['yname1'][0]
var yname2 = data['yname2'][0]
var minspm = minspm.value
var maxspm = maxspm.value
var mindist = mindist.value
var maxdist = maxdist.value
var xm = 0
var ym1 = 0
var ym2 = 0
data2['x1'] = []
data2['y1'] = []
data2['y2'] = []
data2['spm'] = []
data2['time'] = []
data2['pace'] = []
data2['hr'] = []
data2['distance'] = []
data2['power'] = []
data2['x1mean'] = []
data2['y1mean'] = []
data2['y2mean'] = []
data2['xvals'] = []
data2['y1vals'] = []
data2['y2vals'] = []
for (i=0; i<x1.length; i++) {
if (spm1[i]>=minspm && spm1[i]<=maxspm) {
if (distance1[i]>=mindist && distance1[i]<=maxdist) {
data2['x1'].push(x1[i])
data2['y1'].push(y1[i])
data2['y2'].push(y2[i])
data2['spm'].push(spm1[i])
data2['time'].push(time1[i])
data2['pace'].push(pace1[i])
data2['hr'].push(hr1[i])
data2['distance'].push(distance1[i])
data2['power'].push(power1[i])
xm += x1[i]
ym1 += y1[i]
ym2 += y2[i]
}
}
}
xm /= data2['x1'].length
ym1 /= data2['x1'].length
ym2 /= data2['x1'].length
data2['x1mean'] = [xm,xm]
data2['y1mean'] = [ym1,ym1]
data2['y2mean'] = [ym2,ym2]
x1means.location = xm
y1means.location = ym1
y2means.location = ym2
y1label.text = yname1+': '+ym1.toFixed(2)
y2label.text = yname2+': '+ym2.toFixed(2)
xlabel.text = xname+': '+xm.toFixed(2)
source2.trigger('change');
""")
slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1,
title="Min SPM",callback=callback)
callback.args["minspm"] = slider_spm_min
slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1,
title="Max SPM",callback=callback)
callback.args["maxspm"] = slider_spm_max
distmax = 100+100*int(datadf['distance'].max()/100.)
slider_dist_min = Slider(start=0,end=distmax,value=0,step=1,
title="Min Distance",callback=callback)
callback.args["mindist"] = slider_dist_min
slider_dist_max = Slider(start=0,end=distmax,value=distmax,
step=1,
title="Max Distance",callback=callback)
callback.args["maxdist"] = slider_dist_max
layout = layoutrow([layoutcolumn([slider_spm_min,
slider_spm_max,
slider_dist_min,
slider_dist_max,
],
),
plot])
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return [script,div,js_resources,css_resources]
def interactive_flex_chart2(id=0,promember=0,
@@ -1292,8 +914,8 @@ def interactive_flex_chart2(id=0,promember=0,
'drivespeed':4,
}
rowdata,row = dataprep.getrowdata(id=id)
if rowdata == 0:
rowdata,row = dataprep.getrowdata_db(id=id)
if rowdata.empty:
return "","CSV Data File Not Found"
workoutstateswork = [1,4,5,8,9,6,7]
@@ -1302,16 +924,10 @@ def interactive_flex_chart2(id=0,promember=0,
if workstrokesonly:
try:
rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)]
rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)]
except KeyError:
pass
rowdata = dataprep.dataprep(rowdata.df)
# get user
# u = User.objects.get(id=row.user.id)
rowdata['x1'] = rowdata.ix[:,xparam]
rowdata['y1'] = rowdata.ix[:,yparam1]
@@ -1634,15 +1250,10 @@ def interactive_flex_chart2(id=0,promember=0,
def interactive_bar_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata(id=id)
if rowdata == 0:
rowdata,row = dataprep.getrowdata_db(id=id)
if rowdata.empty:
return "","CSV Data File Not Found"
rowdata = dataprep.dataprep(rowdata.df,bands=True,barchart=True)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
@@ -1653,8 +1264,6 @@ def interactive_bar_chart(id=0,promember=0):
rowdata
)
plot = Figure(x_axis_type="datetime",y_axis_type="datetime",
toolbar_sticky=False,
plot_width=920,
@@ -1751,19 +1360,14 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
# check if valid ID exists (workout exists)
rowdata1,row1 = dataprep.getrowdata(id=id1)
rowdata2,row2 = dataprep.getrowdata(id=id2)
if rowdata1 == 0:
rowdata1,row1 = dataprep.getrowdata_db(id=id1)
rowdata2,row2 = dataprep.getrowdata_db(id=id2)
if rowdata1.empty:
return "","CSV Data File Not Found"
if rowdata2 == 0:
if rowdata2.empty:
return "","CSV Data File Not Found"
rowdata1 = dataprep.dataprep(rowdata1.df)
rowdata2 = dataprep.dataprep(rowdata2.df)
x1 = rowdata1.ix[:,xparam]
x2 = rowdata2.ix[:,xparam]
@@ -1899,12 +1503,10 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
def interactive_otw_advanced_pace_chart(id=0,promember=0):
# check if valid ID exists (workout exists)
rowdata,row = dataprep.getrowdata(id=id)
if rowdata == 0:
rowdata,row = dataprep.getrowdata_db(id=id)
if rowdata.empty:
return "","CSV Data File Not Found"
rowdata = dataprep.dataprep(rowdata.df,otwpower=True)
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'

View File

@@ -9,8 +9,31 @@ from django.forms.widgets import SplitDateTimeWidget
from datetimewidget.widgets import DateTimeWidget
import os
# Create your models here.
from django.conf import settings
from sqlalchemy import create_engine
import sqlalchemy as sa
from sqlite3 import OperationalError
user = settings.DATABASES['default']['USER']
password = settings.DATABASES['default']['PASSWORD']
database_name = settings.DATABASES['default']['NAME']
host = settings.DATABASES['default']['HOST']
port = settings.DATABASES['default']['PORT']
database_url = 'mysql://{user}:{password}@{host}:{port}/{database_name}'.format(
user=user,
password=password,
database_name=database_name,
host=host,
port=port,
)
if settings.DEBUG or user=='':
database_url = 'sqlite:///db.sqlite3'
engine = create_engine(database_url, echo=False)
# Create your models here.
class Team(models.Model):
name = models.CharField(max_length=150)
notes = models.CharField(blank=True,max_length=200)
@@ -120,7 +143,54 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
if os.path.isfile(instance.csvfilename):
os.remove(instance.csvfilename)
@receiver(models.signals.post_delete,sender=Workout)
def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
if instance.id:
query = sa.text('DELETE FROM strokedata WHERE workoutid={id};'.format(
id=instance.id,
))
with engine.connect() as conn, conn.begin():
try:
result = conn.execute(query)
except:
print "Database Locked"
class StrokeData(models.Model):
class Meta:
db_table = 'strokedata'
workoutid = models.IntegerField(null=True)
time = models.TimeField(null=True)
timesecs = models.FloatField(null=True)
hr = models.IntegerField(null=True)
pace = models.TimeField(null=True)
workoutstate = models.IntegerField(null=True,default=1)
pseconds = models.FloatField(null=True)
spm = models.FloatField(null=True)
cumdist = models.FloatField(null=True)
ftime = models.CharField(max_length=30)
fpace = models.CharField(max_length=30)
driveenergy = models.FloatField(null=True)
power = models.FloatField(null=True)
averageforce = models.FloatField(null=True)
drivelength = models.FloatField(null=True)
peakforce = models.FloatField(null=True)
forceratio = models.FloatField(null=True)
distance = models.FloatField(null=True)
drivespeed = models.FloatField(null=True)
hr_ut2 = models.IntegerField(null=True)
hr_ut1 = models.IntegerField(null=True)
hr_at = models.IntegerField(null=True)
hr_tr = models.IntegerField(null=True)
hr_an = models.IntegerField(null=True)
hr_max = models.IntegerField(null=True)
hr_bottom = models.IntegerField(null=True)
x_right = models.FloatField(null=True)
ergpace = models.TimeField(null=True)
nowindpace = models.TimeField(null=True)
equivergpower = models.FloatField(null=True)
fergpace = models.CharField(max_length=30)
fnowindpace = models.CharField(max_length=30)
class GraphImage(models.Model):
filename = models.CharField(default='',max_length=150,blank=True,null=True)

280
rowers/ownapistuff.py Normal file
View File

@@ -0,0 +1,280 @@
# Python
import oauth2 as oauth
import cgi
import requests
import requests.auth
import json
from django.utils import timezone
from datetime import datetime
import numpy as np
from dateutil import parser
import time
import math
from math import sin,cos,atan2,sqrt
import urllib
import c2stuff
# Django
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect, HttpResponse,JsonResponse
from django.conf import settings
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.models import User
from django.contrib.auth.decorators import login_required
# Project
# from .models import Profile
from rowingdata import rowingdata
import pandas as pd
from rowers.models import Rower,Workout
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
TEST_CLIENT_ID = "1"
TEST_CLIENT_SECRET = "aapnootmies"
TEST_REDIRECT_URI = "http://localhost:8000/rowers/test_callback"
def custom_exception_handler(exc,message):
response = {
"errors": [
{
"code": str(exc),
"detail": message,
}
]
}
res = HttpResponse(message)
res.status_code = 401
res.json = json.dumps(response)
return res
def do_refresh_token(refreshtoken):
client_auth = requests.auth.HTTPBasicAuth(TEST_CLIENT_ID, TEST_CLIENT_SECRET)
post_data = {"grant_type": "refresh_token",
"client_secret": TEST_CLIENT_SECRET,
"client_id":TEST_CLIENT_ID,
"refresh_token": refreshtoken,
}
headers = {'user-agent': 'sanderroosendaal',
'Accept': 'application/json',
'Content-Type': 'application/json'}
url = "http://localhost:8000/rowers/o/token"
response = requests.post(url,
data=json.dumps(post_data),
headers=headers)
token_json = response.json()
thetoken = token_json['access_token']
expires_in = token_json['expires_in']
try:
refresh_token = token_json['refresh_token']
except KeyError:
refresh_token = refreshtoken
return [thetoken,expires_in,refresh_token]
def get_token(code):
client_auth = requests.auth.HTTPBasicAuth(TEST_CLIENT_ID, TEST_CLIENT_SECRET)
post_data = {"grant_type": "authorization_code",
"code": code,
"redirect_uri": TEST_REDIRECT_URI,
"client_secret": TEST_CLIENT_SECRET,
"client_id":TEST_CLIENT_ID,
}
headers = {'Accept': 'application/json',
'Content-Type': 'application/json'}
url = "http://localhost:8000/rowers/o/token/"
response = requests.post(url,
data=json.dumps(post_data),
headers=headers)
print response.text
token_json = response.json()
thetoken = token_json['access_token']
expires_in = token_json['expires_in']
refresh_token = token_json['refresh_token']
return [thetoken,expires_in,refresh_token]
def make_authorization_url(request):
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
from uuid import uuid4
state = str(uuid4())
params = {"client_id": TEST_CLIENT_ID,
"response_type": "code",
"redirect_uri": TEST_REDIRECT_URI,
"scope":"write",
"state":state}
import urllib
url = "http://localhost:8000/rowers/o/authorize" +urllib.urlencode(params)
return HttpResponseRedirect(url)
def rower_ownapi_token_refresh(user):
r = Rower.objects.get(user=user)
res = do_refresh_token(r.ownapirefreshtoken)
access_token = res[0]
expires_in = res[1]
refresh_token = res[2]
expirydatetime = timezone.now()+timedelta(seconds=expires_in)
r = Rower.objects.get(user=user)
r.ownapitoken = access_token
r.tokenexpirydate = expirydatetime
r.ownapirefreshtoken = refresh_token
r.save()
return r.ownapitoken
def get_ownapi_workout_list(user):
r = Rower.objects.get(user=user)
if (r.ownapitoken == '') or (r.ownapitoken is None):
s = "Token doesn't exist. Need to authorize"
return custom_exception_handler(401,s)
elif (timezone.now()>r.ownapitokenexpirydate):
s = "Token expired. Needs to refresh."
return custom_exception_handler(401,s)
else:
# ready to fetch. Hurray
authorizationstring = str('Bearer ' + r.ownapitoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.ownapi.mobi/api/v2/fitnessActivities"
s = requests.get(url,headers=headers)
return s
def get_ownapi_workout(user,ownapiid):
r = Rower.objects.get(user=user)
if (r.ownapitoken == '') or (r.ownapitoken is None):
return custom_exception_handler(401,s)
s = "Token doesn't exist. Need to authorize"
elif (timezone.now()>r.ownapitokenexpirydate):
s = "Token expired. Needs to refresh."
return custom_exception_handler(401,s)
else:
# ready to fetch. Hurray
authorizationstring = str('Bearer ' + r.ownapitoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.ownapi.mobi/api/v2/fitnessActivities/"+str(ownapiid)
s = requests.get(url,headers=headers)
return s
def createownapiworkoutdata(w):
filename = w.csvfilename
row = rowingdata(filename)
averagehr = int(row.df[' HRCur (bpm)'].mean())
maxhr = int(row.df[' HRCur (bpm)'].max())
# adding diff, trying to see if this is valid
t = row.df.ix[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)']
t[0] = t[1]
d = row.df.ix[:,'cum_dist'].values
d[0] = d[1]
t = t.astype(int)
d = d.astype(int)
spm = row.df[' Cadence (stokes/min)'].astype(int)
spm[0] = spm[1]
hr = row.df[' HRCur (bpm)'].astype(int)
haslatlon=1
try:
lat = row.df[' latitude'].values
lon = row.df[' longitude'].values
except KeyError:
haslatlon = 0
haspower = 1
try:
power = row.df[' Power (watts)'].values
except KeyError:
haspower = 0
locdata = []
hrdata = []
spmdata = []
distancedata = []
powerdata = []
for i in range(len(t)):
hrdata.append(t[i])
hrdata.append(hr[i])
distancedata.append(t[i])
distancedata.append(d[i])
spmdata.append(t[i])
spmdata.append(spm[i])
if haslatlon:
locdata.append(t[i])
locdata.append([lat[i],lon[i]])
if haspower:
powerdata.append(t[i])
powerdata.append(power[i])
if haslatlon:
data = {
"type": "Rowing",
"name": w.name,
# "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
"start_time": w.startdatetime.isoformat(),
"total_distance": int(w.distance),
"duration": int(max(t)),
"notes": w.notes,
"avg_heartrate": averagehr,
"max_heartrate": maxhr,
"location": locdata,
"distance": distancedata,
"cadence": spmdata,
"heartrate": hrdata,
}
else:
data = {
"type": "Rowing",
"name": w.name,
# "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
"start_time": w.startdatetime.isoformat(),
"total_distance": int(w.distance),
"duration": int(max(t)),
"notes": w.notes,
"avg_heartrate": averagehr,
"max_heartrate": maxhr,
"distance": distancedata,
"cadence": spmdata,
"heartrate": hrdata,
}
if haspower:
data['power'] = powerdata
return data
def getidfromresponse(response):
t = json.loads(response.text)
uri = t['uris'][0]
id = uri[len(uri)-13:len(uri)-5]
return int(id)

21
rowers/permissions.py Normal file
View File

@@ -0,0 +1,21 @@
from rest_framework import permissions
from rowers.models import Rower
class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user
class IsOwnerOrNot(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
r = Rower.objects.get(user=request.user)
return (obj.user == r)

105
rowers/serializers.py Normal file
View File

@@ -0,0 +1,105 @@
from rest_framework import serializers
from rowers.models import Workout,Rower
import datetime
# Serializers define the API representation.
class RowerSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Rower
fields = (
'weightcategory',
'max',
'rest',
'ut2',
'ut1',
'at',
'tr',
'an',
'ftp',
)
class WorkoutSerializer(serializers.ModelSerializer):
class Meta:
model = Workout
fields = (
'id',
'name',
'date',
'workouttype',
'starttime',
'distance',
'duration',
'averagehr',
'maxhr',
'notes',
'summary',
)
def create(self, validated_data):
r = Rower.objects.get(user=self.context['request'].user)
d = validated_data['date']
t = validated_data['starttime']
rowdatetime = datetime.datetime(d.year,
d.month,
d.day,
t.hour,
t.minute,
t.second)
w = Workout(user=r,
name=validated_data['name'],
date=validated_data['date'],
workouttype=validated_data['workouttype'],
duration=validated_data['duration'],
distance=validated_data['distance'],
weightcategory=r.weightcategory,
starttime=validated_data['starttime'],
csvfilename='',
notes=validated_data['notes'],
uploadedtoc2=0,
summary=validated_data['summary'],
averagehr=validated_data['averagehr'],
maxhr=validated_data['maxhr'],
startdatetime=rowdatetime)
w.save()
return w
def update(self, instance, validated_data):
d = validated_data['date']
t = validated_data['starttime']
rowdatetime = datetime.datetime(d.year,
d.month,
d.day,
t.hour,
t.minute,
t.second)
instance.name=validated_data['name']
instance.date=validated_data['date']
instance.workouttype=validated_data['workouttype']
instance.duration=validated_data['duration']
instance.distance=validated_data['distance']
instance.starttime=validated_data['starttime']
instance.notes=validated_data['notes']
instance.summary=validated_data['summary']
instance.averagehr=validated_data['averagehr']
instance.maxhr=validated_data['maxhr']
instance.startdatetime=rowdatetime
instance.save()
return instance
class StrokeDataSerializer(serializers.Serializer):
workoutid = serializers.IntegerField
strokedata = serializers.JSONField
def create(self, validated_data):
"""
Create and enter a new set of stroke data into the DB
"""
# do something
print "fake serializer"
return 1

View File

@@ -0,0 +1,25 @@
{% extends "base.html" %}
{% block title %}Change Rower {% endblock %}
{% block content %}
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<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">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<div class="grid_2 prefix_2 suffix_2">
<input class="button green" type="submit" value="POST">
</form>
</div>
</div>
{% endblock %}

1
rowers/testdata/strokedata.txt vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
from django.test import TestCase, Client
from django.test import TestCase, Client,override_settings
from django.test.client import RequestFactory
from .views import checkworkoutuser,c2_open
from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage
@@ -24,6 +24,11 @@ import numpy as np
from rowers import urls
from rowers.views import error500_view,error404_view,error400_view,error403_view
from dataprep import delete_strokedata
class DjangoTestCase(TestCase, MockTestCase):
def _pre_setup(self):
MockTestCase.setUp(self)
@@ -33,6 +38,7 @@ class DjangoTestCase(TestCase, MockTestCase):
def _post_teardown(self):
TestCase._post_teardown(self)
MockTestCase.tearDown(self)
delete_strokedata(1)
# Create your tests here.
@@ -149,6 +155,7 @@ class STObjects(DjangoTestCase):
class TestErrorPages(TestCase):
def test_error_handlers(self):
self.assertTrue(urls.handler404.endswith('.error404_view'))
self.assertTrue(urls.handler500.endswith('.error500_view'))
factory = RequestFactory()
@@ -315,13 +322,12 @@ class DataTest(TestCase):
form = DocumentsForm(form_data,file_data)
self.assertTrue(form.is_valid())
f.close()
u = User.objects.get(username='john')
r = Rower.objects.get(user=u)
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an,ftp=r.ftp)

View File

@@ -1,5 +1,11 @@
from django.conf import settings
from django.conf.urls import url, include
from django.contrib.auth.models import User
from models import Workout,Rower
from rest_framework import routers, serializers, viewsets,permissions
from rest_framework.urlpatterns import format_suffix_patterns
from . import views
from django.contrib.auth import views as auth_views
@@ -8,6 +14,20 @@ from django.conf.urls import (
handler400, handler403, handler404, handler500,
)
from rowers.permissions import IsOwnerOrNot,IsOwnerOrReadOnly
from rowers.serializers import WorkoutSerializer,RowerSerializer
class WorkoutViewSet(viewsets.ModelViewSet):
queryset = Workout.objects.all().order_by("-date", "-starttime")
serializer_class = WorkoutSerializer
permission_classes = (IsOwnerOrNot,)
# Routers provide an easy way of automatically determining the URL conf.
router = routers.DefaultRouter()
router.register(r'api/workouts',WorkoutViewSet)
#router.register(r'api/rower',RowerViewSet)
handler500 = 'views.error500_view'
handler404 = 'views.error404_view'
handler400 = 'views.error400_view'
@@ -16,6 +36,11 @@ handler403 = 'views.error403_view'
urlpatterns = [
# url(r'^password_change/$',auth_views.password_change),
# url(r'^password_change_done/$',auth_views.password_change_done),
url(r'^o/', include('oauth2_provider.urls', namespace='oauth2_provider')),
url(r'^', include(router.urls)),
url(r'^api-docs$', views.schema_view),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api/workouts/(\d+)/strokedata$',views.strokedatajson),
url(r'^testbokeh$',views.testbokeh),
url(r'^500/$', TemplateView.as_view(template_name='500.html'),name='500'),
url(r'^404/$', TemplateView.as_view(template_name='404.html'),name='404'),
@@ -138,6 +163,8 @@ urlpatterns = [
url(r'^workout/(?P<id>\d+)/flexchart$',views.workout_flexchart3_view),
url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/(?P<plottype>\w+.*)$',views.workout_comparison_view2),
url(r'^workout/compare/(?P<id1>\d+)/(?P<id2>\d+)/(?P<xparam>\w+.*)/(?P<yparam>\w+.*)/$',views.workout_comparison_view2),
url(r'^test\_callback',views.rower_process_testcallback),
url(r'^workout/(\d+)/test\_strokedata$',views.strokedataform),
]
if settings.DEBUG:
@@ -146,3 +173,5 @@ if settings.DEBUG:
url(r'^testreverse/$',views.test_reverse_view),
url(r'^c2listug/$',views.c2listdebug_view),
]
#urlpatterns = format_suffix_patterns(urlpatterns)

View File

@@ -15,7 +15,7 @@ from django.utils import timezone,translation
from django.core.mail import send_mail, BadHeaderError
from rowers.forms import EmailForm, RegistrationForm, RegistrationFormTermsOfService,RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,UpdateStreamForm
from rowers.forms import PredictedPieceForm,DateRangeForm,DeltaDaysForm
from rowers.forms import SummaryStringForm,IntervalUpdateForm
from rowers.forms import SummaryStringForm,IntervalUpdateForm,StrokeDataForm
from rowers.models import Workout, User, Rower, WorkoutForm
from rowers.models import RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm
import StringIO
@@ -29,10 +29,14 @@ from c2stuff import C2NoTokenError
from iso8601 import ParseError
import stravastuff
import sporttracksstuff
import ownapistuff
from ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET
from rowsandall_app.settings import SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET
import requests
import json
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rowsandall_app.rows import handle_uploaded_file
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
from rowers.tasks import handle_sendemail_unrecognized
@@ -64,6 +68,16 @@ queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from rest_framework_swagger.views import get_swagger_view
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
from rest_framework.response import Response
from rowers.serializers import RowerSerializer,WorkoutSerializer
from rest_framework import status,permissions,generics
from rest_framework.decorators import api_view
from permissions import IsOwnerOrNot
import plots
import mailprocessing
@@ -77,6 +91,10 @@ USER_LANGUAGE = 'en-US'
from interactiveplots import *
schema_view = get_swagger_view(title='Rowsandall API (Unstable)')
def error500_view(request):
response = render_to_response('500.html', {},
context_instance = RequestContext(request))
@@ -1153,6 +1171,7 @@ def rower_process_stravacallback(request):
return imports_view(request,successmessage=successmessage)
@login_required()
def rower_process_sporttrackscallback(request):
code = request.GET['code']
@@ -1174,6 +1193,26 @@ def rower_process_sporttrackscallback(request):
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def rower_process_testcallback(request):
code = request.GET['code']
res = ownapistuff.get_token(code)
access_token = res[0]
expires_in = res[1]
refresh_token = res[2]
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
text = "Access Token:\n"
text += access_token
text += "\n\nRefresh Token:\n"
text += refresh_token
return HttpResponse(text)
@login_required()
def histo_all(request,theuser=0):
promember=0
@@ -1867,7 +1906,7 @@ def workouts_view(request,message='',successmessage='',
'enddate':enddate,
})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
return HttpResponse("User has no rower instance")
@user_passes_test(promember,login_url="/login")
def workout_comparison_list(request,id=0,message='',successmessage='',
@@ -1942,7 +1981,7 @@ def workout_comparison_list(request,id=0,message='',successmessage='',
'enddate':enddate,
})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
return HttpResponse("User has no rower instance")
def workout_view(request,id=0):
try:
@@ -2859,17 +2898,16 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
u = request.user
r = Rower.objects.get(user=u)
res = interactive_chart(id)
script = res[0]
div = res[1]
rowdata = rdata(f1)
hascoordinates = 1
try:
latitude = rowdata.df[' latitude']
except KeyError:
hascoordinates = 0
if rowdata != 0:
try:
latitude = rowdata.df[' latitude']
except KeyError,AttributeError:
hascoordinates = 0
else:
hascoordinates = 0
if hascoordinates:
res = googlemap_chart(rowdata.df[' latitude'],
rowdata.df[' longitude'],
@@ -2892,8 +2930,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
'gmscript': gmscript,
'gmdiv': gmdiv,
})
# 'interactiveplot':script,
# 'the_div':div})
else:
return render(request, 'workout_form.html',
{'form':form,
@@ -2905,8 +2942,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
'gmscript': gmscript,
'gmdiv': gmdiv,
})
# 'interactiveplot':script,
# 'the_div':div})
except Workout.DoesNotExist:
form = WorkoutForm(
@@ -3644,6 +3680,8 @@ def workout_upload_view(request,message=""):
startdatetime=workoutstartdatetime)
w.save()
# put stroke data in database
res = dataprep.dataprep(row.df,id=w.id,bands=True,barchart=True,otwpower=True)
# Make Plot
if (make_plot):
@@ -3716,7 +3754,7 @@ def workout_upload_view(request,message=""):
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
url = "httpvs://log.concept2.com/api/users/%s/results" % (c2userid)
response = requests.post(url,headers=headers,data=json.dumps(data))
# response = c2stuff.workout_c2_upload(request.user,w)
@@ -4077,7 +4115,7 @@ def dashboard_view(request,message="",successmessage=""):
'successmessage':successmessage})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
return HttpResponse("User has no rower instance")
@login_required()
@@ -4104,7 +4142,7 @@ def graphs_view(request):
{'graphs1': g[0:5],
'graphs2': g[5:10]})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
return HttpResponse("User has no rower instance")
def graph_show_view(request,id):
@@ -4435,4 +4473,150 @@ def rower_edit_view(request,message=""):
except Rower.DoesNotExist:
return HttpResponse("This user doesn't exist")
class JSONResponse(HttpResponse):
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
def totimestamp(dt, epoch=datetime.datetime(1970,1,1,tzinfo=tz('UTC'))):
td = dt - epoch
# return td.total_seconds()
return (td.microseconds + (td.seconds + td.days * 86400) * 10**6) / 10**6
def trydf(df,aantal,column):
try:
s = df[column]
if len(s) != aantal:
return np.zeros(aantal)
if not np.issubdtype(s,np.number):
return np.zeros(aantal)
except KeyError:
s = np.zeros(aantal)
return s
@login_required()
def strokedataform(request,id=0):
if request.method == 'GET':
form = StrokeDataForm()
return render(request, 'strokedata_form.html',
{
'form':form,
'id':id,
})
elif request.method == 'POST':
form = StrokeDataForm()
return render(request, 'strokedata_form.html',
{
'form':form,
'id':id,
})
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
@login_required()
def strokedatajson(request,id):
try:
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("Permission error")
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
try:
id = int(id)
except ValueError:
return HttpResponse("Not a valid workout number")
if request.method == 'GET':
columns = ['spm','timesecs','hr','pseconds','power','distance']
datadf = dataprep.getsmallrowdata_db(columns,ids=[id])
return JSONResponse(datadf)
if request.method == 'POST':
checkdata,r = dataprep.getrowdata_db(id=row.id)
if not checkdata.empty:
return "Not OK 1"
# strokedata = request.POST['strokedata']
print request.body
received_json_data = json.loads(request.body)
# checking/validating and cleaning
try:
strokedata = json.loads(received_json_data['strokedata'])
except:
return HttpResponse("Not OK 2")
df = pd.DataFrame(strokedata)
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['timesecs']
aantal = len(time)
pace = df['pseconds']
if len(pace) != aantal:
return "Not OK"
distance = df['distance']
if len(distance) != aantal:
return "Not OK 3"
spm = df['spm']
if len(spm) != aantal:
return "Not OK 4"
res = dataprep.testdata(time,distance,pace,spm)
if not res:
return HttpResponse("Not OK 5")
power = trydf(df,aantal,'power')
drivelength = trydf(df,aantal,'drivelength')
drivespeed = trydf(df,aantal,'drivespeed')
dragfactor = trydf(df,aantal,'dragfactor')
drivetime = trydf(df,aantal,'drivetime')
strokerecoverytime = trydf(df,aantal,'strokerecoverytime')
averagedriveforce = trydf(df,aantal,'averagedriveforce')
peakdriveforce = trydf(df,aantal,'peakdriveforce')
lapidx = trydf(df,aantal,'lapidx')
hr = trydf(df,aantal,'hr')
starttime = totimestamp(row.startdatetime)+time
unixtime = starttime+time
data = pd.DataFrame({'TimeStamp (sec)':unixtime,
' Horizontal (meters)': distance,
' Cadence (stokes/min)':spm,
' HRCur (bpm)':hr,
' DragFactor':dragfactor,
' Stroke500mPace (sec/500m)':pace,
' Power (watts)':power,
' DriveLength (meters)':drivelength,
' DriveTime (ms)':drivetime,
' StrokeRecoveryTime (ms)':strokerecoverytime,
' AverageDriveForce (lbs)':averagedriveforce,
' PeakDriveForce (lbs)':peakdriveforce,
' lapIdx':lapidx,
' ElapsedTime (sec)':time,
})
timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S")
csvfilename ='media/Import_'+timestr+'.csv'
res = data.to_csv(csvfilename,index_label='index')
row.csvfilename = csvfilename
row.save()
r = Rower.objects.get(user=request.user)
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an,ftp=r.ftp)
rowdata = rdata(row.csvfilename,rower=rr).df
datadf = dataprep.dataprep(rowdata,id=row.id,bands=True,barchart=True,otwpower=True)
# mangling
#
return HttpResponse("OK")

View File

@@ -47,16 +47,28 @@ INSTALLED_APPS = [
'translation_manager',
'debug_toolbar',
'django_mailbox',
'rest_framework',
'rest_framework_swagger',
'oauth2_provider',
'corsheaders',
]
AUTHENTICATION_BACKENDS = (
'oauth2_provider.backends.OAuth2Backend',
# Uncomment following if you want to access the admin
'django.contrib.auth.backends.ModelBackend',
)
MIDDLEWARE_CLASSES = [
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'oauth2_provider.middleware.OAuth2TokenMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
'debug_toolbar.middleware.DebugToolbarMiddleware',
@@ -86,6 +98,8 @@ TEMPLATES = [
]
CORS_ORIGIN_ALLOW_ALL = True
WSGI_APPLICATION = 'rowsandall_app.wsgi.application'
@@ -230,5 +244,26 @@ EMAIL_USE_TLS = True
FORECAST_IO_KEY = "bc8196fbd89f11375c7dfc8aa6323c72"
GMAPIKEY = "AIzaSyAgu1w9QSthaGPMLp8y9JedPoMc9sfEgJ8"
# test
# OAUTH2
OAUTH2_PROVIDER = {
# this is the list of available scopes
'SCOPES': {'read': 'Read scope', 'write': 'Write scope', 'groups': 'Access to your groups'}
}
# REST Framework
REST_FRAMEWORK = {
# Use Django's standard `django.contrib.auth` permissions,
# or allow read-only access for unauthenticated users.
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated'
],
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'oauth2_provider.ext.rest_framework.OAuth2Authentication',
),
'PAGE_SIZE': 20,
}

View File

@@ -26,6 +26,7 @@ from rowers import views as rowersviews
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
# url('^', include('django.contrib.auth.urls')),
url(r'^$',rootview),
url(r'^version/$',version),