From f17fb560c59cfcf85ca2ccceed2a315cbe79e11b Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Thu, 16 Feb 2023 08:39:27 +0100 Subject: [PATCH] refactoring importviews, part 1 --- rowers/integrations/__init__.py | 9 + rowers/integrations/c2.py | 8 + rowers/integrations/integrations.py | 7 + rowers/integrations/nk.py | 6 + rowers/integrations/rp3.py | 14 +- rowers/integrations/sporttracks.py | 5 + rowers/integrations/strava.py | 6 + rowers/integrations/trainingpeaks.py | 17 +- rowers/urls.py | 32 +--- rowers/views/importviews.py | 272 ++++----------------------- 10 files changed, 113 insertions(+), 263 deletions(-) diff --git a/rowers/integrations/__init__.py b/rowers/integrations/__init__.py index 06b659fd..96bb9221 100644 --- a/rowers/integrations/__init__.py +++ b/rowers/integrations/__init__.py @@ -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, +} + diff --git a/rowers/integrations/c2.py b/rowers/integrations/c2.py index 45397cfa..60a066e3 100644 --- a/rowers/integrations/c2.py +++ b/rowers/integrations/c2.py @@ -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" diff --git a/rowers/integrations/integrations.py b/rowers/integrations/integrations.py index d014a221..df11b674 100644 --- a/rowers/integrations/integrations.py +++ b/rowers/integrations/integrations.py @@ -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): diff --git a/rowers/integrations/nk.py b/rowers/integrations/nk.py index 42b1d17a..987b8972 100644 --- a/rowers/integrations/nk.py +++ b/rowers/integrations/nk.py @@ -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 diff --git a/rowers/integrations/rp3.py b/rowers/integrations/rp3.py index fb1230c4..02c8f8d0 100644 --- a/rowers/integrations/rp3.py +++ b/rowers/integrations/rp3.py @@ -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 = { diff --git a/rowers/integrations/sporttracks.py b/rowers/integrations/sporttracks.py index e790f9e2..1c65b4da 100644 --- a/rowers/integrations/sporttracks.py +++ b/rowers/integrations/sporttracks.py @@ -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) diff --git a/rowers/integrations/strava.py b/rowers/integrations/strava.py index efd83ccc..6344fd1c 100644 --- a/rowers/integrations/strava.py +++ b/rowers/integrations/strava.py @@ -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) diff --git a/rowers/integrations/trainingpeaks.py b/rowers/integrations/trainingpeaks.py index d9cea185..c816ee6a 100644 --- a/rowers/integrations/trainingpeaks.py +++ b/rowers/integrations/trainingpeaks.py @@ -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) diff --git a/rowers/urls.py b/rowers/urls.py index e81ffb7f..40810641 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -672,16 +672,10 @@ urlpatterns = [ name='workout_polarimport_view'), re_path(r'^workout/polarimport/user/(?P\d+)/', views.workout_polarimport_view, name='workout_polarimport_view'), - re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/c2uploadw/$', - views.workout_c2_upload_view, name='workout_c2_upload_view'), - re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/stravauploadw/$', - views.workout_strava_upload_view, name='workout_strava_upload_view'), + re_path('r^workout/(?P\b[0-9A-Fa-f]+\b)/(?P\w+.*)uploadw/$', + views.workout_export_view, name='workout_export_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/recalcsummary/$', views.workout_recalcsummary_view, name='workout_recalcsummary_view'), - re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/sporttracksuploadw/$', - views.workout_sporttracks_upload_view, name='workout_sporttracks_upload_view'), - re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/tpuploadw/$', - views.workout_tp_upload_view, name='workout_tp_upload_view'), re_path(r'^alerts/user/(?P\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\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\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\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\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\d+)/$', diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 4193d681..9e102150 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -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")