diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 4719bee3..5adffab1 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -114,7 +114,11 @@ class Command(BaseCommand): extension = attachment.document.name[-3:].lower() try: message = Message.objects.get(id=attachment.message_id) - body = "\n".join(message.text.splitlines()) + if message.text: + body = "\n".join(message.text.splitlines()) + else: + body = message.body + uploadoptions = uploads.upload_options(body) from_address = message.from_address[0].lower() name = message.subject diff --git a/rowers/templates/document_form.html b/rowers/templates/document_form.html index 7ad85c58..23888508 100644 --- a/rowers/templates/document_form.html +++ b/rowers/templates/document_form.html @@ -15,7 +15,10 @@ {% endblock %} - {% block content %} +{% block content %} +
@@ -25,7 +28,7 @@ Upload?

{% endif %} {% if form.errors %} -

+

Please correct the error{{ form.errors|pluralize }} below.

{% endif %} @@ -53,7 +56,7 @@ If you check "make private", this workout will not be visible to your followers and will not show up in your teams' workouts list. With the Landing Page option, you can select to which (workout related) page you will be taken after a successfull upload.

-

Select Files with the File button or drag them on the marked area

+

Select Files with the File button or drag them on the marked area

@@ -79,6 +82,10 @@ formdatasetok = false; } + if (!formdatasetok) { + $("#id_dropregion").remove(); + } + if (formdatasetok) { $(document).ready(function() { @@ -99,7 +106,14 @@ console.log("Loading dropper"); jQuery.event.props.push('dataTransfer'); - + $(window).on('dragenter', function() { + $("#id_drop-files").css("background-color","#E9E9E4"); + $("#id_dropregion").addClass("watermark").removeClass("invisible");}) + + $(window).on('dragleave', function() { + $("#id_drop-files").css("background-color","#FFFFFF"); + $("#id_dropregion").removeClass("watermark").addClass("invisible");}) + var frm = $("#file_form"); if( window.FormData === undefined ) { @@ -141,7 +155,7 @@ $('#id_offline').prop('checked','True'); data.set($('#id_offline').attr('name'),$('#id_offline').prop('checked')); console.log("Set offline to True"); - $('#extra_message').text('Because of the large size, we recommend to use background processing. You will receive email when it is done. The extra actions will not be performed.'); + $('#extra_message').text('Because of the large size, we recommend to use background processing. You will receive email when it is done.'); $('#extra_message').addClass('message'); } } @@ -240,7 +254,7 @@ $('#id_offline').prop('checked','True'); data.set($('#id_offline').attr('name'),$('#id_offline').prop('checked')); console.log("Set offline to True"); - $('#extra_message').text('Because of the large size, we recommend to use background processing. You will receive email when it is done. The extra actions will not be performed.'); + $('#extra_message').text('Because of the large size, we recommend to use background processing. You will receive email when it is done.'); $('#extra_message').addClass('message'); } data.set("file",f); diff --git a/rowers/uploads.py b/rowers/uploads.py index a6fab4a1..ea29c505 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -19,6 +19,9 @@ import yamllint from subprocess import call import re +from verbalexpressions import VerEx +import re + import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') @@ -45,6 +48,85 @@ def cleanbody(body): return body +# currently only matches one chart +def matchchart(line): + results = [] + tester = VerEx().start_of_line().find('chart').OR().find('plot') + tester2 = VerEx().start_of_line().find('chart').OR().find('plot').anything().find('distance') + tester3 = VerEx().start_of_line().find('chart').OR().find('plot').anything().find('time') + tester4 = VerEx().start_of_line().find('chart').OR().find('plot').anything().find('pie') + if tester.match(line.lower()): + if tester2.match(line.lower()): + return 'distanceplot' + if tester3.match(line.lower()): + return 'timeplot' + if tester3.match(line.lower()): + return 'pieplot' + +def matchsync(line): + results = [] + tester = '((sync)|(synchronization)|(export))' + tester2 = tester+'(.*)((c2)|(concept2)|(logbook))' + tester3 = tester+'(.*)((tp)|(trainingpeaks))' + tester4 = tester+'(.*)(strava)' + tester5 = tester+'(.*)((st)|(sporttracks))' + tester6 = tester+'(.*)((rk)|(runkeeper))' + tester7 = tester+'(.*)((mapmyfitness)|(underarmour)|(ua))' + + tester = re.compile(tester) + + if tester.match(line.lower()): + testers = [ + ('upload_to_C2',re.compile(tester2)), + ('upload_totp',re.compile(tester3)), + ('upload_to_Strava',re.compile(tester4)), + ('upload_to_SportTracks',re.compile(tester5)), + ('upload_to_RunKeeper',re.compile(tester6)), + ('upload_to_MapMyFitness',re.compile(tester7)), + ] + for t in testers: + if t[1].match(line.lower()): + results.append(t[0]) + + return results + +def getprivateoptions_body2(uploadoptions,body): + tester = re.compile('^(priva)') + for line in body.splitlines(): + if tester.match(line.lower()): + v = True + negs = ['false','False','None','no'] + for neg in negs: + tstr = re.compile('^(.*)'+neg) + + if tstr.match(line.lower()): + v = False + + uploadoptions['makeprivate'] = v + + return uploadoptions + +def getplotoptions_body2(uploadoptions,body): + for line in body.splitlines(): + chart = matchchart(line) + if chart: + uploadoptions['make_plot'] = True + uploadoptions['plottype'] = chart + + return uploadoptions + +def getsyncoptions_body2(uploadoptions,body): + result = [] + for line in body.splitlines(): + result = result+matchsync(line) + + result = list(set(result)) + + for r in result: + uploadoptions[r] = True + + return uploadoptions + def getsyncoptions(uploadoptions,values): try: value = values.lower() @@ -109,6 +191,8 @@ def upload_options(body): body = cleanbody(body) try: yml = (yaml.load(body)) + if yml and 'fromuploadform' in yml: + return yml try: for key, value in yml.iteritems(): lowkey = key.lower() @@ -121,13 +205,18 @@ def upload_options(body): except AttributeError: pass except yaml.YAMLError as exc: - 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, + try: + uploadoptions = getplotoptions_body2(uploadoptions,body) + uploadoptions = getsyncoptions_body2(uploadoptions,body) + uploadoptions = getprivateoptions_body2(uploadoptions,body) + except IOError: + pm = exc.problem_mark + strpm = str(pm) + pbm = "Your email has an issue on line {} at position {}. The error is: ".format( + pm.line+1, + pm.column+1, )+strpm - return {'error':pbm} + return {'error':pbm} if uploadoptions == {}: uploadoptions['message'] = 'No parsing issue. No valid commands detected' diff --git a/rowers/views.py b/rowers/views.py index bfa49541..619a99db 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -8,6 +8,7 @@ import pytz import operator import warnings import urllib +import yaml from PIL import Image from numbers import Number from django.views.generic.base import TemplateView @@ -8551,9 +8552,14 @@ def workout_upload_view(request, ) else: workoutsbox = Mailbox.objects.filter(name='workouts')[0] + uploadoptions['fromuploadform'] = True + bodyyaml = yaml.safe_dump( + uploadoptions, + default_flow_style=False + ) msg = Message(mailbox=workoutsbox, from_header=r.user.email, - subject = t) + subject = t,body=bodyyaml) msg.save() f3 = 'media/mailbox_attachments/'+f2[6:] copyfile(f2,f3) diff --git a/static/css/rowsandall.css b/static/css/rowsandall.css index fe739c64..0362df15 100644 --- a/static/css/rowsandall.css +++ b/static/css/rowsandall.css @@ -26,6 +26,24 @@ background-image: url("/static/img/landing8b.jpg"); } +.watermark { + position: absolute; + float: center; + opacity: 0.25; + font-size: 3em; + width: 100%; + top: 50%; + left: 50%; + transform: translateX(-25%) translateY(-50%); + text-align: center; + vertical-align: middle; + z-index: 1000; +} + +.invisible { + display: none +} + html { font-size: 62.5%; }