diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py index e59d0e64..a68ef21c 100644 --- a/rowers/c2stuff.py +++ b/rowers/c2stuff.py @@ -22,14 +22,17 @@ import json from json.decoder import JSONDecodeError from rowsandall_app.settings import ( - C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET + C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, + UPLOAD_SERVICE_URL, UPLOAD_SERVICE_SECRET ) -from rowers.tasks import handle_c2_import_stroke_data, handle_c2_sync +from rowers.tasks import ( + handle_c2_import_stroke_data, handle_c2_sync, handle_c2_async_workout, + ) import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') -queuehigh = django_rq.get_queue('low') +queuehigh = django_rq.get_queue('high') from rowers.utils import myqueue from rowers.models import C2WorldClassAgePerformance @@ -185,8 +188,15 @@ def get_c2_workouts(rower): newids = [c2id for c2id in c2ids if not c2id in knownc2ids] for c2id in newids: - workoutid = create_async_workout(alldata, - rower.user,c2id) + res = myqueue(queuehigh, + handle_c2_async_workout, + alldata, + rower.user.id, + rower.c2token, + c2id, + ) + #workoutid = create_async_workout(alldata, + # rower.user,c2id) return 1 @@ -203,6 +213,16 @@ def create_async_workout(alldata,user,c2id): startdatetime = iso8601.parse_date(data['date']) weightclass = data['weight_class'] + try: + title = data['name'] + except KeyError: + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:40] + except: + title = 'Imported' + weightcategory = 'hwt' if weightclass == "L": weightcategory = 'lwt' @@ -234,31 +254,120 @@ def create_async_workout(alldata,user,c2id): r = Rower.objects.get(user=user) + authorizationstring = str('Bearer ' + r.c2token) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url2 = "https://log.concept2.com/api/users/me/results"+str(c2id) + url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes" + try: + s = requests.get(url,headers=headers) + except ConnectionError: + return 0 - w = Workout( - user=r, - workouttype = workouttype, - name = name, - date = workoutdate, - starttime = starttime, - startdatetime = startdatetime, - timezone = timezone_str, - duration = duration, - distance=distance, - weightcategory = weightcategory, - uploadedtoc2 = c2id, - csvfilename = csvfilename, - notes = notes - ) + if s.status_code != 200: + return 0 - w.save() + strokedata = pd.DataFrame.from_dict(s.json()['data']) - # Check if workout has stroke data, and get the stroke data + res = make_cumvalues(0.1*strokedata['t']) + cum_time = res[0] + lapidx = res[1] - result = add_stroke_data(user,c2id,w.id,startdatetime,csvfilename, - workouttype = w.workouttype) + starttimeunix = arrow.get(startdatetime).timestamp + + unixtime = cum_time+starttimeunix + # unixtime[0] = starttimeunix + seconds = 0.1*strokedata.loc[:,'t'] + + nr_rows = len(unixtime) + + try: + latcoord = strokedata.loc[:,'lat'] + loncoord = strokedata.loc[:,'lon'] + except: + latcoord = np.zeros(nr_rows) + loncoord = np.zeros(nr_rows) + + + try: + strokelength = strokedata.loc[:,'strokelength'] + except: + strokelength = np.zeros(nr_rows) + + dist2 = 0.1*strokedata.loc[:,'d'] + + try: + spm = strokedata.loc[:,'spm'] + except KeyError: + spm = 0*dist2 + + try: + hr = strokedata.loc[:,'hr'] + except KeyError: + hr = 0*spm + + pace = strokedata.loc[:,'p']/10. + pace = np.clip(pace,0,1e4) + pace = pace.replace(0,300) + + velo = 500./pace + power = 2.8*velo**3 + if workouttype == 'bike': + velo = 1000./pace + + 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, + ' WorkoutState': 4, + ' ElapsedTime (sec)':seconds, + 'cum_dist': dist2 + }) + + + df.sort_values(by='TimeStamp (sec)',ascending=True) + + res = df.to_csv(csvfilename,index_label='index', + compression='gzip') + + userid = r.user.id + + uploadoptions = { + 'secret':UPLOAD_SERVICE_SECRET, + 'user':userid, + 'file': csvfilename, + 'title': title, + 'workouttype':workouttype, + 'boattype':'1x', + 'c2id':c2id, + } + + session = requests.session() + newHeaders = {'Content-type': 'application/json', 'Accept': 'text/plain'} + session.headers.update(newHeaders) + + response = session.post(UPLOAD_SERVICE_URL,json=uploadoptions) + + if response.status_code != 200: + return 0 + + workoutid = response.json()['id'] + + return workoutid - return w.id # convert datetime object to seconds def makeseconds(t): @@ -800,7 +909,7 @@ def get_c2_workout_list(user,page=1): return custom_exception_handler(401,s) elif (timezone.now()>r.tokenexpirydate): s = "Token expired. Needs to refresh." - + return custom_exception_handler(401,s) else: # ready to fetch. Hurray diff --git a/rowers/tasks.py b/rowers/tasks.py index 61479080..5fc39a65 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -2710,6 +2710,169 @@ def handle_sendemail_invite_accept(email, name, teamname, managername, def add2(x, y,debug=False,**kwargs): return x + y +@app.task +def handle_c2_async_workout(alldata,userid,c2token,c2id,debug=False,**kwargs): + data = alldata[c2id] + splitdata = None + + distance = data['distance'] + c2id = data['id'] + workouttype = data['type'] + verified = data['verified'] + startdatetime = iso8601.parse_date(data['date']) + weightclass = data['weight_class'] + + try: + title = data['name'] + except KeyError: + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:40] + except: + title = 'Imported' + + 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 = 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') + + try: + notes = data['comments'] + name = notes[:40] + except (KeyError,TypeError): + notes = 'C2 Import Workout from {startdatetime}'.format(startdatetime=startdatetime) + name = notes + + 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" + try: + s = requests.get(url,headers=headers) + except ConnectionError: + return 0 + + if s.status_code != 200: + return 0 + + strokedata = pd.DataFrame.from_dict(s.json()['data']) + + res = make_cumvalues(0.1*strokedata['t']) + cum_time = res[0] + lapidx = res[1] + + starttimeunix = arrow.get(startdatetime).timestamp + + unixtime = cum_time+starttimeunix + # unixtime[0] = starttimeunix + seconds = 0.1*strokedata.loc[:,'t'] + + nr_rows = len(unixtime) + + try: + latcoord = strokedata.loc[:,'lat'] + loncoord = strokedata.loc[:,'lon'] + except: + latcoord = np.zeros(nr_rows) + loncoord = np.zeros(nr_rows) + + + try: + strokelength = strokedata.loc[:,'strokelength'] + except: + strokelength = np.zeros(nr_rows) + + dist2 = 0.1*strokedata.loc[:,'d'] + + try: + spm = strokedata.loc[:,'spm'] + except KeyError: + spm = 0*dist2 + + try: + hr = strokedata.loc[:,'hr'] + except KeyError: + hr = 0*spm + + pace = strokedata.loc[:,'p']/10. + pace = np.clip(pace,0,1e4) + pace = pace.replace(0,300) + + velo = 500./pace + power = 2.8*velo**3 + if workouttype == 'bike': + velo = 1000./pace + + 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, + ' WorkoutState': 4, + ' ElapsedTime (sec)':seconds, + 'cum_dist': dist2 + }) + + + df.sort_values(by='TimeStamp (sec)',ascending=True) + + res = df.to_csv(csvfilename,index_label='index', + compression='gzip') + + uploadoptions = { + 'secret':UPLOAD_SERVICE_SECRET, + 'user':userid, + 'file': csvfilename, + 'title': title, + 'workouttype':workouttype, + 'boattype':'1x', + 'c2id':c2id, + } + + session = requests.session() + newHeaders = {'Content-type': 'application/json', 'Accept': 'text/plain'} + session.headers.update(newHeaders) + + response = session.post(UPLOAD_SERVICE_URL,json=uploadoptions) + + if response.status_code != 200: + return 0 + + workoutid = response.json()['id'] + + return workoutid + + @app.task def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debug=False,**kwargs): fetchresolution = 'high' diff --git a/rowers/uploads.py b/rowers/uploads.py index 2a5456bc..f887b0f5 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -548,9 +548,22 @@ def do_sync(w,options, quick=False): pass + try: + upload_to_c2 = options['upload_to_C2'] + except KeyError: + upload_to_c2 = False - if ('upload_to_C2' in options and options['upload_to_C2']) or (w.user.c2_auto_export): + + try: + if options['c2id'] != 0 and options['c2id'] != '': + w.uploadedtoc2 = options['c2id'] + upload_to_c2 = False + w.save() + except KeyError: + pass + + if ('upload_to_C2' in options and upload_to_c2) or (w.user.c2_auto_export): try: message,id = c2stuff.workout_c2_upload(w.user.user,w,asynchron=True) except NoTokenError: diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 4b9a031f..6c58b720 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -4769,6 +4769,11 @@ def workout_upload_api(request): except KeyError: stravaid = '' + try: + c2id = post_data['c2id'] + except KeyError: + c2id = '' + try: garminid = post_data['garminid'] except KeyError: