# 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 django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') from mytypes import workouttypes,boattypes,otwtypes,workoutsources 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 sources = [s for s,name in workoutsources] def matchsource(line): results = [] for s in sources: testert = '^source.*(%s)' % s tester = re.compile(testert) if tester.match(line.lower()): return group(1) # 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 getworkoutsources(uploadoptions,body): for line in body.splitlines(): workoutsource = matchsource(line) if workoutsource: uploadoptions['workoutsource'] = workoutsource 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 getsource(uploadoptions,value,key): workoutsource = 'unknown' for type,verb in workoutsources: if value == type: workoutsource = type if value == verb: workoutsource = type uploadoptions[key] = workoutsource 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' or lowkey == 'export': 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') if 'source' in lowkey: uploadoptions = getsource(uploadoptions,value,'workoutsource') 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) uploadoptions = getworkoutsources(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 set_workoutsource(w,options): try: w.workoutsource = options['workoutsource'] w.save() except KeyError: pass 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)): if ('upload_to_C2' in options and not options['upload_to_C2']): pass else: 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)): if ('upload_to_Strava' in options and not options['upload_to_Strava']): pass else: 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)): if ('upload_to_SportTracks' in options and not options['upload_to_SportTracks']): pass else: 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)): if ('upload_to_RunKeeper' in options and not options['upload_to_RunKeeper']): pass else: 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)): if ('upload_to_MapMyFitness' in options and not options['upload_to_MapMyFitness']): pass else: 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)): if ('upload_to_TrainingPeaks' in options and not options['upload_to_TrainingPeaks']): pass else: try: message,id = tpstuff.workout_tp_upload( w.user.user,w ) except NoTokenError: message = "Please connect to TrainingPeaks first" id = 0 return 1