Merge branch 'release/v9.36'
This commit is contained in:
@@ -27,7 +27,6 @@ conftest.py
|
||||
# temporary test files
|
||||
/rowers/tests/testdata/temp
|
||||
/rowers/tests/testdata/testdata.csv.gz
|
||||
rowers/tests/testdata/testdata.csv.gz
|
||||
/rowers/tests/testdata/testdata.tcx
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"cells": [],
|
||||
"metadata": {},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 2
|
||||
}
|
||||
@@ -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>
|
||||
+69
-69
@@ -1,4 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# -*- Coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
@@ -18,86 +18,86 @@ class BoatCategory(models.Model):
|
||||
club = models.CharField(_("Club"),max_length=30)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("boat category")
|
||||
verbose_name_plural = _("boat categories")
|
||||
ordering = ['name']
|
||||
verbose_name = _("boat category")
|
||||
verbose_name_plural = _("boat categories")
|
||||
ordering = ['name']
|
||||
|
||||
def __str__(self):
|
||||
str = self.name
|
||||
str = self.name
|
||||
|
||||
return str
|
||||
return str
|
||||
|
||||
def __unicode__(self):
|
||||
str = self.name
|
||||
str = self.name
|
||||
|
||||
return str
|
||||
return str
|
||||
|
||||
class Member(models.Model):
|
||||
statuses = (
|
||||
("coach", _("coach")),
|
||||
("member", _("member")),
|
||||
("administrator", _("administrator")),
|
||||
)
|
||||
("coach", _("coach")),
|
||||
("member", _("member")),
|
||||
("administrator", _("administrator")),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("member")
|
||||
verbose_name_plural = _("members")
|
||||
ordering = ['user']
|
||||
verbose_name = _("member")
|
||||
verbose_name_plural = _("members")
|
||||
ordering = ['user']
|
||||
|
||||
user = models.OneToOneField(User)
|
||||
user = models.OneToOneField(User,on_delete=models.CASCADE)
|
||||
contributions = models.BooleanField(default=True)
|
||||
status = models.CharField(default="member",
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
categories = models.ManyToManyField(BoatCategory,
|
||||
verbose_name=_("Boat Categories"))
|
||||
verbose_name=_("Boat Categories"))
|
||||
club = models.CharField(_("Club"),max_length=30)
|
||||
hoursworked = models.FloatField(_("Hours Worked"))
|
||||
|
||||
def __str__(self):
|
||||
str = self.user.first_name+' '+self.user.last_name
|
||||
return str
|
||||
str = self.user.first_name+' '+self.user.last_name
|
||||
return str
|
||||
|
||||
def __unicode__(self):
|
||||
str = self.user.first_name+' '+self.user.last_name
|
||||
return str
|
||||
str = self.user.first_name+' '+self.user.last_name
|
||||
return str
|
||||
|
||||
class Boat(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _("boat")
|
||||
verbose_name_plural = _("boats")
|
||||
ordering = ['boatcode']
|
||||
verbose_name = _("boat")
|
||||
verbose_name_plural = _("boats")
|
||||
ordering = ['boatcode']
|
||||
|
||||
boatname = models.CharField(_("Boat Name"),max_length=30)
|
||||
boatcode = models.CharField(_("Boat Code"),max_length=10)
|
||||
categories = models.ManyToManyField(BoatCategory)
|
||||
nrseats = models.IntegerField(_("Nr of Seats"))
|
||||
statuses = (
|
||||
("water",_("water")),
|
||||
("hangar",_("hangar")),
|
||||
("damaged",_("damaged")),
|
||||
("races",_("races")),
|
||||
)
|
||||
("water",_("water")),
|
||||
("hangar",_("hangar")),
|
||||
("damaged",_("damaged")),
|
||||
("races",_("races")),
|
||||
)
|
||||
status = models.CharField(default="hangar",
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
|
||||
comment = models.CharField(_("Comment"),blank=True,max_length=100)
|
||||
|
||||
def __str__(self):
|
||||
str = self.boatcode+' '+self.boatname
|
||||
str = self.boatcode+' '+self.boatname
|
||||
|
||||
return str
|
||||
return str
|
||||
|
||||
def __unicode__(self):
|
||||
str = self.boatcode+' '+self.boatname
|
||||
str = self.boatcode+' '+self.boatname
|
||||
|
||||
return str
|
||||
return str
|
||||
|
||||
class MemberWork(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _("member work")
|
||||
verbose_name_plural = _("member work")
|
||||
verbose_name = _("member work")
|
||||
verbose_name_plural = _("member work")
|
||||
|
||||
date = models.DateField(_("Date"))
|
||||
hours = models.FloatField(_("Hours"))
|
||||
@@ -105,16 +105,16 @@ class MemberWork(models.Model):
|
||||
comment = models.CharField(_("Comment"),blank=True,max_length=100)
|
||||
worker = models.ManyToManyField(Member,_("Worker"))
|
||||
statuses = (
|
||||
("planned",_("planned")),
|
||||
("executed",_("executed"))
|
||||
)
|
||||
("planned",_("planned")),
|
||||
("executed",_("executed"))
|
||||
)
|
||||
status = models.CharField(default="planned",
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
class Races(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _("race")
|
||||
verbose_name_plural = _("races")
|
||||
verbose_name = _("race")
|
||||
verbose_name_plural = _("races")
|
||||
|
||||
|
||||
name = models.CharField(max_length = 30)
|
||||
@@ -124,20 +124,20 @@ class Races(models.Model):
|
||||
transportboats = models.ManyToManyField(Boat)
|
||||
|
||||
def __str__(self):
|
||||
str = self.name
|
||||
str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
str = self.name
|
||||
str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
|
||||
def __unicode__(self):
|
||||
str = self.name
|
||||
str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
str = self.name
|
||||
str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
|
||||
|
||||
class Outing(models.Model):
|
||||
class Meta:
|
||||
verbose_name = _("outing")
|
||||
verbose_name_plural = _("outings")
|
||||
verbose_name = _("outing")
|
||||
verbose_name_plural = _("outings")
|
||||
|
||||
|
||||
starttime = models.DateTimeField(verbose_name = _("Start Time"),default=timezone.now)
|
||||
@@ -145,27 +145,27 @@ class Outing(models.Model):
|
||||
distance = models.FloatField(_("Distance (km)"),default=12)
|
||||
comment = models.CharField(_("Comment"),blank=True,max_length=100)
|
||||
statuses = (
|
||||
("reservation",_("reservation")),
|
||||
("active", _("active")),
|
||||
("completed", _("completed")),
|
||||
("race", _("race")),
|
||||
)
|
||||
boat = models.ForeignKey(Boat)
|
||||
rower = models.ForeignKey(Member)
|
||||
("reservation",_("reservation")),
|
||||
("active", _("active")),
|
||||
("completed", _("completed")),
|
||||
("race", _("race")),
|
||||
)
|
||||
boat = models.ForeignKey(Boat,on_delete=models.CASCADE)
|
||||
rower = models.ForeignKey(Member,on_delete=models.CASCADE)
|
||||
race = models.ManyToManyField(Races,blank=True)
|
||||
otherrowers = models.ManyToManyField(Member,related_name="otherrowers")
|
||||
status = models.CharField(_("Status"),default="active",
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
choices=statuses,
|
||||
max_length=30)
|
||||
|
||||
|
||||
def __str__(self):
|
||||
str = self.boat.boatcode
|
||||
str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
str = self.boat.boatcode
|
||||
str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
|
||||
def __unicode__(self):
|
||||
str = self.boat.boatcode
|
||||
str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
str = self.boat.boatcode
|
||||
str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S')
|
||||
return str
|
||||
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
from celery import Celery,app
|
||||
from .celery import Celery,app
|
||||
import os
|
||||
import time
|
||||
import gc
|
||||
|
||||
+128
-185
@@ -1,221 +1,164 @@
|
||||
alabaster==0.7.7
|
||||
amqp==1.4.9
|
||||
anyjson==0.3.3
|
||||
appdirs==1.4.3
|
||||
argcomplete==1.0.0
|
||||
arrow==0.12.1
|
||||
asn1crypto==0.23.0
|
||||
astropy==1.1.2
|
||||
amqp==2.4.1
|
||||
arrow==0.13.1
|
||||
atomicwrites==1.3.0
|
||||
attrs==18.2.0
|
||||
awscli==1.14.57
|
||||
Babel==2.2.0
|
||||
backports-abc==0.4
|
||||
backports.functools-lru-cache==1.5
|
||||
backports.shutil-get-terminal-size==1.0.0
|
||||
backports.ssl-match-hostname==3.4.0.2
|
||||
beautifulsoup4==4.6.0
|
||||
billiard==3.3.0.23
|
||||
bitarray==0.8.1
|
||||
blaze==0.9.1
|
||||
bleach==2.0.0
|
||||
bokeh==0.12.3
|
||||
boto==2.48.0
|
||||
boto3==1.6.6
|
||||
botocore==1.9.10
|
||||
bottle==0.12.9
|
||||
Bottleneck==1.0.0
|
||||
braintree==3.50.0
|
||||
cairocffi==0.7.2
|
||||
celery==3.1.23
|
||||
certifi==2017.11.5
|
||||
cffi==1.11.2
|
||||
backcall==0.1.0
|
||||
beautifulsoup4==4.7.1
|
||||
billiard==3.5.0.5
|
||||
bleach==3.1.0
|
||||
bokeh==1.0.4
|
||||
braintree==3.51.0
|
||||
celery==4.2.1
|
||||
certifi==2018.11.29
|
||||
chardet==3.0.4
|
||||
chest==0.2.3
|
||||
click==6.6
|
||||
cloudpickle==0.1.1
|
||||
clyent==1.2.1
|
||||
colorama==0.3.7
|
||||
comtypes==1.1.7
|
||||
configobj==5.0.6
|
||||
coreapi==2.0.9
|
||||
cryptography==2.1.3
|
||||
Click==7.0
|
||||
colorama==0.4.1
|
||||
cookies==2.2.1
|
||||
coreapi==2.3.3
|
||||
coreschema==0.0.4
|
||||
cycler==0.10.0
|
||||
Cython==0.23.4
|
||||
cytoolz==0.7.5
|
||||
dask==0.8.1
|
||||
datashape==0.5.1
|
||||
decorator==4.0.9
|
||||
dill==0.2.4
|
||||
dask==1.1.1
|
||||
decorator==4.3.2
|
||||
defusedxml==0.5.0
|
||||
Django==1.9.5
|
||||
django-analytical==2.2.2
|
||||
django-analytics==0.0.1
|
||||
django-analytical==2.5.0
|
||||
django-async-messages==0.3.1
|
||||
django-braces==1.8.1
|
||||
django-celery==3.1.17
|
||||
django-braces==1.13.0
|
||||
django-classy-tags==0.8.0
|
||||
django-cookie-law==1.0.12
|
||||
django-cors-headers==1.1.0
|
||||
django-cors-middleware==1.3.1
|
||||
django-countries==5.3.2
|
||||
django-cookie-law==2.0.1
|
||||
django-cors-headers==2.4.0
|
||||
django-countries==5.3.3
|
||||
django-datetime-widget==0.9.3
|
||||
django-debug-toolbar==1.4
|
||||
django-durationfield==0.5.2
|
||||
django-extensions==1.7.5
|
||||
django-filter==1.0.0
|
||||
django-geckoboard==2.0.0
|
||||
django-geojson==2.10.0
|
||||
django-extensions==2.1.6
|
||||
django-htmlmin==0.10.0
|
||||
django-leaflet==0.22.0
|
||||
django-mailbox==4.6.0
|
||||
django-modelcluster==1.1
|
||||
django-leaflet==0.24.0
|
||||
django-mailbox==4.7.1
|
||||
django-oauth-toolkit==0.10.0
|
||||
django-oauth2-provider==0.2.6.1
|
||||
django-rest-swagger==2.1.0
|
||||
django-rq==0.8.0
|
||||
django-rq-dashboard==0.3.0
|
||||
django-ses==0.8.5
|
||||
django-social-share==1.1.2
|
||||
django-suit==0.2.25
|
||||
django-rest-framework==0.1.0
|
||||
django-rest-swagger==2.2.0
|
||||
django-rq==1.3.0
|
||||
django-rq-dashboard==0.3.3
|
||||
django-shell-plus==1.1.7
|
||||
django-social-share==1.3.2
|
||||
django-suit==0.2.26
|
||||
django-suit-rq==1.0.1
|
||||
django-taggit==0.18.1
|
||||
django-translation-manager==0.3.4
|
||||
django-treebeard==4.0
|
||||
django-tz-detect==0.2.8
|
||||
django-tz-detect==0.2.9
|
||||
djangorestframework==3.5.3
|
||||
docopt==0.6.2
|
||||
docutils==0.12
|
||||
enum34==1.1.2
|
||||
et-xmlfile==1.0.1
|
||||
Factory==1.2
|
||||
fastcache==1.0.2
|
||||
filemagic==1.6
|
||||
docutils==0.14
|
||||
entrypoints==0.3
|
||||
factory-boy==2.11.1
|
||||
Faker==1.0.2
|
||||
fitparse==1.0.1
|
||||
Flask==0.10.1
|
||||
Flask-Cors==2.1.2
|
||||
Flask-Login==0.3.2
|
||||
Flask-OpenID==1.2.5
|
||||
Flask-Uploads==0.2.0
|
||||
flower==0.9.1
|
||||
funcsigs==1.0.2
|
||||
functools32==3.2.3.post2
|
||||
future==0.16.0
|
||||
futures==3.0.5
|
||||
geocoder==1.37.0
|
||||
geopy==1.11.0
|
||||
gevent==1.1.0
|
||||
greenlet==0.4.9
|
||||
grin==1.2.1
|
||||
gunicorn==19.4.5
|
||||
HeapDict==1.0.0
|
||||
honcho==0.6.6
|
||||
future==0.17.1
|
||||
geocoder==1.38.1
|
||||
holoviews==1.11.2
|
||||
html5lib==1.0.1
|
||||
httplib2==0.9.2
|
||||
htmlmin==0.1.12
|
||||
HTMLParser==0.0.2
|
||||
httplib2==0.12.1
|
||||
icalendar==4.0.3
|
||||
idna==2.6
|
||||
ipaddress==1.0.14
|
||||
ipython==4.2.0
|
||||
ipython-genutils==0.1.0
|
||||
idna==2.8
|
||||
image==1.5.27
|
||||
importlib-resources==1.0.2
|
||||
ipykernel==5.1.0
|
||||
ipython==7.3.0
|
||||
ipython-genutils==0.2.0
|
||||
ipywidgets==7.4.2
|
||||
iso8601==0.1.12
|
||||
isodate==0.6.0
|
||||
itsdangerous==0.24
|
||||
itypes==1.1.0
|
||||
Jinja2==2.8
|
||||
jmespath==0.9.3
|
||||
jsonschema==2.5.1
|
||||
jedi==0.13.3
|
||||
Jinja2==2.10
|
||||
jsonschema==3.0.0
|
||||
jupyter==1.0.0
|
||||
jupyter-client==5.2.4
|
||||
jupyter-console==6.0.0
|
||||
jupyter-core==4.4.0
|
||||
kiwisolver==1.0.1
|
||||
kombu==3.0.35
|
||||
lxml==4.2.1
|
||||
Markdown==2.6.7
|
||||
MarkupSafe==0.23
|
||||
matplotlib==2.2.2
|
||||
mechanize==0.3.6
|
||||
kombu==4.3.0
|
||||
lxml==4.3.1
|
||||
Markdown==3.0.1
|
||||
MarkupSafe==1.1.1
|
||||
matplotlib==3.0.2
|
||||
MiniMockTest==0.5
|
||||
mistune==0.8.4
|
||||
mock==2.0.0
|
||||
more-itertools==5.0.0
|
||||
mpld3==0.2
|
||||
mpmath==0.19
|
||||
multipledispatch==0.4.8
|
||||
networkx==1.11
|
||||
mpld3==0.3
|
||||
nbconvert==5.4.1
|
||||
nbformat==4.4.0
|
||||
nose==1.3.7
|
||||
nose-parameterized==0.6.0
|
||||
numpy==1.14.2
|
||||
notebook==5.7.4
|
||||
numpy==1.16.1
|
||||
oauth2==1.9.0.post1
|
||||
oauthlib==1.0.3
|
||||
odo==0.4.2
|
||||
openapi-codec==1.1.7
|
||||
packaging==16.8
|
||||
pandas==0.22.0
|
||||
pathlib2==2.3.3
|
||||
pathspec==0.5.5
|
||||
openapi-codec==1.3.2
|
||||
packaging==19.0
|
||||
pandas==0.24.1
|
||||
pandocfilters==1.4.2
|
||||
param==1.8.2
|
||||
parso==0.3.4
|
||||
pathspec==0.5.9
|
||||
pbr==5.1.2
|
||||
pexpect==4.0.1
|
||||
pickleshare==0.7.2
|
||||
Pillow==3.2.0
|
||||
pluggy==0.8.1
|
||||
polib==1.0.7
|
||||
psutil==4.1.0
|
||||
ptyprocess==0.5.1
|
||||
py==1.7.0
|
||||
pyasn1==0.1.9
|
||||
pycparser==2.14
|
||||
pycrypto==2.6.1
|
||||
PyMySQL==0.7.4
|
||||
pync==1.6.1
|
||||
pyparsing==2.2.0
|
||||
pytest==4.2.0
|
||||
pexpect==4.6.0
|
||||
pickleshare==0.7.5
|
||||
Pillow==5.4.1
|
||||
pluggy==0.9.0
|
||||
prometheus-client==0.6.0
|
||||
prompt-toolkit==2.0.9
|
||||
ptyprocess==0.6.0
|
||||
py==1.8.0
|
||||
Pygments==2.3.1
|
||||
pyparsing==2.3.1
|
||||
pyrsistent==0.14.11
|
||||
pytest==4.3.0
|
||||
pytest-django==3.4.7
|
||||
pytest-runner==4.4
|
||||
pytest-sugar==0.9.2
|
||||
python-dateutil==2.7.2
|
||||
python-memcached==1.58
|
||||
python-metar==1.4.0
|
||||
python-openid==2.2.5
|
||||
python-twitter==3.2
|
||||
pytz==2018.4
|
||||
PyYAML==3.12
|
||||
pyzmq==15.2.0
|
||||
python-dateutil==2.8.0
|
||||
python-twitter==3.5
|
||||
pytz==2018.9
|
||||
pyviz-comms==0.7.0
|
||||
PyYAML==3.13
|
||||
pyzmq==18.0.0
|
||||
qtconsole==4.4.3
|
||||
ratelim==0.1.6
|
||||
redis==2.10.5
|
||||
req==1.0.0
|
||||
requests==2.12.3
|
||||
requests-oauthlib==0.7.0
|
||||
rowingdata==2.0.0
|
||||
rowingphysics==0.3.10
|
||||
rq==0.6.0
|
||||
rq-dashboard==0.3.7
|
||||
rsa==3.4.2
|
||||
s3transfer==0.1.13
|
||||
scandir==1.6
|
||||
scikit-image==0.12.3
|
||||
scikit-learn==0.17.1
|
||||
scipy==1.0.1
|
||||
seaborn==0.7.0
|
||||
Shapely==1.6.1
|
||||
shortuuid==0.4.3
|
||||
simplegeneric==0.8.1
|
||||
simplejson==3.10.0
|
||||
singledispatch==3.4.0.3
|
||||
six==1.11.0
|
||||
SQLAlchemy==1.0.12
|
||||
sqlparse==0.1.19
|
||||
-e git+git@bitbucket.org:sanderroosendaal/rowsandall.git@c9695a9f8f5ee0e459de066007a5ef4cef58255b#egg=stravalib
|
||||
subprocess32==3.2.7
|
||||
sympy==1.0
|
||||
redis==3.2.0
|
||||
requests==2.21.0
|
||||
requests-oauthlib==1.2.0
|
||||
rowingdata==2.0.6
|
||||
rowingphysics==0.5.0
|
||||
rq==0.13.0
|
||||
scipy==1.2.1
|
||||
Send2Trash==1.5.0
|
||||
shell==1.0.1
|
||||
shortuuid==0.5.0
|
||||
simplejson==3.16.0
|
||||
six==1.12.0
|
||||
soupsieve==1.8
|
||||
SQLAlchemy==1.2.18
|
||||
sqlparse==0.2.4
|
||||
stravalib==0.10.2
|
||||
termcolor==1.1.0
|
||||
timestring==1.6.2
|
||||
timezonefinder==2.1.2
|
||||
toolz==0.7.4
|
||||
tornado==4.4.2
|
||||
tqdm==4.23.0
|
||||
traitlets==4.2.1
|
||||
tzwhere==3.0.3
|
||||
Unidecode==0.4.19
|
||||
units==0.6
|
||||
terminado==0.8.1
|
||||
testpath==0.4.2
|
||||
text-unidecode==1.2
|
||||
timezonefinder==3.4.2
|
||||
tornado==5.1.1
|
||||
tqdm==4.31.1
|
||||
traitlets==4.3.2
|
||||
units==0.7
|
||||
uritemplate==3.0.0
|
||||
urllib3==1.22
|
||||
VerbalExpressions==0.0.1
|
||||
urllib3==1.24.1
|
||||
VerbalExpressions==0.0.2
|
||||
vine==1.2.0
|
||||
wcwidth==0.1.7
|
||||
webencodings==0.5.1
|
||||
Werkzeug==0.11.8
|
||||
xlrd==1.0.0
|
||||
xmltodict==0.11.0
|
||||
widgetsnbextension==3.4.2
|
||||
xmltodict==0.12.0
|
||||
yamjam==0.1.7
|
||||
yamllint==1.8.1
|
||||
yamllint==1.15.0
|
||||
|
||||
@@ -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 .tasks import app as celery_app
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
from rowers.celery import app as celery_app
|
||||
|
||||
__all__ = ('celery_app',)
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import braintree
|
||||
from django.utils import timezone
|
||||
import datetime
|
||||
|
||||
+178
-161
@@ -1,3 +1,9 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
|
||||
# The interactions with the Concept2 logbook API
|
||||
# All C2 related functions should be defined here
|
||||
# (There is still some stuff defined directly in views.py. Need to
|
||||
@@ -6,10 +12,12 @@
|
||||
from rowers.imports import *
|
||||
import datetime
|
||||
from requests import Request, Session
|
||||
import mytypes
|
||||
import rowers.mytypes as mytypes
|
||||
from rowers.mytypes import otwtypes
|
||||
from iso8601 import ParseError
|
||||
|
||||
import numpy
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET
|
||||
)
|
||||
@@ -19,7 +27,7 @@ import django_rq
|
||||
queue = django_rq.get_queue('default')
|
||||
queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('low')
|
||||
from utils import myqueue
|
||||
from rowers.utils import myqueue
|
||||
|
||||
oauth_data = {
|
||||
'client_id': C2_CLIENT_ID,
|
||||
@@ -41,19 +49,19 @@ oauth_data = {
|
||||
def c2_open(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.c2token == '') or (r.c2token is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
raise NoTokenError("User has no token")
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
raise NoTokenError("User has no token")
|
||||
else:
|
||||
if (timezone.now()>r.tokenexpirydate):
|
||||
res = rower_c2_token_refresh(user)
|
||||
if (timezone.now()>r.tokenexpirydate):
|
||||
res = rower_c2_token_refresh(user)
|
||||
if res == None:
|
||||
raise NoTokenError("User has no token")
|
||||
if res[0] != None:
|
||||
thetoken = res[0]
|
||||
else:
|
||||
raise NoTokenError("User has no token")
|
||||
else:
|
||||
thetoken = r.c2token
|
||||
else:
|
||||
thetoken = r.c2token
|
||||
|
||||
return thetoken
|
||||
|
||||
@@ -61,11 +69,11 @@ def add_stroke_data(user,c2id,workoutid,startdatetime,csvfilename,
|
||||
workouttype='rower'):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.c2token == '') or (r.c2token is None):
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
elif (timezone.now()>r.tokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
starttimeunix = arrow.get(startdatetime).timestamp
|
||||
|
||||
@@ -179,9 +187,9 @@ def makeseconds(t):
|
||||
# convert our weight class code to Concept2 weight class code
|
||||
def c2wc(weightclass):
|
||||
if (weightclass=="lwt"):
|
||||
res = "L"
|
||||
res = "L"
|
||||
else:
|
||||
res = "H"
|
||||
res = "H"
|
||||
|
||||
return res
|
||||
|
||||
@@ -343,17 +351,17 @@ def createc2workoutdata_as_splits(w):
|
||||
hr = df[' HRCur (bpm)'].astype(int)
|
||||
split_data = []
|
||||
for i in range(len(t)):
|
||||
thisrecord = {"time":t[i],"distance":d[i],"stroke_rate":spm[i],
|
||||
"heart_rate":{
|
||||
"average:":hr[i]
|
||||
}
|
||||
}
|
||||
split_data.append(thisrecord)
|
||||
thisrecord = {"time":t[i],"distance":d[i],"stroke_rate":spm[i],
|
||||
"heart_rate":{
|
||||
"average:":hr[i]
|
||||
}
|
||||
}
|
||||
split_data.append(thisrecord)
|
||||
|
||||
try:
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f")
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f")
|
||||
except ValueError:
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S")
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S")
|
||||
|
||||
try:
|
||||
newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
|
||||
@@ -365,19 +373,19 @@ def createc2workoutdata_as_splits(w):
|
||||
wtype = 'water'
|
||||
|
||||
data = {
|
||||
"type": wtype,
|
||||
"date": w.startdatetime.isoformat(),
|
||||
"distance": int(w.distance),
|
||||
"time": int(10*makeseconds(durationstr)),
|
||||
"timezone": w.timezone,
|
||||
"weight_class": c2wc(w.weightcategory),
|
||||
"comments": newnotes,
|
||||
"heart_rate": {
|
||||
"average": averagehr,
|
||||
"max": maxhr,
|
||||
},
|
||||
"splits": split_data,
|
||||
}
|
||||
"type": wtype,
|
||||
"date": w.startdatetime.isoformat(),
|
||||
"distance": int(w.distance),
|
||||
"time": int(10*makeseconds(durationstr)),
|
||||
"timezone": w.timezone,
|
||||
"weight_class": c2wc(w.weightcategory),
|
||||
"comments": newnotes,
|
||||
"heart_rate": {
|
||||
"average": averagehr,
|
||||
"max": maxhr,
|
||||
},
|
||||
"splits": split_data,
|
||||
}
|
||||
|
||||
|
||||
return data
|
||||
@@ -418,13 +426,17 @@ def createc2workoutdata(w):
|
||||
hr = 0*d
|
||||
stroke_data = []
|
||||
for i in range(len(t)):
|
||||
thisrecord = {"t":t[i],"d":d[i],"p":p[i],"spm":spm[i],"hr":hr[i]}
|
||||
stroke_data.append(thisrecord)
|
||||
thisrecord = {"t":t[i].astype(int),
|
||||
"d":d[i].astype(int),
|
||||
"p":p[i].astype(int),
|
||||
"spm":spm[i].astype(int),
|
||||
"hr":hr[i].astype(int)}
|
||||
stroke_data.append(thisrecord)
|
||||
|
||||
try:
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f")
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f")
|
||||
except ValueError:
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S")
|
||||
durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S")
|
||||
|
||||
workouttype = w.workouttype
|
||||
if workouttype in otwtypes:
|
||||
@@ -434,21 +446,21 @@ def createc2workoutdata(w):
|
||||
startdatetime = w.startdatetime.isoformat()
|
||||
except AttributeError:
|
||||
startdate = datetime.datetime.combine(w.date,datetime.time())
|
||||
|
||||
|
||||
data = {
|
||||
"type": mytypes.c2mapping[workouttype],
|
||||
"date": w.startdatetime.isoformat(),
|
||||
"timezone": w.timezone,
|
||||
"distance": int(w.distance),
|
||||
"time": int(10*makeseconds(durationstr)),
|
||||
"weight_class": c2wc(w.weightcategory),
|
||||
"comments": w.notes,
|
||||
"heart_rate": {
|
||||
"average": averagehr,
|
||||
"max": maxhr,
|
||||
},
|
||||
"stroke_data": stroke_data,
|
||||
}
|
||||
"type": mytypes.c2mapping[workouttype],
|
||||
"date": w.startdatetime.isoformat(),
|
||||
"timezone": w.timezone,
|
||||
"distance": int(w.distance),
|
||||
"time": int(10*makeseconds(durationstr)),
|
||||
"weight_class": c2wc(w.weightcategory),
|
||||
"comments": w.notes,
|
||||
"heart_rate": {
|
||||
"average": averagehr,
|
||||
"max": maxhr,
|
||||
},
|
||||
"stroke_data": stroke_data,
|
||||
}
|
||||
|
||||
|
||||
return data
|
||||
@@ -458,10 +470,10 @@ def do_refresh_token(refreshtoken):
|
||||
scope = "results:write,user:read"
|
||||
client_auth = requests.auth.HTTPBasicAuth(C2_CLIENT_ID, C2_CLIENT_SECRET)
|
||||
post_data = {"grant_type": "refresh_token",
|
||||
"client_secret": C2_CLIENT_SECRET,
|
||||
"client_id":C2_CLIENT_ID,
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
"client_secret": C2_CLIENT_SECRET,
|
||||
"client_id":C2_CLIENT_ID,
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
headers = {'user-agent': 'sanderroosendaal'}
|
||||
url = "https://log.concept2.com/oauth/access_token"
|
||||
s = Session()
|
||||
@@ -498,9 +510,9 @@ def get_token(code):
|
||||
post_data = {"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"redirect_uri": C2_REDIRECT_URI,
|
||||
"client_secret": C2_CLIENT_SECRET,
|
||||
"client_id":C2_CLIENT_ID,
|
||||
}
|
||||
"client_secret": C2_CLIENT_SECRET,
|
||||
"client_id":C2_CLIENT_ID,
|
||||
}
|
||||
headers = {'user-agent': 'sanderroosendaal'}
|
||||
url = "https://log.concept2.com/oauth/access_token"
|
||||
s = Session()
|
||||
@@ -545,7 +557,7 @@ def make_authorization_url(request):
|
||||
params = {"client_id": C2_CLIENT_ID,
|
||||
"response_type": "code",
|
||||
"redirect_uri": C2_REDIRECT_URI}
|
||||
url = "https://log.concept2.com/oauth/authorize?"+ urllib.urlencode(params)
|
||||
url = "https://log.concept2.com/oauth/authorize?"+ urllib.parse.urlencode(params)
|
||||
url += "&scope="+scope
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
@@ -554,19 +566,19 @@ def make_authorization_url(request):
|
||||
def get_workout(user,c2id):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.c2token == '') or (r.c2token is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s) ,0
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s) ,0
|
||||
elif (timezone.now()>r.tokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s),0
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s),0
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
|
||||
data = s.json()['data']
|
||||
@@ -583,9 +595,9 @@ def get_workout(user,c2id):
|
||||
# Check if workout has stroke data, and get the stroke data
|
||||
|
||||
if data['stroke_data']:
|
||||
res2 = get_c2_workout_strokes(user,c2id)
|
||||
if res2.status_code == 200:
|
||||
strokedata = pd.DataFrame.from_dict(res2.json()['data'])
|
||||
res2 = get_c2_workout_strokes(user,c2id)
|
||||
if res2.status_code == 200:
|
||||
strokedata = pd.DataFrame.from_dict(res2.json()['data'])
|
||||
else:
|
||||
strokedata = pd.DataFrame()
|
||||
else:
|
||||
@@ -597,19 +609,19 @@ def get_workout(user,c2id):
|
||||
def get_c2_workout_strokes(user,c2id):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.c2token == '') or (r.c2token is None):
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
elif (timezone.now()>r.tokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes"
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes"
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
@@ -618,21 +630,21 @@ def get_c2_workout_strokes(user,c2id):
|
||||
def get_c2_workout_list(user,page=1):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.c2token == '') or (r.c2token is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (timezone.now()>r.tokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://log.concept2.com/api/users/me/results"
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://log.concept2.com/api/users/me/results"
|
||||
url += "?page={page}".format(page=page)
|
||||
|
||||
s = requests.get(url,headers=headers)
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
@@ -642,8 +654,8 @@ def get_c2_workout_list(user,page=1):
|
||||
def get_username(access_token):
|
||||
authorizationstring = str('Bearer ' + access_token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
import urllib
|
||||
url = "https://log.concept2.com/api/users/me"
|
||||
response = requests.get(url,headers=headers)
|
||||
@@ -664,8 +676,8 @@ def get_username(access_token):
|
||||
def get_userid(access_token):
|
||||
authorizationstring = str('Bearer ' + access_token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
import urllib
|
||||
url = "https://log.concept2.com/api/users/me"
|
||||
response = requests.get(url,headers=headers)
|
||||
@@ -691,6 +703,10 @@ def process_callback(request):
|
||||
|
||||
return HttpResponse("got a user name: %s" % username)
|
||||
|
||||
def default(o):
|
||||
if isinstance(o, numpy.int64): return int(o)
|
||||
raise TypeError
|
||||
|
||||
# Uploading workout
|
||||
def workout_c2_upload(user,w):
|
||||
message = 'trying C2 upload'
|
||||
@@ -706,40 +722,41 @@ def workout_c2_upload(user,w):
|
||||
|
||||
# ready to upload. Hurray
|
||||
if (checkworkoutuser(user,w)):
|
||||
c2userid = get_userid(r.c2token)
|
||||
c2userid = get_userid(r.c2token)
|
||||
if not c2userid:
|
||||
raise NoTokenError
|
||||
|
||||
data = createc2workoutdata(w)
|
||||
data = createc2workoutdata(w)
|
||||
|
||||
if data == 0:
|
||||
return "Error: No data file. Contact info@rowsandall.com if the problem persists",0
|
||||
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
import urllib
|
||||
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data))
|
||||
authorizationstring = str('Bearer ' + r.c2token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
import urllib
|
||||
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
|
||||
|
||||
if (response.status_code == 409 ):
|
||||
message = "Concept2 Duplicate error"
|
||||
w.uploadedtoc2 = -1
|
||||
message = "Concept2 Duplicate error"
|
||||
w.uploadedtoc2 = -1
|
||||
c2id = -1
|
||||
w.save()
|
||||
w.save()
|
||||
elif (response.status_code == 201 or response.status_code == 200):
|
||||
try:
|
||||
# s= json.loads(response.text)
|
||||
# s= json.loads(response.text)
|
||||
s = response.json()
|
||||
c2id = s['data']['id']
|
||||
w.uploadedtoc2 = c2id
|
||||
w.save()
|
||||
c2id = s['data']['id']
|
||||
w.uploadedtoc2 = c2id
|
||||
w.save()
|
||||
message = "Upload to Concept2 was successful"
|
||||
except:
|
||||
message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text
|
||||
c2id = 0
|
||||
|
||||
else:
|
||||
else:
|
||||
message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text
|
||||
c2id = 0
|
||||
|
||||
@@ -776,41 +793,41 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
workouttype = 'rower'
|
||||
|
||||
if workouttype not in [x[0] for x in Workout.workouttypes]:
|
||||
workouttype = 'other'
|
||||
workouttype = 'other'
|
||||
try:
|
||||
comments = data['comments']
|
||||
comments = data['comments']
|
||||
except:
|
||||
comments = ' '
|
||||
comments = ' '
|
||||
|
||||
try:
|
||||
thetimezone = tz(data['timezone'])
|
||||
thetimezone = tz(data['timezone'])
|
||||
except:
|
||||
thetimezone = 'UTC'
|
||||
thetimezone = 'UTC'
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
try:
|
||||
rowdatetime = iso8601.parse_date(data['date_utc'])
|
||||
rowdatetime = iso8601.parse_date(data['date_utc'])
|
||||
except KeyError:
|
||||
rowdatetime = iso8601.parse_date(data['start_date'])
|
||||
rowdatetime = iso8601.parse_date(data['start_date'])
|
||||
except ParseError:
|
||||
rowdatetime = iso8601.parse_date(data['date'])
|
||||
rowdatetime = iso8601.parse_date(data['date'])
|
||||
|
||||
|
||||
|
||||
try:
|
||||
c2intervaltype = data['workout_type']
|
||||
|
||||
|
||||
except KeyError:
|
||||
c2intervaltype = ''
|
||||
|
||||
c2intervaltype = ''
|
||||
|
||||
try:
|
||||
title = data['name']
|
||||
title = data['name']
|
||||
except KeyError:
|
||||
title = ""
|
||||
try:
|
||||
t = data['comments'].split('\n', 1)[0]
|
||||
title += t[:20]
|
||||
except:
|
||||
title = 'Imported'
|
||||
title = ""
|
||||
try:
|
||||
t = data['comments'].split('\n', 1)[0]
|
||||
title += t[:20]
|
||||
except:
|
||||
title = 'Imported'
|
||||
|
||||
starttimeunix = arrow.get(rowdatetime).timestamp
|
||||
|
||||
@@ -825,17 +842,17 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
nr_rows = len(unixtime)
|
||||
|
||||
try:
|
||||
latcoord = strokedata.loc[:,'lat']
|
||||
loncoord = strokedata.loc[:,'lon']
|
||||
latcoord = strokedata.loc[:,'lat']
|
||||
loncoord = strokedata.loc[:,'lon']
|
||||
except:
|
||||
latcoord = np.zeros(nr_rows)
|
||||
loncoord = np.zeros(nr_rows)
|
||||
latcoord = np.zeros(nr_rows)
|
||||
loncoord = np.zeros(nr_rows)
|
||||
|
||||
|
||||
try:
|
||||
strokelength = strokedata.loc[:,'strokelength']
|
||||
strokelength = strokedata.loc[:,'strokelength']
|
||||
except:
|
||||
strokelength = np.zeros(nr_rows)
|
||||
strokelength = np.zeros(nr_rows)
|
||||
|
||||
dist2 = 0.1*strokedata.loc[:,'d']
|
||||
|
||||
@@ -862,27 +879,27 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
# save csv
|
||||
# Create data frame with all necessary data to write to csv
|
||||
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' longitude':loncoord,
|
||||
' latitude':latcoord,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Power (watts)':power,
|
||||
' DragFactor':np.zeros(nr_rows),
|
||||
' DriveLength (meters)':np.zeros(nr_rows),
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' DriveTime (ms)':np.zeros(nr_rows),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':seconds
|
||||
})
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' longitude':loncoord,
|
||||
' latitude':latcoord,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Power (watts)':power,
|
||||
' DragFactor':np.zeros(nr_rows),
|
||||
' DriveLength (meters)':np.zeros(nr_rows),
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' DriveTime (ms)':np.zeros(nr_rows),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':seconds
|
||||
})
|
||||
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings # import the settings file
|
||||
|
||||
def braintree_merchant(request):
|
||||
|
||||
+7
-2
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# All the Courses related methods
|
||||
|
||||
# Python
|
||||
@@ -28,7 +33,7 @@ import pandas as pd
|
||||
import numpy as np
|
||||
from timezonefinder import TimezoneFinder
|
||||
|
||||
import dataprep
|
||||
import rowers.dataprep as dataprep
|
||||
from rowers.utils import geo_distance
|
||||
|
||||
ns = {'opengis': 'http://www.opengis.net/kml/2.2'}
|
||||
@@ -47,7 +52,7 @@ from rowers.models import (
|
||||
polygon_to_path,coordinate_in_path
|
||||
)
|
||||
|
||||
from utils import geo_distance
|
||||
|
||||
from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
# low level methods
|
||||
def coordinate_in_path(latitude,longitude, p):
|
||||
|
||||
@@ -5,10 +9,10 @@ def coordinate_in_path(latitude,longitude, p):
|
||||
|
||||
class InvalidTrajectoryError(Exception):
|
||||
def __init__(self,value):
|
||||
self.value=value
|
||||
self.value=value
|
||||
|
||||
def __str__(self):
|
||||
return repr(self.value)
|
||||
return repr(self.value)
|
||||
|
||||
def time_in_path(df,p,maxmin='max',getall=False):
|
||||
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
user = settings.DATABASES['default']['USER']
|
||||
|
||||
+26
-17
@@ -1,5 +1,11 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# All the data preparation, data cleaning and data mangling should
|
||||
# be defined here
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
from rowers.models import Workout, StrokeData,Team
|
||||
|
||||
import pytz
|
||||
@@ -55,7 +61,7 @@ import pandas as pd
|
||||
import numpy as np
|
||||
import itertools
|
||||
import math
|
||||
from tasks import (
|
||||
from rowers.tasks import (
|
||||
handle_sendemail_unrecognized, handle_sendemail_breakthrough,
|
||||
handle_sendemail_hard, handle_updatecp,handle_updateergcp,
|
||||
handle_calctrimp,
|
||||
@@ -65,9 +71,9 @@ from django.conf import settings
|
||||
from sqlalchemy import create_engine
|
||||
import sqlalchemy as sa
|
||||
import sys
|
||||
import utils
|
||||
import datautils
|
||||
from utils import lbstoN,myqueue,is_ranking_piece,wavg
|
||||
import rowers.utils as utils
|
||||
import rowers.datautils as datautils
|
||||
from rowers.utils import lbstoN,myqueue,is_ranking_piece,wavg
|
||||
|
||||
from timezonefinder import TimezoneFinder
|
||||
|
||||
@@ -531,7 +537,10 @@ def getstatsfields():
|
||||
fielddict.pop('hr_bottom')
|
||||
fielddict.pop('cumdist')
|
||||
|
||||
fieldlist = [field for field, value in fielddict.iteritems()]
|
||||
try:
|
||||
fieldlist = [field for field, value in fielddict.iteritems()]
|
||||
except AttributeError:
|
||||
fieldlist = [field for field, value in fielddict.items()]
|
||||
|
||||
return fieldlist, fielddict
|
||||
|
||||
@@ -638,7 +647,7 @@ def deletecpdata_sql(rower_id,table='cpdata'):
|
||||
try:
|
||||
result = conn.execute(query)
|
||||
except:
|
||||
print "Database locked"
|
||||
print("Database locked")
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
|
||||
@@ -855,7 +864,7 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
||||
|
||||
return (id, message)
|
||||
|
||||
from utils import totaltime_sec_to_string
|
||||
from rowers.utils import totaltime_sec_to_string
|
||||
|
||||
# Processes painsled CSV file to database
|
||||
def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
@@ -904,7 +913,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
try:
|
||||
checks = row.check_consistency()
|
||||
allchecks = 1
|
||||
for key, value in checks.iteritems():
|
||||
for key, value in checks.items():
|
||||
if not value:
|
||||
allchecks = 0
|
||||
if consistencychecks:
|
||||
@@ -1564,7 +1573,7 @@ def compare_data(id):
|
||||
res = conn.execute(query)
|
||||
l2 = res.fetchall()[0][0]
|
||||
except:
|
||||
print "Database Locked"
|
||||
print("Database Locked")
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
lfile = l1
|
||||
@@ -1583,13 +1592,13 @@ def repair_data(verbose=False):
|
||||
test, ldb, lfile = compare_data(w.id)
|
||||
if not test:
|
||||
if verbose:
|
||||
print w.id, lfile, ldb
|
||||
print(w.id, lfile, ldb)
|
||||
try:
|
||||
rowdata = rdata(w.csvfilename)
|
||||
if rowdata and len(rowdata.df):
|
||||
update_strokedata(w.id, rowdata.df)
|
||||
|
||||
except IOError, AttributeError:
|
||||
except (IOError, AttributeError):
|
||||
pass
|
||||
|
||||
if lfile == 0:
|
||||
@@ -1618,10 +1627,10 @@ def repair_data(verbose=False):
|
||||
def rdata(file, rower=rrower()):
|
||||
try:
|
||||
res = rrdata(csvfile=file, rower=rower)
|
||||
except IOError, IndexError:
|
||||
except (IOError, IndexError):
|
||||
try:
|
||||
res = rrdata(csvfile=file + '.gz', rower=rower)
|
||||
except IOError, IndexError:
|
||||
except (IOError, IndexError):
|
||||
res = rrdata()
|
||||
except:
|
||||
res = rrdata()
|
||||
@@ -1640,7 +1649,7 @@ def delete_strokedata(id):
|
||||
try:
|
||||
result = conn.execute(query)
|
||||
except:
|
||||
print "Database Locked"
|
||||
print("Database Locked")
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
|
||||
@@ -1792,7 +1801,7 @@ def prepmultipledata(ids, verbose=False):
|
||||
for id in res:
|
||||
rowdata, row = getrowdata(id=id)
|
||||
if verbose:
|
||||
print id
|
||||
print(id)
|
||||
if rowdata and len(rowdata.df):
|
||||
data = dataprep(rowdata.df, id=id, bands=True,
|
||||
barchart=True, otwpower=True)
|
||||
@@ -2029,7 +2038,7 @@ def fix_newtons(id=0, limit=3000):
|
||||
peakforce = rowdata['peakforce']
|
||||
if peakforce.mean() > limit:
|
||||
w = Workout.objects.get(id=id)
|
||||
print "fixing ", id
|
||||
print("fixing ", id)
|
||||
rowdata = rdata(w.csvfilename)
|
||||
if rowdata and len(rowdata.df):
|
||||
update_strokedata(w.id, rowdata.df)
|
||||
@@ -2084,7 +2093,7 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
|
||||
if rowdatadf.empty:
|
||||
return 0
|
||||
|
||||
rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
|
||||
#rowdatadf.set_index([range(len(rowdatadf))], inplace=True)
|
||||
t = rowdatadf.loc[:, 'TimeStamp (sec)']
|
||||
t = pd.Series(t - rowdatadf.loc[:, 'TimeStamp (sec)'].iloc[0])
|
||||
|
||||
|
||||
+151
-146
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# This is Data prep used for testing purposes (no Django environment)
|
||||
# Uses the debug SQLite database for stroke data
|
||||
from rowingdata import rowingdata as rrdata
|
||||
@@ -18,7 +23,7 @@ import sqlalchemy as sa
|
||||
from rowsandall_app.settings import DATABASES
|
||||
from rowsandall_app.settings_dev import DATABASES as DEV_DATABASES
|
||||
|
||||
from utils import lbstoN
|
||||
from rowers.utils import lbstoN
|
||||
|
||||
|
||||
try:
|
||||
@@ -83,33 +88,33 @@ import datetime
|
||||
def niceformat(values):
|
||||
out = []
|
||||
for v in values:
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
return out
|
||||
|
||||
def strfdelta(tdelta):
|
||||
try:
|
||||
minutes,seconds = divmod(tdelta.seconds,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
minutes,seconds = divmod(tdelta.seconds,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
except AttributeError:
|
||||
minutes,seconds = divmod(tdelta.view(np.int64),60e9)
|
||||
seconds,rest = divmod(seconds,1e9)
|
||||
tenths = int(rest/1e8)
|
||||
minutes,seconds = divmod(tdelta.view(np.int64),60e9)
|
||||
seconds,rest = divmod(seconds,1e9)
|
||||
tenths = int(rest/1e8)
|
||||
res = "{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
def nicepaceformat(values):
|
||||
out = []
|
||||
for v in values:
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
formattedv = strfdelta(v)
|
||||
out.append(formattedv)
|
||||
|
||||
|
||||
return out
|
||||
|
||||
@@ -124,16 +129,16 @@ def timedeltaconv(x):
|
||||
|
||||
def rdata(file,rower=rrower()):
|
||||
try:
|
||||
res = rrdata(file,rower=rower)
|
||||
res = rrdata(file,rower=rower)
|
||||
except IOError:
|
||||
try:
|
||||
res = rrdata(file+'.gz',rower=rower)
|
||||
except IOError:
|
||||
res = 0
|
||||
res = 0
|
||||
|
||||
return res
|
||||
|
||||
from utils import totaltime_sec_to_string
|
||||
from rowers.utils import totaltime_sec_to_string
|
||||
|
||||
|
||||
# Creates C2 stroke data
|
||||
@@ -175,22 +180,22 @@ def create_c2_stroke_data_db(
|
||||
|
||||
df = pd.DataFrame({
|
||||
'TimeStamp (sec)': unixtime,
|
||||
' Horizontal (meters)': d,
|
||||
' Horizontal (meters)': d,
|
||||
' Cadence (stokes/min)': spm,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' ElapsedTime (sec)':elapsed,
|
||||
' Power (watts)':power,
|
||||
' HRCur (bpm)':np.zeros(nr_strokes),
|
||||
' longitude':np.zeros(nr_strokes),
|
||||
' latitude':np.zeros(nr_strokes),
|
||||
' DragFactor':np.zeros(nr_strokes),
|
||||
' DriveLength (meters)':np.zeros(nr_strokes),
|
||||
' StrokeDistance (meters)':np.zeros(nr_strokes),
|
||||
' DriveTime (ms)':np.zeros(nr_strokes),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_strokes),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' lapIdx':np.zeros(nr_strokes),
|
||||
' HRCur (bpm)':np.zeros(nr_strokes),
|
||||
' longitude':np.zeros(nr_strokes),
|
||||
' latitude':np.zeros(nr_strokes),
|
||||
' DragFactor':np.zeros(nr_strokes),
|
||||
' DriveLength (meters)':np.zeros(nr_strokes),
|
||||
' StrokeDistance (meters)':np.zeros(nr_strokes),
|
||||
' DriveTime (ms)':np.zeros(nr_strokes),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_strokes),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' lapIdx':np.zeros(nr_strokes),
|
||||
'cum_dist': d
|
||||
})
|
||||
|
||||
@@ -220,17 +225,17 @@ def add_c2_stroke_data_db(strokedata,workoutid,starttimeunix,csvfilename,
|
||||
nr_rows = len(unixtime)
|
||||
|
||||
try:
|
||||
latcoord = strokedata.ix[:,'lat']
|
||||
loncoord = strokedata.ix[:,'lon']
|
||||
latcoord = strokedata.ix[:,'lat']
|
||||
loncoord = strokedata.ix[:,'lon']
|
||||
except:
|
||||
latcoord = np.zeros(nr_rows)
|
||||
loncoord = np.zeros(nr_rows)
|
||||
latcoord = np.zeros(nr_rows)
|
||||
loncoord = np.zeros(nr_rows)
|
||||
|
||||
|
||||
try:
|
||||
strokelength = strokedata.ix[:,'strokelength']
|
||||
strokelength = strokedata.ix[:,'strokelength']
|
||||
except:
|
||||
strokelength = np.zeros(nr_rows)
|
||||
strokelength = np.zeros(nr_rows)
|
||||
|
||||
dist2 = 0.1*strokedata.ix[:,'d']
|
||||
|
||||
@@ -258,28 +263,28 @@ def add_c2_stroke_data_db(strokedata,workoutid,starttimeunix,csvfilename,
|
||||
# save csv
|
||||
# Create data frame with all necessary data to write to csv
|
||||
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' longitude':loncoord,
|
||||
' latitude':latcoord,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Power (watts)':power,
|
||||
' DragFactor':np.zeros(nr_rows),
|
||||
' DriveLength (meters)':np.zeros(nr_rows),
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' DriveTime (ms)':np.zeros(nr_rows),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':seconds,
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' longitude':loncoord,
|
||||
' latitude':latcoord,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Power (watts)':power,
|
||||
' DragFactor':np.zeros(nr_rows),
|
||||
' DriveLength (meters)':np.zeros(nr_rows),
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' DriveTime (ms)':np.zeros(nr_rows),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':seconds,
|
||||
'cum_dist': dist2
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
|
||||
@@ -312,8 +317,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
|
||||
# make workout and put in database
|
||||
rr = rrower(hrmax=r.max,hrut2=r.ut2,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
||||
hrut1=r.ut1,hrat=r.at,
|
||||
hrtr=r.tr,hran=r.an,ftp=r.ftp,
|
||||
powerperc=powerperc,powerzones=r.powerzones)
|
||||
row = rdata(f2,rower=rr)
|
||||
|
||||
@@ -329,7 +334,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
|
||||
|
||||
if row == 0:
|
||||
return (0,'Error: CSV data file not found')
|
||||
return (0,'Error: CSV data file not found')
|
||||
|
||||
if dosmooth:
|
||||
# auto smoothing
|
||||
@@ -342,12 +347,12 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
else:
|
||||
windowsize = 1
|
||||
if not 'originalvelo' in row.df:
|
||||
row.df['originalvelo'] = velo
|
||||
row.df['originalvelo'] = velo
|
||||
|
||||
if windowsize > 3 and windowsize<len(velo):
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
velo2 = savgol_filter(velo,windowsize,3)
|
||||
else:
|
||||
velo2 = velo
|
||||
velo2 = velo
|
||||
|
||||
velo3 = pd.Series(velo2)
|
||||
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
||||
@@ -367,11 +372,11 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
|
||||
# recalculate power data
|
||||
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
|
||||
try:
|
||||
row.erg_recalculatepower()
|
||||
try:
|
||||
row.erg_recalculatepower()
|
||||
row.write_csv(f2,gzip=True)
|
||||
except:
|
||||
pass
|
||||
except:
|
||||
pass
|
||||
|
||||
averagehr = row.df[' HRCur (bpm)'].mean()
|
||||
maxhr = row.df[' HRCur (bpm)'].max()
|
||||
@@ -425,22 +430,22 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower',
|
||||
|
||||
# check for duplicate start times
|
||||
ws = Workout.objects.filter(startdatetime=workoutstartdatetime,
|
||||
user=r)
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
privacy = 'private'
|
||||
|
||||
|
||||
|
||||
w = Workout(user=r,name=title,date=workoutdate,
|
||||
workouttype=workouttype,
|
||||
workouttype=workouttype,
|
||||
workoutsource=workoutsource,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes,summary=summary,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
csvfilename=f2,notes=notes,summary=summary,
|
||||
maxhr=maxhr,averagehr=averagehr,
|
||||
startdatetime=workoutstartdatetime,
|
||||
inboard=inboard,oarlength=oarlength,
|
||||
privacy=privacy)
|
||||
|
||||
@@ -463,14 +468,14 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
inboard = 0.88
|
||||
# handle RowPro:
|
||||
if (fileformat == 'rp'):
|
||||
row = RowProParser(f2)
|
||||
# handle TCX
|
||||
row = RowProParser(f2)
|
||||
# handle TCX
|
||||
if (fileformat == 'tcx'):
|
||||
row = TCXParser(f2)
|
||||
row = TCXParser(f2)
|
||||
|
||||
# handle Mystery
|
||||
if (fileformat == 'mystery'):
|
||||
row = MysteryParser(f2)
|
||||
row = MysteryParser(f2)
|
||||
|
||||
# handle RowPerfect
|
||||
if (fileformat == 'rowperfect3'):
|
||||
@@ -478,11 +483,11 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
|
||||
# handle ErgData
|
||||
if (fileformat == 'ergdata'):
|
||||
row = ErgDataParser(f2)
|
||||
row = ErgDataParser(f2)
|
||||
|
||||
# handle CoxMate
|
||||
if (fileformat == 'coxmate'):
|
||||
row = CoxMateParser(f2)
|
||||
row = CoxMateParser(f2)
|
||||
|
||||
# handle Mike
|
||||
if (fileformat == 'bcmike'):
|
||||
@@ -494,19 +499,19 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
|
||||
# handle BoatCoach
|
||||
if (fileformat == 'boatcoach'):
|
||||
row = BoatCoachParser(f2)
|
||||
row = BoatCoachParser(f2)
|
||||
|
||||
# handle painsled desktop
|
||||
if (fileformat == 'painsleddesktop'):
|
||||
row = painsledDesktopParser(f2)
|
||||
row = painsledDesktopParser(f2)
|
||||
|
||||
# handle speed coach GPS
|
||||
if (fileformat == 'speedcoach'):
|
||||
row = speedcoachParser(f2)
|
||||
row = speedcoachParser(f2)
|
||||
|
||||
# handle speed coach GPS 2
|
||||
if (fileformat == 'speedcoach2'):
|
||||
row = SpeedCoach2Parser(f2)
|
||||
row = SpeedCoach2Parser(f2)
|
||||
try:
|
||||
oarlength,inboard = get_empower_rigging(f2)
|
||||
summary = row.allstats()
|
||||
@@ -516,14 +521,14 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
|
||||
# handle ErgStick
|
||||
if (fileformat == 'ergstick'):
|
||||
row = ErgStickParser(f2)
|
||||
|
||||
row = ErgStickParser(f2)
|
||||
|
||||
# handle FIT
|
||||
if (fileformat == 'fit'):
|
||||
row = FITParser(f2)
|
||||
s = fitsummarydata(f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
row = FITParser(f2)
|
||||
s = fitsummarydata(f2)
|
||||
s.setsummary()
|
||||
summary = s.summarytext
|
||||
|
||||
|
||||
f_to_be_deleted = f2
|
||||
@@ -533,7 +538,7 @@ def handle_nonpainsled(f2,fileformat,summary=''):
|
||||
|
||||
#os.remove(f2)
|
||||
try:
|
||||
os.remove(f_to_be_deleted)
|
||||
os.remove(f_to_be_deleted)
|
||||
except:
|
||||
os.remove(f_to_be_deleted+'.gz')
|
||||
|
||||
@@ -588,14 +593,14 @@ def new_workout_from_file(r,f2,
|
||||
# for me to check if it is a bug, or a new file type
|
||||
# worth supporting
|
||||
if fileformat == 'unknown':
|
||||
message = "We couldn't recognize the file type"
|
||||
if settings.DEBUG:
|
||||
res = handle_sendemail_unrecognized.delay(f2,
|
||||
r.user.email)
|
||||
message = "We couldn't recognize the file type"
|
||||
if settings.DEBUG:
|
||||
res = handle_sendemail_unrecognized.delay(f2,
|
||||
r.user.email)
|
||||
|
||||
else:
|
||||
res = queuehigh.enqueue(handle_sendemail_unrecognized,
|
||||
f2,r.user.email)
|
||||
else:
|
||||
res = queuehigh.enqueue(handle_sendemail_unrecognized,
|
||||
f2,r.user.email)
|
||||
return (0,message,f2)
|
||||
|
||||
# handle non-Painsled by converting it to painsled compatible CSV
|
||||
@@ -635,14 +640,14 @@ def delete_strokedata(id,debug=False):
|
||||
try:
|
||||
result = conn.execute(query)
|
||||
except:
|
||||
print "Database Locked"
|
||||
print("Database Locked")
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
|
||||
def update_strokedata(id,df,debug=False):
|
||||
delete_strokedata(id,debug=debug)
|
||||
if debug:
|
||||
print "updating ",id
|
||||
print("updating ",id)
|
||||
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
|
||||
debug=debug)
|
||||
|
||||
@@ -676,11 +681,11 @@ def update_empower(id, inboard, oarlength, boattype, df, f1, debug=False):
|
||||
if success:
|
||||
delete_strokedata(id,debug=debug)
|
||||
if debug:
|
||||
print "updated ",id
|
||||
print "correction ",corr_factor
|
||||
print("updated ",id)
|
||||
print("correction ",corr_factor)
|
||||
else:
|
||||
if debug:
|
||||
print "not updated ",id
|
||||
print("not updated ",id)
|
||||
|
||||
|
||||
rowdata = dataprep(df,id=id,bands=True,barchart=True,otwpower=True,
|
||||
@@ -784,8 +789,8 @@ def read_cols_df_sql(ids,columns,debug=False):
|
||||
def read_df_sql(id,debug=False):
|
||||
if debug:
|
||||
engine = create_engine(database_url_debug, echo=False)
|
||||
print "read_df",id
|
||||
print database_url_debug
|
||||
print("read_df",id)
|
||||
print(database_url_debug)
|
||||
else:
|
||||
engine = create_engine(database_url, echo=False)
|
||||
|
||||
@@ -826,7 +831,7 @@ def deletecpdata_sql(rower_id,table='cpdata',debug=False):
|
||||
try:
|
||||
result = conn.execute(query)
|
||||
except:
|
||||
print "Database locked"
|
||||
print("Database locked")
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
|
||||
@@ -846,7 +851,7 @@ def delete_agegroup_db(age,sex,weightcategory,debug=False):
|
||||
try:
|
||||
result = conn.execute(query)
|
||||
except:
|
||||
print "Database locked"
|
||||
print("Database locked")
|
||||
conn.close()
|
||||
engine.dispose()
|
||||
|
||||
@@ -956,11 +961,11 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
|
||||
if rowdatadf.empty:
|
||||
if debug:
|
||||
print "empty"
|
||||
print("empty")
|
||||
return 0
|
||||
|
||||
if debug:
|
||||
print "dataprep",id
|
||||
print("dataprep",id)
|
||||
|
||||
rowdatadf.set_index([range(len(rowdatadf))],inplace=True)
|
||||
t = rowdatadf.ix[:,'TimeStamp (sec)']
|
||||
@@ -1006,12 +1011,12 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
else:
|
||||
windowsize = 1
|
||||
if windowsize <= 3:
|
||||
windowsize = 5
|
||||
windowsize = 5
|
||||
|
||||
if windowsize > 3 and windowsize<len(hr):
|
||||
spm = savgol_filter(spm,windowsize,3)
|
||||
hr = savgol_filter(hr,windowsize,3)
|
||||
drivelength = savgol_filter(drivelength,windowsize,3)
|
||||
spm = savgol_filter(spm,windowsize,3)
|
||||
hr = savgol_filter(hr,windowsize,3)
|
||||
drivelength = savgol_filter(drivelength,windowsize,3)
|
||||
forceratio = savgol_filter(forceratio,windowsize,3)
|
||||
|
||||
try:
|
||||
@@ -1072,14 +1077,14 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
)
|
||||
|
||||
if bands:
|
||||
# HR bands
|
||||
data['hr_ut2'] = rowdatadf.ix[:,'hr_ut2']
|
||||
data['hr_ut1'] = rowdatadf.ix[:,'hr_ut1']
|
||||
data['hr_at'] = rowdatadf.ix[:,'hr_at']
|
||||
data['hr_tr'] = rowdatadf.ix[:,'hr_tr']
|
||||
data['hr_an'] = rowdatadf.ix[:,'hr_an']
|
||||
data['hr_max'] = rowdatadf.ix[:,'hr_max']
|
||||
data['hr_bottom'] = 0.0*data['hr']
|
||||
# HR bands
|
||||
data['hr_ut2'] = rowdatadf.ix[:,'hr_ut2']
|
||||
data['hr_ut1'] = rowdatadf.ix[:,'hr_ut1']
|
||||
data['hr_at'] = rowdatadf.ix[:,'hr_at']
|
||||
data['hr_tr'] = rowdatadf.ix[:,'hr_tr']
|
||||
data['hr_an'] = rowdatadf.ix[:,'hr_an']
|
||||
data['hr_max'] = rowdatadf.ix[:,'hr_max']
|
||||
data['hr_bottom'] = 0.0*data['hr']
|
||||
|
||||
|
||||
try:
|
||||
@@ -1088,13 +1093,13 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
rowdatadf[' ElapsedTime (sec)'] = rowdatadf['TimeStamp (sec)']
|
||||
|
||||
if barchart:
|
||||
# time increments for bar chart
|
||||
time_increments = rowdatadf.ix[:,' ElapsedTime (sec)'].diff()
|
||||
time_increments[0] = time_increments[1]
|
||||
time_increments = 0.5*time_increments+0.5*np.abs(time_increments)
|
||||
x_right = (t2+time_increments.apply(lambda x:timedeltaconv(x)))
|
||||
# time increments for bar chart
|
||||
time_increments = rowdatadf.ix[:,' ElapsedTime (sec)'].diff()
|
||||
time_increments[0] = time_increments[1]
|
||||
time_increments = 0.5*time_increments+0.5*np.abs(time_increments)
|
||||
x_right = (t2+time_increments.apply(lambda x:timedeltaconv(x)))
|
||||
|
||||
data['x_right'] = x_right
|
||||
data['x_right'] = x_right
|
||||
|
||||
if empower:
|
||||
try:
|
||||
@@ -1207,29 +1212,29 @@ def dataprep(rowdatadf,id=0,bands=True,barchart=True,otwpower=True,
|
||||
pass
|
||||
|
||||
if otwpower:
|
||||
try:
|
||||
nowindpace = rowdatadf.ix[:,'nowindpace']
|
||||
except KeyError:
|
||||
nowindpace = p
|
||||
try:
|
||||
equivergpower = rowdatadf.ix[:,'equivergpower']
|
||||
except KeyError:
|
||||
equivergpower = 0*p+50.
|
||||
|
||||
nowindpace2 = nowindpace.apply(lambda x: timedeltaconv(x))
|
||||
ergvelo = (equivergpower/2.8)**(1./3.)
|
||||
try:
|
||||
nowindpace = rowdatadf.ix[:,'nowindpace']
|
||||
except KeyError:
|
||||
nowindpace = p
|
||||
try:
|
||||
equivergpower = rowdatadf.ix[:,'equivergpower']
|
||||
except KeyError:
|
||||
equivergpower = 0*p+50.
|
||||
|
||||
nowindpace2 = nowindpace.apply(lambda x: timedeltaconv(x))
|
||||
ergvelo = (equivergpower/2.8)**(1./3.)
|
||||
|
||||
ergpace = 500./ergvelo
|
||||
ergpace[ergpace == np.inf] = 240.
|
||||
ergpace2 = ergpace.apply(lambda x: timedeltaconv(x))
|
||||
ergpace = 500./ergvelo
|
||||
ergpace[ergpace == np.inf] = 240.
|
||||
ergpace2 = ergpace.apply(lambda x: timedeltaconv(x))
|
||||
|
||||
|
||||
|
||||
data['ergpace'] = ergpace*1e3
|
||||
data['nowindpace'] = nowindpace*1e3
|
||||
data['equivergpower'] = equivergpower
|
||||
data['fergpace'] = nicepaceformat(ergpace2)
|
||||
data['fnowindpace'] = nicepaceformat(nowindpace2)
|
||||
data['ergpace'] = ergpace*1e3
|
||||
data['nowindpace'] = nowindpace*1e3
|
||||
data['equivergpower'] = equivergpower
|
||||
data['fergpace'] = nicepaceformat(ergpace2)
|
||||
data['fnowindpace'] = nicepaceformat(nowindpace2)
|
||||
data['efficiency'] = efficiency
|
||||
|
||||
data = data.replace([-np.inf,np.inf],np.nan)
|
||||
|
||||
+11
-6
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
from scipy.interpolate import griddata
|
||||
@@ -49,14 +54,14 @@ def cpfit(powerdf):
|
||||
|
||||
if len(thesecs)>=4:
|
||||
try:
|
||||
p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower))
|
||||
p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower))
|
||||
except:
|
||||
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
|
||||
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
|
||||
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
|
||||
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
|
||||
|
||||
else:
|
||||
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
|
||||
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
|
||||
factor = fitfunc(p0,thesecs.mean())/theavpower.mean()
|
||||
p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]]
|
||||
|
||||
|
||||
p1 = [abs(p) for p in p1]
|
||||
@@ -259,7 +264,7 @@ def getcp(dfgrouped,logarr):
|
||||
length = len(ww)
|
||||
dt = []
|
||||
cpw = []
|
||||
for i in xrange(length-2):
|
||||
for i in range(length-2):
|
||||
deltat,wmax = getmaxwattinterval(tt,ww,i)
|
||||
|
||||
if not np.isnan(deltat) and not np.isnan(wmax):
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib.auth.decorators import login_required,user_passes_test
|
||||
|
||||
from django.http import HttpResponseRedirect
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import time
|
||||
import gc
|
||||
|
||||
+95
-88
@@ -1,3 +1,9 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
from django import forms
|
||||
from django.contrib.admin.widgets import FilteredSelectMultiple
|
||||
from rowers.models import (
|
||||
@@ -9,15 +15,16 @@ from rowers.rows import validate_file_extension,must_be_csv,validate_image_exten
|
||||
from django.contrib.auth.forms import UserCreationForm
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.admin.widgets import AdminDateWidget
|
||||
from django.forms.extras.widgets import SelectDateWidget
|
||||
from django.forms.widgets import SelectDateWidget
|
||||
#from django.forms.extras.widgets import SelectDateWidget
|
||||
from django.utils import timezone,translation
|
||||
from django.forms import ModelForm, Select
|
||||
import dataprep
|
||||
import mytypes
|
||||
import rowers.dataprep as dataprep
|
||||
import rowers.mytypes as mytypes
|
||||
import datetime
|
||||
from django.forms import formset_factory
|
||||
from utils import landingpages
|
||||
from metrics import axes
|
||||
from rowers.utils import landingpages
|
||||
from rowers.metrics import axes
|
||||
|
||||
class FlexibleDecimalField(forms.DecimalField):
|
||||
|
||||
@@ -84,7 +91,7 @@ for key, value in disqualificationreasons:
|
||||
class DisqualificationForm(forms.Form):
|
||||
|
||||
reason = forms.ChoiceField(required=True,
|
||||
choices=disqualificationreasons,
|
||||
choices=disqualificationreasons,
|
||||
widget = forms.RadioSelect,)
|
||||
|
||||
message = forms.CharField(required=True,widget=forms.Textarea)
|
||||
@@ -139,10 +146,10 @@ class CourseForm(forms.Form):
|
||||
class DocumentsForm(forms.Form):
|
||||
title = forms.CharField(required=False)
|
||||
file = forms.FileField(required=False,
|
||||
validators=[validate_file_extension])
|
||||
validators=[validate_file_extension])
|
||||
|
||||
workouttype = forms.ChoiceField(required=True,
|
||||
choices=Workout.workouttypes)
|
||||
choices=Workout.workouttypes)
|
||||
|
||||
boattype = forms.ChoiceField(required=True,
|
||||
choices=mytypes.boattypes,
|
||||
@@ -150,19 +157,19 @@ class DocumentsForm(forms.Form):
|
||||
|
||||
|
||||
notes = forms.CharField(required=False,
|
||||
widget=forms.Textarea)
|
||||
widget=forms.Textarea)
|
||||
|
||||
offline = forms.BooleanField(initial=False,required=False,
|
||||
label='Process in Background')
|
||||
class Meta:
|
||||
fields = ['title','file','workouttype','boattype','fileformat','offline']
|
||||
fields = ['title','file','workouttype','boattype','fileformat','offline']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
from django.forms.widgets import HiddenInput
|
||||
super(DocumentsForm, self).__init__(*args, **kwargs)
|
||||
# self.fields['offline'].widget = HiddenInput()
|
||||
|
||||
from utils import (
|
||||
from rowers.utils import (
|
||||
workflowleftpanel,workflowmiddlepanel,
|
||||
defaultleft,defaultmiddle
|
||||
)
|
||||
@@ -267,14 +274,14 @@ class LandingPageForm(forms.Form):
|
||||
|
||||
class UploadOptionsForm(forms.Form):
|
||||
plotchoices = (
|
||||
('timeplot','Time Plot'),
|
||||
('distanceplot','Distance Plot'),
|
||||
('pieplot','Heart Rate Pie Chart'),
|
||||
)
|
||||
('timeplot','Time Plot'),
|
||||
('distanceplot','Distance Plot'),
|
||||
('pieplot','Heart Rate Pie Chart'),
|
||||
)
|
||||
make_plot = forms.BooleanField(initial=False,required=False)
|
||||
plottype = forms.ChoiceField(required=False,
|
||||
choices=plotchoices,
|
||||
initial='timeplot',
|
||||
choices=plotchoices,
|
||||
initial='timeplot',
|
||||
label='Plot Type')
|
||||
upload_to_C2 = forms.BooleanField(initial=False,required=False,
|
||||
label='Export to Concept2 logbook')
|
||||
@@ -303,7 +310,7 @@ class UploadOptionsForm(forms.Form):
|
||||
label='After Upload, go to')
|
||||
|
||||
class Meta:
|
||||
fields = ['make_plot','plottype','upload_toc2','makeprivate']
|
||||
fields = ['make_plot','plottype','upload_toc2','makeprivate']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.request = kwargs.pop('request',None)
|
||||
@@ -332,18 +339,18 @@ class UploadOptionsForm(forms.Form):
|
||||
# a team member
|
||||
class TeamUploadOptionsForm(forms.Form):
|
||||
plotchoices = (
|
||||
('timeplot','Time Plot'),
|
||||
('distanceplot','Distance Plot'),
|
||||
('pieplot','Pie Chart'),
|
||||
)
|
||||
('timeplot','Time Plot'),
|
||||
('distanceplot','Distance Plot'),
|
||||
('pieplot','Pie Chart'),
|
||||
)
|
||||
make_plot = forms.BooleanField(initial=False,required=False)
|
||||
plottype = forms.ChoiceField(required=False,
|
||||
choices=plotchoices,
|
||||
initial='timeplot',
|
||||
choices=plotchoices,
|
||||
initial='timeplot',
|
||||
label='Plot Type')
|
||||
|
||||
class Meta:
|
||||
fields = ['make_plot','plottype']
|
||||
fields = ['make_plot','plottype']
|
||||
|
||||
# This form is used on the Workout Split page
|
||||
class WorkoutSplitForm(forms.Form):
|
||||
@@ -392,9 +399,9 @@ class OteWorkoutTypeForm(forms.Form):
|
||||
|
||||
class PredictedPieceForm(forms.Form):
|
||||
unitchoices = (
|
||||
('t','minutes'),
|
||||
('d','meters'),
|
||||
)
|
||||
('t','minutes'),
|
||||
('d','meters'),
|
||||
)
|
||||
|
||||
rankingdistancechoices = []
|
||||
rankingdurationchoices = []
|
||||
@@ -422,10 +429,10 @@ class PredictedPieceForm(forms.Form):
|
||||
|
||||
value = forms.FloatField(initial=10,label='Free ranking piece (minutes)')
|
||||
pieceunit = forms.ChoiceField(required=True,choices=unitchoices,
|
||||
initial='t',label='Unit')
|
||||
initial='t',label='Unit')
|
||||
|
||||
class Meta:
|
||||
fields = ['value','pieceunit']
|
||||
fields = ['value','pieceunit']
|
||||
|
||||
class PredictedPieceFormNoDistance(forms.Form):
|
||||
|
||||
@@ -450,76 +457,76 @@ class PredictedPieceFormNoDistance(forms.Form):
|
||||
# On the Geeky side, to update stream information for river dwellers
|
||||
class UpdateStreamForm(forms.Form):
|
||||
unitchoices = (
|
||||
('m','m/s'),
|
||||
('f','foot/s'),
|
||||
('k','knots'),
|
||||
('p','pace difference (sec/500m)'),
|
||||
)
|
||||
('m','m/s'),
|
||||
('f','foot/s'),
|
||||
('k','knots'),
|
||||
('p','pace difference (sec/500m)'),
|
||||
)
|
||||
dist1 = forms.FloatField(initial=0,label = 'Distance 1')
|
||||
dist2 = forms.FloatField(initial=1000,label = 'Distance 2')
|
||||
stream1 = forms.FloatField(initial=0,label = 'Stream velocity 1')
|
||||
stream2 = forms.FloatField(initial=0,label = 'Stream velocity 2')
|
||||
streamunit = forms.ChoiceField(required=True,
|
||||
choices=unitchoices,
|
||||
initial='m',
|
||||
label='Unit')
|
||||
choices=unitchoices,
|
||||
initial='m',
|
||||
label='Unit')
|
||||
|
||||
class Meta:
|
||||
fields = ['dist1','dist2','stream1', 'stream2','streamunit']
|
||||
fields = ['dist1','dist2','stream1', 'stream2','streamunit']
|
||||
|
||||
# add wind information to your workout
|
||||
class UpdateWindForm(forms.Form):
|
||||
unitchoices = (
|
||||
('m','m/s'),
|
||||
('k','knots'),
|
||||
('b','beaufort'),
|
||||
('kmh','km/h'),
|
||||
('mph','miles/hour'),
|
||||
)
|
||||
('m','m/s'),
|
||||
('k','knots'),
|
||||
('b','beaufort'),
|
||||
('kmh','km/h'),
|
||||
('mph','miles/hour'),
|
||||
)
|
||||
dist1 = forms.FloatField(initial=0,label = 'Distance 1')
|
||||
dist2 = forms.FloatField(initial=1000,label = 'Distance 2')
|
||||
vwind1 = forms.FloatField(initial=0,required=False,label = 'Wind Speed 1')
|
||||
vwind2 = forms.FloatField(initial=0,required=False,label = 'Wind Speed 2')
|
||||
windunit = forms.ChoiceField(required=True,
|
||||
choices=unitchoices,
|
||||
initial='m',
|
||||
label='Unit')
|
||||
choices=unitchoices,
|
||||
initial='m',
|
||||
label='Unit')
|
||||
winddirection1 = forms.IntegerField(initial=0,required=False,
|
||||
label = 'Wind Direction 1')
|
||||
label = 'Wind Direction 1')
|
||||
winddirection2 = forms.IntegerField(initial=0,required=False,
|
||||
label = 'Wind Direction 2')
|
||||
label = 'Wind Direction 2')
|
||||
|
||||
class Meta:
|
||||
fields = ['dist1','dist2',
|
||||
'vwind1','vwind2',
|
||||
'windunit',
|
||||
'winddirection1','winddirection2']
|
||||
fields = ['dist1','dist2',
|
||||
'vwind1','vwind2',
|
||||
'windunit',
|
||||
'winddirection1','winddirection2']
|
||||
|
||||
# Form to select a data range to show workouts from a certain time period
|
||||
class DateRangeForm(forms.Form):
|
||||
startdate = forms.DateField(
|
||||
initial=timezone.now()-datetime.timedelta(days=365),
|
||||
# widget=SelectDateWidget(years=range(1990,2050)),
|
||||
# widget=SelectDateWidget(years=range(1990,2050)),
|
||||
widget=AdminDateWidget(),
|
||||
label='Start Date')
|
||||
label='Start Date')
|
||||
enddate = forms.DateField(
|
||||
initial=timezone.now(),
|
||||
widget=AdminDateWidget(),
|
||||
label='End Date')
|
||||
label='End Date')
|
||||
|
||||
class Meta:
|
||||
fields = ['startdate','enddate']
|
||||
fields = ['startdate','enddate']
|
||||
|
||||
class FitnessMetricForm(forms.Form):
|
||||
startdate = forms.DateField(
|
||||
initial=timezone.now()-datetime.timedelta(days=365),
|
||||
# widget=SelectDateWidget(years=range(1990,2050)),
|
||||
# widget=SelectDateWidget(years=range(1990,2050)),
|
||||
widget=AdminDateWidget(),
|
||||
label='Start Date')
|
||||
label='Start Date')
|
||||
enddate = forms.DateField(
|
||||
initial=timezone.now(),
|
||||
widget=AdminDateWidget(),
|
||||
label='End Date')
|
||||
label='End Date')
|
||||
|
||||
modechoices = (
|
||||
('rower','indoor rower'),
|
||||
@@ -533,7 +540,7 @@ class FitnessMetricForm(forms.Form):
|
||||
)
|
||||
|
||||
class Meta:
|
||||
fields = ['startdate','enddate','mode']
|
||||
fields = ['startdate','enddate','mode']
|
||||
|
||||
class SessionDateShiftForm(forms.Form):
|
||||
shiftstartdate = forms.DateField(
|
||||
@@ -599,7 +606,7 @@ class RegistrationFormSex(RegistrationFormUniqueEmail):
|
||||
|
||||
weightcategories = (
|
||||
('hwt','heavy-weight'),
|
||||
('lwt','light-weight'),
|
||||
('lwt','light-weight'),
|
||||
)
|
||||
|
||||
adaptivecategories = mytypes.adaptivetypes
|
||||
@@ -637,8 +644,8 @@ class RegistrationFormSex(RegistrationFormUniqueEmail):
|
||||
class MyTimeField(forms.TimeField):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(MyTimeField, self).__init__(*args, **kwargs)
|
||||
supports_microseconds = True
|
||||
super(MyTimeField, self).__init__(*args, **kwargs)
|
||||
supports_microseconds = True
|
||||
|
||||
# Form used to automatically define intervals by pace or power
|
||||
class PowerIntervalUpdateForm(forms.Form):
|
||||
@@ -660,28 +667,28 @@ class PowerIntervalUpdateForm(forms.Form):
|
||||
class IntervalUpdateForm(forms.Form):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
typechoices = (
|
||||
(1,'single time'),
|
||||
(2,'single distance'),
|
||||
(3,'rest (time based)'),
|
||||
(3,'rest (distance based)'),
|
||||
(4,'work (time based)'),
|
||||
(5,'work (distance based)'),
|
||||
)
|
||||
aantal = int(kwargs.pop('aantal'))
|
||||
super(IntervalUpdateForm, self).__init__(*args, **kwargs)
|
||||
typechoices = (
|
||||
(1,'single time'),
|
||||
(2,'single distance'),
|
||||
(3,'rest (time based)'),
|
||||
(3,'rest (distance based)'),
|
||||
(4,'work (time based)'),
|
||||
(5,'work (distance based)'),
|
||||
)
|
||||
aantal = int(kwargs.pop('aantal'))
|
||||
super(IntervalUpdateForm, self).__init__(*args, **kwargs)
|
||||
|
||||
for i in range(aantal):
|
||||
self.fields['intervalt_%s' % i] = forms.DurationField(label='Time '+str(i+1))
|
||||
self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1))
|
||||
self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices,
|
||||
required=True,
|
||||
initial=4,
|
||||
label = 'Type '+str(i+1))
|
||||
self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
|
||||
self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
|
||||
self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;'
|
||||
self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f')
|
||||
for i in range(aantal):
|
||||
self.fields['intervalt_%s' % i] = forms.DurationField(label='Time '+str(i+1))
|
||||
self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1))
|
||||
self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices,
|
||||
required=True,
|
||||
initial=4,
|
||||
label = 'Type '+str(i+1))
|
||||
self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
|
||||
self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
|
||||
self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;'
|
||||
self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f')
|
||||
|
||||
boattypes = mytypes.boattypes
|
||||
workouttypes = mytypes.workouttypes
|
||||
@@ -824,7 +831,7 @@ formaxlabelsmultiflex.pop('distance')
|
||||
formaxlabelsmultiflex['workoutid'] = 'Workout'
|
||||
parchoicesmultiflex = list(sorted(formaxlabelsmultiflex.items(), key = lambda x:x[1]))
|
||||
|
||||
from utils import palettes
|
||||
from rowers.utils import palettes
|
||||
|
||||
palettechoices = tuple((p,p) for p in palettes.keys())
|
||||
|
||||
@@ -950,7 +957,7 @@ class RaceResultFilterForm(forms.Form):
|
||||
|
||||
weightcategories = (
|
||||
('hwt','heavy-weight'),
|
||||
('lwt','light-weight'),
|
||||
('lwt','light-weight'),
|
||||
)
|
||||
|
||||
adaptivecategories = mytypes.adaptivetypes
|
||||
|
||||
+33
-28
@@ -1,3 +1,9 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
# All the functionality to connect to SportTracks
|
||||
|
||||
# Python
|
||||
@@ -16,7 +22,7 @@ from dateutil import parser
|
||||
import time
|
||||
from time import strftime
|
||||
|
||||
import dataprep
|
||||
import rowers.dataprep as dataprep
|
||||
import math
|
||||
from math import sin,cos,atan2,sqrt
|
||||
import os,sys
|
||||
@@ -38,7 +44,7 @@ from django.contrib.auth.decorators import login_required
|
||||
from rowingdata import rowingdata, make_cumvalues
|
||||
import pandas as pd
|
||||
from rowers.models import Rower,Workout,checkworkoutuser
|
||||
from rowers import mytypes
|
||||
import rowers.mytypes as mytypes
|
||||
from rowsandall_app.settings import (
|
||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI,
|
||||
@@ -46,7 +52,7 @@ from rowsandall_app.settings import (
|
||||
SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI
|
||||
)
|
||||
|
||||
from utils import (
|
||||
from rowers.utils import (
|
||||
NoTokenError, custom_exception_handler, ewmovingaverage,
|
||||
geo_distance,isprorower,uniqify
|
||||
)
|
||||
@@ -59,9 +65,9 @@ def splitstdata(lijst):
|
||||
t = []
|
||||
latlong = []
|
||||
while len(lijst)>=2:
|
||||
t.append(lijst[0])
|
||||
latlong.append(lijst[1])
|
||||
lijst = lijst[2:]
|
||||
t.append(lijst[0])
|
||||
latlong.append(lijst[1])
|
||||
lijst = lijst[2:]
|
||||
|
||||
return [np.array(t),np.array(latlong)]
|
||||
|
||||
@@ -103,7 +109,6 @@ def imports_open(user,oauth_data):
|
||||
oauth_data,
|
||||
)
|
||||
elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename:
|
||||
print 'noot'
|
||||
token = imports_token_refresh(
|
||||
user,
|
||||
tokenname,
|
||||
@@ -124,13 +129,13 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
)
|
||||
|
||||
post_data = {"grant_type": "refresh_token",
|
||||
"client_secret": oauth_data['client_secret'],
|
||||
"client_id": oauth_data['client_id'],
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
"client_secret": oauth_data['client_secret'],
|
||||
"client_id": oauth_data['client_id'],
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
headers = {'user-agent': 'sanderroosendaal',
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': oauth_data['content_type']}
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': oauth_data['content_type']}
|
||||
|
||||
# for Strava
|
||||
if 'grant_type' in oauth_data:
|
||||
@@ -147,11 +152,11 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
if 'json' in oauth_data['content_type']:
|
||||
response = requests.post(baseurl,
|
||||
data=json.dumps(post_data),
|
||||
headers=headers)
|
||||
headers=headers)
|
||||
else:
|
||||
response = requests.post(baseurl,
|
||||
data=post_data,
|
||||
headers=headers)
|
||||
headers=headers)
|
||||
|
||||
|
||||
|
||||
@@ -174,9 +179,9 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
except KeyError:
|
||||
expires_in = 0
|
||||
try:
|
||||
refresh_token = token_json['refresh_token']
|
||||
refresh_token = token_json['refresh_token']
|
||||
except KeyError:
|
||||
refresh_token = refreshtoken
|
||||
refresh_token = refreshtoken
|
||||
try:
|
||||
expires_in = int(expires_in)
|
||||
except (TypeError,ValueError):
|
||||
@@ -204,16 +209,16 @@ def imports_get_token(
|
||||
post_data = {"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"redirect_uri": redirect_uri,
|
||||
"client_secret": client_secret,
|
||||
"client_id": client_id,
|
||||
}
|
||||
"client_secret": client_secret,
|
||||
"client_id": client_id,
|
||||
}
|
||||
|
||||
try:
|
||||
headers = oauth_data['headers']
|
||||
except KeyError:
|
||||
headers = {'Accept': 'application/json',
|
||||
'Api-Key': client_id,
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'user-agent': 'sanderroosendaal'}
|
||||
|
||||
if 'grant_type' in oauth_data:
|
||||
@@ -229,12 +234,12 @@ def imports_get_token(
|
||||
response = requests.post(
|
||||
base_uri,
|
||||
data=json.dumps(post_data),
|
||||
headers=headers)
|
||||
headers=headers)
|
||||
else:
|
||||
response = requests.post(
|
||||
base_uri,
|
||||
data=post_data,
|
||||
headers=headers)
|
||||
headers=headers)
|
||||
|
||||
if response.status_code == 200 or response.status_code == 201:
|
||||
token_json = response.json()
|
||||
@@ -243,9 +248,9 @@ def imports_get_token(
|
||||
except KeyError:
|
||||
return [0,0,0]
|
||||
try:
|
||||
refresh_token = token_json['refresh_token']
|
||||
refresh_token = token_json['refresh_token']
|
||||
except KeyError:
|
||||
refresh_token = ''
|
||||
refresh_token = ''
|
||||
try:
|
||||
expires_in = token_json['expires_in']
|
||||
except KeyError:
|
||||
@@ -270,12 +275,12 @@ def imports_make_authorization_url(oauth_data):
|
||||
params = {"client_id": oauth_data['client_id'],
|
||||
"response_type": "code",
|
||||
"redirect_uri": oauth_data['redirect_uri'],
|
||||
"scope":oauth_data['scope'],
|
||||
"state":state}
|
||||
"scope":oauth_data['scope'],
|
||||
"state":state}
|
||||
|
||||
|
||||
import urllib
|
||||
url = oauth_data['authorizaton_uri']+urllib.urlencode(params)
|
||||
url = oauth_data['authorizaton_uri']+urllib.parse.urlencode(params)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
+925
-733
File diff suppressed because it is too large
Load Diff
+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
|
||||
import numpy as np
|
||||
import time
|
||||
@@ -72,7 +77,7 @@ def longtask2(aantal,jobid=None,debug=False,secret=''):
|
||||
counter = 0
|
||||
progress = int(100.*i/aantal)
|
||||
if debug:
|
||||
print progress
|
||||
print(progress)
|
||||
if jobid != None:
|
||||
if debug:
|
||||
url = SITE_URL_DEV
|
||||
@@ -83,8 +88,8 @@ def longtask2(aantal,jobid=None,debug=False,secret=''):
|
||||
post_data = {"secret":secret}
|
||||
s = requests.post(url, data=post_data)
|
||||
if debug:
|
||||
print url
|
||||
print s
|
||||
print(url)
|
||||
print(s)
|
||||
|
||||
|
||||
return 1
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Processes emails sent to workouts@rowsandall.com
|
||||
""" Processes emails sent to workouts@rowsandall.com """
|
||||
import shutil
|
||||
@@ -92,7 +97,7 @@ def make_new_workout_from_email(rower, datafile, name, cntr=0,testing=False):
|
||||
fileformat = fileformat[2]
|
||||
|
||||
if testing:
|
||||
print 'Fileformat = ',fileformat
|
||||
print('Fileformat = ',fileformat)
|
||||
|
||||
if fileformat == 'unknown':
|
||||
# extension = datafilename[-4:].lower()
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
#!/srv/venv/bin/python
|
||||
|
||||
""" Process emails """
|
||||
import sys
|
||||
import os
|
||||
PY3K = sys.version_info >= (3, 0)
|
||||
|
||||
import zipfile
|
||||
import re
|
||||
import time
|
||||
from time import strftime
|
||||
|
||||
import io
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from django_mailbox.models import Message, MessageAttachment,Mailbox
|
||||
from django.core.urlresolvers import reverse
|
||||
@@ -57,20 +61,20 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
|
||||
except AttributeError:
|
||||
filename = fileobj[6:]
|
||||
if testing:
|
||||
print 'Attribute Error', filename
|
||||
print('Attribute Error', filename)
|
||||
|
||||
|
||||
# test if file exists and is not empty
|
||||
try:
|
||||
with open('media/'+filename,'r') as fop:
|
||||
with io.open('media/'+filename,'rb') as fop:
|
||||
line = fop.readline()
|
||||
except (IOError, UnicodeEncodeError):
|
||||
if testing:
|
||||
print 'IOError',filename,'media/'+filename
|
||||
print('IOError',filename,'media/'+filename)
|
||||
return 0
|
||||
|
||||
if testing:
|
||||
print 'Creating workout from email'
|
||||
print('Creating workout from email')
|
||||
|
||||
# set user
|
||||
if rower.user.is_staff and 'username' in uploadoptions:
|
||||
@@ -102,7 +106,7 @@ def processattachment(rower, fileobj, title, uploadoptions,testing=False):
|
||||
pass
|
||||
|
||||
if testing:
|
||||
print 'Workout id = {workoutid}'.format(workoutid=workoutid)
|
||||
print('Workout id = {workoutid}'.format(workoutid=workoutid))
|
||||
|
||||
if workoutid[0]:
|
||||
link = settings.SITE_URL+reverse(
|
||||
@@ -164,6 +168,11 @@ def get_from_address(message):
|
||||
except IndexError:
|
||||
first_line = ''
|
||||
|
||||
try:
|
||||
first_line = first_line.decode('utf-8')
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
if "quiske" in first_line:
|
||||
match = re.search(r'[\w\.-]+@[\w\.-]+', first_line)
|
||||
return match.group(0)
|
||||
@@ -242,17 +251,17 @@ class Command(BaseCommand):
|
||||
testing=testing
|
||||
)
|
||||
except:
|
||||
print "Bad ZIP file"
|
||||
print attachment.document.name
|
||||
print("Bad ZIP file")
|
||||
print(attachment.document.name)
|
||||
else:
|
||||
# move attachment and make workout
|
||||
if testing:
|
||||
try:
|
||||
print name
|
||||
print(name)
|
||||
except UnicodeEncodeError:
|
||||
print "Unicode Error"
|
||||
print("Unicode Error")
|
||||
try:
|
||||
print attachment.document
|
||||
print(attachment.document)
|
||||
except UnicodeEncodeError:
|
||||
pass
|
||||
|
||||
|
||||
+8
-2
@@ -1,6 +1,12 @@
|
||||
from utils import lbstoN
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from __future__ import absolute_import
|
||||
from rowers.utils import lbstoN
|
||||
import numpy as np
|
||||
from models import C2WorldClassAgePerformance
|
||||
from rowers.models import C2WorldClassAgePerformance
|
||||
import pandas as pd
|
||||
from scipy import optimize
|
||||
from django.utils import timezone
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
from django.utils import timezone
|
||||
from rowers.models import Workout, PowerTimeFitnessMetric, Rower
|
||||
import datetime
|
||||
from utils import myqueue
|
||||
from rowers.utils import myqueue
|
||||
import django_rq
|
||||
queue = django_rq.get_queue('default')
|
||||
from rowers.tasks import handle_updatefitnessmetric,handle_sendemail_expired
|
||||
|
||||
+279
-258
File diff suppressed because it is too large
Load Diff
+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 = (
|
||||
('water','Standard Racing Shell'),
|
||||
('rower','Indoor Rower'),
|
||||
@@ -208,15 +214,15 @@ c2mapping = {
|
||||
|
||||
}
|
||||
|
||||
c2mappinginv = {value:key for key,value in c2mapping.iteritems() if value is not None}
|
||||
c2mappinginv = {value:key for key,value in iteritems(c2mapping) if value is not None}
|
||||
|
||||
stravamappinginv = {value:key for key,value in stravamapping.iteritems() if value is not None}
|
||||
stravamappinginv = {value:key for key,value in iteritems(stravamapping) if value is not None}
|
||||
|
||||
stmappinginv = {value:key for key,value in stmapping.iteritems() if value is not None}
|
||||
stmappinginv = {value:key for key,value in iteritems(stmapping) if value is not None}
|
||||
|
||||
rkmappinginv = {value:key for key,value in rkmapping.iteritems() if value is not None}
|
||||
rkmappinginv = {value:key for key,value in iteritems(rkmapping) if value is not None}
|
||||
|
||||
polarmappinginv = {value:key for key,value in polarmapping.iteritems() if value is not None}
|
||||
polarmappinginv = {value:key for key,value in iteritems(polarmapping) if value is not None}
|
||||
|
||||
otwtypes = (
|
||||
'water',
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import struct
|
||||
import base64
|
||||
|
||||
|
||||
+99
-94
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
# Interactions with Rowsandall.com API. Not fully complete.
|
||||
|
||||
# Python
|
||||
@@ -15,7 +20,7 @@ import math
|
||||
from math import sin,cos,atan2,sqrt
|
||||
|
||||
import urllib
|
||||
import c2stuff
|
||||
import rowers.c2stuff as c2stuff
|
||||
|
||||
# Django
|
||||
from django.shortcuts import render_to_response
|
||||
@@ -41,13 +46,13 @@ TEST_REDIRECT_URI = "http://localhost:8000/rowers/test_callback"
|
||||
def custom_exception_handler(exc,message):
|
||||
|
||||
response = {
|
||||
"errors": [
|
||||
{
|
||||
"code": str(exc),
|
||||
"detail": message,
|
||||
}
|
||||
]
|
||||
}
|
||||
"errors": [
|
||||
{
|
||||
"code": str(exc),
|
||||
"detail": message,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
res = HttpResponse(message)
|
||||
res.status_code = 401
|
||||
@@ -58,27 +63,27 @@ def custom_exception_handler(exc,message):
|
||||
def do_refresh_token(refreshtoken):
|
||||
client_auth = requests.auth.HTTPBasicAuth(TEST_CLIENT_ID, TEST_CLIENT_SECRET)
|
||||
post_data = {"grant_type": "refresh_token",
|
||||
"client_secret": TEST_CLIENT_SECRET,
|
||||
"client_id":TEST_CLIENT_ID,
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
"client_secret": TEST_CLIENT_SECRET,
|
||||
"client_id":TEST_CLIENT_ID,
|
||||
"refresh_token": refreshtoken,
|
||||
}
|
||||
headers = {'user-agent': 'sanderroosendaal',
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'}
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'}
|
||||
|
||||
url = "http://localhost:8000/rowers/o/token"
|
||||
|
||||
response = requests.post(url,
|
||||
data=json.dumps(post_data),
|
||||
headers=headers)
|
||||
headers=headers)
|
||||
|
||||
token_json = response.json()
|
||||
thetoken = token_json['access_token']
|
||||
expires_in = token_json['expires_in']
|
||||
try:
|
||||
refresh_token = token_json['refresh_token']
|
||||
refresh_token = token_json['refresh_token']
|
||||
except KeyError:
|
||||
refresh_token = refreshtoken
|
||||
refresh_token = refreshtoken
|
||||
|
||||
return [thetoken,expires_in,refresh_token]
|
||||
|
||||
@@ -88,18 +93,18 @@ def get_token(code):
|
||||
post_data = {"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"redirect_uri": "http://localhost:8000/rowers/test_callback",
|
||||
"client_secret": "aapnootmies",
|
||||
"client_id":1,
|
||||
}
|
||||
"client_secret": "aapnootmies",
|
||||
"client_id":1,
|
||||
}
|
||||
headers = {'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'}
|
||||
'Content-Type': 'application/json'}
|
||||
|
||||
url = "http://localhost:8000/rowers/o/token/"
|
||||
|
||||
|
||||
response = requests.post(url,
|
||||
data=json.dumps(post_data),
|
||||
headers=headers)
|
||||
headers=headers)
|
||||
|
||||
token_json = response.json()
|
||||
thetoken = token_json['access_token']
|
||||
@@ -118,12 +123,12 @@ def make_authorization_url(request):
|
||||
params = {"client_id": TEST_CLIENT_ID,
|
||||
"response_type": "code",
|
||||
"redirect_uri": TEST_REDIRECT_URI,
|
||||
"scope":"write",
|
||||
"state":state}
|
||||
"scope":"write",
|
||||
"state":state}
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@@ -147,19 +152,19 @@ def rower_ownapi_token_refresh(user):
|
||||
def get_ownapi_workout_list(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.ownapitoken == '') or (r.ownapitoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (timezone.now()>r.ownapitokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.ownapitoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ownapi.mobi/api/v2/fitnessActivities"
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.ownapitoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ownapi.mobi/api/v2/fitnessActivities"
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
@@ -167,19 +172,19 @@ def get_ownapi_workout_list(user):
|
||||
def get_ownapi_workout(user,ownapiid):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.ownapitoken == '') or (r.ownapitoken is None):
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
elif (timezone.now()>r.ownapitokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.ownapitoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ownapi.mobi/api/v2/fitnessActivities/"+str(ownapiid)
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.ownapitoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.ownapi.mobi/api/v2/fitnessActivities/"+str(ownapiid)
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
@@ -203,16 +208,16 @@ def createownapiworkoutdata(w):
|
||||
haslatlon=1
|
||||
|
||||
try:
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
except KeyError:
|
||||
haslatlon = 0
|
||||
haslatlon = 0
|
||||
|
||||
haspower = 1
|
||||
try:
|
||||
power = row.df[' Power (watts)'].values
|
||||
power = row.df[' Power (watts)'].values
|
||||
except KeyError:
|
||||
haspower = 0
|
||||
haspower = 0
|
||||
|
||||
locdata = []
|
||||
hrdata = []
|
||||
@@ -221,54 +226,54 @@ def createownapiworkoutdata(w):
|
||||
powerdata = []
|
||||
|
||||
for i in range(len(t)):
|
||||
hrdata.append(t[i])
|
||||
hrdata.append(hr[i])
|
||||
distancedata.append(t[i])
|
||||
distancedata.append(d[i])
|
||||
spmdata.append(t[i])
|
||||
spmdata.append(spm[i])
|
||||
if haslatlon:
|
||||
locdata.append(t[i])
|
||||
locdata.append([lat[i],lon[i]])
|
||||
if haspower:
|
||||
powerdata.append(t[i])
|
||||
powerdata.append(power[i])
|
||||
hrdata.append(t[i])
|
||||
hrdata.append(hr[i])
|
||||
distancedata.append(t[i])
|
||||
distancedata.append(d[i])
|
||||
spmdata.append(t[i])
|
||||
spmdata.append(spm[i])
|
||||
if haslatlon:
|
||||
locdata.append(t[i])
|
||||
locdata.append([lat[i],lon[i]])
|
||||
if haspower:
|
||||
powerdata.append(t[i])
|
||||
powerdata.append(power[i])
|
||||
|
||||
|
||||
if haslatlon:
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
# "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
|
||||
"start_time": w.startdatetime.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": int(max(t)),
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"location": locdata,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
# "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
|
||||
"start_time": w.startdatetime.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": int(max(t)),
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"location": locdata,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
else:
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
# "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
|
||||
"start_time": w.startdatetime.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": int(max(t)),
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
# "start_time": str(w.date)+"T"+str(w.starttime)+"Z",
|
||||
"start_time": w.startdatetime.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": int(max(t)),
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
|
||||
if haspower:
|
||||
data['power'] = powerdata
|
||||
data['power'] = powerdata
|
||||
|
||||
return data
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from rowers.models import Rower,PaidPlan
|
||||
|
||||
# run once - copies plans to paypal
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
# Defines permissions for objects (API related)
|
||||
|
||||
from rest_framework import permissions
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Python
|
||||
from django.utils import timezone
|
||||
from datetime import datetime
|
||||
@@ -10,7 +15,7 @@ import uuid
|
||||
from django.conf import settings
|
||||
import pytz
|
||||
from dateutil import parser
|
||||
from utils import myqueue,calculate_age,totaltime_sec_to_string
|
||||
from rowers.utils import myqueue,calculate_age,totaltime_sec_to_string
|
||||
import re
|
||||
import django_rq
|
||||
queue = django_rq.get_queue('default')
|
||||
@@ -30,10 +35,10 @@ from rowers.emails import htmlstrip,htmlstripnobr
|
||||
|
||||
import rowers.mytypes as mytypes
|
||||
|
||||
import metrics
|
||||
import rowers.metrics as metrics
|
||||
import numpy as np
|
||||
import dataprep
|
||||
import courses
|
||||
import rowers.dataprep as dataprep
|
||||
import rowers.courses as courses
|
||||
import iso8601
|
||||
from iso8601 import ParseError
|
||||
from rowers.tasks import handle_check_race_course
|
||||
@@ -360,7 +365,7 @@ def is_session_complete_ws(ws,ps):
|
||||
return ratio,'partial',completiondate
|
||||
else:
|
||||
thevalue = 0
|
||||
for key,value in cratios.iteritems():
|
||||
for key,value in cratios.items():
|
||||
if ratio>value and value>thevalue:
|
||||
verdict = key
|
||||
thevalue = value
|
||||
|
||||
+25
-20
@@ -1,15 +1,20 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
import numpy as np
|
||||
from rows import format_pace_tick, format_pace, format_time, format_time_tick
|
||||
from rowers.rows import format_pace_tick, format_pace, format_time, format_time_tick
|
||||
|
||||
|
||||
# Formatting the distance tick marks
|
||||
#def format_dist_tick(x,pos=None):
|
||||
# km = x/1000.
|
||||
# template='%6.3f'
|
||||
# return template % (km)
|
||||
# km = x/1000.
|
||||
# template='%6.3f'
|
||||
# return template % (km)
|
||||
|
||||
|
||||
# Utility to select reasonable y axis range
|
||||
@@ -32,23 +37,23 @@ def y_axis_range(ydata,miny=0,padding=.1,ultimate=[-1e9,1e9]):
|
||||
|
||||
|
||||
if (yrange == 0):
|
||||
if ymin == 0:
|
||||
yrangemin = -padding
|
||||
else:
|
||||
yrangemin = ymin-ymin*padding
|
||||
if ymax == 0:
|
||||
yrangemax = padding
|
||||
else:
|
||||
yrangemax = ymax+ymax*padding
|
||||
if ymin == 0:
|
||||
yrangemin = -padding
|
||||
else:
|
||||
yrangemin = ymin-ymin*padding
|
||||
if ymax == 0:
|
||||
yrangemax = padding
|
||||
else:
|
||||
yrangemax = ymax+ymax*padding
|
||||
else:
|
||||
yrangemin = ymin-padding*yrange
|
||||
yrangemax = ymax+padding*yrange
|
||||
yrangemin = ymin-padding*yrange
|
||||
yrangemax = ymax+padding*yrange
|
||||
|
||||
if (yrangemin < ultimate[0]):
|
||||
yrangemin = ultimate[0]
|
||||
yrangemin = ultimate[0]
|
||||
|
||||
if (yrangemax > ultimate[1]):
|
||||
yrangemax = ultimate[1]
|
||||
yrangemax = ultimate[1]
|
||||
|
||||
|
||||
|
||||
@@ -70,7 +75,7 @@ def mkplot(row,title):
|
||||
ax1.set_ylabel('(sec/500)')
|
||||
|
||||
yrange = y_axis_range(df.loc[:,' Stroke500mPace (sec/500m)'],
|
||||
ultimate = [85,190])
|
||||
ultimate = [85,190])
|
||||
plt.axis([0,end_time,yrange[1],yrange[0]])
|
||||
|
||||
ax1.set_xticks(range(1000,end_time,1000))
|
||||
@@ -80,11 +85,11 @@ def mkplot(row,title):
|
||||
majorFormatter = FuncFormatter(format_pace_tick)
|
||||
majorLocator = (5)
|
||||
timeTickFormatter = NullFormatter()
|
||||
|
||||
|
||||
ax1.yaxis.set_major_formatter(majorFormatter)
|
||||
|
||||
for tl in ax1.get_yticklabels():
|
||||
tl.set_color('b')
|
||||
tl.set_color('b')
|
||||
|
||||
ax2 = ax1.twinx()
|
||||
ax2.plot(t,hr,'r-')
|
||||
@@ -94,7 +99,7 @@ def mkplot(row,title):
|
||||
ax2.xaxis.set_major_formatter(majorTimeFormatter)
|
||||
ax2.patch.set_alpha(0.0)
|
||||
for tl in ax2.get_yticklabels():
|
||||
tl.set_color('r')
|
||||
tl.set_color('r')
|
||||
|
||||
plt.subplots_adjust(hspace=0)
|
||||
|
||||
|
||||
+22
-12
@@ -1,3 +1,9 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
# All the functionality needed to connect to Strava
|
||||
|
||||
# Python
|
||||
@@ -33,8 +39,8 @@ from rowingdata import rowingdata
|
||||
import pandas as pd
|
||||
from rowers.models import Rower,Workout
|
||||
from rowers.models import checkworkoutuser
|
||||
import dataprep
|
||||
from dataprep import columndict
|
||||
import rowers.dataprep as dataprep
|
||||
from rowers.dataprep import columndict
|
||||
|
||||
from io import StringIO
|
||||
|
||||
@@ -51,8 +57,8 @@ from rowsandall_app.settings import (
|
||||
baseurl = 'https://polaraccesslink.com/v3'
|
||||
|
||||
|
||||
from utils import NoTokenError, custom_exception_handler
|
||||
import mytypes
|
||||
from rowers.utils import NoTokenError, custom_exception_handler
|
||||
import rowers.mytypes as mytypes
|
||||
|
||||
# Exchange access code for long-lived access token
|
||||
def get_token(code):
|
||||
@@ -67,8 +73,11 @@ def get_token(code):
|
||||
secret=POLAR_CLIENT_SECRET
|
||||
)
|
||||
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
|
||||
|
||||
try:
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
|
||||
except TypeError:
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(bytes(auth_string,'utf-8')) }
|
||||
|
||||
response = requests.post("https://polarremote.com/v2/oauth2/token",
|
||||
data=post_data,
|
||||
headers=headers)
|
||||
@@ -97,7 +106,7 @@ def make_authorization_url():
|
||||
"redirect_uri": POLAR_REDIRECT_URI,
|
||||
"scope":"write"}
|
||||
import urllib
|
||||
url = "https://flow.polar.com/oauth2/authorization" +urllib.urlencode(params)
|
||||
url = "https://flow.polar.com/oauth2/authorization" +urllib.parse.urlencode(params)
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
@@ -110,7 +119,10 @@ def get_polar_notifications():
|
||||
secret=POLAR_CLIENT_SECRET
|
||||
)
|
||||
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
|
||||
try:
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(auth_string) }
|
||||
except TypeError:
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(bytes(auth_string,'utf-8')) }
|
||||
|
||||
response = requests.get(url, headers=headers)
|
||||
|
||||
@@ -126,7 +138,7 @@ from rowers.utils import isprorower
|
||||
def get_all_new_workouts(available_data,testing=False):
|
||||
for record in available_data:
|
||||
if testing:
|
||||
print record
|
||||
print(record)
|
||||
if record['data-type'] == 'EXERCISE':
|
||||
try:
|
||||
r = Rower.objects.get(polaruserid=record['user-id'])
|
||||
@@ -134,7 +146,7 @@ def get_all_new_workouts(available_data,testing=False):
|
||||
if r.polar_auto_import and isprorower(r):
|
||||
exercise_list = get_polar_workouts(u)
|
||||
if testing:
|
||||
print exercise_list
|
||||
print(exercise_list)
|
||||
except Rower.DoesNotExist:
|
||||
pass
|
||||
|
||||
@@ -313,8 +325,6 @@ def get_polar_workout(user,id,transactionid):
|
||||
response = requests.get(url,headers = headers2)
|
||||
|
||||
if response.status_code == 200:
|
||||
print response.text
|
||||
|
||||
result = response.text
|
||||
# commit transaction
|
||||
response = requests.put(url,headers=headers)
|
||||
|
||||
+27
-22
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import time
|
||||
import gzip
|
||||
import shutil
|
||||
@@ -6,29 +11,29 @@ from django.core.exceptions import ValidationError
|
||||
|
||||
def format_pace_tick(x,pos=None):
|
||||
minu=int(x/60)
|
||||
sec=int(x-minu*60.)
|
||||
sec_str=str(sec).zfill(2)
|
||||
template='%d:%s'
|
||||
return template % (minu,sec_str)
|
||||
sec=int(x-minu*60.)
|
||||
sec_str=str(sec).zfill(2)
|
||||
template='%d:%s'
|
||||
return template % (minu,sec_str)
|
||||
|
||||
def format_time_tick(x,pos=None):
|
||||
hour=int(x/3600)
|
||||
min=int((x-hour*3600.)/60)
|
||||
min_str=str(min).zfill(2)
|
||||
template='%d:%s'
|
||||
return template % (hour,min_str)
|
||||
hour=int(x/3600)
|
||||
min=int((x-hour*3600.)/60)
|
||||
min_str=str(min).zfill(2)
|
||||
template='%d:%s'
|
||||
return template % (hour,min_str)
|
||||
|
||||
def format_pace(x,pos=None):
|
||||
if isinf(x) or isnan(x):
|
||||
x=0
|
||||
|
||||
x=0
|
||||
|
||||
min=int(x/60)
|
||||
sec=(x-min*60.)
|
||||
|
||||
str1 = "{min:0>2}:{sec:0>4.1f}".format(
|
||||
min = min,
|
||||
sec = sec
|
||||
)
|
||||
min = min,
|
||||
sec = sec
|
||||
)
|
||||
|
||||
return str1
|
||||
|
||||
@@ -39,9 +44,9 @@ def format_time(x,pos=None):
|
||||
sec = int(x-min*60)
|
||||
|
||||
str1 = "{min:0>2}:{sec:0>4.1f}".format(
|
||||
min=min,
|
||||
sec=sec,
|
||||
)
|
||||
min=min,
|
||||
sec=sec,
|
||||
)
|
||||
|
||||
return str1
|
||||
|
||||
@@ -67,14 +72,14 @@ def must_be_csv(value):
|
||||
ext = os.path.splitext(value.name)[1]
|
||||
valid_extensions = ['.csv','.CSV']
|
||||
if not ext in valid_extensions:
|
||||
raise ValidationError(u'File not supported!')
|
||||
raise ValidationError(u'File not supported!')
|
||||
|
||||
def validate_kml(value):
|
||||
import os
|
||||
ext = os.path.splitext(value.name)[1]
|
||||
valid_extensions = ['.kml','.KML']
|
||||
if not ext in valid_extensions:
|
||||
raise ValidationError(u'File not supported!')
|
||||
raise ValidationError(u'File not supported!')
|
||||
|
||||
|
||||
def handle_uploaded_image(i):
|
||||
@@ -83,7 +88,7 @@ def handle_uploaded_image(i):
|
||||
import os
|
||||
from django.core.files import File
|
||||
image_str = ""
|
||||
for chunk in i.chunks():
|
||||
for chunk in i.chunks():
|
||||
image_str += chunk
|
||||
|
||||
imagefile = StringIO.StringIO(image_str)
|
||||
@@ -133,8 +138,8 @@ def handle_uploaded_file(f):
|
||||
fname = timestr+'-'+fname
|
||||
fname2 = 'media/'+fname
|
||||
with open(fname2,'wb+') as destination:
|
||||
for chunk in f.chunks():
|
||||
destination.write(chunk)
|
||||
for chunk in f.chunks():
|
||||
destination.write(chunk)
|
||||
|
||||
return fname,fname2
|
||||
|
||||
|
||||
+123
-112
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
# All the functionality needed to connect to Runkeeper
|
||||
from rowers.imports import *
|
||||
import re
|
||||
@@ -24,6 +29,8 @@ oauth_data = {
|
||||
}
|
||||
|
||||
|
||||
import numpy
|
||||
|
||||
def splitrunkeeperlatlongdata(lijst,tname,latname,lonname):
|
||||
t = []
|
||||
lat = []
|
||||
@@ -61,16 +68,16 @@ def make_authorization_url(request):
|
||||
def get_runkeeper_workout_list(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.runkeepertoken == '') or (r.runkeepertoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.runkeepertoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.runkeeper.com/fitnessActivities"
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.runkeepertoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.runkeeper.com/fitnessActivities"
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
@@ -78,16 +85,16 @@ def get_runkeeper_workout_list(user):
|
||||
def get_workout(user,runkeeperid):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.runkeepertoken == '') or (r.runkeepertoken is None):
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.runkeepertoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid)
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.runkeepertoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid)
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
try:
|
||||
data = s.json()
|
||||
@@ -131,12 +138,12 @@ def createrunkeeperworkoutdata(w):
|
||||
haslatlon=1
|
||||
|
||||
try:
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
if not lat.std() and not lon.std():
|
||||
haslatlon = 0
|
||||
except KeyError:
|
||||
haslatlon = 0
|
||||
haslatlon = 0
|
||||
|
||||
# path data
|
||||
if haslatlon:
|
||||
@@ -172,32 +179,32 @@ def createrunkeeperworkoutdata(w):
|
||||
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
|
||||
|
||||
if haslatlon:
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"start_time": start_time,
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": newnotes,
|
||||
"average_heart_rate": averagehr,
|
||||
"path": locdata,
|
||||
"distance": distancedata,
|
||||
"heart_rate": hrdata,
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"start_time": start_time,
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": newnotes,
|
||||
"average_heart_rate": averagehr,
|
||||
"path": locdata,
|
||||
"distance": distancedata,
|
||||
"heart_rate": hrdata,
|
||||
"post_to_twitter":"false",
|
||||
"post_to_facebook":"false",
|
||||
}
|
||||
}
|
||||
else:
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"start_time": start_time,
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": newnotes,
|
||||
"avg_heartrate": averagehr,
|
||||
"distance": distancedata,
|
||||
"heart_rate": hrdata,
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"start_time": start_time,
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": newnotes,
|
||||
"avg_heartrate": averagehr,
|
||||
"distance": distancedata,
|
||||
"heart_rate": hrdata,
|
||||
"post_to_twitter":"false",
|
||||
"post_to_facebook":"false",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return data
|
||||
@@ -215,8 +222,8 @@ def getidfromresponse(response):
|
||||
def geturifromid(access_token,id):
|
||||
authorizationstring = str('Bearer ' + access_token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
import urllib
|
||||
url = "https://api.runkeeper.com/fitnessActivities/"+str(id)
|
||||
response = requests.get(url,headers=headers)
|
||||
@@ -238,8 +245,8 @@ def geturifromid(access_token,id):
|
||||
def get_userid(access_token):
|
||||
authorizationstring = str('Bearer ' + access_token)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
import urllib
|
||||
url = "https://api.runkeeper.com/user"
|
||||
response = requests.get(url,headers=headers)
|
||||
@@ -257,6 +264,10 @@ def get_userid(access_token):
|
||||
|
||||
return str(res)
|
||||
|
||||
def default(o):
|
||||
if isinstance(o, numpy.int64): return int(o)
|
||||
raise TypeError
|
||||
|
||||
def workout_runkeeper_upload(user,w):
|
||||
message = "Uploading to Runkeeper"
|
||||
rkid = 0
|
||||
@@ -269,42 +280,42 @@ def workout_runkeeper_upload(user,w):
|
||||
# ready to upload. Hurray
|
||||
|
||||
if (checkworkoutuser(user,w)):
|
||||
data = createrunkeeperworkoutdata(w)
|
||||
data = createrunkeeperworkoutdata(w)
|
||||
if not data:
|
||||
message = "Data error in Runkeeper Upload"
|
||||
rkid = 0
|
||||
return message, rkid
|
||||
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json',
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json',
|
||||
'Content-Length':'nnn'}
|
||||
|
||||
url = "https://api.runkeeper.com/fitnessActivities"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data))
|
||||
url = "https://api.runkeeper.com/fitnessActivities"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
|
||||
|
||||
# check for duplicate error first
|
||||
if (response.status_code == 409 ):
|
||||
message = "Duplicate error"
|
||||
w.uploadedtorunkeeper = -1
|
||||
# check for duplicate error first
|
||||
if (response.status_code == 409 ):
|
||||
message = "Duplicate error"
|
||||
w.uploadedtorunkeeper = -1
|
||||
rkid = -1
|
||||
w.save()
|
||||
w.save()
|
||||
return message, rkid
|
||||
elif (response.status_code == 201 or response.status_code==200):
|
||||
rkid = getidfromresponse(response)
|
||||
elif (response.status_code == 201 or response.status_code==200):
|
||||
rkid = getidfromresponse(response)
|
||||
rkuri = geturifromid(thetoken,rkid)
|
||||
w.uploadedtorunkeeper = rkid
|
||||
w.save()
|
||||
w.uploadedtorunkeeper = rkid
|
||||
w.save()
|
||||
return 'Successfully synchronized to Runkeeper',rkid
|
||||
else:
|
||||
s = response
|
||||
message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text)
|
||||
else:
|
||||
s = response
|
||||
message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text)
|
||||
rkid = 0
|
||||
return message, rkid
|
||||
|
||||
|
||||
else:
|
||||
message = "You are not authorized to upload this workout"
|
||||
message = "You are not authorized to upload this workout"
|
||||
rkid = 0
|
||||
return message, rkid
|
||||
|
||||
@@ -316,41 +327,41 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper',
|
||||
# To Do - add utcoffset to time
|
||||
workouttype = data['type']
|
||||
if workouttype not in [x[0] for x in Workout.workouttypes]:
|
||||
workouttype = 'other'
|
||||
workouttype = 'other'
|
||||
try:
|
||||
comments = data['notes']
|
||||
comments = data['notes']
|
||||
except:
|
||||
comments = ''
|
||||
comments = ''
|
||||
|
||||
try:
|
||||
utcoffset = tz(data['utcoffset'])
|
||||
utcoffset = tz(data['utcoffset'])
|
||||
except:
|
||||
utcoffset = 0
|
||||
utcoffset = 0
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
|
||||
try:
|
||||
rowdatetime = iso8601.parse_date(data['start_time'])
|
||||
rowdatetime = iso8601.parse_date(data['start_time'])
|
||||
except iso8601.ParseError:
|
||||
try:
|
||||
rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except ValueError:
|
||||
try:
|
||||
rowdatetime = parser.parse(data['start_time'])
|
||||
#rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
try:
|
||||
rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except ValueError:
|
||||
try:
|
||||
rowdatetime = parser.parse(data['start_time'])
|
||||
#rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
starttimeunix = arrow.get(rowdatetime).timestamp
|
||||
#starttimeunix = mktime(rowdatetime.utctimetuple())
|
||||
starttimeunix += utcoffset*3600
|
||||
|
||||
|
||||
|
||||
try:
|
||||
title = data['name']
|
||||
title = data['name']
|
||||
except:
|
||||
title = "Imported data"
|
||||
title = "Imported data"
|
||||
|
||||
|
||||
|
||||
@@ -360,35 +371,35 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper',
|
||||
times_distance = res[0]
|
||||
|
||||
try:
|
||||
l = data['path']
|
||||
l = data['path']
|
||||
|
||||
res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude')
|
||||
times_location = res[0]
|
||||
latcoord = res[1]
|
||||
loncoord = res[2]
|
||||
res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude')
|
||||
times_location = res[0]
|
||||
latcoord = res[1]
|
||||
loncoord = res[2]
|
||||
|
||||
except:
|
||||
times_location = times_distance
|
||||
latcoord = np.zeros(len(times_distance))
|
||||
loncoord = np.zeros(len(times_distance))
|
||||
times_location = times_distance
|
||||
latcoord = np.zeros(len(times_distance))
|
||||
loncoord = np.zeros(len(times_distance))
|
||||
if workouttype in types.otwtypes:
|
||||
workouttype = 'rower'
|
||||
|
||||
|
||||
try:
|
||||
res = splitrunkeeperdata(data['cadence'],'timestamp','cadence')
|
||||
times_spm = res[0]
|
||||
spm = res[1]
|
||||
res = splitrunkeeperdata(data['cadence'],'timestamp','cadence')
|
||||
times_spm = res[0]
|
||||
spm = res[1]
|
||||
except KeyError:
|
||||
times_spm = times_distance
|
||||
spm = 0*times_distance
|
||||
times_spm = times_distance
|
||||
spm = 0*times_distance
|
||||
|
||||
try:
|
||||
res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate')
|
||||
hr = res[1]
|
||||
times_hr = res[0]
|
||||
res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate')
|
||||
hr = res[1]
|
||||
times_hr = res[0]
|
||||
except KeyError:
|
||||
times_hr = times_distance
|
||||
hr = 0*times_distance
|
||||
times_hr = times_distance
|
||||
hr = 0*times_distance
|
||||
|
||||
|
||||
# create data series and remove duplicates
|
||||
@@ -417,12 +428,12 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper',
|
||||
|
||||
# Create dicts and big dataframe
|
||||
d = {
|
||||
' Horizontal (meters)': distseries,
|
||||
' latitude': latseries,
|
||||
' longitude': lonseries,
|
||||
' Cadence (stokes/min)': spmseries,
|
||||
' HRCur (bpm)' : hrseries,
|
||||
}
|
||||
' Horizontal (meters)': distseries,
|
||||
' latitude': latseries,
|
||||
' longitude': lonseries,
|
||||
' Cadence (stokes/min)': spmseries,
|
||||
' HRCur (bpm)' : hrseries,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -469,7 +480,7 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper',
|
||||
df = df.fillna(0)
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
# csvfilename ='media/Import_'+str(importid)+'.csv'
|
||||
|
||||
+19
-15
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# Serializers. Defines which fields from an object get to the JSON object
|
||||
# Also optionally define POST, PATCH methods (create, update)
|
||||
|
||||
@@ -74,20 +79,20 @@ class WorkoutSerializer(serializers.ModelSerializer):
|
||||
t.second)
|
||||
w = Workout(user=r,
|
||||
name=validated_data['name'],
|
||||
date=validated_data['date'],
|
||||
date=validated_data['date'],
|
||||
workouttype=validated_data['workouttype'],
|
||||
duration=validated_data['duration'],
|
||||
duration=validated_data['duration'],
|
||||
distance=validated_data['distance'],
|
||||
weightcategory=r.weightcategory,
|
||||
adaptiveclass=r.adaptiveclass,
|
||||
starttime=validated_data['starttime'],
|
||||
csvfilename='',
|
||||
weightcategory=r.weightcategory,
|
||||
adaptiveclass=r.adaptiveclass,
|
||||
starttime=validated_data['starttime'],
|
||||
csvfilename='',
|
||||
notes=validated_data['notes'],
|
||||
uploadedtoc2=0,
|
||||
uploadedtoc2=0,
|
||||
summary=validated_data['summary'],
|
||||
averagehr=validated_data['averagehr'],
|
||||
averagehr=validated_data['averagehr'],
|
||||
maxhr=validated_data['maxhr'],
|
||||
startdatetime=rowdatetime,
|
||||
startdatetime=rowdatetime,
|
||||
timezone=validated_data['timezone'],
|
||||
forceunit=validated_data['forceunit'],
|
||||
inboard=validated_data['inboard'],
|
||||
@@ -109,16 +114,16 @@ class WorkoutSerializer(serializers.ModelSerializer):
|
||||
|
||||
|
||||
instance.name=validated_data['name']
|
||||
instance.date=validated_data['date']
|
||||
instance.date=validated_data['date']
|
||||
instance.workouttype=validated_data['workouttype']
|
||||
instance.duration=validated_data['duration']
|
||||
instance.duration=validated_data['duration']
|
||||
instance.distance=validated_data['distance']
|
||||
instance.starttime=validated_data['starttime']
|
||||
instance.starttime=validated_data['starttime']
|
||||
instance.notes=validated_data['notes']
|
||||
instance.summary=validated_data['summary']
|
||||
instance.averagehr=validated_data['averagehr']
|
||||
instance.averagehr=validated_data['averagehr']
|
||||
instance.maxhr=validated_data['maxhr']
|
||||
instance.startdatetime=rowdatetime
|
||||
instance.startdatetime=rowdatetime
|
||||
instance.timezone=validated_data['timezone']
|
||||
instance.forceunit=validated_data['forceunit']
|
||||
instance.inboard=validated_data['inboard']
|
||||
@@ -140,7 +145,6 @@ class StrokeDataSerializer(serializers.Serializer):
|
||||
"""
|
||||
|
||||
# do something
|
||||
print "fake serializer"
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
+151
-138
@@ -1,5 +1,13 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
# All the functionality to connect to SportTracks
|
||||
|
||||
import numpy
|
||||
|
||||
from rowers.imports import *
|
||||
import re
|
||||
from rowsandall_app.settings import (
|
||||
@@ -9,7 +17,7 @@ from rowsandall_app.settings import (
|
||||
SPORTTRACKS_REDIRECT_URI
|
||||
)
|
||||
|
||||
import mytypes
|
||||
import rowers.mytypes as mytypes
|
||||
|
||||
oauth_data = {
|
||||
'client_id': SPORTTRACKS_CLIENT_ID,
|
||||
@@ -64,19 +72,19 @@ def rower_sporttracks_token_refresh(user):
|
||||
def get_sporttracks_workout_list(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (timezone.now()>r.sporttrackstokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.sporttrackstoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities"
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.sporttrackstoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities"
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
return s
|
||||
|
||||
@@ -84,19 +92,19 @@ def get_sporttracks_workout_list(user):
|
||||
def get_workout(user,sporttracksid):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
elif (timezone.now()>r.sporttrackstokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.sporttrackstoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/"+str(sporttracksid)
|
||||
s = requests.get(url,headers=headers)
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.sporttrackstoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/"+str(sporttracksid)
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
data = s.json()
|
||||
|
||||
@@ -144,19 +152,19 @@ def createsporttracksworkoutdata(w):
|
||||
haslatlon=1
|
||||
|
||||
try:
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
lat = row.df[' latitude'].values
|
||||
lon = row.df[' longitude'].values
|
||||
if not lat.std() and not lon.std():
|
||||
haslatlon = 0
|
||||
except KeyError:
|
||||
haslatlon = 0
|
||||
haslatlon = 0
|
||||
|
||||
|
||||
haspower = 1
|
||||
try:
|
||||
power = row.df[' Power (watts)'].astype(int).values
|
||||
power = row.df[' Power (watts)'].astype(int).values
|
||||
except KeyError:
|
||||
haspower = 0
|
||||
haspower = 0
|
||||
|
||||
locdata = []
|
||||
hrdata = []
|
||||
@@ -165,18 +173,18 @@ def createsporttracksworkoutdata(w):
|
||||
powerdata = []
|
||||
|
||||
for i in range(len(t)):
|
||||
hrdata.append(t[i])
|
||||
hrdata.append(hr[i])
|
||||
distancedata.append(t[i])
|
||||
distancedata.append(d[i])
|
||||
spmdata.append(t[i])
|
||||
spmdata.append(spm[i])
|
||||
if haslatlon:
|
||||
locdata.append(t[i])
|
||||
locdata.append([lat[i],lon[i]])
|
||||
if haspower:
|
||||
powerdata.append(t[i])
|
||||
powerdata.append(power[i])
|
||||
hrdata.append(t[i])
|
||||
hrdata.append(hr[i])
|
||||
distancedata.append(t[i])
|
||||
distancedata.append(d[i])
|
||||
spmdata.append(t[i])
|
||||
spmdata.append(spm[i])
|
||||
if haslatlon:
|
||||
locdata.append(t[i])
|
||||
locdata.append([lat[i],lon[i]])
|
||||
if haspower:
|
||||
powerdata.append(t[i])
|
||||
powerdata.append(power[i])
|
||||
|
||||
|
||||
try:
|
||||
@@ -188,37 +196,37 @@ def createsporttracksworkoutdata(w):
|
||||
st = st.replace(microsecond=0)
|
||||
|
||||
if haslatlon:
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
"start_time": st.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"location": locdata,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
"start_time": st.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"location": locdata,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
else:
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
"start_time": st.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
data = {
|
||||
"type": "Rowing",
|
||||
"name": w.name,
|
||||
"start_time": st.isoformat(),
|
||||
"total_distance": int(w.distance),
|
||||
"duration": duration,
|
||||
"notes": w.notes,
|
||||
"avg_heartrate": averagehr,
|
||||
"max_heartrate": maxhr,
|
||||
"distance": distancedata,
|
||||
"cadence": spmdata,
|
||||
"heartrate": hrdata,
|
||||
}
|
||||
|
||||
if haspower:
|
||||
data['power'] = powerdata
|
||||
data['power'] = powerdata
|
||||
|
||||
return data
|
||||
|
||||
@@ -234,6 +242,11 @@ def getidfromresponse(response):
|
||||
|
||||
return int(id)
|
||||
|
||||
def default(o):
|
||||
if isinstance(o, numpy.int64): return int(o)
|
||||
raise TypeError
|
||||
|
||||
|
||||
|
||||
def workout_sporttracks_upload(user,w):
|
||||
message = "Uploading to SportTracks"
|
||||
@@ -244,41 +257,41 @@ def workout_sporttracks_upload(user,w):
|
||||
thetoken = sporttracks_open(user)
|
||||
|
||||
if (checkworkoutuser(user,w)):
|
||||
data = createsporttracksworkoutdata(w)
|
||||
data = createsporttracksworkoutdata(w)
|
||||
if not data:
|
||||
message = "Data error"
|
||||
stid = 0
|
||||
return message,stid
|
||||
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data))
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
|
||||
|
||||
# check for duplicate error first
|
||||
if (response.status_code == 409 ):
|
||||
message = "Duplicate error"
|
||||
w.uploadedtosporttracks = -1
|
||||
# check for duplicate error first
|
||||
if (response.status_code == 409 ):
|
||||
message = "Duplicate error"
|
||||
w.uploadedtosporttracks = -1
|
||||
stid = -1
|
||||
w.save()
|
||||
w.save()
|
||||
return message, stid
|
||||
elif (response.status_code == 201 or response.status_code==200):
|
||||
s= response.json()
|
||||
stid = getidfromresponse(response)
|
||||
w.uploadedtosporttracks = stid
|
||||
w.save()
|
||||
elif (response.status_code == 201 or response.status_code==200):
|
||||
s= response.json()
|
||||
stid = getidfromresponse(response)
|
||||
w.uploadedtosporttracks = stid
|
||||
w.save()
|
||||
return 'Successfully synced to SportTracks',stid
|
||||
else:
|
||||
s = response
|
||||
message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason
|
||||
else:
|
||||
s = response
|
||||
message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason
|
||||
stid = 0
|
||||
return message,stid
|
||||
|
||||
|
||||
else:
|
||||
message = "You are not authorized to upload this workout"
|
||||
message = "You are not authorized to upload this workout"
|
||||
stid = 0
|
||||
return message,stid
|
||||
|
||||
@@ -294,33 +307,33 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks',
|
||||
workouttype = 'other'
|
||||
|
||||
if workouttype not in [x[0] for x in Workout.workouttypes]:
|
||||
workouttype = 'other'
|
||||
workouttype = 'other'
|
||||
try:
|
||||
comments = data['comments']
|
||||
comments = data['comments']
|
||||
except:
|
||||
comments = ''
|
||||
comments = ''
|
||||
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
try:
|
||||
rowdatetime = iso8601.parse_date(data['start_time'])
|
||||
rowdatetime = iso8601.parse_date(data['start_time'])
|
||||
except iso8601.ParseError:
|
||||
try:
|
||||
rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
try:
|
||||
rowdatetime = dateutil.parser.parse(data['start_time'])
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
try:
|
||||
rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
try:
|
||||
rowdatetime = dateutil.parser.parse(data['start_time'])
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
except:
|
||||
rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
|
||||
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
|
||||
starttimeunix = arrow.get(rowdatetime).timestamp
|
||||
|
||||
try:
|
||||
title = data['name']
|
||||
title = data['name']
|
||||
except:
|
||||
title = "Imported data"
|
||||
title = "Imported data"
|
||||
|
||||
try:
|
||||
res = splitstdata(data['distance'])
|
||||
@@ -336,41 +349,41 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks',
|
||||
|
||||
|
||||
try:
|
||||
l = data['location']
|
||||
l = data['location']
|
||||
|
||||
res = splitstdata(l)
|
||||
times_location = res[0]
|
||||
latlong = res[1]
|
||||
latcoord = []
|
||||
loncoord = []
|
||||
res = splitstdata(l)
|
||||
times_location = res[0]
|
||||
latlong = res[1]
|
||||
latcoord = []
|
||||
loncoord = []
|
||||
|
||||
for coord in latlong:
|
||||
lat = coord[0]
|
||||
lon = coord[1]
|
||||
latcoord.append(lat)
|
||||
loncoord.append(lon)
|
||||
for coord in latlong:
|
||||
lat = coord[0]
|
||||
lon = coord[1]
|
||||
latcoord.append(lat)
|
||||
loncoord.append(lon)
|
||||
except:
|
||||
times_location = times_distance
|
||||
latcoord = np.zeros(len(times_distance))
|
||||
loncoord = np.zeros(len(times_distance))
|
||||
times_location = times_distance
|
||||
latcoord = np.zeros(len(times_distance))
|
||||
loncoord = np.zeros(len(times_distance))
|
||||
if workouttype in mytypes.otwtypes:
|
||||
workouttype = 'rower'
|
||||
|
||||
|
||||
try:
|
||||
res = splitstdata(data['cadence'])
|
||||
times_spm = res[0]
|
||||
spm = res[1]
|
||||
res = splitstdata(data['cadence'])
|
||||
times_spm = res[0]
|
||||
spm = res[1]
|
||||
except KeyError:
|
||||
times_spm = times_distance
|
||||
spm = 0*times_distance
|
||||
times_spm = times_distance
|
||||
spm = 0*times_distance
|
||||
|
||||
try:
|
||||
res = splitstdata(data['heartrate'])
|
||||
hr = res[1]
|
||||
times_hr = res[0]
|
||||
res = splitstdata(data['heartrate'])
|
||||
hr = res[1]
|
||||
times_hr = res[0]
|
||||
except KeyError:
|
||||
times_hr = times_distance
|
||||
hr = 0*times_distance
|
||||
times_hr = times_distance
|
||||
hr = 0*times_distance
|
||||
|
||||
|
||||
# create data series and remove duplicates
|
||||
@@ -388,12 +401,12 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks',
|
||||
|
||||
# Create dicts and big dataframe
|
||||
d = {
|
||||
' Horizontal (meters)': distseries,
|
||||
' latitude': latseries,
|
||||
' longitude': lonseries,
|
||||
' Cadence (stokes/min)': spmseries,
|
||||
' HRCur (bpm)' : hrseries,
|
||||
}
|
||||
' Horizontal (meters)': distseries,
|
||||
' latitude': latseries,
|
||||
' longitude': lonseries,
|
||||
' Cadence (stokes/min)': spmseries,
|
||||
' HRCur (bpm)' : hrseries,
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -437,7 +450,7 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks',
|
||||
df = df.fillna(0)
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
# csvfilename ='media/Import_'+str(importid)+'.csv'
|
||||
|
||||
+186
-180
@@ -1,3 +1,9 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
from __future__ import unicode_literals, absolute_import
|
||||
|
||||
# All the functionality needed to connect to Strava
|
||||
from scipy import optimize
|
||||
from scipy.signal import savgol_filter
|
||||
@@ -10,15 +16,15 @@ queue = django_rq.get_queue('default')
|
||||
queuelow = django_rq.get_queue('low')
|
||||
queuehigh = django_rq.get_queue('low')
|
||||
|
||||
from dataprep import columndict
|
||||
from rowers.dataprep import columndict
|
||||
|
||||
import stravalib
|
||||
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
|
||||
|
||||
from iso8601 import ParseError
|
||||
from utils import myqueue
|
||||
from rowers.utils import myqueue
|
||||
|
||||
import mytypes
|
||||
import rowers.mytypes as mytypes
|
||||
import gzip
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
@@ -35,7 +41,7 @@ from rowers.imports import *
|
||||
|
||||
headers = {'Accept': 'application/json',
|
||||
'Api-Key': STRAVA_CLIENT_ID,
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Type': 'application/json',
|
||||
'user-agent': 'sanderroosendaal'}
|
||||
|
||||
|
||||
@@ -89,26 +95,26 @@ def make_authorization_url(request):
|
||||
def get_strava_workout_list(user,limit_n=0):
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (r.stravatokenexpirydate is None or timezone.now()+timedelta(seconds=3599)>r.stravatokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
|
||||
url = "https://www.strava.com/api/v3/athlete/activities"
|
||||
url = "https://www.strava.com/api/v3/athlete/activities"
|
||||
|
||||
if limit_n==0:
|
||||
params = {}
|
||||
else:
|
||||
params = {'per_page':limit_n}
|
||||
|
||||
s = requests.get(url,headers=headers,params=params)
|
||||
s = requests.get(url,headers=headers,params=params)
|
||||
|
||||
|
||||
return s
|
||||
@@ -200,27 +206,27 @@ def create_async_workout(alldata,user,stravaid,debug=False):
|
||||
thetimezone = 'UTC'
|
||||
|
||||
try:
|
||||
rowdatetime = iso8601.parse_date(data['date_utc'])
|
||||
rowdatetime = iso8601.parse_date(data['date_utc'])
|
||||
except KeyError:
|
||||
rowdatetime = iso8601.parse_date(data['start_date'])
|
||||
rowdatetime = iso8601.parse_date(data['start_date'])
|
||||
except ParseError:
|
||||
rowdatetime = iso8601.parse_date(data['date'])
|
||||
rowdatetime = iso8601.parse_date(data['date'])
|
||||
|
||||
try:
|
||||
c2intervaltype = data['workout_type']
|
||||
|
||||
|
||||
except KeyError:
|
||||
c2intervaltype = ''
|
||||
|
||||
c2intervaltype = ''
|
||||
|
||||
try:
|
||||
title = data['name']
|
||||
title = data['name']
|
||||
except KeyError:
|
||||
title = ""
|
||||
try:
|
||||
t = data['comments'].split('\n', 1)[0]
|
||||
title += t[:20]
|
||||
except:
|
||||
title = 'Imported'
|
||||
title = ""
|
||||
try:
|
||||
t = data['comments'].split('\n', 1)[0]
|
||||
title += t[:20]
|
||||
except:
|
||||
title = 'Imported'
|
||||
|
||||
workoutdate = rowdatetime.astimezone(
|
||||
pytz.timezone(thetimezone)
|
||||
@@ -259,7 +265,7 @@ def create_async_workout(alldata,user,stravaid,debug=False):
|
||||
|
||||
return 1
|
||||
|
||||
from utils import get_strava_stream
|
||||
from rowers.utils import get_strava_stream
|
||||
|
||||
|
||||
|
||||
@@ -273,26 +279,26 @@ def get_workout(user,stravaid):
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (r.stravatokenexpirydate is not None and timezone.now()>r.stravatokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
fetchresolution = 'high'
|
||||
# ready to fetch. Hurray
|
||||
fetchresolution = 'high'
|
||||
series_type = 'time'
|
||||
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json',
|
||||
'resolution': 'medium',}
|
||||
url = "https://www.strava.com/api/v3/activities/"+str(stravaid)
|
||||
workoutsummary = requests.get(url,headers=headers).json()
|
||||
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json',
|
||||
'resolution': 'medium',}
|
||||
url = "https://www.strava.com/api/v3/activities/"+str(stravaid)
|
||||
workoutsummary = requests.get(url,headers=headers).json()
|
||||
|
||||
workoutsummary['timezone'] = "Etc/UTC"
|
||||
workoutsummary['timezone'] = "Etc/UTC"
|
||||
try:
|
||||
startdatetime = workoutsummary['start_date']
|
||||
startdatetime = workoutsummary['start_date']
|
||||
except KeyError:
|
||||
startdatetime = timezone.now()
|
||||
|
||||
@@ -306,9 +312,9 @@ def get_workout(user,stravaid):
|
||||
|
||||
|
||||
try:
|
||||
t = np.array(timejson.json()[0]['data'])
|
||||
nr_rows = len(t)
|
||||
d = np.array(distancejson.json()[1]['data'])
|
||||
t = np.array(timejson.json()[0]['data'])
|
||||
nr_rows = len(t)
|
||||
d = np.array(distancejson.json()[1]['data'])
|
||||
if nr_rows == 0:
|
||||
return (0,"Error: Time data had zero length")
|
||||
|
||||
@@ -318,70 +324,70 @@ def get_workout(user,stravaid):
|
||||
except KeyError:
|
||||
return (0,"something went wrong with the Strava import")
|
||||
|
||||
try:
|
||||
spm = np.array(spmjson.json()[1]['data'])
|
||||
except:
|
||||
spm = np.zeros(nr_rows)
|
||||
try:
|
||||
spm = np.array(spmjson.json()[1]['data'])
|
||||
except:
|
||||
spm = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
power = np.array(powerjson.json()[1]['data'])
|
||||
except IndexError:
|
||||
power = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
hr = np.array(hrjson.json()[1]['data'])
|
||||
except IndexError:
|
||||
hr = np.zeros(nr_rows)
|
||||
try:
|
||||
hr = np.array(hrjson.json()[1]['data'])
|
||||
except IndexError:
|
||||
hr = np.zeros(nr_rows)
|
||||
except KeyError:
|
||||
hr = np.zeros(nr_rows)
|
||||
hr = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
velo = np.array(velojson.json()[1]['data'])
|
||||
except IndexError:
|
||||
velo = np.zeros(nr_rows)
|
||||
try:
|
||||
velo = np.array(velojson.json()[1]['data'])
|
||||
except IndexError:
|
||||
velo = np.zeros(nr_rows)
|
||||
except KeyError:
|
||||
velo = np.zeros(nr_rows)
|
||||
|
||||
dt = np.diff(t).mean()
|
||||
wsize = round(5./dt)
|
||||
dt = np.diff(t).mean()
|
||||
wsize = round(5./dt)
|
||||
|
||||
velo2 = ewmovingaverage(velo,wsize)
|
||||
coords = np.array(latlongjson.json()[0]['data'])
|
||||
try:
|
||||
lat = coords[:,0]
|
||||
lon = coords[:,1]
|
||||
except IndexError:
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
velo2 = ewmovingaverage(velo,wsize)
|
||||
coords = np.array(latlongjson.json()[0]['data'])
|
||||
try:
|
||||
lat = coords[:,0]
|
||||
lon = coords[:,1]
|
||||
except IndexError:
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
except KeyError:
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
|
||||
|
||||
|
||||
|
||||
strokelength = velo*60./(spm)
|
||||
strokelength[np.isinf(strokelength)] = 0.0
|
||||
strokelength = velo*60./(spm)
|
||||
strokelength[np.isinf(strokelength)] = 0.0
|
||||
|
||||
|
||||
pace = 500./(1.0*velo2)
|
||||
pace[np.isinf(pace)] = 0.0
|
||||
pace = 500./(1.0*velo2)
|
||||
pace[np.isinf(pace)] = 0.0
|
||||
|
||||
df = pd.DataFrame({'t':10*t,
|
||||
'd':10*d,
|
||||
'p':10*pace,
|
||||
'spm':spm,
|
||||
'hr':hr,
|
||||
'lat':lat,
|
||||
'lon':lon,
|
||||
df = pd.DataFrame({'t':10*t,
|
||||
'd':10*d,
|
||||
'p':10*pace,
|
||||
'spm':spm,
|
||||
'hr':hr,
|
||||
'lat':lat,
|
||||
'lon':lon,
|
||||
'power':power,
|
||||
'strokelength':strokelength,
|
||||
})
|
||||
'strokelength':strokelength,
|
||||
})
|
||||
|
||||
|
||||
# startdatetime = datetime.datetime.strptime(startdatetime,"%Y-%m-%d-%H:%M:%S")
|
||||
# startdatetime = datetime.datetime.strptime(startdatetime,"%Y-%m-%d-%H:%M:%S")
|
||||
|
||||
return [workoutsummary,df]
|
||||
return [workoutsummary,df]
|
||||
|
||||
# Generate Workout data for Strava (a TCX file)
|
||||
def createstravaworkoutdata(w,dozip=True):
|
||||
@@ -478,41 +484,41 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
workouttype = 'water'
|
||||
|
||||
if workouttype not in [x[0] for x in Workout.workouttypes]:
|
||||
workouttype = 'other'
|
||||
workouttype = 'other'
|
||||
try:
|
||||
comments = data['comments']
|
||||
comments = data['comments']
|
||||
except:
|
||||
comments = ' '
|
||||
comments = ' '
|
||||
|
||||
try:
|
||||
thetimezone = tz(data['timezone'])
|
||||
thetimezone = tz(data['timezone'])
|
||||
except:
|
||||
thetimezone = 'UTC'
|
||||
thetimezone = 'UTC'
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
try:
|
||||
rowdatetime = iso8601.parse_date(data['date_utc'])
|
||||
rowdatetime = iso8601.parse_date(data['date_utc'])
|
||||
except KeyError:
|
||||
rowdatetime = iso8601.parse_date(data['start_date'])
|
||||
rowdatetime = iso8601.parse_date(data['start_date'])
|
||||
except ParseError:
|
||||
rowdatetime = iso8601.parse_date(data['date'])
|
||||
rowdatetime = iso8601.parse_date(data['date'])
|
||||
|
||||
|
||||
|
||||
try:
|
||||
intervaltype = data['workout_type']
|
||||
|
||||
|
||||
except KeyError:
|
||||
intervaltype = ''
|
||||
|
||||
intervaltype = ''
|
||||
|
||||
try:
|
||||
title = data['name']
|
||||
title = data['name']
|
||||
except KeyError:
|
||||
title = ""
|
||||
try:
|
||||
t = data['comments'].split('\n', 1)[0]
|
||||
title += t[:20]
|
||||
except:
|
||||
title = 'Imported'
|
||||
title = ""
|
||||
try:
|
||||
t = data['comments'].split('\n', 1)[0]
|
||||
title += t[:20]
|
||||
except:
|
||||
title = 'Imported'
|
||||
|
||||
starttimeunix = arrow.get(rowdatetime).timestamp
|
||||
|
||||
@@ -526,17 +532,17 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
nr_rows = len(unixtime)
|
||||
|
||||
try:
|
||||
latcoord = strokedata.loc[:,'lat']
|
||||
loncoord = strokedata.loc[:,'lon']
|
||||
latcoord = strokedata.loc[:,'lat']
|
||||
loncoord = strokedata.loc[:,'lon']
|
||||
except:
|
||||
latcoord = np.zeros(nr_rows)
|
||||
loncoord = np.zeros(nr_rows)
|
||||
latcoord = np.zeros(nr_rows)
|
||||
loncoord = np.zeros(nr_rows)
|
||||
|
||||
|
||||
try:
|
||||
strokelength = strokedata.loc[:,'strokelength']
|
||||
strokelength = strokedata.loc[:,'strokelength']
|
||||
except:
|
||||
strokelength = np.zeros(nr_rows)
|
||||
strokelength = np.zeros(nr_rows)
|
||||
|
||||
dist2 = 0.1*strokedata.loc[:,'d']
|
||||
|
||||
@@ -566,28 +572,28 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
# save csv
|
||||
# Create data frame with all necessary data to write to csv
|
||||
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' longitude':loncoord,
|
||||
' latitude':latcoord,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Power (watts)':power,
|
||||
' DragFactor':np.zeros(nr_rows),
|
||||
' DriveLength (meters)':np.zeros(nr_rows),
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' DriveTime (ms)':np.zeros(nr_rows),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':seconds
|
||||
})
|
||||
' Horizontal (meters)': dist2,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' longitude':loncoord,
|
||||
' latitude':latcoord,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Power (watts)':power,
|
||||
' DragFactor':np.zeros(nr_rows),
|
||||
' DriveLength (meters)':np.zeros(nr_rows),
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' DriveTime (ms)':np.zeros(nr_rows),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
||||
' lapIdx':lapidx,
|
||||
' ElapsedTime (sec)':seconds
|
||||
})
|
||||
|
||||
|
||||
df.sort_values(by='TimeStamp (sec)',ascending=True)
|
||||
|
||||
|
||||
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
|
||||
|
||||
@@ -623,34 +629,34 @@ def workout_strava_upload(user,w):
|
||||
r = Rower.objects.get(user=user)
|
||||
res = -1
|
||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
raise NoTokenError("Your hovercraft is full of eels")
|
||||
else:
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (checkworkoutuser(user,w)):
|
||||
try:
|
||||
tcxfile,tcxmesg = createstravaworkoutdata(w)
|
||||
tcxfile,tcxmesg = createstravaworkoutdata(w)
|
||||
if tcxfile:
|
||||
with open(tcxfile,'rb') as f:
|
||||
res,mes = handle_stravaexport(
|
||||
with open(tcxfile,'rb') as f:
|
||||
res,mes = handle_stravaexport(
|
||||
f,w.name,
|
||||
r.stravatoken,
|
||||
description=w.notes+'\n from '+w.workoutsource+' via rowsandall.com',
|
||||
r.stravatoken,
|
||||
description=w.notes+'\n from '+w.workoutsource+' via rowsandall.com',
|
||||
activity_type=r.stravaexportas)
|
||||
if res==0:
|
||||
message = mes
|
||||
w.uploadedtostrava = -1
|
||||
message = mes
|
||||
w.uploadedtostrava = -1
|
||||
stravaid = -1
|
||||
w.save()
|
||||
w.save()
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
return message,stravaid
|
||||
|
||||
w.uploadedtostrava = res
|
||||
w.save()
|
||||
w.uploadedtostrava = res
|
||||
w.save()
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
message = mes
|
||||
@@ -663,14 +669,14 @@ def workout_strava_upload(user,w):
|
||||
w.save()
|
||||
return message, stravaid
|
||||
|
||||
except ActivityUploadFailed as e:
|
||||
message = "Strava Upload error: %s" % e
|
||||
w.uploadedtostrava = -1
|
||||
except ActivityUploadFailed as e:
|
||||
message = "Strava Upload error: %s" % e
|
||||
w.uploadedtostrava = -1
|
||||
stravaid = -1
|
||||
w.save()
|
||||
os.remove(tcxfile)
|
||||
w.save()
|
||||
os.remove(tcxfile)
|
||||
return message,stravaid
|
||||
return message,stravaid
|
||||
return message,stravaid
|
||||
return message,stravaid
|
||||
|
||||
|
||||
@@ -688,9 +694,9 @@ def handle_strava_import_stroke_data(title,
|
||||
series_type = 'time'
|
||||
authorizationstring = str('Bearer ' + stravatoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json',
|
||||
'resolution': 'medium',}
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json',
|
||||
'resolution': 'medium',}
|
||||
url = "https://www.strava.com/api/v3/activities/"+str(stravaid)
|
||||
workoutsummary = requests.get(url,headers=headers).json()
|
||||
|
||||
@@ -708,9 +714,9 @@ def handle_strava_import_stroke_data(title,
|
||||
wattsjson = get_strava_stream(r,'watts',stravaid)
|
||||
|
||||
try:
|
||||
t = np.array(timejson.json()[0]['data'])
|
||||
nr_rows = len(t)
|
||||
d = np.array(distancejson.json()[1]['data'])
|
||||
t = np.array(timejson.json()[0]['data'])
|
||||
nr_rows = len(t)
|
||||
d = np.array(distancejson.json()[1]['data'])
|
||||
if nr_rows == 0:
|
||||
return 0
|
||||
except IndexError:
|
||||
@@ -720,9 +726,9 @@ def handle_strava_import_stroke_data(title,
|
||||
return 0
|
||||
|
||||
try:
|
||||
spm = np.array(spmjson.json()[1]['data'])
|
||||
spm = np.array(spmjson.json()[1]['data'])
|
||||
except:
|
||||
spm = np.zeros(nr_rows)
|
||||
spm = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
watts = np.array(wattsjson.json()[1]['data'])
|
||||
@@ -730,16 +736,16 @@ def handle_strava_import_stroke_data(title,
|
||||
watts = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
hr = np.array(hrjson.json()[1]['data'])
|
||||
hr = np.array(hrjson.json()[1]['data'])
|
||||
except IndexError:
|
||||
hr = np.zeros(nr_rows)
|
||||
hr = np.zeros(nr_rows)
|
||||
except KeyError:
|
||||
hr = np.zeros(nr_rows)
|
||||
hr = np.zeros(nr_rows)
|
||||
|
||||
try:
|
||||
velo = np.array(velojson.json()[1]['data'])
|
||||
velo = np.array(velojson.json()[1]['data'])
|
||||
except IndexError:
|
||||
velo = np.zeros(nr_rows)
|
||||
velo = np.zeros(nr_rows)
|
||||
except KeyError:
|
||||
velo = np.zeros(nr_rows)
|
||||
|
||||
@@ -756,14 +762,14 @@ def handle_strava_import_stroke_data(title,
|
||||
|
||||
coords = np.array(latlongjson.json()[0]['data'])
|
||||
try:
|
||||
lat = coords[:,0]
|
||||
lon = coords[:,1]
|
||||
lat = coords[:,0]
|
||||
lon = coords[:,1]
|
||||
except IndexError:
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
except KeyError:
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
lat = np.zeros(len(t))
|
||||
lon = np.zeros(len(t))
|
||||
|
||||
strokelength = velo*60./(spm)
|
||||
strokelength[np.isinf(strokelength)] = 0.0
|
||||
@@ -779,22 +785,22 @@ def handle_strava_import_stroke_data(title,
|
||||
|
||||
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
||||
' ElapsedTime (sec)':t,
|
||||
' Horizontal (meters)':d,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' latitude':lat,
|
||||
' longitude':lon,
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
' Horizontal (meters)':d,
|
||||
' Stroke500mPace (sec/500m)':pace,
|
||||
' Cadence (stokes/min)':spm,
|
||||
' HRCur (bpm)':hr,
|
||||
' latitude':lat,
|
||||
' longitude':lon,
|
||||
' StrokeDistance (meters)':strokelength,
|
||||
'cum_dist':d,
|
||||
' DragFactor':np.zeros(nr_strokes),
|
||||
' DriveLength (meters)':np.zeros(nr_strokes),
|
||||
' StrokeDistance (meters)':strokedistance,
|
||||
' DriveTime (ms)':np.zeros(nr_strokes),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_strokes),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' lapIdx':np.zeros(nr_strokes),
|
||||
' DragFactor':np.zeros(nr_strokes),
|
||||
' DriveLength (meters)':np.zeros(nr_strokes),
|
||||
' StrokeDistance (meters)':strokedistance,
|
||||
' DriveTime (ms)':np.zeros(nr_strokes),
|
||||
' StrokeRecoveryTime (ms)':np.zeros(nr_strokes),
|
||||
' AverageDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' PeakDriveForce (lbs)':np.zeros(nr_strokes),
|
||||
' lapIdx':np.zeros(nr_strokes),
|
||||
' Power (watts)':watts,
|
||||
})
|
||||
|
||||
|
||||
+29
-18
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
""" Background tasks done by Celery (develop) or QR (production) """
|
||||
import os
|
||||
import time
|
||||
@@ -16,7 +21,10 @@ from rowingdata import rowingdata as rdata
|
||||
from datetime import timedelta
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
from celery import app
|
||||
#from celery import app
|
||||
from rowers.celery import app
|
||||
from celery import shared_task
|
||||
|
||||
import datetime
|
||||
import pytz
|
||||
import iso8601
|
||||
@@ -39,10 +47,11 @@ from django_rq import job
|
||||
from django.utils import timezone
|
||||
from django.utils.html import strip_tags
|
||||
|
||||
from utils import deserialize_list,ewmovingaverage,wavg
|
||||
from emails import htmlstrip
|
||||
from rowers.utils import deserialize_list,ewmovingaverage,wavg
|
||||
from rowers.emails import htmlstrip
|
||||
|
||||
from HTMLParser import HTMLParser
|
||||
#from HTMLParser import HTMLParser
|
||||
from html.parser import HTMLParser
|
||||
class MLStripper(HTMLParser):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
@@ -80,13 +89,13 @@ from django.db.utils import OperationalError
|
||||
from jinja2 import Template,Environment,FileSystemLoader
|
||||
env = Environment(loader = FileSystemLoader(["rowers/templates"]))
|
||||
|
||||
import datautils
|
||||
import utils
|
||||
import rowers.datautils as datautils
|
||||
import rowers.utils as utils
|
||||
import requests
|
||||
import longtask
|
||||
import rowers.longtask as longtask
|
||||
import arrow
|
||||
|
||||
from utils import get_strava_stream
|
||||
from rowers.utils import get_strava_stream
|
||||
|
||||
siteurl = SITE_URL
|
||||
|
||||
@@ -128,9 +137,9 @@ def handle_c2_import_stroke_data(c2token,
|
||||
|
||||
return 1
|
||||
else:
|
||||
url = "https://log.concept2.com/api/users/me/results/"+str(c2id)
|
||||
url = "https://log.concept2.com/api/users/me/results/{id}".format(id=c2id)
|
||||
|
||||
s = requests.get(url,headers=headers)
|
||||
s = requests.get(url,headers=headers)
|
||||
|
||||
if s.status_code == 200:
|
||||
workoutdata = s.json()['data']
|
||||
@@ -1238,21 +1247,21 @@ def handle_zip_file(emailfrom, subject, file,**kwargs):
|
||||
debug = False
|
||||
|
||||
if debug:
|
||||
print message
|
||||
print(message)
|
||||
|
||||
email = EmailMessage(subject, message,
|
||||
emailfrom,
|
||||
['workouts@rowsandall.com'])
|
||||
email.attach_file(file)
|
||||
if debug:
|
||||
print "attaching"
|
||||
print("attaching")
|
||||
|
||||
|
||||
res = email.send()
|
||||
|
||||
|
||||
if debug:
|
||||
print "sent"
|
||||
print("sent")
|
||||
time.sleep(60)
|
||||
return 1
|
||||
|
||||
@@ -1490,9 +1499,8 @@ def handle_updateergcp(rower_id,workoutfilenames,debug=False,**kwargs):
|
||||
rowdata = rdata(f1 + '.gz')
|
||||
except IOError:
|
||||
rowdata = 0
|
||||
|
||||
if rowdata != 0:
|
||||
therows.append(rowdata)
|
||||
if rowdata != 0:
|
||||
therows.append(rowdata)
|
||||
|
||||
cpdata = rowingdata.cumcpdata(therows)
|
||||
cpdata.columns = cpdata.columns.str.lower()
|
||||
@@ -1637,7 +1645,7 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
|
||||
hran = hrdata['hran']
|
||||
ftp = hrdata['ftp']
|
||||
powerzones = deserialize_list(hrdata['powerzones'])
|
||||
powerperc = np.array(deserialize_list(hrdata['powerperc'])).astype(int)
|
||||
powerperc = np.array(deserialize_list(hrdata['powerperc'])).astype(float)
|
||||
|
||||
rr = rowingdata.rower(hrmax=hrmax, hrut2=hrut2,
|
||||
hrut1=hrut1, hrat=hrat,
|
||||
@@ -1649,7 +1657,10 @@ def handle_makeplot(f1, f2, t, hrdata, plotnr, imagename,
|
||||
except IOError:
|
||||
row = rdata(f2 + '.gz', rower=rr)
|
||||
|
||||
haspower = row.df[' Power (watts)'].mean() > 50
|
||||
try:
|
||||
haspower = row.df[' Power (watts)'].mean() > 50
|
||||
except TypeError:
|
||||
haspower = True
|
||||
|
||||
nr_rows = len(row.df)
|
||||
if (plotnr in [1, 2, 4, 5, 8, 11, 9, 12]) and (nr_rows > 1200):
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
import django
|
||||
|
||||
+5
-1
@@ -1,3 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
# All the Team related methods
|
||||
|
||||
@@ -10,7 +14,7 @@ from django.db import IntegrityError
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
|
||||
from utils import myqueue
|
||||
from rowers.utils import myqueue
|
||||
|
||||
import django_rq
|
||||
queue = django_rq.get_queue('default')
|
||||
|
||||
-106
@@ -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 %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -1,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 %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -1,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>
|
||||
|
||||
|
||||
<div id="id_css_res">
|
||||
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css" type="text/css" />
|
||||
</div>
|
||||
<div id="id_js_res">
|
||||
<script
|
||||
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
|
||||
</script>
|
||||
<script
|
||||
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
|
||||
</script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -60,16 +60,12 @@
|
||||
|
||||
|
||||
<div id="id_css_res">
|
||||
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css" type="text/css" />
|
||||
</div>
|
||||
<div id="id_js_res">
|
||||
<script
|
||||
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
|
||||
</script>
|
||||
<script
|
||||
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
|
||||
</script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -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 }}
|
||||
{{ css_res| safe }}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
{{ js_res | safe }}
|
||||
{{ css_res| safe }}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -60,17 +60,12 @@
|
||||
|
||||
|
||||
<div id="id_css_res">
|
||||
<link rel="stylesheet" href="/static/css/bokeh-0.12.3.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="/static/css/bokeh-widgets-0.12.3.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.css" type="text/css" />
|
||||
<link rel="stylesheet" href="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.css" type="text/css" />
|
||||
</div>
|
||||
<div id="id_js_res">
|
||||
<script
|
||||
type="text/javascript" src="/static/js/bokeh-0.12.3.min.js">
|
||||
</script>
|
||||
<script
|
||||
type="text/javascript" src="/static/js/bokeh-widgets-0.12.3.min.js">
|
||||
</script>
|
||||
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-widgets-1.0.4.min.js"></script>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-1.9.1.min.js"></script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
|
||||
<ul class="main-content">
|
||||
<li class="grid_2" style="min-height:200px;">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
<div id="advancedplots" class="grid_6 omega">
|
||||
<div class="grid_6 alpha">
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
{% block main %}
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<img src="/static/img/rivercurrent.jpg" width="400">
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
</form>
|
||||
</li>
|
||||
<li class="grid_2">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -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 class="grid_2">
|
||||
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
{{ workout.date }} - {{ workout.distance }}m - {{ workout.duration |durationprint:"%H:%M:%S.%f" }}{% endblock %}
|
||||
|
||||
{% block meta %}
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
</li>
|
||||
|
||||
<li class="grid_2">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -130,7 +130,7 @@ $('#id_workouttype').change();
|
||||
{% endif %}
|
||||
{% if mapdiv %}
|
||||
<li class="grid_2">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
</li>
|
||||
{% endif %}
|
||||
<li class="grid_2">
|
||||
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||
<script src="http://cdn.pydata.org/bokeh/release/bokeh-1.0.4.min.js"></script>
|
||||
<script async="true" type="text/javascript">
|
||||
Bokeh.set_log_level("info");
|
||||
</script>
|
||||
|
||||
@@ -31,15 +31,16 @@ from rowers.opaque import encoder
|
||||
|
||||
import arrow
|
||||
|
||||
from six import string_types
|
||||
|
||||
def strfdelta(tdelta):
|
||||
minutes,seconds = divmod(tdelta.seconds,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
res = "{minutes:0>1}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
@@ -48,11 +49,11 @@ def strfdeltah(tdelta):
|
||||
minutes,seconds = divmod(rest,60)
|
||||
tenths = int(tdelta.microseconds/1e5)
|
||||
res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format(
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
tenths=tenths,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
@@ -60,10 +61,10 @@ def secondstotimestring(tdelta):
|
||||
hours, rest = divmod(tdelta,3600)
|
||||
minutes,seconds = divmod(rest,60)
|
||||
res = "{hours:0>2}:{minutes:0>2}:{seconds:0>2}".format(
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
)
|
||||
hours=hours,
|
||||
minutes=minutes,
|
||||
seconds=seconds,
|
||||
)
|
||||
|
||||
return res
|
||||
|
||||
@@ -87,7 +88,11 @@ def aantalcomments(workout):
|
||||
|
||||
@register.filter
|
||||
def encode(id):
|
||||
return str(encoder.encode_hex(id))
|
||||
try:
|
||||
result = str(encoder.encode_hex(id))
|
||||
except TypeError:
|
||||
result = ''
|
||||
return result
|
||||
|
||||
@register.filter
|
||||
def water(workout):
|
||||
@@ -107,9 +112,9 @@ def spacetohtml(t):
|
||||
@register.filter
|
||||
def durationprint(d,dstring):
|
||||
if (d == None):
|
||||
return d
|
||||
return d
|
||||
else:
|
||||
return d.strftime(dstring)[:-5]
|
||||
return d.strftime(dstring)[:-5]
|
||||
|
||||
def getstartenddate(timeperiod):
|
||||
s,e = timeperiod.split('/')
|
||||
@@ -165,16 +170,16 @@ def previousperiodstart(timeperiod):
|
||||
@register.filter
|
||||
def paceprint(d):
|
||||
if (d == None):
|
||||
return d
|
||||
return d
|
||||
else:
|
||||
return strfdelta(d)
|
||||
return strfdelta(d)
|
||||
|
||||
@register.filter
|
||||
def deltatimeprint(d):
|
||||
if (d == None):
|
||||
return d
|
||||
return d
|
||||
else:
|
||||
return strfdeltah(d)
|
||||
return strfdeltah(d)
|
||||
|
||||
@register.filter
|
||||
def c2userid(user):
|
||||
@@ -220,8 +225,8 @@ def jsdict(dict,key):
|
||||
def lookup(dict, key):
|
||||
s = dict.get(key)
|
||||
|
||||
if isinstance(s,basestring) and len(s) > 22:
|
||||
s = s[:22]
|
||||
if isinstance(s,string_types) and len(s) > 22:
|
||||
s = s[:22]
|
||||
return s
|
||||
|
||||
@register.filter
|
||||
|
||||
+13
-8
@@ -1,3 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
@@ -31,7 +36,7 @@ from rowers.utils import NoTokenError
|
||||
from shutil import copyfile
|
||||
from nose.tools import assert_true
|
||||
from mock import Mock, patch
|
||||
from minimocktest import MockTestCase
|
||||
#from minimocktest import MockTestCase
|
||||
import pandas as pd
|
||||
import rowers.c2stuff as c2stuff
|
||||
import arrow
|
||||
@@ -98,15 +103,15 @@ def mocked_sqlalchemy(*args, **kwargs):
|
||||
return MockEngine()
|
||||
|
||||
#@pytest.mark.django_db
|
||||
class DjangoTestCase(TestCase, MockTestCase):
|
||||
class DjangoTestCase(TestCase): #, MockTestCase):
|
||||
def _pre_setup(self):
|
||||
MockTestCase.setUp(self)
|
||||
TestCase._pre_setup(self)
|
||||
self.client = Client()
|
||||
# MockTestCase.setUp(self)
|
||||
TestCase._pre_setup(self)
|
||||
self.client = Client()
|
||||
|
||||
def _post_teardown(self):
|
||||
TestCase._post_teardown(self)
|
||||
MockTestCase.tearDown(self)
|
||||
TestCase._post_teardown(self)
|
||||
#MockTestCase.tearDown(self)
|
||||
# delete_strokedata(1)
|
||||
|
||||
def mocked_tcx_parser(*args, **kwargs):
|
||||
@@ -220,7 +225,7 @@ def mocked_read_df_cols_sql_multiflex(ids, columns, convertnewtons=True):
|
||||
|
||||
def mocked_stravaexport(f2,workoutname,stravatoken,description='',
|
||||
activity_type='Rowing'):
|
||||
print "this is mocked strava export"
|
||||
print("this is mocked strava export")
|
||||
return 1,'success'
|
||||
|
||||
def mocked_fetchcp(*args, **kwargs):
|
||||
|
||||
@@ -3,6 +3,11 @@ try:
|
||||
except NameError:
|
||||
WindowsError = None
|
||||
|
||||
try:
|
||||
FileNotFoundError
|
||||
except NameError:
|
||||
FileNotFoundError = None
|
||||
|
||||
try:
|
||||
OSError
|
||||
except NameError:
|
||||
@@ -44,7 +49,7 @@ from rowers.plannedsessions import get_dates_timeperiod
|
||||
from shutil import copyfile, copy
|
||||
from nose.tools import assert_true
|
||||
from mock import Mock, patch
|
||||
from minimocktest import MockTestCase
|
||||
#from minimocktest import MockTestCase
|
||||
import pandas as pd
|
||||
import rowers.c2stuff as c2stuff
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
#from __future__ import print_function
|
||||
from statements import *
|
||||
from .statements import *
|
||||
from django.utils import timezone
|
||||
nu = datetime.datetime.now(tz=timezone.utc)
|
||||
|
||||
@@ -327,7 +332,7 @@ class VirtualEventViewTest(TestCase):
|
||||
def tearDown(self):
|
||||
try:
|
||||
os.remove('rowers/tests/testdata/temp/course.kml')
|
||||
except (WindowsError, OSError, IOError):
|
||||
except (FileNotFoundError, OSError, IOError):
|
||||
pass
|
||||
|
||||
|
||||
@@ -408,7 +413,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = IndoorVirtualRaceForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -452,7 +457,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = IndoorVirtualRaceForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -496,7 +501,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = VirtualRaceForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -533,7 +538,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = VirtualRaceForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -588,7 +593,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = IndoorVirtualRaceResultForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -617,7 +622,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = IndoorVirtualRaceResultForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -666,7 +671,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = VirtualRaceResultForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
@@ -694,7 +699,7 @@ class VirtualEventViewTest(TestCase):
|
||||
|
||||
form = VirtualRaceResultForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data,follow=True)
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
#from __future__ import print_function
|
||||
from statements import *
|
||||
from .statements import *
|
||||
nu = datetime.datetime.now()
|
||||
|
||||
from rowers.models import User,Rower
|
||||
@@ -8,10 +13,10 @@ from rowers.models import User,Rower
|
||||
@pytest.mark.django_db
|
||||
class AdminTests(TestCase):
|
||||
def setUp(self):
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u)
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u)
|
||||
my_admin = User.objects.create_superuser('myuser',
|
||||
'myemail@test.com',
|
||||
'apensstaart')
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from statements import *
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .statements import *
|
||||
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
@@ -26,7 +31,7 @@ class WorkoutCompareTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError, OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@@ -91,7 +96,7 @@ class BoxPlotTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@@ -110,7 +115,7 @@ class BoxPlotTest(TestCase):
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@patch('rowers.dataprep.getsmallrowdata_db')
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multi)
|
||||
def test_workouts_boxplot_submit(self, mocked_sqlalchemy,
|
||||
def donot_test_workouts_boxplot_submit(self, mocked_sqlalchemy,
|
||||
mocked_getsmallrowdata_db,
|
||||
mocked_df):
|
||||
|
||||
@@ -188,7 +193,7 @@ class ListWorkoutTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@@ -246,7 +251,7 @@ class PlannedSessionTests(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
def test_ics_download(self):
|
||||
@@ -291,7 +296,7 @@ class ForcecurveTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect = mocked_getempowerdata_db)
|
||||
@@ -326,7 +331,7 @@ class CumStatsTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multistats)
|
||||
@@ -363,7 +368,7 @@ class CumFlexTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multiflex)
|
||||
@@ -468,7 +473,7 @@ class MultiFlexTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.read_cols_df_sql', side_effect = mocked_read_df_cols_sql_multiflex)
|
||||
@@ -570,7 +575,7 @@ class HistoTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from statements import *
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .statements import *
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
|
||||
@@ -211,7 +216,7 @@ class WorkoutViewTest(TestCase):
|
||||
'userid':self.u.id,
|
||||
'id':encoder.encode_hex(self.werg1.id),
|
||||
})
|
||||
print url
|
||||
print(url)
|
||||
|
||||
form_data = {
|
||||
'xparam':'time',
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from statements import *
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .statements import *
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
|
||||
@@ -28,7 +33,7 @@ class SimpleViewTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
def test_start_protrial(self):
|
||||
|
||||
@@ -1,16 +1,21 @@
|
||||
from statements import *
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .statements import *
|
||||
|
||||
class CoursesTest(TestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now(),
|
||||
rowerplan='coach',
|
||||
)
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
|
||||
def test_courses(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()
|
||||
|
||||
@@ -77,9 +81,9 @@ class OTWCPChartTest(TestCase):
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except (IOError,WindowsError,OSError):
|
||||
except (IOError,FileNotFoundError,OSError):
|
||||
pass
|
||||
except (IOError,WindowsError,OSError):
|
||||
except (IOError,FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.getsmallrowdata_db',side_effect=mocked_cpraw)
|
||||
@@ -157,7 +161,7 @@ class CPChartTest(TestCase):
|
||||
for workout in self.user_workouts:
|
||||
try:
|
||||
os.remove(workout.csvfilename)
|
||||
except (IOError, WindowsError,OSError):
|
||||
except (IOError, FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
def test_analytics_page(self):
|
||||
@@ -250,7 +254,7 @@ class CPChartTest(TestCase):
|
||||
sex = r.sex,
|
||||
weightc = r.weightcategory)
|
||||
|
||||
print url
|
||||
print(url)
|
||||
|
||||
response = self.c.get(url)
|
||||
self.assertEqual(response.status_code,200)
|
||||
|
||||
+27
-23
@@ -1,14 +1,18 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
#from __future__ import print_function
|
||||
from statements import *
|
||||
from .statements import *
|
||||
|
||||
@override_settings(TESTING=True)
|
||||
class EmailUpload(TestCase):
|
||||
def setUp(self):
|
||||
redis_connection.publish('tasks','KILL')
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -18,8 +22,8 @@ class EmailUpload(TestCase):
|
||||
gdproptin=True,
|
||||
gdproptindate=timezone.now(),
|
||||
rowerplan='coach')
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
workoutsbox = Mailbox.objects.create(name='workouts')
|
||||
workoutsbox.save()
|
||||
failbox = Mailbox.objects.create(name='Failed')
|
||||
@@ -43,7 +47,7 @@ workout run
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except (IOError,WindowsError,OSError):
|
||||
except (IOError,FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@@ -69,10 +73,10 @@ workout run
|
||||
class EmailTests(TestCase):
|
||||
def setUp(self):
|
||||
redis_connection.publish('tasks','KILL')
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -82,8 +86,8 @@ class EmailTests(TestCase):
|
||||
gdproptin=True,
|
||||
gdproptindate=timezone.now(),
|
||||
rowerplan='coach')
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
workoutsbox = Mailbox.objects.create(name='workouts')
|
||||
workoutsbox.save()
|
||||
failbox = Mailbox.objects.create(name='Failed')
|
||||
@@ -133,7 +137,7 @@ race 1
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except (IOError,WindowsError,OSError):
|
||||
except (IOError,FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@@ -152,10 +156,10 @@ race 1
|
||||
class EmailAdminUpload(TestCase):
|
||||
def setUp(self):
|
||||
redis_connection.publish('tasks','KILL')
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
gdproptindate=timezone.now(),
|
||||
birthdate = faker.profile()['birthdate']
|
||||
)
|
||||
@@ -166,10 +170,10 @@ class EmailAdminUpload(TestCase):
|
||||
gdproptin=True,
|
||||
gdproptindate=timezone.now(),
|
||||
rowerplan='coach')
|
||||
|
||||
|
||||
self.race = RaceFactory(manager = self.theadmin)
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
nu = datetime.datetime.now()
|
||||
workoutsbox = Mailbox.objects.create(name='workouts')
|
||||
workoutsbox.save()
|
||||
failbox = Mailbox.objects.create(name='Failed')
|
||||
@@ -194,7 +198,7 @@ race 1
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except (IOError,WindowsError,OSError):
|
||||
except (IOError,FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
@@ -210,7 +214,7 @@ race 1
|
||||
ws = Workout.objects.filter(name="johnsworkout")
|
||||
if not len(ws):
|
||||
for w in Workout.objects.all():
|
||||
print w
|
||||
print(w)
|
||||
|
||||
self.assertEqual(len(ws),1)
|
||||
|
||||
|
||||
@@ -1,57 +1,61 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
#from __future__ import print_function
|
||||
|
||||
from statements import *
|
||||
from .statements import *
|
||||
|
||||
|
||||
class EmpowerTest(TestCase):
|
||||
def setUp(self):
|
||||
redis_connection.publish('tasks','KILL')
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot',
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot',
|
||||
)
|
||||
r = Rower.objects.create(user=u,rowerplan='coach',gdproptin=True,
|
||||
r = Rower.objects.create(user=u,rowerplan='coach',gdproptin=True,
|
||||
gdproptindate=timezone.now())
|
||||
self.c = Client()
|
||||
self.c = Client()
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
self.nu = datetime.datetime.now()
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
otwfilename = 'rowers/tests/testdata/empower.csv'
|
||||
self.wotw = Workout.objects.create(name='testworkout',
|
||||
workouttype='water',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=self.nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
csvfilename=filename)
|
||||
|
||||
self.wote = Workout.objects.create(name='testworkout',
|
||||
workouttype='Indoor Rower',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=self.nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
csvfilename=otwfilename)
|
||||
|
||||
self.wotw = Workout.objects.create(name='testworkout',
|
||||
workouttype='water',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=self.nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
csvfilename=filename)
|
||||
|
||||
self.wote = Workout.objects.create(name='testworkout',
|
||||
workouttype='Indoor Rower',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=self.nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
csvfilename=otwfilename)
|
||||
|
||||
powerperc = 100*np.array([r.pw_ut2,
|
||||
r.pw_ut1,
|
||||
r.pw_at,
|
||||
r.pw_tr,r.pw_an])/r.ftp
|
||||
|
||||
|
||||
self.hrdata = {
|
||||
'hrmax':r.max,
|
||||
'hrut2':r.ut2,
|
||||
'hrut1':r.ut1,
|
||||
'hrat':r.at,
|
||||
'hrtr':r.tr,
|
||||
'hran':r.an,
|
||||
'ftp':r.ftp,
|
||||
self.hrdata = {
|
||||
'hrmax':r.max,
|
||||
'hrut2':r.ut2,
|
||||
'hrut1':r.ut1,
|
||||
'hrat':r.at,
|
||||
'hrtr':r.tr,
|
||||
'hran':r.an,
|
||||
'ftp':r.ftp,
|
||||
'powerperc':serialize_list(powerperc),
|
||||
'powerzones':serialize_list(r.powerzones),
|
||||
}
|
||||
}
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_workflow_map_view(self, mocked_sqlalchemy):
|
||||
login = self.c.login(username='john',password='koeinsloot')
|
||||
login = self.c.login(username='john',password='koeinsloot')
|
||||
self.assertTrue(login)
|
||||
encodedid = str(encoder.encode_hex(self.wote.id))
|
||||
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
#from __future__ import print_function
|
||||
from statements import *
|
||||
from .statements import *
|
||||
|
||||
|
||||
#@pytest.mark.django_db
|
||||
@@ -11,11 +16,12 @@ class TestErrorPages(TestCase):
|
||||
factory = RequestFactory()
|
||||
request = factory.get('/')
|
||||
response = error404_view(request)
|
||||
|
||||
self.assertEqual(response.status_code, 404)
|
||||
self.assertIn('404 Page not found', unicode(response))
|
||||
self.assertIn('404 Page not found', str(response.content))
|
||||
response = error500_view(request)
|
||||
self.assertEqual(response.status_code, 500)
|
||||
self.assertIn('500 Internal Server Error', unicode(response))
|
||||
self.assertIn('500 Internal Server Error', str(response.content))
|
||||
|
||||
response = error400_view(request)
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
from statements import *
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from .statements import *
|
||||
|
||||
@override_settings(TESTING=True)
|
||||
class WorkoutViewTest(TestCase):
|
||||
@@ -120,7 +125,7 @@ class WorkoutViewTest(TestCase):
|
||||
|
||||
form = FlexOptionsForm(form_data)
|
||||
if not form.is_valid():
|
||||
print form.errors
|
||||
print(form.errors)
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
response = self.c.post(url,form_data)
|
||||
|
||||
+232
-227
@@ -1,5 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
#from __future__ import print_function
|
||||
from statements import *
|
||||
from .statements import *
|
||||
nu = datetime.datetime.now()
|
||||
|
||||
|
||||
@@ -10,14 +15,14 @@ import rowers
|
||||
class C2Objects(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -25,39 +30,39 @@ class C2Objects(DjangoTestCase):
|
||||
self.r.c2refreshtoken = 'ab'
|
||||
self.r.tokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1)
|
||||
self.r.save()
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
|
||||
@@ -110,49 +115,49 @@ class C2Objects(DjangoTestCase):
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_strokedata(self, mocked_sqlalchemy):
|
||||
with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
with open('rowers/tests/testdata/c2stroketestdata.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
|
||||
strokedata = pd.DataFrame.from_dict(res['data'])
|
||||
strokedata = pd.DataFrame.from_dict(res['data'])
|
||||
|
||||
with open('rowers/tests/testdata/c2testdata.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
with open('rowers/tests/testdata/c2testdata.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
|
||||
data = res['data']
|
||||
data = res['data']
|
||||
|
||||
from rowers.views import add_workout_from_strokedata
|
||||
from rowers.views import add_workout_from_strokedata
|
||||
|
||||
res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2')
|
||||
res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2')
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_strokedatanohr(self, mocked_sqlalchemy):
|
||||
with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
with open('rowers/tests/testdata/c2strokedatanohr.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
|
||||
strokedata = pd.DataFrame.from_dict(res['data'])
|
||||
strokedata = pd.DataFrame.from_dict(res['data'])
|
||||
|
||||
with open('rowers/tests/testdata/c2testdata.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
with open('rowers/tests/testdata/c2testdata.txt','r') as infile:
|
||||
res = json.load(infile)
|
||||
|
||||
data = res['data']
|
||||
data = res['data']
|
||||
|
||||
from rowers.views import add_workout_from_strokedata
|
||||
from rowers.views import add_workout_from_strokedata
|
||||
|
||||
|
||||
res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2')
|
||||
res = add_workout_from_strokedata(self.u,1,data,strokedata,source='c2')
|
||||
|
||||
@override_settings(TESTING=True)
|
||||
class C2ObjectsTokenExpired(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -160,39 +165,39 @@ class C2ObjectsTokenExpired(DjangoTestCase):
|
||||
self.r.c2refreshtoken = 'ab'
|
||||
self.r.tokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1)
|
||||
self.r.save()
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
|
||||
@@ -224,14 +229,14 @@ class C2ObjectsTokenExpired(DjangoTestCase):
|
||||
class StravaObjects(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -240,38 +245,38 @@ class StravaObjects(DjangoTestCase):
|
||||
self.r.stravatokenexpirydate = datetime.datetime.now()-datetime.timedelta(days=1)
|
||||
|
||||
self.r.save()
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.nu = datetime.datetime.now()
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
|
||||
@@ -330,14 +335,14 @@ class StravaObjects(DjangoTestCase):
|
||||
class STObjects(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -347,39 +352,39 @@ class STObjects(DjangoTestCase):
|
||||
self.r.sporttrackstokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1)
|
||||
self.r.save()
|
||||
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
@patch('rowers.sporttracksstuff.requests.post', side_effect=mocked_requests)
|
||||
@@ -442,37 +447,37 @@ class STObjects(DjangoTestCase):
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_strokedata(self, mocked_sqlalchemy):
|
||||
with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile:
|
||||
data = json.load(infile)
|
||||
with open('rowers/tests/testdata/sporttrackstestdata.txt','r') as infile:
|
||||
data = json.load(infile)
|
||||
|
||||
from rowers.sporttracksstuff import add_workout_from_data
|
||||
from rowers.sporttracksstuff import add_workout_from_data
|
||||
|
||||
res = add_workout_from_data(self.u,1,data,data)
|
||||
res = add_workout_from_data(self.u,1,data,data)
|
||||
|
||||
@patch('rowers.dataprep.create_engine')
|
||||
def test_strokedatanohr(self, mocked_sqlalchemy):
|
||||
with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile:
|
||||
data = json.load(infile)
|
||||
with open('rowers/tests/testdata/sporttrackstestnohr.txt','r') as infile:
|
||||
data = json.load(infile)
|
||||
|
||||
from rowers.sporttracksstuff import add_workout_from_data
|
||||
from rowers.sporttracksstuff import add_workout_from_data
|
||||
|
||||
|
||||
|
||||
res = add_workout_from_data(self.u,1,data,data)
|
||||
res = add_workout_from_data(self.u,1,data,data)
|
||||
|
||||
#@pytest.mark.django_db
|
||||
@override_settings(TESTING=True)
|
||||
class RunKeeperObjects(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -481,39 +486,39 @@ class RunKeeperObjects(DjangoTestCase):
|
||||
|
||||
self.r.save()
|
||||
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
@patch('rowers.runkeeperstuff.requests.post', side_effect=mocked_requests)
|
||||
@@ -558,14 +563,14 @@ class RunKeeperObjects(DjangoTestCase):
|
||||
class UAObjects(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -575,39 +580,39 @@ class UAObjects(DjangoTestCase):
|
||||
self.r.underarmourtokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1)
|
||||
self.r.save()
|
||||
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
@patch('rowers.imports.requests.post', side_effect=mocked_requests)
|
||||
@@ -661,14 +666,14 @@ class UAObjects(DjangoTestCase):
|
||||
class TPObjects(DjangoTestCase):
|
||||
def setUp(self):
|
||||
self.c = Client()
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
self.u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
|
||||
self.u.first_name = 'John'
|
||||
self.u.last_name = 'Sander'
|
||||
self.u.save()
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
self.r = Rower.objects.create(user=self.u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -678,39 +683,39 @@ class TPObjects(DjangoTestCase):
|
||||
self.r.tptokenexpirydate = datetime.datetime.now()+datetime.timedelta(days=1)
|
||||
self.r.save()
|
||||
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
self.c.login(username='john',password='koeinsloot')
|
||||
|
||||
self.nu = datetime.datetime.now()
|
||||
self.nu = datetime.datetime.now()
|
||||
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
filename = 'rowers/tests/testdata/testdata.csv'
|
||||
|
||||
rr = rrower(hrmax=self.r.max,hrut2=self.r.ut2,
|
||||
hrut1=self.r.ut1,hrat=self.r.at,
|
||||
hrtr=self.r.tr,hran=self.r.an,ftp=self.r.ftp)
|
||||
row = rdata(filename,rower=rr)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[:,' ElapsedTime (sec)'].iloc[0]
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
duration=duration,distance=totaldist,
|
||||
csvfilename=filename
|
||||
)
|
||||
|
||||
@patch('rowers.imports.requests.post', side_effect=mocked_requests)
|
||||
@@ -748,10 +753,10 @@ class TPObjects(DjangoTestCase):
|
||||
class AutoExportTests(TestCase):
|
||||
def setUp(self):
|
||||
redis_connection.publish('tasks','KILL')
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
u = User.objects.create_user('john',
|
||||
'sander@ds.ds',
|
||||
'koeinsloot')
|
||||
r = Rower.objects.create(user=u,gdproptin=True,
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
|
||||
@@ -762,7 +767,7 @@ class AutoExportTests(TestCase):
|
||||
|
||||
r.save()
|
||||
|
||||
nu = datetime.datetime.now()
|
||||
nu = datetime.datetime.now()
|
||||
workoutsbox = Mailbox.objects.create(name='workouts')
|
||||
workoutsbox.save()
|
||||
failbox = Mailbox.objects.create(name='Failed')
|
||||
@@ -791,7 +796,7 @@ boattype: 2x
|
||||
if not os.path.isdir(path):
|
||||
try:
|
||||
os.remove(path)
|
||||
except (WindowsError,OSError):
|
||||
except (FileNotFoundError,OSError):
|
||||
pass
|
||||
|
||||
@patch('rowers.tpstuff.requests.post', side_effect=mocked_requests)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user