Private
Public Access
1
0
Files
rowsandall/rowers/management/commands/processemail.py
Sander Roosendaal b1f04581a8 fixed, tested
2019-04-06 18:27:17 +02:00

309 lines
10 KiB
Python

#!/srv/venv/bin/python
""" Process emails """
import sys
import os
PY3K = sys.version_info >= (3, 0)
import zipfile
import re
import time
from time import strftime
import io
from django.core.management.base import BaseCommand
from django_mailbox.models import Message, MessageAttachment,Mailbox
from django.urls import reverse
from django.conf import settings
from django.utils import timezone
from rowers.models import Workout, Rower
from rowingdata import rower as rrower
from rowingdata import rowingdata as rrdata
import rowers.uploads as uploads
from rowers.mailprocessing import make_new_workout_from_email, send_confirm
import rowers.polarstuff as polarstuff
import rowers.c2stuff as c2stuff
import rowers.stravastuff as stravastuff
from rowers.opaque import encoder
from rowers.models import User,VirtualRace,Workout
from rowers.plannedsessions import email_submit_race
workoutmailbox = Mailbox.objects.get(name='workouts')
failedmailbox = Mailbox.objects.get(name='Failed')
# If you find a solution that does not need the two paths, please comment!
sys.path.append('$path_to_root_of_project$')
sys.path.append('$path_to_root_of_project$/$project_name$')
os.environ['DJANGO_SETTINGS_MODULE'] = '$project_name$.settings'
if not getattr(__builtins__, "WindowsError", None):
class WindowsError(OSError): pass
def rdata(file_obj, rower=rrower()):
""" Read rowing data file and return 0 if file doesn't exist"""
try:
result = rrdata(file_obj, rower=rower)
except IOError:
result = 0
return result
def processattachment(rower, fileobj, title, uploadoptions,testing=False):
try:
filename = fileobj.name
except AttributeError:
filename = fileobj[6:]
if testing:
print('Attribute Error', filename)
# test if file exists and is not empty
try:
with io.open('media/'+filename,'rb') as fop:
line = fop.readline()
except (IOError, UnicodeEncodeError):
if testing:
print('IOError',filename,'media/'+filename)
return 0
if testing:
print('Creating workout from email')
# 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
else:
return 0
else:
therower = rower
workoutid = [
make_new_workout_from_email(therower, filename, title,testing=testing)
]
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:
pass
if testing:
print('Workout id = {workoutid}'.format(workoutid=workoutid))
if workoutid[0]:
link = settings.SITE_URL+reverse(
therower.defaultlandingpage,
kwargs = {
'id':encoder.encode_hex(workoutid[0]),
}
)
if 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 'make_plot' in uploadoptions:
plottype = uploadoptions['plottype']
workoutcsvfilename = workout.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = workoutcsvfilename + timestr + '.png'
result,jobid = uploads.make_plot(
workout.user, workout, workoutcsvfilename,
workout.csvfilename,
plottype, title,
imagename=imagename
)
try:
if workoutid and not testing:
if therower.getemailnotifications and not therower.emailbounced:
email_sent = send_confirm(
therower.user, title, link,
uploadoptions
)
time.sleep(10)
except:
try:
time.sleep(10)
if workoutid:
if therower.getemailnotifications and not therower.emailbounced:
email_sent = send_confirm(
therower.user, title, link,
uploadoptions
)
except:
pass
return workoutid
def get_from_address(message):
from_address = message.from_address[0].lower()
if message.encoded:
body = message.text.splitlines()
else:
body = message.get_body().splitlines()
try:
first_line = body[0].lower()
except IndexError:
first_line = ''
try:
first_line = first_line.decode('utf-8')
except AttributeError:
pass
if "quiske" in first_line:
match = re.search(r'[\w\.-]+@[\w\.-]+', first_line)
return match.group(0)
return from_address
class Command(BaseCommand):
def add_arguments(self, parser):
parser.add_argument(
'--testing',
action='store_true',
dest='testing',
default=False,
help="Run in testing mode, don't send emails",
)
"""Run the Email processing command """
def handle(self, *args, **options):
# Polar
polar_available = polarstuff.get_polar_notifications()
res = polarstuff.get_all_new_workouts(polar_available)
# Concept2
rowers = Rower.objects.filter(c2_auto_import=True).exclude(rowerplan='basic')
for r in rowers:
c2stuff.get_c2_workouts(r)
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
)
if 'testing' in options:
testing = options['testing']
else:
testing = False
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:
# 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
]
except IOError:
rowers = []
except Message.DoesNotExist:
attachment.delete()
for rower in rowers:
if extension == 'zip':
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:
print("Bad ZIP file")
print(attachment.document.name)
else:
# move attachment and make workout
if testing:
try:
print(name)
except UnicodeEncodeError:
print("Unicode Error")
try:
print(attachment.document)
except UnicodeEncodeError:
pass
workoutid = processattachment(
rower, attachment.document, name, uploadoptions,
testing=testing
)
# We're done with the attachment. It can be deleted
try:
attachment.delete()
except IOError:
pass
except WindowsError:
if not testing:
time.sleep(2)
try:
attachment.delete()
except WindowsError:
pass
except:
message.mailbox = failedmailbox
message.save()
if message.attachments.exists() is False:
# no attachments, so can be deleted
message.delete()
messages = Message.objects.all()
for message in messages:
if message.attachments.exists() is False:
message.delete()
# Strava
rowers = Rower.objects.filter(strava_auto_import=True).exclude(rowerplan='basic')
for r in rowers:
stravastuff.get_strava_workouts(r)
self.stdout.write(self.style.SUCCESS(
'Successfully processed email attachments'))