diff --git a/rowers/braintreestuff.py b/rowers/braintreestuff.py index 3825ff21..17584108 100644 --- a/rowers/braintreestuff.py +++ b/rowers/braintreestuff.py @@ -73,7 +73,7 @@ def process_webhook(notification): if notification.kind == 'subscription_charged_successfully': subscription = notification.subscription rs = Rower.objects.filter(subscription_id=subscription.id) - if rs.count() == 0: + if rs.count() == 0: # pragma: no cover dologging('braintreewebhooks.log','Could not find rowers with subscription ID {id}'.format( id=subscription.id )) @@ -209,7 +209,7 @@ def make_payment(rower,data): if 'plan' in data: theplan = data['plan'] additional_text = 'Rowsandall Purchase Plan nr {theplan}'.format(theplan=theplan) - else: + else: # pragma: no cover additional_text = 'Rowsandall Purchase' result = gateway.transaction.sale({ diff --git a/rowers/credits.py b/rowers/credits.py index e57710c9..3ddb6cfb 100644 --- a/rowers/credits.py +++ b/rowers/credits.py @@ -4,16 +4,16 @@ class InsufficientCreditError(Exception): pass def upgrade(amount, rower): - if rower.eurocredits > amount: + if rower.eurocredits > amount: # pragma: no cover return rower.eurocredits else: rower.eurocredits = amount rower.save() return rower.eurocredits - return rower.eurocredits + return rower.eurocredits # pragma: no cover def withdraw(amount, rower): - if rower.eurocredits < amount: + if rower.eurocredits < amount: # pragma: no cover rower.eurocredits = 0 rower.save() raise InsufficientCreditError @@ -22,9 +22,9 @@ def withdraw(amount, rower): rower.save() return rower.eurocredits - return rower.eurocredits + return rower.eurocredits # pragma: no cover -def discount(amount,rower): +def discount(amount,rower): # pragma: no cover if amount < rower.eurocredits: return amount else: @@ -33,9 +33,9 @@ def discount(amount,rower): return 0 def discounted(amount,rower): - if amount > rower.eurocredits: + if amount > rower.eurocredits: # pragma: no cover return amount-rower.eurocredits else: return 0 - return 0 + return 0 # pragma: no cover diff --git a/rowers/dataprep.py b/rowers/dataprep.py index a28b7e25..eaab5f0b 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -28,7 +28,8 @@ from rowingdata import ( from rowers.tasks import ( handle_sendemail_unrecognized,handle_setcp, - handle_getagegrouprecords, handle_update_wps + handle_getagegrouprecords, handle_update_wps, + handle_request_post ) from rowers.tasks import handle_zip_file @@ -42,7 +43,9 @@ from pyarrow.lib import ArrowInvalid from django.utils import timezone from django.utils.timezone import get_current_timezone -from django_mailbox.models import Message,Mailbox,MessageAttachment +from django.urls import reverse +import requests + from django.core.exceptions import ValidationError from time import strftime @@ -74,6 +77,7 @@ allowedcolumns = [key for key,value in strokedatafields.items()] #from async_messages import messages as a_messages import os import zipfile +from zipfile import BadZipFile import pandas as pd import numpy as np import itertools @@ -2024,8 +2028,7 @@ def handle_nonpainsled(f2, fileformat, summary='',startdatetime='',empowerfirmwa return (f2, summary, oarlength, inboard, fileformat, impeller) # Create new workout from file and store it in the database -# This routine should be used everywhere in views.py and mailprocessing.py -# Currently there is code duplication +# This routine should be used everywhere in views.py def get_workouttype_from_fit(filename,workouttype='water'): try: @@ -2102,21 +2105,30 @@ def new_workout_from_file(r, f2, # Save zip files to email box for further processing if len(fileformat) == 3 and fileformat[0] == 'zip': # pragma: no cover - uploadoptions['fromuploadform'] = True - bodyyaml = yaml.safe_dump(uploadoptions,default_flow_style=False) - f_to_be_deleted = f2 + uploadoptions['secret'] = settings.UPLOAD_SERVICE_SECRET + uploadoptions['user'] = r.user.id + uploadoptions['title'] = title + try: + zip_file = zipfile.ZipFile(f2) + for id,filename in enumerate(zip_file.namelist()): + datafile = zip_file.extract(filename, path='media/') + if id>0: + uploadoptions['title'] = title+' ('+str(id+1)+')' + else: + uploadoptions['title'] = title + + uploadoptions['file'] = datafile + url = settings.UPLOAD_SERVICE_URL + + job = myqueue(queuehigh, + handle_request_post, + url, + uploadoptions + ) + + except BadZipFile: # pragma: no cover + pass - workoutsbox = Mailbox.objects.filter(name='workouts')[0] - msg = Message(mailbox=workoutsbox, - from_header=r.user.email, - subject = title,body=bodyyaml) - msg.save() - f3 = 'media/mailbox_attachments/'+f2[6:] - copyfile(f2,f3) - f3 = f3[6:] - a = MessageAttachment(message=msg,document=f3) - a.save() - message = "Zip file was stored for offline processing" return -1, message, f2 diff --git a/rowers/emails.py b/rowers/emails.py index e57d30a1..9694272c 100644 --- a/rowers/emails.py +++ b/rowers/emails.py @@ -120,3 +120,21 @@ def send_template_email(from_email,to_email,subject, return 0 return res + +def send_confirm(user, name, link, options): # pragma: no cover + d = { + 'first_name':user.first_name, + 'name':name, + 'link':link, + } + + fullemail = user.email + subject = 'New Workout Added: '+name + + res = send_template_email('Rowsandall ', + [fullemail], + subject,'confirmemail.html', + d + ) + + return 1 diff --git a/rowers/forms.py b/rowers/forms.py index ce63eb52..deee532d 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1486,7 +1486,7 @@ class RaceResultFilterForm(forms.Form): if records: # group - if groups: + if groups: # pragma: no cover thecategories = [record.entrycategory for record in records] thecategories = list(set(thecategories)) if len(thecategories) <= 1: diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index 27fe8f3b..04d65b3d 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -2429,7 +2429,7 @@ def get_map_script_course( longend, scoordinates, course, - ): + ): # pragma: no cover latmean,lonmean,coordinates = course_coord_center(course) lat_min, lat_max, long_min, long_max = course_coord_maxmin(course) @@ -2742,7 +2742,7 @@ def leaflet_chart(lat,lon,name="",raceresult=0): longend, scoordinates, ) - else: + else: # pragma: no cover record = VirtualRaceResult.objects.get(id=raceresult) course = record.course script = get_map_script_course( @@ -7010,7 +7010,7 @@ def get_zones_report(rower,startdate,enddate,trainingzones='hr',date_agg='week', def interactive_zoneschart(rower,data,startdate,enddate,trainingzones='hr',date_agg='week', yaxis='time'): - if startdate >= enddate: + if startdate >= enddate: # pragma: no cover st = startdate startdate = enddate enddate = st diff --git a/rowers/mailprocessing.py b/rowers/mailprocessing.py deleted file mode 100644 index 2ac8cac8..00000000 --- a/rowers/mailprocessing.py +++ /dev/null @@ -1,189 +0,0 @@ -from __future__ import absolute_import -from __future__ import division -from __future__ import print_function -from __future__ import unicode_literals - -# Processes emails sent to workouts@rowsandall.com -""" Processes emails sent to workouts@rowsandall.com """ -import shutil -import time -from django.conf import settings -from rowers.tasks import ( - handle_sendemail_unrecognized, - handle_sendemail_unrecognizedowner - ) -from django_mailbox.models import Message, MessageAttachment,Mailbox - -#workoutmailbox = Mailbox.objects.get(name='workouts') -#failedmailbox = Mailbox.objects.get(name='Failed') - - -from rowers.models import User, Rower, RowerForm - -from django.core.mail import EmailMessage - -from rowingdata import rower as rrower - -from rowingdata import rowingdata as rrdata - -from rowingdata import get_file_type - -import zipfile -import os -import rowers.dataprep as dataprep - -import django_rq -queue = django_rq.get_queue('default') -queuelow = django_rq.get_queue('low') -queuehigh = django_rq.get_queue('default') - -# Sends a confirmation with a link to the workout -from rowers.emails import send_template_email - -def send_confirm(user, name, link, options): # pragma: no cover - d = { - 'first_name':user.first_name, - 'name':name, - 'link':link, - } - - fullemail = user.email - subject = 'New Workout Added: '+name - - res = send_template_email('Rowsandall ', - [fullemail], - subject,'confirmemail.html', - d - ) - - return 1 - -# Reads a "rowingdata" object, plus some error protections - - -def rdata(file, rower=rrower()): - """ Reads rowingdata data or returns 0 on Error """ - try: - result = rrdata(csvfile=file, rower=rower) - except IOError: # pragma: no cover - try: - result = rrdata(csvfile=file + '.gz', rower=rower) - except IOError: - result = 0 - except TypeError: # pragma: no cover - try: - result = rrdata(csvfile=file) - except IOError: - try: - result = rrdata(csvfile=file+'.gz', rower=rower) - except IOError: - result = 0 - - return result - - - -def make_new_workout_from_email(rower, datafile, name, cntr=0,testing=False): - """ This one is used in processemail """ - workouttype = 'rower' - impeller = False - - try: # pragma: no cover - datafilename = datafile.name - fileformat = get_file_type('media/' + datafilename) - raise ValueError - except IOError: # pragma: no cover - datafilename = datafile.name + '.gz' - fileformat = get_file_type('media/' + datafilename) - except AttributeError: - datafilename = datafile - fileformat = get_file_type('media/' + datafile) - - if len(fileformat) == 3 and fileformat[0] == 'zip': # pragma: no cover - with zipfile.ZipFile('media/' + datafilename) as zip_file: - datafilename = zip_file.extract( - zip_file.namelist()[0], - path='media/')[6:] - fileformat = fileformat[2] - - - - - f,e = os.path.splitext(datafilename) - if fileformat == 'unknown' and 'txt' not in e: - fcopy = "media/"+datafilename - if not testing: # pragma: no cover - if settings.CELERY: - res = handle_sendemail_unrecognized.delay( - fcopy, - rower.user.email - ) - res = handle_sendemail_unrecognizedowner.delay( - rower.user.email, - rower.user.first_name - ) - else: - res = queuehigh.enqueue(handle_sendemail_unrecognized, - fcopy, - rower.user.email) - res = queuehigh.enqueue(handle_sendemail_unrecognizedowner, - rower.user.email, - rower.user.first_name - ) - return 0 - - summary = '' - - - # handle non-Painsled - if fileformat == 'att': - return 0 - if fileformat != 'csv': - filename_mediadir, summary, oarlength, inboard,fileformat,impeller = dataprep.handle_nonpainsled( - 'media/' + datafilename, fileformat, summary) - if not filename_mediadir: # pragma: no cover - return 0 - else: - filename_mediadir = 'media/' + datafilename - inboard = 0.88 - oarlength = 2.89 - - row = rdata(filename_mediadir) - if row == 0: # pragma: no cover - return 0 - - # change filename - if datafilename[:5] != 'media': - timestr = time.strftime("%Y%m%d-%H%M%S") - datafilename = 'media/' + timestr + str(cntr) + 'o.csv' - - try: - avglat = row.df[' latitude'].mean() - avglon = row.df[' longitude'].mean() - if avglat != 0 or avglon != 0: - workouttype = 'water' - except KeyError: - pass - - row.write_csv(datafilename, gzip=True) - dosummary = (fileformat != 'fit' and 'speedcoach2' not in fileformat) - dosummary = dosummary or summary == '' - - if name == '': # pragma: no cover - name = 'Workout from Background Queue' - - id, message = dataprep.save_workout_database( - datafilename, rower, - workouttype=workouttype, - dosummary=dosummary, - summary=summary, - inboard=inboard, - oarlength=oarlength, - title=name, - dosmooth=rower.dosmooth, - workoutsource=fileformat, - notes='',impeller=impeller, - ) - - - return id diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 63b21453..73ef5f40 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -18,7 +18,7 @@ import json import io from django.core.management.base import BaseCommand -from django_mailbox.models import Message, MessageAttachment,Mailbox +#from django_mailbox.models import Message, MessageAttachment,Mailbox from django.urls import reverse from django.conf import settings @@ -29,7 +29,7 @@ from rowingdata import rower as rrower from rowingdata import rowingdata as rrdata import rowers.uploads as uploads -from rowers.mailprocessing import make_new_workout_from_email, send_confirm + import rowers.polarstuff as polarstuff import rowers.c2stuff as c2stuff import rowers.rp3stuff as rp3stuff @@ -37,8 +37,7 @@ import rowers.stravastuff as stravastuff import rowers.nkstuff as nkstuff from rowers.opaque import encoder -from rowers.models import User,VirtualRace,Workout -from rowers.plannedsessions import email_submit_race +from rowers.models import User,Workout from rowers.rower_rules import user_is_not_basic from rowers.utils import dologging @@ -60,102 +59,6 @@ def rdata(file_obj, rower=rrower()): # pragma: no cover return result -def processattachment(rower, fileobj, title, uploadoptions,testing=False): - try: - filename = fileobj.name -# filename = os.path.abspath(fileobj.name) - except AttributeError: - filename = fileobj[6:] - - - # test if file exists and is not empty - try: - with io.open('media/'+filename,'rb') as fop: - line = fop.readline() - except (IOError, UnicodeEncodeError): # pragma: no cover - return 0 - - - # set user - if rower.user.is_staff and 'username' in uploadoptions: - users = User.objects.filter(username=uploadoptions['username']) - if len(users)==1: - therower = users[0].rower - elif uploadoptions['username'] == '': # pragma: no cover - therower = rower - else: # pragma: no cover - return 0 - else: - therower = rower - - - uploadoptions['secret'] = settings.UPLOAD_SERVICE_SECRET - uploadoptions['user'] = therower.user.id - uploadoptions['file'] = 'media/'+filename - uploadoptions['title'] = title - - url = settings.UPLOAD_SERVICE_URL - if not testing: # pragma: no cover - response = requests.post(url,data=uploadoptions) - # print("Upload response status code",response.status_code, response.json()) - if response.status_code == 200: - response_json = response.json() - workoutid = [int(response_json['id'])] - else: - workoutid = [0] - - # this is ugly and needs to be done better - if testing: - workoutid = [ - make_new_workout_from_email(therower, filename, title,testing=testing) - ] - if workoutid[0] and uploadoptions and not 'error' in uploadoptions: - workout = Workout.objects.get(id=workoutid[0]) - uploads.make_private(workout, uploadoptions) - uploads.set_workouttype(workout, uploadoptions) - uploads.do_sync(workout, uploadoptions) - - - if 'raceid' in uploadoptions and workoutid[0] and rower.user.is_staff: - if testing and workoutid[0]: - w = Workout.objects.get(id = workoutid[0]) - w.startdatetime = timezone.now() - w.date = timezone.now().date() - w.save() - try: - race = VirtualRace.objects.get(id=uploadoptions['raceid']) - if race.manager == rower.user: - result = email_submit_race(therower,race,workoutid[0]) - except VirtualRace.DoesNotExist: # pragma: no cover - pass - - - return workoutid - -def get_from_address(message): - - from_address = message.from_address[0].lower() - - if message.encoded: # pragma: no cover - body = message.text.splitlines() - else: - body = message.get_body().splitlines() - - try: - first_line = body[0].lower() - except IndexError: # pragma: no cover - first_line = '' - - try: - first_line = first_line.decode('utf-8') - except AttributeError: # pragma: no cover - pass - - if "quiske" in first_line: # pragma: no cover - match = re.search(r'[\w\.-]+@[\w\.-]+', first_line) - return match.group(0) - - return from_address class Command(BaseCommand): @@ -182,21 +85,11 @@ class Command(BaseCommand): else: # pragma: no cover testing = False - if 'mailbox' in options: - workoutmailbox = Mailbox.objects.get(name=options['mailbox']) - else: # pragma: no cover - workoutmailbox = Mailbox.objects.get(name='workouts') - - if 'failedmailbox' in options: # pragma: no cover - failedmailbox = Mailbox.objects.get(name=options['failedmailbox']) - else: # pragma: no cover - failedmailbox = Mailbox.objects.get(name='Failed') - # Polar try: polar_available = polarstuff.get_polar_notifications() res = polarstuff.get_all_new_workouts(polar_available) - except: + except: # pragma: no cover exc_type, exc_value, exc_traceback = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_traceback) dologging('processemail.log',''.join('!! ' + line for line in lines)) @@ -207,7 +100,7 @@ class Command(BaseCommand): for r in rowers: # pragma: no cover if user_is_not_basic(r.user): c2stuff.get_c2_workouts(r) - except: + except: # pragma: no cover exc_type, exc_value, exc_traceback = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_traceback) dologging('processemail.log',''.join('!! ' + line for line in lines)) @@ -218,7 +111,7 @@ class Command(BaseCommand): for r in rowers: # pragma: no cover if user_is_not_basic(r.user): res = rp3stuff.get_rp3_workouts(r) - except: + except: # pragma: no cover exc_type, exc_value, exc_traceback = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_traceback) dologging('processemail.log',''.join('!! ' + line for line in lines)) @@ -230,105 +123,11 @@ class Command(BaseCommand): s = 'Starting NK Auto Import for user {id}'.format(id=r.user.id) dologging('nklog.log',s) res = nkstuff.get_nk_workouts(r) - except: + except: # pragma: no cover exc_type, exc_value, exc_traceback = sys.exc_info() lines = traceback.format_exception(exc_type, exc_value, exc_traceback) dologging('processemail.log',''.join('!! ' + line for line in lines)) - - messages = Message.objects.filter(mailbox_id = workoutmailbox.id) - message_ids = [m.id for m in messages] - attachments = MessageAttachment.objects.filter( - message_id__in=message_ids - ) - cntr = 0 - for attachment in attachments: - filename, extension = os.path.splitext(attachment.document.name) - extension = extension.lower() -# extension = attachment.document.name[-3:].lower() - try: - message = Message.objects.get(id=attachment.message_id) - if message.encoded: # pragma: no cover -# if message.text: - body = "\n".join(message.text.splitlines()) - else: - body = message.get_body() - - uploadoptions = uploads.upload_options(body) - - from_address = get_from_address(message) - - name = message.subject - # get a list of users - # theusers = User.objects.filter(email=from_address) - rowers = [ - r for r in Rower.objects.all() if r.user.email.lower() == from_address - ] - try: # pragma: no cover - rowers2 = [ - r for r in Rower.objects.all() if from_address in r.emailalternatives - ] - rowers = rowers+rowers2 - except TypeError: - pass - except IOError: # pragma: no cover - rowers = [] - except Message.DoesNotExist: # pragma: no cover - try: - attachment.delete() - except: - pass - for rower in rowers: - if 'zip' in extension: - try: - zip_file = zipfile.ZipFile(attachment.document) - for id,filename in enumerate(zip_file.namelist()): - datafile = zip_file.extract( - filename, path='media/') - if id>0: - title = name+' ('+str(id+1)+')' - else: - title = name - workoutid = processattachment( - rower, datafile, title, uploadoptions, - testing=testing - ) - except BadZipFile: # pragma: no cover - pass - - else: - # move attachment and make workout - - workoutid = processattachment( - rower, attachment.document, name, uploadoptions, - testing=testing - ) - - # We're done with the attachment. It can be deleted - try: - attachment.delete() - except IOError: # pragma: no cover - pass - except WindowsError: # pragma: no cover - if not testing: - time.sleep(2) - try: - attachment.delete() - except WindowsError: - pass - except: # pragma: no cover - message.mailbox = failedmailbox - message.save() - - if message.attachments.exists() is False: - # no attachments, so can be deleted - message.delete() - - messages = Message.objects.all() - for message in messages: - if message.attachments.exists() is False: - message.delete() - # Strava #rowers = Rower.objects.filter(strava_auto_import=True) #for r in rowers: diff --git a/rowers/models.py b/rowers/models.py index 7378789f..5db49f02 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -103,22 +103,22 @@ smoothingchoices = ( def half_year_from_now(ttz=None): if ttz is None: return (datetime.datetime.now(tz=timezone.utc)+timezone.timedelta(days=182)).date() - return (datetime.datetime.utcnow()+timezone.timedelta(days=182)).astimezone(pytz.timezone(ttz)).date() + return (datetime.datetime.utcnow()+timezone.timedelta(days=182)).astimezone(pytz.timezone(ttz)).date() # pragma: no cover def a_week_from_now(ttz=None): if ttz is None: return (datetime.datetime.now(tz=timezone.utc)+timezone.timedelta(days=7)).date() - return (datetime.datetime.utcnow()+timezone.timedelta(days=7)).astimezone(pytz.timezone(ttz)).date() + return (datetime.datetime.utcnow()+timezone.timedelta(days=7)).astimezone(pytz.timezone(ttz)).date() # pragma: no cover def current_day(ttz=None): if ttz is None: return (datetime.datetime.now(tz=timezone.utc)).date() - return datetime.datetime.utcnow().astimezone(pytz.timezone(ttz)).date() + return datetime.datetime.utcnow().astimezone(pytz.timezone(ttz)).date() # pragma: no cover def current_time(ttz=None): # pragma: no cover if ttz is None: return datetime.datetime.now(tz=timezone.utc) - return (datetime.datetime.utcnow()).astimezone(pytz.timezone(ttz)) + return (datetime.datetime.utcnow()).astimezone(pytz.timezone(ttz)) # pragma: no cover class UserFullnameChoiceField(forms.ModelChoiceField): @@ -2188,7 +2188,7 @@ class TrainingMesoCycle(models.Model): if not self.enddate <= self.startdate: super(TrainingMesoCycle,self).save(*args, **kwargs) - else: + else: # pragma: no cover self.enddate = self.startdate super(TrainingMesoCycle,self).save(*args, **kwargs) @@ -2512,18 +2512,18 @@ class PlannedSession(models.Model): elif self.sessiontype != 'coursetest' and self.sessiontype != 'race': self.course = None - if self.enddate < self.startdate: + if self.enddate < self.startdate: # pragma: no cover self.enddate = self.startdate - if self.preferreddate > self.enddate: + if self.preferreddate > self.enddate: # pragma: no cover self.preferreddate = self.enddate - if self.preferreddate < self.startdate: + if self.preferreddate < self.startdate: # pragma: no cover self.preferreddate = self.startdate #super(PlannedSession,self).save(*args, **kwargs) if self.steps: steps = self.steps - elif self.fitfile: + elif self.fitfile: # pragma: no cover steps = steps_read_fit(os.path.join(settings.MEDIA_ROOT,self.fitfile.name)) self.steps = steps diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 8142789e..dd3dbec5 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1145,10 +1145,10 @@ def update_indoorvirtualrace(ps,cd): ps.timezone = timezone_str - if ps.sessiontype == 'fastest_distance': + if ps.sessiontype == 'fastest_distance': # pragma: no cover ps.approximate_distance = ps.sessionvalue - if ps.course is not None: + if ps.course is not None: # pragma: no cover ps.approximate_distance = ps.course.distance ps.save() @@ -1204,7 +1204,7 @@ def update_virtualrace(ps,cd): ps.timezone = timezone_str - if ps.sessiontype == 'fastest_distance': + if ps.sessiontype == 'fastest_distance': # pragma: no cover ps.approximate_distance = ps.sessionvalue if ps.course is not None: @@ -1403,129 +1403,6 @@ def race_can_withdraw(r,race): return True -def email_submit_race(r,race,workoutid): - try: - w = Workout.objects.get(id=workoutid) - except Workout.DoesNotExist: # pragma: no cover - return 0 - - if race.sessionmode == 'time': - wduration = timefield_to_seconds_duration(w.duration) - delta = wduration - (60.*race.sessionvalue) - - if delta > -2 and delta < 2: - w.duration = totaltime_sec_to_string(60.*race.sessionvalue) - w.save() - - - elif race.sessionmode == 'distance': # pragma: no cover - delta = w.distance - race.sessionvalue - - if delta > -5 and delta < 5: - w.distance = race.sessionvalue - w.save() - - - if race_can_register(r,race): - teamname = '' - weightcategory = w.weightcategory - sex = r.sex - if sex == 'not specified': - sex = 'male' - - if not r.birthdate: # pragma: no cover - return 0 - - age = calculate_age(r.birthdate) - - adaptiveclass = r.adaptiveclass - boatclass = w.workouttype - - record = IndoorVirtualRaceResult( - userid = r.id, - teamname=teamname, - race=race, - username = u'{f} {l}'.format( - f = r.user.first_name, - l = r.user.last_name - ), - weightcategory=weightcategory, - adaptiveclass=adaptiveclass, - duration=dt.time(0,0), - boatclass=boatclass, - coursecompleted=False, - sex=sex, - age=age - ) - - record.save() - - result = add_rower_race(r,race) - - otherrecords = IndoorVirtualRaceResult.objects.filter( - race = race) - - - for otherrecord in otherrecords: - otheruser = Rower.objects.get(id=otherrecord.userid) - othername = otheruser.user.first_name+' '+otheruser.user.last_name - registeredname = r.user.first_name+' '+r.user.last_name - if otherrecord.emailnotifications: - job = myqueue( - queue, - handle_sendemail_raceregistration, - otheruser.user.email, othername, - registeredname, - race.name, - race.id - ) - - - if race_can_submit(r,race): - records = IndoorVirtualRaceResult.objects.filter( - userid = r.id, - race=race - ) - - if not records: # pragma: no cover - return 0 - - record = records[0] - - workouts = Workout.objects.filter(id=w.id) - - result,comments,errors,jobid = add_workout_indoorrace( - workouts,race,r,recordid=record.id - ) - - - if result: - otherrecords = IndoorVirtualRaceResult.objects.filter( - race = race) - - for otherrecord in otherrecords: - otheruser = Rower.objects.get(id=otherrecord.userid) - othername = otheruser.user.first_name+' '+otheruser.user.last_name - registeredname = r.user.first_name+' '+r.user.last_name - if otherrecord.emailnotifications: - job = myqueue( - queue, - handle_sendemail_racesubmission, - otheruser.user.email, othername, - registeredname, - race.name, - race.id - ) - - return 1 - else: - return 0 # pragma: no cover - else: # pragma: no cover - - return 0 - - return 0 # pragma: no cover - def race_can_register(r,race): if race.sessiontype in ['race']: diff --git a/rowers/polarstuff.py b/rowers/polarstuff.py index 53699c76..8e18e2a2 100644 --- a/rowers/polarstuff.py +++ b/rowers/polarstuff.py @@ -38,6 +38,7 @@ from django.contrib.auth.decorators import login_required from rowingdata import rowingdata import pandas as pd from rowers.models import Rower,Workout +from rowers.tasks import handle_request_post import rowers.dataprep as dataprep from rowers.dataprep import columndict @@ -47,8 +48,6 @@ from io import StringIO import stravalib from stravalib.exc import ActivityUploadFailed,TimeoutExceeded -from django_mailbox.models import Message,Mailbox,MessageAttachment - from rowsandall_app.settings import ( POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET, ) @@ -115,7 +114,7 @@ def make_authorization_url(): # pragma: no cover return HttpResponseRedirect(url) -def get_polar_notifications(): +def get_polar_notifications(): # pragma: no cover url = baseurl+'/notifications' state = str(uuid4()) auth_string = '{id}:{secret}'.format( @@ -197,7 +196,6 @@ def get_polar_workouts(user): if response.status_code == 201: - workoutsbox = Mailbox.objects.filter(name='workouts')[0] uploadoptions = { 'makeprivate':False, } @@ -231,15 +229,23 @@ def get_polar_workouts(user): with open(filename,'wb') as fop: fop.write(response.content) - msg = Message(mailbox=workoutsbox, - from_header=user.email, - subject = '', - body=bodyyaml) + # post file to upload api + json_data = { + 'title':'', + 'workouttype':'', + 'user':user.id, + 'secret':settings.UPLOAD_SERVICE_SECRET, + 'file':filename, + } + url = reverse('workout_upload_api') - msg.save() - a = MessageAttachment(message=msg,document=filename[6:]) - a.save() + job = myqueue(queuehigh, + handle_request_post, + url, + json_data + ) + exercise_dict['filename'] = filename else: diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index d2ec4af8..9f597ae7 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -11,8 +11,6 @@ import time from time import strftime -from django_mailbox.models import Message,Mailbox,MessageAttachment - import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') @@ -212,157 +210,6 @@ def get_strava_workout_list(user,limit_n=0): return s -# gets all new Strava workouts for a rower -def get_strava_workouts(rower): # pragma: no cover - try: - thetoken = strava_open(rower.user) - except NoTokenError: - return 0 - - res = get_strava_workout_list(rower.user,limit_n=10) - - if (res.status_code != 200): - return 0 - else: - stravaids = [int(item['id']) for item in res.json()] - stravadata = [{ - 'id':int(item['id']), - 'elapsed_time':item['elapsed_time'], - 'start_date':item['start_date'], - } for item in res.json()] - - alldata = {} - for item in res.json(): - alldata[item['id']] = item - - - wfailed = Workout.objects.filter(user=rower,uploadedtostrava=-1) - - for w in wfailed: - for item in stravadata: - elapsed_time = item['elapsed_time'] - start_date = item['start_date'] - stravaid = item['id'] - - if arrow.get(start_date) == arrow.get(w.startdatetime): - dd = datetime.min + timedelta( - seconds=int(elapsed_time) - ) - - - delta = datetime.combine(datetime.min,datetime.time(dd))-datetime.combine(datetime.min,w.duration) - - if delta < timedelta(minutes=2): - w.uploadedtostrava = int(stravaid) - w.save() - - knownstravaids = [ - w.uploadedtostrava for w in Workout.objects.filter(user=rower) - ] - - tombstones = [ - t.uploadedtostrava for t in TombStone.objects.filter(user=rower) - ] - - knownstravaids = uniqify(knownstravaids+tombstones) - - newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids] - - for stravaid in newids: - result = create_async_workout(alldata,rower.user,stravaid) - - return 1 - -def create_async_workout(alldata,user,stravaid,debug=False): - data = alldata[stravaid] - r = Rower.objects.get(user=user) - distance = data['distance'] - stravaid = data['id'] - try: - workouttype = mytypes.stravamappinginv[data['type']] - except: # pragma: no cover - workouttype = 'other' - - if workouttype not in [x[0] for x in Workout.workouttypes]: # pragma: no cover - workouttype = 'other' - - if workouttype.lower() == 'rowing': # pragma: no cover - workouttype = 'rower' - if 'summary_polyline' in data['map']: - workouttype = 'water' - - - try: - comments = data['comments'] - except: - comments = ' ' - - try: - thetimezone = tz(data['timezone']) - except: - thetimezone = 'UTC' - - try: - rowdatetime = iso8601.parse_date(data['date_utc']) - except KeyError: - rowdatetime = iso8601.parse_date(data['start_date']) - except ParseError: # pragma: no cover - rowdatetime = iso8601.parse_date(data['date']) - - try: - c2intervaltype = data['workout_type'] - - except KeyError: # pragma: no cover - c2intervaltype = '' - - try: - title = data['name'] - except KeyError: # pragma: no cover - title = "" - try: - t = data['comments'].split('\n', 1)[0] - title += t[:20] - except: - title = '' - - workoutdate = rowdatetime.astimezone( - pytz.timezone(thetimezone) - ).strftime('%Y-%m-%d') - - starttime = rowdatetime.astimezone( - pytz.timezone(thetimezone) - ).strftime('%H:%M:%S') - - totaltime = data['elapsed_time'] - duration = dataprep.totaltime_sec_to_string(totaltime) - - weightcategory = 'hwt' - - # Create CSV file name and save data to CSV file - csvfilename ='media/mailbox_attachments/{code}_{importid}.csv'.format( - importid=stravaid, - code = uuid4().hex[:16] - ) - - - - # Check if workout has stroke data, and get the stroke data - - starttimeunix = arrow.get(rowdatetime).timestamp() - - result = handle_strava_import_stroke_data( - title, - user.email, - r.stravatoken, - stravaid, - starttimeunix, - csvfilename, - workouttype = workouttype, - boattype = '1x' - ) - - return 1 - from rowers.utils import get_strava_stream def async_get_workout(user,stravaid): @@ -559,174 +406,3 @@ def workout_strava_upload(user,w, quick=False,asynchron=True): os.remove(tcxfile) return message,stravaid return message,stravaid # pragma: no cover - - - -def handle_strava_import_stroke_data(title, - useremail, - stravatoken, - stravaid, - starttimeunix, - csvfilename,debug=True, - workouttype = 'rower', - boattype = '1x', - **kwargs): - # ready to fetch. Hurray - - fetchresolution = 'high' - series_type = 'time' - authorizationstring = str('Bearer ' + stravatoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json', - 'resolution': 'medium',} - url = "https://www.strava.com/api/v3/activities/"+str(stravaid) - workoutsummary = requests.get(url,headers=headers).json() - - workoutsummary['timezone'] = "Etc/UTC" - startdatetime = workoutsummary['start_date'] - - r = type('Rower', (object,), {"stravatoken": stravatoken}) - - spm = get_strava_stream(r,'cadence',stravaid) - t = get_strava_stream(r,'time',stravaid) - - try: - hr = get_strava_stream(r,'heartrate',stravaid) - except JSONDecodeError: # pragma: no cover - hr = 0*spm - - try: - velo = get_strava_stream(r,'velocity_smooth',stravaid) - except JSONDecodeError: # pragma: no cover - velo = 0*t - - try: - d = get_strava_stream(r,'distance',stravaid) - except JSONDecodeError: # pragma: no cover - d = 0*t - - try: - coords = get_strava_stream(r,'latlng',stravaid) - except JSONDecodeError: # pragma: no cover - coords = 0*t - try: - power = get_strava_stream(r,'watts',stravaid) - except JSONDecodeError: # pragma: no cover - power = 0*t - - if t is not None: - nr_rows = len(t) - else: # pragma: no cover - return 0 - - if nr_rows == 0: # pragma: no cover - return 0 - - if d is None: # pragma: no cover - d = 0*t - - if spm is None: # pragma: no cover - spm = np.zeros(nr_rows) - - if power is None: # pragma: no cover - power = np.zeros(nr_rows) - - if hr is None: # pragma: no cover - hr = np.zeros(nr_rows) - - if velo is None: # pragma: no cover - velo = np.zeros(nr_rows) - - - f = np.diff(t).mean() - if f != 0: - windowsize = 2*(int(10./(f)))+1 - else: # pragma: no cover - windowsize = 1 - - if windowsize > 3 and windowsize < len(velo): - velo2 = savgol_filter(velo,windowsize,3) - else: # pragma: no cover - velo2 = velo - - if coords is not None: - try: - lat = coords[:,0] - lon = coords[:,1] - if lat.std() == 0 and lon.std() == 0 and workouttype == 'water': # pragma: no cover - workouttype = 'rower' - except IndexError: # pragma: no cover - lat = np.zeros(len(t)) - lon = np.zeros(len(t)) - if workouttype == 'water': - workouttype = 'rower' - else: # pragma: no cover - lat = np.zeros(len(t)) - lon = np.zeros(len(t)) - if workouttype == 'water': - workouttype = 'rower' - - strokelength = velo*60./(spm) - strokelength[np.isinf(strokelength)] = 0.0 - - pace = 500./(1.0*velo2) - pace[np.isinf(pace)] = 0.0 - - unixtime = starttimeunix+t - - strokedistance = 60.*velo2/spm - - if workouttype == 'rower' and pd.Series(power).mean() == 0: # pragma: no cover - power = 2.8*(velo2**3) - - nr_strokes = len(t) - - df = pd.DataFrame({'TimeStamp (sec)':unixtime, - ' ElapsedTime (sec)':t, - ' Horizontal (meters)':d, - ' Stroke500mPace (sec/500m)':pace, - ' Cadence (stokes/min)':spm, - ' HRCur (bpm)':hr, - ' latitude':lat, - ' longitude':lon, - ' StrokeDistance (meters)':strokelength, - 'cum_dist':d, - ' DragFactor':np.zeros(nr_strokes), - ' DriveLength (meters)':np.zeros(nr_strokes), - ' StrokeDistance (meters)':strokedistance, - ' DriveTime (ms)':np.zeros(nr_strokes), - ' StrokeRecoveryTime (ms)':np.zeros(nr_strokes), - ' AverageDriveForce (lbs)':np.zeros(nr_strokes), - ' PeakDriveForce (lbs)':np.zeros(nr_strokes), - ' lapIdx':np.zeros(nr_strokes), - ' Power (watts)':power, - }) - - - - - df.sort_values(by='TimeStamp (sec)',ascending=True) - - res = df.to_csv(csvfilename,index_label='index') - - workoutsbox = Mailbox.objects.filter(name='workouts')[0] - - body = """stravaid {stravaid} -workouttype {workouttype} -boattype {boattype}""".format( - stravaid=stravaid, - workouttype=workouttype, - boattype=boattype -) - - msg = Message(mailbox=workoutsbox, - from_header=useremail, - subject=title, - body=body) - msg.save() - - a = MessageAttachment(message=msg,document=csvfilename[6:]) - a.save() - - return res diff --git a/rowers/tasks.py b/rowers/tasks.py index a07a41a0..73f2595b 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -284,6 +284,12 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|',workouttype='rower'): return sums,sa,results +@app.task +def handle_request_post(url, data,debug=False, **kwargs): # pragma: no cover + response = requests.post(url,data) + return response.status_code + + @app.task def add(x, y): # pragma: no cover return x + y @@ -1363,7 +1369,8 @@ def handle_send_email_transaction( @app.task def handle_send_email_instantplan_notification( - username, useremail, amount, planname,startdate, enddate, **kwargs): + username, useremail, amount, planname,startdate, enddate, **kwargs + ): # pragma: no cover if 'debug' in kwargs: # pragma: no cover debug = kwargs['debug'] @@ -1531,7 +1538,7 @@ def handle_sendemail_raceregistration( def handle_sendemail_coursesucceed( useremail, username, logfile, workoutid, **kwargs -): +): # pragma: no cover if 'debug' in kwargs: # pragma: no cover debug = kwargs['debug'] else: @@ -3240,7 +3247,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone splitdata = None distance = data['distance'] - try: + try: # pragma: no cover rest_distance = data['rest_distance'] rest_time = data['rest_time']/10. except KeyError: @@ -3319,7 +3326,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone #dologging('debuglog.log',json.dumps(s.json())) try: strokedata = pd.DataFrame.from_dict(s.json()['data']) - except AttributeError: + except AttributeError: # pragma: no cover dologging('debuglog.log','No stroke data in stroke data') return 0 @@ -3327,7 +3334,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone res = make_cumvalues(0.1*strokedata['t']) cum_time = res[0] lapidx = res[1] - except KeyError: + except KeyError: # pragma: no cover dologging('debuglog.log','No time values in stroke data') return 0 @@ -3633,7 +3640,7 @@ def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debu 'power':power, 'strokelength':strokelength, }) - except ValueError: + except ValueError: # pragma: no cover return 0 try: @@ -3648,7 +3655,7 @@ def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debu try: if 'summary_polyline' in workoutsummary['map'] and workouttype=='rower': # pragma: no cover workouttype = 'water' - except KeyError: + except KeyError: # pragma: no cover pass try: diff --git a/rowers/templates/strava_list_import.html b/rowers/templates/strava_list_import.html index 1fe1ea27..c817a092 100644 --- a/rowers/templates/strava_list_import.html +++ b/rowers/templates/strava_list_import.html @@ -8,15 +8,6 @@

Available on Strava

{% if workouts %}
    -
  • - Import all NEW -
  • -
  • -

    This imports all workouts that have not been imported to rowsandall.com. - The action may take a longer time to process, so please be patient. Click on Import in the list below to import an individual workout. -

    -
  • -
  • {% csrf_token %} diff --git a/rowers/tests/mocks.py b/rowers/tests/mocks.py index 045fef9c..23796818 100644 --- a/rowers/tests/mocks.py +++ b/rowers/tests/mocks.py @@ -57,7 +57,6 @@ from rowers.dataprep import delete_strokedata from redis import StrictRedis redis_connection = StrictRedis() -from django_mailbox.models import Mailbox,MessageAttachment,Message def mocked_grpc(*args, **kwargs): class insecure_channel: diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 49083d1b..7d4f8187 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -85,7 +85,6 @@ from importlib import import_module from redis import StrictRedis redis_connection = StrictRedis() -from django_mailbox.models import Mailbox,MessageAttachment,Message from rowers.tests.mocks import * diff --git a/rowers/tests/test_api.py b/rowers/tests/test_api.py index 76c5bbc6..bbb9892a 100644 --- a/rowers/tests/test_api.py +++ b/rowers/tests/test_api.py @@ -37,10 +37,6 @@ class OwnApi(TestCase): gdproptindate=timezone.now(), rowerplan='coach',subscription_id=1) - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() self.c = Client() self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) diff --git a/rowers/tests/test_braintree.py b/rowers/tests/test_braintree.py index 9b938dff..37c08295 100644 --- a/rowers/tests/test_braintree.py +++ b/rowers/tests/test_braintree.py @@ -69,10 +69,6 @@ class BraintreeUnits(TestCase): gdproptindate=timezone.now(), rowerplan='coach',subscription_id=1) - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() self.pp = PaidPlan.objects.create(price=0,paymentprocessor='braintree') self.p2 = PaidPlan.objects.create(price=25,paymentprocessor='braintree') diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py index ea6fdfec..2884d93b 100644 --- a/rowers/tests/test_emails.py +++ b/rowers/tests/test_emails.py @@ -29,18 +29,7 @@ class EmailUpload(TestCase): rowerplan='coach') nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts1') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "run", - body = """ -workout run - """) - m.save() a2 = 'media/mailbox_attachments/colin3.csv' copy('rowers/tests/testdata/emails/colin.csv',a2) a3 = 'media/mailbox_attachments/colin4.csv' @@ -52,8 +41,6 @@ workout run a6 = 'media/mailbox_attachments/colin7.csv' copy('rowers/tests/testdata/emails/colin.csv',a6) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() def tearDown(self): for filename in os.listdir('media/mailbox_attachments'): @@ -64,6 +51,7 @@ workout run except (IOError,FileNotFoundError,OSError): pass + @patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) def test_uploadapi(self,mocked_sqlalchemy,mocked_getsmallrowdata_db): @@ -168,266 +156,7 @@ workout run self.assertEqual(response.status_code,403) - @patch('rowers.dataprep.create_engine') - @patch('rowers.polarstuff.get_polar_notifications') - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - def test_emailupload( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True,mailbox='workouts1') - self.assertIn('Successfully processed email attachments',out.getvalue()) - ws = Workout.objects.filter(name="run") - - self.assertEqual(len(ws),1) - w = ws[0] - self.assertEqual(w.workouttype,'Run') - -@override_settings(TESTING=True) -class ZipEmailUpload(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() - ) - - self.theadmin = UserFactory(is_staff=True) - self.rtheadmin = Rower.objects.create(user=self.theadmin, - birthdate = faker.profile()['birthdate'], - gdproptin=True,surveydone=True, - gdproptindate=timezone.now(), - rowerplan='coach') - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts1') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "Sprint", - body = """ -workout water - """) - m.save() - a2 = 'media/mailbox_attachments/zipfile.zip' - copy('rowers/tests/testdata/zipfile.zip',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - for filename in os.listdir('media/mailbox_attachments'): - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,FileNotFoundError,OSError): - pass - - @patch('rowers.dataprep.create_engine') - @patch('rowers.polarstuff.get_polar_notifications') - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - def test_emailupload( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True,mailbox='workouts1') - self.assertIn('Successfully processed email attachments',out.getvalue()) - - ws = Workout.objects.all() - - self.assertEqual(len(ws),5) - w = ws[4] - self.assertEqual(w.name,'Sprint (5)') - - -@override_settings(TESTING=True) -class EmailUniCodeUpload(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() - ) - - self.theadmin = UserFactory(is_staff=True) - self.rtheadmin = Rower.objects.create(user=self.theadmin, - birthdate = faker.profile()['birthdate'], - gdproptin=True,surveydone=True, - gdproptindate=timezone.now(), - rowerplan='coach') - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts2') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "Třeboň", - body = """ -workout water - """) - m.save() - a2 = 'media/mailbox_attachments/colin4a.csv' - copy('rowers/tests/testdata/emails/colin.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - filename = 'colin4a.csv' - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,FileNotFoundError,OSError): - pass - - @patch('rowers.dataprep.create_engine') - @patch('rowers.polarstuff.get_polar_notifications') - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - def test_emailupload( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True,mailbox='workouts2') - self.assertIn('Successfully processed email attachments',out.getvalue()) - - ws = Workout.objects.filter(name="Třeboň") - - self.assertEqual(len(ws),1) - w = ws[0] - self.assertEqual(w.workouttype,'water') - -@override_settings(TESTING=True) -class EmailBikeErgUpload(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() - ) - - self.theadmin = UserFactory(is_staff=True) - self.rtheadmin = Rower.objects.create(user=self.theadmin, - birthdate = faker.profile()['birthdate'], - gdproptin=True,surveydone=True, - gdproptindate=timezone.now(), - rowerplan='coach') - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts2') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "bikeerg", - body = """ -workout bikeerg - """) - m.save() - a2 = 'media/mailbox_attachments/colin3.csv' - copy('rowers/tests/testdata/emails/colin.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - filename = 'colin3.csv' - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,FileNotFoundError,OSError): - pass - - @patch('rowers.dataprep.create_engine') - @patch('rowers.polarstuff.get_polar_notifications') - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - def test_emailupload( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True,mailbox='workouts2') - self.assertIn('Successfully processed email attachments',out.getvalue()) - - ws = Workout.objects.filter(name="bikeerg") - - self.assertEqual(len(ws),1) - w = ws[0] - self.assertEqual(w.workouttype,'bikeerg') - -@override_settings(TESTING=True) -class EmailBikeUpload(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() - ) - - self.theadmin = UserFactory(is_staff=True) - self.rtheadmin = Rower.objects.create(user=self.theadmin, - birthdate = faker.profile()['birthdate'], - gdproptin=True,surveydone=True, - gdproptindate=timezone.now(), - rowerplan='coach') - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts3') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "bike", - body = """ -workout bike - """) - m.save() - a2 = 'media/mailbox_attachments/colin4.csv' - copy('rowers/tests/testdata/emails/colin.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - filename = 'colin4.csv' - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,FileNotFoundError,OSError): - pass - - @patch('rowers.dataprep.create_engine') - @patch('rowers.polarstuff.get_polar_notifications') - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - def test_emailupload( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True,mailbox='workouts3') - self.assertIn('Successfully processed email attachments',out.getvalue()) - - ws = Workout.objects.filter(name="bike") - - self.assertEqual(len(ws),1) - w = ws[0] - self.assertEqual(w.workouttype,'bike') @@ -451,48 +180,17 @@ class EmailTests(TestCase): rowerplan='coach') nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts4') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - - for filename in os.listdir(u'rowers/tests/testdata/emails'): - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = filename, - body=""" ---- -workouttype: water -boattype: 4x -... - """) - m.save() - a2 = 'media/mailbox_attachments/'+filename - copy(u'rowers/tests/testdata/emails/'+filename,a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "3x(5min/2min)/r2 \r2", - body = """ -workout water - """) - m.save() - a2 = 'media/mailbox_attachments/colin2.csv' + a2 = 'media/mailbox_attachments/colin3.csv' copy('rowers/tests/testdata/emails/colin.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() + a3 = 'media/mailbox_attachments/colin4.csv' + copy('rowers/tests/testdata/emails/colin.csv',a3) + a4 = 'media/mailbox_attachments/colin5.csv' + copy('rowers/tests/testdata/emails/colin.csv',a4) + a5 = 'media/mailbox_attachments/colin6.csv' + copy('rowers/tests/testdata/emails/colin.csv',a5) + a6 = 'media/mailbox_attachments/colin7.csv' + copy('rowers/tests/testdata/emails/colin.csv',a6) - m = Message(mailbox=workoutsbox, - from_header = self.theadmin.email, - subject = "johnsworkout", - body = """ -user john -race 1 - """) - m.save() def tearDown(self): for filename in os.listdir('media/mailbox_attachments'): @@ -512,79 +210,3 @@ race 1 out = StringIO() call_command('processemail', stdout=out,testing=True,mailbox='workouts4') self.assertIn('Successfully processed email attachments',out.getvalue()) - - - -@override_settings(TESTING=True) -class EmailAdminUpload(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now(), - birthdate = faker.profile()['birthdate'] - ) - - self.theadmin = UserFactory(is_staff=True) - self.rtheadmin = Rower.objects.create(user=self.theadmin, - birthdate = faker.profile()['birthdate'], - gdproptin=True,surveydone=True, - gdproptindate=timezone.now(), - rowerplan='coach') - - self.race = RaceFactory(manager = self.theadmin) - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts5') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - m = Message(mailbox=workoutsbox, - from_header = self.theadmin.email, - subject = "johnsworkout", - body = """ -user john -race 1 - """) - m.save() - a2 = 'media/mailbox_attachments/minute.csv' - copy('rowers/tests/testdata/minute.csv',a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - for filename in os.listdir('media/mailbox_attachments'): - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (IOError,FileNotFoundError,OSError): - pass - - @patch('rowers.dataprep.create_engine') - @patch('rowers.polarstuff.get_polar_notifications') - @patch('rowers.c2stuff.requests.get', side_effect=mocked_requests) - @patch('rowers.c2stuff.requests.post', side_effect=mocked_requests) - def test_email_admin_upload( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True,mailbox='workouts5') - self.assertIn('Successfully processed email attachments',out.getvalue()) - - ws = Workout.objects.filter(name="johnsworkout") - - self.assertEqual(len(ws),1) - - w = ws[0] - self.assertEqual(w.user.user.username,u'john') - - results = IndoorVirtualRaceResult.objects.filter( - race=self.race) - - self.assertEqual(len(results),1) - result = results[0] - - self.assertTrue(result.coursecompleted) diff --git a/rowers/tests/test_imports.py b/rowers/tests/test_imports.py index 151a36a6..d46de827 100644 --- a/rowers/tests/test_imports.py +++ b/rowers/tests/test_imports.py @@ -1258,62 +1258,3 @@ class TPObjects(DjangoTestCase): self.assertEqual(response.url, '/rowers/workout/'+encoded1+'/edit/') self.assertEqual(response.status_code, 302) - - -#@pytest.mark.django_db -@override_settings(TESTING=True) -class AutoExportTests(TestCase): - def setUp(self): - redis_connection.publish('tasks','KILL') - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u,gdproptin=True,surveydone=True, - gdproptindate=timezone.now() - ) - - r.c2_auto_export = True - r.sporttracks_auto_export = True - r.mapmyfitness_auto_export = True - r.trainingpeaks_auto_export = True - - r.save() - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - - filename = 'testdata.csv' - - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = filename, - body=""" ---- -workouttype: water -boattype: 2x -... - """) - m.save() - a2 = 'media/mailbox_attachments/'+filename - copy('rowers/tests/testdata/'+filename,a2) - a = MessageAttachment(message=m,document=a2[6:]) - a.save() - - def tearDown(self): - for filename in os.listdir('media/mailbox_attachments'): - path = os.path.join('media/mailbox_attachments/',filename) - if not os.path.isdir(path): - try: - os.remove(path) - except (FileNotFoundError,OSError): - pass - - @patch('rowers.tpstuff.requests.post', side_effect=mocked_requests) - @patch('rowers.tpstuff.requests.get', side_effect=mocked_requests) - def test_emailprocessing(self, mock_post, mock_get): - out = StringIO() - call_command('processemail', stdout=out, testing=True) - self.assertIn('Successfully processed email attachments',out.getvalue()) diff --git a/rowers/tests/test_races.py b/rowers/tests/test_races.py index 53fa254b..43e452a4 100644 --- a/rowers/tests/test_races.py +++ b/rowers/tests/test_races.py @@ -586,6 +586,10 @@ class ChallengesTest(TestCase): 'course': self.ThyroBaantje.id } + form = CourseSelectForm(formdata) + + self.assertTrue(form.is_valid()) + response = self.c.post(url, formdata, follow=True) self.assertEqual(response.status_code, 200) @@ -813,6 +817,7 @@ class ChallengesTest(TestCase): 'yparam': 'spm', 'plottype': 'line', 'teamid':0, + 'course':self.ThyroBaantje.id, } form = ChartParamChoiceForm(form_data) self.assertTrue(form.is_valid()) @@ -829,6 +834,7 @@ class ChallengesTest(TestCase): 'yparam': 'spm', 'plottype': 'line', 'teamid':0, + 'course':self.ThyroBaantje.id } form = ChartParamChoiceForm(form_data) self.assertTrue(form.is_valid()) diff --git a/rowers/tests/test_unit_tests.py b/rowers/tests/test_unit_tests.py index 9deae35c..56cf7b56 100644 --- a/rowers/tests/test_unit_tests.py +++ b/rowers/tests/test_unit_tests.py @@ -35,10 +35,6 @@ class OtherUnitTests(TestCase): defaulttimezone='US/Pacific', rowerplan='coach') - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() # Test get_dates_timeperiod def test_get_dates_timeperiod(self): @@ -99,20 +95,6 @@ class OtherUnitTests(TestCase): self.assertTrue('US/Pacific' in str(startdate.tzinfo)) - @patch('rowers.tasks.requests.get',side_effect=mocked_requests) - def test_strava_asyncworkout(self,mock_get): - with open('rowers/tests/testdata/stravaworkoutlist.txt','r') as f: - s = f.read() - - jsondata = json.loads(s) - alldata = {} - for item in jsondata: - alldata[item['id']] = item - - theid = jsondata[0]['id'] - - workoutid = stravastuff.create_async_workout(alldata,self.r.user,theid) - self.assertEqual(workoutid,1) def test_summaryfromsplitdata(self): with open('rowers/tests/testdata/c2splits.json','r') as f: diff --git a/rowers/tests/test_uploads.py b/rowers/tests/test_uploads.py index 649e8d63..196c69b7 100644 --- a/rowers/tests/test_uploads.py +++ b/rowers/tests/test_uploads.py @@ -132,6 +132,46 @@ class ViewTest(TestCase): except (FileNotFoundError,OSError): pass + @patch('rowers.dataprep.create_engine') + @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) + def test_upload_view_sled_bg(self, mocked_sqlalchemy,mocked_getsmallrowdata_db): + login = self.c.login(username='john',password='koeinsloot') + self.assertTrue(login) + + filename = 'rowers/tests/testdata/testdata.csv' + f = open(filename,'rb') + file_data = {'file': f} + form_data = { + 'title':'test', + 'workouttype':'rower', + 'boattype':'1x', + 'notes':'aap noot mies', + 'rpe':4, + 'make_plot':False, + 'rpe':6, + 'upload_to_c2':False, + 'plottype':'timeplot', + 'landingpage':'workout_edit_view', + 'raceid':0, + 'file': f, + 'offline': True, + } + + request = RequestFactory() + request.user = self.u + form = DocumentsForm(form_data,file_data) + + optionsform = UploadOptionsForm(form_data,request=request) + self.assertTrue(optionsform.is_valid()) + + response = self.c.post('/rowers/workout/upload/', form_data, follow=True) + + self.assertRedirects(response, expected_url=reverse('workout_upload_view'), + status_code=302,target_status_code=200) + + + + f.close() diff --git a/rowers/tests/viewnames.csv b/rowers/tests/viewnames.csv index 6f14f22d..a9b88233 100644 --- a/rowers/tests/viewnames.csv +++ b/rowers/tests/viewnames.csv @@ -87,9 +87,7 @@ 97,114,workout_undo_smoothenpace_view,unsmoothen pace,TRUE,403,pro,302,302,pro,403,403,coach,302,403,FALSE,FALSE,TRUE,TRUE,TRUE, 98,115,workout_c2import_view,list workouts to be imported (test stops at notokenerror),TRUE,302,basic,302,302,basic,403,403,coach,302,403,FALSE,TRUE,FALSE,TRUE,TRUE, 99,120,workout_stravaimport_view,list workouts to be imported (test stops at notokenerror),TRUE,302,basic,302,302,basic,403,403,coach,302,403,FALSE,TRUE,FALSE,TRUE,TRUE, -100,122,workout_getc2workout_all,gets all C2 workouts (now redirects due to NoTokenError,TRUE,302,basic,302,302,FALSE,302,302,FALSE,302,302,FALSE,FALSE,FALSE,TRUE,TRUE, 101,124,workout_getimportview,imports a workout from third party,TRUE,200,basic,200,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE, -102,125,workout_getstravaworkout_all,gets all C2 workouts (now redirects due to NoTokenError,TRUE,302,basic,302,302,FALSE,302,302,FALSE,302,302,FALSE,FALSE,FALSE,TRUE,TRUE, 103,126,workout_getstravaworkout_next,gets all strava workouts,TRUE,302,basic,302,302,FALSE,200,302,FALSE,200,302,FALSE,FALSE,FALSE,FALSE,FALSE, 104,127,workout_sporttracksimport_view,list workouts to be imported (test stops at notokenerror),TRUE,302,basic,302,302,basic,403,403,coach,302,403,FALSE,TRUE,FALSE,TRUE,TRUE, 105,129,workout_getsporttracksworkout_all,gets all C2 workouts (now redirects due to NoTokenError,TRUE,302,basic,302,302,FALSE,302,302,FALSE,302,302,FALSE,FALSE,FALSE,TRUE,TRUE, diff --git a/rowers/uploads.py b/rowers/uploads.py index a1847e20..447a5e48 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -48,360 +48,11 @@ from rowers.utils import ( str2bool,range_to_color_hex,absolute,myqueue,NoTokenError ) -def cleanbody(body): - try: - body = body.decode('utf-8') - except AttributeError: # pragma: no cover - pass - - 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()): # pragma: no cover - return tester.match(line.lower()).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()): # pragma: no cover - if tester2.match(line.lower()): - return 'distanceplot' - if tester3.match(line.lower()): - return 'timeplot' - if tester3.match(line.lower()): - return 'pieplot' - -def matchuser(line): - testert = '^(user)' - tester = re.compile(testert) - if tester.match(line.lower()): - words = line.split() - return words[1] - - return None - -def matchrace(line): - testert = '^(race)' - tester = re.compile(testert) - if tester.match(line.lower()): - words = line.split() - try: - return int(words[1]) - except: # pragma: no cover - return None - - return None - -def matchsync(line): - results = [] - tester = '((sync)|(synchronization)|(export))' - tester2 = tester+'(.*)((c2)|(concept2)|(logbook))' - tester3 = tester+'(.*)((tp)|(trainingpeaks))' - tester4 = tester+'(.*)(strava)' - tester5 = tester+'(.*)((st)|(sporttracks))' - - tester = re.compile(tester) - - if tester.match(line.lower()): # pragma: no cover - 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_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()): # pragma: no cover - 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_ordered.items(): - str1 = '^(workout)(.*)({a})'.format( - a = typ.lower() - ) - testert = re.compile(str1) - if testert.match(line.lower()): - uploadoptions['workouttype'] = typ - break - 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 - break - - return uploadoptions - -def getprivateoptions_body2(uploadoptions,body): - tester = re.compile('^(priva)') - for line in body.splitlines(): - if tester.match(line.lower()): # pragma: no cover - 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: # pragma: no cover - uploadoptions['workoutsource'] = workoutsource - - return uploadoptions - -def getplotoptions_body2(uploadoptions,body): - for line in body.splitlines(): - chart = matchchart(line) - if chart: # pragma: no cover - uploadoptions['make_plot'] = True - uploadoptions['plottype'] = chart - - return uploadoptions - -def getuseroptions_body2(uploadoptions,body): - for line in body.splitlines(): - user = matchuser(line) - if user: - uploadoptions['username'] = user - - return uploadoptions - -def getraceoptions_body2(uploadoptions,body): - for line in body.splitlines(): - raceid = matchrace(line) - if raceid: - uploadoptions['raceid'] = raceid - - 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: # pragma: no cover - uploadoptions[r] = True - - return uploadoptions - -def getsyncoptions(uploadoptions,values): # pragma: no cover - 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 - except AttributeError: - pass - - return uploadoptions - -def getplotoptions(uploadoptions,value): # pragma: no cover - 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): # pragma: no cover - workouttype = 'rower' - for typ,verb in workouttypes_ordered.items(): - if value == typ: - workouttype = typ - break - if value == verb: - workouttype = typ - break - - uploadoptions[key] = workouttype - - return uploadoptions - -def getboattype(uploadoptions,value,key): # pragma: no cover - boattype = '1x' - for type,verb in boattypes: - if value == type: - boattype = type - if value == verb: - boattype = type - - uploadoptions[key] = boattype - - return uploadoptions - -def getuser(uploadoptions,value,key): # pragma: no cover - uploadoptions['username'] = value - - return uploadoptions - -def getrace(uploadoptions,value,key): # pragma: no cover - try: - raceid = int(value) - uploadoptions['raceid'] = raceid - except: - pass - - return uploadoptions - -def getsource(uploadoptions,value,key): # pragma: no cover - 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): # pragma: no cover - 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 = { - 'boattype':'1x', - 'workouttype': 'rower', - } - body = cleanbody(body) - try: - yml = (yaml.safe_load(body)) - if yml and 'fromuploadform' in yml: # pragma: no cover - return yml - try: - for key, value in yml.iteritems(): # pragma: no cover - 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') - if 'username' in lowkey: - uploadoptions = getuser(uploadoptions,value,'username') - if 'raceid' in lowkey: - uploadoptions = getraceid(uploadoptions,value,'raceid') - 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) - uploadoptions = gettypeoptions_body2(uploadoptions,body) - uploadoptions = getstravaid(uploadoptions,body) - uploadoptions = getworkoutsources(uploadoptions,body) - uploadoptions = getuseroptions_body2(uploadoptions,body) - uploadoptions = getraceoptions_body2(uploadoptions,body) - except IOError: # pragma: no cover - 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 == {}: # pragma: no cover - 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 == '': @@ -489,33 +140,7 @@ import rowers.tpstuff as tpstuff from rowers.rower_rules import is_promember -def set_workouttype(w,options): - try: - w.workouttype = options['workouttype'] - w.save() - except KeyError: # pragma: no cover - pass - try: - w.boattype = options['boattype'] - w.save() - except KeyError: # pragma: no cover - pass - return 1 - -def set_workoutsource(w,options): # pragma: no cover - try: - w.workoutsource = options['workoutsource'] - w.save() - except KeyError: # pragma: no cover - pass - -def make_private(w,options): # pragma: no cover - if 'makeprivate' in options and options['makeprivate']: - w.privacy = 'hidden' - w.save() - - return 1 def do_sync(w,options, quick=False): @@ -587,7 +212,7 @@ def do_sync(w,options, quick=False): if w.duplicate: return 0 - if do_c2_export: + if do_c2_export: # pragma: no cover try: message,id = c2stuff.workout_c2_upload(w.user.user,w,asynchron=True) except NoTokenError: @@ -628,7 +253,7 @@ def do_sync(w,options, quick=False): except KeyError: upload_to_tp = False - if do_tp_export: + if do_tp_export: # pragma: no cover try: message,id = sporttracksstuff.workout_sporttracks_upload( w.user.user,w,asynchron=True, diff --git a/rowers/urls.py b/rowers/urls.py index 8e997c17..25bbf732 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -510,7 +510,7 @@ urlpatterns = [ re_path(r'^workout/rp3import/all/$',views.workout_getrp3workout_all,name='workout_getrp3workout_all'), re_path(r'^workout/(?P\w+.*)import/(?P\d+)/$',views.workout_getimportview,name='workout_getimportview'), re_path(r'^workout/(?P\w+.*)import/(?P\d+)/async/$',views.workout_getimportview,{'do_async':True},name='workout_getimportview'), - re_path(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'), +# re_path(r'^workout/stravaimport/all/$',views.workout_getstravaworkout_all,name='workout_getstravaworkout_all'), re_path(r'^workout/stravaimport/next/$',views.workout_getstravaworkout_next,name='workout_getstravaworkout_next'), re_path(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'), re_path(r'^workout/sporttracksimport/user/(?P\d+)/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'), diff --git a/rowers/utils.py b/rowers/utils.py index 14c10d99..b6feb80a 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -120,7 +120,7 @@ def dologging(filename,s): f.write(' ') f.write(s) -def to_pace(pace): +def to_pace(pace): # pragma: no cover minutes, seconds = divmod(pace,60) seconds, rest = divmod(seconds, 1) tenths = int(rest*10) @@ -518,7 +518,7 @@ def custom_exception_handler(exc,message): return res def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high',authorizationstring=''): - if r is not None: + if r is not None: # pragma: no cover authorizationstring = str('Bearer ' + r.stravatoken) headers = {'Authorization': authorizationstring, 'user-agent': 'sanderroosendaal', @@ -569,7 +569,7 @@ def allsundays(startdate,enddate): yield d d += datetime.timedelta(days=7) -def steps_read_fit(filename,name='',sport='Custom'): +def steps_read_fit(filename,name='',sport='Custom'): # pragma: no cover authorizationstring = 'Bearer '+settings.WORKOUTS_FIT_TOKEN url = settings.WORKOUTS_FIT_URL+"/tojson" headers = {'Authorization':authorizationstring} @@ -622,7 +622,7 @@ def step_to_time_dist(step,avgspeed = 3.2,ftp=200,ftspm=25,ftv=3.7): distance = avgspeed*seconds rscore = 60.*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) diff --git a/rowers/views/apiviews.py b/rowers/views/apiviews.py index 7ff2f1ca..ab78a6f7 100644 --- a/rowers/views/apiviews.py +++ b/rowers/views/apiviews.py @@ -5,7 +5,6 @@ from __future__ import unicode_literals from rowers.views.statements import * from rowers.tasks import handle_calctrimp -from rowers.mailprocessing import send_confirm from rowers.opaque import encoder import sys diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index 6d0b1582..b6d150a5 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -637,7 +637,7 @@ def workout_nkimport_view(request,userid=0,after=0,before=0): workouts = workouts[::-1] - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover try: tdict = dict(request.POST.lists()) ids = tdict['workoutid'] @@ -1053,7 +1053,7 @@ def workout_stravaimport_view(request,message="",userid=0): messages.info(request,'Your Strava workouts will be imported in the background. It may take a few minutes before it appears.'.format(stravaid=stravaid)) url = reverse('workouts_view') return HttpResponseRedirect(url) - except KeyError: + except KeyError: # pragma: no cover pass breadcrumbs = [ @@ -1133,7 +1133,7 @@ def strava_webhook_view(request): except Rower.DoesNotExist: # pragma: no cover dologging('strava_webhooks.log','Rower not found') return HttpResponse(status=200) - except MultipleObjectsReturned: + except MultipleObjectsReturned: # pragma: no cover s = 'Multiple rowers found for strava ID {id}'.format(id=strava_owner) dologging('strava_webhooks.log',s) rs = Rower.objects.filter(strava_owner_id=strava_owner) @@ -1164,7 +1164,7 @@ def strava_webhook_view(request): except Rower.DoesNotExist: # pragma: no cover dologging('strava_webhooks.log','Rower not found') return HttpResponse(status=200) - except MultipleObjectsReturned: + except MultipleObjectsReturned: # pragma: no cover rs = Rower.objects.filter(strava_owner_id=strava_owner) r = rs[0] if r.strava_auto_delete: # pragma: no cover @@ -1619,7 +1619,7 @@ def workout_c2import_view(request,page=1,userid=0,message=""): messages.info(request,'Your Concept2 workouts will be imported in the background. It may take a few minutes before it appears.'.format(c2id=c2id)) url = reverse('workouts_view') return HttpResponseRedirect(url) - except KeyError: + except KeyError: # pragma: no cover pass @@ -1768,18 +1768,6 @@ def workout_getsporttracksworkout_all(request): return HttpResponseRedirect(url) -# Imports all new workouts from SportTracks -@login_required() -def workout_getstravaworkout_all(request): - r = getrower(request.user) - res = stravastuff.get_strava_workouts(r) - if res == 1: # pragma: no cover - messages.info(request,"Your workouts are being imported and should appear on the site in the next 15 minutes") - else: - messages.error(request,"Couldn't import Strava workouts ") - - url = reverse('workouts_view') - return HttpResponseRedirect(url) # Imports all new workouts from SportTracks diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py index f133ce0b..a72bcc46 100644 --- a/rowers/views/paymentviews.py +++ b/rowers/views/paymentviews.py @@ -132,7 +132,7 @@ def buy_trainingplan_view(request,id=0): status = True # get target and set enddate - try: + try: # pragma: no cover targetid = cd['target'] target = TrainingTarget.objects.get(id=int(targetid)) except (KeyError,ValueError): @@ -192,7 +192,7 @@ def purchase_checkouts_view(request): }) return HttpResponseRedirect(url) - if r.rowerplan == 'freecoach': + if r.rowerplan == 'freecoach': # pragma: no cover messages.error(request,'You cannot purchase this training plan as a free coach member') url = reverse('rower_view_instantplan',kwargs={ 'id':plan.uuid, @@ -230,7 +230,7 @@ def purchase_checkouts_view(request): startdate = enddate-datetime.timedelta(days=plan.duration) # upgrade rower - if r.rowerplan == 'basic': + if r.rowerplan == 'basic': # pragma: no cover messages.info(request,'You have been upgraded to the Self-Coach plan for the duration of the plan') r.rowerplan = 'plan' r.planexpires = enddate @@ -280,7 +280,7 @@ def purchase_checkouts_view(request): messages.error(request,"There was an error in the payment form") url = reverse("purchase_checkouts_view") return HttpResponseRedirect(url) - else: + else: # pragma: no cover messages.error(request,"There was an error in the payment form") url = reverse('rower_select_instantplan') # pragma: no cover diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 112b7f5b..67947454 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -234,14 +234,14 @@ def course_view(request,id=0): if request.user.is_authenticated: notsharing = Rower.objects.filter(share_course_results=False).exclude(id=r.id) - else: + else: # pragma: no cover notsharing = Rower.objects.filter(share_course_results=False) notsharing_ids = [o.user.id for o in notsharing] records = records.exclude(userid__in=notsharing_ids) - if 'onlyme' in request.GET: + if 'onlyme' in request.GET: # pragma: no cover onlyme = request.GET.get('onlyme',False) if onlyme == 'true': onlyme = True @@ -253,7 +253,7 @@ def course_view(request,id=0): form = RaceResultFilterForm(records=records,groups=False) - if request.method == 'POST': + if request.method == 'POST': # pragma: no cover form = RaceResultFilterForm(request.POST,records=records,groups=False) if form.is_valid(): cd = form.cleaned_data diff --git a/rowers/views/statements.py b/rowers/views/statements.py index 3ae8441c..7aa031c8 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -203,6 +203,7 @@ from rowers.plannedsessions import * from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv from rowers.tasks import ( handle_sendemail_unrecognized,handle_sendemailnewcomment, + handle_request_post, handle_sendemailsummary, handle_rp3_async_workout, handle_send_template_email, @@ -242,7 +243,7 @@ import pandas as pd import numpy as np import matplotlib.pyplot as plt -from rowers.emails import send_template_email,htmlstrip +from rowers.emails import send_template_email,htmlstrip, send_confirm from rowers.alerts import * from pytz import timezone as tz,utc @@ -271,7 +272,6 @@ from rq import Queue,cancel_job from django.utils.crypto import get_random_string from django.core.cache import cache -from django_mailbox.models import Message,Mailbox,MessageAttachment from rules.contrib.views import permission_required, objectgetter @@ -703,7 +703,7 @@ from rest_framework.permissions import IsAuthenticated from rowers.permissions import IsOwnerOrNot, IsCompetitorOrNot import rowers.plots as plots -import rowers.mailprocessing as mailprocessing + from io import BytesIO from scipy.special import lambertw diff --git a/rowers/views/userviews.py b/rowers/views/userviews.py index 8cf39c7c..a7306d34 100644 --- a/rowers/views/userviews.py +++ b/rowers/views/userviews.py @@ -396,7 +396,7 @@ def rower_exportsettings_view(request,userid=0): def rower_edit_view(request,rowerid=0,userid=0,message=""): r = getrequestrowercoachee(request,rowerid=rowerid,userid=userid,notpermanent=True) - if 'courseshare' in request.GET: + if 'courseshare' in request.GET: # pragma: no cover courseshare = request.GET.get('courseshare',"ok") if courseshare == 'true': r.share_course_results = True diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index 680ecb24..00b1e4a5 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -10,7 +10,6 @@ from rowers.views.statements import * import rowers.teams as teams import rowers.mytypes as mytypes 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 @@ -1738,7 +1737,7 @@ def course_compare_view(request,id=0): 'teamid':0 } ) - if request.method == 'POST' and 'workouts' in request.POST: + if request.method == 'POST' and 'workouts' in request.POST: # pragma: no cover form = WorkoutMultipleCompareForm(request.POST) form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) chartform = ChartParamChoiceForm(request.POST) @@ -1752,7 +1751,7 @@ def course_compare_view(request,id=0): teamid = chartform.cleaned_data['teamid'] ids = [int(w.id) for w in workouts] request.session['ids'] = ids - elif request.method == 'POST': + elif request.method == 'POST': # pragma: no cover form = WorkoutMultipleCompareForm() form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) request.session['ids'] = workoutids @@ -1924,7 +1923,7 @@ def virtualevent_compare_view(request,id=0): 'teamid':0 } ) - if request.method == 'POST' and 'workouts' in request.POST: + if request.method == 'POST' and 'workouts' in request.POST: # pragma: no cover form = WorkoutMultipleCompareForm(request.POST) form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) chartform = ChartParamChoiceForm(request.POST) @@ -5435,26 +5434,19 @@ def workout_upload_view(request, title = t, notes=notes, ) - else: # pragma: no cover - workoutsbox = Mailbox.objects.filter(name='workouts')[0] - uploadoptions['fromuploadform'] = True - bodyyaml = yaml.safe_dump( - uploadoptions, - default_flow_style=False - ) - msg = Message(mailbox=workoutsbox, - from_header=r.user.email, - subject = t,body=bodyyaml) - msg.save() - f3 = 'media/mailbox_attachments/'+f2[6:] - copyfile(f2,f3) - f3 = f3[6:] - a = MessageAttachment(message=msg,document=f3) - try: - a.save() - except DataError: - pass - os.remove(f2) + else: + uploadoptions['secret'] = settings.UPLOAD_SERVICE_SECRET + uploadoptions['user'] = r.user.id + uploadoptions['title'] = t + uploadoptions['file'] = f2 + + url = settings.UPLOAD_SERVICE_URL + + job = myqueue(queuehigh, + handle_request_post, + url, + uploadoptions + ) messages.info( request, @@ -6563,7 +6555,7 @@ def workout_summary_edit_view(request,id,message="",successmessage="" course=course, workoutid=row.id ) - if records: + if records: # pragma: no cover record = records[0] else: # create record diff --git a/rowsandall_app/settings.py b/rowsandall_app/settings.py index 93d5c7f3..80fd504f 100644 --- a/rowsandall_app/settings.py +++ b/rowsandall_app/settings.py @@ -69,7 +69,7 @@ INSTALLED_APPS = [ 'django_rq', # 'django_rq_dashboard', # 'translation_manager', - 'django_mailbox', +# 'django_mailbox', 'rest_framework', 'datetimewidget', 'rest_framework_swagger', diff --git a/rowsandall_app/urls.py b/rowsandall_app/urls.py index b805e902..9fb16da9 100644 --- a/rowsandall_app/urls.py +++ b/rowsandall_app/urls.py @@ -13,7 +13,7 @@ Including another URLconf 1. Import the include() function: from django.conf.urls import url, include 2. Add a URL to urlpatterns: re_path(r'^blog/', include('blog.urls')) """ -from django.conf.urls import url,include +from django.conf.urls import include from django.urls import path, re_path from django.conf import settings from django.conf.urls.static import static