From bc396e62a1e433b532e68f4871d660f355d2db83 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Tue, 26 Jun 2018 16:01:46 +0200 Subject: [PATCH] done all except mapmyfitness --- rowers/c2stuff.py | 177 ++++++++- rowers/runkeeperstuff.py | 222 +++++++++++- rowers/sporttracksstuff.py | 209 ++++++++++- rowers/stravastuff.py | 145 +++++++- rowers/urls.py | 8 +- rowers/utils.py | 4 +- rowers/views.py | 724 +++++++------------------------------ 7 files changed, 883 insertions(+), 606 deletions(-) diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py index 41201a7e..028576f6 100644 --- a/rowers/c2stuff.py +++ b/rowers/c2stuff.py @@ -15,6 +15,7 @@ from django.utils import timezone from datetime import datetime from datetime import timedelta import time +from time import strftime # Django from django.shortcuts import render_to_response @@ -25,7 +26,7 @@ from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required import dataprep import pytz -from rowingdata import rowingdata +from rowingdata import rowingdata, make_cumvalues import pandas as pd import numpy as np from rowers.models import Rower,Workout @@ -36,6 +37,8 @@ from requests import Request, Session from utils import myqueue,uniqify,isprorower, custom_exception_handler, NoTokenError +from uuid import uuid4 + from rowers.types import otwtypes from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET @@ -540,7 +543,7 @@ def make_authorization_url(request): return HttpResponseRedirect(url) # Get workout from C2 ID -def get_c2_workout(user,c2id): +def get_workout(user,c2id): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): s = "Token doesn't exist. Need to authorize" @@ -557,7 +560,24 @@ def get_c2_workout(user,c2id): url = "https://log.concept2.com/api/users/me/results/"+str(c2id) s = requests.get(url,headers=headers) - return s + data = s.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 = get_c2_workout_strokes(user,c2id) + if res2.status_code == 200: + strokedata = pd.DataFrame.from_dict(res2.json()['data']) + else: + strokedata = pd.DataFrame() + + return data,strokedata # Get stroke data belonging to C2 ID def get_c2_workout_strokes(user,c2id): @@ -725,3 +745,154 @@ def rower_c2_token_refresh(user): else: return None +# Create workout data from Strava or Concept2 +# data and create the associated Workout object and save it +def add_workout_from_data(user,importid,data,strokedata, + source='c2',splitdata=None, + workoutsource='concept2'): + try: + workouttype = data['type'] + except KeyError: + workouttype = 'rower' + + if workouttype not in [x[0] for x in Workout.workouttypes]: + workouttype = 'other' + try: + comments = data['comments'] + except: + comments = ' ' + + try: + thetimezone = tz(data['timezone']) + except: + thetimezone = 'UTC' + + r = Rower.objects.get(user=user) + try: + rowdatetime = iso8601.parse_date(data['date_utc']) + except KeyError: + rowdatetime = iso8601.parse_date(data['start_date']) + except ParseError: + rowdatetime = iso8601.parse_date(data['date']) + + + try: + c2intervaltype = data['workout_type'] + + except KeyError: + c2intervaltype = '' + + try: + title = data['name'] + except KeyError: + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:20] + except: + title = 'Imported' + + starttimeunix = arrow.get(rowdatetime).timestamp + + 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 + }) + + + 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 + csvfilename ='media/{code}_{importid}.csv'.format( + importid=importid, + code = uuid4().hex[:16] + ) + + res = df.to_csv(csvfilename+'.gz',index_label='index', + compression='gzip') + + + # with Concept2 + if source=='c2': + try: + totaldist = data['distance'] + totaltime = data['time']/10. + except KeyError: + totaldist = 0 + totaltime = 0 + else: + totaldist = 0 + totaltime = 0 + + id,message = dataprep.save_workout_database( + csvfilename,r, + workouttype=workouttype, + title=title,notes=comments, + workoutsource=workoutsource, + dosummary=True + ) + + + + return id,message diff --git a/rowers/runkeeperstuff.py b/rowers/runkeeperstuff.py index 8f8afb71..db49b902 100644 --- a/rowers/runkeeperstuff.py +++ b/rowers/runkeeperstuff.py @@ -12,6 +12,8 @@ from datetime import datetime import numpy as np from dateutil import parser import time +import dateutil +from time import strftime import math from math import sin,cos,atan2,sqrt import os,sys @@ -29,7 +31,10 @@ from django.contrib.auth.decorators import login_required from rowingdata import rowingdata import pandas as pd from rowers.models import Rower,Workout,checkworkoutuser - +from uuid import uuid4 +import iso8601 +import arrow +from rowers import types from rowsandall_app.settings import ( C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, @@ -38,6 +43,27 @@ from rowsandall_app.settings import ( from utils import geo_distance,ewmovingaverage,NoTokenError, custom_exception_handler +def splitrunkeeperlatlongdata(lijst,tname,latname,lonname): + t = [] + lat = [] + lon = [] + for d in lijst: + t.append(d[tname]) + lat.append(d[latname]) + lon.append(d[lonname]) + + return [np.array(t),np.array(lat),np.array(lon)] + +def splitrunkeeperdata(lijst,xname,yname): + x = [] + y = [] + for d in lijst: + x.append(d[xname]) + y.append(d[yname]) + + return [np.array(x),np.array(y)] + +import dataprep # Checks if user has SportTracks token, renews them if they are expired def runkeeper_open(user): @@ -75,7 +101,6 @@ def get_token(code): 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": RUNKEEPER_CLIENT_ID, @@ -105,7 +130,7 @@ def get_runkeeper_workout_list(user): return s # Get workout summary data by Runkeeper ID -def get_runkeeper_workout(user,runkeeperid): +def get_workout(user,runkeeperid): r = Rower.objects.get(user=user) if (r.runkeepertoken == '') or (r.runkeepertoken is None): return custom_exception_handler(401,s) @@ -119,7 +144,16 @@ def get_runkeeper_workout(user,runkeeperid): url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid) s = requests.get(url,headers=headers) - return s + try: + data = s.json() + except ValueError: + data = {} + + strokedata = pd.DataFrame.from_dict({ + key: pd.Series(value) for key, value in data.items() + }) + + return data,strokedata # Create Workout Data for upload to SportTracks def createrunkeeperworkoutdata(w): @@ -328,3 +362,183 @@ def workout_runkeeper_upload(user,w): return message, rkid return message,rkid + +# Create workout from RunKeeper Data +def add_workout_from_data(user,importid,data,strokedata,source='runkeeper', + workoutsource='runkeeper'): + # To Do - add utcoffset to time + workouttype = data['type'] + if workouttype not in [x[0] for x in Workout.workouttypes]: + workouttype = 'other' + try: + comments = data['notes'] + except: + comments = '' + + try: + utcoffset = tz(data['utcoffset']) + except: + utcoffset = 0 + + r = Rower.objects.get(user=user) + + try: + rowdatetime = iso8601.parse_date(data['start_time']) + except iso8601.ParseError: + try: + rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except ValueError: + try: + rowdatetime = dateutil.parser.parse(data['start_time']) + #rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except: + rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + starttimeunix = arrow.get(rowdatetime).timestamp + #starttimeunix = mktime(rowdatetime.utctimetuple()) + starttimeunix += utcoffset*3600 + + + try: + title = data['name'] + except: + title = "Imported data" + + + + res = splitrunkeeperdata(data['distance'],'timestamp','distance') + + distance = res[1] + times_distance = res[0] + + try: + l = data['path'] + + res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude') + times_location = res[0] + latcoord = res[1] + loncoord = res[2] + + except: + times_location = times_distance + latcoord = np.zeros(len(times_distance)) + loncoord = np.zeros(len(times_distance)) + if workouttype in types.otwtypes: + workouttype = 'rower' + + try: + res = splitrunkeeperdata(data['cadence'],'timestamp','cadence') + times_spm = res[0] + spm = res[1] + except KeyError: + times_spm = times_distance + spm = 0*times_distance + + try: + res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate') + hr = res[1] + times_hr = res[0] + except KeyError: + times_hr = times_distance + hr = 0*times_distance + + + # create data series and remove duplicates + distseries = pd.Series(distance,index=times_distance) + distseries = distseries.groupby(distseries.index).first() + latseries = pd.Series(latcoord,index=times_location) + try: + latseries = latseries.groupby(latseries.index).first() + except TypeError: + latseries = 0.0*distseries + + lonseries = pd.Series(loncoord,index=times_location) + try: + lonseries = lonseries.groupby(lonseries.index).first() + except TypeError: + lonseries = 0.0*distseries + + spmseries = pd.Series(spm,index=times_spm) + spmseries = spmseries.groupby(spmseries.index).first() + hrseries = pd.Series(hr,index=times_hr) + try: + hrseries = hrseries.groupby(hrseries.index).first() + except TypeError: + hrseries = 0*distseries + + + # Create dicts and big dataframe + d = { + ' Horizontal (meters)': distseries, + ' latitude': latseries, + ' longitude': lonseries, + ' Cadence (stokes/min)': spmseries, + ' HRCur (bpm)' : hrseries, + } + + + + df = pd.DataFrame(d) + + df = df.groupby(level=0).last() + + cum_time = df.index.values + df[' ElapsedTime (sec)'] = cum_time + + velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff() + + df[' Power (watts)'] = 0.0*velo + + nr_rows = len(velo.values) + + df[' DriveLength (meters)'] = np.zeros(nr_rows) + df[' StrokeDistance (meters)'] = np.zeros(nr_rows) + df[' DriveTime (ms)'] = np.zeros(nr_rows) + df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows) + df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows) + df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows) + df[' lapIdx'] = np.zeros(nr_rows) + + + + unixtime = cum_time+starttimeunix + try: + unixtime[0] = starttimeunix + except IndexError: + return (0,'No data to import') + + df['TimeStamp (sec)'] = unixtime + + + dt = np.diff(cum_time).mean() + wsize = round(5./dt) + + # velo2 = stravastuff.ewmovingaverage(velo,wsize) + + # df[' Stroke500mPace (sec/500m)'] = 500./velo2 + + + df = df.fillna(0) + + df.sort_values(by='TimeStamp (sec)',ascending=True) + + timestr = strftime("%Y%m%d-%H%M%S") + +# csvfilename ='media/Import_'+str(importid)+'.csv' + csvfilename ='media/{code}_{importid}.csv'.format( + importid=importid, + code = uuid4().hex[:16] + ) + + res = df.to_csv(csvfilename+'.gz',index_label='index', + compression='gzip') + + id,message = dataprep.save_workout_database(csvfilename,r, + workouttype=workouttype, + workoutsource='runkeeper', + title=title, + notes=comments) + + return (id,message) + diff --git a/rowers/sporttracksstuff.py b/rowers/sporttracksstuff.py index 8190cbdb..d449a163 100644 --- a/rowers/sporttracksstuff.py +++ b/rowers/sporttracksstuff.py @@ -17,7 +17,9 @@ from math import sin,cos,atan2,sqrt import urllib import c2stuff import pytz - +import iso8601 +from uuid import uuid4 +import arrow # Django from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse,JsonResponse @@ -31,10 +33,26 @@ from django.contrib.auth.decorators import login_required from rowingdata import rowingdata import pandas as pd from rowers.models import Rower,Workout,checkworkoutuser - +from rowers import types 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 -from utils import NoTokenError, custom_exception_handler +from utils import NoTokenError, custom_exception_handler, ewmovingaverage + +from time import strftime +import dataprep + +# Splits SportTracks data which is one long sequence of +# [t,[lat,lon],t2,[lat2,lon2] ...] +# to [t,t2,t3, ...], [[lat,long],[lat2,long2],... +def splitstdata(lijst): + t = [] + latlong = [] + while len(lijst)>=2: + t.append(lijst[0]) + latlong.append(lijst[1]) + lijst = lijst[2:] + + return [np.array(t),np.array(latlong)] # Checks if user has SportTracks token, renews them if they are expired @@ -125,7 +143,7 @@ def get_token(code): 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": SPORTTRACKS_CLIENT_ID, @@ -178,7 +196,7 @@ def get_sporttracks_workout_list(user): return s # Get workout summary data by SportTracks ID -def get_sporttracks_workout(user,sporttracksid): +def get_workout(user,sporttracksid): r = Rower.objects.get(user=user) if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): return custom_exception_handler(401,s) @@ -195,7 +213,13 @@ def get_sporttracks_workout(user,sporttracksid): url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/"+str(sporttracksid) s = requests.get(url,headers=headers) - return s + data = s.json() + + strokedata = pd.DataFrame.from_dict({ + key: pd.Series(value) for key, value in data.items() + }) + + return data,strokedata # Create Workout Data for upload to SportTracks def createsporttracksworkoutdata(w): @@ -366,3 +390,176 @@ def workout_sporttracks_upload(user,w): return message,stid return message,stid + +# Create workout from SportTracks Data, which are slightly different +# than Strava or Concept2 data +def add_workout_from_data(user,importid,data,strokedata,source='sporttracks', + workoutsource='sporttracks'): + try: + workouttype = data['type'] + except KeyError: + workouttype = 'other' + + if workouttype not in [x[0] for x in Workout.workouttypes]: + workouttype = 'other' + try: + comments = data['comments'] + except: + comments = '' + + + r = Rower.objects.get(user=user) + try: + rowdatetime = iso8601.parse_date(data['start_time']) + except iso8601.ParseError: + try: + rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except: + try: + rowdatetime = dateutil.parser.parse(data['start_time']) + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except: + rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + starttimeunix = arrow.get(rowdatetime).timestamp + + try: + title = data['name'] + except: + title = "Imported data" + + try: + res = splitstdata(data['distance']) + distance = res[1] + times_distance = res[0] + except KeyError: + try: + res = splitstdata(data['heartrate']) + times_distance = res[0] + distance = 0*times_distance + except KeyError: + return (0,"No distance or heart rate data in the workout") + + + try: + l = data['location'] + + res = splitstdata(l) + times_location = res[0] + latlong = res[1] + latcoord = [] + loncoord = [] + + for coord in latlong: + lat = coord[0] + lon = coord[1] + latcoord.append(lat) + loncoord.append(lon) + except: + times_location = times_distance + latcoord = np.zeros(len(times_distance)) + loncoord = np.zeros(len(times_distance)) + if workouttype in types.otwtypes: + workouttype = 'rower' + + try: + res = splitstdata(data['cadence']) + times_spm = res[0] + spm = res[1] + except KeyError: + times_spm = times_distance + spm = 0*times_distance + + try: + res = splitstdata(data['heartrate']) + hr = res[1] + times_hr = res[0] + except KeyError: + times_hr = times_distance + hr = 0*times_distance + + + # create data series and remove duplicates + distseries = pd.Series(distance,index=times_distance) + distseries = distseries.groupby(distseries.index).first() + latseries = pd.Series(latcoord,index=times_location) + latseries = latseries.groupby(latseries.index).first() + lonseries = pd.Series(loncoord,index=times_location) + lonseries = lonseries.groupby(lonseries.index).first() + spmseries = pd.Series(spm,index=times_spm) + spmseries = spmseries.groupby(spmseries.index).first() + hrseries = pd.Series(hr,index=times_hr) + hrseries = hrseries.groupby(hrseries.index).first() + + + # Create dicts and big dataframe + d = { + ' Horizontal (meters)': distseries, + ' latitude': latseries, + ' longitude': lonseries, + ' Cadence (stokes/min)': spmseries, + ' HRCur (bpm)' : hrseries, + } + + + + df = pd.DataFrame(d) + + df = df.groupby(level=0).last() + + cum_time = df.index.values + df[' ElapsedTime (sec)'] = cum_time + + velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff() + + df[' Power (watts)'] = 0.0*velo + + nr_rows = len(velo.values) + + df[' DriveLength (meters)'] = np.zeros(nr_rows) + df[' StrokeDistance (meters)'] = np.zeros(nr_rows) + df[' DriveTime (ms)'] = np.zeros(nr_rows) + df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows) + df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows) + df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows) + df[' lapIdx'] = np.zeros(nr_rows) + + + + unixtime = cum_time+starttimeunix + unixtime[0] = starttimeunix + + df['TimeStamp (sec)'] = unixtime + + + dt = np.diff(cum_time).mean() + wsize = round(5./dt) + + velo2 = ewmovingaverage(velo,wsize) + + df[' Stroke500mPace (sec/500m)'] = 500./velo2 + + + df = df.fillna(0) + + df.sort_values(by='TimeStamp (sec)',ascending=True) + + timestr = strftime("%Y%m%d-%H%M%S") + +# csvfilename ='media/Import_'+str(importid)+'.csv' + csvfilename ='media/{code}_{importid}.csv'.format( + importid=importid, + code = uuid4().hex[:16] + ) + + res = df.to_csv(csvfilename+'.gz',index_label='index', + compression='gzip') + + id,message = dataprep.save_workout_database(csvfilename,r, + workouttype=workouttype, + title=title, + notes=comments, + workoutsource='sporttracks') + + return (id,message) diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index b1c2d3ed..988e1ba7 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -11,6 +11,7 @@ from datetime import datetime import numpy as np from dateutil import parser import time +from time import strftime,strptime import math from math import sin,cos,atan2,sqrt import os,sys @@ -35,6 +36,7 @@ queuehigh = django_rq.get_queue('low') # Project # from .models import Profile from rowingdata import rowingdata +from rowingdata import make_cumvalues import pandas as pd from rowers.models import Rower,Workout from rowers.models import checkworkoutuser @@ -252,7 +254,7 @@ def create_async_workout(alldata,user,stravaid): from utils import get_strava_stream # Get a Strava workout summary data and stroke data by ID -def get_strava_workout(user,stravaid): +def get_workout(user,stravaid): r = Rower.objects.get(user=user) if (r.stravatoken == '') or (r.stravatoken is None): s = "Token doesn't exist. Need to authorize" @@ -347,7 +349,7 @@ def get_strava_workout(user,stravaid): # startdatetime = datetime.datetime.strptime(startdatetime,"%Y-%m-%d-%H:%M:%S") return [workoutsummary,df] - + # Generate Workout data for Strava (a TCX file) def createstravaworkoutdata(w,dozip=True): filename = w.csvfilename @@ -482,3 +484,142 @@ def workout_strava_upload(user,w): return message,stravaid return message,stravaid return message,stravaid + +# Create workout data from Strava or Concept2 +# data and create the associated Workout object and save it +def add_workout_from_data(user,importid,data,strokedata, + source='strava',splitdata=None, + workoutsource='strava'): + try: + workouttype = data['type'] + except KeyError: + workouttype = 'rower' + + if workouttype not in [x[0] for x in Workout.workouttypes]: + workouttype = 'other' + try: + comments = data['comments'] + except: + comments = ' ' + + try: + thetimezone = tz(data['timezone']) + except: + thetimezone = 'UTC' + + r = Rower.objects.get(user=user) + try: + rowdatetime = iso8601.parse_date(data['date_utc']) + except KeyError: + rowdatetime = iso8601.parse_date(data['start_date']) + except ParseError: + rowdatetime = iso8601.parse_date(data['date']) + + + try: + intervaltype = data['workout_type'] + + except KeyError: + intervaltype = '' + + try: + title = data['name'] + except KeyError: + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:20] + except: + title = 'Imported' + + starttimeunix = arrow.get(rowdatetime).timestamp + + res = make_cumvalues(0.1*strokedata['t']) + cum_time = res[0] + lapidx = res[1] + + unixtime = cum_time+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 + }) + + + 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 + csvfilename ='media/{code}_{importid}.csv'.format( + importid=importid, + code = uuid4().hex[:16] + ) + + res = df.to_csv(csvfilename+'.gz',index_label='index', + compression='gzip') + + + id,message = dataprep.save_workout_database( + csvfilename,r, + workouttype=workouttype, + title=title,notes=comments, + workoutsource=workoutsource, + dosummary=True + ) + + + + return id,message diff --git a/rowers/urls.py b/rowers/urls.py index ff7ba9e6..c800e2d1 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -321,17 +321,17 @@ urlpatterns = [ url(r'^workout/c2list/$',views.workout_c2import_view), url(r'^workout/c2list/(?P\d+)$',views.workout_c2import_view), url(r'^workout/stravaimport/$',views.workout_stravaimport_view), - url(r'^workout/c2import/(?P\d+)/$',views.workout_getc2workout_view), +# url(r'^workout/c2import/(?P\d+)/$',views.workout_getc2workout_view), url(r'^workout/c2import/all/$',views.workout_getc2workout_all), url(r'^workout/c2import/all/(?P\d+)$',views.workout_getc2workout_all), - url(r'^workout/stravaimport/(?P\d+)/$',views.workout_getstravaworkout_view), +# url(r'^workout/stravaimport/(?P\d+)/$',views.workout_getstravaworkout_view), + url(r'^workout/(?P\w+.*)import/(?P\d+)/$',views.workout_getimportview), url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all), url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view), - url(r'^workout/sporttracksimport/(?P\d+)/$',views.workout_getsporttracksworkout_view), url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all), url(r'^workout/polarimport/$',views.workout_polarimport_view), url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view), - url(r'^workout/runkeeperimport/(?P\d+)/$',views.workout_getrunkeeperworkout_view), +# url(r'^workout/runkeeperimport/(?P\d+)/$',views.workout_getrunkeeperworkout_view), url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view), url(r'^workout/underarmourimport/(?P\d+)/$',views.workout_getunderarmourworkout_view), url(r'^workout/(?P\d+)/deleteconfirm$',views.workout_delete_confirm_view), diff --git a/rowers/utils.py b/rowers/utils.py index 1efd8aed..d88b07f4 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -435,8 +435,8 @@ def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high 'Content-Type': 'application/json', 'resolution': 'medium',} - url = "https://www.strava.com/api/v3/activities/{stravaid}/streams/{metric}?resolution={fetchresolutions}&series_type={series_type}".format( - stravaid=stravid, + url = "https://www.strava.com/api/v3/activities/{stravaid}/streams/{metric}?resolution={fetchresolution}&series_type={series_type}".format( + stravaid=stravaid, fetchresolution=fetchresolution, series_type=series_type, metric=metric diff --git a/rowers/views.py b/rowers/views.py index 60416947..3b902137 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -839,6 +839,12 @@ def get_time(second): def getidfromsturi(uri,length=8): return uri[len(uri)-length:] +import re + +def getidfromuri(uri): + m = re.search('/(\w.*)\/(\d+)',uri) + return m.group(2) + def splituadata(lijst): t = [] y = [] @@ -848,38 +854,6 @@ def splituadata(lijst): return np.array(t),np.array(y) -def splitrunkeeperlatlongdata(lijst,tname,latname,lonname): - t = [] - lat = [] - lon = [] - for d in lijst: - t.append(d[tname]) - lat.append(d[latname]) - lon.append(d[lonname]) - - return [np.array(t),np.array(lat),np.array(lon)] - -def splitrunkeeperdata(lijst,xname,yname): - x = [] - y = [] - for d in lijst: - x.append(d[xname]) - y.append(d[yname]) - - return [np.array(x),np.array(y)] - -# Splits SportTracks data which is one long sequence of -# [t,[lat,lon],t2,[lat2,lon2] ...] -# to [t,t2,t3, ...], [[lat,long],[lat2,long2],... -def splitstdata(lijst): - t = [] - latlong = [] - while len(lijst)>=2: - t.append(lijst[0]) - latlong.append(lijst[1]) - lijst = lijst[2:] - - return [np.array(t),np.array(latlong)] from utils import ( geo_distance,serialize_list,deserialize_list,uniqify, @@ -1268,353 +1242,8 @@ def add_workout_from_strokedata(user,importid,data,strokedata, return id,message -# Create workout from RunKeeper Data -def add_workout_from_runkeeperdata(user,importid,data): - # To Do - add utcoffset to time - workouttype = data['type'] - if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' - try: - comments = data['notes'] - except: - comments = '' - - try: - utcoffset = tz(data['utcoffset']) - except: - utcoffset = 0 - - r = getrower(user) - - try: - rowdatetime = iso8601.parse_date(data['start_time']) - except iso8601.ParseError: - try: - rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - try: - rowdatetime = dateutil.parser.parse(data['start_time']) - #rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - starttimeunix = arrow.get(rowdatetime).timestamp - #starttimeunix = mktime(rowdatetime.utctimetuple()) - starttimeunix += utcoffset*3600 - - - try: - title = data['name'] - except: - title = "Imported data" - - - - res = splitrunkeeperdata(data['distance'],'timestamp','distance') - - distance = res[1] - times_distance = res[0] - - try: - l = data['path'] - - res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude') - times_location = res[0] - latcoord = res[1] - loncoord = res[2] - - except: - times_location = times_distance - latcoord = np.zeros(len(times_distance)) - loncoord = np.zeros(len(times_distance)) - if workouttype in types.otwtypes: - workouttype = 'rower' - - try: - res = splitrunkeeperdata(data['cadence'],'timestamp','cadence') - times_spm = res[0] - spm = res[1] - except KeyError: - times_spm = times_distance - spm = 0*times_distance - - try: - res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate') - hr = res[1] - times_hr = res[0] - except KeyError: - times_hr = times_distance - hr = 0*times_distance - - - # create data series and remove duplicates - distseries = pd.Series(distance,index=times_distance) - distseries = distseries.groupby(distseries.index).first() - latseries = pd.Series(latcoord,index=times_location) - try: - latseries = latseries.groupby(latseries.index).first() - except TypeError: - latseries = 0.0*distseries - - lonseries = pd.Series(loncoord,index=times_location) - try: - lonseries = lonseries.groupby(lonseries.index).first() - except TypeError: - lonseries = 0.0*distseries - - spmseries = pd.Series(spm,index=times_spm) - spmseries = spmseries.groupby(spmseries.index).first() - hrseries = pd.Series(hr,index=times_hr) - try: - hrseries = hrseries.groupby(hrseries.index).first() - except TypeError: - hrseries = 0*distseries - - - # Create dicts and big dataframe - d = { - ' Horizontal (meters)': distseries, - ' latitude': latseries, - ' longitude': lonseries, - ' Cadence (stokes/min)': spmseries, - ' HRCur (bpm)' : hrseries, - } - - df = pd.DataFrame(d) - - df = df.groupby(level=0).last() - - cum_time = df.index.values - df[' ElapsedTime (sec)'] = cum_time - - velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff() - - df[' Power (watts)'] = 0.0*velo - - nr_rows = len(velo.values) - - df[' DriveLength (meters)'] = np.zeros(nr_rows) - df[' StrokeDistance (meters)'] = np.zeros(nr_rows) - df[' DriveTime (ms)'] = np.zeros(nr_rows) - df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows) - df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows) - df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows) - df[' lapIdx'] = np.zeros(nr_rows) - - - - unixtime = cum_time+starttimeunix - try: - unixtime[0] = starttimeunix - except IndexError: - return (0,'No data to import') - - df['TimeStamp (sec)'] = unixtime - - - dt = np.diff(cum_time).mean() - wsize = round(5./dt) - - # velo2 = stravastuff.ewmovingaverage(velo,wsize) - - # df[' Stroke500mPace (sec/500m)'] = 500./velo2 - - - df = df.fillna(0) - - df.sort_values(by='TimeStamp (sec)',ascending=True) - - timestr = strftime("%Y%m%d-%H%M%S") - -# csvfilename ='media/Import_'+str(importid)+'.csv' - csvfilename ='media/{code}_{importid}.csv'.format( - importid=importid, - code = uuid4().hex[:16] - ) - - res = df.to_csv(csvfilename+'.gz',index_label='index', - compression='gzip') - - id,message = dataprep.save_workout_database(csvfilename,r, - workouttype=workouttype, - workoutsource='runkeeper', - title=title, - notes=comments) - - return (id,message) - - - -# Create workout from SportTracks Data, which are slightly different -# than Strava or Concept2 data -def add_workout_from_stdata(user,importid,data): - workouttype = data['type'] - if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' - try: - comments = data['comments'] - except: - comments = '' - - - r = getrower(user) - try: - rowdatetime = iso8601.parse_date(data['start_time']) - except iso8601.ParseError: - try: - rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - try: - rowdatetime = dateutil.parser.parse(data['start_time']) - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - starttimeunix = arrow.get(rowdatetime).timestamp - - try: - title = data['name'] - except: - title = "Imported data" - - try: - res = splitstdata(data['distance']) - distance = res[1] - times_distance = res[0] - except KeyError: - try: - res = splitstdata(data['heartrate']) - times_distance = res[0] - distance = 0*times_distance - except KeyError: - return (0,"No distance or heart rate data in the workout") - - - try: - l = data['location'] - - res = splitstdata(l) - times_location = res[0] - latlong = res[1] - latcoord = [] - loncoord = [] - - for coord in latlong: - lat = coord[0] - lon = coord[1] - latcoord.append(lat) - loncoord.append(lon) - except: - times_location = times_distance - latcoord = np.zeros(len(times_distance)) - loncoord = np.zeros(len(times_distance)) - if workouttype in types.otwtypes: - workouttype = 'rower' - - try: - res = splitstdata(data['cadence']) - times_spm = res[0] - spm = res[1] - except KeyError: - times_spm = times_distance - spm = 0*times_distance - - try: - res = splitstdata(data['heartrate']) - hr = res[1] - times_hr = res[0] - except KeyError: - times_hr = times_distance - hr = 0*times_distance - - - # create data series and remove duplicates - distseries = pd.Series(distance,index=times_distance) - distseries = distseries.groupby(distseries.index).first() - latseries = pd.Series(latcoord,index=times_location) - latseries = latseries.groupby(latseries.index).first() - lonseries = pd.Series(loncoord,index=times_location) - lonseries = lonseries.groupby(lonseries.index).first() - spmseries = pd.Series(spm,index=times_spm) - spmseries = spmseries.groupby(spmseries.index).first() - hrseries = pd.Series(hr,index=times_hr) - hrseries = hrseries.groupby(hrseries.index).first() - - - # Create dicts and big dataframe - d = { - ' Horizontal (meters)': distseries, - ' latitude': latseries, - ' longitude': lonseries, - ' Cadence (stokes/min)': spmseries, - ' HRCur (bpm)' : hrseries, - } - - - - df = pd.DataFrame(d) - - df = df.groupby(level=0).last() - - cum_time = df.index.values - df[' ElapsedTime (sec)'] = cum_time - - velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff() - - df[' Power (watts)'] = 0.0*velo - - nr_rows = len(velo.values) - - df[' DriveLength (meters)'] = np.zeros(nr_rows) - df[' StrokeDistance (meters)'] = np.zeros(nr_rows) - df[' DriveTime (ms)'] = np.zeros(nr_rows) - df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows) - df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows) - df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows) - df[' lapIdx'] = np.zeros(nr_rows) - - - - unixtime = cum_time+starttimeunix - unixtime[0] = starttimeunix - - df['TimeStamp (sec)'] = unixtime - - - dt = np.diff(cum_time).mean() - wsize = round(5./dt) - - velo2 = stravastuff.ewmovingaverage(velo,wsize) - - df[' Stroke500mPace (sec/500m)'] = 500./velo2 - - - df = df.fillna(0) - - df.sort_values(by='TimeStamp (sec)',ascending=True) - - timestr = strftime("%Y%m%d-%H%M%S") - -# csvfilename ='media/Import_'+str(importid)+'.csv' - csvfilename ='media/{code}_{importid}.csv'.format( - importid=importid, - code = uuid4().hex[:16] - ) - - res = df.to_csv(csvfilename+'.gz',index_label='index', - compression='gzip') - - id,message = dataprep.save_workout_database(csvfilename,r, - workouttype=workouttype, - title=title, - notes=comments, - workoutsource='sporttracks') - - return (id,message) # Create workout from SportTracks Data, which are slightly different # than Strava or Concept2 data @@ -9781,12 +9410,13 @@ def workout_runkeeperimport_view(request,message=""): workouts = [] for item in res.json()['items']: d = int(float(item['total_distance'])) - i = getidfromsturi(item['uri'],length=9) + i = getidfromuri(item['uri']) ttot = str(datetime.timedelta(seconds=int(float(item['duration'])))) s = item['start_time'] r = item['type'] keys = ['id','distance','duration','starttime','type'] values = [i,d,ttot,s,r] + res = dict(zip(keys,values)) workouts.append(res) return render(request,'runkeeper_list_import.html', @@ -9906,14 +9536,14 @@ def workout_sporttracksimport_view(request,message=""): else: workouts = [] r = getrower(request.user) - stids = [int(getidfromsturi(item['uri'])) for item in res.json()['items']] + stids = [int(getidfromuri(item['uri'])) for item in res.json()['items']] knownstids = uniqify([ w.uploadedtosporttracks for w in Workout.objects.filter(user=r) ]) newids = [stid for stid in stids if not stid in knownstids] for item in res.json()['items']: d = int(float(item['total_distance'])) - i = int(getidfromsturi(item['uri'])) + i = int(getidfromuri(item['uri'])) if i in knownstids: nnn = '' else: @@ -10060,63 +9690,151 @@ def workout_c2import_view(request,page=1,message=""): 'page':page, }) - -# Import a workout from Strava +importsources = { + 'c2':c2stuff, + 'strava':stravastuff, + 'polar':polarstuff, + 'ownapi':ownapistuff, + 'runkeeper':runkeeperstuff, + 'sporttracks':sporttracksstuff, + 'trainingpeaks':tpstuff, + 'underarmour':underarmourstuff + } + @login_required() -def workout_getstravaworkout_view(request,stravaid): - res = stravastuff.get_strava_workout(request.user,stravaid) +def workout_getimportview(request,externalid,source = 'c2'): + res = importsources[source].get_workout(request.user,externalid) if not res[0]: messages.error(request,res[1]) return imports_view(request) - + strokedata = res[1] data = res[0] - id,message = add_workout_from_strokedata(request.user,stravaid,data,strokedata, - source='strava', - workoutsource='strava') + + + # Now works only for C2 + if strokedata.empty: + 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' + totaltime = data['time']/10. + duration = dataprep.totaltime_sec_to_string(totaltime) + duration = datetime.datetime.strptime(duration,'%H:%M:%S.%f').time() + + try: + timezone_str = data['timezone'] + except: + timezone_str = 'UTC' + + if timezone_str is None: + 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 = getrower(request.user) + + id, message = dataprep.create_row_df(r, + distance, + duration, + startdatetime, + workouttype=workouttype) + + w = Workout.objects.get(id=id) + w.uploadedtoc2 = c2id + w.name = 'Imported from C2' + w.workouttype = 'rower' + w.save() + + message = "This workout does not have any stroke data associated with it. We created synthetic stroke data." + messages.info(request,message) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id), + }) + + return HttpResponseRedirect(url) + + # strokdata not empty - continue + id,message = importsources[source].add_workout_from_data( + request.user, + externalid,data, + strokedata, + source=source, + workoutsource=source) + w = get_workout(id) - w.uploadedtostrava=stravaid + if 'workout' in data: + if 'splits' in data['workout']: + splitdata = data['workout']['splits'] + if 'intervals' in data['workout']: + splitdata = data['workout']['intervals'] + else: + splitdata = False + + # splitdata (only for C2) + if splitdata: + w.summary,sa,results = c2stuff.summaryfromsplitdata(splitdata,data,w.csvfilename) + w.save() + + from rowingdata.trainingparser import getlist + # set stroke data in CSV file + if sa: + values = getlist(sa) + units = getlist(sa,sel='unit') + types = getlist(sa,sel='type') + + rowdata = rdata(w.csvfilename) + if rowdata: + rowdata.updateintervaldata(values, + units,types,results) + + rowdata.write_csv(w.csvfilename,gzip=True) + dataprep.update_strokedata(w.id,rowdata.df) + + + + if source == 'strava': + w.uploadedtostrava = externalid + elif source == 'c2': + w.uploadedtoc2 = externalid + elif source == 'polar': + w.uploadedtopolar = externalid + elif source == 'runkeeper': + w.uploadedtorunkeeper = externalid + elif source == 'sporttracks': + w.uploadedtosporttracks = externalid + elif source == 'trainingpeaks': + w.uploadedtotp = externalid + elif source == 'underarmour': + w.uploadedtounderarmour = externalid + w.save() - if message: - messages.error(request,message) - - r = getrower(request.user) - - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':int(id), - }) - - return HttpResponseRedirect(url) - -# Imports a workout from Runkeeper -@login_required() -def workout_getrunkeeperworkout_view(request,runkeeperid): - res = runkeeperstuff.get_runkeeper_workout(request.user,runkeeperid) - try: - data = res.json() - except ValueError: - messages.error(request,'Error getting workout from Runkeeper') - url = reverse(workout_runkeeperimport_view) - return HttpResponseRedirect(url) - - id,message = add_workout_from_runkeeperdata(request.user,runkeeperid,data) - w = Workout.objects.get(id=id) - w.uploadedtorunkeeper=runkeeperid - thetoken = runkeeper_open(request.user) - w.save() if message: messages.error(request,message) r = getrower(request.user) - + url = reverse(r.defaultlandingpage, kwargs = { - 'id':int(id), - }) + 'id':int(id) + }) + return HttpResponseRedirect(url) + + # Imports a workout from Underarmour @login_required() @@ -10141,30 +9859,6 @@ def workout_getunderarmourworkout_view(request,underarmourid): -# Imports a workout from SportTracks -@login_required() -def workout_getsporttracksworkout_view(request,sporttracksid): - res = sporttracksstuff.get_sporttracks_workout(request.user,sporttracksid) - data = res.json() - - id,message = add_workout_from_stdata(request.user,sporttracksid,data) - if id==0: - messages.error(request,message) - url = reverse(workouts_view) - return HttpResponseRedirect(url) - w = Workout.objects.get(id=id) - w.uploadedtosporttracks=sporttracksid - w.save() - if message: - messages.error(request,message) - - r = getrower(request.user) - - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':int(id), - }) - return HttpResponseRedirect(url) # Imports all new workouts from SportTracks @login_required() @@ -10172,7 +9866,7 @@ def workout_getsporttracksworkout_all(request): res = sporttracksstuff.get_sporttracks_workout_list(request.user) if (res.status_code == 200): r = getrower(request.user) - stids = [int(getidfromsturi(item['uri'])) for item in res.json()['items']] + stids = [int(getidfromuri(item['uri'])) for item in res.json()['items']] knownstids = uniqify([ w.uploadedtosporttracks for w in Workout.objects.filter(user=r) ]) @@ -10235,146 +9929,6 @@ def workout_getstravaworkout_all(request): -# Imports a workout from Concept2 -@login_required() -def workout_getc2workout_view(request,c2id): - try: - thetoken = c2_open(request.user) - except NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - res = c2stuff.get_c2_workout(request.user,c2id) - if (res.status_code == 200): - data = res.json()['data'] - splitdata = None - if 'workout' in data: - if 'splits' in data['workout']: - splitdata = data['workout']['splits'] - if 'intervals' in data['workout']: - splitdata = data['workout']['intervals'] - - # Check if workout has stroke data, and get the stroke data - if data['stroke_data']: - res2 = c2stuff.get_c2_workout_strokes(request.user,c2id) - else: - 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' - totaltime = data['time']/10. - duration = dataprep.totaltime_sec_to_string(totaltime) - duration = datetime.datetime.strptime(duration,'%H:%M:%S.%f').time() - - try: - timezone_str = data['timezone'] - except: - timezone_str = 'UTC' - - if timezone_str is None: - 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 = getrower(request.user) - - id, message = dataprep.create_row_df(r, - distance, - duration, - startdatetime, -# title = 'Imported from C2', - workouttype=workouttype) - - w = Workout.objects.get(id=id) - w.uploadedtoc2 = c2id - w.name = 'Imported from C2' - w.workouttype = 'rower' - w.save() - - message = "This workout does not have any stroke data associated with it. We created synthetic stroke data." - messages.info(request,message) - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':int(id), - }) - - return HttpResponseRedirect(url) - - # We have stroke data - if res2.status_code == 200: - strokedata = pd.DataFrame.from_dict(res2.json()['data']) - # create the workout - id,message = add_workout_from_strokedata(request.user,c2id,data,strokedata, - source='c2') - w = Workout.objects.get(id=id) - w.uploadedtoc2=c2id - # If we have split data, update the stroke data so they - # match exactly (some users are anal about this) - if splitdata: - try: - w.summary,sa,results = c2stuff.summaryfromsplitdata(splitdata,data,w.csvfilename) - except: - sa = [] - results = [] - with open("media/c2splitdata.log","a") as errorlog: - errorstring = str(sys.exc_info()[0]) - timestr = strftime("%Y%m%d-%H%M%S") - errorlog.write(timestr+errorstring+"\r\n") - errorlog.write("views.py line 952\r\n") - - w.save() - - from rowingdata.trainingparser import getlist - # set stroke data in CSV file - if sa: - values = getlist(sa) - units = getlist(sa,sel='unit') - types = getlist(sa,sel='type') - - rowdata = rdata(w.csvfilename) - if rowdata: - rowdata.updateintervaldata(values, - units,types,results) - - rowdata.write_csv(w.csvfilename,gzip=True) - dataprep.update_strokedata(w.id,rowdata.df) - - if message: - messages.error(request,message) - - r = getrower(request.user) - - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':int(id), - }) - - return HttpResponseRedirect(url) - else: - # message = json.loads(s.text)['message'] - message = json.loads(res2.text)['message'] - messages.error(request,message) - - url = reverse(workout_c2import_view) - return HttpResponseRedirect(url) - - else: - message = "Received error code from Concept2" - messages.error(request,message) - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workout_c2import_view) - return HttpResponseRedirect(url) @login_required def workout_toggle_ranking(request,id=0):