This is still experimental and there are known bugs. Use at your own risk. Nothing is stored permanently until you hit Save in the Updated Summary section. You can use the restore original button to restore the original values.
-
-
-
Interval Shorthand How-To
This is a quick way to enter the intervals using a special mini-language.
You enter something like 8x500m/3min, press "Update" and the site will interpret this for you and update the summary on the right. If you're happy with the result, press the green Save button to update the values. Nothing will be changed permanently until you hit Save.
diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py
index 1227ff68..1f46d518 100644
--- a/rowers/views/workoutviews.py
+++ b/rowers/views/workoutviews.py
@@ -6425,133 +6425,9 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
}
powerupdateform = PowerIntervalUpdateForm(initial=cd)
form = SummaryStringForm(initial={'intervalstring':intervalString})
-
-
-
- # we are saving the results obtained from the detailed form
- elif request.method == 'POST' and "savedetailform" in request.POST: # pragma: no cover
- savebutton = 'savedetailform'
- form = SummaryStringForm()
- nrintervals = int(request.POST['nrintervals'])
- detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
- itime = []
- idist = []
- itype = []
- ivalues = []
- iunits = []
- itypes = []
- iresults = []
- for i in range(nrintervals):
- try:
- t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S.%f")
- except ValueError:
- t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S")
-
- timesecs = 3600*t.hour+60*t.minute+t.second+t.microsecond/1.e6
- itime += [timesecs]
- idist += [int(request.POST['intervald_%s' % i])]
- itype += [int(request.POST['type_%s' % i])]
-
- if itype[i] == 3: # rest
- itypes += ['rest']
- ivalues += [timesecs]
- iresults += [idist[i]]
- iunits += ['seconds']
- if itype[i] == 5 or itype[i] == 2: # distance based work
- itypes += ['work']
- ivalues += [idist[i]]
- iresults += [timesecs]
- iunits += ['meters']
- if itype[i] == 4 or itype[i] == 1: # time based work
- itypes += ['work']
- ivalues += [timesecs]
- iresults += [idist[i]]
- iunits += ['seconds']
-
-
- rowdata.updateintervaldata(ivalues,iunits,itypes,iresults=iresults)
- intervalstats = rowdata.allstats()
- row.summary = intervalstats
- try:
- row.notes += "\n"+s
- except TypeError:
- pass
-
- row.save()
- rowdata.write_csv(f1,gzip=True)
- dataprep.update_strokedata(encoder.decode_hex(id),rowdata.df)
- messages.info(request,"Updated interval data saved")
-
- form = SummaryStringForm()
- powerupdateform = PowerIntervalUpdateForm(initial={
- 'power': int(normp),
- 'pace': avpace,
- 'selector': 'power',
- 'work': int(normw),
- 'spm': int(normspm),
- 'activeminutesmin': 0,
- 'activeminutesmax': activeminutesmax,
- })
-
-
- # we are processing the details form
- elif request.method == 'POST' and "nrintervals" in request.POST: # pragma: no cover
- savebutton = 'savedetailform'
- nrintervals = int(request.POST['nrintervals'])
- detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
- if detailform.is_valid():
- cd = detailform.cleaned_data
- itime = []
- idist = []
- itype = []
- ivalues = []
- iunits = []
- itypes = []
- iresults = []
- for i in range(nrintervals):
- t = cd['intervalt_%s' % i]
- timesecs = t.total_seconds()
- itime += [timesecs]
- idist += [cd['intervald_%s' % i]]
- itype += [cd['type_%s' % i]]
-
- if itype[i] == '3': # rest
- itypes += ['rest']
- ivalues += [timesecs]
- iresults += [idist[i]]
- iunits += ['seconds']
- if itype[i] == '5' or itype[i] == '2': # distance based work
- itypes += ['work']
- ivalues += [idist[i]]
- iresults += [timesecs]
- iunits += ['meters']
- if itype[i] == '4' or itype[i] == '1': # time based work
- itypes += ['work']
- ivalues += [timesecs]
- iresults += [idist[i]]
- iunits += ['seconds']
-
- rowdata.updateintervaldata(ivalues,iunits,
- itypes,iresults=iresults)
- intervalstats = rowdata.allstats()
-
-
- form = SummaryStringForm()
- powerupdateform = PowerIntervalUpdateForm()
- initial = {}
- for i in range(nrintervals):
- try:
- initial['intervald_%s' % i] = idist[i]
- initial['intervalt_%s' % i] = get_time(itime[i])
- initial['type_%s' % i] = itype[i]
- except IndexError: # pragma: no cover
- pass
-
-
- detailform = IntervalUpdateForm(aantal=nrintervals,initial=initial)
# create interactive plot
try:
@@ -6576,7 +6452,6 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
'activeminutesmax':activeminutesmax,
'activeminutesmin':activeminutesmin,
'maxminutes': maxminutes,
- 'detailform':detailform,
'powerupdateform':powerupdateform,
'workout':row,
'rower':r,
From 06c50cedfe516a46f3b5685aa625f251398c7d06 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Mon, 10 May 2021 21:16:07 +0200
Subject: [PATCH 07/12] recognizing images / json
---
rowers/dataprep.py | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index 66e63a01..afe94e76 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -2013,6 +2013,16 @@ def new_workout_from_file(r, f2,
return -1, message, f2
# Some people try to upload Concept2 logbook summaries
+ if fileformat == 'imageformat':
+ os.remove(f2)
+ message = "You cannot upload image files here"
+ return (0, message, f2)
+
+ if fileformat == 'json':
+ os.remove(f2)
+ message = "JSON format not supported in direct upload"
+ return (0, message, f2)
+
if fileformat == 'c2log':
os.remove(f2)
message = "This summary does not contain stroke data. Use the files containing stroke by stroke data."
From f03e31e74b33d40c7c4e86bfb2bd6863f40eb1e0 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Mon, 10 May 2021 21:34:32 +0200
Subject: [PATCH 08/12] recognizing img files
---
rowers/rows.py | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/rowers/rows.py b/rowers/rows.py
index b5b8d854..8f1c3643 100644
--- a/rowers/rows.py
+++ b/rowers/rows.py
@@ -68,7 +68,8 @@ def validate_file_extension(value):
ext = os.path.splitext(value.name)[1]
valid_extensions = ['.tcx','.csv','.TCX','.gpx','.GPX',
'.CSV','.fit','.FIT','.zip','.ZIP',
- '.gz','.GZ','.xls']
+ '.gz','.GZ','.xls',
+ '.jpg','.jpeg','.tiff','.png','.gif','.bmp']
if not ext in valid_extensions: # pragma: no cover
raise ValidationError(u'File not supported!')
From 2235b28cd589bc05bd1728a2190354f57d4e0474 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Tue, 11 May 2021 18:19:22 +0200
Subject: [PATCH 09/12] c2 stuff now using timezone info
---
rowers/c2stuff.py | 27 ++++++++++++++++-----------
rowers/dataprep.py | 4 ++++
rowers/stravastuff.py | 2 +-
rowers/tests/mocks.py | 8 +++++++-
rowers/tests/test_imports.py | 15 +++++++++++++++
rowers/views/importviews.py | 1 +
6 files changed, 44 insertions(+), 13 deletions(-)
diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py
index 496cc8d7..4c9f6506 100644
--- a/rowers/c2stuff.py
+++ b/rowers/c2stuff.py
@@ -1076,20 +1076,21 @@ def add_workout_from_data(user,importid,data,strokedata,
except: # pragma: no cover
comments = ' '
- try:
- thetimezone = tz(data['timezone'])
- except:
- thetimezone = 'UTC'
+
+ thetimezone = pytz.timezone(data['timezone'])
+
r = Rower.objects.get(user=user)
try:
rowdatetime = iso8601.parse_date(data['date_utc'])
+ thetimezone = 'UTC'
except KeyError: # pragma: no cover
rowdatetime = iso8601.parse_date(data['start_date'])
+ rowdatetime = rowdatetime.make_aware(thetimezone)
except ParseError: # pragma: no cover
rowdatetime = iso8601.parse_date(data['date'])
-
+ rowdatetime = rowdatetime.make_aware(thetimezone)
try:
@@ -1119,7 +1120,9 @@ def add_workout_from_data(user,importid,data,strokedata,
cum_time = res[0]
lapidx = res[1]
- starttimeunix = starttimeunix - cum_time.max()
+ totaltime = data['time']/10.
+ starttimeunix = starttimeunix - totaltime
+
unixtime = cum_time+starttimeunix
# unixtime[0] = starttimeunix
@@ -1161,7 +1164,6 @@ def add_workout_from_data(user,importid,data,strokedata,
velo = 1000./pace
pace = 500./velo
-
# save csv
# Create data frame with all necessary data to write to csv
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
@@ -1223,15 +1225,18 @@ def add_workout_from_data(user,importid,data,strokedata,
w = Workout.objects.get(id=id)
+ local_tz = pytz.timezone(data['timezone'])
+# local_tz = pytz.timezone(thetimezone)
+
+ w.startdatetime = w.startdatetime.astimezone(local_tz)
+ w.starttime = w.startdatetime.strftime('%H:%M:%S')
+ w.timezone = local_tz
w.duration = dataprep.totaltime_sec_to_string(totaltime)
w.distance = totaldist
- w.startdatetime = rowdatetime
- w.starttime = rowdatetime.time()
- w.date = rowdatetime.date()
+
w.save()
-
return id,message
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index afe94e76..f55ff83e 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -1692,6 +1692,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
+
try:
latavg = row.df[' latitude'].mean()
lonavg = row.df[' longitude'].mean()
@@ -1717,6 +1718,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
except KeyError:
timezone_str = r.defaulttimezone
+
duration = totaltime_sec_to_string(totaltime)
workoutdate = workoutstartdatetime.astimezone(
@@ -1785,6 +1787,8 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
except ValidationError:
return (0,'Unable to create your workout')
+
+
if privacy == 'visible':
ts = Team.objects.filter(rower=r)
for t in ts:
diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py
index 8e9b7ebc..93d865ae 100644
--- a/rowers/stravastuff.py
+++ b/rowers/stravastuff.py
@@ -330,7 +330,7 @@ def create_async_workout(alldata,user,stravaid,debug=False):
starttime = rowdatetime.astimezone(
pytz.timezone(thetimezone)
- ).strftime('%H:%m:%S')
+ ).strftime('%H:%M:%S')
totaltime = data['elapsed_time']
duration = dataprep.totaltime_sec_to_string(totaltime)
diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py
index 8c0d1f51..891aa3ac 100644
--- a/rowers/tests/mocks.py
+++ b/rowers/tests/mocks.py
@@ -713,6 +713,9 @@ def mocked_requests(*args, **kwargs):
with open('rowers/tests/testdata/c2jsonworkoutdata.txt','r') as infile:
c2workoutdata = json.load(infile)
+ with open('rowers/tests/testdata/c2_timezone.json','r') as infile:
+ c2timezoneworkoutdata = json.load(infile)
+
with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile:
c2strokedata = json.load(infile)
@@ -1181,7 +1184,10 @@ def mocked_requests(*args, **kwargs):
if c2strokestester.match(args[0]):
return MockResponse(c2strokedata,200)
elif c2importtester.match(args[0]):
- return MockResponse(c2workoutdata,200)
+ if '12' in args[0]:
+ return MockResponse(c2workoutdata,200)
+ else:
+ return MockResponse(c2timezoneworkoutdata,200)
elif c2workoutlisttester.match(args[0]):
return MockResponse(c2workoutlist,200)
elif 'access_token' in args[0]:
diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py
index 233ad051..d9ddabc0 100644
--- a/rowers/tests/test_imports.py
+++ b/rowers/tests/test_imports.py
@@ -261,6 +261,21 @@ class C2Objects(DjangoTestCase):
self.assertEqual(response.status_code, 200)
+ @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests)
+ @patch('rowers.dataprep.create_engine')
+ def test_c2_import_tz(self, mock_get, mocked_sqlalchemy):
+
+ response = self.c.get('/rowers/workout/c2import/22/',follow=True)
+
+ self.assertRedirects(response,
+ expected_url='/rowers/workout/'+encoded2+'/edit/',
+ status_code=302,target_status_code=200)
+
+ self.assertEqual(response.status_code, 200)
+
+ w = Workout.objects.get(id=2)
+ self.assertEqual(w.timezone,'Europe/Prague')
+
@patch('rowers.dataprep.create_engine')
def test_strokedata(self, mocked_sqlalchemy):
diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py
index 1993490b..08922a89 100644
--- a/rowers/views/importviews.py
+++ b/rowers/views/importviews.py
@@ -2099,6 +2099,7 @@ def workout_getimportview(request,externalid,source = 'c2',do_async=False):
+
workoutdate = startdatetime.astimezone(
pytz.timezone(timezone_str)
).strftime('%Y-%m-%d')
From 4afaa5fd10519a23fdf87f6156ef88a2a6d58e57 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Wed, 12 May 2021 06:52:53 +0200
Subject: [PATCH 10/12] testing c2 import
---
rowers/c2stuff.py | 3 +++
rowers/dataprep.py | 4 ++--
rowers/forms.py | 26 --------------------------
rowers/templatetags/rowerfilters.py | 4 ++--
rowers/tests/mocks.py | 6 ++++++
rowers/tests/test_imports.py | 18 ++++++++++++++++++
rowers/utils.py | 14 +++++++-------
rowers/views/statements.py | 4 ++--
8 files changed, 40 insertions(+), 39 deletions(-)
diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py
index 4c9f6506..503dd850 100644
--- a/rowers/c2stuff.py
+++ b/rowers/c2stuff.py
@@ -848,6 +848,9 @@ def get_workout(user,c2id,do_async=False):
data = s.json()['data']
splitdata = None
+ #with open('c2temp.json','w') as f:
+ # f.write(json.dumps(s.json()))
+ # print(s.json())
if 'workout' in data:
if 'splits' in data['workout']: # pragma: no cover
diff --git a/rowers/dataprep.py b/rowers/dataprep.py
index f55ff83e..2711a35d 100644
--- a/rowers/dataprep.py
+++ b/rowers/dataprep.py
@@ -2017,12 +2017,12 @@ def new_workout_from_file(r, f2,
return -1, message, f2
# Some people try to upload Concept2 logbook summaries
- if fileformat == 'imageformat':
+ if fileformat == 'imageformat': # pragma: no cover
os.remove(f2)
message = "You cannot upload image files here"
return (0, message, f2)
- if fileformat == 'json':
+ if fileformat == 'json': # pragma: no cover
os.remove(f2)
message = "JSON format not supported in direct upload"
return (0, message, f2)
diff --git a/rowers/forms.py b/rowers/forms.py
index c1957690..76d00219 100644
--- a/rowers/forms.py
+++ b/rowers/forms.py
@@ -994,32 +994,6 @@ class PowerIntervalUpdateForm(forms.Form):
activeminutesmin = forms.IntegerField(required=False,initial=0,widget=forms.HiddenInput())
activeminutesmax = forms.IntegerField(required=False,initial=0,widget=forms.HiddenInput())
-# Form used to update interval stats
-class IntervalUpdateForm(forms.Form):
-
- def __init__(self, *args, **kwargs):
- typechoices = (
- (1,'single time'),
- (2,'single distance'),
- (3,'rest (time based)'),
- (3,'rest (distance based)'),
- (4,'work (time based)'),
- (5,'work (distance based)'),
- )
- aantal = int(kwargs.pop('aantal'))
- super(IntervalUpdateForm, self).__init__(*args, **kwargs)
-
- for i in range(aantal):
- self.fields['intervalt_%s' % i] = forms.DurationField(label='Time '+str(i+1))
- self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1))
- self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices,
- required=True,
- initial=4,
- label = 'Type '+str(i+1))
- self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
- self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
- self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;'
- self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f')
boattypes = mytypes.boattypes
workouttypes = mytypes.workouttypes
diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py
index 3c7a1624..2ee4bf9d 100644
--- a/rowers/templatetags/rowerfilters.py
+++ b/rowers/templatetags/rowerfilters.py
@@ -559,7 +559,7 @@ def iterrows(df): # pragma: no cover
return df.iterrows()
@register.filter(name='times')
-def times(number):
+def times(number): # pragma: no cover
return range(number)
@register.simple_tag
@@ -567,7 +567,7 @@ def get_df_iloc(data,i,j): # pragma: no cover
return data.iloc(i,j)
@register.simple_tag
-def get_field_id(id,s,form):
+def get_field_id(id,s,form): # pragma: no cover
field_name = s+str(id)
return form.__getitem__(field_name)
diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py
index 891aa3ac..66ba56bf 100644
--- a/rowers/tests/mocks.py
+++ b/rowers/tests/mocks.py
@@ -716,6 +716,10 @@ def mocked_requests(*args, **kwargs):
with open('rowers/tests/testdata/c2_timezone.json','r') as infile:
c2timezoneworkoutdata = json.load(infile)
+ with open('rowers/tests/testdata/c2_timezone2.json','r') as infile:
+ c2timezoneworkoutdata2 = json.load(infile)
+
+
with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile:
c2strokedata = json.load(infile)
@@ -1186,6 +1190,8 @@ def mocked_requests(*args, **kwargs):
elif c2importtester.match(args[0]):
if '12' in args[0]:
return MockResponse(c2workoutdata,200)
+ elif '31' in args[0]:
+ return MockResponse(c2timezoneworkoutdata2,200)
else:
return MockResponse(c2timezoneworkoutdata,200)
elif c2workoutlisttester.match(args[0]):
diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py
index d9ddabc0..cd4640a3 100644
--- a/rowers/tests/test_imports.py
+++ b/rowers/tests/test_imports.py
@@ -276,6 +276,24 @@ class C2Objects(DjangoTestCase):
w = Workout.objects.get(id=2)
self.assertEqual(w.timezone,'Europe/Prague')
+ @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests)
+ @patch('rowers.dataprep.create_engine')
+ def test_c2_import_tz2(self, mock_get, mocked_sqlalchemy):
+
+ response = self.c.get('/rowers/workout/c2import/31/',follow=True)
+
+ self.assertRedirects(response,
+ expected_url='/rowers/workout/'+encoded2+'/edit/',
+ status_code=302,target_status_code=200)
+
+ self.assertEqual(response.status_code, 200)
+
+ w = Workout.objects.get(id=2)
+ self.assertEqual(w.timezone,'Europe/Amsterdam')
+
+ self.assertEqual(w.starttime.strftime("%H:%M:%S"),"20:04:56")
+
+
@patch('rowers.dataprep.create_engine')
def test_strokedata(self, mocked_sqlalchemy):
diff --git a/rowers/utils.py b/rowers/utils.py
index 4330767b..defdd0af 100644
--- a/rowers/utils.py
+++ b/rowers/utils.py
@@ -699,7 +699,7 @@ def step_to_time_dist(step,avgspeed = 3.2,ftp=200,ftspm=25,ftv=3.7):
rscore = 100.*(avgpower/ftp)*seconds/3600.
- if targettype == 'Cadence':
+ if targettype == 'Cadence': # pragma: no cover
value = step.get('targetValue',0)
valuelow = step.get('targetValueLow',0)
valuehigh = step.get('targetValueHigh',0)
@@ -1166,26 +1166,26 @@ def request_is_ajax(request):
return is_ajax
def intervals_to_string(vals, units, typ):
- if vals is None or units is None or typ is None:
+ if vals is None or units is None or typ is None: # pragma: no cover
return ''
- if len(vals) != len(units) or len(vals) != len(typ):
+ if len(vals) != len(units) or len(vals) != len(typ): # pragma: no cover
return ''
s = ''
previous = 'rest'
for i in range(len(vals)):
if typ[i] == 'rest' and previous == 'rest':
- if units[i] == 'min':
+ if units[i] == 'min': # pragma: no cover
val = int(vals[i])*60
unit = 'sec'
else:
val = int(vals[i])
- if units[i] == 'meters':
+ if units[i] == 'meters': # pragma: no cover
unit = 'm'
if units[i] == 'seconds':
unit = 'sec'
s += '+0min/{val}{unit}'.format(val=val,unit=unit)
- elif typ[i] == 'rest':
+ elif typ[i] == 'rest': # pragma: no cover
if units[i] == 'min':
val = int(vals[i])*60
unit = 'sec'
@@ -1197,7 +1197,7 @@ def intervals_to_string(vals, units, typ):
unit = 'sec'
s += '/{val}{unit}'.format(val=val,unit=unit)
previous = 'rest'
- else: # work interval
+ else: # pragma: no cover # work interval
if units[i] == 'min':
val = int(vals[i])*60
unit = 'sec'
diff --git a/rowers/views/statements.py b/rowers/views/statements.py
index 67f62298..b74f1616 100644
--- a/rowers/views/statements.py
+++ b/rowers/views/statements.py
@@ -91,7 +91,7 @@ from django.utils.datastructures import MultiValueDictKeyError
from django.utils import timezone,translation
from django.core.mail import send_mail, BadHeaderError
from rowers.forms import (
- SummaryStringForm,IntervalUpdateForm,StrokeDataForm,
+ SummaryStringForm,StrokeDataForm,
StatsOptionsForm,PredictedPieceForm,DateRangeForm,DeltaDaysForm,
FitnessMetricForm,PredictedPieceFormNoDistance,
EmailForm, RegistrationForm, RegistrationFormTermsOfService,
@@ -1161,7 +1161,7 @@ def get_my_teams(user):
return teams
# Used for the interval editor - translates seconds to a time object
-def get_time(second):
+def get_time(second): # pragma: no cover
if (second<=0) or (second>1e9):
hours = 0
minutes=0
From 4db0c20efa3dfb6c74cac332b1eeea6c5c4be8f5 Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Wed, 12 May 2021 08:52:51 +0200
Subject: [PATCH 11/12] further timezone magic c2
---
rowers/c2stuff.py | 2 +-
rowers/tasks.py | 31 +++++++++++++++----------------
rowers/tests/test_imports.py | 2 ++
rowers/views/workoutviews.py | 11 +++++++++--
4 files changed, 27 insertions(+), 19 deletions(-)
diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py
index 503dd850..d7544dfc 100644
--- a/rowers/c2stuff.py
+++ b/rowers/c2stuff.py
@@ -238,7 +238,7 @@ def create_async_workout(alldata,user,c2id):
duration = dataprep.totaltime_sec_to_string(totaltime)
try:
- timezone_str = tz(data['timezone'])
+ timezone_str = data['timezone']
except:
timezone_str = 'UTC'
diff --git a/rowers/tasks.py b/rowers/tasks.py
index fdaf22fe..9bfb8d28 100644
--- a/rowers/tasks.py
+++ b/rowers/tasks.py
@@ -419,7 +419,7 @@ def handle_c2_import_stroke_data(c2token,
duration = datetime.datetime.strptime(duration,'%H:%M:%S.%f').time()
try:
- timezone_str = tz(workoutdata['timezone'])
+ timezone_str = workoutdata['timezone']
except:
timezone_str = 'UTC'
@@ -2991,7 +2991,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
c2id = data['id']
workouttype = data['type']
verified = data['verified']
- startdatetime = iso8601.parse_date(data['date'])
+ startdatetime = iso8601.parse_date(data['date_utc'])
weightclass = data['weight_class']
try:
@@ -3013,21 +3013,18 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
totaltime = data['time']/10.
duration = totaltime_sec_to_string(totaltime)
+ starttimeunix = arrow.get(startdatetime).timestamp()-totaltime
+ startdatetime = arrow.get(starttimeunix)
- try:
- timezone_str = tz(data['timezone'])
- except:
- timezone_str = defaulttimezone
+ timezone = pytz.timezone(data['timezone'])
+ startdatetime = startdatetime.astimezone(timezone)
- startdatetime = startdatetime.replace(tzinfo=None)
- tz = pytz.timezone(timezone_str)
- startdatetime = tz.localize(startdatetime)
workoutdate = startdatetime.astimezone(
- pytz.timezone(timezone_str)
+ timezone
).strftime('%Y-%m-%d')
starttime = startdatetime.astimezone(
- pytz.timezone(timezone_str)
+ timezone
).strftime('%H:%M:%S')
try:
@@ -3056,8 +3053,6 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
cum_time = res[0]
lapidx = res[1]
- starttimeunix = arrow.get(startdatetime).timestamp()
- starttimeunix = starttimeunix-cum_time.max()
unixtime = cum_time+starttimeunix
# unixtime[0] = starttimeunix
@@ -3134,6 +3129,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
'workouttype':workouttype,
'boattype':'1x',
'c2id':c2id,
+ 'timezone':str(timezone)
}
session = requests.session()
@@ -3165,8 +3161,11 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
parkedids = []
with open('c2blocked.json','r') as c2blocked:
- jsondata = json.load(c2blocked)
- parkedids = jsondata['ids']
+ try:
+ jsondata = json.load(c2blocked)
+ parkedids = jsondata['ids']
+ except JSONDecodeError:
+ parkedids = []
newparkedids = [id for id in parkedids if id != newc2id]
with open('c2blocked.json','wt') as c2blocked:
@@ -3364,7 +3363,7 @@ def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debu
comments = ' '
try:
- thetimezone = tz(workoutsummary['timezone'])
+ thetimezone = workoutsummary['timezone']
except:
thetimezone = 'UTC'
diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py
index cd4640a3..bfef0eee 100644
--- a/rowers/tests/test_imports.py
+++ b/rowers/tests/test_imports.py
@@ -158,6 +158,7 @@ class C2Objects(DjangoTestCase):
self.r.c2token = '12'
self.r.c2refreshtoken = 'ab'
self.r.tokenexpirydate = arrow.get(datetime.datetime.now()+datetime.timedelta(days=1)).datetime
+ self.r.defaulttimezone = 'Europe/Prague'
self.r.save()
self.c.login(username='john',password='koeinsloot')
@@ -342,6 +343,7 @@ class C2Objects(DjangoTestCase):
res = tasks.handle_c2_async_workout(alldata,self.u.id,self.r.c2token,33991243,0,self.r.defaulttimezone)
self.assertEqual(res,1)
+
@override_settings(TESTING=True)
class C2ObjectsTokenExpired(DjangoTestCase):
def setUp(self):
diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py
index 1f46d518..0767310c 100644
--- a/rowers/views/workoutviews.py
+++ b/rowers/views/workoutviews.py
@@ -4813,8 +4813,8 @@ def workout_upload_api(request):
totalDistance = post_data.get('totalDistance',None)
elapsedTime = post_data.get('elapsedTime',None)
summary = post_data.get('summary',None)
-
-
+ timezone = post_data.get('timezone',None)
+
r = None
if form.is_valid():
t = form.cleaned_data['title']
@@ -4905,6 +4905,13 @@ def workout_upload_api(request):
return JSONResponse(status=200,data=message)
w = Workout.objects.get(id=id)
+ if timezone is not None:
+ w.startdatetime = w.startdatetime.astimezone(pytz.timezone(timezone))
+ w.workoutdate = w.startdatetime.strftime('%Y-%m-%d')
+ w.starttime = w.starttime.strftime('%H:%M:%S')
+ w.timezone = timezone
+ w.save()
+
if make_plot: # pragma: no cover
From ae87acc14b52f7765f654d915c8e8f0f925c41db Mon Sep 17 00:00:00 2001
From: Sander Roosendaal
Date: Wed, 12 May 2021 09:28:00 +0200
Subject: [PATCH 12/12] finishing c2 sync
---
rowers/c2stuff.py | 2 +-
rowers/tasks.py | 2 +-
rowers/views/workoutviews.py | 4 ++--
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py
index d7544dfc..28084073 100644
--- a/rowers/c2stuff.py
+++ b/rowers/c2stuff.py
@@ -239,7 +239,7 @@ def create_async_workout(alldata,user,c2id):
try:
timezone_str = data['timezone']
- except:
+ except: # pragma: no cover
timezone_str = 'UTC'
workoutdate = startdatetime.astimezone(
diff --git a/rowers/tasks.py b/rowers/tasks.py
index 9bfb8d28..b4d9b3b2 100644
--- a/rowers/tasks.py
+++ b/rowers/tasks.py
@@ -3164,7 +3164,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
try:
jsondata = json.load(c2blocked)
parkedids = jsondata['ids']
- except JSONDecodeError:
+ except JSONDecodeError: # pragma: no cover
parkedids = []
newparkedids = [id for id in parkedids if id != newc2id]
diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py
index 0767310c..ec44ea1a 100644
--- a/rowers/views/workoutviews.py
+++ b/rowers/views/workoutviews.py
@@ -4814,7 +4814,7 @@ def workout_upload_api(request):
elapsedTime = post_data.get('elapsedTime',None)
summary = post_data.get('summary',None)
timezone = post_data.get('timezone',None)
-
+
r = None
if form.is_valid():
t = form.cleaned_data['title']
@@ -4905,7 +4905,7 @@ def workout_upload_api(request):
return JSONResponse(status=200,data=message)
w = Workout.objects.get(id=id)
- if timezone is not None:
+ if timezone is not None: # pragma: no cover
w.startdatetime = w.startdatetime.astimezone(pytz.timezone(timezone))
w.workoutdate = w.startdatetime.strftime('%Y-%m-%d')
w.starttime = w.starttime.strftime('%H:%M:%S')