c2stuff.create_async_workout start
works but is not async yet
This commit is contained in:
@@ -9,6 +9,7 @@ import cgi
|
|||||||
import requests
|
import requests
|
||||||
import requests.auth
|
import requests.auth
|
||||||
import json
|
import json
|
||||||
|
import iso8601
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
@@ -21,8 +22,8 @@ from django.conf import settings
|
|||||||
from django.contrib.auth import authenticate, login, logout
|
from django.contrib.auth import authenticate, login, logout
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
|
import dataprep
|
||||||
|
import pytz
|
||||||
from rowingdata import rowingdata
|
from rowingdata import rowingdata
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
@@ -34,6 +35,8 @@ from requests import Request, Session
|
|||||||
|
|
||||||
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
|
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
|
||||||
|
|
||||||
|
from rowers.tasks import handle_c2_import_stroke_data
|
||||||
|
|
||||||
# Custom error class - to raise a NoTokenError
|
# Custom error class - to raise a NoTokenError
|
||||||
class C2NoTokenError(Exception):
|
class C2NoTokenError(Exception):
|
||||||
def __init__(self,value):
|
def __init__(self,value):
|
||||||
@@ -82,7 +85,96 @@ def c2_open(user):
|
|||||||
|
|
||||||
return thetoken
|
return thetoken
|
||||||
|
|
||||||
|
def add_stroke_data(user,c2id,workoutid,startdatetime,csvfilename):
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
if (r.c2token == '') or (r.c2token is None):
|
||||||
|
return custom_exception_handler(401,s)
|
||||||
|
s = "Token doesn't exist. Need to authorize"
|
||||||
|
elif (timezone.now()>r.tokenexpirydate):
|
||||||
|
s = "Token expired. Needs to refresh."
|
||||||
|
return custom_exception_handler(401,s)
|
||||||
|
else:
|
||||||
|
# ready to fetch. Hurray
|
||||||
|
|
||||||
|
res = handle_c2_import_stroke_data(r.c2token,
|
||||||
|
c2id,
|
||||||
|
workoutid,
|
||||||
|
startdatetime,
|
||||||
|
csvfilename)
|
||||||
|
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
# get workout metrics, then relay stroke data to an asynchronous task
|
||||||
|
def create_async_workout(user,c2id):
|
||||||
|
|
||||||
|
res = get_c2_workout(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']
|
||||||
|
|
||||||
|
distance = data['distance']
|
||||||
|
c2id = data['id']
|
||||||
|
workouttype = data['type']
|
||||||
|
verified = data['verified']
|
||||||
|
startdatetime = iso8601.parse_date(data['date'])
|
||||||
|
weightclass = data['weight_class']
|
||||||
|
weightcategory = 'hwt'
|
||||||
|
if weightclass == "L":
|
||||||
|
weightcategory = 'lwt'
|
||||||
|
|
||||||
|
# Create CSV file name and save data to CSV file
|
||||||
|
csvfilename ='media/Import_'+str(c2id)+'.csv.gz'
|
||||||
|
|
||||||
|
totaltime = data['time']/10.
|
||||||
|
duration = dataprep.totaltime_sec_to_string(totaltime)
|
||||||
|
|
||||||
|
try:
|
||||||
|
timezone_str = tz(data['timezone'])
|
||||||
|
except:
|
||||||
|
timezone_str = 'UTC'
|
||||||
|
|
||||||
|
workoutdate = startdatetime.astimezone(
|
||||||
|
pytz.timezone(timezone_str)
|
||||||
|
).strftime('%Y-%m-%d')
|
||||||
|
starttime = startdatetime.astimezone(
|
||||||
|
pytz.timezone(timezone_str)
|
||||||
|
).strftime('%H:%M:%S')
|
||||||
|
|
||||||
|
r = Rower.objects.get(user=user)
|
||||||
|
|
||||||
|
|
||||||
|
w = Workout(
|
||||||
|
user=r,
|
||||||
|
workouttype = workouttype,
|
||||||
|
name = 'Imported workout',
|
||||||
|
date = workoutdate,
|
||||||
|
starttime = starttime,
|
||||||
|
startdatetime = startdatetime,
|
||||||
|
timezone = timezone_str,
|
||||||
|
duration = duration,
|
||||||
|
distance=distance,
|
||||||
|
weightcategory = weightcategory,
|
||||||
|
uploadedtoc2 = c2id,
|
||||||
|
csvfilename = csvfilename,
|
||||||
|
notes = 'imported from Concept2 log'
|
||||||
|
)
|
||||||
|
|
||||||
|
w.save()
|
||||||
|
|
||||||
|
# Check if workout has stroke data, and get the stroke data
|
||||||
|
if data['stroke_data']:
|
||||||
|
result = add_stroke_data(user,c2id,w.id,startdatetime,csvfilename)
|
||||||
|
else:
|
||||||
|
# create synthetic stroke data
|
||||||
|
pass
|
||||||
|
|
||||||
|
return w.id
|
||||||
|
|
||||||
# convert datetime object to seconds
|
# convert datetime object to seconds
|
||||||
def makeseconds(t):
|
def makeseconds(t):
|
||||||
|
|||||||
@@ -723,9 +723,35 @@ def create_row_df(r,distance,duration,startdatetime,
|
|||||||
return (id, message)
|
return (id, message)
|
||||||
|
|
||||||
|
|
||||||
|
def totaltime_sec_to_string(totaltime):
|
||||||
|
hours = int(totaltime / 3600.)
|
||||||
|
if hours > 23:
|
||||||
|
message = 'Warning: The workout duration was longer than 23 hours. '
|
||||||
|
hours = 23
|
||||||
|
|
||||||
|
minutes = int((totaltime - 3600. * hours) / 60.)
|
||||||
|
if minutes > 59:
|
||||||
|
minutes = 59
|
||||||
|
if not message:
|
||||||
|
message = 'Warning: there is something wrong with the workout duration'
|
||||||
|
|
||||||
|
seconds = int(totaltime - 3600. * hours - 60. * minutes)
|
||||||
|
if seconds > 59:
|
||||||
|
seconds = 59
|
||||||
|
if not message:
|
||||||
|
message = 'Warning: there is something wrong with the workout duration'
|
||||||
|
|
||||||
|
tenths = int(10 * (totaltime - 3600. * hours - 60. * minutes - seconds))
|
||||||
|
if tenths > 9:
|
||||||
|
tenths = 9
|
||||||
|
if not message:
|
||||||
|
message = 'Warning: there is something wrong with the workout duration'
|
||||||
|
|
||||||
|
duration = "%s:%s:%s.%s" % (hours, minutes, seconds, tenths)
|
||||||
|
|
||||||
|
return duration
|
||||||
|
|
||||||
# Processes painsled CSV file to database
|
# Processes painsled CSV file to database
|
||||||
|
|
||||||
|
|
||||||
def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||||
dosummary=True, title='Workout',
|
dosummary=True, title='Workout',
|
||||||
workoutsource='unknown',
|
workoutsource='unknown',
|
||||||
@@ -838,30 +864,6 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
if np.isnan(totaltime):
|
if np.isnan(totaltime):
|
||||||
totaltime = 0
|
totaltime = 0
|
||||||
|
|
||||||
hours = int(totaltime / 3600.)
|
|
||||||
if hours > 23:
|
|
||||||
message = 'Warning: The workout duration was longer than 23 hours. '
|
|
||||||
hours = 23
|
|
||||||
|
|
||||||
minutes = int((totaltime - 3600. * hours) / 60.)
|
|
||||||
if minutes > 59:
|
|
||||||
minutes = 59
|
|
||||||
if not message:
|
|
||||||
message = 'Warning: there is something wrong with the workout duration'
|
|
||||||
|
|
||||||
seconds = int(totaltime - 3600. * hours - 60. * minutes)
|
|
||||||
if seconds > 59:
|
|
||||||
seconds = 59
|
|
||||||
if not message:
|
|
||||||
message = 'Warning: there is something wrong with the workout duration'
|
|
||||||
|
|
||||||
tenths = int(10 * (totaltime - 3600. * hours - 60. * minutes - seconds))
|
|
||||||
if tenths > 9:
|
|
||||||
tenths = 9
|
|
||||||
if not message:
|
|
||||||
message = 'Warning: there is something wrong with the workout duration'
|
|
||||||
|
|
||||||
duration = "%s:%s:%s.%s" % (hours, minutes, seconds, tenths)
|
|
||||||
|
|
||||||
if dosummary:
|
if dosummary:
|
||||||
summary = row.allstats()
|
summary = row.allstats()
|
||||||
@@ -897,6 +899,8 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
timezone_str = r.defaulttimezone
|
timezone_str = r.defaulttimezone
|
||||||
|
|
||||||
|
duration = totaltime_sec_to_string(totaltime)
|
||||||
|
|
||||||
workoutdate = workoutstartdatetime.astimezone(
|
workoutdate = workoutstartdatetime.astimezone(
|
||||||
pytz.timezone(timezone_str)
|
pytz.timezone(timezone_str)
|
||||||
).strftime('%Y-%m-%d')
|
).strftime('%Y-%m-%d')
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
# This is Data prep used for testing purposes (no Django environment)
|
# This is Data prep used for testing purposes (no Django environment)
|
||||||
# Uses the debug SQLite database for stroke data
|
# Uses the debug SQLite database for stroke data
|
||||||
from rowingdata import rowingdata as rrdata
|
from rowingdata import rowingdata as rrdata
|
||||||
|
from rowingdata import make_cumvalues
|
||||||
from rowingdata import rower as rrower
|
from rowingdata import rower as rrower
|
||||||
from rowingdata import main as rmain
|
from rowingdata import main as rmain
|
||||||
|
from time import strftime
|
||||||
from pandas import DataFrame,Series
|
from pandas import DataFrame,Series
|
||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -131,6 +131,89 @@ def rdata(file,rower=rrower()):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
# Saves C2 stroke data to CSV and database
|
||||||
|
def add_c2_stroke_data_db(strokedata,workoutid,starttimeunix,csvfilename,
|
||||||
|
debug=False):
|
||||||
|
|
||||||
|
res = make_cumvalues(0.1*strokedata['t'])
|
||||||
|
cum_time = res[0]
|
||||||
|
lapidx = res[1]
|
||||||
|
|
||||||
|
unixtime = cum_time+starttimeunix
|
||||||
|
# unixtime[0] = starttimeunix
|
||||||
|
seconds = 0.1*strokedata.ix[:,'t']
|
||||||
|
|
||||||
|
nr_rows = len(unixtime)
|
||||||
|
|
||||||
|
try:
|
||||||
|
latcoord = strokedata.ix[:,'lat']
|
||||||
|
loncoord = strokedata.ix[:,'lon']
|
||||||
|
except:
|
||||||
|
latcoord = np.zeros(nr_rows)
|
||||||
|
loncoord = np.zeros(nr_rows)
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
strokelength = strokedata.ix[:,'strokelength']
|
||||||
|
except:
|
||||||
|
strokelength = np.zeros(nr_rows)
|
||||||
|
|
||||||
|
dist2 = 0.1*strokedata.ix[:,'d']
|
||||||
|
|
||||||
|
try:
|
||||||
|
spm = strokedata.ix[:,'spm']
|
||||||
|
except KeyError:
|
||||||
|
spm = 0*dist2
|
||||||
|
|
||||||
|
try:
|
||||||
|
hr = strokedata.ix[:,'hr']
|
||||||
|
except KeyError:
|
||||||
|
hr = 0*spm
|
||||||
|
pace = strokedata.ix[:,'p']/10.
|
||||||
|
pace = np.clip(pace,0,1e4)
|
||||||
|
pace = pace.replace(0,300)
|
||||||
|
|
||||||
|
velo = 500./pace
|
||||||
|
|
||||||
|
power = 2.8*velo**3
|
||||||
|
|
||||||
|
# save csv
|
||||||
|
# Create data frame with all necessary data to write to csv
|
||||||
|
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||||
|
' Horizontal (meters)': dist2,
|
||||||
|
' Cadence (stokes/min)':spm,
|
||||||
|
' HRCur (bpm)':hr,
|
||||||
|
' longitude':loncoord,
|
||||||
|
' latitude':latcoord,
|
||||||
|
' Stroke500mPace (sec/500m)':pace,
|
||||||
|
' Power (watts)':power,
|
||||||
|
' DragFactor':np.zeros(nr_rows),
|
||||||
|
' DriveLength (meters)':np.zeros(nr_rows),
|
||||||
|
' StrokeDistance (meters)':strokelength,
|
||||||
|
' DriveTime (ms)':np.zeros(nr_rows),
|
||||||
|
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||||
|
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||||
|
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||||
|
' lapIdx':lapidx,
|
||||||
|
' ElapsedTime (sec)':seconds,
|
||||||
|
'cum_dist': dist2
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||||
|
|
||||||
|
timestr = strftime("%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
|
|
||||||
|
# Create CSV file name and save data to CSV file
|
||||||
|
|
||||||
|
res = df.to_csv(csvfilename,index_label='index',
|
||||||
|
compression='gzip')
|
||||||
|
|
||||||
|
data = dataprep(df,id=workoutid,bands=False,debug=debug)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
# Processes painsled CSV file to database
|
# Processes painsled CSV file to database
|
||||||
def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||||
dosummary=True,title='Workout',
|
dosummary=True,title='Workout',
|
||||||
|
|||||||
@@ -32,7 +32,8 @@ from utils import deserialize_list
|
|||||||
from rowers.dataprepnodjango import (
|
from rowers.dataprepnodjango import (
|
||||||
update_strokedata, new_workout_from_file,
|
update_strokedata, new_workout_from_file,
|
||||||
getsmallrowdata_db, updatecpdata_sql,
|
getsmallrowdata_db, updatecpdata_sql,
|
||||||
update_agegroup_db,fitnessmetric_to_sql
|
update_agegroup_db,fitnessmetric_to_sql,
|
||||||
|
add_c2_stroke_data_db
|
||||||
)
|
)
|
||||||
|
|
||||||
from django.core.mail import send_mail, EmailMessage
|
from django.core.mail import send_mail, EmailMessage
|
||||||
@@ -40,8 +41,9 @@ from django.db.utils import OperationalError
|
|||||||
|
|
||||||
import datautils
|
import datautils
|
||||||
import utils
|
import utils
|
||||||
|
import requests
|
||||||
import longtask
|
import longtask
|
||||||
|
import arrow
|
||||||
|
|
||||||
# testing task
|
# testing task
|
||||||
|
|
||||||
@@ -50,6 +52,33 @@ import longtask
|
|||||||
def add(x, y):
|
def add(x, y):
|
||||||
return x + y
|
return x + y
|
||||||
|
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def handle_c2_import_stroke_data(c2token,
|
||||||
|
c2id,workoutid,
|
||||||
|
startdatetime,
|
||||||
|
csvfilename,debug=True):
|
||||||
|
authorizationstring = str('Bearer ' + c2token)
|
||||||
|
headers = {'Authorization': authorizationstring,
|
||||||
|
'user-agent': 'sanderroosendaal',
|
||||||
|
'Content-Type': 'application/json'}
|
||||||
|
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes"
|
||||||
|
s = requests.get(url,headers=headers)
|
||||||
|
if s.status_code == 200:
|
||||||
|
strokedata = pd.DataFrame.from_dict(s.json()['data'])
|
||||||
|
starttimeunix = arrow.get(startdatetime).timestamp
|
||||||
|
result = add_c2_stroke_data_db(
|
||||||
|
strokedata,workoutid,starttimeunix,
|
||||||
|
csvfilename,debug=debug,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
return 1
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
def getagegrouprecord(age,sex='male',weightcategory='hwt',
|
def getagegrouprecord(age,sex='male',weightcategory='hwt',
|
||||||
distance=2000,duration=None,indf=pd.DataFrame()):
|
distance=2000,duration=None,indf=pd.DataFrame()):
|
||||||
|
|
||||||
|
|||||||
@@ -9115,34 +9115,7 @@ def workout_getc2workout_all(request,page=1,message=""):
|
|||||||
])
|
])
|
||||||
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
||||||
for c2id in newids:
|
for c2id in newids:
|
||||||
res = c2stuff.get_c2_workout(request.user,c2id)
|
workoutid = c2stuff.create_async_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
|
|
||||||
try:
|
|
||||||
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)
|
|
||||||
except KeyError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
url = reverse(workouts_view)
|
url = reverse(workouts_view)
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|||||||
Reference in New Issue
Block a user