Private
Public Access
1
0

Merge branch 'release/v9.36'

This commit is contained in:
Sander Roosendaal
2019-03-02 16:03:34 +01:00
5328 changed files with 255544 additions and 26642 deletions
-1
View File
@@ -27,7 +27,6 @@ conftest.py
# temporary test files
/rowers/tests/testdata/temp
/rowers/tests/testdata/testdata.csv.gz
rowers/tests/testdata/testdata.csv.gz
/rowers/tests/testdata/testdata.tcx
@@ -0,0 +1,6 @@
{
"cells": [],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}
-574
View File
@@ -1,574 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?><gpx xmlns="http://www.topografix.com/GPX/1/1" xmlns:gpxx="http://www.garmin.com/xmlschemas/GpxExtensions/v3" xmlns:gpxtpx="http://www.garmin.com/xmlschemas/TrackPointExtension/v1" creator="Oregon 400t" version="1.1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd"><metadata><link href="http://www.garmin.com"><text>Garmin International</text></link><time>2016-05-20T15:41:26</time></metadata><trk><name>Export by rowingdata</name><trkseg> <trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:26+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:29.238150+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:32.148290+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:35.269000+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:38.152180+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:41.148270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:44.148910+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:46.908250+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:49.819010+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:52.942510+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:55.639670+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:41:58.370000+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:01.188270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:04.008300+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:06.888990+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:09.678900+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:12.469140+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:15.199010+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:17.963080+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:20.658340+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:23.538800+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:26.269790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:28.848350+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:31.729550+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:34.398400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:37.038360+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:39.499250+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:42.349070+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:45.079070+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:47.752890+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:50.452350+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:53.182630+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:55.789410+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:42:58.671890+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:01.338860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:04.068490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:06.862620+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:09.618500+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:12.379160+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:15.229200+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:17.963150+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:20.692490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:23.628520+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:26.329210+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:29.148960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:31.668570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:34.490920+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:37.369250+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:40.189230+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:42.798860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:45.708750+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:48.318590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:51.199500+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:53.869290+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:56.572490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:43:59.212410+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:01.912890+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:04.459350+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:07.249360+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:09.949930+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:12.619870+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:15.378800+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:18.049420+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:20.719440+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:23.298970+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:26.178820+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:28.669980+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:31.429270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:34.042790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:36.589070+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:39.412800+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:42.078870+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:44.783760+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:47.450710+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:50.149400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:52.789720+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:55.429750+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:44:58.069700+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:00.742790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:03.442700+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:06.139610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:08.689490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:11.479530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:14.119610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:16.792860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:19.368950+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:22.158960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:24.889580+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:27.558940+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:30.469760+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:33.259860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:36.079590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:38.899560+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:41.689980+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:44.568940+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:47.329670+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:50.149560+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:52.969660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:55.879910+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:45:58.789690+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:01.729660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:04.669610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:07.549730+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:10.458930+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:13.488980+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:16.429320+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:19.519650+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:22.459630+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:25.338880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:28.459530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:31.401590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:34.339560+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:37.309450+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:40.098920+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:43.039950+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:46.039490+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:48.979630+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:51.949590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:54.709590+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:46:57.589710+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:00.503120+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:03.408950+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:06.323410+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:09.229670+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:12.198960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:15.079930+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:17.989660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:20.959680+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:23.869730+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:26.782970+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:29.688910+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:32.539570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:35.449720+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:38.329080+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:41.148960+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:44.088880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:47.150600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:50.029750+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:52.998850+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:55.880360+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:47:58.789400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:01.639760+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:04.492770+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:07.429530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:10.373270+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:13.309500+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:16.279570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:19.160740+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:21.948820+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:25.039520+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:27.949340+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:30.890880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:33.648790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:36.770050+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:39.499600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:42.559140+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:45.439020+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:48.439810+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:51.379570+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:54.259600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:48:57.139300+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:00.049550+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:02.838790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:05.839540+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:08.749400+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:11.689540+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:14.538900+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:17.389440+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:20.058880+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:23.059530+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:25.880610+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:28.608730+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:31.582600+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:34.278700+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:37.068660+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:40.039460+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:42.889790+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:45.772580+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:48.708690+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:51.679450+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:54.499470+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:49:57.409440+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:00.439330+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:03.408680+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:06.378680+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:09.168860+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:12.229650+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:15.138650+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:18.049470+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:20.959460+00:00</time>
</trkpt>
<trkpt lat="0.0" lon="0.0">
<time>2016-05-20T13:50:23.242360+00:00</time>
</trkpt>
</trkseg></trk></gpx>
+4 -4
View File
@@ -1,4 +1,4 @@
# -*- coding: utf-8 -*-
# -*- Coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models
@@ -44,7 +44,7 @@ class Member(models.Model):
verbose_name_plural = _("members")
ordering = ['user']
user = models.OneToOneField(User)
user = models.OneToOneField(User,on_delete=models.CASCADE)
contributions = models.BooleanField(default=True)
status = models.CharField(default="member",
choices=statuses,
@@ -150,8 +150,8 @@ class Outing(models.Model):
("completed", _("completed")),
("race", _("race")),
)
boat = models.ForeignKey(Boat)
rower = models.ForeignKey(Member)
boat = models.ForeignKey(Boat,on_delete=models.CASCADE)
rower = models.ForeignKey(Member,on_delete=models.CASCADE)
race = models.ManyToManyField(Races,blank=True)
otherrowers = models.ManyToManyField(Member,related_name="otherrowers")
status = models.CharField(_("Status"),default="active",
+1 -1
View File
@@ -1,4 +1,4 @@
from celery import Celery,app
from .celery import Celery,app
import os
import time
import gc
+128 -185
View File
@@ -1,221 +1,164 @@
alabaster==0.7.7
amqp==1.4.9
anyjson==0.3.3
appdirs==1.4.3
argcomplete==1.0.0
arrow==0.12.1
asn1crypto==0.23.0
astropy==1.1.2
amqp==2.4.1
arrow==0.13.1
atomicwrites==1.3.0
attrs==18.2.0
awscli==1.14.57
Babel==2.2.0
backports-abc==0.4
backports.functools-lru-cache==1.5
backports.shutil-get-terminal-size==1.0.0
backports.ssl-match-hostname==3.4.0.2
beautifulsoup4==4.6.0
billiard==3.3.0.23
bitarray==0.8.1
blaze==0.9.1
bleach==2.0.0
bokeh==0.12.3
boto==2.48.0
boto3==1.6.6
botocore==1.9.10
bottle==0.12.9
Bottleneck==1.0.0
braintree==3.50.0
cairocffi==0.7.2
celery==3.1.23
certifi==2017.11.5
cffi==1.11.2
backcall==0.1.0
beautifulsoup4==4.7.1
billiard==3.5.0.5
bleach==3.1.0
bokeh==1.0.4
braintree==3.51.0
celery==4.2.1
certifi==2018.11.29
chardet==3.0.4
chest==0.2.3
click==6.6
cloudpickle==0.1.1
clyent==1.2.1
colorama==0.3.7
comtypes==1.1.7
configobj==5.0.6
coreapi==2.0.9
cryptography==2.1.3
Click==7.0
colorama==0.4.1
cookies==2.2.1
coreapi==2.3.3
coreschema==0.0.4
cycler==0.10.0
Cython==0.23.4
cytoolz==0.7.5
dask==0.8.1
datashape==0.5.1
decorator==4.0.9
dill==0.2.4
dask==1.1.1
decorator==4.3.2
defusedxml==0.5.0
Django==1.9.5
django-analytical==2.2.2
django-analytics==0.0.1
django-analytical==2.5.0
django-async-messages==0.3.1
django-braces==1.8.1
django-celery==3.1.17
django-braces==1.13.0
django-classy-tags==0.8.0
django-cookie-law==1.0.12
django-cors-headers==1.1.0
django-cors-middleware==1.3.1
django-countries==5.3.2
django-cookie-law==2.0.1
django-cors-headers==2.4.0
django-countries==5.3.3
django-datetime-widget==0.9.3
django-debug-toolbar==1.4
django-durationfield==0.5.2
django-extensions==1.7.5
django-filter==1.0.0
django-geckoboard==2.0.0
django-geojson==2.10.0
django-extensions==2.1.6
django-htmlmin==0.10.0
django-leaflet==0.22.0
django-mailbox==4.6.0
django-modelcluster==1.1
django-leaflet==0.24.0
django-mailbox==4.7.1
django-oauth-toolkit==0.10.0
django-oauth2-provider==0.2.6.1
django-rest-swagger==2.1.0
django-rq==0.8.0
django-rq-dashboard==0.3.0
django-ses==0.8.5
django-social-share==1.1.2
django-suit==0.2.25
django-rest-framework==0.1.0
django-rest-swagger==2.2.0
django-rq==1.3.0
django-rq-dashboard==0.3.3
django-shell-plus==1.1.7
django-social-share==1.3.2
django-suit==0.2.26
django-suit-rq==1.0.1
django-taggit==0.18.1
django-translation-manager==0.3.4
django-treebeard==4.0
django-tz-detect==0.2.8
django-tz-detect==0.2.9
djangorestframework==3.5.3
docopt==0.6.2
docutils==0.12
enum34==1.1.2
et-xmlfile==1.0.1
Factory==1.2
fastcache==1.0.2
filemagic==1.6
docutils==0.14
entrypoints==0.3
factory-boy==2.11.1
Faker==1.0.2
fitparse==1.0.1
Flask==0.10.1
Flask-Cors==2.1.2
Flask-Login==0.3.2
Flask-OpenID==1.2.5
Flask-Uploads==0.2.0
flower==0.9.1
funcsigs==1.0.2
functools32==3.2.3.post2
future==0.16.0
futures==3.0.5
geocoder==1.37.0
geopy==1.11.0
gevent==1.1.0
greenlet==0.4.9
grin==1.2.1
gunicorn==19.4.5
HeapDict==1.0.0
honcho==0.6.6
future==0.17.1
geocoder==1.38.1
holoviews==1.11.2
html5lib==1.0.1
httplib2==0.9.2
htmlmin==0.1.12
HTMLParser==0.0.2
httplib2==0.12.1
icalendar==4.0.3
idna==2.6
ipaddress==1.0.14
ipython==4.2.0
ipython-genutils==0.1.0
idna==2.8
image==1.5.27
importlib-resources==1.0.2
ipykernel==5.1.0
ipython==7.3.0
ipython-genutils==0.2.0
ipywidgets==7.4.2
iso8601==0.1.12
isodate==0.6.0
itsdangerous==0.24
itypes==1.1.0
Jinja2==2.8
jmespath==0.9.3
jsonschema==2.5.1
jedi==0.13.3
Jinja2==2.10
jsonschema==3.0.0
jupyter==1.0.0
jupyter-client==5.2.4
jupyter-console==6.0.0
jupyter-core==4.4.0
kiwisolver==1.0.1
kombu==3.0.35
lxml==4.2.1
Markdown==2.6.7
MarkupSafe==0.23
matplotlib==2.2.2
mechanize==0.3.6
kombu==4.3.0
lxml==4.3.1
Markdown==3.0.1
MarkupSafe==1.1.1
matplotlib==3.0.2
MiniMockTest==0.5
mistune==0.8.4
mock==2.0.0
more-itertools==5.0.0
mpld3==0.2
mpmath==0.19
multipledispatch==0.4.8
networkx==1.11
mpld3==0.3
nbconvert==5.4.1
nbformat==4.4.0
nose==1.3.7
nose-parameterized==0.6.0
numpy==1.14.2
notebook==5.7.4
numpy==1.16.1
oauth2==1.9.0.post1
oauthlib==1.0.3
odo==0.4.2
openapi-codec==1.1.7
packaging==16.8
pandas==0.22.0
pathlib2==2.3.3
pathspec==0.5.5
openapi-codec==1.3.2
packaging==19.0
pandas==0.24.1
pandocfilters==1.4.2
param==1.8.2
parso==0.3.4
pathspec==0.5.9
pbr==5.1.2
pexpect==4.0.1
pickleshare==0.7.2
Pillow==3.2.0
pluggy==0.8.1
polib==1.0.7
psutil==4.1.0
ptyprocess==0.5.1
py==1.7.0
pyasn1==0.1.9
pycparser==2.14
pycrypto==2.6.1
PyMySQL==0.7.4
pync==1.6.1
pyparsing==2.2.0
pytest==4.2.0
pexpect==4.6.0
pickleshare==0.7.5
Pillow==5.4.1
pluggy==0.9.0
prometheus-client==0.6.0
prompt-toolkit==2.0.9
ptyprocess==0.6.0
py==1.8.0
Pygments==2.3.1
pyparsing==2.3.1
pyrsistent==0.14.11
pytest==4.3.0
pytest-django==3.4.7
pytest-runner==4.4
pytest-sugar==0.9.2
python-dateutil==2.7.2
python-memcached==1.58
python-metar==1.4.0
python-openid==2.2.5
python-twitter==3.2
pytz==2018.4
PyYAML==3.12
pyzmq==15.2.0
python-dateutil==2.8.0
python-twitter==3.5
pytz==2018.9
pyviz-comms==0.7.0
PyYAML==3.13
pyzmq==18.0.0
qtconsole==4.4.3
ratelim==0.1.6
redis==2.10.5
req==1.0.0
requests==2.12.3
requests-oauthlib==0.7.0
rowingdata==2.0.0
rowingphysics==0.3.10
rq==0.6.0
rq-dashboard==0.3.7
rsa==3.4.2
s3transfer==0.1.13
scandir==1.6
scikit-image==0.12.3
scikit-learn==0.17.1
scipy==1.0.1
seaborn==0.7.0
Shapely==1.6.1
shortuuid==0.4.3
simplegeneric==0.8.1
simplejson==3.10.0
singledispatch==3.4.0.3
six==1.11.0
SQLAlchemy==1.0.12
sqlparse==0.1.19
-e git+git@bitbucket.org:sanderroosendaal/rowsandall.git@c9695a9f8f5ee0e459de066007a5ef4cef58255b#egg=stravalib
subprocess32==3.2.7
sympy==1.0
redis==3.2.0
requests==2.21.0
requests-oauthlib==1.2.0
rowingdata==2.0.6
rowingphysics==0.5.0
rq==0.13.0
scipy==1.2.1
Send2Trash==1.5.0
shell==1.0.1
shortuuid==0.5.0
simplejson==3.16.0
six==1.12.0
soupsieve==1.8
SQLAlchemy==1.2.18
sqlparse==0.2.4
stravalib==0.10.2
termcolor==1.1.0
timestring==1.6.2
timezonefinder==2.1.2
toolz==0.7.4
tornado==4.4.2
tqdm==4.23.0
traitlets==4.2.1
tzwhere==3.0.3
Unidecode==0.4.19
units==0.6
terminado==0.8.1
testpath==0.4.2
text-unidecode==1.2
timezonefinder==3.4.2
tornado==5.1.1
tqdm==4.31.1
traitlets==4.3.2
units==0.7
uritemplate==3.0.0
urllib3==1.22
VerbalExpressions==0.0.1
urllib3==1.24.1
VerbalExpressions==0.0.2
vine==1.2.0
wcwidth==0.1.7
webencodings==0.5.1
Werkzeug==0.11.8
xlrd==1.0.0
xmltodict==0.11.0
widgetsnbextension==3.4.2
xmltodict==0.12.0
yamjam==0.1.7
yamllint==1.8.1
yamllint==1.15.0
+142
View File
@@ -0,0 +1,142 @@
amqp==2.4.1
arrow==0.13.1
atomicwrites==1.3.0
attrs==18.2.0
backcall==0.1.0
beautifulsoup4==4.7.1
billiard==3.5.0.5
bleach==3.1.0
bokeh==1.0.4
braintree==3.51.0
celery==4.2.1
certifi==2018.11.29
chardet==3.0.4
Click==7.0
colorama==0.4.1
cookies==2.2.1
coreapi==2.3.3
coreschema==0.0.4
cycler==0.10.0
dask==1.1.1
decorator==4.3.2
Django==1.9.5
django-analytical==2.5.0
django-async-messages==0.3.1
django-braces==1.13.0
django-classy-tags==0.8.0
django-cookie-law==2.0.1
django-cors-headers==2.4.0
django-countries==5.3.3
django-datetime-widget==0.9.3
django-debug-toolbar==1.4
django-extensions==2.1.6
django-htmlmin==0.10.0
django-leaflet==0.24.0
django-mailbox==4.7.1
django-oauth-toolkit==0.10.0
django-oauth2-provider==0.2.6.1
django-rest-framework==0.1.0
django-rest-swagger==2.2.0
django-rq==1.3.0
django-rq-dashboard==0.3.3
django-shell-plus==1.1.7
django-social-share==1.3.2
django-suit==0.2.26
django-suit-rq==1.0.1
django-tz-detect==0.2.9
djangorestframework==3.5.3
docopt==0.6.2
docutils==0.14
factory-boy==2.11.1
Faker==1.0.2
fitparse==1.0.1
future==0.17.1
geocoder==1.38.1
holoviews==1.11.2
html5lib==1.0.1
htmlmin==0.1.12
HTMLParser==0.0.2
httplib2==0.12.1
icalendar==4.0.3
idna==2.8
image==1.5.27
importlib-resources==1.0.2
ipython==7.3.0
ipython-genutils==0.2.0
iso8601==0.1.12
isodate==0.6.0
itypes==1.1.0
jedi==0.13.3
Jinja2==2.10
kiwisolver==1.0.1
kombu==4.3.0
lxml==4.3.1
Markdown==3.0.1
MarkupSafe==1.1.1
matplotlib==3.0.2
MiniMockTest==0.5
mock==2.0.0
more-itertools==5.0.0
mpld3==0.3
nose==1.3.7
nose-parameterized==0.6.0
numpy==1.16.1
oauth2==1.9.0.post1
oauthlib==1.0.3
openapi-codec==1.3.2
packaging==19.0
pandas==0.24.1
param==1.8.2
parso==0.3.4
pathspec==0.5.9
pbr==5.1.2
pexpect==4.6.0
pickleshare==0.7.5
Pillow==5.4.1
pluggy==0.9.0
prompt-toolkit==2.0.9
ptyprocess==0.6.0
py==1.8.0
Pygments==2.3.1
pyparsing==2.3.1
pytest==4.3.0
pytest-django==3.4.7
pytest-runner==4.4
pytest-sugar==0.9.2
python-dateutil==2.8.0
python-twitter==3.5
pytz==2018.9
pyviz-comms==0.7.0
PyYAML==3.13
ratelim==0.1.6
redis==3.2.0
requests==2.21.0
requests-oauthlib==1.2.0
rowingdata==2.0.6
rowingphysics==0.5.0
rq==0.13.0
scipy==1.2.1
shell==1.0.1
shortuuid==0.5.0
simplejson==3.16.0
six==1.12.0
soupsieve==1.8
SQLAlchemy==1.2.18
sqlparse==0.2.4
stravalib==0.10.2
termcolor==1.1.0
text-unidecode==1.2
timezonefinder==3.4.2
tornado==5.1.1
tqdm==4.31.1
traitlets==4.3.2
units==0.7
uritemplate==3.0.0
urllib3==1.24.1
VerbalExpressions==0.0.2
vine==1.2.0
wcwidth==0.1.7
webencodings==0.5.1
xmltodict==0.12.0
yamjam==0.1.7
yamllint==1.15.0
+6 -2
View File
@@ -1,5 +1,9 @@
from __future__ import absolute_import
from .tasks import app as celery_app
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from rowers.celery import app as celery_app
__all__ = ('celery_app',)
+4
View File
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
+3
View File
@@ -1,3 +1,6 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.apps import AppConfig
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import braintree
from django.utils import timezone
import datetime
+22 -5
View File
@@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# The interactions with the Concept2 logbook API
# All C2 related functions should be defined here
# (There is still some stuff defined directly in views.py. Need to
@@ -6,10 +12,12 @@
from rowers.imports import *
import datetime
from requests import Request, Session
import mytypes
import rowers.mytypes as mytypes
from rowers.mytypes import otwtypes
from iso8601 import ParseError
import numpy
from rowsandall_app.settings import (
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
)
@@ -19,7 +27,7 @@ import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from utils import myqueue
from rowers.utils import myqueue
oauth_data = {
'client_id': C2_CLIENT_ID,
@@ -418,7 +426,11 @@ def createc2workoutdata(w):
hr = 0*d
stroke_data = []
for i in range(len(t)):
thisrecord = {"t":t[i],"d":d[i],"p":p[i],"spm":spm[i],"hr":hr[i]}
thisrecord = {"t":t[i].astype(int),
"d":d[i].astype(int),
"p":p[i].astype(int),
"spm":spm[i].astype(int),
"hr":hr[i].astype(int)}
stroke_data.append(thisrecord)
try:
@@ -545,7 +557,7 @@ def make_authorization_url(request):
params = {"client_id": C2_CLIENT_ID,
"response_type": "code",
"redirect_uri": C2_REDIRECT_URI}
url = "https://log.concept2.com/oauth/authorize?"+ urllib.urlencode(params)
url = "https://log.concept2.com/oauth/authorize?"+ urllib.parse.urlencode(params)
url += "&scope="+scope
return HttpResponseRedirect(url)
@@ -691,6 +703,10 @@ def process_callback(request):
return HttpResponse("got a user name: %s" % username)
def default(o):
if isinstance(o, numpy.int64): return int(o)
raise TypeError
# Uploading workout
def workout_c2_upload(user,w):
message = 'trying C2 upload'
@@ -711,6 +727,7 @@ def workout_c2_upload(user,w):
raise NoTokenError
data = createc2workoutdata(w)
if data == 0:
return "Error: No data file. Contact info@rowsandall.com if the problem persists",0
@@ -720,7 +737,7 @@ def workout_c2_upload(user,w):
'Content-Type': 'application/json'}
import urllib
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
response = requests.post(url,headers=headers,data=json.dumps(data))
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
if (response.status_code == 409 ):
message = "Concept2 Duplicate error"
+3
View File
@@ -1,4 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import os
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.conf import settings # import the settings file
def braintree_merchant(request):
+7 -2
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# All the Courses related methods
# Python
@@ -28,7 +33,7 @@ import pandas as pd
import numpy as np
from timezonefinder import TimezoneFinder
import dataprep
import rowers.dataprep as dataprep
from rowers.utils import geo_distance
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
@@ -47,7 +52,7 @@ from rowers.models import (
polygon_to_path,coordinate_in_path
)
from utils import geo_distance
from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path
+4
View File
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# low level methods
def coordinate_in_path(latitude,longitude, p):
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.conf import settings
user = settings.DATABASES['default']['USER']
+25 -16
View File
@@ -1,5 +1,11 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# All the data preparation, data cleaning and data mangling should
# be defined here
from __future__ import unicode_literals, absolute_import
from rowers.models import Workout, StrokeData,Team
import pytz
@@ -55,7 +61,7 @@ import pandas as pd
import numpy as np
import itertools
import math
from tasks import (
from rowers.tasks import (
handle_sendemail_unrecognized, handle_sendemail_breakthrough,
handle_sendemail_hard, handle_updatecp,handle_updateergcp,
handle_calctrimp,
@@ -65,9 +71,9 @@ from django.conf import settings
from sqlalchemy import create_engine
import sqlalchemy as sa
import sys
import utils
import datautils
from utils import lbstoN,myqueue,is_ranking_piece,wavg
import rowers.utils as utils
import rowers.datautils as datautils
from rowers.utils import lbstoN,myqueue,is_ranking_piece,wavg
from timezonefinder import TimezoneFinder
@@ -531,7 +537,10 @@ def getstatsfields():
fielddict.pop('hr_bottom')
fielddict.pop('cumdist')
try:
fieldlist = [field for field, value in fielddict.iteritems()]
except AttributeError:
fieldlist = [field for field, value in fielddict.items()]
return fieldlist, fielddict
@@ -638,7 +647,7 @@ def deletecpdata_sql(rower_id,table='cpdata'):
try:
result = conn.execute(query)
except:
print "Database locked"
print("Database locked")
conn.close()
engine.dispose()
@@ -855,7 +864,7 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
return (id, message)
from utils import totaltime_sec_to_string
from rowers.utils import totaltime_sec_to_string
# Processes painsled CSV file to database
def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
@@ -904,7 +913,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
try:
checks = row.check_consistency()
allchecks = 1
for key, value in checks.iteritems():
for key, value in checks.items():
if not value:
allchecks = 0
if consistencychecks:
@@ -1564,7 +1573,7 @@ def compare_data(id):
res = conn.execute(query)
l2 = res.fetchall()[0][0]
except:
print "Database Locked"
print("Database Locked")
conn.close()
engine.dispose()
lfile = l1
@@ -1583,13 +1592,13 @@ def repair_data(verbose=False):
test, ldb, lfile = compare_data(w.id)
if not test:
if verbose:
print w.id, lfile, ldb
print(w.id, lfile, ldb)
try:
rowdata = rdata(w.csvfilename)
if rowdata and len(rowdata.df):
update_strokedata(w.id, rowdata.df)
except IOError, AttributeError:
except (IOError, AttributeError):
pass
if lfile == 0:
@@ -1618,10 +1627,10 @@ def repair_data(verbose=False):
def rdata(file, rower=rrower()):
try:
res = rrdata(csvfile=file, rower=rower)
except IOError, IndexError:
except (IOError, IndexError):
try:
res = rrdata(csvfile=file + '.gz', rower=rower)
except IOError, IndexError:
except (IOError, IndexError):
res = rrdata()
except:
res = rrdata()
@@ -1640,7 +1649,7 @@ def delete_strokedata(id):
try:
result = conn.execute(query)
except:
print "Database Locked"
print("Database Locked")
conn.close()
engine.dispose()
@@ -1792,7 +1801,7 @@ def prepmultipledata(ids, verbose=False):
for id in res:
rowdata, row = getrowdata(id=id)
if verbose:
print id
print(id)
if rowdata and len(rowdata.df):
data = dataprep(rowdata.df, id=id, bands=True,
barchart=True, otwpower=True)
@@ -2029,7 +2038,7 @@ def fix_newtons(id=0, limit=3000):
peakforce = rowdata['peakforce']
if peakforce.mean() > limit:
w = Workout.objects.get(id=id)
print "fixing ", id
print("fixing ", id)
rowdata = rdata(w.csvfilename)
if rowdata and len(rowdata.df):
update_strokedata(w.id, rowdata.df)
@@ -2084,7 +2093,7 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
if rowdatadf.empty:
return 0
rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
#rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
t = rowdatadf.loc[:, 'TimeStamp (sec)']
t = pd.Series(t - rowdatadf.loc[:, 'TimeStamp (sec)'].iloc[0])
+18 -13
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# This is Data prep used for testing purposes (no Django environment)
# Uses the debug SQLite database for stroke data
from rowingdata import rowingdata as rrdata
@@ -18,7 +23,7 @@ import sqlalchemy as sa
from rowsandall_app.settings import DATABASES
from rowsandall_app.settings_dev import DATABASES as DEV_DATABASES
from utils import lbstoN
from rowers.utils import lbstoN
try:
@@ -133,7 +138,7 @@ def rdata(file,rower=rrower()):
return res
from utils import totaltime_sec_to_string
from rowers.utils import totaltime_sec_to_string
# Creates C2 stroke data
@@ -635,14 +640,14 @@ def delete_strokedata(id,debug=False):
try:
result = conn.execute(query)
except:
print "Database Locked"
print("Database Locked")
conn.close()
engine.dispose()
def update_strokedata(id,df,debug=False):
delete_strokedata(id,debug=debug)
if debug:
print "updating ",id
print("updating ",id)
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
debug=debug)
@@ -676,11 +681,11 @@ def update_empower(id, inboard, oarlength, boattype, df, f1, debug=False):
if success:
delete_strokedata(id,debug=debug)
if debug:
print "updated ",id
print "correction ",corr_factor
print("updated ",id)
print("correction ",corr_factor)
else:
if debug:
print "not updated ",id
print("not updated ",id)
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
@@ -784,8 +789,8 @@ def read_cols_df_sql(ids,columns,debug=False):
def read_df_sql(id,debug=False):
if debug:
engine = create_engine(database_url_debug, echo=False)
print "read_df",id
print database_url_debug
print("read_df",id)
print(database_url_debug)
else:
engine = create_engine(database_url, echo=False)
@@ -826,7 +831,7 @@ def deletecpdata_sql(rower_id,table='cpdata',debug=False):
try:
result = conn.execute(query)
except:
print "Database locked"
print("Database locked")
conn.close()
engine.dispose()
@@ -846,7 +851,7 @@ def delete_agegroup_db(age,sex,weightcategory,debug=False):
try:
result = conn.execute(query)
except:
print "Database locked"
print("Database locked")
conn.close()
engine.dispose()
@@ -956,11 +961,11 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
if rowdatadf.empty:
if debug:
print "empty"
print("empty")
return 0
if debug:
print "dataprep",id
print("dataprep",id)
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
t = rowdatadf.ix[:,'TimeStamp (sec)']
+6 -1
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import pandas as pd
import numpy as np
from scipy.interpolate import griddata
@@ -259,7 +264,7 @@ def getcp(dfgrouped,logarr):
length = len(ww)
dt = []
cpw = []
for i in xrange(length-2):
for i in range(length-2):
deltat,wmax = getmaxwattinterval(tt,ww,i)
if not np.isnan(deltat) and not np.isnan(wmax):
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from django.contrib.auth.decorators import login_required,user_passes_test
from django.http import HttpResponseRedirect
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import os
import time
import gc
+14 -7
View File
@@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
from django import forms
from django.contrib.admin.widgets import FilteredSelectMultiple
from rowers.models import (
@@ -9,15 +15,16 @@ from rowers.rows import validate_file_extension,must_be_csv,validate_image_exten
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.contrib.admin.widgets import AdminDateWidget
from django.forms.extras.widgets import SelectDateWidget
from django.forms.widgets import SelectDateWidget
#from django.forms.extras.widgets import SelectDateWidget
from django.utils import timezone,translation
from django.forms import ModelForm, Select
import dataprep
import mytypes
import rowers.dataprep as dataprep
import rowers.mytypes as mytypes
import datetime
from django.forms import formset_factory
from utils import landingpages
from metrics import axes
from rowers.utils import landingpages
from rowers.metrics import axes
class FlexibleDecimalField(forms.DecimalField):
@@ -162,7 +169,7 @@ class DocumentsForm(forms.Form):
super(DocumentsForm, self).__init__(*args, **kwargs)
# self.fields['offline'].widget = HiddenInput()
from utils import (
from rowers.utils import (
workflowleftpanel,workflowmiddlepanel,
defaultleft,defaultmiddle
)
@@ -824,7 +831,7 @@ formaxlabelsmultiflex.pop('distance')
formaxlabelsmultiflex['workoutid'] = 'Workout'
parchoicesmultiflex = list(sorted(formaxlabelsmultiflex.items(), key = lambda x:x[1]))
from utils import palettes
from rowers.utils import palettes
palettechoices = tuple((p,p) for p in palettes.keys())
+10 -5
View File
@@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
# All the functionality to connect to SportTracks
# Python
@@ -16,7 +22,7 @@ from dateutil import parser
import time
from time import strftime
import dataprep
import rowers.dataprep as dataprep
import math
from math import sin,cos,atan2,sqrt
import os,sys
@@ -38,7 +44,7 @@ from django.contrib.auth.decorators import login_required
from rowingdata import rowingdata, make_cumvalues
import pandas as pd
from rowers.models import Rower,Workout,checkworkoutuser
from rowers import mytypes
import rowers.mytypes as mytypes
from rowsandall_app.settings import (
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI,
@@ -46,7 +52,7 @@ from rowsandall_app.settings import (
SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
)
from utils import (
from rowers.utils import (
NoTokenError, custom_exception_handler, ewmovingaverage,
geo_distance,isprorower,uniqify
)
@@ -103,7 +109,6 @@ def imports_open(user,oauth_data):
oauth_data,
)
elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename:
print 'noot'
token = imports_token_refresh(
user,
tokenname,
@@ -275,7 +280,7 @@ def imports_make_authorization_url(oauth_data):
import urllib
url = oauth_data['authorizaton_uri']+urllib.urlencode(params)
url = oauth_data['authorizaton_uri']+urllib.parse.urlencode(params)
return HttpResponseRedirect(url)
+289 -97
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import colorsys
from rowers.models import (
Workout, User, Rower, WorkoutForm,RowerForm,
@@ -15,19 +20,19 @@ from bokeh.palettes import Dark2_8 as palette
import itertools
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
from bokeh.charts import Histogram,HeatMap,Area,BoxPlot,Bar
from bokeh.charts.attributes import CatAttr
from bokeh.resources import CDN,INLINE
from bokeh.embed import components
from bokeh.layouts import layout,widgetbox
from bokeh.layouts import row as layoutrow
from bokeh.layouts import column as layoutcolumn
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
from bokeh.io import output_file, show, vplot
#from bokeh.io import output_file, show, vplot
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle,
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool,
SaveTool, # ResizeTool,
ResetTool, TapTool,CrosshairTool,BoxZoomTool,
Span, Label
)
from bokeh.models.glyphs import ImageURL
@@ -38,7 +43,7 @@ from bokeh.core.properties import value
from collections import OrderedDict
from django.conf import settings
from courses import (
from rowers.courses import (
course_coord_center,course_coord_maxmin,
polygon_coord_center
)
@@ -49,6 +54,8 @@ import datetime
import math
import numpy as np
import pandas as pd
import holoviews as hv
from holoviews import opts
from pytz import timezone as tz,utc
from django.utils.timezone import get_current_timezone
from django.utils.timezone import activate
@@ -62,7 +69,7 @@ from scipy.signal import savgol_filter
from scipy.interpolate import griddata
import stravastuff
import rowers.stravastuff as stravastuff
from rowers.dataprep import rdata
import rowers.dataprep as dataprep
@@ -70,21 +77,10 @@ import rowers.metrics as metrics
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima
from utils import lbstoN
from datautils import p0
import datautils
from rowers.utils import lbstoN
from rowers.datautils import p0
import rowers.datautils as datautils
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
def errorbar(fig, x, y, source=ColumnDataSource(),
xerr=False, yerr=False, color='black',
@@ -173,16 +169,31 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
if datadf.empty:
return '','It looks like there are no data matching your filter'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,resize,hover'
tooltips = [
('Value', '@'+fieldname),
]
plot = BoxPlot(datadf, values=fieldname, label='date',
legend=False,
title=axlabels[fieldname]+' '+extratitle,
outliers=False,
tools=TOOLS,
toolbar_location="above",
toolbar_sticky=False,
x_mapper_type='datetime',plot_width=920)
hover = HoverTool(tooltips=tooltips)
TOOLS = [hover]
hv.extension('bokeh')
boxwhiskers = hv.BoxWhisker(datadf,'date',fieldname)
boxwhiskers.opts(tools=TOOLS)
plot = hv.render(boxwhiskers)
#plot = BoxPlot(datadf, values=fieldname, label='date',
# legend=False,
# title=axlabels[fieldname]+' '+extratitle,
# outliers=False,
# tools=TOOLS,
# toolbar_location="above",
# toolbar_sticky=False,
# x_mapper_type='datetime',plot_width=920)
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
plot.y_range = yrange1
@@ -192,22 +203,6 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
plot.yaxis.axis_label = axlabels[fieldname]
# add watermark
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.image_url([watermarkurl],watermarkx,watermarky,
watermarkw,watermarkh,
global_alpha=watermarkalpha,
w_units='screen',
h_units='screen',
anchor=watermarkanchor,
dilate=True,
x_range_name = "watermark",
y_range_name = "watermark",
)
plot.xaxis.formatter = DatetimeTickFormatter(
days=["%d %B %Y"],
months=["%d %B %Y"],
@@ -223,20 +218,13 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
plot.xaxis.major_label_orientation = pi/4
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('Value','@y'),
('Date','@x'),
])
hover.mode = 'mouse'
plot.plot_width=920
plot.plot_height=600
script, div = components(plot)
return script,div
def interactive_activitychart(workouts,startdate,enddate,stack='type'):
dates = []
@@ -249,6 +237,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
seen = ['seen']
idseen = []
for w in workouts:
aantal=1
initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
@@ -296,7 +285,14 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
dates_sorting.append(d.strftime('%Y/%m/%d'))
durations.append(0)
types.append('rower')
rowers.append('Sander')
try:
rowers.append(rowers[0])
except IndexError:
try:
rowers.append(str(workouts[0].user))
except IndexError:
rowers.append(' ')
d += datetime.timedelta(days=1)
@@ -310,45 +306,71 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
df.sort_values('date_sorting',inplace=True)
hv.extension('bokeh')
p = Bar(df,values='duration',
label = CatAttr(columns=['date'], sort=False),
xlabel='Date',
ylabel='Time',
title='Activity {d1} to {d2}'.format(
if stack == 'type':
table = hv.Table(df,[('date','Date'),('type','Workout Type')],[('duration','Minutes')])
else:
table = hv.Table(df,[('date','Date'),('rower','Rower')],[('duration','Minutes')])
bars=table.to.bars(['date',stack],['duration'])
bars.opts(
opts.Bars(color=hv.Cycle('Category10'), show_legend=True, stacked=True,
tools=['hover'], width=600, xrotation=90,))
# legend_position='bottom',show_frame=True))
p = hv.render(bars)
p.title.text = 'Activity {d1} to {d2}'.format(
d1 = startdate.strftime("%Y-%m-%d"),
d2 = enddate.strftime("%Y-%m-%d"),
),
stack=stack,
plot_width=350,
plot_height=250,
toolbar_location = None,
)
p.plot_width=550
p.plot_height=350
p.toolbar_location = None
for legend in p.legend:
new_items = []
for legend_item in legend.items:
it = legend_item.label['value']
tot = df[df[stack]==it].duration.sum()
if tot != 0:
new_items.append(legend_item)
legend.items = new_items
# p = hv.Bars(df,values='duration',
# label = CatAttr(columns=['date'], sort=False),
# xlabel='Date',
# ylabel='Time',
# title='Activity {d1} to {d2}'.format(
# d1 = startdate.strftime("%Y-%m-%d"),
# d2 = enddate.strftime("%Y-%m-%d"),
# ),
# stack=stack,
# plot_width=350,
# plot_height=250,
# toolbar_location = None,
# )
p.legend.location = "top_left"
p.legend.background_fill_alpha = 0.7
# for legend in p.legend:
# new_items = []
# for legend_item in legend.items:
# it = legend_item.label['value']
# tot = df[df[stack]==it].duration.sum()
# if tot != 0:
# new_items.append(legend_item)
# legend.items = new_items
# p.legend.location = "top_left"
# p.legend.background_fill_alpha = 0.7
#p.sizing_mode = 'scale_width'
p.sizing_mode = 'stretch_both'
#p.sizing_mode = 'stretch_both'
p.yaxis.axis_label = 'Minutes'
#p.yaxis.axis_label = 'Minutes'
script,div = components(p)
return script,div
def interactive_forcecurve(theworkouts,workstrokesonly=False):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
ids = [int(w.id) for w in theworkouts]
@@ -438,6 +460,17 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -741,13 +774,24 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower'):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
plot = Figure(tools=TOOLS,toolbar_location="above",
toolbar_sticky=False,width=900,
x_axis_type='datetime')
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
@@ -805,7 +849,7 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower'):
return [script,div]
def interactive_histoall(theworkouts):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
ids = [int(w.id) for w in theworkouts]
@@ -834,6 +878,17 @@ def interactive_histoall(theworkouts):
)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
@@ -890,7 +945,12 @@ def interactive_histoall(theworkouts):
axis_label="Cumulative % of strokes"),'right')
plot.sizing_mode = 'scale_width'
try:
script, div = components(plot)
except ValueError:
script = ''
div = ''
return [script,div]
def course_map(course):
@@ -1484,7 +1544,7 @@ def interactive_agegroupcpchart(age,normalized=False):
x_axis_type = 'log'
y_axis_type = 'linear'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
plot = Figure(plot_width=900,x_axis_type=x_axis_type,
tools=TOOLS)
@@ -1531,7 +1591,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""):
powerdf = powerdf[~(powerdf == 0).any(axis=1)]
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -1578,6 +1638,17 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""):
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -1667,7 +1738,7 @@ def interactive_agegroup_plot(df,distance=2000,duration=None,
)
)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
plot = Figure(tools=TOOLS,plot_width=900)
plot.sizing_mode='scale_width'
@@ -1699,7 +1770,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
message = 0
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -1867,6 +1938,17 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -2033,7 +2115,7 @@ def interactive_windchart(id=0,promember=0):
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
@@ -2103,7 +2185,7 @@ def interactive_streamchart(id=0,promember=0):
# plot tools
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
@@ -2130,7 +2212,7 @@ def interactive_streamchart(id=0,promember=0):
def interactive_chart(id=0,promember=0,intervaldata = {}):
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -2174,6 +2256,17 @@ def interactive_chart(id=0,promember=0,intervaldata = {}):
tools=TOOLS)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
@@ -2338,7 +2431,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
)
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap'
if groupby != 'date':
hover = HoverTool(names=['data'],
@@ -2358,7 +2451,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
hover.mode = 'mouse'
TOOLS = [SaveTool(),PanTool(),BoxZoomTool(),WheelZoomTool(),
ResetTool(),TapTool(),ResizeTool(),hover]
ResetTool(),TapTool(),hover]
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
@@ -2367,6 +2460,17 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
toolbar_sticky=False,plot_width=920)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
@@ -2586,7 +2690,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
@@ -2596,6 +2700,17 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -2826,6 +2941,19 @@ def interactive_flex_chart2(id=0,promember=0,
plottype='line',
workstrokesonly=False):
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
#rowdata,row = dataprep.getrowdata_db(id=id)
columns = [xparam,yparam1,yparam2,
'ftime','distance','fpace',
@@ -3001,7 +3129,7 @@ def interactive_flex_chart2(id=0,promember=0,
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -3015,6 +3143,17 @@ def interactive_flex_chart2(id=0,promember=0,
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -3612,7 +3751,7 @@ def interactive_bar_chart(id=0,promember=0):
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -3626,6 +3765,17 @@ def interactive_bar_chart(id=0,promember=0):
tools=TOOLS)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -3771,7 +3921,7 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
@@ -3795,6 +3945,17 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -3816,7 +3977,12 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
cntr = 0
l1 = []
for id,color in itertools.izip(ids,colors):
try:
items = itertools.izip(ids,colors)
except AttributeError:
items = zip(ids,colors)
for id,color in items:
group = datadf[datadf['workoutid']==int(id)].copy()
@@ -3993,7 +4159,7 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
spm2 = rowdata2.loc[:,'spm']
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -4042,6 +4208,17 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -4158,7 +4335,7 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0):
# Add hover to this comma-separated string and see what changes
if (promember==1):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
else:
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
@@ -4173,6 +4350,17 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0):
toolbar_sticky=False)
# add watermark
watermarkurl = "/static/img/logo7.png"
watermarksource = ColumnDataSource(dict(
url = [watermarkurl],))
watermarkrange = Range1d(start=0,end=1)
watermarkalpha = 0.6
watermarkx = 0.99
watermarky = 0.01
watermarkw = 184
watermarkh = 35
watermarkanchor = 'bottom_right'
plot.extra_y_ranges = {"watermark": watermarkrange}
plot.extra_x_ranges = {"watermark": watermarkrange}
plot.sizing_mode = 'scale_width'
@@ -4226,7 +4414,11 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0):
hover.mode = 'mouse'
try:
script, div = components(plot)
except:
script = ''
div = ''
return [script,div]
+8 -3
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
import numpy as np
import time
@@ -72,7 +77,7 @@ def longtask2(aantal,jobid=None,debug=False,secret=''):
counter = 0
progress = int(100.*i/aantal)
if debug:
print progress
print(progress)
if jobid != None:
if debug:
url = SITE_URL_DEV
@@ -83,8 +88,8 @@ def longtask2(aantal,jobid=None,debug=False,secret=''):
post_data = {"secret":secret}
s = requests.post(url, data=post_data)
if debug:
print url
print s
print(url)
print(s)
return 1
+6 -1
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# Processes emails sent to workouts@rowsandall.com
""" Processes emails sent to workouts@rowsandall.com """
import shutil
@@ -92,7 +97,7 @@ def make_new_workout_from_email(rower, datafile, name, cntr=0,testing=False):
fileformat = fileformat[2]
if testing:
print 'Fileformat = ',fileformat
print('Fileformat = ',fileformat)
if fileformat == 'unknown':
# extension = datafilename[-4:].lower()
+19 -10
View File
@@ -1,13 +1,17 @@
#!/srv/venv/bin/python
""" Process emails """
import sys
import os
PY3K = sys.version_info >= (3, 0)
import zipfile
import re
import time
from time import strftime
import io
from django.core.management.base import BaseCommand
from django_mailbox.models import Message, MessageAttachment,Mailbox
from django.core.urlresolvers import reverse
@@ -57,20 +61,20 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
except AttributeError:
filename = fileobj[6:]
if testing:
print 'Attribute Error', filename
print('Attribute Error', filename)
# test if file exists and is not empty
try:
with open('media/'+filename,'r') as fop:
with io.open('media/'+filename,'rb') as fop:
line = fop.readline()
except (IOError, UnicodeEncodeError):
if testing:
print 'IOError',filename,'media/'+filename
print('IOError',filename,'media/'+filename)
return 0
if testing:
print 'Creating workout from email'
print('Creating workout from email')
# set user
if rower.user.is_staff and 'username' in uploadoptions:
@@ -102,7 +106,7 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
pass
if testing:
print 'Workout id = {workoutid}'.format(workoutid=workoutid)
print('Workout id = {workoutid}'.format(workoutid=workoutid))
if workoutid[0]:
link = settings.SITE_URL+reverse(
@@ -164,6 +168,11 @@ def get_from_address(message):
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)
@@ -242,17 +251,17 @@ class Command(BaseCommand):
testing=testing
)
except:
print "Bad ZIP file"
print attachment.document.name
print("Bad ZIP file")
print(attachment.document.name)
else:
# move attachment and make workout
if testing:
try:
print name
print(name)
except UnicodeEncodeError:
print "Unicode Error"
print("Unicode Error")
try:
print attachment.document
print(attachment.document)
except UnicodeEncodeError:
pass
+8 -2
View File
@@ -1,6 +1,12 @@
from utils import lbstoN
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import absolute_import
from rowers.utils import lbstoN
import numpy as np
from models import C2WorldClassAgePerformance
from rowers.models import C2WorldClassAgePerformance
import pandas as pd
from scipy import optimize
from django.utils import timezone
+1 -1
View File
@@ -2,7 +2,7 @@
from django.utils import timezone
from rowers.models import Workout, PowerTimeFitnessMetric, Rower
import datetime
from utils import myqueue
from rowers.utils import myqueue
import django_rq
queue = django_rq.get_queue('default')
from rowers.tasks import handle_updatefitnessmetric,handle_sendemail_expired
+91 -70
View File
@@ -1,4 +1,10 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
from django.utils.encoding import python_2_unicode_compatible
from django.db import models,IntegrityError
from django.contrib.auth.models import User
@@ -7,8 +13,8 @@ from django.core.exceptions import ValidationError
from django import forms
from django.forms import ModelForm
from django.dispatch import receiver
from django.forms.widgets import SplitDateTimeWidget
from django.forms.extras.widgets import SelectDateWidget
from django.forms.widgets import SplitDateTimeWidget,SelectDateWidget
#from django.forms.extras.widgets import SelectDateWidget
from django.forms.formsets import BaseFormSet
from django.contrib.admin.widgets import AdminDateWidget,AdminTimeWidget,AdminSplitDateTime
from datetimewidget.widgets import DateTimeWidget
@@ -35,7 +41,7 @@ from rowers.rows import validate_file_extension
from collections import OrderedDict
from timezonefinder import TimezoneFinder
import mytypes
import rowers.mytypes as mytypes
from matplotlib import path
from rowsandall_app.settings import (
@@ -108,7 +114,7 @@ class TemplateListField(models.TextField):
def get_db_prep_value(self, value, connection, prepared=False):
if not value: return
assert(isinstance(value, list) or isinstance(value, tuple))
return self.token.join([unicode(s) for s in value])
return self.token.join([str(s) for s in value])
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
@@ -151,7 +157,7 @@ class PowerZonesField(models.TextField):
def get_db_prep_value(self, value, connection, prepared=False):
if not value: return
assert(isinstance(value, list) or isinstance(value, tuple))
return self.token.join([unicode(s) for s in value])
return self.token.join([str(s) for s in value])
def value_to_string(self, obj):
value = self._get_val_from_obj(obj)
@@ -216,7 +222,7 @@ def update_records(url=c2url,verbose=True):
)
try:
if verbose:
print record
print(record)
record.save()
except:
if verbose:
@@ -261,7 +267,7 @@ class PowerTimeFitnessMetric(models.Model):
date = models.DateField(default=current_day)
last_workout = models.IntegerField(default=0)
user = models.ForeignKey(User)
user = models.ForeignKey(User,on_delete=models.CASCADE)
PowerFourMin = models.FloatField(default=0)
PowerTwoK = models.FloatField(default=0)
PowerOneHour = models.FloatField(default=0)
@@ -270,6 +276,7 @@ class PowerTimeFitnessMetric(models.Model):
class Meta:
db_table = 'powertimefitnessmetric'
@python_2_unicode_compatible
class C2WorldClassAgePerformance(models.Model):
weightcategories = (
('hwt','heavy-weight'),
@@ -300,7 +307,7 @@ class C2WorldClassAgePerformance(models.Model):
class Meta:
unique_together = ('age','sex','weightcategory','distance')
def __unicode__(self):
def __str__(self):
thestring = '{s} {w} {n} age {a} ({season}) {distance}m {duration} seconds'.format(
s = self.sex,
w = self.weightcategory,
@@ -321,6 +328,7 @@ def is_not_basic(user):
# For future Team functionality
@python_2_unicode_compatible
class Team(models.Model):
choices = (
('private','private'),
@@ -334,14 +342,14 @@ class Team(models.Model):
name = models.CharField(max_length=150,unique=True,verbose_name='Team Name')
notes = models.CharField(blank=True,max_length=200,verbose_name='Team Purpose')
manager = models.ForeignKey(User, null=True,) # validators=[is_not_basic])
manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) # validators=[is_not_basic])
private = models.CharField(max_length=30,choices=choices,default='open',
verbose_name='Team Type')
viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')
def __unicode__(self):
def __str__(self):
return self.name
def save(self, *args, **kwargs):
@@ -371,8 +379,8 @@ class TeamForm(ModelForm):
}
class TeamInvite(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User,null=True)
team = models.ForeignKey(Team,on_delete=models.CASCADE)
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
issuedate = models.DateField(default=current_day)
code = models.CharField(max_length=150,unique=True)
email = models.CharField(max_length=150,null=True,blank=True)
@@ -388,17 +396,17 @@ class TeamInviteForm(ModelForm):
class TeamRequest(models.Model):
team = models.ForeignKey(Team)
user = models.ForeignKey(User,null=True)
team = models.ForeignKey(Team,on_delete=models.CASCADE)
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
issuedate = models.DateField(default=current_day)
code = models.CharField(max_length=150,unique=True)
from utils import (
from rowers.utils import (
workflowleftpanel,workflowmiddlepanel,
defaultleft,defaultmiddle,landingpages
)
from utils import geo_distance
from rowers.utils import geo_distance
def polygon_coord_center(polygon):
@@ -606,6 +614,7 @@ paymentprocessors = (
('braintree','BrainTree')
)
@python_2_unicode_compatible
class PaidPlan(models.Model):
shortname = models.CharField(max_length=50,choices=plans)
name = models.CharField(max_length=200)
@@ -623,7 +632,7 @@ class PaidPlan(models.Model):
clubsize = models.IntegerField(default=0)
def __unicode__(self):
def __str__(self):
return '{name} - {shortname} at {price:.2f} EURO ({paymenttype} payment)'.format(
name = self.name,
shortname = self.shortname,
@@ -632,16 +641,18 @@ class PaidPlan(models.Model):
paymentprocessor = self.paymentprocessor,
)
@python_2_unicode_compatible
class CoachingGroup(models.Model):
name = models.CharField(default='group',max_length=30,null=True,blank=True)
def __unicode__(self):
def __str__(self):
return 'Coaching Group {id}: {name}'.format(
id = self.pk,
name = self.name
)
# Extension of User with rowing specific data
@python_2_unicode_compatible
class Rower(models.Model):
adaptivetypes = mytypes.adaptivetypes
stravatypes = (
@@ -675,7 +686,7 @@ class Rower(models.Model):
('Workout','Workout'),
('Yoga','Yoga'),
)
user = models.OneToOneField(User)
user = models.OneToOneField(User,on_delete=models.CASCADE)
#billing details
country = CountryField(default=None, null=True, blank=True)
@@ -699,7 +710,7 @@ class Rower(models.Model):
null=True,blank=True,
default='braintree')
paidplan = models.ForeignKey(PaidPlan,null=True,default=None)
paidplan = models.ForeignKey(PaidPlan,null=True,default=None,on_delete=models.SET_NULL)
planexpires = models.DateField(default=current_day)
teamplanexpires = models.DateField(default=current_day)
@@ -840,7 +851,7 @@ class Rower(models.Model):
# Friends/Team
friends = models.ManyToManyField("self",blank=True)
mycoachgroup = models.ForeignKey(CoachingGroup,related_name='coachingrole',null=True)
mycoachgroup = models.ForeignKey(CoachingGroup,related_name='coachingrole',null=True,on_delete=models.SET_NULL)
coachinggroups = models.ManyToManyField(CoachingGroup,related_name='coaches')
privacy = models.CharField(default='visible',max_length=30,
choices=privacychoices)
@@ -859,9 +870,6 @@ class Rower(models.Model):
def __str__(self):
return self.user.first_name+' '+self.user.last_name
def __unicode__(self):
return self.user.first_name+' '+self.user.last_name
def clean_email(self):
return self.user.email.lower()
@@ -881,15 +889,15 @@ class DeleteUserForm(forms.ModelForm):
# requestor is user
class CoachRequest(models.Model):
coach = models.ForeignKey(Rower)
user = models.ForeignKey(User,null=True)
coach = models.ForeignKey(Rower,on_delete=models.CASCADE)
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
issuedate = models.DateField(default=current_day)
code = models.CharField(max_length=150,unique=True)
# requestor is coach
class CoachOffer(models.Model):
coach = models.ForeignKey(Rower)
user = models.ForeignKey(User,null=True)
coach = models.ForeignKey(Rower,on_delete=models.CASCADE)
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
issuedate = models.DateField(default=current_day)
code = models.CharField(max_length=150,unique=True)
@@ -956,7 +964,7 @@ class FavoriteChart(models.Model):
reststrokes = models.BooleanField(default=True,verbose_name="Incl. Rest")
notes = models.CharField(max_length=300,verbose_name='Chart Notes',
default='Flex Chart Notes',blank=True)
user = models.ForeignKey(Rower)
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
class FavoriteForm(ModelForm):
@@ -1049,7 +1057,7 @@ def checkviewworkouts(user,rower):
if rower == r:
return True
teams = Team.objects.filter(manager=user)
print Rower.objects.filter(team__in=teams)
print(Rower.objects.filter(team__in=teams))
if rower in Rower.objects.filter(team__in=teams):
return True
except Rower.DoesNotExist:
@@ -1095,13 +1103,14 @@ timezones = (
# models related to geo data (points, polygon, courses)
@python_2_unicode_compatible
class GeoCourse(models.Model):
manager = models.ForeignKey(Rower)
manager = models.ForeignKey(Rower,null=True,on_delete=models.SET_NULL)
distance = models.IntegerField(default=0)
name = models.CharField(max_length=150,blank=True)
country = models.CharField(max_length=150,blank=True)
notes = models.CharField(blank=True,max_length=200,verbose_name='Course Notes')
def __unicode__(self):
def __str__(self):
name = self.name
country = self.country
d = self.distance
@@ -1125,12 +1134,13 @@ class GeoCourseEditForm(ModelForm):
'notes': forms.Textarea,
}
@python_2_unicode_compatible
class GeoPolygon(models.Model):
name = models.CharField(max_length=150,blank=True)
course = models.ForeignKey(GeoCourse, blank=True)
course = models.ForeignKey(GeoCourse, blank=True,on_delete=models.CASCADE)
order_in_course = models.IntegerField(default=0)
def __unicode__(self):
def __str__(self):
name = self.name
coursename = self.course.name
@@ -1146,7 +1156,7 @@ class GeoPolygon(models.Model):
class GeoPoint(models.Model):
latitude = models.FloatField(default=0)
longitude = models.FloatField(default=0)
polygon = models.ForeignKey(GeoPolygon,blank=True)
polygon = models.ForeignKey(GeoPolygon,blank=True,on_delete=models.CASCADE)
order_in_poly = models.IntegerField(default=0)
# need error checking to "insert" new point into existing polygon? This affects order_in_poly
@@ -1159,13 +1169,13 @@ class GeoPoint(models.Model):
class TrainingTarget(models.Model):
rowers = models.ManyToManyField(Rower, related_name='targetathletes',
verbose_name='Athletes')
manager = models.ForeignKey(Rower,related_name='targetmanager',null=True)
manager = models.ForeignKey(Rower,related_name='targetmanager',null=True,on_delete=models.CASCADE)
name = models.CharField(max_length=150,blank=True)
date = models.DateField(
default=half_year_from_now)
notes = models.TextField(max_length=300,blank=True)
def __unicode__(self):
def __str__(self):
date = self.date
name = self.name
id = self.pk
@@ -1217,7 +1227,7 @@ class TrainingTargetForm(ModelForm):
@python_2_unicode_compatible
class TrainingPlan(models.Model):
statuschoices = (
@@ -1227,15 +1237,15 @@ class TrainingPlan(models.Model):
rowers = models.ManyToManyField(Rower,related_name='planathletes',
verbose_name='Athletes')
manager = models.ForeignKey(Rower,related_name='planmanager',null=True)
manager = models.ForeignKey(Rower,related_name='planmanager',null=True,on_delete=models.SET_NULL)
name = models.CharField(max_length=150,blank=True)
status = models.BooleanField(default=True,verbose_name='Active')
target = models.ForeignKey(TrainingTarget,blank=True,null=True)
target = models.ForeignKey(TrainingTarget,blank=True,null=True,on_delete=models.SET_NULL)
startdate = models.DateField(default=current_day)
enddate = models.DateField(
default=half_year_from_now)
def __unicode__(self):
def __str__(self):
name = self.name
startdate = self.startdate
enddate = self.enddate
@@ -1599,8 +1609,9 @@ def macrocyclecheckdates(plan):
pass
cycles = cycles[1:]
@python_2_unicode_compatible
class TrainingMacroCycle(models.Model):
plan = models.ForeignKey(TrainingPlan)
plan = models.ForeignKey(TrainingPlan,on_delete=models.CASCADE)
name = models.CharField(max_length=150,blank=True)
startdate = models.DateField(default=current_day)
enddate = models.DateField(
@@ -1621,7 +1632,7 @@ class TrainingMacroCycle(models.Model):
actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore')
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
def __unicode__(self):
def __str__(self):
stri = 'Macro Cycle - {n} ({sd} - {ed})'.format(
n = self.name,
sd = self.startdate,
@@ -1687,8 +1698,9 @@ class TrainingMacroCycleForm(ModelForm):
'enddate': AdminDateWidget()
}
@python_2_unicode_compatible
class TrainingMesoCycle(models.Model):
plan = models.ForeignKey(TrainingMacroCycle)
plan = models.ForeignKey(TrainingMacroCycle,on_delete=models.CASCADE)
name = models.CharField(max_length=150,blank=True)
startdate = models.DateField(default=current_day)
enddate = models.DateField(
@@ -1709,7 +1721,7 @@ class TrainingMesoCycle(models.Model):
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
def __unicode__(self):
def __str__(self):
stri = 'Meso Cycle - {n} ({sd} - {ed})'.format(
n = self.name,
sd = self.startdate,
@@ -1763,8 +1775,9 @@ class TrainingMesoCycle(models.Model):
createmicrofillers(self)
@python_2_unicode_compatible
class TrainingMicroCycle(models.Model):
plan = models.ForeignKey(TrainingMesoCycle)
plan = models.ForeignKey(TrainingMesoCycle,on_delete=models.CASCADE)
name = models.CharField(max_length=150,blank=True)
startdate = models.DateField(default=current_day)
enddate = models.DateField(
@@ -1787,7 +1800,7 @@ class TrainingMicroCycle(models.Model):
def __unicode__(self):
def __str__(self):
stri = 'Micro Cycle - {n} ({sd} - {ed})'.format(
n = self.name,
sd = self.startdate,
@@ -1858,6 +1871,7 @@ regularsessiontypechoices = (
)
# model for Planned Session (Workout, Challenge, Test)
@python_2_unicode_compatible
class PlannedSession(models.Model):
sessiontypechoices = (
@@ -1903,9 +1917,9 @@ class PlannedSession(models.Model):
('None',None),
)
manager = models.ForeignKey(User)
manager = models.ForeignKey(User,on_delete=models.PROTECT)
course = models.ForeignKey(GeoCourse,blank=True,null=True,
verbose_name='OTW Course')
verbose_name='OTW Course',on_delete=models.SET_NULL)
name = models.CharField(max_length=150,blank=True,
verbose_name='Name')
@@ -1960,7 +1974,7 @@ class PlannedSession(models.Model):
hasranking = models.BooleanField(default=False)
def __unicode__(self):
def __str__(self):
name = self.name
startdate = self.startdate
@@ -2036,6 +2050,7 @@ registerchoices = (
('manual','Manual - select below'),
)
@python_2_unicode_compatible
class VirtualRace(PlannedSession):
# has_registration = models.BooleanField(default=False)
registration_form = models.CharField(
@@ -2065,7 +2080,7 @@ class VirtualRace(PlannedSession):
contact_email = models.EmailField(max_length=254,
validators=[validate_email],blank=True)
def __unicode__(self):
def __str__(self):
name = self.name
startdate = self.startdate
@@ -2111,7 +2126,7 @@ class VirtualRace(PlannedSession):
class RaceLogo(models.Model):
filename = models.CharField(default='',max_length=150)
creationdatetime = models.DateTimeField()
user = models.ForeignKey(User)
user = models.ForeignKey(User,on_delete=models.PROTECT)
width = models.IntegerField(default=1200)
height = models.IntegerField(default=600)
race = models.ManyToManyField(VirtualRace,related_name='logos')
@@ -2121,7 +2136,7 @@ class RaceLogo(models.Model):
def delete(self, *args, **kwargs):
os.remove(self.filename)
print 'file deleted'
print('file deleted')
super(RaceLogo,self).delete(*args, **kwargs)
# Date input utility
@@ -2486,16 +2501,17 @@ class PlannedSessionFormSmall(ModelForm):
boattypes = mytypes.boattypes
# Workout
@python_2_unicode_compatible
class Workout(models.Model):
workouttypes = mytypes.workouttypes
workoutsources = mytypes.workoutsources
privacychoices = mytypes.privacychoices
adaptivetypes = mytypes.adaptivetypes
user = models.ForeignKey(Rower)
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
team = models.ManyToManyField(Team,blank=True)
plannedsession = models.ForeignKey(PlannedSession, blank=True,null=True,
verbose_name='Session')
verbose_name='Session',on_delete=models.SET_NULL)
name = models.CharField(max_length=150,blank=True,null=True)
date = models.DateField()
workouttype = models.CharField(choices=workouttypes,max_length=50,
@@ -2555,7 +2571,7 @@ class Workout(models.Model):
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout')
def __unicode__(self):
def __str__(self):
date = self.date
name = self.name
@@ -2649,11 +2665,12 @@ def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
try:
result = conn.execute(query)
except:
print "Database Locked"
print("Database Locked")
conn.close()
engine.dispose()
# Virtual Race results (for keeping results when workouts are deleted)
@python_2_unicode_compatible
class VirtualRaceResult(models.Model):
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otwtypes)
userid = models.IntegerField(default=0)
@@ -2667,7 +2684,7 @@ class VirtualRaceResult(models.Model):
adaptiveclass = models.CharField(default="None",max_length=50,
choices=mytypes.adaptivetypes,
verbose_name="Adaptive Class")
race = models.ForeignKey(VirtualRace)
race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE)
duration = models.TimeField(default=datetime.time(1,0))
distance = models.IntegerField(default=0)
boatclass = models.CharField(choices=boatclasses,
@@ -2688,7 +2705,7 @@ class VirtualRaceResult(models.Model):
emailnotifications = models.BooleanField(default=True,
verbose_name = 'Receive race notifications by email')
def __unicode__(self):
def __str__(self):
rr = Rower.objects.get(id=self.userid)
name = '{u1} {u2}'.format(
u1 = rr.user.first_name,
@@ -2713,6 +2730,7 @@ class VirtualRaceResult(models.Model):
)
# Virtual Race results (for keeping results when workouts are deleted)
@python_2_unicode_compatible
class IndoorVirtualRaceResult(models.Model):
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otetypes)
userid = models.IntegerField(default=0) # ID of rower object
@@ -2726,7 +2744,7 @@ class IndoorVirtualRaceResult(models.Model):
adaptiveclass = models.CharField(default="None",max_length=50,
choices=mytypes.adaptivetypes,
verbose_name="Adaptive Class")
race = models.ForeignKey(VirtualRace)
race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE)
duration = models.TimeField(default=datetime.time(1,0))
distance = models.IntegerField(default=0)
boatclass = models.CharField(choices=boatclasses,
@@ -2743,7 +2761,7 @@ class IndoorVirtualRaceResult(models.Model):
emailnotifications = models.BooleanField(default=True,
verbose_name = 'Receive race notifications by email')
def __unicode__(self):
def __str__(self):
rr = Rower.objects.get(id=self.userid)
name = '{u1} {u2}'.format(
u1 = rr.user.first_name,
@@ -2769,7 +2787,7 @@ class IndoorVirtualRaceResult(models.Model):
class CourseTestResult(models.Model):
userid = models.IntegerField(default=0)
workoutid = models.IntegerField(null=True)
plannedsession = models.ForeignKey(PlannedSession)
plannedsession = models.ForeignKey(PlannedSession,on_delete=models.CASCADE)
duration = models.TimeField(default=datetime.time(1,0))
distance = models.IntegerField(default=0)
coursecompleted = models.BooleanField(default=False)
@@ -2900,10 +2918,11 @@ class ergcpdata(models.Model):
app_label = 'rowers'
# A wrapper around the png files
@python_2_unicode_compatible
class GraphImage(models.Model):
filename = models.CharField(default='',max_length=150,blank=True,null=True)
creationdatetime = models.DateTimeField()
workout = models.ForeignKey(Workout)
workout = models.ForeignKey(Workout,on_delete=models.CASCADE)
width = models.IntegerField(default=1200)
height = models.IntegerField(default=600)
@@ -2920,7 +2939,7 @@ def auto_delete_image_on_delete(sender,instance, **kwargs):
if len(others) == 0:
os.remove(instance.filename)
else:
print "couldn't find the file "+instance.filename
print("couldn't find the file "+instance.filename)
# Form to update Workout data
@@ -3445,15 +3464,16 @@ class SiteAnnouncement(models.Model):
return super(SiteAnnouncement,self).save(*args, **kwargs)
# A comment by a user on a training
@python_2_unicode_compatible
class WorkoutComment(models.Model):
comment = models.TextField(max_length=300)
created = models.DateTimeField(default=timezone.now)
read = models.BooleanField(default=False)
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
user = models.ForeignKey(User)
workout = models.ForeignKey(Workout)
user = models.ForeignKey(User,on_delete=models.PROTECT)
workout = models.ForeignKey(Workout,on_delete=models.CASCADE)
def __unicode__(self):
def __str__(self):
return u'Comment to: {w} by {u1} {u2}'.format(
w=self.workout,
u1 = self.user.first_name,
@@ -3470,15 +3490,16 @@ class WorkoutCommentForm(ModelForm):
}
# A comment by a user on a training
@python_2_unicode_compatible
class PlannedSessionComment(models.Model):
comment = models.TextField(max_length=300)
created = models.DateTimeField(default=timezone.now)
read = models.BooleanField(default=False)
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
user = models.ForeignKey(User)
plannedsession = models.ForeignKey(PlannedSession)
user = models.ForeignKey(User,on_delete=models.PROTECT)
plannedsession = models.ForeignKey(PlannedSession,on_delete=models.CASCADE)
def __unicode__(self):
def __str__(self):
return u'Comment to: {w} by {u1} {u2}'.format(
w=self.workout,
u1 = self.user.first_name,
+11 -5
View File
@@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from six import iteritems
workouttypes = (
('water','Standard Racing Shell'),
('rower','Indoor Rower'),
@@ -208,15 +214,15 @@ c2mapping = {
}
c2mappinginv = {value:key for key,value in c2mapping.iteritems() if value is not None}
c2mappinginv = {value:key for key,value in iteritems(c2mapping) if value is not None}
stravamappinginv = {value:key for key,value in stravamapping.iteritems() if value is not None}
stravamappinginv = {value:key for key,value in iteritems(stravamapping) if value is not None}
stmappinginv = {value:key for key,value in stmapping.iteritems() if value is not None}
stmappinginv = {value:key for key,value in iteritems(stmapping) if value is not None}
rkmappinginv = {value:key for key,value in rkmapping.iteritems() if value is not None}
rkmappinginv = {value:key for key,value in iteritems(rkmapping) if value is not None}
polarmappinginv = {value:key for key,value in polarmapping.iteritems() if value is not None}
polarmappinginv = {value:key for key,value in iteritems(polarmapping) if value is not None}
otwtypes = (
'water',
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import struct
import base64
+7 -2
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
# Interactions with Rowsandall.com API. Not fully complete.
# Python
@@ -15,7 +20,7 @@ import math
from math import sin,cos,atan2,sqrt
import urllib
import c2stuff
import rowers.c2stuff as c2stuff
# Django
from django.shortcuts import render_to_response
@@ -123,7 +128,7 @@ def make_authorization_url(request):
import urllib
url = "http://localhost:8000/rowers/o/authorize" +urllib.urlencode(params)
url = "http://localhost:8000/rowers/o/authorize" +urllib.parse.urlencode(params)
return HttpResponseRedirect(url)
+4
View File
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from rowers.models import Rower,PaidPlan
# run once - copies plans to paypal
+4
View File
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# Defines permissions for objects (API related)
from rest_framework import permissions
+10 -5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# Python
from django.utils import timezone
from datetime import datetime
@@ -10,7 +15,7 @@ import uuid
from django.conf import settings
import pytz
from dateutil import parser
from utils import myqueue,calculate_age,totaltime_sec_to_string
from rowers.utils import myqueue,calculate_age,totaltime_sec_to_string
import re
import django_rq
queue = django_rq.get_queue('default')
@@ -30,10 +35,10 @@ from rowers.emails import htmlstrip,htmlstripnobr
import rowers.mytypes as mytypes
import metrics
import rowers.metrics as metrics
import numpy as np
import dataprep
import courses
import rowers.dataprep as dataprep
import rowers.courses as courses
import iso8601
from iso8601 import ParseError
from rowers.tasks import handle_check_race_course
@@ -360,7 +365,7 @@ def is_session_complete_ws(ws,ps):
return ratio,'partial',completiondate
else:
thevalue = 0
for key,value in cratios.iteritems():
for key,value in cratios.items():
if ratio>value and value>thevalue:
verdict = key
thevalue = value
+6 -1
View File
@@ -1,8 +1,13 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter
import matplotlib.pyplot as plt
import numpy as np
from rows import format_pace_tick, format_pace, format_time, format_time_tick
from rowers.rows import format_pace_tick, format_pace, format_time, format_time_tick
# Formatting the distance tick marks
+19 -9
View File
@@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
# All the functionality needed to connect to Strava
# Python
@@ -33,8 +39,8 @@ from rowingdata import rowingdata
import pandas as pd
from rowers.models import Rower,Workout
from rowers.models import checkworkoutuser
import dataprep
from dataprep import columndict
import rowers.dataprep as dataprep
from rowers.dataprep import columndict
from io import StringIO
@@ -51,8 +57,8 @@ from rowsandall_app.settings import (
baseurl = 'https://polaraccesslink.com/v3'
from utils import NoTokenError, custom_exception_handler
import mytypes
from rowers.utils import NoTokenError, custom_exception_handler
import rowers.mytypes as mytypes
# Exchange access code for long-lived access token
def get_token(code):
@@ -67,7 +73,10 @@ def get_token(code):
secret=POLAR_CLIENT_SECRET
)
try:
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
except TypeError:
headers = { 'Authorization': 'Basic %s' % base64.b64encode(bytes(auth_string,'utf-8')) }
response = requests.post("https://polarremote.com/v2/oauth2/token",
data=post_data,
@@ -97,7 +106,7 @@ def make_authorization_url():
"redirect_uri": POLAR_REDIRECT_URI,
"scope":"write"}
import urllib
url = "https://flow.polar.com/oauth2/authorization" +urllib.urlencode(params)
url = "https://flow.polar.com/oauth2/authorization" +urllib.parse.urlencode(params)
return HttpResponseRedirect(url)
@@ -110,7 +119,10 @@ def get_polar_notifications():
secret=POLAR_CLIENT_SECRET
)
try:
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
except TypeError:
headers = { 'Authorization': 'Basic %s' % base64.b64encode(bytes(auth_string,'utf-8')) }
response = requests.get(url, headers=headers)
@@ -126,7 +138,7 @@ from rowers.utils import isprorower
def get_all_new_workouts(available_data,testing=False):
for record in available_data:
if testing:
print record
print(record)
if record['data-type'] == 'EXERCISE':
try:
r = Rower.objects.get(polaruserid=record['user-id'])
@@ -134,7 +146,7 @@ def get_all_new_workouts(available_data,testing=False):
if r.polar_auto_import and isprorower(r):
exercise_list = get_polar_workouts(u)
if testing:
print exercise_list
print(exercise_list)
except Rower.DoesNotExist:
pass
@@ -313,8 +325,6 @@ def get_polar_workout(user,id,transactionid):
response = requests.get(url,headers = headers2)
if response.status_code == 200:
print response.text
result = response.text
# commit transaction
response = requests.put(url,headers=headers)
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import time
import gzip
import shutil
+12 -1
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
# All the functionality needed to connect to Runkeeper
from rowers.imports import *
import re
@@ -24,6 +29,8 @@ oauth_data = {
}
import numpy
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
t = []
lat = []
@@ -257,6 +264,10 @@ def get_userid(access_token):
return str(res)
def default(o):
if isinstance(o, numpy.int64): return int(o)
raise TypeError
def workout_runkeeper_upload(user,w):
message = "Uploading to Runkeeper"
rkid = 0
@@ -282,7 +293,7 @@ def workout_runkeeper_upload(user,w):
'Content-Length':'nnn'}
url = "https://api.runkeeper.com/fitnessActivities"
response = requests.post(url,headers=headers,data=json.dumps(data))
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
# check for duplicate error first
if (response.status_code == 409 ):
+5 -1
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# Serializers. Defines which fields from an object get to the JSON object
# Also optionally define POST, PATCH methods (create, update)
@@ -140,7 +145,6 @@ class StrokeDataSerializer(serializers.Serializer):
"""
# do something
print "fake serializer"
return 1
+15 -2
View File
@@ -1,5 +1,13 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
# All the functionality to connect to SportTracks
import numpy
from rowers.imports import *
import re
from rowsandall_app.settings import (
@@ -9,7 +17,7 @@ from rowsandall_app.settings import (
SPORTTRACKS_REDIRECT_URI
)
import mytypes
import rowers.mytypes as mytypes
oauth_data = {
'client_id': SPORTTRACKS_CLIENT_ID,
@@ -234,6 +242,11 @@ def getidfromresponse(response):
return int(id)
def default(o):
if isinstance(o, numpy.int64): return int(o)
raise TypeError
def workout_sporttracks_upload(user,w):
message = "Uploading to SportTracks"
@@ -256,7 +269,7 @@ def workout_sporttracks_upload(user,w):
'Content-Type': 'application/json'}
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
response = requests.post(url,headers=headers,data=json.dumps(data))
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
# check for duplicate error first
if (response.status_code == 409 ):
+10 -4
View File
@@ -1,3 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from __future__ import unicode_literals, absolute_import
# All the functionality needed to connect to Strava
from scipy import optimize
from scipy.signal import savgol_filter
@@ -10,15 +16,15 @@ queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
from dataprep import columndict
from rowers.dataprep import columndict
import stravalib
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
from iso8601 import ParseError
from utils import myqueue
from rowers.utils import myqueue
import mytypes
import rowers.mytypes as mytypes
import gzip
from rowsandall_app.settings import (
@@ -259,7 +265,7 @@ def create_async_workout(alldata,user,stravaid,debug=False):
return 1
from utils import get_strava_stream
from rowers.utils import get_strava_stream
+25 -14
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
""" Background tasks done by Celery (develop) or QR (production) """
import os
import time
@@ -16,7 +21,10 @@ from rowingdata import rowingdata as rdata
from datetime import timedelta
from sqlalchemy import create_engine
from celery import app
#from celery import app
from rowers.celery import app
from celery import shared_task
import datetime
import pytz
import iso8601
@@ -39,10 +47,11 @@ from django_rq import job
from django.utils import timezone
from django.utils.html import strip_tags
from utils import deserialize_list,ewmovingaverage,wavg
from emails import htmlstrip
from rowers.utils import deserialize_list,ewmovingaverage,wavg
from rowers.emails import htmlstrip
from HTMLParser import HTMLParser
#from HTMLParser import HTMLParser
from html.parser import HTMLParser
class MLStripper(HTMLParser):
def __init__(self):
self.reset()
@@ -80,13 +89,13 @@ from django.db.utils import OperationalError
from jinja2 import Template,Environment,FileSystemLoader
env = Environment(loader = FileSystemLoader(["rowers/templates"]))
import datautils
import utils
import rowers.datautils as datautils
import rowers.utils as utils
import requests
import longtask
import rowers.longtask as longtask
import arrow
from utils import get_strava_stream
from rowers.utils import get_strava_stream
siteurl = SITE_URL
@@ -128,7 +137,7 @@ def handle_c2_import_stroke_data(c2token,
return 1
else:
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)
url = "https://log.concept2.com/api/users/me/results/{id}".format(id=c2id)
s = requests.get(url,headers=headers)
@@ -1238,21 +1247,21 @@ def handle_zip_file(emailfrom, subject, file,**kwargs):
debug = False
if debug:
print message
print(message)
email = EmailMessage(subject, message,
emailfrom,
['workouts@rowsandall.com'])
email.attach_file(file)
if debug:
print "attaching"
print("attaching")
res = email.send()
if debug:
print "sent"
print("sent")
time.sleep(60)
return 1
@@ -1490,7 +1499,6 @@ def handle_updateergcp(rower_id,workoutfilenames,debug=False,**kwargs):
rowdata = rdata(f1 + '.gz')
except IOError:
rowdata = 0
if rowdata != 0:
therows.append(rowdata)
@@ -1637,7 +1645,7 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
hran = hrdata['hran']
ftp = hrdata['ftp']
powerzones = deserialize_list(hrdata['powerzones'])
powerperc = np.array(deserialize_list(hrdata['powerperc'])).astype(int)
powerperc = np.array(deserialize_list(hrdata['powerperc'])).astype(float)
rr = rowingdata.rower(hrmax=hrmax, hrut2=hrut2,
hrut1=hrut1, hrat=hrat,
@@ -1649,7 +1657,10 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
except IOError:
row = rdata(f2 + '.gz', rower=rr)
try:
haspower = row.df[' Power (watts)'].mean() > 50
except TypeError:
haspower = True
nr_rows = len(row.df)
if (plotnr in [1, 2, 4, 5, 8, 11, 9, 12]) and (nr_rows > 1200):
+5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import os
import sys
import django
+5 -1
View File
@@ -1,3 +1,7 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
# All the Team related methods
@@ -10,7 +14,7 @@ from django.db import IntegrityError
import uuid
from django.conf import settings
from utils import myqueue
from rowers.utils import myqueue
import django_rq
queue = django_rq.get_queue('default')
-106
View File
@@ -1,106 +0,0 @@
# This is just a scratch pad to temporarily park code, just in case I need
# it later. Hardly used since i have proper versioning
#
def createc2workoutdata_grouped(w):
filename = w.csvfilename
row = rowingdata(filename)
# resize per minute
df = row.df.groupby(lambda x:x/10).mean()
averagehr = int(df[' HRCur (bpm)'].mean())
maxhr = int(df[' HRCur (bpm)'].max())
# adding diff, trying to see if this is valid
t = 10*df.ix[:,' ElapsedTime (sec)'].values
t[0] = t[1]
d = df.ix[:,' Horizontal (meters)'].values
d[0] = d[1]
p = 10*df.ix[:,' Stroke500mPace (sec/500m)'].values
t = t.astype(int)
d = d.astype(int)
p = p.astype(int)
spm = df[' Cadence (stokes/min)'].astype(int)
spm[0] = spm[1]
hr = df[' HRCur (bpm)'].astype(int)
stroke_data = []
for i in range(len(t)):
thisrecord = {"t":t[i],"d":d[i],"p":p[i],"spm":spm[i],"hr":hr[i]}
stroke_data.append(thisrecord)
try:
durationstr = datetime.strptime(str(w.duration),"%H:%M:%S.%f")
except ValueError:
durationstr = datetime.strptime(str(w.duration),"%H:%M:%S")
data = {
"type": w.workouttype,
"date": w.startdatetime.isoformat(),
"distance": int(w.distance),
"time": int(10*makeseconds(durationstr)),
"weight_class": c2wc(w.weightcategory),
"timezone": "Etc/UTC",
"comments": w.notes,
"heart_rate": {
"average": averagehr,
"max": maxhr,
},
"stroke_data": stroke_data,
}
return data
@login_required()
def workout_edit_view(request,id=0):
if request.method == 'POST':
# Form was submitted
form = WorkoutForm(request.POST)
if form.is_valid():
# Get values from form
name = request.POST['name']
date = request.POST['date']
workouttype = request.POST['workouttype']
notes = request.POST['notes']
try:
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# check if user is owner of this workout
if checkworkoutuser(request.user,row):
row.name = name
row.date = date
row.workouttype = workouttype
row.notes = notes
row.save()
response = HttpResponse("data updated")
else:
response = HttpResponse("You are not allowed to change this workout")
except Workout.DoesNotExist:
# create new workout
r = Rower.objects.get(user=request.user)
w = Workout(name=name,date=date,workouttype=workouttype,
user=r)
w.save()
response = HttpResponse("New workout created")
else:
response = HttpResponse("invalid form")
return response
else:
try:
row = Workout.objects.get(id=id)
form = WorkoutForm(instance=row)
# check if user is owner of this workout
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to edit this workout")
except Workout.DoesNotExist:
form = WorkoutForm(
initial = {'workouttype' : 'rower'}
)
return render(request, 'workout_form.html',
{'form':form,})
-227
View File
@@ -1,227 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}{{ workout.name }} Advanced {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
<div class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>{{ workout.name }} - Advanced</h1>
{% if user.rower.rowerplan == 'basic' %}
<p>Functionality marked with an asterisk (*) is limited to the paid plans. See
<a href="/rowers/paidplans">the page about Pro membership</a>
for more information and to sign up for Pro Membership</a></p>
{% endif %}
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/workflow">Workflow View</a>
</p>
</div>
<div class="grid_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/export">Export</a>
</p>
</div>
</div>
<div class="grid_6 alpha">
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id|encode }}">https://rowsandall.com/rowers/workout/{{ workout.id|encode }}</a>
<td>
</table>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id|encode }}">Compare Workouts</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans/">Compare Workouts*</a>
{% endif %}
<p>
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
</p>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/flexchart">
Flexible Interactive Plot
</a>
<p>
Flexible Interactive plot. Pick your own X and Y axis parameters.
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/editintervals">Edit Intervals</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Edit Intervals*</a>
{% endif %}
</p>
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
<p>
Enter or change the interval and summary data for your workout
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/adddistanceplot2">Dist Metrics Plot</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Dist Metrics Plot*</a>
{% endif %}
</p>
<p>
Various advanced stroke metrics plotted versus distance.
</p>
</div>
<div class="grid_2">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/addtimeplot2">Time Metrics Plot</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Time Metrics Plot*</a>
{% endif %}
</p>
<p>
Various advanced stroke metrics plotted versus time.
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/histo">Power Histogram</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Power Histogram*</a>
{% endif %}
</p>
<p>
Plot the Power Histogram of this workout
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workouts-join-select">Glue</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Glue*</a>
{% endif %}
</p>
<p>
Glue multiple workouts together (into one workout). For example, to combine separately recorded intervals.
</p>
</div>
<div class="grid_2">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id|encode }}/">Sensor Fusion</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Sensor Fusion*</a>
{% endif %}
</p>
<p>
Merge data from another source into this workout
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/split">Split Workout</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Split Workout*</a>
{% endif %}
</p>
<p>
Split workout into two seperate workouts
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/interactiveplot">Big Interactive Plot</a>
</p>
<p>
See (and save) the big interactive plot
</p>
</div>
<div class="grid_2">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/instroke">In-Stroke Metrics</a></p>
<p>
If your workout has in-stroke metrics (like a stroke power curve or boat acceleration curve), you will find it here.
</p>
</div>
</div>
</div>
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
</div>
</div>
{% endblock %}
-284
View File
@@ -1,284 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}{{ workout.name }} Advanced {% endblock %}
{% block content %}
<div id="workouts" class="grid_6 alpha">
{% if form.errors %}
<p style="color: red;">
Please correct the error{{ form.errors|pluralize }} below.
</p>
{% endif %}
<h1>{{ workout.name }} - Advanced OTW</h1>
{% if user.rower.rowerplan == 'basic' %}
<p>Functionality marked with an asterisk (*) is limited to the paid plans. See
<a href="/rowers/paidplans">the page about Pro membership</a>
for more information and to sign up for Pro Membership</a></p>
{% endif %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/workflow">Workflow View</a>
</p>
</div>
<div class="grid_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/export">Export</a>
</p>
</div>
<div class="grid_6 alpha">
<table width=100%>
<tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
<th>Public link to this workout</th>
<td>
<a href="/rowers/workout/{{ workout.id|encode }}">https://rowsandall.com/rowers/workout/{{ workout.id|encode }}</a>
<td>
</table>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/compare/{{ workout.id|encode }}">Compare Workouts</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Compare Workouts*</a>
{% endif %}
</p>
<p>
Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts.
</p>
</div>
<div class="grid_2">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/flexchart">Flexible Interactive Plot</a>
</p>
<p>
Flexible Interactive plot. Pick your own X and Y axis parameters.
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/editintervals">Edit Intervals</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Edit Intervals*</a>
{% endif %}
</p>
<span class="tooltiptext">Enter or change the interval and summary data for your workout</span>
<p>
Enter or change the interval and summary data for your workout
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user|is_promember %}
<a class="button blue small"href="/rowers/workout/{{ workout.id|encode }}/crewnerdsummary">CrewNerd Summary</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">CrewNerd Summary*</a>
{% endif %}
</p>
<p>
Upload a CrewNerd Summary (CSV file) to this workout.
</p>
</div>
<div class="grid_2 tooltip">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/forcecurve">Stroke Profile (Empower)</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Stroke Profile (Empower)*</a>
{% endif %}
</p>
<span class="tooltiptext">Analyze your stroke force profile (need Empower Oarlock data)</span> <p>
Interactive plot of Stroke Profile (with Empower Oarlock)
</p>
</div>
<div class="grid_2 omega tooltip">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/addotwpowerplot">OTW Power Plot</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">OTW Power Plot*</a>
{% endif %}
</p>
<span class="tooltiptext">Note: You must run the OTW calculations under Geeky Stuff first. Otherwise the plot will be empty</span>
<p>
Pace, wind corrected pace, power, equivalent erg power in a static plot
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/geeky">Geeky Stuff</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Geeky Stuff*</a>
{% endif %}
</p>
<p>
Add weather and current data and OTW power calculations.
</p>
</div>
<div class="grid_2 tooltip">
<p>
{% if user|is_promember %}
<a class="button blue small"href="/rowers/workout/{{ workout.id|encode }}/smoothenpace">Smooth out Pace Data</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Smooth out Pace Data*</a>
{% endif %}
</p>
<span class="tooltiptext">This will reduce noise on your pace data. The smoothing is irreversible but you can use the reset smoothing button.</span>
<p>
Pace data too noisy? Press this button!
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user|is_promember %}
<a class="button blue small"href="/rowers/workout/{{ workout.id|encode }}/undosmoothenpace">Raw Data</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Reset Smoothing*</a>
{% endif %}
</p>
<p>
Reset pace data to values before smoothing
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workouts-join-select">Glue</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Glue*</a>
{% endif %}
</p>
<p>
Glue multiple workouts together (into one workout). For example, to combine separately recorded intervals.
</p>
</div>
<div class="grid_2">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id|encode }}/">Sensor Fusion</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Sensor Fusion*</a>
{% endif %}
</p>
<p>
Merge data from another source into this workout
</p>
</div>
<div class="grid_2 omega">
<p>
{% if user|is_promember %}
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/split">Split Workout</a>
{% else %}
<a class="button blue small" href="/rowers/paidplans">Split Workout*</a>
{% endif %}
</p>
<p>
Split workout into two seperate workouts
</p>
</div>
</div>
<div class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/interactiveplot">Big Interactive Plot</a>
</p>
<p>
See (and save) the big interactive plot
</p>
</div>
<div class="grid_2">
<p>
<a class="button blue small" href="/rowers/workout/{{ workout.id|encode }}/instroke">In-Stroke Metrics</a></p>
<p>
If your workout has in-stroke metrics (like a stroke power curve or boat acceleration curve), you will find it here.
</p>
</div>
</div>
</div>
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, true);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="interactiveplot" class="grid_6 omega">
{{ the_div |safe }}
</div>
</div>
</div>
{% endblock %}
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
-232
View File
@@ -1,232 +0,0 @@
{% load cookielaw_tags %}
{% load leaflet_tags %}
{% load tz_detect %}
{% tz_detect %}
{% load analytical %}
{% block filters %}
{% endblock %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
{% block headtext %}{% endblock %}
<script src="/static/cookielaw/js/cookielaw.js"></script>
{% analytical_head_top %}
{% if GOOGLE_ANALYTICS_PROPERTY_ID %}
{% include "ga.html" %}
{% endif %}
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="https://webapiv2.navionics.com/dist/webapi/webapi.min.css" >
<script type="text/javascript" src="https://webapiv2.navionics.com/dist/webapi/webapi.min.no-dep.js"></script>
<link rel="shortcut icon" href="/static/img/favicon.ico" type="image/x-icon" />
<link rel="icon" sizes="32x32" href="/static/img/favicon-32x32.png" type="image/png"/>
<link rel="icon" sizes="64x64" href="/static/img/favicon-64x64.png" type="image/png"/>
<link rel="icon" sizes="192x192" href="/static/img/favicon-192x192.png" type="image/png"/>
<link rel="icon" sizes="16x16" href="/static/img/favicon-16x16.png" type="image/png"/>
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=0.67">
<title>{% block title %}Rowsandall{% endblock %}</title>
<link rel="stylesheet" href="/static/css/reset.css" />
<link rel="stylesheet" href="/static/css/text.css" />
<link rel="stylesheet" href="/static/css/960_12_col.css" />
<link rel="stylesheet" href="/static/css/rowsandall.css" />
<link rel="stylesheet" href="/static/css/leaflet.css" />
<script src="/static/css/leaflet.js" ></script>
{% block meta %} {% endblock %}
{% analytical_head_bottom %}
</head>
<body>
{% analytical_body_top %}
{% block body_top %}{% endblock %}
<div class="container_12">
<div class="grid_12">
&nbsp;
</div>
<div class="grid_12">
<div id="logo" class="grid_6 alpha">
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
<p><a href="/"><img src="/static/img/logo7.png"
alt="Rowsandall logo" height="80"></a></p>
{% else %}
<p><a href="/"><img src="/static/img/logo7.png"
alt="Rowsandall logo" height="80"></a></p>
{% endif %}
</div>
<div class="grid_6 omega">
<div class="grid_4 alpha">
<div class="grid_1 alpha">
<p id="header">
<a class="button gray small" href="/rowers/videos">Videos</a></p>
</div>
<div class="grid_2">
<p id="header">
<a class="button gray small" href="http://analytics.rowsandall.com/">Rowing Analytics BLOG</a></p>
</div>
<div class="grid_1 omega">
<p id="header">
<a class="button gray small" href="/rowers/email">Contact</a>
</p>
</div>
<div class="grid_4 alpha">
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
</div>
</div>
<div class="grid_1">
<div class="grid_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/me/edit">{{ user.first_name }}</a>
</p>
<span class="tooltiptext">Edit user account, e.g. heart rate zones, power zones, email, teams</span>
{% else %}
<p><a class="button gray small" href="{% url 'login' %}">login</a> </p>
{% endif %}
</div>
<div class="grid_1">
{% if user.is_authenticated %}
<p><a class="button gray small" href="{% url 'logout' %}">logout</a></p>
{% else %}
<p>&nbsp</p>
{% endif %}
</div>
</div>
<div class="grid_1 omega">
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
<h6 class="graytext">Pro Member</h6>
{% else %}
<div class="grid_1"><a class="button green small" href="/rowers/paidplans">Upgrade to Pro</a></div>
{% endif %}
</div>
</div>
</div>
<div class="grid_12">
<div class="grid_1 alpha tooltip">
{% if user.is_authenticated %}
<p><a class="button gray small" href="/rowers/workout/upload/">Upload</a></p>
<span class="tooltiptext">Upload CSV, TCX, FIT data files to rowsandall.com</span>
{% else %}
<p><a class="button green small" href="/rowers/register">Register (free)</a></p>
{% endif %}
</div>
<div class="grid_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/imports/">Import</a>
</p>
<span class="tooltiptext">Import workouts from Strava, SportTracks, and C2 logbook</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/list-workouts/">Workouts</a>
</p>
<span class="tooltiptext">See your list of workouts</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/list-graphs/">Graphs</a>
</p>
<span class="tooltiptext">See your most recent charts</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/analysis">Analysis</a>
</p>
<span class="tooltiptext">Analysis of workouts over a period of time</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_1 tooltip">
{% block teams %}
{% endblock %}
</div>
</div>
<div class="clear"></div>
<div class="grid_12">
{% block message %}
{% if message %}
<p class="message">
{{ message }}
</p>
{% endif %}
{% if successmessage %}
<p class="successmessage">
{{ successmessage }}
</p>
{% endif %}
{% endblock %}
</div>
<div class="grid_12">
{% load tz %}
{% block content %}{% endblock %}
</div>
<div class="clear"></div>
<div class="grid_12 omega" >
{% block footer %}
<p id="footer">{{ versionstring }}</p>
<div class="grid_2 alpha">
<p id="footer"><a href="/rowers/email/">&copy; Sander Roosendaal</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/about">About</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/brochure">Brochure</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/developers">Developers</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/legal">Legal</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/partners">Partners</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/physics">Physics</a></p>
</div>
<div class="grid_2">
<p id="footer">
<a href="http://analytics.rowsandall.com/">Rowing Analytics BLOG</a></p>
</div>
<div class="grid_2 omega">
<p id="footer">
<a href="https://www.facebook.com/groups/rowsandall/">Facebook group</a></p>
</div>
{% endblock %}
</div>
{% cookielaw_banner %}
</div>
<!-- end container -->
{% analytical_body_bottom %}
{% block body_bottom %}{% endblock %}
</body>
</html>
-194
View File
@@ -1,194 +0,0 @@
{% load rowerfilters %}
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">
<html lang="en">
<head>
<script src="/static/cookielaw/js/cookielaw.js"></script>
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
<link rel="shortcut icon" href="/static/img/myicon.png" />
<link rel="shortcut icon" href="/static/img/favicon.ico" />
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=0.67">
<title>Rowsandall</title>
<link rel="stylesheet" href="/static/css/reset.css" />
<link rel="stylesheet" href="/static/css/text.css" />
<link rel="stylesheet" href="/static/css/960_12_col.css" />
<link rel="stylesheet" href="/static/css/rowsandall.css" />
{% block meta %} {% endblock %}
</head>
<body>
<div class="container_12">
<div id="logo" class="grid_2">
{% if user|is_promember %}
<p><a href="/"><img src="/static/img/logocroppedpro.gif"
alt="Rowsandall logo" width="110" heigt="110"></a></p>
{% else %}
<p><a href="/"><img src="/static/img/logocropped.gif"
alt="Rowsandall logo" width="110" heigt="110"></a></p>
{% endif %}
</div>
<div class="grid_10 omega">
<div class="grid_8 alpha"><p>&nbsp</p></div>
<div class="grid_2 omega">
{% if user.is_authenticated %}
<p><a class="button gray small" href="/password_change/">Password Change</a></p>
{% else %}
<p><a class="button gray small" href="/password_reset/">Forgotten Password?</a></p>
{% endif %}
</div>
</div>
<div class="grid_10 omega">
<div class="grid_4 suffix_2 alpha">
<p>Free Data and Analysis. For Rowers. By Rowers.</p>
</div>
<div class="grid_3">
{% if user|is_promember %}
<h6>Pro Member</h6>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_1 omega">
{% if user.is_authenticated %}
<p><a class="button gray small" href="{% url 'logout' %}">logout</a></p>
{% else %}
<p>&nbsp</p>
{% endif %}
</div>
</div>
<div class="grid_10" omega>
<div class="grid_1 alpha tooltip">
{% if user.is_authenticated %}
<p><a class="button gray small" href="/rowers/workout/upload/">Upload</a></p>
<span class="tooltiptext">Upload CSV, TCX, FIT data files to rowsandall.com</span>
{% else %}
<p><a class="button green small" href="/rowers/register">Register (free)</a></p>
{% endif %}
</div>
<div class="grid_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/imports/">Import</a>
</p>
<span class="tooltiptext">Import workouts from Strava, SportTracks, and C2 logbook</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/list-workouts/">Workouts</a>
</p>
<span class="tooltiptext">See your list of workouts</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/list-graphs/">Graphs</a>
</p>
<span class="tooltiptext">See your most recent charts</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_2 suffix_1 tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/analysis">Analysis</a>
</p>
<span class="tooltiptext">Analysis of workouts over a period of time</span>
{% else %}
<p>&nbsp;</p>
{% endif %}
</div>
<div class="grid_1 omega tooltip">
{% if user.is_authenticated %}
<p>
<a class="button gray small" href="/rowers/me/edit">{{ user.first_name }}</a>
</p>
<span class="tooltiptext">Edit user data, e.g. heart rate zones</span>
{% else %}
<p><a class="button gray small" href="{% url 'login' %}">login</a> </p>
{% endif %}
</div>
</div>
<div class="clear"></div>
<div class="grid_12">
{% block message %}
{% if message %}
<p class="message">
{{ message }}
</p>
{% endif %}
{% if successmessage %}
<p class="successmessage">
{{ successmessage }}
</p>
{% endif %}
{% endblock %}
</div>
<div class="grid_12">
{% load tz %}
{% block content %}{% endblock %}
</div>
<div class="clear"></div>
<div class="grid_12 omega" >
{% block footer %}
<p id="footer"
>{{ versionstring }}</p>
<div class="grid_2 alpha">
<p id="footer"><a href="/rowers/email/">&copy; Sander Roosendaal</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/about">About</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/brochure">Brochure</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/developers">Developers</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/legal">Legal</a></p>
</div>
<div class="grid_1">
<p id="footer">
<a href="/rowers/physics">Physics</a></p>
</div>
<div class="grid_2">
<p id="footer">
<a href="/rowers/videos">Videos</a></p>
</div>
<div class="grid_2">
<p id="footer">
<a href="http://analytics.rowsandall.com/">Rowing Analytics BLOG</a></p>
</div>
<div class="grid_1 omega">
<p id="footer">
<a href="/rowers/email">Contact</a></p>
</div>
{% endblock %}
</div>
</div>
<!-- end container -->
</body>
</html>
-60
View File
@@ -1,60 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Rowsandall {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, false, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="workouts" class="grid_12 alpha">
<h1>Interactive Plot</h1>
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_2 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ workout.id|encode }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
{{ the_div|safe }}
</div>
{% endblock %}
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
-77
View File
@@ -1,77 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Compare Workouts {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="other" class="grid_12 alpha">
<div class="grid_2 alpha suffix_10">
<a class="button blue small"
href="/rowers/workout/compare/{{ id2 }}/{{ id1 }}/{{ xparam }}/{{ yparam }}">Swap Workouts</a>
</div>
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/time/{{ yparam }}">Time</a>
</div>
<div class="grid_2 suffix_2 omega">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/distance/{{ yparam }}">Distance</a>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 alpha">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/pace">Pace</a>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/hr">Heart Rate</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/spm">SPM</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}
-131
View File
@@ -1,131 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %} Comparison Plot {% endblock %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/compare/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha">
<p>
<a class="button blue small"
href="/rowers/workout/compare/{{ id2 }}/{{ id1 }}/{{ xparam }}/{{ yparam }}/{{ plottype }}">Swap Workouts</a>
</p>
</div>
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
{% for key, value in axchoicesbasic.items %}
{% if key != 'None' %}
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1}}/{{ id2 }}/{{ key }}/{{ yparam }}/{{ plottype }}">{{ value }}</a>
{% endif %}
{% endfor %}
{% if promember %}
{% for key, value in axchoicespro.items %}
<a class="button blue small alpha" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ key }}/{{ yparam }}/{{ plottype }}">{{ value }}</a>
{% endfor %}
{% else %}
{% for key, value in axchoicespro.items %}
<a class="button rosy small" href="/rowers/paidplans">{{ value }}</a>
{% endfor %}
{% endif %}
</div>
</div>
<div class="grid_2 omega dropdown">
<button class="grid_2 alpha button blue small dropbtn">Y-axis</button>
<div class="dropdown-content">
{% for key, value in axchoicesbasic.items %}
{% if key not in noylist and key != 'None' %}
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/{{ key }}/{{ plottype }}">{{ value }}</a>
{% endif %}
{% endfor %}
{% if promember %}
{% for key, value in axchoicespro.items %}
{% if key not in noylist %}
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/{{ key }}/{{ plottype }}">{{ value }}</a>
{% endif %}
{% endfor %}
{% else %}
{% for key, value in axchoicespro.items %}
{% if key not in noylist %}
<a class="button rosy small" href="/rowers/paidplans">{{ value }} (Pro)</a>
{% endif %}
{% endfor %}
{% endif %}
</div>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 prefix_2 alpha">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/{{ yparam }}/line">Line Plot</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/compare/{{ id1 }}/{{ id2 }}/{{ xparam }}/{{ yparam }}/scatter">Scatter Plot</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha flexplot">
{{ the_div|safe }}
</div>
{% endblock %}
+4 -9
View File
@@ -58,18 +58,13 @@
</script>
<div id="id_css_res">
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css" type="text/css" />
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css" type="text/css" />
</div>
<div id="id_js_res">
<script
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
</script>
<script
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
</script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
</div>
+4 -8
View File
@@ -60,16 +60,12 @@
<div id="id_css_res">
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css" type="text/css" />
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css" type="text/css" />
</div>
<div id="id_js_res">
<script
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
</script>
<script
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
</script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
</div>
+1 -1
View File
@@ -98,7 +98,7 @@
</li>
{% endif %}
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -48,7 +48,7 @@
});
</script>
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
-182
View File
@@ -1,182 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% load tz %}
{% block title %} Flexible Plot {% endblock %}
{% localtime on %}
{% block content %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ interactiveplot |safe }}
{{ widgetscript | safe }}
<script>
// Set things up to resize the plot on a window resize. You can play with
// the arguments of resize_width_height() to change the plot's behavior.
var plot_resize_setup = function () {
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
var plot = Bokeh.index[plotid];
var plotresizer = function() {
// arguments: use width, use height, maintain aspect ratio
plot.resize_width_height(true, true, false);
};
window.addEventListener('resize', plotresizer);
plotresizer();
};
window.addEventListener('load', plot_resize_setup);
</script>
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<p>&nbsp;</p>
<div id="plotbuttons" class="grid_12 alpha">
<div id="x-axis" class="grid_6 alpha">
<div class="grid_2 alpha dropdown">
<button class="grid_2 alpha button blue small dropbtn">X-axis</button>
<div class="dropdown-content">
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/time/{{ yparam1 }}/{{ yparam2 }}/{{ plottype }}">Time</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/distance/{{ yparam1 }}/{{ yparam2 }}/{{ plottype }}">Distance</a>
{% if promember %}
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/power/{{ yparam1 }}/{{ yparam2 }}/scatter">Power</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/hr/{{ yparam1 }}/{{ yparam2 }}/scatter">HR</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/spm/{{ yparam1 }}/{{ yparam2 }}/scatter">SPM</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/peakforce/{{ yparam1 }}/{{ yparam2 }}/scatter">Peak Force</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/averageforce/{{ yparam1 }}/{{ yparam2 }}/scatter">Average Force</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/drivelength/{{ yparam1 }}/{{ yparam2 }}/scatter">Drive Length</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/driveenergy/{{ yparam1 }}/{{ yparam2 }}/scatter">Work per Stroke</a>
<a class="button blue small alpha" href="/rowers/workout/{{ id }}/flexchart/drivespeed/{{ yparam1 }}/{{ yparam2 }}/scatter">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/paidplans">Power (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">HR (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">SPM (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown">
<button class="grid_2 alpha button blue small dropbtn">Left</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/pace/{{ yparam2 }}/{{ plottype }}">Pace</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/hr/{{ yparam2 }}/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/spm/{{ yparam2 }}/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/power/{{ yparam2 }}/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/peakforce/{{ yparam2 }}/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/averageforce/{{ yparam2 }}/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/drivelength/{{ yparam2 }}/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/driveenergy/{{ yparam2 }}/{{ plottype }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/drivespeed/{{ yparam2 }}/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/paidplans">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Drive Speed (Pro)</a>
{% endif %}
</div>
</div>
<div class="grid_2 dropdown omega">
<button class="grid_2 alpha button blue small dropbtn">Right</button>
<div class="dropdown-content">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/hr/{{ plottype }}">HR</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/spm/{{ plottype }}">SPM</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/power/{{ plottype }}">Power</a>
{% if promember %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/peakforce/{{ plottype }}">Peak Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/averageforce/{{ plottype }}">Average Force</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/drivelength/{{ plottype }}">Drive Length</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/driveenergy/{{ plottype }}">Work per Stroke</a>
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/drivespeed/{{ plottype }}">Drive Speed</a>
{% else %}
<a class="button rosy small" href="/rowers/paidplans">Peak Force (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Average Force (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Drive Length (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Work per Stroke (Pro)</a>
<a class="button rosy small" href="/rowers/paidplans">Drive Speed (Pro)</a>
{% endif %}
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/None/{{ plottype }}">None</a>
</div>
</div>
</div>
<div id="y-axis" class="grid_6 omega">
<div class="grid_2 alpha tooltip">
<form enctype="multipart/form-data" action="{{ formloc }}" method="post">
{% csrf_token %}
{% if workstrokesonly %}
<input type="hidden" name="workstrokesonly" value="True">
{% else %}
<input class="grid_2 alpha button blue small" type="hidden" name="workstrokesonly" value="False">
{% endif %}
<input class="grid_2 alpha button blue small" value="Toggle Work Strokes" type="Submit">
</form>
<span class="tooltiptext">If your data source allows, this will show or hide strokes taken during rest intervals.</span>
</div>
<div class="grid_2">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/{{ yparam2 }}/line">Line Plot</a>
</div>
<div class="grid_2 omega">
<a class="button blue small" href="/rowers/workout/{{ id }}/flexchart/{{ xparam }}/{{ yparam1 }}/{{ yparam2 }}/scatter">Scatter Plot</a>
</div>
</div>
</div>
<div id="theplot" class="grid_12 alpha flexplot">
{{ the_div|safe }}
</div>
<div id="thewidgets" class="grid_12 alpha">
{{ widgetdiv1|safe }}
{{ widgetdiv2|safe }}
</div>
{% endblock %}
{% endlocaltime %}
+2 -2
View File
@@ -11,8 +11,8 @@
{{ js_res | safe }}
{{ css_res| safe }}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+2 -2
View File
@@ -11,8 +11,8 @@
{{ js_res | safe }}
{{ css_res| safe }}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+4 -9
View File
@@ -60,17 +60,12 @@
<div id="id_css_res">
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css" type="text/css" />
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css" type="text/css" />
</div>
<div id="id_js_res">
<script
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
</script>
<script
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
</script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
</div>
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -59,7 +59,7 @@
<ul class="main-content">
<li class="grid_2" style="min-height:200px;">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -10,7 +10,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -138,7 +138,7 @@
<div id="advancedplots" class="grid_6 omega">
<div class="grid_6 alpha">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -6,7 +6,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -10,7 +10,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -13,7 +13,7 @@
{% block main %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -23,7 +23,7 @@
</li>
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -31,7 +31,7 @@
<img src="/static/img/rivercurrent.jpg" width="400">
</li>
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -62,7 +62,7 @@
</form>
</li>
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
-54
View File
@@ -1,54 +0,0 @@
{% extends "base.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %} Flexible Plot {% endblock %}
{% block content %}
{{ js_res | safe }}
{{ css_res| safe }}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ the_script |safe }}
<style>
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
html, body {height: 100%; margin:5px;}
</style>
<div id="navigation" class="grid_12 alpha">
{% if user.is_authenticated and mayedit %}
<div class="grid_2 alpha">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/edit">Edit Workout</a>
</p>
</div>
<div class="grid_2 suffix_8 omega">
<p>
<a class="button gray small" href="/rowers/workout/{{ id }}/advanced">Advanced Edit</a>
</p>
</div>
{% endif %}
</div>
<p>&nbsp;</p>
<div id="theplot" class="grid_12 alpha">
{{ the_div|safe }}
</div>
{% endblock %}
+1 -1
View File
@@ -53,7 +53,7 @@
</li>
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -13,7 +13,7 @@
{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %}
{% block meta %}
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -86,7 +86,7 @@
</li>
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -130,7 +130,7 @@ $('#id_workouttype').change();
{% endif %}
{% if mapdiv %}
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+1 -1
View File
@@ -121,7 +121,7 @@
</li>
{% endif %}
<li class="grid_2">
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
+7 -2
View File
@@ -31,6 +31,7 @@ from rowers.opaque import encoder
import arrow
from six import string_types
def strfdelta(tdelta):
minutes,seconds = divmod(tdelta.seconds,60)
@@ -87,7 +88,11 @@ def aantalcomments(workout):
@register.filter
def encode(id):
return str(encoder.encode_hex(id))
try:
result = str(encoder.encode_hex(id))
except TypeError:
result = ''
return result
@register.filter
def water(workout):
@@ -220,7 +225,7 @@ def jsdict(dict,key):
def lookup(dict, key):
s = dict.get(key)
if isinstance(s,basestring) and len(s) > 22:
if isinstance(s,string_types) and len(s) > 22:
s = s[:22]
return s
+10 -5
View File
@@ -1,3 +1,8 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import pytest
pytestmark = pytest.mark.django_db
@@ -31,7 +36,7 @@ from rowers.utils import NoTokenError
from shutil import copyfile
from nose.tools import assert_true
from mock import Mock, patch
from minimocktest import MockTestCase
#from minimocktest import MockTestCase
import pandas as pd
import rowers.c2stuff as c2stuff
import arrow
@@ -98,15 +103,15 @@ def mocked_sqlalchemy(*args, **kwargs):
return MockEngine()
#@pytest.mark.django_db
class DjangoTestCase(TestCase, MockTestCase):
class DjangoTestCase(TestCase): #, MockTestCase):
def _pre_setup(self):
MockTestCase.setUp(self)
# MockTestCase.setUp(self)
TestCase._pre_setup(self)
self.client = Client()
def _post_teardown(self):
TestCase._post_teardown(self)
MockTestCase.tearDown(self)
#MockTestCase.tearDown(self)
# delete_strokedata(1)
def mocked_tcx_parser(*args, **kwargs):
@@ -220,7 +225,7 @@ def mocked_read_df_cols_sql_multiflex(ids, columns, convertnewtons=True):
def mocked_stravaexport(f2,workoutname,stravatoken,description='',
activity_type='Rowing'):
print "this is mocked strava export"
print("this is mocked strava export")
return 1,'success'
def mocked_fetchcp(*args, **kwargs):
+6 -1
View File
@@ -3,6 +3,11 @@ try:
except NameError:
WindowsError = None
try:
FileNotFoundError
except NameError:
FileNotFoundError = None
try:
OSError
except NameError:
@@ -44,7 +49,7 @@ from rowers.plannedsessions import get_dates_timeperiod
from shutil import copyfile, copy
from nose.tools import assert_true
from mock import Mock, patch
from minimocktest import MockTestCase
#from minimocktest import MockTestCase
import pandas as pd
import rowers.c2stuff as c2stuff
+15 -10
View File
@@ -1,5 +1,10 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#from __future__ import print_function
from statements import *
from .statements import *
from django.utils import timezone
nu = datetime.datetime.now(tz=timezone.utc)
@@ -327,7 +332,7 @@ class VirtualEventViewTest(TestCase):
def tearDown(self):
try:
os.remove('rowers/tests/testdata/temp/course.kml')
except (WindowsError, OSError, IOError):
except (FileNotFoundError, OSError, IOError):
pass
@@ -408,7 +413,7 @@ class VirtualEventViewTest(TestCase):
form = IndoorVirtualRaceForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -452,7 +457,7 @@ class VirtualEventViewTest(TestCase):
form = IndoorVirtualRaceForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -496,7 +501,7 @@ class VirtualEventViewTest(TestCase):
form = VirtualRaceForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -533,7 +538,7 @@ class VirtualEventViewTest(TestCase):
form = VirtualRaceForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -588,7 +593,7 @@ class VirtualEventViewTest(TestCase):
form = IndoorVirtualRaceResultForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -617,7 +622,7 @@ class VirtualEventViewTest(TestCase):
form = IndoorVirtualRaceResultForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -666,7 +671,7 @@ class VirtualEventViewTest(TestCase):
form = VirtualRaceResultForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
@@ -694,7 +699,7 @@ class VirtualEventViewTest(TestCase):
form = VirtualRaceResultForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data,follow=True)
+6 -1
View File
@@ -1,5 +1,10 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#from __future__ import print_function
from statements import *
from .statements import *
nu = datetime.datetime.now()
from rowers.models import User,Rower
+16 -11
View File
@@ -1,4 +1,9 @@
from statements import *
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from .statements import *
nu = datetime.datetime.now()
@@ -26,7 +31,7 @@ class WorkoutCompareTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError, OSError):
pass
@patch('rowers.dataprep.create_engine')
@@ -91,7 +96,7 @@ class BoxPlotTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.create_engine')
@@ -110,7 +115,7 @@ class BoxPlotTest(TestCase):
@patch('rowers.dataprep.create_engine')
@patch('rowers.dataprep.getsmallrowdata_db')
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multi)
def test_workouts_boxplot_submit(self, mocked_sqlalchemy,
def donot_test_workouts_boxplot_submit(self, mocked_sqlalchemy,
mocked_getsmallrowdata_db,
mocked_df):
@@ -188,7 +193,7 @@ class ListWorkoutTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.create_engine')
@@ -246,7 +251,7 @@ class PlannedSessionTests(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
def test_ics_download(self):
@@ -291,7 +296,7 @@ class ForcecurveTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.getsmallrowdata_db',side_effect = mocked_getempowerdata_db)
@@ -326,7 +331,7 @@ class CumStatsTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
@@ -363,7 +368,7 @@ class CumFlexTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multiflex)
@@ -468,7 +473,7 @@ class MultiFlexTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multiflex)
@@ -570,7 +575,7 @@ class HistoTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.create_engine')
+7 -2
View File
@@ -1,4 +1,9 @@
from statements import *
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from .statements import *
nu = datetime.datetime.now()
@@ -211,7 +216,7 @@ class WorkoutViewTest(TestCase):
'userid':self.u.id,
'id':encoder.encode_hex(self.werg1.id),
})
print url
print(url)
form_data = {
'xparam':'time',
+7 -2
View File
@@ -1,4 +1,9 @@
from statements import *
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from .statements import *
nu = datetime.datetime.now()
@@ -28,7 +33,7 @@ class SimpleViewTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
def test_start_protrial(self):
+6 -1
View File
@@ -1,4 +1,9 @@
from statements import *
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from .statements import *
class CoursesTest(TestCase):
def setUp(self):
+9 -5
View File
@@ -1,5 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from statements import *
from .statements import *
nu = datetime.datetime.now()
@@ -77,9 +81,9 @@ class OTWCPChartTest(TestCase):
if not os.path.isdir(path):
try:
os.remove(path)
except (IOError,WindowsError,OSError):
except (IOError,FileNotFoundError,OSError):
pass
except (IOError,WindowsError,OSError):
except (IOError,FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_cpraw)
@@ -157,7 +161,7 @@ class CPChartTest(TestCase):
for workout in self.user_workouts:
try:
os.remove(workout.csvfilename)
except (IOError, WindowsError,OSError):
except (IOError, FileNotFoundError,OSError):
pass
def test_analytics_page(self):
@@ -250,7 +254,7 @@ class CPChartTest(TestCase):
sex = r.sex,
weightc = r.weightcategory)
print url
print(url)
response = self.c.get(url)
self.assertEqual(response.status_code,200)
+9 -5
View File
@@ -1,5 +1,9 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#from __future__ import print_function
from statements import *
from .statements import *
@override_settings(TESTING=True)
class EmailUpload(TestCase):
@@ -43,7 +47,7 @@ workout run
if not os.path.isdir(path):
try:
os.remove(path)
except (IOError,WindowsError,OSError):
except (IOError,FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.create_engine')
@@ -133,7 +137,7 @@ race 1
if not os.path.isdir(path):
try:
os.remove(path)
except (IOError,WindowsError,OSError):
except (IOError,FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.create_engine')
@@ -194,7 +198,7 @@ race 1
if not os.path.isdir(path):
try:
os.remove(path)
except (IOError,WindowsError,OSError):
except (IOError,FileNotFoundError,OSError):
pass
@patch('rowers.dataprep.create_engine')
@@ -210,7 +214,7 @@ race 1
ws = Workout.objects.filter(name="johnsworkout")
if not len(ws):
for w in Workout.objects.all():
print w
print(w)
self.assertEqual(len(ws),1)
+5 -1
View File
@@ -1,6 +1,10 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#from __future__ import print_function
from statements import *
from .statements import *
class EmpowerTest(TestCase):
+9 -3
View File
@@ -1,5 +1,10 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#from __future__ import print_function
from statements import *
from .statements import *
#@pytest.mark.django_db
@@ -11,11 +16,12 @@ class TestErrorPages(TestCase):
factory = RequestFactory()
request = factory.get('/')
response = error404_view(request)
self.assertEqual(response.status_code, 404)
self.assertIn('404 Page not found', unicode(response))
self.assertIn('404 Page not found', str(response.content))
response = error500_view(request)
self.assertEqual(response.status_code, 500)
self.assertIn('500 Internal Server Error', unicode(response))
self.assertIn('500 Internal Server Error', str(response.content))
response = error400_view(request)
self.assertEqual(response.status_code, 400)
+7 -2
View File
@@ -1,4 +1,9 @@
from statements import *
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
from .statements import *
@override_settings(TESTING=True)
class WorkoutViewTest(TestCase):
@@ -120,7 +125,7 @@ class WorkoutViewTest(TestCase):
form = FlexOptionsForm(form_data)
if not form.is_valid():
print form.errors
print(form.errors)
self.assertTrue(form.is_valid())
response = self.c.post(url,form_data)
+7 -2
View File
@@ -1,5 +1,10 @@
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
#from __future__ import print_function
from statements import *
from .statements import *
nu = datetime.datetime.now()
@@ -791,7 +796,7 @@ boattype: 2x
if not os.path.isdir(path):
try:
os.remove(path)
except (WindowsError,OSError):
except (FileNotFoundError,OSError):
pass
@patch('rowers.tpstuff.requests.post', side_effect=mocked_requests)

Some files were not shown because too many files have changed in this diff Show More