diff --git a/cvkbrno/__init__.pyc b/cvkbrno/__init__.pyc deleted file mode 100644 index 4cc88b3b..00000000 Binary files a/cvkbrno/__init__.pyc and /dev/null differ diff --git a/cvkbrno/admin.pyc b/cvkbrno/admin.pyc deleted file mode 100644 index e674dee8..00000000 Binary files a/cvkbrno/admin.pyc and /dev/null differ diff --git a/cvkbrno/celery.pyc b/cvkbrno/celery.pyc deleted file mode 100644 index c05582e5..00000000 Binary files a/cvkbrno/celery.pyc and /dev/null differ diff --git a/cvkbrno/forms.pyc b/cvkbrno/forms.pyc deleted file mode 100644 index 8094a3c4..00000000 Binary files a/cvkbrno/forms.pyc and /dev/null differ diff --git a/cvkbrno/locale/cs/LC_MESSAGES/django.po~ b/cvkbrno/locale/cs/LC_MESSAGES/django.po~ deleted file mode 100644 index 764d27f7..00000000 --- a/cvkbrno/locale/cs/LC_MESSAGES/django.po~ +++ /dev/null @@ -1,244 +0,0 @@ -#: .\cvkbrno\models.py:16 -msgid "Boat Category" -msgstr "" - -#: .\cvkbrno\models.py:19 -msgid "boat category" -msgstr "" - -#: .\cvkbrno\models.py:20 -msgid "boat categories" -msgstr "" - -#: .\cvkbrno\models.py:34 -msgid "coach" -msgstr "" - -#: .\cvkbrno\models.py:35 .\cvkbrno\models.py:40 -msgid "member" -msgstr "" - -#: .\cvkbrno\models.py:36 -msgid "administrator" -msgstr "" - -#: .\cvkbrno\models.py:41 -msgid "members" -msgstr "" - -#: .\cvkbrno\models.py:49 -msgid "Boat Categories" -msgstr "" - -#: .\cvkbrno\models.py:50 -msgid "Club" -msgstr "" - -#: .\cvkbrno\models.py:51 -msgid "Hours Worked" -msgstr "" - -#: .\cvkbrno\models.py:63 -msgid "boat" -msgstr "" - -#: .\cvkbrno\models.py:64 -msgid "boats" -msgstr "" - -#: .\cvkbrno\models.py:66 -msgid "Boat Name" -msgstr "" - -#: .\cvkbrno\models.py:67 -msgid "Boat Code" -msgstr "" - -#: .\cvkbrno\models.py:69 -msgid "Nr of Seats" -msgstr "" - -#: .\cvkbrno\models.py:71 -msgid "water" -msgstr "" - -#: .\cvkbrno\models.py:72 -msgid "hangar" -msgstr "" - -#: .\cvkbrno\models.py:73 .\cvkbrno\views.py:661 -msgid "damaged" -msgstr "" - -#: .\cvkbrno\models.py:74 -msgid "races" -msgstr "" - -#: .\cvkbrno\models.py:94 .\cvkbrno\models.py:95 -msgid "member work" -msgstr "" - -#: .\cvkbrno\models.py:97 -msgid "Date" -msgstr "" - -#: .\cvkbrno\models.py:98 -msgid "Hours" -msgstr "" - -#: .\cvkbrno\models.py:99 -msgid "Work Event Name" -msgstr "" - -#: .\cvkbrno\models.py:102 -msgid "planned" -msgstr "" - -#: .\cvkbrno\models.py:103 -msgid "executed" -msgstr "" - -#: .\cvkbrno\models.py:111 -msgid "outing" -msgstr "" - -#: .\cvkbrno\models.py:112 -msgid "outings" -msgstr "" - -#: .\cvkbrno\models.py:115 -msgid "Start Date/Time" -msgstr "" - -#: .\cvkbrno\models.py:116 -msgid "End Date/Time" -msgstr "" - -#: .\cvkbrno\models.py:117 -msgid "Distance" -msgstr "" - -#: .\cvkbrno\models.py:118 -msgid "Comment" -msgstr "" - -#: .\cvkbrno\models.py:120 -msgid "reservation" -msgstr "" - -#: .\cvkbrno\models.py:121 -msgid "active" -msgstr "" - -#: .\cvkbrno\models.py:122 -msgid "completed" -msgstr "" - -#: .\cvkbrno\models.py:123 -msgid "race" -msgstr "" - -#: .\cvkbrno\models.py:127 -msgid "Status" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:29 -msgid "Welcome," -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:33 -msgid "Password Change" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:45 -msgid "Members Work" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:59 -msgid "Go Rowing" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:69 -msgid "Reservations" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:78 -msgid "Boats" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:86 -msgid "Members" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:94 -msgid "Transport" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:102 -msgid "Categories" -msgstr "" - -#: .\cvkbrno\templates\cvkbrnobase.html:109 -msgid "logout" -msgstr "" - -#: .\cvkbrno\views.py:245 -msgid "boat deleted" -msgstr "" - -#: .\cvkbrno\views.py:259 -msgid "member deleted" -msgstr "" - -#: .\cvkbrno\views.py:273 -msgid "category deleted" -msgstr "" - -#: .\cvkbrno\views.py:304 .\cvkbrno\views.py:398 .\cvkbrno\views.py:445 -#: .\cvkbrno\views.py:493 -msgid "invalid form" -msgstr "" - -#: .\cvkbrno\views.py:537 .\cvkbrno\views.py:543 .\cvkbrno\views.py:921 -msgid "Changes saved" -msgstr "" - -#: .\cvkbrno\views.py:643 -msgid "You have no active outings. Go rowing first." -msgstr "" - -#: .\cvkbrno\views.py:649 -msgid "You are not out. Go rowing first." -msgstr "" - -#: .\cvkbrno\views.py:714 -msgid "Conflicting reservations exist" -msgstr "" - -#: .\cvkbrno\views.py:731 -msgid "Invalid Form" -msgstr "" - -#: .\cvkbrno\views.py:747 -msgid "Make a reservation" -msgstr "" - -#: .\cvkbrno\views.py:773 .\cvkbrno\views.py:814 -msgid "There is already a boat with that code" -msgstr "" - -#: .\cvkbrno\views.py:823 -msgid "Changes Saved" -msgstr "" - -#: .\cvkbrno\views.py:848 -msgid "The two passwords are not equal" -msgstr "" - -#: .\cvkbrno\views.py:855 -msgid "There is already a user with that username" -msgstr "" - -#: .\cvkbrno\views.py:880 -msgid "New Member Created" -msgstr "" diff --git a/cvkbrno/locale/nl/LC_MESSAGES/django.po~ b/cvkbrno/locale/nl/LC_MESSAGES/django.po~ deleted file mode 100644 index 6b263121..00000000 --- a/cvkbrno/locale/nl/LC_MESSAGES/django.po~ +++ /dev/null @@ -1,263 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 08:27+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: .\cvkbrno\models.py:16 -msgid "Boat Category" -msgstr "Kategorie Lodí" - -#: .\cvkbrno\models.py:19 -msgid "boat category" -msgstr "kategorie lodí" - -#: .\cvkbrno\models.py:20 -msgid "boat categories" -msgstr "kategorie lodí" - -#: .\cvkbrno\models.py:34 -msgid "coach" -msgstr "trenér" - -#: .\cvkbrno\models.py:35 .\cvkbrno\models.py:40 -msgid "member" -msgstr "clen" - -#: .\cvkbrno\models.py:36 -msgid "administrator" -msgstr "správce" - -#: .\cvkbrno\models.py:41 -msgid "members" -msgstr "clenové" - -#: .\cvkbrno\models.py:49 -msgid "Boat Categories" -msgstr "Kategorie Lodí" - -#: .\cvkbrno\models.py:50 -msgid "Club" -msgstr "Klub" - -#: .\cvkbrno\models.py:51 -msgid "Hours Worked" -msgstr "Odpracované hodiny" - -#: .\cvkbrno\models.py:63 -msgid "boat" -msgstr "lod" - -#: .\cvkbrno\models.py:64 -msgid "boats" -msgstr "lode" - -#: .\cvkbrno\models.py:66 -msgid "Boat Name" -msgstr "název lodi" - -#: .\cvkbrno\models.py:67 -msgid "Boat Code" -msgstr "Kód Lode" - -#: .\cvkbrno\models.py:69 -msgid "Nr of Seats" -msgstr "Pocet míst" - -#: .\cvkbrno\models.py:71 -msgid "water" -msgstr "na vode" - -#: .\cvkbrno\models.py:72 -msgid "hangar" -msgstr "v hangaru" - -#: .\cvkbrno\models.py:73 .\cvkbrno\views.py:656 -msgid "damaged" -msgstr "poškozená" - -#: .\cvkbrno\models.py:74 -msgid "races" -msgstr "na závodech" - -#: .\cvkbrno\models.py:94 .\cvkbrno\models.py:95 -msgid "member work" -msgstr "brigády" - -#: .\cvkbrno\models.py:97 -msgid "Date" -msgstr "Datum" - -#: .\cvkbrno\models.py:98 -msgid "Hours" -msgstr "Hodiny" - -#: .\cvkbrno\models.py:99 -msgid "Work Event Name" -msgstr "Název Brigády" - -#: .\cvkbrno\models.py:102 -msgid "planned" -msgstr "plánovaná" - -#: .\cvkbrno\models.py:103 -msgid "executed" -msgstr "hotová" - -#: .\cvkbrno\models.py:111 -msgid "outing" -msgstr "výjezd" - -#: .\cvkbrno\models.py:112 -msgid "outings" -msgstr "výjezdy" - -#: .\cvkbrno\models.py:115 -msgid "Start Date/Time" -msgstr "Startovní Datum/Cas" - -#: .\cvkbrno\models.py:116 -msgid "End Date/Time" -msgstr "Datum/Cas ukoncení" - -#: .\cvkbrno\models.py:117 -msgid "Distance" -msgstr "Vzdálenost" - -#: .\cvkbrno\models.py:118 -msgid "Comment" -msgstr "Komentár" - -#: .\cvkbrno\models.py:120 -msgid "reservation" -msgstr "rezervace" - -#: .\cvkbrno\models.py:121 -msgid "active" -msgstr "aktivní" - -#: .\cvkbrno\models.py:122 -msgid "completed" -msgstr "dokoncený" - -#: .\cvkbrno\models.py:123 -msgid "race" -msgstr "závod" - -#: .\cvkbrno\models.py:127 -msgid "Status" -msgstr "Status" - -#: .\cvkbrno\templates\cvkbrnobase.html:26 -msgid "Welcome," -msgstr "Vítej," - -#: .\cvkbrno\templates\cvkbrnobase.html:30 -msgid "Password Change" -msgstr "Zmenit Heslo" - -#: .\cvkbrno\templates\cvkbrnobase.html:42 -msgid "Members Work" -msgstr "Brigády" - -#: .\cvkbrno\templates\cvkbrnobase.html:56 -msgid "Go Rowing" -msgstr "Jdi na vodu" - -#: .\cvkbrno\templates\cvkbrnobase.html:66 -msgid "Reservations" -msgstr "Rezervace" - -#: .\cvkbrno\templates\cvkbrnobase.html:75 -msgid "Boats" -msgstr "Lode" - -#: .\cvkbrno\templates\cvkbrnobase.html:83 -msgid "Members" -msgstr "Clenové" - -#: .\cvkbrno\templates\cvkbrnobase.html:91 -msgid "Transport" -msgstr "Doprava" - -#: .\cvkbrno\templates\cvkbrnobase.html:99 -msgid "Categories" -msgstr "Kategorie" - -#: .\cvkbrno\templates\cvkbrnobase.html:106 -msgid "logout" -msgstr "odhlásit" - -#: .\cvkbrno\views.py:240 -msgid "boat deleted" -msgstr "lod smazána" - -#: .\cvkbrno\views.py:254 -msgid "member deleted" -msgstr "clen smazán" - -#: .\cvkbrno\views.py:268 -msgid "category deleted" -msgstr "kategorie smazána" - -#: .\cvkbrno\views.py:299 .\cvkbrno\views.py:393 .\cvkbrno\views.py:440 -#: .\cvkbrno\views.py:488 -msgid "invalid form" -msgstr "neplatný formulár" - -#: .\cvkbrno\views.py:532 .\cvkbrno\views.py:538 .\cvkbrno\views.py:916 -msgid "Changes saved" -msgstr "Zmeny uloženy" - -#: .\cvkbrno\views.py:638 -msgid "You have no active outings. Go rowing first." -msgstr "Nemáte žádné aktivní výjezdy. Jdete nejdríve na vodu." - -#: .\cvkbrno\views.py:644 -msgid "You are not out. Go rowing first." -msgstr "Nejste na vode. Jdete nejdríve na vodu." - -#: .\cvkbrno\views.py:709 -msgid "Conflicting reservations exist" -msgstr "Konflikt rezervací" - -#: .\cvkbrno\views.py:726 -msgid "Invalid Form" -msgstr "Neplatný Formulár" - -#: .\cvkbrno\views.py:742 -msgid "Make a reservation" -msgstr "Rezervujte" - -#: .\cvkbrno\views.py:768 .\cvkbrno\views.py:809 -msgid "There is already a boat with that code" -msgstr "Již existuje jiná lod s tímto kódem." - -#: .\cvkbrno\views.py:818 -msgid "Changes Saved" -msgstr "Zmeny Uloženy" - -#: .\cvkbrno\views.py:843 -msgid "The two passwords are not equal" -msgstr "Nazadal jste stejná hesla." - -#: .\cvkbrno\views.py:850 -msgid "There is already a user with that username" -msgstr "Uživatel s tímto uživatelském jménem již existuje" - -#: .\cvkbrno\views.py:875 -msgid "New Member Created" -msgstr "Nový clen vytvoren" diff --git a/cvkbrno/migrations/0001_initial.pyc b/cvkbrno/migrations/0001_initial.pyc deleted file mode 100644 index 6e561ee5..00000000 Binary files a/cvkbrno/migrations/0001_initial.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0002_auto_20160515_0910.pyc b/cvkbrno/migrations/0002_auto_20160515_0910.pyc deleted file mode 100644 index ef5d4ad5..00000000 Binary files a/cvkbrno/migrations/0002_auto_20160515_0910.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0003_member_club.pyc b/cvkbrno/migrations/0003_member_club.pyc deleted file mode 100644 index 1fa508a9..00000000 Binary files a/cvkbrno/migrations/0003_member_club.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0004_auto_20160518_2001.pyc b/cvkbrno/migrations/0004_auto_20160518_2001.pyc deleted file mode 100644 index 96b8485f..00000000 Binary files a/cvkbrno/migrations/0004_auto_20160518_2001.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0005_auto_20160519_0750.pyc b/cvkbrno/migrations/0005_auto_20160519_0750.pyc deleted file mode 100644 index 2f133f77..00000000 Binary files a/cvkbrno/migrations/0005_auto_20160519_0750.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0006_auto_20160519_0805.pyc b/cvkbrno/migrations/0006_auto_20160519_0805.pyc deleted file mode 100644 index 6881744c..00000000 Binary files a/cvkbrno/migrations/0006_auto_20160519_0805.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0007_auto_20160519_1103.pyc b/cvkbrno/migrations/0007_auto_20160519_1103.pyc deleted file mode 100644 index bff387a2..00000000 Binary files a/cvkbrno/migrations/0007_auto_20160519_1103.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0008_auto_20160519_1204.pyc b/cvkbrno/migrations/0008_auto_20160519_1204.pyc deleted file mode 100644 index 7ae14603..00000000 Binary files a/cvkbrno/migrations/0008_auto_20160519_1204.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0009_auto_20160519_1207.pyc b/cvkbrno/migrations/0009_auto_20160519_1207.pyc deleted file mode 100644 index d8846bdc..00000000 Binary files a/cvkbrno/migrations/0009_auto_20160519_1207.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0010_auto_20160608_0811.pyc b/cvkbrno/migrations/0010_auto_20160608_0811.pyc deleted file mode 100644 index f3783923..00000000 Binary files a/cvkbrno/migrations/0010_auto_20160608_0811.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0011_auto_20160613_1640.pyc b/cvkbrno/migrations/0011_auto_20160613_1640.pyc deleted file mode 100644 index 06e73d5a..00000000 Binary files a/cvkbrno/migrations/0011_auto_20160613_1640.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0012_auto_20160719_2240.pyc b/cvkbrno/migrations/0012_auto_20160719_2240.pyc deleted file mode 100644 index f15e71ea..00000000 Binary files a/cvkbrno/migrations/0012_auto_20160719_2240.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0013_auto_20160719_2245.pyc b/cvkbrno/migrations/0013_auto_20160719_2245.pyc deleted file mode 100644 index 7c2504e6..00000000 Binary files a/cvkbrno/migrations/0013_auto_20160719_2245.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0014_auto_20160719_2313.pyc b/cvkbrno/migrations/0014_auto_20160719_2313.pyc deleted file mode 100644 index cebd63e5..00000000 Binary files a/cvkbrno/migrations/0014_auto_20160719_2313.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0015_auto_20160720_1741.pyc b/cvkbrno/migrations/0015_auto_20160720_1741.pyc deleted file mode 100644 index 1a073758..00000000 Binary files a/cvkbrno/migrations/0015_auto_20160720_1741.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0016_outing_race.pyc b/cvkbrno/migrations/0016_outing_race.pyc deleted file mode 100644 index 48485307..00000000 Binary files a/cvkbrno/migrations/0016_outing_race.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0017_auto_20160721_1621.pyc b/cvkbrno/migrations/0017_auto_20160721_1621.pyc deleted file mode 100644 index 85547a44..00000000 Binary files a/cvkbrno/migrations/0017_auto_20160721_1621.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0018_auto_20160722_1043.pyc b/cvkbrno/migrations/0018_auto_20160722_1043.pyc deleted file mode 100644 index f5fa6cc1..00000000 Binary files a/cvkbrno/migrations/0018_auto_20160722_1043.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0019_boatcategory_club.pyc b/cvkbrno/migrations/0019_boatcategory_club.pyc deleted file mode 100644 index 1b68d381..00000000 Binary files a/cvkbrno/migrations/0019_boatcategory_club.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0020_remove_member_club.pyc b/cvkbrno/migrations/0020_remove_member_club.pyc deleted file mode 100644 index 414fef5f..00000000 Binary files a/cvkbrno/migrations/0020_remove_member_club.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0021_member_club.pyc b/cvkbrno/migrations/0021_member_club.pyc deleted file mode 100644 index 3172a6bd..00000000 Binary files a/cvkbrno/migrations/0021_member_club.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0022_auto_20160723_1502.pyc b/cvkbrno/migrations/0022_auto_20160723_1502.pyc deleted file mode 100644 index 5c0e5252..00000000 Binary files a/cvkbrno/migrations/0022_auto_20160723_1502.pyc and /dev/null differ diff --git a/cvkbrno/migrations/0023_memberwork_comment.pyc b/cvkbrno/migrations/0023_memberwork_comment.pyc deleted file mode 100644 index bb61dae6..00000000 Binary files a/cvkbrno/migrations/0023_memberwork_comment.pyc and /dev/null differ diff --git a/cvkbrno/migrations/__init__.pyc b/cvkbrno/migrations/__init__.pyc deleted file mode 100644 index 1e3d53c1..00000000 Binary files a/cvkbrno/migrations/__init__.pyc and /dev/null differ diff --git a/cvkbrno/models.pyc b/cvkbrno/models.pyc deleted file mode 100644 index 13ac628e..00000000 Binary files a/cvkbrno/models.pyc and /dev/null differ diff --git a/cvkbrno/tasks.pyc b/cvkbrno/tasks.pyc deleted file mode 100644 index d5332688..00000000 Binary files a/cvkbrno/tasks.pyc and /dev/null differ diff --git a/cvkbrno/templates/cvkbrno_boat_add_form.html~ b/cvkbrno/templates/cvkbrno_boat_add_form.html~ deleted file mode 100644 index 568a34ac..00000000 --- a/cvkbrno/templates/cvkbrno_boat_add_form.html~ +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Create Boat" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Create Boat" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_boat_delete_confirm.html~ b/cvkbrno/templates/cvkbrno_boat_delete_confirm.html~ deleted file mode 100644 index 91df8317..00000000 --- a/cvkbrno/templates/cvkbrno_boat_delete_confirm.html~ +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% "Delete Boat" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_boat_edit_form.html~ b/cvkbrno/templates/cvkbrno_boat_edit_form.html~ deleted file mode 100644 index ca52ec17..00000000 --- a/cvkbrno/templates/cvkbrno_boat_edit_form.html~ +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Edit Boat" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Edit Boat" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
-
-

{% trans "Recent Outings with this boat" %}

- -
-

-   -

-
- - - - - - - - - - - {% for outing in theoutings %} - - - - - - {% endfor %} - -
{% trans "Date" %}{% trans "Rower" %}{% trans "Status" %}
{{ outing.starttime }}{{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }}{% trans outing.status %}
- -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_boats_admin.html~ b/cvkbrno/templates/cvkbrno_boats_admin.html~ deleted file mode 100644 index 9c1daded..00000000 --- a/cvkbrno/templates/cvkbrno_boats_admin.html~ +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Boats Admin" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Boats Admin" %}

- - - - - - - - - - - - - - - {% for boat in theboats %} - - - - - - - {% endfor %} - -
{% trans "Code" %}{% trans "Name" %}{% trans "Status" %}{% trans "Edit" %}
{{ boat.boatcode }}{{ boat.boatname }}{% trans boat.status %}E
- {% csrf_token %} -
-
-

{% trans "Recent Outings" %}

- -
-

-   -

-
- - - - - - - - - - - - {% for outing in theoutings %} - - - - - - - {% endfor %} - -
{% trans "Date" %}{% trans "Name" %}{% trans "Rower" %}{% trans "Status" %}
{{ outing.starttime }}{{ outing.boat.boatname }}{{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }}{% trans outing.status %}
- - -
-{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_categories_admin.html~ b/cvkbrno/templates/cvkbrno_categories_admin.html~ deleted file mode 100644 index 3ff4be05..00000000 --- a/cvkbrno/templates/cvkbrno_categories_admin.html~ +++ /dev/null @@ -1,45 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Boat Category Admin" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Boat Category Admin" %}

- - - - - - - - - - - - - {% for category in thecats %} - - - - - {% endfor %} - -
{% trans "Name" %}{% trans "Edit" %}
{{ category.name }}E
- {% csrf_token %} -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_categories_delete_confirm.html~ b/cvkbrno/templates/cvkbrno_categories_delete_confirm.html~ deleted file mode 100644 index a33fcf60..00000000 --- a/cvkbrno/templates/cvkbrno_categories_delete_confirm.html~ +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Delete Boat Category" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_categories_edit_form.html~ b/cvkbrno/templates/cvkbrno_categories_edit_form.html~ deleted file mode 100644 index 54895782..00000000 --- a/cvkbrno/templates/cvkbrno_categories_edit_form.html~ +++ /dev/null @@ -1,37 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Edit Category" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Edit Category" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_category_add_form.html~ b/cvkbrno/templates/cvkbrno_category_add_form.html~ deleted file mode 100644 index aca068a7..00000000 --- a/cvkbrno/templates/cvkbrno_category_add_form.html~ +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Create Category" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Create Category" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_login.html~ b/cvkbrno/templates/cvkbrno_login.html~ deleted file mode 100644 index bb36b200..00000000 --- a/cvkbrno/templates/cvkbrno_login.html~ +++ /dev/null @@ -1,81 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} - -{% block content %} -
-{% if form.errors %} -

{% trans "Your username and password didn't match. Please try again." %}

-{% endif %} - -
-{% csrf_token %} -{% if next %} - - {% endif %} - - - - - - - -
- - - -
- - - -
 

-
- -
-
-
- -
-

{% trans "Boats Out" %}

- - - - - - - - - - {% for outing in activeoutings %} - - - - - {% endfor %} - - -
{% trans "Boat" %}{% trans "Departure time" %}
{{ outing.boat.boatname }} {{ outing.starttime }}
-
-
-

{% trans "Reservations" %}

- - - - - - - - - - - {% for res in reservations %} - - - - - - {% endfor %} - - -
{% trans "Boat" %}{% trans "Departure time" %}{% trans "Reserved by" %}
{{ res.boat.boatname }} {{ res.starttime }} {{ res.rower.user.first_name }} {{ res.rower.user.last_name }}
-{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_member_add_form.html~ b/cvkbrno/templates/cvkbrno_member_add_form.html~ deleted file mode 100644 index a88384c1..00000000 --- a/cvkbrno/templates/cvkbrno_member_add_form.html~ +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Create Member" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Create Member" %}

- - -
- - {{ form1.as_table }} - {{ form2.as_table }} - {{ form3.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_member_edit_form.html~ b/cvkbrno/templates/cvkbrno_member_edit_form.html~ deleted file mode 100644 index 98a3ba4f..00000000 --- a/cvkbrno/templates/cvkbrno_member_edit_form.html~ +++ /dev/null @@ -1,38 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Edit Member" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Edit Member" %}

- - -
- - {{ form1.as_table }} - {{ form2.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_members_admin.html~ b/cvkbrno/templates/cvkbrno_members_admin.html~ deleted file mode 100644 index 6bbfc96e..00000000 --- a/cvkbrno/templates/cvkbrno_members_admin.html~ +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Members Admin" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Members Admin" %}

- - - - - {% if themembers %} - - - - - - - - - - - - {% for member in themembers %} - - - - - - - {% endfor %} - -
{% trans "Last Name" %}{% trans "First Name" %}{% trans "Contributions" %}{% trans "Edit" %}
{{ member.user.last_name }}{{ member.user.first_name }}{{ member.contributions }}E
- - {% endif %} - {% csrf_token %} -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_members_delete_confirm.html~ b/cvkbrno/templates/cvkbrno_members_delete_confirm.html~ deleted file mode 100644 index f26b4cae..00000000 --- a/cvkbrno/templates/cvkbrno_members_delete_confirm.html~ +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Delete Member" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_memberswork_admin.html~ b/cvkbrno/templates/cvkbrno_memberswork_admin.html~ deleted file mode 100644 index a9c24caa..00000000 --- a/cvkbrno/templates/cvkbrno_memberswork_admin.html~ +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Members Admin" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Members Admin" %}

- - - - - {% if themembers %} - - - - - - - - - - - - {% for member in themembers %} - - - - - - - {% endfor %} - -
{% trans "Last Name" %}{% trans "First Name" %}{% trans "Contributions" %}{% trans "Edit" %}
{{ member.user.last_name }}{{ member.user.first_name }}{{ member.contributions }}E
- - {% endif %} - {% csrf_token %} -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_memberwork_edit_form.html~ b/cvkbrno/templates/cvkbrno_memberwork_edit_form.html~ deleted file mode 100644 index 551d0caf..00000000 --- a/cvkbrno/templates/cvkbrno_memberwork_edit_form.html~ +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Edit Member Work" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Edit Boat" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
-
-

{% trans "Recent Outings with this boat" %}

- -
-

-   -

-
- - - - - - - - - - - {% for outing in theoutings %} - - - - - - {% endfor %} - -
{% trans "Date" %}{% trans "Rower" %}{% trans "Status" %}
{{ outing.starttime }}{{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }}{% trans outing.status %}
- -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_meterboard.html~ b/cvkbrno/templates/cvkbrno_meterboard.html~ deleted file mode 100644 index 357f9881..00000000 --- a/cvkbrno/templates/cvkbrno_meterboard.html~ +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Meterboard" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Meterboard" %}

- - - {{ data|safe }} - - {% csrf_token %} -
-
-

{% trans "Recent Outings" %}

- - - - - - - - - - - - {% for outing in theoutings %} - - - - - - - {% endfor %} - -
{% trans "Date" %}{% trans "Name" %}{% trans "Rower" %}{% trans "Status" %}
{{ outing.starttime }}{{ outing.boat.boatname }}{{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }}{% trans outing.status %}
- - -
-{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_outing_admin.html~ b/cvkbrno/templates/cvkbrno_outing_admin.html~ deleted file mode 100644 index c07cd961..00000000 --- a/cvkbrno/templates/cvkbrno_outing_admin.html~ +++ /dev/null @@ -1,66 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "View Outing" %}{% endblock %} - -{% block content %} -
- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Edit Boat" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
-
-

{% trans "Recent Outings with this boat" %}

- -
-

-   -

-
- - - - - - - - - - - {% for outing in theoutings %} - - - - - - {% endfor %} - -
{% trans "Date" %}{% trans "Rower" %}{% trans "Status" %}
{{ outing.starttime }}{{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }}{% trans outing.status %}
- -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_outing_closeform.html~ b/cvkbrno/templates/cvkbrno_outing_closeform.html~ deleted file mode 100644 index dace5944..00000000 --- a/cvkbrno/templates/cvkbrno_outing_closeform.html~ +++ /dev/null @@ -1,40 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Return from outing" %} -{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Return from outing" %}

-

{{ outing.boat.boatcode }} {{ outing.boat.boatname }}

-

{% trans "Please check the boat" %}

- -
- - - - - - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_outing_form.html~ b/cvkbrno/templates/cvkbrno_outing_form.html~ deleted file mode 100644 index d10da855..00000000 --- a/cvkbrno/templates/cvkbrno_outing_form.html~ +++ /dev/null @@ -1,182 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} -{% load tz %} - -{% block title %}{% trans "Going Rowing" %} {% endblock %} - -{% block content %} -{% localtime on %} - - -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Going Rowing" %}

- - -
- - {{ form.as_table }} - - -
-

 

- -

1: {{ user.first_name }} {{ user.last_name }}

-

- {% csrf_token %} -
- -
-
- - -
-
-

{% trans "Reservations" %}

- - - - - - - - - - - {% for outing in reservations %} - - - - - {% if user == outing.rower.user or thisclub_admin %} - - {% else %} - - {% endfor %} - - -
{% trans "Boat" %}{% trans "Departure time" %}{% trans "Reserved by" %}{% trans "Delete" %} -
{{ outing.boat.boatname }} {{ outing.starttime }} {{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }} D  - -
- -
- -
-{% if damagedboats %} -

{% trans "Temporarily Unavailable" %}

- - - {% for boat in damagedboats %} - - - - {% endfor %} - - - -
{{ boat.boatname }}
-{% endif %} - -{% if races %} -

{% trans "Upcoming Races" %}

- - - - - - - - - - {% for race in races %} - - - - - - {% endfor %} - -
{% trans "Name" %}{% trans "Start Date" %}{% trans "End Date" %}
{{ race.name }}{{ race.startdatetime }}{{ race.enddatetime }}
-{% endif %} -
- -
-{% if plannedwork %} -

{% trans "Upcoming Members Work" %}

- - - - - - - - - - {% for w in plannedwork %} - - - - {% if member in w.worker.all %} - - {% else %} - - {% endif %} - - {% endfor %} - -
{% trans "Name" %}{% trans "Date" %}{% trans "Action" %}
{{ w.name }}{{ w.date }}{% trans "Remove me" %}{% trans "Add me" %}
-{% endif %} -
-{% endlocaltime %} -{% endblock %} diff --git a/cvkbrno/templates/cvkbrno_races_form.html~ b/cvkbrno/templates/cvkbrno_races_form.html~ deleted file mode 100644 index db6f64de..00000000 --- a/cvkbrno/templates/cvkbrno_races_form.html~ +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Create Races Event" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Create Races Event" %}

- - -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_races_list.html~ b/cvkbrno/templates/cvkbrno_races_list.html~ deleted file mode 100644 index f980d84b..00000000 --- a/cvkbrno/templates/cvkbrno_races_list.html~ +++ /dev/null @@ -1,45 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Races Admin" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Races Admin" %}

- - - - - - - - - - - - - {% for race in races %} - - - - - {% endfor %} - -
{% trans "Name" %}{% trans "Edit" %}
{{ race.name }}E
- {% csrf_token %} -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_reservation_form.html~ b/cvkbrno/templates/cvkbrno_reservation_form.html~ deleted file mode 100644 index abe096e3..00000000 --- a/cvkbrno/templates/cvkbrno_reservation_form.html~ +++ /dev/null @@ -1,74 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load i18n %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}{% trans "Make a Reservation" %}{% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

{% trans "Make a reservation" %}

- - -
- - {{ form.as_table }} - - - -
- {% csrf_token %} -
- -
-
-
-
-

{% trans "Reservations" %}

- - - - - - - - - - - - - - {% for outing in reservations %} - - - - - - - {% if user == outing.rower.user or thisclub_admin %} - - {% else %} - - {% endfor %} - - -
{% trans "Boat" %}{% trans "Date" %}{% trans "Departure time" %}{% trans "Return time" %}{% trans "Reserved by" %}{% trans "Delete" %}
{{ outing.boat.boatname }} {{ outing.starttime |date:'d/m/y ' }}   {{ outing.starttime |time:'H:i ' }}   {{ outing.endtime |time:'H:i '}}   {{ outing.rower.user.first_name }} {{ outing.rower.user.last_name }} D  -
- -
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrno_setlanguage.html~ b/cvkbrno/templates/cvkbrno_setlanguage.html~ deleted file mode 100644 index cdbc5781..00000000 --- a/cvkbrno/templates/cvkbrno_setlanguage.html~ +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "cvkbrnobase.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Jdu na vodu {% endblock %} - -{% block content %} -{% load i18n %} - -
{% csrf_token %} - - - -
-{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templates/cvkbrnobase.html~ b/cvkbrno/templates/cvkbrnobase.html~ deleted file mode 100644 index 7e27da4d..00000000 --- a/cvkbrno/templates/cvkbrnobase.html~ +++ /dev/null @@ -1,193 +0,0 @@ - - - - {% load i18n %} - {% load tz %} - {% get_current_language as LANGUAGE_CODE %} - {% language LANGUAGE_CODE %} - {% get_available_languages as LANGUAGES %} - {% get_current_language_bidi as LANGUAGE_BIDI %} - - - - - CVK Brno - - - - - - - {% block meta %} {% endblock %} - - -
- -
-
-

{% trans "Welcome," %} {{ user.first_name }}

-
-
- - CZ flag - -
-
- - EN flag - -
-
- - NL flag - -
-
- {% if user.is_authenticated %} -

- {% trans "Password Change" %}

- {% else %} -

{% trans "Forgotten Password?" %}

- {% endif %} -
-
- -
-
-

{% trans "Worked hours" %}: {{ worked_hours }} -

-
-
- {% if user.is_authenticated %} -

- - {% trans "Meterboard" %} - -

- {% else %} -

 

- {% endif %} -
-
- {% if thisclub_admin %} -

- - {% trans "Members Work" %} -

- {% else %} -

 

- {% endif %} -
-
- - -
-
- {% if user.is_authenticated %} -

- - {% trans "Go Rowing" %} -

- {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

- - {% trans "Reservations" %} -

- {% else %} -

 

- {% endif %} -
-
- {% if thisclub_admin %} -

- {% trans "Boats" %}

- {% else %} -

 

- {% endif %} -
-
- {% if thisclub_admin %} -

- {% trans "Members" %}

- {% else %} -

 

- {% endif %} -
-
- {% if thisclub_admin %} -

- {% trans "Transport" %}

- {% else %} -

 

- {% endif %} -
-
- {% if thisclub_admin %} -

- {% trans "Categories" %}

- {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

{% trans "logout" %}

- - {% else %} -

 

- {% endif %} - -
-
- - -
-
- {% block message %} - {% if message %} -

- {{ message }} -

- {% endif %} - {% if successmessage %} -

- {{ successmessage }} -

- {% endif %} - {% endblock %} -
-
- {% timezone "Europe/Paris" %} - {% block content %}{% endblock %} - {% endtimezone %} -
-
- -
- {% block footer %} - -
- -
-
- -
-
- -
- {% endblock %} -
-
- - -{% endlanguage %} - \ No newline at end of file diff --git a/cvkbrno/templates/registration/login.html~ b/cvkbrno/templates/registration/login.html~ deleted file mode 100644 index 23230990..00000000 --- a/cvkbrno/templates/registration/login.html~ +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "cvkbrnobase.html" %} - -{% block content %} - -{% if form.errors %} -

Your username and password didn't match. Please try again.

-{% endif %} - -
-{% csrf_token %} - - - - - - - - - -
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
- - - -{% if next %} - -{% else %} - -{% endif %} - - -
- -

Lodě na vodě

- - - - - - - - - - {% for outing in activeoutings %} - - - - - {% endfor %} - - -
BoatDeparture time
{{ outing.boat.boatname }} {{ outing.starttime }}
- -{% endblock %} \ No newline at end of file diff --git a/cvkbrno/templatetags/__init__.pyc b/cvkbrno/templatetags/__init__.pyc deleted file mode 100644 index dab59a3b..00000000 Binary files a/cvkbrno/templatetags/__init__.pyc and /dev/null differ diff --git a/cvkbrno/templatetags/filter.pyc b/cvkbrno/templatetags/filter.pyc deleted file mode 100644 index 0dd10c1f..00000000 Binary files a/cvkbrno/templatetags/filter.pyc and /dev/null differ diff --git a/cvkbrno/templatetags/filter.py~ b/cvkbrno/templatetags/filter.py~ deleted file mode 100644 index dcf7af73..00000000 --- a/cvkbrno/templatetags/filter.py~ +++ /dev/null @@ -1,7 +0,0 @@ -from django import template - -register = template.Library() - -@register.filter -def filteriternum(d): - return d+1 diff --git a/cvkbrno/tests.pyc b/cvkbrno/tests.pyc deleted file mode 100644 index 6bd68300..00000000 Binary files a/cvkbrno/tests.pyc and /dev/null differ diff --git a/cvkbrno/tests.py~ b/cvkbrno/tests.py~ deleted file mode 100644 index 7ce503c2..00000000 --- a/cvkbrno/tests.py~ +++ /dev/null @@ -1,3 +0,0 @@ -from django.test import TestCase - -# Create your tests here. diff --git a/cvkbrno/urls.pyc b/cvkbrno/urls.pyc deleted file mode 100644 index f5b35e28..00000000 Binary files a/cvkbrno/urls.pyc and /dev/null differ diff --git a/cvkbrno/urls.py~ b/cvkbrno/urls.py~ deleted file mode 100644 index e8841230..00000000 --- a/cvkbrno/urls.py~ +++ /dev/null @@ -1,96 +0,0 @@ -from django.conf import settings -from django.conf.urls import url - -from . import views -from django.contrib.auth import views as auth_views - -from forms import BoatEditForm - - - -urlpatterns = [ -# url(r'^login$',auth_views.login, -# {'template_name':'registration/cvkbrno_login.html', -# 'extra_context':{ -# 'activeoutings':views.get_active_outings(), -# 'reservations':views.get_future_reservations(), -# }, -# }), - url(r'^login/$',views.login_user_view), - url(r'^logout/$',views.logout_then_login), - url(r'^meterboard/$',views.meterboard_view), - url(r'^meterboard$',views.meterboard_view), - url(r'^memberswork/c/(?P\w+.*)/s/(?P\w+.*)$',views.members_work_admin_view), - url(r'^memberswork/s/(?P\w+.*)$',views.members_work_admin_view), - url(r'^memberswork/c/(?P\w+.*)$',views.members_work_admin_view), - url(r'^memberswork/add$',views.members_work_add_view), - url(r'^memberswork/(?P\d+)/addme$',views.members_work_addme), - url(r'^memberswork/(?P\d+)/removeme$',views.members_work_removeme), - url(r'^memberswork/$',views.members_work_admin_view), - url(r'^memberswork/(?P\d+)/edit/c/(?P\w+.*)/s/(?P\w+.*)$',views.members_work_edit_view), - url(r'^memberswork/(?P\d+)/edit/s/(?P\w+.*)$',views.members_work_edit_view), - url(r'^memberswork/(?P\d+)/edit$',views.members_work_edit_view), - url(r'^memberswork/(?P\d+)/edit/c/(?P\w+.*)$',views.members_work_edit_view), - url(r'^memberswork/add$',views.members_work_add_view), - url(r'^memberswork/(?P\d+)/delete$',views.members_work_delete_view), - url(r'^memberswork/$',views.members_work_admin_view), - url(r'^memberswork/(?P\d+)/complete$',views.members_work_complete_view), - url(r'^createouting/c/(?P\w+.*)/s/(?P\w+.*)$',views.createouting_view), - url(r'^createouting/c/(?P\w+.*)$',views.createouting_view), - url(r'^createouting$',views.createouting_view), - url(r'^closeouting/c/(?P\w+.*)$',views.closeouting_view), - url(r'^closeouting$',views.closeouting_view), - url(r'^makereservation/c/(?P\w+.*)/s/(?P\w+.*)$',views.makereservation_view), - url(r'^makereservation/c/(?P\w+.*)$',views.makereservation_view), - url(r'^makereservation$',views.makereservation_view), - url(r'^transport/c/(?P\w+.*)/s/(?P\w+.*)$',views.transport_view), - url(r'^transport/c/(?P\w+.*)$',views.transport_view), - url(r'^transport/s/(?P\w+.*)$',views.transport_view), - url(r'^transport$',views.transport_view), - url(r'^transport/add$',views.transport_add_view), - url(r'^transport/(?P\d+)/delete$',views.races_admin_delete_view), -# url(r'^c/(?P\w+.*)/s/(?P\w+.*)$',views.base_view), -# url(r'^c/(?P\w+.*)$',views.base_view), -# url(r'^s/(?P\w+.*)$',views.base_view), - url(r'^$',views.base_view), - url(r'^outing/(?P\d+)$',views.outing_admin_view), - url(r'^boats/c/(?P\w+.*)/s/(?P\w+.*)$',views.boats_admin_view), - url(r'^boats/(?P\d+)/edit/c/(?P\w+.*)/s/(?P\w+.*)$',views.boats_admin_edit_view), - url(r'^boats/(?P\d+)/edit/c/(?P\w+.*)$',views.boats_admin_edit_view), - url(r'^boats/(?P\d+)/edit$',views.boats_admin_edit_view), - url(r'^boats/c/(?P\w+.*)$',views.boats_admin_view), - url(r'^boats/s/(?P\w+.*)$',views.boats_admin_view), - url(r'^boats$',views.boats_admin_view), - url(r'^boats/(\d+)/deleteconfirm$',views.boats_admin_delete_confirm_view), - url(r'^boats/(\d+)/delete$',views.boats_admin_delete_view), - url(r'^boats/add/c/(?P\w+.*)$',views.boats_admin_add_view), - url(r'^boats/add$',views.boats_admin_add_view), - url(r'^categories/c/(?P\w+.*)/s/(?P\w+.*)$',views.categories_admin_view), - url(r'^categories/(?P\d+)/edit/c/(?P\w+.*)/s/(?P\w+.*)$',views.categories_admin_edit_view), - url(r'^categories/(?P\d+)/edit/c/(?P\w+.*)$',views.categories_admin_edit_view), - url(r'^categories/(?P\d+)/edit$',views.categories_admin_edit_view), - url(r'^categories/c/(?P\w+.*)$',views.categories_admin_view), - url(r'^categories/s/(?P\w+.*)$',views.categories_admin_view), - url(r'^categories$',views.categories_admin_view), - url(r'^categories/(\d+)/deleteconfirm$',views.categories_admin_delete_confirm_view), - url(r'^categories/(\d+)/delete$',views.categories_admin_delete_view), - url(r'^categories/add/c/(?P\w+.*)$',views.categories_admin_add_view), - url(r'^categories/add$',views.categories_admin_add_view), - - url(r'^members/c/(?P\w+.*)/s/(?P\w+.*)$',views.members_admin_view), - url(r'^members/(?P\d+)/edit/c/(?P\w+.*)/s/(?P\w+.*)$',views.members_admin_edit_view), - url(r'^members/(?P\d+)/edit/c/(?P\w+.*)$',views.members_admin_edit_view), - url(r'^members/(?P\d+)/edit$',views.members_admin_edit_view), - url(r'^members/c/(?P\w+.*)$',views.members_admin_view), - url(r'^members/s/(?P\w+.*)$',views.members_admin_view), - url(r'^members$',views.members_admin_view), - url(r'^members/(\d+)/deleteconfirm$',views.members_admin_delete_confirm_view), - url(r'^members/(\d+)/delete$',views.members_admin_delete_view), - url(r'^members/add/c/(?P\w+.*)$',views.members_admin_add_view), - url(r'^members/add$',views.members_admin_add_view), - url(r'^outing/(\d+)/delete$',views.members_outing_delete_view), - url(r'^language/(?P[A-z]{2})/$',views.change_language_view), - url(r'^language/(?P[A-z]{2}\-[A-z]{2})/$',views.change_language_view), -# url(r'^i18n/', include('django.conf.urls.i18n')), -] - diff --git a/cvkbrno/views.pyc b/cvkbrno/views.pyc deleted file mode 100644 index be4e03a7..00000000 Binary files a/cvkbrno/views.pyc and /dev/null differ diff --git a/cvkbrno/views.py~ b/cvkbrno/views.py~ deleted file mode 100644 index 8caeeca8..00000000 --- a/cvkbrno/views.py~ +++ /dev/null @@ -1,1763 +0,0 @@ -# -*- coding: utf-8 -*- - -from django.shortcuts import render,render_to_response,redirect -from django.template import RequestContext -from django.template.response import TemplateResponse -from django.http import HttpResponse, HttpResponseRedirect -from django.contrib.auth import logout,login,authenticate -from django.contrib.auth.models import User -from django.contrib.auth import views as auth_views -from django.contrib.auth.decorators import login_required,user_passes_test -from models import Boat,BoatCategory,Member,Outing,Races,MemberWork -from forms import OutingForm,OutingCloseForm,OutingReserveForm,MemberEditForm -from forms import UserEditForm,UserCreateForm,PassWordConfirmForm -from forms import BoatEditForm,BoatCategoryEditForm,RacesEditForm -from forms import MemberWorkCreateForm -import datetime -from django.utils import timezone,translation -from django.utils.translation import ugettext_lazy as _ -from django.core.urlresolvers import reverse,reverse_lazy -from dateutil import parser -from pytz import timezone as tz,utc -from django.conf import settings - -from django.utils.encoding import smart_text -from cvkbrno.tasks import handle_sendemailwork - -import json -import pandas as pd - -from requests.utils import quote -from django.utils.translation import ugettext as _ -from django.core.exceptions import ObjectDoesNotExist - -import unidecode - -import django_rq -queue = django_rq.get_queue('default') -queuelow = django_rq.get_queue('low') -queuehigh = django_rq.get_queue('low') - -# settings -THISCLUB = "cvkbrno" -LOCALTIMEZONE = tz('Europe/Prague') -TEMPLATEPREFIX = THISCLUB+'_' -USER_LANGUAGE = 'cs' -translation.activate(USER_LANGUAGE) -BLOCKHOURS = 1.5 -RACEBLOCKHOURS = 2 -RESERVATIONEXPIRYMINUTES = 15 -OUTINGDURATIONHOURS = 1.5 - -# Create your views here. - -def distancecount(u): - member = Member.objects.get(user=u) - cumdistance = 0 - monthdistance = 0 - yeardistance = 0 - weekdistance = 0 - today = timezone.now().date() - weeknr = today.isocalendar()[1] - thisyear = today.year - thismonth = today.month - # sum km own rows - theoutings = Outing.objects.filter(rower=member).filter(status="completed") - for o in theoutings: - cumdistance += o.distance - oyear = o.starttime.year - oweek = o.starttime.date().isocalendar()[1] - omonth = o.starttime.month - if thisyear == oyear: - yeardistance += o.distance - if thismonth == omonth: - monthdistance += o.distance - if weeknr == oweek: - weekdistance += o.distance - - theoutings = Outing.objects.filter(otherrowers=member).filter(status="completed") - for o in theoutings: - cumdistance += o.distance - oyear = o.starttime.year - oweek = o.starttime.date().isocalendar()[1] - omonth = o.starttime.month - if thisyear == oyear: - yeardistance += o.distance - if thismonth == omonth: - monthdistance += o.distance - if weeknr == oweek: - weekdistance += o.distance - - return [cumdistance,yeardistance,monthdistance,weekdistance] - -def distancecountb(boat): - cumdistance = 0 - monthdistance = 0 - yeardistance = 0 - weekdistance = 0 - today = timezone.now().date() - weeknr = today.isocalendar()[1] - thisyear = today.year - thismonth = today.month - # sum km own rows - theoutings = Outing.objects.filter(boat=boat).filter(status="completed") - for o in theoutings: - cumdistance += o.distance - oyear = o.starttime.year - oweek = o.starttime.date().isocalendar()[1] - omonth = o.starttime.month - if thisyear == oyear: - yeardistance += o.distance - if thismonth == omonth: - monthdistance += o.distance - if weeknr == oweek: - weekdistance += o.distance - - return [cumdistance,yeardistance,monthdistance,weekdistance] - -def getclubmembers(): - members = Member.objects.all().filter(contributions=True).filter(club=THISCLUB) - return members - -def getmembers_json(u): - members = Member.objects.all().filter(contributions=True).filter(club=THISCLUB).exclude(user=u).order_by('user__last_name') - dd = {} - for m in members: - dd[m.user.id] = m.user.first_name+' '+m.user.last_name - - return json.dumps(dd) - -def thisclub_member(user): - member = Member.objects.get(user=user) - result = user.is_authenticated() and member.club==THISCLUB and member.contributions - return result - -def thisclub_admin(user): - if user.is_authenticated(): - member = Member.objects.get(user=user) - result = user.is_authenticated() and member.club==THISCLUB and \ - (member.status in ["administrator","coach"]) - else: - result = False - - return result - -def conflicting_reservations(boat,starttime,endtime): - thisboatoutings = Outing.objects.filter(boat=boat).exclude(status="completed") - - check = False - message = "" - # starttime = LOCALTIMEZONE.localize(starttime) - - for outing in thisboatoutings: - if (outing.status == "active"): - if outing.starttime+datetime.timedelta(hours=OUTINGDURATIONHOURS)>starttime: - check = True - message = _("Boat is on the water at that time") - if (outing.status == "race"): - # if boat goes on transport in two hours from reservation time - if (outing.starttime < starttime+datetime.timedelta(hours=RACEBLOCKHOURS)): - check = True - message = _("Boat is planned to go on transport at that time") - # if boat is out racing during reservation time - if (outing.endtime > starttime): - check = True - message = _("Boat is at races at that time") - # if boat is already back frmo racing during reservation time - if (outing.endtime <= starttime): - check = False - message = "" - if (outing.status == "reservation"): - # check if our reservation end time is before - # or our reservation start time is - # after this reservation - - if (outing.starttime < endtime and outing.endtime > starttime): - check = True - message = _("Conflicting reservations") - - if (outing.endtime > starttime) and (outing.starttime < starttime): - check = True - message = _("Conflicting reservations") - if (outing.status == "race"): - # check if our reservation end time is before - # or our reservation start time is - # after this reservation - - if (outing.starttime-datetime.timedelta(RACEBLOCKHOURS) < endtime and outing.endtime > starttime): - check = True - message = _("Boat will go to races at that time") - - if (outing.endtime > starttime) and (outing.starttime-datetime.timedelta(RACEBLOCKHOURS) < starttime): - check = True - message = _("Boat is at races at that time") - - return check,message - -def cleanoldreservations(): - reservations = Outing.objects.filter(status="reservation") - now = timezone.now() - for reservation in reservations: - dt = reservation.starttime - if dt < now-datetime.timedelta(minutes=RESERVATIONEXPIRYMINUTES): - reservation.delete() - # code to change boats that go on transport and remove boats that have returned from transport - races = Outing.objects.filter(status="race") - for race in races: - if now > race.starttime-datetime.timedelta(hours=RACEBLOCKHOURS): - race.boat.status="races" - race.boat.save() - if now > race.endtime: - race.boat.status="hangar" - race.boat.save() - -def get_damagedboats(): - damagedboats = Boat.objects.filter(status="damaged") - return list(set(damagedboats)) - -def get_availableboats(m,t): - hangarboats = Boat.objects.filter(status="hangar") - cleanoldreservations() - allowedboats = [] - reservations = Outing.objects.filter(status="reservation") - starttime = timezone.now() - - # add boats from allowed categories - for category in m.categories.all(): - thiscategoryboats = hangarboats.filter(categories=category) - for theboat in thiscategoryboats: - thisboatreservations = Outing.objects.filter(status="reservation",boat=theboat) - addboat = True - # the below should go to a subroutine - # do not allow to add boats that go on transport or are reserved - # in the near future - for res in thisboatreservations: - if (res.starttime < starttime+datetime.timedelta(hours=OUTINGDURATIONHOURS)): - addboat = False - if res.rower == m: - addboat = True - if (res.endtime): - if (res.endtime > starttime): - addboat = False - if res.rower == m: - addboat=True - thisboatrace = Outing.objects.filter(status="race",boat=theboat) - for race in thisboatrace: - if (race.starttime < starttime+datetime.timedelta(hours=RACEBLOCKHOURS)) and (race.endtime > starttime): - addboat = False - race.boat.status="races" - race.boat.save() - if (race.endtime < starttime): - addboat = True - race.boat.status="hangar" - race.boat.save() - - if addboat: - allowedboats += [theboat] - - - - return list(set(allowedboats)) - -def get_availableboats_reservation(m,t): - hangarboats = Boat.objects.filter(status__in = ["hangar","water","reservation","races"]) - allowedboats = [] - cleanoldreservations() - reservations = Outing.objects.filter(status="reservation") - # code to remove reservations from list of hangar boats - # & clear reservations that are >15 min beyond start time - - # code to remove boats that go on transport within two hours - - - # add boats from available categories - for category in m.categories.all(): - allowedboats += hangarboats.filter(categories=category) - - return list(set(allowedboats)) - - -def get_active_outings(): - activeoutings = Outing.objects.filter(status="active") - - return activeoutings - -def get_future_reservations(): - cleanoldreservations() - reservations = Outing.objects.filter(status="reservation").order_by("starttime") - return reservations - -def get_future_races(): - cleanoldreservations() - races = Races.objects.filter(startdatetime__gt=timezone.now()).order_by("startdatetime") - return races - -def login_user_view(request,activeoutings=get_active_outings(),reservations=get_future_reservations()): - logout(request) - request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE - username = password = '' - if request.POST: - username = request.POST['username'] - password = request.POST['password'] - - user = authenticate(username=username, password=password) - if user is not None: - if user.is_active: - login(request, user) - url = reverse(base_view) - return HttpResponseRedirect(url) - return render(request,'cvkbrno_login.html', - {'activeoutings':get_active_outings(), - 'reservations':get_future_reservations()}) - -def change_language_view(request,languagecode): - USER_LANGUAGE = languagecode - translation.activate(USER_LANGUAGE) - request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE - url = request.META.get('HTTP_REFERER','/') - return HttpResponseRedirect(url) - -@login_required(login_url='/cvkbrno/login/') -def base_view(request): - cleanoldreservations() - request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE - # Switcher between different views depending on user's status - member = Member.objects.get(user=request.user) - activeoutings = Outing.objects.filter(status="active",rower=member) - if (len(activeoutings)!=0): - # we are still out - url = reverse(closeouting_view) - return HttpResponseRedirect(url) - else: - url = reverse(createouting_view) - return HttpResponseRedirect(url) - - - -def logout_then_login(request): - logout(request) - extra_context = {'activeoutings':get_active_outings()} - context = RequestContext(request) - context.update(extra_context) - activeoutings = get_active_outings() - url = reverse(base_view) - return HttpResponseRedirect(url) - - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def boats_admin_view(request,message="",successmessage=""): - cleanoldreservations() - theboats = Boat.objects.all().order_by("boatcode") - theoutings = Outing.objects.exclude(status="reservation").exclude(status="race").order_by("-starttime")[0:20] - return render(request, - TEMPLATEPREFIX+'boats_admin.html', - {'theboats':theboats, - 'theoutings':theoutings, - 'message':message, - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def categories_admin_view(request,message="",successmessage=""): - cleanoldreservations() - thecats = BoatCategory.objects.all().order_by("name") - return render(request, - TEMPLATEPREFIX+'categories_admin.html', - {'thecats':thecats, - 'message':message, - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_admin_view(request,message="",successmessage=""): - cleanoldreservations() - themembers = Member.objects.filter(club=THISCLUB).order_by('user') - - - return render(request, - TEMPLATEPREFIX+'members_admin.html', - {'themembers':themembers, - 'message':message, - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_work_admin_view(request,message="",successmessage=""): - cleanoldreservations() - theworks = MemberWork.objects.filter(status='planned') - return render(request, - TEMPLATEPREFIX+'memberswork_admin.html', - {'theworks':theworks, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_work_add_view(request,message="",successmessage=""): - cleanoldreservations() - if request.method == 'POST': - # Form was submitted - form = MemberWorkCreateForm(request.POST) - - if form.is_valid(): - # do something - res = addmemberwork(request.POST) - func = res[0] - message = res[1] - successmessage = res[2] - theid = res[3] - kwargs = {} - if successmessage != "": - kwargs['successmessage'] = successmessage.encode('utf8') - if message != "": - kwargs['message'] = message.encode('utf8') - - theworks = MemberWork.objects.filter(status='planned') -# args['theworks'] = theworks - - url = reverse(func,kwargs = kwargs) - - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'memberswork_add_form.html', - {'form':form, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user), - } - ) - - else: - form = MemberWorkCreateForm() - if (message != ""): - return render(request, - TEMPLATEPREFIX+'memberswork_add_form.html', - {'form':form, - 'message':message, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'memberswork_add_form.html', - {'form':form, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def boats_admin_delete_confirm_view(request,id): - theboat = Boat.objects.get(id=id) - return render(request, - TEMPLATEPREFIX+'boat_delete_confirm.html', - {'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def outing_admin_view(request,id): - theouting = Outing.objects.get(id=id) - return render(request, - TEMPLATEPREFIX+'outing_admin.html', - {'outing':theouting, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def categories_admin_delete_confirm_view(request,id): - thecategory = BoatCategory.objects.get(id=id) - return render(request, - TEMPLATEPREFIX+'categories_delete_confirm.html', - {'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_admin_delete_confirm_view(request,id): - themember = Member.objects.get(id=id) - return render(request, - TEMPLATEPREFIX+'members_delete_confirm.html', - {'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def boats_admin_delete_view(request,id): - try: - theboat = Boat.objects.get(id=id) - theboat.delete() - except: - pass - - url = reverse(boats_admin_view,kwargs={ - 'successmessage': _("boat deleted").encode('utf8'), - }) - - return HttpResponseRedirect(url) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_admin_delete_view(request,id): - try: - themember = Member.objects.get(id=id) - themember.user.delete() - themember.delete() - except: - pass - - url = reverse(members_admin_view,kwargs={ - 'successmessage': _("member deleted").encode('utf8'), - }) - - return HttpResponseRedirect(url) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def categories_admin_delete_view(request,id): - try: - thecategory = BoatCategory.objects.get(id=id) - thecategory.delete() - except: - pass - - url = reverse(categories_admin_view,kwargs={ - 'successmessage': _("category deleted").encode('utf8'), - }) - - return HttpResponseRedirect(url) - - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def boats_admin_add_view(request,message="",successmessage=""): - if request.method == 'POST': - # Form was submitted - form = BoatEditForm(request.POST) - - if form.is_valid(): - # do something - res = addboat(request.POST) - func = res[0] - message = res[1] - successmessage = res[2] - theid = res[3] - kwargs = {} - if successmessage != "": - kwargs['successmessage'] = successmessage.encode('utf8') - if message != "": - kwargs['message'] = message.encode('utf8') - if theid != 0: - kwargs['id'] = int(theid) - url = reverse(func,kwargs = kwargs) - - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'boat_add_form.html', - {'form':form, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user), - } - ) - - else: - form = BoatEditForm() - if (message != ""): - return render(request, - TEMPLATEPREFIX+'boat_add_form.html', - {'form':form, - 'message':message, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'boat_add_form.html', - {'form':form, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_admin_add_view(request,message="",successmessage=""): - if request.method == 'POST': - # Form was submitted - form = MemberEditForm(request.POST) - - if form.is_valid(): - # do something - res = addmember(request.POST) - func = res[0] - message = res[1] - successmessage = res[2] - theid = res[3] - kwargs = {} - if successmessage != "": - kwargs['successmessage'] = successmessage - if message != "": - kwargs['message'] = message - if theid != 0: - kwargs['id'] = int(theid) - url = reverse(func,kwargs = kwargs) - - return HttpResponseRedirect(url) - else: - memberform = form - userform = UserCreateForm() - passwordconfirmform = PassWordConfirmForm() - return render(request, - TEMPLATEPREFIX+'member_add_form.html', - {'form1':memberform, - 'form2':userform, - 'form3':passwordconfirmform, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - else: - memberform = MemberEditForm() - userform = UserCreateForm() - passwordconfirmform = PassWordConfirmForm() - if (message != ""): - return render(request, - TEMPLATEPREFIX+'member_add_form.html', - {'form1':memberform, - 'form2':userform, - 'form3':passwordconfirmform, - 'message':message, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'member_add_form.html', - {'form1':memberform, - 'form2':userform, - 'form3':passwordconfirmform, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def categories_admin_add_view(request,message="",successmessage=""): - if request.method == 'POST': - # Form was submitted - form = BoatCategoryEditForm(request.POST) - - if form.is_valid(): - # do something - message = "" - successmessage = "" - name = request.POST['name'] - thecategory = BoatCategory(name=name) - thecategory.save() - kwargs = {} - if message != "": - kwargs['message'] = message - if successmessage != '': - kwargs['successmessage'] = successmessage - - url = reverse(categories_admin_view,kwargs=kwargs) - - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'category_add_form.html', - {'form':form, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - else: - form = BoatCategoryEditForm() - if (message != ""): - return render(request, - TEMPLATEPREFIX+'category_add_form.html', - {'form':form, - 'message':message, - 'successmessage':successmessage, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'category_add_form.html', - {'form':form, - 'successmessage':successmessage, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def boats_admin_edit_view(request,id,message="",successmessage=""): - theboat = Boat.objects.get(id=id) - if request.method == 'POST': - # Form was submitted - form = BoatEditForm(request.POST) - - if form.is_valid(): - res = editboat(request.POST,theboat) - func = res[0] - message = res[1] - successmessage = res[2] - theid = res[3] - kwargs = {} - if successmessage != "": - kwargs['successmessage'] = successmessage - if message != "": - kwargs['message'] = message - if theid != 0: - kwargs['id'] = int(theid) - url = reverse(func,kwargs = kwargs) - - return HttpResponseRedirect(url) - else: - theoutings = Outing.objects.exclude(status="reservation").filter(boat=theboat).order_by("-starttime")[0:20] - return render(request, - TEMPLATEPREFIX+'boat_edit_form.html', - {'form':form, - 'theoutings':theoutings, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - else: - form = BoatEditForm(instance=theboat) - theoutings = Outing.objects.exclude(status="reservation").filter(boat=theboat).order_by("-starttime")[0:20] - if (message != ""): - return render(request, - TEMPLATEPREFIX+'boat_edit_form.html', - {'form':form, - 'message':message, - 'theoutings':theoutings, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'boat_edit_form.html', - {'form':form, - 'theoutings':theoutings, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_work_edit_view(request,id,message="",successmessage=""): - thework = MemberWork.objects.get(id=id) - if request.method == 'POST': - # Form was submitted - form = MemberWorkCreateForm(request.POST) - - if form.is_valid(): - res = editmemberwork(request.POST,thework) - func = res[0] - message = res[1] - successmessage = res[2] - theid = res[3] - kwargs = {} - if successmessage != "": - kwargs['successmessage'] = successmessage - if message != "": - kwargs['message'] = message - if theid != 0: - kwargs['id'] = int(theid) - url = reverse(func,kwargs = kwargs) - - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'memberwork_edit_form.html', - {'form':form, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - else: - form = MemberWorkCreateForm(instance=thework) - if (message != ""): - return render(request, - TEMPLATEPREFIX+'memberwork_edit_form.html', - {'form':form, - 'message':message, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'memberwork_edit_form.html', - {'form':form, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_admin_edit_view(request,id,message="",successmessage=""): - themember = Member.objects.get(id=id) - if request.method == 'POST': - # Form was submitted - form = MemberEditForm(request.POST) - - if form.is_valid(): - res = editmember(request.POST,themember) - func = res[0] - message = res[1] - successmessage = res[2] - theid = res[3] - kwargs = {} - if successmessage != "": - kwargs['successmessage'] = successmessage - if message != "": - kwargs['message'] = message - if theid != 0: - kwargs['id'] = int(theid) - url = reverse(func,kwargs = kwargs) - - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'member_edit_form.html', - {'form1':memberform, - 'form2':userform, - 'id':id, - 'username': themember.user.username, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - - else: - memberform = MemberEditForm(instance=themember) - userform = UserEditForm(instance=themember.user) - if (message != ""): - return render(request, - TEMPLATEPREFIX+'member_edit_form.html', - {'form1':memberform, - 'form2':userform, - 'username': themember.user.username, - 'message':message, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'member_edit_form.html', - {'form1':memberform, - 'form2':userform, - 'username': themember.user.username, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def categories_admin_edit_view(request,id,message="",successmessage=""): - thecategory = BoatCategory.objects.get(id=id) - if request.method == 'POST': - # Form was submitted - form = BoatCategoryEditForm(request.POST) - - if form.is_valid(): - # do something - message = "" - successmessage = "" - name = request.POST['name'] - thecategory.name = name - thecategory.save() - - - if (message != ""): - url = reverse(categories_admin_view, - kwargs = { - 'successmessage': _('Changes saved'), - 'message': message - }) - else: - url = reverse(categories_admin_view, - kwargs = { - 'successmessage': _('Changes saved'), - }) - - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'categories_edit_form.html', - {'form':form, - 'successmessage':successmessage, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - form = BoatCategoryEditForm(instance=thecategory) - if (message != ""): - return render(request, - TEMPLATEPREFIX+'categories_edit_form.html', - {'form':form, - 'message':message, - 'successmessage':successmessage, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - else: - - return render(request, - TEMPLATEPREFIX+'categories_edit_form.html', - {'form':form, - 'successmessage':successmessage, - 'id':id, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,} - ) - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def meterboard_view(request,message="",successmessage="",sortby="year"): - try: - sortby = request.GET['sortby'] - except KeyError: - pass - now = timezone.now() - members = getclubmembers() - boats = Boat.objects.all() - df = pd.DataFrame() - dfb = pd.DataFrame() - theoutings = Outing.objects.exclude(status="reservation").exclude(status="race").order_by("-starttime")[0:20] - - for member in members: - cumdist,yeardist,monthdist,weekdist = distancecount(member.user) - df2 = pd.DataFrame( - { - 'Cumulative Distance':[cumdist], - 'This Year':[yeardist], - 'This Month':[monthdist], - 'This Week':[weekdist], - }, - index = [member] - ) - df = df.append(df2) - - for boat in boats: - cumdist,yeardist,monthdist,weekdist = distancecountb(boat) - df3 = pd.DataFrame( - { - 'Cumulative':[cumdist], - 'This Year':[yeardist], - 'This Month':[monthdist], - 'This Week':[weekdist], - }, - index = [boat] - ) - dfb = dfb.append(df3) - - sortorder = ['This Year', 'This Month', 'This Week'] - if sortby == 'month': - sortorder = ['This Month','This Year','This Week'] - if sortby == 'week': - sortorder = ['This Week','This Year','This Month'] - - data = df.sort_values(by=sortorder,ascending=False).to_html(classes='listtable paddedtable',columns=['This Year','This Month','This Week']) - datab = dfb.sort_values(by=sortorder,ascending=False).to_html(classes='listtable paddedtable',columns=['This Year','This Month','This Week']) - return render(request, - TEMPLATEPREFIX+'meterboard.html', - {'data':data, - 'datab':datab, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def createouting_view(request,message="",successmessage=""): - cleanoldreservations() - today = timezone.now().date() - member = Member.objects.get(user=request.user) - activeoutings = Outing.objects.filter(rower=member,status="active") - theboats = get_availableboats(member,timezone.now()) - plannedwork = MemberWork.objects.filter(status='planned') - - # You are still out - if (len(activeoutings)!=0): - # we are still out - errormessg = _("You still have an active outing. Check in first.").encode('utf8') - url = reverse(closeouting_view, - kwargs = { - 'message':str(errormessg), - }) - - return HttpResponseRedirect(url) - # You have submitted the form - if request.method == 'POST': - # Form was submitted - form = OutingForm(request.POST) - # form is valid - if form.is_valid(): - # Get values from form - dist = request.POST['distance'] - boat = Boat.objects.get(id=request.POST['boat']) - boat.status = "water" - boat.save() - additionalcrew = [] - if boat.nrseats>1: - for i in range(boat.nrseats-1): - snr = i+2 - try: - crewid = int(request.POST['crew'+str(snr)]) - except: - message = _("You must select additional crew members for this boat") - return render(request, - TEMPLATEPREFIX+'outing_form.html', - {'form':form, - 'theboats':theboats, - 'reservations':get_future_reservations(), - 'races':get_future_races(), - 'damagedboats':get_damagedboats(), - 'plannedwork':plannedwork, - 'member':member, - 'message':message, - 'jsonmembers':getmembers_json(request.user), - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - additionalcrew.append(Member.objects.get(user__id=crewid)) - # remove duplicates - additionalcrew = list(set(additionalcrew)) - - - starttime = timezone.now() - myreservations = Outing.objects.filter(status="reservation", - rower=member, - starttime__year=today.year, - starttime__month=today.month, - starttime__day=today.day).order_by("starttime") - - # form is valid and you have some reservation (for today) - if len(myreservations) != 0: - nextreservation=myreservations.first() - # you are taking the boat that you reserved - - if (nextreservation.boat == boat): - nextreservation.starttime = starttime - nextreservation.status = "active" - nextreservation.distance = dist - nextreservation.save() - for member in additionalcrew: - nextreservation.otherrowers.add(member) - nextreservation.save() - # you are taking another boat - else: - o = Outing(starttime=starttime,rower=member, - boat=boat,distance=dist, - status="active") - o.save() - for member in additionalcrew: - o.otherrowers.add(member) - o.save() - # form is valid and you have no reservations - else: - o = Outing(starttime=starttime,rower=member,boat=boat, - distance=dist, - status="active") - o.save() - for member in additionalcrew: - o.otherrowers.add(member) - o.save() - if not settings.DEBUG: - logout(request) - url = reverse(base_view) - return HttpResponseRedirect(url) - # You have not submitted a form with errors - else: - return render(request, - TEMPLATEPREFIX+'outing_form.html', - {'form':form, - 'theboats':theboats, - 'reservations':get_future_reservations(), - 'races':get_future_races(), - 'member':member, - 'damagedboats':get_damagedboats(), - 'plannedwork':plannedwork, - 'message':message, - 'jsonmembers':getmembers_json(request.user), - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - # You have not submitted the form - else: - form = OutingForm( - initial={'distance':12, - } - ) - today = timezone.now().date() - myreservations = Outing.objects.filter(status="reservation", - rower=member, - starttime__year=today.year, - starttime__month=today.month, - starttime__day=today.day).order_by("starttime") - - - form = OutingForm( - initial={ - 'distance':12, - }) - return render(request, - TEMPLATEPREFIX+'outing_form.html', - {'form':form, - 'theboats':theboats, - 'reservations':get_future_reservations(), - 'member':member, - 'races':get_future_races(), - 'damagedboats':get_damagedboats(), - 'plannedwork':plannedwork, - 'message':message, - 'successmessage':successmessage, - 'jsonmembers':getmembers_json(request.user), - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def closeouting_view(request,message="",successmessage=""): - cleanoldreservations() - member = Member.objects.get(user=request.user) - activeoutings = Outing.objects.filter(rower=member,status="active") - if (len(activeoutings)==0): - # no active outings - errormessg = _("You have no active outings. Go rowing first.").encode('utf8') - url = reverse(createouting_view, - kwargs = { - 'message':str(errormessg), - }) - - return HttpResponseRedirect(url) - if request.method == 'POST': - # Form was submitted - form = OutingCloseForm(request.POST) - if form.is_valid(): - # Get values from form - dist = request.POST['distance'] - comment = request.POST['comment'] - endtime = timezone.now() - damagecheck = request.POST['damagecheck'] - o = Outing.objects.get(rower=member,status="active") - if (damagecheck == "No"): - o.boat.status = _("damaged") - o.boat.comment += "\n"+timezone.localtime(timezone.now()).strftime('%Y-%m-%d %H:%M:%S') - o.boat.comment += " "+comment - else: - o.boat.status = "hangar" - o.boat.save() - o.endtime = endtime - o.comment = comment - o.distance = dist - o.status = "completed" - o.save() - if not settings.DEBUG: - logout(request) - url = reverse(base_view) - return HttpResponseRedirect(url) - - else: - outing = Outing.objects.get(rower=member,status="active") - form = OutingCloseForm() - return render(request, - TEMPLATEPREFIX+'outing_closeform.html', - {'form':form, - 'outing':outing, - 'thisclub_admin':thisclub_admin(request.user), - 'message':message, - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -def get_races(datum): - allraces = Races.objects.filter(enddatetime__gt=datum) - return allraces - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def transport_view(request,message="",successmessage=""): - cleanoldreservations() - theraces = get_future_races() - return render(request, - TEMPLATEPREFIX+'races_list.html', - {'races':theraces, - 'thisclub_admin':thisclub_admin(request.user), - 'message':message, - 'successmessage':successmessage, - 'worked_hours':Member.objects.get(user=request.user).hoursworked, - }) - - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def transport_add_view(request,message="",successmessage=""): - cleanoldreservations() - member = Member.objects.get(user=request.user) - theboats = Boat.objects.all().order_by("boatcode") - if request.method=='POST': - #Form was submitted - form = RacesEditForm(request.POST) - if form.is_valid(): - # Get values from form - name = form.cleaned_data['name'] - startdate = form.cleaned_data['startdate'] - starttime = form.cleaned_data['starttime'] - enddate = form.cleaned_data['enddate'] - endtime = form.cleaned_data['endtime'] - transportboats = form.cleaned_data['transportboats'] - - startdatetime = (str(startdate) + ' ' + str(starttime)) - startdatetime = datetime.datetime.strptime(startdatetime, - "%Y-%m-%d %H:%M:%S") - startdatetime = timezone.make_aware(startdatetime, - timezone=LOCALTIMEZONE) - enddatetime = (str(enddate) + ' ' + str(endtime)) - enddatetime = datetime.datetime.strptime(enddatetime, - "%Y-%m-%d %H:%M:%S") - enddatetime = timezone.make_aware(enddatetime, - timezone=LOCALTIMEZONE) - - r = Races(name=name, - startdatetime=startdatetime, - enddatetime=enddatetime) - - r.save() - for b in transportboats: - r.transportboats.add(b) - o = Outing(starttime=startdatetime, - endtime=enddatetime, - distance=0, - comment=name, - boat=b, - rower=member, - status="race") - o.save() - o.race.add(r) - o.save() - - r.save() - successmessage = _("Race has been saved").encode('utf8') - return render(request, - TEMPLATEPREFIX+'races_list.html', - { - 'thisclub_admin':thisclub_admin(request.user), - 'message':message, - 'races':get_future_races(), - 'successmessage':successmessage, - 'worked_hours':Member.objects.get(user=request.user).hoursworked, - }) - else: - return render(request, - TEMPLATEPREFIX+'races_form.html', - {'form':form, - 'theboats':theboats, - 'thisclub_admin':thisclub_admin(request.user), - 'message':message, - 'successmessage':successmessage, - 'worked_hours':Member.objects.get(user=request.user).hoursworked, }) - - else: - form = RacesEditForm() - - return render(request, - TEMPLATEPREFIX+'races_form.html', - {'form':form, - 'theboats':theboats, - 'thisclub_admin':thisclub_admin(request.user), - 'message':message, - 'successmessage':successmessage, - 'worked_hours':Member.objects.get(user=request.user).hoursworked, - }) - - -@user_passes_test(thisclub_admin,login_url="cvkbrno/login") -def races_admin_delete_view(request,id): - # put in a try except block - try: - therace = Races.objects.get(id=id) - theoutings = Outing.objects.filter(race=therace) - - - for outing in theoutings: - outing.delete() - - therace.delete() - except ObjectDoesNotExist: - pass - - successmessage = _("Race deleted") - - url = reverse(transport_view, - kwargs={ - 'successmessage':successmessage, - }) - - return HttpResponseRedirect(url) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_work_complete_view(request,id=0): - thework = MemberWork.objects.get(id=id) - thework.status = "executed" - thework.save() - for member in thework.worker.all(): - member.hoursworked+=thework.hours - member.save() - - theworks = MemberWork.objects.filter(status='planned') - return render(request, - TEMPLATEPREFIX+'memberswork_admin.html', - {'theworks':theworks, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_admin,login_url="/cvkbrno/login") -def members_work_delete_view(request,id=0): - thework = MemberWork.objects.get(id=id) - thework.delete() - - theworks = MemberWork.objects.filter(status='planned') - return render(request, - TEMPLATEPREFIX+'memberswork_admin.html', - {'theworks':theworks, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def members_work_addme(request,id,message="",successmessage=""): - thework = MemberWork.objects.get(id=id) - themember = Member.objects.get(user=request.user) - thework.worker.add(themember) - - url = reverse(base_view) - return HttpResponseRedirect(url) - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def members_work_removeme(request,id,message="",successmessage=""): - thework = MemberWork.objects.get(id=id) - themember = Member.objects.get(user=request.user) - thework.worker.remove(themember) - - url = reverse(base_view) - return HttpResponseRedirect(url) - - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def makereservation_view(request,message="",successmessage=""): - cleanoldreservations() - member = Member.objects.get(user=request.user) - activeoutings = Outing.objects.filter(rower=member,status="active") - theboats = get_availableboats_reservation(member,timezone.now()) - # theboats = Boat.objects.filter(status__in = ["hangar", "water", "races"]) - if (len(activeoutings)!=0): - # we are still out - url = reverse(closeouting_view) - return HttpResponseRedirect(url) - if request.method == 'POST': - # Form was submitted - form = OutingReserveForm(request.POST) - if form.is_valid(): - # Get values from form - dist = request.POST['distance'] - boat = Boat.objects.get(id=request.POST['boat']) - stime = request.POST['starttime'] - sdate = request.POST['startdate'] - etime = request.POST['endtime'] - - starttime = parser.parse(sdate+' '+stime) - #starttime = timezone.make_aware(starttime) - starttime = LOCALTIMEZONE.localize(starttime) - - endtime = parser.parse(sdate+' '+etime) - #endtime = timezone.make_aware(endtime) - endtime = LOCALTIMEZONE.localize(endtime) - - # check if conflicting reservations exist - check,errormessg = conflicting_reservations(boat,starttime,endtime) - - if check: - url = reverse(makereservation_view, - kwargs = { - 'message':errormessg, - }) - - return HttpResponseRedirect(url) - else: - o = Outing(starttime=starttime,endtime=endtime,rower=member, - boat=boat,distance=dist, - status="reservation") - o.save() - # if not settings.DEBUG: - # logout(request) - url = reverse(base_view) - return HttpResponseRedirect(url) - else: - return render(request, - TEMPLATEPREFIX+'reservation_form.html', - {'form':form, - 'theboats':theboats, - 'reservations':get_future_reservations(), - 'message':message, - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - else: - nownaive = timezone.now().replace(tzinfo=None) - nowlocal = timezone.now().astimezone(LOCALTIMEZONE) - - form = OutingReserveForm( - initial={'distance':11, - 'starttime': nowlocal, - 'startdate': nowlocal, - 'endtime': nowlocal+datetime.timedelta(hours=1.5)} - ) - return render(request, - TEMPLATEPREFIX+'reservation_form.html', - {'form':form, - 'theboats':theboats, - 'reservations':get_future_reservations(), - 'message':message, - 'successmessage':successmessage, - 'thisclub_admin':thisclub_admin(request.user), - 'worked_hours':Member.objects.get(user=request.user).hoursworked,}) - - return HttpResponse(_("Make a reservation")) - - - -@user_passes_test(thisclub_member,login_url="/cvkbrno/login") -def members_outing_delete_view(request,id): - o = Outing.objects.get(id=id) - o.delete() - url = reverse(makereservation_view) - return HttpResponseRedirect(url) - -# functions - -def addmemberwork(formdict): - message = "" - successmessage = "" - id = 0 - date = formdict['date'] - name = formdict['name'] - comment = formdict['comment'] - worker = dict(formdict)['worker'] - hours = int(formdict['hours']) - status = 'planned' - thework = MemberWork(date=date, - hours=hours, - name=name,status=status,comment=comment) - thework.save() - if len(worker) != 0: - for index in worker: - theworker = Member.objects.get(id=index) - thework.worker.add(theworker) - thework.save() - - id = thework.id - theview = members_work_admin_view - successmessage = _("Members Work Created") - message = "" - - # send email - members = getclubmembers() - bcclist = [] - for member in members: - bcclist.append(member.user.email) - - print bcclist - - if settings.DEBUG: - res = handle_sendemailwork.delay(bcclist,thework.name, - thework.date,thework.comment) - - else: - res = queue.enqueue(handle_sendemailwork,bcclist, - thework.name,thework.date,thework.comment) - - - return [theview,message,successmessage,id] - -def addbulkboat(xlsfile): - df = pd.read_excel(xlsfile) - for index,row in df.iterrows(): - boatcode = df.ix[index,'code'] - boatname = smart_text(df.ix[index,'name']) - nrseats = df.ix[index,'nrseats'] - status = 'hangar' - cats = df.ix[index,'categories'] - cats = str(cats).split() - print boatcode - - theboat = Boat(boatcode=boatcode,boatname=boatname, - nrseats=int(nrseats), - status=status) - - theboat.save() - if (len(cats) !=0): - for index in cats: - print index - thecategory = BoatCategory.objects.get(id=index) - print unidecode.unidecode(thecategory.name) - theboat.categories.add(thecategory) - - theboat.save() - - -def addboat(formdict): - message = "" - successmessage = "" - id = 0 - cats = dict(formdict)["categories"] - boatcode = formdict['boatcode'] - boatname = formdict['boatname'] - nrseats = formdict['nrseats'] - status = formdict['status'] - comment = formdict['comment'] - theboat = Boat(boatcode=boatcode,boatname=boatname, - nrseats=int(nrseats), - status=status,comment=comment) - # check if other boat exists with new code - if len(Boat.objects.filter(boatcode=boatcode)) != 0: - message = _("There is already a boat with that code") - theview = boats_admin_add_view - return [theview,message,"",id] - else: - theboat.save() - - if len(cats) !=0: - for index in cats: - thecategory = BoatCategory.objects.get(id=index) - theboat.categories.add(thecategory) - - theview = boats_admin_view - successmessage = _('Boat created') - message = '' - return [theview,message,successmessage,id] - -def editboat(formdict,theboat): - # do something - message = "" - successmessage = "" - theid = 0 - boatcode = formdict['boatcode'] - boatname = formdict['boatname'] - cats = dict(formdict)["categories"] - nrseats = formdict['nrseats'] - status = formdict['status'] - comment = formdict['comment'] - theboat.boatname = boatname - theboat.nrseats = nrseats - theboat.status = status - theboat.comment = comment - theboat.categories.clear() - theboat.save() - if (len(cats) !=0): - for index in cats: - thecategory = BoatCategory.objects.get(id=index) - theboat.categories.add(thecategory) - - # check if other boat exists with new code - if boatcode != theboat.boatcode: - if len(Boat.objects.filter(boatcode=boatcode)) != 0: - message = _("There is already a boat with that code") - theview = boats_admin_edit_view - theid = theboat.id - return [theview,message,"",theid] - else: - theboat.boatcode = boatcode - - theboat.save() - - successmessage = _("Changes Saved") - theview = boats_admin_view - return [theview,"",successmessage,theid] - -def addbulkmember(cats,xlsfile,sheetname): - df = pd.read_excel(xlsfile,sheetname=sheetname) - for index,row in df.iterrows(): - lastname,firstname = df.ix[index,'name'].split() - email = df.ix[index,'e-mail'] - username = unidecode.unidecode(lastname)+unidecode.unidecode(firstname)[0] - username = username.lower() - password = 'cvkbrno' - contributions = True - hoursworked = 0 - status = 'member' - - print username - - theuser = User.objects.create_user(username,password=password) - theuser.first_name = firstname - theuser.last_name = lastname - theuser.email = email - theuser.save() - - themember = Member(user=theuser,status=status, - contributions=contributions, - hoursworked=hoursworked, - club=THISCLUB) - - themember.save() - - if (len(cats) !=0): - for index in cats: - thecategory = BoatCategory.objects.get(id=index) - themember.categories.add(thecategory) - - themember.save() - -def addmember(formdict): - message = "" - successmessage = "" - theid = 0 - theview = members_admin_view - status = formdict['status'] - username = formdict['username'] - email = formdict['email'] - password = formdict['password'] - password2 = formdict['passwordconfirm'] - first_name = formdict['first_name'] - last_name = formdict['last_name'] - try: - contributions = formdict['contributions'] - except: - contributions = False - hoursworked = formdict['hoursworked'] - cats = dict(formdict)["categories"] - - #check if passwords are equal - if (password != password2): - message = _("The two passwords are not equal") - theview = members_admin_add_view - theid = 0 - return [theview,message,"",theid] - - #check if there isn't already a user with this username - if len(User.objects.filter(username=username)) != 0: - message = _("There is already a user with that username") - theview = members_admin_add_view - theid = 0 - return [theview,message,"",theid] - else: - - theuser = User.objects.create_user(username,password=password) - theuser.first_name = first_name - theuser.last_name = last_name - theuser.email = email - theuser.save() - - themember = Member(user=theuser,status=status, - contributions=contributions, - hoursworked=hoursworked, - club=THISCLUB) - - themember.save() - - if (len(cats) !=0): - for index in cats: - thecategory = BoatCategory.objects.get(id=index) - themember.categories.add(thecategory) - - themember.save() - - successmessage = _("New Member Created") - - return [theview,"",successmessage,theid] - -def editmemberwork(formdict,thework): - message = "" - successmessage = "" - theid = thework.id - theview = members_work_admin_view - name = formdict['name'] - date = formdict['date'] - comment = formdict['comment'] - workers = dict(formdict)["worker"] - hours = formdict['hours'] - - thework.date = date - thework.name = name - thework.hours = hours - thework.comment = comment - thework.save() - - if (len(workers) != 0): - for index in workers: - theworker = Member.objects.get(id=index) - thework.worker.add(theworker) - - thework.save() - successmessage = _("Members Work Updated") - - return [theview,"",successmessage,0] - -def editmember(formdict,themember): - message = "" - successmessage = "" - theid = themember.id - theview = members_admin_view - status = formdict['status'] - first_name = formdict['first_name'] - last_name = formdict['last_name'] - try: - contributions = formdict['contributions'] - except: - contributions = False - hoursworked = formdict['hoursworked'] - cats = dict(formdict)["categories"] - email = formdict['email'] - - themember.status = status - themember.contributions = contributions - themember.hoursworked = hoursworked - themember.categories.clear() - - if (len(cats) !=0): - for index in cats: - thecategory = BoatCategory.objects.get(id=index) - themember.categories.add(thecategory) - - themember.save() - - - - theuser = themember.user - theuser.first_name = first_name - theuser.last_name = last_name - theuser.email = email - theuser.save() - - successmessage = _("Changes saved") - - return [theview,"",successmessage,0] - - diff --git a/locale/cs/LC_MESSAGES/django.po~ b/locale/cs/LC_MESSAGES/django.po~ deleted file mode 100644 index 78e44044..00000000 --- a/locale/cs/LC_MESSAGES/django.po~ +++ /dev/null @@ -1,7 +0,0 @@ -#: .\rowsandall_app\settings.py:135 -msgid "Czech" -msgstr "" - -#: .\rowsandall_app\settings.py:136 -msgid "Dutch" -msgstr "" diff --git a/locale/nl/LC_MESSAGES/django.po~ b/locale/nl/LC_MESSAGES/django.po~ deleted file mode 100644 index 6b263121..00000000 --- a/locale/nl/LC_MESSAGES/django.po~ +++ /dev/null @@ -1,263 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR , YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-05-19 08:27+0200\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME \n" -"Language-Team: LANGUAGE \n" -"Language: \n" -"MIME-Version: 1.0\n" -"Content-Type: text/plain; charset=UTF-8\n" -"Content-Transfer-Encoding: 8bit\n" - -#: .\cvkbrno\models.py:16 -msgid "Boat Category" -msgstr "Kategorie Lodí" - -#: .\cvkbrno\models.py:19 -msgid "boat category" -msgstr "kategorie lodí" - -#: .\cvkbrno\models.py:20 -msgid "boat categories" -msgstr "kategorie lodí" - -#: .\cvkbrno\models.py:34 -msgid "coach" -msgstr "trenér" - -#: .\cvkbrno\models.py:35 .\cvkbrno\models.py:40 -msgid "member" -msgstr "clen" - -#: .\cvkbrno\models.py:36 -msgid "administrator" -msgstr "správce" - -#: .\cvkbrno\models.py:41 -msgid "members" -msgstr "clenové" - -#: .\cvkbrno\models.py:49 -msgid "Boat Categories" -msgstr "Kategorie Lodí" - -#: .\cvkbrno\models.py:50 -msgid "Club" -msgstr "Klub" - -#: .\cvkbrno\models.py:51 -msgid "Hours Worked" -msgstr "Odpracované hodiny" - -#: .\cvkbrno\models.py:63 -msgid "boat" -msgstr "lod" - -#: .\cvkbrno\models.py:64 -msgid "boats" -msgstr "lode" - -#: .\cvkbrno\models.py:66 -msgid "Boat Name" -msgstr "název lodi" - -#: .\cvkbrno\models.py:67 -msgid "Boat Code" -msgstr "Kód Lode" - -#: .\cvkbrno\models.py:69 -msgid "Nr of Seats" -msgstr "Pocet míst" - -#: .\cvkbrno\models.py:71 -msgid "water" -msgstr "na vode" - -#: .\cvkbrno\models.py:72 -msgid "hangar" -msgstr "v hangaru" - -#: .\cvkbrno\models.py:73 .\cvkbrno\views.py:656 -msgid "damaged" -msgstr "poškozená" - -#: .\cvkbrno\models.py:74 -msgid "races" -msgstr "na závodech" - -#: .\cvkbrno\models.py:94 .\cvkbrno\models.py:95 -msgid "member work" -msgstr "brigády" - -#: .\cvkbrno\models.py:97 -msgid "Date" -msgstr "Datum" - -#: .\cvkbrno\models.py:98 -msgid "Hours" -msgstr "Hodiny" - -#: .\cvkbrno\models.py:99 -msgid "Work Event Name" -msgstr "Název Brigády" - -#: .\cvkbrno\models.py:102 -msgid "planned" -msgstr "plánovaná" - -#: .\cvkbrno\models.py:103 -msgid "executed" -msgstr "hotová" - -#: .\cvkbrno\models.py:111 -msgid "outing" -msgstr "výjezd" - -#: .\cvkbrno\models.py:112 -msgid "outings" -msgstr "výjezdy" - -#: .\cvkbrno\models.py:115 -msgid "Start Date/Time" -msgstr "Startovní Datum/Cas" - -#: .\cvkbrno\models.py:116 -msgid "End Date/Time" -msgstr "Datum/Cas ukoncení" - -#: .\cvkbrno\models.py:117 -msgid "Distance" -msgstr "Vzdálenost" - -#: .\cvkbrno\models.py:118 -msgid "Comment" -msgstr "Komentár" - -#: .\cvkbrno\models.py:120 -msgid "reservation" -msgstr "rezervace" - -#: .\cvkbrno\models.py:121 -msgid "active" -msgstr "aktivní" - -#: .\cvkbrno\models.py:122 -msgid "completed" -msgstr "dokoncený" - -#: .\cvkbrno\models.py:123 -msgid "race" -msgstr "závod" - -#: .\cvkbrno\models.py:127 -msgid "Status" -msgstr "Status" - -#: .\cvkbrno\templates\cvkbrnobase.html:26 -msgid "Welcome," -msgstr "Vítej," - -#: .\cvkbrno\templates\cvkbrnobase.html:30 -msgid "Password Change" -msgstr "Zmenit Heslo" - -#: .\cvkbrno\templates\cvkbrnobase.html:42 -msgid "Members Work" -msgstr "Brigády" - -#: .\cvkbrno\templates\cvkbrnobase.html:56 -msgid "Go Rowing" -msgstr "Jdi na vodu" - -#: .\cvkbrno\templates\cvkbrnobase.html:66 -msgid "Reservations" -msgstr "Rezervace" - -#: .\cvkbrno\templates\cvkbrnobase.html:75 -msgid "Boats" -msgstr "Lode" - -#: .\cvkbrno\templates\cvkbrnobase.html:83 -msgid "Members" -msgstr "Clenové" - -#: .\cvkbrno\templates\cvkbrnobase.html:91 -msgid "Transport" -msgstr "Doprava" - -#: .\cvkbrno\templates\cvkbrnobase.html:99 -msgid "Categories" -msgstr "Kategorie" - -#: .\cvkbrno\templates\cvkbrnobase.html:106 -msgid "logout" -msgstr "odhlásit" - -#: .\cvkbrno\views.py:240 -msgid "boat deleted" -msgstr "lod smazána" - -#: .\cvkbrno\views.py:254 -msgid "member deleted" -msgstr "clen smazán" - -#: .\cvkbrno\views.py:268 -msgid "category deleted" -msgstr "kategorie smazána" - -#: .\cvkbrno\views.py:299 .\cvkbrno\views.py:393 .\cvkbrno\views.py:440 -#: .\cvkbrno\views.py:488 -msgid "invalid form" -msgstr "neplatný formulár" - -#: .\cvkbrno\views.py:532 .\cvkbrno\views.py:538 .\cvkbrno\views.py:916 -msgid "Changes saved" -msgstr "Zmeny uloženy" - -#: .\cvkbrno\views.py:638 -msgid "You have no active outings. Go rowing first." -msgstr "Nemáte žádné aktivní výjezdy. Jdete nejdríve na vodu." - -#: .\cvkbrno\views.py:644 -msgid "You are not out. Go rowing first." -msgstr "Nejste na vode. Jdete nejdríve na vodu." - -#: .\cvkbrno\views.py:709 -msgid "Conflicting reservations exist" -msgstr "Konflikt rezervací" - -#: .\cvkbrno\views.py:726 -msgid "Invalid Form" -msgstr "Neplatný Formulár" - -#: .\cvkbrno\views.py:742 -msgid "Make a reservation" -msgstr "Rezervujte" - -#: .\cvkbrno\views.py:768 .\cvkbrno\views.py:809 -msgid "There is already a boat with that code" -msgstr "Již existuje jiná lod s tímto kódem." - -#: .\cvkbrno\views.py:818 -msgid "Changes Saved" -msgstr "Zmeny Uloženy" - -#: .\cvkbrno\views.py:843 -msgid "The two passwords are not equal" -msgstr "Nazadal jste stejná hesla." - -#: .\cvkbrno\views.py:850 -msgid "There is already a user with that username" -msgstr "Uživatel s tímto uživatelském jménem již existuje" - -#: .\cvkbrno\views.py:875 -msgid "New Member Created" -msgstr "Nový clen vytvoren" diff --git a/move_db.py~ b/move_db.py~ deleted file mode 100644 index 792c3f6e..00000000 --- a/move_db.py~ +++ /dev/null @@ -1,76 +0,0 @@ -# The following code is tested on Django 1.7 -import django -import sys -import logging - -from django.apps import apps -from django.db.migrations.recorder import MigrationRecorder -if django.get_version() > '1.7': - from django.core.serializers import sort_dependencies -else: - from django.core.management.commands.dumpdata import sort_dependencies - - -LOG_FORMAT = '%(asctime)s|%(levelname)s|%(message)s' -logging.basicConfig(stream=sys.stdout, level=logging.INFO, format=LOG_FORMAT) -logger = logging.getLogger(__name__) - - -def copy(model): - table_name = model._meta.db_table - logger.info('Start import %s into new_db' % table_name) - - table_objects = model.objects.all() - for t in table_objects: - t.save(using='new_db') - - logger.info('Successfuly imported %s into new_db' % table_name) - -''' -Please note that the id for many to many objects might be diffrent from source table. -This is because id is not specified in the add method. -''' -def copy_m2m(model, m2m_field): - table_name = m2m_field.rel.through._meta.db_table - field_name = m2m_field.name - to_model = m2m_field.rel.to - pk_name = model._meta.pk.name - child_pk_name = to_model._meta.pk.name - - logger.info('Start import %s into new_db' % table_name) - - for o in model.objects.all(): - pk_value = getattr(o, pk_name) - new_o = model.objects.using('new_db').get(**{pk_name: pk_value}) - for child in getattr(o, field_name).all(): - child_pk_value = getattr(child, child_pk_name) - new_child = to_model.objects.using('new_db').get(**{child_pk_name: child_pk_value}) - getattr(new_o, field_name).add(new_child) - - logger.info('Successfuly imported %s into new_db' % table_name) - - -def run(): - logger.info('Start move data into new_db') - - app_configs = apps.get_app_configs() - app_list = [(a, None) for a in app_configs] - models = sort_dependencies(app_list) - models_with_m2m = [] - - for m in models: - copy(m) - if m._meta.many_to_many: - models_with_m2m.append(m) - - # Migration model needs to copy separately as it is not in the INSTALLED_APPS - copy(MigrationRecorder.Migration) - - # re-create object in ManyToManyField - for m in models_with_m2m: - for field in m._meta.many_to_many: - # data for field that has specific through model should have been copied in earlier steps - if field.rel.through._meta.auto_created: - copy_m2m(m, field) - - logger.info('Successfully moved data into new_db') diff --git a/no_templates/add_result.html~ b/no_templates/add_result.html~ deleted file mode 100644 index 182ffd65..00000000 --- a/no_templates/add_result.html~ +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}Here's your plot{% endblock %} - -{% block content %} -Waiting for the task to complete. -{% endblock %} - diff --git a/no_templates/base.html~ b/no_templates/base.html~ deleted file mode 100644 index 42a8a0f5..00000000 --- a/no_templates/base.html~ +++ /dev/null @@ -1,16 +0,0 @@ - - - - {% block title %}{% endblock %} - {% block meta %} {% endblock %} - - -

My helpful rowing site

- {% block content %}{% endblock %} - {% block footer %} -
-

{{ versionstring }}.

-

Thanks for visiting my site.

- {% endblock %} - - \ No newline at end of file diff --git a/no_templates/contact_form.html~ b/no_templates/contact_form.html~ deleted file mode 100644 index cbd1e4f2..00000000 --- a/no_templates/contact_form.html~ +++ /dev/null @@ -1,24 +0,0 @@ -# contact_form.html - - - - Contact us - - -

Contact us

- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- - {{ form.as_table }} -
- {% csrf_token %} - -
- - \ No newline at end of file diff --git a/no_templates/current_datetime.html~ b/no_templates/current_datetime.html~ deleted file mode 100644 index 2c849ba4..00000000 --- a/no_templates/current_datetime.html~ +++ /dev/null @@ -1 +0,0 @@ -

It is now {{ current_date }}

\ No newline at end of file diff --git a/no_templates/document_form.html~ b/no_templates/document_form.html~ deleted file mode 100644 index 39c240e8..00000000 --- a/no_templates/document_form.html~ +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}File loading{% endblock %} - -{% block content %} -

File Upload

- {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- - {{ form.as_table }} -
- {% csrf_token %} - - -{% endblock %} diff --git a/no_templates/future_time.html~ b/no_templates/future_time.html~ deleted file mode 100644 index 7124294e..00000000 --- a/no_templates/future_time.html~ +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Current time{% endblock %} - -{% block content %} -

It is now {{ current_date }}.

-{% endblock %} diff --git a/no_templates/image_page.html~ b/no_templates/image_page.html~ deleted file mode 100644 index 7d70c330..00000000 --- a/no_templates/image_page.html~ +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}Here's your plot{% endblock %} - -{% block content %} -

Here's your plot

-

-{% endblock %} - diff --git a/no_templates/list_workouts.html~ b/no_templates/list_workouts.html~ deleted file mode 100644 index 296cd9b2..00000000 --- a/no_templates/list_workouts.html~ +++ /dev/null @@ -1,36 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -

My Workouts

- {% if workouts %} - - - - - - - - - - - - {% for workout in workouts %} - - - - - - - - - - - {% endfor %} -
Date Time Name Type Distance Duration Edit
{{ workout.date }} {{ workout.starttime }} {{ workout.name }} {{ workout.workouttype }} {{ workout.distance }}m {{ workout.duration }} E
- {% else %} -

No workouts found

- {% endif %} -{% endblock %} diff --git a/no_templates/login_form.html~ b/no_templates/login_form.html~ deleted file mode 100644 index 01eb64a0..00000000 --- a/no_templates/login_form.html~ +++ /dev/null @@ -1,22 +0,0 @@ - - - File selection - - -

Select File

- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - - - {{ form.as_table }} -
- {% csrf_token %} - -
- - \ No newline at end of file diff --git a/no_templates/rower_form.html~ b/no_templates/rower_form.html~ deleted file mode 100644 index 4bd36414..00000000 --- a/no_templates/rower_form.html~ +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Change Rower {% endblock %} - -{% block content %} - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- - {{ form.as_table }} -
- {% csrf_token %} - - -{% endblock %} \ No newline at end of file diff --git a/no_templates/rowingdata.html~ b/no_templates/rowingdata.html~ deleted file mode 100644 index 4cd58022..00000000 --- a/no_templates/rowingdata.html~ +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Rowingdata Version{% endblock %} - -{% block content %} -

{{ versionstring }}.

-{% endblock %} diff --git a/no_templates/waiting_page.html~ b/no_templates/waiting_page.html~ deleted file mode 100644 index 8dd1f0a7..00000000 --- a/no_templates/waiting_page.html~ +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}Waiting{% endblock %} -{% block meta %}{% endblock %} - -{% block content %} -

Waiting for your image to be processed

-

{{ message }}

-

Page should refresh automatically (or you can hit reload)

-{% endblock %} diff --git a/no_templates/workout_form.html~ b/no_templates/workout_form.html~ deleted file mode 100644 index fa9c18a0..00000000 --- a/no_templates/workout_form.html~ +++ /dev/null @@ -1,19 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - - - {{ form.as_table }} -
- {% csrf_token %} - - -{% endblock %} \ No newline at end of file diff --git a/requirements.txt~ b/requirements.txt~ deleted file mode 100644 index 1ee0d957..00000000 --- a/requirements.txt~ +++ /dev/null @@ -1,189 +0,0 @@ -alabaster==0.7.7 -amqp==1.4.9 -anaconda-client==1.4.0 -anaconda-navigator==1.1.0 -anyjson==0.3.3 -argcomplete==1.0.0 -astropy==1.1.2 -Babel==2.2.0 -backports-abc==0.4 -backports.ssl-match-hostname==3.4.0.2 -beautifulsoup4==4.4.1 -billiard==3.3.0.23 -bitarray==0.8.1 -blaze==0.9.1 -bokeh==0.11.1 -boto==2.39.0 -Bottleneck==1.0.0 -cairocffi==0.7.2 -cdecimal==2.3 -celery==3.1.23 -certifi==2016.2.28 -cffi==1.5.2 -chest==0.2.3 -click==6.6 -cloudpickle==0.1.1 -clyent==1.2.1 -colorama==0.3.7 -comtypes==1.1.2 -conda==4.0.5 -conda-build==1.20.0 -conda-env==2.4.5 -conda-manager==0.3.1 -configobj==5.0.6 -cryptography==1.3 -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 -Django==1.9.5 -django-braces==1.8.1 -django-celery==3.1.17 -django-cors-headers==1.1.0 -django-durationfield==0.5.2 -django-modelcluster==1.1 -django-oauth-toolkit==0.10.0 -django-rq==0.9.0 -django-taggit==0.18.1 -django-translation-manager==0.3.4 -django-treebeard==4.0 -djangorestframework==3.3.3 -docopt==0.6.2 -docutils==0.12 -enum34==1.1.2 -et-xmlfile==1.0.1 -fastcache==1.0.2 -filemagic==1.6 -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==0.4 -future==0.15.2 -futures==3.0.3 -gevent==1.1.0 -greenlet==0.4.9 -grin==1.2.1 -gunicorn==19.4.5 -h5py==2.5.0 -HeapDict==1.0.0 -html5lib==0.9999999 -httplib2==0.9.2 -idna==2.0 -ipaddress==1.0.14 -ipykernel==4.3.1 -ipython==4.1.2 -ipython-genutils==0.1.0 -ipywidgets==4.1.1 -itsdangerous==0.24 -jdcal==1.2 -jedi==0.9.0 -Jinja2==2.8 -jsonschema==2.4.0 -jupyter==1.0.0 -jupyter-client==4.2.2 -jupyter-console==4.1.1 -jupyter-core==4.1.0 -kombu==3.0.35 -libmagic==1.0 -llvmlite==0.9.0 -locket==0.2.0 -lxml==3.6.0 -MarkupSafe==0.23 -matplotlib==1.5.1 -mechanize==0.2.5 -menuinst==1.3.2 -mistune==0.7.2 -mpld3==0.2 -mpmath==0.19 -multipledispatch==0.4.8 -nbconvert==4.1.0 -nbformat==4.0.1 -networkx==1.11 -nltk==3.2 -nose==1.3.7 -notebook==4.1.0 -numba==0.24.0 -numexpr==2.5 -numpy==1.11.0 -oauth2==1.9.0.post1 -oauthlib==1.0.3 -odo==0.4.2 -openpyxl==2.3.2 -pandas==0.18.0 -partd==0.3.2 -path.py==0.0.0 -patsy==0.4.0 -pep8==1.7.0 -pickleshare==0.5 -Pillow==3.1.1 -ply==3.8 -polib==1.0.7 -psutil==4.1.0 -py==1.4.31 -pyasn1==0.1.9 -pycosat==0.6.1 -pycparser==2.14 -pycrypto==2.6.1 -pyflakes==1.1.0 -Pygments==2.1.1 -pymarc==3.1.1 -pyOpenSSL==0.15.1 -pyparsing==2.0.3 -pypi-data==0.1.4 -pypilist==0.1.0 -pyreadline==2.1 -pytest==2.8.5 -python-dateutil==2.5.1 -python-magic==0.4.11 -python-openid==2.2.5 -pytz==2016.4 -pywin32==220 -PyYAML==3.11 -pyzmq==15.2.0 -QtAwesome==0.3.2 -qtconsole==4.2.0 -QtPy==1.0 -redis==2.10.5 -requests==2.9.1 -requests-oauthlib==0.6.1 -rope==0.9.4 -rowingdata==0.80.4 -rowingphysics==0.2.4 -rq==0.6.0 -scikit-image==0.12.3 -scikit-learn==0.17.1 -scipy==0.17.0 -simplegeneric==0.8.1 -singledispatch==3.4.0.3 -six==1.10.0 -snowballstemmer==1.2.1 -sockjs-tornado==1.0.1 -South==1.0.2 -sphinx==1.3.5 -sphinx-pypi-upload==0.2.1 -sphinx-rtd-theme==0.1.9 -spyder==2.3.8 -SQLAlchemy==1.0.12 -statsmodels==0.6.1 -sympy==1.0 -tables==3.2.2 -toolz==0.7.4 -tornado==4.2 -tqdm==4.4.0 -traitlets==4.2.1 -unicodecsv==0.14.1 -Unidecode==0.4.19 -virtualenv==15.0.1 -wagtail==1.4.3 -Werkzeug==0.11.4 -Willow==0.3 -xlrd==0.9.4 -XlsxWriter==0.8.4 -xlwings==0.7.0 -xlwt==1.0.0 diff --git a/rowers/__init__.pyc b/rowers/__init__.pyc deleted file mode 100644 index 442ccdd8..00000000 Binary files a/rowers/__init__.pyc and /dev/null differ diff --git a/rowers/__init__.py~ b/rowers/__init__.py~ deleted file mode 100644 index 66cd71ed..00000000 --- a/rowers/__init__.py~ +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import - -from .tasks import app as celery_app diff --git a/rowers/admin.pyc b/rowers/admin.pyc deleted file mode 100644 index a32b49f6..00000000 Binary files a/rowers/admin.pyc and /dev/null differ diff --git a/rowers/admin.py~ b/rowers/admin.py~ deleted file mode 100644 index 3d8d951f..00000000 --- a/rowers/admin.py~ +++ /dev/null @@ -1,23 +0,0 @@ -from django.contrib import admin -from django.contrib.auth.admin import UserAdmin -from django.contrib.auth.models import User - -from .models import Rower, Workout,GraphImage - -# Register your models here. - -class RowerInline(admin.StackedInline): - model = Rower - can_delete = False - verbose_name_plural = 'rower' - -class UserAdmin(UserAdmin): - inlines = (RowerInline,) - -class WorkoutAdmin(admin.ModelAdmin): - list_display = ('date','user','name','workouttype') - -admin.site.unregister(User) -admin.site.register(User,UserAdmin) -admin.site.register(Workout,WorkoutAdmin) -admin.site.register(GraphImage) diff --git a/rowers/apps.pyc b/rowers/apps.pyc deleted file mode 100644 index 2a023dd7..00000000 Binary files a/rowers/apps.pyc and /dev/null differ diff --git a/rowers/c2stuff.pyc b/rowers/c2stuff.pyc deleted file mode 100644 index 156297f3..00000000 Binary files a/rowers/c2stuff.pyc and /dev/null differ diff --git a/rowers/c2stuff.py~ b/rowers/c2stuff.py~ deleted file mode 100644 index 415ef080..00000000 --- a/rowers/c2stuff.py~ +++ /dev/null @@ -1,432 +0,0 @@ -# Python -import oauth2 as oauth -import cgi -import requests -import requests.auth -import json -from django.utils import timezone -from datetime import datetime -from datetime import timedelta - -# Django -from django.shortcuts import render_to_response -from django.http import HttpResponseRedirect, HttpResponse,JsonResponse -from django.conf import settings -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.models import User -from django.contrib.auth.decorators import login_required - -# Project -# from .models import Profile -from rowingdata import rowingdata -import pandas as pd -import numpy as np -from rowers.models import Rower,Workout - -from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET - -class C2NoTokenError(Exception): - def __init__(self,value): - self.value=value - - def __str__(self): - return repr(self.value) - - - -def custom_exception_handler(exc,message): - - response = { - "errors": [ - { - "code": str(exc), - "detail": message, - } - ] - } - - res = HttpResponse(message) - res.status_code = 401 - res.json = json.dumps(response) - - return res - - -def checkworkoutuser(user,workout): - try: - r = Rower.objects.get(user=user) - return (workout.user == r) - except Rower.DoesNotExist: - return(False) - - -def makeseconds(t): - seconds = t.hour*3600.+t.minute*60.+t.second+0.1*int(t.microsecond/1.e5) - return seconds - -def c2wc(weightclass): - if (weightclass=="lwt"): - res = "L" - else: - res = "H" - - return res - -def createc2workoutdata_as_splits(w): - filename = w.csvfilename - row = rowingdata(filename) - - # resize per minute - df = row.df.groupby(lambda x:x/60).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)'].diff().values - t[0] = t[1] - d = df.ix[:,' Horizontal (meters)'].diff().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) - 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) - - 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": str(w.date)+" "+str(w.starttime), - "distance": int(w.distance), - "time": int(10*makeseconds(durationstr)), - "timezone": "Etc/UTC", - "weight_class": c2wc(w.weightcategory), - "comments": w.notes, - "heart_rate": { - "average": averagehr, - "max": maxhr, - }, - "splits": split_data, - } - - - return data - -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": str(w.date)+" "+str(w.starttime), - "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 - -def createc2workoutdata(w): - filename = w.csvfilename - row = rowingdata(filename) - averagehr = int(row.df[' HRCur (bpm)'].mean()) - maxhr = int(row.df[' HRCur (bpm)'].max()) - - # adding diff, trying to see if this is valid - t = 10*row.df.ix[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)'] - t[0] = t[1] - d = 10*row.df.ix[:,' Horizontal (meters)'].values - d[0] = d[1] - p = abs(10*row.df.ix[:,' Stroke500mPace (sec/500m)'].values) - p = np.clip(p,0,3600) - t = t.astype(int) - d = d.astype(int) - p = p.astype(int) - spm = row.df[' Cadence (stokes/min)'].astype(int) - spm[0] = spm[1] - hr = row.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": str(w.date)+" "+str(w.starttime), - "timezone": "Etc/UTC", - "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 - -def do_refresh_token(refreshtoken): - 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, - } - headers = {'user-agent': 'sanderroosendaal'} - response = requests.post("https://log.concept2.com/oauth/access_token", - data=post_data, - headers=headers) - - token_json = response.json() - thetoken = token_json['access_token'] - expires_in = token_json['expires_in'] - refresh_token = token_json['refresh_token'] - - return [thetoken,expires_in,refresh_token] - - -def get_token(code): - client_auth = requests.auth.HTTPBasicAuth(C2_CLIENT_ID, C2_CLIENT_SECRET) - post_data = {"grant_type": "authorization_code", - "code": code, - "redirect_uri": C2_REDIRECT_URI, - "client_secret": C2_CLIENT_SECRET, - "client_id":C2_CLIENT_ID, - } - headers = {'user-agent': 'sanderroosendaal'} - response = requests.post("https://log.concept2.com/oauth/access_token", - data=post_data, - headers=headers) - token_json = response.json() - thetoken = token_json['access_token'] - expires_in = token_json['expires_in'] - refresh_token = token_json['refresh_token'] - - return [thetoken,expires_in,refresh_token] - -def make_authorization_url(request): - # Generate a random string for the state parameter - # Save it for use later to prevent xsrf attacks - from uuid import uuid4 - state = str(uuid4()) - - params = {"client_id": CLIENT_ID, - "response_type": "code", - "redirect_uri": REDIRECT_URI} - import urllib - url = "https://log.concept2.com/oauth/authorize?"+ urllib.urlencode(params) - # url = "https://ssl.reddit.com/api/v1/authorize?" + urllib.urlencode(params) - - return HttpResponseRedirect(url) - -def get_c2_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) - elif (timezone.now()>r.tokenexpirydate): - 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) - s = requests.get(url,headers=headers) - - return s - -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" - elif (timezone.now()>r.tokenexpirydate): - 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) - - return s - -def get_c2_workout_list(user): - 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) - elif (timezone.now()>r.tokenexpirydate): - 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" - s = requests.get(url,headers=headers) - - return s - - - -def get_username(access_token): - authorizationstring = str('Bearer ' + access_token) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - import urllib - url = "https://log.concept2.com/api/users/me" - response = requests.get(url,headers=headers) - - - me_json = response.json() - - - return me_json['data']['username'] - -def get_userid(access_token): - authorizationstring = str('Bearer ' + access_token) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - import urllib - url = "https://log.concept2.com/api/users/me" - response = requests.get(url,headers=headers) - - - me_json = response.json() - - - return me_json['data']['id'] - -def process_callback(request): - # need error handling - - code = request.GET['code'] - - access_token = get_token(code) - - username = get_username(access_token) - - return HttpResponse("got a user name: %s" % username) - -def workout_c2_upload(user,w): - response = 'trying C2 upload' - 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) - elif (timezone.now()>r.tokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) - else: - # ready to upload. Hurray - if (checkworkoutuser(user,w)): - c2userid = get_userid(r.c2token) - data = createc2workoutdata(w) - # if (w.workouttype=='water'): - # data = createc2workoutdata_as_splits(w) - 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)) - if (response.status_code == 201): - s= json.loads(response.text) - c2id = s['data']['id'] - w.uploadedtoc2 = c2id - w.save() - else: - response = "You are not authorized to upload this workout" - - return response - -def rower_c2_token_refresh(user): - r = Rower.objects.get(user=user) - res = do_refresh_token(r.c2refreshtoken) - access_token = res[0] - expires_in = res[1] - refresh_token = res[2] - expirydatetime = timezone.now()+timedelta(seconds=expires_in) - - r = Rower.objects.get(user=user) - r.c2token = access_token - r.tokenexpirydate = expirydatetime - r.c2refreshtoken = refresh_token - - r.save() - return r.c2token - diff --git a/rowers/celery.pyc b/rowers/celery.pyc deleted file mode 100644 index b805df7a..00000000 Binary files a/rowers/celery.pyc and /dev/null differ diff --git a/rowers/email.pyc b/rowers/email.pyc deleted file mode 100644 index 7439c47f..00000000 Binary files a/rowers/email.pyc and /dev/null differ diff --git a/rowers/email.py~ b/rowers/email.py~ deleted file mode 100644 index 6b186d2e..00000000 --- a/rowers/email.py~ +++ /dev/null @@ -1,80 +0,0 @@ -import time -from django.views.generic.base import TemplateView -from django.shortcuts import render -from django.http import HttpResponse, HttpResponseRedirect -from django.contrib.auth import authenticate, login, logout -from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm -from django.core.urlresolvers import reverse -from django.conf import settings -from django.utils.datastructures import MultiValueDictKeyError -from django.utils import timezone,translation -from django.core.mail import send_mail, BadHeaderError -from rowers.forms import EmailForm, RegistrationForm, RegistrationFormTermsOfService,RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,UpdateStreamForm -from rowers.forms import PredictedPieceForm -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage,AdvancedWorkoutForm -import StringIO -from django.contrib.auth.decorators import login_required,user_passes_test -from time import strftime,strptime,mktime,time,daylight -import os,sys -import datetime -import iso8601 -import c2stuff -from c2stuff import C2NoTokenError -from iso8601 import ParseError -import stravastuff -import sporttracksstuff -from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET -from rowsandall_app.settings import SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET -import requests -import json -from rowsandall_app.rows import handle_uploaded_file -from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx -from scipy.signal import savgol_filter - -from rowingdata import rower as rrower -from rowingdata import main as rmain -from rowingdata import rowingdata as rdata -from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR -from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser -from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata -from rowingdata import make_cumvalues -from rowingdata import summarydata,get_file_type -import pandas as pd -import numpy as np -import matplotlib.pyplot as plt -from pytz import timezone as tz,utc -import dateutil -import mpld3 -from mpld3 import plugins -import stravalib -from stravalib.exc import ActivityUploadFailed,TimeoutExceeded -from weather import get_wind_data - -import django_rq -queue = django_rq.get_queue('default') -queuelow = django_rq.get_queue('low') -queuehigh = django_rq.get_queue('low') - -import plots - -from io import BytesIO -from scipy.special import lambertw - -def emailall(emailfile,subject): - rowers = Rower.objects.all() - for rower in rowers: - email = rower.user.email - firstname = rower.user.first_name - - with open(emailfile) as f: - message = f.read() - - message = '\nDear '+firstname+'\n\n'+str(message) - print message - - send_mail( - subject, - message, - 'info@rowsandall.com', - [email], - ) diff --git a/rowers/emailtxt.txt~ b/rowers/emailtxt.txt~ deleted file mode 100644 index 554580c4..00000000 --- a/rowers/emailtxt.txt~ +++ /dev/null @@ -1,9 +0,0 @@ -It is a little while since you registered at Rowsandall.com and we do hope you are enjoying analysing your rowing data using the tools we have designed. We are continuing to add features and functionality to the site as we grow and hopefully you will have seen some of these developments since you registered. - -We are always interested in users' views on Rowsandall.com as we strive to improve the interface and functionality of the site. We have therefore compiled a short questionnaire to capture your thoughts and experiences. The questionnaire can be found at: - -https://surveynuts.com/surveys/take?id=108060&c=764200337FDHD - -We do ask that you take a few moments to complete the survey and we would also welcome any other suggestions you may have directly to us (insert email address) if you feel a free-form response suits you better. Respondents to the questionnaire will receive a complementary Pro membership for 3 months. - -Best regards, Sander Roosendaal & the Rowsandall Team \ No newline at end of file diff --git a/rowers/forms.pyc b/rowers/forms.pyc deleted file mode 100644 index fd2c0560..00000000 Binary files a/rowers/forms.pyc and /dev/null differ diff --git a/rowers/forms.py~ b/rowers/forms.py~ deleted file mode 100644 index 2f199bbc..00000000 --- a/rowers/forms.py~ +++ /dev/null @@ -1,215 +0,0 @@ -from django import forms -from rowers.models import Workout -from rowsandall_app.rows import validate_file_extension,must_be_csv -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.utils import timezone,translation - -import datetime - -class LoginForm(forms.Form): - username = forms.CharField() - password = forms.CharField(widget=forms.PasswordInput()) - -class EmailForm(forms.Form): - firstname = forms.CharField(max_length=255) - lastname = forms.CharField(max_length=255) - email = forms.EmailField() - subject = forms.CharField(max_length=255) - botcheck = forms.CharField(max_length=5) - message = forms.CharField() - -class CNsummaryForm(forms.Form): - file = forms.FileField(required=True,validators=[must_be_csv]) - -class SummaryStringForm(forms.Form): - intervalstring = forms.CharField(max_length=255,label='Workout Description') - -class DocumentsForm(forms.Form): - filetypechoices = ( - ('csv' , 'Painsled iOS CSV'), - ('tcx' , 'TCX'), - ('tcxnohr' , 'TCX No HR'), - ('rp' , 'RowPro CSV'), - ('speedcoach' , 'SpeedCoach GPS CSV'), - ('speedcoach2' , 'SpeedCoach GPS 2 CSV'), - ('ergdata' , 'ErgData CSV'), - ('ergstick' , 'ErgStick CSV'), - ('painsleddesktop' , 'Painsled Desktop CSV'), - ) - title = forms.CharField(required=False) - file = forms.FileField(required=True, - validators=[validate_file_extension]) - workouttype = forms.ChoiceField(required=True, - choices=Workout.workouttypes, - initial='rower') -# fileformat = forms.ChoiceField(required=True, -# choices=filetypechoices, -# initial='csv') - notes = forms.CharField(required=False, - widget=forms.Textarea) - - class Meta: - fields = ['title','file','workouttype','fileformat'] - - - -class UploadOptionsForm(forms.Form): - plotchoices = ( - ('timeplot','Time Plot'), - ('distanceplot','Distance Plot'), - ('pieplot','Pie Chart'), - ) - make_plot = forms.BooleanField(initial=False) - plottype = forms.ChoiceField(required=False, - choices=plotchoices, - initial='timeplot') - upload_to_C2 = forms.BooleanField(initial=False) - - class Meta: - fields = ['make_plot','plottype','upload_toc2'] - -class PredictedPieceForm(forms.Form): - unitchoices = ( - ('t','minutes'), - ('d','meters'), - ) - pieceunit = forms.ChoiceField(required=True,choices=unitchoices, - initial='t',label='Unit') - value = forms.IntegerField(initial=10,label='Value') - - class Meta: - fields = ['value','pieceunit'] - -class UpdateStreamForm(forms.Form): - unitchoices = ( - ('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') - - class Meta: - fields = ['dist1','dist2','stream1', 'stream2','streamunit'] - -class UpdateWindForm(forms.Form): - unitchoices = ( - ('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') - winddirection1 = forms.IntegerField(initial=0,required=False, - label = 'Wind Direction 1') - winddirection2 = forms.IntegerField(initial=0,required=False, - label = 'Wind Direction 2') - - class Meta: - fields = ['dist1','dist2', - 'vwind1','vwind2', - 'windunit', - 'winddirection1','winddirection2'] - - - -class DateRangeForm(forms.Form): - startdate = forms.DateField(initial=timezone.now()-datetime.timedelta(days=365), - widget=SelectDateWidget(years=range(1990,2050)), - label='Start Date') - enddate = forms.DateField(initial=timezone.now(), - widget=SelectDateWidget(years=range(1990,2050)), - label='End Date') - - class Meta: - fields = ['startdate','enddate'] - -class DeltaDaysForm(forms.Form): - deltadays = forms.IntegerField(initial=0,required=False,label='') - -class RegistrationForm(UserCreationForm): - """ - Form for registering a new user account. - Validates that the requested username is not already in use, and - requires the password to be entered twice to catch typos. - Subclasses should feel free to add any additional validation they - need, but should avoid defining a ``save()`` method -- the actual - saving of collected user data is delegated to the active - registration backend. - """ - required_css_class = 'required' - email = forms.EmailField(label="E-mail") - - class Meta: - model = User - fields = ("username", "first_name", "last_name", "email", "password1", "password2") - -class RegistrationFormTermsOfService(RegistrationForm): - """ - Subclass of ``RegistrationForm`` which adds a required checkbox - for agreeing to a site's Terms of Service. - """ - tos = forms.BooleanField(widget=forms.CheckboxInput, - label='I have read and agree to the Terms of Service', - error_messages={'required': "You must agree to the terms to register"}) - - -class RegistrationFormUniqueEmail(RegistrationFormTermsOfService): - """ - Subclass of ``RegistrationFormTermsOfService`` which enforces uniqueness of - email addresses. - """ - def clean_email(self): - """ - Validate that the supplied email address is unique for the - site. - """ - if User.objects.filter(email__iexact=self.cleaned_data['email']): - raise forms.ValidationError("This email address is already in use. Please supply a different email address.") - return self.cleaned_data['email'] - - -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) - - for i in range(aantal): - self.fields['intervalt_%s' % i] = forms.TimeField(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;' - - diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index accc3d4b..73d1eac7 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -787,10 +787,24 @@ def interactive_cum_flex_chart(theworkouts,promember=0, thedata['driveenergy'] = thedata[' DriveLength (meters)']*thedata[' AverageDriveForce (lbs)']*4.44822 + # throw out zeros from dataframe + thedata = thedata[thedata[csvcolumns[yparam1]] > 0] + thedata = thedata[thedata[csvcolumns[xparam]] > 0] + if yparam2 != 'None': + thedata = thedata[thedata[csvcolumns[yparam2]] > 0] + + # check if dataframe not empty + if thedata.empty: + return ['','

No non-zero data in selection

','',''] + spm = thedata.ix[:,csvcolumns['spm']] f = thedata['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 + if not np.isnan(f): + windowsize = 2*(int(10./(f)))+1 + else: + windowsize = 5 + if windowsize <= 3: windowsize = 5 @@ -806,8 +820,6 @@ def interactive_cum_flex_chart(theworkouts,promember=0, thedata['drivespeed'] = drivelength/thedata[' DriveTime (ms)']*1.0e3 - # get user - # u = User.objects.get(id=row.user.id) x1 = thedata.ix[:,csvcolumns[xparam]] @@ -819,9 +831,31 @@ def interactive_cum_flex_chart(theworkouts,promember=0, if xparam=='time': - xaxmax = get_datetimes([x1.max()])[0] - xaxmin = get_datetimes([x1.min()])[0] + xaxmax = x1.max() + xaxmin = x1.min() + xaxmax = get_datetimes([xaxmax],tzinfo=1)[0] + xaxmin = get_datetimes([xaxmin],tzinfo=1)[0] x1 = get_datetimes(x1,tzinfo=1) + elif xparam=='distance': + xaxmax = x1.max() + xaxmin = x1.min() + else: + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] + + # average values + if xparam != 'time': + x1mean = x1.mean() + else: + x1mean = 0 + + y1mean = y1.mean() + y2mean = y2.mean() + + if xparam != 'time': + xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100. + else: + xvals = np.arange(100) x_axis_type = 'linear' y_axis_type = 'linear' @@ -836,7 +870,6 @@ def interactive_cum_flex_chart(theworkouts,promember=0, time = thedata.ix[:,csvcolumns['time']] - time = time-time[0] hr = thedata.ix[:,csvcolumns['hr']] if windowsize > 3: @@ -849,6 +882,7 @@ def interactive_cum_flex_chart(theworkouts,promember=0, power = thedata.ix[:,csvcolumns['power']] + # Add hover to this comma-separated string and see what changes if (promember==1): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' @@ -856,11 +890,21 @@ def interactive_cum_flex_chart(theworkouts,promember=0, TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - plot_width=900, tools=TOOLS, toolbar_location="above", toolbar_sticky=False) + x1means = Span(location=x1mean,dimension='height',line_color='green', + line_dash=[6,6], line_width=2) + + y1means = Span(location=y1mean,dimension='width',line_color='blue', + line_dash=[6,6],line_width=2) + y2means = y1means + + if (xparam != 'time') and (xparam != 'distance'): + plot.add_layout(x1means) + + plot.add_layout(y1means) source = ColumnDataSource( data = dict( @@ -877,9 +921,24 @@ def interactive_cum_flex_chart(theworkouts,promember=0, ) ) + source2 = ColumnDataSource( + data = dict( + x1=x1, + y1=y1, + y2=y2, + time=niceformat(get_datetimes(time,tzinfo=1)), + pace=nicepaceformat(get_datetimes(pace)), + hr = hr, + spm = spm, + spmc=np.rint(10*spm)/10., + distance=distance, + power=power, + ) + ) + # plot.circle('x1','y1',source=source,legend=yparam1,size=3) - plot.circle('x1','y1',source=source,fill_alpha=0.3,line_color=None, + plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None, legend=yparamname1, ) @@ -921,11 +980,17 @@ def interactive_cum_flex_chart(theworkouts,promember=0, plot.circle('x1','y2',color="red",y_range_name="yax2", legend=yparamname2, - source=source,fill_alpha=0.3,line_color=None) + source=source2,fill_alpha=0.3,line_color=None) plot.add_layout(LinearAxis(y_range_name="yax2", axis_label=axlabels[yparam2]),'right') + y2means = Span(location=y2mean,dimension='width',line_color='red', + line_dash=[6,6],line_width=2,y_range_name="yax2") + + + plot.add_layout(y2means) + hover = plot.select(dict(type=HoverTool)) @@ -939,11 +1004,119 @@ def interactive_cum_flex_chart(theworkouts,promember=0, hover.mode = 'mouse' + callback = CustomJS(args = dict(source=source,source2=source2, + x1means=x1means, + y1means=y1means, + y2means=y2means), code=""" + var data = source.data + var data2 = source2.data + var x1 = data['x1'] + var y1 = data['y1'] + var y2 = data['y2'] + var spm1 = data['spm'] + var time1 = data['time'] + var pace1 = data['pace'] + var hr1 = data['hr'] + var spmc1 = data['spmc'] + var distance1 = data['distance'] + var power1 = data['power'] + + var minspm = minspm.value + var maxspm = maxspm.value + var mindist = mindist.value + var maxdist = maxdist.value + var xm = 0 + var ym1 = 0 + var ym2 = 0 + + data2['x1'] = [] + data2['y1'] = [] + data2['y2'] = [] + data2['spm'] = [] + data2['time'] = [] + data2['pace'] = [] + data2['hr'] = [] + data2['spmc'] = [] + data2['distance'] = [] + data2['power'] = [] + data2['x1mean'] = [] + data2['y1mean'] = [] + data2['y2mean'] = [] + data2['xvals'] = [] + data2['y1vals'] = [] + data2['y2vals'] = [] + + for (i=0; i=minspm && spm1[i]<=maxspm) { + if (distance1[i]>=mindist && distance1[i]<=maxdist) { + data2['x1'].push(x1[i]) + data2['y1'].push(y1[i]) + data2['y2'].push(y2[i]) + data2['spm'].push(spm1[i]) + data2['time'].push(time1[i]) + data2['pace'].push(pace1[i]) + data2['hr'].push(hr1[i]) + data2['spmc'].push(spmc1[i]) + data2['distance'].push(distance1[i]) + data2['power'].push(power1[i]) + + xm += x1[i] + ym1 += y1[i] + ym2 += y2[i] + + } + } + } + + xm /= data2['x1'].length + ym1 /= data2['x1'].length + ym2 /= data2['x1'].length + + data2['x1mean'] = [xm,xm] + data2['y1mean'] = [ym1,ym1] + data2['y2mean'] = [ym2,ym2] + x1means.location = xm + y1means.location = ym1 + y2means.location = ym2 + + source2.trigger('change'); + """) + + slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1, + title="Min SPM",callback=callback) + callback.args["minspm"] = slider_spm_min + + + slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1, + title="Max SPM",callback=callback) + callback.args["maxspm"] = slider_spm_max + + distmax = 100+100*int(distance.max()/100.) + + slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, + title="Min Distance",callback=callback) + callback.args["mindist"] = slider_dist_min + + slider_dist_max = Slider(start=0,end=distmax,value=distmax, + step=1, + title="Max Distance",callback=callback) + callback.args["maxdist"] = slider_dist_max + + layout = layoutrow([layoutcolumn([slider_spm_min, + slider_spm_max, + slider_dist_min, + slider_dist_max, + ], + ), + plot]) + + script, div = components(layout) + js_resources = INLINE.render_js() + css_resources = INLINE.render_css() - script, div = components(plot) - return [script,div] + return [script,div,js_resources,css_resources] @@ -1389,7 +1562,6 @@ def interactive_flex_chart2(id=0,promember=0, y2 = y1 if xparam=='time': - xaxmax = x1.max() xaxmin = x1.min() xaxmax = get_datetimes([xaxmax],tzinfo=1)[0] @@ -1574,6 +1746,7 @@ def interactive_flex_chart2(id=0,promember=0, plot.line('x1','y2',color="red",y_range_name="yax2", legend=axlabels[yparam2], source=source2) +<<<<<<< HEAD elif plottype=='scatter': # plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2, @@ -1605,6 +1778,39 @@ def interactive_flex_chart2(id=0,promember=0, hover.mode = 'mouse' +======= + + elif plottype=='scatter': +# plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2, +# source=source,size=3) + plot.scatter('x1','y2',source=source2,legend=axlabels[yparam2] + ,fill_alpha=0.4, + line_color=None,color="red",y_range_name="yax2") + + plot.add_layout(LinearAxis(y_range_name="yax2", + axis_label=axlabels[yparam2]),'right') + + y2means = Span(location=y2mean,dimension='width',line_color='red', + line_dash=[6,6],line_width=2,y_range_name="yax2") + + + plot.add_layout(y2means) + + hover = plot.select(dict(type=HoverTool)) + + + hover.tooltips = OrderedDict([ + ('Time','@time'), + ('Distance','@distance'), + ('Pace','@pace'), + ('HR','@hr'), + ('SPM','@spmc{1.1}'), + ('Power','@power{int}'), + ]) + + hover.mode = 'mouse' + +>>>>>>> feature/sliders callback = CustomJS(args = dict(source=source,source2=source2, x1means=x1means, y1means=y1means, diff --git a/rowers/interactiveplots.pyc b/rowers/interactiveplots.pyc deleted file mode 100644 index 98bd63fe..00000000 Binary files a/rowers/interactiveplots.pyc and /dev/null differ diff --git a/rowers/interactiveplots.py~ b/rowers/interactiveplots.py~ deleted file mode 100644 index 1a7861d7..00000000 --- a/rowers/interactiveplots.py~ +++ /dev/null @@ -1,2246 +0,0 @@ -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage -from rowingdata import rower as rrower -from rowingdata import main as rmain -from rowingdata import cumcpdata,histodata - -from rowingdata import rowingdata as rrdata -from rowingdata import TCXParser,RowProParser,ErgDataParser -from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser - -from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc -from bokeh.models import CustomJS,Slider -from bokeh.charts import Histogram -from bokeh.resources import CDN,INLINE -from bokeh.embed import components -from bokeh.layouts import layout,widgetbox -from bokeh.layouts import row as layoutrow -from bokeh.layouts import column as layoutcolumn -from bokeh.models import LinearAxis,LogAxis,Range1d,DatetimeTickFormatter,HoverTool -from bokeh.io import output_file, show -from bokeh.models import ( - GMapPlot, GMapOptions, ColumnDataSource, Circle, - DataRange1d, PanTool, WheelZoomTool, BoxSelectTool, - SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool, -) -#from bokeh.models.widgets import Slider, Select, TextInput -from bokeh.core.properties import value - -from collections import OrderedDict -from django.conf import settings - -import datetime -import math -import numpy as np -import pandas as pd -from pytz import timezone as tz,utc -from django.utils.timezone import get_current_timezone -from django.utils.timezone import activate -activate(settings.TIME_ZONE) -thetimezone = get_current_timezone() - -from scipy.stats import linregress -from scipy import optimize -from scipy.signal import savgol_filter - -import stravastuff - -def rdata(file,rower=rrower()): - try: - res = rrdata(file,rower=rower) - except IOError: - res = 0 - - return res - - -def tailwind(bearing,vwind,winddir): - """ Calculates head-on head/tailwind in direction of rowing - - positive numbers are tail wind - - """ - - b = np.radians(bearing) - w = np.radians(winddir) - - vtail = -vwind*np.cos(w-b) - - return vtail - -def niceformat(values): - out = [] - for v in values: - formattedv = v.strftime("%H:%M:%S") - out.append(formattedv) - - return out - -def nicepaceformat(values): - out = [] - for v in values: - formattedv = v.strftime("%M:%S.%f") - out.append(formattedv[:-5]) - - - return out - -def get_datetimes(seconds,tzinfo=0): - out = [] - for second in seconds: - if (second<=0) or (second>1e9): - days = 0 - hours = 0 - minutes=0 - sec=0 - microsecond = 0 - elif math.isnan(second): - days = 0 - hours = 0 - minutes=0 - sec=0 - microsecond = 0 - else: - days = int(second/(24.*3600.)) % (24*3600) - hours = int((second-24.*3600.*days)/3600.) % 24 - - minutes = int((second-3600.*(hours+24.*days))/60.) % 60 - sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60 - microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec)) - dt = datetime.datetime(2016,5,1,hours,minutes,sec,microsecond) - - if tzinfo: - dt = thetimezone.localize(dt, is_dst=True) - # this is ugly -# dt = dt+datetime.timedelta(hours=1) - out.append(dt) - - - - return out - -def interactive_histoall(theworkouts): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - - therows = [] - for workout in theworkouts: - f1 = workout.csvfilename - rowdata = rdata(f1) - if rowdata != 0: - therows.append(rowdata) - - histopwr = histodata(therows) - # throw out nans - histopwr = histopwr[~np.isinf(histopwr)] - histopwr = histopwr[histopwr > 25] - - plot = Figure(tools=TOOLS,plot_width=900, - toolbar_sticky=False, - toolbar_location="above" - ) - - hist,edges = np.histogram(histopwr,bins=150) - - histsum = np.cumsum(hist) - histsum = 100.*histsum/max(histsum) - - hist_norm = 100.*hist/float(hist.sum()) - - source = ColumnDataSource( - data = dict( - left = edges[:-1], - right = edges[1:], - histsum = histsum, - hist_norm = hist_norm, - ) - ) - - -# plot.quad(top='hist_norm',bottom=0,left=edges[:-1],right=edges[1:]) - plot.quad(top='hist_norm',bottom=0,left='left',right='right',source=source) - - plot.xaxis.axis_label = "Power (W)" - plot.yaxis.axis_label = "% of strokes" - plot.y_range = Range1d(0,1.05*max(hist_norm)) - - hover = plot.select(dict(type=HoverTool)) - - hover.tooltips = OrderedDict([ - ('Power(W)','@left{int}'), - ('% of strokes','@hist_norm'), - ('Cumulative %','@histsum{int}'), - ]) - - hover.mode = 'mouse' - - plot.extra_y_ranges = {"fraction": Range1d(start=0,end=105)} - plot.line('right','histsum',source=source,color="red", - y_range_name="fraction") - plot.add_layout(LinearAxis(y_range_name="fraction", - axis_label="Cumulative % of strokes"),'right') - - script, div = components(plot) - return [script,div] - -def googlemap_chart(lat,lon,name=""): - # plot tools - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' - - map_options = GMapOptions(lat = lat.mean(),lng=lon.mean(), - map_type="roadmap",zoom=11) - - plot = GMapPlot( - x_range=DataRange1d(), y_range=DataRange1d(), - map_options=map_options, - api_key = "AIzaSyAgu1w9QSthaGPMLp8y9JedPoMc9sfEgJ8", - plot_width=400,plot_height=400, - toolbar_sticky=False, - - ) - - - source = ColumnDataSource( - data = dict( - lat=lat, - lon=lon, - ) - ) - - circle = Circle(x="lon",y="lat",size=5,fill_color="blue", - fill_alpha=0.2,line_color=None) - plot.add_glyph(source,circle) - plot.add_tools(PanTool(), WheelZoomTool(), - SaveTool(), ResizeTool(), ResetTool(), - TapTool(),CrosshairTool(), - ) - plot.title.text = name - plot.title.text_font="1.0em" - script, div = components(plot) - - return [script,div] - - -def interactive_cpchart(thedistances,thesecs,theavpower, - theworkouts,promember=0): - - message = 0 - # plot tools - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - - x_axis_type = 'log' - y_axis_type = 'linear' - - velo = thedistances/thesecs - p = 500./velo - - p2 = get_datetimes(p) - - source = ColumnDataSource( - data = dict( - dist = thedistances, - duration = thesecs, - spm = 0*theavpower, - tim = niceformat(get_datetimes(thesecs,tzinfo=1)), - power = theavpower, - pace = nicepaceformat(p2), - ) - ) - - # fitting the data to Paul - if len(thedistances)>=2: - paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p) - else: - paulslope = 5.0/np.log10(2.0) - paulintercept = p[0]-paulslope*np.log10(thedistances[0]) - - fitx = np.arange(100)*2*max(np.log10(thedistances))/100. - - fitp = paulslope*fitx+paulintercept - - fitvelo = 500./fitp - fitpower = 2.8*(fitvelo**3) - fitt = 10**fitx/fitvelo - fitp2 = get_datetimes(fitp) - - - sourcepaul = ColumnDataSource( - data = dict( - dist = 10**fitx, - duration = fitt, - power = fitpower, - spm = 0*fitpower, - tim = niceformat(get_datetimes(fitt,tzinfo=1)), - pace = nicepaceformat(fitp2), - ) - ) - - # fitting the data to simple CP model -# simpleslope, simpleintercept,r,p,stderr = linregress(1./thesecs,theavpower) - -# fitx = 1.e-4+np.arange(10000)/10000. -# fitpower = simpleslope*fitx+simpleintercept -# fitvelo = (fitpower/2.8)**(1./3.) -# fitt = 1./fitx -# fitdist = fitt*fitvelo -# fitp = 500./fitvelo -# fitp2 = get_datetimes(fitp) - -# sourcesimple = ColumnDataSource( -# data = dict( -# dist = fitdist, -# duration = fitt, -# power = fitpower, -# tim = niceformat(get_datetimes(fitt)), -# pace = nicepaceformat(fitp2), -# ) -# ) - - # fitting the data to three parameter CP model - fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3])) - errfunc = lambda pars,x,y: fitfunc(pars,x)-y - - p0 = [500,350,10,8000] - - p1 = p0 - if len(thesecs)>=4: - p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) - else: - factor = fitfunc(p0,thesecs.mean())/theavpower.mean() - p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] - - - fitt = 10**(4*np.arange(100)/100.) - - fitpower = fitfunc(p1,fitt) - - message = "" - if len(fitpower[fitpower<0]) > 0: - message = "CP model fit didn't give correct results" - - fitvelo = (fitpower/2.8)**(1./3.) - fitdist = fitt*fitvelo - fitp = 500./fitvelo - fitp2 = get_datetimes(fitp) - - sourcecomplex = ColumnDataSource( - data = dict( - dist = fitdist, - duration = fitt, - tim = niceformat(get_datetimes(fitt,tzinfo=1)), - spm = 0*fitpower, - power = fitpower, - pace = nicepaceformat(fitp2), - ) - ) - - - - # making the plot - plot = Figure(tools=TOOLS,x_axis_type=x_axis_type, - plot_width=900, - toolbar_location="above", - toolbar_sticky=False) - plot.circle('duration','power',source=source,fill_color='red',size=15, - legend='Power') - plot.xaxis.axis_label = "Duration (seconds)" - plot.yaxis.axis_label = "Power (W)" - - therows = [] - for workout in theworkouts: - f1 = workout.csvfilename - rowdata = rdata(f1) - if rowdata != 0: - therows.append(rowdata) - - cpdata = cumcpdata(therows) - - velo = cpdata['Distance']/cpdata['Delta'] - - p = 500./velo - - p2 = get_datetimes(p) - - source2 = ColumnDataSource( - data = dict( - duration = cpdata['Delta'], - power = cpdata['CP'], - tim = niceformat(get_datetimes(cpdata['Delta'],tzinfo=1)), - dist = cpdata['Distance'], - pace = nicepaceformat(p2), - ) - ) - - plot.circle('duration','power',source=source2, - fill_color='blue',size=3, - legend = 'Power from segments') - -# for workout in theworkouts: -# f1 = workout.csvfilename -# rowdata = rdata(f1) -# cpdata = rowdata.getcp() - -# source2 = ColumnDataSource( -# data = dict( -# duration = cpdata['Delta'], -# power = cpdata['CP'], -# dist = cpdata['Distance'], -# ) -# ) - -# plot.circle('duration','power',source=source2,fill_color='blue',size=3) - - - hover = plot.select(dict(type=HoverTool)) - - hover.tooltips = OrderedDict([ - ('Duration ','@tim'), - ('Power (W)','@power{int}'), - ('Distance (m)','@dist{int}'), - ('Pace (/500m)','@pace'), - ]) - - hover.mode = 'mouse' - - plot.y_range = Range1d(0,1.5*max(theavpower)) - plot.x_range = Range1d(1,2*max(thesecs)) - plot.legend.orientation = "vertical" - -# plot.extra_y_ranges = {"distance": Range1d(start=0, -# end=1.1*max(thedistances))} -# plot.circle('duration','dist',source=source,fill_color='white',size=15, -# legend='Distance', -# y_range_name="distance") -# plot.line('duration','dist',source=sourcepaul,y_range_name="distance") -# plot.line('duration','dist',source=sourcesimple,legend="Simple CP model", -# color='red',y_range_name="distance") -# plot.line('duration','dist',source=sourcecomplex,legend="Simple CP model", -# color='green',y_range_name="distance") -# plot.add_layout(LinearAxis(y_range_name="distance", -# axis_label="Distance (m)"),'right') - - plot.line('duration','power',source=sourcepaul,legend="Paul's Law") -# plot.line('duration','power',source=sourcesimple,legend="Simple CP model", -# color='red') - plot.line('duration','power',source=sourcecomplex,legend="CP Model", - color='green') - - - script, div = components(plot) - - return [script,div,paulslope,paulintercept,p1,message] - -def interactive_windchart(id=0,promember=0): - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - - f1 = row.csvfilename - - # create interactive plot - plot = Figure(plot_width=400,plot_height=300) - # get user - # u = User.objects.get(id=row.user.id) - r = row.user - u = r.user - - - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return 0 - - dist = rowdata.df.ix[:,'cum_dist'] - - try: - vwind = rowdata.df.ix[:,'vwind'] - winddirection = rowdata.df.ix[:,'winddirection'] - bearing = rowdata.df.ix[:,'bearing'] - except KeyError: - rowdata.add_wind(0,0) - rowdata.add_bearing() - vwind = rowdata.df.ix[:,'vwind'] - winddirection = rowdata.df.ix[:,'winddirection'] - bearing = rowdata.df.ix[:,'winddirection'] - rowdata.write_csv(f1) - - winddirection = winddirection % 360 - winddirection = (winddirection + 360) % 360 - - tw = tailwind(bearing,vwind,1.0*winddirection) - - - source = ColumnDataSource( - data = dict( - dist=dist, - vwind=vwind, - tw=tw, - winddirection=winddirection, - ) - ) - - # plot tools - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' - - - - # making the plot - plot = Figure(tools=TOOLS,plot_width=400,height=500, -# toolbar_location="below", - toolbar_sticky=False, - ) - plot.line('dist','vwind',source=source,legend="Wind Speed (m/s)") - plot.line('dist','tw',source=source,legend="Tail (+)/Head (-) Wind (m/s)",color='black') - plot.title.text = row.name - # plot.title.text_font_size=value("1.0em") - plot.title.text_font="1.0em" - plot.xaxis.axis_label = "Distance (m)" - plot.yaxis.axis_label = "Wind Speed (m/s)" - plot.y_range = Range1d(-7,7) - - - plot.extra_y_ranges = {"winddirection": Range1d(start=0,end=360)} - plot.line('dist','winddirection',source=source, - legend='Wind Direction',color="red", - y_range_name="winddirection") - plot.add_layout(LinearAxis(y_range_name="winddirection",axis_label="Wind Direction (degree)"),'right') - - - script, div = components(plot) - - return [script,div] - -def interactive_streamchart(id=0,promember=0): - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - - f1 = row.csvfilename - - # create interactive plot - plot = Figure(plot_width=400, - ) - # get user - # u = User.objects.get(id=row.user.id) - r = row.user - u = r.user - - - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return "","CSV Data File Not Found" - - dist = rowdata.df.ix[:,'cum_dist'] - - try: - vstream = rowdata.df.ix[:,'vstream'] - except KeyError: - rowdata.add_stream(0) - vstream = rowdata.df.ix[:,'vstream'] - rowdata.write_csv(f1) - - # plot tools - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' - - - - # making the plot - plot = Figure(tools=TOOLS,plot_width=400,height=500, -# toolbar_location="below", - toolbar_sticky=False, - ) - plot.line(dist,vstream,legend="River Stream Velocity (m/s)") - plot.title.text = row.name - plot.title.text_font_size=value("1.0em") - plot.xaxis.axis_label = "Distance (m)" - plot.yaxis.axis_label = "River Current (m/s)" - plot.y_range = Range1d(-2,2) - - - script, div = components(plot) - - return [script,div] - -def interactive_chart(id=0,promember=0): - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - - f1 = row.csvfilename - - # create interactive plot - # get user - # u = User.objects.get(id=row.user.id) - r = row.user - u = r.user - - - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return "","CSV Data File Not Found" - - t = rowdata.df.ix[:,'TimeStamp (sec)'] - t = t-rowdata.df.ix[0,'TimeStamp (sec)'] - - row_index = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] > 3000 - rowdata.df.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000. - - p = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] - hr = rowdata.df.ix[:,' HRCur (bpm)'] - spm = rowdata.df.ix[:,' Cadence (stokes/min)'] - cumdist = rowdata.df.ix[:,'cum_dist'] - - f = rowdata.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - if windowsize > 3: - spm = savgol_filter(spm,windowsize,3) - - - - - t2 = get_datetimes(t,tzinfo=1) - - # p[p>3000] = 3000. - - p2 = get_datetimes(p) - - source = ColumnDataSource( - data = dict( - x=t2, - y=hr, - y2=p2, - tf = niceformat(t2), - pace = nicepaceformat(p2), - heartrate = hr, - spm=spm, - spmc=np.rint(10*spm)/10., - cumdist=cumdist, - ) - ) - - - - plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - plot_width=400, - plot_height=400, - toolbar_sticky=False, -# toolbar_location="below", - tools=TOOLS) - - # plot.line(t2,p2,legend="Pace") - plot.line('x','y2',source=source,legend="Pace") - plot.title.text = row.name - plot.title.text_font_size=value("1.0em") - plot.xaxis.axis_label = "Time" - plot.yaxis.axis_label = "Pace (/500m)" - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,2,30) - - if row.workouttype == 'water': - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,3,30) - - plot.y_range = Range1d(ymin,ymax) - - - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@tf'), - ('Pace','@pace'), - ('HR','@heartrate'), - ('SPM','@spmc{1.1}'), - ('Distance','@cumdist{1.1}'), - ]) - - hover.mode = 'mouse' - - plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)} - # plot.line(t2,hr,color="red",y_range_name="hr",legend="Heart Rate") - plot.line('x','y',source=source,color="red", - y_range_name="hr", legend="Heart Rate") - plot.add_layout(LinearAxis(y_range_name="hr",axis_label="HR"),'right') - - plot.legend.location = "bottom_right" - - script, div = components(plot) - - return [script,div] - -def interactive_cum_flex_chart(theworkouts,promember=0, - xparam='spm', - yparam1='power', - yparam2='hr', - ): - - - therows = [] - for workout in theworkouts: - f1 = workout.csvfilename - rowdata = rdata(f1) - if rowdata != 0: - therows.append(rowdata.df) - - thedata = pd.concat(therows) - - csvcolumns = { - 'time': 'TimeStamp (sec)', - 'distance': 'cum_dist', - 'hr': ' HRCur (bpm)', - 'spm': ' Cadence (stokes/min)', - 'pace': ' Stroke500mPace (sec/500m)', - 'power': ' Power (watts)', - 'averageforce': ' AverageDriveForce (lbs)', - 'drivelength': ' DriveLength (meters)', - 'peakforce': ' PeakDriveForce (lbs)', - 'driveenergy': 'driveenergy', - 'drivespeed': 'drivespeed', - } - - axlabels = { - 'time': 'Time', - 'distance': 'Distance (m)', - 'hr': 'Heart Rate (bpm)', - 'spm': 'Stroke Rate (spm)', - 'pace': 'Pace (/500m)', - 'power': 'Power (Watt)', - 'averageforce': 'Average Drive Force (lbs)', - 'drivelength': 'Drive Length (m)', - 'peakforce': 'Peak Drive Force (lbs)', - 'driveenergy': 'Work per Stroke (J)', - 'drivespeed': 'Drive Speed (m/s)', - 'None': '', - } - - yparamname1 = axlabels[yparam1] - yparamname2 = axlabels[yparam2] - - yaxminima = { - 'hr':100, - 'spm':15, - 'pace': datetime.datetime(2016,5,1,0,3,30), - 'power': 0, - 'averageforce': 0, - 'peakforce': 0, - 'drivelength':0.5, - 'driveenergy': 0, - 'drivespeed': 0, - } - - yaxmaxima = { - 'hr':200, - 'spm':45, - 'pace':datetime.datetime(2016,5,1,0,1,30), - 'power': 600, - 'averageforce':200, - 'peakforce':400, - 'drivelength':2.0, - 'driveenergy': 1000, - 'drivespeed':4, - } - - - thedata['driveenergy'] = thedata[' DriveLength (meters)']*thedata[' AverageDriveForce (lbs)']*4.44822 - - spm = thedata.ix[:,csvcolumns['spm']] - - f = thedata['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - if windowsize > 3: - spm = savgol_filter(spm,windowsize,3) - - thedata[' Cadence (stokes/min)'] = spm - - drivelength = thedata[' DriveLength (meters)'] - if windowsize > 3: - drivelength = savgol_filter(drivelength,windowsize,3) - thedata[' DriveLength (meters)'] = drivelength - - thedata['drivespeed'] = drivelength/thedata[' DriveTime (ms)']*1.0e3 - - # get user - # u = User.objects.get(id=row.user.id) - - x1 = thedata.ix[:,csvcolumns[xparam]] - - y1 = thedata.ix[:,csvcolumns[yparam1]] - if yparam2 != 'None': - y2 = thedata.ix[:,csvcolumns[yparam2]] - else: - y2 = y1 - - - if xparam=='time': - xaxmax = get_datetimes([x1.max()])[0] - xaxmin = get_datetimes([x1.min()])[0] - x1 = get_datetimes(x1,tzinfo=1) - - x_axis_type = 'linear' - y_axis_type = 'linear' - if xparam == 'time': - x_axis_type = 'datetime' - - if yparam1 == 'pace': - y_axis_type = 'datetime' - y1 = get_datetimes(y1) - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,2,30) - - - time = thedata.ix[:,csvcolumns['time']] - time = time-time[0] - - hr = thedata.ix[:,csvcolumns['hr']] - if windowsize > 3: - hr = savgol_filter(hr,windowsize,3) - - - pace = thedata.ix[:,csvcolumns['pace']] - - distance = thedata.ix[:,csvcolumns['distance']] - - power = thedata.ix[:,csvcolumns['power']] - - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - plot_width=900, - tools=TOOLS, - toolbar_location="above", - toolbar_sticky=False) - - - source = ColumnDataSource( - data = dict( - x1=x1, - y1=y1, - y2=y2, - time=niceformat(get_datetimes(time,tzinfo=1)), - pace=nicepaceformat(get_datetimes(pace)), - hr = hr, - spm = spm, - spmc=np.rint(10*spm)/10., - distance=distance, - power=power, - ) - ) - - - # plot.circle('x1','y1',source=source,legend=yparam1,size=3) - plot.circle('x1','y1',source=source,fill_alpha=0.3,line_color=None, - legend=yparamname1, - ) - - plot.xaxis.axis_label = axlabels[xparam] - plot.yaxis.axis_label = axlabels[yparam1] - - - yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) - plot.y_range = yrange1 - - if (xparam != 'time') and (xparam != 'distance'): - xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) - plot.x_range = xrange1 - - if xparam == 'time': - xrange1 = Range1d(start=xaxmin,end=xaxmax) - plot.x_range = xrange1 - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - - - - if yparam1 == 'pace': - plot.y_range = Range1d(ymin,ymax) - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) - - if yparam2 != 'None': - yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) - plot.extra_y_ranges = {"yax2": yrange2} - - plot.circle('x1','y2',color="red",y_range_name="yax2", - legend=yparamname2, - source=source,fill_alpha=0.3,line_color=None) - - plot.add_layout(LinearAxis(y_range_name="yax2", - axis_label=axlabels[yparam2]),'right') - - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@time'), - ('Pace','@pace'), - ('HR','@hr'), - ('SPM','@spmc{1.1}'), - ('Power','@power{int}'), - ]) - - hover.mode = 'mouse' - - - - script, div = components(plot) - - return [script,div] - - - -def interactive_flex_chart(id=0,promember=0, - xparam='time', - yparam1='pace', - yparam2='hr', - plottype='line', - workstrokesonly=False): - - csvcolumns = { - 'time': 'TimeStamp (sec)', - 'distance': 'cum_dist', - 'hr': ' HRCur (bpm)', - 'spm': ' Cadence (stokes/min)', - 'pace': ' Stroke500mPace (sec/500m)', - 'power': ' Power (watts)', - 'averageforce': ' AverageDriveForce (lbs)', - 'drivelength': ' DriveLength (meters)', - 'peakforce': ' PeakDriveForce (lbs)', - 'driveenergy': 'driveenergy', - 'drivespeed': 'drivespeed', - } - - axlabels = { - 'time': 'Time', - 'distance': 'Distance (m)', - 'hr': 'Heart Rate (bpm)', - 'spm': 'Stroke Rate (spm)', - 'pace': 'Pace (/500m)', - 'power': 'Power (Watt)', - 'averageforce': 'Average Drive Force (lbs)', - 'drivelength': 'Drive Length (m)', - 'peakforce': 'Peak Drive Force (lbs)', - 'driveenergy': 'Work per Stroke (J)', - 'drivespeed': 'Drive Speed (m/s)', - 'None': '', - } - - yaxminima = { - 'hr':100, - 'spm':15, - 'pace': datetime.datetime(2016,5,1,0,3,30), - 'power': 0, - 'averageforce': 0, - 'peakforce': 0, - 'drivelength':0.5, - 'driveenergy': 0, - 'drivespeed': 0, - } - - yaxmaxima = { - 'hr':200, - 'spm':45, - 'pace':datetime.datetime(2016,5,1,0,1,30), - 'power': 600, - 'averageforce':200, - 'peakforce':400, - 'drivelength':2.0, - 'driveenergy': 1000, - 'drivespeed':4, - } - - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - - f1 = row.csvfilename - - r = row.user - u = r.user - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return "","CSV Data File Not Found" - - workoutstateswork = [1,4,5,8,9,6,7] - workoutstatesrest = [3] - workoutstatetransition = [0,2,10,11,12,13] - - if workstrokesonly: - try: - rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)] - except KeyError: - pass - - - rowdata.df['driveenergy'] = rowdata.df[' DriveLength (meters)']*rowdata.df[' AverageDriveForce (lbs)']*4.44822 - - f = rowdata.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - spm = rowdata.df.ix[:,csvcolumns['spm']] - hr = rowdata.df.ix[:,csvcolumns['hr']] - - - if windowsize > 3: - spm = savgol_filter(spm,windowsize,3) - hr = savgol_filter(hr,windowsize,3) - - rowdata.df[' Cadence (stokes/min)'] = spm - rowdata.df[' HRCur (bpm)'] = hr - - drivelength = rowdata.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength = savgol_filter(drivelength,windowsize,3) - - rowdata.df[' DriveLength (meters)'] = drivelength - - rowdata.df['drivespeed'] = drivelength/rowdata.df[' DriveTime (ms)']*1.0e3 - - # get user - # u = User.objects.get(id=row.user.id) - - x1 = rowdata.df.ix[:,csvcolumns[xparam]] - - y1 = rowdata.df.ix[:,csvcolumns[yparam1]] - - - if yparam2 != 'None': - y2 = rowdata.df.ix[:,csvcolumns[yparam2]] - else: - y2 = y1 - - if xparam=='time': - - xaxmax = x1.max() - xaxmin = x1.min() - xaxmax = get_datetimes([xaxmax],tzinfo=1)[0] - xaxmin = get_datetimes([xaxmin],tzinfo=1)[0] - x1 = get_datetimes(x1,tzinfo=1) - - if xparam=='distance': - xaxmax = x1.max() - xaxmin = x1.min() - - # average values - y1mean = y1.median()+0.0*np.arange(100) - y2mean = y2.median()+0.0*np.arange(100) - if xparam != 'time': - x1mean = x1.median()+0.0*np.arange(100) - else: - x1mean = 0+0.0*np.arange(100) - - - - if xparam != 'time' and xparam != 'distance' and yparam1 != 'pace': - xvals = yaxminima[xparam]+np.arange(100)*(yaxmaxima[xparam]-yaxminima[xparam])/100. - y1vals = yaxminima[yparam1]+np.arange(100)*(yaxmaxima[yparam1]-yaxminima[yparam1])/100. - else: - xvals = np.arange(100) - y1vals = np.arange(100) - - - - # constant power plot - if yparam1 == 'driveenergy': - if xparam == 'spm': - yconstantpower = y1.median()*x1.median()/xvals - - - - - x_axis_type = 'linear' - y_axis_type = 'linear' - if xparam == 'time': - x_axis_type = 'datetime' - - if yparam1 == 'pace': - y_axis_type = 'datetime' - y1 = get_datetimes(y1) - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,2,30) - - if row.workouttype == 'water': - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,3,30) - - time = rowdata.df.ix[:,csvcolumns['time']] - time = time-time[time.index[0]] - - hr = rowdata.df.ix[:,csvcolumns['hr']] - - - pace = rowdata.df.ix[:,csvcolumns['pace']] - - distance = rowdata.df.ix[:,csvcolumns['distance']] - - power = rowdata.df.ix[:,csvcolumns['power']] - - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - toolbar_sticky=False, - plot_width=900, - ) - - - source = ColumnDataSource( - data = dict( - x1=x1, - y1=y1, - y2=y2, - time=niceformat(get_datetimes(time,tzinfo=1)), - pace=nicepaceformat(get_datetimes(pace)), - hr = hr, - spm = spm, - spmc=np.rint(10*spm)/10., - distance=distance, - power=power, - xvals=xvals, - y1mean=y1mean, - x1mean=x1mean, - y1vals=y1vals, - ) - ) - - - # average values - plot.line('xvals','y1mean',color="black",source=source) - plot.line('x1mean','y1vals',color="black",source=source) - if yparam1 == 'driveenergy': - if xparam == 'spm': - plot.line(xvals,yconstantpower,color="green",legend="Constant Power") - - if plottype=='line': - plot.line('x1','y1',source=source,legend=axlabels[yparam1]) - elif plottype=='scatter': -# plot.circle('x1','y1',source=source,legend=yparam1,size=3) - plot.scatter('x1','y1',source=source,legend=axlabels[yparam1],fill_alpha=0.4, - line_color=None) - - plot.title.text = row.name - plot.title.text_font_size=value("1.0em") - plot.xaxis.axis_label = axlabels[xparam] - plot.yaxis.axis_label = axlabels[yparam1] - - - yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) - plot.y_range = yrange1 - - if (xparam != 'time') and (xparam != 'distance'): - xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) - plot.x_range = xrange1 - - if xparam == 'time': - xrange1 = Range1d(start=xaxmin,end=xaxmax) - plot.x_range = xrange1 - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - - - if yparam1 == 'pace': - plot.y_range = Range1d(ymin,ymax) - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) - - if yparam2 != 'None': - yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) - plot.extra_y_ranges = {"yax2": yrange2} - plot.line(xvals,y2mean,color="black",y_range_name="yax2") - - if plottype=='line': - plot.line('x1','y2',color="red",y_range_name="yax2", - legend=axlabels[yparam2], - source=source) - - elif plottype=='scatter': -# plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2, -# source=source,size=3) - plot.scatter('x1','y2',source=source,legend=axlabels[yparam2] - ,fill_alpha=0.4, - line_color=None,color="red",y_range_name="yax2") - - plot.add_layout(LinearAxis(y_range_name="yax2", - axis_label=axlabels[yparam2]),'right') - - - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@time'), - ('Distance','@distance{int}'), - ('Pace','@pace'), - ('HR','@hr'), - ('SPM','@spmc{1.1}'), - ('Power','@power{int}'), - ]) - - hover.mode = 'mouse' - - - - script, div = components(plot) - - return [script,div] - - -def interactive_flex_chart2(id=0,promember=0, - xparam='time', - yparam1='pace', - yparam2='hr', - plottype='line', - workstrokesonly=False): - - csvcolumns = { - 'time': 'TimeStamp (sec)', - 'distance': 'cum_dist', - 'hr': ' HRCur (bpm)', - 'spm': ' Cadence (stokes/min)', - 'pace': ' Stroke500mPace (sec/500m)', - 'power': ' Power (watts)', - 'averageforce': ' AverageDriveForce (lbs)', - 'drivelength': ' DriveLength (meters)', - 'peakforce': ' PeakDriveForce (lbs)', - 'driveenergy': 'driveenergy', - 'drivespeed': 'drivespeed', - } - - axlabels = { - 'time': 'Time', - 'distance': 'Distance (m)', - 'hr': 'Heart Rate (bpm)', - 'spm': 'Stroke Rate (spm)', - 'pace': 'Pace (/500m)', - 'power': 'Power (Watt)', - 'averageforce': 'Average Drive Force (lbs)', - 'drivelength': 'Drive Length (m)', - 'peakforce': 'Peak Drive Force (lbs)', - 'driveenergy': 'Work per Stroke (J)', - 'drivespeed': 'Drive Speed (m/s)', - 'None': '', - } - - yaxminima = { - 'hr':100, - 'spm':15, - 'pace': datetime.datetime(2016,5,1,0,3,30), - 'power': 0, - 'averageforce': 0, - 'peakforce': 0, - 'drivelength':0.5, - 'driveenergy': 0, - 'drivespeed': 0, - } - - yaxmaxima = { - 'hr':200, - 'spm':45, - 'pace':datetime.datetime(2016,5,1,0,1,30), - 'power': 600, - 'averageforce':200, - 'peakforce':400, - 'drivelength':2.0, - 'driveenergy': 1000, - 'drivespeed':4, - } - - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - - f1 = row.csvfilename - - r = row.user - u = r.user - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return "","CSV Data File Not Found" - - workoutstateswork = [1,4,5,8,9,6,7] - workoutstatesrest = [3] - workoutstatetransition = [0,2,10,11,12,13] - - if workstrokesonly: - try: - rowdata.df = rowdata.df[~rowdata.df[' WorkoutState'].isin(workoutstatesrest)] - except KeyError: - pass - - - rowdata.df['driveenergy'] = rowdata.df[' DriveLength (meters)']*rowdata.df[' AverageDriveForce (lbs)']*4.44822 - - spm = rowdata.df.ix[:,csvcolumns['spm']] - hr = rowdata.df.ix[:,csvcolumns['hr']] - - f = rowdata.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - if windowsize > 3: - spm = savgol_filter(spm,windowsize,3) - hr = savgol_filter(hr,windowsize,3) - - rowdata.df[' Cadence (stokes/min)'] = spm - rowdata.df[' HRCur (bpm)'] = hr - - drivelength = rowdata.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength = savgol_filter(drivelength,windowsize,3) - - rowdata.df[' DriveLength (meters)'] = drivelength - - rowdata.df['drivespeed'] = drivelength/rowdata.df[' DriveTime (ms)']*1.0e3 - - # get user - # u = User.objects.get(id=row.user.id) - - x1 = rowdata.df.ix[:,csvcolumns[xparam]] - - y1 = rowdata.df.ix[:,csvcolumns[yparam1]] - - - if yparam2 != 'None': - y2 = rowdata.df.ix[:,csvcolumns[yparam2]] - else: - y2 = y1 - - if xparam=='time': - - xaxmax = x1.max() - xaxmin = x1.min() - xaxmax = get_datetimes([xaxmax],tzinfo=1)[0] - xaxmin = get_datetimes([xaxmin],tzinfo=1)[0] - x1 = get_datetimes(x1,tzinfo=1) - - if xparam=='distance': - xaxmax = x1.max() - xaxmin = x1.min() - - # average values - y1mean = y1.mean()+0.0*np.arange(100) - y2mean = y2.mean()+0.0*np.arange(100) - if xparam != 'time': - x1mean = x1.mean()+0.0*np.arange(100) - else: - x1mean = 0+0.0*np.arange(100) - - - - if xparam != 'time' and xparam != 'distance' and yparam1 != 'pace': - xvals = yaxminima[xparam]+np.arange(100)*(yaxmaxima[xparam]-yaxminima[xparam])/100. - y1vals = yaxminima[yparam1]+np.arange(100)*(yaxmaxima[yparam1]-yaxminima[yparam1])/100. - else: - xvals = np.arange(100) - y1vals = np.arange(100) - - - - # constant power plot - if yparam1 == 'driveenergy': - if xparam == 'spm': - yconstantpower = y1.median()*x1.median()/xvals - - - - - x_axis_type = 'linear' - y_axis_type = 'linear' - if xparam == 'time': - x_axis_type = 'datetime' - - if yparam1 == 'pace': - y_axis_type = 'datetime' - y1 = get_datetimes(y1) - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,2,30) - - if row.workouttype == 'water': - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,3,30) - - time = rowdata.df.ix[:,csvcolumns['time']] - time = time-time[time.index[0]] - - hr = rowdata.df.ix[:,csvcolumns['hr']] - - - pace = rowdata.df.ix[:,csvcolumns['pace']] - - distance = rowdata.df.ix[:,csvcolumns['distance']] - - power = rowdata.df.ix[:,csvcolumns['power']] - - # prepare data - source = ColumnDataSource( - data = dict( - x1=x1, - y1=y1, - y2=y2, - time=niceformat(get_datetimes(time,tzinfo=1)), - pace=nicepaceformat(get_datetimes(pace)), - hr = hr, - spm = spm, - spmc=np.rint(10*spm)/10., - distance=distance, - power=power, - xvals=xvals, - y1mean=y1mean, - y2mean=y2mean, - x1mean=x1mean, - y1vals=y1vals, - ) - ) - - # second source for filtering - source2 = ColumnDataSource( - data = dict( - x1=x1, - y1=y1, - y2=y2, - time=niceformat(get_datetimes(time,tzinfo=1)), - pace=nicepaceformat(get_datetimes(pace)), - hr = hr, - spm = spm, - spmc=np.rint(10*spm)/10., - distance=distance, - power=power, - xvals=xvals, - y1mean=y1mean, - y2mean=y2mean, - x1mean=x1mean, - y1vals=y1vals, - ) - ) - - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - - - sizing_mode = 'fixed' # 'scale_width' also looks nice with this example - - plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - toolbar_sticky=False, -# plot_width=900, - ) - - - callback = CustomJS(args = dict(source=source,source2=source2), code=""" - var data = source.data - var data2 = source2.data - var x1 = data['x1'] - var y1 = data['y1'] - var y2 = data['y2'] - var spm1 = data['spm'] - var time1 = data['time'] - var pace1 = data['pace'] - var hr1 = data['hr'] - var spmc1 = data['spmc'] - var distance1 = data['distance'] - var power1 = data['power'] - - var minspm = minspm.value - var maxspm = maxspm.value - var mindist = mindist.value - var maxdist = maxdist.value - var xm = 0 - var ym1 = 0 - var ym2 = 0 - - data2['x1'] = [] - data2['y1'] = [] - data2['y2'] = [] - data2['spm'] = [] - data2['time'] = [] - data2['pace'] = [] - data2['hr'] = [] - data2['spmc'] = [] - data2['distance'] = [] - data2['power'] = [] - data2['x1mean'] = [] - data2['y1mean'] = [] - data2['y2mean'] = [] - data2['xvals'] = [] - data2['y1vals'] = [] - data2['y2vals'] = [] - - for (i=0; i=minspm && spm1[i]<=maxspm) { - if (distance1[i]>=mindist && distance1[i]<=maxdist) { - data2['x1'].push(x1[i]) - data2['y1'].push(y1[i]) - data2['y2'].push(y2[i]) - data2['spm'].push(spm1[i]) - data2['time'].push(time1[i]) - data2['pace'].push(pace1[i]) - data2['hr'].push(hr1[i]) - data2['spmc'].push(spmc1[i]) - data2['distance'].push(distance1[i]) - data2['power'].push(power1[i]) - - xm += x1[i] - ym1 += y1[i] - ym2 += y2[i] - } - } - } - - xm /= data2['x1'].length - ym1 /= data2['x1'].length - ym2 /= data2['x1'].length - - data2['x1mean'] = [xm,xm] - data2['y1mean'] = [ym1,ym1] - data2['y2mean'] = [ym2,ym2] - - data2['xvals'] = [0,3e4] - data2['y1vals'] = [0,3e4] - data2['y2vals'] = [0,3e4] - - source2.trigger('change'); - """) - - slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1, - title="Min SPM",callback=callback) - callback.args["minspm"] = slider_spm_min - - - slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1, - title="Max SPM",callback=callback) - callback.args["maxspm"] = slider_spm_max - - distmax = 100+100*int(distance.max()/100.) - - slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, - title="Min Distance",callback=callback) - callback.args["mindist"] = slider_dist_min - - slider_dist_max = Slider(start=0,end=distmax,value=distmax, - step=1, - title="Max Distance",callback=callback) - callback.args["maxdist"] = slider_dist_max - - # average values - plot.line('xvals','y1mean',color="black",source=source2) - plot.line('x1mean','y1vals',color="black",source=source2) - if yparam1 == 'driveenergy': - if xparam == 'spm': - plot.line(xvals,yconstantpower,color="green",legend="Constant Power") - - if plottype=='line': - plot.line('x1','y1',source=source2,legend=axlabels[yparam1]) - elif plottype=='scatter': -# plot.circle('x1','y1',source=source2,legend=yparam1,size=3) - plot.scatter('x1','y1',source=source2,legend=axlabels[yparam1],fill_alpha=0.4, - line_color=None) - - plot.title.text = row.name - plot.title.text_font_size=value("1.0em") - plot.xaxis.axis_label = axlabels[xparam] - plot.yaxis.axis_label = axlabels[yparam1] - - - yrange1 = Range1d(start=yaxminima[yparam1],end=yaxmaxima[yparam1]) - plot.y_range = yrange1 - - if (xparam != 'time') and (xparam != 'distance'): - xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) - plot.x_range = xrange1 - - if xparam == 'time': - xrange1 = Range1d(start=xaxmin,end=xaxmax) - plot.x_range = xrange1 - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - - - if yparam1 == 'pace': - plot.y_range = Range1d(ymin,ymax) - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) - - if yparam2 != 'None': - yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) - plot.extra_y_ranges = {"yax2": yrange2} - plot.line('xvals','y2mean',color="black",y_range_name="yax2", - source=source2) - - if plottype=='line': - plot.line('x1','y2',color="red",y_range_name="yax2", - legend=axlabels[yparam2], - source=source2) - - elif plottype=='scatter': -# plot.circle(x1,y2,color="red",y_range_name="yax2",legend=yparam2, -# source=source,size=3) - plot.scatter('x1','y2',source=source2,legend=axlabels[yparam2] - ,fill_alpha=0.4, - line_color=None,color="red",y_range_name="yax2") - - plot.add_layout(LinearAxis(y_range_name="yax2", - axis_label=axlabels[yparam2]),'right') - - - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@time'), - ('Distance','@distance'), - ('Pace','@pace'), - ('HR','@hr'), - ('SPM','@spmc{1.1}'), - ('Power','@power{int}'), - ]) - - hover.mode = 'mouse' - - layout = layoutrow([layoutcolumn([slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, - ], - ), - plot]) - - script, div = components(layout) - js_resources = INLINE.render_js() - css_resources = INLINE.render_css() - - - - return [script,div,js_resources,css_resources] - - -def interactive_bar_chart(id=0,promember=0): - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - - f1 = row.csvfilename - - # create interactive plot - plot = Figure(plot_width=400,plot_height=300) - # get user - # u = User.objects.get(id=row.user.id) - r = row.user - u = r.user - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return "","CSV Data File Not Found" - - t = rowdata.df.ix[:,'TimeStamp (sec)'] - t = t-rowdata.df.ix[0,'TimeStamp (sec)'] - - row_index = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] > 3000 - rowdata.df.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000. - - - p = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] - hr = rowdata.df.ix[:,' HRCur (bpm)'] - spm = rowdata.df.ix[:,' Cadence (stokes/min)'] - f = rowdata.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - if windowsize > 3: - spm = savgol_filter(spm,windowsize,3) - rowdata.df[' Cadence (stokes/min)'] = spm - drivelength = rowdata.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength = savgol_filter(drivelength,windowsize,3) - rowdata.df[' DriveLength (meters)'] = drivelength - - hr_ut2 = rowdata.df.ix[:,'hr_ut2'] - hr_ut1 = rowdata.df.ix[:,'hr_ut1'] - hr_at = rowdata.df.ix[:,'hr_at'] - hr_tr = rowdata.df.ix[:,'hr_tr'] - hr_an = rowdata.df.ix[:,'hr_an'] - hr_max = rowdata.df.ix[:,'hr_max'] - - # time increments for bar chart - time_increments = rowdata.df.ix[:,' ElapsedTime (sec)'].diff() - time_increments[0] = time_increments[1] - time_increments = 0.5*time_increments+0.5*np.abs(time_increments) - - - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - t2 = get_datetimes(t,tzinfo=1) - p2 = get_datetimes(p) - - source = ColumnDataSource( - data = dict( - x=t2, - x_right = get_datetimes(t+time_increments,tzinfo=1), - hr=hr, - hr_ut2=hr_ut2, - hr_ut1=hr_ut1, - hr_at=hr_at, - hr_tr=hr_tr, - hr_an=hr_an, - hr_max=hr_max, - hr_bottom = 0.0*hr, - y2=p2, - tf = niceformat(t2), - pace = nicepaceformat(p2), - heartrate = hr, - spmc=np.rint(10*spm)/10., - spm=spm, - ) - ) - - - plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - toolbar_sticky=False, - plot_width=920, -# toolbar_location="above", - tools=TOOLS) - plot.title.text = row.name - plot.title.text_font_size=value("1.0em") - plot.xaxis.axis_label = "Time" - plot.yaxis.axis_label = "Pace (/500m)" - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours ="", - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] -) - - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"], -) - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,2,30) - - if row.workouttype == 'water': - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,3,30) - - plot.y_range = Range1d(ymin,ymax) - - - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('Time','@tf'), - ('Pace','@pace'), - ('HR','@heartrate'), - ('SPM','@spmc{1.1}'), - ]) - - hover.mode = 'mouse' - - plot.extra_y_ranges = {"hr": Range1d(start=100,end=200)} - plot.quad(left='x',top='hr_ut2',bottom='hr_bottom', - right='x_right',source=source,color="gray", - y_range_name="hr", legend=" 3: - spm1 = savgol_filter(spm1,windowsize,3) - rowdata1.df[' Cadence (stokes/min)'] = spm1 - drivelength1 = rowdata1.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength1 = savgol_filter(drivelength1,windowsize,3) - rowdata1.df[' DriveLength (meters)'] = drivelength1 - - drivelength2 = rowdata2.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength2 = savgol_filter(drivelength2,windowsize,3) - rowdata2.df[' DriveLength (meters)'] = drivelength2 - - - f = rowdata2.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - if windowsize > 3: - spm2 = savgol_filter(spm2,windowsize,3) - rowdata2.df[' Cadence (stokes/min)'] = spm2 - drivelength2 = rowdata2.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength2 = savgol_filter(drivelength2,windowsize,3) - rowdata2.df[' DriveLength (meters)'] = drivelength2 - - rowdata1.df['drivespeed'] = drivelength1/rowdata1.df[' DriveTime (ms)']*1.0e3 - rowdata2.df['drivespeed'] = drivelength2/rowdata2.df[' DriveTime (ms)']*1.0e3 - - - x1 = rowdata1.df.ix[:,csvcolumns[xparam]] - x2 = rowdata2.df.ix[:,csvcolumns[xparam]] - - y1 = rowdata1.df.ix[:,csvcolumns[yparam]] - y2 = rowdata2.df.ix[:,csvcolumns[yparam]] - - if xparam=='time': - x1 = x1-x1[0] - x2 = x2-x2[0] - x1 = get_datetimes(x1,tzinfo=1) - x2 = get_datetimes(x2,tzinfo=1) - - x_axis_type = 'linear' - y_axis_type = 'linear' - if xparam == 'time': - x_axis_type = 'datetime' - - if yparam == 'pace': - y_axis_type = 'datetime' - y1 = get_datetimes(y1) - y2 = get_datetimes(y2) - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,2,30) - - if row1.workouttype == 'water': - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,3,30) - - time1 = rowdata1.df.ix[:,csvcolumns['time']] - time2 = rowdata2.df.ix[:,csvcolumns['time']] - - time1 = time1-time1[0] - time2 = time2-time2[0] - - hr1 = rowdata1.df.ix[:,csvcolumns['hr']] - hr2 = rowdata2.df.ix[:,csvcolumns['hr']] - - - pace1 = rowdata1.df.ix[:,csvcolumns['pace']] - pace2 = rowdata2.df.ix[:,csvcolumns['pace']] - - distance1 = rowdata1.df.ix[:,csvcolumns['distance']] - distance2 = rowdata2.df.ix[:,csvcolumns['distance']] - - - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - - - source = ColumnDataSource( - data = dict( - x1=x1, - x2=x2, - y1=y1, - y2=y2, - time1=niceformat(get_datetimes(time1,tzinfo=1)), - time2=niceformat(get_datetimes(time2,tzinfo=1)), - pace1=nicepaceformat(get_datetimes(pace1)), - pace2=nicepaceformat(get_datetimes(pace2)), - hr1 = hr1, - hr2 = hr2, - spm1 = spm1, - spm2 = spm2, - spm1c=np.rint(10*spm1)/10., - spm2c=np.rint(10*spm2)/10., - distance1=distance1, - distance2=distance2, - ) - ) - - - - # create interactive plot - plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - plot_width=920, - # toolbar_location="above", - toolbar_sticky=False) - - - # plot.multi_line([x1,x2],[y1,y2],color=["blue","red"]) - if plottype=='line': - plot.line('x1','y1',source=source,color="blue",legend=row1.name) - plot.line('x2','y2',source=source,color="red",legend=row2.name) - elif plottype=='scatter': -# plot.circle('x1','y1',source=source,color="blue",legend=row1.name,size=3) -# plot.circle('x2','y2',source=source,color="red",legend=row2.name,size=3) - plot.scatter('x1','y1',source=source,legend=row1.name,fill_alpha=0.4, - line_color=None) - plot.scatter('x2','y2',source=source,legend=row2.name,fill_alpha=0.4, - line_color=None,color="red") - - - - - - # plot.scatter('x1','y1',source=source,color="blue") - # plot.scatter('x2','y2',source=source,color="red") - - plot.legend.location = "bottom_right" - - plot.title.text = row1.name+' vs '+row2.name - plot.title.text_font_size=value("1.2em") - plot.xaxis.axis_label = axlabels[xparam] - plot.yaxis.axis_label = axlabels[yparam] - - if xparam == 'time': - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - - - if yparam == 'pace': - plot.y_range = Range1d(ymin,ymax) - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) - - - #hover = [t for t in plot.tools if isinstance(t, HoverTool)][0] - hover = plot.select(dict(type=HoverTool)) - - - hover.tooltips = OrderedDict([ - ('time1','@time1'), - ('time2','@time2'), - ('pace1','@pace1'), - ('pace2','@pace2'), - ('hr1','@hr1'), - ('hr2','@hr2'), - ('spm1','@spm1c{1.1}'), - ('spm2','@spm2c{1.1}'), - ('distance1','@distance1{5}'), - ('distance2','@distance2{5}'), - ]) - - hover.mode = 'mouse' - - script, div = components(plot) - - return [script,div] - -def interactive_otw_advanced_pace_chart(id=0,promember=0): - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - - f1 = row.csvfilename - - - # get user - # u = User.objects.get(id=row.user.id) - r = row.user - u = r.user - - rowdata = rdata(f1) - if rowdata == 0: - return "","CSV Data File Not Found" - - t = rowdata.df.ix[:,'TimeStamp (sec)'] - t = t-rowdata.df.ix[0,'TimeStamp (sec)'] - - - row_index = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] > 3000 - rowdata.df.loc[row_index,' Stroke500mPace (sec/500m)'] = 3000. - - - p = rowdata.df.ix[:,' Stroke500mPace (sec/500m)'] - try: - nowindpace = rowdata.df.ix[:,'nowindpace'] - except KeyError: - nowindpace = p - try: - equivergpower = rowdata.df.ix[:,'equivergpower'] - except KeyError: - equivergpower = 0*p+50. - - ergvelo = (equivergpower/2.8)**(1./3.) - - # ergvelo = stravastuff.ewmovingaverage(ergvelo,25) - - ergpace = 500./ergvelo - ergpace[ergpace == np.inf] = 240. - - hr = rowdata.df.ix[:,' HRCur (bpm)'] - spm = rowdata.df.ix[:,' Cadence (stokes/min)'] - - f = rowdata.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - if windowsize > 3: - spm = savgol_filter(spm,windowsize,3) - rowdata.df[' Cadence (stokes/min)'] = spm - drivelength = rowdata.df[' DriveLength (meters)'] - if windowsize > 3: - drivelength = savgol_filter(drivelength,windowsize,3) - rowdata.df[' DriveLength (meters)'] = drivelength - - t2 = get_datetimes(t,tzinfo=1) - p2 = get_datetimes(p) - nowindp2 = get_datetimes(nowindpace) - ergpace2 = get_datetimes(ergpace) - - # Add hover to this comma-separated string and see what changes - if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' - - source = ColumnDataSource( - data = dict( - x=t2, - p=p2, - nowindp2 = nowindp2, - ergpace2 = ergpace2, - tf = niceformat(t2), - pace = nicepaceformat(p2), - ergpace = nicepaceformat(ergpace2), - nowindpace = nicepaceformat(nowindp2), - heartrate = hr, - spm=spm, - spmc=np.rint(10*spm)/10., - ) - ) - - plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - tools=TOOLS, - plot_width=920, - toolbar_sticky=False) - - plot.title.text = row.name - plot.title.text_font_size=value("1.2em") - plot.xaxis.axis_label = "Time" - plot.yaxis.axis_label = "Pace (/500m)" - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) - - ymax = datetime.datetime(2016,5,1,0,1,30) - ymin = datetime.datetime(2016,5,1,0,3,30) - - plot.y_range = Range1d(ymin,ymax) - - - hover = plot.select(dict(type=HoverTool)) - - plot.line('x','p',source=source,legend="Pace",color="black") - plot.line('x','nowindp2',source=source,legend="Corrected Pace",color="red") - plot.line('x','ergpace2',source=source,legend="Equivalent Erg Pace",color="blue") - - hover.tooltips = OrderedDict([ - ('Time','@tf'), - ('Pace','@pace'), - ('Corrected Pace','@nowindpace'), - ('Equiv. Erg Pace','@ergpace'), - ('HR','@heartrate'), - ('SPM','@spmc{1.1}'), - ]) - - hover.mode = 'mouse' - - script, div = components(plot) - - return [script,div] - diff --git a/rowers/mailprocessing.pyc b/rowers/mailprocessing.pyc deleted file mode 100644 index 628c8af6..00000000 Binary files a/rowers/mailprocessing.pyc and /dev/null differ diff --git a/rowers/mailprocessing.py~ b/rowers/mailprocessing.py~ deleted file mode 100644 index e39c7402..00000000 --- a/rowers/mailprocessing.py~ +++ /dev/null @@ -1,225 +0,0 @@ -import time -from django.conf import settings -from rowers.tasks import handle_sendemail_unrecognized -from django_mailbox.models import Mailbox,Message,MessageAttachment -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage,AdvancedWorkoutForm -from django.core.files.base import ContentFile - -from rowsandall_app.settings import BASE_DIR - -from rowingdata import rower as rrower -from rowingdata import main as rmain -from rowingdata import rowingdata as rrdata -from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR -from rowingdata import MysteryParser -from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser -from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata -from rowingdata import make_cumvalues -from rowingdata import summarydata,get_file_type - -from scipy.signal import savgol_filter - -def rdata(file,rower=rrower()): - try: - res = rrdata(file,rower=rower) - except IOError: - res = 0 - - return res - -def safeprocessattachments(): - try: - return processattachments() - except: - return [0] - -def processattachments(): - res = [] - attachments = MessageAttachment.objects.all() - for a in attachments: - donotdelete = 0 - m = Message.objects.get(id=a.message_id) - from_address = m.from_address[0] - name = m.subject - - # get a list of users - theusers = User.objects.filter(email=from_address) - for u in theusers: - try: - rr = Rower.objects.get(user=u.id) - # move attachment and make workout - try: - res += [make_new_workout_from_email(rr,a.document,name)] - except: - # replace with code to process error - res += ['fail: '+name] - donotdelete = 1 - except Rower.DoesNotExist: - pass - - - # remove attachment - if donotdelete == 0: - a.delete() - - if m.attachments.exists()==False: - # no attachments, so can be deleted - m.delete() - - mm = Message.objects.all() - for m in mm: - if m.attachments.exists()==False: - m.delete() - - return res - -def make_new_workout_from_email(rr,f2,name): - workouttype = 'rower' - f2 = f2.name - fileformat = get_file_type('media/'+f2) - if fileformat == 'unknown': - if settings.DEBUG: - res = handle_sendemail_unrecognized.delay(f2, - "roosendaalsander@gmail.com") - - else: - res = queuehigh.enqueue(handle_sendemail_unrecognized, - f2,"roosendaalsander@gmail.com") - - return 0 - - summary = '' - # handle non-Painsled - if (fileformat != 'csv'): - # handle RowPro: - if (fileformat == 'rp'): - row = RowProParser('media/'+f2) - - # handle TCX - if (fileformat == 'tcx'): - row = TCXParser('media/'+f2) - - # handle Mystery - if (fileformat == 'mystery'): - row = MysteryParser('media/'+f2) - - # handle TCX no HR - if (fileformat == 'tcxnohr'): - row = TCXParserNoHR('media/'+f2) - - # handle ErgData - if (fileformat == 'ergdata'): - row = ErgDataParser('media/'+f2) - - # handle painsled desktop - if (fileformat == 'painsleddesktop'): - row = painsledDesktopParser('media/'+f2) - - # handle speed coach GPS - if (fileformat == 'speedcoach'): - row = speedcoachParser('media/'+f2) - - # handle speed coach GPS 2 - if (fileformat == 'speedcoach2'): - row = SpeedCoach2Parser('media/'+f2) - - # handle ErgStick - if (fileformat == 'ergstick'): - row = ErgStickParser('media/'+f2) - - # handle FIT - if (fileformat == 'fit'): - row = FITParser('media/'+f2) - s = fitsummarydata('media/'+f2) - s.setsummary() - summary = s.summarytext - - timestr = time.strftime("%Y%m%d-%H%M%S") - filename = timestr+'o.csv' - row.write_csv('media/'+filename) - f2 = filename - - # make workout and put in database - #r = rrower(hrmax=rr.max,hrut2=rr.ut2, - # hrut1=rr.ut1,hrat=rr.at, - # hrtr=rr.tr,hran=rr.an) - row = rdata('media/'+f2) #,rower=r) - if row == 0: - return 0 - - # change filename - if f2[:5] != 'media': - timestr = time.strftime("%Y%m%d-%H%M%S") - f2 = 'media/'+timestr+'o.csv' - - # auto smoothing - pace = row.df[' Stroke500mPace (sec/500m)'].values - velo = 500./pace - - f = row.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - - if not 'originalvelo' in row.df: - row.df['originalvelo'] = velo - - if windowsize > 3: - velo2 = savgol_filter(velo,windowsize,3) - else: - velo2 = velo - - pace2 = 500./abs(velo2) - row.df[' Stroke500mPace (sec/500m)'] = pace2 - - row.df = row.df.fillna(0) - - row.write_csv(f2) - - # recalculate power data - if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides': - try: - row.erg_recalculatepower() - # row.spm_fromtimestamps() - row.write_csv(f2) - except: - pass - - if fileformat != 'fit': - summary = row.summary() - summary += '\n' - summary += row.intervalstats_painsled() - - averagehr = row.df[' HRCur (bpm)'].mean() - maxhr = row.df[' HRCur (bpm)'].max() - - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - 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) - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - notes = 'imported through email' - - w = Workout(user=rr,name=name,date=workoutdate, - workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=rr.weightcategory, - starttime=workoutstarttime, - csvfilename=f2,notes=notes,summary=summary, - maxhr=maxhr,averagehr=averagehr, - startdatetime=row.rowdatetime) - - w.save() - return 1 - - - diff --git a/rowers/management/commands/__init__.pyc b/rowers/management/commands/__init__.pyc deleted file mode 100644 index 6e12a359..00000000 Binary files a/rowers/management/commands/__init__.pyc and /dev/null differ diff --git a/rowers/management/commands/processemail.pyc b/rowers/management/commands/processemail.pyc deleted file mode 100644 index 9e91284a..00000000 Binary files a/rowers/management/commands/processemail.pyc and /dev/null differ diff --git a/rowers/management/commands/processemail.py~ b/rowers/management/commands/processemail.py~ deleted file mode 100644 index 196fcb17..00000000 --- a/rowers/management/commands/processemail.py~ +++ /dev/null @@ -1,236 +0,0 @@ -#!/srv/venv/bin/python -import sys -import os -# If you find a solution that does not need the two paths, please comment! -sys.path.append('$path_to_root_of_project$') -sys.path.append('$path_to_root_of_project$/$project_name$') - -os.environ['DJANGO_SETTINGS_MODULE'] = '$project_name$.settings' - -from django.core.management.base import BaseCommand, CommandError -from django.conf import settings -#from rowers.mailprocessing import processattachments -import time -from django.conf import settings -from rowers.tasks import handle_sendemail_unrecognized -from django_mailbox.models import Mailbox,Message,MessageAttachment -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage,AdvancedWorkoutForm -from django.core.files.base import ContentFile - -from rowsandall_app.settings import BASE_DIR - -from rowingdata import rower as rrower -from rowingdata import main as rmain -from rowingdata import rowingdata as rrdata -from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR -from rowingdata import MysteryParser -from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser -from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata -from rowingdata import make_cumvalues -from rowingdata import summarydata,get_file_type - -from scipy.signal import savgol_filter - -def rdata(file,rower=rrower()): - try: - res = rrdata(file,rower=rower) - except IOError: - res = 0 - - return res - -def make_new_workout_from_email(rr,f2,name): - workouttype = 'rower' - f2 = f2.name - fileformat = get_file_type('media/'+f2) - if fileformat == 'unknown': - if settings.DEBUG: - res = handle_sendemail_unrecognized.delay(f2, - "roosendaalsander@gmail.com") - - else: - res = queuehigh.enqueue(handle_sendemail_unrecognized, - f2,"roosendaalsander@gmail.com") - - return 0 - - summary = '' - # handle non-Painsled - if (fileformat != 'csv'): - # handle RowPro: - if (fileformat == 'rp'): - row = RowProParser('media/'+f2) - - # handle TCX - if (fileformat == 'tcx'): - row = TCXParser('media/'+f2) - - # handle Mystery - if (fileformat == 'mystery'): - row = MysteryParser('media/'+f2) - - # handle TCX no HR - if (fileformat == 'tcxnohr'): - row = TCXParserNoHR('media/'+f2) - - # handle ErgData - if (fileformat == 'ergdata'): - row = ErgDataParser('media/'+f2) - - # handle painsled desktop - if (fileformat == 'painsleddesktop'): - row = painsledDesktopParser('media/'+f2) - - # handle speed coach GPS - if (fileformat == 'speedcoach'): - row = speedcoachParser('media/'+f2) - - # handle speed coach GPS 2 - if (fileformat == 'speedcoach2'): - row = SpeedCoach2Parser('media/'+f2) - - # handle ErgStick - if (fileformat == 'ergstick'): - row = ErgStickParser('media/'+f2) - - # handle FIT - if (fileformat == 'fit'): - row = FITParser('media/'+f2) - s = fitsummarydata('media/'+f2) - s.setsummary() - summary = s.summarytext - - timestr = time.strftime("%Y%m%d-%H%M%S") - filename = timestr+'o.csv' - row.write_csv('media/'+filename) - f2 = filename - - # make workout and put in database - #r = rrower(hrmax=rr.max,hrut2=rr.ut2, - # hrut1=rr.ut1,hrat=rr.at, - # hrtr=rr.tr,hran=rr.an) - row = rdata('media/'+f2) #,rower=r) - if row == 0: - return 0 - - # change filename - if f2[:5] != 'media': - timestr = time.strftime("%Y%m%d-%H%M%S") - f2 = 'media/'+timestr+'o.csv' - - # auto smoothing - pace = row.df[' Stroke500mPace (sec/500m)'].values - velo = 500./pace - - f = row.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - - if not 'originalvelo' in row.df: - row.df['originalvelo'] = velo - - if windowsize > 3: - velo2 = savgol_filter(velo,windowsize,3) - else: - velo2 = velo - - pace2 = 500./abs(velo2) - row.df[' Stroke500mPace (sec/500m)'] = pace2 - - row.df = row.df.fillna(0) - - row.write_csv(f2) - - # recalculate power data - if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides': - try: - row.erg_recalculatepower() - # row.spm_fromtimestamps() - row.write_csv(f2) - except: - pass - - if fileformat != 'fit': - summary = row.summary() - summary += '\n' - summary += row.intervalstats_painsled() - - averagehr = row.df[' HRCur (bpm)'].mean() - maxhr = row.df[' HRCur (bpm)'].max() - - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - 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) - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - notes = 'imported through email' - - w = Workout(user=rr,name=name,date=workoutdate, - workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=rr.weightcategory, - starttime=workoutstarttime, - csvfilename=f2,notes=notes,summary=summary, - maxhr=maxhr,averagehr=averagehr, - startdatetime=row.rowdatetime) - - w.save() - return 1 - - - - -class Command(BaseCommand): - def handle(self, *args, **options): - res = [] - attachments = MessageAttachment.objects.all() - for a in attachments: - donotdelete = 0 - m = Message.objects.get(id=a.message_id) - from_address = m.from_address[0] - name = m.subject - - # get a list of users - theusers = User.objects.filter(email=from_address) - for u in theusers: - try: - rr = Rower.objects.get(user=u.id) - # move attachment and make workout - try: - res += [make_new_workout_from_email(rr,a.document,name)] - except: - # replace with code to process error - res += ['fail: '+name] - donotdelete = 1 - except Rower.DoesNotExist: - pass - - - # remove attachment - if donotdelete == 0: - a.delete() - - if m.attachments.exists()==False: - # no attachments, so can be deleted - m.delete() - - mm = Message.objects.all() - for m in mm: - if m.attachments.exists()==False: - m.delete() - - self.stdout.write(self.style.SUCCESS('Successfully processed email attachments')) - - - - diff --git a/rowers/migrations/0001_initial.pyc b/rowers/migrations/0001_initial.pyc deleted file mode 100644 index 46e5d13b..00000000 Binary files a/rowers/migrations/0001_initial.pyc and /dev/null differ diff --git a/rowers/migrations/0002_auto_20160426_1043.pyc b/rowers/migrations/0002_auto_20160426_1043.pyc deleted file mode 100644 index 10dd9065..00000000 Binary files a/rowers/migrations/0002_auto_20160426_1043.pyc and /dev/null differ diff --git a/rowers/migrations/0003_auto_20160426_1048.pyc b/rowers/migrations/0003_auto_20160426_1048.pyc deleted file mode 100644 index c0abc97e..00000000 Binary files a/rowers/migrations/0003_auto_20160426_1048.pyc and /dev/null differ diff --git a/rowers/migrations/0004_auto_20160426_1441.pyc b/rowers/migrations/0004_auto_20160426_1441.pyc deleted file mode 100644 index 8de2554e..00000000 Binary files a/rowers/migrations/0004_auto_20160426_1441.pyc and /dev/null differ diff --git a/rowers/migrations/0005_auto_20160426_1446.pyc b/rowers/migrations/0005_auto_20160426_1446.pyc deleted file mode 100644 index 8394ecf7..00000000 Binary files a/rowers/migrations/0005_auto_20160426_1446.pyc and /dev/null differ diff --git a/rowers/migrations/0006_auto_20160427_1350.pyc b/rowers/migrations/0006_auto_20160427_1350.pyc deleted file mode 100644 index fa3e7c4d..00000000 Binary files a/rowers/migrations/0006_auto_20160427_1350.pyc and /dev/null differ diff --git a/rowers/migrations/0007_auto_20160428_1153.pyc b/rowers/migrations/0007_auto_20160428_1153.pyc deleted file mode 100644 index 3886d3b2..00000000 Binary files a/rowers/migrations/0007_auto_20160428_1153.pyc and /dev/null differ diff --git a/rowers/migrations/0008_auto_20160428_1154.pyc b/rowers/migrations/0008_auto_20160428_1154.pyc deleted file mode 100644 index 1dd08499..00000000 Binary files a/rowers/migrations/0008_auto_20160428_1154.pyc and /dev/null differ diff --git a/rowers/migrations/0009_auto_20160428_1955.pyc b/rowers/migrations/0009_auto_20160428_1955.pyc deleted file mode 100644 index e01b2e5e..00000000 Binary files a/rowers/migrations/0009_auto_20160428_1955.pyc and /dev/null differ diff --git a/rowers/migrations/0010_workout_distance.pyc b/rowers/migrations/0010_workout_distance.pyc deleted file mode 100644 index 8404dc7e..00000000 Binary files a/rowers/migrations/0010_workout_distance.pyc and /dev/null differ diff --git a/rowers/migrations/0011_auto_20160428_2009.pyc b/rowers/migrations/0011_auto_20160428_2009.pyc deleted file mode 100644 index 15a51bae..00000000 Binary files a/rowers/migrations/0011_auto_20160428_2009.pyc and /dev/null differ diff --git a/rowers/migrations/0012_auto_20160428_2010.pyc b/rowers/migrations/0012_auto_20160428_2010.pyc deleted file mode 100644 index ad6f21c3..00000000 Binary files a/rowers/migrations/0012_auto_20160428_2010.pyc and /dev/null differ diff --git a/rowers/migrations/0013_auto_20160428_2021.pyc b/rowers/migrations/0013_auto_20160428_2021.pyc deleted file mode 100644 index 88f611c7..00000000 Binary files a/rowers/migrations/0013_auto_20160428_2021.pyc and /dev/null differ diff --git a/rowers/migrations/0014_auto_20160428_2251.pyc b/rowers/migrations/0014_auto_20160428_2251.pyc deleted file mode 100644 index b9cd5787..00000000 Binary files a/rowers/migrations/0014_auto_20160428_2251.pyc and /dev/null differ diff --git a/rowers/migrations/0015_auto_20160429_2038.pyc b/rowers/migrations/0015_auto_20160429_2038.pyc deleted file mode 100644 index 2971c08d..00000000 Binary files a/rowers/migrations/0015_auto_20160429_2038.pyc and /dev/null differ diff --git a/rowers/migrations/0016_auto_20160501_1119.pyc b/rowers/migrations/0016_auto_20160501_1119.pyc deleted file mode 100644 index e6c556e3..00000000 Binary files a/rowers/migrations/0016_auto_20160501_1119.pyc and /dev/null differ diff --git a/rowers/migrations/0017_auto_20160501_1126.pyc b/rowers/migrations/0017_auto_20160501_1126.pyc deleted file mode 100644 index e69b67fb..00000000 Binary files a/rowers/migrations/0017_auto_20160501_1126.pyc and /dev/null differ diff --git a/rowers/migrations/0018_auto_20160501_1944.pyc b/rowers/migrations/0018_auto_20160501_1944.pyc deleted file mode 100644 index ca8002a6..00000000 Binary files a/rowers/migrations/0018_auto_20160501_1944.pyc and /dev/null differ diff --git a/rowers/migrations/0019_auto_20160522_1659.pyc b/rowers/migrations/0019_auto_20160522_1659.pyc deleted file mode 100644 index 90afe19a..00000000 Binary files a/rowers/migrations/0019_auto_20160522_1659.pyc and /dev/null differ diff --git a/rowers/migrations/0020_auto_20160522_1726.pyc b/rowers/migrations/0020_auto_20160522_1726.pyc deleted file mode 100644 index 0b706ffa..00000000 Binary files a/rowers/migrations/0020_auto_20160522_1726.pyc and /dev/null differ diff --git a/rowers/migrations/0021_rower_rowerplan.pyc b/rowers/migrations/0021_rower_rowerplan.pyc deleted file mode 100644 index 1d656773..00000000 Binary files a/rowers/migrations/0021_rower_rowerplan.pyc and /dev/null differ diff --git a/rowers/migrations/0022_auto_20160529_2115.pyc b/rowers/migrations/0022_auto_20160529_2115.pyc deleted file mode 100644 index 9625c498..00000000 Binary files a/rowers/migrations/0022_auto_20160529_2115.pyc and /dev/null differ diff --git a/rowers/migrations/0023_auto_20160530_0914.pyc b/rowers/migrations/0023_auto_20160530_0914.pyc deleted file mode 100644 index 7f3f4d26..00000000 Binary files a/rowers/migrations/0023_auto_20160530_0914.pyc and /dev/null differ diff --git a/rowers/migrations/0024_workout_uploadedtostrava.pyc b/rowers/migrations/0024_workout_uploadedtostrava.pyc deleted file mode 100644 index 14194594..00000000 Binary files a/rowers/migrations/0024_workout_uploadedtostrava.pyc and /dev/null differ diff --git a/rowers/migrations/0025_workout_summary.pyc b/rowers/migrations/0025_workout_summary.pyc deleted file mode 100644 index f78d2706..00000000 Binary files a/rowers/migrations/0025_workout_summary.pyc and /dev/null differ diff --git a/rowers/migrations/0026_auto_20160608_2137.pyc b/rowers/migrations/0026_auto_20160608_2137.pyc deleted file mode 100644 index 64d1fe6c..00000000 Binary files a/rowers/migrations/0026_auto_20160608_2137.pyc and /dev/null differ diff --git a/rowers/migrations/0027_workout_uploadedtosporttracks.pyc b/rowers/migrations/0027_workout_uploadedtosporttracks.pyc deleted file mode 100644 index 50b24abb..00000000 Binary files a/rowers/migrations/0027_workout_uploadedtosporttracks.pyc and /dev/null differ diff --git a/rowers/migrations/0028_rower_sporttrackstoken.pyc b/rowers/migrations/0028_rower_sporttrackstoken.pyc deleted file mode 100644 index 1b85e5ba..00000000 Binary files a/rowers/migrations/0028_rower_sporttrackstoken.pyc and /dev/null differ diff --git a/rowers/migrations/0029_auto_20160610_0825.pyc b/rowers/migrations/0029_auto_20160610_0825.pyc deleted file mode 100644 index f094d4f8..00000000 Binary files a/rowers/migrations/0029_auto_20160610_0825.pyc and /dev/null differ diff --git a/rowers/migrations/0030_auto_20160610_0826.pyc b/rowers/migrations/0030_auto_20160610_0826.pyc deleted file mode 100644 index 2e4a5470..00000000 Binary files a/rowers/migrations/0030_auto_20160610_0826.pyc and /dev/null differ diff --git a/rowers/migrations/0031_auto_20160610_0843.pyc b/rowers/migrations/0031_auto_20160610_0843.pyc deleted file mode 100644 index e737df1c..00000000 Binary files a/rowers/migrations/0031_auto_20160610_0843.pyc and /dev/null differ diff --git a/rowers/migrations/0032_auto_20160615_1332.pyc b/rowers/migrations/0032_auto_20160615_1332.pyc deleted file mode 100644 index 28f0c678..00000000 Binary files a/rowers/migrations/0032_auto_20160615_1332.pyc and /dev/null differ diff --git a/rowers/migrations/0033_auto_20160617_0927.pyc b/rowers/migrations/0033_auto_20160617_0927.pyc deleted file mode 100644 index 90e839b8..00000000 Binary files a/rowers/migrations/0033_auto_20160617_0927.pyc and /dev/null differ diff --git a/rowers/migrations/0034_auto_20160617_0929.pyc b/rowers/migrations/0034_auto_20160617_0929.pyc deleted file mode 100644 index f3ccd9e7..00000000 Binary files a/rowers/migrations/0034_auto_20160617_0929.pyc and /dev/null differ diff --git a/rowers/migrations/0035_auto_20160623_0815.pyc b/rowers/migrations/0035_auto_20160623_0815.pyc deleted file mode 100644 index 9c0f47fc..00000000 Binary files a/rowers/migrations/0035_auto_20160623_0815.pyc and /dev/null differ diff --git a/rowers/migrations/0036_rower_team.pyc b/rowers/migrations/0036_rower_team.pyc deleted file mode 100644 index 0ea77bd3..00000000 Binary files a/rowers/migrations/0036_rower_team.pyc and /dev/null differ diff --git a/rowers/migrations/0037_auto_20160629_1014.pyc b/rowers/migrations/0037_auto_20160629_1014.pyc deleted file mode 100644 index 892a89c2..00000000 Binary files a/rowers/migrations/0037_auto_20160629_1014.pyc and /dev/null differ diff --git a/rowers/migrations/0038_auto_20160629_1023.pyc b/rowers/migrations/0038_auto_20160629_1023.pyc deleted file mode 100644 index 99cc565c..00000000 Binary files a/rowers/migrations/0038_auto_20160629_1023.pyc and /dev/null differ diff --git a/rowers/migrations/0039_auto_20160719_2240.pyc b/rowers/migrations/0039_auto_20160719_2240.pyc deleted file mode 100644 index 7d6b9238..00000000 Binary files a/rowers/migrations/0039_auto_20160719_2240.pyc and /dev/null differ diff --git a/rowers/migrations/0040_workout_startdatetime.pyc b/rowers/migrations/0040_workout_startdatetime.pyc deleted file mode 100644 index 3939afae..00000000 Binary files a/rowers/migrations/0040_workout_startdatetime.pyc and /dev/null differ diff --git a/rowers/migrations/0041_rower_friends.pyc b/rowers/migrations/0041_rower_friends.pyc deleted file mode 100644 index fd14121e..00000000 Binary files a/rowers/migrations/0041_rower_friends.pyc and /dev/null differ diff --git a/rowers/migrations/__init__.pyc b/rowers/migrations/__init__.pyc deleted file mode 100644 index 749ae9a7..00000000 Binary files a/rowers/migrations/__init__.pyc and /dev/null differ diff --git a/rowers/models.pyc b/rowers/models.pyc deleted file mode 100644 index b65aa8dc..00000000 Binary files a/rowers/models.pyc and /dev/null differ diff --git a/rowers/models.py~ b/rowers/models.py~ deleted file mode 100644 index f9c9f72e..00000000 --- a/rowers/models.py~ +++ /dev/null @@ -1,301 +0,0 @@ -from __future__ import unicode_literals - -from django.db import models -from django.contrib.auth.models import User -from django import forms -from django.forms import ModelForm -from django.dispatch import receiver -from django.forms.widgets import SplitDateTimeWidget -from datetimewidget.widgets import DateTimeWidget -import os - -# Create your models here. - -class Team(models.Model): - name = models.CharField(max_length=150) - notes = models.CharField(blank=True,max_length=200) - - -class Rower(models.Model): - weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) - user = models.OneToOneField(User) - max = models.IntegerField(default=192,verbose_name="Max Heart Rate") - rest = models.IntegerField(default=48,verbose_name="Resting Heart Rate") - ut2 = models.IntegerField(default=105,verbose_name="UT2 band lower HR") - ut1 = models.IntegerField(default=146,verbose_name="UT1 band lower HR") - at = models.IntegerField(default=160,verbose_name="AT band lower HR") - tr = models.IntegerField(default=167,verbose_name="TR band lower HR") - an = models.IntegerField(default=180,verbose_name="AN band lower HR") - weightcategory = models.CharField(default="hwt", - max_length=30, - choices=weightcategories) - - c2token = models.CharField(default='',max_length=200,blank=True,null=True) - tokenexpirydate = models.DateTimeField(blank=True,null=True) - c2refreshtoken = models.CharField(default='',max_length=200,blank=True,null=True) - sporttrackstoken = models.CharField(default='',max_length=200,blank=True,null=True) - sporttrackstokenexpirydate = models.DateTimeField(blank=True,null=True) - sporttracksrefreshtoken = models.CharField(default='',max_length=200, - blank=True,null=True) - stravatoken = models.CharField(default='',max_length=200,blank=True,null=True) - - plans = ( - ('basic','basic'), - ('pro','pro'), - ('coach','coach') - ) - rowerplan = models.CharField(default='basic',max_length=30, - choices=plans) - friends = models.ManyToManyField("self") - - team = models.ForeignKey(Team,blank=True,null=True) - - - def __str__(self): - return self.user.username - -class Workout(models.Model): - workouttypes = ( - ('water','On-water'), - ('rower','Indoor Rower'), - ('skierg','Ski Erg'), - ('dynamic','Dynamic Indoor Rower'), - ('slides','Indoor Rower on Slides'), - ('paddle','Paddle Adapter'), - ('snow','On-snow'), - ) - - boattypes = ( - ('1x', '1x (single)'), - ('2x', '2x (double)'), - ('2-', '2- (pair)'), - ('4x', '4x (quad)'), - ('4-', '4- (four)'), - ('8+', '8+ (eight)'), - ) - - user = models.ForeignKey(Rower) - team = models.ForeignKey(Team,blank=True,null=True) - name = models.CharField(max_length=150) - date = models.DateField() - workouttype = models.CharField(choices=workouttypes,max_length=50) - boattype = models.CharField(choices=boattypes,max_length=50, - default='1x (single)', - verbose_name = 'Boat Type') - starttime = models.TimeField(blank=True,null=True) - startdatetime = models.DateTimeField(blank=True,null=True) - distance = models.IntegerField(default=0,blank=True) - duration = models.TimeField(default=1,blank=True) - weightcategory = models.CharField(default="hwt",max_length=10) - weightvalue = models.FloatField(default=80.0,blank=True,verbose_name = 'Average Crew Weight (kg)') - csvfilename = models.CharField(blank=True,max_length=150) - uploadedtoc2 = models.IntegerField(default=0) - averagehr = models.IntegerField(blank=True,null=True) - maxhr = models.IntegerField(blank=True,null=True) - uploadedtostrava = models.IntegerField(default=0) - uploadedtosporttracks = models.IntegerField(default=0) - notes = models.CharField(blank=True,max_length=200) - summary = models.TextField(blank=True) - - def __str__(self): - - date = self.date - name = self.name - - str = date.strftime('%Y-%m-%d')+'_'+name - - return str - -# delete files belonging to workout instance -# related GraphImage objects should be deleted automatically -@receiver(models.signals.post_delete,sender=Workout) -def auto_delete_file_on_delete(sender, instance, **kwargs): - # delete CSV file - if instance.csvfilename: - if os.path.isfile(instance.csvfilename): - os.remove(instance.csvfilename) - - - -class GraphImage(models.Model): - filename = models.CharField(default='',max_length=150,blank=True,null=True) - creationdatetime = models.DateTimeField() - workout = models.ForeignKey(Workout) - - def __str__(self): - return self.filename - -# delete related file object -@receiver(models.signals.post_delete,sender=GraphImage) -def auto_delete_image_on_delete(sender,instance, **kwargs): - if instance.filename: - if os.path.isfile(instance.filename): - os.remove(instance.filename) - else: - print "couldn't find the file "+instance.filename - - -class DateInput(forms.DateInput): - input_type = 'date' - - -class WorkoutForm(ModelForm): - duration = forms.TimeInput(format='%H:%M:%S.%f') - class Meta: - model = Workout - fields = ['name','date','starttime','duration','distance','workouttype','notes'] - widgets = { - 'date': DateInput(), - 'notes': forms.Textarea, - 'duration': forms.TimeInput(format='%H:%M:%S.%f'), - } - -class AdvancedWorkoutForm(ModelForm): - class Meta: - model = Workout - fields = ['boattype','weightvalue'] - - -class RowerForm(ModelForm): - class Meta: - model = Rower - fields = ['rest','ut2','ut1','at','tr','an','max','weightcategory'] - - - def clean_rest(self): - rest = self.cleaned_data['rest'] - - if rest<10: - self.data['rest']=10 - raise forms.ValidationError("Resting heart rate should be higher than 10 bpm") - - - if rest>250: - self.data['rest'] = 250 - raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") - - - return rest - - def clean_ut2(self): - ut2 = self.cleaned_data['ut2'] - - if ut2<10: - raise forms.ValidationError("UT2 heart rate should be higher than 10 bpm") - - if ut2>250: - raise forms.ValidationError("UT2 heart rate should be lower than 250 bpm") - - return ut2 - - def clean_ut1(self): - ut1 = self.cleaned_data['ut1'] - - if ut1<10: - raise forms.ValidationError("UT1 heart rate should be higher than 10 bpm") - - if ut1>250: - raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") - - return ut1 - - def clean_at(self): - at = self.cleaned_data['at'] - - if at<10: - raise forms.ValidationError("AT heart rate should be higher than 10 bpm") - - if at>250: - raise forms.ValidationError("AT heart rate should be lower than 250 bpm") - - return at - - def clean_tr(self): - tr = self.cleaned_data['tr'] - - if tr<10: - raise forms.ValidationError("TR heart rate should be higher than 10 bpm") - - if tr>250: - raise forms.ValidationError("TR heart rate should be lower than 250 bpm") - - return tr - - def clean_an(self): - an = self.cleaned_data['an'] - - if an<10: - raise forms.ValidationError("AN heart rate should be higher than 10 bpm") - - if an>250: - raise forms.ValidationError("AN heart rate should be lower than 250 bpm") - - return an - - def clean_max(self): - max = self.cleaned_data['max'] - - if max<10: - raise forms.ValidationError("Max heart rate should be higher than 10 bpm") - - if max>250: - raise forms.ValidationError("Max heart rate should be lower than 250 bpm") - - return max - - - def clean(self): - - - try: - rest = self.cleaned_data['rest'] - except: - rest = int(self.data['rest']) - - try: - ut2 = self.cleaned_data['ut2'] - except: - ut2 = self.data['ut2'] - - try: - ut1 = self.cleaned_data['ut1'] - except: - ut1 = self.data['ut1'] - - try: - at = self.cleaned_data['at'] - except: - at = self.data['at'] - - try: - an = self.cleaned_data['an'] - except: - an = self.data['an'] - - try: - tr = self.cleaned_data['tr'] - except: - tr = self.data['tr'] - - try: - max = self.cleaned_data['max'] - except: - max = self.data['max'] - - if rest>=ut2: - raise forms.ValidationError("Resting heart rate should be lower than UT2") - if ut2>=ut1: - raise forms.ValidationError("UT2 should be lower than UT1") - if ut2>=ut1: - raise forms.ValidationError("UT2 should be lower than UT1") - if ut1>=at: - raise forms.ValidationError("UT1 should be lower than AT") - if at>=tr: - raise forms.ValidationError("AT should be lower than TR") - if tr>=an: - raise forms.ValidationError("TR should be lower than AN") - if an>=max: - raise forms.ValidationError("AN should be lower than Max") diff --git a/rowers/plots.pyc b/rowers/plots.pyc deleted file mode 100644 index 8e00daea..00000000 Binary files a/rowers/plots.pyc and /dev/null differ diff --git a/rowers/plots.py~ b/rowers/plots.py~ deleted file mode 100644 index 0ea1b6be..00000000 --- a/rowers/plots.py~ +++ /dev/null @@ -1,133 +0,0 @@ -from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter -import matplotlib.pyplot as plt - -import numpy as np - -def format_pace_tick(x,pos=None): - min=int(x/60) - sec=int(x-min*60.) - sec_str=str(sec).zfill(2) - template='%d:%s' - return template % (min,sec_str) - -def format_pace(x,pos=None): - if isinf(x) or isnan(x): - x=0 - - min=int(x/60) - sec=(x-min*60.) - - str1 = "{min:0>2}:{sec:0>4.1f}".format( - min = min, - sec = sec - ) - - return str1 - -def format_time(x,pos=None): - - - min = int(x/60.) - sec = int(x-min*60) - - str1 = "{min:0>2}:{sec:0>4.1f}".format( - min=min, - sec=sec, - ) - - return str1 - -def format_dist_tick(x,pos=None): - km = x/1000. - template='%6.3f' - return template % (km) - -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) - -def y_axis_range(ydata,miny=0,padding=.1,ultimate=[-1e9,1e9]): - - # ydata must by a numpy array - - ymin = np.ma.masked_invalid(ydata).min() - ymax = np.ma.masked_invalid(ydata).max() - - - yrange = ymax-ymin - yrangemin = ymin - yrangemax = ymax - - - - if (yrange == 0): - 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 - - if (yrangemin < ultimate[0]): - yrangemin = ultimate[0] - - if (yrangemax > ultimate[1]): - yrangemax = ultimate[1] - - - - return [yrangemin,yrangemax] - -def mkplot(row,title): - df = row.df - - t = df.ix[:,' ElapsedTime (sec)'] - p = df.ix[:,' Stroke500mPace (sec/500m)'] - hr = df.ix[:,' HRCur (bpm)'] - end_time = int(df.ix[df.shape[0]-1,'TimeStamp (sec)']) - - fig, ax1 = plt.subplots(figsize=(5,4)) - - ax1.plot(t,p,'b-') - ax1.set_xlabel('Time (h:m)') - ax1.set_ylabel('(sec/500)') - - yrange = y_axis_range(df.ix[:,' Stroke500mPace (sec/500m)'], - ultimate = [85,190]) - plt.axis([0,end_time,yrange[1],yrange[0]]) - - ax1.set_xticks(range(1000,end_time,1000)) - ax1.set_yticks(range(185,90,-10)) - ax1.set_title(title) - plt.grid(True) - 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') - - ax2 = ax1.twinx() - ax2.plot(t,hr,'r-') - ax2.set_ylabel('Heart Rate',color='r') - majorTimeFormatter = FuncFormatter(format_time_tick) - majorLocator = (15*60) - ax2.xaxis.set_major_formatter(majorTimeFormatter) - ax2.patch.set_alpha(0.0) - for tl in ax2.get_yticklabels(): - tl.set_color('r') - - plt.subplots_adjust(hspace=0) - - return fig - diff --git a/rowers/sporttracksstuff.pyc b/rowers/sporttracksstuff.pyc deleted file mode 100644 index 30d37184..00000000 Binary files a/rowers/sporttracksstuff.pyc and /dev/null differ diff --git a/rowers/sporttracksstuff.py~ b/rowers/sporttracksstuff.py~ deleted file mode 100644 index 8645a7b2..00000000 --- a/rowers/sporttracksstuff.py~ +++ /dev/null @@ -1,271 +0,0 @@ -# Python -import oauth2 as oauth -import cgi -import requests -import requests.auth -import json -from django.utils import timezone -from datetime import datetime -import numpy as np -from dateutil import parser -import time -import math -from math import sin,cos,atan2,sqrt - -import urllib -import c2stuff - -# Django -from django.shortcuts import render_to_response -from django.http import HttpResponseRedirect, HttpResponse,JsonResponse -from django.conf import settings -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.models import User -from django.contrib.auth.decorators import login_required - -# Project -# from .models import Profile -from rowingdata import rowingdata -import pandas as pd -from rowers.models import Rower,Workout - -from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET, SPORTTRACKS_CLIENT_SECRET, SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI - -def custom_exception_handler(exc,message): - - response = { - "errors": [ - { - "code": str(exc), - "detail": message, - } - ] - } - - res = HttpResponse(message) - res.status_code = 401 - res.json = json.dumps(response) - - return res - -def do_refresh_token(refreshtoken): - client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET) - post_data = {"grant_type": "refresh_token", - "client_secret": SPORTTRACKS_CLIENT_SECRET, - "client_id":SPORTTRACKS_CLIENT_ID, - "refresh_token": refreshtoken, - } - headers = {'user-agent': 'sanderroosendaal', - 'Accept': 'application/json', - 'Content-Type': 'application/json'} - - url = "https://api.sporttracks.mobi/oauth2/token" - - response = requests.post(url, - data=json.dumps(post_data), - headers=headers) - - token_json = response.json() - thetoken = token_json['access_token'] - expires_in = token_json['expires_in'] - try: - refresh_token = token_json['refresh_token'] - except KeyError: - refresh_token = refreshtoken - - return [thetoken,expires_in,refresh_token] - - -def get_token(code): - client_auth = requests.auth.HTTPBasicAuth(SPORTTRACKS_CLIENT_ID, SPORTTRACKS_CLIENT_SECRET) - post_data = {"grant_type": "authorization_code", - "code": code, - "redirect_uri": SPORTTRACKS_REDIRECT_URI, - "client_secret": SPORTTRACKS_CLIENT_SECRET, - "client_id":SPORTTRACKS_CLIENT_ID, - } - headers = {'Accept': 'application/json', - 'Content-Type': 'application/json'} - - url = "https://api.sporttracks.mobi/oauth2/token" - - - response = requests.post(url, - data=json.dumps(post_data), - headers=headers) - token_json = response.json() - thetoken = token_json['access_token'] - expires_in = token_json['expires_in'] - refresh_token = token_json['refresh_token'] - - return [thetoken,expires_in,refresh_token] - -def make_authorization_url(request): - # Generate a random string for the state parameter - # Save it for use later to prevent xsrf attacks - from uuid import uuid4 - state = str(uuid4()) - - params = {"client_id": SPORTTRACKS_CLIENT_ID, - "response_type": "code", - "redirect_uri": SPORTTRACKS_REDIRECT_URI, - "scope":"write", - "state":state} - - - import urllib - url = "https://api.sporttracks.mobi/oauth2/authorize" +urllib.urlencode(params) - - return HttpResponseRedirect(url) - - -def rower_sporttracks_token_refresh(user): - r = Rower.objects.get(user=user) - res = do_refresh_token(r.sporttracksrefreshtoken) - access_token = res[0] - expires_in = res[1] - refresh_token = res[2] - expirydatetime = timezone.now()+timedelta(seconds=expires_in) - - r = Rower.objects.get(user=user) - r.sporttrackstoken = access_token - r.tokenexpirydate = expirydatetime - r.sporttracksrefreshtoken = refresh_token - - r.save() - return r.sporttrackstoken - -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) - elif (timezone.now()>r.sporttrackstokenexpirydate): - 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) - - return s - - -def get_sporttracks_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" - elif (timezone.now()>r.sporttrackstokenexpirydate): - 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) - - return s - -def createsporttracksworkoutdata(w): - filename = w.csvfilename - row = rowingdata(filename) - averagehr = int(row.df[' HRCur (bpm)'].mean()) - maxhr = int(row.df[' HRCur (bpm)'].max()) - - # adding diff, trying to see if this is valid - t = row.df.ix[:,'TimeStamp (sec)'].values-10*row.df.ix[0,'TimeStamp (sec)'] - t[0] = t[1] - d = row.df.ix[:,'cum_dist'].values - d[0] = d[1] - t = t.astype(int) - d = d.astype(int) - spm = row.df[' Cadence (stokes/min)'].astype(int) - spm[0] = spm[1] - hr = row.df[' HRCur (bpm)'].astype(int) - - haslatlon=1 - - try: - lat = row.df[' latitude'].values - lon = row.df[' longitude'].values - except KeyError: - haslatlon = 0 - - haspower = 1 - try: - power = row.df[' Power (watts)'].values - except KeyError: - haspower = 0 - - locdata = [] - hrdata = [] - spmdata = [] - distancedata = [] - 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]) - - - if haslatlon: - data = { - "type": "Rowing", - "name": w.name, - "start_time": str(w.date)+"T"+str(w.starttime)+"Z", - "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", - "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 - - return data - -def getidfromresponse(response): - t = json.loads(response.text) - uri = t['uris'][0] - id = uri[len(uri)-13:len(uri)-5] - - return int(id) - - diff --git a/rowers/stravastruff.py~ b/rowers/stravastruff.py~ deleted file mode 100644 index ead9965c..00000000 --- a/rowers/stravastruff.py~ +++ /dev/null @@ -1,25 +0,0 @@ -# Python -import oauth2 as oauth -import cgi -import requests -import requests.auth -import json -from django.utils import timezone -from datetime import datetime - - -# Django -from django.shortcuts import render_to_response -from django.http import HttpResponseRedirect, HttpResponse,JsonResponse -from django.conf import settings -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.models import User -from django.contrib.auth.decorators import login_required - -# Project -# from .models import Profile -from rowingdata import rowingdata -import pandas as pd -from rowers.models import Rower,Workout - -from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET diff --git a/rowers/stravastuff.pyc b/rowers/stravastuff.pyc deleted file mode 100644 index cc3e8ed5..00000000 Binary files a/rowers/stravastuff.pyc and /dev/null differ diff --git a/rowers/stravastuff.py~ b/rowers/stravastuff.py~ deleted file mode 100644 index a7db6a44..00000000 --- a/rowers/stravastuff.py~ +++ /dev/null @@ -1,267 +0,0 @@ -# Python -import oauth2 as oauth -import cgi -import requests -import requests.auth -import json -from django.utils import timezone -from datetime import datetime -import numpy as np -from dateutil import parser -import time -import math -from math import sin,cos,atan2,sqrt - -# Django -from django.shortcuts import render_to_response -from django.http import HttpResponseRedirect, HttpResponse,JsonResponse -from django.conf import settings -from django.contrib.auth import authenticate, login, logout -from django.contrib.auth.models import User -from django.contrib.auth.decorators import login_required - -# Project -# from .models import Profile -from rowingdata import rowingdata -import pandas as pd -from rowers.models import Rower,Workout - -import stravalib - -from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET - -def ewmovingaverage(interval,window_size): - # Experimental code using Exponential Weighted moving average - - intervaldf = pd.DataFrame({'v':interval}) - idf_ewma1 = intervaldf.ewm(span=window_size) - idf_ewma2 = intervaldf[::-1].ewm(span=window_size) - - i_ewma1 = idf_ewma1.mean().ix[:,'v'] - i_ewma2 = idf_ewma2.mean().ix[:,'v'] - - interval2 = np.vstack((i_ewma1,i_ewma2[::-1])) - interval2 = np.mean( interval2, axis=0) # average - - return interval2 - -def geo_distance(lat1,lon1,lat2,lon2): - """ Approximate distance and bearing between two points - defined by lat1,lon1 and lat2,lon2 - This is a slight underestimate but is close enough for our purposes, - We're never moving more than 10 meters between trackpoints - - Bearing calculation fails if one of the points is a pole. - - """ - - # radius of earth in km - R = 6373.0 - - # pi - pi = math.pi - - lat1 = math.radians(lat1) - lat2 = math.radians(lat2) - lon1 = math.radians(lon1) - lon2 = math.radians(lon2) - - dlon = lon2 - lon1 - dlat = lat2 - lat1 - - a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2 - c = 2 * atan2(sqrt(a), sqrt(1 - a)) - - distance = R * c - - tc1 = atan2(sin(lon2-lon1)*cos(lat2), - cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1)) - - tc1 = tc1 % (2*pi) - - bearing = math.degrees(tc1) - - return [distance,bearing] - - -def custom_exception_handler(exc,message): - - response = { - "errors": [ - { - "code": str(exc), - "detail": message, - } - ] - } - - res = HttpResponse(message) - res.status_code = 401 - res.json = json.dumps(response) - - return res - -def get_token(code): - client_auth = requests.auth.HTTPBasicAuth(STRAVA_CLIENT_ID, STRAVA_CLIENT_SECRET) - post_data = {"grant_type": "authorization_code", - "code": code, - "redirect_uri": STRAVA_REDIRECT_URI, - "client_secret": STRAVA_CLIENT_SECRET, - "client_id":STRAVA_CLIENT_ID, - } - headers = {'user-agent': 'sanderroosendaal'} - response = requests.post("https://www.strava.com/oauth/token", - data=post_data, - headers=headers) - token_json = response.json() - thetoken = token_json['access_token'] - - return [thetoken] - - -def make_authorization_url(request): - # Generate a random string for the state parameter - # Save it for use later to prevent xsrf attacks - from uuid import uuid4 - state = str(uuid4()) - - params = {"client_id": STRAVA_CLIENT_ID, - "response_type": "code", - "redirect_uri": STRAVA_REDIRECT_URI, - "scope":"write"} - import urllib - url = "https://www.strava.com/oauth/authorize" +urllib.urlencode(params) - - return HttpResponseRedirect(url) - -def get_strava_workout_list(user): - 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) - else: - # 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" - s = requests.get(url,headers=headers) - - return s - -def get_strava_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) - else: - # ready to fetch. Hurray - fetchresolution = 'high' - 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" - startdatetime = workoutsummary['start_date'] - - url = "https://www.strava.com/api/v3/activities/"+str(stravaid)+"/streams/cadence?resolution="+fetchresolution - spmjson = requests.get(url,headers=headers) - url = "https://www.strava.com/api/v3/activities/"+str(stravaid)+"/streams/heartrate?resolution="+fetchresolution - hrjson = requests.get(url,headers=headers) - url = "https://www.strava.com/api/v3/activities/"+str(stravaid)+"/streams/time?resolution="+fetchresolution - timejson = requests.get(url,headers=headers) - url = "https://www.strava.com/api/v3/activities/"+str(stravaid)+"/streams/velocity_smooth?resolution="+fetchresolution - velojson = requests.get(url,headers=headers) - url = "https://www.strava.com/api/v3/activities/"+str(stravaid)+"/streams/distance?resolution="+fetchresolution - distancejson = requests.get(url,headers=headers) - url = "https://www.strava.com/api/v3/activities/"+str(stravaid)+"/streams/latlng?resolution="+fetchresolution - latlongjson = requests.get(url,headers=headers) - - t = np.array(timejson.json()[0]['data']) - d = np.array(distancejson.json()[0]['data']) - nr_rows = len(t) - - try: - spm = np.array( spmjson.json()[1]['data']) - except IndexError: - spm = np.zeros(nr_rows) - - try: - hr = np.array(hrjson.json()[1]['data']) - except IndexError: - hr = np.zeros(nr_rows) - - try: - velo = np.array(velojson.json()[1]['data']) - except IndexError: - velo = np.zeros(nr_rows) - - 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)) - - - - - strokelength = velo*60./(spm) - strokelength[np.isinf(strokelength)] = 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, - 'strokelength':strokelength, - }) - - # startdatetime = datetime.datetime.strptime(startdatetime,"%Y-%m-%d-%H:%M:%S") - - return [workoutsummary,df] - -def createstravaworkoutdata(w): - filename = w.csvfilename - row = rowingdata(filename) - tcxfilename = filename[:-4]+'.tcx' - row.exporttotcx(tcxfilename) - - print tcxfilename - - return tcxfilename - -def handle_stravaexport(file,workoutname,stravatoken,description=''): - # w = Workout.objects.get(id=workoutid) - client = stravalib.Client(access_token=stravatoken) - - act = client.upload_activity(file,'tcx',name=workoutname) - res = act.wait(poll_interval=5.0) - - - # description doesn't work yet. Have to wait for stravalib to update - act = client.update_activity(res.id,activity_type='Rowing',description=description) - - - # w.uploadedtostrava = res.id - # w.save() - file.close() - - return res.id - - diff --git a/rowers/tasks.pyc b/rowers/tasks.pyc deleted file mode 100644 index c2ac47c9..00000000 Binary files a/rowers/tasks.pyc and /dev/null differ diff --git a/rowers/tasks.py~ b/rowers/tasks.py~ deleted file mode 100644 index 5de66b1c..00000000 --- a/rowers/tasks.py~ +++ /dev/null @@ -1,172 +0,0 @@ -from celery import Celery,app -import os -import time -import gc - -import rowingdata -from rowingdata import main as rmain -from rowingdata import rowingdata as rdata -import rowingdata -#from rowers.models import Workout -from matplotlib.backends.backend_agg import FigureCanvas -#from matplotlib.backends.backend_cairo import FigureCanvasCairo as FigureCanvas -import matplotlib.pyplot as plt -from matplotlib import figure - -import stravalib - -from django.core.mail import send_mail, BadHeaderError,EmailMessage - - -@app.task -def add(x, y): - return x + y - - -@app.task -def handle_sendemail_unrecognized(unrecognizedfile,useremail): - - # send email with attachment - fullemail = 'roosendaalsander@gmail.com' - subject = "Unrecognized file from Rowsandall.com" - message = "Dear Sander,\n\n" - message += "Please find attached a file that someone tried to upload to rowsandall.com. The file was not recognized as a valid file type.\n\n" - message += "User Email "+useremail+"\n\n" - message += "Best Regards, the Rowsandall Team" - - email = EmailMessage(subject, message, - 'Rowsandall ', - [fullemail]) - - - email.attach_file(unrecognizedfile) - - res = email.send() - - # remove tcx file - os.remove(unrecognizedfile) - return 1 - - -@app.task -def handle_sendemailtcx(first_name,last_name,email,tcxfile): - - # send email with attachment - fullemail = first_name + " " + last_name + " " + "<" + email + ">" - subject = "File from Rowsandall.com" - message = "Dear "+first_name+",\n\n" - message += "Please find attached the requested file for your workout.\n\n" - message += "Best Regards, the Rowsandall Team" - - email = EmailMessage(subject, message, - 'Rowsandall ', - [fullemail]) - - - email.attach_file(tcxfile) - - res = email.send() - - # remove tcx file - os.remove(tcxfile) - return 1 - -@app.task -def handle_otwsetpower(f1,boattype,weightvalue,first_name,last_name,email,workoutid): - rowdata = rdata(f1) - weightvalue = float(weightvalue) - - # do something with boat type - boatfile = { - '1x':'static/rigging/1x.txt', - '2x':'static/rigging/2x.txt', - '2-':'static/rigging/2-.txt', - '4x':'static/rigging/4x.txt', - '4-':'static/rigging/4-.txt', - '8+':'static/rigging/8+.txt', - } - try: - rg = rowingdata.getrigging(boatfile[boattype]) - except KeyError: - rg = rowingdata.getrigging('static/rigging/1x.txt') - - # do calculation - rowdata.otw_setpower_silent(skiprows=5,mc=weightvalue,rg=rg) - - # save data - rowdata.write_csv(f1) - - # send email - fullemail = first_name + " " + last_name + " " + "<" + email + ">" - subject = "Your Rowsandall OTW calculations are ready" - message = "Dear "+first_name+",\n\n" - message += "Your Rowsandall OTW calculations are ready.\n" - # message += "You can now create OTW plots with power information and wind corrections.\n\n" - message += "Thank you for using rowsandall.com.\n\n" - message += "Rowsandall OTW calculations have not been fully implemented yet.\n" - message += "We are now running an experimental version for debugging purposes. \n" - message += "Your wind/stream corrected plot is available here: http://rowsandall.com/rowers/workout/" - message += workoutid - message +="/interactiveotwplot\n\n" - # message += "This functionality will be available soon, though.\n\n" - message += "Please report any bugs/inconsistencies/unexpected results at rowsandall.slack.com or by reply to this email.\n\n" - message += "Best Regards, The Rowsandall Physics Department." - - send_mail(subject, message, - 'Rowsandall Physics Department ', - [fullemail]) - - return 1 - -@app.task -def handle_makeplot(f1,f2,t,hrdata,plotnr,imagename): - hrmax = hrdata['hrmax'] - hrut2 = hrdata['hrut2'] - hrut1 = hrdata['hrut1'] - hrat = hrdata['hrat'] - hrtr = hrdata['hrtr'] - hran = hrdata['hran'] - - - rr = rowingdata.rower(hrmax=hrmax,hrut2=hrut2, - hrut1=hrut1,hrat=hrat, - hrtr=hrtr,hran=hran) - row = rdata(f2,rower=rr) - nr_rows = len(row.df) - if (plotnr in [1,2,4,5,8,11,9,12]) and (nr_rows > 1200): - bin = int(nr_rows/1200.) - df = row.df.groupby(lambda x:x/bin).mean() - row.df = df - nr_rows = len(row.df) - if (plotnr==1): - fig1 = row.get_timeplot_erg(t) - elif (plotnr==2): - fig1 = row.get_metersplot_erg(t) - elif (plotnr==3): - fig1 = row.get_piechart(t) - elif (plotnr==4): - fig1 = row.get_timeplot_otw(t) - elif (plotnr==5): - fig1 = row.get_metersplot_otw(t) - elif (plotnr==6): - fig1 = row.get_piechart(t) - elif (plotnr==7) or (plotnr==10): - fig1 = row.get_metersplot_erg2(t) - elif (plotnr==8) or (plotnr==11): - fig1 = row.get_timeplot_erg2(t) - elif (plotnr==9) or (plotnr==12): - fig1 = row.get_time_otwpower(t) - - canvas = FigureCanvas(fig1) - - # plt.savefig('static/plots/'+imagename,format='png') - canvas.print_figure('static/plots/'+imagename) - # plt.imsave(fname='static/plots/'+imagename) - plt.close(fig1) - fig1.clf() - gc.collect() - return imagename - - -def add2(x,y): - return x+y diff --git a/rowers/templates/400.html~ b/rowers/templates/400.html~ deleted file mode 100644 index 456e38c9..00000000 --- a/rowers/templates/400.html~ +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} - -
-

Page not found

-

-We could not find the page on our server. -

-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/403.html~ b/rowers/templates/403.html~ deleted file mode 100644 index 735edfd4..00000000 --- a/rowers/templates/403.html~ +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} - -
-

Bad Request

-

-HTTP Error 400 Bad Request. -

-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/404.html~ b/rowers/templates/404.html~ deleted file mode 100644 index 456e38c9..00000000 --- a/rowers/templates/404.html~ +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} - -
-

Page not found

-

-We could not find the page on our server. -

-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/500.html~ b/rowers/templates/500.html~ deleted file mode 100644 index 8954c2df..00000000 --- a/rowers/templates/500.html~ +++ /dev/null @@ -1,16 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} - -
-

Internal Server Error

-

-The site reported an internal server error. If this behavior repeats, please inform us by using the contact form at the bottom of this page. This allows us to improve the site's behaviour. -

-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/about_us.html~ b/rowers/templates/about_us.html~ deleted file mode 100644 index a58ac601..00000000 --- a/rowers/templates/about_us.html~ +++ /dev/null @@ -1,123 +0,0 @@ - - {% extends "base.html" %} - {% block title %}About us{% endblock title %} - {% block content %} - -
-

Introduction

-

This is a solution for the self-tracking rowers.

-

Some of us use Concept2 rowing machines. Some of us are On-The-Water -rowers. All of us will use smartphone apps, smart watches, fitness (GPS) -watches, etc. to track our activities.

-

Most of them will cross-train. Bike. Run. Skate.

-

That means, the Concept2 logbook is not a sufficient training logbook for us.

-

At the same time, the Concept2 logbook is used in rankings, for challenges, -and more. Many of us will want to log all our rowing on the Concept2 logbook.

-

So there are a couple of challenges here:

-
    -
  • How do I get my erg rows on Strava/SportTracks/Garmin Connect?

    -
    -
      -
    • Use an ANT+ device, like explained here: https://dr3do.wordpress.com/2015/07/09/hurray/
    • -
    • Import from RowPro to SportTracks
    • -
    • There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.
    • -
    -
    -
  • -
  • How do I get all my rows (including OTW) into the Concept2 logbook

    -
    -
      -
    • For On-Water and Erg: Add them manually
    • -
    • For erg: Upload from ErgData, RowPro, Concept2 utility
    • -
    -
    -
  • -
-

This project aims at giving you ways to:

-
    -
  • Upload fitness data captured in TCX format to the Concept2 logbook (implemented)

    -
    -
      -
    • This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.
    • -
    -
    -
  • -
  • Get erg data captured with apps that have no upload to Concept2 functionality and upload them to the Concept2 logbook (implemented)

    -
    -
      -
    • For example: painsled
    • -
    -
    -
  • Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:

    -
    -
      -
    • Color HR band charts or Pie Charts (implemented)
    • -
    • Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)
    • -
    -
    -
  • -
-
-
-
-

Credits

-

The project is based on python plotting code by -Greg Smith (https://quantifiedrowing.wordpress.com/) -and inspired by the RowPro Dan Burpee spreadsheet -(http://www.sub7irc.com/RP_Split_Template.zip).

-
-
-

Pro Membership

- -

Donations are welcome to keep this web site going. To help cover the hosting -costs, I have created a Pro membership option (for only 5 EURO per year). Once I process your -donation, I will give you access to some special features on this -website.

- -

Currently, the Pro membership will give you the following extra functionality (and more will follow): -

    -
  • More stroke metrics plots
  • -
  • Power curves for OTW rowing
  • -
  • Power histogram
  • -
-

- -

Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time. -You will be taken to the secure PayPal payment site. -

    -
  • Please mention the username you are registered under in "instructions to seller".
  • -
-

- - - - - - - - -

What's new?

- -

-

    -
  • 2016-09-30 Stroke Analysis Plot - with date range filtering
  • -
  • 2016-09-29 Improved Flex plot, Power Histogram and Ranking Pieces - with date range filtering
  • -
  • 2016-09-20 Added the Power histogram
  • -
  • 2016-08-31 Added the Ranking Piece summary and pace predictor
  • -
  • 2016-08-02 Added support for the SpeedCoach GPS 2 CSV/FIT file export
  • -
  • 2016-07-19 Added the possibility to download wind data from The Dark Sky / Forecast.io
  • -
  • 2016-07-19 New Flexible interactive charts for OTE and OTW (pick your own axes parameters)
  • -
  • 2016-07-07 Wind and Stream corrections for OTW (Pro functionality)
  • -
  • 2016-06-23 Pro users can now compare workouts
  • -
  • 2016-06-20 Fixed Strava upload and added SportTracks import and export. The export is not working reliably. We are debugging this,
  • -
  • 2016-06-08 Added possibility to upload CrewNerd summary CSV file for Pro Members
  • -
  • 2016-06-08 Added workout summaries
  • -
  • 2016-06-05 Export to Strava is working
  • -
  • 2016-06-01 We're approved on the Concept2 logbook!!!! -
-

- -
-
- - {% endblock content %} \ No newline at end of file diff --git a/rowers/templates/add_result.html~ b/rowers/templates/add_result.html~ deleted file mode 100644 index d0fa8aa7..00000000 --- a/rowers/templates/add_result.html~ +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}Here's your result{% endblock %} - -{% block content %} -Waiting for task with result {{ task }} -{% endblock %} - diff --git a/rowers/templates/advancededit.html~ b/rowers/templates/advancededit.html~ deleted file mode 100644 index e4129a0e..00000000 --- a/rowers/templates/advancededit.html~ +++ /dev/null @@ -1,158 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Advanced Features {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Advanced Workout Editor

- {% if user.rower.rowerplan == 'basic' %} -

This is a preview of the page with advanced functionality for Pro users. See the page about Pro membership for more information and to sign up for Pro Membership - {% endif %} -

-

- Edit Workout -

-
-
-

- Export -

- -
-
- - - - - - - - - - - - -
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Public link to this workout - http://rowsandall.com/rowers/workout/{{ workout.id }} - -
-
- -
-
- {% if user.rower.rowerplan == 'pro' %} - Compare Workouts - {% else %} - Compare Workouts - {% endif %} -

- Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts. -

-
-
- - Flexible Interactive Plot - -

- Flexible Interactive plot. Pick your own X and Y axis parameters. -

-
- -
-

- {% if user.rower.rowerplan == 'pro' %} - Edit Intervals - {% else %} - Edit Intervals - {% endif %} -

- Enter or change the interval and summary data for your workout - -

-Enter or change the interval and summary data for your workout -

-
-
-
- -
-

- {% if user.rower.rowerplan == 'pro' %} - Dist Metrics Plot - {% else %} - Dist Metrics Plot - {% endif %} -

-

- Various advanced stroke metrics plotted versus distance. -

-
-
-

- {% if user.rower.rowerplan == 'pro' %} - Time Metrics Plot - {% else %} - Time Metrics Plot - {% endif %} -

-

- Various advanced stroke metrics plotted versus time. -

-
-
-

- Big Interactive Plot -

-

- See (and save) the big interactive plot -

-
-
-
- -
-
- - - - - {{ interactiveplot |safe }} - - - - - -
- {{ the_div |safe }} -
-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/advancedotw.html~ b/rowers/templates/advancedotw.html~ deleted file mode 100644 index e828f07f..00000000 --- a/rowers/templates/advancedotw.html~ +++ /dev/null @@ -1,208 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Advanced Features {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Advanced OTW features

- {% if user.rower.rowerplan == 'basic' %} -

This is a preview of the page with advanced functionality for Pro users. See the page about Pro membership for more information and to sign up for Pro Membership - {% endif %} -

-

- Edit Workout -

-
-
-

- Export -

- -
-
- - - - - - - - - - - - -
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Public link to this workout - http://rowsandall.com/rowers/workout/{{ workout.id }} - -
-
- -
-
-

- {% if user.rower.rowerplan == 'pro' %} - Compare Workouts - {% else %} - Compare Workouts - {% endif %} -

-

- Compare this workout to other workouts. Plot HR, SPM, or pace vs time or distance for the two workouts. -

-
-
-

- {% if user.rower.rowerplan == 'pro' %} - Smooth out Pace Data - {% else %} - Smooth out Pace Data - {% endif %} - -

-

- This will reduce noise on your pace data (EWMA average). The smoothing is irreversible - but you can use the reset smoothing button. -

-
-
-

- {% if user.rower.rowerplan == 'pro' %} - Raw Data - {% else %} - Reset Smoothing - {% endif %} -

-

- Reset pace data to values before smoothing (as originally imported/uploaded) -

-
-
-
-
-

- {% if user.rower.rowerplan == 'pro' %} - CrewNerd Summary - {% else %} - CrewNerd Summary - {% endif %} - -

-

- Upload a CrewNerd Summary (CSV file) to this workout. -

-
-
-

- {% if user.rower.rowerplan == 'pro' %} - Geeky Stuff - {% else %} - Geeky Stuff - {% endif %} - -

-

- Add weather and current data and OTW power calculations. -

-
-
-

- Big Interactive Plot -

-

- See (and save) the big interactive plot -

-
- -
- -
- - -
-

- Flexible Interactive Plot -

-

- Flexible Interactive plot. Pick your own X and Y axis parameters. -

- -
-
-

- {% if user.rower.rowerplan == 'pro' %} - OTW Power Plot - {% else %} - OTW Power Plot - {% endif %} -

- Note: You must run the OTW calculations under Geeky Stuff first. Otherwise the plot will be empty - -

-Pace, wind corrected pace, power, equivalent erg power in a static plot -

-
- -
-

- {% if user.rower.rowerplan == 'pro' %} - Edit Intervals - {% else %} - Edit Intervals - {% endif %} -

- Enter or change the interval and summary data for your workout - -

-Enter or change the interval and summary data for your workout -

-
- -
-
-
-
- - - - - {{ interactiveplot |safe }} - - - - - -
- {{ the_div |safe }} -
-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/analysis.html~ b/rowers/templates/analysis.html~ deleted file mode 100644 index 58259b20..00000000 --- a/rowers/templates/analysis.html~ +++ /dev/null @@ -1,76 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Analysis {% endblock %} - -{% block content %} - -

Analysis

-

Functionality to analyze multiple workouts.

- - -
-
-

Basic

-
-

- Ranking Pieces

-

Analyze your Concept2 ranking pieces over the past 12 months and predict your pace on other pieces.

-
-
-

- Analysis Feature 2 -

-

- Reserved for future functionality. -

-
-
-

- Analysis Feature 3 -

-

- Reserved for future functionality. -

-
- -
- -
-

Pro

-
-

- {% if user.rower.rowerplan == 'pro' %} - Power Histogram - {% else %} - Power Histogram - {% endif %} -

-

- Plot a power histogram of all your strokes over the past 12 months. -

-
-
-

- Pro Feature 2 -

-

- Reserved for future functionality. -

-
-
-

- Pro Feature 3 -

-

- Reserved for future functionality. -

-
-
- - -
- - -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/base.html~ b/rowers/templates/base.html~ deleted file mode 100644 index ea24d2cb..00000000 --- a/rowers/templates/base.html~ +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - Rowsandall - - - - - {% block meta %} {% endblock %} - - -
- -
-

 

-
- {% if user.is_authenticated %} -

Password Change

- {% else %} -

Forgotten Password?

- {% endif %} -
-
- - -
-
-

Free Data and Analysis. For Rowers. By Rowers.

-
-
- {% if user.rower.rowerplan == 'pro' %} -
Pro Member
- {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

logout

- - {% else %} -

 

- {% endif %} - -
-
- -
-
- {% if user.is_authenticated %} -

Upload

- Upload CSV, TCX, FIT data files to rowsandall.com - {% else %} -

Register (free)

- {% endif %} -
-
- {% if user.is_authenticated %} -

- Import -

- Import workouts from Strava, SportTracks, and C2 logbook - {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

- Workouts -

- See your list of workouts - {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

- Graphs -

- See your most recent charts - {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

- Analysis -

- Analysis of workouts over a period of time - {% else %} -

 

- {% endif %} -
-
- {% if user.is_authenticated %} -

- {{ user.first_name }} -

- Edit user data, e.g. heart rate zones - - {% else %} -

login

- {% endif %} -
-
- - -
-
- {% block message %} - {% if message %} -

- {{ message }} -

- {% endif %} - {% if successmessage %} -

- {{ successmessage }} -

- {% endif %} - {% endblock %} -
-
- {% load tz %} - - {% block content %}{% endblock %} -
-
- -
- {% block footer %} - - -
- -
-
- -
-
- -
-
- -
- -
- -
- {% endblock %} -
-
- - - \ No newline at end of file diff --git a/rowers/templates/biginteractive1.html~ b/rowers/templates/biginteractive1.html~ deleted file mode 100644 index 58f27e4f..00000000 --- a/rowers/templates/biginteractive1.html~ +++ /dev/null @@ -1,60 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}View Workout {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - -
- - -

Interactive Plot

- - {% if user.is_authenticated and mayedit %} -
-

- Edit Workout -

-
-
-

- Advanced Edit -

- -
- {% endif %} - - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/c2_list_import.html~ b/rowers/templates/c2_list_import.html~ deleted file mode 100644 index 1ea5c4eb..00000000 --- a/rowers/templates/c2_list_import.html~ +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -

Available on C2 Logbook

- {% if data %} - - - - - - - - - - - - {% for workout in data %} - - {% for key,value in workout.items %} - {% if key == "date" %} - - {% endif %} - {% if key == "type" %} - - {% endif %} - {% if key == "distance" %} - - {% endif %} - {% if key == "time_formatted" %} - - {% endif %} - {% if key == "id" %} - - {% endif %} - {% endfor %} - - - {% endfor %} - -
Distance Duration Date Type Import
{{ value }}{{ value }}{{ value }}m{{ value }}Import
- {% else %} -

No workouts found

- {% endif %} -{% endblock %} diff --git a/rowers/templates/c2_list_import2.html~ b/rowers/templates/c2_list_import2.html~ deleted file mode 100644 index 32730e31..00000000 --- a/rowers/templates/c2_list_import2.html~ +++ /dev/null @@ -1,39 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -

Available on C2 Logbook

- {% if workouts %} - - - - - - - - - - - - - {% for workout in workouts %} - - - - - - - - - - {% endfor %} - -
Import Date/Time Duration Total Distance Type Source
-Import{{ workout|lookup:'starttime' }}{{ workout|lookup:'duration' }}{{ workout|lookup:'distance' }}{{ workout|lookup:'rowtype' }}{{ workout|lookup:'source' }}
- {% else %} -

No workouts found

- {% endif %} -{% endblock %} diff --git a/rowers/templates/cn_form.html~ b/rowers/templates/cn_form.html~ deleted file mode 100644 index dd501661..00000000 --- a/rowers/templates/cn_form.html~ +++ /dev/null @@ -1,20 +0,0 @@ - {% extends "base.html" %} - {% block title %}Upload CrewNerd Summary CSV{% endblock title %} - {% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - -
{% csrf_token %} - - -
-
-
- {% endblock content %} - \ No newline at end of file diff --git a/rowers/templates/comparison_list.html~ b/rowers/templates/comparison_list.html~ deleted file mode 100644 index 409360b6..00000000 --- a/rowers/templates/comparison_list.html~ +++ /dev/null @@ -1,75 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -
- - -

Workout {{ id }}

- - - - - - - - - - - - - - - - - - - - -
Rower:{{ first_name }} {{ last_name }}
Name:{{ workout.name }}
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Type:{{ workout.workouttype }}
Weight Category:{{ workout.weightcategory }}
-
- -
-

Compare this workout to:

- {% if workouts %} - - - - - - - - - - - - - - - - {% for cworkout in workouts %} - {% if id != cworkout.id %} - - - - - - - - - - - - - {% endif %} - {% endfor %} - -
Date Time Name Type Distance Duration Avg HR Max HR Compare
{{ cworkout.date }} {{ cworkout.starttime }} {{ cworkout.name }} {{ cworkout.workouttype }} {{ cworkout.distance }}m {{ cworkout.duration |durationprint:"%H:%M:%S.%f" }} {{ cworkout.averagehr }} {{ cworkout.maxhr }} Compare
- {% else %} -

No workouts found

- {% endif %} -
-{% endblock %} diff --git a/rowers/templates/comparisonchart.html~ b/rowers/templates/comparisonchart.html~ deleted file mode 100644 index 3902f74b..00000000 --- a/rowers/templates/comparisonchart.html~ +++ /dev/null @@ -1,77 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Compare Workouts {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - -
- -
- -

 

- -
-
-
- Time -
-
- Distance -
-
- -
-
- Pace -
- -
- SPM -
-
- -
- -
- - - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/comparisonchart2.html~ b/rowers/templates/comparisonchart2.html~ deleted file mode 100644 index cf155f98..00000000 --- a/rowers/templates/comparisonchart2.html~ +++ /dev/null @@ -1,146 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %} Comparison Plot {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - - - - - -

 

- -
- - -
- - - - - -
- -
-
- Line Plot -
- -
- -
- -
- - - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/css/demo.css~ b/rowers/templates/css/demo.css~ deleted file mode 100644 index d689be41..00000000 --- a/rowers/templates/css/demo.css~ +++ /dev/null @@ -1,55 +0,0 @@ -body { - background: #123; - color: #333; - font-size: 11px; - height: auto; - padding-bottom: 20px; -} - -a { - color: #fff; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -h1 { - font-family: Georgia, serif; - font-weight: normal; - padding-top: 20px; - text-align: center; -} - -h2 { - padding-top: 20px; - text-align: center; -} - -p { - border: 1px solid #666; - overflow: hidden; - padding: 10px 0; - text-align: center; -} - -.container_12, -.container_16, -.container_24 { - background-color: #fff; - background-repeat: repeat-y; - margin-bottom: 20px; -} - -.container_12 { - background-image: url(../img/12_col.gif); -} - -.container_16 { - background-image: url(../img/16_col.gif); -} - -.container_24 { - background-image: url(../img/24_col.gif); -} \ No newline at end of file diff --git a/rowers/templates/css/rowsandall.css~ b/rowers/templates/css/rowsandall.css~ deleted file mode 100644 index 13961f33..00000000 --- a/rowers/templates/css/rowsandall.css~ +++ /dev/null @@ -1,55 +0,0 @@ -body { - background: #123; - color: #333; - font-size: 11px; - height: auto; - padding-bottom: 20px; -} - -a { - color: #fff; - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -h1 { - font-family: Georgia, serif; - font-weight: normal; - padding-top: 20px; - text-align: left; -} - -h2 { - padding-top: 20px; - text-align: left; -} - -p { - border: 1px solid #666; - overflow: hidden; - padding: 10px 0; - text-align: left; -} - -.container_12, -.container_16, -.container_24 { - background-color: #fff; - background-repeat: repeat-y; - margin-bottom: 20px; -} - -.container_12 { - background-image: url(../img/12_col.gif); -} - -.container_16 { - background-image: url(../img/16_col.gif); -} - -.container_24 { - background-image: url(../img/24_col.gif); -} \ No newline at end of file diff --git a/rowers/templates/cum_flex.html b/rowers/templates/cum_flex.html index 8fde5825..065e8bfe 100644 --- a/rowers/templates/cum_flex.html +++ b/rowers/templates/cum_flex.html @@ -6,28 +6,17 @@ {% block content %} + {{ js_res | safe }} + {{ css_res| safe }} + + {{ interactiveplot |safe }} - - - -
-

Indoor Rower Stroke Analysis

-
- -
- - - -

Summary for {{ theuser.first_name }} {{ theuser.last_name }} - between {{ startdate|date }} and {{ enddate|date }}

- - -
- - - - - - -
-
-

 

-

Warning: Large date ranges may take a long time to load. Huge date ranges may crash your browser.

-
-
-
-

Use this form to select a different date range:

-

- Select start and end date for a date range: -

- -
- - - {{ form.as_table }} -
- {% csrf_token %} -
-
- -
-
-
- Or use the last {{ deltaform }} days. -
-
- {% csrf_token %} - - -
-
- - - - - - - - -
- - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/dashboard.html~ b/rowers/templates/dashboard.html~ deleted file mode 100644 index 88d0e9ab..00000000 --- a/rowers/templates/dashboard.html~ +++ /dev/null @@ -1,114 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - - - -{% block title %}Graphs{% endblock %} - -{% block content %} -
-

Workouts

- {% if workouts %} - - - - - - - - - - - - - - {% for workout in workouts %} - - - - - - - - {% if not workout.uploadedtoc2 %} - - {% else %} - - {% endif %} - - - {% endfor %} -
Date Time Name Type Edit Delete C2 upload
{{ workout.date }} {{ workout.starttime }} {{ workout.name }} {{ workout.workouttype }} E D C2  
- - {% else %} -

No workouts found

- {% endif %} - -
- -
-

Recent Graphs

- {% if graphs1 %} - - {% for graph in graphs1 %} - {% if forloop.counter == 1 %} -
- - {{ graph.filename }} -
- {% elif forloop.counter == 3 %} -
- - {{ graph.filename }} -
- - {% else %} -
- - {{ graph.filename }} -
- {% endif %} - {% endfor %} - - - {% for graph in graphs2 %} - {% if forloop.counter == 1 %} -
- - {{ graph.filename }} -
- {% elif forloop.counter == 3 %} -
- - {{ graph.filename }} -
- - {% else %} -
- - {{ graph.filename }} -
- {% endif %} - {% endfor %} - - - - - {% else %} -

No graphs found

- {% endif %} -
-{% endblock %} diff --git a/rowers/templates/document_form.html~ b/rowers/templates/document_form.html~ deleted file mode 100644 index de53ef7d..00000000 --- a/rowers/templates/document_form.html~ +++ /dev/null @@ -1,50 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}File loading{% endblock %} - -{% block content %} -
-
-

Upload Workout File

- {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
- - - - -
-{% endblock %} diff --git a/rowers/templates/email.html~ b/rowers/templates/email.html~ deleted file mode 100644 index 74691f2b..00000000 --- a/rowers/templates/email.html~ +++ /dev/null @@ -1,60 +0,0 @@ - {% extends "base.html" %} - {% block title %}Contact Us{% endblock title %} - {% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - -
{% csrf_token %} - - - - - -
- - - - - -
- - - - - - -
- - - -
- - - -
- - - - - -
- Do you want to send me an email? - - -
- - - -
- -
-
-
- {% endblock content %} - \ No newline at end of file diff --git a/rowers/templates/export.html~ b/rowers/templates/export.html~ deleted file mode 100644 index 43374c57..00000000 --- a/rowers/templates/export.html~ +++ /dev/null @@ -1,115 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Export {% endblock %} - -{% block content %} -
- - -

Export Workout

- -
-

- Edit Workout -

-
-
-

- Advanced Edit -

- -
- -
-

-Click on the icon to upload this workout to your site of choice. A checkmark indicates that the workout has already been uploaded. If the button is grayed out, click it to authorize the connection to that site. Use TCX export to email a TCX file of your workout to yourself. -

- -
- -{% if workout.uploadedtoc2 == 0 %} - {% if user.rower.c2token == None or user.rower.c2token == '' %} -
- - C2 icon -
- {% else %} -
- Concept2 icon -
- {% endif %} -{% else %} -
- Concept2 icon -
-{% endif %} - -{% if workout.uploadedtostrava == 0 %} - {% if user.rower.stravatoken == None or user.rower.stravatoken == '' %} -
- - Strava icon -
- {% else %} -
- Strava icon -
- {% endif %} -{% else %} -
- Concept2 icon -
-{% endif %} -{% if workout.uploadedtosporttracks == 0 %} - {% if user.rower.sporttrackstoken == None or user.rower.sporttrackstoken == '' %} -
- - SportTracks icon -
- {% else %} -
- - SportTracks icon -
- {% endif %} -{% else %} -
- Concept2 icon -
-{% endif %} -
- - TCX Export -
- -
- -
-

Connect

- -
-

Click one of the below logos to connect to the service of your choice. -You only need to do this once. After that, the site will have access until you -revoke the authorization for the "rowingdata" app.

- -
-

connect with strava

- -
-
-

connect with Concept2

-
- - -
-

connect with SportTracks

-
- -
-
- - - -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/flexchart.html~ b/rowers/templates/flexchart.html~ deleted file mode 100644 index f6cef9ee..00000000 --- a/rowers/templates/flexchart.html~ +++ /dev/null @@ -1,95 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %} Flexible Plot {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - - - -

 

- -
- - -
-
- Time -
-
- Distance -
- -
- -
-
- Pace -
-
- HR -
-
- SPM -
-
- Power -
-
- -
- -
- - - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/flexchart2.html~ b/rowers/templates/flexchart2.html~ deleted file mode 100644 index 8dbf755f..00000000 --- a/rowers/templates/flexchart2.html~ +++ /dev/null @@ -1,182 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} -{% load tz %} - -{% block title %} Flexible Plot {% endblock %} - -{% localtime on %} -{% block content %} - - - - - - {{ interactiveplot |safe }} - - {{ widgetscript | safe }} - - - - - - - -

 

- -
- - - - -
-
-
- {% csrf_token %} - {% if workstrokesonly %} - - {% else %} - - {% endif %} - -
- If your data source allows, this will show or hide strokes taken during rest intervals. -
-
- Line Plot -
- -
- -
- -
- - - {{ the_div|safe }} - -
- -
- - - {{ widgetdiv1|safe }} - {{ widgetdiv2|safe }} - -
- -{% endblock %} -{% endlocaltime %} diff --git a/rowers/templates/flexchart3.html~ b/rowers/templates/flexchart3.html~ deleted file mode 100644 index 46ab7e73..00000000 --- a/rowers/templates/flexchart3.html~ +++ /dev/null @@ -1,162 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} -{% load tz %} - -{% block title %} Flexible Plot {% endblock %} - -{% localtime on %} -{% block content %} - - {{ js_res | safe }} - {{ css_res| safe }} - - - - - - {{ the_script |safe }} - - - - - - - -

 

- -
- - - - -
-
-
- {% csrf_token %} - {% if workstrokesonly %} - - {% else %} - - {% endif %} - -
- If your data source allows, this will show or hide strokes taken during rest intervals. -
-
- Line Plot -
- -
- -
- -
- - - {{ the_div|safe }} - -
- - -{% endblock %} -{% endlocaltime %} diff --git a/rowers/templates/frontpage.html~ b/rowers/templates/frontpage.html~ deleted file mode 100644 index 5b95c90a..00000000 --- a/rowers/templates/frontpage.html~ +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} - -
-

-Henley Regatta, Henley-on-Thames, England, 1890s

-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/graphimage_delete_confirm.html~ b/rowers/templates/graphimage_delete_confirm.html~ deleted file mode 100644 index 647c083c..00000000 --- a/rowers/templates/graphimage_delete_confirm.html~ +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Delete Graph Image {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Confirm Workout Delete

- This will delete the following workout and all linked graph images: - - - - - - - - - - - -
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
- -
-

- Cancel -

- -
-

- Delete -

-
- -
- -
-

-   - -

- - -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/histo.html~ b/rowers/templates/histo.html~ deleted file mode 100644 index d7eecd52..00000000 --- a/rowers/templates/histo.html~ +++ /dev/null @@ -1,85 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}View Workout {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - -
-

Indoor Rower Power Histogram

-
- -
- - - -

Summary for {{ theuser.first_name }} {{ theuser.last_name }} - between {{ startdate|date }} and {{ enddate|date }}

- -

Direct link for other Pro users: - http://rowsandall.com/rowers/{{ id }}/histo/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }} -

-
-
-

Use this form to select a different date range:

-

- Select start and end date for a date range: -

- -
- - - {{ form.as_table }} -
- {% csrf_token %} -
-
- -
-
-
- Or use the last {{ deltaform }} days. -
-
- {% csrf_token %} - - -
-
- -
- - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/histoall.html~ b/rowers/templates/histoall.html~ deleted file mode 100644 index f8e68fc8..00000000 --- a/rowers/templates/histoall.html~ +++ /dev/null @@ -1,53 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}View Workout {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - -
- - -

Indoor Rower Power Histogram

- -

Summary of the past 12 months for {{ theuser.first_name }} {{ theuser.last_name }}

- -

Direct link for other Pro users: - http://rowsandall.com/rowers/{{ id }}/histo-all -

- - - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/imports.html~ b/rowers/templates/imports.html~ deleted file mode 100644 index cb6962f7..00000000 --- a/rowers/templates/imports.html~ +++ /dev/null @@ -1,64 +0,0 @@ - {% extends "base.html" %} - {% block title %}Contact Us{% endblock title %} - {% block content %} - -
-

Import Workouts

- -
-
-

- strava logo -

-
-
-

Import workouts from Strava

-
-
-
-
-

- Concept2 logo -

-
-
-

Import workouts from the Concept2 logbook

-
-
-

- SportTracks logo -

-
-
-

Import workouts from SportTracks

-
-
-
- -
-

Connect

- -
-

Click one of the below logos to connect to the service of your choice. -You only need to do this once. After that, the site will have access until you -revoke the authorization for the "rowingdata" app.

- -
-

connect with strava

- -
-
-

connect with Concept2

-
- - -
-

connect with SportTracks

-
- -
-
- - - {% endblock content %} - \ No newline at end of file diff --git a/rowers/templates/interactiveplot.html~ b/rowers/templates/interactiveplot.html~ deleted file mode 100644 index d4585020..00000000 --- a/rowers/templates/interactiveplot.html~ +++ /dev/null @@ -1,3 +0,0 @@ -graph = {{ my_data|safe }}; - -mpld3.draw_figure("fig01", graph); \ No newline at end of file diff --git a/rowers/templates/legal.html~ b/rowers/templates/legal.html~ deleted file mode 100644 index 3ba717e3..00000000 --- a/rowers/templates/legal.html~ +++ /dev/null @@ -1,68 +0,0 @@ - - {% extends "base.html" %} - {% block title %}About us{% endblock title %} - {% block content %} - -
-

Introduction

-

This is a solution for the self-tracking rowers.

-

Some of us use Concept2 rowing machines. Some of us are On-The-Water -rowers. All of us will use smartphone apps, smart watches, fitness (GPS) -watches, etc. to track our activities.

-

Most of them will cross-train. Bike. Run. Skate.

-

That means, the Concept2 logbook is not a sufficient training logbook for us.

-

At the same time, the Concept2 logbook is used in rankings, for challenges, -and more. Many of us will want to log all our rowing on the Concept2 logbook.

-

So there are a couple of challenges here:

-
    -
  • How do I get my erg rows on Strava/SportTracks/Garmin Connect?

    -
    -
      -
    • Use an ANT+ device, like explained here: https://dr3do.wordpress.com/2015/07/09/hurray/
    • -
    • Import from RowPro to SportTracks
    • -
    • There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.
    • -
    -
    -
  • -
  • How do I get all my rows (including OTW) into the Concept2 logbook

    -
    -
      -
    • For On-Water and Erg: Add them manually
    • -
    • For erg: Upload from ErgData, RowPro, Concept2 utility
    • -
    -
    -
  • -
-

This project aims at giving you ways to:

-
    -
  • Upload fitness data captured in TCX format to the Concept2 logbook (implemented)

    -
    -
      -
    • This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.
    • -
    -
    -
  • -
  • Get erg data captured with apps that have no upload to Concept2 functionality and upload them to the Concept2 logbook (implemented)

    -
    -
      -
    • For example: painsled
    • -
    -
    -
  • Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:

    -
    -
      -
    • Color HR band charts or Pie Charts (implemented)
    • -
    • Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)
    • -
    -
    -
  • -
-
-
-

Credits

-

The project is based on python plotting code by -Greg Smith (https://quantifiedrowing.wordpress.com/) -and inspired by the RowPro Dan Burpee spreadsheet -(http://www.sub7irc.com/RP_Split_Template.zip).

-
- {% endblock content %} \ No newline at end of file diff --git a/rowers/templates/list_graphs.html~ b/rowers/templates/list_graphs.html~ deleted file mode 100644 index 512ab975..00000000 --- a/rowers/templates/list_graphs.html~ +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Graphs{% endblock %} - -{% block content %} -

Recent Graphs

- {% if graphs1 %} -
-

 

-
- - {% for graph in graphs1 %} -
- - {{ graph.filename }} -
- {% endfor %} - -
-

 

-
- - -
-

 

-
- -
-

 

-
- - {% for graph in graphs2 %} -
- - {{ graph.filename }} -
- {% endfor %} - - -
-

 

-
- - - {% else %} -

No graphs found

- {% endif %} -{% endblock %} diff --git a/rowers/templates/list_workouts.html~ b/rowers/templates/list_workouts.html~ deleted file mode 100644 index 0b4334ef..00000000 --- a/rowers/templates/list_workouts.html~ +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -

My Workouts

- {% if workouts %} - - - - - - - - - - - - - - - - - {% for workout in workouts %} - - - - - {% else %} -{{ workout.name }} - {% endif %} - - - - - - - - - - - {% endfor %} - -
Date Time Name Type Distance Duration Avg HR Max HR Delete Export
{{ workout.date }} {{ workout.starttime }} - {% if user.rower.rowerplan == 'pro' %} -{{ workout.name }} {{ workout.workouttype }} {{ workout.distance }}m {{ workout.duration |durationprint:"%H:%M:%S.%f" }} {{ workout.averagehr }} {{ workout.maxhr }} Delete Export
- {% else %} -

No workouts found

- {% endif %} -{% endblock %} diff --git a/rowers/templates/login_form.html~ b/rowers/templates/login_form.html~ deleted file mode 100644 index 990c51f9..00000000 --- a/rowers/templates/login_form.html~ +++ /dev/null @@ -1,26 +0,0 @@ - - - Login Form - - -

Login

- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- - {{ form.as_table }} -
- {% csrf_token %} - - -
-

- register -

- - \ No newline at end of file diff --git a/rowers/templates/otwgeeky.html~ b/rowers/templates/otwgeeky.html~ deleted file mode 100644 index 33844eec..00000000 --- a/rowers/templates/otwgeeky.html~ +++ /dev/null @@ -1,162 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Advanced Features {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Advanced OTW features

- {% if user.rower.rowerplan == 'basic' %} -

This is a preview of the page with advanced functionality for Pro users. See the About page for more information and to sign up for Pro Membership - {% endif %} -

-

- Edit Workout -

-
-
-

- Advanced Edit -

-
-
-

- Export -

- -
- -
- - - - - - - - - - - - -
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Public link to this workout - http://rowsandall.com/rowers/workout/{{ workout.id }} - -
-
- - -
-
-

- {% if user.rower.rowerplan == 'pro' %} - Edit Wind Data - {% else %} - Edit Wind Data - {% endif %} - -

-

- Add wind data for OTW workouts -

-
-
-

- {% if user.rower.rowerplan == 'pro' %} - Edit Stream Data - {% else %} - Edit Stream Data - {% endif %} - -

-

- For river dwellers. Add stream information. -

-
-
-

- {% if user.rower.rowerplan == 'pro' %} - OTW Power - {% else %} - OTW Power - {% endif %} -

-

- Run OTW Power calculations (wind & stream correction, equivalent erg pace) -

-
- - - -
- -
-

- {% if user.rower.rowerplan == 'pro' %} - Corrected Pace Plot - {% else %} - Corrected Pace Plot - {% endif %} - -

-

- Wind and Stream corrected pace plots will be here. -

-
-
-

- Big Interactive Plot -

-

- See (and save) the big interactive plot -

-
-
-
-
- -
-
- - - - - {{ interactiveplot |safe }} - - - - - -
- {{ the_div |safe }} -
-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/otwinteractive.html~ b/rowers/templates/otwinteractive.html~ deleted file mode 100644 index 289d5d58..00000000 --- a/rowers/templates/otwinteractive.html~ +++ /dev/null @@ -1,80 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}View Workout {% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - -
- - -

Interactive Plot

- - {% if user.is_authenticated and mayedit %} -
-

- Edit Workout -

-
-
-

- Advanced Edit -

- -
- - -
- OTW Power -
- {% endif %} - - {{ the_div|safe }} - - -

-

Notes

-
    -
  • Is your erg pace slower than you expected? This may be a sign of room for improvement regarding your technique. An alternative explanation is that your team mates are fatter than they told you! For example, put 80.0 kg if your four consists of 2 70kg guys and 2 90kg guys.
  • -
  • In order to speed up the calculation, we are running the calculation only for every 10th datapoint, using interpolation in between. Some very fine pace shifts may disappear.
  • -
  • While the wind and stream correction is fairly reliable, the OTW to OTE conversion sometimes throws errors. Those data points are omitted and replaced by interpolated values. We are sorry if this messed up some of your plots.
  • -
  • Read more details about the way we calculate things here.
  • -
-

- -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/otwsetpower.html~ b/rowers/templates/otwsetpower.html~ deleted file mode 100644 index 68a08f8e..00000000 --- a/rowers/templates/otwsetpower.html~ +++ /dev/null @@ -1,58 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Advanced Features {% endblock %} - -{% block content %} -
- - -

Run OTW Power Calculations

-
-

- Edit Workout -

-
-
-

- Advanced Edit -

- -
-
-

- For the advanced OTW power and wind correction calculation, - we need to know the boat type and the average weight per crew member. - Currently only 1x (single) is implemented. Setting the value to - 2x (double) will still run the calculations for a single. - We use FISA minimum boat weight and standard rigging for our calculations. -

- -
- {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - - {{ form.as_table }} -
- {% csrf_token %} -
-
- -
- - -
- -
- - The Rowsandall Physics Department at work. -
- - - -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/physics.html~ b/rowers/templates/physics.html~ deleted file mode 100644 index 793c3741..00000000 --- a/rowers/templates/physics.html~ +++ /dev/null @@ -1,155 +0,0 @@ - - {% extends "base.html" %} - {% block title %}About us{% endblock title %} - {% block content %} - -
-

How we calculate things

-

You are reading this because you want to understand how the wind/stream conversion and the conversion from OTW pace to OTE pace works.

- -

The conversions are done using a one-dimensional mechanical model that is -introduced here. -The model takes into account, among others, the following parameters: -

    -
  • Stroke rate
  • -
  • Stroke length
  • -
  • Rigging parameters
  • -
  • Rower and boat weight
  • -
-For this site, we use "standard" rigging parameters, blade shapes, and FISA minimum boat weights. For the eight, I add the weight of a cox (at the FISA minimum weight). The stroke length is also set at a fixed value, but in the future I -will allow you to adjust to your own stroke length. -

-

-Knowing boat type (rigging), pace and stroke rate, and taking into account -the influence of wind and stream (if provided), I am able to find the -mechanical power that you provide to the rowing system by a reverse -calculation. That is, I vary the input force until I find the one that -corresponds to your actual pace at that stroke rate. -

-

-Knowing the power, I can calculate how fast you would have gone without -external wind and stream influences by running the calculation in a forward -way, using the power and force profile found. This is the wind/stream -corrected pace, which I think is useful to know and be able to compare -from training to training and between different rowing venues. -

- -

-Using another algorithm to calculate total mechanical power on an erg, I can -calculate what the erg display would show you if you rowed on the erg with -the same average power, at the same stroke rate. The calculations are done -for a statical Concept2 erg with a fairly standard drag factor. I cannot -take into account the fact that you may use different technique or would -row at a different stroke rate on the erg. -

- -

-It is important to understand that the Power display on the erg is not showing -you the complete picture. In my calculations, I use my proprietary algorithms -to calculate the additional power that goes into moving your body weight up -and down the slide on a static erg. To get the most accurate results, it is -important to be honest about your weight and set it independently for each -workout. -

- -

Not taken into account are the following factors: -

    -
  • Water Temperature
  • -
  • Heavier/shorter/wider boats than the ones used by the elite
  • -
  • Bungees, weed, or other artefacts slowing down the boat
  • -
  • Boat stopping technique flaws
  • -
  • Effect of wave height or cross-wind
  • -
-The water temperature has a small but measurable effect on the water density -(and thus on the drag). I am using the value at 20 degrees C, which is a -good average over the OTW season for a lake in a temperate climate. All -the other elements result in an equivalent erg pace that is probably slower -than what you can achieve on the erg. So look at it as an incentive to -improve your technique (big effect) and/or buy a faster boat (minor effect). -If your OTW to OTE pace conversion results in numbers close to what you -normally achieve on the erg, you are rowing like an elite rower (but possibly -at a lower power)! -

- -

-I have checked the model both from a Physics perspective (I have a degree in -Physics, if you are interested) and compared with the data available. -An important data set has been published here by Dr Kleshnev. For sculling, -my algorithms are extremely close in reproducing that data set. For sweep -rowing, I am still fine tuning some parameters, but I am close for a pair and -a four. I had to make assumptions about Kleshnev's data, especially about the -stroke rate, but as I got realistic stroke rates (35 and higher) for world -record performance, I am quite confident. -

- -

-On top of that I am constantly comparing the model's results to my own sculling -and rowing, and I will be the first to admit flaws and correct them. So please -contact me if there are any inconsistencies, suspicions, questions or simply -if you want to chat about Rowing Physics. -

- - -
-
-

Manual

- -

Here's the best way - in my mind - to use the Rowing Physics -functionality. I am assuming you have successfully uploaded or imported -a rowing workout. You must have position data (lat/long) with your row. A -TCX from CrewNerd or RiM or a workout imported from SportTracks or Strava -(where you see a map of your workout on those sites) should have those -data. I am working on adding the FIT file format that is used by SpeedCoach -GPS. For now, export the data to Strava and then import them here. -

- -

Recipe for success: -

    -
  1. Click on the workout. This will bring you to the workout Edit view
  2. -
  3. Click on the "Advanced" button
  4. -
  5. Click on Edit Wind Data (optional) to edit wind data. Go back to Advanced when you're done.
  6. -
  7. Click on Edit Stream Data (optional) to edit stream data. Go back to Advanced when you're done.
  8. -
  9. Click on OTW Power
  10. -
  11. Select the boat type and enter the average weight per crew member. - Do not use the crew total weight.
  12. -
  13. Click "Update & Run"
  14. -
  15. Go do something else. You will receive an email when the calculations are finished. The calculation itself will take about 10 minutes for an -hour long row, but there may be other people's calculations in the queue, so -it may take longer.
  16. -
  17. From the "Advanced" view, click on "Corrected Pace Plot" to see the result. From here, you can re-run the calculation with different parameters.
  18. -
-

- -

-Once you have run the calculation, the boat type, average crew weight, -Power and corrected pace data are stored permanently on the site. If you would -export the data to Strava or SportTracks now, those sites will have the -Power data. -

- -

Why does the calculation take so much time?

- -

I am running the calculations from a first principles base, so for -each data point that I am calculating, I am finding the stroke average -force, then calculating corrected pace (wind/stream) and finding the -corresponding erg power. I am not taking any shortcuts. The advantage -of this approach is that I can give you numbers irrespective of your -weight, speed, stroke rate, sex, etc. The model can deal with circumstances -it has not encountered before. The downside is that it takes time.

- -

-A much faster approach would be to simply take pre-calculated data from -a table and interpolate. The advantage of this approach is is speed. The -disadvantage is that extrapolation outside the limits of the available -data is dangerous and will lead to erroneous results.

- -

Future versions of this site will use a hybrid approach -but only for pace/wind/stream/stroke rate/weight combinations that I consider -well validated. For that, I need to collect data, so keep the workouts coming! -

- - - -
- - {% endblock content %} \ No newline at end of file diff --git a/rowers/templates/promembership.html~ b/rowers/templates/promembership.html~ deleted file mode 100644 index 4bc8e179..00000000 --- a/rowers/templates/promembership.html~ +++ /dev/null @@ -1,122 +0,0 @@ - - {% extends "base.html" %} - {% block title %}About us{% endblock title %} - {% block content %} - -
-

Introduction

-

This is a solution for the self-tracking rowers.

-

Some of us use Concept2 rowing machines. Some of us are On-The-Water -rowers. All of us will use smartphone apps, smart watches, fitness (GPS) -watches, etc. to track our activities.

-

Most of them will cross-train. Bike. Run. Skate.

-

That means, the Concept2 logbook is not a sufficient training logbook for us.

-

At the same time, the Concept2 logbook is used in rankings, for challenges, -and more. Many of us will want to log all our rowing on the Concept2 logbook.

-

So there are a couple of challenges here:

-
    -
  • How do I get my erg rows on Strava/SportTracks/Garmin Connect?

    -
    -
      -
    • Use an ANT+ device, like explained here: https://dr3do.wordpress.com/2015/07/09/hurray/
    • -
    • Import from RowPro to SportTracks
    • -
    • There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.
    • -
    -
    -
  • -
  • How do I get all my rows (including OTW) into the Concept2 logbook

    -
    -
      -
    • For On-Water and Erg: Add them manually
    • -
    • For erg: Upload from ErgData, RowPro, Concept2 utility
    • -
    -
    -
  • -
-

This project aims at giving you ways to:

-
    -
  • Upload fitness data captured in TCX format to the Concept2 logbook (implemented)

    -
    -
      -
    • This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.
    • -
    -
    -
  • -
  • Get erg data captured with apps that have no upload to Concept2 functionality and upload them to the Concept2 logbook (implemented)

    -
    -
      -
    • For example: painsled
    • -
    -
    -
  • Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:

    -
    -
      -
    • Color HR band charts or Pie Charts (implemented)
    • -
    • Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)
    • -
    -
    -
  • -
-
-
-
-

Credits

-

The project is based on python plotting code by -Greg Smith (https://quantifiedrowing.wordpress.com/) -and inspired by the RowPro Dan Burpee spreadsheet -(http://www.sub7irc.com/RP_Split_Template.zip).

-
-
-

Pro Membership

- -

Donations are welcome to keep this web site going. To help cover the hosting -costs, I have created a Pro membership option (for only 5 EURO per year). Once I process your -donation, I will give you access to some special features on this -website.

- -

These features are currently under development. The current Pro membership -gives you access to a big interactive chart and a stroke metrics plot. In the near future, I am planning to add:

- -
    -
  • More stroke metrics plots
  • -
  • Power curves for OTW rowing
  • -
  • Compare OTW with OTE rows
  • -
- -

Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time. -You will be taken to the secure PayPal payment site. -

    -
  • Please mention the username you are registered under in "instructions to seller".
  • -
-

- -
- - - - -
- -

What's new?

- -

-

    -
  • 2016-09-20 Added the Power histogram
  • -
  • 2016-08-31 Added the Ranking Piece summary and pace predictor
  • -
  • 2016-08-02 Added support for the SpeedCoach GPS 2 CSV/FIT file export
  • -
  • 2016-07-19 Added the possibility to download wind data from The Dark Sky / Forecast.io
  • -
  • 2016-07-19 New Flexible interactive charts for OTE and OTW (pick your own axes parameters)
  • -
  • 2016-07-07 Wind and Stream corrections for OTW (Pro functionality)
  • -
  • 2016-06-23 Pro users can now compare workouts
  • -
  • 2016-06-20 Fixed Strava upload and added SportTracks import and export. The export is not working reliably. We are debugging this,
  • -
  • 2016-06-08 Added possibility to upload CrewNerd summary CSV file for Pro Members
  • -
  • 2016-06-08 Added workout summaries
  • -
  • 2016-06-05 Export to Strava is working
  • -
  • 2016-06-01 We're approved on the Concept2 logbook!!!! -
-

- -
-
- - {% endblock content %} \ No newline at end of file diff --git a/rowers/templates/rankings.html~ b/rowers/templates/rankings.html~ deleted file mode 100644 index 41372f4e..00000000 --- a/rowers/templates/rankings.html~ +++ /dev/null @@ -1,227 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} - - - - - {{ interactiveplot |safe }} - - - - - -
-

Ranking Pieces (Indoor Rower)

-
- -
-

Summary for {{ theuser.first_name }} {{ theuser.last_name }} - between {{ startdate|date }} and {{ enddate|date }}

- -

Direct link for other users: - http://rowsandall.com/rowers/{{ id }}/ote-bests/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }} -

- -

The table gives the best efforts achieved on the official Concept2 ranking pieces in the selected date range.

- -

This page will evolve and try to give you guidance on where to improve.

-
-
-

Use this form to select a different date range:

-

- Select start and end date for a date range: -

- -
- - - {{ dateform.as_table }} -
- {% csrf_token %} -
-
- -
-
-
- Or use the last {{ deltaform }} days. -
-
- {% csrf_token %} - - -
-
- -
- -

Ranking Piece Results

- - {% if rankingworkouts %} - - - - - - - - - - - - - - {% for workout in rankingworkouts %} - - - - - - - - - - - {% endfor %} - -
Distance Duration Date Avg HR Max HR Edit
{{ workout.distance }} {{ workout.duration |durationprint:"%H:%M:%S.%f" }} {{ workout.date }} {{ workout.averagehr }} {{ workout.maxhr }} - {{ workout.name }}
- {% else %} -

No ranking workouts found

- {% endif %} - -
- - -
- -

Critical Power Plot

- - {{ the_div|safe }} - -
- -
-

Pace predictions for Ranking Pieces

- -

Add non-ranking piece using the form. The piece will be added in the prediction tables below.

-
-
- {{ form.value }} {{ form.pieceunit }} - - {% csrf_token %} -
-
- - -
- - - -
-

Paul's Law

-{% if nrdata >= 1 %} - - - - - - - - - - - {% for pred in predictions %} - - {% for key, value in pred.items %} - {% if key == "distance" %} - - {% endif %} - {% if key == "pace" %} - - {% endif %} - {% if key == "power" %} - - {% endif %} - {% if key == "duration" %} - - {% endif %} - {% endfor %} - - {% endfor %} - -
Duration Distance Power Pace
{{ value }} m {{ value |durationprint:"%M:%S.%f" }} {{ value }} W {{ value |durationprint:"%H:%M:%S.%f" }}
- -{% else %} -

Insufficient data to make predictions

- -{% endif %} -
-
-

CP Model

-{% if nrdata >= 4 %} - - - - - - - - - - - {% for pred in cpredictions %} - - {% for key, value in pred.items %} - {% if key == "distance" %} - - {% endif %} - {% if key == "pace" %} - - {% endif %} - {% if key == "power" %} - - {% endif %} - {% if key == "duration" %} - - {% endif %} - {% endfor %} - - {% endfor %} - -
Duration Distance Power Pace
{{ value }} m {{ value |durationprint:"%M:%S.%f" }} {{ value }} W {{ value |durationprint:"%H:%M:%S.%f" }}
- -{% else %} -

Insufficient data to make predictions

- -{% endif %} -
-
- -{% endblock %} diff --git a/rowers/templates/registration_form.html~ b/rowers/templates/registration_form.html~ deleted file mode 100644 index ed1cc317..00000000 --- a/rowers/templates/registration_form.html~ +++ /dev/null @@ -1,25 +0,0 @@ - {% extends "base.html" %} - {% block title %}Contact Us{% endblock title %} - {% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -
- {% csrf_token %} - - {{ form.as_table }} -
- Terms of Service -
- -
-
- -
- {% endblock content %} - \ No newline at end of file diff --git a/rowers/templates/rower_form.html~ b/rowers/templates/rower_form.html~ deleted file mode 100644 index 44298eb3..00000000 --- a/rowers/templates/rower_form.html~ +++ /dev/null @@ -1,34 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Change Rower {% endblock %} - -{% block content %} - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} -
-

Edit your Parameters

- -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
-

Tokens etcetera

-

- - - - -
Concept2 sync issues? Click:Concept2 logo
-

-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/show_graph.html~ b/rowers/templates/show_graph.html~ deleted file mode 100644 index 02c2a01a..00000000 --- a/rowers/templates/show_graph.html~ +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} - -{% block title %}{{ workout.name }}{% endblock %} - -{% block content %} -

{{ workout.name }}

-

- -/{{ graph.filename }} - -

-{% endblock %} - diff --git a/rowers/templates/simple_chart.html~ b/rowers/templates/simple_chart.html~ deleted file mode 100644 index 910f0582..00000000 --- a/rowers/templates/simple_chart.html~ +++ /dev/null @@ -1,15 +0,0 @@ - - - - - Experiment with Bokeh - - - - - - {{ the_div|safe }} - - {{ the_script|safe }} - - \ No newline at end of file diff --git a/rowers/templates/sporttracks_list_import.html~ b/rowers/templates/sporttracks_list_import.html~ deleted file mode 100644 index a99ea834..00000000 --- a/rowers/templates/sporttracks_list_import.html~ +++ /dev/null @@ -1,52 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -

Available on Strava

- {% if data %} - - - - - - - - - - - - - {% for workout in data %} - - {% for key,value in workout.items %} - {% if key == "start_date" %} - - {% endif %} - {% if key == "name" %} - - {% endif %} - {% if key == "type" %} - - {% endif %} - {% if key == "distance" %} - - {% endif %} - {% if key == "elapsed_time" %} - - {% endif %} - {% if key == "id" %} - - {% endif %} - {% endfor %} - - - {% endfor %} - -
Import Duration Type Date Distance Name
{{ value }}{{ value }}{{ value }}{{ value }}m{{ value }}Import
- {% else %} -

No workouts found

- {% endif %} -{% endblock %} diff --git a/rowers/templates/strava_list_import.html~ b/rowers/templates/strava_list_import.html~ deleted file mode 100644 index 9eb38370..00000000 --- a/rowers/templates/strava_list_import.html~ +++ /dev/null @@ -1,48 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Workouts{% endblock %} - -{% block content %} -

Available on Strava

- {% if data %} - - - - - - - - - - - - {% for workout in data %} - - {% for key,value in workout.items %} - {% if key == "start_date" %} - - {% endif %} - {% if key == "type" %} - - {% endif %} - {% if key == "distance" %} - - {% endif %} - {% if key == "elapsed_time" %} - - {% endif %} - {% if key == "id" %} - - {% endif %} - {% endfor %} - - - {% endfor %} - -
Import Duration Type Date Distance
{{ value }}{{ value }}{{ value }}m{{ value }}Import
- {% else %} -

No workouts found

- {% endif %} -{% endblock %} diff --git a/rowers/templates/streamedit.html~ b/rowers/templates/streamedit.html~ deleted file mode 100644 index 9522dabc..00000000 --- a/rowers/templates/streamedit.html~ +++ /dev/null @@ -1,89 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Advanced Features {% endblock %} - -{% block content %} -
- - -

Stream Editor

-
-

- Edit Workout -

-
-
-

- Advanced Edit -

- -
-
-

OTW Power

- Run calculations to get power values for your row. - -
-
-

- Edit river Stream between turning points in your row. - Use positive (+) values to denote rowing with the stream, - negative (-) values to denote rowing against the stream. -

- - - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - - {{ form.as_table }} -
- {% csrf_token %} -
-
- -
- - - -
- -
- - - - - {{ interactiveplot |safe }} - - - - - -
- {{ the_div |safe }} -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/summary_edit.html~ b/rowers/templates/summary_edit.html~ deleted file mode 100644 index ed5dd1c8..00000000 --- a/rowers/templates/summary_edit.html~ +++ /dev/null @@ -1,203 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} -{% load tz %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Edit Workout Interval Data

-
-
-

- Edit -

-
-
-

- Export - -

-
-
-

- Advanced -

- Advanced Functionality (More interactive Charts) - -
-
- - -{% localtime on %} - - - - - - - - - - - - -
Date/Time:{{ workout.startdatetime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Public link to this workout - http://rowsandall.com/rowers/workout/{{ workout.id }} - -
Public link to interactive chart - http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot - -
-{% endlocaltime %} -

Interval Translator

-

This is a quick way to enter the intervals using a special mini-language.

-

You enter something like 8x500m/3min, press "Update" and the site will interpret this for you and update the summary on the right. If you're happy with the result, press the green Save button to update the values. Nothing will be changed permanently until you hit Save.

- -

Special characters are x (times), + and / (denotes a rest interval), as well as ( and ). Units are min (minutes), sec (seconds), m (meters) and km (km).

- -

A typical interval is described as "10min/5min", with the work part before the "/" and the rest part after it. A zero rest can be omitted, so a single 1000m piece could be described either as "1km" or "1000m". The basic units can be combined with "+" and "Nx". You can use parentheses as in the example below.

- -

Here are a few examples.

- - - - - - - - - - - - - - - - - -
8x500m/2min8 times 500m with 2 minutes rest
10kmSingle distance of 10km
6min/3min + 5min/3min + 3min/3min + 3min Four intervals of 6, 5, 3 and 3 minutes length, 3 minutes rest
4x(500m+500m)/5min4 times 1km, but each km is reported as two 500m intervals without rest
2x500m/500mA 2k rowed as 500m "on", 500m "off"
- -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
- -
-
- - - - - {{ interactiveplot |safe }} - - - - - -
- {{ the_div |safe }} -
-
- - -
-

Updated Summary

-
- {% csrf_token %} - - - {% for field in detailform %} - {{ field.as_hidden }} - {% endfor %} -
- -
- - -
-
-

-

-{{ intervalstats }}
-
-

-
-
- -
-

Detailed Summary Edit

-

This is still experimental and there are known bugs. Use at your own risk. Nothing is stored permanently until you hit Save on the summary above. You can use the restore original button to restore the original values.

-
-
#
-
- Time -
-
- Distance -
-
- Type -
-
-
- {% for i in nrintervals|times %} -
-
{{ i }}
-
- {% get_field_id i "intervalt_" detailform %} -
-
- {% get_field_id i "intervald_" detailform %} -
-
- {% get_field_id i "type_" detailform %} -
-
- {% endfor %} - {% csrf_token %} -
- - -
-
-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/test.html~ b/rowers/templates/test.html~ deleted file mode 100644 index 32dd9782..00000000 --- a/rowers/templates/test.html~ +++ /dev/null @@ -1,54 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %} Flexible Plot {% endblock %} - -{% block content %} - - {{ js_res | safe }} - {{ css_res| safe }} - - - - - - {{ the_script |safe }} - - - - - - -

 

- - - - -
- - - {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/videos.html~ b/rowers/templates/videos.html~ deleted file mode 100644 index a58ac601..00000000 --- a/rowers/templates/videos.html~ +++ /dev/null @@ -1,123 +0,0 @@ - - {% extends "base.html" %} - {% block title %}About us{% endblock title %} - {% block content %} - -
-

Introduction

-

This is a solution for the self-tracking rowers.

-

Some of us use Concept2 rowing machines. Some of us are On-The-Water -rowers. All of us will use smartphone apps, smart watches, fitness (GPS) -watches, etc. to track our activities.

-

Most of them will cross-train. Bike. Run. Skate.

-

That means, the Concept2 logbook is not a sufficient training logbook for us.

-

At the same time, the Concept2 logbook is used in rankings, for challenges, -and more. Many of us will want to log all our rowing on the Concept2 logbook.

-

So there are a couple of challenges here:

-
    -
  • How do I get my erg rows on Strava/SportTracks/Garmin Connect?

    -
    -
      -
    • Use an ANT+ device, like explained here: https://dr3do.wordpress.com/2015/07/09/hurray/
    • -
    • Import from RowPro to SportTracks
    • -
    • There are many smartphone apps to capture data from the PM3/4/5 erg monitor. Not many of them export in a format that is suitable for upload to the above-mentioned sites.
    • -
    -
    -
  • -
  • How do I get all my rows (including OTW) into the Concept2 logbook

    -
    -
      -
    • For On-Water and Erg: Add them manually
    • -
    • For erg: Upload from ErgData, RowPro, Concept2 utility
    • -
    -
    -
  • -
-

This project aims at giving you ways to:

-
    -
  • Upload fitness data captured in TCX format to the Concept2 logbook (implemented)

    -
    -
      -
    • This should cover all your On-Water activities, whether they are captured with a SpeedCoach, a GPS fitness watch, your phone, or any other device. As long as you are able to export a valid TCX file.
    • -
    -
    -
  • -
  • Get erg data captured with apps that have no upload to Concept2 functionality and upload them to the Concept2 logbook (implemented)

    -
    -
      -
    • For example: painsled
    • -
    -
    -
  • Create useful plots. Who wants to be limited to what the on-line logbooks plot. Get your data and create:

    -
    -
      -
    • Color HR band charts or Pie Charts (implemented)
    • -
    • Plot drive length, drive time, and other erg related parameters as a function of time or distance (to be implemented)
    • -
    -
    -
  • -
-
-
-
-

Credits

-

The project is based on python plotting code by -Greg Smith (https://quantifiedrowing.wordpress.com/) -and inspired by the RowPro Dan Burpee spreadsheet -(http://www.sub7irc.com/RP_Split_Template.zip).

-
-
-

Pro Membership

- -

Donations are welcome to keep this web site going. To help cover the hosting -costs, I have created a Pro membership option (for only 5 EURO per year). Once I process your -donation, I will give you access to some special features on this -website.

- -

Currently, the Pro membership will give you the following extra functionality (and more will follow): -

    -
  • More stroke metrics plots
  • -
  • Power curves for OTW rowing
  • -
  • Power histogram
  • -
-

- -

Click on the PayPal button to pay for your Pro membership. It will be valid for one year with automatic renewal which you can stop at any time. -You will be taken to the secure PayPal payment site. -

    -
  • Please mention the username you are registered under in "instructions to seller".
  • -
-

- -
- - - - -
- -

What's new?

- -

-

    -
  • 2016-09-30 Stroke Analysis Plot - with date range filtering
  • -
  • 2016-09-29 Improved Flex plot, Power Histogram and Ranking Pieces - with date range filtering
  • -
  • 2016-09-20 Added the Power histogram
  • -
  • 2016-08-31 Added the Ranking Piece summary and pace predictor
  • -
  • 2016-08-02 Added support for the SpeedCoach GPS 2 CSV/FIT file export
  • -
  • 2016-07-19 Added the possibility to download wind data from The Dark Sky / Forecast.io
  • -
  • 2016-07-19 New Flexible interactive charts for OTE and OTW (pick your own axes parameters)
  • -
  • 2016-07-07 Wind and Stream corrections for OTW (Pro functionality)
  • -
  • 2016-06-23 Pro users can now compare workouts
  • -
  • 2016-06-20 Fixed Strava upload and added SportTracks import and export. The export is not working reliably. We are debugging this,
  • -
  • 2016-06-08 Added possibility to upload CrewNerd summary CSV file for Pro Members
  • -
  • 2016-06-08 Added workout summaries
  • -
  • 2016-06-05 Export to Strava is working
  • -
  • 2016-06-01 We're approved on the Concept2 logbook!!!! -
-

- -
-
- - {% endblock content %} \ No newline at end of file diff --git a/rowers/templates/windedit.html~ b/rowers/templates/windedit.html~ deleted file mode 100644 index fd72d47e..00000000 --- a/rowers/templates/windedit.html~ +++ /dev/null @@ -1,114 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Advanced Features {% endblock %} - -{% block content %} -
- -

Wind Editor

-
-

- Edit Workout -

-
-
-

- Advanced Edit -

- -
-
-

OTW Power

- Run calculations to get power values for your row. - -
-
-

- Update wind between distance 1 and distance 2. Submit wind strength - and direction at start and end of segment. Blank the form for values - you want to keep intact. -

- -

- Check www.wunderground.com - to find historical weather data from an on-line weather station near - the location of your row. -

- -
-
- {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - - - {{ form.as_table }} -
- {% csrf_token %} - -
-
- Dark Sky Data -

- Download wind speed and bearing from The Dark Sky -

-
-
- -

- Manual update of the wind data from the form. -

-
- - -
-
-
- - - - - {{ interactiveplot |safe }} - - {{ gmap |safe }} - - - - - -
-
- {{ the_div |safe }} -
-
- -
-
- {{ gmapdiv |safe }} -
-
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/workout_delete_confirm.html~ b/rowers/templates/workout_delete_confirm.html~ deleted file mode 100644 index 5ef3d443..00000000 --- a/rowers/templates/workout_delete_confirm.html~ +++ /dev/null @@ -1,51 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Confirm Workout Delete

- This will delete the following workout and all linked graph images: - - - - - - - - - - - -
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
- -
-

- Cancel -

- -
-

- Delete -

-
- -
- -
-

-   - -

- - -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/workout_form.html~ b/rowers/templates/workout_form.html~ deleted file mode 100644 index e1bf9cf7..00000000 --- a/rowers/templates/workout_form.html~ +++ /dev/null @@ -1,192 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} -{% load tz %} - -{% block title %}Change Workout {% endblock %} - -{% block content %} -
- - {% if form.errors %} -

- Please correct the error{{ form.errors|pluralize }} below. -

- {% endif %} - -

Edit Workout Data

-
-
-

- Delete -

-
-
-

- Export - -

-
-
-

- Advanced -

- Advanced Functionality (More interactive Charts) - -
-
- - -{% localtime on %} - - - - - - - - - - - - -
Date/Time:{{ workout.startdatetime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Public link to this workout - http://rowsandall.com/rowers/workout/{{ workout.id }} - -
Public link to interactive chart - http://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot - -
-{% endlocaltime %} -
- - {{ form.as_table }} -
- {% csrf_token %} -
- -
-
-
-
-

Images linked to this workout

-
-
-

- Add Time Plot -

-
- -
-

- Add Pie Chart -

-
-
-

Generating images takes roughly 1 second per minute - of your workout's duration. Please reload after a minute or so.

-
-
- {% if graphs1 %} - - {% for graph in graphs1 %} - {% if forloop.counter == 1 %} -
- - {{ graph.filename }} -
- {% elif forloop.counter == 3 %} -
- - {{ graph.filename }} -
- - {% else %} -
- - {{ graph.filename }} -
- {% endif %} - {% endfor %} - - - {% for graph in graphs2 %} - {% if forloop.counter == 1 %} -
- - {{ graph.filename }} -
- {% elif forloop.counter == 3 %} -
- - {{ graph.filename }} -
- - {% else %} -
- - {{ graph.filename }} -
- {% endif %} - {% endfor %} - - - - - {% else %} -

No graphs found

- {% endif %} -
- - - - -
-

Workout Summary

- -

-

-{{ workout.summary }}
-
-

- -
- -
- {{ the_div|safe }} -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templates/workout_view.html~ b/rowers/templates/workout_view.html~ deleted file mode 100644 index 0d9b6e20..00000000 --- a/rowers/templates/workout_view.html~ +++ /dev/null @@ -1,142 +0,0 @@ -{% extends "base.html" %} -{% load staticfiles %} -{% load rowerfilters %} - -{% block title %}View Workout {% endblock %} - -{% block content %} -
- - -

Workout Data

- - - - - - - - - - - - - - - - - - - - -
Rower:{{ first_name }} {{ last_name }}
Name:{{ workout.name }}
Date:{{ workout.date }}
Time:{{ workout.starttime }}
Distance:{{ workout.distance }}m
Duration:{{ workout.duration |durationprint:"%H:%M:%S.%f" }}
Type:{{ workout.workouttype }}
Weight Category:{{ workout.weightcategory }}
- -

Workout Summary

- -

-

-{{ workout.summary }}
-
-

- -
-
- -

Images linked to this workout

- {% if graphs1 %} - - {% for graph in graphs1 %} - {% if forloop.counter == 1 %} -
- - {{ graph.filename }} -
- {% elif forloop.counter == 3 %} -
- - {{ graph.filename }} -
- - {% else %} -
- - {{ graph.filename }} -
- {% endif %} - {% endfor %} - - - {% for graph in graphs2 %} - {% if forloop.counter == 1 %} -
- - {{ graph.filename }} -
- {% elif forloop.counter == 3 %} -
- - {{ graph.filename }} -
- - {% else %} -
- - {{ graph.filename }} -
- {% endif %} - {% endfor %} - - - - - {% else %} -

No graphs found

- {% endif %} -
- - - - - {{ interactiveplot |safe }} - - - - - -
- {{ the_div|safe }} - -
- -{% endblock %} \ No newline at end of file diff --git a/rowers/templatetags/__init__.pyc b/rowers/templatetags/__init__.pyc deleted file mode 100644 index 2338838d..00000000 Binary files a/rowers/templatetags/__init__.pyc and /dev/null differ diff --git a/rowers/templatetags/rowerfilters.pyc b/rowers/templatetags/rowerfilters.pyc deleted file mode 100644 index e434f2c2..00000000 Binary files a/rowers/templatetags/rowerfilters.pyc and /dev/null differ diff --git a/rowers/templatetags/rowerfilters.py~ b/rowers/templatetags/rowerfilters.py~ deleted file mode 100644 index 665f66a3..00000000 --- a/rowers/templatetags/rowerfilters.py~ +++ /dev/null @@ -1,20 +0,0 @@ -from django import template -from time import strftime - -register = template.Library() - -@register.filter -def durationprint(d,dstring): - if (d == None): - return d - else: - return d.strftime(dstring)[:-5] - -@register.filter -def lookup(dict, key): - s = dict.get(key) - - if isinstance(s,basestring) and len(s) > 22: - s = s[:22] - return s - diff --git a/rowers/tests.py~ b/rowers/tests.py~ deleted file mode 100644 index ec62d6c7..00000000 --- a/rowers/tests.py~ +++ /dev/null @@ -1,1017 +0,0 @@ -from django.test import TestCase, Client -from .views import checkworkoutuser,c2_open -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage -from rowers.forms import DocumentsForm,CNsummaryForm -import rowers.plots as plots -import rowers.interactiveplots as iplots -import datetime -from rowingdata import rowingdata as rdata -from rowingdata import rower as rrower -from rowsandall_app.rows import handle_uploaded_file -from django.core.files.uploadedfile import SimpleUploadedFile -from time import strftime,strptime,mktime,time,daylight -import os -from rowers.tasks import handle_makeplot -from rowers.c2stuff import C2NoTokenError - -import json - -# Create your tests here. - -class WorkoutTests(TestCase): - def setUp(self): - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u) - nu = datetime.datetime.now() - w = Workout.objects.create(name='testworkout',workouttype='On-water', - user=r,date=nu.strftime('%Y-%m-%d'), - starttime=nu.strftime('%H:%M:%S'), - duration="0:55:00",distance=8000) - - def test_checkworkoutuser(self): - u = User.objects.get(username='john') - r = Rower.objects.get(user=u) - w = Workout.objects.get(user=r) - - self.assertEqual(checkworkoutuser(u,w),True) - -class C2Tests(TestCase): - def setUp(self): - self.u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - self.r = Rower.objects.create(user=u) - self.nu = datetime.datetime.now() - self.w = Workout.objects.create(name='testworkout',workouttype='On-water', - user=r,date=nu.strftime('%Y-%m-%d'), - starttime=nu.strftime('%H:%M:%S'), - duration="0:55:00",distance=8000) - - def c2_notokentest(self): - thetoken = c2_open(self.u) - # should raise C2NoTokenError - self.assertRaises(C2NoTokenError) - -class DataTest(TestCase): - def setUp(self): - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u) - self.nu = datetime.datetime.now() - - - def test_workoutform(self): - form_data = { - 'name':'test', - 'date':'2016-05-01', - 'starttime':'07:53:00', - 'duration':'0:55:00.1', - 'distance':8000, - 'notes':'Aap noot \n mies', - 'workouttype':'water', - } - form = WorkoutForm(data=form_data) - self.assertTrue(form.is_valid()) - - def test_rower_form_withvalidnumbers(self): - form_data = { - 'max':192, - 'rest':48, - 'ut2':105, - 'ut1':148, - 'at':160, - 'tr':167, - 'an':180, - 'weightcategory':'lwt', - } - form = RowerForm(data=form_data) - self.assertTrue(form.is_valid()) - - - def test_rower_form_twoequalvalues(self): - form_data = { - 'max':192, - 'rest':48, - 'ut2':105, - 'ut1':105, - 'at':160, - 'an':180, - 'tr':167, - 'weightcategory':'lwt', - } - form = RowerForm(data=form_data) - self.assertFalse(form.is_valid()) - - def test_rower_form_abovemaxallowed(self): - form_data = { - 'max':300, - 'rest':48, - 'ut2':105, - 'ut1':148, - 'at':160, - 'an':180, - 'tr':167, - 'weightcategory':'lwt', - } - form = RowerForm(data=form_data) - self.assertFalse(form.is_valid()) - - def test_rower_form_wrongorder(self): - form_data = { - 'max':192, - 'rest':48, - 'ut2':20, - 'ut1':148, - 'at':160, - 'an':180, - 'tr':167, - 'weightcategory':'lwt', - } - form = RowerForm(data=form_data) - self.assertFalse(form.is_valid()) - - def test_rower_form_belowminalloed(self): - form_data = { - 'max':192, - 'rest':2, - 'ut2':105, - 'ut1':148, - 'at':160, - 'an':180, - 'tr':167, - 'weightcategory':'lwt', - } - form = RowerForm(data=form_data) - self.assertFalse(form.is_valid()) - - def test_rower_form_wrongorder2(self): - form_data = { - 'max':192, - 'rest':48, - 'ut2':105, - 'ut1':170, - 'at':160, - 'an':180, - 'tr':167, - 'weightcategory':'lwt', - } - form = RowerForm(data=form_data) - self.assertFalse(form.is_valid()) - - def test_painsled(self): - filename = 'C:\\python\\rowingdata\\testdata\\testdata.csv' - f = open(filename,'rb') - file_data = {'file': SimpleUploadedFile(f.name, f.read())} - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - } - - form = DocumentsForm(form_data,file_data) - self.assertTrue(form.is_valid()) - - f.close() - - u = User.objects.get(username='john') - r = Rower.objects.get(user=u) - - - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - 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.ix[0,' ElapsedTime (sec)'] - - - 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) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - w = Workout.objects.create(name='testworkout',workouttype='On-water', - user=r,date=self.nu.strftime('%Y-%m-%d'), - starttime=workoutstarttime, - duration=duration,distance=totaldist, - csvfilename=filename) - - - fig1 = plots.mkplot(row,'test') - res = iplots.interactive_chart(w.id) - res = iplots.interactive_chart(w.id,promember=1) - res = iplots.interactive_bar_chart(w.id) - res = iplots.interactive_bar_chart(w.id,promember=1) - res = iplots.interactive_flex_chart(w.id,promember=0,xparam='time', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart(w.id,promember=0,xparam='distance', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart(w.id,promember=0,xparam='time', - yparam1='pace',yparam2='spm') - res = iplots.interactive_flex_chart(w.id,promember=0,xparam='distance', - yparam1='pace',yparam2='spm') - - res = iplots.interactive_flex_chart(w.id,promember=1,xparam='time', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart(w.id,promember=1,xparam='distance', - yparam1='pace',yparam2='hr') - res = iplots.interactive_flex_chart(w.id,promember=1,xparam='time', - yparam1='pace',yparam2='spm') - res = iplots.interactive_flex_chart(w.id,promember=1,xparam='distance', - yparam1='pace',yparam2='spm') - - - - -class ViewTest(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) - self.nu = datetime.datetime.now() - - def test_upload_view_notloggedin(self): - response = self.c.post('/rowers/workout/upload/',follow=True) - - - self.assertRedirects(response, expected_url='/login/?next=/rowers/workout/upload/', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - def test_upload_view_sled(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\testdata.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - - f.close() - - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - response = self.c.get('/rowers/workout/1/', form_data, follow=True) - self.assertEqual(response.status_code, 200) - - response = self.c.get('/rowers/workout/1/interactiveplot', form_data, follow=True) - self.assertEqual(response.status_code, 200) - - - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - - def test_upload_view_notloggedin(self): - response = self.c.post('/rowers/workout/upload/',follow=True) - - - self.assertRedirects(response, expected_url='/login/?next=/rowers/workout/upload/', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - def test_upload_view_sled_negativetime(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\tim.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - - f.close() - - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - response = self.c.get('/rowers/workout/1/', form_data, follow=True) - self.assertEqual(response.status_code, 200) - - response = self.c.get('/rowers/workout/1/interactiveplot', form_data, follow=True) - self.assertEqual(response.status_code, 200) - - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - - - - def test_upload_view_sled_noname(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\testdata.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - - f.close() - - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - - - def test_upload_view_TCX_CN(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\crewnerddata.tcx' - f = open(filename,'rb') - file_data = {'file': f} - - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - filename = 'C:\\python\\rowingdata\\testdata\\crewnerddata.CSV' - f = open(filename,'rb') - file_data = {'file': f} - form_data = {} - form = CNsummaryForm(form_data,file_data) - - response = self.c.post('rowers/workout/1/crewnerdsummary', - form_data, - follow=True) - - f.close() - - self.assertEqual(response.status_code, 200) - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_TCX_SpeedCoach2(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\Speedcoach2example.csv' - f = open(filename,'rb') - file_data = {'file': f} - - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_TCX_SpeedCoach2(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\Speedcoach2example.csv' - f = open(filename,'rb') - file_data = {'file': f} - - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - - - def test_upload_view_TCX_SpeedCoach2(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\speedcoach3test3.csv' - f = open(filename,'rb') - file_data = {'file': f} - - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_TCX_NoHR(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\NoHR.tcx' - f = open(filename,'rb') - file_data = {'file': f} - - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_TCX_CN(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\rowinginmotionexample.tcx' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_RP(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\RP_testdata.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_Mystery(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\mystery.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_RP_interval(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\RP_interval.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_sled_desktop(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\painsled_desktop_example.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_sled_ergdata(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\ergdata_example.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_sled_ergstick(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\ergstick.csv' - f = open(filename,'rb') - file_data = {'file': f} - form_data = { - 'title':'test', - 'workouttype':'rower', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - - def test_upload_view_FIT_SpeedCoach2a(self): - self.c.login(username='john',password='koeinsloot') - - filename = 'C:\\python\\rowingdata\\testdata\\3x250m.fit' - f = open(filename,'rb') - file_data = {'file': f} - - form_data = { - 'title':'test', - 'workouttype':'water', - 'notes':'aap noot mies', - 'make_plot':False, - 'upload_to_c2':False, - 'plottype':'timeplot', - 'file': f, - } - - form = DocumentsForm(form_data,file_data) - - response = self.c.post('/rowers/workout/upload/', form_data, follow=True) - f.close() - self.assertRedirects(response, expected_url='/rowers/workout/1/edit', - status_code=302,target_status_code=200) - - self.assertEqual(response.status_code, 200) - - w = Workout.objects.get(id=1) - f_to_be_deleted = w.csvfilename - os.remove(f_to_be_deleted) - -class subroutinetests(TestCase): - def setUp(self): - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u) - nu = datetime.datetime.now() - filename = 'C:\\python\\rowingdata\\testdata\\testdata.csv' - self.w = Workout.objects.create(name='testworkout', - workouttype='On-water', - user=r,date=nu.strftime('%Y-%m-%d'), - starttime=nu.strftime('%H:%M:%S'), - duration="0:55:00",distance=8000, - csvfilename=filename) - - def test_seconds(self): - seconds = [30.3,75.8,3900.3,104670.2] - res = iplots.get_datetimes(seconds) - - - def c2stuff(self): - data = c2stuff.createc2workoutdata(self.w) - jsond = json.dumps(data) - data = c2stuff.createc2workoutdata_as_splits(w) - jsond = json.dumps(data) - data = c2stuff.createc2workoutdata_as_grouped(w) - jsond = json.dumps(data) - - -class PlotTests(TestCase): - def setUp(self): - u = User.objects.create_user('john', - 'sander@ds.ds', - 'koeinsloot') - r = Rower.objects.create(user=u) - self.nu = datetime.datetime.now() - filename = 'C:\\python\\rowingdata\\testdata\\testdata.csv' - self.wotw = Workout.objects.create(name='testworkout', - workouttype='On-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=filename) - -# timestr = strftime("%Y%m%d-%H%M%S") -# imagename = f1+timestr+'.png' -# fullpathimagename = 'static/plots/'+imagename - self.hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - - def test_ote_plots(self): - w = self.wote - f1 = 'testdata.csv'[:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - # make plot - asynchronous task - plotnr = 1 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 1 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 2 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 3 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 4 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 5 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 6 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 7 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 8 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - def test_otw_plots(self): - w = self.wotw - f1 = 'testdata.csv'[:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - # make plot - asynchronous task - plotnr = 1 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 1 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 2 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 3 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 4 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 5 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 6 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 7 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) - - plotnr = 8 - if (w.workouttype=='water'): - plotnr = plotnr+3 - - res = handle_makeplot(f1,w.csvfilename, - w.name,self.hrdata,plotnr,imagename) - i = GraphImage(workout=w,creationdatetime=self.nu, - filename=fullpathimagename) - os.remove(fullpathimagename) diff --git a/rowers/urls.pyc b/rowers/urls.pyc deleted file mode 100644 index 5976cb9d..00000000 Binary files a/rowers/urls.pyc and /dev/null differ diff --git a/rowers/urls.py~ b/rowers/urls.py~ deleted file mode 100644 index 1eac2682..00000000 --- a/rowers/urls.py~ +++ /dev/null @@ -1,145 +0,0 @@ -from django.conf import settings -from django.conf.urls import url, include - -from . import views -from django.contrib.auth import views as auth_views -from django.views.generic.base import TemplateView -from django.conf.urls import ( - handler400, handler403, handler404, handler500, - ) - -handler500 = 'views.error500_view' -handler404 = 'views.error404_view' -handler400 = 'views.error400_view' -handler403 = 'views.error403_view' - -urlpatterns = [ -# url(r'^password_change/$',auth_views.password_change), -# url(r'^password_change_done/$',auth_views.password_change_done), - url(r'^testbokeh$',views.testbokeh), - url(r'^500/$', TemplateView.as_view(template_name='500.html'),name='500'), - url(r'^404/$', TemplateView.as_view(template_name='404.html'),name='404'), - url(r'^400/$', TemplateView.as_view(template_name='400.html'),name='400'), - url(r'^403/$', TemplateView.as_view(template_name='403.html'),name='403'), - url(r'^imports/s/(?P\w+.*)/$', TemplateView.as_view(template_name='imports.html'), name='imports'), - url(r'^imports/$', TemplateView.as_view(template_name='imports.html'), name='imports'), - url(r'^list-workouts/c/(?P\w+.*)/$',views.workouts_view), - url(r'^list-workouts/s/(?P\w+.*)/$',views.workouts_view), - url(r'^list-workouts/c/(?P\w+.*)/s/(?P\w+.*)$',views.workouts_view), - url(r'^list-workouts/$',views.workouts_view), - url(r'^list-graphs/$',views.graphs_view), - url(r'^dashboard/c/(?P\w+.*)/$',views.dashboard_view), - url(r'^dashboard/s/(?P\w+.*)/$',views.dashboard_view), - url(r'^dashboard/c/(?P\w+.*)/s/(?P\w+.*)$',views.dashboard_view), - url(r'^dashboard/$',views.dashboard_view), - url(r'^(?P\d+)/ote-bests/(?P\w+.*)/(?P\w+.*)$',views.rankings_view), - url(r'^(?P\d+)/ote-bests/(?P\d+)$',views.rankings_view), - url(r'^ote-bests/(?P\w+.*)/(?P\w+.*)$',views.rankings_view), - url(r'^ote-bests/(?P\d+)$',views.rankings_view), - url(r'^ote-bests/$',views.rankings_view), - url(r'^(?P\d+)/ote-bests/$',views.rankings_view), - - url(r'^flexall/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.cum_flex), - url(r'^flexall/$',views.cum_flex), - - url(r'^(?P\d+)/histo/(?P\w+.*)/(?P\w+.*)$',views.histo), - url(r'^(?P\d+)/histo/(?P\d+)$',views.histo), - url(r'^histo/(?P\w+.*)/(?P\w+.*)$',views.histo), - url(r'^histo/(?P\d+)$',views.histo), - url(r'^histo/$',views.histo), - url(r'^histo-all/$',views.histo_all), - url(r'^(?P\d+)/histo-all/$',views.histo_all), - url(r'^graph/(\d+)/$',views.graph_show_view), - url(r'^graph/(\d+)/deleteconfirm$',views.graph_delete_confirm_view), - url(r'^graph/(\d+)/delete$',views.graph_delete_view), - url(r'^workout/upload/$',views.workout_upload_view), - url(r'^workout/upload/(.+.*)$',views.workout_upload_view), - url(r'^workout/(?P\d+)/export/c/(?P\w+.*)/s/(?P\w+.*)$',views.workout_export_view), - url(r'^workout/(?P\d+)/export/c/(?P\w+.*)$',views.workout_export_view), - url(r'^workout/(?P\d+)/export/s/(?P\w+.*)$',views.workout_export_view), - url(r'^workout/(?P\d+)/export$',views.workout_export_view), - url(r'^workout/(\d+)/emailtcx$',views.workout_tcxemail_view), - url(r'^workout/(\d+)/emailcsv$',views.workout_csvemail_view), - url(r'^workout/compare/(\d+)/$',views.workout_comparison_list), - url(r'^workout/compare2/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P\w+.*)/$',views.workout_comparison_view), - url(r'^workout/(?P\d+)/export/c/(?P\w+.*)/s/(?P\w+.*)$',views.workout_edit_view), - url(r'^workout/(?P\d+)/edit/c/(?P.+.*)$',views.workout_edit_view), - url(r'^workout/(?P\d+)/edit/s/(?P.+.*)$',views.workout_edit_view), - url(r'^workout/(\d+)/edit$',views.workout_edit_view), - url(r'^workout/(?P\d+)/advanced/c/(?P.+.*)$',views.workout_advanced_view), - url(r'^workout/(?P\d+)/advanced/s/(?P.+.*)$',views.workout_advanced_view), - url(r'^workout/(?P\d+)/geeky$',views.workout_geeky_view), - url(r'^workout/(\d+)/advanced$',views.workout_advanced_view), - url(r'^workout/(\d+)/otwsetpower$',views.workout_otwsetpower_view), - url(r'^workout/(\d+)/interactiveotwplot$',views.workout_otwpowerplot_view), - url(r'^workout/(\d+)/wind$',views.workout_wind_view), - url(r'^workout/(?P\d+)/wind/c/(?P\w+.*)$',views.workout_wind_view), - url(r'^workout/(?P\d+)/wind/s/(?P\w+.*)$',views.workout_wind_view), - url(r'^workout/(?P\d+)/darkskywind$',views.workout_downloadwind_view), - url(r'^workout/(\d+)/stream$',views.workout_stream_view), - url(r'^workout/(?P\d+)/stream/c/(?P\w+.*)$',views.workout_stream_view), - url(r'^workout/(\d+)/crewnerdsummary$',views.workout_crewnerd_summary_view), - url(r'^workout/(?P\d+)/editintervals/(?P\w+.*)$',views.workout_summary_edit_view), - url(r'^workout/(\d+)/editintervals$',views.workout_summary_edit_view), - url(r'^workout/(\d+)/restore$',views.workout_summary_restore_view), - url(r'^workout/(\d+)/interactiveplot$',views.workout_biginteractive_view), - url(r'^workout/(\d+)/view$',views.workout_view), - url(r'^workout/(\d+)$',views.workout_view), - url(r'^physics$',TemplateView.as_view(template_name='physics.html'),name='physics'), - url(r'^workout/(\d+)/$',views.workout_view), - url(r'^workout/(\d+)/addtimeplot$',views.workout_add_timeplot_view), - url(r'^workout/(\d+)/addpiechart$',views.workout_add_piechart_view), - url(r'^workout/(\d+)/adddistanceplot$',views.workout_add_distanceplot_view), - url(r'^workout/(\d+)/adddistanceplot2$',views.workout_add_distanceplot2_view), - url(r'^workout/(\d+)/addotwpowerplot$',views.workout_add_otw_powerplot_view), - url(r'^workout/(\d+)/addtimeplot2$',views.workout_add_timeplot2_view), - url(r'^workout/(\d+)/delete$',views.workout_delete_view), - url(r'^workout/(\d+)/smoothenpace$',views.workout_smoothenpace_view), - url(r'^workout/(\d+)/undosmoothenpace$',views.workout_undo_smoothenpace_view), - url(r'^workout/c2import/c/(?P\w+.*)$',views.workout_c2import_view), - url(r'^workout/c2import/$',views.workout_c2import_view), - url(r'^workout/stravaimport/$',views.workout_stravaimport_view), - url(r'^workout/c2import/(\d+)/$',views.workout_getc2workout_view), - url(r'^workout/stravaimport/(\d+)/$',views.workout_getstravaworkout_view), - url(r'^workout/sporttracksimport/$',views.workout_sporttracksimport_view), - url(r'^workout/sporttracksimport/(\d+)/$',views.workout_getsporttracksworkout_view), - url(r'^workout/(\d+)/deleteconfirm$',views.workout_delete_confirm_view), - url(r'^workout/(\d+)/c2upload/$',views.list_c2_upload_view), - url(r'^workout/(\d+)/c2uploadw/$',views.workout_c2_upload_view), - url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view), - url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view), - url(r'^me/edit/$',views.rower_edit_view), - url(r'^me/edit/(.+.*)/$',views.rower_edit_view), - url(r'^me/c2authorize/$',views.rower_c2_authorize), - url(r'^me/stravaauthorize/$',views.rower_strava_authorize), - url(r'^me/sporttracksauthorize/$',views.rower_sporttracks_authorize), - url(r'^me/sporttracksrefresh/$',views.rower_sporttracks_token_refresh), - url(r'^me/c2refresh/$',views.rower_c2_token_refresh), - url(r'^email/send/$', views.sendmail), - url(r'^email/thankyou/$', TemplateView.as_view(template_name='thankyou.html'), name='thankyou'), - url(r'^email/$', TemplateView.as_view(template_name='email.html'), name='email'), - url(r'^about', TemplateView.as_view(template_name='about_us.html'),name='about'), - url(r'^videos', TemplateView.as_view(template_name='videos.html'),name='videos'), - url(r'^analysis', TemplateView.as_view(template_name='analysis.html'),name='analysis'), - url(r'^promembership', TemplateView.as_view(template_name='promembership.html'),name='promembership'), - url(r'^legal', TemplateView.as_view(template_name='legal.html'),name='legal'), - url(r'^register$',views.rower_register_view), - url(r'^register/thankyou/$', TemplateView.as_view(template_name='registerthankyou.html'), name='registerthankyou'), - url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\w+)/$',views.workout_flexchart2_view), - url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_flexchart2_view), - url(r'^workout/(?P\d+)/flexchart/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_flexchart2_view), - url(r'^workout/(?P\d+)/flexchart$',views.workout_flexchart2_view), - url(r'^workout/(?P\d+)/flexchart2/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\w+)/$',views.workout_flexchart3_view), - url(r'^workout/(?P\d+)/flexchart2/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_flexchart3_view), - url(r'^workout/(?P\d+)/flexchart2/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_flexchart3_view), - url(r'^workout/(?P\d+)/flexchart2$',views.workout_flexchart3_view), - url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P\w+.*)/(?P\w+.*)$',views.workout_comparison_view2), - url(r'^workout/compare/(?P\d+)/(?P\d+)/(?P\w+.*)/(?P\w+.*)/$',views.workout_comparison_view2), - ] - -if settings.DEBUG: - urlpatterns += [ - url(r'^workout/uploadd/$',views.workout_upload_view_debug), - url(r'^testreverse/$',views.test_reverse_view), - url(r'^c2listug/$',views.c2listdebug_view), - ] diff --git a/rowers/views.py b/rowers/views.py index 6d84ceb3..47420fa3 100644 --- a/rowers/views.py +++ b/rowers/views.py @@ -1295,14 +1295,19 @@ def cum_flex(request,theuser=0, promember=promember) script = res[0] div = res[1] + js_resources = res[2] + css_resources = res[3] else: script = '' div = '

No erg pieces uploaded for this date range.

' - + js_resources = '' + css_resources = '' return render(request, 'cum_flex.html', {'interactiveplot':script, 'the_div':div, + 'js_res': js_resources, + 'css_res':css_resources, 'id':theuser, 'theuser':u, 'startdate':startdate, diff --git a/rowers/views.pyc b/rowers/views.pyc deleted file mode 100644 index faa9087c..00000000 Binary files a/rowers/views.pyc and /dev/null differ diff --git a/rowers/views.py~ b/rowers/views.py~ deleted file mode 100644 index 6d84ceb3..00000000 --- a/rowers/views.py~ +++ /dev/null @@ -1,4243 +0,0 @@ -import time -from django.views.generic.base import TemplateView -from django.shortcuts import render -from django.http import HttpResponse, HttpResponseRedirect -from django.contrib.auth import authenticate, login, logout -from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm -from django.core.urlresolvers import reverse -from django.template import RequestContext -from django.conf import settings -from django.utils.datastructures import MultiValueDictKeyError -from django.utils import timezone,translation -from django.core.mail import send_mail, BadHeaderError -from rowers.forms import EmailForm, RegistrationForm, RegistrationFormTermsOfService,RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,UpdateStreamForm -from rowers.forms import PredictedPieceForm,DateRangeForm,DeltaDaysForm -from rowers.forms import SummaryStringForm,IntervalUpdateForm -from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage,AdvancedWorkoutForm -import StringIO -from django.contrib.auth.decorators import login_required,user_passes_test -from time import strftime,strptime,mktime,time,daylight -import os,sys -import datetime -import iso8601 -import c2stuff -from c2stuff import C2NoTokenError -from iso8601 import ParseError -import stravastuff -import sporttracksstuff -from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET -from rowsandall_app.settings import SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET -import requests -import json -from rowsandall_app.rows import handle_uploaded_file -from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv -from rowers.tasks import handle_sendemail_unrecognized -from scipy.signal import savgol_filter -from django.shortcuts import render_to_response - -from rowingdata import rower as rrower -from rowingdata import main as rmain -from rowingdata import rowingdata as rrdata -from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR -from rowingdata import MysteryParser -from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser -from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata -from rowingdata import make_cumvalues -from rowingdata import summarydata,get_file_type -import pandas as pd -import numpy as np -import matplotlib.pyplot as plt -from pytz import timezone as tz,utc -import dateutil -import mpld3 -from mpld3 import plugins -import stravalib -from stravalib.exc import ActivityUploadFailed,TimeoutExceeded -from weather import get_wind_data - -import django_rq -queue = django_rq.get_queue('default') -queuelow = django_rq.get_queue('low') -queuehigh = django_rq.get_queue('low') - -import plots -import mailprocessing - -from io import BytesIO -from scipy.special import lambertw - - -LOCALTIMEZONE = tz('Etc/UTC') -USER_LANGUAGE = 'en-US' - -from interactiveplots import * - -def error500_view(request): - response = render_to_response('500.html', {}, - context_instance = RequestContext(request)) - - response.status_code = 500 - return response - -def error404_view(request): - response = render_to_response('404.html', {}, - context_instance = RequestContext(request)) - - response.status_code = 404 - return response - -def error400_view(request): - response = render_to_response('400.html', {}, - context_instance = RequestContext(request)) - - response.status_code = 400 - return response - -def error403_view(request): - response = render_to_response('403.html', {}, - context_instance = RequestContext(request)) - - response.status_code = 403 - return response - -def rdata(file,rower=rrower()): - try: - res = rrdata(file,rower=rower) - except IOError: - res = 0 - - return res - -def get_time(second): - if (second<=0) or (second>1e9): - hours = 0 - minutes=0 - sec=0 - microsecond = 0 - elif math.isnan(second): - hours = 0 - minutes=0 - sec=0 - microsecond = 0 - else: - days = int(second/(24.*3600.)) % (24*3600) - hours = int((second-24.*3600.*days)/3600.) % 24 - minutes = int((second-3600.*(hours+24.*days))/60.) % 60 - sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60 - microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec)) - return datetime.time(hours,minutes,sec,microsecond) - - - -def getidfromsturi(uri): - return uri[len(uri)-8:] - -def splitstdata(lijst): - t = [] - latlong = [] - while len(lijst)>=2: - t.append(lijst[0]) - latlong.append(lijst[1]) - lijst = lijst[2:] - - return [np.array(t),np.array(latlong)] - - -def geo_distance(lat1,lon1,lat2,lon2): - """ Approximate distance and bearing between two points - defined by lat1,lon1 and lat2,lon2 - This is a slight underestimate but is close enough for our purposes, - We're never moving more than 10 meters between trackpoints - - Bearing calculation fails if one of the points is a pole. - - """ - - # radius of earth in km - R = 6373.0 - - # pi - pi = math.pi - - lat1 = math.radians(lat1) - lat2 = math.radians(lat2) - lon1 = math.radians(lon1) - lon2 = math.radians(lon2) - - dlon = lon2 - lon1 - dlat = lat2 - lat1 - - a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2 - c = 2 * atan2(sqrt(a), sqrt(1 - a)) - - distance = R * c - - tc1 = atan2(sin(lon2-lon1)*cos(lat2), - cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1)) - - tc1 = tc1 % (2*pi) - - bearing = math.degrees(tc1) - - return [distance,bearing] - -def promember(user): - r = Rower.objects.get(user=user) - result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach') - return result - -def rower_register_view(request): - if request.method == 'POST': - form = RegistrationFormUniqueEmail(request.POST) - if form.is_valid(): - first_name = form.cleaned_data['first_name'] - last_name = form.cleaned_data['last_name'] - email = form.cleaned_data['email'] - password = form.cleaned_data['password1'] - username = form.cleaned_data['username'] - theuser = User.objects.create_user(username,password=password) - theuser.first_name = first_name - theuser.last_name = last_name - theuser.email = email - theuser.save() - - - therower = Rower(user=theuser) - - therower.save() - - fullemail = first_name + " " + last_name + " " + "<" + email + ">" - subject = "Thank you for registering on rowsandall.com" - message = "Thank you for registering on rowsandall.com. You can now login using the credentials you provided.\n" - message += "The first thing you might want to do is check and edit the heart rate band values. After logging in, click the button with your first name.\n" - message += "You can also check our videos page at http://rowsandall.com/rowers/videos for some helpful instruction videos.\n\n" - message += "User name:"+username+"\n" - message += "Password :"+password+"\n\n" - message += "For all your questions, just reply to this email.\n\n" - message += "Happy rowing!\n\n\n" - message += "Oh, one more thing. The site is currently in beta and is developing fast. Bear with us. Don't hesitate to contact me if anything is broken or doesn't seem to work as advertised." - send_mail(subject, message, - 'Sander Roosendaal ', - [fullemail]) - - subject2 = "New User" - message2 = "New user registered.\n" - message2 += fullemail + "\n" - message2 += "User name: "+username - - send_mail(subject2, message2, - 'Rowsandall Server ', - ['roosendaalsander@gmail.com']) - - return HttpResponseRedirect('/rowers/register/thankyou/') - - else: - return render(request, - "registration_form.html", - {'form':form}) - else: - form = RegistrationFormUniqueEmail() - return render(request, - "registration_form.html", - {'form':form,}) - -def sendmail(request): - if request.method == 'POST': - form = EmailForm(request.POST) - if form.is_valid(): - firstname = form.cleaned_data['firstname'] - lastname = form.cleaned_data['lastname'] - email = form.cleaned_data['email'] - subject = form.cleaned_data['subject'] - botcheck = form.cleaned_data['botcheck'].lower() - message = form.cleaned_data['message'] - if botcheck == 'yes': - try: - fullemail = firstname + " " + lastname + " " + "<" + email + ">" - send_mail(subject, message, fullemail, ['info@rowsandall.com']) - return HttpResponseRedirect('/rowers/email/thankyou/') - except: - return HttpResponseRedirect('/rowers/email/') - else: - return HttpResponseRedirect('/rowers/email/') - else: - return HttpResponseRedirect('/rowers/email/') - -def checkworkoutuser(user,workout): - try: - r = Rower.objects.get(user=user) - return (workout.user == r) - except Rower.DoesNotExist: - return(False) - -def add_workout_from_strokedata(user,importid,data,strokedata,source='c2'): - workouttype = data['type'] - if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'water' - try: - comments = data['comments'] - except: - comments = ' ' - -# comments = "Imported data \n %s" % comments -# comments = "Imported data \n"+comments # str(comments) - try: - thetimezone = tz(data['timezone']) - except: - thetimezone = 'UTC' - - r = Rower.objects.get(user=user) - try: - rowdatetime = iso8601.parse_date(data['date_utc']) - except KeyError: - rowdatetime = iso8601.parse_date(data['start_date']) - except ParseError: - rowdatetime = iso8601.parse_date(data['date']) -# try: - # rowdatetime = datetime.datetime.strptime(data['date_utc'],"%Y-%m-%d %H:%M:%S") - # rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) -# except KeyError: -# try: -# rowdatetime = dateutil.parser.parse(data['start_date']) -# 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: - c2intervaltype = data['workout_type'] - - except KeyError: - c2intervaltype = '' - - try: - title = data['name'] - except KeyError: - title = "" - try: - t = data['comments'].split('\n', 1)[0] - title += t[:20] - except: - pass - - starttimeunix = mktime(rowdatetime.timetuple()) - - res = make_cumvalues(0.1*strokedata['t']) - cum_time = res[0] - lapidx = res[1] - - unixtime = cum_time+starttimeunix - # unixtime[0] = starttimeunix - seconds = 0.1*strokedata.ix[:,'t'] - - nr_rows = len(unixtime) - - try: - latcoord = strokedata.ix[:,'lat'] - loncoord = strokedata.ix[:,'lon'] - except: - latcoord = np.zeros(nr_rows) - loncoord = np.zeros(nr_rows) - - - try: - strokelength = strokedata.ix[:,'strokelength'] - except: - strokelength = np.zeros(nr_rows) - - dist2 = 0.1*strokedata.ix[:,'d'] - - spm = strokedata.ix[:,'spm'] - hr = strokedata.ix[:,'hr'] - pace = strokedata.ix[:,'p']/10. - - velo = 500./pace -# if (source=='c2' or source=='strava'): - power = 2.8*velo**3 -# else: -# power = 0.0*velo - - # 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, - ' 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 - }) - - # data.sort(['TimeStamp (sec)'],ascending=True) - df.sort_values(by='TimeStamp (sec)',ascending=True) - - timestr = strftime("%Y%m%d-%H%M%S") - - # auto smoothing - pace = df[' Stroke500mPace (sec/500m)'].values - velo = 500./pace - - f = df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - if windowsize <= 3: - windowsize = 5 - - df['originalvelo'] = velo - - if windowsize > 3: - velo2 = savgol_filter(velo,windowsize,3) - else: - velo2=velo - - pace2 = 500./abs(velo2) - df[' Stroke500mPace (sec/500m)'] = pace2 - - df = df.fillna(0) - - # end autosmoothing - - csvfilename ='media/Import_'+str(importid)+'.csv' - - res = df.to_csv(csvfilename,index_label='index') - - averagehr = df[' HRCur (bpm)'].mean() - maxhr = df[' HRCur (bpm)'].max() - - # make workout - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - row = rdata(csvfilename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - 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) - - - summary = row.summary() - summary += '\n' - summary += row.intervalstats() - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - # check for duplicate start times - ws = Workout.objects.filter(starttime=workoutstarttime, - user=r) - if (len(ws) != 0): - print "Warning: This workout probably already exists in the database" - - w = Workout(user=r,name=title, - date=workoutdate,workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=r.weightcategory, - starttime=workoutstarttime, - csvfilename=csvfilename,notes=comments, - uploadedtoc2=0,summary=summary, - averagehr=averagehr,maxhr=maxhr, - startdatetime=rowdatetime) - w.save() - - return w.id - -def add_workout_from_stdata(user,importid,data): - workouttype = data['type'] - if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'water' - try: - comments = data['comments'] - except: - comments = '' - -# comments = "Imported data \n"+str(comments) - try: - thetimezone = tz(data['timezone']) - except: - thetimezone = 'UTC' - - r = Rower.objects.get(user=user) - try: - 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: - c2intervaltype = data['workout_type'] - - except: - c2intervaltype = '' - - try: - title = data['name'] - except: - title = "Imported data" - - starttimeunix = mktime(rowdatetime.timetuple()) - - res = splitstdata(data['distance']) - - distance = res[1] - times_distance = res[0] - - try: - l = data['location'] - - 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) - except: - times_location = times_distance - latcoord = np.zeros(len(times_distance)) - loncoord = np.zeros(len(times_distance)) - - - try: - res = splitstdata(data['cadence']) - times_spm = res[0] - spm = res[1] - except KeyError: - times_spm = times_distance - spm = 0*times_distance - - try: - res = splitstdata(data['heartrate']) - hr = res[1] - times_hr = res[0] - except KeyError: - times_hr = times_distance - hr = 0*times_distance - - - # create data series and remove duplicates - distseries = pd.Series(distance,index=times_distance) - distseries = distseries.groupby(distseries.index).first() - latseries = pd.Series(latcoord,index=times_location) - latseries = latseries.groupby(latseries.index).first() - lonseries = pd.Series(loncoord,index=times_location) - lonseries = lonseries.groupby(lonseries.index).first() - spmseries = pd.Series(spm,index=times_spm) - spmseries = spmseries.groupby(spmseries.index).first() - hrseries = pd.Series(hr,index=times_hr) - hrseries = hrseries.groupby(hrseries.index).first() - - - # Create dicts and big dataframe - d = { - ' Horizontal (meters)': distseries, - ' latitude': latseries, - ' longitude': lonseries, - ' Cadence (stokes/min)': spmseries, - ' HRCur (bpm)' : hrseries, - } - - - - df = pd.DataFrame(d) - - df = df.groupby(level=0).last() - - cum_time = df.index.values - df[' ElapsedTime (sec)'] = cum_time - - velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff() - - df[' Power (watts)'] = 0.0*velo - - nr_rows = len(velo.values) - - df[' DriveLength (meters)'] = np.zeros(nr_rows) - df[' StrokeDistance (meters)'] = np.zeros(nr_rows) - df[' DriveTime (ms)'] = np.zeros(nr_rows) - df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows) - df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows) - df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows) - df[' lapIdx'] = np.zeros(nr_rows) - - - - unixtime = cum_time+starttimeunix - unixtime[0] = starttimeunix - - df['TimeStamp (sec)'] = unixtime - - - dt = np.diff(cum_time).mean() - wsize = round(5./dt) - - velo2 = stravastuff.ewmovingaverage(velo,wsize) - - df[' Stroke500mPace (sec/500m)'] = 500./velo2 - - - df = df.fillna(0) - - - # data.sort(['TimeStamp (sec)'],ascending=True) - df.sort_values(by='TimeStamp (sec)',ascending=True) - - timestr = strftime("%Y%m%d-%H%M%S") - - # auto smoothing - pace = df[' Stroke500mPace (sec/500m)'].values - velo = 500./pace - - f = df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - - df['originalvelo'] = velo - - if windowsize > 3: - velo2 = savgol_filter(velo,windowsize,3) - else: - velo2 = velo - - pace2 = 500./abs(velo2) - df[' Stroke500mPace (sec/500m)'] = pace2 - - df = df.fillna(0) - - # end autosmoothing - - csvfilename ='media/Import_'+str(importid)+'.csv' - - res = df.to_csv(csvfilename,index_label='index') - - averagehr = df[' HRCur (bpm)'].mean() - maxhr = df[' HRCur (bpm)'].max() - - # make workout - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - row = rdata(csvfilename,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - 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) - - - summary = row.summary() - summary += '\n' - summary += row.intervalstats() - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - # check for duplicate start times - ws = Workout.objects.filter(starttime=workoutstarttime, - user=r) - if (len(ws) != 0): - print "Warning: This workout probably already exists in the database" - - w = Workout(user=r,name=title, - date=workoutdate,workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=r.weightcategory, - starttime=workoutstarttime, - csvfilename=csvfilename,notes=comments, - uploadedtoc2=0,summary=summary, - averagehr=averagehr,maxhr=maxhr, - startdatetime=rowdatetime) - w.save() - - return w.id - -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 C2NoTokenError("User has no token") -# return HttpResponseRedirect("/rowers/me/c2authorize/") - else: - if (timezone.now()>r.tokenexpirydate): - thetoken = c2stuff.rower_c2_token_refresh(user) - else: - thetoken = r.c2token - - return thetoken - - -def sporttracks_open(user): - r = Rower.objects.get(user=user) - if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): - s = "Token doesn't exist. Need to authorize" - raise SportTracksNoTokenError("User has no token") - else: - if (timezone.now()>r.sporttrackstokenexpirydate): - thetoken = sporttracksstuff.rower_sporttracks_token_refresh(user) - else: - thetoken = r.sporttrackstoken - - return thetoken - - -# Create your views here. - -@login_required() -def list_c2_upload_view(request,id=0): - message = "" - try: - thetoken = c2_open(request.user) - except C2NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - # ready to upload. Hurray - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)): - c2userid = c2stuff.get_userid(thetoken) - data = c2stuff.createc2workoutdata(w) - authorizationstring = str('Bearer ' + thetoken) - 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)) - - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" - w.uploadedtoc2 = -1 - w.save() - elif (response.status_code == 201 or response.status_code == 200): - try: - s= json.loads(response.text) - c2id = s['data']['id'] - w.uploadedtoc2 = c2id - w.save() - url = reverse(workouts_view) - return HttpResponseRedirect(url) - except: - message = "Something went wrong in list_c2_upload_view. Response 200/201 but Upload to C2 failed: "+response.text - else: - s = response - message = "Something went wrong in list_c2_upload_view. Upload to C2 failed." - - else: - message = "You are not authorized to upload this workout" - - url = reverse(workouts_view, - kwargs = { - 'message':str(message), - }) - - - return HttpResponseRedirect(url) - -@login_required() -def workout_tcxemail_view(request,id=0): - message = "" - r = Rower.objects.get(user=request.user) - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)): - tcxfile = stravastuff.createstravaworkoutdata(w) - if settings.DEBUG: - res = handle_sendemailtcx.delay(r.user.first_name, - r.user.last_name, - r.user.email,tcxfile) - - else: - res = queuehigh.enqueue(handle_sendemailtcx,r.user.first_name, - r.user.last_name, - r.user.email,tcxfile) - - successmessage = "The TCX file was sent to you per email" - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - 'successmessage':successmessage, - }) - response = HttpResponseRedirect(url) - - else: - message = "You are not allowed to export this workout" - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - 'message':message, - }) - response = HttpResponseRedirect(url) - - return response - -@login_required() -def workout_csvemail_view(request,id=0): - message = "" - r = Rower.objects.get(user=request.user) - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)): - csvfile = w.csvfilename - if settings.DEBUG: - res = handle_sendemailcsv.delay(r.user.first_name, - r.user.last_name, - r.user.email,csvfile) - - else: - res = queuehigh.enqueue(handle_sendemailcsv,r.user.first_name, - r.user.last_name, - r.user.email,csvfile) - - successmessage = "The CSV file was sent to you per email" - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - 'successmessage':successmessage, - }) - response = HttpResponseRedirect(url) - - else: - message = "You are not allowed to export this workout" - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - 'message':message, - }) - response = HttpResponseRedirect(url) - - return response - -@login_required() -def workout_strava_upload_view(request,id=0): - message = "" - r = Rower.objects.get(user=request.user) - if (r.stravatoken == '') or (r.stravatoken is None): - s = "Token doesn't exist. Need to authorize" - return HttpResponseRedirect("/rowers/me/stravaauthorize/") - else: - # ready to upload. Hurray - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)): - tcxfile = stravastuff.createstravaworkoutdata(w) - - - try: - with open(tcxfile,'rb') as f: - res = stravastuff.handle_stravaexport(f,w.name, - r.stravatoken, - description=w.notes) - - w.uploadedtostrava = res - w.save() - os.remove(tcxfile) - url = "/rowers/workout/"+str(w.id)+"/edit" - successmessage = 'Workout sent to Strava.' - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - } - ) - response = HttpResponseRedirect(url) - except ActivityUploadFailed as e: - message = "Strava Upload error: %s" % e - w.uploadedtostrava = -1 - w.save() - os.remove(tcxfile) - url = reverse(workout_export_view, - kwargs = { - 'id':str(w.id), - 'message':message, - }) - response = HttpResponseRedirect(url) - # except TimeoutExceeded as e: - # w.uploadedtostrava = -1 - # w.save() - # url = reverse(workout_export_view, - # kwargs = { - # 'id':str(w.id), - # 'message':'Strava Upload attempted. No response within 10 seconds. You may be OK. Check on Strava', - # }) - # response = HttpResponseRedirect(url) - - - return response - -@login_required() -def workout_c2_upload_view(request,id=0): - message = "" - try: - thetoken = c2_open(request.user) - except C2NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - # ready to upload. Hurray - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)): - c2userid = c2stuff.get_userid(thetoken) - data = c2stuff.createc2workoutdata(w) - authorizationstring = str('Bearer ' + thetoken) - 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)) - - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" - w.uploadedtoc2 = -1 - w.save() - elif (response.status_code == 201 or response.status_code == 200): - try: - s= json.loads(response.text) - c2id = s['data']['id'] - w.uploadedtoc2 = c2id - w.save() - url = "/rowers/workout/"+str(w.id)+"/export" - return HttpResponseRedirect(url) - except: - message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text - else: - s = response - message = "Something went wrong in workout_c2_upload_view. C2 sync failed." - - else: - message = "You are not authorized to upload this workout" - - url = reverse(workout_export_view, - kwargs = { - 'message':str(message), - 'id':str(w.id), - }) - - return HttpResponseRedirect(url) - -@login_required() -def workout_sporttracks_upload_view(request,id=0): - message = "" - try: - thetoken = sporttracks_open(request.user) - except SportTracksNoTokenError: - return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") - - # ready to upload. Hurray - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)): - data = sporttracksstuff.createsporttracksworkoutdata(w) - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - - import urllib - url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json" - response = requests.post(url,headers=headers,data=json.dumps(data)) - - - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" - w.uploadedtosporttracks = -1 - w.save() - elif (response.status_code == 201 or response.status_code==200): - s= json.loads(response.text) - sporttracksid = sporttracksstuff.getidfromresponse(response) - w.uploadedtosporttracks = sporttracksid - w.save() - url = "/rowers/workout/"+str(w.id)+"/export" - return HttpResponseRedirect(url) - else: - s = response - message = "Something went wrong in workout_sporttracks_upload_view %s" % s - - else: - message = "You are not authorized to upload this workout" - - url = reverse(workout_export_view, - kwargs = { - 'message':str(message), - 'id':str(w.id), - }) - - return HttpResponseRedirect(url) - - -@login_required() -def rower_c2_authorize(request): - # Generate a random string for the state parameter - # Save it for use later to prevent xsrf attacks - from uuid import uuid4 - state = str(uuid4()) - - params = {"client_id": C2_CLIENT_ID, - "response_type": "code", - "redirect_uri": C2_REDIRECT_URI} - import urllib - url = "http://log.concept2.com/oauth/authorize?"+ urllib.urlencode(params) - - return HttpResponseRedirect(url) - -@login_required() -def rower_strava_authorize(request): - # Generate a random string for the state parameter - # Save it for use later to prevent xsrf attacks - from uuid import uuid4 - state = str(uuid4()) - - params = {"client_id": STRAVA_CLIENT_ID, - "response_type": "code", - "redirect_uri": STRAVA_REDIRECT_URI, - "scope": "write"} - - import urllib - url = "https://www.strava.com/oauth/authorize?"+ urllib.urlencode(params) - - return HttpResponseRedirect(url) - -@login_required() -def rower_sporttracks_authorize(request): - # Generate a random string for the state parameter - # Save it for use later to prevent xsrf attacks - from uuid import uuid4 - state = str(uuid4()) - - params = {"client_id": SPORTTRACKS_CLIENT_ID, - "response_type": "code", - "state": state, - "redirect_uri": SPORTTRACKS_REDIRECT_URI} - - import urllib - url = "https://api.sporttracks.mobi/oauth2/authorize?"+ urllib.urlencode(params) - - - return HttpResponseRedirect(url) - -@login_required() -def rower_c2_token_refresh(request): - r = Rower.objects.get(user=request.user) - res = c2stuff.do_refresh_token(r.c2refreshtoken) - access_token = res[0] - expires_in = res[1] - refresh_token = res[2] - expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in) - - r = Rower.objects.get(user=request.user) - r.c2token = access_token - r.tokenexpirydate = expirydatetime - r.c2refreshtoken = refresh_token - - r.save() - - successmessage = "Tokens refreshed. Good to go" - return imports_view(request,successmessage=successmessage) - -@login_required() -def rower_sporttracks_token_refresh(request): - r = Rower.objects.get(user=request.user) - res = sporttracksstuff.do_refresh_token(r.sporttracksrefreshtoken) - access_token = res[0] - expires_in = res[1] - refresh_token = res[2] - expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in) - - r = Rower.objects.get(user=request.user) - r.sporttrackstoken = access_token - r.sporttrackstokenexpirydate = expirydatetime - r.sporttracksrefreshtoken = refresh_token - - r.save() - - successmessage = "Tokens refreshed. Good to go" - return imports_view(request,successmessage=successmessage) - - -@login_required() -def rower_process_callback(request): - code = request.GET['code'] - - res = c2stuff.get_token(code) - access_token = res[0] - expires_in = res[1] - refresh_token = res[2] - expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in) - - r = Rower.objects.get(user=request.user) - r.c2token = access_token - r.tokenexpirydate = expirydatetime - r.c2refreshtoken = refresh_token - - r.save() - - successmessage = "Tokens stored. Good to go" - return imports_view(request,successmessage=successmessage) - -@login_required() -def imports_view(request,successmessage=""): - return render(request,"imports.html",{'successmessage': successmessage}) - -@login_required() -def test_reverse_view(request): - successmessage = "Tokens stored. Good to go" - - return imports_view(request,successmessage=successmessage) - - -@login_required() -def rower_process_stravacallback(request): - code = request.GET['code'] - res = stravastuff.get_token(code) - - access_token = res[0] - - r = Rower.objects.get(user=request.user) - r.stravatoken = access_token - - r.save() - - successmessage = "Tokens stored. Good to go" - return imports_view(request,successmessage=successmessage) - - -@login_required() -def rower_process_sporttrackscallback(request): - code = request.GET['code'] - res = sporttracksstuff.get_token(code) - - - access_token = res[0] - expires_in = res[1] - refresh_token = res[2] - expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in) - - r = Rower.objects.get(user=request.user) - r.sporttrackstoken = access_token - r.sporttrackstokenexpirydate = expirydatetime - r.sporttracksrefreshtoken = refresh_token - - r.save() - - successmessage = "Tokens stored. Good to go" - return imports_view(request,successmessage=successmessage) - -@login_required() -def histo_all(request,theuser=0): - promember=0 - if theuser == 0: - theuser = request.user.id - - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - - if not promember: - return HttpResponseRedirect("/rowers/about/") - - # get all indoor rows of past 12 months - ayearago = timezone.now()-datetime.timedelta(days=365) - try: - r2 = Rower.objects.get(user=theuser) - allergworkouts = Workout.objects.filter(user=r2, - workouttype__in=['rower','dynamic','slides'], - startdatetime__gte=ayearago) - except Rower.DoesNotExist: - allergworkouts = [] - r2=0 - - try: - u = User.objects.get(id=theuser) - except User.DoesNotExist: - u = '' - - if allergworkouts: - res = interactive_histoall(allergworkouts) - script = res[0] - div = res[1] - else: - script = '' - div = '

No erg pieces uploaded yet.

' - - return render(request, 'histoall.html', - {'interactiveplot':script, - 'the_div':div, - 'id':theuser, - 'theuser':u, - }) - -@login_required() -def cum_flex(request,theuser=0, - xparam='spm', - yparam1='power', - yparam2='None', - startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring=""): - - if deltadays>0: - startdate = enddate-datetime.timedelta(days=int(deltadays)) - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - promember=0 - if theuser == 0: - theuser = request.user.id - - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - - if not promember: - return HttpResponseRedirect("/rowers/about/") - - # get all indoor rows of in date range - - # process form - if request.method == 'POST' and "daterange" in request.POST: - form = DateRangeForm(request.POST) - deltaform = DeltaDaysForm(request.POST) - if form.is_valid(): - startdate = form.cleaned_data['startdate'] - enddate = form.cleaned_data['enddate'] - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - elif request.method == 'POST' and "datedelta" in request.POST: - deltaform = DeltaDaysForm(request.POST) - if deltaform.is_valid(): - deltadays = deltaform.cleaned_data['deltadays'] - if deltadays != 0: - enddate = timezone.now() - startdate = enddate-datetime.timedelta(days=deltadays) - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - - else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - deltaform = DeltaDaysForm() - - try: - r2 = Rower.objects.get(user=theuser) - allergworkouts = Workout.objects.filter(user=r2, - workouttype__in=['rower','dynamic','slides'], - startdatetime__gte=startdate, - startdatetime__lte=enddate) - - except Rower.DoesNotExist: - allergworkouts = [] - r2=0 - - try: - u = User.objects.get(id=theuser) - except User.DoesNotExist: - u = '' - - if allergworkouts: - res = interactive_cum_flex_chart(allergworkouts,xparam=xparam, - yparam1=yparam1,yparam2=yparam2, - promember=promember) - script = res[0] - div = res[1] - else: - script = '' - div = '

No erg pieces uploaded for this date range.

' - - - return render(request, 'cum_flex.html', - {'interactiveplot':script, - 'the_div':div, - 'id':theuser, - 'theuser':u, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, - 'deltaform':deltaform, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'promember':promember, - }) - - -@login_required() -def histo(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring=""): - - if deltadays>0: - startdate = enddate-datetime.timedelta(days=int(deltadays)) - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - promember=0 - if theuser == 0: - theuser = request.user.id - - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - - if not promember: - return HttpResponseRedirect("/rowers/about/") - - # get all indoor rows of in date range - - # process form - if request.method == 'POST' and "daterange" in request.POST: - form = DateRangeForm(request.POST) - deltaform = DeltaDaysForm(request.POST) - if form.is_valid(): - startdate = form.cleaned_data['startdate'] - enddate = form.cleaned_data['enddate'] - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - elif request.method == 'POST' and "datedelta" in request.POST: - deltaform = DeltaDaysForm(request.POST) - if deltaform.is_valid(): - deltadays = deltaform.cleaned_data['deltadays'] - if deltadays != 0: - enddate = timezone.now() - startdate = enddate-datetime.timedelta(days=deltadays) - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - - else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - deltaform = DeltaDaysForm() - - try: - r2 = Rower.objects.get(user=theuser) - allergworkouts = Workout.objects.filter(user=r2, - workouttype__in=['rower','dynamic','slides'], - startdatetime__gte=startdate, - startdatetime__lte=enddate) - - except Rower.DoesNotExist: - allergworkouts = [] - r2=0 - - try: - u = User.objects.get(id=theuser) - except User.DoesNotExist: - u = '' - - if allergworkouts: - res = interactive_histoall(allergworkouts) - script = res[0] - div = res[1] - else: - script = '' - div = '

No erg pieces uploaded for this date range.

' - - - return render(request, 'histo.html', - {'interactiveplot':script, - 'the_div':div, - 'id':theuser, - 'theuser':u, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, - 'deltaform':deltaform, - }) - -@login_required() -def rankings_view(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring=""): - - if deltadays>0: - startdate = enddate-datetime.timedelta(days=int(deltadays)) - - if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) - - if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) - - if enddate < startdate: - s = enddate - enddate = startdate - startdate = s - - if theuser == 0: - theuser = request.user.id - - promember=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - - # get all indoor rows of in date range - - # process form - if request.method == 'POST' and "daterange" in request.POST: - dateform = DateRangeForm(request.POST) - deltaform = DeltaDaysForm(request.POST) - if dateform.is_valid(): - startdate = dateform.cleaned_data['startdate'] - enddate = dateform.cleaned_data['enddate'] - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - elif request.method == 'POST' and "datedelta" in request.POST: - deltaform = DeltaDaysForm(request.POST) - if deltaform.is_valid(): - deltadays = deltaform.cleaned_data['deltadays'] - if deltadays != 0: - enddate = timezone.now() - startdate = enddate-datetime.timedelta(days=deltadays) - if startdate > enddate: - s = enddate - enddate = startdate - startdate = s - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - - else: - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - deltaform = DeltaDaysForm() - - # get all 2k (if any) - this rower, in date range - try: - r = Rower.objects.get(user=theuser) - except Rower.DoesNotExist: - allergworkouts = [] - r=0 - - - try: - uu = User.objects.get(id=theuser) - except User.DoesNotExist: - uu = '' - - - # test to fix bug - startdate = datetime.datetime.combine(startdate,datetime.time()) - enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) - - rankingdistances = [100,500,1000,2000,5000,6000,10000,21097,42195,100000] - rankingdurations = [] - rankingdurations.append(datetime.time(minute=1)) - rankingdurations.append(datetime.time(minute=4)) - rankingdurations.append(datetime.time(minute=30)) - rankingdurations.append(datetime.time(hour=1)) - - thedistances = [] - theworkouts = [] - thesecs = [] - - - - rankingdistances.sort() - rankingdurations.sort() - - for rankingdistance in rankingdistances: - - workouts = Workout.objects.filter(user=r,distance=rankingdistance, - workouttype__in=['rower','dynamic','slides'], - startdatetime__gte=startdate, - startdatetime__lte=enddate).order_by('duration') - if workouts: - thedistances.append(rankingdistance) - theworkouts.append(workouts[0]) - - timesecs = 3600*workouts[0].duration.hour - timesecs += 60*workouts[0].duration.minute - timesecs += workouts[0].duration.second - timesecs += 1.e-6*workouts[0].duration.microsecond - - thesecs.append(timesecs) - - for rankingduration in rankingdurations: - - workouts = Workout.objects.filter(user=r,duration=rankingduration, - workouttype='rower', - startdatetime__gte=startdate, - startdatetime__lte=enddate).order_by('-distance') - if workouts: - thedistances.append(workouts[0].distance) - theworkouts.append(workouts[0]) - - timesecs = 3600*workouts[0].duration.hour - timesecs += 60*workouts[0].duration.minute - timesecs += workouts[0].duration.second - timesecs += 1.e-5*workouts[0].duration.microsecond - - thesecs.append(timesecs) - - thedistances = np.array(thedistances) - thesecs = np.array(thesecs) - - thevelos = thedistances/thesecs - theavpower = 2.8*(thevelos**3) - - - # create interactive plot - if len(thedistances) !=0 : - res = interactive_cpchart(thedistances,thesecs,theavpower, - theworkouts,promember=promember) - script = res[0] - div = res[1] - paulslope = res[2] - paulintercept = res[3] - p1 = res[4] - message = res[5] - else: - script = '' - div = '

No ranking pieces found.

' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" - - - if request.method == 'POST' and "piece" in request.POST: - form = PredictedPieceForm(request.POST) - if form.is_valid(): - value = form.cleaned_data['value'] - pieceunit = form.cleaned_data['pieceunit'] - if pieceunit == 'd': - rankingdistances.append(value) - else: - rankingdurations.append(datetime.time(minute=value)) - else: - form = PredictedPieceForm() - - rankingdistances.sort() - rankingdurations.sort() - - - predictions = [] - cpredictions = [] - - - for rankingdistance in rankingdistances: - # Paul's model - p = paulslope*np.log10(rankingdistance)+paulintercept - velo = 500./p - t = rankingdistance/velo - pwr = 2.8*(velo**3) - a = {'distance':rankingdistance, - 'duration':get_datetimes([t])[0], - 'pace':get_datetimes([p])[0], - 'power':int(pwr)} - predictions.append(a) - - # CP model - - pwr2 = p1[0]/(1+t/p1[2]) - pwr2 += p1[1]/(1+t/p1[3]) - - if pwr2 <= 0: - pwr2 = 50. - - velo2 = (pwr2/2.8)**(1./3.) - - if np.isnan(velo2) or velo2 <= 0: - velo2 = 1.0 - - t2 = rankingdistance/velo2 - - pwr3 = p1[0]/(1+t2/p1[2]) - pwr3 += p1[1]/(1+t2/p1[3]) - - if pwr3 <= 0: - pwr3 = 50. - - velo3 = (pwr3/2.8)**(1./3.) - if np.isnan(velo3) or velo3 <= 0: - velo3 = 1.0 - - t3 = rankingdistance/velo3 - p3 = 500./velo3 - - a = {'distance':rankingdistance, - 'duration':get_datetimes([t3])[0], - 'pace':get_datetimes([p3])[0], - 'power':int(pwr3)} - cpredictions.append(a) - - - - - for rankingduration in rankingdurations: - t = 3600.*rankingduration.hour - t += 60.*rankingduration.minute - t += rankingduration.second - t += rankingduration.microsecond/1.e6 - - # Paul's model - ratio = paulintercept/paulslope - - u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope - - d = 500*t*np.log(10.) - d = d/(paulslope*lambertw(u)) - d = d.real - - velo = d/t - p = 500./velo - pwr = 2.8*(velo**3) - a = {'distance':int(d), - 'duration':get_datetimes([t])[0], - 'pace':get_datetimes([p])[0], - 'power':int(pwr)} - predictions.append(a) - - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) - - if pwr <= 0: - pwr = 50. - - velo = (pwr/2.8)**(1./3.) - - if np.isnan(velo) or velo <=0: - velo = 1.0 - - d = t*velo - p = 500./velo - a = {'distance':int(d), - 'duration':get_datetimes([t])[0], - 'pace':get_datetimes([p])[0], - 'power':int(pwr)} - cpredictions.append(a) - - - - return render(request, 'rankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, - 'predictions':predictions, - 'cpredictions':cpredictions, - 'nrdata':len(thedistances), - 'form':form, - 'dateform':dateform, - 'deltaform':deltaform, - 'id': theuser, - 'theuser':uu, - 'message':message, - 'startdate':startdate, - 'enddate':enddate, - }) - -@login_required() -def workouts_view(request,message='',successmessage=''): - try: - r = Rower.objects.get(user=request.user) - # res = mailprocessing.safeprocessattachments() - #if len(res)>0 and np.cumsum(np.array(res)).max()>0: - # successmessage = 'New Workouts have been created from email' - - workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") - - return render(request, 'list_workouts.html', - {'workouts': workouts, - 'message': message, - 'successmessage':successmessage, - }) - except Rower.DoesNotExist: - return HttpResponse("Admin has no rower instance") - -@user_passes_test(promember,login_url="/login") -def workout_comparison_list(request,id=0,message='',successmessage=''): - try: - r = Rower.objects.get(user=request.user) - u = User.objects.get(id=r.user.id) - workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime").exclude(id=id) - row = Workout.objects.get(id=id) - - return render(request, 'comparison_list.html', - {'id':id, - 'workout':row, - 'workouts': workouts, - 'last_name':u.last_name, - 'first_name':u.first_name, - 'message': message, - 'successmessage':successmessage, - }) - except Rower.DoesNotExist: - return HttpResponse("Admin has no rower instance") - -def workout_view(request,id=0): - try: - # check if valid ID exists (workout exists) - row = Workout.objects.get(id=id) - g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - r = Rower.objects.get(id=row.user.id) - u = User.objects.get(id=r.user.id) - - - # create interactive plot - res = interactive_chart(id) - script = res[0] - div = res[1] - - - # render page - if (len(g)<=3): - return render(request, 'workout_view.html', - {'workout':row, - 'graphs1':g[0:3], - 'last_name':u.last_name, - 'first_name':u.first_name, - 'interactiveplot':script, - 'the_div':div}) - else: - return render(request, 'workout_view.html', - {'workout':row, - 'graphs1':g[0:3], - 'graphs2':g[3:6], - 'last_name':u.last_name, - 'first_name':u.first_name, - 'interactiveplot':script, - 'the_div':div}) - - - except Workout.DoesNotExist: - return HttpResponse("Workout doesn't exist") - - -@user_passes_test(promember,login_url="/login") -def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - filename = row.csvfilename - row = rdata(filename) - if row == 0: - return HttpResponse("Error: CSV Data File Not Found") - - if 'originalvelo' in row.df: - velo = row.df['originalvelo'].values - row.df[' Stroke500mPace (sec/500m)'] = 500./velo - - row.write_csv(filename) - - url = "/rowers/workout/"+str(id)+"/advanced" - - return HttpResponseRedirect(url) - - - -@user_passes_test(promember,login_url="/login") -def workout_smoothenpace_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - filename = row.csvfilename - row = rdata(filename) - if row == 0: - return HttpResponse("Error: CSV Data File Not Found") - - pace = row.df[' Stroke500mPace (sec/500m)'].values - velo = 500./pace - - if not 'originalvelo' in row.df: - row.df['originalvelo'] = velo - - velo2 = stravastuff.ewmovingaverage(velo,5) - - pace2 = 500./abs(velo2) - - row.df[' Stroke500mPace (sec/500m)'] = pace2 - - row.df = row.df.fillna(0) - - row.write_csv(filename) - - url = "/rowers/workout/"+str(id)+"/advanced" - - return HttpResponseRedirect(url) - -@user_passes_test(promember,login_url="/login") -def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - if request.method == 'POST': - form = CNsummaryForm(request.POST,request.FILES) - if form.is_valid(): - f = request.FILES['file'] - res = handle_uploaded_file(f) - fname = res[1] - try: - sumd = summarydata(fname) - row.summary = sumd.allstats() - row.save() - os.remove(fname) - successmessage = "CrewNerd summary added" - url = reverse(workout_edit_view, - kwargs = { - 'id':str(id), - 'successmessage':str(successmessage), - }) - - return HttpResponseRedirect(url) - except: - os.remove(fname) - message = "Something went wrong (workout_crewnerd_summary_view)" - url = reverse(workout_edit_view, - kwargs = { - 'id':str(id), - 'message':str(message), - }) - return HttpResponseRedirect(url) - else: - return render(request, - "cn_form.html", - {'form':form, - 'id':row.id}) - else: - form = CNsummaryForm() - - return render(request, - "cn_form.html", - {'form':form, - 'id':row.id}) - -@user_passes_test(promember,login_url="/login") -def workout_downloadwind_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - f1 = row.csvfilename - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - # create bearing - rowdata = rdata(f1) - if rowdata == 0: - return HttpResponse("Error: CSV Data File Not Found") - - try: - bearing = rowdata.df.ix[:,'bearing'].values - except KeyError: - rowdata.add_bearing() - rowdata.write_csv(f1) - - # get wind - try: - avglat = rowdata.df[' latitude'].mean() - avglon = rowdata.df[' longitude'].mean() - avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.ix[0,'TimeStamp (sec)']) - startdatetime = dateutil.parser.parse("{}, {}".format(row.date, - row.starttime)) - - starttimeunix = int(mktime(startdatetime.timetuple())) - avgtime = starttimeunix+avgtime - winddata = get_wind_data(avglat,avglon,avgtime) - windspeed = winddata[0] - windbearing = winddata[1] - message = winddata[2] - row.notes += "\n"+message - row.save() - rowdata.add_wind(windspeed,windbearing) - rowdata.write_csv(f1) - - kwargs = {'successmessage':str(message), - 'id':str(id)} - - url = reverse(workout_wind_view,kwargs=kwargs) - response = HttpResponseRedirect(url) - except KeyError: - message = "No latitude/longitude data" - kwargs = {'message':str(message), - 'id':str(id)} - url = reverse(workout_wind_view,kwargs=kwargs) - response = HttpResponseRedirect(url) - - - - return response - - -@user_passes_test(promember,login_url="/login") -def workout_wind_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - - # get data - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - - # create bearing - rowdata = rdata(f1) - if row == 0: - return HttpResponse("Error: CSV Data File Not Found") - - - hascoordinates = 1 - try: - latitude = rowdata.df.ix[:,' latitude'] - except KeyError: - hascoordinates = 0 - - try: - bearing = rowdata.df.ix[:,'bearing'].values - except KeyError: - rowdata.add_bearing() - rowdata.write_csv(f1) - - - - - if request.method == 'POST': - # process form - form = UpdateWindForm(request.POST) - - if form.is_valid(): - - vwind1 = form.cleaned_data['vwind1'] - vwind2 = form.cleaned_data['vwind2'] - dist1 = form.cleaned_data['dist1'] - dist2 = form.cleaned_data['dist2'] - winddirection1 = form.cleaned_data['winddirection1'] - winddirection2 = form.cleaned_data['winddirection2'] - windunit = form.cleaned_data['windunit'] - - rowdata.update_wind(vwind1,vwind2, - winddirection1, - winddirection2, - dist1,dist2, - units=windunit) - - rowdata.write_csv(f1) - - - else: - message = "Invalid Form" - kwargs = {'message':str(message), - 'id':str(id)} - url = reverse(workout_wind_view,kwargs=kwargs) - response = HttpResponseRedirect(url) - - else: - form = UpdateWindForm() - - # create interactive plot - res = interactive_windchart(id,promember=1) - script = res[0] - div = res[1] - - if hascoordinates: - res = googlemap_chart(rowdata.df[' latitude'], - rowdata.df[' longitude'], - row.name) - gmscript = res[0] - gmdiv = res[1] - else: - gmscript = "" - gmdiv = "No GPS data available" - - return render(request, - 'windedit.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'form':form, - 'the_div':div, - 'gmap':gmscript, - 'gmapdiv':gmdiv}) - - -@user_passes_test(promember,login_url="/login") -def workout_stream_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - - # create interactive plot - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - - rowdata = rdata(f1) - if rowdata == 0: - return HttpResponse("Error: CSV Data File Not Found") - - if request.method == 'POST': - # process form - form = UpdateStreamForm(request.POST) - - if form.is_valid(): - - dist1 = form.cleaned_data['dist1'] - dist2 = form.cleaned_data['dist2'] - stream1 = form.cleaned_data['stream1'] - stream2 = form.cleaned_data['stream2'] - streamunit = form.cleaned_data['streamunit'] - - rowdata.update_stream(stream1,stream2,dist1,dist2, - units=streamunit) - - rowdata.write_csv(f1) - - - else: - message = "Invalid Form" - kwargs = {'message':str(message), - 'id':str(id)} - url = reverse(workout_wind_view,kwargs=kwargs) - response = HttpResponseRedirect(url) - - else: - form = UpdateStreamForm() - - # create interactive plot - res = interactive_streamchart(id,promember=1) - script = res[0] - div = res[1] - - return render(request, - 'streamedit.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'form':form, - 'the_div':div}) - - -@user_passes_test(promember, login_url="/login") -def workout_otwsetpower_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - - if request.method == 'POST': - # process form - form = AdvancedWorkoutForm(request.POST) - - if form.is_valid(): - boattype = form.cleaned_data['boattype'] - weightvalue = form.cleaned_data['weightvalue'] - row.boattype = boattype - row.weightvalue = weightvalue - row.save() - - # load row data & create power/wind/bearing columns if not set - f1 = row.csvfilename - rowdata = rdata(f1) - if rowdata == 0: - return HttpResponse("Error: CSV Data File Not Found") - try: - vstream = rowdata.df['vstream'] - except KeyError: - rowdata.add_stream(0) - rowdata.write_csv(f1) - - try: - bearing = rowdata.df['bearing'] - except KeyError: - rowdata.add_bearing() - rowdata.write_csv(f1) - - try: - vwind = rowdata.df['vwind'] - except KeyError: - rowdata.add_wind(0,0) - rowdata.write_csv(f1) - - # do power calculation (asynchronous) - u = request.user - first_name = u.first_name - last_name = u.last_name - emailaddress = u.email - - if settings.DEBUG: - res = handle_otwsetpower.delay(f1,boattype,weightvalue, - first_name,last_name,emailaddress,id) - else: - res = queuelow.enqueue(handle_otwsetpower,f1,boattype, - weightvalue, - first_name,last_name,emailaddress,id) - - - successmessage = "Your calculations have been submitted. You will receive an email when they are done." - kwargs = {'successmessage':str(successmessage), - 'id':str(id)} - - url = reverse(workout_advanced_view,kwargs=kwargs) - response = HttpResponseRedirect(url) - return response - - else: - message = "Invalid Form" - kwargs = {'message':str(message), - 'id':str(id)} - url = reverse(workout_otwsetpower_view,kwargs=kwargs) - response = HttpResponseRedirect(url) - - else: - form = AdvancedWorkoutForm(instance=row) - - return render(request, - 'otwsetpower.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'form':form, - }) - - -@login_required() -def workout_geeky_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - form = WorkoutForm(instance=row) - g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - # check if user is owner of this workout - - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - - # create interactive plot - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - - # create interactive plot - try: - res = interactive_chart(id,promember=1) - script = res[0] - div = res[1] - except ValueError: - pass - - if row.workouttype=='water': - return render(request, - 'otwgeeky.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div}) - else: - return render(request, - 'advancededit.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div}) - -#@user_passes_test(promember,login_url="/login") -@login_required() -def workout_advanced_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - form = WorkoutForm(instance=row) - g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - # check if user is owner of this workout - - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - - # create interactive plot - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - - # create interactive plot - try: - res = interactive_chart(id,promember=1) - script = res[0] - div = res[1] - except ValueError: - pass - - if row.workouttype=='water': - return render(request, - 'advancedotw.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div}) - else: - return render(request, - 'advancededit.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div}) - -def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'): - promember=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - - # create interactive plot - res = interactive_comparison_chart(id1,id2,xparam=xparam,yparam=yparam, - promember=promember) - script = res[0] - div = res[1] - - - return render(request, - 'comparisonchart.html', - {'interactiveplot':script, - 'the_div':div, - 'id1':id1, - 'id2':id2, - 'xparam':xparam, - 'yparam':yparam, - }) - -def workout_comparison_view2(request,id1=0,id2=0,xparam='distance', - yparam='spm',plottype='line'): - promember=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - - # create interactive plot - res = interactive_comparison_chart(id1,id2,xparam=xparam,yparam=yparam, - promember=promember,plottype=plottype) - script = res[0] - div = res[1] - - return render(request, - 'comparisonchart2.html', - {'interactiveplot':script, - 'the_div':div, - 'id1':id1, - 'id2':id2, - 'xparam':xparam, - 'yparam':yparam, - 'plottype':plottype, - 'promember':promember, - }) - -def workout_flexchart_view(request,id=0,xparam='distance',yparam1='pace', - yparam2='hr', - promember=0): - - if request.method == 'POST': - workstrokesonly = request.POST['workstrokesonly'] - else: - workstrokesonly = False - - row = Workout.objects.get(id=id) - promember=0 - mayedit=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - if request.user == row.user.user: - mayedit=1 - - # create interactive plot - res = interactive_flex_chart(id,xparam=xparam,yparam1=yparam1, - yparam2=yparam2, - promember=promember) - script = res[0] - div = res[1] - - - return render(request, - 'flexchart.html', - {'interactiveplot':script, - 'the_div':div, - 'id':id, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'mayedit':mayedit, - }) - -def workout_flexchart2_view(request,id=0,xparam='distance',yparam1='pace', - yparam2='hr',plottype='line', - promember=0): - - if request.method == 'POST': - workstrokesonly = request.POST['workstrokesonly'] - if workstrokesonly == 'True': - workstrokesonly = True - else: - workstrokesonly = False - else: - workstrokesonly = False - - row = Workout.objects.get(id=id) - promember=0 - mayedit=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - if request.user == row.user.user: - mayedit=1 - - # create interactive plot - res = interactive_flex_chart(id,xparam=xparam,yparam1=yparam1, - yparam2=yparam2, - promember=promember,plottype=plottype, - workstrokesonly=workstrokesonly) - script = res[0] - div = res[1] - - - return render(request, - 'flexchart2.html', - {'interactiveplot':script, - 'the_div':div, - 'id':id, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'plottype':plottype, - 'mayedit':mayedit, - 'promember':promember, - 'workstrokesonly': not workstrokesonly, - }) - - -def workout_flexchart3_view(request,id=0,xparam='distance',yparam1='pace', - yparam2='hr',plottype='line', - promember=0): - - if request.method == 'POST': - workstrokesonly = request.POST['workstrokesonly'] - if workstrokesonly == 'True': - workstrokesonly = True - else: - workstrokesonly = False - else: - workstrokesonly = False - - row = Workout.objects.get(id=id) - promember=0 - mayedit=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - if request.user == row.user.user: - mayedit=1 - - # create interactive plot - res = interactive_flex_chart2(id,xparam=xparam,yparam1=yparam1, - yparam2=yparam2, - promember=promember,plottype=plottype, - workstrokesonly=workstrokesonly) - script = res[0] - div = res[1] - js_resources = res[2] - css_resources = res[3] - - return render(request, - 'flexchart3.html', - {'the_script':script, - 'the_div':div, - 'js_res': js_resources, - 'css_res':css_resources, - 'id':id, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'plottype':plottype, - 'mayedit':mayedit, - 'promember':promember, - 'workstrokesonly': not workstrokesonly, - }) - -def testbokeh(request): - - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' - - x = np.array(range(51))/10. - y = x**2. - z = (2*(x-2.5))**2 - data = dict( - x = x, - y = y, - z = z, - ) - - df = pd.DataFrame(data) - filtered_df = df - - source = ColumnDataSource( - df - ) - - source2 = ColumnDataSource( - filtered_df - ) - - plot = Figure(tools=TOOLS) - plot.circle('x','y',source=source2) - plot.xaxis.axis_label = "X" - plot.yaxis.axis_label = "Y" - plot.x_range = Range1d(-1,6) - plot.y_range = Range1d(-5,30) - - callback = CustomJS(args = dict(source=source,source2=source2), code=""" - var data = source.data - var data2 = source2.data - var x1 = data['x'] - var y1 = data['y'] - var z1 = data['z'] - var mina = mina.value - var maxa = maxa.value - var minz = minz.value - var maxz = maxz.value - data2['x'] = [] - data2['y'] = [] - data2['z'] = [] - - for (i=0; i=mina && x1[i]<=maxa && z1[i]<=maxz && z1[i]>=minz) { - data2['x'].push(x1[i]) - data2['y'].push(y1[i]) - data2['z'].push(z1[i]) - } - } - - source2.trigger('change'); - """) - - s1 = Slider(start=0.0, end=5,value=0.0, step=.1,title="Min X Value",callback=callback) - callback.args["mina"] = s1 - - s2 = Slider(start=0.0, end=5,value=5.0, step=.1,title="Max X Value",callback=callback) - callback.args["maxa"] = s2 - - s3 = Slider(start=0.0, end=25,value=0.0, step=.1,title="Min Z Value",callback=callback) - callback.args["minz"] = s3 - - s4 = Slider(start=0.0, end=25,value=25.0, step=.1,title="Max Z Value",callback=callback) - callback.args["maxz"] = s4 - - hover = plot.select(dict(type=HoverTool)) - - hover.tooltips = OrderedDict([ - ('X value','@x'), - ('Y value','@y'), - ('Z value','@z'), - ]) - - hover.mode = 'mouse' - - layout = layoutrow([layoutcolumn([s1,s2,s3,s4]),plot]) -# widgetbox(s) - script, div = components(layout) - js_resources = INLINE.render_js() - css_resources = INLINE.render_css() - return render(request, - 'test.html', - {'the_script': script, - 'the_div': div, - 'js_res': js_resources, - 'css_res':css_resources, - }) - -#@user_passes_test(promember,login_url="/login") -def workout_biginteractive_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - # check if user is owner of this workout - - - # create interactive plot - f1 = row.csvfilename - u = request.user - # r = Rower.objects.get(user=u) - - promember=0 - mayedit=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - if request.user == row.user.user: - mayedit=1 - - - # create interactive plot - res = interactive_bar_chart(id,promember=promember) - script = res[0] - div = res[1] - - return render(request, - 'biginteractive1.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div, - 'promember':promember, - 'mayedit':mayedit}) - -def workout_otwpowerplot_view(request,id=0,message="",successmessage=""): - row = Workout.objects.get(id=id) - # check if user is owner of this workout - - - # create interactive plot - f1 = row.csvfilename - u = request.user - # r = Rower.objects.get(user=u) - - promember=0 - mayedit=0 - if not request.user.is_anonymous(): - r = Rower.objects.get(user=request.user) - result = request.user.is_authenticated() and r.rowerplan=='pro' - if result: - promember=1 - if request.user == row.user.user: - mayedit=1 - - # create interactive plot - res = interactive_otw_advanced_pace_chart(id,promember=promember) - script = res[0] - div = res[1] - - - return render(request, - 'otwinteractive.html', - {'workout':row, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div, - 'mayedit':mayedit}) - -@login_required() -def workout_export_view(request,id=0, message="", successmessage=""): - request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE - - row = Workout.objects.get(id=id) - form = WorkoutForm(instance=row) - g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - # check if user is owner of this workout - - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - else: - return render(request, - 'export.html', - {'workout':row, - 'message':message, - 'successmessage':successmessage, - }) - -@login_required() -def workout_edit_view(request,id=0,message="",successmessage=""): - request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE - - if request.method == 'POST': - # Form was submitted - form = WorkoutForm(request.POST) - if form.is_valid(): - # Get values from form - name = form.cleaned_data['name'] - date = form.cleaned_data['date'] - starttime = form.cleaned_data['starttime'] - workouttype = form.cleaned_data['workouttype'] - duration = form.cleaned_data['duration'] - distance = form.cleaned_data['distance'] - notes = form.cleaned_data['notes'] - startdatetime = (str(date) + ' ' + str(starttime)) - startdatetime = datetime.datetime.strptime(startdatetime, - "%Y-%m-%d %H:%M:%S") - startdatetime = timezone.make_aware(startdatetime) - 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.starttime = starttime - row.startdatetime = startdatetime - row.workouttype = workouttype - row.notes = notes - row.duration = duration - row.distance = distance - row.save() - # change data in csv file - # startdatetime = dateutil.parser.parse("{}, {}".format(date,starttime)) - r = rdata(row.csvfilename) - if r == 0: - return HttpResponse("Error: CSV Data File Not Found") - r.rowdatetime = startdatetime - r.write_csv(row.csvfilename) - successmessage = "Changes saved" - url = "/rowers/workout/"+str(row.id)+"/edit" - url = reverse(workout_edit_view, - kwargs = { - 'id':str(row.id), - 'successmessage':str(successmessage), - }) - response = HttpResponseRedirect(url) - else: - message = "You are not allowed to change this workout" - url = reverse(workouts_view,args=[str(message)]) - - response = HttpResponseRedirect(url) - 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() - successmessage = "New Workout Created" - url = reverse(workouts_view, - kwargs = { - 'successmessage':str(successmessage), - }) - - response = HttpResponseRedirect(url) - else: - message = "Invalid Form" - url = reverse(workouts_view,args=[str(message)]) - response = HttpResponseRedirect(url) - - return response - else: - try: - row = Workout.objects.get(id=id) - form = WorkoutForm(instance=row) - g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") - # check if user is owner of this workout - - if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" - url = reverse(workouts_view,args=[str(message)]) - - return HttpResponseRedirect(url) - - else: - # create interactive plot - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - - res = interactive_chart(id) - script = res[0] - div = res[1] - - rowdata = rdata(f1) - hascoordinates = 1 - try: - latitude = rowdata.df[' latitude'] - except KeyError: - hascoordinates = 0 - - if hascoordinates: - res = googlemap_chart(rowdata.df[' latitude'], - rowdata.df[' longitude'], - row.name) - gmscript = res[0] - gmdiv = res[1] - else: - gmscript = "" - gmdiv = "" - - - # render page - if (len(g)<=3): - return render(request, 'workout_form.html', - {'form':form, - 'workout':row, - 'graphs1':g[0:3], - 'message': message, - 'successmessage': successmessage, - 'gmscript': gmscript, - 'gmdiv': gmdiv, - }) -# 'interactiveplot':script, -# 'the_div':div}) - else: - return render(request, 'workout_form.html', - {'form':form, - 'workout':row, - 'graphs1':g[0:3], - 'graphs2':g[3:6], - 'message': message, - 'successmessage': successmessage, - 'gmscript': gmscript, - 'gmdiv': gmdiv, - }) -# 'interactiveplot':script, -# 'the_div':div}) - - except Workout.DoesNotExist: - form = WorkoutForm( - initial = {'workouttype' : 'rower'} - ) - return render(request, - 'workout_form.html', - {'form':form}) - -@user_passes_test(promember,login_url="/login") -def workout_add_otw_powerplot_view(request,id): - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)==False): - return HttpResponse("You are not allowed add plots to this workout") - else: - f1 = w.csvfilename[6:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=u) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnr = 9 - - if (w.workouttype=='water'): - plotnr = plotnr+3 - - if settings.DEBUG: - res = handle_makeplot.delay(f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - else: - res = queue.enqueue(handle_makeplot,f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - -# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i = GraphImage(workout=w,creationdatetime=timezone.now(), - filename=fullpathimagename) - i.save() - - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - - -@login_required() -def workout_add_piechart_view(request,id): - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)==False): - return HttpResponse("You are not allowed add plots to this workout") - else: - f1 = w.csvfilename[6:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=u) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnr = 3 - - if (w.workouttype=='water'): - plotnr = plotnr+3 - - if settings.DEBUG: - res = handle_makeplot.delay(f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - else: - res = queue.enqueue(handle_makeplot,f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - -# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i = GraphImage(workout=w,creationdatetime=timezone.now(), - filename=fullpathimagename) - i.save() - - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - -@login_required() -def workout_add_timeplot_view(request,id): - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)==False): - return HttpResponse("You are not allowed add plots to this workout") - else: - f1 = w.csvfilename[6:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=u) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnr = 1 - - if (w.workouttype=='water'): - plotnr = plotnr+3 - - if settings.DEBUG: - res = handle_makeplot.delay(f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - else: - res = queue.enqueue(handle_makeplot,f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - - i = GraphImage(workout=w,creationdatetime=timezone.now(), - filename=fullpathimagename) -# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i.save() - - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - - -@login_required() -def workout_add_distanceplot_view(request,id): - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)==False): - return HttpResponse("You are not allowed add plots to this workout") - else: - f1 = w.csvfilename[6:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=u) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnr = 2 - - if (w.workouttype=='water'): - plotnr = plotnr+3 - - if settings.DEBUG: - res = handle_makeplot.delay(f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - else: - res = queue.enqueue(handle_makeplot,f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - - i = GraphImage(workout=w,creationdatetime=timezone.now(), - filename=fullpathimagename) -# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i.save() - - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - -@user_passes_test(promember,login_url="/login") -def workout_add_distanceplot2_view(request,id): - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)==False): - return HttpResponse("You are not allowed add plots to this workout") - else: - f1 = w.csvfilename[6:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=u) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnr = 7 - - if (w.workouttype=='water'): - plotnr = plotnr+3 - - if settings.DEBUG: - res = handle_makeplot.delay(f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - else: - res = queue.enqueue(handle_makeplot,f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - - i = GraphImage(workout=w,creationdatetime=timezone.now(), - filename=fullpathimagename) -# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i.save() - - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - - -@user_passes_test(promember,login_url="/login") -def workout_add_timeplot2_view(request,id): - w = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,w)==False): - return HttpResponse("You are not allowed add plots to this workout") - else: - f1 = w.csvfilename[6:-4] - timestr = strftime("%Y%m%d-%H%M%S") - imagename = f1+timestr+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=u) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnr = 8 - - if (w.workouttype=='water'): - plotnr = plotnr+3 - - if settings.DEBUG: - res = handle_makeplot.delay(f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - else: - res = queue.enqueue(handle_makeplot,f1,w.csvfilename, - w.name,hrdata,plotnr,imagename) - - i = GraphImage(workout=w,creationdatetime=timezone.now(), - filename=fullpathimagename) -# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i.save() - - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - -@login_required() -def workout_stravaimport_view(request,message=""): - res = stravastuff.get_strava_workout_list(request.user) - if (res.status_code != 200): - if (res.status_code == 401): - r = Rower.objects.get(user=request.user) - if (r.stravatoken == '') or (r.stravatoken is None): - s = "Token doesn't exist. Need to authorize" - return HttpResponseRedirect("/rowers/me/stravaauthorize/") - message = "Something went wrong in workout_stravaimport_view" - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workouts_view, - kwargs = { - 'message': str(message) - }) - return HttpResponseRedirect(url) - else: - data = res.json() - - return render(request,'strava_list_import.html', - {'data':data, - 'message':message, - }) - - return HttpResponse(res) - -@login_required() -def workout_sporttracksimport_view(request,message=""): - res = sporttracksstuff.get_sporttracks_workout_list(request.user) - if (res.status_code != 200): - if (res.status_code == 401): - r = Rower.objects.get(user=request.user) - if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): - s = "Token doesn't exist. Need to authorize" - return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") - message = "Something went wrong in workout_sporttracksimport_view" - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workouts_view, - kwargs = { - 'message': str(message) - }) - return HttpResponseRedirect(url) - else: - workouts = [] - for item in res.json()['items']: - d = int(float(item['total_distance'])) - i = getidfromsturi(item['uri']) - n = item['name'] - ttot = str(datetime.timedelta(seconds=int(float(item['duration'])))) - s = item['start_time'] - r = item['type'] - keys = ['id','distance','duration','starttime','type','name'] - values = [i,d,ttot,s,r,n] - res = dict(zip(keys,values)) - workouts.append(res) - return render(request,'sporttracks_list_import.html', - {'workouts':workouts, - 'message':message, - }) - - return HttpResponse(res) - -@login_required() -def c2listdebug_view(request,message=""): - try: - thetoken = c2_open(request.user) - except C2NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - r = Rower.objects.get(user=request.user) - #if (r.c2token == '') or (r.c2token is None): - #s = "Token doesn't exist. Need to authorize" - #return HttpResponseRedirect("/rowers/me/c2authorize/") - - #elif (timezone.now()>r.tokenexpirydate): - #s = "Token expired. Needs to refresh." - #res = c2stuff.rower_c2_token_refresh(request.user) - - res = c2stuff.get_c2_workout_list(request.user) - - if (res.status_code != 200): - message = "Something went wrong in workout_c2import_view (C2 token renewal)" - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workouts_view, - kwargs = { - 'message': str(message) - }) - return HttpResponseRedirect(url) - else: - workouts = [] - for item in res.json()['data']: - d = item['distance'] - i = item['id'] - ttot = item['time_formatted'] - s = item['date'] - r = item['type'] - s2 = item['source'] - c = item['comments'] - keys = ['id','distance','duration','starttime','rowtype','source','comment'] - values = [i,d,ttot,s,r,s2,c] - res = dict(zip(keys,values)) - workouts.append(res) - - - return render(request, - 'c2_list_import2.html', - {'workouts':workouts, - 'message':message}) - - -@login_required() -def workout_c2import_view(request,message=""): - try: - thetoken = c2_open(request.user) - except C2NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - #r = Rower.objects.get(user=request.user) - #if (r.c2token == '') or (r.c2token is None): - #s = "Token doesn't exist. Need to authorize" - #return HttpResponseRedirect("/rowers/me/c2authorize/") - - #elif (timezone.now()>r.tokenexpirydate): - #s = "Token expired. Needs to refresh." - #res = c2stuff.rower_c2_token_refresh(request.user) - - res = c2stuff.get_c2_workout_list(request.user) - - if (res.status_code != 200): - message = "Something went wrong in workout_c2import_view (C2 token refresh)" - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workouts_view, - kwargs = { - 'message': str(message) - }) - return HttpResponseRedirect(url) - else: - workouts = [] - for item in res.json()['data']: - d = item['distance'] - i = item['id'] - ttot = item['time_formatted'] - s = item['date'] - r = item['type'] - s2 = item['source'] - c = item['comments'] - keys = ['id','distance','duration','starttime','rowtype','source','comment'] - values = [i,d,ttot,s,r,s2,c] - res = dict(zip(keys,values)) - workouts.append(res) - - - return render(request, - 'c2_list_import2.html', - {'workouts':workouts, - 'message':message}) - -@login_required() -def workout_getstravaworkout_view(request,stravaid): - res = stravastuff.get_strava_workout(request.user,stravaid) - strokedata = res[1] - data = res[0] - id = add_workout_from_strokedata(request.user,stravaid,data,strokedata, - source='strava') - w = Workout.objects.get(id=id) - w.uploadedtostrava=stravaid - w.save() - url = "/rowers/workout/"+str(id)+"/edit" - return HttpResponseRedirect(url) - -@login_required() -def workout_getsporttracksworkout_view(request,sporttracksid): - res = sporttracksstuff.get_sporttracks_workout(request.user,sporttracksid) - data = res.json() - - id = add_workout_from_stdata(request.user,sporttracksid,data) - w = Workout.objects.get(id=id) - w.uploadedtosporttracks=sporttracksid - w.save() - url = "/rowers/workout/"+str(id)+"/edit" - return HttpResponseRedirect(url) - -@login_required() -def workout_getc2workout_view(request,c2id): - res = c2stuff.get_c2_workout(request.user,c2id) - if (res.status_code == 200): - data = res.json()['data'] - if 'stroke_data' in data: - # test = data['stroke_data'] - res2 = c2stuff.get_c2_workout_strokes(request.user,c2id) - # 2016-07-27 added below if statement (balkanboy error report) - if res2.status_code == 200: - strokedata = pd.DataFrame.from_dict(res2.json()['data']) - id = add_workout_from_strokedata(request.user,c2id,data,strokedata, - source='c2') - w = Workout.objects.get(id=id) - w.uploadedtoc2=c2id - w.save() - url = "/rowers/workout/"+str(id)+"/edit" - return HttpResponseRedirect(url) - else: - message = json.loads(s.text)['message'] - url = reverse(workout_c2import_view, - kwargs={ - 'message':message, - }) - return HttpResponseRedirect(url) - else: - message = "This workout doesn't contain stroke data" - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workout_c2import_view, - kwargs={ - 'message':message, - }) - return HttpResponseRedirect(url) - - else: - message = "Received error code from Concept2" - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse(workout_c2import_view, - kwargs={ - 'message':message, - }) - return HttpResponseRedirect(url) - - -@login_required() -def workout_upload_view(request,message=""): - if request.method == 'POST': - form = DocumentsForm(request.POST,request.FILES) - optionsform = UploadOptionsForm(request.POST) - if form.is_valid(): - f = request.FILES['file'] - res = handle_uploaded_file(f) - t = form.cleaned_data['title'] - # fileformat = form.cleaned_data['fileformat'] - workouttype = form.cleaned_data['workouttype'] - - notes = form.cleaned_data['notes'] - make_plot = request.POST.getlist('make_plot') - plottype = request.POST['plottype'] - upload_to_c2 = request.POST.getlist('upload_to_C2') - - - f1 = res[0] # file name - f2 = res[1] # file name incl media directory - - # new - fileformat = get_file_type(f2) - - if fileformat == 'unknown': - message = "We couldn't recognize the file type" - url = reverse(workout_upload_view, - args=[str(message)]) - response = HttpResponseRedirect(url) - if settings.DEBUG: - res = handle_sendemail_unrecognized.delay(f2, - request.user.email) - - else: - res = queuehigh.enqueue(handle_sendemail_unrecognized, - f2,request.user.email) - - return response - - summary = '' - # handle non-Painsled - try: - if (fileformat != 'csv'): - # handle RowPro: - if (fileformat == 'rp'): - row = RowProParser(f2) - # handle TCX - if (fileformat == 'tcx'): - row = TCXParser(f2) - - # handle Mystery - if (fileformat == 'mystery'): - row = MysteryParser(f2) - - # handle TCX no HR - if (fileformat == 'tcxnohr'): - row = TCXParserNoHR(f2) - - # handle ErgData - if (fileformat == 'ergdata'): - row = ErgDataParser(f2) - - # handle painsled desktop - if (fileformat == 'painsleddesktop'): - row = painsledDesktopParser(f2) - - # handle speed coach GPS - if (fileformat == 'speedcoach'): - row = speedcoachParser(f2) - - # handle speed coach GPS 2 - if (fileformat == 'speedcoach2'): - row = SpeedCoach2Parser(f2) - - # handle ErgStick - if (fileformat == 'ergstick'): - row = ErgStickParser(f2) - - # handle FIT - if (fileformat == 'fit'): - row = FITParser(f2) - s = fitsummarydata(f2) - s.setsummary() - summary = s.summarytext - - - f_to_be_deleted = f2 - # should delete file - f2 = f2[:-4]+'o.csv' - row.write_csv(f2) - os.remove(f_to_be_deleted) - - # make workout and put in database - r = Rower.objects.get(user=request.user) - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - row = rdata(f2,rower=rr) - if row == 0: - return HttpResponse("Error: CSV Data File Not Found") - - # auto smoothing - pace = row.df[' Stroke500mPace (sec/500m)'].values - velo = 500./pace - - f = row.df['TimeStamp (sec)'].diff().mean() - windowsize = 2*(int(10./(f)))+1 - - if not 'originalvelo' in row.df: - row.df['originalvelo'] = velo - - if windowsize > 3: - velo2 = savgol_filter(velo,windowsize,3) - else: - velo2 = velo - - pace2 = 500./abs(velo2) - row.df[' Stroke500mPace (sec/500m)'] = pace2 - - row.df = row.df.fillna(0) - - row.write_csv(f2) - - # recalculate power data - if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides': - try: - row.erg_recalculatepower() -# row.spm_fromtimestamps() - row.write_csv(f2) - except: - pass - - if fileformat != 'fit': - summary = row.summary() - summary += '\n' - summary += row.intervalstats_painsled() - - averagehr = row.df[' HRCur (bpm)'].mean() - maxhr = row.df[' HRCur (bpm)'].max() - - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - 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) - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - workoutstartdatetime = thetimezone.localize(row.rowdatetime).astimezone(utc) - - # check for duplicate start times - r = Rower.objects.get(user=request.user) - - ws = Workout.objects.filter(starttime=workoutstarttime, - user=r) - if (len(ws) != 0): - message = "Warning: This workout probably already exists in the database" - - - w = Workout(user=r,name=t,date=workoutdate, - workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=r.weightcategory, - starttime=workoutstarttime, - csvfilename=f2,notes=notes,summary=summary, - maxhr=maxhr,averagehr=averagehr, - startdatetime=workoutstartdatetime) - - w.save() - - # Make Plot - if (make_plot): - imagename = f1[:-4]+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnrs = { - 'timeplot':1, - 'distanceplot':2, - 'pieplot':3, - } - - plotnr = plotnrs[plottype] - if (workouttype=='water'): - plotnr = plotnr+3 - - -# res = handle_makeplot.delay(f1,f2,t, -# hrdata,plotnr,imagename) - if settings.DEBUG: - res = handle_makeplot.delay(f1,f2,t, - hrdata,plotnr, - imagename) - else: - res = queue.enqueue(handle_makeplot,f1,f2, - t,hrdata, - plotnr,imagename) - - - i = GraphImage(workout=w, - creationdatetime=timezone.now(), - filename=fullpathimagename) -# i = GraphImage(workout=w, -# creationdatetime=datetime.datetime.now(), -# filename=fullpathimagename) - i.save() - - # upload to C2 - if (upload_to_c2): - try: - thetoken = c2_open(request.user) - except C2NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - #r = Rower.objects.get(user=request.user) - #if (r.c2token == '') or (r.c2token is None): - # s = "Token doesn't exist. Need to authorize" - #return HttpResponseRedirect("/rowers/me/c2authorize/") - - #elif (timezone.now()>r.tokenexpirydate): - #s = "Token expired. Needs to refresh." - #res = c2stuff.rower_c2_token_refresh(request.user) - - try: - - c2userid = c2stuff.get_userid(thetoken) - data = c2stuff.createc2workoutdata(w) - authorizationstring = str('Bearer ' + thetoken) - 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)) - - # response = c2stuff.workout_c2_upload(request.user,w) - if (response.status_code != 201): - if settings.DEBUG: - return HttpResponse(response) - else: - message = "C2 upload failed" - url = reverse(workout_edit_view, - kwargs={ - 'message':message, - 'id':str(w.id), - }) - return HttpResponseRedirect(url) - else: - s= json.loads(response.text) - c2id = s['data']['id'] - w.uploadedtoc2 = c2id - w.save() - - except: - message = "C2 upload failed" - url = reverse(workout_edit_view, - kwargs={ - 'message':message, - 'id':str(w.id), - }) - return HttpResponseRedirect(url) - - # redirect to workout edit page - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - except: - message = "something went wrong (workout_upload_view)" - - url = reverse(workout_upload_view, - args=[str(message)]) - response = HttpResponseRedirect(url) - else: - response = render(request, - 'document_form.html', - {'form':form, - 'optionsform': optionsform, - 'message':message}) - - return response - else: - form = DocumentsForm() - optionsform = UploadOptionsForm() - return render(request, 'document_form.html', - {'form':form, - 'optionsform': optionsform, - 'message':message}) - - -@login_required() -def workout_upload_view_debug(request,message=""): - if request.method == 'POST': - form = DocumentsForm(request.POST,request.FILES) - optionsform = UploadOptionsForm(request.POST) - if form.is_valid(): - f = request.FILES['file'] - res = handle_uploaded_file(f) - t = form.cleaned_data['title'] - fileformat = form.cleaned_data['fileformat'] - workouttype = form.cleaned_data['workouttype'] - notes = form.cleaned_data['notes'] - make_plot = request.POST.getlist('make_plot') - plottype = request.POST['plottype'] - upload_to_c2 = request.POST.getlist('upload_to_C2') - - - f1 = res[0] # file name - f2 = res[1] # file name incl media directory - - - print fileformat - - # handle non-Painsled - if (fileformat != 'csv'): - # handle RowPro: - if (fileformat == 'rp'): - row = RowProParser(f2) - - # handle TCX - if (fileformat == 'tcx'): - row = TCXParser(f2) - - # handle TCX no HR - if (fileformat == 'tcxnohr'): - row = TCXParserNoHR(f2) - - # handle ErgData - if (fileformat == 'ergdata'): - row = ErgDataParser(f2) - - - # handle painsled desktop - if (fileformat == 'painsleddesktop'): - row = painsledDesktopParser(f2) - - # handle speed coach - if (fileformat == 'speedcoach'): - row = speedcoachParser(f2) - - # handle ErgStick - if (fileformat == 'ergstick'): - row = ErgStickParser(f2) - - f_to_be_deleted = f2 - # should delete file - f2 = f2[:-4]+'o.csv' - row.write_csv(f2) - os.remove(f_to_be_deleted) - - # make workout and put in database - r = Rower.objects.get(user=request.user) - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - row = rdata(f2,rower=rr) - if row == 0: - return HttpResponse("Error: CSV Data File Not Found") - averagehr = row.df[' HRCur (bpm)'].mean() - maxhr = row.df[' HRCur (bpm)'].max() - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - 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)) - - summary = row.summary() - summary += '\n' - summary += row.intervalstats() - - duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - # check for duplicate start times - r = Rower.objects.get(user=request.user) - - ws = Workout.objects.filter(starttime=workoutstarttime, - user=r) - if (len(ws) != 0): - print "Warning: This workout probably already exists in the database" - - - w = Workout(user=r,name=t,date=workoutdate, - workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=r.weightcategory, - starttime=workoutstarttime, - csvfilename=f2,notes=notes,summary=summary, - averagehr=averagehr,maxhr=maxhr) - - w.save() - - # Make Plot - if (make_plot): - imagename = f1[:-4]+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - plotnrs = { - 'timeplot':1, - 'distanceplot':2, - 'pieplot':3, - } - - plotnr = plotnrs[plottype] - if (workouttype=='water'): - plotnr = plotnr+3 - - - # res = handle_makeplot.delay(f1,f2,t, - # hrdata,plotnr,imagename) - if settings.DEBUG: - res = handle_makeplot.delay(f1,f2,t, - hrdata,plotnr, - imagename) - else: - res = queue.enqueue(handle_makeplot,f1,f2, - t,hrdata, - plotnr,imagename) - - - i = GraphImage(workout=w, - creationdatetime=timezone.now(), - filename=fullpathimagename) - # i = GraphImage(workout=w, - # creationdatetime=datetime.datetime.now(), - # filename=fullpathimagename) - i.save() - - # upload to C2 - if (upload_to_c2): - try: - thetoken = c2_open(request.user) - except C2NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") - - #r = Rower.objects.get(user=request.user) - #if (r.c2token == '') or (r.c2token is None): - # s = "Token doesn't exist. Need to authorize" - #return HttpResponseRedirect("/rowers/me/c2authorize/") - - #elif (timezone.now()>r.tokenexpirydate): - #s = "Token expired. Needs to refresh." - #res = c2stuff.rower_c2_token_refresh(request.user) - - try: - response = c2stuff.workout_c2_upload(request.user,w) - if (response.status_code != 201): - if settings.DEBUG: - return HttpResponse(response) - else: - message = "C2 upload failed" - url = reverse(workout_edit_view, - kwargs={ - 'message':message, - 'id':str(w.id), - }) - return HttpResponseRedirect(url) - except: - message = "C2 upload failed" - url = reverse(workout_edit_view, - kwargs={ - 'message':message, - 'id':str(w.id), - }) - return HttpResponseRedirect(url) - - # redirect to workout edit page - url = "/rowers/workout/"+str(w.id)+"/edit" - return HttpResponseRedirect(url) - - else: - response = render(request, - 'document_form.html', - {'form':form, - 'optionsform': optionsform, - 'message':message}) - - return response - else: - form = DocumentsForm() - optionsform = UploadOptionsForm() - return render(request, 'document_form.html', - {'form':form, - 'optionsform': optionsform, - 'message':message}) - - -@login_required() -def workout_delete_confirm_view(request, id=0): - try: - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - return HttpResponse("You are not allowed to delete this workout") - else: - return render(request,'workout_delete_confirm.html', - {'id':id, - 'workout':row}) - - except Workout.DoesNotExist: - return HttpResponse("Workout doesn't exist") - -@login_required() -def workout_delete_view(request,id=0): - try: - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - return HttpResponse("You are not allowed to delete this workout") - else: - # files are removed by pre-delete in models.py - row.delete() - - url = reverse(workouts_view,kwargs={ - 'successmessage': "Workout deleted", - } - ) - return HttpResponseRedirect(url) - - except Workout.DoesNotExist: - return HttpResponse("Workout doesn't exist") - - -@login_required() -def graph_delete_confirm_view(request, id=0): - try: - img = GraphImage.objects.get(id=id) - row = Workout.objects.get(id=img.workout.id) - if (checkworkoutuser(request.user,row)==False): - return HttpResponse("You are not allowed to delete this workout") - else: - return render(request,'graphimage_delete_confirm.html', - {'id':id, - 'graph':img}) - - except Workout.DoesNotExist: - return HttpResponse("Workout doesn't exist") - -@login_required() -def graph_delete_view(request,id=0): - try: - img = GraphImage.objects.get(id=id) - row = Workout.objects.get(id=img.workout.id) - if (checkworkoutuser(request.user,row)==False): - return HttpResponse("You are not allowed to delete this graph") - else: - img.delete() - - url = reverse(workouts_view,kwargs={ - 'successmessage': "Graph deleted", - } - - ) - return HttpResponseRedirect(url) - - except GraphImage.DoesNotExist: - return HttpResponse("Graph Image doesn't exist") - - -@login_required() -def dashboard_view(request,message="",successmessage=""): - try: - request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE - - r = Rower.objects.get(user=request.user) - workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") - g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime") - if (len(g)<=3): - return render(request,'dashboard.html', - {'workouts':workouts, - 'graphs1':g[0:3], - 'message':message, - 'successmessage':successmessage}) - else: - return render(request,'dashboard.html', - {'workouts':workouts, - 'graphs1':g[0:3], - 'graphs2':g[3:6], - 'message':message, - 'successmessage':successmessage}) - - except Rower.DoesNotExist: - return HttpResponse("Admin has no rower instance") - - -@login_required() -def graphs_view(request): - try: - r = Rower.objects.get(user=request.user) - workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime") - g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime") - if (len(g)<=5): - return render(request, 'list_graphs.html', - {'graphs1': g[0:4]}) - else: - return render(request, 'list_graphs.html', - {'graphs1': g[0:5], - 'graphs2': g[5:10]}) - except Rower.DoesNotExist: - return HttpResponse("Admin has no rower instance") - - -def graph_show_view(request,id): - try: - g = GraphImage.objects.get(id=id) - w = Workout.objects.get(id=g.workout.id) - r = Rower.objects.get(id=w.user.id) - - return render(request,'show_graph.html', - {'graph':g, - 'workout':w, - 'rower':r,}) - - except GraphImage.DoesNotExist: - return HttpResponse("This graph doesn't exist") - -@login_required() -def workout_summary_restore_view(request,id,message="",successmessage=""): - try: - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - return HttpResponse("You are not allowed to edit this workout") - except Workout.DoesNotExist: - return HttpResponse("Workout doesn't exist") - - s = "" - # still here - this is a workout we may edit - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return HttpResponse("Error: CSV Data File Not Found") - rowdata.restoreintervaldata() - rowdata.write_csv(f1) - intervalstats = rowdata.allstats() - row.summary = intervalstats - row.save() - itime,idist,itype = rowdata.intervalstats_values() - nrintervals = len(idist) - - # create interactive plot - try: - res = interactive_chart(id,promember=1) - script = res[0] - div = res[1] - except ValueError: - pass - - - url = reverse(workout_summary_edit_view,kwargs={ - 'id':id, - 'successmessage': "Original Interval Data Restored", - } - - ) - return HttpResponseRedirect(url) - - - -@login_required() -def workout_summary_edit_view(request,id,message="",successmessage="" - ): - try: - row = Workout.objects.get(id=id) - if (checkworkoutuser(request.user,row)==False): - return HttpResponse("You are not allowed to edit this workout") - except Workout.DoesNotExist: - return HttpResponse("Workout doesn't exist") - - s = "" - # still here - this is a workout we may edit - f1 = row.csvfilename - u = request.user - r = Rower.objects.get(user=u) - rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an) - rowdata = rdata(f1,rower=rr) - if rowdata == 0: - return HttpResponse("Error: CSV Data File Not Found") - intervalstats = rowdata.allstats() - itime,idist,itype = rowdata.intervalstats_values() - nrintervals = len(idist) - - # create interactive plot - try: - res = interactive_chart(id,promember=1) - script = res[0] - div = res[1] - except ValueError: - pass - - savebutton = 'nosavebutton' - - # We have submitted the mini language interpreter - if request.method == 'POST' and "intervalstring" in request.POST: - form = SummaryStringForm(request.POST) - if form.is_valid(): - cd = form.cleaned_data - s = cd["intervalstring"] - rowdata.updateinterval_string(s) - intervalstats = rowdata.allstats() - itime,idist,itype = rowdata.intervalstats_values() - nrintervals = len(idist) - savebutton = 'savestringform' - - # we are saving the results obtained from the mini language interpreter - elif request.method == 'POST' and "savestringform" in request.POST: - s = request.POST["savestringform"] - rowdata.updateinterval_string(s) - intervalstats = rowdata.allstats() - itime,idist,itype = rowdata.intervalstats_values() - nrintervals = len(idist) - row.summary = intervalstats - #intervalstats = rowdata.allstats() - row.notes += "\n"+s - row.save() - rowdata.write_csv(f1) - data = {'intervalstring':s} - form = SummaryStringForm(initial=data) - savebutton = 'savestringform' - - # we are saving the results obtained from the detailed form - elif request.method == 'POST' and "savedetailform" in request.POST: - savebutton = 'savedetailform' - form = SummaryStringForm() - nrintervals = int(request.POST['nrintervals']) - detailform = IntervalUpdateForm(request.POST,aantal=nrintervals) - itime = [] - idist = [] - itype = [] - ivalues = [] - iunits = [] - itypes = [] - iresults = [] - for i in range(nrintervals): - try: - t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S.%f") - except ValueError: - t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S") - - timesecs = 3600*t.hour+60*t.minute+t.second+t.microsecond/1.e6 - itime += [timesecs] - idist += [int(request.POST['intervald_%s' % i])] - itype += [int(request.POST['type_%s' % i])] - - if itype[i] == 3: # rest - itypes += ['rest'] - ivalues += [timesecs] - iresults += [idist[i]] - iunits += ['seconds'] - if itype[i] == 5 or itype[i] == 2: # distance based work - itypes += ['work'] - ivalues += [idist[i]] - iresults += [timesecs] - iunits += ['meters'] - if itype[i] == 4 or itype[i] == 1: # time based work - itypes += ['work'] - ivalues += [timesecs] - iresults += [idist[i]] - iunits += ['seconds'] - - - rowdata.updateintervaldata(ivalues,iunits,itypes,iresults=iresults) - intervalstats = rowdata.allstats() - row.summary = intervalstats - row.notes += "\n"+s - row.save() - rowdata.write_csv(f1) - - - form = SummaryStringForm() - - # we are processing the details form - elif request.method == 'POST' and "nrintervals" in request.POST: - savebutton = 'savedetailform' - nrintervals = int(request.POST['nrintervals']) - detailform = IntervalUpdateForm(request.POST,aantal=nrintervals) - if detailform.is_valid(): - cd = detailform.cleaned_data - itime = [] - idist = [] - itype = [] - ivalues = [] - iunits = [] - itypes = [] - iresults = [] - for i in range(nrintervals): - t = cd['intervalt_%s' % i] - timesecs = t.total_seconds() - itime += [timesecs] - idist += [cd['intervald_%s' % i]] - itype += [cd['type_%s' % i]] - - if itype[i] == '3': # rest - itypes += ['rest'] - ivalues += [timesecs] - iresults += [idist[i]] - iunits += ['seconds'] - if itype[i] == '5' or itype[i] == '2': # distance based work - itypes += ['work'] - ivalues += [idist[i]] - iresults += [timesecs] - iunits += ['meters'] - if itype[i] == '4' or itype[i] == '1': # time based work - itypes += ['work'] - ivalues += [timesecs] - iresults += [idist[i]] - iunits += ['seconds'] - - rowdata.updateintervaldata(ivalues,iunits, - itypes,iresults=iresults) - intervalstats = rowdata.allstats() - - - form = SummaryStringForm() - - else: - form = SummaryStringForm() - - initial = {} - for i in range(nrintervals): - initial['intervald_%s' % i] = idist[i] - initial['intervalt_%s' % i] = get_time(itime[i]) - initial['type_%s' % i] = itype[i] - - - detailform = IntervalUpdateForm(aantal=nrintervals,initial=initial) - - # render page - return render(request, 'summary_edit.html', - {'form':form, - 'detailform':detailform, - 'workout':row, - 'intervalstats':intervalstats, - 'nrintervals':nrintervals, - 'message': message, - 'successmessage': successmessage, - 'interactiveplot':script, - 'the_div':div, - 'intervalstring':s, - 'savebutton':savebutton, - }) - - - -@login_required() -def rower_edit_view(request,message=""): - if request.method == 'POST': - form = RowerForm(request.POST) - if form.is_valid(): - # something - cd = form.cleaned_data - hrmax = cd['max'] - ut2 = cd['ut2'] - ut1 = cd['ut1'] - at = cd['at'] - tr = cd['tr'] - an = cd['an'] - rest = cd['rest'] - weightcategory = cd['weightcategory'] - try: - r = Rower.objects.get(user=request.user) - r.max = max(min(hrmax,250),10) - r.ut2 = max(min(ut2,250),10) - r.ut1 = max(min(ut1,250),10) - r.at = max(min(at,250),10) - r.tr = max(min(tr,250),10) - r.an = max(min(an,250),10) - r.rest = max(min(rest,250),10) - r.weightcategory = weightcategory - r.save() - message = "User data changed" - url = reverse(workouts_view,args=[str(message)]) - response = HttpResponseRedirect(url) - except Rower.DoesNotExist: - message = "Funny. This user doesn't exist." - url = reverse(workouts_view,args=[str(message)]) - response = HttpResponseRedirect(url) - else: - message = HttpResponse("invalid form") - return render(request, 'rower_form.html', - {'form':form,}) - # url = reverse(rower_edit_view,args=[str(message)]) - # response = HttpResponseRedirect(url) - - - return response - else: - try: - r = Rower.objects.get(user=request.user) - form = RowerForm(instance=r) - return render(request, 'rower_form.html', - {'form':form,}) - except Rower.DoesNotExist: - return HttpResponse("This user doesn't exist") - - diff --git a/rowers/weather.pyc b/rowers/weather.pyc deleted file mode 100644 index 987a65a3..00000000 Binary files a/rowers/weather.pyc and /dev/null differ diff --git a/rowers/weather.py~ b/rowers/weather.py~ deleted file mode 100644 index 795a939f..00000000 --- a/rowers/weather.py~ +++ /dev/null @@ -1,69 +0,0 @@ -import requests -import json -import time -from datetime import datetime -from rowingdata import rowingdata -import pandas as pd -from rowers.models import Rower, Workout - -from rowsandall_app.settings import FORECAST_IO_KEY - - -def get_weather_data(long,lat,unixtime): - url = "https://api.forecast.io/forecast/"+FORECAST_IO_KEY+"/" - url += str(long)+","+str(lat)+","+str(unixtime) - - s = requests.get(url) - - if s.ok: - return s.json() - else: - return 0 - -def get_wind_data(lat,long,unixtime): - data = get_weather_data(lat,long,unixtime) - if data: - try: - # we are getting wind in mph - windspeed = data['currently']['windSpeed']*0.44704 - windbearing = data['currently']['windBearing'] - except KeyError: - windspeed = 0 - windbearing = 0 - - try: - airports = data['flags']['madis-stations'] - except KeyError: - airports = ['unknown'] - - try: - temperature = data['currently']['temperature'] - temperaturec = (temperature-32.)*(5./9.) - temperaturec = int(10*temperaturec)/10. - except KeyError: - temperature = 'unknown' - temperaturec = 'unknown' - - try: - summary = data['currently']['summary'] - except KeyError: - summary = 'unknown' - else: - windspeed = 0 - windbearing = 0 - message = 'Not able to get weather data' - - # apply Hellman's coefficient for neutral air above human inhabitated areas - windspeed = windspeed*(0.1)**0.34 - windspeed = 0.01*int(100*windspeed) - - timestamp = datetime.utcfromtimestamp(unixtime).isoformat()+'Z' - - message = 'Summary for your location at '+timestamp+': '+summary - message += '. Temperature '+str(temperature)+'F/'+str(temperaturec)+'C' - - if data: - message += '. Wind: '+str(windspeed)+' m/s. Wind Bearing: '+str(windbearing)+' degrees' - - - return [windspeed,windbearing,message,airports,timestamp] diff --git a/rowsandall_app/__init__.pyc b/rowsandall_app/__init__.pyc deleted file mode 100644 index b156a277..00000000 Binary files a/rowsandall_app/__init__.pyc and /dev/null differ diff --git a/rowsandall_app/__init__.py~ b/rowsandall_app/__init__.py~ deleted file mode 100644 index 66cd71ed..00000000 --- a/rowsandall_app/__init__.py~ +++ /dev/null @@ -1,3 +0,0 @@ -from __future__ import absolute_import - -from .tasks import app as celery_app diff --git a/rowsandall_app/celery.py~ b/rowsandall_app/celery.py~ deleted file mode 100644 index d5473c5b..00000000 --- a/rowsandall_app/celery.py~ +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import absolute_import - -import os - -from celery import Celery - -# set the default Django settings module for the 'celery' program. -os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings') - -from django.conf import settings # noqa - -app = Celery('proj') - -# Using a string here means the worker will not have to -# pickle the object when using Windows. -app.config_from_object('django.conf:settings') -app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) - - -@app.task(bind=True) -def debug_task(self): - print('Request: {0!r}'.format(self.request)) diff --git a/rowsandall_app/forms.pyc b/rowsandall_app/forms.pyc deleted file mode 100644 index 8e07993e..00000000 Binary files a/rowsandall_app/forms.pyc and /dev/null differ diff --git a/rowsandall_app/forms.py~ b/rowsandall_app/forms.py~ deleted file mode 100644 index e5bf6828..00000000 --- a/rowsandall_app/forms.py~ +++ /dev/null @@ -1,29 +0,0 @@ - -from django import forms -from rowers.models import Workout - -class ContactForm(forms.Form): - subject = forms.CharField() - email = forms.EmailField(required=False) - message = forms.CharField(widget=forms.Textarea) - -class DocumentsForm(forms.Form): - filetypechoices = ( - ('tcx' , 'TCX'), - ('csv' , 'Painsled CSV') - ) - title = forms.CharField(required=False) - file = forms.FileField(required=True) - workouttype = forms.ChoiceField(required=True, - choices=Workout.workouttypes, - initial='rower') - fileformat = forms.ChoiceField(required=True, - choices=filetypechoices, - initial='csv') - - class Meta: - fields = ['title','file','workouttype','fileformat'] - - - - diff --git a/rowsandall_app/models.pyc b/rowsandall_app/models.pyc deleted file mode 100644 index 86b2af7d..00000000 Binary files a/rowsandall_app/models.pyc and /dev/null differ diff --git a/rowsandall_app/models.py~ b/rowsandall_app/models.py~ deleted file mode 100644 index 578e1de4..00000000 --- a/rowsandall_app/models.py~ +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -from django.db import models - -class Document(models.Model): - docfile = models.FileField(upload_to='documents/%Y/%m/%d') diff --git a/rowsandall_app/rctasks.pyc b/rowsandall_app/rctasks.pyc deleted file mode 100644 index 800a31ac..00000000 Binary files a/rowsandall_app/rctasks.pyc and /dev/null differ diff --git a/rowsandall_app/rctasks.py~ b/rowsandall_app/rctasks.py~ deleted file mode 100644 index 6bf0187f..00000000 --- a/rowsandall_app/rctasks.py~ +++ /dev/null @@ -1,3 +0,0 @@ - -def addrc(x,y): - return x+y diff --git a/rowsandall_app/rows.pyc b/rowsandall_app/rows.pyc deleted file mode 100644 index 530d47e7..00000000 Binary files a/rowsandall_app/rows.pyc and /dev/null differ diff --git a/rowsandall_app/rows.py~ b/rowsandall_app/rows.py~ deleted file mode 100644 index bad5eac3..00000000 --- a/rowsandall_app/rows.py~ +++ /dev/null @@ -1,80 +0,0 @@ -import time -from django.core.exceptions import ValidationError - -def format_pace_tick(x,pos=None): - min=int(x/60) - sec=int(x-min*60.) - sec_str=str(sec).zfill(2) - template='%d:%s' - return template % (min,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) - -def format_pace(x,pos=None): - if isinf(x) or isnan(x): - x=0 - - min=int(x/60) - sec=(x-min*60.) - - str1 = "{min:0>2}:{sec:0>4.1f}".format( - min = min, - sec = sec - ) - - return str1 - -def format_time(x,pos=None): - - - min = int(x/60.) - sec = int(x-min*60) - - str1 = "{min:0>2}:{sec:0>4.1f}".format( - min=min, - sec=sec, - ) - - return str1 - -def validate_file_extension(value): - import os - ext = os.path.splitext(value.name)[1] - valid_extensions = ['.tcx','.csv','.TCX','.CSV','.fit','.FIT'] - if not ext in valid_extensions: - raise ValidationError(u'File not supported!') - -def must_be_csv(value): - import os - ext = os.path.splitext(value.name)[1] - valid_extensions = ['.csv','.CSV'] - if not ext in valid_extensions: - raise ValidationError(u'File not supported!') - - -def handle_uploaded_file(f): - fname = f.name - timestr = time.strftime("%Y%m%d-%H%M%S") - fname = timestr+'-'+fname - fname2 = 'media/'+fname - with open(fname2,'wb+') as destination: - for chunk in f.chunks(): - destination.write(chunk) - - return fname,fname2 - -# this might work on windows - -#import magic -#def validate_mime_type(value): -# supported_types=['text/csv','application/vnd.garmin.tcx+xml'] -# with magic.Magic(flags=magic.MAGIC_MIME_TYPE) as m: -# mime_type=m.id_buffer(value.file.read()) -# value.file.seek(0) -# if mime_type not in supported_types: -# raise ValidationError(u'Unsupported file type.') diff --git a/rowsandall_app/settings.pyc b/rowsandall_app/settings.pyc deleted file mode 100644 index e356dbc8..00000000 Binary files a/rowsandall_app/settings.pyc and /dev/null differ diff --git a/rowsandall_app/settings.py~ b/rowsandall_app/settings.py~ deleted file mode 100644 index 4d4eaa1f..00000000 --- a/rowsandall_app/settings.py~ +++ /dev/null @@ -1,236 +0,0 @@ -""" -Django settings for rowsandall_app project. - -Generated by 'django-admin startproject' using Django 1.9.5. - -For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ -""" -# -*- coding: utf-8 -*- -import os -from django.utils.translation import ugettext_lazy as _ - - -DEFAULT_CHARSET = 'UTF-8' - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = 'z_@2yia858=2i1cygo4ne3+14&i_&@wlty68$q1igdvn=9k5mo' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = False - -ALLOWED_HOSTS = ['rowsandall.com','rowsandall-1072.rostiapp.cz'] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', - 'rowers', - 'cvkbrno', - 'django_rq', - 'translation_manager', - 'debug_toolbar', - 'django_mailbox', -] - -MIDDLEWARE_CLASSES = [ - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.locale.LocaleMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'rowsandall_app.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [os.path.join(BASE_DIR,'templates')], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - 'django.template.context_processors.i18n', - ], -# 'loaders': [ -# 'django.template.loaders.app_directories.Loader', -# ], - }, - - }, -] - - -WSGI_APPLICATION = 'rowsandall_app.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.mysql', - 'NAME': 'rowsanda_107501', - 'USER': 'rowsanda_107501', - 'PASSWORD': 'roeidata', - 'HOST': 'store3.rosti.cz', - 'PORT': '3306', - }, - 'slave': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - }, - 'TEST': { - 'CHARSET': 'utf8', - 'COLLATION': 'utf8_general_ci', - }, -} - - -# Password validation -# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/1.9/topics/i18n/ - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - -LOCALE_PATHS = ( - os.path.join(BASE_DIR, 'locale'), - os.path.join(BASE_DIR, 'cvkbrno/locale'), - ) - -LANGUAGES = ( - ('cs',_(u'Czech')), - ('nl',_(u'Dutch')) - ) - -LANGUAGE_CODE = 'en-us' -LANGUAGE_COOKIE_NAME = 'wm_lang' - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.9/howto/static-files/ - -STATIC_URL = '/static/' -STATIC_ROOT = os.path.join(BASE_DIR, 'static') - -STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static'), - os.path.join(BASE_DIR, 'static/plots'),] - - -BROKER_URL = 'redis://localhost:6379/0' -CELERY_RESULT_BACKEND = 'redis://localhost:6379/0' -CELERY_IGNORE_RESULT = False - -CELERY_ACCEPT_CONTENT = ['json'] -CELERY_TASK_SERIALIZER = 'json' -CELERY_RESULT_SERIALIZER = 'json' -CELERY_TRACK_STARTED = True -CELERY_SEND_TASK_SENT_EVENT = True - -# user authentication - -# user authentication -LOGIN_REDIRECT_URL = '/rowers/list-workouts/' -LOGIN_URL = '/login/' - -# Concept 2 -C2_CLIENT_ID = "bgTBbmjSyn8wbJb0JEdlYjDUfSZFAPQSzJV8YDwH" -C2_CLIENT_SECRET = "HD6HnEu8bFWGkrpGoa89kliXhofLzAHzllltWMPg" -C2_REDIRECT_URI = "http://rowsandall.com/call_back" - -# Strava - -STRAVA_CLIENT_ID = "11567" -STRAVA_CLIENT_SECRET = "9e55d439879e1da6724e75e4a3220b35a493fe24" -STRAVA_REDIRECT_URI = "http://rowsandall.com/stravacall_back" - -# SportTracks - -SPORTTRACKS_CLIENT_ID = "rowingdata" -SPORTTRACKS_CLIENT_SECRET = "3GZVXH8GB4PZQHPD" -SPORTTRACKS_REDIRECT_URI = "http://rowsandall.com/sporttracks_callback" - -# RQ stuff - -RQ_QUEUES = { - 'default': { - 'HOST': 'localhost', - 'PORT': 6379, - 'DB': 0, -# 'PASSWORD': 'some-password', - 'DEFAULT_TIMEOUT': 360, - }, - 'low': { - 'HOST': 'localhost', - 'PORT': 6379, - 'DB': 0, -# 'PASSWORD': 'some-password', - 'DEFAULT_TIMEOUT': 360, - }, -} - - -#SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" -#SESSION_ENGINE = "django.contrib.sessions.backends.cached_db" -SESSION_ENGINE = "django.contrib.sessions.backends.cache" - -# email stuff - -EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' -EMAIL_HOST = 'mail.rosti.cz' -EMAIL_PORT = '25' -EMAIL_HOST_USER = 'info@rowsandall.com' -EMAIL_HOST_PASSWORD = 'lnD3mbZ1NoI8RK1StOdO' -EMAIL_USE_TLS = True - -# weather stuff - -FORECAST_IO_KEY = "bc8196fbd89f11375c7dfc8aa6323c72" -GMAPIKEY = "AIzaSyAgu1w9QSthaGPMLp8y9JedPoMc9sfEgJ8" diff --git a/rowsandall_app/settings_dev.pyc b/rowsandall_app/settings_dev.pyc deleted file mode 100644 index 2dd9bca2..00000000 Binary files a/rowsandall_app/settings_dev.pyc and /dev/null differ diff --git a/rowsandall_app/settings_dev.py~ b/rowsandall_app/settings_dev.py~ deleted file mode 100644 index a1b69514..00000000 --- a/rowsandall_app/settings_dev.py~ +++ /dev/null @@ -1,64 +0,0 @@ -""" -Django settings for rowsandall_app project. - -Generated by 'django-admin startproject' using Django 1.9.5. - -For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ -""" -from settings import * - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),}, -# 'TEST': { -# 'CHARSET': 'utf8', -# 'COLLATION': 'utf8_general_ci', -# }, - -# 'slave': { -# 'ENGINE': 'django.db.backends.mysql', -# 'NAME': 'rowsanda_107501', -# 'USER': 'rowsanda_107501', -# 'PASSWORD': 'roeidata', -# 'HOST': 'store3.rosti.cz', -# 'PORT': '3306', -# } - } - - - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - - -STATIC_URL = '/static/' -STATIC_ROOT = 'C:/python/rowsandallapp' - - -MEDIA_URL = '/media/' -MEDIA_ROOT = os.path.join(BASE_DIR, 'media') - -LOGIN_REDIRECT_URL = '/rowers/list-workouts/' - -SESSION_ENGINE = "django.contrib.sessions.backends.signed_cookies" - -#EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' - -#EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' -#EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' - -#EMAIL_HOST = 'localhost' -#EMAIL_PORT = '1025' -#EMAIL_HOST_USER = '' -#EMAIL_HOST_PASSWORD = '' -#EMAIL_USE_TLS = True diff --git a/rowsandall_app/settings_orig.pyc b/rowsandall_app/settings_orig.pyc deleted file mode 100644 index 0ca1ec43..00000000 Binary files a/rowsandall_app/settings_orig.pyc and /dev/null differ diff --git a/rowsandall_app/settings_orig.py~ b/rowsandall_app/settings_orig.py~ deleted file mode 100644 index a69ba65a..00000000 --- a/rowsandall_app/settings_orig.py~ +++ /dev/null @@ -1,121 +0,0 @@ -""" -Django settings for rowsandall_app project. - -Generated by 'django-admin startproject' using Django 1.9.5. - -For more information on this file, see -https://docs.djangoproject.com/en/1.9/topics/settings/ - -For the full list of settings and their values, see -https://docs.djangoproject.com/en/1.9/ref/settings/ -""" - -import os - -# Build paths inside the project like this: os.path.join(BASE_DIR, ...) -BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - - -# Quick-start development settings - unsuitable for production -# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/ - -# SECURITY WARNING: keep the secret key used in production secret! -SECRET_KEY = '&cg#y8h-8s#00ayk#gu)+l43j1j9^9r&qf$3!$x#ov@1houiph' - -# SECURITY WARNING: don't run with debug turned on in production! -DEBUG = True - -ALLOWED_HOSTS = [] - - -# Application definition - -INSTALLED_APPS = [ - 'django.contrib.admin', - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.messages', - 'django.contrib.staticfiles', -] - -MIDDLEWARE_CLASSES = [ - 'django.middleware.security.SecurityMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.middleware.common.CommonMiddleware', - 'django.middleware.csrf.CsrfViewMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', - 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', - 'django.contrib.messages.middleware.MessageMiddleware', - 'django.middleware.clickjacking.XFrameOptionsMiddleware', -] - -ROOT_URLCONF = 'rowsandall_app.urls' - -TEMPLATES = [ - { - 'BACKEND': 'django.template.backends.django.DjangoTemplates', - 'DIRS': [], - 'APP_DIRS': True, - 'OPTIONS': { - 'context_processors': [ - 'django.template.context_processors.debug', - 'django.template.context_processors.request', - 'django.contrib.auth.context_processors.auth', - 'django.contrib.messages.context_processors.messages', - ], - }, - }, -] - -WSGI_APPLICATION = 'rowsandall_app.wsgi.application' - - -# Database -# https://docs.djangoproject.com/en/1.9/ref/settings/#databases - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), - } -} - - -# Password validation -# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators - -AUTH_PASSWORD_VALIDATORS = [ - { - 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', - }, - { - 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', - }, -] - - -# Internationalization -# https://docs.djangoproject.com/en/1.9/topics/i18n/ - -LANGUAGE_CODE = 'en-us' - -TIME_ZONE = 'UTC' - -USE_I18N = True - -USE_L10N = True - -USE_TZ = True - - -# Static files (CSS, JavaScript, Images) -# https://docs.djangoproject.com/en/1.9/howto/static-files/ - -STATIC_URL = '/static/' diff --git a/rowsandall_app/tasks.py~ b/rowsandall_app/tasks.py~ deleted file mode 100644 index 4c4639d4..00000000 --- a/rowsandall_app/tasks.py~ +++ /dev/null @@ -1,42 +0,0 @@ -from celery import Celery -import os - -import rowingdata -from rowingdata import main as rmain -from rowingdata import rowingdata as rdata -import rowingdata -from matplotlib.backends.backend_agg import FigureCanvasAgg -import matplotlib.pyplot as plt -from rowers.models import Rower, User - -app = Celery('tasks', - broker='redis://localhost', - backend='redis://localhost',) - -# Using a string here means the worker will not have to -# pickle the object when using Windows. -#app.config_from_object('django.conf:settings') - - -@app.task -def add(x, y): - return x + y - -@app.task -def handle_makeplot(f1,f2,t): #,user): - r = Rower.objects.get(user=user) - rr = rowingdata.rower(hrmax=r.max,hrut2=r.ut2,hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an,weightcategory=r.weightcategory) - row = rdata(f2,rower=rr) - fig1 = row.get_timeplot_erg(t) - - canvas = FigureCanvasAgg(fig1) - imagename = f1+'.png' - - plt.savefig('static/plots/'+imagename,format='png') - plt.close(fig1) - return imagename - - -def add2(x,y): - return x+y diff --git a/rowsandall_app/urls.pyc b/rowsandall_app/urls.pyc deleted file mode 100644 index b3b06517..00000000 Binary files a/rowsandall_app/urls.pyc and /dev/null differ diff --git a/rowsandall_app/urls.py~ b/rowsandall_app/urls.py~ deleted file mode 100644 index 809f9bbd..00000000 --- a/rowsandall_app/urls.py~ +++ /dev/null @@ -1,58 +0,0 @@ -"""rowsandall_app URL Configuration - -The `urlpatterns` list routes URLs to views. For more information please see: - https://docs.djangoproject.com/en/1.9/topics/http/urls/ -Examples: -Function views - 1. Add an import: from my_app import views - 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') -Class-based views - 1. Add an import: from other_app.views import Home - 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') -Including another URLconf - 1. Import the include() function: from django.conf.urls import url, include - 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) -""" -from django.conf.urls import url,include -from django.conf import settings -from django.conf.urls.static import static -from django.contrib import admin -from rowsandall_app.views import rootview,version,rowingdata,showStaticImage,\ - add,wait,nrowingdata,waitforplot,showplot,interactiveplot -from rowsandall_app.views import uploadfile -from django.contrib.auth import views as auth_views -from rowers import views as rowersviews - - -urlpatterns = [ - url(r'^admin/', admin.site.urls), -# url('^', include('django.contrib.auth.urls')), - url(r'^$',rootview), - url(r'^version/$',version), -# url(r'^rowingdata/$',rowingdata,{'formloc':'/rowingdata/'}), -# url(r'^nrowingdata/$',nrowingdata,{'formloc':'/nrowingdata/'}), -# url(r'^upload/$',uploadfile,{'formloc':'/upload/'}), - url(r'^addresult/(.+.*)/$',wait), -# url(r'^waitforplot/(.+.*)/$',waitforplot), -# url(r'^showplot/(.+.*)/$',showplot), - url(r'^login/',auth_views.login, name='login'), - url(r'^logout/',auth_views.logout_then_login,name='logout'), - url(r'^password_change_done/$',auth_views.password_change_done,name='password_change_done'), - url(r'^password_change/',auth_views.password_change), - url(r'^password_reset/$',auth_views.password_reset,name='password_reset'), - url(r'^password_reset_done/$',auth_views.password_reset_done,name='password_reset_done'), - url(r'^password_reset_confirm/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', 'django.contrib.auth.views.password_reset_confirm',name='password_reset_confirm'), - url(r'^password_reset_confirm/$',auth_views.password_reset_confirm,name='password_reset_confirm'), - url(r'^password_reset_complete/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$', 'django.contrib.auth.views.password_reset_complete',name='password_reset_complete'), - url(r'^password_reset_complete/$',auth_views.password_reset_complete,name='password_reset_complete'), - url(r'^rowers/',include('rowers.urls')), - url(r'^cvkbrno/',include('cvkbrno.urls')), - url(r'^add/(\d+)/(\d+)/$',add), - url(r'^call\_back',rowersviews.rower_process_callback), - url(r'^stravacall\_back',rowersviews.rower_process_stravacallback), - url(r'^sporttracks\_callback',rowersviews.rower_process_sporttrackscallback), - url(r'^interactiveplot',interactiveplot), - url(r'^i18n/', include('django.conf.urls.i18n')), - ] - - diff --git a/rowsandall_app/views.pyc b/rowsandall_app/views.pyc deleted file mode 100644 index a9390336..00000000 Binary files a/rowsandall_app/views.pyc and /dev/null differ diff --git a/rowsandall_app/views.py~ b/rowsandall_app/views.py~ deleted file mode 100644 index 54ae5330..00000000 --- a/rowsandall_app/views.py~ +++ /dev/null @@ -1,258 +0,0 @@ -from django.http import HttpResponse,Http404,HttpResponseRedirect -from django.template import Template, Context -from django.template.loader import get_template -from django.shortcuts import render, redirect, render_to_response -from django.conf import settings -from rowsandall_app.forms import ContactForm,DocumentsForm -from django.core.mail import send_mail -from django.core.urlresolvers import reverse -from matplotlib.pyplot import figure, axes, pie, title -from matplotlib.backends.backend_agg import FigureCanvasAgg -from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter -import matplotlib.pyplot as plt -from rowingdata import rower as rrower -from rowingdata import main as rmain -from rowingdata import rowingdata as rdata -from rowingdata import TCXParser -import StringIO -from django.contrib.auth.decorators import login_required - -import django_rq -queue = django_rq.get_queue('default') - -import datetime -import pandas as pd -import os -import numpy as np -import json -import mpld3 - -from rctasks import addrc - -from rows import * -from rowers.tasks import add as addtask -from rowers.tasks import handle_makeplot -from celery.result import AsyncResult -from celery.exceptions import TimeoutError -from rowers.models import Rower,User,Workout,GraphImage - - -def showStaticImage(request,imagename): - return render(request, 'image_page.html', {'imagename': imagename}) - -def rootview(request): - magicsentence = rmain() - return render(request, 'base.html', {'versionstring': magicsentence}) - - -def version(request): - magicsentence = rmain() - return render(request, 'base.html', {'versionstring': magicsentence}) - -def rowingdata(request,formloc): - if request.method == 'POST': - form = DocumentsForm(request.POST,request.FILES) - - if form.is_valid(): - f = request.FILES['file'] - t = request.POST['title'] - res = handle_uploaded_file(f) - f1 = res[0] - f2 = res[1] - row = rdata(f2) - fig1 = row.get_timeplot_erg(t) - - canvas = FigureCanvasAgg(fig1) - # response = HttpResponse(content_type='image/png') - # canvas.print_png(response) - imagename = f1+'.png' - plt.savefig('static/plots/'+imagename,format='png') - plt.close(fig1) - response = render(request,'image_page.html',{'imagename':'plots/'+imagename}) - - else: - response = HttpResponse("invalid form") - - return response - else: - form = DocumentsForm() - return render(request, 'document_form.html', - {'form':form, 'formloc': formloc}) - -@login_required() -def nrowingdata(request,formloc): - if request.method == 'POST': - form = DocumentsForm(request.POST,request.FILES) - - if form.is_valid(): - f = request.FILES['file'] - res = handle_uploaded_file(f) - t = request.POST['title'] - fileformat = request.POST['fileformat'] - workouttype = request.POST['workouttype'] - notes = request.POST['notes'] - - f1 = res[0] # file name - f2 = res[1] # file name incl media directory - - # handle TCX - if (fileformat == 'tcx'): - row = TCXParser(f2) - f_to_be_deleted = f2 - # should delete file - f2 = f2+'.csv' - row.write_csv(f2) - os.remove(f_to_be_deleted) - - imagename = f1+'.png' - fullpathimagename = 'static/plots/'+imagename - u = request.user - r = Rower.objects.get(user=request.user) - hrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - } - - # make plot - asynchronous task - res = handle_makeplot.delay(f1,f2,t,hrdata) - - # 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) - row = rdata(f2,rower=rr) - totaldist = row.df['cum_dist'].max() - totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min() - totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)'] - - - hours = int(totaltime/3600.) - minutes = int((totaltime - 3600.*hours)/60.) - seconds = int(totaltime - 3600.*hours - 60.*minutes) - - duration = "%s:%s:%s" % (hours,minutes,seconds) - - - workoutdate = row.rowdatetime.strftime('%Y-%m-%d') - workoutstarttime = row.rowdatetime.strftime('%H:%M:%S') - - # check for duplicate start times - r = Rower.objects.get(user=request.user) - - ws = Workout.objects.filter(starttime=workoutstarttime, - user=r) - if (len(ws) != 0): - print "Warning: This workout probably already exists in the database" - - w = Workout(user=r,name=t,date=workoutdate,workouttype=workouttype, - duration=duration,distance=totaldist, - weightcategory=r.weightcategory, - starttime=workoutstarttime, - csvfilename=f2,notes=notes) - w.save() - - i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(), - filename=fullpathimagename) - i.save() - - url = reverse(waitforplot,args=[str(res.id)]) - return HttpResponseRedirect(url) - - else: - response = HttpResponse("invalid form") - - return response - else: - form = DocumentsForm() - return render(request, 'document_form.html', - {'form':form, 'formloc': formloc}) - - - -def uploadfile(request,formloc): - if request.method == 'POST': - form = DocumentsForm(request.POST, request.FILES) - - if form.is_valid(): - result = handle_uploaded_file(request.FILES['file']) - return HttpResponse("succes! "+result) - else: - return HttpResponse("Invalid Form") - else: - form = DocumentsForm() - return render(request, 'document_form.html', - {'form': form, 'formloc':formloc}) - -@login_required() -def add(request,x,y): - if settings.DEBUG: - task = addtask.apply_async((int(x),int(y)),countdown=10) - task_id = AsyncResult(task) - print task.id - else: - task = queue.enqueue(addrc,x,y,0) - task_id = task.id - - url = reverse(wait,args=[str(task_id)]) - return HttpResponseRedirect(url) - - - - -def wait(request,task_id=""): - if settings.DEBUG: - res = AsyncResult(task_id) - else: - res = queue.fetch_job(task_id) - if (res.status == 'SUCCESS') or (res.status == 'finished'): - return HttpResponse("Task complete. Result: "+str(res.result)) - else: - m = "Task status: "+str(res.status) - return render(request,'waiting_page.html',{'message':m}) - return HttpResponse("Task status: "+str(res.status)+".

Hit reload to check again") - - -def waitforplot(request,task_id=""): - res = AsyncResult(task_id) - if (res.status == 'SUCCESS'): - url = reverse(showplot,args=[str(res.result)]) - return HttpResponseRedirect(url) - else: - m = "Task status: "+str(res.status) - - return render(request,'waiting_page.html',{'message':m}) - -def showplot(request,imagename=""): - return render(request,'image_page.html',{'imagename':'plots/'+imagename}) - - -def contact(request): - if request.method == 'POST': - form = ContactForm(request.POST) - if form.is_valid(): - cd = form.cleaned_data - send_mail( - cd['subject'], - cd['message'], - cd.get('email', 'noreply@example.com'), - ['siteowner@example.com'], - ) - return HttpResponseRedirect('/contact/thanks/') - else: - form = ContactForm() - return render(request, 'contact_form.html', {'form': form}) - -def interactiveplot(request): - x = np.linspace(-10,10,num=1200) - y = x**2-5*x+4 - fig = plt.figure(figsize=(6,5)) - graph = plt.plot(x,y) - g = mpld3.fig_to_html(fig) - # js_data = json.dumps(mpld3.fig_to_dict(fig)) - plt.close() - # return render(request,'interactiveplot.html',{"my_data":js_data}) - return HttpResponse(g) diff --git a/rowsandall_app/wsgi.pyc b/rowsandall_app/wsgi.pyc deleted file mode 100644 index 8aecfe67..00000000 Binary files a/rowsandall_app/wsgi.pyc and /dev/null differ diff --git a/static/css/nav.css~ b/static/css/nav.css~ deleted file mode 100644 index 375dd307..00000000 --- a/static/css/nav.css~ +++ /dev/null @@ -1,63 +0,0 @@ -body {padding: 0; margin: 0;} - -#wrap { - width: 100%; - height: 50px; - margin: 0; - z-index: 99; - position: relative; - background-color: #366b82; - } - - .navbar { - height: 50px; - padding: 0; - margin: 0; - position: absolute; - border-right: 1px solid #54879d; - } - - .navbar li { - height: auto; - width: 150px; - float: left; - text-align: center; - list-style: none; - font: normal bold 12px/1.2em Arial, Verdana, Helvetica; - padding: 0; - margin: 0; - background-color: #366b82; - } - - .navbar a { - padding: 18px 0; - border-left: 1px solid #54879d; - border-right: 1px solid #1f5065; - text-decoration: none; - color: white; - display: block; - } - - .navbar li:hover, a:hover {background-color: #54879d;} - - .navbar li ul { - display: none; - height: auto; - margin: 0; - padding: 0; - } - - .navbar li:hover ul { - display: block; - } - - .navbar li ul li {background-color: #54879d;} - - .navbar li ul li a { - border-left: 1px solid #1f5065; - border-right: 1px solid #1f5065; - border-top: 1px solid #74a3b7; - border-bottom: 1px solid #1f5065; - } - - .navbar li ul li a:hover {background-color: #366b82;} diff --git a/static/css/rowsandall.css~ b/static/css/rowsandall.css~ deleted file mode 100644 index 999a9189..00000000 --- a/static/css/rowsandall.css~ +++ /dev/null @@ -1,473 +0,0 @@ - -html { - font-size: 62.5%; -} - -body { - background: #edc; - color: #333; - font-size: 1.2em; - height: auto; - padding-bottom: 20px; -} - -a { -/* color: #fff; */ - text-decoration: none; -} - -a:visited { color:#000; } - -a:link { color: #000; } - -a:hover { - text-decoration: underline; -} - -h1 { -/* font-family: Georgia, serif; */ - font-weight: normal; -/* padding-top: 20px; */ - text-align: left; -} - -h2 { -/* padding-top: 20px; */ - text-align: left; -} - -p { -/* border: 1px solid #666; */ - overflow: hidden; -/* padding: 10px 0; */ - text-align: left; -} - - -th { - font-weight: bold; - } - -.listtable tbody tr:nth-of-type(even) { background-color: #DDD; } -.listtable thead th { - font-weight: bold; -} -.paddedtable td { padding: 1px 20px } - - -.fixtable table { - table-layout: fixed; - width: 60%; - } - -.message { - border: 1px solid #000; - background-color: #f88; - font-weight: bold; - color: #000; - text-align: center; - } - -.midden { text-align: center } - -.successmessage { - border: 1px solid #000; - background-color: #8f8; - color: #000; - text-align: center; - font-weight: bold; - } - -.deletelink { - border: 1px solid #000; - background-color: #f88; - color: #000; - text-align: center; - font-weight: bold; - } - -.navbar { - border: 1px solid #666; - color: #000; - - - overflow: hidden; - background-color: #ddd; -/* padding: 10px 0; */ - text-align: center; -} - -.navbutton { - background-color: #ddd; - -moz-border-radius: 15px; - -webkit-border-radius: 15px; - border: 2px solid #666; - padding: 5px; - text-align: center; - } - -.tooltip { - position: relative; - display: inline-block; -} - -.tooltip .tooltiptext { - visibility: hidden; - width: 120px; - background-color: #ffff66; - color: black; - text-align: center; - border-radius: 6px; - padding: 5px 5px; - - /* Position the tooltip */ - position: absolute; - z-index: 999; -} - -.tooltip:hover .tooltiptext { - visibility: visible; - transition-delay:1s; -} - -.caption { - text-align: center; - } - -.button { - font: 1.1em/1.5em sans-serif; - text-decoration: none; - display: block; - /* width: 100%; */ - color: white; - padding: 0.2em 0.0em 0.2em 0.0em; - zoom: 1; - border-radius: .5em; - -moz-border-radius: .5em; - -webkit-border-radius: .5em; - -box-shadow: 0 1px 3px rgba(0,0,0,0.5); - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5); - text-shadow: 0 -1px 1px rgba(0,0,0,0.25); - text-align: center; -} - -.input { - font: 1.1em/1.5em sans-serif; - text-decoration: none; - display: block; - /* width: 100%; */ - color: white; - padding: 0.2em 0.0em 0.2em 0.0em; - zoom: 1; - border-radius: .5em; - -moz-border-radius: .5em; - -webkit-border-radius: .5em; - -box-shadow: 0 1px 3px rgba(0,0,0,0.5); - -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5); - -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5); - text-shadow: 0 -1px 1px rgba(0,0,0,0.25); - text-align: center; -} - -a.button { - color: white; - } - -.button:hover { - background: #d8e6ff; /* old browsers */ - background: -moz-linear-gradient(top, #d8e6ff 0%, #8da8d7 100%); /* firefox */ - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#d8e6ff), color-stop(100%,#8da8d7)); /* webkit */ - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#d8e6ff', endColorstr='#8da8d7',GradientType=0 ); /* ie */ - text-decoration: none; -} - -.button:active { - position: relative; - top: 1px; -} - -.bigrounded { - -webkit-border-radius: 2em; - -moz-border-radius: 2em; - border-radius: 2em; -} -.medium { - font-size: 1.2em; -} -.small { - font-size: 1.0em; -} - -/* black */ -.black { - color: #d7d7d7; - border: solid 1px #333; - background: #333; - background: -webkit-gradient(linear, left top, left bottom, from(#666), to(#000)); - background: -moz-linear-gradient(top, #666, #000); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#666666', endColorstr='#000000'); -} -.black:hover { - background: #000; - background: -webkit-gradient(linear, left top, left bottom, from(#444), to(#000)); - background: -moz-linear-gradient(top, #444, #000); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#444444', endColorstr='#000000'); -} -.black:active { - color: #666; - background: -webkit-gradient(linear, left top, left bottom, from(#000), to(#444)); - background: -moz-linear-gradient(top, #000, #444); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#000000', endColorstr='#666666'); -} - -/* gray */ -.gray { - color: #e9e9e9; - border: solid 1px #555; - background: #6e6e6e; - background: -webkit-gradient(linear, left top, left bottom, from(#888), to(#575757)); - background: -moz-linear-gradient(top, #888, #575757); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#888888', endColorstr='#575757'); -} -.gray:hover { - background: #616161; - background: -webkit-gradient(linear, left top, left bottom, from(#757575), to(#4b4b4b)); - background: -moz-linear-gradient(top, #757575, #4b4b4b); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#757575', endColorstr='#4b4b4b'); -} -.gray:active { - color: #afafaf; - background: -webkit-gradient(linear, left top, left bottom, from(#575757), to(#888)); - background: -moz-linear-gradient(top, #575757, #888); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#575757', endColorstr='#888888'); -} - -/* white */ -.white { - color: #606060; - border: solid 1px #b7b7b7; - background: #fff; - background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#ededed)); - background: -moz-linear-gradient(top, #fff, #ededed); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed'); -} -.white:hover { - background: #ededed; - background: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#dcdcdc)); - background: -moz-linear-gradient(top, #fff, #dcdcdc); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#dcdcdc'); -} -.white:active { - color: #999; - background: -webkit-gradient(linear, left top, left bottom, from(#ededed), to(#fff)); - background: -moz-linear-gradient(top, #ededed, #fff); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff'); -} - -/* orange */ -.orange { - color: #fef4e9; - border: solid 1px #da7c0c; - background: #f78d1d; - background: -webkit-gradient(linear, left top, left bottom, from(#faa51a), to(#f47a20)); - background: -moz-linear-gradient(top, #faa51a, #f47a20); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#faa51a', endColorstr='#f47a20'); -} -.orange:hover { - background: #f47c20; - background: -webkit-gradient(linear, left top, left bottom, from(#f88e11), to(#f06015)); - background: -moz-linear-gradient(top, #f88e11, #f06015); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f88e11', endColorstr='#f06015'); -} -.orange:active { - color: #fcd3a5; - background: -webkit-gradient(linear, left top, left bottom, from(#f47a20), to(#faa51a)); - background: -moz-linear-gradient(top, #f47a20, #faa51a); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f47a20', endColorstr='#faa51a'); -} - -/* red */ -.red { - color: #faddde; - border: solid 1px #980c10; - background: #d81b21; - background: -webkit-gradient(linear, left top, left bottom, from(#ed1c24), to(#aa1317)); - background: -moz-linear-gradient(top, #ed1c24, #aa1317); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ed1c24', endColorstr='#aa1317'); -} -.red:hover { - background: #b61318; - background: -webkit-gradient(linear, left top, left bottom, from(#c9151b), to(#a11115)); - background: -moz-linear-gradient(top, #c9151b, #a11115); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#c9151b', endColorstr='#a11115'); -} -.red:active { - color: #de898c; - background: -webkit-gradient(linear, left top, left bottom, from(#aa1317), to(#ed1c24)); - background: -moz-linear-gradient(top, #aa1317, #ed1c24); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#aa1317', endColorstr='#ed1c24'); -} - -/* blue */ -.blue { - color: #d9eef7; - border: solid 1px #0076a3; - background: #0095cd; - background: -webkit-gradient(linear, left top, left bottom, from(#00adee), to(#0078a5)); - background: -moz-linear-gradient(top, #00adee, #0078a5); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00adee', endColorstr='#0078a5'); -} -.blue:hover { - background: #007ead; - background: -webkit-gradient(linear, left top, left bottom, from(#0095cc), to(#00678e)); - background: -moz-linear-gradient(top, #0095cc, #00678e); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0095cc', endColorstr='#00678e'); -} -.blue:active { - color: #80bed6; - background: -webkit-gradient(linear, left top, left bottom, from(#0078a5), to(#00adee)); - background: -moz-linear-gradient(top, #0078a5, #00adee); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0078a5', endColorstr='#00adee'); -} - -/* rosy */ -.rosy { - color: #fae7e9; - border: solid 1px #b73948; - background: #da5867; - background: -webkit-gradient(linear, left top, left bottom, from(#f16c7c), to(#bf404f)); - background: -moz-linear-gradient(top, #f16c7c, #bf404f); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f16c7c', endColorstr='#bf404f'); -} -.rosy:hover { - background: #ba4b58; - background: -webkit-gradient(linear, left top, left bottom, from(#cf5d6a), to(#a53845)); - background: -moz-linear-gradient(top, #cf5d6a, #a53845); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#cf5d6a', endColorstr='#a53845'); -} -.rosy:active { - color: #dca4ab; - background: -webkit-gradient(linear, left top, left bottom, from(#bf404f), to(#f16c7c)); - background: -moz-linear-gradient(top, #bf404f, #f16c7c); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#bf404f', endColorstr='#f16c7c'); -} - -/* green */ -.green { - color: #e8f0de; - border: solid 1px #538312; - background: #64991e; - background: -webkit-gradient(linear, left top, left bottom, from(#7db72f), to(#4e7d0e)); - background: -moz-linear-gradient(top, #7db72f, #4e7d0e); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#7db72f', endColorstr='#4e7d0e'); -} -.green:hover { - background: #538018; - background: -webkit-gradient(linear, left top, left bottom, from(#6b9d28), to(#436b0c)); - background: -moz-linear-gradient(top, #6b9d28, #436b0c); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#6b9d28', endColorstr='#436b0c'); -} -.green:active { - color: #a9c08c; - background: -webkit-gradient(linear, left top, left bottom, from(#4e7d0e), to(#7db72f)); - background: -moz-linear-gradient(top, #4e7d0e, #7db72f); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#4e7d0e', endColorstr='#7db72f'); -} - -/* pink */ -.pink { - color: #feeef5; - border: solid 1px #d2729e; - background: #f895c2; - background: -webkit-gradient(linear, left top, left bottom, from(#feb1d3), to(#f171ab)); - background: -moz-linear-gradient(top, #feb1d3, #f171ab); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#feb1d3', endColorstr='#f171ab'); -} -.pink:hover { - background: #d57ea5; - background: -webkit-gradient(linear, left top, left bottom, from(#f4aacb), to(#e86ca4)); - background: -moz-linear-gradient(top, #f4aacb, #e86ca4); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f4aacb', endColorstr='#e86ca4'); -} -.pink:active { - color: #f3c3d9; - background: -webkit-gradient(linear, left top, left bottom, from(#f171ab), to(#feb1d3)); - background: -moz-linear-gradient(top, #f171ab, #feb1d3); - filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#f171ab', endColorstr='#feb1d3'); -} - - -.greenbar { - border: 1px solid #666; - color: #000; - - - overflow: hidden; - background-color: #8f8; -/* padding: 10px 0; */ - text-align: center; -} - - -#footer { - text-align:center; - } - -.container_12, -.container_16, -.container_24 { - background-color: #fff; - background-repeat: repeat-y; -/* margin-bottom: 20px; */ -} - -.container_12 { -/* background-image: url(../img/12_col.gif); */ -} - - -/* Style The Dropdown Button */ -.dropbtn { - color: white; -} - -/* The container

- needed to position the dropdown content */ -.dropdown { - position: relative; - display: inline-block; -} - -/* Dropdown Content (Hidden by Default) */ -.dropdown-content { - display: none; - position: absolute; - min-width: 160px; - box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2); - z-index: 999; -} - -/* Links inside the dropdown */ -.dropdown-content a { - text-decoration: none; - display: block; - z-index: 999; -} - -/* Change color of dropdown links on hover */ -/* .dropdown-content a:hover {background-color: #f1f1f1} */ - -/* Show the dropdown menu on hover */ -.dropdown:hover .dropdown-content { - display: block; -} - -/* Change the background color of the dropdown button when the dropdown content is shown */ -.dropdown:hover .dropbtn { - background-color: #3e8e41; -} - -.flexplot { - position: relative; - z-index: 10; -} \ No newline at end of file diff --git a/static/css/text.css~ b/static/css/text.css~ deleted file mode 100644 index 2c115db2..00000000 --- a/static/css/text.css~ +++ /dev/null @@ -1,86 +0,0 @@ -/* - 960 Grid System ~ Text CSS. - Learn more ~ http://960.gs/ - - Licensed under GPL and MIT. -*/ - -/* `Basic HTML -----------------------------------------------------------------------------------------------------*/ - -body { - font: 13px/1.5 "Helvetica Neue", Arial, "Liberation Sans", FreeSans, sans-serif; -} - -pre, -code { - font-family: "DejaVu Sans Mono", Menlo, Consolas, monospace; -} - -hr { - border: 0 solid #ccc; - border-top-width: 1px; - clear: both; - height: 0; -} - -/* `Headings -----------------------------------------------------------------------------------------------------*/ - -h1 { - font-size: 25px; -} - -h2 { - font-size: 23px; -} - -h3 { - font-size: 21px; -} - -h4 { - font-size: 19px; -} - -h5 { - font-size: 17px; -} - -h6 { - font-size: 15px; -} - -/* `Spacing -----------------------------------------------------------------------------------------------------*/ - -ol { - list-style: decimal; -} - -ul { - list-style: disc; -} - -li { - margin-left: 30px; -} - -p, -dl, -hr, -h1, -h2, -h3, -h4, -h5, -h6, -ol, -ul, -pre, -table, -address, -fieldset, -figure { - margin-bottom: 20px; -} \ No newline at end of file diff --git a/static/rigging/1x.txt~ b/static/rigging/1x.txt~ deleted file mode 100644 index 0b3915de..00000000 --- a/static/rigging/1x.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -(irigging -rigging -p0 -(dp1 -S'catchangle' -p2 -F-0.93 -sS'lscull' -p3 -F2.655 -sS'span' -p4 -F1.6 -sS'Nrowers' -p5 -I1 -sS'mb' -p6 -I14 -sS'roworscull' -p7 -S'scull' -p8 -sS'lin' -p9 -F0.9 -sS'_rigging__spread' -p10 -F0.88 -sS'bladelength' -p11 -F0.46 -sS'dragform' -p12 -I1 -sS'_rigging__bladearea' -p13 -F0.0822 -sb. \ No newline at end of file diff --git a/static/rigging/2-.txt~ b/static/rigging/2-.txt~ deleted file mode 100644 index 69f21c42..00000000 --- a/static/rigging/2-.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -(irigging -rigging -p0 -(dp1 -S'catchangle' -p2 -F-0.93 -sS'lscull' -p3 -F3.205 -sS'span' -p4 -F1.6 -sS'Nrowers' -p5 -I2 -sS'mb' -p6 -I27 -sS'roworscull' -p7 -S'row' -p8 -sS'lin' -p9 -F1.14 -sS'_rigging__spread' -p10 -F0.88 -sS'bladelength' -p11 -F0.545 -sS'dragform' -p12 -F1.05 -sS'_rigging__bladearea' -p13 -F0.1174 -sb. \ No newline at end of file diff --git a/static/rigging/2x.txt~ b/static/rigging/2x.txt~ deleted file mode 100644 index 21d5c03c..00000000 --- a/static/rigging/2x.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -(irigging -rigging -p0 -(dp1 -S'catchangle' -p2 -F-0.93 -sS'lscull' -p3 -F2.655 -sS'span' -p4 -F1.6 -sS'Nrowers' -p5 -I2 -sS'mb' -p6 -I27 -sS'roworscull' -p7 -S'scull' -p8 -sS'lin' -p9 -F0.9 -sS'_rigging__spread' -p10 -F0.88 -sS'bladelength' -p11 -F0.46 -sS'dragform' -p12 -F1.05 -sS'_rigging__bladearea' -p13 -F0.0822 -sb. \ No newline at end of file diff --git a/static/rigging/4-.txt~ b/static/rigging/4-.txt~ deleted file mode 100644 index 2051d937..00000000 --- a/static/rigging/4-.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -(irigging -rigging -p0 -(dp1 -S'catchangle' -p2 -F-0.93 -sS'lscull' -p3 -F3.205 -sS'span' -p4 -F1.6 -sS'Nrowers' -p5 -I4 -sS'mb' -p6 -I50 -sS'roworscull' -p7 -S'row' -p8 -sS'lin' -p9 -F1.14 -sS'_rigging__spread' -p10 -F0.88 -sS'bladelength' -p11 -F0.545 -sS'dragform' -p12 -I1 -sS'_rigging__bladearea' -p13 -F0.1174 -sb. \ No newline at end of file diff --git a/static/rigging/4x.txt~ b/static/rigging/4x.txt~ deleted file mode 100644 index 4b9a7da3..00000000 --- a/static/rigging/4x.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -(irigging -rigging -p0 -(dp1 -S'catchangle' -p2 -F-0.93 -sS'lscull' -p3 -F2.655 -sS'span' -p4 -F1.6 -sS'Nrowers' -p5 -I4 -sS'mb' -p6 -F52.0 -sS'roworscull' -p7 -S'scull' -p8 -sS'lin' -p9 -F0.9 -sS'_rigging__spread' -p10 -F0.88 -sS'bladelength' -p11 -F0.46 -sS'dragform' -p12 -F1.11 -sS'_rigging__bladearea' -p13 -F0.0822 -sb. \ No newline at end of file diff --git a/static/rigging/8+.txt~ b/static/rigging/8+.txt~ deleted file mode 100644 index 3ba1f98b..00000000 --- a/static/rigging/8+.txt~ +++ /dev/null @@ -1,39 +0,0 @@ -(irigging -rigging -p0 -(dp1 -S'catchangle' -p2 -F-0.93 -sS'lscull' -p3 -F3.205 -sS'span' -p4 -F1.6 -sS'Nrowers' -p5 -I8 -sS'mb' -p6 -I151 -sS'roworscull' -p7 -S'row' -p8 -sS'lin' -p9 -F1.14 -sS'_rigging__spread' -p10 -F0.88 -sS'bladelength' -p11 -F0.545 -sS'dragform' -p12 -I1 -sS'_rigging__bladearea' -p13 -F0.1174 -sb. \ No newline at end of file diff --git a/workersettings.py~ b/workersettings.py~ deleted file mode 100644 index ca95b3d5..00000000 --- a/workersettings.py~ +++ /dev/null @@ -1,10 +0,0 @@ -REDIS_URL = 'redis://localhost:6379/0' - -# You can also specify the Redis DB to use -# REDIS_HOST = 'redis.example.com' -# REDIS_PORT = 6380 -# REDIS_DB = 3 -# REDIS_PASSWORD = 'very secret' - -# Queues to listen on -#QUEUES = ['high', 'normal', 'low']