Merge branch 'release/v16.2.0'
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
from requests_oauthlib import OAuth1Session, OAuth1
|
||||
import hmac
|
||||
import hashlib
|
||||
|
||||
import requests
|
||||
from urllib.parse import quote_plus as rawurlencode
|
||||
|
||||
import logging
|
||||
|
||||
logging.basicConfig()
|
||||
logging.getLogger().setLevel(logging.DEBUG)
|
||||
requests_log = logging.getLogger("requests.packages.urllib3")
|
||||
requests_log.setLevel(logging.DEBUG)
|
||||
requests_log.propagate = True
|
||||
|
||||
|
||||
payload = {
|
||||
'workoutName': '30min at threshold',
|
||||
'sport': 'GENERIC',
|
||||
'description': 'Uploaded from Rowsandall.com',
|
||||
'estimatedDurationInSecs': 1800,
|
||||
'estimatedDistanceInMeters': 6936,
|
||||
'workoutProvider': 'Rowsandall.com',
|
||||
'workoutSourceId': 'Rowsandall.com',
|
||||
'steps': [
|
||||
{
|
||||
'type': 'Step', 'stepOrder': 0,
|
||||
'repeatType': 'Step',
|
||||
'repeatValue': 1,
|
||||
'intensity': 'Active',
|
||||
'description': '0',
|
||||
'durationType': 'TIME',
|
||||
'durationValue': 1800,
|
||||
'durationValueType': '',
|
||||
'targetType': 'Power',
|
||||
'targetValue': 1226,
|
||||
'targetValueLow': 0, 'targetValueHigh': (0,)
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
payload = {}
|
||||
|
||||
oauth_consumer_key = b'ca29ba5e-6868-4468-987d-4ee60a1f04bf'
|
||||
oauth_consumer_secret = b'SKRqjML9mOBV7BcPpN7LsbuDNDtvLOvRiyo'
|
||||
oauth_token = b'79454eab-bf82-4329-9de2-82a6bd911498'
|
||||
oauth_token_secret = b'DihdHJ2ThEdbsyoStpPTEmYh5F52L697HhD'
|
||||
|
||||
authheaders = OAuth1(client_key=oauth_consumer_key,
|
||||
client_secret=oauth_consumer_secret,
|
||||
resource_owner_key=oauth_token,
|
||||
resource_owner_secret=oauth_token_secret,
|
||||
signature_method='HMAC-SHA1',
|
||||
#encoding='base64'
|
||||
)
|
||||
|
||||
|
||||
url = 'https://apis.garmin.com/training-api/workout/'
|
||||
|
||||
response = requests.post(url,payload,auth=authheaders)
|
||||
|
||||
# build base_string
|
||||
base_string1 = b'POST&https%3A%2F%2Fapis.garmin.com%2Ftraining-api%2Fworkout%2F&description%3DUploaded%2520from%2520Rowsandall.com%26estimatedDistanceInMeters%3D6936%26estimatedDurationInSecs%3D1800%26oauth_consumer_key%3Dca29ba5e-6868-4468-987d-4ee60a1f04bf%26oauth_nonce%3D163208869057942765101620205416%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1620205416%26oauth_token%3D79454eab-bf82-4329-9de2-82a6bd911498%26oauth_version%3D1.0%26sport%3DGENERIC%26steps%3Ddescription%26steps%3DdurationType%26steps%3DdurationValue%26steps%3DdurationValueType%26steps%3Dintensity%26steps%3DrepeatType%26steps%3DrepeatValue%26steps%3DstepOrder%26steps%3DtargetType%26steps%3DtargetValue%26steps%3DtargetValueHigh%26steps%3DtargetValueLow%26steps%3Dtype%26workoutName%3D30min%2520at%2520threshold%26workoutProvider%3DRowsandall.com%26workoutSourceId%3DRowsandall.com'
|
||||
|
||||
base_stringa = b'POST&https%3A%2F%2Fapis.garmin.com%2Ftraining-api%2Fworkout%2F&oauth_consumer_key%3Dca29ba5e-6868-4468-987d-4ee60a1f04bf%26oauth_nonce%3D90559685229655402871620208938%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1620208938%26oauth_token%3D79454eab-bf82-4329-9de2-82a6bd911498%26oauth_version%3D1.0'
|
||||
base_string2 = b'POST&https%3A%2F%2Fapis.garmin.com%2Ftraining-api%2Fworkout%2F&oauth_consumer_key%3Dca29ba5e-6868-4468-987d-4ee60a1f04bf%26oauth_nonce%3DIyk9Ambokd2%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1620138340%26oauth_token%3D673806b7-aa7b-4064-8290-2dd1b0236ae6%26oauth_version%3D1.0'
|
||||
|
||||
|
||||
base_string3 = b'POST&https%3A%2F%2Fapis.garmin.com%2Ftraining-api%2Fworkout&oauth_consumer_key%3Dca29ba5e-6868-4468-987d-4ee60a1f04bf%26oauth_nonce%3D90559685229655402871620208938%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1620208938%26oauth_token%3D79454eab-bf82-4329-9de2-82a6bd911498%26oauth_version%3D1.0'
|
||||
|
||||
auth = b'&'.join([oauth_consumer_secret,oauth_token_secret])
|
||||
signingKey = bytes(rawurlencode(oauth_consumer_secret) + "&" + rawurlencode(oauth_token_secret),'utf-8')
|
||||
print(auth)
|
||||
print(signingKey)
|
||||
print(base_string3)
|
||||
|
||||
sig = hmac.new(signingKey, base_string3, hashlib.sha1)
|
||||
|
||||
print(response.status_code)
|
||||
print(response.text)
|
||||
|
||||
|
||||
print(sig.hexdigest().encode())
|
||||
+21
-13
@@ -238,8 +238,8 @@ def create_async_workout(alldata,user,c2id):
|
||||
duration = dataprep.totaltime_sec_to_string(totaltime)
|
||||
|
||||
try:
|
||||
timezone_str = tz(data['timezone'])
|
||||
except:
|
||||
timezone_str = data['timezone']
|
||||
except: # pragma: no cover
|
||||
timezone_str = 'UTC'
|
||||
|
||||
workoutdate = startdatetime.astimezone(
|
||||
@@ -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
|
||||
@@ -1076,20 +1079,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 +1123,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 +1167,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 +1228,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
|
||||
|
||||
+15
-1
@@ -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:
|
||||
@@ -2013,6 +2017,16 @@ def new_workout_from_file(r, f2,
|
||||
return -1, message, f2
|
||||
|
||||
# Some people try to upload Concept2 logbook summaries
|
||||
if fileformat == 'imageformat': # pragma: no cover
|
||||
os.remove(f2)
|
||||
message = "You cannot upload image files here"
|
||||
return (0, message, f2)
|
||||
|
||||
if fileformat == 'json': # pragma: no cover
|
||||
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."
|
||||
@@ -2435,7 +2449,7 @@ def getsmallrowdata_db(columns, ids=[], doclean=True,workstrokesonly=True,comput
|
||||
else:
|
||||
try:
|
||||
df = pd.read_parquet(csvfilenames[0],columns=columns)
|
||||
except (OSError,ArrowInvalid):
|
||||
except (OSError,ArrowInvalid,IndexError):
|
||||
rowdata,row = getrowdata(id=ids[0])
|
||||
if rowdata and len(rowdata.df): # pragma: no cover
|
||||
data = dataprep(rowdata.df,id=ids[0],bands=True,otwpower=True,barchart=True)
|
||||
|
||||
@@ -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
|
||||
|
||||
+4
-13
@@ -2,6 +2,7 @@ from rowers.imports import *
|
||||
import datetime
|
||||
|
||||
import requests
|
||||
from requests import Session, Request
|
||||
from requests_oauthlib import OAuth1,OAuth1Session
|
||||
from requests_oauthlib.oauth1_session import TokenRequestDenied
|
||||
from requests import Request, Session
|
||||
@@ -302,24 +303,14 @@ def ps_to_garmin(ps,r):
|
||||
lijst.append(gstep)
|
||||
|
||||
payload['steps'] = lijst
|
||||
url = 'https://apis.garmin.com/training-api/workout/'
|
||||
|
||||
garmin = OAuth1Session(oauth_data['client_id'],
|
||||
client_secret=oauth_data['client_secret'],
|
||||
resource_owner_key=r.garmintoken,
|
||||
resource_owner_secret=r.garminrefreshtoken,
|
||||
signature_method='HMAC-SHA1'
|
||||
)
|
||||
|
||||
|
||||
url = 'https://apis.garmin.com/training-api/workout/'
|
||||
|
||||
|
||||
garminauth = OAuth1(
|
||||
client_key=oauth_data['client_id'],
|
||||
client_secret=oauth_data['client_secret'],
|
||||
resource_owner_key=r.garmintoken,
|
||||
resource_owner_secret=r.garminrefreshtoken,
|
||||
signature_method='HMAC-SHA1'
|
||||
signature_method='HMAC-SHA1',
|
||||
encoding='base64'
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -571,7 +571,6 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo
|
||||
while d<=enddate:
|
||||
dd = d.strftime('%d')
|
||||
|
||||
|
||||
if totaldays<30:
|
||||
dates.append(d.strftime('%m/%d'))
|
||||
dates_sorting.append(d.strftime('%Y/%m/%d'))
|
||||
@@ -582,6 +581,9 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type',toolbar_lo
|
||||
rscores.append(0)
|
||||
trimps.append(0)
|
||||
links.append('')
|
||||
try:
|
||||
types.append(types[0])
|
||||
except IndexError:
|
||||
types.append('rower')
|
||||
|
||||
try:
|
||||
|
||||
+1
-1
@@ -3158,7 +3158,7 @@ class Workout(models.Model):
|
||||
timezone = models.CharField(default='UTC',
|
||||
choices=timezones,
|
||||
max_length=100)
|
||||
distance = models.IntegerField(default=0,blank=True)
|
||||
distance = models.IntegerField(default=0)
|
||||
duration = models.TimeField(blank=True)
|
||||
dragfactor = models.IntegerField(default=0,blank=True)
|
||||
|
||||
|
||||
+10
-10
@@ -21,7 +21,7 @@ workouttypes_ordered = collections.OrderedDict({
|
||||
'c-boat':'Dutch C boat',
|
||||
'churchboat':'Finnish Church boat',
|
||||
'Ride':'Ride',
|
||||
'Bike':'Bike',
|
||||
'bike':'Bike',
|
||||
'Run':'Run',
|
||||
'NordicSki':'NordicSki',
|
||||
'Swim':'Swim',
|
||||
@@ -36,7 +36,7 @@ workouttypes_ordered = collections.OrderedDict({
|
||||
'Kayaking':'Kayaking',
|
||||
'Workout':'Workout',
|
||||
'Yoga':'Yoga',
|
||||
'bike':'Bike',
|
||||
# 'bike':'Bike',
|
||||
'other':'Other',
|
||||
}
|
||||
)
|
||||
@@ -51,7 +51,7 @@ stravacollection = (
|
||||
('water','Rowing'),
|
||||
('rower','Rowing'),
|
||||
('skierg','NordicSki'),
|
||||
('Bike','Ride'),
|
||||
('bike','Ride'),
|
||||
('bikeerg','Ride'),
|
||||
('dynamic','Rowing'),
|
||||
('slides','Rowing'),
|
||||
@@ -84,7 +84,7 @@ garmincollection = (
|
||||
('water','ROWING'),
|
||||
('rower','INDOOR_ROWING'),
|
||||
('skierg','CROSS_COUNTRY_SKIING'),
|
||||
('Bike','ROAD_BIKING'),
|
||||
('bike','ROAD_BIKING'),
|
||||
('bikeerg','INDOOR_CYCLING'),
|
||||
('dynamic','INDOOR_ROWING'),
|
||||
('slides','INDOOR_ROWING'),
|
||||
@@ -117,7 +117,7 @@ fitcollection = (
|
||||
('water','rowing'),
|
||||
('rower','rowing'),
|
||||
('skierg','cross_country_skiing'),
|
||||
('Bike','cycling'),
|
||||
('bike','cycling'),
|
||||
('bikeerg','cycling'),
|
||||
('dynamic','rowing'),
|
||||
('slides','rowing'),
|
||||
@@ -153,7 +153,7 @@ stcollection = (
|
||||
('water','Rowing'),
|
||||
('rower','Rowing'),
|
||||
('skierg','Skiing:Nordic'),
|
||||
('Bike','Cycling'),
|
||||
('bike','Cycling'),
|
||||
('bikeerg','Cycling'),
|
||||
('dynamic','Rowing'),
|
||||
('slides','Rowing'),
|
||||
@@ -187,7 +187,7 @@ rkcollection = (
|
||||
('water','Rowing'),
|
||||
('rower','Rowing'),
|
||||
('skierg','Cross-Country Skiing'),
|
||||
('Bike','Cycling'),
|
||||
('bike','Cycling'),
|
||||
('bikeerg','Cycling'),
|
||||
('dynamic','Rowing'),
|
||||
('slides','Rowing'),
|
||||
@@ -220,7 +220,7 @@ polarcollection = (
|
||||
('water','Rowing'),
|
||||
('rower','Rowing'),
|
||||
('skierg','Skiing'),
|
||||
('Bike','Cycling'),
|
||||
('bike','Cycling'),
|
||||
('bikeerg','Cycling'),
|
||||
('dynamic','Rowing'),
|
||||
('slides','Rowing'),
|
||||
@@ -253,7 +253,7 @@ tpcollection = (
|
||||
('water','rowing'),
|
||||
('rower','rowing'),
|
||||
('skierg','xc-ski'),
|
||||
('Bike','bike'),
|
||||
('bike','bike'),
|
||||
('Bikeerg','bike'),
|
||||
('dynamic','rowing'),
|
||||
('slides','rowing'),
|
||||
@@ -286,7 +286,7 @@ c2collection = (
|
||||
('water','water'),
|
||||
('rower','rower'),
|
||||
('skierg','skierg'),
|
||||
('Bike','bike'),
|
||||
('bike','bike'),
|
||||
('bikeerg','bike'),
|
||||
('dynamic','dynamic'),
|
||||
('slides','slides'),
|
||||
|
||||
+2
-1
@@ -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!')
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
+13
-14
@@ -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:
|
||||
try:
|
||||
jsondata = json.load(c2blocked)
|
||||
parkedids = jsondata['ids']
|
||||
except JSONDecodeError: # pragma: no cover
|
||||
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'
|
||||
|
||||
|
||||
@@ -111,9 +111,6 @@
|
||||
{% for key,value in formvalues.items %}
|
||||
<input type="hidden" name="{{ key }}" value="{{ value|safe }}">
|
||||
{% endfor %}
|
||||
{% for field in detailform %}
|
||||
{{ field.as_hidden }}
|
||||
{% endfor %}
|
||||
<p>
|
||||
<input type="submit" value="Save">
|
||||
</p>
|
||||
@@ -130,38 +127,6 @@
|
||||
</p>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<h1>Detailed Summary Edit</h1>
|
||||
<p>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.</p>
|
||||
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id|encode }}/editintervals/" method="post">
|
||||
<table width=100%>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>#</th><th>Time</th><th>Distance</th><th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for i in nrintervals|times %}
|
||||
<tr>
|
||||
<td>{{ i }} </td>
|
||||
<td>
|
||||
{% get_field_id i "intervalt_" detailform %}
|
||||
</td>
|
||||
<td>
|
||||
{% get_field_id i "intervald_" detailform %}
|
||||
</td>
|
||||
<td>
|
||||
{% get_field_id i "type_" detailform %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="nrintervals" value={{ nrintervals }}>
|
||||
<input class="button" type="submit" value="Update">
|
||||
</form>
|
||||
</li>
|
||||
<li class="grid_4">
|
||||
<h1 id="howto">Interval Shorthand How-To</h1>
|
||||
<p>This is a quick way to enter the intervals using a special mini-language.</p>
|
||||
<p>You enter something like <em>8x500m/3min</em>, 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.</p>
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -713,6 +713,13 @@ 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/c2_timezone2.json','r') as infile:
|
||||
c2timezoneworkoutdata2 = json.load(infile)
|
||||
|
||||
|
||||
with open('rowers/tests/testdata/c2jsonstrokedata.txt','r') as infile:
|
||||
c2strokedata = json.load(infile)
|
||||
|
||||
@@ -1181,7 +1188,12 @@ def mocked_requests(*args, **kwargs):
|
||||
if c2strokestester.match(args[0]):
|
||||
return MockResponse(c2strokedata,200)
|
||||
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]):
|
||||
return MockResponse(c2workoutlist,200)
|
||||
elif 'access_token' in args[0]:
|
||||
|
||||
@@ -427,7 +427,7 @@ workout bike
|
||||
|
||||
self.assertEqual(len(ws),1)
|
||||
w = ws[0]
|
||||
self.assertEqual(w.workouttype,'Bike')
|
||||
self.assertEqual(w.workouttype,'bike')
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -261,6 +262,39 @@ 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.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):
|
||||
@@ -309,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):
|
||||
|
||||
+63
-16
@@ -524,7 +524,6 @@ def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high
|
||||
if metric=='power': # pragma: no cover
|
||||
with open('data.txt', 'w') as outfile:
|
||||
json.dump(s.json(), outfile)
|
||||
print('saved to file')
|
||||
|
||||
for data in s.json():
|
||||
y = None
|
||||
@@ -589,18 +588,15 @@ def step_to_time_dist(step,avgspeed = 3.2,ftp=200,ftspm=25,ftv=3.7):
|
||||
seconds = 0
|
||||
distance = 0
|
||||
rscore = 0
|
||||
durationtype = step['durationType']
|
||||
durationtype = step.get('durationType',0)
|
||||
value = step.get('durationValue',0)
|
||||
|
||||
if step['durationValue'] == 0: # pragma: no cover
|
||||
if value == 0: # pragma: no cover
|
||||
return 0,0,0
|
||||
|
||||
try:
|
||||
targettype = step['targetType']
|
||||
except KeyError: # pragma: no cover
|
||||
targettype = 0
|
||||
targettype = step.get('targetType',0)
|
||||
|
||||
if durationtype == 'Time':
|
||||
value = step['durationValue']
|
||||
seconds = value/1000.
|
||||
distance = avgspeed*seconds
|
||||
rscore = 60.*seconds/3600.
|
||||
@@ -616,6 +612,8 @@ def step_to_time_dist(step,avgspeed = 3.2,ftp=200,ftspm=25,ftv=3.7):
|
||||
elif valuelow != 0 and valuehigh != 0: # pragma: no cover
|
||||
distance = seconds*(valuelow+valuehigh)/2.
|
||||
velomid = (valuelow+valuehigh)/2000.
|
||||
else:
|
||||
velomid = avgspeed
|
||||
|
||||
veloratio = (velomid/ftv)**(3.0)
|
||||
rscoreperhour = 100.*veloratio
|
||||
@@ -657,22 +655,21 @@ def step_to_time_dist(step,avgspeed = 3.2,ftp=200,ftspm=25,ftv=3.7):
|
||||
rscore = 100*(avgpower/ftp)*seconds/3600.
|
||||
|
||||
return seconds,distance,rscore
|
||||
elif durationtype == 'Distance': # pragma: no cover
|
||||
value = step['durationValue']
|
||||
elif durationtype == 'Distance':
|
||||
distance = value/100.
|
||||
seconds = distance/avgspeed
|
||||
rscore = 60*seconds/3600.
|
||||
rscore = 60.*float(seconds)/3600.
|
||||
|
||||
if targettype == 'Speed':
|
||||
if targettype == 'Speed': # pragma: no cover
|
||||
value = step.get('targetValue',0)
|
||||
valuelow = step.get('targetValueLow',0)
|
||||
valuehigh = step.get('targetValueHigh',0)
|
||||
velomid = 0
|
||||
|
||||
if value != 0: # pragma: no cover
|
||||
if value != 0:
|
||||
seconds = distance/value
|
||||
velomid = value/1000.
|
||||
elif valuelow != 0 and valuehigh != 0: # pragma: no cover
|
||||
elif valuelow != 0 and valuehigh != 0:
|
||||
velomid = (valuelow+valuehigh)/2000.
|
||||
seconds = distance/velomid
|
||||
|
||||
@@ -680,7 +677,7 @@ def step_to_time_dist(step,avgspeed = 3.2,ftp=200,ftspm=25,ftv=3.7):
|
||||
rscoreperhour = 100.*veloratio
|
||||
rscore = rscoreperhour*seconds/3600.
|
||||
|
||||
if targettype == 'Power':
|
||||
if targettype == 'Power': # pragma: no cover
|
||||
value = step.get('targetValue',0)
|
||||
valuelow = step.get('targetValueLow',0)
|
||||
valuehigh = step.get('targetValueHigh',0)
|
||||
@@ -702,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)
|
||||
@@ -1167,3 +1164,53 @@ def request_is_ajax(request):
|
||||
# is_ajax = True
|
||||
|
||||
return is_ajax
|
||||
|
||||
def intervals_to_string(vals, units, typ):
|
||||
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): # pragma: no cover
|
||||
return ''
|
||||
|
||||
s = ''
|
||||
previous = 'rest'
|
||||
for i in range(len(vals)):
|
||||
if typ[i] == 'rest' and previous == 'rest':
|
||||
if units[i] == 'min': # pragma: no cover
|
||||
val = int(vals[i])*60
|
||||
unit = 'sec'
|
||||
else:
|
||||
val = int(vals[i])
|
||||
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': # pragma: no cover
|
||||
if units[i] == 'min':
|
||||
val = int(vals[i])*60
|
||||
unit = 'sec'
|
||||
else:
|
||||
val = int(vals[i])
|
||||
if units[i] == 'meters':
|
||||
unit = 'm'
|
||||
if units[i] == 'seconds':
|
||||
unit = 'sec'
|
||||
s += '/{val}{unit}'.format(val=val,unit=unit)
|
||||
previous = 'rest'
|
||||
else: # pragma: no cover # work interval
|
||||
if units[i] == 'min':
|
||||
val = int(vals[i])*60
|
||||
unit = 'sec'
|
||||
else:
|
||||
val = int(vals[i])
|
||||
if units[i] == 'meters':
|
||||
unit = 'm'
|
||||
if units[i] == 'seconds':
|
||||
unit = 'sec'
|
||||
s += '+{val}{unit}'.format(val=val,unit=unit)
|
||||
previous = 'work'
|
||||
|
||||
if s[0] == '+':
|
||||
s = s[1:]
|
||||
|
||||
return s
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
+31
-141
@@ -13,6 +13,7 @@ import numpy
|
||||
from rowers.mailprocessing import send_confirm
|
||||
import rowers.uploads as uploads
|
||||
import rowers.utils as utils
|
||||
from rowers.utils import intervals_to_string
|
||||
|
||||
from urllib.parse import urlparse, parse_qs
|
||||
from json.decoder import JSONDecodeError
|
||||
@@ -2297,7 +2298,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0)
|
||||
intervaldata['itime'] = itime
|
||||
intervaldata['itype'] = itype
|
||||
|
||||
rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
|
||||
vals, units, typ = rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow = [startsecond,endsecond])
|
||||
summary = rowdata.allstats()
|
||||
@@ -2316,7 +2317,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0)
|
||||
intervaldata['itime'] = itime
|
||||
intervaldata['itype'] = itype
|
||||
|
||||
rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
|
||||
vals, units, typ = rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow = [startsecond,endsecond])
|
||||
summary = rowdata.allstats()
|
||||
@@ -2336,7 +2337,7 @@ def workout_view(request,id=0,raceresult=0,sessionresult=0,nocourseraceresult=0)
|
||||
intervaldata['itime'] = itime
|
||||
intervaldata['itype'] = itype
|
||||
|
||||
rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
|
||||
vals, units, typ = rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',0.1,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow = [startsecond,endsecond])
|
||||
summary = rowdata.allstats()
|
||||
@@ -4812,7 +4813,7 @@ 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():
|
||||
@@ -4904,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: # 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')
|
||||
w.timezone = timezone
|
||||
w.save()
|
||||
|
||||
|
||||
|
||||
if make_plot: # pragma: no cover
|
||||
@@ -6240,7 +6248,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
|
||||
if powerorpace == 'power' and power is not None:
|
||||
try:
|
||||
rowdata.updateinterval_metric(
|
||||
vals, units, typ = rowdata.updateinterval_metric(
|
||||
' Power (watts)',power,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow=[activesecondsmin,activesecondsmax],
|
||||
@@ -6250,7 +6258,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
elif powerorpace == 'pace': # pragma: no cover
|
||||
try:
|
||||
velo = 500./pace_secs
|
||||
rowdata.updateinterval_metric(
|
||||
vals, units, typ = rowdata.updateinterval_metric(
|
||||
' AverageBoatSpeed (m/s)',velo,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow=[activesecondsmin,activesecondsmax],
|
||||
@@ -6259,7 +6267,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
messages.error(request,'Error updating pace')
|
||||
elif powerorpace == 'work': # pragma: no cover
|
||||
try:
|
||||
rowdata.updateinterval_metric(
|
||||
vals, units, typ = rowdata.updateinterval_metric(
|
||||
'driveenergy',work,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow=[activesecondsmin,activesecondsmax],
|
||||
@@ -6268,13 +6276,17 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
messages.error(request,'Error updating Work per Stroke')
|
||||
elif powerorpace == 'spm': # pragma: no cover
|
||||
try:
|
||||
rowdata.updateinterval_metric(
|
||||
vals, units, typ = rowdata.updateinterval_metric(
|
||||
' Cadence (stokes/min)',spm,mode='larger',
|
||||
debug=False,smoothwindow=2.,
|
||||
activewindow=[activesecondsmin,activesecondsmax],)
|
||||
except:
|
||||
messages.error(request,'Error updating SPM')
|
||||
|
||||
intervalString = ''
|
||||
if vals is not None:
|
||||
intervalString = intervals_to_string(vals, units, typ)
|
||||
|
||||
intervalstats = rowdata.allstats()
|
||||
itime,idist,itype = rowdata.intervalstats_values()
|
||||
nrintervals = len(idist)
|
||||
@@ -6296,7 +6308,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
'activeminutesmin': activeminutesmin,
|
||||
'activeminutesmax': activeminutesmax,
|
||||
}
|
||||
form = SummaryStringForm()
|
||||
form = SummaryStringForm(initial={'intervalstring':intervalString})
|
||||
powerupdateform = PowerIntervalUpdateForm(initial=data)
|
||||
savebutton = 'savepowerpaceform'
|
||||
formvalues = {
|
||||
@@ -6368,7 +6380,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
pace_secs = 120.
|
||||
|
||||
if powerorpace == 'power' and power is not None:
|
||||
rowdata.updateinterval_metric(' Power (watts)',power,mode='larger',
|
||||
vals, units, typ = rowdata.updateinterval_metric(' Power (watts)',power,mode='larger',
|
||||
debug=False,smoothwindow=15,
|
||||
activewindow=[activesecondsmin,activesecondsmax],
|
||||
)
|
||||
@@ -6376,7 +6388,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
elif powerorpace == 'pace': # pragma: no cover
|
||||
try:
|
||||
velo = 500./pace_secs
|
||||
rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',velo,mode='larger',
|
||||
vals, units, typ = rowdata.updateinterval_metric(' AverageBoatSpeed (m/s)',velo,mode='larger',
|
||||
debug=False,smoothwindow=15,
|
||||
activewindow=[activesecondsmin,activesecondsmax],
|
||||
)
|
||||
@@ -6384,7 +6396,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
messages.error(request,'Error updating pace')
|
||||
elif powerorpace == 'work': # pragma: no cover
|
||||
try:
|
||||
rowdata.updateinterval_metric(
|
||||
vals, units, typ = rowdata.updateinterval_metric(
|
||||
'driveenergy',work,mode='larger',
|
||||
debug=False,smoothwindow=15.,
|
||||
activewindow=[activesecondsmin,activesecondsmax],)
|
||||
@@ -6392,7 +6404,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
messages.error(request,'Error updating Work per Stroke')
|
||||
elif powerorpace == 'spm': # pragma: no cover
|
||||
try:
|
||||
rowdata.updateinterval_metric(' Cadence (stokes/min)',spm,mode='larger',
|
||||
vals, units, typ = rowdata.updateinterval_metric(' Cadence (stokes/min)',spm,mode='larger',
|
||||
debug=False,smoothwindow=2.,
|
||||
activewindow=[activesecondsmin,activesecondsmax],
|
||||
)
|
||||
@@ -6400,6 +6412,11 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
messages.error(request,'Error updating SPM')
|
||||
|
||||
|
||||
intervalString = ''
|
||||
if vals is not None:
|
||||
intervalString = intervals_to_string(vals, units, typ)
|
||||
|
||||
|
||||
intervalstats = rowdata.allstats()
|
||||
itime,idist,itype = rowdata.intervalstats_values()
|
||||
nrintervals = len(idist)
|
||||
@@ -6414,135 +6431,10 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
'activeminutesmax': activeminutesmax,
|
||||
}
|
||||
powerupdateform = PowerIntervalUpdateForm(initial=cd)
|
||||
form = SummaryStringForm()
|
||||
|
||||
|
||||
form = SummaryStringForm()
|
||||
|
||||
# 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()
|
||||
form = SummaryStringForm(initial={'intervalstring':intervalString})
|
||||
|
||||
|
||||
|
||||
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:
|
||||
@@ -6562,13 +6454,11 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
div = ''
|
||||
|
||||
# render page
|
||||
|
||||
return render(request, 'summary_edit.html',
|
||||
{'form':form,
|
||||
'activeminutesmax':activeminutesmax,
|
||||
'activeminutesmin':activeminutesmin,
|
||||
'maxminutes': maxminutes,
|
||||
'detailform':detailform,
|
||||
'powerupdateform':powerupdateform,
|
||||
'workout':row,
|
||||
'rower':r,
|
||||
|
||||
Reference in New Issue
Block a user