Private
Public Access
1
0

under armour & trainingpeaks done

This commit is contained in:
Sander Roosendaal
2018-07-04 13:30:30 +02:00
parent 8da86e610d
commit 45a6300c76
9 changed files with 271 additions and 25 deletions

View File

@@ -81,7 +81,7 @@ def imports_open(user,oauth_data):
refreshtoken = None refreshtoken = None
try: try:
tokenexpirydate = getattr(r,oauthdata['expirydatename']) tokenexpirydate = getattr(r,oauth_data['expirydatename'])
except AttributeError: except AttributeError:
tokenexpirydate = None tokenexpirydate = None
@@ -97,7 +97,7 @@ def imports_open(user,oauth_data):
return token return token
# Refresh ST token using refresh token # Refresh token using refresh token
def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''): def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
client_auth = requests.auth.HTTPBasicAuth( client_auth = requests.auth.HTTPBasicAuth(
oauth_data['client_id'], oauth_data['client_id'],
@@ -105,16 +105,15 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
) )
post_data = {"grant_type": "refresh_token", post_data = {"grant_type": "refresh_token",
"client_secret": client_secret, "client_secret": oauth_data['client_secret'],
"client_id": client_id, "client_id": oauth_data['client_id'],
"refresh_token": refreshtoken, "refresh_token": refreshtoken,
} }
headers = {'user-agent': 'sanderroosendaal', headers = {'user-agent': 'sanderroosendaal',
'Accept': 'application/json', 'Accept': 'application/json',
'Content-Type': oauth_data['content_type']} 'Content-Type': oauth_data['content_type']}
if oauth_data['bearer_auth']: if oauth_data['bearer_auth']:
headers['authorization'] = 'Bearer %s' % access_token headers['authorization'] = 'Bearer %s' % access_token
baseurl = oauth_data['base_url'] baseurl = oauth_data['base_url']
@@ -129,6 +128,7 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
headers=headers) headers=headers)
token_json = response.json() token_json = response.json()
thetoken = token_json['access_token'] thetoken = token_json['access_token']
expires_in = token_json['expires_in'] expires_in = token_json['expires_in']
try: try:

1
rowers/testdata/tpuploadresponse.txt vendored Normal file
View File

@@ -0,0 +1 @@
[{"EnergyPlanned": null, "ElevationMaximum": null, "HeartRateMinimum": null, "Title": "2ks with focus (6)", "HeartRateMaximum": null, "CaloriesPlanned": null, "WorkoutDay": "2018-07-02T00:00:00-06:00", "VelocityMaximum": null, "StartTimePlanned": null, "PowerAverage": null, "ElevationMinimum": null, "TssCalculationMethod": null, "VelocityAverage": null, "AthleteId": 1696848, "Completed": true, "CadenceAverage": null, "TssActual": null, "IFPlanned": null, "ElevationLoss": null, "HeartRateAverage": null, "Energy": null, "WorkoutType": "Rowing", "TorqueMaximum": null, "Distance": 1328.0, "VelocityPlanned": null, "TssPlanned": null, "TempAvg": null, "TorqueAverage": null, "Calories": null, "ElevationAverage": null, "PowerMaximum": null, "TotalTimePlanned": null, "ElevationGainPlanned": null, "Feeling": null, "DistanceCustomized": null, "IF": null, "TotalTime": 0.10333333333333333, "NormalizedPower": null, "NormalizedSpeed": null, "DistancePlanned": null, "CadenceMaximum": null, "ElevationGain": null, "TempMin": null, "Rpe": null, "StartTime": "2018-07-02T11:24:05-06:00", "Id": 615737179, "TempMax": null}]

View File

@@ -0,0 +1 @@
{"start_datetime": "2018-07-02T17:24:05+00:00", "name": "2ks with focus (6)", "is_default_name": false, "created_datetime": "2018-07-04T09:17:58+00:00", "notes": " \n from strava via rowsandall.com", "updated_datetime": "2018-07-04T09:17:58+00:00", "reference_key": null, "start_locale_timezone": "Europe/Bratislava", "source": "", "source_manufacturer": null, "_links": {"privacy": [{"href": "/v7.1/privacy_option/1/", "id": "1"}], "route": [{"href": "/v7.1/route/2136037651/", "id": "2136037651"}], "documentation": [{"href": "https://developer.underarmour.com/docs/v71_Workout"}], "user": [{"href": "/v7.1/user/109227799/", "id": "109227799"}], "self": [{"href": "/v7.1/workout/2994311008/", "id": "2994311008"}], "activity_type": [{"href": "/v7.1/activity_type/128/", "id": "128"}]}, "has_time_series": true, "is_verified": true, "aggregates": {"active_time_total": 372.0, "distance_total": 1328.000091264, "cadence_max": 11.0, "speed_max": 4.3000016, "speed_min": 1.6666679, "cadence_min": 9.0, "speed_avg": 3.6897879, "cadence_avg": 9.0, "elapsed_time_total": 372.0, "heartrate_avg": 148.0}}

1
rowers/testdata/uastrokes.txt vendored Normal file

File diff suppressed because one or more lines are too long

1
rowers/testdata/uauser.txt vendored Normal file
View File

@@ -0,0 +1 @@
{"last_name": "Roosendaal", "weight": null, "communication": {"promotions": false, "newsletter": false, "system_messages": false}, "height": null, "hobbies": "", "id": 109227799, "date_joined": "2017-03-28T11:32:53+00:00", "first_name": "Sander", "display_name": "Sander Roosendaal", "introduction": "", "display_measurement_system": "metric", "last_login": "2017-03-28T11:32:53+00:00", "location": {"country": "US", "region": "VA", "address": "", "locality": "Ashburn"}, "_links": {"stats": [{"href": "/v7.1/user_stats/109227799/?aggregate_by_period=month", "id": "109227799", "name": "month"}, {"href": "/v7.1/user_stats/109227799/?aggregate_by_period=day", "id": "109227799", "name": "day"}, {"href": "/v7.1/user_stats/109227799/?aggregate_by_period=week", "id": "109227799", "name": "week"}, {"href": "/v7.1/user_stats/109227799/?aggregate_by_period=year", "id": "109227799", "name": "year"}, {"href": "/v7.1/user_stats/109227799/?aggregate_by_period=lifetime", "id": "109227799", "name": "lifetime"}], "privacy": [{"href": "/v7.1/privacy_option/1/", "id": "1", "name": "status_post"}, {"href": "/v7.1/privacy_option/1/", "id": "1", "name": "workout"}, {"href": "/v7.1/privacy_option/0/", "id": "0", "name": "workout_music"}, {"href": "/v7.1/privacy_option/3/", "id": "3", "name": "activity_feed"}, {"href": "/v7.1/privacy_option/0/", "id": "0", "name": "bodymass"}, {"href": "/v7.1/privacy_option/1/", "id": "1", "name": "food_log"}, {"href": "/v7.1/privacy_option/3/", "id": "3", "name": "email_search"}, {"href": "/v7.1/privacy_option/1/", "id": "1", "name": "profile"}, {"href": "/v7.1/privacy_option/1/", "id": "1", "name": "route"}, {"href": "/v7.1/privacy_option/0/", "id": "0", "name": "sleep"}], "image": [{"href": "/v7.1/user_profile_photo/109227799/", "id": "109227799", "name": "user_profile_photo"}], "documentation": [{"href": "https://developer.underarmour.com/docs/v71_User"}], "deactivation": [{"href": "/v7.1/user_deactivation/"}], "user_achievements": [{"href": "/v7.1/user_achievement/?user=109227799"}], "friendships": [{"href": "/v7.1/friendship/?from_user=109227799"}], "workouts": [{"href": "/v7.1/workout/?user=109227799&order_by=-start_datetime"}], "self": [{"href": "/v7.1/user/109227799/", "id": "109227799"}]}, "email": "roosendaalsander@gmail.com", "goal_statement": null, "username": "Sander109227799", "sharing": {"twitter": false, "facebook": false}, "last_initial": "R.", "preferred_language": "en-US", "gender": "M", "time_zone": "Europe/Bratislava", "birthdate": "1972-04-19", "profile_statement": ""}

1
rowers/testdata/uaworkoutlist.txt vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -84,6 +84,7 @@ def mocked_requests(*args, **kwargs):
sporttracksworkoutlist = json.load(open('rowers/testdata/sporttracksworkouts.txt')) sporttracksworkoutlist = json.load(open('rowers/testdata/sporttracksworkouts.txt'))
rkworkoutlistjson = json.load(open('rowers/testdata/rkworkoutslist.txt','r')) rkworkoutlistjson = json.load(open('rowers/testdata/rkworkoutslist.txt','r'))
uaworkoutlistjson = json.load(open('rowers/testdata/uaworkoutlist.txt','r'))
stravasummaryjson = json.load(open('rowers/testdata/stravaworkoutsummary.txt','r')) stravasummaryjson = json.load(open('rowers/testdata/stravaworkoutsummary.txt','r'))
@@ -94,6 +95,10 @@ def mocked_requests(*args, **kwargs):
stravahrjson = json.load(open('rowers/testdata/stravahrtestdata.txt','r')) stravahrjson = json.load(open('rowers/testdata/stravahrtestdata.txt','r'))
stravaspmjson = json.load(open('rowers/testdata/stravaspmtestdata.txt','r')) stravaspmjson = json.load(open('rowers/testdata/stravaspmtestdata.txt','r'))
uapostworkoutjson = json.load(open('rowers/testdata/uapostworkoutresponse.txt','r'))
tpuploadresponse = json.load(open('rowers/testdata/tpuploadresponse.txt','r'))
stravastreamjson = { stravastreamjson = {
'time':stravatimejson, 'time':stravatimejson,
'velocity_smooth':stravavelojson, 'velocity_smooth':stravavelojson,
@@ -107,6 +112,9 @@ def mocked_requests(*args, **kwargs):
rkstrokesjson = json.load(open('rowers/testdata/rkstrokes.txt','r')) rkstrokesjson = json.load(open('rowers/testdata/rkstrokes.txt','r'))
uastrokesjson = json.load(open('rowers/testdata/uastrokes.txt','r'))
uauserjson = json.load(open('rowers/testdata/uauser.txt','r'))
class MockResponse: class MockResponse:
def __init__(self, json_data, status_code): def __init__(self, json_data, status_code):
self.json_data = json_data self.json_data = json_data
@@ -143,6 +151,8 @@ def mocked_requests(*args, **kwargs):
stravatester = re.compile('.*?strava\.com') stravatester = re.compile('.*?strava\.com')
sttester = re.compile('.*?sporttracks\.mobi') sttester = re.compile('.*?sporttracks\.mobi')
rktester = re.compile('.*?runkeeper\.com') rktester = re.compile('.*?runkeeper\.com')
uatester = re.compile('.*?mapmyfitness\.com')
tptester = re.compile('.*?trainingpeaks\.com')
c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+' c2importregex = '.*?concept2.com\/api\/users\/me\/results\/\d+'
c2importtester = re.compile(c2importregex) c2importtester = re.compile(c2importregex)
@@ -180,6 +190,64 @@ def mocked_requests(*args, **kwargs):
rkusertester = re.compile(rkuserregex) rkusertester = re.compile(rkuserregex)
rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$' rkstrokesregex = '.*?api\.runkeeper\.com\/fitnessActivities/\d+$'
rkstrokestester = re.compile(rkstrokesregex) rkstrokestester = re.compile(rkstrokesregex)
uaapiregex = '.*?api\.ua\.com'
uaapitester = re.compile(uaapiregex)
uauploadregex = '.*?api\.ua\.com\/v7.1\/workout\/$'
uauploadtester = re.compile(uauploadregex)
uastrokesregex = '.*?api\.ua\.com\/v7.1\/workout\/\d+'
uastrokestester = re.compile(uastrokesregex)
ualistregex = '.*?api\.ua\.com\/v7.1\/workout\/\?user'
ualisttester = re.compile(ualistregex)
uauserregex = '.*?api\.ua\.com\/v7.1\/user\/self\/'
uausertester = re.compile(uauserregex)
tpuploadregex = '.*?trainingpeaks\.com\/v1\/file'
tpuploadtester = re.compile(tpuploadregex)
if tptester.match(args[0]):
if 'token' in args[0]:
json_data = {
'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq',
'expires_in': 604800,
'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR'
}
return MockResponse(json_data,200)
elif tpuploadtester.match(args[0]):
return MockResponse(tpuploadresponse,200)
if uaapitester.match(args[0]):
if 'access_token' in args[0]:
json_data = {
'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq',
'expires_in': 604800,
'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR'
}
return MockResponse(json_data,200)
elif uauploadtester.match(args[0]):
if 'data' in kwargs:
return MockResponse(uapostworkoutjson,200)
elif uastrokestester.match(args[0]):
return MockResponse(uastrokesjson,200)
elif ualisttester.match(args[0]):
return MockResponse(uaworkoutlistjson,200)
elif uausertester.match(args[0]):
return MockResponse(uauserjson,200)
if uatester.match(args[0]):
if 'access_token' in args[0]:
json_data = {
'access_token': 'TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq',
'expires_in': 604800,
'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR'
}
return MockResponse(json_data,200)
if rktester.match(args[0]): if rktester.match(args[0]):
if 'token' in args[0]: if 'token' in args[0]:
@@ -189,7 +257,7 @@ def mocked_requests(*args, **kwargs):
'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR' 'refresh_token': 'jHJhFzCfOOKB8oyiayubhLAlxaMkG3ruC1E8YxaR'
} }
return MockResponse(json_data,200) return MockResponse(json_data,200)
if rkuploadtester.match(args[0]): elif rkuploadtester.match(args[0]):
if 'data' in kwargs: if 'data' in kwargs:
# post # post
header_data = { header_data = {
@@ -199,7 +267,7 @@ def mocked_requests(*args, **kwargs):
else: else:
json_data = rkworkoutlistjson json_data = rkworkoutlistjson
return MockResponse(json_data,200) return MockResponse(json_data,200)
if rkusertester.match(args[0]): elif rkusertester.match(args[0]):
json_data = { json_data = {
"userID": 1234567890, "userID": 1234567890,
"profile": "/profile", "profile": "/profile",
@@ -216,7 +284,7 @@ def mocked_requests(*args, **kwargs):
"team": "/team" "team": "/team"
} }
return MockResponse(json_data, 200) return MockResponse(json_data, 200)
if rkstrokestester.match(args[0]): elif rkstrokestester.match(args[0]):
return MockResponse(rkstrokesjson,200) return MockResponse(rkstrokesjson,200)
if sttester.match(args[0]): if sttester.match(args[0]):
@@ -661,6 +729,192 @@ class RunKeeperObjects(DjangoTestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
class UAObjects(DjangoTestCase):
def setUp(self):
self.c = Client()
self.u = User.objects.create_user('john',
'sander@ds.ds',
'koeinsloot')
self.u.first_name = 'John'
self.u.last_name = 'Sander'
self.u.save()
self.r = Rower.objects.create(user=self.u,gdproptin=True,
gdproptindate=timezone.now()
)
self.r.underarmourtoken = '12'
self.r.underarmourrefreshtoken = '12'
self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1)
self.r.save()
self.c.login(username='john',password='koeinsloot')
self.nu = datetime.datetime.now()
filename = 'rowers/testdata/testdata.csv'
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
hrut1=self.r.ut1,hrat=self.r.at,
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
row = rdata(filename,rower=rr)
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
duration=duration,distance=totaldist,
csvfilename=filename
)
@patch('rowers.imports.requests.post', side_effect=mocked_requests)
def test_underarmour_callback(self, mock_post):
response = self.c.get('/underarmour_callback?code=dsdoij232s',follow=True)
self.assertEqual(response.status_code, 200)
@patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests)
def test_underarmour_token_refresh(self, mock_post):
response = self.c.get('/rowers/me/underarmourrefresh/',follow=True)
self.assertEqual(response.status_code, 200)
@patch('rowers.underarmourstuff.requests.post', side_effect=mocked_requests)
@patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests)
def test_underarmour_upload(self, mock_get, mock_post):
response = self.c.get('/rowers/workout/1/underarmouruploadw/')
self.assertRedirects(response,
expected_url = '/rowers/workout/1/export',
status_code=302,target_status_code=200)
self.assertEqual(response.url, '/rowers/workout/1/export')
self.assertEqual(response.status_code, 302)
@patch('rowers.underarmourstuff.requests.get', side_effect=mocked_requests)
def test_underarmour_list(self, mock_get):
response = self.c.get('/rowers/workout/underarmourimport',follow=True)
self.assertEqual(response.status_code,200)
@patch('rowers.imports.requests.get', side_effect=mocked_requests)
def test_underarmour_import(self, mock_get):
response = self.c.get('/rowers/workout/underarmourimport/12/',follow=True)
self.assertRedirects(response,
expected_url='/rowers/workout/2/edit',
status_code=302,target_status_code=200)
self.assertEqual(response.status_code, 200)
class TPObjects(DjangoTestCase):
def setUp(self):
self.c = Client()
self.u = User.objects.create_user('john',
'sander@ds.ds',
'koeinsloot')
self.u.first_name = 'John'
self.u.last_name = 'Sander'
self.u.save()
self.r = Rower.objects.create(user=self.u,gdproptin=True,
gdproptindate=timezone.now()
)
self.r.tptoken = '12'
self.r.tprefreshtoken = '12'
self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1)
self.r.save()
self.c.login(username='john',password='koeinsloot')
self.nu = datetime.datetime.now()
filename = 'rowers/testdata/testdata.csv'
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
hrut1=self.r.ut1,hrat=self.r.at,
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
row = rdata(filename,rower=rr)
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
self.w = Workout.objects.create(
name='testworkout',workouttype='On-water',
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
starttime=workoutstarttime,
startdatetime=row.rowdatetime,
duration=duration,distance=totaldist,
csvfilename=filename
)
@patch('rowers.imports.requests.post', side_effect=mocked_requests)
def test_tp_callback(self, mock_post):
response = self.c.get('/tp_callback?code=dsdoij232s',follow=True)
self.assertEqual(response.status_code, 200)
@patch('rowers.tpstuff.requests.post', side_effect=mocked_requests)
def test_tp_token_refresh(self, mock_post):
response = self.c.get('/rowers/me/tprefresh/',follow=True)
self.assertEqual(response.status_code, 200)
@patch('rowers.tpstuff.requests.post', side_effect=mocked_requests)
@patch('rowers.tpstuff.requests.get', side_effect=mocked_requests)
def test_tp_upload(self, mock_get, mock_post):
response = self.c.get('/rowers/workout/1/tpuploadw/')
self.assertRedirects(response,
expected_url = '/rowers/workout/1/export',
status_code=302,target_status_code=200)
self.assertEqual(response.url, '/rowers/workout/1/export')
self.assertEqual(response.status_code, 302)
class TestErrorPages(TestCase): class TestErrorPages(TestCase):
def test_error_handlers(self): def test_error_handlers(self):

View File

@@ -229,7 +229,6 @@ def uploadactivity(access_token,filename,description='',
data = json.dumps(data), data = json.dumps(data),
headers=headers) headers=headers)
print resp.status_code
if resp.status_code != 200: if resp.status_code != 200:
if settings.DEBUG: if settings.DEBUG:
print resp.status_code print resp.status_code
@@ -237,24 +236,11 @@ def uploadactivity(access_token,filename,description='',
print "" print ""
print headers print headers
print "" print ""
with open("media/tperrors.log","a") as errorlog:
errorlog.write(str(resp.status_code))
errorlog.write("\r\n")
timestr = strftime("%Y%m%d-%H%M%S")
errorlog.write(timestr+"\r\n")
errorlog.write("\r\n")
errorlog.write(str(resp.reason))
errorlog.write("\r\n")
try:
errorlog.write(str(resp.json()))
except:
pass
errorlog.write("\r\n")
return 0,resp.reason,resp.status_code,headers return 0,resp.reason,resp.status_code,headers
else: else:
return resp.json()[0]["Id"],"ok",200,"" return resp.json()[0]["Id"],"ok",200,""
return 0 return 0,0,0,0
def workout_tp_upload(user,w): def workout_tp_upload(user,w):

View File

@@ -52,6 +52,7 @@ def get_underarmour_workout_list(user):
'Content-Type': 'application/json'} 'Content-Type': 'application/json'}
url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime" url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime"
print url
s = requests.get(url,headers=headers) s = requests.get(url,headers=headers)
@@ -221,7 +222,7 @@ def get_idfromuri(user,links):
return id,typename return id,typename
def getidfromresponse(response): def getidfromresponse(response):
t = json.loads(response.text) t = response.json()
links = t["_links"] links = t["_links"]