From 12d95cfe43889b1cef61a553ed767cbb10350de0 Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Wed, 17 May 2017 11:54:02 +0200 Subject: [PATCH] C2 and ST button to import all new workouts --- rowers/dataprepnodjango.py | 2 + rowers/templates/c2_list_import2.html | 78 +++++++----- rowers/templates/sporttracks_list_import.html | 73 ++++++----- rowers/urls.py | 2 + rowers/utils.py | 15 +++ rowers/views.py | 117 ++++++++++++++++-- 6 files changed, 218 insertions(+), 69 deletions(-) diff --git a/rowers/dataprepnodjango.py b/rowers/dataprepnodjango.py index 8872d4e7..af17d87a 100644 --- a/rowers/dataprepnodjango.py +++ b/rowers/dataprepnodjango.py @@ -18,6 +18,7 @@ from rowsandall_app.settings import DATABASES from utils import lbstoN + user = DATABASES['default']['USER'] password = DATABASES['default']['PASSWORD'] database_name = DATABASES['default']['NAME'] @@ -335,6 +336,7 @@ def handle_nonpainsled(f2,fileformat,summary=''): return (f2,summary,oarlength,inboard) + # Create new workout from file and store it in the database # This routine should be used everywhere in views.py and mailprocessing.py # Currently there is code duplication diff --git a/rowers/templates/c2_list_import2.html b/rowers/templates/c2_list_import2.html index 03f2d8e7..886542be 100644 --- a/rowers/templates/c2_list_import2.html +++ b/rowers/templates/c2_list_import2.html @@ -6,36 +6,50 @@ {% block content %}

Available on C2 Logbook

- {% if workouts %} - - - - - - - - - - - - - - {% for workout in workouts %} - - - - - - - - - - - {% endfor %} - -
Import Date/Time Duration Total Distance Type Source Comment
-Import{{ workout|lookup:'starttime' }}{{ workout|lookup:'duration' }}{{ workout|lookup:'distance' }}{{ workout|lookup:'rowtype' }}{{ workout|lookup:'source' }}{{ workout|lookup:'comment' }}
- {% else %} -

No workouts found

- {% endif %} + +{% if workouts %} +
+ Import all NEW +
+
+

This imports all workouts that have not been imported to rowsandall.com. + The action may take a longer time to process, so please be patient. Click on Import in the list below to import an individual workout. +

+
+ +
+ + + + + + + + + + + + + + + {% for workout in workouts %} + + + + + + + + + + + + {% endfor %} + +
Import Date/Time Duration Total Distance Type Source Comment New
+ Import{{ workout|lookup:'starttime' }}{{ workout|lookup:'duration' }}{{ workout|lookup:'distance' }}{{ workout|lookup:'rowtype' }}{{ workout|lookup:'source' }}{{ workout|lookup:'comment' }}{{ workout|lookup:'new' }}
+
+{% else %} +

No workouts found

+{% endif %} {% endblock %} diff --git a/rowers/templates/sporttracks_list_import.html b/rowers/templates/sporttracks_list_import.html index 96a2aa2d..b547efc8 100644 --- a/rowers/templates/sporttracks_list_import.html +++ b/rowers/templates/sporttracks_list_import.html @@ -6,34 +6,47 @@ {% block content %}

Available on SportTracks

- {% if workouts %} - - - - - - - - - - - - - {% for workout in workouts %} - - - - - - - - - - {% endfor %} - -
Import Name Date/Time Duration Total Distance Type
-Import{{ workout|lookup:'name' }}{{ workout|lookup:'starttime' }}{{ workout|lookup:'duration' }} {{ workout|lookup:'distance' }} m{{ workout|lookup:'type' }}
- {% else %} -

No workouts found

- {% endif %} +{% if workouts %} +
+ Import all NEW +
+
+

This imports all workouts that have not been imported to rowsandall.com. + The action may take a longer time to process, so please be patient. Click on Import in the list below to import an individual workout. +

+
+ +
+ + + + + + + + + + + + + + {% for workout in workouts %} + + + + + + + + + + + {% endfor %} + +
Import Name Date/Time Duration Total Distance Type New
+ Import{{ workout|lookup:'name' }}{{ workout|lookup:'starttime' }}{{ workout|lookup:'duration' }} {{ workout|lookup:'distance' }} m{{ workout|lookup:'type' }}{{ workout|lookup:'new' }}
+
+{% else %} +

No workouts found

+{% endif %} {% endblock %} diff --git a/rowers/urls.py b/rowers/urls.py index dbb5fcd9..ec5d73a4 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -211,9 +211,11 @@ urlpatterns = [ url(r'^workout/c2import/$',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/all/$',views.workout_getc2workout_all), url(r'^workout/stravaimport/(?P\d+)/$',views.workout_getstravaworkout_view), 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/runkeeperimport/$',views.workout_runkeeperimport_view), url(r'^workout/runkeeperimport/(?P\d+)/$',views.workout_getrunkeeperworkout_view), url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view), diff --git a/rowers/utils.py b/rowers/utils.py index b700cba3..b78310cd 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -4,6 +4,21 @@ import numpy as np lbstoN = 4.44822 +def uniqify(seq, idfun=None): + # order preserving + if idfun is None: + def idfun(x): return x + seen = {} + result = [] + for item in seq: + marker = idfun(item) + # in old Python versions: + # if seen.has_key(marker) + # but in new ones: + if marker in seen: continue + seen[marker] = 1 + result.append(item) + return result def serialize_list(value,token=','): assert(isinstance(value, list) or isinstance(value, tuple) or isinstance(value,np.ndarray)) diff --git a/rowers/views.py b/rowers/views.py index 376fa0d1..460ef645 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -267,7 +267,7 @@ def splitstdata(lijst): return [np.array(t),np.array(latlong)] -from utils import geo_distance,serialize_list,deserialize_list +from utils import geo_distance,serialize_list,deserialize_list,uniqify from rowers.models import checkworkoutuser # Check if a user is a Coach member @@ -5764,15 +5764,25 @@ def workout_sporttracksimport_view(request,message=""): return HttpResponseRedirect(url) else: workouts = [] + r = Rower.objects.get(user=request.user) + stids = [int(getidfromsturi(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 = getidfromsturi(item['uri']) + i = int(getidfromsturi(item['uri'])) + if i in knownstids: + nnn = '' + else: + nnn = 'NEW' n = item['name'] ttot = str(datetime.timedelta(seconds=int(float(item['duration'])))) s = item['start_time'] r = item['type'] - keys = ['id','distance','duration','starttime','type','name'] - values = [i,d,ttot,s,r,n] + keys = ['id','distance','duration','starttime','type','name','new'] + values = [i,d,ttot,s,r,n,nnn] res = dict(zip(keys,values)) workouts.append(res) return render(request,'sporttracks_list_import.html', @@ -5823,7 +5833,58 @@ def c2listdebug_view(request,message=""): {'workouts':workouts, 'teams':get_my_teams(request.user), }) - + +# Import all unknown workouts available on Concept2 logbook +@login_required() +def workout_getc2workout_all(request,message=""): + try: + thetoken = c2_open(request.user) + except C2NoTokenError: + return HttpResponseRedirect("/rowers/me/c2authorize/") + + res = c2stuff.get_c2_workout_list(request.user) + + if (res.status_code != 200): + message = "Something went wrong in workout_c2import_view (C2 token refresh)" + messages.error(request,message) + else: + r = Rower.objects.get(user=request.user) + c2ids = [item['id'] for item in res.json()['data']] + knownc2ids = uniqify([ + w.uploadedtoc2 for w in Workout.objects.filter(user=r) + ]) + newids = [c2id for c2id in c2ids if not c2id in knownc2ids] + for c2id in newids: + 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) + # 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 + w.save() + if message: + messages.error(request,message) + + url = reverse(workouts_view) + return HttpResponseRedirect(url) + + # List of workouts available on Concept2 logbook - for import @login_required() def workout_c2import_view(request,message=""): @@ -5844,6 +5905,12 @@ def workout_c2import_view(request,message=""): return HttpResponseRedirect(url) else: workouts = [] + r = Rower.objects.get(user=request.user) + c2ids = [item['id'] for item in res.json()['data']] + knownc2ids = uniqify([ + w.uploadedtoc2 for w in Workout.objects.filter(user=r) + ]) + newids = [c2id for c2id in c2ids if not c2id in knownc2ids] for item in res.json()['data']: d = item['distance'] i = item['id'] @@ -5852,8 +5919,12 @@ def workout_c2import_view(request,message=""): r = item['type'] s2 = item['source'] c = item['comments'] - keys = ['id','distance','duration','starttime','rowtype','source','comment'] - values = [i,d,ttot,s,r,s2,c] + if i in knownc2ids: + nnn = '' + else: + nnn = 'NEW' + keys = ['id','distance','duration','starttime','rowtype','source','comment','new'] + values = [i,d,ttot,s,r,s2,c,nnn] res = dict(zip(keys,values)) workouts.append(res) @@ -5959,6 +6030,38 @@ def workout_getsporttracksworkout_view(request,sporttracksid): }) return HttpResponseRedirect(url) +# Imports all new workouts from SportTracks +@login_required() +def workout_getsporttracksworkout_all(request): + res = sporttracksstuff.get_sporttracks_workout_list(request.user) + if (res.status_code == 200): + r = Rower.objects.get(user=request.user) + stids = [int(getidfromsturi(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 sporttracksid in newids: + res = sporttracksstuff.get_sporttracks_workout( + request.user,sporttracksid) + data = res.json() + + id,message = add_workout_from_stdata(request.user,sporttracksid,data) + print sporttracksid,id + if id==0: + messages.error(request,message) + + else: + w = Workout.objects.get(id=id) + w.uploadedtosporttracks=sporttracksid + print 'saved' + w.save() + + url = reverse(workouts_view) + return HttpResponseRedirect(url) + + + # Imports a workout from Concept2 @login_required() def workout_getc2workout_view(request,c2id):