Private
Public Access
1
0

sporttracks, not fully tested

This commit is contained in:
Sander Roosendaal
2023-02-13 22:50:01 +01:00
parent 410722a990
commit 91583134d2
11 changed files with 290 additions and 561 deletions

View File

@@ -1,7 +1,9 @@
from .integrations import SyncIntegration, NoTokenError
from rowers.models import User, Rower, Workout, TombStone
from rowers.tasks import handle_sporttracks_sync
from rowingdata import rowingdata
from rowers.tasks import handle_sporttracks_sync, handle_sporttracks_workout_from_data
from rowers.rower_rules import is_workout_user
import rowers.mytypes as mytypes
from rowsandall_app.settings import (
@@ -11,13 +13,38 @@ from rowsandall_app.settings import (
import re
import numpy
import pytz
import json
import requests
import datetime
import pandas as pd
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('high')
from rowers.utils import myqueue, dologging
from rowers.utils import myqueue, dologging, uniqify
def getidfromuri(uri): # pragma: no cover
m = re.search('/(\w.*)\/(\d+)', uri)
return m.group(2)
def getidfromresponse(response): # pragma: no cover
t = response.json()
uri = t['uris'][0]
regex = '.*?sporttracks\.mobi\/api\/v2\/fitnessActivities/(\d+)\.json$'
m = re.compile(regex).match(uri).group(1)
id = int(m)
return int(id)
def default(o): # pragma: no cover
if isinstance(o, numpy.int64):
return int(o)
raise TypeError
class SportTracksIntegration(SyncIntegration):
def __init__(self, *args, **kwargs):
@@ -27,7 +54,7 @@ class SportTracksIntegration(SyncIntegration):
'client_id': SPORTTRACKS_CLIENT_ID,
'client_secret': SPORTTRACKS_CLIENT_SECRET,
'redirect_uri': SPORTTRACKS_REDIRECT_URI,
'autorization_uri': "https://api.sporttracks.mobi/oauth2/authorize",
'authorization_uri': "https://api.sporttracks.mobi/oauth2/authorize",
'content_type': 'application/json',
'tokenname': 'sporttrackstoken',
'refreshtokenname': 'sporttracksrefreshtoken',
@@ -42,13 +69,178 @@ class SportTracksIntegration(SyncIntegration):
return super(SportTracksIntegration, self).open(*args, **kwargs)
def createworkoutdata(self, w, *args, **kwargs):
return None
timezone = pytz.timezone(w.timezone)
filename = w.csvfilename
try:
row = rowingdata(csvfile=filename)
except: # pragma: no cover
return {}
try:
averagehr = int(row.df[' HRCur (bpm)'].mean())
maxhr = int(row.df[' HRCur (bpm)'].max())
except KeyError: # pragma: no cover
averagehr = 0
maxhr = 0
try:
duration = w.duration.hour*3600
duration += w.duration.minute*60
duration += w.duration.second
duration += +1.0e-6*w.duration.microsecond
except AttributeError: # pragma: no cover
return {}
t = row.df.loc[:, 'TimeStamp (sec)'].values - \
row.df.loc[:, 'TimeStamp (sec)'].iloc[0]
try:
t[0] = t[1]
except IndexError: # pragma: no cover
return {}
d = row.df.loc[:, 'cum_dist'].values
d[0] = d[1]
t = t.astype(int)
d = d.astype(int)
spm = row.df[' Cadence (stokes/min)'].astype(int).values
spm[0] = spm[1]
hr = row.df[' HRCur (bpm)'].astype(int).values
haslatlon = 1
try:
lat = row.df[' latitude'].values
lon = row.df[' longitude'].values
if not lat.std() and not lon.std(): # pragma: no cover
haslatlon = 0
except KeyError:
haslatlon = 0
haspower = 1
try:
power = row.df[' Power (watts)'].astype(int).values
except KeyError: # pragma: no cover
haspower = 0
locdata = []
hrdata = []
spmdata = []
distancedata = []
powerdata = []
t = t.tolist()
hr = hr.tolist()
d = d.tolist()
spm = spm.tolist()
if haslatlon:
lat = lat.tolist()
lon = lon.tolist()
power = power.tolist()
for i in range(len(t)):
hrdata.append(t[i])
hrdata.append(hr[i])
distancedata.append(t[i])
distancedata.append(d[i])
spmdata.append(t[i])
spmdata.append(spm[i])
if haslatlon:
locdata.append(t[i])
locdata.append([lat[i], lon[i]])
if haspower:
powerdata.append(t[i])
powerdata.append(power[i])
try:
w.notes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
except TypeError:
w.notes = 'from '+w.workoutsource+' via rowsandall.com'
st = w.startdatetime.astimezone(timezone)
st = st.replace(microsecond=0)
data = {
"type": "Rowing",
"name": w.name,
"start_time": st.isoformat(),
"total_distance": int(w.distance),
"duration": duration,
"notes": w.notes,
"avg_heartrate": averagehr,
"max_heartrate": maxhr,
"distance": distancedata,
"cadence": spmdata,
"heartrate": hrdata,
}
if haslatlon:
data = {
"type": "Rowing",
"name": w.name,
"start_time": st.isoformat(),
"total_distance": int(w.distance),
"duration": duration,
"notes": w.notes,
"avg_heartrate": averagehr,
"max_heartrate": maxhr,
"location": locdata,
"distance": distancedata,
"cadence": spmdata,
"heartrate": hrdata,
}
if haspower:
data['power'] = powerdata
return data
def workout_export(self, workout, *args, **kwargs) -> str:
pass
thetoken = self.open()
stid = "0"
# ready to upload. Hurray
if not(is_workout_user(self.user, workout)):
return "0"
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
data = self.createworkoutdata(workout)
if not data:
return "0"
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
_ = myqueue(
queue,
handle_sporttracks_sync,
workout.id,
url,
headers,
json.dumps(data, default=default))
return 1
def get_workouts(self, *args, **kwargs) -> int:
pass
r = self.rower
workouts_json = self.get_workout_list_json(*args, **kwargs)
stids = [int(getidfromuri(item['uri']))
for item in workouts_json['items']]
knownstids = uniqify([
w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
])
newids = [stid for stid in stids if stid not in knownstids]
for sporttracksid in newids:
id = self.get_workout(sporttracksid)
return 1
@@ -57,33 +249,19 @@ class SportTracksIntegration(SyncIntegration):
r = self.rower
authorizationstring = str('Bearer ' + r.sporttrackstoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/" + \
str(sporttracksid)
s = requests.get(url, headers=headers)
data = s.json()
strokedata = pd.DataFrame.from_dict({
key: pd.Series(value, dtype='object') for key, value in data.items()
})
id = myqueue(
job = myqueue(
queue,
handle_sporttracks_workout_from_data,
self.user,
sporttracksid, data,
strokedata,
id,
'sporttracks',
'sporttracks'
)
return id
return job.id
def get_workout_list(self, *args, **kwargs) -> list:
def get_workout_list_json(self, *args, **kwargs) -> dict:
_ = self.open()
r = self.rower
@@ -98,13 +276,18 @@ class SportTracksIntegration(SyncIntegration):
s = "Token doesn't exist. Need to authorize"
raise NoTokenError(s)
return res.json()
def get_workout_list(self, *args, **kwargs) -> list:
r = self.rower
workouts_json = self.get_workout_list_json(*args, **kwargs)
workouts = []
knownstids = uniqify([
w.uploadedtosporttracks for w in Workout.objects.filter(user=r)
])
for item in res.json()['items']:
for item in workouts_json['items']:
d = int(float(item['total_distance']))
i = int(getidfromuri(item['uri']))
if i in knownstids: # pragma: no cover
@@ -127,7 +310,7 @@ class SportTracksIntegration(SyncIntegration):
return super(SportTracksIntegration, self).make_authorization_url(*args, **kwargs)
def get_token(self, code, *args, **kwargs) -> (str, int, str):
return ""
return super(SportTracksIntegration, self).get_token(code, *args, **kwargs)