diff --git a/rowers/templates/c2_list_import2.html b/rowers/templates/c2_list_import2.html index 033994e4..c88715aa 100644 --- a/rowers/templates/c2_list_import2.html +++ b/rowers/templates/c2_list_import2.html @@ -1,68 +1,74 @@ -{% extends "base.html" %} +{% extends "newbase.html" %} {% load staticfiles %} {% load rowerfilters %} {% block title %}Workouts{% endblock %} -{% block content %} +{% block main %}

Available on C2 Logbook

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

This imports all workouts that have not been imported to rowsandall.com. +

- -
- {% if page > 1 %} - < + +
  • +

    + + {% if page > 1 %} + + + + {% endif %} + + + + +

    +
  • +
  • + + + + + + + + + + + + + + + {% 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 %} -
    -
    - > -
    - -
    - - - - - - - - - - - - - - - {% 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 %} + +{% block sidebar %} +{% include 'menu_workouts.html' %} {% endblock %} diff --git a/rowers/templates/menu_workout.html b/rowers/templates/menu_workout.html index edbdc5c6..c045c36d 100644 --- a/rowers/templates/menu_workout.html +++ b/rowers/templates/menu_workout.html @@ -113,15 +113,111 @@
  • diff --git a/rowers/templates/menu_workouts.html b/rowers/templates/menu_workouts.html index 852dc0be..0370e37a 100644 --- a/rowers/templates/menu_workouts.html +++ b/rowers/templates/menu_workouts.html @@ -28,7 +28,7 @@ {% else %}

    No workouts found diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index e3d86059..6a8289c0 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -13,7 +13,12 @@ from rowers.plannedsessions import ( race_can_register, race_can_submit,race_rower_status ) +from rowers import c2stuff, runkeeperstuff +from rowers.c2stuff import c2_open +from rowers.runkeeperstuff import runkeeper_open + from rowers.types import otwtypes +from rowers.utils import NoTokenError def strfdelta(tdelta): minutes,seconds = divmod(tdelta.seconds,60) @@ -86,6 +91,28 @@ def deltatimeprint(d): else: return strfdeltah(d) +@register.filter +def c2userid(user): + try: + thetoken = c2_open(user) + except NoTokenError: + return 0 + + c2userid = c2stuff.get_userid(thetoken) + + return c2userid + +@register.filter +def rkuserid(user): + try: + thetoken = runkeeper_open(user) + except NoTokenError: + return 0 + + rkuserid = runkeeperstuff.get_userid(thetoken) + + return rkuserid + @register.filter def courselength(course): return course_length(course) diff --git a/rowers/urls.py b/rowers/urls.py index 149a5bc1..ac80f4a7 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -138,8 +138,8 @@ urlpatterns = [ url(r'^list-workouts/team/(?P\d+)/$',views.workouts_view), url(r'^(?P\d+)/list-workouts/$',views.workouts_view), url(r'^(?P\d+)/list-workouts/(?P\w+.*)/(?P\w+.*)$',views.workouts_view), - url(r'^u/(?P\d+)/list-workouts/$',views.workouts_view), - url(r'^u/(?P\d+)/list-workouts/(?P\w+.*)/(?P\w+.*)$',views.workouts_view), + url(r'^list-workouts/user/(?P\d+)/$',views.workouts_view), + url(r'^list-workouts/(?P\w+.*)/(?P\w+.*)/user/(?P\d+)/$',views.workouts_view), url(r'^list-workouts/(?P\w+.*)/(?P\w+.*)$',views.workouts_view), url(r'^virtualevents$',views.virtualevents_view), url(r'^virtualevent/create$',views.virtualevent_create_view), @@ -302,16 +302,22 @@ urlpatterns = [ url(r'^workout/c2import/$',views.workout_c2import_view), url(r'^workout/c2list/$',views.workout_c2import_view), url(r'^workout/c2list/(?P\d+)$',views.workout_c2import_view), + url(r'^workout/c2list/user/(?P\d+)$',views.workout_c2import_view), + url(r'^workout/c2list/(?P\d+)/user/(?P\d+)$',views.workout_c2import_view), url(r'^workout/stravaimport/$',views.workout_stravaimport_view), + url(r'^workout/stravaimport/user/(?P\d+)$',views.workout_stravaimport_view), url(r'^workout/c2import/all/$',views.workout_getc2workout_all), url(r'^workout/c2import/all/(?P\d+)$',views.workout_getc2workout_all), url(r'^workout/(?P\w+.*)import/(?P\d+)/$',views.workout_getimportview), url(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all), url(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next), url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view), + url(r'^workout/sporttracksimport/user/(?P\d+)$',views.workout_sporttracksimport_view), url(r'^workout/sporttracksimport/all/$',views.workout_getsporttracksworkout_all), url(r'^workout/polarimport/$',views.workout_polarimport_view), + url(r'^workout/polarimport/user/(?P\d+)/',views.workout_polarimport_view), url(r'^workout/runkeeperimport/$',views.workout_runkeeperimport_view), + url(r'^workout/runkeeperimport/user/(?P\d+)$',views.workout_runkeeperimport_view), url(r'^workout/underarmourimport/$',views.workout_underarmourimport_view), # url(r'^workout/(?P\d+)/deleteconfirm$',views.workout_delete_confirm_view), url(r'^workout/(?P\d+)/c2uploadw/$',views.workout_c2_upload_view), diff --git a/rowers/views.py b/rowers/views.py index 78945187..e86ec07f 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -1277,22 +1277,24 @@ def workout_tcxemail_view(request,id=0): if r.emailbounced: message = "Please check your email address first. Email to this address bounced." messages.error(request, message) - return HttpResponseRedirect( - reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) - ) + + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) + + return HttpResponseRedirect(url) + tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w,dozip=False) if tcxfile == 0: message = "Something went wrong (TCX export) "+tcxmessg messages.error(request,message) - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) return HttpResponseRedirect(url) if tcxfile: res = myqueue(queuehigh,handle_sendemailtcx, @@ -1307,19 +1309,19 @@ def workout_tcxemail_view(request,id=0): messages.info(request,successmessage) - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) response = HttpResponseRedirect(url) else: message = "You are not allowed to export this workout" messages.error(request,message) - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) response = HttpResponseRedirect(url) return response @@ -1375,12 +1377,12 @@ def workout_gpxemail_view(request,id=0): if r.emailbounced: message = "Please check your email address first. Email to this address bounced." messages.error(request, message) - return HttpResponseRedirect( - reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) - ) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) + + return HttpResponseRedirect(url) w = get_workout(id) @@ -1399,17 +1401,17 @@ def workout_gpxemail_view(request,id=0): successmessage = "The GPX file was sent to you per email" messages.info(request,successmessage) - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) response = HttpResponseRedirect(url) else: message = "You are not allowed to export this workout" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1425,7 +1427,7 @@ def workouts_summaries_email_view(request): message = "Please check your email address first. Email to this address bounced." messages.error(request, message) return HttpResponseRedirect( - reverse(workout_export_view, + reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1468,7 +1470,7 @@ def workout_csvemail_view(request,id=0): message = "Please check your email address first. Email to this address bounced." messages.error(request, message) return HttpResponseRedirect( - reverse(workout_export_view, + reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1486,7 +1488,7 @@ def workout_csvemail_view(request,id=0): successmessage = "The CSV file was sent to you per email" messages.info(request,successmessage) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1495,7 +1497,7 @@ def workout_csvemail_view(request,id=0): else: message = "You are not allowed to export this workout" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1577,7 +1579,7 @@ def workout_tp_upload_view(request,id=0): message = "You are not allowed to export this workout to TP" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1621,7 +1623,7 @@ def workout_strava_upload_view(request,id=0): os.remove(tcxfile) except WindowsError: pass - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1651,14 +1653,14 @@ def workout_strava_upload_view(request,id=0): messages.error(request,message) w.uploadedtostrava = -1 w.save() - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) response = HttpResponseRedirect(url) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), } @@ -1670,7 +1672,7 @@ def workout_strava_upload_view(request,id=0): w.uploadedtostrava = -1 w.save() os.remove(tcxfile) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1697,10 +1699,11 @@ def workout_c2_upload_view(request,id=0): messages.info(request,message) - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - }) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':int(id) + }) + response = HttpResponseRedirect(url) @@ -1725,7 +1728,7 @@ def workout_runkeeper_upload_view(request,id=0): if not data: message = "Data error" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1761,7 +1764,7 @@ def workout_runkeeper_upload_view(request,id=0): message = "You are not authorized to upload this workout" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1787,7 +1790,7 @@ def workout_underarmour_upload_view(request,id=0): if not data: message = "Data error" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1824,7 +1827,7 @@ def workout_underarmour_upload_view(request,id=0): message = "You are not authorized to upload this workout" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1851,7 +1854,7 @@ def workout_sporttracks_upload_view(request,id=0): if not data: message = "Data error" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -1889,7 +1892,7 @@ def workout_sporttracks_upload_view(request,id=0): message = "You are not authorized to upload this workout" messages.error(request,message) - url = reverse(workout_export_view, + url = reverse(r.defaultlandingpage, kwargs = { 'id':str(w.id), }) @@ -9543,9 +9546,16 @@ def workout_add_chart_view(request,id,plotnr=1): # The page where you select which Strava workout to import @login_required() -def workout_stravaimport_view(request,message=""): +def workout_stravaimport_view(request,message="",userid=0): res = stravastuff.get_strava_workout_list(request.user) + r = getrequestrower(request,userid=userid) + + if r.user != request.user: + messages.info(request,"You cannot import other people's workouts from Concept2") + + r = getrower(request.user) + if (res.status_code != 200): if (res.status_code == 401): r = getrower(request.user) @@ -9605,10 +9615,25 @@ def workout_stravaimport_view(request,message=""): res = dict(zip(keys,values)) workouts.append(res) + breadcrumbs = [ + { + 'url':'/rowers/list-workouts', + 'name':'Workouts' + }, + { + 'url':reverse(workout_stravaimport_view), + 'name':'Strava' + }, + ] + + + r = getrower(request.user) return render(request,'strava_list_import.html', {'workouts':workouts, + 'rower':r, 'active':'nav-workouts', + 'breadcrumbs':breadcrumbs, 'teams':get_my_teams(request.user), }) @@ -9616,7 +9641,7 @@ def workout_stravaimport_view(request,message=""): # The page where you select which RunKeeper workout to import @login_required() -def workout_runkeeperimport_view(request,message=""): +def workout_runkeeperimport_view(request,message="",userid=0): res = runkeeperstuff.get_runkeeper_workout_list(request.user) if (res.status_code != 200): if (res.status_code == 401): @@ -9632,29 +9657,46 @@ def workout_runkeeperimport_view(request,message=""): else: url = reverse(workouts_view) return HttpResponseRedirect(url) - else: - workouts = [] - for item in res.json()['items']: - d = int(float(item['total_distance'])) - 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', - {'workouts':workouts, - 'teams':get_my_teams(request.user), - }) + workouts = [] + for item in res.json()['items']: + d = int(float(item['total_distance'])) + 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) + + breadcrumbs = [ + { + 'url':'/rowers/list-workouts', + 'name':'Workouts' + }, + { + 'url':reverse(workout_runkeeperimport_view), + 'name':'Runkeeper' + } + ] + + r = getrower(request.user) + + return render(request,'runkeeper_list_import.html', + {'workouts':workouts, + 'rower':r, + 'active':'nav-workouts', + 'breadcrumbs':breadcrumbs, + 'teams':get_my_teams(request.user), + }) return HttpResponse(res) # The page where you select which RunKeeper workout to import @login_required() -def workout_underarmourimport_view(request,message=""): +def workout_underarmourimport_view(request,message="",userid=0): res = underarmourstuff.get_underarmour_workout_list(request.user) if (res.status_code != 200): if (res.status_code == 401): @@ -9666,38 +9708,53 @@ def workout_underarmourimport_view(request,message=""): messages.error(request,message) url = reverse(workouts_view) return HttpResponseRedirect(url) - else: - workouts = [] - items = res.json()['_embedded']['workouts'] - for item in items: - s = item['start_datetime'] - i,r = underarmourstuff.get_idfromuri(request.user,item['_links']) - n = item['name'] - try: - d = item['aggregates']['distance_total'] - except KeyError: - d = 0 - try: - ttot = item['aggregates']['active_time_total'] - except KeyError: - ttot = 0 - - keys = ['id','distance','duration','starttime','type'] - values = [i,d,ttot,s,r] - thedict = dict(zip(keys,values)) - - workouts.append(thedict) - return render(request,'underarmour_list_import.html', - {'workouts':workouts, - 'teams':get_my_teams(request.user), - }) + workouts = [] + items = res.json()['_embedded']['workouts'] + for item in items: + s = item['start_datetime'] + i,r = underarmourstuff.get_idfromuri(request.user,item['_links']) + n = item['name'] + try: + d = item['aggregates']['distance_total'] + except KeyError: + d = 0 + try: + ttot = item['aggregates']['active_time_total'] + except KeyError: + ttot = 0 + + keys = ['id','distance','duration','starttime','type'] + values = [i,d,ttot,s,r] + thedict = dict(zip(keys,values)) + + workouts.append(thedict) + + rower = getrower(request.user) + breadcrumbs = [ + { + 'url':'/rowers/list-workouts', + 'name':'Workouts' + }, + { + 'url':reverse(workout_c2import_view), + 'name':'Concept2' + }, + ] + + return render(request,'underarmour_list_import.html', + {'workouts':workouts, + 'breadcrumbs':breadcrumbs, + 'rower':rower, + 'active':'nav-workouts', + 'teams':get_my_teams(request.user), + }) return HttpResponse(res) # the page where you select which Polar workout to Import @login_required() -def workout_polarimport_view(request): +def workout_polarimport_view(request,userid=0): exercises = polarstuff.get_polar_workouts(request.user) workouts = [] @@ -9727,10 +9784,25 @@ def workout_polarimport_view(request): res = dict(zip(keys,values)) workouts.append(res) + breadcrumbs = [ + { + 'url':'/rowers/list-workouts', + 'name':'Workouts' + }, + { + 'url':reverse(workout_polarimport_view), + 'name':'Polar' + }, + ] + + r = getrower(request.user) return render(request, 'polar_list_import.html', { 'workouts':workouts, + 'active':'nav-workouts', + 'rower':r, + 'breadcrumbs':breadcrumbs, 'teams':get_my_teams(request.user), }) @@ -9739,7 +9811,9 @@ def workout_polarimport_view(request): # The page where you select which SportTracks workout to import @login_required() -def workout_sporttracksimport_view(request,message=""): +def workout_sporttracksimport_view(request,message="",userid=0): + + res = sporttracksstuff.get_sporttracks_workout_list(request.user) if (res.status_code != 200): if (res.status_code == 401): @@ -9756,31 +9830,48 @@ def workout_sporttracksimport_view(request,message=""): else: url = reverse(workouts_view) return HttpResponseRedirect(url) - else: - workouts = [] - r = getrower(request.user) - 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(getidfromuri(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','new'] - values = [i,d,ttot,s,r,n,nnn] - res = dict(zip(keys,values)) - workouts.append(res) - return render(request,'sporttracks_list_import.html', + + workouts = [] + r = getrower(request.user) + 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(getidfromuri(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','new'] + values = [i,d,ttot,s,r,n,nnn] + res = dict(zip(keys,values)) + workouts.append(res) + + r = getrower(request.user) + + breadcrumbs = [ + { + 'url':'/rowers/list-workouts', + 'name':'Workouts' + }, + { + 'url':reverse(workout_sporttracksimport_view), + 'name':'SportTracks' + }, + ] + + return render(request,'sporttracks_list_import.html', {'workouts':workouts, + 'breadcrumbs':breadcrumbs, + 'active':'nav-workouts', + 'rower':r, 'teams':get_my_teams(request.user), }) @@ -9864,7 +9955,15 @@ def workout_getc2workout_all(request,page=1,message=""): # List of workouts available on Concept2 logbook - for import @login_required() -def workout_c2import_view(request,page=1,message=""): +def workout_c2import_view(request,page=1,userid=0,message=""): + + r = getrequestrower(request,userid=userid) + + if r.user != request.user: + messages.info(request,"You cannot import other people's workouts from Concept2") + + r = getrower(request.user) + try: thetoken = c2_open(request.user) except NoTokenError: @@ -9877,38 +9976,57 @@ def workout_c2import_view(request,page=1,message=""): messages.error(request,message) url = reverse(workouts_view) return HttpResponseRedirect(url) - else: - workouts = [] - r = getrower(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'] - ttot = item['time_formatted'] - s = item['date'] - r = item['type'] - s2 = item['source'] - c = item['comments'] - 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) - - return render(request, - 'c2_list_import2.html', - {'workouts':workouts, - 'teams':get_my_teams(request.user), - 'page':page, - }) + workouts = [] + 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'] + ttot = item['time_formatted'] + s = item['date'] + r = item['type'] + s2 = item['source'] + c = item['comments'] + 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) + + + breadcrumbs = [ + { + 'url':'/rowers/list-workouts', + 'name':'Workouts' + }, + { + 'url':reverse(workout_c2import_view), + 'name':'Concept2' + }, + { + 'url':reverse(workout_c2import_view,kwargs={'page':page}), + 'name':'Page '+str(page) + } + ] + + r = getrower(request.user) + + return render(request, + 'c2_list_import2.html', + {'workouts':workouts, + 'rower':r, + 'active':'nav-workouts', + 'breadcrumbs':breadcrumbs, + 'teams':get_my_teams(request.user), + 'page':page, + }) importsources = { 'c2':c2stuff,