Private
Public Access
1
0

Merge branch 'release/v13.30'

This commit is contained in:
Sander Roosendaal
2020-07-10 11:05:06 +02:00
5 changed files with 117 additions and 22 deletions

View File

@@ -70,6 +70,7 @@ import zipfile
import pandas as pd import pandas as pd
import numpy as np import numpy as np
import itertools import itertools
from fitparse import FitFile
import math import math
from rowers.tasks import ( from rowers.tasks import (
handle_sendemail_unrecognized, handle_sendemail_breakthrough, handle_sendemail_unrecognized, handle_sendemail_breakthrough,
@@ -94,6 +95,7 @@ queuehigh = django_rq.get_queue('default')
from rowsandall_app.settings import SITE_URL from rowsandall_app.settings import SITE_URL
from rowers.mytypes import otwtypes,otetypes from rowers.mytypes import otwtypes,otetypes
from rowers import mytypes
from rowers.database import * from rowers.database import *
from rowers.opaque import encoder from rowers.opaque import encoder
@@ -747,6 +749,19 @@ def clean_df_stats(datadf, workstrokesonly=True, ignorehr=True,
return datadf return datadf
def getpartofday(dt):
h = dt.hour
if h < 12:
return "Morning"
elif h < 18:
return "Afternoon"
elif h < 22:
return "Evening"
else:
return "Night"
return None
def getstatsfields(): def getstatsfields():
fielddict = {name:d['verbose_name'] for name,d in rowingmetrics} fielddict = {name:d['verbose_name'] for name,d in rowingmetrics}
@@ -1138,8 +1153,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
impeller=False): impeller=False):
message = None message = None
if title is None:
title = 'Workout'
powerperc = 100 * np.array([r.pw_ut2, powerperc = 100 * np.array([r.pw_ut2,
r.pw_ut1, r.pw_ut1,
@@ -1153,6 +1167,16 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
powerperc=powerperc, powerzones=r.powerzones) powerperc=powerperc, powerzones=r.powerzones)
row = rdata(f2, rower=rr) row = rdata(f2, rower=rr)
if title is None or title == '':
title = 'Workout'
partofday = getpartofday(row.rowdatetime)
if partofday is not None:
title = '{partofday} workout {workouttype}'.format(
partofday=partofday,
workouttype=workouttype,
)
if row.df.empty: if row.df.empty:
return (0, 'Error: CSV data file was empty') return (0, 'Error: CSV data file was empty')
@@ -1533,6 +1557,38 @@ def handle_nonpainsled(f2, fileformat, summary=''):
# This routine should be used everywhere in views.py and mailprocessing.py # This routine should be used everywhere in views.py and mailprocessing.py
# Currently there is code duplication # Currently there is code duplication
def get_workouttype_from_fit(filename,workouttype='water'):
fitfile = FitFile(filename,check_crc=False)
records = fitfile.messages
fittype = 'rowing'
for record in records:
if record.name == 'sport':
fittype = record.get_values()['sport'].lower()
try:
workouttype = mytypes.fitmappinginv[fittype]
except KeyError:
return workouttype
return workouttype
import rowingdata.tcxtools as tcxtools
def get_workouttype_from_tcx(filename,workouttype='water'):
d = tcxtools.tcx_getdict(filename)
tcxtype = 'rowing'
try:
tcxtype = d['Activities']['Activity']['@Sport'].lower()
if tcxtype == 'other':
tcxtype = 'rowing'
except KeyError:
return workouttype
try:
workouttype = mytypes.garminmappinginv[tcxtype.upper()]
except KeyError:
return workouttype
return workouttype
def new_workout_from_file(r, f2, def new_workout_from_file(r, f2,
workouttype='rower', workouttype='rower',
@@ -1554,6 +1610,8 @@ def new_workout_from_file(r, f2,
summary = '' summary = ''
oarlength = 2.89 oarlength = 2.89
inboard = 0.88 inboard = 0.88
# Save zip files to email box for further processing
if len(fileformat) == 3 and fileformat[0] == 'zip': if len(fileformat) == 3 and fileformat[0] == 'zip':
uploadoptions['fromuploadform'] = True uploadoptions['fromuploadform'] = True
bodyyaml = yaml.safe_dump(uploadoptions,default_flow_style=False) bodyyaml = yaml.safe_dump(uploadoptions,default_flow_style=False)
@@ -1621,10 +1679,17 @@ def new_workout_from_file(r, f2,
r.user.email) r.user.email)
return (0, message, f2) return (0, message, f2)
if fileformat == 'att': if fileformat == 'att':
# email attachment which can safely be ignored # email attachment which can safely be ignored
return (0, '', f2) return (0, '', f2)
# Get workout type from fit & tcx
if (fileformat == 'fit'):
workouttype = get_workouttype_from_fit(f2,workouttype=workouttype)
if (fileformat == 'tcx'):
workouttype = get_workouttype_from_tcx(f2,workouttype=workouttype)
# handle non-Painsled by converting it to painsled compatible CSV # handle non-Painsled by converting it to painsled compatible CSV
if (fileformat != 'csv'): if (fileformat != 'csv'):
f2, summary, oarlength, inboard, fileformat, impeller = handle_nonpainsled( f2, summary, oarlength, inboard, fileformat, impeller = handle_nonpainsled(
@@ -1636,6 +1701,8 @@ def new_workout_from_file(r, f2,
message = 'Something went wrong' message = 'Something went wrong'
return (0, message, '') return (0, message, '')
dosummary = (fileformat != 'fit' and 'speedcoach2' not in fileformat) dosummary = (fileformat != 'fit' and 'speedcoach2' not in fileformat)
dosummary = dosummary or summary == '' dosummary = dosummary or summary == ''

View File

@@ -112,6 +112,42 @@ garmincollection = (
garminmapping = {key:value for key,value in Reverse(garmincollection)} garminmapping = {key:value for key,value in Reverse(garmincollection)}
fitcollection = (
('water','rowing'),
('rower','rowing'),
('skierg','cross_country_skiing'),
('Bike','cycling'),
('bikeerg','cycling'),
('dynamic','rowing'),
('slides','rowing'),
('paddle','paddling'),
('snow','cross_country_skiing'),
('coastal','rowing'),
('c-boat','rowing'),
('churchboat','rowing'),
('Ride','cycling'),
('Run','running'),
('NordicSki','cross_country_skiing'),
('Swim','swimming'),
('Hike','hiking'),
('RollerSki','cross_country_skiing'),
('Walk','walking'),
('Canoeing','boating'),
('Crossfit','fitness_equipment'),
('StandUpPaddling','stand_up_paddle_boarding'),
('IceSkate','ice_skating'),
('WeightTraining','training'),
('InlineSkate','inline_skating'),
('Kayaking','kayaking'),
('Workout','generic'),
('Yoga','generic'),
('other','generic'),
)
fitmapping = {key:value for key,value in Reverse(fitcollection)}
stcollection = ( stcollection = (
('water','Rowing'), ('water','Rowing'),
('rower','Rowing'), ('rower','Rowing'),
@@ -289,6 +325,8 @@ polarmappinginv = {value:key for key,value in Reverse(polarcollection) if value
garminmappinginv = {value:key for key, value in Reverse(garmincollection) if value is not None} garminmappinginv = {value:key for key, value in Reverse(garmincollection) if value is not None}
fitmappinginv = {value:key for key,value in Reverse(fitcollection) if value is not None}
otwtypes = ( otwtypes = (
'water', 'water',
'coastal', 'coastal',

View File

@@ -707,7 +707,6 @@ def handle_get_garmin_file(client_id,
)+filetype )+filetype
response = garmin.get(url, stream=True) response = garmin.get(url, stream=True)
print(response.status_code,filename)
if response.status_code == 200: if response.status_code == 200:
with open(filename, 'wb') as out_file: with open(filename, 'wb') as out_file:
shutil.copyfileobj(response.raw, out_file) shutil.copyfileobj(response.raw, out_file)
@@ -718,7 +717,7 @@ def handle_get_garmin_file(client_id,
'secret':UPLOAD_SERVICE_SECRET, 'secret':UPLOAD_SERVICE_SECRET,
'user':userid, 'user':userid,
'file': filename, 'file': filename,
'title': filename[6:], 'title': '',
'workouttype':'water', 'workouttype':'water',
'boattype':'1x', 'boattype':'1x',
} }

View File

@@ -123,12 +123,12 @@
</p> </p>
<h2>On-line Racing</h2> <h2>On-line Challenges</h2>
<p> <p>
<a href="/rowers/virtualevents">On-line racing</a> is a <a href="/rowers/virtualevents">On-line challenges</a> are a
fun way to race other Rowsandall.com users fun way to test your boat speed and course line against other Rowsandall.com users
rowing on the same stretch of water. rowing on the same stretch of water or on the Concept2 ergometer.
</p> </p>
<h2>Training Plan</h2> <h2>Training Plan</h2>

View File

@@ -1035,11 +1035,7 @@ def garmin_summaries_view(request):
def garmin_newfiles_ping(request): def garmin_newfiles_ping(request):
t = time.localtime() t = time.localtime()
timestamp = time.strftime('%b-%d-%Y_%H%M', t) timestamp = time.strftime('%b-%d-%Y_%H%M', t)
with open('garminlog.log','a') as f:
f.write('\n')
f.write(timestamp)
f.write(' ')
f.write(str(request.body))
if request.method != 'POST': if request.method != 'POST':
return HttpResponse(status=200) return HttpResponse(status=200)
@@ -1090,11 +1086,6 @@ def garmin_details_view(request):
t = time.localtime() t = time.localtime()
timestamp = time.strftime('%b-%d-%Y_%H%M', t) timestamp = time.strftime('%b-%d-%Y_%H%M', t)
with open('garminlog.log','a') as f:
f.write('\n')
f.write(timestamp)
f.write(' ')
f.write(str(request.body))
# POST request # POST request
data = json.loads(request.body) data = json.loads(request.body)