Private
Public Access
1
0

refactoring importviews, part 1

This commit is contained in:
Sander Roosendaal
2023-02-16 08:39:27 +01:00
parent b179f3f9cf
commit f17fb560c5
10 changed files with 113 additions and 263 deletions

View File

@@ -5,3 +5,12 @@ from .sporttracks import SportTracksIntegration
from .rp3 import RP3Integration
from .trainingpeaks import TPIntegration
importsources = {
'c2': C2Integration,
'strava': StravaIntegration,
'sporttracks': SportTracksIntegration,
'trainingpeaks': TPIntegration,
'nk': NKIntegration,
'rp3':RP3Integration,
}

View File

@@ -71,6 +71,14 @@ class C2Integration(SyncIntegration):
'scope': 'write',
}
def get_name(self):
return "Concept2 Logbook"
def get_shortname(self):
return "c2"
def get_token(self, code, *args, **kwargs):
messg = ''
scope = "user:read,results:write"

View File

@@ -36,6 +36,13 @@ class SyncIntegration(metaclass=ABCMeta):
callable(subclass.get_token) or
NotImplemented)
@abstractmethod
def get_name(self):
raise NotImplementedError
@abstractmethod
def get_shortname(self):
raise NotImplementedError
@abstractmethod
def createworkoutdata(self, w, *args, **kwargs):

View File

@@ -44,6 +44,12 @@ class NKIntegration(SyncIntegration):
'scope': 'read',
}
def get_name(self):
return "NK Logbook"
def get_shortname(self):
return "nk"
def createworkoutdata(self, w, *args, **kwargs):
return None

View File

@@ -40,6 +40,11 @@ class RP3Integration(SyncIntegration):
'scope': 'read,write',
}
def get_name(self):
return "RP3 Logbook"
def get_shortname(self):
return "rp3"
def createworkoutdata(self, w, *args, **kwargs):
return None
@@ -200,7 +205,14 @@ class RP3Integration(SyncIntegration):
def make_authorization_url(self, *args, **kwargs) -> str: # pragma: no cover
return super(RP3Integration, self).make_authorization_url(*args, **krags)
params = {"client_id": RP3_CLIENT_KEY,
"response_type": "code",
"redirect_uri": RP3_REDIRECT_URI,
}
url = "https://rp3rowing-app.com/oauth/authorize/?" + \
urllib.parse.urlencode(params)
return url
def get_token(self, code, *args, **kwargs) -> (str, int, str):
post_data = {

View File

@@ -64,6 +64,11 @@ class SportTracksIntegration(SyncIntegration):
'scope': 'write',
}
def get_name(self):
return "SportTracks"
def get_shortname(self):
return "sporttracks"
def open(self, *args, **kwargs) -> str:
return super(SportTracksIntegration, self).open(*args, **kwargs)

View File

@@ -99,6 +99,12 @@ class StravaIntegration(SyncIntegration):
def get_token(self, code, *args, **kwargs):
return super(StravaIntegration, self).get_token(code, *args, **kwargs)
def get_name(self):
return "Strava"
def get_shortname(self):
return "strava"
def open(self, *args, **kwargs):
dologging('strava_log.log','Getting token for user {id}'.format(id=self.rower.id))
token = super(StravaIntegration, self).open(*args, **kwargs)

View File

@@ -51,6 +51,12 @@ class TPIntegration(SyncIntegration):
'scope': 'write',
}
def get_name(self):
return "TrainingPeaks"
def get_shortname(self):
return "trainingpeaks"
def createworkoutdata(self, w, *args, **kwargs):
filename = w.csvfilename
row = rowingdata(csvfile=filename)
@@ -88,7 +94,16 @@ class TPIntegration(SyncIntegration):
raise NotImplementedError("not implemented")
def make_authorization_url(self, *args, **kwargs) -> str: # pragma: no cover
return super(TPIntegration, self).make_authorization_url(self, *args, **kwargs)
params = {"client_id": TP_CLIENT_KEY,
"response_type": "code",
"redirect_uri": TP_REDIRECT_URI,
"scope": "file:write",
}
url = TP_OAUTH_LOCATION+"oauth/authorize/?" + \
urllib.parse.urlencode(params)
return url
def get_token(self, code, *args, **kwargs) -> (str, int, str):
# client_auth = requests.auth.HTTPBasicAuth(TP_CLIENT_KEY, TP_CLIENT_SECRET)

View File

@@ -672,16 +672,10 @@ urlpatterns = [
name='workout_polarimport_view'),
re_path(r'^workout/polarimport/user/(?P<userid>\d+)/',
views.workout_polarimport_view, name='workout_polarimport_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/c2uploadw/$',
views.workout_c2_upload_view, name='workout_c2_upload_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stravauploadw/$',
views.workout_strava_upload_view, name='workout_strava_upload_view'),
re_path('r^workout/(?P<id>\b[0-9A-Fa-f]+\b)/(?P<source>\w+.*)uploadw/$',
views.workout_export_view, name='workout_export_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/recalcsummary/$',
views.workout_recalcsummary_view, name='workout_recalcsummary_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/sporttracksuploadw/$',
views.workout_sporttracks_upload_view, name='workout_sporttracks_upload_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/tpuploadw/$',
views.workout_tp_upload_view, name='workout_tp_upload_view'),
re_path(r'^alerts/user/(?P<userid>\d+)/$',
views.alerts_view, name='alerts_view'),
re_path(r'^alerts/$', views.alerts_view, name='alerts_view'),
@@ -791,32 +785,18 @@ urlpatterns = [
re_path(r'^me/prefs/user/(?P<userid>\d+)/$',
views.rower_simpleprefs_view, name='rower_simpleprefs_view'),
re_path(r'^me/edit/(.+.*)/$', views.rower_edit_view, name='rower_edit_view'),
re_path(r'^me/c2authorize/$', views.rower_c2_authorize,
name='rower_c2_authorize'),
re_path(r'^me/nkauthorize/$', views.rower_nk_authorize,
name='rower_nk_authorize'),
re_path(r'^me/(?P<source>\w+.*)authorize', views.rower_integration_authorize,
name='rower_integration_authorize'),
re_path(r'^me/rojaboauthorize/$', views.rower_rojabo_authorize,
name='rower_rojabo_authorize'),
re_path(r'^me/polarauthorize/$', views.rower_polar_authorize,
name='rower_polar_authorize'),
re_path(r'^me/revokeapp/(?P<id>\d+)/$',
views.rower_revokeapp_view, name='rower_revokeapp_view'),
re_path(r'^me/stravaauthorize/$', views.rower_strava_authorize,
name='rower_strava_authorize'),
re_path(r'^me/garminauthorize/$', views.rower_garmin_authorize,
name='rower_garmin_authorize'),
re_path(r'^me/sporttracksauthorize/$', views.rower_sporttracks_authorize,
name='rower_sporttracks_authorize'),
re_path(r'^me/tpauthorize/$', views.rower_tp_authorize,
name='rower_tp_authorize'),
re_path(r'^me/rp3authorize/$', views.rower_rp3_authorize,
name='rower_rp3_authorize'),
re_path(r'^me/sporttracksrefresh/$', views.rower_sporttracks_token_refresh,
name='rower_sporttracks_token_refresh'),
re_path(r'^me/tprefresh/$', views.rower_tp_token_refresh,
name='rower_tp_token_refresh'),
re_path(r'^me/c2refresh/$', views.rower_c2_token_refresh,
name='rower_c2_token_refresh'),
re_path(r'^me/(?P<source>\w+.*)refresh/$', views.rower_integration_token_refresh,
name='rower_integration_token_refresh'),
re_path(r'^me/favoritecharts/$', views.rower_favoritecharts_view,
name='rower_favoritecharts_view'),
re_path(r'^me/favoritecharts/user/(?P<userid>\d+)/$',

View File

@@ -7,9 +7,9 @@ from rowers.views.statements import *
from rowers.plannedsessions import get_dates_timeperiod
from rowers.tasks import fetch_strava_workout
from rowers.integrations import C2Integration, StravaIntegration, NKIntegration
import rowers.integrations.strava as strava
from rowers.integrations import importsources
import numpy
@@ -19,87 +19,21 @@ def default(o): # pragma: no cover
return int(o)
raise TypeError
# Send workout to TP
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
def workout_tp_upload_view(request, id=0):
message = ""
r = getrower(request.user)
res = -1
tp_integration = TPIntegration(request.user)
try:
_ = tp_integration.open()
except NoTokenError: # pragma: no cover
return HttpResponseRedirect("/rowers/me/tpauthorize/")
# ready to upload. Hurray
w = get_workout_by_opaqueid(request, id)
r = w.user
jobid = tp_integration.workout_export(w)
messages.info(request,'Your workout will be exported to TrainingPeaks in the background')
url = reverse(r.defaultlandingpage,
kwargs={
'id': encoder.encode_hex(w.id),
})
return HttpResponseRedirect(url)
# Send workout to Strava
# abundance of error logging here because there were/are some bugs
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid, raise_exception=True)
def workout_strava_upload_view(request, id=0):
def workout_export_view(request, id=0, source='c2'):
r = getrower(request.user)
w = get_workout_by_opaqueid(request, id)
result = -1
strava_integration = StravaIntegration(request.user)
integration = importsources[source](request.user)
try:
stravaid = strava_integration.workout_export(w)
id = integration.workout_export(w)
except NoTokenError:
return HttpResponseRedirect("/rowers/me/stravaauthorize")
return HttpResponseRedirect(integration.make_authorization_url())
messages.info(
request, 'Your workout will be synchronized to Strava in the background')
url = reverse(r.defaultlandingpage,
kwargs={
'id': encoder.encode_hex(w.id),
}
)
return HttpResponseRedirect(url)
# Upload workout to Concept2 logbook
@login_required()
def workout_c2_upload_view(request, id=0):
message = ""
# ready to upload. Hurray
w = get_workout(id)
r = w.user
s = 'C2 Upload Workout starttime {startdatetime} timezone {timezone} user id {userid}'.format(
startdatetime=w.startdatetime,
timezone=w.timezone,
userid=w.user.user.id
request,
"Your workout will be synchronized to {name} in the background".format(
name=integration.get_name()
)
)
dologging('c2_log.log', s)
c2_integration = C2Integration(request.user)
try:
c2id = c2_integration.workout_export(w)
except NoTokenError: # pragma: no cover
return HttpResponseRedirect("/rowers/me/c2authorize/")
messages.info(
request, 'Your workout will be synchronized to the Concept2 Logbook in the background')
url = reverse(r.defaultlandingpage,
kwargs={
@@ -109,38 +43,12 @@ def workout_c2_upload_view(request, id=0):
return HttpResponseRedirect(url)
# Upload workout to SportTracks
@permission_required('workout.change_workout', fn=get_workout_by_opaqueid)
def workout_sporttracks_upload_view(request, id=0):
st_integration = SportTracksIntegration(request.user)
# ready to upload. Hurray
w = get_workout(id)
r = w.user
id = st_integration.workout_export(w)
messages.info(
request, 'Your workout will be synchronized with SportTracks in the background')
url = reverse(r.defaultlandingpage,
kwargs={
'id': encoder.encode_hex(w.id),
}) # pragma: no cover
return HttpResponseRedirect(url) # pragma: no cover
# ROJABO authorization
def rower_rojabo_authorize(request): # pragma: no cover
state = str(uuid4())
scope = "read"
params = {
# "grant_type": "authorization_code",
# "response_type": "code",
"client_id": ROJABO_CLIENT_ID,
#"client_secret": ROJABO_CLIENT_SECRET,
# "scope": scope,
#"state": state,
"redirect_uri": ROJABO_REDIRECT_URI,
}
@@ -148,25 +56,13 @@ def rower_rojabo_authorize(request): # pragma: no cover
return HttpResponseRedirect(url)
# NK Logbook authorization
@login_required()
def rower_nk_authorize(request): # pragma: no cover
nk_integration = NKIntegration(request.user)
url = nk_integration.make_authorization_url()
def rower_integration_authorize(request, source='c2'):
integration = importsources[source](request.user)
url = integration.make_authorization_url()
return HttpResponseRedirect(url)
# Concept2 authorization
@login_required()
def rower_c2_authorize(request): # pragma: no cover
c2_integration = C2Integration(request.user)
url = c2_integration.make_authorization_url()
return HttpResponseRedirect(url)
# Garmin authorization
@login_required()
def rower_garmin_authorize(request): # pragma: no cover
@@ -175,20 +71,8 @@ def rower_garmin_authorize(request): # pragma: no cover
request.session['garmin_owner_secret'] = secret
return HttpResponseRedirect(authorization_url)
# Strava Authorization
@login_required()
def rower_strava_authorize(request): # pragma: no cover
strava_integration = StravaIntegration(request.user)
url = strava_integration.make_authorization_url()
return HttpResponseRedirect(url)
# Polar Authorization
@login_required()
def rower_polar_authorize(request): # pragma: no cover
@@ -208,89 +92,17 @@ def rower_polar_authorize(request): # pragma: no cover
return HttpResponseRedirect(url)
# SportTracks Authorization
@login_required()
def rower_sporttracks_authorize(request): # pragma: no cover
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
st_integration = SportTracksIntegration(request.user)
url = st_integration.make_authorization_url()
return HttpResponseRedirect(url)
# RP3 Authorization
@login_required()
def rower_rp3_authorize(request): # pragma: no cover
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
# state = str(uuid4())
params = {"client_id": RP3_CLIENT_KEY,
"response_type": "code",
"redirect_uri": RP3_REDIRECT_URI,
}
url = "https://rp3rowing-app.com/oauth/authorize/?" + \
urllib.parse.urlencode(params)
return HttpResponseRedirect(url)
# TrainingPeaks Authorization
@login_required()
def rower_tp_authorize(request): # pragma: no cover
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
# state = str(uuid4())
params = {"client_id": TP_CLIENT_KEY,
"response_type": "code",
"redirect_uri": TP_REDIRECT_URI,
"scope": "file:write",
}
url = TP_OAUTH_LOCATION+"oauth/authorize/?" + \
urllib.parse.urlencode(params)
return HttpResponseRedirect(url)
# Concept2 token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_c2_token_refresh(request):
c2_integration = C2Integration(request.user)
def rower_integration_token_refresh(request, source='c2'):
integration = importsource[source](request.user)
try:
token = c2_integration.token_refresh()
token = integration.token_refresh()
messages.info(request, "Tokens refreshed. Good to go")
except NoTokenError:
messages.error(request, "Something went wrong refreshing C2 tokens. Please reauthorize")
url = reverse('workouts_view')
return HttpResponseRedirect(url)
# TrainingPeaks token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_tp_token_refresh(request):
r = getrower(request.user)
tp_integration = TPIntegration(request.user)
token = tp_integration.token_refresh()
successmessage = "Tokens refreshed. Good to go"
messages.info(request, successmessage)
url = reverse('workouts_view')
return HttpResponseRedirect(url)
# SportTracks token refresh. URL for manual refresh. Not visible to users
@login_required()
def rower_sporttracks_token_refresh(request):
st_integration = SportTracksIntegration(request.user)
result = st_integration.token_refresh()
messages.error(request,
"Something went wrong refreshing your access tokens to {name}. Please reauthorize".format(
name=integration.get_name()
))
url = reverse('workouts_view')
@@ -300,7 +112,7 @@ def rower_sporttracks_token_refresh(request):
# Concept2 Callback
@login_required()
def rower_process_callback(request):
c2_integration = C2Integration(request.user)
c2_integration = importsources['c2'](request.user)
try:
code = request.GET['code']
res = c2_integration.get_token(code)
@@ -473,7 +285,7 @@ def rower_process_nkcallback(request): # pragma: no cover
# do stuff
try:
code = request.GET.get('code', None)
nk_integration = NKIntegration(request.user)
nk_integration = importsources['nk'](request.user)
access_token, expires_in, refresh_token = nk_integration.get_token(code)
except MultiValueDictKeyError:
message = "The resource owner or authorization server denied the request"
@@ -520,7 +332,7 @@ def workout_getnkworkout_all(request, startdatestring='', enddatestring=''):
after = arrow.get(startdate)
after = str(int(after.timestamp()*1000))
nk_integration = NKIntegration(request.user)
nk_integration = importsources['nk'](request.user)
try:
_ = nk_integration.open()
@@ -550,7 +362,7 @@ def workout_nkimport_view(request, userid=0, after=0, before=0):
startdate = startdate.date()
enddate = enddate.date()
r = getrequestrower(request, userid=userid)
nk_integration = NKIntegration(request.user)
nk_integration = importsources['nk'](request.user)
try:
_ = nk_integration.open()
@@ -609,7 +421,7 @@ def workout_nkimport_view(request, userid=0, after=0, before=0):
@login_required()
def rower_process_stravacallback(request):
strava_integration = StravaIntegration(request.user)
strava_integration = importsources['strava'](request.user)
try:
code = request.GET['code']
_ = request.GET['scope']
@@ -663,7 +475,7 @@ def rower_process_sporttrackscallback(request):
url = reverse('rower_exportsettings_view')
return HttpResponseRedirect(url)
st_integration = SportTracksIntegration(request.user)
st_integration = importsources['sporttracks'](request.user)
token = st_integration.get_token(code)
successmessage = "Tokens stored. Good to go. Please check your import/export settings"
@@ -687,7 +499,7 @@ def rower_process_rp3callback(request): # pragma: no cover
url = reverse('rower_exportsettings_view')
return HttpResponseRedirect(url)
rp3_integration = RP3Integration(request.user)
rp3_integration = importsources['rp3'](request.user)
access_token, expires_in, refresh_token = rp3_integration.get_token(code)
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
@@ -721,7 +533,7 @@ def rower_process_tpcallback(request):
url = reverse('rower_exportsettings_view')
return HttpResponseRedirect(url)
tp_integration = TPIntegration(request.user)
tp_integration = importsources['trainingpeaks'](request.user)
access_token, expires_in, refresh_token = tp_integration.get_token(code)
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
@@ -760,7 +572,7 @@ def rower_process_testcallback(request): # pragma: no cover
@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True)
def workout_rp3import_view(request, userid=0):
r = getrequestrower(request, userid=userid)
rp3_integration = RP3Integration(request.user)
rp3_integration = importsources['rp3'](request.user)
try:
_ = rp3_integration.open()
@@ -993,7 +805,7 @@ def workout_stravaimport_view(request, message="", userid=0):
kwargs={'userid': request.user.id})
return HttpResponseRedirect(url)
strava_integration = StravaIntegration(request.user)
strava_integration = importsources['strava'](request.user)
try:
_ = strava_integration.open()
except NoTokenError: # pragma: no cover
@@ -1099,7 +911,7 @@ def strava_webhook_view(request):
ws = Workout.objects.filter(uploadedtostrava=stravaid)
if ws.count() == 0 and r.strava_auto_import:
strava_integration = StravaIntegration(r.user)
strava_integration = importsources['strava'](r.user)
jobid = strava_integration.get_workout(stravaid)
if jobid == 0: # pragma: no cover
dologging('strava_webhooks.log',
@@ -1316,7 +1128,7 @@ def workout_polarimport_view(request, userid=0): # pragma: no cover
@permission_required('rower.is_coach', fn=get_user_by_userid, raise_exception=True)
@permission_required('rower.is_not_freecoach', fn=get_user_by_userid, raise_exception=True)
def workout_sporttracksimport_view(request, message="", userid=0):
st_integration = SportTracksIntegration(request.user)
st_integration = importsources['sporttracks'](request.user)
try:
_ = st_integration.open()
except NoTokenError:
@@ -1379,7 +1191,7 @@ def workout_sporttracksimport_view(request, message="", userid=0):
@login_required()
def workout_getc2workout_all(request, page=1, message=""): # pragma: no cover
r = getrequestrower(request)
c2_integration = C2Integration(request.user)
c2_integration = importsources['c2'](request.user)
try:
_ = c2_integration.open()
except NoTokenError: # pragma: no cover
@@ -1406,7 +1218,7 @@ def workout_getrp3workout_all(request): # pragma: no cover
r = getrequestrower(request)
rp3_integration = RP3Integration(request.user)
rp3_integration = importsources['rp3'](request.user)
result = rp3_integration.get_workouts()
if result:
@@ -1432,7 +1244,7 @@ def workout_c2import_view(request, page=1, userid=0, message=""):
'userid': request.user.id})
return HttpResponseRedirect(url)
c2_integration = C2Integration(request.user)
c2_integration = importsources['c2'](request.user)
try:
_ = c2_integration.open()
except NoTokenError: # pragma: no cover
@@ -1513,16 +1325,6 @@ importauthorizeviews = {
'rp3': 'rower_rp3_authorize',
}
importsources = {
'c2': C2Integration,
'strava': StravaIntegration,
'polar': polarstuff,
'ownapi': ownapistuff,
'sporttracks': SportTracksIntegration,
'trainingpeaks': TPIntegration,
'nk': NKIntegration,
'rp3':RP3Integration,
}
@@ -1561,7 +1363,7 @@ def workout_getimportview_old(request, externalid, source='c2', do_async=True):
# Imports all new workouts from SportTracks
@login_required()
def workout_getsporttracksworkout_all(request):
st_integration = SportTracksIntegration(request.user)
st_integration = importsources['sporttracks'](request.user)
st_integration.get_workouts()
messages.info(request,"Your SportTracks workouts will be imported in the background")
@@ -1573,7 +1375,7 @@ def workout_getsporttracksworkout_all(request):
def workout_getimportview(request, externalid, source='c2', do_async=True):
try:
integration = importsources[source](request.user)
except TypeError:
except (TypeError, NotImplementedError, KeyError):
return workout_getimportview_old(request, externalid, source=source, do_async=True)
if 'startdate' in request.session and source == 'nk': # pragma: no cover
startdate = request.session.get('startdate')
@@ -1606,7 +1408,7 @@ def workout_getimportview(request, externalid, source='c2', do_async=True):
# Imports all new workouts from SportTracks
@login_required()
def workout_getsporttracksworkout_all(request):
st_integration = SportTracksIntegration(request.user)
st_integration = importsources['sporttracks'](request.user)
try:
_ = st_integration.get_workouts()
messages.info(request,"Your SportTracks workouts will be imported in the background")