Private
Public Access
1
0
Files
rowsandall/rowers/management/commands/processemail.py
2021-04-15 18:13:41 +02:00

314 lines
9.9 KiB
Python

#!/srv/venv/bin/python
""" Process emails """
import sys
import os
PY3K = sys.version_info >= (3, 0)
import zipfile
from zipfile import BadZipFile
import re
import time
from time import strftime
import requests
import json
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.rp3stuff as rp3stuff
import rowers.stravastuff as stravastuff
import rowers.nkstuff as nkstuff
from rowers.opaque import encoder
from rowers.models import User,VirtualRace,Workout
from rowers.plannedsessions import email_submit_race
from rowers.rower_rules import user_is_not_basic
# 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
# 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):
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'] == '':
therower = rower
else:
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:
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:
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",
)
parser.add_argument(
'--mailbox',
action='store_true',
dest='mailbox',
default='workouts',
help="Changing mailbox name",
)
"""Run the Email processing command """
def handle(self, *args, **options):
if 'testing' in options:
testing = options['testing']
else:
testing = False
if 'mailbox' in options:
workoutmailbox = Mailbox.objects.get(name=options['mailbox'])
else:
workoutmailbox = Mailbox.objects.get(name='workouts')
if 'failedmailbox' in options:
failedmailbox = Mailbox.objects.get(name=options['failedmailbox'])
else:
failedmailbox = Mailbox.objects.get(name='Failed')
# Polar
polar_available = polarstuff.get_polar_notifications()
res = polarstuff.get_all_new_workouts(polar_available)
# Concept2
rowers = Rower.objects.filter(c2_auto_import=True)
for r in rowers:
if user_is_not_basic(r.user):
c2stuff.get_c2_workouts(r)
rowers = Rower.objects.filter(rp3_auto_import=True)
for r in rowers:
if user_is_not_basic(r.user):
res = rp3stuff.get_rp3_workouts(r)
rowers = Rower.objects.filter(nk_auto_import=True)
for r in rowers:
if user_is_not_basic(r.user):
res = nkstuff.get_nk_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
)
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
]
try:
rowers2 = [
r for r in Rower.objects.all() if from_address in r.emailalternatives
]
rowers = rowers+rowers2
except TypeError:
pass
except IOError:
rowers = []
except Message.DoesNotExist:
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:
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:
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)
#for r in rowers:
# stravastuff.get_strava_workouts(r)
self.stdout.write(self.style.SUCCESS(
'Successfully processed email attachments'))