Private
Public Access
1
0

Uploading files

This commit is contained in:
sanderroosendaal
2016-10-30 17:39:32 +01:00
parent c135e98d61
commit 3eed3cc3e7
2164 changed files with 3126790 additions and 0 deletions

3
rowers/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
from __future__ import absolute_import
from .tasks import app as celery_app

BIN
rowers/__init__.pyc Normal file

Binary file not shown.

3
rowers/__init__.py~ Normal file
View File

@@ -0,0 +1,3 @@
from __future__ import absolute_import
from .tasks import app as celery_app

23
rowers/admin.py Normal file
View File

@@ -0,0 +1,23 @@
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)

BIN
rowers/admin.pyc Normal file

Binary file not shown.

23
rowers/admin.py~ Normal file
View File

@@ -0,0 +1,23 @@
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)

7
rowers/apps.py Normal file
View File

@@ -0,0 +1,7 @@
from __future__ import unicode_literals
from django.apps import AppConfig
class RowersConfig(AppConfig):
name = 'rowers'

BIN
rowers/apps.pyc Normal file

Binary file not shown.

435
rowers/c2stuff.py Normal file
View File

@@ -0,0 +1,435 @@
# 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),
"date": w.startdatetime.isoformat(),
"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),
"date": w.startdatetime.isoformat(),
"distance": int(w.distance),
"time": int(10*makeseconds(durationstr)),
"weight_class": c2wc(w.weightcategory),
"timezone": "Etc/UTC",
"comments": w.notes,
"heart_rate": {
"average": averagehr,
"max": maxhr,
},
"stroke_data": stroke_data,
}
return data
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),
"date": w.startdatetime.isoformat(),
"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

BIN
rowers/c2stuff.pyc Normal file

Binary file not shown.

432
rowers/c2stuff.py~ Normal file
View File

@@ -0,0 +1,432 @@
# 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

27
rowers/celery.py Normal file
View File

@@ -0,0 +1,27 @@
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', 'rowsandall_app.settings')
from django.conf import settings # noqa
app = Celery('tasks',
broker='redis://localhost',
backend='redis://localhost',)
class Config:
CELERY_TIMEZONE = 'Europe/Prague'
# 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))

BIN
rowers/celery.pyc Normal file

Binary file not shown.

81
rowers/email.py Normal file
View File

@@ -0,0 +1,81 @@
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
print email
with open(emailfile) as f:
message = f.read()
message = '\nDear '+firstname+',\n\n'+str(message)
send_mail(
subject,
message,
'info@rowsandall.com',
[email],
)

BIN
rowers/email.pyc Normal file

Binary file not shown.

80
rowers/email.py~ Normal file
View File

@@ -0,0 +1,80 @@
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],
)

16
rowers/emailtxt.txt Normal file
View File

@@ -0,0 +1,16 @@
-------
In our hurry to get the emailing out to you, I forgot two things:
- The email address that you can use to communicate directly is info@rowsandall.com
- The questionnaire is anonymous, so we have no way to find out who is eligible for the three months of Pro membership. We have updated the questionnaire so you can add your email address.
Please accept our apologies for the confusion and don't hesitate to contact us if you have a question or concern.
-------
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 (info@rowsandall.com or reply to this email) if you feel a free-form response suits you better. Respondents to the questionnaire will receive a complementary Pro membership for 3 months. In order to claim your Pro membership, please leave your email address at the end of the questionnaire.
Best regards, Sander Roosendaal & the Rowsandall Team

9
rowers/emailtxt.txt~ Normal file
View File

@@ -0,0 +1,9 @@
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

220
rowers/forms.py Normal file
View File

@@ -0,0 +1,220 @@
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 MyTimeField(forms.TimeField):
def __init__(self, *args, **kwargs):
super(MyTimeField, self).__init__(*args, **kwargs)
supports_microseconds = True
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.DurationField(label='Time '+str(i+1))
self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1))
self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices,
required=True,
initial=4,
label = 'Type '+str(i+1))
self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;'
self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;'
self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f')

BIN
rowers/forms.pyc Normal file

Binary file not shown.

215
rowers/forms.py~ Normal file
View File

@@ -0,0 +1,215 @@
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;'

2246
rowers/interactiveplots.py Normal file

File diff suppressed because it is too large Load Diff

BIN
rowers/interactiveplots.pyc Normal file

Binary file not shown.

2245
rowers/interactiveplots.py~ Normal file

File diff suppressed because it is too large Load Diff

226
rowers/mailprocessing.py Normal file
View File

@@ -0,0 +1,226 @@
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,cntr=0):
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+str(cntr)+'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+str(cntr)+'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

BIN
rowers/mailprocessing.pyc Normal file

Binary file not shown.

225
rowers/mailprocessing.py~ Normal file
View File

@@ -0,0 +1,225 @@
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

View File

Binary file not shown.

View File

Binary file not shown.

View File

@@ -0,0 +1,89 @@
#!/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
from rowers.mailprocessing import make_new_workout_from_email
def rdata(file,rower=rrower()):
try:
res = rrdata(file,rower=rower)
except IOError:
res = 0
return res
class Command(BaseCommand):
def handle(self, *args, **options):
res = []
attachments = MessageAttachment.objects.all()
cntr = 0
for a in attachments:
donotdelete = 0
m = Message.objects.get(id=a.message_id)
from_address = m.from_address[0]
name = m.subject
cntr += 1
# 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,cntr=cntr)]
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'))

Binary file not shown.

View File

@@ -0,0 +1,236 @@
#!/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'))

View File

@@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-26 08:42
from __future__ import unicode_literals
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Rower',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('max', models.IntegerField()),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
],
),
migrations.CreateModel(
name='Workout',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=30)),
('date', models.DateField()),
('type', models.CharField(choices=[('OTW', 'On-water'), ('OTE', 'Indoor Rower')], max_length=30)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Rower')),
],
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-26 08:43
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('rowers', '0001_initial'),
]
operations = [
migrations.RenameField(
model_name='workout',
old_name='type',
new_name='workouttype',
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-26 08:48
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0002_auto_20160426_1043'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='workouttype',
field=models.CharField(choices=[('water', 'On-water'), ('rower', 'Indoor Rower'), ('skierg', 'Ski Erg'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides'), ('paddle', 'Paddle Adapter'), ('snow', 'On-snow')], max_length=30),
),
]

Binary file not shown.

View File

@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-26 12:41
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0003_auto_20160426_1048'),
]
operations = [
migrations.AddField(
model_name='rower',
name='an',
field=models.IntegerField(default=180),
),
migrations.AddField(
model_name='rower',
name='at',
field=models.IntegerField(default=160),
),
migrations.AddField(
model_name='rower',
name='rest',
field=models.IntegerField(default=48),
),
migrations.AddField(
model_name='rower',
name='tr',
field=models.IntegerField(default=167),
),
migrations.AddField(
model_name='rower',
name='ut1',
field=models.IntegerField(default=146),
),
migrations.AddField(
model_name='rower',
name='ut2',
field=models.IntegerField(default=105),
),
migrations.AlterField(
model_name='rower',
name='max',
field=models.IntegerField(default=192),
),
]

Binary file not shown.

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-26 12:46
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0004_auto_20160426_1441'),
]
operations = [
migrations.AddField(
model_name='rower',
name='c2token',
field=models.CharField(default='', max_length=50),
),
migrations.AddField(
model_name='rower',
name='tokenexpirydate',
field=models.DateField(blank=True, null=True),
),
migrations.AddField(
model_name='rower',
name='weightcategory',
field=models.CharField(default='hwt', max_length=30),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-27 11:50
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0005_auto_20160426_1446'),
]
operations = [
migrations.AlterField(
model_name='rower',
name='c2token',
field=models.CharField(blank=True, default='', max_length=50, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 09:53
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('rowers', '0006_auto_20160427_1350'),
]
operations = [
migrations.CreateModel(
name='GraphImage',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('filename', models.CharField(blank=True, default='', max_length=50, null=True)),
('creationdatetime', models.DateTimeField()),
('workout', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='rowers.Workout')),
],
),
migrations.AlterField(
model_name='rower',
name='weightcategory',
field=models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'leight-weight')], default='hwt', max_length=30),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 09:54
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0007_auto_20160428_1153'),
]
operations = [
migrations.AlterField(
model_name='rower',
name='weightcategory',
field=models.CharField(choices=[('hwt', 'heavy-weight'), ('lwt', 'light-weight')], default='hwt', max_length=30),
),
]

Binary file not shown.

View File

@@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 17:55
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0008_auto_20160428_1154'),
]
operations = [
migrations.AddField(
model_name='workout',
name='starttime',
field=models.TimeField(blank=True, null=True),
),
migrations.AlterField(
model_name='rower',
name='an',
field=models.IntegerField(default=180, verbose_name='AN band lower HR'),
),
migrations.AlterField(
model_name='rower',
name='at',
field=models.IntegerField(default=160, verbose_name='AT band lower HR'),
),
migrations.AlterField(
model_name='rower',
name='max',
field=models.IntegerField(default=192, verbose_name='Max Heart Rate'),
),
migrations.AlterField(
model_name='rower',
name='rest',
field=models.IntegerField(default=48, verbose_name='Resting Heart Rate'),
),
migrations.AlterField(
model_name='rower',
name='tr',
field=models.IntegerField(default=167, verbose_name='TR band lower HR'),
),
migrations.AlterField(
model_name='rower',
name='ut1',
field=models.IntegerField(default=146, verbose_name='UT1 band lower HR'),
),
migrations.AlterField(
model_name='rower',
name='ut2',
field=models.IntegerField(default=105, verbose_name='UT2 band lower HR'),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 17:58
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0009_auto_20160428_1955'),
]
operations = [
migrations.AddField(
model_name='workout',
name='distance',
field=models.IntegerField(blank=True, default=0),
),
]

Binary file not shown.

View File

@@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 18:09
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0010_workout_distance'),
]
operations = [
migrations.AddField(
model_name='workout',
name='csvfilename',
field=models.CharField(blank=True, max_length=50),
),
migrations.AddField(
model_name='workout',
name='duration',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
migrations.AddField(
model_name='workout',
name='notes',
field=models.CharField(blank=True, max_length=100),
),
migrations.AddField(
model_name='workout',
name='uploadedtoc2',
field=models.BooleanField(default=False),
),
migrations.AddField(
model_name='workout',
name='weightclass',
field=models.CharField(default='hwt', max_length=10),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 18:10
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0011_auto_20160428_2009'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='duration',
field=models.IntegerField(blank=True, default=1),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 18:21
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('rowers', '0012_auto_20160428_2010'),
]
operations = [
migrations.RenameField(
model_name='workout',
old_name='weightclass',
new_name='weightcategory',
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-28 20:51
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0013_auto_20160428_2021'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='duration',
field=models.TimeField(blank=True, default=1),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-04-29 18:38
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0014_auto_20160428_2251'),
]
operations = [
migrations.AlterField(
model_name='graphimage',
name='filename',
field=models.CharField(blank=True, default='', max_length=150, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-01 09:19
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0015_auto_20160429_2038'),
]
operations = [
migrations.AddField(
model_name='rower',
name='c2refreshtoken',
field=models.CharField(blank=True, default='', max_length=200, null=True),
),
migrations.AlterField(
model_name='rower',
name='c2token',
field=models.CharField(blank=True, default='', max_length=200, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-01 09:26
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0016_auto_20160501_1119'),
]
operations = [
migrations.AlterField(
model_name='rower',
name='tokenexpirydate',
field=models.DateTimeField(blank=True, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-01 17:44
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0017_auto_20160501_1126'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='uploadedtoc2',
field=models.IntegerField(default=0),
),
]

Binary file not shown.

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-22 14:59
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0018_auto_20160501_1944'),
]
operations = [
migrations.AddField(
model_name='rower',
name='stravarefreshtoken',
field=models.CharField(blank=True, default='', max_length=200, null=True),
),
migrations.AddField(
model_name='rower',
name='stravatoken',
field=models.CharField(blank=True, default='', max_length=200, null=True),
),
migrations.AddField(
model_name='rower',
name='stravatokenexpirydate',
field=models.DateTimeField(blank=True, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-22 15:26
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('rowers', '0019_auto_20160522_1659'),
]
operations = [
migrations.RemoveField(
model_name='rower',
name='stravarefreshtoken',
),
migrations.RemoveField(
model_name='rower',
name='stravatokenexpirydate',
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-25 12:50
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0020_auto_20160522_1726'),
]
operations = [
migrations.AddField(
model_name='rower',
name='rowerplan',
field=models.CharField(choices=[('basic', 'basic'), ('pro', 'pro')], default='basic', max_length=30),
),
]

Binary file not shown.

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-29 19:15
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0021_rower_rowerplan'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='csvfilename',
field=models.CharField(blank=True, max_length=150),
),
migrations.AlterField(
model_name='workout',
name='notes',
field=models.CharField(blank=True, max_length=200),
),
migrations.AlterField(
model_name='workout',
name='workouttype',
field=models.CharField(choices=[('water', 'On-water'), ('rower', 'Indoor Rower'), ('skierg', 'Ski Erg'), ('dynamic', 'Dynamic Indoor Rower'), ('slides', 'Indoor Rower on Slides'), ('paddle', 'Paddle Adapter'), ('snow', 'On-snow')], max_length=50),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-05-30 07:14
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0022_auto_20160529_2115'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='name',
field=models.CharField(max_length=150),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-02 13:56
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0023_auto_20160530_0914'),
]
operations = [
migrations.AddField(
model_name='workout',
name='uploadedtostrava',
field=models.IntegerField(default=0),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-08 06:11
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0024_workout_uploadedtostrava'),
]
operations = [
migrations.AddField(
model_name='workout',
name='summary',
field=models.TextField(blank=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,27 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-08 19:37
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0025_workout_summary'),
]
operations = [
migrations.AddField(
model_name='workout',
name='averagehr',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
migrations.AddField(
model_name='workout',
name='maxhr',
field=models.IntegerField(blank=True, default=0),
preserve_default=False,
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-09 16:22
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0026_auto_20160608_2137'),
]
operations = [
migrations.AddField(
model_name='workout',
name='uploadedtosporttracks',
field=models.IntegerField(default=0),
),
]

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-09 16:37
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0027_workout_uploadedtosporttracks'),
]
operations = [
migrations.AddField(
model_name='rower',
name='sporttrackstoken',
field=models.CharField(blank=True, default='', max_length=200, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-10 06:25
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0028_rower_sporttrackstoken'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='uploadedtosporttracks',
field=models.IntegerField(blank=True, default=0),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-10 06:26
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0029_auto_20160610_0825'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='uploadedtosporttracks',
field=models.IntegerField(blank=True, default=0, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,30 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-10 06:43
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0030_auto_20160610_0826'),
]
operations = [
migrations.AlterField(
model_name='workout',
name='averagehr',
field=models.IntegerField(blank=True, null=True),
),
migrations.AlterField(
model_name='workout',
name='maxhr',
field=models.IntegerField(blank=True, null=True),
),
migrations.AlterField(
model_name='workout',
name='uploadedtosporttracks',
field=models.IntegerField(default=0),
),
]

Binary file not shown.

View File

@@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-15 11:32
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('rowers', '0031_auto_20160610_0843'),
]
operations = [
migrations.AddField(
model_name='rower',
name='sporttracksrefreshtoken',
field=models.CharField(blank=True, default='', max_length=200, null=True),
),
migrations.AddField(
model_name='rower',
name='sporttrackstokenexpirytdata',
field=models.DateTimeField(blank=True, null=True),
),
]

Binary file not shown.

View File

@@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.5 on 2016-06-17 07:27
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('rowers', '0032_auto_20160615_1332'),
]
operations = [
migrations.RenameField(
model_name='rower',
old_name='sporttrackstokenexpirytdata',
new_name='sporttrackstokenexpirytdate',
),
]

Binary file not shown.

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