# 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 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 ) 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 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 ) 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) 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 ('water','coastal'): 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 ('water','coastal'): 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 def do_sync(w,options): if ('upload_to_C2' in options and options['upload_to_C2']) or w.user.c2_auto_export: try: message,id = c2stuff.workout_c2_upload(w.user.user,w) except c2stuff.C2NoTokenError: 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: try: message,id = stravastuff.workout_strava_upload( w.user.user,w ) except stravastuff.StravaNoTokenError: 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: try: message,id = sporttracksstuff.workout_sporttracks_upload( w.user.user,w ) except sporttracksstuff.SportTracksNoTokenError: 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: try: message,id = runkeeperstuff.workout_runkeeper_upload( w.user.user,w ) except runkeeperstuff.RunKeeperNoTokenError: 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: try: message,id = underarmourstuff.workout_ua_upload( w.user.user,w ) except underarmourstuff.UnderArmourNoTokenError: 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: try: message,id = tpstuff.workout_tp_upload( w.user.user,w ) except tpstuff.TPNoTokenError: message = "Please connect to TrainingPeaks first" id = 0 return 1