From 20a7ebea46c5b8ab46ae1645c0f3dcc0c8c0e1ff Mon Sep 17 00:00:00 2001 From: Sander Roosendaal Date: Fri, 17 Feb 2023 17:14:56 +0100 Subject: [PATCH] testing full refactor, excluding garmin, polar, rojabo --- rowers/integrations/__init__.py | 2 + rowers/templates/list_import.html | 11 +- rowers/templates/menu_workouts.html | 2 +- rowers/tests/test_imports.py | 38 +- rowers/tests/testdata/testdata.tcx.gz | Bin 4001 -> 4001 bytes rowers/traverselinktest.py | 1 - rowers/urls.py | 50 +-- rowers/views/importviews.py | 492 ++++---------------------- 8 files changed, 97 insertions(+), 499 deletions(-) diff --git a/rowers/integrations/__init__.py b/rowers/integrations/__init__.py index 96bb9221..4e34497e 100644 --- a/rowers/integrations/__init__.py +++ b/rowers/integrations/__init__.py @@ -5,12 +5,14 @@ from .sporttracks import SportTracksIntegration from .rp3 import RP3Integration from .trainingpeaks import TPIntegration + importsources = { 'c2': C2Integration, 'strava': StravaIntegration, 'sporttracks': SportTracksIntegration, 'trainingpeaks': TPIntegration, 'nk': NKIntegration, + 'tp':TPIntegration, 'rp3':RP3Integration, } diff --git a/rowers/templates/list_import.html b/rowers/templates/list_import.html index 1a0f21c2..643bd6db 100644 --- a/rowers/templates/list_import.html +++ b/rowers/templates/list_import.html @@ -8,6 +8,15 @@

Available on {{ integration }}

    +
  • +
    + + {{ dateform.as_table }} +
    + {% csrf_token %} + +
    +
  • {% if workouts %} {% if integration == 'C2 Logbook' %}
  • @@ -30,7 +39,7 @@

  • - {% endif %} + {% endif %}
  • {% csrf_token %} diff --git a/rowers/templates/menu_workouts.html b/rowers/templates/menu_workouts.html index e7bc91c7..b85f728f 100644 --- a/rowers/templates/menu_workouts.html +++ b/rowers/templates/menu_workouts.html @@ -51,7 +51,7 @@
      -
    • Concept2
    • +
    • Concept2
    • NK Logbook
    • Strava
    • SportTracks
    • diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 8ff6ab46..e84c7404 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -359,8 +359,8 @@ class C2Objects(DjangoTestCase): @patch('rowers.integrations.c2.requests.post', side_effect=mocked_requests) @patch('rowers.integrations.c2.requests.get', side_effect=mocked_requests) def test_c2_upload(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/'+encoded1+'/c2uploadw/') - + url = '/rowers/workout/'+encoded1+'/c2uploadw/' + response = self.c.get(url) self.assertRedirects(response, expected_url = '/rowers/workout/'+encoded1+'/edit/', status_code=302,target_status_code=200) @@ -371,7 +371,7 @@ class C2Objects(DjangoTestCase): @patch('rowers.integrations.c2.requests.post', side_effect=mocked_requests) @patch('rowers.integrations.c2.requests.get', side_effect=mocked_requests) def test_c2_list(self, mock_get, mock_post): - response = self.c.get('/rowers/workout/c2list',follow=True) + response = self.c.get('/rowers/workout/c2import',follow=True) self.assertEqual(response.status_code,200) @@ -381,7 +381,7 @@ class C2Objects(DjangoTestCase): response = self.c.get('/rowers/workout/c2import/12/',follow=True) - expected_url = reverse('workout_c2import_view') + expected_url = reverse('workout_import_view',kwargs={'source':'c2'}) self.assertRedirects(response, expected_url=expected_url, @@ -513,7 +513,7 @@ class C2Objects(DjangoTestCase): def test_c2_import_tz(self, mock_get, mocked_sqlalchemy, mock_session): response = self.c.get('/rowers/workout/c2import/22/',follow=True) - expected_url = '/rowers/workout/c2list/' + expected_url = '/rowers/workout/c2import/' self.assertRedirects(response, expected_url=expected_url, @@ -532,7 +532,7 @@ class C2Objects(DjangoTestCase): def test_c2_import_tz3(self, mock_get, mocked_sqlalchemy): response = self.c.get('/rowers/workout/c2import/32/',follow=True) - expected_url = '/rowers/workout/c2list/' + expected_url = '/rowers/workout/c2import/' self.assertRedirects(response, expected_url=expected_url, @@ -552,7 +552,7 @@ class C2Objects(DjangoTestCase): def test_c2_import_tz2(self, mock_get, mocked_sqlalchemy, MockSession): response = self.c.get('/rowers/workout/c2import/31/',follow=True) - expected_url = '/rowers/workout/c2list/' + expected_url = '/rowers/workout/c2import/' result = tasks.handle_c2_getworkout(self.r.user.id,self.r.c2token,31,self.r.defaulttimezone) @@ -648,7 +648,7 @@ class C2ObjectsTokenExpired(DjangoTestCase): @patch('rowers.integrations.c2.requests.get', side_effect=mocked_requests) @patch('rowers.integrations.c2.Session',side_effect=mocked_requests) def test_c2_list(self, mock_get, mock_post, mock_Session): - response = self.c.get('/rowers/workout/c2list',follow=True) + response = self.c.get('/rowers/workout/c2import/',follow=True) self.assertEqual(response.status_code,200) @@ -757,14 +757,10 @@ class NKObjects(DjangoTestCase): result = integration.open() self.assertEqual(result,"TA3n1vrNjuQJWw0TdCDHnjSmrjIPULhTlejMIWqq") - response = self.c.get('/rowers/workout/nkimport/all/',follow=True) + response = self.c.get('/rowers/workout/nkimport/?selectallnew=true',follow=True) expected = reverse('workouts_view') - self.assertRedirects(response, - expected_url=expected, - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) @patch('rowers.integrations.nk.requests.get', side_effect=mocked_requests) @@ -780,7 +776,7 @@ class NKObjects(DjangoTestCase): response = self.c.get('/rowers/workout/nkimport/469',follow=True) - expected_url = reverse('workout_nkimport_view') + expected_url = reverse('workout_import_view',kwargs={'source':'nk'}) self.assertRedirects(response, expected_url=expected_url, @@ -804,7 +800,7 @@ class NKObjects(DjangoTestCase): result = integration.token_refresh() response = self.c.get('/rowers/workout/nkimport/404',follow=True) - expected_url = reverse('workout_nkimport_view') + expected_url = reverse('workout_import_view',kwargs={'source':'nk'}) self.assertRedirects(response, expected_url=expected_url, @@ -979,7 +975,7 @@ class RP3Objects(DjangoTestCase): response = self.c.get('/rowers/workout/rp3import/591621',follow=True) - expected_url = reverse('workout_rp3import_view') + expected_url = reverse('workout_import_view',kwargs={'source':'rp3'}) self.assertRedirects(response, expected_url=expected_url, @@ -1163,7 +1159,7 @@ class StravaObjects(DjangoTestCase): mocked_getsmallrowdata_db): response = self.c.get('/rowers/workout/stravaimport/12',follow=True) - expected_url = reverse('workout_stravaimport_view') + expected_url = reverse('workout_import_view',kwargs={'source':'strava'}) self.assertRedirects(response, expected_url=expected_url, @@ -1296,13 +1292,7 @@ class STObjects(DjangoTestCase): @patch('rowers.imports.requests.get', side_effect=mocked_requests) def test_sporttracks_import_all(self, mock_get): - response = self.c.get('/rowers/workout/sporttracksimport/all/',follow=True) - - expected_url = reverse('workouts_view') - - self.assertRedirects(response, - expected_url=expected_url, - status_code=302,target_status_code=200) + response = self.c.get('/rowers/workout/sporttracksimport/?selectallnew=true') self.assertEqual(response.status_code, 200) diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz index 2dd6e24406acadd4db84d1855eeae830fc2ab225..7322a59a7d7e228cffee8b1b4a65350d9f9b57f1 100644 GIT binary patch literal 4001 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 H#DD<+O*R%J diff --git a/rowers/traverselinktest.py b/rowers/traverselinktest.py index 44fbd53a..503b4fbd 100644 --- a/rowers/traverselinktest.py +++ b/rowers/traverselinktest.py @@ -95,7 +95,6 @@ class TraverseLinksTest(TestCase): '.*authorize.*', '.*youtu.*', '.*earth.*', - '.*c2list.*', '.*stravaimport.*', '.*performancephones.*', '.*sporttracks.*', diff --git a/rowers/urls.py b/rowers/urls.py index 40810641..d448a193 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -618,61 +618,17 @@ urlpatterns = [ views.workout_smoothenpace_view, name='workout_smoothenpace_view'), re_path(r'^workout/(?P\b[0-9A-Fa-f]+\b)/undosmoothenpace/$', views.workout_undo_smoothenpace_view, name='workout_undo_smoothenpace_view'), - re_path(r'^workout/c2import/$', views.workout_c2import_view, - name='workout_c2import_view'), - re_path(r'^workout/c2list/$', views.workout_c2import_view, - name='workout_c2import_view'), - re_path(r'^workout/c2list/(?P\d+)/$', - views.workout_c2import_view, name='workout_c2import_view'), - re_path(r'^workout/c2list/user/(?P\d+)/$', - views.workout_c2import_view, name='workout_c2import_view'), - re_path(r'^workout/c2list/(?P\d+)/user/(?P\d+)/$', - views.workout_c2import_view, name='workout_c2import_view'), - re_path(r'^workout/rp3import/$', views.workout_rp3import_view, - name='workout_rp3import_view'), - re_path(r'^workout/rp3import/user/(?P\d+)/$', - views.workout_rp3import_view, name='workout_rp3import_view'), - re_path(r'^workout/stravaimport/$', views.workout_stravaimport_view, - name='workout_stravaimport_view'), re_path(r'^session/rojaboimport/$', views.workout_rojaboimport_view, name='workout_rojaboimport_view'), - re_path(r'^workout/stravaimport/user/(?P\d+)/$', - views.workout_stravaimport_view, name='workout_stravaimport_view'), - re_path(r'^workout/c2import/all/$', views.workout_getc2workout_all, - name='workout_getc2workout_all'), - re_path(r'^workout/c2import/all/(?P\d+)/$', - views.workout_getc2workout_all, name='workout_getc2workout_all'), - re_path(r'^workout/nkimport/$', views.workout_nkimport_view, - name='workout_nkimport_view'), - re_path(r'^workout/nkimport/(?P\d+)/(?P\d+)/$', - views.workout_nkimport_view, name='workout_nkimport_view'), - re_path(r'^workout/nkimport/user/(?P\d+)/$', - views.workout_nkimport_view, name='workout_nkimport_view'), - re_path(r'^workout/nkimport/all/$', views.workout_getnkworkout_all, - name='workout_getnkworkout_all'), - re_path(r'^workout/nkimport/all/(?P\d+-\d+-\d+)/(?P\d+-\d+-\d+)/$', - views.workout_getnkworkout_all, - name='workout_getnkworkout_all'), - re_path(r'^workout/rp3import/user/(?P\d+)/$', - views.workout_rp3import_view, name='workout_rp3import_view'), - re_path(r'^workout/rp3import/all/$', views.workout_getrp3workout_all, - name='workout_getrp3workout_all'), + re_path(r'^workout/(?P\w+.*)import/$', + views.workout_import_view, name='workout_import_view'), re_path(r'^workout/(?P\w+.*)import/(?P\d+)/$', views.workout_getimportview, name='workout_getimportview'), - re_path(r'^workout/(?P\w+.*)import/(?P\d+)/async/$', - views.workout_getimportview, {'do_async': True}, name='workout_getimportview'), - # re_path(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'), - re_path(r'^workout/sporttracksimport/$', views.workout_sporttracksimport_view, - name='workout_sporttracksimport_view'), - re_path(r'^workout/sporttracksimport/user/(?P\d+)/$', - views.workout_sporttracksimport_view, name='workout_sporttracksimport_view'), - re_path(r'^workout/sporttracksimport/all/$', views.workout_getsporttracksworkout_all, - name='workout_getsporttracksworkout_all'), re_path(r'^workout/polarimport/$', views.workout_polarimport_view, 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)/(?P\w+.*)uploadw/$', + re_path(r'^workout/(?P[0-9A-Fa-f]+)/(?P[0-9A-za-z]+)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'), diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 9e102150..99dae081 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -10,6 +10,7 @@ from rowers.tasks import fetch_strava_workout import rowers.integrations.strava as strava from rowers.integrations import importsources +from rowers.utils import NoTokenError import numpy @@ -94,7 +95,11 @@ def rower_polar_authorize(request): # pragma: no cover @login_required() def rower_integration_token_refresh(request, source='c2'): - integration = importsource[source](request.user) + try: + integration = importsources[source](request.user) + except KeyError: + url = reverse('workouts_view') + return HttpResponseRedirect(url) try: token = integration.token_refresh() messages.info(request, "Tokens refreshed. Good to go") @@ -320,58 +325,57 @@ def rower_process_nkcallback(request): # pragma: no cover return HttpResponseRedirect(url) + @login_required() -def workout_getnkworkout_all(request, startdatestring='', enddatestring=''): +@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_import_view(request, source='c2'): startdate, enddate = get_dates_timeperiod( - request, startdatestring=startdatestring, enddatestring=enddatestring) + request, defaulttimeperiod='last30') startdate = startdate.date() enddate = enddate.date() + r = getrequestrower(request) + integration = importsources[source](request.user) + + try: + _ = integration.open() + except NoTokenError: # pragma: no cover + return HttpResponseRedirect("/rowers/me/nkauthorize/") + + + + + if request.method == 'POST': # pragma: no cover + dateform = DateRangeForm(request.POST) + if dateform.is_valid(): + startdate = dateform.cleaned_data['startdate'] + enddate = dateform.cleaned_data['enddate'] + \ + datetime.timedelta(days=1) + else: + dateform = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) + + if enddate < startdate: # pragma: no cover + s = enddate + enddate = startdate + startdate = s + + startdatestring = startdate.strftime('%Y-%m-%d') + enddatestring = enddate.strftime('%Y-%m-%d') + + request.session['startdate'] = startdatestring + request.session['enddate'] = enddatestring + before = arrow.get(enddate) before = str(int(before.timestamp()*1000)) after = arrow.get(startdate) after = str(int(after.timestamp()*1000)) - nk_integration = importsources['nk'](request.user) - try: - _ = nk_integration.open() - except NoTokenError: # pragma: no cover - return HttpResponseRedirect("rower_nk_authorize") - - r = getrequestrower(request) - - result = nk_integration.get_workouts(before=before, after=after) - - if result: - messages.info( - request, "Your NK workouts will be imported in the coming few minutes") - else: # pragma: no cover - messages.error(request, "Your NK workouts import failed") - - url = reverse('workouts_view') - return HttpResponseRedirect(url) - - -@login_required() -@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_nkimport_view(request, userid=0, after=0, before=0): - startdate, enddate = get_dates_timeperiod( - request, defaulttimeperiod='last30') - startdate = startdate.date() - enddate = enddate.date() - r = getrequestrower(request, userid=userid) - nk_integration = importsources['nk'](request.user) - - try: - _ = nk_integration.open() - except NoTokenError: # pragma: no cover - return HttpResponseRedirect("/rowers/me/nkauthorize/") - - - - workouts = nk_integration.get_workout_list(before=0, after=0) + workouts = integration.get_workout_list(before=before, after=after, startdate=startdate, enddate=enddate) if request.method == 'POST': # pragma: no cover @@ -380,11 +384,11 @@ def workout_nkimport_view(request, userid=0, after=0, before=0): ids = tdict['workoutid'] nkids = [int(id) for id in ids] for nkid in nkids: - _ = nk_integration.get_workout(nkid) + _ = integration.get_workout(nkid) messages.info( request, - 'Your NK logbook workouts will be imported in the background.' - ' It may take a few minutes before they appear.') + 'Your {source} workouts will be imported in the background.' + ' It may take a few minutes before they appear.'.format(source=integration.get_name())) url = reverse('workouts_view') return HttpResponseRedirect(url) except KeyError: @@ -396,27 +400,29 @@ def workout_nkimport_view(request, userid=0, after=0, before=0): 'name': 'Workouts' }, { - 'url': reverse('workout_nkimport_view'), - 'name': 'NK Logbook' + 'url': reverse('workout_import_view',kwargs={'source':source}), + 'name': integration.get_name() }, ] checknew = request.GET.get('selectallnew', False) + return render(request, 'list_import.html', { 'workouts': workouts, 'rower': r, - 'startdate': startdate, - 'enddate': enddate, + 'dateform':dateform, 'active': 'nav-workouts', 'breadcrumbs': breadcrumbs, 'teams': get_my_teams(request.user), 'checknew': checknew, - 'integration': 'NK Logbook' + 'startdate':startdate, + 'enddate': enddate, + 'integration': integration.get_name() }) + -# Process Strava Callback @login_required() @@ -568,67 +574,6 @@ def rower_process_testcallback(request): # pragma: no cover return HttpResponse(text) -@login_required() -@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 = importsources['rp3'](request.user) - - try: - _ = rp3_integration.open() - except NoTokenError: # pragma: no cover - url = reverse('rower_rp3_authorize') - return HttpResponseRedirect(url) - - workouts = rp3_integration.get_workout_list() - datedict = {} - for workout in workouts: - datedict[workout['id']] = workout['starttime'] - - - if request.method == "POST": - try: # pragma: no cover - tdict = dict(request.POST.lists()) - ids = tdict['workoutid'] - rp3ids = [int(id) for id in ids] - - for rp3id in rp3ids: - rp3_integration.get_workout(rp3id,startdatetime=datedict[rp3id]) - # done, redirect to workouts list - messages.info( - request, - 'Your RP3 workouts will be imported in the background.' - ' It may take a few minutes before they appear.') - url = reverse('workouts_view') - return HttpResponseRedirect(url) - except KeyError: # pragma: no cover - pass - - - breadcrumbs = [ - { - 'url': '/rowers/list-workouts/', - 'name': 'Workouts' - }, - { - 'url': reverse('workout_rp3import_view'), - 'name': 'RP3' - }, - ] - - checknew = request.GET.get('selectallnew', False) - - - return render(request, 'list_import.html', - { - 'workouts': workouts, - 'rower': r, - 'active': 'nav-workouts', - 'breadcrumbs': breadcrumbs, - 'teams': get_my_teams(request.user), - 'integration': 'RP3', - 'checknew': checknew, - }) # The page where you select which Strava workout to import @login_required() @@ -791,72 +736,6 @@ def workout_rojaboimport_view(request, message="", userid=0): 'checknew': checknew, }) -# The page where you select which Strava workout to import -@login_required() -@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_stravaimport_view(request, message="", userid=0): - - r = getrequestrower(request, userid=userid) - if r.user != request.user: - messages.error( - request, 'You can only access your own workouts on the NK Logbook, not those of your athletes') - url = reverse('workout_stravaimport_view', - kwargs={'userid': request.user.id}) - return HttpResponseRedirect(url) - - strava_integration = importsources['strava'](request.user) - try: - _ = strava_integration.open() - except NoTokenError: # pragma: no cover - return HttpResponseRedirect("/rowers/me/stravaauthorize/") - - workouts = strava_integration.get_workout_list() - - if request.method == "POST": - try: # pragma: no cover - tdict = dict(request.POST.lists()) - ids = tdict['workoutid'] - stravaids = [int(id) for id in ids] - alldata = {} - - for stravaid in stravaids: - res = strava_integration.get_workout(id) - - # done, redirect to workouts list - messages.info(request, - 'Your Strava workouts will be imported in the background.' - ' It may take a few minutes before they appear.') - url = reverse('workouts_view') - return HttpResponseRedirect(url) - except KeyError: # pragma: no cover - pass - - breadcrumbs = [ - { - 'url': '/rowers/list-workouts/', - 'name': 'Workouts' - }, - { - 'url': reverse('workout_stravaimport_view'), - 'name': 'Strava' - }, - ] - - checknew = request.GET.get('selectallnew', False) - - # 2022-10-24 sorting the results - workouts = sorted(workouts, key = lambda d:d['starttime'], reverse=True) - - return render(request, 'list_import.html', - {'workouts': workouts, - 'rower': r, - 'active': 'nav-workouts', - 'breadcrumbs': breadcrumbs, - 'teams': get_my_teams(request.user), - 'checknew': checknew, - 'integration': 'Strava' - }) # for Strava webhook request validation @@ -1122,261 +1001,24 @@ def workout_polarimport_view(request, userid=0): # pragma: no cover 'teams': get_my_teams(request.user), }) - -# The page where you select which SportTracks workout to import -@login_required() -@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 = importsources['sporttracks'](request.user) - try: - _ = st_integration.open() - except NoTokenError: - return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") - - workouts = st_integration.get_workout_list() - - r = getrower(request.user) - - if request.method == "POST": - try: # pragma: no cover - tdict = dict(request.POST.lists()) - ids = tdict['workoutid'] - stids = [int(id) for id in ids] - alldata = {} - - for id in stids: - res = st_integration.get_workout(id) - - # done, redirect to workouts list - messages.info(request, - 'Your SportTracks workouts will be imported in the background.' - ' It may take a few minutes before they appear.') - url = reverse('workouts_view') - return HttpResponseRedirect(url) - except KeyError: # pragma: no cover - pass - - breadcrumbs = [ - { - 'url': '/rowers/list-workouts/', - 'name': 'Workouts' - }, - { - 'url': reverse('workout_sporttracksimport_view'), - 'name': 'SportTracks' - }, - ] - - checknew = request.GET.get('selectallnew', False) - - - return render(request, 'list_import.html', - {'workouts': workouts, - 'breadcrumbs': breadcrumbs, - 'active': 'nav-workouts', - 'rower': r, - 'teams': get_my_teams(request.user), - 'integration':'SportTracks', - 'checknew': checknew, - }) - - return HttpResponse(res) # pragma: no cover - -# List of workouts on Concept2 logbook. This view only used for debugging - - - -# Import all unknown workouts available on Concept2 logbook -@login_required() -def workout_getc2workout_all(request, page=1, message=""): # pragma: no cover - r = getrequestrower(request) - c2_integration = importsources['c2'](request.user) - try: - _ = c2_integration.open() - except NoTokenError: # pragma: no cover - return HttpResponseRedirect("/rowers/me/c2authorize/") - - result = c2_integration.get_workouts(page=page) - - if result: - messages.info( - request, 'Your C2 workouts will be imported in the coming few minutes') - else: - messages.error(request, 'Your C2 workouts import failed') - - url = reverse('workouts_view') - return HttpResponseRedirect(url) - - -@login_required() -def workout_getrp3workout_all(request): # pragma: no cover - try: - _ = rp3_open(request.user) - except NoTokenError: # pragma: no cover - return HttpResponseRedirect("/rowers/me/rp3authorize/") - - r = getrequestrower(request) - - rp3_integration = importsources['rp3'](request.user) - result = rp3_integration.get_workouts() - - if result: - messages.info( - request, 'Your RP3 workouts will be imported in the coming few minutes') - else: - messages.error(request, 'Your RP3 workouts import failed') - - url = reverse('workouts_view') - return HttpResponseRedirect(url) - -# List of workouts available on Concept2 logbook - for import -@login_required() -@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_c2import_view(request, page=1, userid=0, message=""): - - rower = getrequestrower(request, userid=userid) - if rower.user != request.user: - messages.error( - request, 'You can only access your own workouts on the Concept2 Logbook, not those of your athletes') - url = reverse('workout_c2import_view', kwargs={ - 'userid': request.user.id}) - return HttpResponseRedirect(url) - - c2_integration = importsources['c2'](request.user) - try: - _ = c2_integration.open() - except NoTokenError: # pragma: no cover - return HttpResponseRedirect("/rowers/me/c2authorize/") - - workouts = c2_integration.get_workout_list(page=1) - - - if request.method == "POST": - try: # pragma: no cover - tdict = dict(request.POST.lists()) - ids = tdict['workoutid'] - c2ids = [int(id) for id in ids] - - for c2id in c2ids: - c2_integration.get_workout(c2id) - # done, redirect to workouts list - messages.info( - request, - 'Your Concept2 workouts will be imported in the background.' - ' It may take a few minutes before they appear.') - url = reverse('workouts_view') - return HttpResponseRedirect(url) - except KeyError: # pragma: no cover - pass - - breadcrumbs = [ - { - 'url': '/rowers/list-workouts/', - 'name': 'Workouts' - }, - { - 'url': reverse('workout_c2import_view'), - 'name': 'Concept2' - }, - { - 'url': reverse('workout_c2import_view', kwargs={'page': page}), - 'name': 'Page '+str(page) - } - ] - - rower = getrower(request.user) - - checknew = request.GET.get('selectallnew', False) - - return render(request, - 'list_import.html', - {'workouts': workouts, - 'rower': rower, - 'active': 'nav-workouts', - 'breadcrumbs': breadcrumbs, - 'teams': get_my_teams(request.user), - 'page': page, - 'checknew': checknew, - 'integration': 'C2 Logbook' - }) - - -importlistviews = { - 'c2': 'workout_c2import_view', - 'strava': 'workout_stravaimport_view', - 'polar': 'workout_polarimport_view', - 'ownapi': 'workout_view', - 'sporttracks': 'workout_sporttracksimport_view', - 'trainingpeaks': 'workout_view', - 'nk': 'workout_nkimport_view', - 'rp3': 'workout_rp3import_view', -} - importauthorizeviews = { - 'c2': 'rower_c2_authorize', - 'strava': 'rower_strava_authorize', + 'c2': 'rower_integration_authorize', + 'strava': 'rower_integration_authorize', 'polar': 'rower_polar_authorize', 'ownapi': 'workout_view', - 'sporttracks': 'rower_sporttracks_authorize', - 'trainingpeaks': 'rower_tp_authorize', - 'nk': 'rower_nk_authorize', - 'rp3': 'rower_rp3_authorize', + 'sporttracks': 'rower_integration_authorize', + 'trainingpeaks': 'rower_integration_authorize', + 'nk': 'rower_integration_authorize', + 'rp3': 'rower_integration_authorize', } - - -@login_required() -def workout_getimportview_old(request, externalid, source='c2', do_async=True): - if 'startdate' in request.session and source == 'nk': # pragma: no cover - startdate = request.session.get('startdate') - enddate = request.session.get('enddate') - - try: - result = importsources[source].get_workout(request.user, externalid, do_async=do_async, - startdate=startdate, enddate=enddate) - except NoTokenError: - return HttpResponseRedirect(reverse(importauthorizeviews[source])) - - url = reverse(importlistviews[source]) - return HttpResponseRedirect(url) - try: - result = importsources[source].get_workout(request.user, externalid, - do_async=do_async) - except NoTokenError: - - return HttpResponseRedirect(reverse(importauthorizeviews[source])) - - if result: # pragma: no cover - messages.info( - request, "Your workout will be imported in the background") - # this should return to the respective import list page - else: # pragma: no cover - messages.error(request, 'Error getting the workout') - - url = reverse(importlistviews[source]) - return HttpResponseRedirect(url) - - -# Imports all new workouts from SportTracks -@login_required() -def workout_getsporttracksworkout_all(request): - st_integration = importsources['sporttracks'](request.user) - st_integration.get_workouts() - messages.info(request,"Your SportTracks workouts will be imported in the background") - - url = reverse('workouts_view') - return HttpResponseRedirect(url) - - @login_required() def workout_getimportview(request, externalid, source='c2', do_async=True): try: integration = importsources[source](request.user) except (TypeError, NotImplementedError, KeyError): - return workout_getimportview_old(request, externalid, source=source, do_async=True) + return reverse("workouts_view") if 'startdate' in request.session and source == 'nk': # pragma: no cover startdate = request.session.get('startdate') enddate = request.session.get('enddate') @@ -1385,14 +1027,14 @@ def workout_getimportview(request, externalid, source='c2', do_async=True): try: result = integration.get_workout(externalid, startdate=startdate, enddate=enddate) except NoTokenError: - return HttpResponseRedirect(reverse(importauthorizeviews[source])) + return HttpResponseRedirect(reverse(importauthorizeviews[source],kwargs={'source':source})) url = reverse(importlistviews[source]) return HttpResponseRedirect(url) try: result = integration.get_workout(externalid) except NoTokenError: - return HttpResponseRedirect(reverse(importauthorizeviews[source])) + return HttpResponseRedirect(reverse(importauthorizeviews[source],kwargs={'source':source})) if result: # pragma: no cover messages.info( @@ -1401,7 +1043,7 @@ def workout_getimportview(request, externalid, source='c2', do_async=True): else: # pragma: no cover messages.error(request, 'Error getting the workout') - url = reverse(importlistviews[source]) + url = reverse("workout_import_view", kwargs={'source':source}) return HttpResponseRedirect(url)