Private
Public Access
1
0

Merge branch 'feature/admintouser' into develop

This commit is contained in:
Sander Roosendaal
2019-01-24 21:45:19 +01:00
13 changed files with 1183 additions and 173 deletions
+3
View File
@@ -1225,7 +1225,10 @@ def handle_nonpainsled(f2, fileformat, summary=''):
try: try:
os.remove(f_to_be_deleted) os.remove(f_to_be_deleted)
except: except:
try:
os.remove(f_to_be_deleted + '.gz') os.remove(f_to_be_deleted + '.gz')
except:
pass
return (f2, summary, oarlength, inboard, fileformat) return (f2, summary, oarlength, inboard, fileformat)
+34 -6
View File
@@ -13,6 +13,7 @@ from django_mailbox.models import Message, MessageAttachment,Mailbox
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.conf import settings from django.conf import settings
from django.utils import timezone
from rowers.models import Workout, Rower from rowers.models import Workout, Rower
from rowingdata import rower as rrower 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.polarstuff as polarstuff
import rowers.c2stuff as c2stuff import rowers.c2stuff as c2stuff
import rowers.stravastuff as stravastuff 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') workoutmailbox = Mailbox.objects.get(name='workouts')
failedmailbox = Mailbox.objects.get(name='Failed') failedmailbox = Mailbox.objects.get(name='Failed')
@@ -66,16 +69,41 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
if testing: if testing:
print 'Creating workout from email' 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 = [ 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: if testing:
print 'Workout id = {workoutid}'.format(workoutid=workoutid) print 'Workout id = {workoutid}'.format(workoutid=workoutid)
if workoutid[0]: if workoutid[0]:
link = settings.SITE_URL+reverse( link = settings.SITE_URL+reverse(
rower.defaultlandingpage, therower.defaultlandingpage,
kwargs = { kwargs = {
'id':workoutid[0], 'id':workoutid[0],
} }
@@ -99,9 +127,9 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
) )
try: try:
if workoutid and not testing: if workoutid and not testing:
if rower.getemailnotifications and not rower.emailbounced: if therower.getemailnotifications and not therower.emailbounced:
email_sent = send_confirm( email_sent = send_confirm(
rower.user, title, link, therower.user, title, link,
uploadoptions uploadoptions
) )
time.sleep(10) time.sleep(10)
@@ -109,9 +137,9 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
try: try:
time.sleep(10) time.sleep(10)
if workoutid: if workoutid:
if rower.getemailnotifications and not rower.emailbounced: if therower.getemailnotifications and not therower.emailbounced:
email_sent = send_confirm( email_sent = send_confirm(
rower.user, title, link, therower.user, title, link,
uploadoptions uploadoptions
) )
except: except:
+128 -1
View File
@@ -36,6 +36,10 @@ import courses
import iso8601 import iso8601
from iso8601 import ParseError from iso8601 import ParseError
from rowers.tasks import handle_check_race_course 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): def get_indoorraces(workout):
races1 = VirtualRace.objects.filter( races1 = VirtualRace.objects.filter(
@@ -777,7 +781,6 @@ def race_can_submit(r,race):
else: else:
return False return False
print 'pop'
return False return False
def race_can_resubmit(r,race): def race_can_resubmit(r,race):
@@ -877,6 +880,130 @@ 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:
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): def race_can_register(r,race):
if race.sessiontype == 'race': if race.sessiontype == 'race':
recordobj = VirtualRaceResult recordobj = VirtualRaceResult
+503
View File
@@ -0,0 +1,503 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Rowsandall Virtual Race{% endblock %}
{% block scripts %}
{% include "monitorjobs.html" %}
<script>
setTimeout("location.reload(true);",60000);
</script>
{% endblock %}
{% block og_title %}{{ race.name }}{% endblock %}
{% block description %}Virtual Rowing Race {{ race.name }}{% endblock %}
{% if racelogo %}
{% block og_image %}
<meta property="og:image" content="http://rowsandall.com/{{ racelogo.filename|spacetohtml }}" />
<meta property="og:image:secure_url" content="https://rowsandall.com/{{ racelogo.filename |spacetohtml }}" />
<meta property="og:image:width" content="{{ racelogo.width }}" />
<meta property="og:image:height" content="{{ racelogo.height }}" />
{% endblock %}
{% block image_src %}
<link rel="image_src" href="/{{ racelogo.filename |spacetohtml }}" />
{% endblock %}
{% endif %}
{% block main %}
<h1>{{ race.name }}</h1>
<ul class="main-content">
<li class="grid_2">
<div id="results">
<p>
{% if race|is_final %}
<h2>Final Results</h2>
{% else %}
<h2>Results</h2>
{% endif %}
</p>
{% if results or dns %}
<p>
<table class="listtable shortpadded" width="100%">
<thead>
<tr>
<th>&nbsp;</th>
<th>Name</th>
<th>Team Name</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>&nbsp;</th>
<th>Class</th>
{% if race.sessiontype == 'race' %}
<th>Boat</th>
{% endif %}
<th>Time</th>
<th>Distance</th>
<th>Details</th>
<th>&nbsp;</th>
</tr>
</thead>
<tbody>
{% for result in results %}
<tr>
<td>{{ forloop.counter }}</td>
<td>
<a href="/rowers/workout/{{ result.workoutid }}">
{{ result.username }}</a></td>
<td>{{ result.teamname }}</td>
<td>{{ result.age }}</td>
<td>{{ result.sex }}</td>
<td>{{ result.weightcategory }}</td>
<td>
{% if result.adaptiveclass == 'None' %}
&nbsp;
{% else %}
{{ result.adaptiveclass }}
{% endif %}
</td>
<td>{{ result.boatclass }}</td>
{% if race.sessiontype == 'race' %}
<td>{{ result.boattype }}</td>
{% endif %}
<td>{{ result.duration |durationprint:"%H:%M:%S.%f" }}</td>
<td>{{ result.distance }} m</td>
<td>
<a href="/rowers/workout/{{ result.workoutid }}">
Details</a></td>
<td>
{% if race.manager == request.user and not race|is_final %}
<a href="/rowers/virtualevent/{{ race.id }}/disqualify/{{ result.id }}/">
Disqualify
</a>
{% else %}
&nbsp;
{% endif %}
</td>
</tr>
{% endfor %}
{% for result in dns %}
<tr>
<td>&nbsp;</td>
<td>{{ result.username }}</td>
<td>{{ result.teamname }}</td>
<td>{{ result.age }}</td>
<td>{{ result.sex }}</td>
<td>{{ result.weightcategory }}</td>
<td>
{% if result.adaptiveclass == 'None' %}
&nbsp;
{% else %}
{{ result.adaptiveclass }}
{% endif %}
</td>
<td>{{ result.boatclass }}</td>
{% if race.sessiontype == 'race' %}
<td>{{ result.boattype }}</td>
{% endif %}
<td>DNS</td>
</tr>
{% endfor %}
</tbody>
</table>
</p>
<p>
<a href="/rowers/virtualevent/{{ race.id }}/compare"
title="Compare the workouts of all competitors">Compare Results</a>
</p>
{% else %}
<p>
No results yet
</p>
{% endif %}
</div>
</li>
{% if form %}
<li class="grid_2">
<p>
<h2>Filter Results</h2>
</p>
<p>
<form id="result_filter_form", method="post">
<table>
{{ form.as_table }}
</table>
{% csrf_token %}
<input type="submit" value="Submit">
</p>
</li>
{% endif %}
{% if racelogo %}
<li class="grid_2">
<img src="/{{ racelogo.filename }}" alt="{{ racelogo.filename }}" height="100" width="120">
{% if race.manager == request.user %}
<a href="/rowers/virtualevent/{{ race.id }}/image">Edit Image</a>
{% endif %}
</li>
{% endif %}
{% if race.sessiontype == 'race' %}
<li class="grid_2">
<p>
<h2>Course</h2>
</p>
<div class="mapdiv">
{{ coursediv|safe }}
{{ coursescript|safe }}
</div>
</li>
{% endif %}
<li class="grid_2">
<div id="raceinfo">
<p>
<h2>Race Information</h2>
</p>
<p>
<table class="listtable shortpadded" width="100%">
<tbody>
{% if race.sessiontype == 'race' %}
<tr>
<th>Course</th><td>{{ race.course }}</td>
</tr>
{% else %}
<tr>
<th>Indoor Race</th><td>To be rowed on a Concept2 ergometer</td>
</tr>
<tr>
<th>Time Zone</th><td>{{ race.timezone }}</td>
</tr>
{% endif %}
<tr>
<th>
{{ race.sessionmode }} challenge
</th><td>{{ race.sessionvalue }} {{ race.sessionunit }}
</td>
</tr>
<tr>
<th>Registration closure</th>
<td>{{ race.registration_closure }}</td>
</tr>
<tr>
<th>Date</th><td>{{ race.startdate }}</td>
</tr>
<tr>
<th>Race Window</th><td>{{ race.startdate }} {{ race.start_time }} to {{ race.enddate }} {{ race.end_time }}</td>
</tr>
<tr>
<th>Results Submission Deadline</th><td>{{ race.evaluation_closure }}</td>
</tr>
<tr>
<th>Organizer</th><td>{{ race.manager.first_name }} {{ race.manager.last_name }}</td>
</tr>
<tr>
<th>Contact Email</th><td>{{ race.contact_email }}</td>
</tr>
<tr>
<th>Contact Phone</th><td>{{ race.contact_phone }}</td>
</tr>
<tr>
<th>Comment</th><td>{{ race.comment|linebreaks }}</td>
</tr>
</tbody>
</table>
</p>
</div>
</li>
<li class="grid_2">
<div id="registerbuttons">
{% if request.user.is_anonymous %}
<p>
Registered users of rowsandall.com can participate in this event. Participation is free, unless specified differently in the race comment above.
{% if race.sessiontype == 'race' %}
<a href="/rowers/virtualevent/{{ race.id }}/register"><h3>Register</h3></a>
{% else %}
<a href="/rowers/virtualevent/{{ race.id }}/registerindoor"><h3>Register</h3></a>
{% endif %}
</p>
{% else %}
<p>
See race rules below. Participation to this race is free,
unless specified differently in the race comment above.
</p>
<p>
{% for button in buttons %}
{% if button == 'registerbutton' %}
<p>
{% if race.sessiontype == 'race' %}
<a href="/rowers/virtualevent/{{ race.id }}/register"><h3>Register</h3></a>
{% else %}
<a href="/rowers/virtualevent/{{ race.id }}/registerindoor"><h3>Register</h3></a>
{% endif %}
</p>
{% endif %}
{% if button == 'submitbutton' %}
<table width=100% class="shortpadded">
<tr>
<td>
<a href="/rowers/virtualevent/{{ race.id }}/submit">Submit Workout</a>
</td>
<td>
Submit a workout that is already on the site as your race result
</td>
</tr>
<tr>
<td>
<a href="/rowers/workout/upload">Upload your race result</a>
</td>
<td>
Upload a new workout to the site and submit it as a result. You
need a workout data file.
</td>
</tr>
{% if race.sessiontype == 'indoorrace' %}
<tr>
<td>
<a href="/rowers/workout/addmanual">Enter your race result manually</a>
</td>
<td>
If you don't have a data file, enter the results
manually. If you have a photo of the monitor with the
result, it is recommended to add this to the workout.
</td>
</tr>
{% endif %}
</table>
{% endif %}
{% if button == 'resubmitbutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/submit">Submit New Result</a>
</p>
{% endif %}
{% if button == 'withdrawbutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/withdraw">Withdraw</a>
</p>
{% endif %}
{% if button == 'adddisciplinebutton' %}
<p>
<a href="/rowers/virtualevent/{{ race.id }}/adddiscipline">
Register New Boat
</a>
</p>
{% endif %}
{% if button == 'editbutton' %}
<p>
{% if race.sessiontype == 'race' %}
<a href="/rowers/virtualevent/{{ race.id }}/edit">Edit Race
</a>
{% else %}
<a href="/rowers/virtualevent/{{ race.id }}/editindoor">Edit Race
</a>
{% endif %}
</p>
{% endif %}
{% endfor %}
{% endif %}
</div>
</li>
<li class="grid_2">
<div id="registered">
{% if records %}
<h2>Registered Competitors</h2>
<table class="listtable shortpadded" width="100%">
<thead>
<tr>
<th>Name</th>
<th>Team Name</th>
{% if race.sessiontype == 'race' %}
<th>Class</th>
<th>Boat</th>
{% else %}
<th>Class</th>
{% endif %}
<th>Age</th>
<th>Gender</th>
<th>Weight Category</th>
<th>Adaptive</th>
</tr>
<tbody>
{% for record in records %}
<tr>
<td>{{ record.username }}
<td>{{ record.teamname }}</td>
<td>{{ record.boatclass }}</td>
{% if race.sessiontype == 'race' %}
<td>{{ record.boattype }}</td>
{% endif %}
<td>{{ record.age }}</td>
<td>{{ record.sex }}</td>
<td>{{ record.weightcategory }}</td>
<td>
{% if record.adaptiveclass == 'None' %}
&nbsp;
{% else %}
{{ record.adaptiveclass }}
{% endif %}
</td>
{% if record.userid == rower.id and 'withdrawbutton' in buttons %}
<td>
<a href="/rowers/virtualevent/{{ race.id }}/withdraw/{{ record.id }}" >Withdraw</a>
</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% for record in records %}
{% if record.userid == request.user.rower.id %}
{% if race.sessiontype == 'race' %}
{% if record.emailnotifications %}
<a href="/rowers/raceregistration/togglenotification/{{ race.id }}">
Unsubscribe from race notifications by email
</a>
{% else %}
<a href="/rowers/raceregistration/togglenotification/{{ race.id }}">
Subscribe to race notifications by email
</a>
{% endif %}
{% else %}
{% if record.emailnotifications %}
<a href="/rowers/indoorraceregistration/togglenotification/{{ race.id }}">
Unsubscribe from race notifications by email
</a>
{% else %}
<a href="/rowers/indoorraceregistration/togglenotification/{{ race.id }}">
Subscribe to race notifications by email
</a>
{% endif %}
{% endif %}
{% endif %}
{% endfor %}
</li>
<li class="grid_4">
<div id="rules">
<p>
<h2>Rules</h2>
</p>
<p>
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.
</p>
<p>
On the water races are rowed on the course shown.
You cannot submit results rowed
on other bodies of water.
</p>
<p>
Indoor races are open for all, wherever you live.
However, be aware of the
time zone for the race window.
</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
The results table has a link to a page where details of your workout
are shown.
</p>
<p>
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.
</p>
<p>
If you use a manually added workout for your indoor race result,
please attach a screenshot of the ergometer display for verification.
</p>
<p>
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.
</p>
<p>
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.
</p>
<p>
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.
</p>
</div>
</li>
</ul>
<p>
<div class="fb-share-button"
data-href="{{ request.build_absolute_uri }}"
data-layout="button" data-size="small" data-mobile-iframe="false">
<a class="fb-xfbml-parse-ignore" target="_blank"
href="https://www.facebook.com/sharer/sharer.php?u={{ request.build_absolute_uri }}">Share</a>
</div>
</p><p>
<a class="twitter-share-button"
href="https://twitter.com/intent/tweet"
data-url="{{ request.build_absolute_uri }}"
{% if race.sessiontype == 'race' %}
data-text="@rowsandall #rowingdata Participate in virtual race '{{ race.name }}'">Tweet</a>
{% else %}
data-text="@rowsandall #rowingdata Participate in Indoor Rowing virtual race '{{ race.name }}'">Tweet</a>
{% endif %}
</p><p>
<a href="https://www.pinterest.com/pin/create/button/"
data-pin-do="buttonBookmark">
</a>
</p>
{% if not racelogo and race.manager == request.user %}
<a href="/rowers/virtualevent/{{ race.id }}/image">Add Race Logo</a>
{% endif %}
{% endblock %}
{% block sidebar %}
{% include 'menu_racing.html' %}
{% endblock %}
+33
View File
@@ -128,6 +128,22 @@ class UserFactory(factory.DjangoModelFactory):
first_name = faker.name().split(' ')[0] first_name = faker.name().split(' ')[0]
last_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 WorkoutFactory(factory.DjangoModelFactory):
class Meta: class Meta:
model = Workout model = Workout
@@ -150,3 +166,20 @@ class SessionFactory(factory.DjangoModelFactory):
name = factory.LazyAttribute(lambda _: faker.word()) name = factory.LazyAttribute(lambda _: faker.word())
comment = faker.text() 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)
+224
View File
@@ -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)
-164
View File
@@ -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())
+18
View File
@@ -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
1 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
2 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
3 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
4 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
5 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
6 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
7 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
8 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
9 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
10 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
11 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
12 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
13 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
14 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
15 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
16 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
17 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
18 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
Binary file not shown.
+1 -1
View File
@@ -2502,7 +2502,7 @@
</Trackpoint> </Trackpoint>
</Track> </Track>
</Lap> </Lap>
<Notes>&lt;Element 'Notes' at 0x13f67128&gt;</Notes> <Notes>&lt;Element 'Notes' at 0x18ae8668&gt;</Notes>
</Activity> </Activity>
</Activities> </Activities>
<Creator> <Creator>
+57
View File
@@ -82,6 +82,27 @@ def matchchart(line):
if tester3.match(line.lower()): if tester3.match(line.lower()):
return 'pieplot' 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:
return None
return None
def matchsync(line): def matchsync(line):
results = [] results = []
tester = '((sync)|(synchronization)|(export))' tester = '((sync)|(synchronization)|(export))'
@@ -176,6 +197,22 @@ def getplotoptions_body2(uploadoptions,body):
return uploadoptions 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): def getsyncoptions_body2(uploadoptions,body):
result = [] result = []
for line in body.splitlines(): for line in body.splitlines():
@@ -261,6 +298,20 @@ def getboattype(uploadoptions,value,key):
return uploadoptions return uploadoptions
def getuser(uploadoptions,value,key):
uploadoptions['username'] = value
return uploadoptions
def getrace(uploadoptions,value,key):
try:
raceid = int(value)
uploadoptions['raceid'] = raceid
except:
pass
return uploadoptions
def getsource(uploadoptions,value,key): def getsource(uploadoptions,value,key):
workoutsource = 'unknown' workoutsource = 'unknown'
for type,verb in workoutsources: for type,verb in workoutsources:
@@ -306,6 +357,10 @@ def upload_options(body):
uploadoptions = getboattype(uploadoptions,value,'boattype') uploadoptions = getboattype(uploadoptions,value,'boattype')
if 'source' in lowkey: if 'source' in lowkey:
uploadoptions = getsource(uploadoptions,value,'workoutsource') 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: except AttributeError:
#pass #pass
raise yaml.YAMLError raise yaml.YAMLError
@@ -317,6 +372,8 @@ def upload_options(body):
uploadoptions = gettypeoptions_body2(uploadoptions,body) uploadoptions = gettypeoptions_body2(uploadoptions,body)
uploadoptions = getstravaid(uploadoptions,body) uploadoptions = getstravaid(uploadoptions,body)
uploadoptions = getworkoutsources(uploadoptions,body) uploadoptions = getworkoutsources(uploadoptions,body)
uploadoptions = getuseroptions_body2(uploadoptions,body)
uploadoptions = getraceoptions_body2(uploadoptions,body)
except IOError: except IOError:
pm = exc.problem_mark pm = exc.problem_mark
strpm = str(pm) strpm = str(pm)
+1
View File
@@ -149,6 +149,7 @@ urlpatterns = [
url(r'^indoorraceregistration/togglenotification/(?P<id>\d+)/$', url(r'^indoorraceregistration/togglenotification/(?P<id>\d+)/$',
views.indoorvirtualevent_toggle_email_view), views.indoorvirtualevent_toggle_email_view),
url(r'^virtualevent/(?P<id>\d+)/$',views.virtualevent_view), url(r'^virtualevent/(?P<id>\d+)/$',views.virtualevent_view),
url(r'^virtualevent/(?P<id>\d+)/ranking$',views.virtualevent_ranking_view),
url(r'^virtualevent/(?P<id>\d+)/edit/$',views.virtualevent_edit_view), url(r'^virtualevent/(?P<id>\d+)/edit/$',views.virtualevent_edit_view),
url(r'^virtualevent/(?P<id>\d+)/editindoor/$',views.indoorvirtualevent_edit_view), url(r'^virtualevent/(?P<id>\d+)/editindoor/$',views.indoorvirtualevent_edit_view),
url(r'^virtualevent/(?P<id>\d+)/register/$',views.virtualevent_register_view), url(r'^virtualevent/(?P<id>\d+)/register/$',views.virtualevent_register_view),
+180
View File
@@ -16128,6 +16128,186 @@ def virtualevent_view(request,id=0):
'active':'nav-racing', 'active':'nav-racing',
}) })
def virtualevent_ranking_view(request,id=0):
results = []
if not request.user.is_anonymous():
r = getrower(request.user)
else:
r = None
try:
race = VirtualRace.objects.get(id=id)
except VirtualRace.DoesNotExist:
raise Http404("Virtual Race does not exist")
if race.sessiontype == 'race':
script,div = course_map(race.course)
resultobj = VirtualRaceResult
else:
script = ''
div = ''
resultobj = IndoorVirtualRaceResult
records = resultobj.objects.filter(race=race)
buttons = []
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
)
if not request.user.is_anonymous():
if race_can_register(r,race):
buttons += ['registerbutton']
if race_can_adddiscipline(r,race):
buttons += ['adddisciplinebutton']
if race_can_submit(r,race):
buttons += ['submitbutton']
if race_can_resubmit(r,race):
buttons += ['resubmitbutton']
if race_can_withdraw(r,race):
buttons += ['withdrawbutton']
if race_can_edit(r,race):
buttons += ['editbutton']
if request.method == 'POST':
form = RaceResultFilterForm(request.POST,records=records)
if form.is_valid():
cd = form.cleaned_data
try:
sex = cd['sex']
except KeyError:
sex = ['female','male','mixed']
try:
boattype = cd['boattype']
except KeyError:
boattype = mytypes.waterboattype
try:
boatclass = cd['boatclass']
except KeyError:
if race.sessiontype == 'race':
boatclass = [t for t in mytypes.otwtypes]
else:
boatclass = [t for t in mytypes.otetypes]
age_min = cd['age_min']
age_max = cd['age_max']
try:
weightcategory = cd['weightcategory']
except KeyError:
weightcategory = ['hwt','lwt']
try:
adaptiveclass = cd['adaptiveclass']
except KeyError:
adaptiveclass = ['None','PR1','PR2','PR3','FES']
if race.sessiontype == 'race':
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
boatclass__in=boatclass,
boattype__in=boattype,
sex__in=sex,
weightcategory__in=weightcategory,
adaptiveclass__in=adaptiveclass,
age__gte=age_min,
age__lte=age_max
).order_by("duration")
else:
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
boatclass__in=boatclass,
sex__in=sex,
weightcategory__in=weightcategory,
adaptiveclass__in=adaptiveclass,
age__gte=age_min,
age__lte=age_max
).order_by("duration","-distance")
# to-do - add DNS
dns = []
if timezone.now() > race.evaluation_closure:
dns = resultobj.objects.filter(
race=race,
workoutid__isnull=True,
boatclass__in=boatclass,
sex__in=sex,
weightcategory__in=weightcategory,
adaptiveclass__in=adaptiveclass,
age__gte=age_min,
age__lte=age_max
)
else:
results = resultobj.objects.filter(
race=race,
workoutid__isnull=False,
coursecompleted=True,
).order_by("duration","-distance")
if results:
form = RaceResultFilterForm(records=records)
else:
form = None
breadcrumbs = [
{
'url':reverse(virtualevents_view),
'name': 'Racing'
},
{
'url':reverse(virtualevent_view,
kwargs={'id':race.id}
),
'name': race.name
}
]
racelogos = race.logos.all()
if racelogos:
racelogo = racelogos[0]
else:
racelogo = None
return render(request,'virtualeventranking.html',
{
'coursescript':script,
'coursediv':div,
'breadcrumbs':breadcrumbs,
'race':race,
'rower':r,
'results':results,
'buttons':buttons,
'dns':dns,
'records':records,
'racelogo':racelogo,
'form':form,
'active':'nav-racing',
})
@login_required() @login_required()
def virtualevent_withdraw_view(request,id=0,recordid=None): def virtualevent_withdraw_view(request,id=0,recordid=None):
r = getrower(request.user) r = getrower(request.user)