Private
Public Access
1
0

Merge branch 'feature/othertypes' into develop

This commit is contained in:
Sander Roosendaal
2018-11-14 22:27:42 +01:00
12 changed files with 396 additions and 83 deletions
+9 -3
View File
@@ -6,7 +6,7 @@
from rowers.imports import *
import datetime
from requests import Request, Session
import mytypes
from rowers.mytypes import otwtypes
from iso8601 import ParseError
@@ -428,7 +428,7 @@ def createc2workoutdata(w):
startdate = datetime.datetime.combine(w.date,datetime.time())
data = {
"type": workouttype,
"type": mytypes.c2mapping[workouttype],
"date": w.startdatetime.isoformat(),
"timezone": w.timezone,
"distance": int(w.distance),
@@ -684,6 +684,12 @@ def process_callback(request):
# Uploading workout
def workout_c2_upload(user,w):
message = 'trying C2 upload'
try:
if mytypes.c2mapping[w.workouttype] is None:
return "This workout type cannot be uploaded to Concept2",0
except KeyError:
return "This workout type cannot be uploaded to Concept2",0
thetoken = c2_open(user)
r = Rower.objects.get(user=user)
@@ -755,7 +761,7 @@ def add_workout_from_data(user,importid,data,strokedata,
source='c2',splitdata=None,
workoutsource='concept2'):
try:
workouttype = data['type']
workouttype = mytypes.c2mappinginv[data['type']]
except KeyError:
workouttype = 'rower'
+3 -1
View File
@@ -741,6 +741,7 @@ def fetchcp(rower,theworkouts,table='cpdata'):
def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
avghr=None,avgpwr=None,avgspm=None,
rankingpiece = False,
duplicate=False,
title='Manual entry',notes='',weightcategory='hwt'):
@@ -813,6 +814,7 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
title=title,
notes=notes,
rankingpiece=rankingpiece,
duplicate=duplicate,
dosmooth=False,
workouttype=workouttype,
consistencychecks=False,
@@ -829,6 +831,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
workoutsource='unknown',
notes='', totaldist=0, totaltime=0,
rankingpiece=False,
duplicate=False,
summary='',
makeprivate=False,
oarlength=2.89, inboard=0.88,
@@ -999,7 +1002,6 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
maxhr = np.nan_to_num(maxhr)
averagehr = np.nan_to_num(averagehr)
duplicate = False
t = datetime.datetime.strptime(duration,"%H:%M:%S.%f")
delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)
+2
View File
@@ -866,6 +866,8 @@ def update_agegroup_db(age,sex,weightcategory,wcdurations,wcpower,
df['sex'] = sex
df['age'] = age
df['weightcategory'] = weightcategory
df.replace([np.inf,-np.inf],np.nan,inplace=True)
df.dropna(axis=0,inplace=True)
if debug:
engine = create_engine(database_url_debug, echo=False)
+311
View File
@@ -10,9 +10,311 @@ workouttypes = (
('coastal','Coastal'),
('c-boat','Dutch C boat'),
('churchboat','Finnish Church boat'),
('Ride','Ride'),
('Kitesurf','Kitesurf'),
('Run','Run'),
('NordicSki','NordicSki'),
('Swim','Swim'),
('RockClimbing','RockClimbing'),
('Hike','Hike'),
('RollerSki','RollerSki'),
('Walk','Walk'),
('AlpineSki','AlpineSki'),
('Snowboard','Snowboard'),
('BackcountrySki','BackcountrySki'),
('Snowshoe','Snowshoe'),
('Canoeing','Canoeing'),
('StairStepper','StairStepper'),
('Crossfit','Crossfit'),
('StandUpPaddling','StandUpPaddling'),
('EBikeRide','EBikeRide'),
('Surfing','Surfing'),
('Elliptical','Elliptical'),
('VirtualRide','VirtualRide'),
('IceSkate','IceSkate'),
('WeightTraining','WeightTraining'),
('InlineSkate','InlineSkate'),
('Windsurf','Windsurf'),
('Kayaking','Kayaking'),
('Workout','Workout'),
('Yoga','Yoga'),
('other','Other'),
)
stravamapping = {
'water':'Rowing',
'rower':'Rowing',
'skierg':'NordicSki',
'bike':'Ride',
'dynamic':'Rowing',
'slides':'Rowing',
'paddle':'StandUpPaddling',
'snow':'NordicSki',
'coastal':'Rowing',
'c-boat':'Rowing',
'churchboat':'Rowing',
'Ride':'Ride',
'Kitesurf':'Kitesurf',
'Run':'Run',
'NordicSki':'NordicSki',
'Swim':'Swim',
'RockClimbing':'RockClimbing',
'Hike':'Hike',
'RollerSki':'RollerSki',
'Walk':'Walk',
'AlpineSki':'AlpineSki',
'Snowboard':'Snowboard',
'BackcountrySki':'BackcountrySki',
'Snowshoe':'Snowshoe',
'Canoeing':'Canoeing',
'StairStepper':'StairStepper',
'Crossfit':'Crossfit',
'StandUpPaddling':'StandUpPaddling',
'EBikeRide':'EBikeRide',
'Surfing':'Surfing',
'Elliptical':'Elliptical',
'VirtualRide':'VirtualRide',
'IceSkate':'IceSkate',
'WeightTraining':'WeightTraining',
'InlineSkate':'InlineSkate',
'Windsurf':'Windsurf',
'Kayaking':'Kayaking',
'Workout':'Workout',
'Yoga':'Yoga',
'other':'Workout',
}
stmapping = {
'water':'Rowing',
'rower':'Rowing',
'skierg':'Skiing:Nordic',
'bike':'Cycling',
'dynamic':'Rowing',
'slides':'Rowing',
'paddle':'Other:Paddling',
'snow':'Skiing:Nordic',
'coastal':'Rowing',
'c-boat':'Rowing',
'churchboat':'Rowing',
'Ride':'Cycling',
'Kitesurf':'Other:Kitesurf',
'Run':'Running',
'NordicSki':'Skiing:Nordic',
'Swim':'Swimming',
'RockClimbing':'Other:RockClimbing',
'Hike':'Hiking',
'RollerSki':'Other:RollerSki',
'Walk':'Other:Walk',
'AlpineSki':'Skiing:AlpineSki',
'Snowboard':'Other:Snowboard',
'BackcountrySki':'Skiing:BackcountrySki',
'Snowshoe':'Other:Snowshoe',
'Canoeing':'Other:Canoeing',
'StairStepper':'Other:StairStepper',
'Crossfit':'Other:Crossfit',
'StandUpPaddling':'Other:StandUpPaddling',
'EBikeRide':'Cycling:EBikeRide',
'Surfing':'Other:Surfing',
'Elliptical':'Other:Elliptical',
'VirtualRide':'Cycling:VirtualRide',
'IceSkate':'Skating',
'WeightTraining':'Other:WeightTraining',
'InlineSkate':'Skating:InlineSkate',
'Windsurf':'Other:Windsurf',
'Kayaking':'Other:Kayaking',
'Workout':'Other:Workout',
'Yoga':'Other:Yoga',
'other':'Other',
}
rkmapping = {
'water':'Rowing',
'rower':'Rowing',
'skierg':'Cross-Country Skiing',
'bike':'Cycling',
'dynamic':'Rowing',
'slides':'Rowing',
'paddle':'Other:Paddling',
'snow':'Cross-Country Skiing',
'coastal':'Rowing',
'c-boat':'Rowing',
'churchboat':'Rowing',
'Ride':'Cycling',
'Kitesurf':'Other',
'Run':'Running',
'NordicSki':'Cross-Country Skiing',
'Swim':'Swimming',
'RockClimbing':'Other',
'Hike':'Hiking',
'RollerSki':'Other:RollerSki',
'Walk':'Walking',
'AlpineSki':'Downhill Skiing',
'Snowboard':'Snowboarding',
'BackcountrySki':'Downhill Skiing',
'Snowshoe':'Other',
'Canoeing':'Other',
'StairStepper':'Stairmaster',
'Crossfit':'CrossFit',
'StandUpPaddling':'Other',
'EBikeRide':'Cycling',
'Surfing':'Other',
'Elliptical':'Elliptical',
'VirtualRide':'Cycling',
'IceSkate':'Skating',
'WeightTraining':'Other',
'InlineSkate':'Skating',
'Windsurf':'Other',
'Kayaking':'Other',
'Workout':'Other',
'Yoga':'Yoga',
'other':'Other',
}
polarmapping = {
'water':'Rowing',
'rower':'Rowing',
'skierg':'Skiing',
'bike':'Cycling',
'dynamic':'Rowing',
'slides':'Rowing',
'paddle':'Other Outdoor',
'snow':'Skiing',
'coastal':'Rowing',
'c-boat':'Rowing',
'churchboat':'Rowing',
'Ride':'Cycling',
'Kitesurf':'Kitesurfing',
'Run':'Running',
'NordicSki':'Skiing',
'Swim':'Swimming',
'RockClimbing':'Other Outdoor',
'Hike':'Hiking',
'RollerSki':'Other Outdoor',
'Walk':'Walking',
'AlpineSki':'Downhill skiing',
'Snowboard':'Snowboarding',
'BackcountrySki':'Downhill skiing',
'Snowshoe':'Snowshoe trekking',
'Canoeing':'Canoeing',
'StairStepper':'Other Indoor',
'Crossfit':'Crossfit',
'StandUpPaddling':'Other Outdoor',
'EBikeRide':'Cycling',
'Surfing':'Surfing',
'Elliptical':'Other Indoor',
'VirtualRide':'Cycling',
'IceSkate':'Skating',
'WeightTraining':'Strength training',
'InlineSkate':'Skating',
'Windsurf':'Windsurfing',
'Kayaking':'Kayaking',
'Workout':'Other Indoor',
'Yoga':'Yoga',
'other':'Other Indoor',
}
tpmapping = {
'water':'rowing',
'rower':'rowing',
'skierg':'xc-ski',
'bike':'bike',
'dynamic':'rowing',
'slides':'rowing',
'paddle':'other',
'snow':'xc-ski',
'coastal':'rowing',
'c-boat':'rowing',
'churchboat':'rowing',
'Ride':'cycling',
'Kitesurf':'other',
'Run':'run',
'NordicSki':'xc-ski',
'Swim':'swim',
'RockClimbing':'other',
'Hike':'other',
'RollerSki':'other',
'Walk':'walk',
'AlpineSki':'other',
'Snowboard':'other',
'BackcountrySki':'other',
'Snowshoe':'other',
'Canoeing':'other',
'StairStepper':'other',
'Crossfit':'other',
'StandUpPaddling':'other',
'EBikeRide':'other',
'Surfing':'other',
'Elliptical':'other',
'VirtualRide':'bike',
'IceSkate':'other',
'WeightTraining':'strength',
'InlineSkate':'other',
'Windsurf':'other',
'Kayaking':'other',
'Workout':'other',
'Yoga':'other',
'other':'other',
}
c2mapping = {
'water':'water',
'rower':'rower',
'skierg':'skierg',
'bike':'bike',
'dynamic':'dynamic',
'slides':'slides',
'paddle':'paddle',
'snow':'snow',
'coastal':'water',
'c-boat':'water',
'churchboat':'water',
'Ride':'bike',
'Kitesurf':None,
'Run':None,
'NordicSki':'snow',
'Swim':None,
'RockClimbing':None,
'Hike':None,
'RollerSki':'snow',
'Walk':None,
'AlpineSki':None,
'Snowboard':None,
'BackcountrySki':'snow',
'Snowshoe':'snow',
'Canoeing':'paddle',
'StairStepper':None,
'Crossfit':None,
'StandUpPaddling':None,
'EBikeRide':None,
'Surfing':None,
'Elliptical':None,
'VirtualRide':None,
'IceSkate':None,
'WeightTraining':None,
'InlineSkate':None,
'Windsurf':None,
'Kayaking':None,
'Workout':None,
'Yoga':None,
'other':None,
}
c2mappinginv = {value:key for key,value in c2mapping.iteritems() if value is not None}
stravamappinginv = {value:key for key,value in stravamapping.iteritems() if value is not None}
stmappinginv = {value:key for key,value in stmapping.iteritems() if value is not None}
rkmappinginv = {value:key for key,value in rkmapping.iteritems() if value is not None}
polarmappinginv = {value:key for key,value in polarmapping.iteritems() if value is not None}
otwtypes = (
'water',
'coastal',
@@ -20,6 +322,15 @@ otwtypes = (
'churchboat'
)
rowtypes = (
'water',
'rower',
'dynamic',
'slides',
'coastal',
'c-boat',
'churchboat'
)
checktypes = [i[0] for i in workouttypes]
+1 -1
View File
@@ -52,7 +52,7 @@ baseurl = 'https://polaraccesslink.com/v3'
from utils import NoTokenError, custom_exception_handler
import mytypes
# Exchange access code for long-lived access token
def get_token(code):
+6 -5
View File
@@ -18,7 +18,7 @@ from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
from iso8601 import ParseError
from utils import myqueue
import mytypes
import gzip
from rowsandall_app.settings import (
@@ -163,7 +163,7 @@ def create_async_workout(alldata,user,stravaid,debug=False):
distance = data['distance']
stravaid = data['id']
try:
workouttype = data['type']
workouttype = mytypes.stravamappinginv[data['type']]
except:
workouttype = 'rower'
@@ -444,14 +444,15 @@ def add_workout_from_data(user,importid,data,strokedata,
source='strava',splitdata=None,
workoutsource='strava'):
try:
workouttype = data['type']
workouttype = mytypes.stravamappinginv[data['type']]
except KeyError:
workouttype = 'rower'
if workouttype.lower() == 'rowing':
workouttype = 'rower'
if 'summary_polyline' in data['map']:
workouttype = 'water'
if 'summary_polyline' in data['map'] and workouttype=='rower':
workouttype = 'water'
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'other'
+6 -9
View File
@@ -83,18 +83,15 @@
$( document ).ready(function() {
$('#id_workouttype').on('change', function(){
if (
$(this).val() == 'rower'
|| $(this).val() == 'skierg'
|| $(this).val() == 'dynamic'
|| $(this).val() == 'slides'
|| $(this).val() == 'paddle'
|| $(this).val() == 'bike'
|| $(this).val() == 'snow'
$(this).val() == 'water'
|| $(this).val() == 'coastal'
|| $(this).val() == 'c-boat'
|| $(this).val() == 'churchboat'
) {
$('#id_boattype').toggle(true);
} else {
$('#id_boattype').toggle(false);
$('#id_boattype').val('1x');
} else {
$('#id_boattype').toggle(true);
}
});
$('#id_workouttype').change();
+6 -9
View File
@@ -16,18 +16,15 @@
$( document ).ready(function() {
$('#id_workouttype').on('change', function(){
if (
$(this).val() == 'rower'
|| $(this).val() == 'skierg'
|| $(this).val() == 'dynamic'
|| $(this).val() == 'slides'
|| $(this).val() == 'paddle'
|| $(this).val() == 'bike'
|| $(this).val() == 'snow'
$(this).val() == 'water'
|| $(this).val() == 'coastal'
|| $(this).val() == 'c-boat'
|| $(this).val() == 'churchboat'
) {
$('#id_boattype').toggle(true);
} else {
$('#id_boattype').toggle(false);
$('#id_boattype').val('1x');
} else {
$('#id_boattype').toggle(true);
}
});
$('#id_workouttype').change();
+16 -19
View File
@@ -76,25 +76,22 @@
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script>
$( document ).ready(function() {
$('#id_workouttype').on('change', function(){
if (
$(this).val() == 'rower'
|| $(this).val() == 'skierg'
|| $(this).val() == 'dynamic'
|| $(this).val() == 'slides'
|| $(this).val() == 'paddle'
|| $(this).val() == 'bike'
|| $(this).val() == 'snow'
) {
$('#id_boattype').toggle(false);
$('#id_boattype').val('1x');
} else {
$('#id_boattype').toggle(true);
}
});
$('#id_workouttype').change();
});
$( document ).ready(function() {
$('#id_workouttype').on('change', function(){
if (
$(this).val() == 'water'
|| $(this).val() == 'coastal'
|| $(this).val() == 'c-boat'
|| $(this).val() == 'churchboat'
) {
$('#id_boattype').toggle(true);
} else {
$('#id_boattype').toggle(false);
$('#id_boattype').val('1x');
}
});
$('#id_workouttype').change();
});
</script>
{% endblock %}
+6 -9
View File
@@ -23,18 +23,15 @@
$( document ).ready(function() {
$('#id_workouttype').on('change', function(){
if (
$(this).val() == 'rower'
|| $(this).val() == 'skierg'
|| $(this).val() == 'dynamic'
|| $(this).val() == 'slides'
|| $(this).val() == 'paddle'
|| $(this).val() == 'snow'
|| $(this).val() == 'bike'
$(this).val() == 'water'
|| $(this).val() == 'coastal'
|| $(this).val() == 'c-boat'
|| $(this).val() == 'churchboat'
) {
$('#id_boattype').toggle(true);
} else {
$('#id_boattype').toggle(false);
$('#id_boattype').val('1x');
} else {
$('#id_boattype').toggle(true);
}
});
$('#id_workouttype').change();
+11 -11
View File
@@ -412,7 +412,7 @@ class C2Objects(DjangoTestCase):
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
name='testworkout',workouttype='water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
@@ -583,7 +583,7 @@ class STObjects(DjangoTestCase):
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
name='testworkout',workouttype='water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
@@ -699,7 +699,7 @@ class RunKeeperObjects(DjangoTestCase):
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
name='testworkout',workouttype='water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
@@ -791,7 +791,7 @@ class UAObjects(DjangoTestCase):
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
name='testworkout',workouttype='water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
@@ -891,7 +891,7 @@ class TPObjects(DjangoTestCase):
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
name='testworkout',workouttype='water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
@@ -1083,7 +1083,7 @@ class WorkoutTests(TestCase):
)
nu = datetime.datetime.now()
self.w = Workout.objects.create(name='testworkout',
workouttype='On-water',
workouttype='water',
user=self.r,date=nu.strftime('%Y-%m-%d'),
starttime=nu.strftime('%H:%M:%S'),
duration="0:55:00",distance=8000)
@@ -1101,7 +1101,7 @@ class C2Tests(TestCase):
gdproptindate=timezone.now()
)
self.nu = datetime.datetime.now()
self.w = Workout.objects.create(name='testworkout',workouttype='On-water',
self.w = Workout.objects.create(name='testworkout',workouttype='water',
user=r,date=nu.strftime('%Y-%m-%d'),
starttime=nu.strftime('%H:%M:%S'),
duration="0:55:00",distance=8000)
@@ -1264,7 +1264,7 @@ class DataTest(TestCase):
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
w = Workout.objects.create(name='testworkout',workouttype='On-water',
w = Workout.objects.create(name='testworkout',workouttype='water',
user=r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
duration=duration,distance=totaldist,
@@ -2008,7 +2008,7 @@ class URLTests(TestCase):
self.nu = datetime.datetime.now()
filename = 'rowers/testdata/testdata.csv'
self.wotw = Workout.objects.create(name='testworkout',
workouttype='On-water',
workouttype='water',
user=r,date=self.nu.strftime('%Y-%m-%d'),
starttime=self.nu.strftime('%H:%M:%S'),
duration="0:55:00",distance=8000,
@@ -2250,7 +2250,7 @@ class subroutinetests(TestCase):
nu = datetime.datetime.now()
filename = 'rowers/testdata/testdata.csv'
self.w = Workout.objects.create(name='testworkout',
workouttype='On-water',
workouttype='water',
user=r,date=nu.strftime('%Y-%m-%d'),
starttime=nu.strftime('%H:%M:%S'),
duration="0:55:00",distance=8000,
@@ -2275,7 +2275,7 @@ class PlotTests(TestCase):
self.nu = datetime.datetime.now()
filename = 'rowers/testdata/testdata.csv'
self.wotw = Workout.objects.create(name='testworkout',
workouttype='On-water',
workouttype='water',
user=r,date=self.nu.strftime('%Y-%m-%d'),
starttime=self.nu.strftime('%H:%M:%S'),
duration="0:55:00",distance=8000,
+19 -16
View File
@@ -1733,6 +1733,12 @@ def workout_strava_upload_view(request,id=0):
message = ""
r = getrower(request.user)
res = -1
try:
thetoken = strava_open(request.user)
except NoTokenError:
return HttpResponseRedirect("/rowers/me/stravaauthorize")
if (r.stravatoken == '') or (r.stravatoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/stravaauthorize/")
@@ -1749,11 +1755,16 @@ def workout_strava_upload_view(request,id=0):
newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
except TypeError:
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
activity_type = r.stravaexportas
res,mes = stravastuff.handle_stravaexport(f,w.name,
r.stravatoken,
description=newnotes,
activity_type=activity_type)
if w.workouttype in mytypes.rowtypes:
activity_type = r.stravaexportas
else:
activity_type = mytypes.stravamapping[w.workouttype]
res,mes = stravastuff.handle_stravaexport(
f,w.name,
r.stravatoken,
description=newnotes,
activity_type=activity_type)
if res==0:
messages.error(request,mes)
w.uploadedtostrava = -1
@@ -10464,15 +10475,7 @@ def workout_runkeeperimport_view(request,message="",userid=0):
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):
r = getrower(request.user)
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
message = "Something went wrong in workout_underarmourimport_view"
messages.error(request,message)
url = reverse(workouts_view)
return HttpResponseRedirect(url)
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
workouts = []
items = res.json()['_embedded']['workouts']
@@ -10822,7 +10825,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
if strokedata.empty:
distance = data['distance']
c2id = data['id']
workouttype = data['type']
workouttype = mytypes.c2mappinginv[data['type']]
verified = data['verified']
startdatetime = iso8601.parse_date(data['date'])
weightclass = data['weight_class']
@@ -10871,7 +10874,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
return HttpResponseRedirect(url)
# strokdata not empty - continue
# strokedata not empty - continue
id,message = importsources[source].add_workout_from_data(
request.user,
externalid,data,