C2 and ST button to import all new workouts
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -6,36 +6,50 @@
|
||||
|
||||
{% block content %}
|
||||
<h1>Available on C2 Logbook</h1>
|
||||
{% if workouts %}
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Import </th>
|
||||
<th> Date/Time </th>
|
||||
<th> Duration </th>
|
||||
<th> Total Distance</th>
|
||||
<th> Type</th>
|
||||
<th> Source</th>
|
||||
<th> Comment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for workout in workouts %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/workout/c2import/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||
<td>{{ workout|lookup:'starttime' }}</td>
|
||||
<td>{{ workout|lookup:'duration' }}</td>
|
||||
<td>{{ workout|lookup:'distance' }}</td>
|
||||
<td>{{ workout|lookup:'rowtype' }}</td>
|
||||
<td>{{ workout|lookup:'source' }}</td>
|
||||
<td>{{ workout|lookup:'comment' }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
{% if workouts %}
|
||||
<div class="grid_2 alpha ">
|
||||
<a href="/rowers/workout/c2import/all/" class="button gray">Import all NEW</a>
|
||||
</div>
|
||||
<div class="grid_10 omega">
|
||||
<p>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.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="grid_12 alpha">
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Import </th>
|
||||
<th> Date/Time </th>
|
||||
<th> Duration </th>
|
||||
<th> Total Distance</th>
|
||||
<th> Type</th>
|
||||
<th> Source</th>
|
||||
<th> Comment</th>
|
||||
<th> New</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for workout in workouts %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/workout/c2import/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||
<td>{{ workout|lookup:'starttime' }}</td>
|
||||
<td>{{ workout|lookup:'duration' }}</td>
|
||||
<td>{{ workout|lookup:'distance' }}</td>
|
||||
<td>{{ workout|lookup:'rowtype' }}</td>
|
||||
<td>{{ workout|lookup:'source' }}</td>
|
||||
<td>{{ workout|lookup:'comment' }}</td>
|
||||
<td>{{ workout|lookup:'new' }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -6,34 +6,47 @@
|
||||
|
||||
{% block content %}
|
||||
<h1>Available on SportTracks</h1>
|
||||
{% if workouts %}
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Import </th>
|
||||
<th> Name </th>
|
||||
<th> Date/Time </th>
|
||||
<th> Duration </th>
|
||||
<th> Total Distance</th>
|
||||
<th> Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for workout in workouts %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/workout/sporttracksimport/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||
<td>{{ workout|lookup:'name' }}</td>
|
||||
<td>{{ workout|lookup:'starttime' }}</td>
|
||||
<td>{{ workout|lookup:'duration' }} </td>
|
||||
<td>{{ workout|lookup:'distance' }} m</td>
|
||||
<td>{{ workout|lookup:'type' }}</td>
|
||||
</tr>
|
||||
{% if workouts %}
|
||||
<div class="grid_2 alpha ">
|
||||
<a href="/rowers/workout/sporttracksimport/all/" class="button gray">Import all NEW</a>
|
||||
</div>
|
||||
<div class="grid_10 omega">
|
||||
<p>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.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
<div class="grid_12 alpha">
|
||||
<table width="70%" class="listtable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th> Import </th>
|
||||
<th> Name </th>
|
||||
<th> Date/Time </th>
|
||||
<th> Duration </th>
|
||||
<th> Total Distance</th>
|
||||
<th> Type</th>
|
||||
<th> New</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for workout in workouts %}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="/rowers/workout/sporttracksimport/{{ workout|lookup:'id' }}/">Import</a></td>
|
||||
<td>{{ workout|lookup:'name' }}</td>
|
||||
<td>{{ workout|lookup:'starttime' }}</td>
|
||||
<td>{{ workout|lookup:'duration' }} </td>
|
||||
<td>{{ workout|lookup:'distance' }} m</td>
|
||||
<td>{{ workout|lookup:'type' }}</td>
|
||||
<td>{{ workout|lookup:'new' }}</td>
|
||||
</tr>
|
||||
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
@@ -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<c2id>\d+)/$',views.workout_getc2workout_view),
|
||||
url(r'^workout/c2import/all/$',views.workout_getc2workout_all),
|
||||
url(r'^workout/stravaimport/(?P<stravaid>\d+)/$',views.workout_getstravaworkout_view),
|
||||
url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view),
|
||||
url(r'^workout/sporttracksimport/(?P<sporttracksid>\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<runkeeperid>\d+)/$',views.workout_getrunkeeperworkout_view),
|
||||
url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view),
|
||||
|
||||
@@ -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))
|
||||
|
||||
115
rowers/views.py
115
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',
|
||||
@@ -5824,6 +5834,57 @@ def c2listdebug_view(request,message=""):
|
||||
'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):
|
||||
|
||||
Reference in New Issue
Block a user