Uploading files
This commit is contained in:
3
rowers/__init__.py
Normal file
3
rowers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .tasks import app as celery_app
|
||||
BIN
rowers/__init__.pyc
Normal file
BIN
rowers/__init__.pyc
Normal file
Binary file not shown.
3
rowers/__init__.py~
Normal file
3
rowers/__init__.py~
Normal file
@@ -0,0 +1,3 @@
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .tasks import app as celery_app
|
||||
23
rowers/admin.py
Normal file
23
rowers/admin.py
Normal 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
BIN
rowers/admin.pyc
Normal file
Binary file not shown.
23
rowers/admin.py~
Normal file
23
rowers/admin.py~
Normal 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
7
rowers/apps.py
Normal 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
BIN
rowers/apps.pyc
Normal file
Binary file not shown.
435
rowers/c2stuff.py
Normal file
435
rowers/c2stuff.py
Normal 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
BIN
rowers/c2stuff.pyc
Normal file
Binary file not shown.
432
rowers/c2stuff.py~
Normal file
432
rowers/c2stuff.py~
Normal 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
27
rowers/celery.py
Normal 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
BIN
rowers/celery.pyc
Normal file
Binary file not shown.
81
rowers/email.py
Normal file
81
rowers/email.py
Normal 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
BIN
rowers/email.pyc
Normal file
Binary file not shown.
80
rowers/email.py~
Normal file
80
rowers/email.py~
Normal 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
16
rowers/emailtxt.txt
Normal 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
9
rowers/emailtxt.txt~
Normal 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
220
rowers/forms.py
Normal 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
BIN
rowers/forms.pyc
Normal file
Binary file not shown.
215
rowers/forms.py~
Normal file
215
rowers/forms.py~
Normal 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
2246
rowers/interactiveplots.py
Normal file
File diff suppressed because it is too large
Load Diff
BIN
rowers/interactiveplots.pyc
Normal file
BIN
rowers/interactiveplots.pyc
Normal file
Binary file not shown.
2245
rowers/interactiveplots.py~
Normal file
2245
rowers/interactiveplots.py~
Normal file
File diff suppressed because it is too large
Load Diff
226
rowers/mailprocessing.py
Normal file
226
rowers/mailprocessing.py
Normal 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
BIN
rowers/mailprocessing.pyc
Normal file
Binary file not shown.
225
rowers/mailprocessing.py~
Normal file
225
rowers/mailprocessing.py~
Normal 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
|
||||
|
||||
|
||||
|
||||
0
rowers/management/__init__.py
Normal file
0
rowers/management/__init__.py
Normal file
BIN
rowers/management/__init__.pyc
Normal file
BIN
rowers/management/__init__.pyc
Normal file
Binary file not shown.
0
rowers/management/commands/__init__.py
Normal file
0
rowers/management/commands/__init__.py
Normal file
BIN
rowers/management/commands/__init__.pyc
Normal file
BIN
rowers/management/commands/__init__.pyc
Normal file
Binary file not shown.
89
rowers/management/commands/processemail.py
Normal file
89
rowers/management/commands/processemail.py
Normal 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'))
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
rowers/management/commands/processemail.pyc
Normal file
BIN
rowers/management/commands/processemail.pyc
Normal file
Binary file not shown.
236
rowers/management/commands/processemail.py~
Normal file
236
rowers/management/commands/processemail.py~
Normal 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'))
|
||||
|
||||
|
||||
|
||||
|
||||
37
rowers/migrations/0001_initial.py
Normal file
37
rowers/migrations/0001_initial.py
Normal 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')),
|
||||
],
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0001_initial.pyc
Normal file
BIN
rowers/migrations/0001_initial.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0002_auto_20160426_1043.py
Normal file
20
rowers/migrations/0002_auto_20160426_1043.py
Normal 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',
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0002_auto_20160426_1043.pyc
Normal file
BIN
rowers/migrations/0002_auto_20160426_1043.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0003_auto_20160426_1048.py
Normal file
20
rowers/migrations/0003_auto_20160426_1048.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0003_auto_20160426_1048.pyc
Normal file
BIN
rowers/migrations/0003_auto_20160426_1048.pyc
Normal file
Binary file not shown.
50
rowers/migrations/0004_auto_20160426_1441.py
Normal file
50
rowers/migrations/0004_auto_20160426_1441.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0004_auto_20160426_1441.pyc
Normal file
BIN
rowers/migrations/0004_auto_20160426_1441.pyc
Normal file
Binary file not shown.
30
rowers/migrations/0005_auto_20160426_1446.py
Normal file
30
rowers/migrations/0005_auto_20160426_1446.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0005_auto_20160426_1446.pyc
Normal file
BIN
rowers/migrations/0005_auto_20160426_1446.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0006_auto_20160427_1350.py
Normal file
20
rowers/migrations/0006_auto_20160427_1350.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0006_auto_20160427_1350.pyc
Normal file
BIN
rowers/migrations/0006_auto_20160427_1350.pyc
Normal file
Binary file not shown.
30
rowers/migrations/0007_auto_20160428_1153.py
Normal file
30
rowers/migrations/0007_auto_20160428_1153.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0007_auto_20160428_1153.pyc
Normal file
BIN
rowers/migrations/0007_auto_20160428_1153.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0008_auto_20160428_1154.py
Normal file
20
rowers/migrations/0008_auto_20160428_1154.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0008_auto_20160428_1154.pyc
Normal file
BIN
rowers/migrations/0008_auto_20160428_1154.pyc
Normal file
Binary file not shown.
55
rowers/migrations/0009_auto_20160428_1955.py
Normal file
55
rowers/migrations/0009_auto_20160428_1955.py
Normal 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'),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0009_auto_20160428_1955.pyc
Normal file
BIN
rowers/migrations/0009_auto_20160428_1955.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0010_workout_distance.py
Normal file
20
rowers/migrations/0010_workout_distance.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0010_workout_distance.pyc
Normal file
BIN
rowers/migrations/0010_workout_distance.pyc
Normal file
Binary file not shown.
41
rowers/migrations/0011_auto_20160428_2009.py
Normal file
41
rowers/migrations/0011_auto_20160428_2009.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0011_auto_20160428_2009.pyc
Normal file
BIN
rowers/migrations/0011_auto_20160428_2009.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0012_auto_20160428_2010.py
Normal file
20
rowers/migrations/0012_auto_20160428_2010.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0012_auto_20160428_2010.pyc
Normal file
BIN
rowers/migrations/0012_auto_20160428_2010.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0013_auto_20160428_2021.py
Normal file
20
rowers/migrations/0013_auto_20160428_2021.py
Normal 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',
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0013_auto_20160428_2021.pyc
Normal file
BIN
rowers/migrations/0013_auto_20160428_2021.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0014_auto_20160428_2251.py
Normal file
20
rowers/migrations/0014_auto_20160428_2251.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0014_auto_20160428_2251.pyc
Normal file
BIN
rowers/migrations/0014_auto_20160428_2251.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0015_auto_20160429_2038.py
Normal file
20
rowers/migrations/0015_auto_20160429_2038.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0015_auto_20160429_2038.pyc
Normal file
BIN
rowers/migrations/0015_auto_20160429_2038.pyc
Normal file
Binary file not shown.
25
rowers/migrations/0016_auto_20160501_1119.py
Normal file
25
rowers/migrations/0016_auto_20160501_1119.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0016_auto_20160501_1119.pyc
Normal file
BIN
rowers/migrations/0016_auto_20160501_1119.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0017_auto_20160501_1126.py
Normal file
20
rowers/migrations/0017_auto_20160501_1126.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0017_auto_20160501_1126.pyc
Normal file
BIN
rowers/migrations/0017_auto_20160501_1126.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0018_auto_20160501_1944.py
Normal file
20
rowers/migrations/0018_auto_20160501_1944.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0018_auto_20160501_1944.pyc
Normal file
BIN
rowers/migrations/0018_auto_20160501_1944.pyc
Normal file
Binary file not shown.
30
rowers/migrations/0019_auto_20160522_1659.py
Normal file
30
rowers/migrations/0019_auto_20160522_1659.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0019_auto_20160522_1659.pyc
Normal file
BIN
rowers/migrations/0019_auto_20160522_1659.pyc
Normal file
Binary file not shown.
23
rowers/migrations/0020_auto_20160522_1726.py
Normal file
23
rowers/migrations/0020_auto_20160522_1726.py
Normal 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',
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0020_auto_20160522_1726.pyc
Normal file
BIN
rowers/migrations/0020_auto_20160522_1726.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0021_rower_rowerplan.py
Normal file
20
rowers/migrations/0021_rower_rowerplan.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0021_rower_rowerplan.pyc
Normal file
BIN
rowers/migrations/0021_rower_rowerplan.pyc
Normal file
Binary file not shown.
30
rowers/migrations/0022_auto_20160529_2115.py
Normal file
30
rowers/migrations/0022_auto_20160529_2115.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0022_auto_20160529_2115.pyc
Normal file
BIN
rowers/migrations/0022_auto_20160529_2115.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0023_auto_20160530_0914.py
Normal file
20
rowers/migrations/0023_auto_20160530_0914.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0023_auto_20160530_0914.pyc
Normal file
BIN
rowers/migrations/0023_auto_20160530_0914.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0024_workout_uploadedtostrava.py
Normal file
20
rowers/migrations/0024_workout_uploadedtostrava.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0024_workout_uploadedtostrava.pyc
Normal file
BIN
rowers/migrations/0024_workout_uploadedtostrava.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0025_workout_summary.py
Normal file
20
rowers/migrations/0025_workout_summary.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0025_workout_summary.pyc
Normal file
BIN
rowers/migrations/0025_workout_summary.pyc
Normal file
Binary file not shown.
27
rowers/migrations/0026_auto_20160608_2137.py
Normal file
27
rowers/migrations/0026_auto_20160608_2137.py
Normal 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,
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0026_auto_20160608_2137.pyc
Normal file
BIN
rowers/migrations/0026_auto_20160608_2137.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0027_workout_uploadedtosporttracks.py
Normal file
20
rowers/migrations/0027_workout_uploadedtosporttracks.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0027_workout_uploadedtosporttracks.pyc
Normal file
BIN
rowers/migrations/0027_workout_uploadedtosporttracks.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0028_rower_sporttrackstoken.py
Normal file
20
rowers/migrations/0028_rower_sporttrackstoken.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0028_rower_sporttrackstoken.pyc
Normal file
BIN
rowers/migrations/0028_rower_sporttrackstoken.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0029_auto_20160610_0825.py
Normal file
20
rowers/migrations/0029_auto_20160610_0825.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0029_auto_20160610_0825.pyc
Normal file
BIN
rowers/migrations/0029_auto_20160610_0825.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0030_auto_20160610_0826.py
Normal file
20
rowers/migrations/0030_auto_20160610_0826.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0030_auto_20160610_0826.pyc
Normal file
BIN
rowers/migrations/0030_auto_20160610_0826.pyc
Normal file
Binary file not shown.
30
rowers/migrations/0031_auto_20160610_0843.py
Normal file
30
rowers/migrations/0031_auto_20160610_0843.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0031_auto_20160610_0843.pyc
Normal file
BIN
rowers/migrations/0031_auto_20160610_0843.pyc
Normal file
Binary file not shown.
25
rowers/migrations/0032_auto_20160615_1332.py
Normal file
25
rowers/migrations/0032_auto_20160615_1332.py
Normal 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),
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0032_auto_20160615_1332.pyc
Normal file
BIN
rowers/migrations/0032_auto_20160615_1332.pyc
Normal file
Binary file not shown.
20
rowers/migrations/0033_auto_20160617_0927.py
Normal file
20
rowers/migrations/0033_auto_20160617_0927.py
Normal 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',
|
||||
),
|
||||
]
|
||||
BIN
rowers/migrations/0033_auto_20160617_0927.pyc
Normal file
BIN
rowers/migrations/0033_auto_20160617_0927.pyc
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user