Private
Public Access
1
0

Merge branch 'feature/nomailbox' into develop

This commit is contained in:
Sander Roosendaal
2021-12-20 08:31:19 +01:00
36 changed files with 209 additions and 1829 deletions
+2 -2
View File
@@ -73,7 +73,7 @@ def process_webhook(notification):
if notification.kind == 'subscription_charged_successfully': if notification.kind == 'subscription_charged_successfully':
subscription = notification.subscription subscription = notification.subscription
rs = Rower.objects.filter(subscription_id=subscription.id) 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( dologging('braintreewebhooks.log','Could not find rowers with subscription ID {id}'.format(
id=subscription.id id=subscription.id
)) ))
@@ -209,7 +209,7 @@ def make_payment(rower,data):
if 'plan' in data: if 'plan' in data:
theplan = data['plan'] theplan = data['plan']
additional_text = 'Rowsandall Purchase Plan nr {theplan}'.format(theplan=theplan) additional_text = 'Rowsandall Purchase Plan nr {theplan}'.format(theplan=theplan)
else: else: # pragma: no cover
additional_text = 'Rowsandall Purchase' additional_text = 'Rowsandall Purchase'
result = gateway.transaction.sale({ result = gateway.transaction.sale({
+7 -7
View File
@@ -4,16 +4,16 @@ class InsufficientCreditError(Exception):
pass pass
def upgrade(amount, rower): def upgrade(amount, rower):
if rower.eurocredits > amount: if rower.eurocredits > amount: # pragma: no cover
return rower.eurocredits return rower.eurocredits
else: else:
rower.eurocredits = amount rower.eurocredits = amount
rower.save() rower.save()
return rower.eurocredits return rower.eurocredits
return rower.eurocredits return rower.eurocredits # pragma: no cover
def withdraw(amount, rower): def withdraw(amount, rower):
if rower.eurocredits < amount: if rower.eurocredits < amount: # pragma: no cover
rower.eurocredits = 0 rower.eurocredits = 0
rower.save() rower.save()
raise InsufficientCreditError raise InsufficientCreditError
@@ -22,9 +22,9 @@ def withdraw(amount, rower):
rower.save() rower.save()
return rower.eurocredits 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: if amount < rower.eurocredits:
return amount return amount
else: else:
@@ -33,9 +33,9 @@ def discount(amount,rower):
return 0 return 0
def discounted(amount,rower): def discounted(amount,rower):
if amount > rower.eurocredits: if amount > rower.eurocredits: # pragma: no cover
return amount-rower.eurocredits return amount-rower.eurocredits
else: else:
return 0 return 0
return 0 return 0 # pragma: no cover
+30 -18
View File
@@ -28,7 +28,8 @@ from rowingdata import (
from rowers.tasks import ( from rowers.tasks import (
handle_sendemail_unrecognized,handle_setcp, 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 from rowers.tasks import handle_zip_file
@@ -42,7 +43,9 @@ from pyarrow.lib import ArrowInvalid
from django.utils import timezone from django.utils import timezone
from django.utils.timezone import get_current_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 django.core.exceptions import ValidationError
from time import strftime from time import strftime
@@ -74,6 +77,7 @@ allowedcolumns = [key for key,value in strokedatafields.items()]
#from async_messages import messages as a_messages #from async_messages import messages as a_messages
import os import os
import zipfile import zipfile
from zipfile import BadZipFile
import pandas as pd import pandas as pd
import numpy as np import numpy as np
import itertools import itertools
@@ -2024,8 +2028,7 @@ def handle_nonpainsled(f2, fileformat, summary='',startdatetime='',empowerfirmwa
return (f2, summary, oarlength, inboard, fileformat, impeller) return (f2, summary, oarlength, inboard, fileformat, impeller)
# Create new workout from file and store it in the database # Create new workout from file and store it in the database
# This routine should be used everywhere in views.py and mailprocessing.py # This routine should be used everywhere in views.py
# Currently there is code duplication
def get_workouttype_from_fit(filename,workouttype='water'): def get_workouttype_from_fit(filename,workouttype='water'):
try: try:
@@ -2102,21 +2105,30 @@ def new_workout_from_file(r, f2,
# Save zip files to email box for further processing # Save zip files to email box for further processing
if len(fileformat) == 3 and fileformat[0] == 'zip': # pragma: no cover if len(fileformat) == 3 and fileformat[0] == 'zip': # pragma: no cover
uploadoptions['fromuploadform'] = True uploadoptions['secret'] = settings.UPLOAD_SERVICE_SECRET
bodyyaml = yaml.safe_dump(uploadoptions,default_flow_style=False) uploadoptions['user'] = r.user.id
f_to_be_deleted = f2 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 return -1, message, f2
+18
View File
@@ -120,3 +120,21 @@ def send_template_email(from_email,to_email,subject,
return 0 return 0
return res 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 <info@rowsandall.com>',
[fullemail],
subject,'confirmemail.html',
d
)
return 1
+1 -1
View File
@@ -1486,7 +1486,7 @@ class RaceResultFilterForm(forms.Form):
if records: if records:
# group # group
if groups: if groups: # pragma: no cover
thecategories = [record.entrycategory for record in records] thecategories = [record.entrycategory for record in records]
thecategories = list(set(thecategories)) thecategories = list(set(thecategories))
if len(thecategories) <= 1: if len(thecategories) <= 1:
+3 -3
View File
@@ -2429,7 +2429,7 @@ def get_map_script_course(
longend, longend,
scoordinates, scoordinates,
course, course,
): ): # pragma: no cover
latmean,lonmean,coordinates = course_coord_center(course) latmean,lonmean,coordinates = course_coord_center(course)
lat_min, lat_max, long_min, long_max = course_coord_maxmin(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, longend,
scoordinates, scoordinates,
) )
else: else: # pragma: no cover
record = VirtualRaceResult.objects.get(id=raceresult) record = VirtualRaceResult.objects.get(id=raceresult)
course = record.course course = record.course
script = get_map_script_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', def interactive_zoneschart(rower,data,startdate,enddate,trainingzones='hr',date_agg='week',
yaxis='time'): yaxis='time'):
if startdate >= enddate: if startdate >= enddate: # pragma: no cover
st = startdate st = startdate
startdate = enddate startdate = enddate
enddate = st enddate = st
-189
View File
@@ -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 <info@rowsandall.com>',
[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
+7 -208
View File
@@ -18,7 +18,7 @@ import json
import io import io
from django.core.management.base import BaseCommand 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.urls import reverse
from django.conf import settings from django.conf import settings
@@ -29,7 +29,7 @@ from rowingdata import rower as rrower
from rowingdata import rowingdata as rrdata from rowingdata import rowingdata as rrdata
import rowers.uploads as uploads import rowers.uploads as uploads
from rowers.mailprocessing import make_new_workout_from_email, send_confirm
import rowers.polarstuff as polarstuff import rowers.polarstuff as polarstuff
import rowers.c2stuff as c2stuff import rowers.c2stuff as c2stuff
import rowers.rp3stuff as rp3stuff import rowers.rp3stuff as rp3stuff
@@ -37,8 +37,7 @@ import rowers.stravastuff as stravastuff
import rowers.nkstuff as nkstuff import rowers.nkstuff as nkstuff
from rowers.opaque import encoder from rowers.opaque import encoder
from rowers.models import User,VirtualRace,Workout from rowers.models import User,Workout
from rowers.plannedsessions import email_submit_race
from rowers.rower_rules import user_is_not_basic from rowers.rower_rules import user_is_not_basic
from rowers.utils import dologging from rowers.utils import dologging
@@ -60,102 +59,6 @@ def rdata(file_obj, rower=rrower()): # pragma: no cover
return result 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): class Command(BaseCommand):
@@ -182,21 +85,11 @@ class Command(BaseCommand):
else: # pragma: no cover else: # pragma: no cover
testing = False 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 # Polar
try: try:
polar_available = polarstuff.get_polar_notifications() polar_available = polarstuff.get_polar_notifications()
res = polarstuff.get_all_new_workouts(polar_available) res = polarstuff.get_all_new_workouts(polar_available)
except: except: # pragma: no cover
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
lines = traceback.format_exception(exc_type, exc_value, exc_traceback) lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
dologging('processemail.log',''.join('!! ' + line for line in lines)) dologging('processemail.log',''.join('!! ' + line for line in lines))
@@ -207,7 +100,7 @@ class Command(BaseCommand):
for r in rowers: # pragma: no cover for r in rowers: # pragma: no cover
if user_is_not_basic(r.user): if user_is_not_basic(r.user):
c2stuff.get_c2_workouts(r) c2stuff.get_c2_workouts(r)
except: except: # pragma: no cover
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
lines = traceback.format_exception(exc_type, exc_value, exc_traceback) lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
dologging('processemail.log',''.join('!! ' + line for line in lines)) dologging('processemail.log',''.join('!! ' + line for line in lines))
@@ -218,7 +111,7 @@ class Command(BaseCommand):
for r in rowers: # pragma: no cover for r in rowers: # pragma: no cover
if user_is_not_basic(r.user): if user_is_not_basic(r.user):
res = rp3stuff.get_rp3_workouts(r) res = rp3stuff.get_rp3_workouts(r)
except: except: # pragma: no cover
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
lines = traceback.format_exception(exc_type, exc_value, exc_traceback) lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
dologging('processemail.log',''.join('!! ' + line for line in lines)) 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) s = 'Starting NK Auto Import for user {id}'.format(id=r.user.id)
dologging('nklog.log',s) dologging('nklog.log',s)
res = nkstuff.get_nk_workouts(r) res = nkstuff.get_nk_workouts(r)
except: except: # pragma: no cover
exc_type, exc_value, exc_traceback = sys.exc_info() exc_type, exc_value, exc_traceback = sys.exc_info()
lines = traceback.format_exception(exc_type, exc_value, exc_traceback) lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
dologging('processemail.log',''.join('!! ' + line for line in lines)) 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 # Strava
#rowers = Rower.objects.filter(strava_auto_import=True) #rowers = Rower.objects.filter(strava_auto_import=True)
#for r in rowers: #for r in rowers:
+9 -9
View File
@@ -103,22 +103,22 @@ smoothingchoices = (
def half_year_from_now(ttz=None): def half_year_from_now(ttz=None):
if ttz is None: if ttz is None:
return (datetime.datetime.now(tz=timezone.utc)+timezone.timedelta(days=182)).date() 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): def a_week_from_now(ttz=None):
if ttz is None: if ttz is None:
return (datetime.datetime.now(tz=timezone.utc)+timezone.timedelta(days=7)).date() 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): def current_day(ttz=None):
if ttz is None: if ttz is None:
return (datetime.datetime.now(tz=timezone.utc)).date() 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 def current_time(ttz=None): # pragma: no cover
if ttz is None: if ttz is None:
return datetime.datetime.now(tz=timezone.utc) 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): class UserFullnameChoiceField(forms.ModelChoiceField):
@@ -2188,7 +2188,7 @@ class TrainingMesoCycle(models.Model):
if not self.enddate <= self.startdate: if not self.enddate <= self.startdate:
super(TrainingMesoCycle,self).save(*args, **kwargs) super(TrainingMesoCycle,self).save(*args, **kwargs)
else: else: # pragma: no cover
self.enddate = self.startdate self.enddate = self.startdate
super(TrainingMesoCycle,self).save(*args, **kwargs) super(TrainingMesoCycle,self).save(*args, **kwargs)
@@ -2512,18 +2512,18 @@ class PlannedSession(models.Model):
elif self.sessiontype != 'coursetest' and self.sessiontype != 'race': elif self.sessiontype != 'coursetest' and self.sessiontype != 'race':
self.course = None self.course = None
if self.enddate < self.startdate: if self.enddate < self.startdate: # pragma: no cover
self.enddate = self.startdate self.enddate = self.startdate
if self.preferreddate > self.enddate: if self.preferreddate > self.enddate: # pragma: no cover
self.preferreddate = self.enddate self.preferreddate = self.enddate
if self.preferreddate < self.startdate: if self.preferreddate < self.startdate: # pragma: no cover
self.preferreddate = self.startdate self.preferreddate = self.startdate
#super(PlannedSession,self).save(*args, **kwargs) #super(PlannedSession,self).save(*args, **kwargs)
if self.steps: if self.steps:
steps = 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)) steps = steps_read_fit(os.path.join(settings.MEDIA_ROOT,self.fitfile.name))
self.steps = steps self.steps = steps
+3 -126
View File
@@ -1145,10 +1145,10 @@ def update_indoorvirtualrace(ps,cd):
ps.timezone = timezone_str ps.timezone = timezone_str
if ps.sessiontype == 'fastest_distance': if ps.sessiontype == 'fastest_distance': # pragma: no cover
ps.approximate_distance = ps.sessionvalue 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.approximate_distance = ps.course.distance
ps.save() ps.save()
@@ -1204,7 +1204,7 @@ def update_virtualrace(ps,cd):
ps.timezone = timezone_str ps.timezone = timezone_str
if ps.sessiontype == 'fastest_distance': if ps.sessiontype == 'fastest_distance': # pragma: no cover
ps.approximate_distance = ps.sessionvalue ps.approximate_distance = ps.sessionvalue
if ps.course is not None: if ps.course is not None:
@@ -1403,129 +1403,6 @@ def race_can_withdraw(r,race):
return True 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): def race_can_register(r,race):
if race.sessiontype in ['race']: if race.sessiontype in ['race']:
+17 -11
View File
@@ -38,6 +38,7 @@ from django.contrib.auth.decorators import login_required
from rowingdata import rowingdata from rowingdata import rowingdata
import pandas as pd import pandas as pd
from rowers.models import Rower,Workout from rowers.models import Rower,Workout
from rowers.tasks import handle_request_post
import rowers.dataprep as dataprep import rowers.dataprep as dataprep
from rowers.dataprep import columndict from rowers.dataprep import columndict
@@ -47,8 +48,6 @@ from io import StringIO
import stravalib import stravalib
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
from django_mailbox.models import Message,Mailbox,MessageAttachment
from rowsandall_app.settings import ( from rowsandall_app.settings import (
POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET, POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET,
) )
@@ -115,7 +114,7 @@ def make_authorization_url(): # pragma: no cover
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
def get_polar_notifications(): def get_polar_notifications(): # pragma: no cover
url = baseurl+'/notifications' url = baseurl+'/notifications'
state = str(uuid4()) state = str(uuid4())
auth_string = '{id}:{secret}'.format( auth_string = '{id}:{secret}'.format(
@@ -197,7 +196,6 @@ def get_polar_workouts(user):
if response.status_code == 201: if response.status_code == 201:
workoutsbox = Mailbox.objects.filter(name='workouts')[0]
uploadoptions = { uploadoptions = {
'makeprivate':False, 'makeprivate':False,
} }
@@ -231,15 +229,23 @@ def get_polar_workouts(user):
with open(filename,'wb') as fop: with open(filename,'wb') as fop:
fop.write(response.content) fop.write(response.content)
msg = Message(mailbox=workoutsbox, # post file to upload api
from_header=user.email, json_data = {
subject = '', 'title':'',
body=bodyyaml) '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:]) job = myqueue(queuehigh,
a.save() handle_request_post,
url,
json_data
)
exercise_dict['filename'] = filename exercise_dict['filename'] = filename
else: else:
-324
View File
@@ -11,8 +11,6 @@ import time
from time import strftime from time import strftime
from django_mailbox.models import Message,Mailbox,MessageAttachment
import django_rq import django_rq
queue = django_rq.get_queue('default') queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low') queuelow = django_rq.get_queue('low')
@@ -212,157 +210,6 @@ def get_strava_workout_list(user,limit_n=0):
return s 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 from rowers.utils import get_strava_stream
def async_get_workout(user,stravaid): def async_get_workout(user,stravaid):
@@ -559,174 +406,3 @@ def workout_strava_upload(user,w, quick=False,asynchron=True):
os.remove(tcxfile) os.remove(tcxfile)
return message,stravaid return message,stravaid
return message,stravaid # pragma: no cover 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
+14 -7
View File
@@ -284,6 +284,12 @@ def summaryfromsplitdata(splitdata,data,filename,sep='|',workouttype='rower'):
return sums,sa,results 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 @app.task
def add(x, y): # pragma: no cover def add(x, y): # pragma: no cover
return x + y return x + y
@@ -1363,7 +1369,8 @@ def handle_send_email_transaction(
@app.task @app.task
def handle_send_email_instantplan_notification( 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 if 'debug' in kwargs: # pragma: no cover
debug = kwargs['debug'] debug = kwargs['debug']
@@ -1531,7 +1538,7 @@ def handle_sendemail_raceregistration(
def handle_sendemail_coursesucceed( def handle_sendemail_coursesucceed(
useremail, username, logfile, workoutid, **kwargs useremail, username, logfile, workoutid, **kwargs
): ): # pragma: no cover
if 'debug' in kwargs: # pragma: no cover if 'debug' in kwargs: # pragma: no cover
debug = kwargs['debug'] debug = kwargs['debug']
else: else:
@@ -3240,7 +3247,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
splitdata = None splitdata = None
distance = data['distance'] distance = data['distance']
try: try: # pragma: no cover
rest_distance = data['rest_distance'] rest_distance = data['rest_distance']
rest_time = data['rest_time']/10. rest_time = data['rest_time']/10.
except KeyError: except KeyError:
@@ -3319,7 +3326,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
#dologging('debuglog.log',json.dumps(s.json())) #dologging('debuglog.log',json.dumps(s.json()))
try: try:
strokedata = pd.DataFrame.from_dict(s.json()['data']) strokedata = pd.DataFrame.from_dict(s.json()['data'])
except AttributeError: except AttributeError: # pragma: no cover
dologging('debuglog.log','No stroke data in stroke data') dologging('debuglog.log','No stroke data in stroke data')
return 0 return 0
@@ -3327,7 +3334,7 @@ def handle_c2_async_workout(alldata,userid,c2token,c2id,delaysec,defaulttimezone
res = make_cumvalues(0.1*strokedata['t']) res = make_cumvalues(0.1*strokedata['t'])
cum_time = res[0] cum_time = res[0]
lapidx = res[1] lapidx = res[1]
except KeyError: except KeyError: # pragma: no cover
dologging('debuglog.log','No time values in stroke data') dologging('debuglog.log','No time values in stroke data')
return 0 return 0
@@ -3633,7 +3640,7 @@ def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debu
'power':power, 'power':power,
'strokelength':strokelength, 'strokelength':strokelength,
}) })
except ValueError: except ValueError: # pragma: no cover
return 0 return 0
try: try:
@@ -3648,7 +3655,7 @@ def fetch_strava_workout(stravatoken,oauth_data,stravaid,csvfilename,userid,debu
try: try:
if 'summary_polyline' in workoutsummary['map'] and workouttype=='rower': # pragma: no cover if 'summary_polyline' in workoutsummary['map'] and workouttype=='rower': # pragma: no cover
workouttype = 'water' workouttype = 'water'
except KeyError: except KeyError: # pragma: no cover
pass pass
try: try:
-9
View File
@@ -8,15 +8,6 @@
<h1>Available on Strava</h1> <h1>Available on Strava</h1>
{% if workouts %} {% if workouts %}
<ul class="main-content"> <ul class="main-content">
<li>
<a href="/rowers/workout/stravaimport/all/" class="blue button">Import all NEW</a>
</li>
<li class="grid_3">
<p>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.
</p>
</li>
<li class="grid_4"> <li class="grid_4">
<form enctype="multipart/form-data" method="post"> <form enctype="multipart/form-data" method="post">
{% csrf_token %} {% csrf_token %}
-1
View File
@@ -57,7 +57,6 @@ from rowers.dataprep import delete_strokedata
from redis import StrictRedis from redis import StrictRedis
redis_connection = StrictRedis() redis_connection = StrictRedis()
from django_mailbox.models import Mailbox,MessageAttachment,Message
def mocked_grpc(*args, **kwargs): def mocked_grpc(*args, **kwargs):
class insecure_channel: class insecure_channel:
-1
View File
@@ -85,7 +85,6 @@ from importlib import import_module
from redis import StrictRedis from redis import StrictRedis
redis_connection = StrictRedis() redis_connection = StrictRedis()
from django_mailbox.models import Mailbox,MessageAttachment,Message
from rowers.tests.mocks import * from rowers.tests.mocks import *
-4
View File
@@ -37,10 +37,6 @@ class OwnApi(TestCase):
gdproptindate=timezone.now(), gdproptindate=timezone.now(),
rowerplan='coach',subscription_id=1) 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.c = Client()
self.user_workouts = WorkoutFactory.create_batch(5, user=self.r) self.user_workouts = WorkoutFactory.create_batch(5, user=self.r)
-4
View File
@@ -69,10 +69,6 @@ class BraintreeUnits(TestCase):
gdproptindate=timezone.now(), gdproptindate=timezone.now(),
rowerplan='coach',subscription_id=1) 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.pp = PaidPlan.objects.create(price=0,paymentprocessor='braintree')
self.p2 = PaidPlan.objects.create(price=25,paymentprocessor='braintree') self.p2 = PaidPlan.objects.create(price=25,paymentprocessor='braintree')
+10 -388
View File
@@ -29,18 +29,7 @@ class EmailUpload(TestCase):
rowerplan='coach') rowerplan='coach')
nu = datetime.datetime.now() 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' a2 = 'media/mailbox_attachments/colin3.csv'
copy('rowers/tests/testdata/emails/colin.csv',a2) copy('rowers/tests/testdata/emails/colin.csv',a2)
a3 = 'media/mailbox_attachments/colin4.csv' a3 = 'media/mailbox_attachments/colin4.csv'
@@ -52,8 +41,6 @@ workout run
a6 = 'media/mailbox_attachments/colin7.csv' a6 = 'media/mailbox_attachments/colin7.csv'
copy('rowers/tests/testdata/emails/colin.csv',a6) copy('rowers/tests/testdata/emails/colin.csv',a6)
a = MessageAttachment(message=m,document=a2[6:])
a.save()
def tearDown(self): def tearDown(self):
for filename in os.listdir('media/mailbox_attachments'): for filename in os.listdir('media/mailbox_attachments'):
@@ -64,6 +51,7 @@ workout run
except (IOError,FileNotFoundError,OSError): except (IOError,FileNotFoundError,OSError):
pass pass
@patch('rowers.dataprep.create_engine') @patch('rowers.dataprep.create_engine')
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db) @patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_getsmallrowdata_db)
def test_uploadapi(self,mocked_sqlalchemy,mocked_getsmallrowdata_db): def test_uploadapi(self,mocked_sqlalchemy,mocked_getsmallrowdata_db):
@@ -168,266 +156,7 @@ workout run
self.assertEqual(response.status_code,403) 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') rowerplan='coach')
nu = datetime.datetime.now() nu = datetime.datetime.now()
workoutsbox = Mailbox.objects.create(name='workouts4') a2 = 'media/mailbox_attachments/colin3.csv'
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'
copy('rowers/tests/testdata/emails/colin.csv',a2) copy('rowers/tests/testdata/emails/colin.csv',a2)
a = MessageAttachment(message=m,document=a2[6:]) a3 = 'media/mailbox_attachments/colin4.csv'
a.save() 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): def tearDown(self):
for filename in os.listdir('media/mailbox_attachments'): for filename in os.listdir('media/mailbox_attachments'):
@@ -512,79 +210,3 @@ race 1
out = StringIO() out = StringIO()
call_command('processemail', stdout=out,testing=True,mailbox='workouts4') call_command('processemail', stdout=out,testing=True,mailbox='workouts4')
self.assertIn('Successfully processed email attachments',out.getvalue()) 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)
-59
View File
@@ -1258,62 +1258,3 @@ class TPObjects(DjangoTestCase):
self.assertEqual(response.url, '/rowers/workout/'+encoded1+'/edit/') self.assertEqual(response.url, '/rowers/workout/'+encoded1+'/edit/')
self.assertEqual(response.status_code, 302) 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())
+6
View File
@@ -586,6 +586,10 @@ class ChallengesTest(TestCase):
'course': self.ThyroBaantje.id 'course': self.ThyroBaantje.id
} }
form = CourseSelectForm(formdata)
self.assertTrue(form.is_valid())
response = self.c.post(url, formdata, follow=True) response = self.c.post(url, formdata, follow=True)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
@@ -813,6 +817,7 @@ class ChallengesTest(TestCase):
'yparam': 'spm', 'yparam': 'spm',
'plottype': 'line', 'plottype': 'line',
'teamid':0, 'teamid':0,
'course':self.ThyroBaantje.id,
} }
form = ChartParamChoiceForm(form_data) form = ChartParamChoiceForm(form_data)
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
@@ -829,6 +834,7 @@ class ChallengesTest(TestCase):
'yparam': 'spm', 'yparam': 'spm',
'plottype': 'line', 'plottype': 'line',
'teamid':0, 'teamid':0,
'course':self.ThyroBaantje.id
} }
form = ChartParamChoiceForm(form_data) form = ChartParamChoiceForm(form_data)
self.assertTrue(form.is_valid()) self.assertTrue(form.is_valid())
-18
View File
@@ -35,10 +35,6 @@ class OtherUnitTests(TestCase):
defaulttimezone='US/Pacific', defaulttimezone='US/Pacific',
rowerplan='coach') rowerplan='coach')
workoutsbox = Mailbox.objects.create(name='workouts')
workoutsbox.save()
failbox = Mailbox.objects.create(name='Failed')
failbox.save()
# Test get_dates_timeperiod # Test get_dates_timeperiod
def test_get_dates_timeperiod(self): def test_get_dates_timeperiod(self):
@@ -99,20 +95,6 @@ class OtherUnitTests(TestCase):
self.assertTrue('US/Pacific' in str(startdate.tzinfo)) 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): def test_summaryfromsplitdata(self):
with open('rowers/tests/testdata/c2splits.json','r') as f: with open('rowers/tests/testdata/c2splits.json','r') as f:
+40
View File
@@ -132,6 +132,46 @@ class ViewTest(TestCase):
except (FileNotFoundError,OSError): except (FileNotFoundError,OSError):
pass 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()
-2
View File
@@ -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, 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, 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, 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, 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, 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, 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, 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,
1 id view function anonymous anonymous_response own own_response own_nonperm member member_response member_nonperm coachee coachee_response coachee_nonperm is_staff userid workoutid dotest realtest kwargs
87 97 114 workout_undo_smoothenpace_view unsmoothen pace TRUE 403 pro 302 302 pro 403 403 coach 302 403 FALSE FALSE TRUE TRUE TRUE
88 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
89 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
90 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
91 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
92 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
93 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
+2 -377
View File
@@ -48,360 +48,11 @@ from rowers.utils import (
str2bool,range_to_color_hex,absolute,myqueue,NoTokenError 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] 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): def make_plot(r,w,f1,f2,plottype,title,imagename='',plotnr=0):
if imagename == '': if imagename == '':
@@ -489,33 +140,7 @@ import rowers.tpstuff as tpstuff
from rowers.rower_rules import is_promember 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): def do_sync(w,options, quick=False):
@@ -587,7 +212,7 @@ def do_sync(w,options, quick=False):
if w.duplicate: if w.duplicate:
return 0 return 0
if do_c2_export: if do_c2_export: # pragma: no cover
try: try:
message,id = c2stuff.workout_c2_upload(w.user.user,w,asynchron=True) message,id = c2stuff.workout_c2_upload(w.user.user,w,asynchron=True)
except NoTokenError: except NoTokenError:
@@ -628,7 +253,7 @@ def do_sync(w,options, quick=False):
except KeyError: except KeyError:
upload_to_tp = False upload_to_tp = False
if do_tp_export: if do_tp_export: # pragma: no cover
try: try:
message,id = sporttracksstuff.workout_sporttracks_upload( message,id = sporttracksstuff.workout_sporttracks_upload(
w.user.user,w,asynchron=True, w.user.user,w,asynchron=True,
+1 -1
View File
@@ -510,7 +510,7 @@ urlpatterns = [
re_path(r'^workout/rp3import/all/$',views.workout_getrp3workout_all,name='workout_getrp3workout_all'), re_path(r'^workout/rp3import/all/$',views.workout_getrp3workout_all,name='workout_getrp3workout_all'),
re_path(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview,name='workout_getimportview'), re_path(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/$',views.workout_getimportview,name='workout_getimportview'),
re_path(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\d+)/async/$',views.workout_getimportview,{'do_async':True},name='workout_getimportview'), re_path(r'^workout/(?P<source>\w+.*)import/(?P<externalid>\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/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/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'),
re_path(r'^workout/sporttracksimport/user/(?P<userid>\d+)/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'), re_path(r'^workout/sporttracksimport/user/(?P<userid>\d+)/$',views.workout_sporttracksimport_view,name='workout_sporttracksimport_view'),
+4 -4
View File
@@ -120,7 +120,7 @@ def dologging(filename,s):
f.write(' ') f.write(' ')
f.write(s) f.write(s)
def to_pace(pace): def to_pace(pace): # pragma: no cover
minutes, seconds = divmod(pace,60) minutes, seconds = divmod(pace,60)
seconds, rest = divmod(seconds, 1) seconds, rest = divmod(seconds, 1)
tenths = int(rest*10) tenths = int(rest*10)
@@ -518,7 +518,7 @@ def custom_exception_handler(exc,message):
return res return res
def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high',authorizationstring=''): 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) authorizationstring = str('Bearer ' + r.stravatoken)
headers = {'Authorization': authorizationstring, headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal', 'user-agent': 'sanderroosendaal',
@@ -569,7 +569,7 @@ def allsundays(startdate,enddate):
yield d yield d
d += datetime.timedelta(days=7) 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 authorizationstring = 'Bearer '+settings.WORKOUTS_FIT_TOKEN
url = settings.WORKOUTS_FIT_URL+"/tojson" url = settings.WORKOUTS_FIT_URL+"/tojson"
headers = {'Authorization':authorizationstring} 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 distance = avgspeed*seconds
rscore = 60.*seconds/3600. rscore = 60.*seconds/3600.
if targettype == 'Speed': if targettype == 'Speed': # pragma: no cover
value = step.get('targetValue',0) value = step.get('targetValue',0)
valuelow = step.get('targetValueLow',0) valuelow = step.get('targetValueLow',0)
valuehigh = step.get('targetValueHigh',0) valuehigh = step.get('targetValueHigh',0)
-1
View File
@@ -5,7 +5,6 @@ from __future__ import unicode_literals
from rowers.views.statements import * from rowers.views.statements import *
from rowers.tasks import handle_calctrimp from rowers.tasks import handle_calctrimp
from rowers.mailprocessing import send_confirm
from rowers.opaque import encoder from rowers.opaque import encoder
import sys import sys
+5 -17
View File
@@ -637,7 +637,7 @@ def workout_nkimport_view(request,userid=0,after=0,before=0):
workouts = workouts[::-1] workouts = workouts[::-1]
if request.method == 'POST': if request.method == 'POST': # pragma: no cover
try: try:
tdict = dict(request.POST.lists()) tdict = dict(request.POST.lists())
ids = tdict['workoutid'] 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)) 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') url = reverse('workouts_view')
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
except KeyError: except KeyError: # pragma: no cover
pass pass
breadcrumbs = [ breadcrumbs = [
@@ -1133,7 +1133,7 @@ def strava_webhook_view(request):
except Rower.DoesNotExist: # pragma: no cover except Rower.DoesNotExist: # pragma: no cover
dologging('strava_webhooks.log','Rower not found') dologging('strava_webhooks.log','Rower not found')
return HttpResponse(status=200) return HttpResponse(status=200)
except MultipleObjectsReturned: except MultipleObjectsReturned: # pragma: no cover
s = 'Multiple rowers found for strava ID {id}'.format(id=strava_owner) s = 'Multiple rowers found for strava ID {id}'.format(id=strava_owner)
dologging('strava_webhooks.log',s) dologging('strava_webhooks.log',s)
rs = Rower.objects.filter(strava_owner_id=strava_owner) rs = Rower.objects.filter(strava_owner_id=strava_owner)
@@ -1164,7 +1164,7 @@ def strava_webhook_view(request):
except Rower.DoesNotExist: # pragma: no cover except Rower.DoesNotExist: # pragma: no cover
dologging('strava_webhooks.log','Rower not found') dologging('strava_webhooks.log','Rower not found')
return HttpResponse(status=200) return HttpResponse(status=200)
except MultipleObjectsReturned: except MultipleObjectsReturned: # pragma: no cover
rs = Rower.objects.filter(strava_owner_id=strava_owner) rs = Rower.objects.filter(strava_owner_id=strava_owner)
r = rs[0] r = rs[0]
if r.strava_auto_delete: # pragma: no cover 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)) 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') url = reverse('workouts_view')
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
except KeyError: except KeyError: # pragma: no cover
pass pass
@@ -1768,18 +1768,6 @@ def workout_getsporttracksworkout_all(request):
return HttpResponseRedirect(url) 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 # Imports all new workouts from SportTracks
+4 -4
View File
@@ -132,7 +132,7 @@ def buy_trainingplan_view(request,id=0):
status = True status = True
# get target and set enddate # get target and set enddate
try: try: # pragma: no cover
targetid = cd['target'] targetid = cd['target']
target = TrainingTarget.objects.get(id=int(targetid)) target = TrainingTarget.objects.get(id=int(targetid))
except (KeyError,ValueError): except (KeyError,ValueError):
@@ -192,7 +192,7 @@ def purchase_checkouts_view(request):
}) })
return HttpResponseRedirect(url) 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') messages.error(request,'You cannot purchase this training plan as a free coach member')
url = reverse('rower_view_instantplan',kwargs={ url = reverse('rower_view_instantplan',kwargs={
'id':plan.uuid, 'id':plan.uuid,
@@ -230,7 +230,7 @@ def purchase_checkouts_view(request):
startdate = enddate-datetime.timedelta(days=plan.duration) startdate = enddate-datetime.timedelta(days=plan.duration)
# upgrade rower # 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') messages.info(request,'You have been upgraded to the Self-Coach plan for the duration of the plan')
r.rowerplan = 'plan' r.rowerplan = 'plan'
r.planexpires = enddate r.planexpires = enddate
@@ -280,7 +280,7 @@ def purchase_checkouts_view(request):
messages.error(request,"There was an error in the payment form") messages.error(request,"There was an error in the payment form")
url = reverse("purchase_checkouts_view") url = reverse("purchase_checkouts_view")
return HttpResponseRedirect(url) return HttpResponseRedirect(url)
else: else: # pragma: no cover
messages.error(request,"There was an error in the payment form") messages.error(request,"There was an error in the payment form")
url = reverse('rower_select_instantplan') # pragma: no cover url = reverse('rower_select_instantplan') # pragma: no cover
+3 -3
View File
@@ -234,14 +234,14 @@ def course_view(request,id=0):
if request.user.is_authenticated: if request.user.is_authenticated:
notsharing = Rower.objects.filter(share_course_results=False).exclude(id=r.id) 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 = Rower.objects.filter(share_course_results=False)
notsharing_ids = [o.user.id for o in notsharing] notsharing_ids = [o.user.id for o in notsharing]
records = records.exclude(userid__in=notsharing_ids) 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) onlyme = request.GET.get('onlyme',False)
if onlyme == 'true': if onlyme == 'true':
onlyme = True onlyme = True
@@ -253,7 +253,7 @@ def course_view(request,id=0):
form = RaceResultFilterForm(records=records,groups=False) 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) form = RaceResultFilterForm(request.POST,records=records,groups=False)
if form.is_valid(): if form.is_valid():
cd = form.cleaned_data cd = form.cleaned_data
+3 -3
View File
@@ -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_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
from rowers.tasks import ( from rowers.tasks import (
handle_sendemail_unrecognized,handle_sendemailnewcomment, handle_sendemail_unrecognized,handle_sendemailnewcomment,
handle_request_post,
handle_sendemailsummary, handle_sendemailsummary,
handle_rp3_async_workout, handle_rp3_async_workout,
handle_send_template_email, handle_send_template_email,
@@ -242,7 +243,7 @@ import pandas as pd
import numpy as np import numpy as np
import matplotlib.pyplot as plt 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 rowers.alerts import *
from pytz import timezone as tz,utc 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.utils.crypto import get_random_string
from django.core.cache import cache from django.core.cache import cache
from django_mailbox.models import Message,Mailbox,MessageAttachment
from rules.contrib.views import permission_required, objectgetter from rules.contrib.views import permission_required, objectgetter
@@ -703,7 +703,7 @@ from rest_framework.permissions import IsAuthenticated
from rowers.permissions import IsOwnerOrNot, IsCompetitorOrNot from rowers.permissions import IsOwnerOrNot, IsCompetitorOrNot
import rowers.plots as plots import rowers.plots as plots
import rowers.mailprocessing as mailprocessing
from io import BytesIO from io import BytesIO
from scipy.special import lambertw from scipy.special import lambertw
+1 -1
View File
@@ -396,7 +396,7 @@ def rower_exportsettings_view(request,userid=0):
def rower_edit_view(request,rowerid=0,userid=0,message=""): def rower_edit_view(request,rowerid=0,userid=0,message=""):
r = getrequestrowercoachee(request,rowerid=rowerid,userid=userid,notpermanent=True) 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") courseshare = request.GET.get('courseshare',"ok")
if courseshare == 'true': if courseshare == 'true':
r.share_course_results = True r.share_course_results = True
+16 -24
View File
@@ -10,7 +10,6 @@ from rowers.views.statements import *
import rowers.teams as teams import rowers.teams as teams
import rowers.mytypes as mytypes import rowers.mytypes as mytypes
import numpy import numpy
from rowers.mailprocessing import send_confirm
import rowers.uploads as uploads import rowers.uploads as uploads
import rowers.utils as utils import rowers.utils as utils
from rowers.utils import intervals_to_string from rowers.utils import intervals_to_string
@@ -1738,7 +1737,7 @@ def course_compare_view(request,id=0):
'teamid':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 = WorkoutMultipleCompareForm(request.POST)
form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids)
chartform = ChartParamChoiceForm(request.POST) chartform = ChartParamChoiceForm(request.POST)
@@ -1752,7 +1751,7 @@ def course_compare_view(request,id=0):
teamid = chartform.cleaned_data['teamid'] teamid = chartform.cleaned_data['teamid']
ids = [int(w.id) for w in workouts] ids = [int(w.id) for w in workouts]
request.session['ids'] = ids request.session['ids'] = ids
elif request.method == 'POST': elif request.method == 'POST': # pragma: no cover
form = WorkoutMultipleCompareForm() form = WorkoutMultipleCompareForm()
form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids)
request.session['ids'] = workoutids request.session['ids'] = workoutids
@@ -1924,7 +1923,7 @@ def virtualevent_compare_view(request,id=0):
'teamid':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 = WorkoutMultipleCompareForm(request.POST)
form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids) form.fields["workouts"].queryset = Workout.objects.filter(id__in=workoutids)
chartform = ChartParamChoiceForm(request.POST) chartform = ChartParamChoiceForm(request.POST)
@@ -5435,26 +5434,19 @@ def workout_upload_view(request,
title = t, title = t,
notes=notes, notes=notes,
) )
else: # pragma: no cover else:
workoutsbox = Mailbox.objects.filter(name='workouts')[0] uploadoptions['secret'] = settings.UPLOAD_SERVICE_SECRET
uploadoptions['fromuploadform'] = True uploadoptions['user'] = r.user.id
bodyyaml = yaml.safe_dump( uploadoptions['title'] = t
uploadoptions, uploadoptions['file'] = f2
default_flow_style=False
url = settings.UPLOAD_SERVICE_URL
job = myqueue(queuehigh,
handle_request_post,
url,
uploadoptions
) )
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)
messages.info( messages.info(
request, request,
@@ -6563,7 +6555,7 @@ def workout_summary_edit_view(request,id,message="",successmessage=""
course=course, course=course,
workoutid=row.id workoutid=row.id
) )
if records: if records: # pragma: no cover
record = records[0] record = records[0]
else: else:
# create record # create record
+1 -1
View File
@@ -69,7 +69,7 @@ INSTALLED_APPS = [
'django_rq', 'django_rq',
# 'django_rq_dashboard', # 'django_rq_dashboard',
# 'translation_manager', # 'translation_manager',
'django_mailbox', # 'django_mailbox',
'rest_framework', 'rest_framework',
'datetimewidget', 'datetimewidget',
'rest_framework_swagger', 'rest_framework_swagger',
+1 -1
View File
@@ -13,7 +13,7 @@ Including another URLconf
1. Import the include() function: from django.conf.urls import url, include 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')) 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.urls import path, re_path
from django.conf import settings from django.conf import settings
from django.conf.urls.static import static from django.conf.urls.static import static