Private
Public Access
1
0
Files
rowsandall/rowers/uploads.py
Sander Roosendaal 75d5db185f small fixes
2018-07-07 16:13:19 +02:00

454 lines
13 KiB
Python

# for actions related to uploads
from django.conf import settings
from django.utils import timezone,translation
from rowers.tasks import (
handle_sendemail_unrecognized,handle_sendemailnewcomment,
handle_sendemailnewresponse, handle_updatedps,
handle_makeplot,handle_otwsetpower,handle_sendemailtcx,
handle_sendemailcsv
)
from rowers.models import GraphImage
from PIL import Image
import numpy as np
import yaml
import argparse
import yamllint
from subprocess import call
import re
from verbalexpressions import VerEx
import re
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from types import workouttypes,boattypes,otwtypes
try:
from cStringIO import StringIO
except:
from StringIO import StringIO
from rowers.utils import (
geo_distance,serialize_list,deserialize_list,uniqify,
str2bool,range_to_color_hex,absolute,myqueue,NoTokenError
)
def cleanbody(body):
regex = r".*---\n([\s\S]*?)\.\.\..*"
matches = re.finditer(regex,body)
for m in matches:
if m != None:
body = m.group(0)
return body
# currently only matches one chart
def matchchart(line):
results = []
testert = '^((chart)|(plot))'
tester2t = testert+'(.*)(dist)'
tester3t = testert+'(.*)(time)'
tester4t = testert+'(.*)(pie)'
tester = re.compile(testert)
tester2 = re.compile(tester2t)
tester3 = re.compile(tester3t)
tester4 = re.compile(tester4t)
if tester.match(line.lower()):
if tester2.match(line.lower()):
return 'distanceplot'
if tester3.match(line.lower()):
return 'timeplot'
if tester3.match(line.lower()):
return 'pieplot'
def matchsync(line):
results = []
tester = '((sync)|(synchronization)|(export))'
tester2 = tester+'(.*)((c2)|(concept2)|(logbook))'
tester3 = tester+'(.*)((tp)|(trainingpeaks))'
tester4 = tester+'(.*)(strava)'
tester5 = tester+'(.*)((st)|(sporttracks))'
tester6 = tester+'(.*)((rk)|(runkeeper))'
tester7 = tester+'(.*)((mapmyfitness)|(underarmour)|(ua))'
tester = re.compile(tester)
if tester.match(line.lower()):
testers = [
('upload_to_C2',re.compile(tester2)),
('upload_totp',re.compile(tester3)),
('upload_to_Strava',re.compile(tester4)),
('upload_to_SportTracks',re.compile(tester5)),
('upload_to_RunKeeper',re.compile(tester6)),
('upload_to_MapMyFitness',re.compile(tester7)),
]
for t in testers:
if t[1].match(line.lower()):
results.append(t[0])
return results
def getstravaid(uploadoptions,body):
stravaid = 0
tester = re.compile('^(stravaid)(.*?)(\d+)')
for line in body.splitlines():
if tester.match(line.lower()):
stravaid = tester.match(line.lower()).group(3)
uploadoptions['stravaid'] = int(stravaid)
return uploadoptions
def gettypeoptions_body2(uploadoptions,body):
tester = re.compile('^(workout)')
testerb = re.compile('^(boat)')
for line in body.splitlines():
if tester.match(line.lower()):
for typ,verb in workouttypes:
str1 = '^(workout)(.*)({a})'.format(
a = typ
)
testert = re.compile(str1)
if testert.match(line.lower()):
uploadoptions['workouttype'] = typ
if testerb.match(line.lower()):
for typ,verb in boattypes:
str1 = '^(boat)(.*)({a})'.format(
a = typ.replace('+'.'\+')
)
testert = re.compile(str1)
if testert.match(line.lower()):
uploadoptions['boattype'] = typ
return uploadoptions
def getprivateoptions_body2(uploadoptions,body):
tester = re.compile('^(priva)')
for line in body.splitlines():
if tester.match(line.lower()):
v = True
negs = ['false','False','None','no']
for neg in negs:
tstr = re.compile('^(.*)'+neg)
if tstr.match(line.lower()):
v = False
uploadoptions['makeprivate'] = v
return uploadoptions
def getplotoptions_body2(uploadoptions,body):
for line in body.splitlines():
chart = matchchart(line)
if chart:
uploadoptions['make_plot'] = True
uploadoptions['plottype'] = chart
return uploadoptions
def getsyncoptions_body2(uploadoptions,body):
result = []
for line in body.splitlines():
result = result+matchsync(line)
result = list(set(result))
for r in result:
uploadoptions[r] = True
return uploadoptions
def getsyncoptions(uploadoptions,values):
try:
value = values.lower()
values = [values]
except AttributeError:
pass
for v in values:
try:
v = v.lower()
if v in ['c2','concept2','logbook']:
uploadoptions['upload_to_C2'] = True
if v in ['tp','trainingpeaks']:
uploadoptions['upload_totp'] = True
if v in ['strava']:
uploadoptions['upload_to_Strava'] = True
if v in ['st','sporttracks']:
uploadoptions['upload_to_SportTracks'] = True
if v in ['rk','runkeeper']:
uploadoptions['upload_to_RunKeeper'] = True
if v in ['ua','underarmour','mapmyfitness']:
uploadoptions['upload_to_MapMyFitness'] = True
except AttributeError:
pass
return uploadoptions
def getplotoptions(uploadoptions,value):
try:
v = value.lower()
if v in ['pieplot','timeplot','distanceplot']:
uploadoptions['make_plot'] = True
uploadoptions['plottype'] = v
elif 'pie' in v:
uploadoptions['make_plot'] = True
uploadoptions['plottype'] = 'pieplot'
elif 'distance' in v:
uploadoptions['make_plot'] = True
uploadoptions['plottype'] = 'distanceplot'
elif 'time' in v:
uploadoptions['make_plot'] = True
uploadoptions['plottype'] = 'timeplot'
except TypeError:
pass
return uploadoptions
def gettype(uploadoptions,value,key):
workouttype = 'rower'
for type,verb in workouttypes:
if value == type:
workouttype = type
if value == verb:
workouttype = type
uploadoptions[key] = workouttype
return uploadoptions
def getboattype(uploadoptions,value,key):
boattype = '1x'
for type,verb in boattypes:
if value == type:
boattype = type
if value == verb:
boattype = type
uploadoptions[key] = boattype
return uploadoptions
def getboolean(uploadoptions,value,key):
b = True
if not value:
b = False
if value in [False,'false','False',None,'no']:
b = False
uploadoptions[key] = b
return uploadoptions
def upload_options(body):
uploadoptions = {}
body = cleanbody(body)
try:
yml = (yaml.load(body))
if yml and 'fromuploadform' in yml:
return yml
try:
for key, value in yml.iteritems():
lowkey = key.lower()
if lowkey == 'sync' or lowkey == 'synchronization':
uploadoptions = getsyncoptions(uploadoptions,value)
if lowkey == 'chart' or lowkey == 'static' or lowkey == 'plot':
uploadoptions = getplotoptions(uploadoptions,value)
if 'priva' in lowkey:
uploadoptions = getboolean(uploadoptions,value,'makeprivate')
if 'workout' in lowkey:
uploadoptions = gettype(uploadoptions,value,'workouttype')
if 'boat' in lowkey:
uploadoptions = getboattype(uploadoptions,value,'boattype')
except AttributeError:
#pass
raise yaml.YAMLError
except yaml.YAMLError as exc:
try:
uploadoptions = getplotoptions_body2(uploadoptions,body)
uploadoptions = getsyncoptions_body2(uploadoptions,body)
uploadoptions = getprivateoptions_body2(uploadoptions,body)
typeoptions = gettypeoptions_body2(uploadoptions,body)
uploadoptions = getstravaid(uploadoptions,body)
except IOError:
pm = exc.problem_mark
strpm = str(pm)
pbm = "Your email has an issue on line {} at position {}. The error is: ".format(
pm.line+1,
pm.column+1,
)+strpm
return {'error':pbm}
if uploadoptions == {}:
uploadoptions['message'] = 'No parsing issue. No valid commands detected'
return uploadoptions
def make_plot(r,w,f1,f2,plottype,title,imagename='',plotnr=0):
if imagename == '':
imagename = f1[:-4]+'.png'
fullpathimagename = 'static/plots/'+imagename
powerperc = 100*np.array([r.pw_ut2,
r.pw_ut1,
r.pw_at,
r.pw_tr,r.pw_an])/r.ftp
ftp = float(r.ftp)
if w.workouttype in otwtypes:
ftp = ftp*(100.-r.otwslack)/100.
hrpwrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
'ftp':ftp,
'powerperc':serialize_list(powerperc),
'powerzones':serialize_list(r.powerzones),
}
# make plot - asynchronous task
plotnrs = {
'timeplot':1,
'distanceplot':2,
'pieplot':3,
}
if plotnr == 0:
plotnr = plotnrs[plottype]
if w.workouttype in otwtypes:
plotnr = plotnr+3
job = myqueue(queue,handle_makeplot,f1,f2,
title,hrpwrdata,
plotnr,imagename)
try:
width,height = Image.open(fullpathimagename).size
except:
width = 1200
height = 600
imgs = GraphImage.objects.filter(workout=w)
if len(imgs) < 7:
i = GraphImage(workout=w,
creationdatetime=timezone.now(),
filename=fullpathimagename,
width=width,height=height)
i.save()
else:
return 0,'You have reached the maximum number of static images for this workout. Delete an image first'
return i.id,job.id
import c2stuff,stravastuff,sporttracksstuff,runkeeperstuff
import underarmourstuff,tpstuff
def set_workouttype(w,options):
try:
w.workouttype = options['workouttype']
w.save()
except KeyError:
pass
try:
w.boattype = options['boattype']
w.save()
except KeyError:
pass
return 1
def make_private(w,options):
if 'makeprivate' in options and options['makeprivate']:
w.privacy = 'hidden'
w.save()
return 1
from rowers.utils import isprorower
def do_sync(w,options):
try:
if options['stravaid'] != 0:
w.uploadedtostrava = options['stravaid']
w.save()
except KeyError:
pass
if ('upload_to_C2' in options and options['upload_to_C2']) or (w.user.c2_auto_export and isprorower(w.user)):
try:
message,id = c2stuff.workout_c2_upload(w.user.user,w)
except NoTokenError:
id = 0
message = "Something went wrong with the Concept2 sync"
if ('upload_to_Strava' in options and options['upload_to_Strava']) or (w.user.strava_auto_export and isprorower(w.user)):
try:
message,id = stravastuff.workout_strava_upload(
w.user.user,w
)
except NoTokenError:
id = 0
message = "Please connect to Strava first"
if ('upload_to_SportTracks' in options and options['upload_to_SportTracks']) or (w.user.sporttracks_auto_export and isprorower(w.user)):
try:
message,id = sporttracksstuff.workout_sporttracks_upload(
w.user.user,w
)
except NoTokenError:
message = "Please connect to SportTracks first"
id = 0
if ('upload_to_RunKeeper' in options and options['upload_to_RunKeeper']) or (w.user.runkeeper_auto_export and isprorower(w.user)):
try:
message,id = runkeeperstuff.workout_runkeeper_upload(
w.user.user,w
)
except NoTokenError:
message = "Please connect to Runkeeper first"
id = 0
if ('upload_to_MapMyFitness' in options and options['upload_to_MapMyFitness']) or (w.user.mapmyfitness_auto_export and isprorower(w.user)):
try:
message,id = underarmourstuff.workout_ua_upload(
w.user.user,w
)
except NoTokenError:
message = "Please connect to MapMyFitness first"
id = 0
if ('upload_to_TrainingPeaks' in options and options['upload_to_TrainingPeaks']) or (w.user.trainingpeaks_auto_export and isprorower(w.user)):
try:
message,id = tpstuff.workout_tp_upload(
w.user.user,w
)
except NoTokenError:
message = "Please connect to TrainingPeaks first"
id = 0
return 1