Merge branch 'release/v9.36'
This commit is contained in:
@@ -27,7 +27,6 @@ conftest.py
|
|||||||
# temporary test files
|
# temporary test files
|
||||||
/rowers/tests/testdata/temp
|
/rowers/tests/testdata/temp
|
||||||
/rowers/tests/testdata/testdata.csv.gz
|
/rowers/tests/testdata/testdata.csv.gz
|
||||||
rowers/tests/testdata/testdata.csv.gz
|
|
||||||
/rowers/tests/testdata/testdata.tcx
|
/rowers/tests/testdata/testdata.tcx
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"cells": [],
|
||||||
|
"metadata": {},
|
||||||
|
"nbformat": 4,
|
||||||
|
"nbformat_minor": 2
|
||||||
|
}
|
||||||
@@ -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
@@ -1,4 +1,4 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- Coding: utf-8 -*-
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
@@ -44,7 +44,7 @@ class Member(models.Model):
|
|||||||
verbose_name_plural = _("members")
|
verbose_name_plural = _("members")
|
||||||
ordering = ['user']
|
ordering = ['user']
|
||||||
|
|
||||||
user = models.OneToOneField(User)
|
user = models.OneToOneField(User,on_delete=models.CASCADE)
|
||||||
contributions = models.BooleanField(default=True)
|
contributions = models.BooleanField(default=True)
|
||||||
status = models.CharField(default="member",
|
status = models.CharField(default="member",
|
||||||
choices=statuses,
|
choices=statuses,
|
||||||
@@ -150,8 +150,8 @@ class Outing(models.Model):
|
|||||||
("completed", _("completed")),
|
("completed", _("completed")),
|
||||||
("race", _("race")),
|
("race", _("race")),
|
||||||
)
|
)
|
||||||
boat = models.ForeignKey(Boat)
|
boat = models.ForeignKey(Boat,on_delete=models.CASCADE)
|
||||||
rower = models.ForeignKey(Member)
|
rower = models.ForeignKey(Member,on_delete=models.CASCADE)
|
||||||
race = models.ManyToManyField(Races,blank=True)
|
race = models.ManyToManyField(Races,blank=True)
|
||||||
otherrowers = models.ManyToManyField(Member,related_name="otherrowers")
|
otherrowers = models.ManyToManyField(Member,related_name="otherrowers")
|
||||||
status = models.CharField(_("Status"),default="active",
|
status = models.CharField(_("Status"),default="active",
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
from celery import Celery,app
|
from .celery import Celery,app
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
import gc
|
import gc
|
||||||
|
|||||||
+128
-185
@@ -1,221 +1,164 @@
|
|||||||
alabaster==0.7.7
|
amqp==2.4.1
|
||||||
amqp==1.4.9
|
arrow==0.13.1
|
||||||
anyjson==0.3.3
|
|
||||||
appdirs==1.4.3
|
|
||||||
argcomplete==1.0.0
|
|
||||||
arrow==0.12.1
|
|
||||||
asn1crypto==0.23.0
|
|
||||||
astropy==1.1.2
|
|
||||||
atomicwrites==1.3.0
|
atomicwrites==1.3.0
|
||||||
attrs==18.2.0
|
attrs==18.2.0
|
||||||
awscli==1.14.57
|
backcall==0.1.0
|
||||||
Babel==2.2.0
|
beautifulsoup4==4.7.1
|
||||||
backports-abc==0.4
|
billiard==3.5.0.5
|
||||||
backports.functools-lru-cache==1.5
|
bleach==3.1.0
|
||||||
backports.shutil-get-terminal-size==1.0.0
|
bokeh==1.0.4
|
||||||
backports.ssl-match-hostname==3.4.0.2
|
braintree==3.51.0
|
||||||
beautifulsoup4==4.6.0
|
celery==4.2.1
|
||||||
billiard==3.3.0.23
|
certifi==2018.11.29
|
||||||
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
|
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
chest==0.2.3
|
Click==7.0
|
||||||
click==6.6
|
colorama==0.4.1
|
||||||
cloudpickle==0.1.1
|
cookies==2.2.1
|
||||||
clyent==1.2.1
|
coreapi==2.3.3
|
||||||
colorama==0.3.7
|
coreschema==0.0.4
|
||||||
comtypes==1.1.7
|
|
||||||
configobj==5.0.6
|
|
||||||
coreapi==2.0.9
|
|
||||||
cryptography==2.1.3
|
|
||||||
cycler==0.10.0
|
cycler==0.10.0
|
||||||
Cython==0.23.4
|
dask==1.1.1
|
||||||
cytoolz==0.7.5
|
decorator==4.3.2
|
||||||
dask==0.8.1
|
defusedxml==0.5.0
|
||||||
datashape==0.5.1
|
|
||||||
decorator==4.0.9
|
|
||||||
dill==0.2.4
|
|
||||||
Django==1.9.5
|
Django==1.9.5
|
||||||
django-analytical==2.2.2
|
django-analytical==2.5.0
|
||||||
django-analytics==0.0.1
|
|
||||||
django-async-messages==0.3.1
|
django-async-messages==0.3.1
|
||||||
django-braces==1.8.1
|
django-braces==1.13.0
|
||||||
django-celery==3.1.17
|
|
||||||
django-classy-tags==0.8.0
|
django-classy-tags==0.8.0
|
||||||
django-cookie-law==1.0.12
|
django-cookie-law==2.0.1
|
||||||
django-cors-headers==1.1.0
|
django-cors-headers==2.4.0
|
||||||
django-cors-middleware==1.3.1
|
django-countries==5.3.3
|
||||||
django-countries==5.3.2
|
|
||||||
django-datetime-widget==0.9.3
|
django-datetime-widget==0.9.3
|
||||||
django-debug-toolbar==1.4
|
django-debug-toolbar==1.4
|
||||||
django-durationfield==0.5.2
|
django-extensions==2.1.6
|
||||||
django-extensions==1.7.5
|
|
||||||
django-filter==1.0.0
|
|
||||||
django-geckoboard==2.0.0
|
|
||||||
django-geojson==2.10.0
|
|
||||||
django-htmlmin==0.10.0
|
django-htmlmin==0.10.0
|
||||||
django-leaflet==0.22.0
|
django-leaflet==0.24.0
|
||||||
django-mailbox==4.6.0
|
django-mailbox==4.7.1
|
||||||
django-modelcluster==1.1
|
|
||||||
django-oauth-toolkit==0.10.0
|
django-oauth-toolkit==0.10.0
|
||||||
django-oauth2-provider==0.2.6.1
|
django-oauth2-provider==0.2.6.1
|
||||||
django-rest-swagger==2.1.0
|
django-rest-framework==0.1.0
|
||||||
django-rq==0.8.0
|
django-rest-swagger==2.2.0
|
||||||
django-rq-dashboard==0.3.0
|
django-rq==1.3.0
|
||||||
django-ses==0.8.5
|
django-rq-dashboard==0.3.3
|
||||||
django-social-share==1.1.2
|
django-shell-plus==1.1.7
|
||||||
django-suit==0.2.25
|
django-social-share==1.3.2
|
||||||
|
django-suit==0.2.26
|
||||||
django-suit-rq==1.0.1
|
django-suit-rq==1.0.1
|
||||||
django-taggit==0.18.1
|
django-tz-detect==0.2.9
|
||||||
django-translation-manager==0.3.4
|
|
||||||
django-treebeard==4.0
|
|
||||||
django-tz-detect==0.2.8
|
|
||||||
djangorestframework==3.5.3
|
djangorestframework==3.5.3
|
||||||
docopt==0.6.2
|
docopt==0.6.2
|
||||||
docutils==0.12
|
docutils==0.14
|
||||||
enum34==1.1.2
|
entrypoints==0.3
|
||||||
et-xmlfile==1.0.1
|
factory-boy==2.11.1
|
||||||
Factory==1.2
|
Faker==1.0.2
|
||||||
fastcache==1.0.2
|
|
||||||
filemagic==1.6
|
|
||||||
fitparse==1.0.1
|
fitparse==1.0.1
|
||||||
Flask==0.10.1
|
future==0.17.1
|
||||||
Flask-Cors==2.1.2
|
geocoder==1.38.1
|
||||||
Flask-Login==0.3.2
|
holoviews==1.11.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
|
|
||||||
html5lib==1.0.1
|
html5lib==1.0.1
|
||||||
httplib2==0.9.2
|
htmlmin==0.1.12
|
||||||
|
HTMLParser==0.0.2
|
||||||
|
httplib2==0.12.1
|
||||||
icalendar==4.0.3
|
icalendar==4.0.3
|
||||||
idna==2.6
|
idna==2.8
|
||||||
ipaddress==1.0.14
|
image==1.5.27
|
||||||
ipython==4.2.0
|
importlib-resources==1.0.2
|
||||||
ipython-genutils==0.1.0
|
ipykernel==5.1.0
|
||||||
|
ipython==7.3.0
|
||||||
|
ipython-genutils==0.2.0
|
||||||
|
ipywidgets==7.4.2
|
||||||
iso8601==0.1.12
|
iso8601==0.1.12
|
||||||
isodate==0.6.0
|
isodate==0.6.0
|
||||||
itsdangerous==0.24
|
|
||||||
itypes==1.1.0
|
itypes==1.1.0
|
||||||
Jinja2==2.8
|
jedi==0.13.3
|
||||||
jmespath==0.9.3
|
Jinja2==2.10
|
||||||
jsonschema==2.5.1
|
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
|
kiwisolver==1.0.1
|
||||||
kombu==3.0.35
|
kombu==4.3.0
|
||||||
lxml==4.2.1
|
lxml==4.3.1
|
||||||
Markdown==2.6.7
|
Markdown==3.0.1
|
||||||
MarkupSafe==0.23
|
MarkupSafe==1.1.1
|
||||||
matplotlib==2.2.2
|
matplotlib==3.0.2
|
||||||
mechanize==0.3.6
|
|
||||||
MiniMockTest==0.5
|
MiniMockTest==0.5
|
||||||
|
mistune==0.8.4
|
||||||
mock==2.0.0
|
mock==2.0.0
|
||||||
more-itertools==5.0.0
|
more-itertools==5.0.0
|
||||||
mpld3==0.2
|
mpld3==0.3
|
||||||
mpmath==0.19
|
nbconvert==5.4.1
|
||||||
multipledispatch==0.4.8
|
nbformat==4.4.0
|
||||||
networkx==1.11
|
|
||||||
nose==1.3.7
|
nose==1.3.7
|
||||||
nose-parameterized==0.6.0
|
nose-parameterized==0.6.0
|
||||||
numpy==1.14.2
|
notebook==5.7.4
|
||||||
|
numpy==1.16.1
|
||||||
oauth2==1.9.0.post1
|
oauth2==1.9.0.post1
|
||||||
oauthlib==1.0.3
|
oauthlib==1.0.3
|
||||||
odo==0.4.2
|
openapi-codec==1.3.2
|
||||||
openapi-codec==1.1.7
|
packaging==19.0
|
||||||
packaging==16.8
|
pandas==0.24.1
|
||||||
pandas==0.22.0
|
pandocfilters==1.4.2
|
||||||
pathlib2==2.3.3
|
param==1.8.2
|
||||||
pathspec==0.5.5
|
parso==0.3.4
|
||||||
|
pathspec==0.5.9
|
||||||
pbr==5.1.2
|
pbr==5.1.2
|
||||||
pexpect==4.0.1
|
pexpect==4.6.0
|
||||||
pickleshare==0.7.2
|
pickleshare==0.7.5
|
||||||
Pillow==3.2.0
|
Pillow==5.4.1
|
||||||
pluggy==0.8.1
|
pluggy==0.9.0
|
||||||
polib==1.0.7
|
prometheus-client==0.6.0
|
||||||
psutil==4.1.0
|
prompt-toolkit==2.0.9
|
||||||
ptyprocess==0.5.1
|
ptyprocess==0.6.0
|
||||||
py==1.7.0
|
py==1.8.0
|
||||||
pyasn1==0.1.9
|
Pygments==2.3.1
|
||||||
pycparser==2.14
|
pyparsing==2.3.1
|
||||||
pycrypto==2.6.1
|
pyrsistent==0.14.11
|
||||||
PyMySQL==0.7.4
|
pytest==4.3.0
|
||||||
pync==1.6.1
|
pytest-django==3.4.7
|
||||||
pyparsing==2.2.0
|
pytest-runner==4.4
|
||||||
pytest==4.2.0
|
|
||||||
pytest-sugar==0.9.2
|
pytest-sugar==0.9.2
|
||||||
python-dateutil==2.7.2
|
python-dateutil==2.8.0
|
||||||
python-memcached==1.58
|
python-twitter==3.5
|
||||||
python-metar==1.4.0
|
pytz==2018.9
|
||||||
python-openid==2.2.5
|
pyviz-comms==0.7.0
|
||||||
python-twitter==3.2
|
PyYAML==3.13
|
||||||
pytz==2018.4
|
pyzmq==18.0.0
|
||||||
PyYAML==3.12
|
qtconsole==4.4.3
|
||||||
pyzmq==15.2.0
|
|
||||||
ratelim==0.1.6
|
ratelim==0.1.6
|
||||||
redis==2.10.5
|
redis==3.2.0
|
||||||
req==1.0.0
|
requests==2.21.0
|
||||||
requests==2.12.3
|
requests-oauthlib==1.2.0
|
||||||
requests-oauthlib==0.7.0
|
rowingdata==2.0.6
|
||||||
rowingdata==2.0.0
|
rowingphysics==0.5.0
|
||||||
rowingphysics==0.3.10
|
rq==0.13.0
|
||||||
rq==0.6.0
|
scipy==1.2.1
|
||||||
rq-dashboard==0.3.7
|
Send2Trash==1.5.0
|
||||||
rsa==3.4.2
|
shell==1.0.1
|
||||||
s3transfer==0.1.13
|
shortuuid==0.5.0
|
||||||
scandir==1.6
|
simplejson==3.16.0
|
||||||
scikit-image==0.12.3
|
six==1.12.0
|
||||||
scikit-learn==0.17.1
|
soupsieve==1.8
|
||||||
scipy==1.0.1
|
SQLAlchemy==1.2.18
|
||||||
seaborn==0.7.0
|
sqlparse==0.2.4
|
||||||
Shapely==1.6.1
|
stravalib==0.10.2
|
||||||
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
|
|
||||||
termcolor==1.1.0
|
termcolor==1.1.0
|
||||||
timestring==1.6.2
|
terminado==0.8.1
|
||||||
timezonefinder==2.1.2
|
testpath==0.4.2
|
||||||
toolz==0.7.4
|
text-unidecode==1.2
|
||||||
tornado==4.4.2
|
timezonefinder==3.4.2
|
||||||
tqdm==4.23.0
|
tornado==5.1.1
|
||||||
traitlets==4.2.1
|
tqdm==4.31.1
|
||||||
tzwhere==3.0.3
|
traitlets==4.3.2
|
||||||
Unidecode==0.4.19
|
units==0.7
|
||||||
units==0.6
|
|
||||||
uritemplate==3.0.0
|
uritemplate==3.0.0
|
||||||
urllib3==1.22
|
urllib3==1.24.1
|
||||||
VerbalExpressions==0.0.1
|
VerbalExpressions==0.0.2
|
||||||
|
vine==1.2.0
|
||||||
|
wcwidth==0.1.7
|
||||||
webencodings==0.5.1
|
webencodings==0.5.1
|
||||||
Werkzeug==0.11.8
|
widgetsnbextension==3.4.2
|
||||||
xlrd==1.0.0
|
xmltodict==0.12.0
|
||||||
xmltodict==0.11.0
|
|
||||||
yamjam==0.1.7
|
yamjam==0.1.7
|
||||||
yamllint==1.8.1
|
yamllint==1.15.0
|
||||||
|
|||||||
@@ -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
@@ -1,5 +1,9 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
from .tasks import app as celery_app
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
|
||||||
|
from rowers.celery import app as celery_app
|
||||||
|
|
||||||
|
__all__ = ('celery_app',)
|
||||||
|
|||||||
@@ -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 import admin
|
||||||
from django.contrib.auth.admin import UserAdmin
|
from django.contrib.auth.admin import UserAdmin
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.apps import AppConfig
|
from django.apps import AppConfig
|
||||||
|
|||||||
@@ -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
|
import braintree
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
import datetime
|
import datetime
|
||||||
|
|||||||
+22
-5
@@ -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
|
# The interactions with the Concept2 logbook API
|
||||||
# All C2 related functions should be defined here
|
# All C2 related functions should be defined here
|
||||||
# (There is still some stuff defined directly in views.py. Need to
|
# (There is still some stuff defined directly in views.py. Need to
|
||||||
@@ -6,10 +12,12 @@
|
|||||||
from rowers.imports import *
|
from rowers.imports import *
|
||||||
import datetime
|
import datetime
|
||||||
from requests import Request, Session
|
from requests import Request, Session
|
||||||
import mytypes
|
import rowers.mytypes as mytypes
|
||||||
from rowers.mytypes import otwtypes
|
from rowers.mytypes import otwtypes
|
||||||
from iso8601 import ParseError
|
from iso8601 import ParseError
|
||||||
|
|
||||||
|
import numpy
|
||||||
|
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
|
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
|
||||||
)
|
)
|
||||||
@@ -19,7 +27,7 @@ import django_rq
|
|||||||
queue = django_rq.get_queue('default')
|
queue = django_rq.get_queue('default')
|
||||||
queuelow = django_rq.get_queue('low')
|
queuelow = django_rq.get_queue('low')
|
||||||
queuehigh = django_rq.get_queue('low')
|
queuehigh = django_rq.get_queue('low')
|
||||||
from utils import myqueue
|
from rowers.utils import myqueue
|
||||||
|
|
||||||
oauth_data = {
|
oauth_data = {
|
||||||
'client_id': C2_CLIENT_ID,
|
'client_id': C2_CLIENT_ID,
|
||||||
@@ -418,7 +426,11 @@ def createc2workoutdata(w):
|
|||||||
hr = 0*d
|
hr = 0*d
|
||||||
stroke_data = []
|
stroke_data = []
|
||||||
for i in range(len(t)):
|
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)
|
stroke_data.append(thisrecord)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -545,7 +557,7 @@ def make_authorization_url(request):
|
|||||||
params = {"client_id": C2_CLIENT_ID,
|
params = {"client_id": C2_CLIENT_ID,
|
||||||
"response_type": "code",
|
"response_type": "code",
|
||||||
"redirect_uri": C2_REDIRECT_URI}
|
"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
|
url += "&scope="+scope
|
||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
@@ -691,6 +703,10 @@ def process_callback(request):
|
|||||||
|
|
||||||
return HttpResponse("got a user name: %s" % username)
|
return HttpResponse("got a user name: %s" % username)
|
||||||
|
|
||||||
|
def default(o):
|
||||||
|
if isinstance(o, numpy.int64): return int(o)
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
# Uploading workout
|
# Uploading workout
|
||||||
def workout_c2_upload(user,w):
|
def workout_c2_upload(user,w):
|
||||||
message = 'trying C2 upload'
|
message = 'trying C2 upload'
|
||||||
@@ -711,6 +727,7 @@ def workout_c2_upload(user,w):
|
|||||||
raise NoTokenError
|
raise NoTokenError
|
||||||
|
|
||||||
data = createc2workoutdata(w)
|
data = createc2workoutdata(w)
|
||||||
|
|
||||||
if data == 0:
|
if data == 0:
|
||||||
return "Error: No data file. Contact info@rowsandall.com if the problem persists",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'}
|
'Content-Type': 'application/json'}
|
||||||
import urllib
|
import urllib
|
||||||
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
|
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 ):
|
if (response.status_code == 409 ):
|
||||||
message = "Concept2 Duplicate error"
|
message = "Concept2 Duplicate error"
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
from django.conf import settings # import the settings file
|
||||||
|
|
||||||
def braintree_merchant(request):
|
def braintree_merchant(request):
|
||||||
|
|||||||
+7
-2
@@ -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
|
# All the Courses related methods
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
@@ -28,7 +33,7 @@ import pandas as pd
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
from timezonefinder import TimezoneFinder
|
from timezonefinder import TimezoneFinder
|
||||||
|
|
||||||
import dataprep
|
import rowers.dataprep as dataprep
|
||||||
from rowers.utils import geo_distance
|
from rowers.utils import geo_distance
|
||||||
|
|
||||||
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
|
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
|
||||||
@@ -47,7 +52,7 @@ from rowers.models import (
|
|||||||
polygon_to_path,coordinate_in_path
|
polygon_to_path,coordinate_in_path
|
||||||
)
|
)
|
||||||
|
|
||||||
from utils import geo_distance
|
|
||||||
from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path
|
from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
# low level methods
|
||||||
def coordinate_in_path(latitude,longitude, p):
|
def coordinate_in_path(latitude,longitude, p):
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
from django.conf import settings
|
||||||
|
|
||||||
user = settings.DATABASES['default']['USER']
|
user = settings.DATABASES['default']['USER']
|
||||||
|
|||||||
+25
-16
@@ -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
|
# All the data preparation, data cleaning and data mangling should
|
||||||
# be defined here
|
# be defined here
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
from rowers.models import Workout, StrokeData,Team
|
from rowers.models import Workout, StrokeData,Team
|
||||||
|
|
||||||
import pytz
|
import pytz
|
||||||
@@ -55,7 +61,7 @@ import pandas as pd
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import itertools
|
import itertools
|
||||||
import math
|
import math
|
||||||
from tasks import (
|
from rowers.tasks import (
|
||||||
handle_sendemail_unrecognized, handle_sendemail_breakthrough,
|
handle_sendemail_unrecognized, handle_sendemail_breakthrough,
|
||||||
handle_sendemail_hard, handle_updatecp,handle_updateergcp,
|
handle_sendemail_hard, handle_updatecp,handle_updateergcp,
|
||||||
handle_calctrimp,
|
handle_calctrimp,
|
||||||
@@ -65,9 +71,9 @@ from django.conf import settings
|
|||||||
from sqlalchemy import create_engine
|
from sqlalchemy import create_engine
|
||||||
import sqlalchemy as sa
|
import sqlalchemy as sa
|
||||||
import sys
|
import sys
|
||||||
import utils
|
import rowers.utils as utils
|
||||||
import datautils
|
import rowers.datautils as datautils
|
||||||
from utils import lbstoN,myqueue,is_ranking_piece,wavg
|
from rowers.utils import lbstoN,myqueue,is_ranking_piece,wavg
|
||||||
|
|
||||||
from timezonefinder import TimezoneFinder
|
from timezonefinder import TimezoneFinder
|
||||||
|
|
||||||
@@ -531,7 +537,10 @@ def getstatsfields():
|
|||||||
fielddict.pop('hr_bottom')
|
fielddict.pop('hr_bottom')
|
||||||
fielddict.pop('cumdist')
|
fielddict.pop('cumdist')
|
||||||
|
|
||||||
|
try:
|
||||||
fieldlist = [field for field, value in fielddict.iteritems()]
|
fieldlist = [field for field, value in fielddict.iteritems()]
|
||||||
|
except AttributeError:
|
||||||
|
fieldlist = [field for field, value in fielddict.items()]
|
||||||
|
|
||||||
return fieldlist, fielddict
|
return fieldlist, fielddict
|
||||||
|
|
||||||
@@ -638,7 +647,7 @@ def deletecpdata_sql(rower_id,table='cpdata'):
|
|||||||
try:
|
try:
|
||||||
result = conn.execute(query)
|
result = conn.execute(query)
|
||||||
except:
|
except:
|
||||||
print "Database locked"
|
print("Database locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
|
|
||||||
@@ -855,7 +864,7 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
|||||||
|
|
||||||
return (id, message)
|
return (id, message)
|
||||||
|
|
||||||
from utils import totaltime_sec_to_string
|
from rowers.utils import totaltime_sec_to_string
|
||||||
|
|
||||||
# Processes painsled CSV file to database
|
# Processes painsled CSV file to database
|
||||||
def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
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:
|
try:
|
||||||
checks = row.check_consistency()
|
checks = row.check_consistency()
|
||||||
allchecks = 1
|
allchecks = 1
|
||||||
for key, value in checks.iteritems():
|
for key, value in checks.items():
|
||||||
if not value:
|
if not value:
|
||||||
allchecks = 0
|
allchecks = 0
|
||||||
if consistencychecks:
|
if consistencychecks:
|
||||||
@@ -1564,7 +1573,7 @@ def compare_data(id):
|
|||||||
res = conn.execute(query)
|
res = conn.execute(query)
|
||||||
l2 = res.fetchall()[0][0]
|
l2 = res.fetchall()[0][0]
|
||||||
except:
|
except:
|
||||||
print "Database Locked"
|
print("Database Locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
lfile = l1
|
lfile = l1
|
||||||
@@ -1583,13 +1592,13 @@ def repair_data(verbose=False):
|
|||||||
test, ldb, lfile = compare_data(w.id)
|
test, ldb, lfile = compare_data(w.id)
|
||||||
if not test:
|
if not test:
|
||||||
if verbose:
|
if verbose:
|
||||||
print w.id, lfile, ldb
|
print(w.id, lfile, ldb)
|
||||||
try:
|
try:
|
||||||
rowdata = rdata(w.csvfilename)
|
rowdata = rdata(w.csvfilename)
|
||||||
if rowdata and len(rowdata.df):
|
if rowdata and len(rowdata.df):
|
||||||
update_strokedata(w.id, rowdata.df)
|
update_strokedata(w.id, rowdata.df)
|
||||||
|
|
||||||
except IOError, AttributeError:
|
except (IOError, AttributeError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if lfile == 0:
|
if lfile == 0:
|
||||||
@@ -1618,10 +1627,10 @@ def repair_data(verbose=False):
|
|||||||
def rdata(file, rower=rrower()):
|
def rdata(file, rower=rrower()):
|
||||||
try:
|
try:
|
||||||
res = rrdata(csvfile=file, rower=rower)
|
res = rrdata(csvfile=file, rower=rower)
|
||||||
except IOError, IndexError:
|
except (IOError, IndexError):
|
||||||
try:
|
try:
|
||||||
res = rrdata(csvfile=file + '.gz', rower=rower)
|
res = rrdata(csvfile=file + '.gz', rower=rower)
|
||||||
except IOError, IndexError:
|
except (IOError, IndexError):
|
||||||
res = rrdata()
|
res = rrdata()
|
||||||
except:
|
except:
|
||||||
res = rrdata()
|
res = rrdata()
|
||||||
@@ -1640,7 +1649,7 @@ def delete_strokedata(id):
|
|||||||
try:
|
try:
|
||||||
result = conn.execute(query)
|
result = conn.execute(query)
|
||||||
except:
|
except:
|
||||||
print "Database Locked"
|
print("Database Locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
|
|
||||||
@@ -1792,7 +1801,7 @@ def prepmultipledata(ids, verbose=False):
|
|||||||
for id in res:
|
for id in res:
|
||||||
rowdata, row = getrowdata(id=id)
|
rowdata, row = getrowdata(id=id)
|
||||||
if verbose:
|
if verbose:
|
||||||
print id
|
print(id)
|
||||||
if rowdata and len(rowdata.df):
|
if rowdata and len(rowdata.df):
|
||||||
data = dataprep(rowdata.df, id=id, bands=True,
|
data = dataprep(rowdata.df, id=id, bands=True,
|
||||||
barchart=True, otwpower=True)
|
barchart=True, otwpower=True)
|
||||||
@@ -2029,7 +2038,7 @@ def fix_newtons(id=0, limit=3000):
|
|||||||
peakforce = rowdata['peakforce']
|
peakforce = rowdata['peakforce']
|
||||||
if peakforce.mean() > limit:
|
if peakforce.mean() > limit:
|
||||||
w = Workout.objects.get(id=id)
|
w = Workout.objects.get(id=id)
|
||||||
print "fixing ", id
|
print("fixing ", id)
|
||||||
rowdata = rdata(w.csvfilename)
|
rowdata = rdata(w.csvfilename)
|
||||||
if rowdata and len(rowdata.df):
|
if rowdata and len(rowdata.df):
|
||||||
update_strokedata(w.id, 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:
|
if rowdatadf.empty:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
|
#rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
|
||||||
t = rowdatadf.loc[:, 'TimeStamp (sec)']
|
t = rowdatadf.loc[:, 'TimeStamp (sec)']
|
||||||
t = pd.Series(t - rowdatadf.loc[:, 'TimeStamp (sec)'].iloc[0])
|
t = pd.Series(t - rowdatadf.loc[:, 'TimeStamp (sec)'].iloc[0])
|
||||||
|
|
||||||
|
|||||||
+18
-13
@@ -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)
|
# This is Data prep used for testing purposes (no Django environment)
|
||||||
# Uses the debug SQLite database for stroke data
|
# Uses the debug SQLite database for stroke data
|
||||||
from rowingdata import rowingdata as rrdata
|
from rowingdata import rowingdata as rrdata
|
||||||
@@ -18,7 +23,7 @@ import sqlalchemy as sa
|
|||||||
from rowsandall_app.settings import DATABASES
|
from rowsandall_app.settings import DATABASES
|
||||||
from rowsandall_app.settings_dev import DATABASES as DEV_DATABASES
|
from rowsandall_app.settings_dev import DATABASES as DEV_DATABASES
|
||||||
|
|
||||||
from utils import lbstoN
|
from rowers.utils import lbstoN
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -133,7 +138,7 @@ def rdata(file,rower=rrower()):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
from utils import totaltime_sec_to_string
|
from rowers.utils import totaltime_sec_to_string
|
||||||
|
|
||||||
|
|
||||||
# Creates C2 stroke data
|
# Creates C2 stroke data
|
||||||
@@ -635,14 +640,14 @@ def delete_strokedata(id,debug=False):
|
|||||||
try:
|
try:
|
||||||
result = conn.execute(query)
|
result = conn.execute(query)
|
||||||
except:
|
except:
|
||||||
print "Database Locked"
|
print("Database Locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
|
|
||||||
def update_strokedata(id,df,debug=False):
|
def update_strokedata(id,df,debug=False):
|
||||||
delete_strokedata(id,debug=debug)
|
delete_strokedata(id,debug=debug)
|
||||||
if debug:
|
if debug:
|
||||||
print "updating ",id
|
print("updating ",id)
|
||||||
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
|
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
|
||||||
debug=debug)
|
debug=debug)
|
||||||
|
|
||||||
@@ -676,11 +681,11 @@ def update_empower(id, inboard, oarlength, boattype, df, f1, debug=False):
|
|||||||
if success:
|
if success:
|
||||||
delete_strokedata(id,debug=debug)
|
delete_strokedata(id,debug=debug)
|
||||||
if debug:
|
if debug:
|
||||||
print "updated ",id
|
print("updated ",id)
|
||||||
print "correction ",corr_factor
|
print("correction ",corr_factor)
|
||||||
else:
|
else:
|
||||||
if debug:
|
if debug:
|
||||||
print "not updated ",id
|
print("not updated ",id)
|
||||||
|
|
||||||
|
|
||||||
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
|
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):
|
def read_df_sql(id,debug=False):
|
||||||
if debug:
|
if debug:
|
||||||
engine = create_engine(database_url_debug, echo=False)
|
engine = create_engine(database_url_debug, echo=False)
|
||||||
print "read_df",id
|
print("read_df",id)
|
||||||
print database_url_debug
|
print(database_url_debug)
|
||||||
else:
|
else:
|
||||||
engine = create_engine(database_url, echo=False)
|
engine = create_engine(database_url, echo=False)
|
||||||
|
|
||||||
@@ -826,7 +831,7 @@ def deletecpdata_sql(rower_id,table='cpdata',debug=False):
|
|||||||
try:
|
try:
|
||||||
result = conn.execute(query)
|
result = conn.execute(query)
|
||||||
except:
|
except:
|
||||||
print "Database locked"
|
print("Database locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
|
|
||||||
@@ -846,7 +851,7 @@ def delete_agegroup_db(age,sex,weightcategory,debug=False):
|
|||||||
try:
|
try:
|
||||||
result = conn.execute(query)
|
result = conn.execute(query)
|
||||||
except:
|
except:
|
||||||
print "Database locked"
|
print("Database locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
|
|
||||||
@@ -956,11 +961,11 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
|||||||
|
|
||||||
if rowdatadf.empty:
|
if rowdatadf.empty:
|
||||||
if debug:
|
if debug:
|
||||||
print "empty"
|
print("empty")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print "dataprep",id
|
print("dataprep",id)
|
||||||
|
|
||||||
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
|
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
|
||||||
t = rowdatadf.ix[:,'TimeStamp (sec)']
|
t = rowdatadf.ix[:,'TimeStamp (sec)']
|
||||||
|
|||||||
+6
-1
@@ -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 pandas as pd
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from scipy.interpolate import griddata
|
from scipy.interpolate import griddata
|
||||||
@@ -259,7 +264,7 @@ def getcp(dfgrouped,logarr):
|
|||||||
length = len(ww)
|
length = len(ww)
|
||||||
dt = []
|
dt = []
|
||||||
cpw = []
|
cpw = []
|
||||||
for i in xrange(length-2):
|
for i in range(length-2):
|
||||||
deltat,wmax = getmaxwattinterval(tt,ww,i)
|
deltat,wmax = getmaxwattinterval(tt,ww,i)
|
||||||
|
|
||||||
if not np.isnan(deltat) and not np.isnan(wmax):
|
if not np.isnan(deltat) and not np.isnan(wmax):
|
||||||
|
|||||||
@@ -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.contrib.auth.decorators import login_required,user_passes_test
|
||||||
|
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
|
|||||||
@@ -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 os
|
||||||
import time
|
import time
|
||||||
import gc
|
import gc
|
||||||
|
|||||||
+14
-7
@@ -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 import forms
|
||||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||||
from rowers.models import (
|
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.forms import UserCreationForm
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
from django.contrib.admin.widgets import AdminDateWidget
|
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.utils import timezone,translation
|
||||||
from django.forms import ModelForm, Select
|
from django.forms import ModelForm, Select
|
||||||
import dataprep
|
import rowers.dataprep as dataprep
|
||||||
import mytypes
|
import rowers.mytypes as mytypes
|
||||||
import datetime
|
import datetime
|
||||||
from django.forms import formset_factory
|
from django.forms import formset_factory
|
||||||
from utils import landingpages
|
from rowers.utils import landingpages
|
||||||
from metrics import axes
|
from rowers.metrics import axes
|
||||||
|
|
||||||
class FlexibleDecimalField(forms.DecimalField):
|
class FlexibleDecimalField(forms.DecimalField):
|
||||||
|
|
||||||
@@ -162,7 +169,7 @@ class DocumentsForm(forms.Form):
|
|||||||
super(DocumentsForm, self).__init__(*args, **kwargs)
|
super(DocumentsForm, self).__init__(*args, **kwargs)
|
||||||
# self.fields['offline'].widget = HiddenInput()
|
# self.fields['offline'].widget = HiddenInput()
|
||||||
|
|
||||||
from utils import (
|
from rowers.utils import (
|
||||||
workflowleftpanel,workflowmiddlepanel,
|
workflowleftpanel,workflowmiddlepanel,
|
||||||
defaultleft,defaultmiddle
|
defaultleft,defaultmiddle
|
||||||
)
|
)
|
||||||
@@ -824,7 +831,7 @@ formaxlabelsmultiflex.pop('distance')
|
|||||||
formaxlabelsmultiflex['workoutid'] = 'Workout'
|
formaxlabelsmultiflex['workoutid'] = 'Workout'
|
||||||
parchoicesmultiflex = list(sorted(formaxlabelsmultiflex.items(), key = lambda x:x[1]))
|
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())
|
palettechoices = tuple((p,p) for p in palettes.keys())
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -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
|
# All the functionality to connect to SportTracks
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
@@ -16,7 +22,7 @@ from dateutil import parser
|
|||||||
import time
|
import time
|
||||||
from time import strftime
|
from time import strftime
|
||||||
|
|
||||||
import dataprep
|
import rowers.dataprep as dataprep
|
||||||
import math
|
import math
|
||||||
from math import sin,cos,atan2,sqrt
|
from math import sin,cos,atan2,sqrt
|
||||||
import os,sys
|
import os,sys
|
||||||
@@ -38,7 +44,7 @@ from django.contrib.auth.decorators import login_required
|
|||||||
from rowingdata import rowingdata, make_cumvalues
|
from rowingdata import rowingdata, make_cumvalues
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from rowers.models import Rower,Workout,checkworkoutuser
|
from rowers.models import Rower,Workout,checkworkoutuser
|
||||||
from rowers import mytypes
|
import rowers.mytypes as mytypes
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI,
|
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI,
|
||||||
@@ -46,7 +52,7 @@ from rowsandall_app.settings import (
|
|||||||
SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
|
SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
|
||||||
)
|
)
|
||||||
|
|
||||||
from utils import (
|
from rowers.utils import (
|
||||||
NoTokenError, custom_exception_handler, ewmovingaverage,
|
NoTokenError, custom_exception_handler, ewmovingaverage,
|
||||||
geo_distance,isprorower,uniqify
|
geo_distance,isprorower,uniqify
|
||||||
)
|
)
|
||||||
@@ -103,7 +109,6 @@ def imports_open(user,oauth_data):
|
|||||||
oauth_data,
|
oauth_data,
|
||||||
)
|
)
|
||||||
elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename:
|
elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename:
|
||||||
print 'noot'
|
|
||||||
token = imports_token_refresh(
|
token = imports_token_refresh(
|
||||||
user,
|
user,
|
||||||
tokenname,
|
tokenname,
|
||||||
@@ -275,7 +280,7 @@ def imports_make_authorization_url(oauth_data):
|
|||||||
|
|
||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
url = oauth_data['authorizaton_uri']+urllib.urlencode(params)
|
url = oauth_data['authorizaton_uri']+urllib.parse.urlencode(params)
|
||||||
|
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|||||||
+290
-98
@@ -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
|
import colorsys
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
Workout, User, Rower, WorkoutForm,RowerForm,
|
Workout, User, Rower, WorkoutForm,RowerForm,
|
||||||
@@ -15,19 +20,19 @@ from bokeh.palettes import Dark2_8 as palette
|
|||||||
import itertools
|
import itertools
|
||||||
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
||||||
from bokeh.models import CustomJS,Slider, TextInput,BoxAnnotation
|
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.resources import CDN,INLINE
|
||||||
from bokeh.embed import components
|
from bokeh.embed import components
|
||||||
from bokeh.layouts import layout,widgetbox
|
from bokeh.layouts import layout,widgetbox
|
||||||
from bokeh.layouts import row as layoutrow
|
from bokeh.layouts import row as layoutrow
|
||||||
from bokeh.layouts import column as layoutcolumn
|
from bokeh.layouts import column as layoutcolumn
|
||||||
from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool
|
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 (
|
from bokeh.models import (
|
||||||
GMapPlot, GMapOptions, ColumnDataSource, Circle,
|
GMapPlot, GMapOptions, ColumnDataSource, Circle,
|
||||||
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
|
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool,
|
||||||
SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool,
|
SaveTool, # ResizeTool,
|
||||||
|
ResetTool, TapTool,CrosshairTool,BoxZoomTool,
|
||||||
Span, Label
|
Span, Label
|
||||||
)
|
)
|
||||||
from bokeh.models.glyphs import ImageURL
|
from bokeh.models.glyphs import ImageURL
|
||||||
@@ -38,7 +43,7 @@ from bokeh.core.properties import value
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from courses import (
|
from rowers.courses import (
|
||||||
course_coord_center,course_coord_maxmin,
|
course_coord_center,course_coord_maxmin,
|
||||||
polygon_coord_center
|
polygon_coord_center
|
||||||
)
|
)
|
||||||
@@ -49,6 +54,8 @@ import datetime
|
|||||||
import math
|
import math
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
import holoviews as hv
|
||||||
|
from holoviews import opts
|
||||||
from pytz import timezone as tz,utc
|
from pytz import timezone as tz,utc
|
||||||
from django.utils.timezone import get_current_timezone
|
from django.utils.timezone import get_current_timezone
|
||||||
from django.utils.timezone import activate
|
from django.utils.timezone import activate
|
||||||
@@ -62,7 +69,7 @@ from scipy.signal import savgol_filter
|
|||||||
from scipy.interpolate import griddata
|
from scipy.interpolate import griddata
|
||||||
|
|
||||||
|
|
||||||
import stravastuff
|
import rowers.stravastuff as stravastuff
|
||||||
|
|
||||||
from rowers.dataprep import rdata
|
from rowers.dataprep import rdata
|
||||||
import rowers.dataprep as dataprep
|
import rowers.dataprep as dataprep
|
||||||
@@ -70,21 +77,10 @@ import rowers.metrics as metrics
|
|||||||
|
|
||||||
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima
|
from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima
|
||||||
|
|
||||||
from utils import lbstoN
|
from rowers.utils import lbstoN
|
||||||
from datautils import p0
|
from rowers.datautils import p0
|
||||||
import datautils
|
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(),
|
def errorbar(fig, x, y, source=ColumnDataSource(),
|
||||||
xerr=False, yerr=False, color='black',
|
xerr=False, yerr=False, color='black',
|
||||||
@@ -173,16 +169,31 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
|||||||
if datadf.empty:
|
if datadf.empty:
|
||||||
return '','It looks like there are no data matching your filter'
|
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',
|
hover = HoverTool(tooltips=tooltips)
|
||||||
legend=False,
|
|
||||||
title=axlabels[fieldname]+' '+extratitle,
|
TOOLS = [hover]
|
||||||
outliers=False,
|
|
||||||
tools=TOOLS,
|
|
||||||
toolbar_location="above",
|
hv.extension('bokeh')
|
||||||
toolbar_sticky=False,
|
|
||||||
x_mapper_type='datetime',plot_width=920)
|
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])
|
yrange1 = Range1d(start=yaxminima[fieldname],end=yaxmaxima[fieldname])
|
||||||
plot.y_range = yrange1
|
plot.y_range = yrange1
|
||||||
@@ -192,22 +203,6 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
|||||||
plot.yaxis.axis_label = axlabels[fieldname]
|
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(
|
plot.xaxis.formatter = DatetimeTickFormatter(
|
||||||
days=["%d %B %Y"],
|
days=["%d %B %Y"],
|
||||||
months=["%d %B %Y"],
|
months=["%d %B %Y"],
|
||||||
@@ -223,20 +218,13 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
|||||||
|
|
||||||
plot.xaxis.major_label_orientation = pi/4
|
plot.xaxis.major_label_orientation = pi/4
|
||||||
|
|
||||||
hover = plot.select(dict(type=HoverTool))
|
plot.plot_width=920
|
||||||
|
plot.plot_height=600
|
||||||
hover.tooltips = OrderedDict([
|
|
||||||
('Value','@y'),
|
|
||||||
('Date','@x'),
|
|
||||||
])
|
|
||||||
|
|
||||||
hover.mode = 'mouse'
|
|
||||||
|
|
||||||
script, div = components(plot)
|
script, div = components(plot)
|
||||||
|
|
||||||
return script,div
|
return script,div
|
||||||
|
|
||||||
|
|
||||||
def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
||||||
|
|
||||||
dates = []
|
dates = []
|
||||||
@@ -249,6 +237,7 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
|||||||
seen = ['seen']
|
seen = ['seen']
|
||||||
idseen = []
|
idseen = []
|
||||||
|
|
||||||
|
|
||||||
for w in workouts:
|
for w in workouts:
|
||||||
aantal=1
|
aantal=1
|
||||||
initials = w.user.user.first_name[0:aantal]+w.user.user.last_name[0:aantal]
|
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'))
|
dates_sorting.append(d.strftime('%Y/%m/%d'))
|
||||||
durations.append(0)
|
durations.append(0)
|
||||||
types.append('rower')
|
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)
|
d += datetime.timedelta(days=1)
|
||||||
|
|
||||||
|
|
||||||
@@ -310,45 +306,71 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
|||||||
|
|
||||||
df.sort_values('date_sorting',inplace=True)
|
df.sort_values('date_sorting',inplace=True)
|
||||||
|
|
||||||
|
hv.extension('bokeh')
|
||||||
|
|
||||||
p = Bar(df,values='duration',
|
if stack == 'type':
|
||||||
label = CatAttr(columns=['date'], sort=False),
|
table = hv.Table(df,[('date','Date'),('type','Workout Type')],[('duration','Minutes')])
|
||||||
xlabel='Date',
|
else:
|
||||||
ylabel='Time',
|
table = hv.Table(df,[('date','Date'),('rower','Rower')],[('duration','Minutes')])
|
||||||
title='Activity {d1} to {d2}'.format(
|
|
||||||
|
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"),
|
d1 = startdate.strftime("%Y-%m-%d"),
|
||||||
d2 = enddate.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:
|
# p = hv.Bars(df,values='duration',
|
||||||
new_items = []
|
# label = CatAttr(columns=['date'], sort=False),
|
||||||
for legend_item in legend.items:
|
# xlabel='Date',
|
||||||
it = legend_item.label['value']
|
# ylabel='Time',
|
||||||
tot = df[df[stack]==it].duration.sum()
|
# title='Activity {d1} to {d2}'.format(
|
||||||
if tot != 0:
|
# d1 = startdate.strftime("%Y-%m-%d"),
|
||||||
new_items.append(legend_item)
|
# d2 = enddate.strftime("%Y-%m-%d"),
|
||||||
legend.items = new_items
|
# ),
|
||||||
|
# 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 = '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)
|
|
||||||
|
|
||||||
|
script,div = components(p)
|
||||||
return script,div
|
return script,div
|
||||||
|
|
||||||
def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
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]
|
ids = [int(w.id) for w in theworkouts]
|
||||||
|
|
||||||
@@ -438,6 +460,17 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False):
|
|||||||
toolbar_sticky=False)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
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",
|
plot = Figure(tools=TOOLS,toolbar_location="above",
|
||||||
toolbar_sticky=False,width=900,
|
toolbar_sticky=False,width=900,
|
||||||
x_axis_type='datetime')
|
x_axis_type='datetime')
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
|
|
||||||
@@ -805,7 +849,7 @@ def fitnessmetric_chart(fitnessmetrics,user,workoutmode='rower'):
|
|||||||
return [script,div]
|
return [script,div]
|
||||||
|
|
||||||
def interactive_histoall(theworkouts):
|
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]
|
ids = [int(w.id) for w in theworkouts]
|
||||||
|
|
||||||
@@ -834,6 +878,17 @@ def interactive_histoall(theworkouts):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
|
|
||||||
@@ -890,7 +945,12 @@ def interactive_histoall(theworkouts):
|
|||||||
axis_label="Cumulative % of strokes"),'right')
|
axis_label="Cumulative % of strokes"),'right')
|
||||||
|
|
||||||
plot.sizing_mode = 'scale_width'
|
plot.sizing_mode = 'scale_width'
|
||||||
|
try:
|
||||||
script, div = components(plot)
|
script, div = components(plot)
|
||||||
|
except ValueError:
|
||||||
|
script = ''
|
||||||
|
div = ''
|
||||||
|
|
||||||
return [script,div]
|
return [script,div]
|
||||||
|
|
||||||
def course_map(course):
|
def course_map(course):
|
||||||
@@ -1484,7 +1544,7 @@ def interactive_agegroupcpchart(age,normalized=False):
|
|||||||
x_axis_type = 'log'
|
x_axis_type = 'log'
|
||||||
y_axis_type = 'linear'
|
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,
|
plot = Figure(plot_width=900,x_axis_type=x_axis_type,
|
||||||
tools=TOOLS)
|
tools=TOOLS)
|
||||||
@@ -1531,7 +1591,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""):
|
|||||||
powerdf = powerdf[~(powerdf == 0).any(axis=1)]
|
powerdf = powerdf[~(powerdf == 0).any(axis=1)]
|
||||||
# plot tools
|
# plot tools
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
@@ -1578,6 +1638,17 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""):
|
|||||||
toolbar_sticky=False)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
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 = Figure(tools=TOOLS,plot_width=900)
|
||||||
plot.sizing_mode='scale_width'
|
plot.sizing_mode='scale_width'
|
||||||
@@ -1699,7 +1770,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
|||||||
message = 0
|
message = 0
|
||||||
# plot tools
|
# plot tools
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
@@ -1867,6 +1938,17 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower,
|
|||||||
toolbar_sticky=False)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
plot.sizing_mode = 'scale_width'
|
||||||
|
|
||||||
@@ -2033,7 +2115,7 @@ def interactive_windchart(id=0,promember=0):
|
|||||||
|
|
||||||
# plot tools
|
# plot tools
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
||||||
|
|
||||||
@@ -2103,7 +2185,7 @@ def interactive_streamchart(id=0,promember=0):
|
|||||||
|
|
||||||
# plot tools
|
# plot tools
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
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 = {}):
|
def interactive_chart(id=0,promember=0,intervaldata = {}):
|
||||||
# Add hover to this comma-separated string and see what changes
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
@@ -2174,6 +2256,17 @@ def interactive_chart(id=0,promember=0,intervaldata = {}):
|
|||||||
tools=TOOLS)
|
tools=TOOLS)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_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':
|
if groupby != 'date':
|
||||||
hover = HoverTool(names=['data'],
|
hover = HoverTool(names=['data'],
|
||||||
@@ -2358,7 +2451,7 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='',
|
|||||||
|
|
||||||
hover.mode = 'mouse'
|
hover.mode = 'mouse'
|
||||||
TOOLS = [SaveTool(),PanTool(),BoxZoomTool(),WheelZoomTool(),
|
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,
|
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)
|
toolbar_sticky=False,plot_width=920)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_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
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
||||||
|
|
||||||
@@ -2596,6 +2700,17 @@ def interactive_cum_flex_chart2(theworkouts,promember=0,
|
|||||||
toolbar_sticky=False)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
plot.sizing_mode = 'scale_width'
|
||||||
@@ -2826,6 +2941,19 @@ def interactive_flex_chart2(id=0,promember=0,
|
|||||||
plottype='line',
|
plottype='line',
|
||||||
workstrokesonly=False):
|
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)
|
#rowdata,row = dataprep.getrowdata_db(id=id)
|
||||||
columns = [xparam,yparam1,yparam2,
|
columns = [xparam,yparam1,yparam2,
|
||||||
'ftime','distance','fpace',
|
'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
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
@@ -3015,6 +3143,17 @@ def interactive_flex_chart2(id=0,promember=0,
|
|||||||
|
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
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
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
||||||
|
|
||||||
@@ -3626,6 +3765,17 @@ def interactive_bar_chart(id=0,promember=0):
|
|||||||
tools=TOOLS)
|
tools=TOOLS)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
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
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
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)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
plot.sizing_mode = 'scale_width'
|
||||||
@@ -3816,7 +3977,12 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
|
|||||||
cntr = 0
|
cntr = 0
|
||||||
l1 = []
|
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()
|
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']
|
spm2 = rowdata2.loc[:,'spm']
|
||||||
|
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
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)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
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
|
# Add hover to this comma-separated string and see what changes
|
||||||
if (promember==1):
|
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:
|
else:
|
||||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair'
|
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)
|
toolbar_sticky=False)
|
||||||
|
|
||||||
# add watermark
|
# 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_y_ranges = {"watermark": watermarkrange}
|
||||||
plot.extra_x_ranges = {"watermark": watermarkrange}
|
plot.extra_x_ranges = {"watermark": watermarkrange}
|
||||||
plot.sizing_mode = 'scale_width'
|
plot.sizing_mode = 'scale_width'
|
||||||
@@ -4226,7 +4414,11 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0):
|
|||||||
|
|
||||||
hover.mode = 'mouse'
|
hover.mode = 'mouse'
|
||||||
|
|
||||||
|
try:
|
||||||
script, div = components(plot)
|
script, div = components(plot)
|
||||||
|
except:
|
||||||
|
script = ''
|
||||||
|
div = ''
|
||||||
|
|
||||||
return [script,div]
|
return [script,div]
|
||||||
|
|
||||||
|
|||||||
+8
-3
@@ -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
|
from __future__ import absolute_import
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import time
|
import time
|
||||||
@@ -72,7 +77,7 @@ def longtask2(aantal,jobid=None,debug=False,secret=''):
|
|||||||
counter = 0
|
counter = 0
|
||||||
progress = int(100.*i/aantal)
|
progress = int(100.*i/aantal)
|
||||||
if debug:
|
if debug:
|
||||||
print progress
|
print(progress)
|
||||||
if jobid != None:
|
if jobid != None:
|
||||||
if debug:
|
if debug:
|
||||||
url = SITE_URL_DEV
|
url = SITE_URL_DEV
|
||||||
@@ -83,8 +88,8 @@ def longtask2(aantal,jobid=None,debug=False,secret=''):
|
|||||||
post_data = {"secret":secret}
|
post_data = {"secret":secret}
|
||||||
s = requests.post(url, data=post_data)
|
s = requests.post(url, data=post_data)
|
||||||
if debug:
|
if debug:
|
||||||
print url
|
print(url)
|
||||||
print s
|
print(s)
|
||||||
|
|
||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|||||||
@@ -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
|
||||||
""" Processes emails sent to workouts@rowsandall.com """
|
""" Processes emails sent to workouts@rowsandall.com """
|
||||||
import shutil
|
import shutil
|
||||||
@@ -92,7 +97,7 @@ def make_new_workout_from_email(rower, datafile, name, cntr=0,testing=False):
|
|||||||
fileformat = fileformat[2]
|
fileformat = fileformat[2]
|
||||||
|
|
||||||
if testing:
|
if testing:
|
||||||
print 'Fileformat = ',fileformat
|
print('Fileformat = ',fileformat)
|
||||||
|
|
||||||
if fileformat == 'unknown':
|
if fileformat == 'unknown':
|
||||||
# extension = datafilename[-4:].lower()
|
# extension = datafilename[-4:].lower()
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
#!/srv/venv/bin/python
|
#!/srv/venv/bin/python
|
||||||
|
|
||||||
""" Process emails """
|
""" Process emails """
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
|
PY3K = sys.version_info >= (3, 0)
|
||||||
|
|
||||||
import zipfile
|
import zipfile
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
from time import strftime
|
from time import strftime
|
||||||
|
|
||||||
|
import io
|
||||||
|
|
||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django_mailbox.models import Message, MessageAttachment,Mailbox
|
from django_mailbox.models import Message, MessageAttachment,Mailbox
|
||||||
from django.core.urlresolvers import reverse
|
from django.core.urlresolvers import reverse
|
||||||
@@ -57,20 +61,20 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
|
|||||||
except AttributeError:
|
except AttributeError:
|
||||||
filename = fileobj[6:]
|
filename = fileobj[6:]
|
||||||
if testing:
|
if testing:
|
||||||
print 'Attribute Error', filename
|
print('Attribute Error', filename)
|
||||||
|
|
||||||
|
|
||||||
# test if file exists and is not empty
|
# test if file exists and is not empty
|
||||||
try:
|
try:
|
||||||
with open('media/'+filename,'r') as fop:
|
with io.open('media/'+filename,'rb') as fop:
|
||||||
line = fop.readline()
|
line = fop.readline()
|
||||||
except (IOError, UnicodeEncodeError):
|
except (IOError, UnicodeEncodeError):
|
||||||
if testing:
|
if testing:
|
||||||
print 'IOError',filename,'media/'+filename
|
print('IOError',filename,'media/'+filename)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
if testing:
|
if testing:
|
||||||
print 'Creating workout from email'
|
print('Creating workout from email')
|
||||||
|
|
||||||
# set user
|
# set user
|
||||||
if rower.user.is_staff and 'username' in uploadoptions:
|
if rower.user.is_staff and 'username' in uploadoptions:
|
||||||
@@ -102,7 +106,7 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if testing:
|
if testing:
|
||||||
print 'Workout id = {workoutid}'.format(workoutid=workoutid)
|
print('Workout id = {workoutid}'.format(workoutid=workoutid))
|
||||||
|
|
||||||
if workoutid[0]:
|
if workoutid[0]:
|
||||||
link = settings.SITE_URL+reverse(
|
link = settings.SITE_URL+reverse(
|
||||||
@@ -164,6 +168,11 @@ def get_from_address(message):
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
first_line = ''
|
first_line = ''
|
||||||
|
|
||||||
|
try:
|
||||||
|
first_line = first_line.decode('utf-8')
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
if "quiske" in first_line:
|
if "quiske" in first_line:
|
||||||
match = re.search(r'[\w\.-]+@[\w\.-]+', first_line)
|
match = re.search(r'[\w\.-]+@[\w\.-]+', first_line)
|
||||||
return match.group(0)
|
return match.group(0)
|
||||||
@@ -242,17 +251,17 @@ class Command(BaseCommand):
|
|||||||
testing=testing
|
testing=testing
|
||||||
)
|
)
|
||||||
except:
|
except:
|
||||||
print "Bad ZIP file"
|
print("Bad ZIP file")
|
||||||
print attachment.document.name
|
print(attachment.document.name)
|
||||||
else:
|
else:
|
||||||
# move attachment and make workout
|
# move attachment and make workout
|
||||||
if testing:
|
if testing:
|
||||||
try:
|
try:
|
||||||
print name
|
print(name)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
print "Unicode Error"
|
print("Unicode Error")
|
||||||
try:
|
try:
|
||||||
print attachment.document
|
print(attachment.document)
|
||||||
except UnicodeEncodeError:
|
except UnicodeEncodeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -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
|
import numpy as np
|
||||||
from models import C2WorldClassAgePerformance
|
from rowers.models import C2WorldClassAgePerformance
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from scipy import optimize
|
from scipy import optimize
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from rowers.models import Workout, PowerTimeFitnessMetric, Rower
|
from rowers.models import Workout, PowerTimeFitnessMetric, Rower
|
||||||
import datetime
|
import datetime
|
||||||
from utils import myqueue
|
from rowers.utils import myqueue
|
||||||
import django_rq
|
import django_rq
|
||||||
queue = django_rq.get_queue('default')
|
queue = django_rq.get_queue('default')
|
||||||
from rowers.tasks import handle_updatefitnessmetric,handle_sendemail_expired
|
from rowers.tasks import handle_updatefitnessmetric,handle_sendemail_expired
|
||||||
|
|||||||
+91
-70
@@ -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
|
||||||
|
from __future__ import unicode_literals, absolute_import
|
||||||
|
|
||||||
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
from django.db import models,IntegrityError
|
from django.db import models,IntegrityError
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
@@ -7,8 +13,8 @@ from django.core.exceptions import ValidationError
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.forms import ModelForm
|
from django.forms import ModelForm
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
from django.forms.widgets import SplitDateTimeWidget
|
from django.forms.widgets import SplitDateTimeWidget,SelectDateWidget
|
||||||
from django.forms.extras.widgets import SelectDateWidget
|
#from django.forms.extras.widgets import SelectDateWidget
|
||||||
from django.forms.formsets import BaseFormSet
|
from django.forms.formsets import BaseFormSet
|
||||||
from django.contrib.admin.widgets import AdminDateWidget,AdminTimeWidget,AdminSplitDateTime
|
from django.contrib.admin.widgets import AdminDateWidget,AdminTimeWidget,AdminSplitDateTime
|
||||||
from datetimewidget.widgets import DateTimeWidget
|
from datetimewidget.widgets import DateTimeWidget
|
||||||
@@ -35,7 +41,7 @@ from rowers.rows import validate_file_extension
|
|||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from timezonefinder import TimezoneFinder
|
from timezonefinder import TimezoneFinder
|
||||||
|
|
||||||
import mytypes
|
import rowers.mytypes as mytypes
|
||||||
from matplotlib import path
|
from matplotlib import path
|
||||||
|
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
@@ -108,7 +114,7 @@ class TemplateListField(models.TextField):
|
|||||||
def get_db_prep_value(self, value, connection, prepared=False):
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
if not value: return
|
if not value: return
|
||||||
assert(isinstance(value, list) or isinstance(value, tuple))
|
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):
|
def value_to_string(self, obj):
|
||||||
value = self._get_val_from_obj(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):
|
def get_db_prep_value(self, value, connection, prepared=False):
|
||||||
if not value: return
|
if not value: return
|
||||||
assert(isinstance(value, list) or isinstance(value, tuple))
|
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):
|
def value_to_string(self, obj):
|
||||||
value = self._get_val_from_obj(obj)
|
value = self._get_val_from_obj(obj)
|
||||||
@@ -216,7 +222,7 @@ def update_records(url=c2url,verbose=True):
|
|||||||
)
|
)
|
||||||
try:
|
try:
|
||||||
if verbose:
|
if verbose:
|
||||||
print record
|
print(record)
|
||||||
record.save()
|
record.save()
|
||||||
except:
|
except:
|
||||||
if verbose:
|
if verbose:
|
||||||
@@ -261,7 +267,7 @@ class PowerTimeFitnessMetric(models.Model):
|
|||||||
|
|
||||||
date = models.DateField(default=current_day)
|
date = models.DateField(default=current_day)
|
||||||
last_workout = models.IntegerField(default=0)
|
last_workout = models.IntegerField(default=0)
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User,on_delete=models.CASCADE)
|
||||||
PowerFourMin = models.FloatField(default=0)
|
PowerFourMin = models.FloatField(default=0)
|
||||||
PowerTwoK = models.FloatField(default=0)
|
PowerTwoK = models.FloatField(default=0)
|
||||||
PowerOneHour = models.FloatField(default=0)
|
PowerOneHour = models.FloatField(default=0)
|
||||||
@@ -270,6 +276,7 @@ class PowerTimeFitnessMetric(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'powertimefitnessmetric'
|
db_table = 'powertimefitnessmetric'
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class C2WorldClassAgePerformance(models.Model):
|
class C2WorldClassAgePerformance(models.Model):
|
||||||
weightcategories = (
|
weightcategories = (
|
||||||
('hwt','heavy-weight'),
|
('hwt','heavy-weight'),
|
||||||
@@ -300,7 +307,7 @@ class C2WorldClassAgePerformance(models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ('age','sex','weightcategory','distance')
|
unique_together = ('age','sex','weightcategory','distance')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
thestring = '{s} {w} {n} age {a} ({season}) {distance}m {duration} seconds'.format(
|
thestring = '{s} {w} {n} age {a} ({season}) {distance}m {duration} seconds'.format(
|
||||||
s = self.sex,
|
s = self.sex,
|
||||||
w = self.weightcategory,
|
w = self.weightcategory,
|
||||||
@@ -321,6 +328,7 @@ def is_not_basic(user):
|
|||||||
|
|
||||||
|
|
||||||
# For future Team functionality
|
# For future Team functionality
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Team(models.Model):
|
class Team(models.Model):
|
||||||
choices = (
|
choices = (
|
||||||
('private','private'),
|
('private','private'),
|
||||||
@@ -334,14 +342,14 @@ class Team(models.Model):
|
|||||||
|
|
||||||
name = models.CharField(max_length=150,unique=True,verbose_name='Team Name')
|
name = models.CharField(max_length=150,unique=True,verbose_name='Team Name')
|
||||||
notes = models.CharField(blank=True,max_length=200,verbose_name='Team Purpose')
|
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',
|
private = models.CharField(max_length=30,choices=choices,default='open',
|
||||||
verbose_name='Team Type')
|
verbose_name='Team Type')
|
||||||
|
|
||||||
viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')
|
viewing = models.CharField(max_length=30,choices=viewchoices,default='allmembers',verbose_name='Sharing Behavior')
|
||||||
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
@@ -371,8 +379,8 @@ class TeamForm(ModelForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
class TeamInvite(models.Model):
|
class TeamInvite(models.Model):
|
||||||
team = models.ForeignKey(Team)
|
team = models.ForeignKey(Team,on_delete=models.CASCADE)
|
||||||
user = models.ForeignKey(User,null=True)
|
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
|
||||||
issuedate = models.DateField(default=current_day)
|
issuedate = models.DateField(default=current_day)
|
||||||
code = models.CharField(max_length=150,unique=True)
|
code = models.CharField(max_length=150,unique=True)
|
||||||
email = models.CharField(max_length=150,null=True,blank=True)
|
email = models.CharField(max_length=150,null=True,blank=True)
|
||||||
@@ -388,17 +396,17 @@ class TeamInviteForm(ModelForm):
|
|||||||
|
|
||||||
|
|
||||||
class TeamRequest(models.Model):
|
class TeamRequest(models.Model):
|
||||||
team = models.ForeignKey(Team)
|
team = models.ForeignKey(Team,on_delete=models.CASCADE)
|
||||||
user = models.ForeignKey(User,null=True)
|
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
|
||||||
issuedate = models.DateField(default=current_day)
|
issuedate = models.DateField(default=current_day)
|
||||||
code = models.CharField(max_length=150,unique=True)
|
code = models.CharField(max_length=150,unique=True)
|
||||||
|
|
||||||
from utils import (
|
from rowers.utils import (
|
||||||
workflowleftpanel,workflowmiddlepanel,
|
workflowleftpanel,workflowmiddlepanel,
|
||||||
defaultleft,defaultmiddle,landingpages
|
defaultleft,defaultmiddle,landingpages
|
||||||
)
|
)
|
||||||
|
|
||||||
from utils import geo_distance
|
from rowers.utils import geo_distance
|
||||||
|
|
||||||
def polygon_coord_center(polygon):
|
def polygon_coord_center(polygon):
|
||||||
|
|
||||||
@@ -606,6 +614,7 @@ paymentprocessors = (
|
|||||||
('braintree','BrainTree')
|
('braintree','BrainTree')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class PaidPlan(models.Model):
|
class PaidPlan(models.Model):
|
||||||
shortname = models.CharField(max_length=50,choices=plans)
|
shortname = models.CharField(max_length=50,choices=plans)
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
@@ -623,7 +632,7 @@ class PaidPlan(models.Model):
|
|||||||
|
|
||||||
clubsize = models.IntegerField(default=0)
|
clubsize = models.IntegerField(default=0)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return '{name} - {shortname} at {price:.2f} EURO ({paymenttype} payment)'.format(
|
return '{name} - {shortname} at {price:.2f} EURO ({paymenttype} payment)'.format(
|
||||||
name = self.name,
|
name = self.name,
|
||||||
shortname = self.shortname,
|
shortname = self.shortname,
|
||||||
@@ -632,16 +641,18 @@ class PaidPlan(models.Model):
|
|||||||
paymentprocessor = self.paymentprocessor,
|
paymentprocessor = self.paymentprocessor,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class CoachingGroup(models.Model):
|
class CoachingGroup(models.Model):
|
||||||
name = models.CharField(default='group',max_length=30,null=True,blank=True)
|
name = models.CharField(default='group',max_length=30,null=True,blank=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return 'Coaching Group {id}: {name}'.format(
|
return 'Coaching Group {id}: {name}'.format(
|
||||||
id = self.pk,
|
id = self.pk,
|
||||||
name = self.name
|
name = self.name
|
||||||
)
|
)
|
||||||
|
|
||||||
# Extension of User with rowing specific data
|
# Extension of User with rowing specific data
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Rower(models.Model):
|
class Rower(models.Model):
|
||||||
adaptivetypes = mytypes.adaptivetypes
|
adaptivetypes = mytypes.adaptivetypes
|
||||||
stravatypes = (
|
stravatypes = (
|
||||||
@@ -675,7 +686,7 @@ class Rower(models.Model):
|
|||||||
('Workout','Workout'),
|
('Workout','Workout'),
|
||||||
('Yoga','Yoga'),
|
('Yoga','Yoga'),
|
||||||
)
|
)
|
||||||
user = models.OneToOneField(User)
|
user = models.OneToOneField(User,on_delete=models.CASCADE)
|
||||||
|
|
||||||
#billing details
|
#billing details
|
||||||
country = CountryField(default=None, null=True, blank=True)
|
country = CountryField(default=None, null=True, blank=True)
|
||||||
@@ -699,7 +710,7 @@ class Rower(models.Model):
|
|||||||
null=True,blank=True,
|
null=True,blank=True,
|
||||||
default='braintree')
|
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)
|
planexpires = models.DateField(default=current_day)
|
||||||
teamplanexpires = models.DateField(default=current_day)
|
teamplanexpires = models.DateField(default=current_day)
|
||||||
@@ -840,7 +851,7 @@ class Rower(models.Model):
|
|||||||
|
|
||||||
# Friends/Team
|
# Friends/Team
|
||||||
friends = models.ManyToManyField("self",blank=True)
|
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')
|
coachinggroups = models.ManyToManyField(CoachingGroup,related_name='coaches')
|
||||||
privacy = models.CharField(default='visible',max_length=30,
|
privacy = models.CharField(default='visible',max_length=30,
|
||||||
choices=privacychoices)
|
choices=privacychoices)
|
||||||
@@ -859,9 +870,6 @@ class Rower(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.user.first_name+' '+self.user.last_name
|
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):
|
def clean_email(self):
|
||||||
return self.user.email.lower()
|
return self.user.email.lower()
|
||||||
|
|
||||||
@@ -881,15 +889,15 @@ class DeleteUserForm(forms.ModelForm):
|
|||||||
|
|
||||||
# requestor is user
|
# requestor is user
|
||||||
class CoachRequest(models.Model):
|
class CoachRequest(models.Model):
|
||||||
coach = models.ForeignKey(Rower)
|
coach = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
||||||
user = models.ForeignKey(User,null=True)
|
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
|
||||||
issuedate = models.DateField(default=current_day)
|
issuedate = models.DateField(default=current_day)
|
||||||
code = models.CharField(max_length=150,unique=True)
|
code = models.CharField(max_length=150,unique=True)
|
||||||
|
|
||||||
# requestor is coach
|
# requestor is coach
|
||||||
class CoachOffer(models.Model):
|
class CoachOffer(models.Model):
|
||||||
coach = models.ForeignKey(Rower)
|
coach = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
||||||
user = models.ForeignKey(User,null=True)
|
user = models.ForeignKey(User,null=True,on_delete=models.CASCADE)
|
||||||
issuedate = models.DateField(default=current_day)
|
issuedate = models.DateField(default=current_day)
|
||||||
code = models.CharField(max_length=150,unique=True)
|
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")
|
reststrokes = models.BooleanField(default=True,verbose_name="Incl. Rest")
|
||||||
notes = models.CharField(max_length=300,verbose_name='Chart Notes',
|
notes = models.CharField(max_length=300,verbose_name='Chart Notes',
|
||||||
default='Flex Chart Notes',blank=True)
|
default='Flex Chart Notes',blank=True)
|
||||||
user = models.ForeignKey(Rower)
|
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
|
||||||
class FavoriteForm(ModelForm):
|
class FavoriteForm(ModelForm):
|
||||||
@@ -1049,7 +1057,7 @@ def checkviewworkouts(user,rower):
|
|||||||
if rower == r:
|
if rower == r:
|
||||||
return True
|
return True
|
||||||
teams = Team.objects.filter(manager=user)
|
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):
|
if rower in Rower.objects.filter(team__in=teams):
|
||||||
return True
|
return True
|
||||||
except Rower.DoesNotExist:
|
except Rower.DoesNotExist:
|
||||||
@@ -1095,13 +1103,14 @@ timezones = (
|
|||||||
|
|
||||||
# models related to geo data (points, polygon, courses)
|
# models related to geo data (points, polygon, courses)
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GeoCourse(models.Model):
|
class GeoCourse(models.Model):
|
||||||
manager = models.ForeignKey(Rower)
|
manager = models.ForeignKey(Rower,null=True,on_delete=models.SET_NULL)
|
||||||
distance = models.IntegerField(default=0)
|
distance = models.IntegerField(default=0)
|
||||||
name = models.CharField(max_length=150,blank=True)
|
name = models.CharField(max_length=150,blank=True)
|
||||||
country = 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')
|
notes = models.CharField(blank=True,max_length=200,verbose_name='Course Notes')
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
name = self.name
|
name = self.name
|
||||||
country = self.country
|
country = self.country
|
||||||
d = self.distance
|
d = self.distance
|
||||||
@@ -1125,12 +1134,13 @@ class GeoCourseEditForm(ModelForm):
|
|||||||
'notes': forms.Textarea,
|
'notes': forms.Textarea,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GeoPolygon(models.Model):
|
class GeoPolygon(models.Model):
|
||||||
name = models.CharField(max_length=150,blank=True)
|
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)
|
order_in_course = models.IntegerField(default=0)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
name = self.name
|
name = self.name
|
||||||
coursename = self.course.name
|
coursename = self.course.name
|
||||||
|
|
||||||
@@ -1146,7 +1156,7 @@ class GeoPolygon(models.Model):
|
|||||||
class GeoPoint(models.Model):
|
class GeoPoint(models.Model):
|
||||||
latitude = models.FloatField(default=0)
|
latitude = models.FloatField(default=0)
|
||||||
longitude = 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)
|
order_in_poly = models.IntegerField(default=0)
|
||||||
|
|
||||||
# need error checking to "insert" new point into existing polygon? This affects order_in_poly
|
# 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):
|
class TrainingTarget(models.Model):
|
||||||
rowers = models.ManyToManyField(Rower, related_name='targetathletes',
|
rowers = models.ManyToManyField(Rower, related_name='targetathletes',
|
||||||
verbose_name='Athletes')
|
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)
|
name = models.CharField(max_length=150,blank=True)
|
||||||
date = models.DateField(
|
date = models.DateField(
|
||||||
default=half_year_from_now)
|
default=half_year_from_now)
|
||||||
notes = models.TextField(max_length=300,blank=True)
|
notes = models.TextField(max_length=300,blank=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
date = self.date
|
date = self.date
|
||||||
name = self.name
|
name = self.name
|
||||||
id = self.pk
|
id = self.pk
|
||||||
@@ -1217,7 +1227,7 @@ class TrainingTargetForm(ModelForm):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class TrainingPlan(models.Model):
|
class TrainingPlan(models.Model):
|
||||||
|
|
||||||
statuschoices = (
|
statuschoices = (
|
||||||
@@ -1227,15 +1237,15 @@ class TrainingPlan(models.Model):
|
|||||||
|
|
||||||
rowers = models.ManyToManyField(Rower,related_name='planathletes',
|
rowers = models.ManyToManyField(Rower,related_name='planathletes',
|
||||||
verbose_name='Athletes')
|
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)
|
name = models.CharField(max_length=150,blank=True)
|
||||||
status = models.BooleanField(default=True,verbose_name='Active')
|
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)
|
startdate = models.DateField(default=current_day)
|
||||||
enddate = models.DateField(
|
enddate = models.DateField(
|
||||||
default=half_year_from_now)
|
default=half_year_from_now)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
name = self.name
|
name = self.name
|
||||||
startdate = self.startdate
|
startdate = self.startdate
|
||||||
enddate = self.enddate
|
enddate = self.enddate
|
||||||
@@ -1599,8 +1609,9 @@ def macrocyclecheckdates(plan):
|
|||||||
pass
|
pass
|
||||||
cycles = cycles[1:]
|
cycles = cycles[1:]
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class TrainingMacroCycle(models.Model):
|
class TrainingMacroCycle(models.Model):
|
||||||
plan = models.ForeignKey(TrainingPlan)
|
plan = models.ForeignKey(TrainingPlan,on_delete=models.CASCADE)
|
||||||
name = models.CharField(max_length=150,blank=True)
|
name = models.CharField(max_length=150,blank=True)
|
||||||
startdate = models.DateField(default=current_day)
|
startdate = models.DateField(default=current_day)
|
||||||
enddate = models.DateField(
|
enddate = models.DateField(
|
||||||
@@ -1621,7 +1632,7 @@ class TrainingMacroCycle(models.Model):
|
|||||||
actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore')
|
actualrscore = models.IntegerField(default=0,verbose_name='Actual rScore')
|
||||||
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
|
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
stri = 'Macro Cycle - {n} ({sd} - {ed})'.format(
|
stri = 'Macro Cycle - {n} ({sd} - {ed})'.format(
|
||||||
n = self.name,
|
n = self.name,
|
||||||
sd = self.startdate,
|
sd = self.startdate,
|
||||||
@@ -1687,8 +1698,9 @@ class TrainingMacroCycleForm(ModelForm):
|
|||||||
'enddate': AdminDateWidget()
|
'enddate': AdminDateWidget()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class TrainingMesoCycle(models.Model):
|
class TrainingMesoCycle(models.Model):
|
||||||
plan = models.ForeignKey(TrainingMacroCycle)
|
plan = models.ForeignKey(TrainingMacroCycle,on_delete=models.CASCADE)
|
||||||
name = models.CharField(max_length=150,blank=True)
|
name = models.CharField(max_length=150,blank=True)
|
||||||
startdate = models.DateField(default=current_day)
|
startdate = models.DateField(default=current_day)
|
||||||
enddate = models.DateField(
|
enddate = models.DateField(
|
||||||
@@ -1709,7 +1721,7 @@ class TrainingMesoCycle(models.Model):
|
|||||||
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
|
actualtrimp = models.IntegerField(default=0,verbose_name='Actual TRIMP')
|
||||||
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
stri = 'Meso Cycle - {n} ({sd} - {ed})'.format(
|
stri = 'Meso Cycle - {n} ({sd} - {ed})'.format(
|
||||||
n = self.name,
|
n = self.name,
|
||||||
sd = self.startdate,
|
sd = self.startdate,
|
||||||
@@ -1763,8 +1775,9 @@ class TrainingMesoCycle(models.Model):
|
|||||||
createmicrofillers(self)
|
createmicrofillers(self)
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class TrainingMicroCycle(models.Model):
|
class TrainingMicroCycle(models.Model):
|
||||||
plan = models.ForeignKey(TrainingMesoCycle)
|
plan = models.ForeignKey(TrainingMesoCycle,on_delete=models.CASCADE)
|
||||||
name = models.CharField(max_length=150,blank=True)
|
name = models.CharField(max_length=150,blank=True)
|
||||||
startdate = models.DateField(default=current_day)
|
startdate = models.DateField(default=current_day)
|
||||||
enddate = models.DateField(
|
enddate = models.DateField(
|
||||||
@@ -1787,7 +1800,7 @@ class TrainingMicroCycle(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
stri = 'Micro Cycle - {n} ({sd} - {ed})'.format(
|
stri = 'Micro Cycle - {n} ({sd} - {ed})'.format(
|
||||||
n = self.name,
|
n = self.name,
|
||||||
sd = self.startdate,
|
sd = self.startdate,
|
||||||
@@ -1858,6 +1871,7 @@ regularsessiontypechoices = (
|
|||||||
)
|
)
|
||||||
|
|
||||||
# model for Planned Session (Workout, Challenge, Test)
|
# model for Planned Session (Workout, Challenge, Test)
|
||||||
|
@python_2_unicode_compatible
|
||||||
class PlannedSession(models.Model):
|
class PlannedSession(models.Model):
|
||||||
|
|
||||||
sessiontypechoices = (
|
sessiontypechoices = (
|
||||||
@@ -1903,9 +1917,9 @@ class PlannedSession(models.Model):
|
|||||||
('None',None),
|
('None',None),
|
||||||
)
|
)
|
||||||
|
|
||||||
manager = models.ForeignKey(User)
|
manager = models.ForeignKey(User,on_delete=models.PROTECT)
|
||||||
course = models.ForeignKey(GeoCourse,blank=True,null=True,
|
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,
|
name = models.CharField(max_length=150,blank=True,
|
||||||
verbose_name='Name')
|
verbose_name='Name')
|
||||||
@@ -1960,7 +1974,7 @@ class PlannedSession(models.Model):
|
|||||||
|
|
||||||
hasranking = models.BooleanField(default=False)
|
hasranking = models.BooleanField(default=False)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
|
|
||||||
name = self.name
|
name = self.name
|
||||||
startdate = self.startdate
|
startdate = self.startdate
|
||||||
@@ -2036,6 +2050,7 @@ registerchoices = (
|
|||||||
('manual','Manual - select below'),
|
('manual','Manual - select below'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
class VirtualRace(PlannedSession):
|
class VirtualRace(PlannedSession):
|
||||||
# has_registration = models.BooleanField(default=False)
|
# has_registration = models.BooleanField(default=False)
|
||||||
registration_form = models.CharField(
|
registration_form = models.CharField(
|
||||||
@@ -2065,7 +2080,7 @@ class VirtualRace(PlannedSession):
|
|||||||
contact_email = models.EmailField(max_length=254,
|
contact_email = models.EmailField(max_length=254,
|
||||||
validators=[validate_email],blank=True)
|
validators=[validate_email],blank=True)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
|
|
||||||
name = self.name
|
name = self.name
|
||||||
startdate = self.startdate
|
startdate = self.startdate
|
||||||
@@ -2111,7 +2126,7 @@ class VirtualRace(PlannedSession):
|
|||||||
class RaceLogo(models.Model):
|
class RaceLogo(models.Model):
|
||||||
filename = models.CharField(default='',max_length=150)
|
filename = models.CharField(default='',max_length=150)
|
||||||
creationdatetime = models.DateTimeField()
|
creationdatetime = models.DateTimeField()
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User,on_delete=models.PROTECT)
|
||||||
width = models.IntegerField(default=1200)
|
width = models.IntegerField(default=1200)
|
||||||
height = models.IntegerField(default=600)
|
height = models.IntegerField(default=600)
|
||||||
race = models.ManyToManyField(VirtualRace,related_name='logos')
|
race = models.ManyToManyField(VirtualRace,related_name='logos')
|
||||||
@@ -2121,7 +2136,7 @@ class RaceLogo(models.Model):
|
|||||||
|
|
||||||
def delete(self, *args, **kwargs):
|
def delete(self, *args, **kwargs):
|
||||||
os.remove(self.filename)
|
os.remove(self.filename)
|
||||||
print 'file deleted'
|
print('file deleted')
|
||||||
super(RaceLogo,self).delete(*args, **kwargs)
|
super(RaceLogo,self).delete(*args, **kwargs)
|
||||||
|
|
||||||
# Date input utility
|
# Date input utility
|
||||||
@@ -2486,16 +2501,17 @@ class PlannedSessionFormSmall(ModelForm):
|
|||||||
boattypes = mytypes.boattypes
|
boattypes = mytypes.boattypes
|
||||||
|
|
||||||
# Workout
|
# Workout
|
||||||
|
@python_2_unicode_compatible
|
||||||
class Workout(models.Model):
|
class Workout(models.Model):
|
||||||
workouttypes = mytypes.workouttypes
|
workouttypes = mytypes.workouttypes
|
||||||
workoutsources = mytypes.workoutsources
|
workoutsources = mytypes.workoutsources
|
||||||
privacychoices = mytypes.privacychoices
|
privacychoices = mytypes.privacychoices
|
||||||
adaptivetypes = mytypes.adaptivetypes
|
adaptivetypes = mytypes.adaptivetypes
|
||||||
|
|
||||||
user = models.ForeignKey(Rower)
|
user = models.ForeignKey(Rower,on_delete=models.CASCADE)
|
||||||
team = models.ManyToManyField(Team,blank=True)
|
team = models.ManyToManyField(Team,blank=True)
|
||||||
plannedsession = models.ForeignKey(PlannedSession, blank=True,null=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)
|
name = models.CharField(max_length=150,blank=True,null=True)
|
||||||
date = models.DateField()
|
date = models.DateField()
|
||||||
workouttype = models.CharField(choices=workouttypes,max_length=50,
|
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')
|
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
|
||||||
duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout')
|
duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
|
|
||||||
date = self.date
|
date = self.date
|
||||||
name = self.name
|
name = self.name
|
||||||
@@ -2649,11 +2665,12 @@ def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
|
|||||||
try:
|
try:
|
||||||
result = conn.execute(query)
|
result = conn.execute(query)
|
||||||
except:
|
except:
|
||||||
print "Database Locked"
|
print("Database Locked")
|
||||||
conn.close()
|
conn.close()
|
||||||
engine.dispose()
|
engine.dispose()
|
||||||
|
|
||||||
# Virtual Race results (for keeping results when workouts are deleted)
|
# Virtual Race results (for keeping results when workouts are deleted)
|
||||||
|
@python_2_unicode_compatible
|
||||||
class VirtualRaceResult(models.Model):
|
class VirtualRaceResult(models.Model):
|
||||||
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otwtypes)
|
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otwtypes)
|
||||||
userid = models.IntegerField(default=0)
|
userid = models.IntegerField(default=0)
|
||||||
@@ -2667,7 +2684,7 @@ class VirtualRaceResult(models.Model):
|
|||||||
adaptiveclass = models.CharField(default="None",max_length=50,
|
adaptiveclass = models.CharField(default="None",max_length=50,
|
||||||
choices=mytypes.adaptivetypes,
|
choices=mytypes.adaptivetypes,
|
||||||
verbose_name="Adaptive Class")
|
verbose_name="Adaptive Class")
|
||||||
race = models.ForeignKey(VirtualRace)
|
race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE)
|
||||||
duration = models.TimeField(default=datetime.time(1,0))
|
duration = models.TimeField(default=datetime.time(1,0))
|
||||||
distance = models.IntegerField(default=0)
|
distance = models.IntegerField(default=0)
|
||||||
boatclass = models.CharField(choices=boatclasses,
|
boatclass = models.CharField(choices=boatclasses,
|
||||||
@@ -2688,7 +2705,7 @@ class VirtualRaceResult(models.Model):
|
|||||||
emailnotifications = models.BooleanField(default=True,
|
emailnotifications = models.BooleanField(default=True,
|
||||||
verbose_name = 'Receive race notifications by email')
|
verbose_name = 'Receive race notifications by email')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
rr = Rower.objects.get(id=self.userid)
|
rr = Rower.objects.get(id=self.userid)
|
||||||
name = '{u1} {u2}'.format(
|
name = '{u1} {u2}'.format(
|
||||||
u1 = rr.user.first_name,
|
u1 = rr.user.first_name,
|
||||||
@@ -2713,6 +2730,7 @@ class VirtualRaceResult(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Virtual Race results (for keeping results when workouts are deleted)
|
# Virtual Race results (for keeping results when workouts are deleted)
|
||||||
|
@python_2_unicode_compatible
|
||||||
class IndoorVirtualRaceResult(models.Model):
|
class IndoorVirtualRaceResult(models.Model):
|
||||||
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otetypes)
|
boatclasses = (type for type in mytypes.workouttypes if type[0] in mytypes.otetypes)
|
||||||
userid = models.IntegerField(default=0) # ID of rower object
|
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,
|
adaptiveclass = models.CharField(default="None",max_length=50,
|
||||||
choices=mytypes.adaptivetypes,
|
choices=mytypes.adaptivetypes,
|
||||||
verbose_name="Adaptive Class")
|
verbose_name="Adaptive Class")
|
||||||
race = models.ForeignKey(VirtualRace)
|
race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE)
|
||||||
duration = models.TimeField(default=datetime.time(1,0))
|
duration = models.TimeField(default=datetime.time(1,0))
|
||||||
distance = models.IntegerField(default=0)
|
distance = models.IntegerField(default=0)
|
||||||
boatclass = models.CharField(choices=boatclasses,
|
boatclass = models.CharField(choices=boatclasses,
|
||||||
@@ -2743,7 +2761,7 @@ class IndoorVirtualRaceResult(models.Model):
|
|||||||
emailnotifications = models.BooleanField(default=True,
|
emailnotifications = models.BooleanField(default=True,
|
||||||
verbose_name = 'Receive race notifications by email')
|
verbose_name = 'Receive race notifications by email')
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
rr = Rower.objects.get(id=self.userid)
|
rr = Rower.objects.get(id=self.userid)
|
||||||
name = '{u1} {u2}'.format(
|
name = '{u1} {u2}'.format(
|
||||||
u1 = rr.user.first_name,
|
u1 = rr.user.first_name,
|
||||||
@@ -2769,7 +2787,7 @@ class IndoorVirtualRaceResult(models.Model):
|
|||||||
class CourseTestResult(models.Model):
|
class CourseTestResult(models.Model):
|
||||||
userid = models.IntegerField(default=0)
|
userid = models.IntegerField(default=0)
|
||||||
workoutid = models.IntegerField(null=True)
|
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))
|
duration = models.TimeField(default=datetime.time(1,0))
|
||||||
distance = models.IntegerField(default=0)
|
distance = models.IntegerField(default=0)
|
||||||
coursecompleted = models.BooleanField(default=False)
|
coursecompleted = models.BooleanField(default=False)
|
||||||
@@ -2900,10 +2918,11 @@ class ergcpdata(models.Model):
|
|||||||
app_label = 'rowers'
|
app_label = 'rowers'
|
||||||
|
|
||||||
# A wrapper around the png files
|
# A wrapper around the png files
|
||||||
|
@python_2_unicode_compatible
|
||||||
class GraphImage(models.Model):
|
class GraphImage(models.Model):
|
||||||
filename = models.CharField(default='',max_length=150,blank=True,null=True)
|
filename = models.CharField(default='',max_length=150,blank=True,null=True)
|
||||||
creationdatetime = models.DateTimeField()
|
creationdatetime = models.DateTimeField()
|
||||||
workout = models.ForeignKey(Workout)
|
workout = models.ForeignKey(Workout,on_delete=models.CASCADE)
|
||||||
width = models.IntegerField(default=1200)
|
width = models.IntegerField(default=1200)
|
||||||
height = models.IntegerField(default=600)
|
height = models.IntegerField(default=600)
|
||||||
|
|
||||||
@@ -2920,7 +2939,7 @@ def auto_delete_image_on_delete(sender,instance, **kwargs):
|
|||||||
if len(others) == 0:
|
if len(others) == 0:
|
||||||
os.remove(instance.filename)
|
os.remove(instance.filename)
|
||||||
else:
|
else:
|
||||||
print "couldn't find the file "+instance.filename
|
print("couldn't find the file "+instance.filename)
|
||||||
|
|
||||||
|
|
||||||
# Form to update Workout data
|
# Form to update Workout data
|
||||||
@@ -3445,15 +3464,16 @@ class SiteAnnouncement(models.Model):
|
|||||||
return super(SiteAnnouncement,self).save(*args, **kwargs)
|
return super(SiteAnnouncement,self).save(*args, **kwargs)
|
||||||
|
|
||||||
# A comment by a user on a training
|
# A comment by a user on a training
|
||||||
|
@python_2_unicode_compatible
|
||||||
class WorkoutComment(models.Model):
|
class WorkoutComment(models.Model):
|
||||||
comment = models.TextField(max_length=300)
|
comment = models.TextField(max_length=300)
|
||||||
created = models.DateTimeField(default=timezone.now)
|
created = models.DateTimeField(default=timezone.now)
|
||||||
read = models.BooleanField(default=False)
|
read = models.BooleanField(default=False)
|
||||||
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
|
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User,on_delete=models.PROTECT)
|
||||||
workout = models.ForeignKey(Workout)
|
workout = models.ForeignKey(Workout,on_delete=models.CASCADE)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return u'Comment to: {w} by {u1} {u2}'.format(
|
return u'Comment to: {w} by {u1} {u2}'.format(
|
||||||
w=self.workout,
|
w=self.workout,
|
||||||
u1 = self.user.first_name,
|
u1 = self.user.first_name,
|
||||||
@@ -3470,15 +3490,16 @@ class WorkoutCommentForm(ModelForm):
|
|||||||
}
|
}
|
||||||
|
|
||||||
# A comment by a user on a training
|
# A comment by a user on a training
|
||||||
|
@python_2_unicode_compatible
|
||||||
class PlannedSessionComment(models.Model):
|
class PlannedSessionComment(models.Model):
|
||||||
comment = models.TextField(max_length=300)
|
comment = models.TextField(max_length=300)
|
||||||
created = models.DateTimeField(default=timezone.now)
|
created = models.DateTimeField(default=timezone.now)
|
||||||
read = models.BooleanField(default=False)
|
read = models.BooleanField(default=False)
|
||||||
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
|
notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications")
|
||||||
user = models.ForeignKey(User)
|
user = models.ForeignKey(User,on_delete=models.PROTECT)
|
||||||
plannedsession = models.ForeignKey(PlannedSession)
|
plannedsession = models.ForeignKey(PlannedSession,on_delete=models.CASCADE)
|
||||||
|
|
||||||
def __unicode__(self):
|
def __str__(self):
|
||||||
return u'Comment to: {w} by {u1} {u2}'.format(
|
return u'Comment to: {w} by {u1} {u2}'.format(
|
||||||
w=self.workout,
|
w=self.workout,
|
||||||
u1 = self.user.first_name,
|
u1 = self.user.first_name,
|
||||||
|
|||||||
+11
-5
@@ -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 = (
|
workouttypes = (
|
||||||
('water','Standard Racing Shell'),
|
('water','Standard Racing Shell'),
|
||||||
('rower','Indoor Rower'),
|
('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 = (
|
otwtypes = (
|
||||||
'water',
|
'water',
|
||||||
|
|||||||
@@ -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 struct
|
||||||
import base64
|
import base64
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
# Interactions with Rowsandall.com API. Not fully complete.
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
@@ -15,7 +20,7 @@ import math
|
|||||||
from math import sin,cos,atan2,sqrt
|
from math import sin,cos,atan2,sqrt
|
||||||
|
|
||||||
import urllib
|
import urllib
|
||||||
import c2stuff
|
import rowers.c2stuff as c2stuff
|
||||||
|
|
||||||
# Django
|
# Django
|
||||||
from django.shortcuts import render_to_response
|
from django.shortcuts import render_to_response
|
||||||
@@ -123,7 +128,7 @@ def make_authorization_url(request):
|
|||||||
|
|
||||||
|
|
||||||
import urllib
|
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)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
from rowers.models import Rower,PaidPlan
|
||||||
|
|
||||||
# run once - copies plans to paypal
|
# run once - copies plans to paypal
|
||||||
|
|||||||
@@ -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)
|
# Defines permissions for objects (API related)
|
||||||
|
|
||||||
from rest_framework import permissions
|
from rest_framework import permissions
|
||||||
|
|||||||
@@ -1,3 +1,8 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
@@ -10,7 +15,7 @@ import uuid
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import pytz
|
import pytz
|
||||||
from dateutil import parser
|
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 re
|
||||||
import django_rq
|
import django_rq
|
||||||
queue = django_rq.get_queue('default')
|
queue = django_rq.get_queue('default')
|
||||||
@@ -30,10 +35,10 @@ from rowers.emails import htmlstrip,htmlstripnobr
|
|||||||
|
|
||||||
import rowers.mytypes as mytypes
|
import rowers.mytypes as mytypes
|
||||||
|
|
||||||
import metrics
|
import rowers.metrics as metrics
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import dataprep
|
import rowers.dataprep as dataprep
|
||||||
import courses
|
import rowers.courses as courses
|
||||||
import iso8601
|
import iso8601
|
||||||
from iso8601 import ParseError
|
from iso8601 import ParseError
|
||||||
from rowers.tasks import handle_check_race_course
|
from rowers.tasks import handle_check_race_course
|
||||||
@@ -360,7 +365,7 @@ def is_session_complete_ws(ws,ps):
|
|||||||
return ratio,'partial',completiondate
|
return ratio,'partial',completiondate
|
||||||
else:
|
else:
|
||||||
thevalue = 0
|
thevalue = 0
|
||||||
for key,value in cratios.iteritems():
|
for key,value in cratios.items():
|
||||||
if ratio>value and value>thevalue:
|
if ratio>value and value>thevalue:
|
||||||
verdict = key
|
verdict = key
|
||||||
thevalue = value
|
thevalue = value
|
||||||
|
|||||||
+6
-1
@@ -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
|
from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter
|
||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
|
|
||||||
import numpy as np
|
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
|
# Formatting the distance tick marks
|
||||||
|
|||||||
+19
-9
@@ -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
|
# All the functionality needed to connect to Strava
|
||||||
|
|
||||||
# Python
|
# Python
|
||||||
@@ -33,8 +39,8 @@ from rowingdata import rowingdata
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
from rowers.models import Rower,Workout
|
from rowers.models import Rower,Workout
|
||||||
from rowers.models import checkworkoutuser
|
from rowers.models import checkworkoutuser
|
||||||
import dataprep
|
import rowers.dataprep as dataprep
|
||||||
from dataprep import columndict
|
from rowers.dataprep import columndict
|
||||||
|
|
||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
@@ -51,8 +57,8 @@ from rowsandall_app.settings import (
|
|||||||
baseurl = 'https://polaraccesslink.com/v3'
|
baseurl = 'https://polaraccesslink.com/v3'
|
||||||
|
|
||||||
|
|
||||||
from utils import NoTokenError, custom_exception_handler
|
from rowers.utils import NoTokenError, custom_exception_handler
|
||||||
import mytypes
|
import rowers.mytypes as mytypes
|
||||||
|
|
||||||
# Exchange access code for long-lived access token
|
# Exchange access code for long-lived access token
|
||||||
def get_token(code):
|
def get_token(code):
|
||||||
@@ -67,7 +73,10 @@ def get_token(code):
|
|||||||
secret=POLAR_CLIENT_SECRET
|
secret=POLAR_CLIENT_SECRET
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
|
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",
|
response = requests.post("https://polarremote.com/v2/oauth2/token",
|
||||||
data=post_data,
|
data=post_data,
|
||||||
@@ -97,7 +106,7 @@ def make_authorization_url():
|
|||||||
"redirect_uri": POLAR_REDIRECT_URI,
|
"redirect_uri": POLAR_REDIRECT_URI,
|
||||||
"scope":"write"}
|
"scope":"write"}
|
||||||
import urllib
|
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)
|
return HttpResponseRedirect(url)
|
||||||
@@ -110,7 +119,10 @@ def get_polar_notifications():
|
|||||||
secret=POLAR_CLIENT_SECRET
|
secret=POLAR_CLIENT_SECRET
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
|
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)
|
response = requests.get(url, headers=headers)
|
||||||
|
|
||||||
@@ -126,7 +138,7 @@ from rowers.utils import isprorower
|
|||||||
def get_all_new_workouts(available_data,testing=False):
|
def get_all_new_workouts(available_data,testing=False):
|
||||||
for record in available_data:
|
for record in available_data:
|
||||||
if testing:
|
if testing:
|
||||||
print record
|
print(record)
|
||||||
if record['data-type'] == 'EXERCISE':
|
if record['data-type'] == 'EXERCISE':
|
||||||
try:
|
try:
|
||||||
r = Rower.objects.get(polaruserid=record['user-id'])
|
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):
|
if r.polar_auto_import and isprorower(r):
|
||||||
exercise_list = get_polar_workouts(u)
|
exercise_list = get_polar_workouts(u)
|
||||||
if testing:
|
if testing:
|
||||||
print exercise_list
|
print(exercise_list)
|
||||||
except Rower.DoesNotExist:
|
except Rower.DoesNotExist:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@@ -313,8 +325,6 @@ def get_polar_workout(user,id,transactionid):
|
|||||||
response = requests.get(url,headers = headers2)
|
response = requests.get(url,headers = headers2)
|
||||||
|
|
||||||
if response.status_code == 200:
|
if response.status_code == 200:
|
||||||
print response.text
|
|
||||||
|
|
||||||
result = response.text
|
result = response.text
|
||||||
# commit transaction
|
# commit transaction
|
||||||
response = requests.put(url,headers=headers)
|
response = requests.put(url,headers=headers)
|
||||||
|
|||||||
@@ -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 time
|
||||||
import gzip
|
import gzip
|
||||||
import shutil
|
import shutil
|
||||||
|
|||||||
@@ -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
|
# All the functionality needed to connect to Runkeeper
|
||||||
from rowers.imports import *
|
from rowers.imports import *
|
||||||
import re
|
import re
|
||||||
@@ -24,6 +29,8 @@ oauth_data = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
import numpy
|
||||||
|
|
||||||
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
|
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
|
||||||
t = []
|
t = []
|
||||||
lat = []
|
lat = []
|
||||||
@@ -257,6 +264,10 @@ def get_userid(access_token):
|
|||||||
|
|
||||||
return str(res)
|
return str(res)
|
||||||
|
|
||||||
|
def default(o):
|
||||||
|
if isinstance(o, numpy.int64): return int(o)
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
def workout_runkeeper_upload(user,w):
|
def workout_runkeeper_upload(user,w):
|
||||||
message = "Uploading to Runkeeper"
|
message = "Uploading to Runkeeper"
|
||||||
rkid = 0
|
rkid = 0
|
||||||
@@ -282,7 +293,7 @@ def workout_runkeeper_upload(user,w):
|
|||||||
'Content-Length':'nnn'}
|
'Content-Length':'nnn'}
|
||||||
|
|
||||||
url = "https://api.runkeeper.com/fitnessActivities"
|
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
|
# check for duplicate error first
|
||||||
if (response.status_code == 409 ):
|
if (response.status_code == 409 ):
|
||||||
|
|||||||
@@ -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
|
# Serializers. Defines which fields from an object get to the JSON object
|
||||||
# Also optionally define POST, PATCH methods (create, update)
|
# Also optionally define POST, PATCH methods (create, update)
|
||||||
|
|
||||||
@@ -140,7 +145,6 @@ class StrokeDataSerializer(serializers.Serializer):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# do something
|
# do something
|
||||||
print "fake serializer"
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
# All the functionality to connect to SportTracks
|
||||||
|
|
||||||
|
import numpy
|
||||||
|
|
||||||
from rowers.imports import *
|
from rowers.imports import *
|
||||||
import re
|
import re
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
@@ -9,7 +17,7 @@ from rowsandall_app.settings import (
|
|||||||
SPORTTRACKS_REDIRECT_URI
|
SPORTTRACKS_REDIRECT_URI
|
||||||
)
|
)
|
||||||
|
|
||||||
import mytypes
|
import rowers.mytypes as mytypes
|
||||||
|
|
||||||
oauth_data = {
|
oauth_data = {
|
||||||
'client_id': SPORTTRACKS_CLIENT_ID,
|
'client_id': SPORTTRACKS_CLIENT_ID,
|
||||||
@@ -234,6 +242,11 @@ def getidfromresponse(response):
|
|||||||
|
|
||||||
return int(id)
|
return int(id)
|
||||||
|
|
||||||
|
def default(o):
|
||||||
|
if isinstance(o, numpy.int64): return int(o)
|
||||||
|
raise TypeError
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def workout_sporttracks_upload(user,w):
|
def workout_sporttracks_upload(user,w):
|
||||||
message = "Uploading to SportTracks"
|
message = "Uploading to SportTracks"
|
||||||
@@ -256,7 +269,7 @@ def workout_sporttracks_upload(user,w):
|
|||||||
'Content-Type': 'application/json'}
|
'Content-Type': 'application/json'}
|
||||||
|
|
||||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.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
|
# check for duplicate error first
|
||||||
if (response.status_code == 409 ):
|
if (response.status_code == 409 ):
|
||||||
|
|||||||
+10
-4
@@ -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
|
# All the functionality needed to connect to Strava
|
||||||
from scipy import optimize
|
from scipy import optimize
|
||||||
from scipy.signal import savgol_filter
|
from scipy.signal import savgol_filter
|
||||||
@@ -10,15 +16,15 @@ queue = django_rq.get_queue('default')
|
|||||||
queuelow = django_rq.get_queue('low')
|
queuelow = django_rq.get_queue('low')
|
||||||
queuehigh = django_rq.get_queue('low')
|
queuehigh = django_rq.get_queue('low')
|
||||||
|
|
||||||
from dataprep import columndict
|
from rowers.dataprep import columndict
|
||||||
|
|
||||||
import stravalib
|
import stravalib
|
||||||
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
|
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
|
||||||
|
|
||||||
from iso8601 import ParseError
|
from iso8601 import ParseError
|
||||||
from utils import myqueue
|
from rowers.utils import myqueue
|
||||||
|
|
||||||
import mytypes
|
import rowers.mytypes as mytypes
|
||||||
import gzip
|
import gzip
|
||||||
|
|
||||||
from rowsandall_app.settings import (
|
from rowsandall_app.settings import (
|
||||||
@@ -259,7 +265,7 @@ def create_async_workout(alldata,user,stravaid,debug=False):
|
|||||||
|
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
from utils import get_strava_stream
|
from rowers.utils import get_strava_stream
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+25
-14
@@ -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) """
|
""" Background tasks done by Celery (develop) or QR (production) """
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
@@ -16,7 +21,10 @@ from rowingdata import rowingdata as rdata
|
|||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
from sqlalchemy import create_engine
|
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 datetime
|
||||||
import pytz
|
import pytz
|
||||||
import iso8601
|
import iso8601
|
||||||
@@ -39,10 +47,11 @@ from django_rq import job
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.html import strip_tags
|
from django.utils.html import strip_tags
|
||||||
|
|
||||||
from utils import deserialize_list,ewmovingaverage,wavg
|
from rowers.utils import deserialize_list,ewmovingaverage,wavg
|
||||||
from emails import htmlstrip
|
from rowers.emails import htmlstrip
|
||||||
|
|
||||||
from HTMLParser import HTMLParser
|
#from HTMLParser import HTMLParser
|
||||||
|
from html.parser import HTMLParser
|
||||||
class MLStripper(HTMLParser):
|
class MLStripper(HTMLParser):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.reset()
|
self.reset()
|
||||||
@@ -80,13 +89,13 @@ from django.db.utils import OperationalError
|
|||||||
from jinja2 import Template,Environment,FileSystemLoader
|
from jinja2 import Template,Environment,FileSystemLoader
|
||||||
env = Environment(loader = FileSystemLoader(["rowers/templates"]))
|
env = Environment(loader = FileSystemLoader(["rowers/templates"]))
|
||||||
|
|
||||||
import datautils
|
import rowers.datautils as datautils
|
||||||
import utils
|
import rowers.utils as utils
|
||||||
import requests
|
import requests
|
||||||
import longtask
|
import rowers.longtask as longtask
|
||||||
import arrow
|
import arrow
|
||||||
|
|
||||||
from utils import get_strava_stream
|
from rowers.utils import get_strava_stream
|
||||||
|
|
||||||
siteurl = SITE_URL
|
siteurl = SITE_URL
|
||||||
|
|
||||||
@@ -128,7 +137,7 @@ def handle_c2_import_stroke_data(c2token,
|
|||||||
|
|
||||||
return 1
|
return 1
|
||||||
else:
|
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)
|
s = requests.get(url,headers=headers)
|
||||||
|
|
||||||
@@ -1238,21 +1247,21 @@ def handle_zip_file(emailfrom, subject, file,**kwargs):
|
|||||||
debug = False
|
debug = False
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print message
|
print(message)
|
||||||
|
|
||||||
email = EmailMessage(subject, message,
|
email = EmailMessage(subject, message,
|
||||||
emailfrom,
|
emailfrom,
|
||||||
['workouts@rowsandall.com'])
|
['workouts@rowsandall.com'])
|
||||||
email.attach_file(file)
|
email.attach_file(file)
|
||||||
if debug:
|
if debug:
|
||||||
print "attaching"
|
print("attaching")
|
||||||
|
|
||||||
|
|
||||||
res = email.send()
|
res = email.send()
|
||||||
|
|
||||||
|
|
||||||
if debug:
|
if debug:
|
||||||
print "sent"
|
print("sent")
|
||||||
time.sleep(60)
|
time.sleep(60)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
@@ -1490,7 +1499,6 @@ def handle_updateergcp(rower_id,workoutfilenames,debug=False,**kwargs):
|
|||||||
rowdata = rdata(f1 + '.gz')
|
rowdata = rdata(f1 + '.gz')
|
||||||
except IOError:
|
except IOError:
|
||||||
rowdata = 0
|
rowdata = 0
|
||||||
|
|
||||||
if rowdata != 0:
|
if rowdata != 0:
|
||||||
therows.append(rowdata)
|
therows.append(rowdata)
|
||||||
|
|
||||||
@@ -1637,7 +1645,7 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
|
|||||||
hran = hrdata['hran']
|
hran = hrdata['hran']
|
||||||
ftp = hrdata['ftp']
|
ftp = hrdata['ftp']
|
||||||
powerzones = deserialize_list(hrdata['powerzones'])
|
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,
|
rr = rowingdata.rower(hrmax=hrmax, hrut2=hrut2,
|
||||||
hrut1=hrut1, hrat=hrat,
|
hrut1=hrut1, hrat=hrat,
|
||||||
@@ -1649,7 +1657,10 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
|
|||||||
except IOError:
|
except IOError:
|
||||||
row = rdata(f2 + '.gz', rower=rr)
|
row = rdata(f2 + '.gz', rower=rr)
|
||||||
|
|
||||||
|
try:
|
||||||
haspower = row.df[' Power (watts)'].mean() > 50
|
haspower = row.df[' Power (watts)'].mean() > 50
|
||||||
|
except TypeError:
|
||||||
|
haspower = True
|
||||||
|
|
||||||
nr_rows = len(row.df)
|
nr_rows = len(row.df)
|
||||||
if (plotnr in [1, 2, 4, 5, 8, 11, 9, 12]) and (nr_rows > 1200):
|
if (plotnr in [1, 2, 4, 5, 8, 11, 9, 12]) and (nr_rows > 1200):
|
||||||
|
|||||||
@@ -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 os
|
||||||
import sys
|
import sys
|
||||||
import django
|
import django
|
||||||
|
|||||||
+5
-1
@@ -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
|
# All the Team related methods
|
||||||
|
|
||||||
@@ -10,7 +14,7 @@ from django.db import IntegrityError
|
|||||||
import uuid
|
import uuid
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from utils import myqueue
|
from rowers.utils import myqueue
|
||||||
|
|
||||||
import django_rq
|
import django_rq
|
||||||
queue = django_rq.get_queue('default')
|
queue = django_rq.get_queue('default')
|
||||||
|
|||||||
-106
@@ -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,})
|
|
||||||
@@ -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 %}
|
|
||||||
@@ -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 %}
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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">
|
|
||||||
|
|
||||||
</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> </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> </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> </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> </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> </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/">© 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>
|
|
||||||
@@ -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> </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> </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> </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> </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> </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> </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> </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/">© 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>
|
|
||||||
@@ -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 %}
|
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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> </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 %}
|
|
||||||
@@ -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 %}
|
|
||||||
@@ -58,18 +58,13 @@
|
|||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<div id="id_css_res">
|
<div id="id_css_res">
|
||||||
<link rel="stylesheet" href="/static/css/bokeh-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="/static/css/bokeh-widgets-0.12.3.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>
|
||||||
<div id="id_js_res">
|
<div id="id_js_res">
|
||||||
<script
|
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||||
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
|
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||||
</script>
|
|
||||||
<script
|
|
||||||
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -60,16 +60,12 @@
|
|||||||
|
|
||||||
|
|
||||||
<div id="id_css_res">
|
<div id="id_css_res">
|
||||||
<link rel="stylesheet" href="/static/css/bokeh-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="/static/css/bokeh-widgets-0.12.3.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>
|
||||||
<div id="id_js_res">
|
<div id="id_js_res">
|
||||||
<script
|
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||||
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
|
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||||
</script>
|
|
||||||
<script
|
|
||||||
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@
|
|||||||
});
|
});
|
||||||
</script>
|
</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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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> </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 %}
|
|
||||||
@@ -11,8 +11,8 @@
|
|||||||
{{ js_res | safe }}
|
{{ js_res | safe }}
|
||||||
{{ css_res| safe }}
|
{{ css_res| safe }}
|
||||||
|
|
||||||
<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 type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
{{ js_res | safe }}
|
{{ js_res | safe }}
|
||||||
{{ css_res| safe }}
|
{{ css_res| safe }}
|
||||||
|
|
||||||
<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 type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -60,17 +60,12 @@
|
|||||||
|
|
||||||
|
|
||||||
<div id="id_css_res">
|
<div id="id_css_res">
|
||||||
<link rel="stylesheet" href="/static/css/bokeh-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="/static/css/bokeh-widgets-0.12.3.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>
|
||||||
<div id="id_js_res">
|
<div id="id_js_res">
|
||||||
<script
|
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||||
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
|
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||||
</script>
|
|
||||||
<script
|
|
||||||
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
|
|
||||||
<ul class="main-content">
|
<ul class="main-content">
|
||||||
<li class="grid_2" style="min-height:200px;">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -138,7 +138,7 @@
|
|||||||
<div id="advancedplots" class="grid_6 omega">
|
<div id="advancedplots" class="grid_6 omega">
|
||||||
<div class="grid_6 alpha">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
{% block main %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<img src="/static/img/rivercurrent.jpg" width="400">
|
<img src="/static/img/rivercurrent.jpg" width="400">
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -62,7 +62,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -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> </p>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<div id="theplot" class="grid_12 alpha">
|
|
||||||
|
|
||||||
|
|
||||||
{{ the_div|safe }}
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %}
|
{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %}
|
||||||
|
|
||||||
{% block meta %}
|
{% 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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -86,7 +86,7 @@
|
|||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ $('#id_workouttype').change();
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% if mapdiv %}
|
{% if mapdiv %}
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li class="grid_2">
|
<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">
|
<script async="true" type="text/javascript">
|
||||||
Bokeh.set_log_level("info");
|
Bokeh.set_log_level("info");
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ from rowers.opaque import encoder
|
|||||||
|
|
||||||
import arrow
|
import arrow
|
||||||
|
|
||||||
|
from six import string_types
|
||||||
|
|
||||||
def strfdelta(tdelta):
|
def strfdelta(tdelta):
|
||||||
minutes,seconds = divmod(tdelta.seconds,60)
|
minutes,seconds = divmod(tdelta.seconds,60)
|
||||||
@@ -87,7 +88,11 @@ def aantalcomments(workout):
|
|||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def encode(id):
|
def encode(id):
|
||||||
return str(encoder.encode_hex(id))
|
try:
|
||||||
|
result = str(encoder.encode_hex(id))
|
||||||
|
except TypeError:
|
||||||
|
result = ''
|
||||||
|
return result
|
||||||
|
|
||||||
@register.filter
|
@register.filter
|
||||||
def water(workout):
|
def water(workout):
|
||||||
@@ -220,7 +225,7 @@ def jsdict(dict,key):
|
|||||||
def lookup(dict, key):
|
def lookup(dict, key):
|
||||||
s = dict.get(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]
|
s = s[:22]
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
|||||||
+10
-5
@@ -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
|
import pytest
|
||||||
|
|
||||||
pytestmark = pytest.mark.django_db
|
pytestmark = pytest.mark.django_db
|
||||||
@@ -31,7 +36,7 @@ from rowers.utils import NoTokenError
|
|||||||
from shutil import copyfile
|
from shutil import copyfile
|
||||||
from nose.tools import assert_true
|
from nose.tools import assert_true
|
||||||
from mock import Mock, patch
|
from mock import Mock, patch
|
||||||
from minimocktest import MockTestCase
|
#from minimocktest import MockTestCase
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import rowers.c2stuff as c2stuff
|
import rowers.c2stuff as c2stuff
|
||||||
import arrow
|
import arrow
|
||||||
@@ -98,15 +103,15 @@ def mocked_sqlalchemy(*args, **kwargs):
|
|||||||
return MockEngine()
|
return MockEngine()
|
||||||
|
|
||||||
#@pytest.mark.django_db
|
#@pytest.mark.django_db
|
||||||
class DjangoTestCase(TestCase, MockTestCase):
|
class DjangoTestCase(TestCase): #, MockTestCase):
|
||||||
def _pre_setup(self):
|
def _pre_setup(self):
|
||||||
MockTestCase.setUp(self)
|
# MockTestCase.setUp(self)
|
||||||
TestCase._pre_setup(self)
|
TestCase._pre_setup(self)
|
||||||
self.client = Client()
|
self.client = Client()
|
||||||
|
|
||||||
def _post_teardown(self):
|
def _post_teardown(self):
|
||||||
TestCase._post_teardown(self)
|
TestCase._post_teardown(self)
|
||||||
MockTestCase.tearDown(self)
|
#MockTestCase.tearDown(self)
|
||||||
# delete_strokedata(1)
|
# delete_strokedata(1)
|
||||||
|
|
||||||
def mocked_tcx_parser(*args, **kwargs):
|
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='',
|
def mocked_stravaexport(f2,workoutname,stravatoken,description='',
|
||||||
activity_type='Rowing'):
|
activity_type='Rowing'):
|
||||||
print "this is mocked strava export"
|
print("this is mocked strava export")
|
||||||
return 1,'success'
|
return 1,'success'
|
||||||
|
|
||||||
def mocked_fetchcp(*args, **kwargs):
|
def mocked_fetchcp(*args, **kwargs):
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ try:
|
|||||||
except NameError:
|
except NameError:
|
||||||
WindowsError = None
|
WindowsError = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
FileNotFoundError
|
||||||
|
except NameError:
|
||||||
|
FileNotFoundError = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
OSError
|
OSError
|
||||||
except NameError:
|
except NameError:
|
||||||
@@ -44,7 +49,7 @@ from rowers.plannedsessions import get_dates_timeperiod
|
|||||||
from shutil import copyfile, copy
|
from shutil import copyfile, copy
|
||||||
from nose.tools import assert_true
|
from nose.tools import assert_true
|
||||||
from mock import Mock, patch
|
from mock import Mock, patch
|
||||||
from minimocktest import MockTestCase
|
#from minimocktest import MockTestCase
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
import rowers.c2stuff as c2stuff
|
import rowers.c2stuff as c2stuff
|
||||||
|
|
||||||
|
|||||||
@@ -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 __future__ import print_function
|
||||||
from statements import *
|
from .statements import *
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
nu = datetime.datetime.now(tz=timezone.utc)
|
nu = datetime.datetime.now(tz=timezone.utc)
|
||||||
|
|
||||||
@@ -327,7 +332,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
def tearDown(self):
|
def tearDown(self):
|
||||||
try:
|
try:
|
||||||
os.remove('rowers/tests/testdata/temp/course.kml')
|
os.remove('rowers/tests/testdata/temp/course.kml')
|
||||||
except (WindowsError, OSError, IOError):
|
except (FileNotFoundError, OSError, IOError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@@ -408,7 +413,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = IndoorVirtualRaceForm(form_data)
|
form = IndoorVirtualRaceForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -452,7 +457,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = IndoorVirtualRaceForm(form_data)
|
form = IndoorVirtualRaceForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -496,7 +501,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = VirtualRaceForm(form_data)
|
form = VirtualRaceForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -533,7 +538,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = VirtualRaceForm(form_data)
|
form = VirtualRaceForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -588,7 +593,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = IndoorVirtualRaceResultForm(form_data)
|
form = IndoorVirtualRaceResultForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -617,7 +622,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = IndoorVirtualRaceResultForm(form_data)
|
form = IndoorVirtualRaceResultForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -666,7 +671,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = VirtualRaceResultForm(form_data)
|
form = VirtualRaceResultForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
@@ -694,7 +699,7 @@ class VirtualEventViewTest(TestCase):
|
|||||||
|
|
||||||
form = VirtualRaceResultForm(form_data)
|
form = VirtualRaceResultForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data,follow=True)
|
response = self.c.post(url,form_data,follow=True)
|
||||||
|
|||||||
@@ -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 __future__ import print_function
|
||||||
from statements import *
|
from .statements import *
|
||||||
nu = datetime.datetime.now()
|
nu = datetime.datetime.now()
|
||||||
|
|
||||||
from rowers.models import User,Rower
|
from rowers.models import User,Rower
|
||||||
|
|||||||
@@ -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()
|
nu = datetime.datetime.now()
|
||||||
@@ -26,7 +31,7 @@ class WorkoutCompareTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError, OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@@ -91,7 +96,7 @@ class BoxPlotTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@@ -110,7 +115,7 @@ class BoxPlotTest(TestCase):
|
|||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multi)
|
@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_getsmallrowdata_db,
|
||||||
mocked_df):
|
mocked_df):
|
||||||
|
|
||||||
@@ -188,7 +193,7 @@ class ListWorkoutTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@@ -246,7 +251,7 @@ class PlannedSessionTests(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_ics_download(self):
|
def test_ics_download(self):
|
||||||
@@ -291,7 +296,7 @@ class ForcecurveTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect = mocked_getempowerdata_db)
|
@patch('rowers.dataprep.getsmallrowdata_db',side_effect = mocked_getempowerdata_db)
|
||||||
@@ -326,7 +331,7 @@ class CumStatsTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
|
@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:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multiflex)
|
@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:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multiflex)
|
@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:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
|
|||||||
@@ -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()
|
nu = datetime.datetime.now()
|
||||||
|
|
||||||
@@ -211,7 +216,7 @@ class WorkoutViewTest(TestCase):
|
|||||||
'userid':self.u.id,
|
'userid':self.u.id,
|
||||||
'id':encoder.encode_hex(self.werg1.id),
|
'id':encoder.encode_hex(self.werg1.id),
|
||||||
})
|
})
|
||||||
print url
|
print(url)
|
||||||
|
|
||||||
form_data = {
|
form_data = {
|
||||||
'xparam':'time',
|
'xparam':'time',
|
||||||
|
|||||||
@@ -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()
|
nu = datetime.datetime.now()
|
||||||
|
|
||||||
@@ -28,7 +33,7 @@ class SimpleViewTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_start_protrial(self):
|
def test_start_protrial(self):
|
||||||
|
|||||||
@@ -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):
|
class CoursesTest(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|||||||
@@ -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()
|
nu = datetime.datetime.now()
|
||||||
|
|
||||||
@@ -77,9 +81,9 @@ class OTWCPChartTest(TestCase):
|
|||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
except (IOError,WindowsError,OSError):
|
except (IOError,FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
except (IOError,WindowsError,OSError):
|
except (IOError,FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_cpraw)
|
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_cpraw)
|
||||||
@@ -157,7 +161,7 @@ class CPChartTest(TestCase):
|
|||||||
for workout in self.user_workouts:
|
for workout in self.user_workouts:
|
||||||
try:
|
try:
|
||||||
os.remove(workout.csvfilename)
|
os.remove(workout.csvfilename)
|
||||||
except (IOError, WindowsError,OSError):
|
except (IOError, FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def test_analytics_page(self):
|
def test_analytics_page(self):
|
||||||
@@ -250,7 +254,7 @@ class CPChartTest(TestCase):
|
|||||||
sex = r.sex,
|
sex = r.sex,
|
||||||
weightc = r.weightcategory)
|
weightc = r.weightcategory)
|
||||||
|
|
||||||
print url
|
print(url)
|
||||||
|
|
||||||
response = self.c.get(url)
|
response = self.c.get(url)
|
||||||
self.assertEqual(response.status_code,200)
|
self.assertEqual(response.status_code,200)
|
||||||
|
|||||||
@@ -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 __future__ import print_function
|
||||||
from statements import *
|
from .statements import *
|
||||||
|
|
||||||
@override_settings(TESTING=True)
|
@override_settings(TESTING=True)
|
||||||
class EmailUpload(TestCase):
|
class EmailUpload(TestCase):
|
||||||
@@ -43,7 +47,7 @@ workout run
|
|||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
except (IOError,WindowsError,OSError):
|
except (IOError,FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@@ -133,7 +137,7 @@ race 1
|
|||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
except (IOError,WindowsError,OSError):
|
except (IOError,FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@@ -194,7 +198,7 @@ race 1
|
|||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
except (IOError,WindowsError,OSError):
|
except (IOError,FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.dataprep.create_engine')
|
@patch('rowers.dataprep.create_engine')
|
||||||
@@ -210,7 +214,7 @@ race 1
|
|||||||
ws = Workout.objects.filter(name="johnsworkout")
|
ws = Workout.objects.filter(name="johnsworkout")
|
||||||
if not len(ws):
|
if not len(ws):
|
||||||
for w in Workout.objects.all():
|
for w in Workout.objects.all():
|
||||||
print w
|
print(w)
|
||||||
|
|
||||||
self.assertEqual(len(ws),1)
|
self.assertEqual(len(ws),1)
|
||||||
|
|
||||||
|
|||||||
@@ -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 __future__ import print_function
|
||||||
|
|
||||||
from statements import *
|
from .statements import *
|
||||||
|
|
||||||
|
|
||||||
class EmpowerTest(TestCase):
|
class EmpowerTest(TestCase):
|
||||||
|
|||||||
@@ -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 __future__ import print_function
|
||||||
from statements import *
|
from .statements import *
|
||||||
|
|
||||||
|
|
||||||
#@pytest.mark.django_db
|
#@pytest.mark.django_db
|
||||||
@@ -11,11 +16,12 @@ class TestErrorPages(TestCase):
|
|||||||
factory = RequestFactory()
|
factory = RequestFactory()
|
||||||
request = factory.get('/')
|
request = factory.get('/')
|
||||||
response = error404_view(request)
|
response = error404_view(request)
|
||||||
|
|
||||||
self.assertEqual(response.status_code, 404)
|
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)
|
response = error500_view(request)
|
||||||
self.assertEqual(response.status_code, 500)
|
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)
|
response = error400_view(request)
|
||||||
self.assertEqual(response.status_code, 400)
|
self.assertEqual(response.status_code, 400)
|
||||||
|
|||||||
@@ -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)
|
@override_settings(TESTING=True)
|
||||||
class WorkoutViewTest(TestCase):
|
class WorkoutViewTest(TestCase):
|
||||||
@@ -120,7 +125,7 @@ class WorkoutViewTest(TestCase):
|
|||||||
|
|
||||||
form = FlexOptionsForm(form_data)
|
form = FlexOptionsForm(form_data)
|
||||||
if not form.is_valid():
|
if not form.is_valid():
|
||||||
print form.errors
|
print(form.errors)
|
||||||
self.assertTrue(form.is_valid())
|
self.assertTrue(form.is_valid())
|
||||||
|
|
||||||
response = self.c.post(url,form_data)
|
response = self.c.post(url,form_data)
|
||||||
|
|||||||
@@ -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 __future__ import print_function
|
||||||
from statements import *
|
from .statements import *
|
||||||
nu = datetime.datetime.now()
|
nu = datetime.datetime.now()
|
||||||
|
|
||||||
|
|
||||||
@@ -791,7 +796,7 @@ boattype: 2x
|
|||||||
if not os.path.isdir(path):
|
if not os.path.isdir(path):
|
||||||
try:
|
try:
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
except (WindowsError,OSError):
|
except (FileNotFoundError,OSError):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@patch('rowers.tpstuff.requests.post', side_effect=mocked_requests)
|
@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
Reference in New Issue
Block a user