diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 6b5bae94..ee9df88f 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1225,7 +1225,10 @@ def handle_nonpainsled(f2, fileformat, summary=''): try: os.remove(f_to_be_deleted) except: - os.remove(f_to_be_deleted + '.gz') + try: + os.remove(f_to_be_deleted + '.gz') + except: + pass return (f2, summary, oarlength, inboard, fileformat) diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 23b640b7..95bc028c 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -13,6 +13,7 @@ from django_mailbox.models import Message, MessageAttachment,Mailbox from django.core.urlresolvers import reverse from django.conf import settings +from django.utils import timezone from rowers.models import Workout, Rower from rowingdata import rower as rrower @@ -23,6 +24,8 @@ 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.models import User,VirtualRace,Workout +from rowers.plannedsessions import email_submit_race workoutmailbox = Mailbox.objects.get(name='workouts') failedmailbox = Mailbox.objects.get(name='Failed') @@ -65,17 +68,42 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False): 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(rower, filename, title,testing=testing) + 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( - rower.defaultlandingpage, + therower.defaultlandingpage, kwargs = { 'id':workoutid[0], } @@ -99,9 +127,9 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False): ) try: if workoutid and not testing: - if rower.getemailnotifications and not rower.emailbounced: + if therower.getemailnotifications and not therower.emailbounced: email_sent = send_confirm( - rower.user, title, link, + therower.user, title, link, uploadoptions ) time.sleep(10) @@ -109,9 +137,9 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False): try: time.sleep(10) if workoutid: - if rower.getemailnotifications and not rower.emailbounced: + if therower.getemailnotifications and not therower.emailbounced: email_sent = send_confirm( - rower.user, title, link, + therower.user, title, link, uploadoptions ) except: diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index bd7f1958..1a48c7ab 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -36,6 +36,10 @@ import courses import iso8601 from iso8601 import ParseError from rowers.tasks import handle_check_race_course +from rowers.tasks import ( + handle_sendemail_raceregistration,handle_sendemail_racesubmission + ) +from rowers.utils import totaltime_sec_to_string def get_indoorraces(workout): races1 = VirtualRace.objects.filter( @@ -777,7 +781,6 @@ def race_can_submit(r,race): else: return False - print 'pop' return False def race_can_resubmit(r,race): @@ -877,6 +880,130 @@ def race_can_withdraw(r,race): return True +def email_submit_race(r,race,workoutid): + try: + w = Workout.objects.get(id=workoutid) + except Workout.DoesNotExist: + 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': + 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: + 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: + 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 + else: + + return 0 + + return 0 + + def race_can_register(r,race): if race.sessiontype == 'race': recordobj = VirtualRaceResult diff --git a/rowers/templates/virtualeventranking.html b/rowers/templates/virtualeventranking.html new file mode 100644 index 00000000..dac83880 --- /dev/null +++ b/rowers/templates/virtualeventranking.html @@ -0,0 +1,503 @@ +{% extends "newbase.html" %} +{% load staticfiles %} +{% load rowerfilters %} + +{% block title %}Rowsandall Virtual Race{% endblock %} + +{% block scripts %} +{% include "monitorjobs.html" %} + +{% endblock %} + +{% block og_title %}{{ race.name }}{% endblock %} +{% block description %}Virtual Rowing Race {{ race.name }}{% endblock %} + +{% if racelogo %} +{% block og_image %} + + + + +{% endblock %} +{% block image_src %} + +{% endblock %} +{% endif %} + +{% block main %} + + +
+ {% if race|is_final %} +
+
| + | Name | +Team Name | ++ | + | + | + | Class | + {% if race.sessiontype == 'race' %} +Boat | + {% endif %} +Time | +Distance | +Details | ++ |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {{ forloop.counter }} | ++ + {{ result.username }} | +{{ result.teamname }} | +{{ result.age }} | +{{ result.sex }} | +{{ result.weightcategory }} | ++ {% if result.adaptiveclass == 'None' %} + + {% else %} + {{ result.adaptiveclass }} + {% endif %} + | +{{ result.boatclass }} | + {% if race.sessiontype == 'race' %} +{{ result.boattype }} | + {% endif %} +{{ result.duration |durationprint:"%H:%M:%S.%f" }} | +{{ result.distance }} m | ++ + Details | ++ {% if race.manager == request.user and not race|is_final %} + + Disqualify + + {% else %} + + {% endif %} + | +
| + | {{ result.username }} | +{{ result.teamname }} | +{{ result.age }} | +{{ result.sex }} | +{{ result.weightcategory }} | ++ {% if result.adaptiveclass == 'None' %} + + {% else %} + {{ result.adaptiveclass }} + {% endif %} + | +{{ result.boatclass }} | + {% if race.sessiontype == 'race' %} +{{ result.boattype }} | + {% endif %} +DNS | +
+ Compare Results +
+ {% else %} ++ No results yet +
+ {% endif %} ++
+ +
+
+
+
| Course | {{ race.course }} | +
|---|---|
| Indoor Race | To be rowed on a Concept2 ergometer | +
| Time Zone | {{ race.timezone }} | +
| + {{ race.sessionmode }} challenge + | {{ race.sessionvalue }} {{ race.sessionunit }} + | +
| Registration closure | +{{ race.registration_closure }} | +
| Date | {{ race.startdate }} | +
| Race Window | {{ race.startdate }} {{ race.start_time }} to {{ race.enddate }} {{ race.end_time }} | +
| Results Submission Deadline | {{ race.evaluation_closure }} | +
| Organizer | {{ race.manager.first_name }} {{ race.manager.last_name }} | +
| Contact Email | {{ race.contact_email }} | +
| Contact Phone | {{ race.contact_phone }} | +
| Comment | {{ race.comment|linebreaks }} | +
| Name | +Team Name | + {% if race.sessiontype == 'race' %} +Class | +Boat | + {% else %} +Class | + {% endif %} +Age | +Gender | +Weight Category | +Adaptive | +
|---|---|---|---|---|---|---|---|---|
| {{ record.username }} + | {{ record.teamname }} | +{{ record.boatclass }} | + {% if race.sessiontype == 'race' %} +{{ record.boattype }} | + {% endif %} +{{ record.age }} | +{{ record.sex }} | +{{ record.weightcategory }} | ++ {% if record.adaptiveclass == 'None' %} + + {% else %} + {{ record.adaptiveclass }} + {% endif %} + | + {% if record.userid == rower.id and 'withdrawbutton' in buttons %} ++ Withdraw + | + {% endif %} +
+
+ Virtual races are intended as an informal way to add a + competitive element to training and as a quick way to set + up and manage small regattas. +
++ On the water races are rowed on the course shown. + You cannot submit results rowed + on other bodies of water. +
++ Indoor races are open for all, wherever you live. + However, be aware of the + time zone for the race window. +
++ As a rowsandall.com user, you can + register to take part in this event. Please note the registration + deadline. You must register before this deadline. + You can always withdraw from participating before the registration + deadline or the start of the race window, whichever is earlier. +
++ After the start of the race window and before the submission deadline, + you can submit results by linking the race to one of your uploaded + workouts. The workout start time must be within the race window + and your course must pass through the blue polygons on the course + map (in the right order), for your result to be valid. +
++ The results table has a link to a page where details of your workout + are shown. +
++ Race results are stored permanently and are not deleted when + you delete the respective workout or remove your account. + By registering, you agree with this and the race rules. +
++ If you use a manually added workout for your indoor race result, + please attach a screenshot of the ergometer display for verification. +
++ Virtual Racing on rowsandall.com is honors based. Please be a good + sport, submit real results rowed by you, and make sure you set the + boat type correctly. For (future functionality) age and gender + corrected times, please be sure your gender and birth date are set + correctly in your user settings. +
++ Virtual races are intended as an informal way to add a + competitive element to training. Virtual races are not + refereed or staffed to provide for participants safety. + Individual participants are entirely responsible for their + safety while participating in a virtual race. +
++ Until the evaluation closure time, the race organizer can + review and reject entries. If you are disqualified in this + way, you will receive an email with the reason. +
++
++ Tweet + {% else %} + data-text="@rowsandall #rowingdata Participate in Indoor Rowing virtual race '{{ race.name }}'">Tweet +{% endif %} +
+ + +
+ + +{% if not racelogo and race.manager == request.user %} +Add Race Logo +{% endif %} +{% endblock %} + +{% block sidebar %} +{% include 'menu_racing.html' %} +{% endblock %} diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index c3679e3b..14e80178 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -127,6 +127,22 @@ class UserFactory(factory.DjangoModelFactory): first_name = faker.name().split(' ')[0] last_name = faker.name().split(' ')[0] + +class RaceFactory(factory.DjangoModelFactory): + class Meta: + model = VirtualRace + + name = factory.LazyAttribute(lambda _: faker.word()) + registration_closure = timezone.now()+datetime.timedelta(days=1) + evaluation_closure = timezone.now()+datetime.timedelta(days=2) + startdate = timezone.now().date() + start_time = datetime.time() + enddate = (timezone.now()+datetime.timedelta(days=1)).date() + end_time = datetime.time() + preferreddate = timezone.now().date() + sessiontype = 'indoorrace' + sessionvalue = 1 + sessionmode = 'time' class WorkoutFactory(factory.DjangoModelFactory): class Meta: @@ -150,3 +166,20 @@ class SessionFactory(factory.DjangoModelFactory): name = factory.LazyAttribute(lambda _: faker.word()) comment = faker.text() +@pytest.fixture(scope="session", autouse=True) +def cleanup(request): + def remove_test_files(): + + for filename in os.listdir('media/mailbox_attachments'): + path = os.path.join('media/mailbox_attachments/',filename) + if not os.path.isdir(path): + os.remove(path) + + for filename in os.listdir('rowers/tests/testdata/temp'): + path = os.path.join('rowers/tests/testdata/temp/',filename) + if not os.path.isdir(path): + os.remove(path) + + + request.addfinalizer(remove_test_files) + diff --git a/rowers/tests/test_emails.py b/rowers/tests/test_emails.py new file mode 100644 index 00000000..bf3e986c --- /dev/null +++ b/rowers/tests/test_emails.py @@ -0,0 +1,224 @@ +#from __future__ import print_function +from statements import * + +class EmailUpload(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, + gdproptindate=timezone.now() + ) + + self.theadmin = UserFactory(is_staff=True) + self.rtheadmin = Rower.objects.create(user=self.theadmin, + birthdate = faker.profile()['birthdate'], + gdproptin=True, + gdproptindate=timezone.now(), + rowerplan='coach') + + nu = datetime.datetime.now() + workoutsbox = Mailbox.objects.create(name='workouts') + 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' + copyfile('rowers/tests/testdata/emails/colin.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,WindowsError): + 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) + 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') + + + +#@pytest.mark.django_db +class EmailTests(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, + gdproptindate=timezone.now() + ) + + self.theadmin = UserFactory(is_staff=True) + self.rtheadmin = Rower.objects.create(user=self.theadmin, + birthdate = faker.profile()['birthdate'], + gdproptin=True, + gdproptindate=timezone.now(), + rowerplan='coach') + + nu = datetime.datetime.now() + workoutsbox = Mailbox.objects.create(name='workouts') + 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 + copyfile(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' + copyfile('rowers/tests/testdata/emails/colin.csv',a2) + a = MessageAttachment(message=m,document=a2[6:]) + a.save() + + m = Message(mailbox=workoutsbox, + from_header = self.theadmin.email, + subject = "johnsworkout", + body = """ +user john +race 1 + """) + m.save() + + def tearDown(self): + for filename in os.listdir('media/mailbox_attachments'): + path = os.path.join('media/mailbox_attachments/',filename) + if not os.path.isdir(path): + try: + os.remove(path) + except (IOError,WindowsError): + 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_emailprocessing( + self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): + out = StringIO() + call_command('processemail', stdout=out,testing=True) + self.assertIn('Successfully processed email attachments',out.getvalue()) + + + +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, + 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, + gdproptindate=timezone.now(), + rowerplan='coach') + + self.race = RaceFactory(manager = self.theadmin) + + nu = datetime.datetime.now() + workoutsbox = Mailbox.objects.create(name='workouts') + 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' + copyfile('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,WindowsError): + 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) + self.assertIn('Successfully processed email attachments',out.getvalue()) + + ws = Workout.objects.filter(name="johnsworkout") + if not len(ws): + for w in Workout.objects.all(): + print w + + self.assertEqual(len(ws),1) + + w = ws[0] + self.assertEqual(w.user.user.username,u'john') + + results = IndoorVirtualRaceResult.objects.filter( + race=self.race) + + self.assertEqual(len(results),1) + result = results[0] + + self.assertTrue(result.coursecompleted) + diff --git a/rowers/tests/test_zemails.py b/rowers/tests/test_zemails.py deleted file mode 100644 index 2d79f37f..00000000 --- a/rowers/tests/test_zemails.py +++ /dev/null @@ -1,164 +0,0 @@ -#from __future__ import print_function -import pytest - -pytestmark = pytest.mark.django_db - -from bs4 import BeautifulSoup -import re -from nose_parameterized import parameterized -from django.test import TestCase, Client,override_settings -from django.core.management import call_command -from django.utils.six import StringIO -from django.test.client import RequestFactory -from rowers.views import checkworkoutuser,c2_open -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage -from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail -import rowers.plots as plots -import rowers.interactiveplots as iplots -import datetime -from rowingdata import rowingdata as rdata -from rowingdata import rower as rrower -from django.utils import timezone -from rowers.rows import handle_uploaded_file -from django.core.files.uploadedfile import SimpleUploadedFile -from time import strftime,strptime,mktime,time,daylight -import os -from rowers.tasks import handle_makeplot -from rowers.utils import serialize_list,deserialize_list -from rowers.utils import NoTokenError -from shutil import copyfile -from nose.tools import assert_true -from mock import Mock, patch -from minimocktest import MockTestCase -import pandas as pd -import rowers.c2stuff as c2stuff - -import json -import numpy as np - -from rowers import urls -from rowers.views import error500_view,error404_view,error400_view,error403_view - -from rowers.dataprep import delete_strokedata - -from redis import StrictRedis -redis_connection = StrictRedis() - -from rowers.tests.test_imports import mocked_requests - - -from django_mailbox.models import Mailbox,MessageAttachment,Message - -from rowers.tests.mocks import mocked_sqlalchemy - - -@pytest.mark.django_db -class UploadTests(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, - gdproptindate=timezone.now(), - getemailnotifications = False, - ) - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts') - workoutsbox.save() - failbox = Mailbox.objects.create(name='Failed') - failbox.save() - m = Message(mailbox=workoutsbox, - from_header = u.email, - subject = "3x(5min/2min)/r2 \r2", - body = """ -workout run - """) - m.save() - a2 = 'media/mailbox_attachments/colin2.csv' - copyfile('rowers/tests/testdata/emails/colin.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,WindowsError): - pass - - @patch('requests.get', side_effect=mocked_requests) - def test_email_workouttype(self, mock_get): - out = StringIO() - call_command('processemail', stdout=out, testing=True) - w = Workout.objects.get(id=1) - self.assertEqual(w.workouttype,'Run') - -#@pytest.mark.django_db -class EmailTests(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, - gdproptindate=timezone.now() - ) - - nu = datetime.datetime.now() - workoutsbox = Mailbox.objects.create(name='workouts') - 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 - copyfile(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' - copyfile('rowers/tests/testdata/emails/colin.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,WindowsError): - 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_emailprocessing( - self, mocked_sqlalchemy,mocked_polar_notifications, mock_get, mock_post): - out = StringIO() - call_command('processemail', stdout=out,testing=True) - self.assertIn('Successfully processed email attachments',out.getvalue()) - diff --git a/rowers/tests/testdata/minute.csv b/rowers/tests/testdata/minute.csv new file mode 100644 index 00000000..9bbf31bb --- /dev/null +++ b/rowers/tests/testdata/minute.csv @@ -0,0 +1,18 @@ +index,TimeStamp (sec), activityIdx, lapIdx, pointIdx, ElapsedTime (sec), Horizontal (meters), Stroke500mPace (sec/500m), Cadence (strokes/min), HRCur (bpm), Power (watts), Calories (kCal), Speed (m/sec), StrokeCount, StrokeDistance (meters), DriveLength (meters), DriveTime (ms), StrokeRecoveryTime (ms), WorkPerStroke (joules), AverageDriveForce (lbs), PeakDriveForce (lbs), DragFactor, ElapsedTimeAtDrive (sec), HorizontalAtDrive (meters), WorkoutType, IntervalType, WorkoutState, RowingState, WorkoutDurationType, WorkoutIntervalCount, Cadence (stokes/min), AverageBoatSpeed (m/s), AverageDriveForce (N), PeakDriveForce (N), Stroke Number,cum_dist,originalvelo +0,1548096824.0,0,0,0,4.18,20.3,93.3506356168139,48,86,436.5048883104004,1,5.3820000000000014,4,6.79,1.36,500,560,0,142.4,222.0,115,0.0,0.0,5,0,1,1,0,0,48.0,5.353892279687333,633.4265280000002,987.50484,2,20.3,5.353892279687333 +1,1548096826.7910905,0,0,1,6.94,35.9,89.62484388832563,45,87,496.4816892895996,2,5.6179999999999986,6,8.15,1.42,490,730,0,142.3,238.8,113,4.18,20.3,5,0,1,1,0,0,45.0,5.587840858292355,632.9817059999998,1062.2349359999996,4,35.9,5.587840858292355 +2,1548096837.108201,0,0,2,17.27,94.5,88.81577825856567,41,96,504.2099300644,8,5.647,13,8.19,1.36,480,770,0,144.0,242.9,112,6.94,35.9,5,0,1,1,0,0,41.0,5.616084465910367,640.54368,1080.4726380000004,11,94.5,5.616084465910367 +3,1548096839.086601,0,0,3,19.25,105.7,88.96490450858349,41,99,504.2099300644,8,5.647,14,8.19,1.39,480,750,0,142.0,244.6,112,17.27,94.5,5,0,1,1,0,0,41.0,5.616084465910367,631.64724,1088.034612,12,105.7,5.616084465910367 +4,1548096842.8994308,0,0,4,23.07,127.2,89.27586762584984,41,104,501.8029914016,11,5.638,17,8.12,1.36,470,760,0,143.6,251.4,112,19.25,105.7,5,0,1,1,0,0,41.0,5.607267018055401,638.7643919999998,1118.282508,15,127.2,5.607267018055401 +5,1548096847.161281,0,0,5,27.31,151.1,89.89298681607487,41,110,489.62041712640007,14,5.5920000000000005,20,8.11,1.36,490,760,0,133.6,231.0,111,23.07,127.2,5,0,1,1,0,0,41.0,5.561116672227786,594.282192,1027.53882,18,151.1,5.561116672227786 +6,1548096850.1555116,0,0,6,30.31,167.8,90.29743877919012,41,112,480.4843223404,15,5.557,22,8.47,1.39,490,820,0,143.9,234.4,111,27.31,151.1,5,0,1,1,0,0,41.0,5.526693931690064,640.0988580000002,1042.662768,20,167.8,5.526693931690064 +7,1548096853.1276512,0,0,7,33.28,184.3,90.39988760767656,40,113,484.1249963508004,17,5.5710000000000015,24,8.24,1.36,490,800,0,138.4,254.1,111,30.31,167.8,5,0,1,1,0,0,40.0,5.540780141843972,615.633648,1130.292702,22,184.3,5.540780141843972 +8,1548096856.0643613,0,0,8,36.21,200.5,90.61884542605642,41,115,477.8950465044004,18,5.5470000000000015,26,8.1,1.36,480,770,0,135.5,227.6,111,33.28,184.3,5,0,1,1,0,0,41.0,5.516936996579499,602.7338100000002,1012.4148720000001,24,200.5,5.516936996579499 +9,1548096859.0091813,0,0,9,39.17,216.8,91.12253138918642,41,116,468.9058576384001,20,5.5120000000000005,28,8.1,1.36,500,770,0,132.7,232.4,111,36.21,200.5,5,0,1,1,0,0,41.0,5.483057352779911,590.2787940000002,1033.766328,26,216.8,5.483057352779911 +10,1548096862.008181,0,0,10,42.16,233.2,91.7159092344983,40,117,462.8074479616,21,5.488,30,8.24,1.33,470,810,0,130.6,218.9,111,39.17,216.8,5,0,1,1,0,0,40.0,5.459111256687411,580.937532,973.715358,28,233.2,5.459111256687411 +11,1548096866.4157307,0,0,11,46.57,257.2,92.13100908526968,41,118,452.5120589444,24,5.447,33,7.89,1.33,470,760,0,133.0,227.5,111,42.16,233.2,5,0,1,1,0,0,41.0,5.417705060136527,591.61326,1011.97005,31,257.2,5.417705060136527 +12,1548096869.206501,0,0,12,49.36,272.4,92.30771272248859,43,118,452.7613310976001,25,5.448,35,7.6,1.3,460,710,0,131.0,208.0,111,46.57,257.2,5,0,1,1,0,0,43.0,5.418879375745096,582.71682,925.2297599999999,33,272.4,5.418879375745096 +13,1548096872.1160307,0,0,13,52.27,288.2,92.39395707918017,42,119,451.2670704864,26,5.442,37,7.96,1.33,480,770,0,132.8,222.3,111,49.36,272.4,5,0,1,1,0,0,42.0,5.413598960589,590.7236160000001,988.839306,35,288.2,5.413598960589 +14,1548096875.085701,0,0,14,55.24,304.2,92.99397114111812,41,119,442.6160316004,28,5.407,39,8.02,1.3,480,790,0,128.7,230.0,111,52.27,288.2,5,0,1,1,0,0,41.0,5.378657487091222,572.485914,1023.0906,37,304.2,5.378657487091222 +15,1548096878.0252109,0,0,15,58.2,319.9,94.06681282362852,41,119,426.8444927264001,29,5.3420000000000005,41,7.95,1.27,490,820,0,123.4,213.1,111,55.24,304.2,5,0,1,1,0,0,41.0,5.314061005420342,548.910348,947.9156820000001,39,319.9,5.314061005420342 +16,1548096880.0612912,0,0,16,60.0,329.3,95.37595742617708,40,120,409.81691239999986,30,5.27,42,8.03,1.27,490,840,0,110.4,193.6,111,58.2,319.9,5,0,10,0,0,0,40.0,5.242738806752646,491.08348800000016,861.175392,40,329.3,5.242738806752646 diff --git a/rowers/tests/testdata/testdata.csv.gz b/rowers/tests/testdata/testdata.csv.gz index a67f9afc..8480fc16 100644 Binary files a/rowers/tests/testdata/testdata.csv.gz and b/rowers/tests/testdata/testdata.csv.gz differ diff --git a/rowers/tests/testdata/testdata.tcx b/rowers/tests/testdata/testdata.tcx index 57cf726e..5842c118 100644 --- a/rowers/tests/testdata/testdata.tcx +++ b/rowers/tests/testdata/testdata.tcx @@ -2502,7 +2502,7 @@ -