From 0e12ba58cd1c85d3999fcd3ff2db822a0a3fabec Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sat, 15 Feb 2025 17:15:45 +0100
Subject: [PATCH 1/2] adding sessions sync
---
rowers/integrations/intervals.py | 69 +++++++++++++++++++++++++++
rowers/templates/plannedsessions.html | 4 ++
rowers/views/planviews.py | 16 +++++++
3 files changed, 89 insertions(+)
diff --git a/rowers/integrations/intervals.py b/rowers/integrations/intervals.py
index 159f0559..5b168f5c 100644
--- a/rowers/integrations/intervals.py
+++ b/rowers/integrations/intervals.py
@@ -560,6 +560,75 @@ class IntervalsIntegration(SyncIntegration):
def token_refresh(self, *args, **kwargs):
return super(IntervalsIntegration, self).token_refresh(*args, **kwargs)
+ def get_plannedsessions(self, *args, **kwargs):
+ try:
+ _ = self.open()
+ except NoTokenError:
+ return []
+
+ r = self.rower
+
+ ids = []
+
+ headers = {
+ 'Authorization': 'Bearer ' + r.intervals_token,
+ }
+
+ oldest = kwargs.get('oldest', (timezone.now()).strftime('%Y-%m-%d'))
+ newest = kwargs.get('newest', (timezone.now() + timedelta(days=7)).strftime('%Y-%m-%d'))
+
+
+ url = self.oauth_data['base_url'] + 'athlete/0/events' #'?category=WORKOUT'
+ url += '?oldest=' + oldest + '&newest=' + newest
+ response = requests.get(url, headers=headers)
+ if response.status_code != 200:
+ return []
+
+ sessions = response.json()
+
+ for session in sessions:
+ localsessions = PlannedSession.objects.filter(intervals_icu_id=session['id'], rower__in=[r])
+ if localsessions.count() == 0:
+ sessiondata = self.get_plannedsession(session['id'])
+ if sessiondata['description'] is None:
+ sessiondata['description'] = ''
+ if sessiondata:
+ timetarget = sessiondata['time_target']
+ if timetarget is None:
+ timetarget = sessiondata['moving_time']
+ if timetarget is None:
+ timetarget = 3600
+ timetarget = int(timetarget)/60.
+ ps = PlannedSession(
+ name=sessiondata['name'],
+ comment=sessiondata['description'],
+ sessionmode='time',
+ sessionvalue=timetarget,
+ startdate=arrow.get(sessiondata['start_date_local']).datetime,
+ enddate=arrow.get(sessiondata['end_date_local']).datetime,
+ preferreddate=arrow.get(sessiondata['start_date_local']).datetime,
+ sessionsport=mytypes.intervalsmappinginv[sessiondata['type']],
+ sessiontype='session',
+ intervals_icu_id=sessiondata['id'],
+ manager=r.user,
+ )
+ ps.save()
+ ps.rower.add(r)
+ if sessiondata['category'].lower() == 'workout':
+ ps.fitfile = sessiondata['fitfile']
+ ps.save()
+ ps.update_steps()
+ if sessiondata['category'].lower() == 'target':
+ ps.sessiontype = 'cycletarget'
+ ps.sessionvalue = int(sessiondata['time_target'])/60.
+ ps.enddate = ps.startdate + datetime.timedelta(days=6)
+ ps.save()
+
+ ids.append(session['id'])
+
+ return ids
+
+
def get_plannedsessions_list(self, *args, **kwargs):
try:
_ = self.open()
diff --git a/rowers/templates/plannedsessions.html b/rowers/templates/plannedsessions.html
index 7f74a3ce..dde17787 100644
--- a/rowers/templates/plannedsessions.html
+++ b/rowers/templates/plannedsessions.html
@@ -39,6 +39,10 @@
+
+ Click here to sync this period with intervals.icu.
+
+
{% if plannedsessions %}
Click on the session name to view, on the circle to attach workouts to the session.
diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py
index 5833c5a5..bf2efbc2 100644
--- a/rowers/views/planviews.py
+++ b/rowers/views/planviews.py
@@ -1455,6 +1455,9 @@ def plannedsessions_view(request,
except PermissionDenied: # pragma: no cover
r = request.user.rower
+ do_intervals_icu_sync = request.GET.get('icu_sync', False)
+
+
if startdatestring: # pragma: no cover
try:
startdate = iso8601.parse_date(startdatestring)
@@ -1475,6 +1478,14 @@ def plannedsessions_view(request,
startdate = startdate.date()
enddate = enddate.date()
+ if do_intervals_icu_sync: # pragma: no cover
+ integration = IntervalsIntegration(request.user)
+ newids = integration.get_plannedsessions(kwargs={'newest':startdate.strftime('%Y-%m-%d'),
+ 'oldest':enddate.strftime('%Y-%m-%d')})
+ for id in newids:
+ messages.info(request, "Session {id} imported from ICU".format(id=id))
+
+
try:
trainingplan = TrainingPlan.objects.filter(
startdate__lte=startdate,
@@ -1573,6 +1584,11 @@ def plannedsessions_view(request,
totals['plannedtrimp'] += ps.sessionvalue
else:
totals['plannedtrimp'] += ps.approximate_rscore*2
+ if ps.intervals_icu_id is None and do_intervals_icu_sync: # pragma: no cover
+ intervals = IntervalsIntegration(request.user)
+ result = intervals.plannedsession_create(ps)
+ messages.info(request, "Session {id} synced to ICU".format(id=ps.id))
+
totals['time'] = int(totals['time']/60.)
totals['actualtime'] = int(totals['actualtime']/60.)
From 8683c5795899e59a0d93b5d8e0b43b23f5c6bb3e Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Sun, 16 Feb 2025 11:29:32 +0100
Subject: [PATCH 2/2] some more icu integrstion
---
rowers/tests/testdata/testdata.tcx.gz | Bin 3989 -> 3989 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/rowers/tests/testdata/testdata.tcx.gz b/rowers/tests/testdata/testdata.tcx.gz
index 0a56fd3394f0b8ddf42433174c37a842757b5634..f16d54bf1f06a73a4723f20143a883bb64991857 100644
GIT binary patch
delta 16
XcmbO#KUJPxzMF$1ao>iG?0x(ID;Nb%
delta 16
XcmbO#KUJPxzMF$1qj>#B_C9_9DS`zF