Private
Public Access
1
0
Files
rowsandall/rowers/views.py~
sanderroosendaal 3eed3cc3e7 Uploading files
2016-10-30 17:39:32 +01:00

4244 lines
113 KiB
Python

import time
from django.views.generic.base import TemplateView
from django.shortcuts import render
from django.http import HttpResponse, HttpResponseRedirect
from django.contrib.auth import authenticate, login, logout
from rowers.forms import LoginForm,DocumentsForm,UploadOptionsForm
from django.core.urlresolvers import reverse
from django.template import RequestContext
from django.conf import settings
from django.utils.datastructures import MultiValueDictKeyError
from django.utils import timezone,translation
from django.core.mail import send_mail, BadHeaderError
from rowers.forms import EmailForm, RegistrationForm, RegistrationFormTermsOfService,RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,UpdateStreamForm
from rowers.forms import PredictedPieceForm,DateRangeForm,DeltaDaysForm
from rowers.forms import SummaryStringForm,IntervalUpdateForm
from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage,AdvancedWorkoutForm
import StringIO
from django.contrib.auth.decorators import login_required,user_passes_test
from time import strftime,strptime,mktime,time,daylight
import os,sys
import datetime
import iso8601
import c2stuff
from c2stuff import C2NoTokenError
from iso8601 import ParseError
import stravastuff
import sporttracksstuff
from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET
from rowsandall_app.settings import SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI, SPORTTRACKS_CLIENT_SECRET
import requests
import json
from rowsandall_app.rows import handle_uploaded_file
from rowers.tasks import handle_makeplot,handle_otwsetpower,handle_sendemailtcx,handle_sendemailcsv
from rowers.tasks import handle_sendemail_unrecognized
from scipy.signal import savgol_filter
from django.shortcuts import render_to_response
from rowingdata import rower as rrower
from rowingdata import main as rmain
from rowingdata import rowingdata as rrdata
from rowingdata import TCXParser,RowProParser,ErgDataParser,TCXParserNoHR
from rowingdata import MysteryParser
from rowingdata import painsledDesktopParser,speedcoachParser,ErgStickParser
from rowingdata import SpeedCoach2Parser,FITParser,fitsummarydata
from rowingdata import make_cumvalues
from rowingdata import summarydata,get_file_type
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from pytz import timezone as tz,utc
import dateutil
import mpld3
from mpld3 import plugins
import stravalib
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
from weather import get_wind_data
import django_rq
queue = django_rq.get_queue('default')
queuelow = django_rq.get_queue('low')
queuehigh = django_rq.get_queue('low')
import plots
import mailprocessing
from io import BytesIO
from scipy.special import lambertw
LOCALTIMEZONE = tz('Etc/UTC')
USER_LANGUAGE = 'en-US'
from interactiveplots import *
def error500_view(request):
response = render_to_response('500.html', {},
context_instance = RequestContext(request))
response.status_code = 500
return response
def error404_view(request):
response = render_to_response('404.html', {},
context_instance = RequestContext(request))
response.status_code = 404
return response
def error400_view(request):
response = render_to_response('400.html', {},
context_instance = RequestContext(request))
response.status_code = 400
return response
def error403_view(request):
response = render_to_response('403.html', {},
context_instance = RequestContext(request))
response.status_code = 403
return response
def rdata(file,rower=rrower()):
try:
res = rrdata(file,rower=rower)
except IOError:
res = 0
return res
def get_time(second):
if (second<=0) or (second>1e9):
hours = 0
minutes=0
sec=0
microsecond = 0
elif math.isnan(second):
hours = 0
minutes=0
sec=0
microsecond = 0
else:
days = int(second/(24.*3600.)) % (24*3600)
hours = int((second-24.*3600.*days)/3600.) % 24
minutes = int((second-3600.*(hours+24.*days))/60.) % 60
sec = int(second-3600.*(hours+24.*days)-60.*minutes) % 60
microsecond = int(1.0e6*(second-3600.*(hours+24.*days)-60.*minutes-sec))
return datetime.time(hours,minutes,sec,microsecond)
def getidfromsturi(uri):
return uri[len(uri)-8:]
def splitstdata(lijst):
t = []
latlong = []
while len(lijst)>=2:
t.append(lijst[0])
latlong.append(lijst[1])
lijst = lijst[2:]
return [np.array(t),np.array(latlong)]
def geo_distance(lat1,lon1,lat2,lon2):
""" Approximate distance and bearing between two points
defined by lat1,lon1 and lat2,lon2
This is a slight underestimate but is close enough for our purposes,
We're never moving more than 10 meters between trackpoints
Bearing calculation fails if one of the points is a pole.
"""
# radius of earth in km
R = 6373.0
# pi
pi = math.pi
lat1 = math.radians(lat1)
lat2 = math.radians(lat2)
lon1 = math.radians(lon1)
lon2 = math.radians(lon2)
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
distance = R * c
tc1 = atan2(sin(lon2-lon1)*cos(lat2),
cos(lat1)*sin(lat2)-sin(lat1)*cos(lat2)*cos(lon2-lon1))
tc1 = tc1 % (2*pi)
bearing = math.degrees(tc1)
return [distance,bearing]
def promember(user):
r = Rower.objects.get(user=user)
result = user.is_authenticated() and (r.rowerplan=='pro' or r.rowerplan=='coach')
return result
def rower_register_view(request):
if request.method == 'POST':
form = RegistrationFormUniqueEmail(request.POST)
if form.is_valid():
first_name = form.cleaned_data['first_name']
last_name = form.cleaned_data['last_name']
email = form.cleaned_data['email']
password = form.cleaned_data['password1']
username = form.cleaned_data['username']
theuser = User.objects.create_user(username,password=password)
theuser.first_name = first_name
theuser.last_name = last_name
theuser.email = email
theuser.save()
therower = Rower(user=theuser)
therower.save()
fullemail = first_name + " " + last_name + " " + "<" + email + ">"
subject = "Thank you for registering on rowsandall.com"
message = "Thank you for registering on rowsandall.com. You can now login using the credentials you provided.\n"
message += "The first thing you might want to do is check and edit the heart rate band values. After logging in, click the button with your first name.\n"
message += "You can also check our videos page at http://rowsandall.com/rowers/videos for some helpful instruction videos.\n\n"
message += "User name:"+username+"\n"
message += "Password :"+password+"\n\n"
message += "For all your questions, just reply to this email.\n\n"
message += "Happy rowing!\n\n\n"
message += "Oh, one more thing. The site is currently in beta and is developing fast. Bear with us. Don't hesitate to contact me if anything is broken or doesn't seem to work as advertised."
send_mail(subject, message,
'Sander Roosendaal <info@rowsandall,com>',
[fullemail])
subject2 = "New User"
message2 = "New user registered.\n"
message2 += fullemail + "\n"
message2 += "User name: "+username
send_mail(subject2, message2,
'Rowsandall Server <info@rowsandall,com>',
['roosendaalsander@gmail.com'])
return HttpResponseRedirect('/rowers/register/thankyou/')
else:
return render(request,
"registration_form.html",
{'form':form})
else:
form = RegistrationFormUniqueEmail()
return render(request,
"registration_form.html",
{'form':form,})
def sendmail(request):
if request.method == 'POST':
form = EmailForm(request.POST)
if form.is_valid():
firstname = form.cleaned_data['firstname']
lastname = form.cleaned_data['lastname']
email = form.cleaned_data['email']
subject = form.cleaned_data['subject']
botcheck = form.cleaned_data['botcheck'].lower()
message = form.cleaned_data['message']
if botcheck == 'yes':
try:
fullemail = firstname + " " + lastname + " " + "<" + email + ">"
send_mail(subject, message, fullemail, ['info@rowsandall.com'])
return HttpResponseRedirect('/rowers/email/thankyou/')
except:
return HttpResponseRedirect('/rowers/email/')
else:
return HttpResponseRedirect('/rowers/email/')
else:
return HttpResponseRedirect('/rowers/email/')
def checkworkoutuser(user,workout):
try:
r = Rower.objects.get(user=user)
return (workout.user == r)
except Rower.DoesNotExist:
return(False)
def add_workout_from_strokedata(user,importid,data,strokedata,source='c2'):
workouttype = data['type']
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'water'
try:
comments = data['comments']
except:
comments = ' '
# comments = "Imported data \n %s" % comments
# comments = "Imported data \n"+comments # str(comments)
try:
thetimezone = tz(data['timezone'])
except:
thetimezone = 'UTC'
r = Rower.objects.get(user=user)
try:
rowdatetime = iso8601.parse_date(data['date_utc'])
except KeyError:
rowdatetime = iso8601.parse_date(data['start_date'])
except ParseError:
rowdatetime = iso8601.parse_date(data['date'])
# try:
# rowdatetime = datetime.datetime.strptime(data['date_utc'],"%Y-%m-%d %H:%M:%S")
# rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
# except KeyError:
# try:
# rowdatetime = dateutil.parser.parse(data['start_date'])
# rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
# except:
# rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
# rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
try:
c2intervaltype = data['workout_type']
except KeyError:
c2intervaltype = ''
try:
title = data['name']
except KeyError:
title = ""
try:
t = data['comments'].split('\n', 1)[0]
title += t[:20]
except:
pass
starttimeunix = mktime(rowdatetime.timetuple())
res = make_cumvalues(0.1*strokedata['t'])
cum_time = res[0]
lapidx = res[1]
unixtime = cum_time+starttimeunix
# unixtime[0] = starttimeunix
seconds = 0.1*strokedata.ix[:,'t']
nr_rows = len(unixtime)
try:
latcoord = strokedata.ix[:,'lat']
loncoord = strokedata.ix[:,'lon']
except:
latcoord = np.zeros(nr_rows)
loncoord = np.zeros(nr_rows)
try:
strokelength = strokedata.ix[:,'strokelength']
except:
strokelength = np.zeros(nr_rows)
dist2 = 0.1*strokedata.ix[:,'d']
spm = strokedata.ix[:,'spm']
hr = strokedata.ix[:,'hr']
pace = strokedata.ix[:,'p']/10.
velo = 500./pace
if (source=='c2'):
power = 2.8*velo**3
else:
power = 0.0*velo
# save csv
# Create data frame with all necessary data to write to csv
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
' Horizontal (meters)': dist2,
' Cadence (stokes/min)':spm,
' HRCur (bpm)':hr,
' longitude':loncoord,
' latitude':latcoord,
' Stroke500mPace (sec/500m)':pace,
' Power (watts)':power,
' DriveLength (meters)':np.zeros(nr_rows),
' StrokeDistance (meters)':strokelength,
' DriveTime (ms)':np.zeros(nr_rows),
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
' AverageDriveForce (lbs)':np.zeros(nr_rows),
' PeakDriveForce (lbs)':np.zeros(nr_rows),
' lapIdx':lapidx,
' ElapsedTime (sec)':seconds
})
# data.sort(['TimeStamp (sec)'],ascending=True)
df.sort_values(by='TimeStamp (sec)',ascending=True)
timestr = strftime("%Y%m%d-%H%M%S")
# auto smoothing
pace = df[' Stroke500mPace (sec/500m)'].values
velo = 500./pace
f = df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if windowsize <= 3:
windowsize = 5
df['originalvelo'] = velo
if windowsize > 3:
velo2 = savgol_filter(velo,windowsize,3)
else:
velo2=velo
pace2 = 500./abs(velo2)
df[' Stroke500mPace (sec/500m)'] = pace2
df = df.fillna(0)
# end autosmoothing
csvfilename ='media/Import_'+str(importid)+'.csv'
res = df.to_csv(csvfilename,index_label='index')
averagehr = df[' HRCur (bpm)'].mean()
maxhr = df[' HRCur (bpm)'].max()
# make workout
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
row = rdata(csvfilename,rower=rr)
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
summary = row.summary()
summary += '\n'
summary += row.intervalstats()
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
# check for duplicate start times
ws = Workout.objects.filter(starttime=workoutstarttime,
user=r)
if (len(ws) != 0):
print "Warning: This workout probably already exists in the database"
w = Workout(user=r,name=title,
date=workoutdate,workouttype=workouttype,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=csvfilename,notes=comments,
uploadedtoc2=0,summary=summary,
averagehr=averagehr,maxhr=maxhr,
startdatetime=rowdatetime)
w.save()
return w.id
def add_workout_from_stdata(user,importid,data):
workouttype = data['type']
if workouttype not in [x[0] for x in Workout.workouttypes]:
workouttype = 'water'
try:
comments = data['comments']
except:
comments = ''
# comments = "Imported data \n"+str(comments)
try:
thetimezone = tz(data['timezone'])
except:
thetimezone = 'UTC'
r = Rower.objects.get(user=user)
try:
rowdatetime = iso8601.parse_date(data['start_time'])
except iso8601.ParseError:
try:
rowdatetime = datetime.datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except:
try:
rowdatetime = dateutil.parser.parse(data['start_time'])
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
except:
rowdatetime = datetime.datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S")
rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc)
try:
c2intervaltype = data['workout_type']
except:
c2intervaltype = ''
try:
title = data['name']
except:
title = "Imported data"
starttimeunix = mktime(rowdatetime.timetuple())
res = splitstdata(data['distance'])
distance = res[1]
times_distance = res[0]
try:
l = data['location']
res = splitstdata(l)
times_location = res[0]
latlong = res[1]
latcoord = []
loncoord = []
for coord in latlong:
lat = coord[0]
lon = coord[1]
latcoord.append(lat)
loncoord.append(lon)
except:
times_location = times_distance
latcoord = np.zeros(len(times_distance))
loncoord = np.zeros(len(times_distance))
try:
res = splitstdata(data['cadence'])
times_spm = res[0]
spm = res[1]
except KeyError:
times_spm = times_distance
spm = 0*times_distance
try:
res = splitstdata(data['heartrate'])
hr = res[1]
times_hr = res[0]
except KeyError:
times_hr = times_distance
hr = 0*times_distance
# create data series and remove duplicates
distseries = pd.Series(distance,index=times_distance)
distseries = distseries.groupby(distseries.index).first()
latseries = pd.Series(latcoord,index=times_location)
latseries = latseries.groupby(latseries.index).first()
lonseries = pd.Series(loncoord,index=times_location)
lonseries = lonseries.groupby(lonseries.index).first()
spmseries = pd.Series(spm,index=times_spm)
spmseries = spmseries.groupby(spmseries.index).first()
hrseries = pd.Series(hr,index=times_hr)
hrseries = hrseries.groupby(hrseries.index).first()
# Create dicts and big dataframe
d = {
' Horizontal (meters)': distseries,
' latitude': latseries,
' longitude': lonseries,
' Cadence (stokes/min)': spmseries,
' HRCur (bpm)' : hrseries,
}
df = pd.DataFrame(d)
df = df.groupby(level=0).last()
cum_time = df.index.values
df[' ElapsedTime (sec)'] = cum_time
velo = df[' Horizontal (meters)'].diff()/df[' ElapsedTime (sec)'].diff()
df[' Power (watts)'] = 0.0*velo
nr_rows = len(velo.values)
df[' DriveLength (meters)'] = np.zeros(nr_rows)
df[' StrokeDistance (meters)'] = np.zeros(nr_rows)
df[' DriveTime (ms)'] = np.zeros(nr_rows)
df[' StrokeRecoveryTime (ms)'] = np.zeros(nr_rows)
df[' AverageDriveForce (lbs)'] = np.zeros(nr_rows)
df[' PeakDriveForce (lbs)'] = np.zeros(nr_rows)
df[' lapIdx'] = np.zeros(nr_rows)
unixtime = cum_time+starttimeunix
unixtime[0] = starttimeunix
df['TimeStamp (sec)'] = unixtime
dt = np.diff(cum_time).mean()
wsize = round(5./dt)
velo2 = stravastuff.ewmovingaverage(velo,wsize)
df[' Stroke500mPace (sec/500m)'] = 500./velo2
df = df.fillna(0)
# data.sort(['TimeStamp (sec)'],ascending=True)
df.sort_values(by='TimeStamp (sec)',ascending=True)
timestr = strftime("%Y%m%d-%H%M%S")
# auto smoothing
pace = df[' Stroke500mPace (sec/500m)'].values
velo = 500./pace
f = df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
df['originalvelo'] = velo
if windowsize > 3:
velo2 = savgol_filter(velo,windowsize,3)
else:
velo2 = velo
pace2 = 500./abs(velo2)
df[' Stroke500mPace (sec/500m)'] = pace2
df = df.fillna(0)
# end autosmoothing
csvfilename ='media/Import_'+str(importid)+'.csv'
res = df.to_csv(csvfilename,index_label='index')
averagehr = df[' HRCur (bpm)'].mean()
maxhr = df[' HRCur (bpm)'].max()
# make workout
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
row = rdata(csvfilename,rower=rr)
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
summary = row.summary()
summary += '\n'
summary += row.intervalstats()
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
# check for duplicate start times
ws = Workout.objects.filter(starttime=workoutstarttime,
user=r)
if (len(ws) != 0):
print "Warning: This workout probably already exists in the database"
w = Workout(user=r,name=title,
date=workoutdate,workouttype=workouttype,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=csvfilename,notes=comments,
uploadedtoc2=0,summary=summary,
averagehr=averagehr,maxhr=maxhr,
startdatetime=rowdatetime)
w.save()
return w.id
def c2_open(user):
r = Rower.objects.get(user=user)
if (r.c2token == '') or (r.c2token is None):
s = "Token doesn't exist. Need to authorize"
raise C2NoTokenError("User has no token")
# return HttpResponseRedirect("/rowers/me/c2authorize/")
else:
if (timezone.now()>r.tokenexpirydate):
thetoken = c2stuff.rower_c2_token_refresh(user)
else:
thetoken = r.c2token
return thetoken
def sporttracks_open(user):
r = Rower.objects.get(user=user)
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
s = "Token doesn't exist. Need to authorize"
raise SportTracksNoTokenError("User has no token")
else:
if (timezone.now()>r.sporttrackstokenexpirydate):
thetoken = sporttracksstuff.rower_sporttracks_token_refresh(user)
else:
thetoken = r.sporttrackstoken
return thetoken
# Create your views here.
@login_required()
def list_c2_upload_view(request,id=0):
message = ""
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
# ready to upload. Hurray
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
c2userid = c2stuff.get_userid(thetoken)
data = c2stuff.createc2workoutdata(w)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
response = requests.post(url,headers=headers,data=json.dumps(data))
# check for duplicate error first
if (response.status_code == 409 ):
message = "Duplicate error"
w.uploadedtoc2 = -1
w.save()
elif (response.status_code == 201 or response.status_code == 200):
try:
s= json.loads(response.text)
c2id = s['data']['id']
w.uploadedtoc2 = c2id
w.save()
url = reverse(workouts_view)
return HttpResponseRedirect(url)
except:
message = "Something went wrong in list_c2_upload_view. Response 200/201 but Upload to C2 failed: "+response.text
else:
s = response
message = "Something went wrong in list_c2_upload_view. Upload to C2 failed."
else:
message = "You are not authorized to upload this workout"
url = reverse(workouts_view,
kwargs = {
'message':str(message),
})
return HttpResponseRedirect(url)
@login_required()
def workout_tcxemail_view(request,id=0):
message = ""
r = Rower.objects.get(user=request.user)
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
tcxfile = stravastuff.createstravaworkoutdata(w)
if settings.DEBUG:
res = handle_sendemailtcx.delay(r.user.first_name,
r.user.last_name,
r.user.email,tcxfile)
else:
res = queuehigh.enqueue(handle_sendemailtcx,r.user.first_name,
r.user.last_name,
r.user.email,tcxfile)
successmessage = "The TCX file was sent to you per email"
url = reverse(workout_export_view,
kwargs = {
'id':str(w.id),
'successmessage':successmessage,
})
response = HttpResponseRedirect(url)
else:
message = "You are not allowed to export this workout"
url = reverse(workout_export_view,
kwargs = {
'id':str(w.id),
'message':message,
})
response = HttpResponseRedirect(url)
return response
@login_required()
def workout_csvemail_view(request,id=0):
message = ""
r = Rower.objects.get(user=request.user)
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
csvfile = w.csvfilename
if settings.DEBUG:
res = handle_sendemailcsv.delay(r.user.first_name,
r.user.last_name,
r.user.email,csvfile)
else:
res = queuehigh.enqueue(handle_sendemailcsv,r.user.first_name,
r.user.last_name,
r.user.email,csvfile)
successmessage = "The CSV file was sent to you per email"
url = reverse(workout_export_view,
kwargs = {
'id':str(w.id),
'successmessage':successmessage,
})
response = HttpResponseRedirect(url)
else:
message = "You are not allowed to export this workout"
url = reverse(workout_export_view,
kwargs = {
'id':str(w.id),
'message':message,
})
response = HttpResponseRedirect(url)
return response
@login_required()
def workout_strava_upload_view(request,id=0):
message = ""
r = Rower.objects.get(user=request.user)
if (r.stravatoken == '') or (r.stravatoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/stravaauthorize/")
else:
# ready to upload. Hurray
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
tcxfile = stravastuff.createstravaworkoutdata(w)
try:
with open(tcxfile,'rb') as f:
res = stravastuff.handle_stravaexport(f,w.name,
r.stravatoken,
description=w.notes)
w.uploadedtostrava = res
w.save()
os.remove(tcxfile)
url = "/rowers/workout/"+str(w.id)+"/edit"
successmessage = 'Workout sent to Strava.'
url = reverse(workout_export_view,
kwargs = {
'id':str(w.id),
}
)
response = HttpResponseRedirect(url)
except ActivityUploadFailed as e:
message = "Strava Upload error: %s" % e
w.uploadedtostrava = -1
w.save()
os.remove(tcxfile)
url = reverse(workout_export_view,
kwargs = {
'id':str(w.id),
'message':message,
})
response = HttpResponseRedirect(url)
# except TimeoutExceeded as e:
# w.uploadedtostrava = -1
# w.save()
# url = reverse(workout_export_view,
# kwargs = {
# 'id':str(w.id),
# 'message':'Strava Upload attempted. No response within 10 seconds. You may be OK. Check on Strava',
# })
# response = HttpResponseRedirect(url)
return response
@login_required()
def workout_c2_upload_view(request,id=0):
message = ""
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
# ready to upload. Hurray
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
c2userid = c2stuff.get_userid(thetoken)
data = c2stuff.createc2workoutdata(w)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
response = requests.post(url,headers=headers,data=json.dumps(data))
# check for duplicate error first
if (response.status_code == 409 ):
message = "Duplicate error"
w.uploadedtoc2 = -1
w.save()
elif (response.status_code == 201 or response.status_code == 200):
try:
s= json.loads(response.text)
c2id = s['data']['id']
w.uploadedtoc2 = c2id
w.save()
url = "/rowers/workout/"+str(w.id)+"/export"
return HttpResponseRedirect(url)
except:
message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text
else:
s = response
message = "Something went wrong in workout_c2_upload_view. C2 sync failed."
else:
message = "You are not authorized to upload this workout"
url = reverse(workout_export_view,
kwargs = {
'message':str(message),
'id':str(w.id),
})
return HttpResponseRedirect(url)
@login_required()
def workout_sporttracks_upload_view(request,id=0):
message = ""
try:
thetoken = sporttracks_open(request.user)
except SportTracksNoTokenError:
return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
# ready to upload. Hurray
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)):
data = sporttracksstuff.createsporttracksworkoutdata(w)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
response = requests.post(url,headers=headers,data=json.dumps(data))
# check for duplicate error first
if (response.status_code == 409 ):
message = "Duplicate error"
w.uploadedtosporttracks = -1
w.save()
elif (response.status_code == 201 or response.status_code==200):
s= json.loads(response.text)
sporttracksid = sporttracksstuff.getidfromresponse(response)
w.uploadedtosporttracks = sporttracksid
w.save()
url = "/rowers/workout/"+str(w.id)+"/export"
return HttpResponseRedirect(url)
else:
s = response
message = "Something went wrong in workout_sporttracks_upload_view %s" % s
else:
message = "You are not authorized to upload this workout"
url = reverse(workout_export_view,
kwargs = {
'message':str(message),
'id':str(w.id),
})
return HttpResponseRedirect(url)
@login_required()
def rower_c2_authorize(request):
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
from uuid import uuid4
state = str(uuid4())
params = {"client_id": C2_CLIENT_ID,
"response_type": "code",
"redirect_uri": C2_REDIRECT_URI}
import urllib
url = "http://log.concept2.com/oauth/authorize?"+ urllib.urlencode(params)
return HttpResponseRedirect(url)
@login_required()
def rower_strava_authorize(request):
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
from uuid import uuid4
state = str(uuid4())
params = {"client_id": STRAVA_CLIENT_ID,
"response_type": "code",
"redirect_uri": STRAVA_REDIRECT_URI,
"scope": "write"}
import urllib
url = "https://www.strava.com/oauth/authorize?"+ urllib.urlencode(params)
return HttpResponseRedirect(url)
@login_required()
def rower_sporttracks_authorize(request):
# Generate a random string for the state parameter
# Save it for use later to prevent xsrf attacks
from uuid import uuid4
state = str(uuid4())
params = {"client_id": SPORTTRACKS_CLIENT_ID,
"response_type": "code",
"state": state,
"redirect_uri": SPORTTRACKS_REDIRECT_URI}
import urllib
url = "https://api.sporttracks.mobi/oauth2/authorize?"+ urllib.urlencode(params)
return HttpResponseRedirect(url)
@login_required()
def rower_c2_token_refresh(request):
r = Rower.objects.get(user=request.user)
res = c2stuff.do_refresh_token(r.c2refreshtoken)
access_token = res[0]
expires_in = res[1]
refresh_token = res[2]
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
r = Rower.objects.get(user=request.user)
r.c2token = access_token
r.tokenexpirydate = expirydatetime
r.c2refreshtoken = refresh_token
r.save()
successmessage = "Tokens refreshed. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def rower_sporttracks_token_refresh(request):
r = Rower.objects.get(user=request.user)
res = sporttracksstuff.do_refresh_token(r.sporttracksrefreshtoken)
access_token = res[0]
expires_in = res[1]
refresh_token = res[2]
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
r = Rower.objects.get(user=request.user)
r.sporttrackstoken = access_token
r.sporttrackstokenexpirydate = expirydatetime
r.sporttracksrefreshtoken = refresh_token
r.save()
successmessage = "Tokens refreshed. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def rower_process_callback(request):
code = request.GET['code']
res = c2stuff.get_token(code)
access_token = res[0]
expires_in = res[1]
refresh_token = res[2]
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
r = Rower.objects.get(user=request.user)
r.c2token = access_token
r.tokenexpirydate = expirydatetime
r.c2refreshtoken = refresh_token
r.save()
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def imports_view(request,successmessage=""):
return render(request,"imports.html",{'successmessage': successmessage})
@login_required()
def test_reverse_view(request):
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def rower_process_stravacallback(request):
code = request.GET['code']
res = stravastuff.get_token(code)
access_token = res[0]
r = Rower.objects.get(user=request.user)
r.stravatoken = access_token
r.save()
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def rower_process_sporttrackscallback(request):
code = request.GET['code']
res = sporttracksstuff.get_token(code)
access_token = res[0]
expires_in = res[1]
refresh_token = res[2]
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
r = Rower.objects.get(user=request.user)
r.sporttrackstoken = access_token
r.sporttrackstokenexpirydate = expirydatetime
r.sporttracksrefreshtoken = refresh_token
r.save()
successmessage = "Tokens stored. Good to go"
return imports_view(request,successmessage=successmessage)
@login_required()
def histo_all(request,theuser=0):
promember=0
if theuser == 0:
theuser = request.user.id
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if not promember:
return HttpResponseRedirect("/rowers/about/")
# get all indoor rows of past 12 months
ayearago = timezone.now()-datetime.timedelta(days=365)
try:
r2 = Rower.objects.get(user=theuser)
allergworkouts = Workout.objects.filter(user=r2,
workouttype__in=['rower','dynamic','slides'],
startdatetime__gte=ayearago)
except Rower.DoesNotExist:
allergworkouts = []
r2=0
try:
u = User.objects.get(id=theuser)
except User.DoesNotExist:
u = ''
if allergworkouts:
res = interactive_histoall(allergworkouts)
script = res[0]
div = res[1]
else:
script = ''
div = '<p>No erg pieces uploaded yet.</p>'
return render(request, 'histoall.html',
{'interactiveplot':script,
'the_div':div,
'id':theuser,
'theuser':u,
})
@login_required()
def cum_flex(request,theuser=0,
xparam='spm',
yparam1='power',
yparam2='None',
startdate=timezone.now()-datetime.timedelta(days=30),
enddate=timezone.now(),
deltadays=-1,
startdatestring="",
enddatestring=""):
if deltadays>0:
startdate = enddate-datetime.timedelta(days=int(deltadays))
if startdatestring != "":
startdate = iso8601.parse_date(startdatestring)
if enddatestring != "":
enddate = iso8601.parse_date(enddatestring)
if enddate < startdate:
s = enddate
enddate = startdate
startdate = s
promember=0
if theuser == 0:
theuser = request.user.id
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if not promember:
return HttpResponseRedirect("/rowers/about/")
# get all indoor rows of in date range
# process form
if request.method == 'POST' and "daterange" in request.POST:
form = DateRangeForm(request.POST)
deltaform = DeltaDaysForm(request.POST)
if form.is_valid():
startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate']
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
elif request.method == 'POST' and "datedelta" in request.POST:
deltaform = DeltaDaysForm(request.POST)
if deltaform.is_valid():
deltadays = deltaform.cleaned_data['deltadays']
if deltadays != 0:
enddate = timezone.now()
startdate = enddate-datetime.timedelta(days=deltadays)
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
form = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
else:
form = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
deltaform = DeltaDaysForm()
try:
r2 = Rower.objects.get(user=theuser)
allergworkouts = Workout.objects.filter(user=r2,
workouttype__in=['rower','dynamic','slides'],
startdatetime__gte=startdate,
startdatetime__lte=enddate)
except Rower.DoesNotExist:
allergworkouts = []
r2=0
try:
u = User.objects.get(id=theuser)
except User.DoesNotExist:
u = ''
if allergworkouts:
res = interactive_cum_flex_chart(allergworkouts,xparam=xparam,
yparam1=yparam1,yparam2=yparam2,
promember=promember)
script = res[0]
div = res[1]
else:
script = ''
div = '<p>No erg pieces uploaded for this date range.</p>'
return render(request, 'cum_flex.html',
{'interactiveplot':script,
'the_div':div,
'id':theuser,
'theuser':u,
'startdate':startdate,
'enddate':enddate,
'form':form,
'deltaform':deltaform,
'xparam':xparam,
'yparam1':yparam1,
'yparam2':yparam2,
'promember':promember,
})
@login_required()
def histo(request,theuser=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
deltadays=-1,
startdatestring="",
enddatestring=""):
if deltadays>0:
startdate = enddate-datetime.timedelta(days=int(deltadays))
if startdatestring != "":
startdate = iso8601.parse_date(startdatestring)
if enddatestring != "":
enddate = iso8601.parse_date(enddatestring)
if enddate < startdate:
s = enddate
enddate = startdate
startdate = s
promember=0
if theuser == 0:
theuser = request.user.id
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if not promember:
return HttpResponseRedirect("/rowers/about/")
# get all indoor rows of in date range
# process form
if request.method == 'POST' and "daterange" in request.POST:
form = DateRangeForm(request.POST)
deltaform = DeltaDaysForm(request.POST)
if form.is_valid():
startdate = form.cleaned_data['startdate']
enddate = form.cleaned_data['enddate']
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
elif request.method == 'POST' and "datedelta" in request.POST:
deltaform = DeltaDaysForm(request.POST)
if deltaform.is_valid():
deltadays = deltaform.cleaned_data['deltadays']
if deltadays != 0:
enddate = timezone.now()
startdate = enddate-datetime.timedelta(days=deltadays)
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
form = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
else:
form = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
deltaform = DeltaDaysForm()
try:
r2 = Rower.objects.get(user=theuser)
allergworkouts = Workout.objects.filter(user=r2,
workouttype__in=['rower','dynamic','slides'],
startdatetime__gte=startdate,
startdatetime__lte=enddate)
except Rower.DoesNotExist:
allergworkouts = []
r2=0
try:
u = User.objects.get(id=theuser)
except User.DoesNotExist:
u = ''
if allergworkouts:
res = interactive_histoall(allergworkouts)
script = res[0]
div = res[1]
else:
script = ''
div = '<p>No erg pieces uploaded for this date range.</p>'
return render(request, 'histo.html',
{'interactiveplot':script,
'the_div':div,
'id':theuser,
'theuser':u,
'startdate':startdate,
'enddate':enddate,
'form':form,
'deltaform':deltaform,
})
@login_required()
def rankings_view(request,theuser=0,
startdate=timezone.now()-datetime.timedelta(days=365),
enddate=timezone.now(),
deltadays=-1,
startdatestring="",
enddatestring=""):
if deltadays>0:
startdate = enddate-datetime.timedelta(days=int(deltadays))
if startdatestring != "":
startdate = iso8601.parse_date(startdatestring)
if enddatestring != "":
enddate = iso8601.parse_date(enddatestring)
if enddate < startdate:
s = enddate
enddate = startdate
startdate = s
if theuser == 0:
theuser = request.user.id
promember=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
# get all indoor rows of in date range
# process form
if request.method == 'POST' and "daterange" in request.POST:
dateform = DateRangeForm(request.POST)
deltaform = DeltaDaysForm(request.POST)
if dateform.is_valid():
startdate = dateform.cleaned_data['startdate']
enddate = dateform.cleaned_data['enddate']
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
elif request.method == 'POST' and "datedelta" in request.POST:
deltaform = DeltaDaysForm(request.POST)
if deltaform.is_valid():
deltadays = deltaform.cleaned_data['deltadays']
if deltadays != 0:
enddate = timezone.now()
startdate = enddate-datetime.timedelta(days=deltadays)
if startdate > enddate:
s = enddate
enddate = startdate
startdate = s
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
else:
dateform = DateRangeForm(initial={
'startdate': startdate,
'enddate': enddate,
})
deltaform = DeltaDaysForm()
# get all 2k (if any) - this rower, in date range
try:
r = Rower.objects.get(user=theuser)
except Rower.DoesNotExist:
allergworkouts = []
r=0
try:
uu = User.objects.get(id=theuser)
except User.DoesNotExist:
uu = ''
# test to fix bug
startdate = datetime.datetime.combine(startdate,datetime.time())
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
rankingdistances = [100,500,1000,2000,5000,6000,10000,21097,42195,100000]
rankingdurations = []
rankingdurations.append(datetime.time(minute=1))
rankingdurations.append(datetime.time(minute=4))
rankingdurations.append(datetime.time(minute=30))
rankingdurations.append(datetime.time(hour=1))
thedistances = []
theworkouts = []
thesecs = []
rankingdistances.sort()
rankingdurations.sort()
for rankingdistance in rankingdistances:
workouts = Workout.objects.filter(user=r,distance=rankingdistance,
workouttype__in=['rower','dynamic','slides'],
startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by('duration')
if workouts:
thedistances.append(rankingdistance)
theworkouts.append(workouts[0])
timesecs = 3600*workouts[0].duration.hour
timesecs += 60*workouts[0].duration.minute
timesecs += workouts[0].duration.second
timesecs += 1.e-6*workouts[0].duration.microsecond
thesecs.append(timesecs)
for rankingduration in rankingdurations:
workouts = Workout.objects.filter(user=r,duration=rankingduration,
workouttype='rower',
startdatetime__gte=startdate,
startdatetime__lte=enddate).order_by('-distance')
if workouts:
thedistances.append(workouts[0].distance)
theworkouts.append(workouts[0])
timesecs = 3600*workouts[0].duration.hour
timesecs += 60*workouts[0].duration.minute
timesecs += workouts[0].duration.second
timesecs += 1.e-5*workouts[0].duration.microsecond
thesecs.append(timesecs)
thedistances = np.array(thedistances)
thesecs = np.array(thesecs)
thevelos = thedistances/thesecs
theavpower = 2.8*(thevelos**3)
# create interactive plot
if len(thedistances) !=0 :
res = interactive_cpchart(thedistances,thesecs,theavpower,
theworkouts,promember=promember)
script = res[0]
div = res[1]
paulslope = res[2]
paulintercept = res[3]
p1 = res[4]
message = res[5]
else:
script = ''
div = '<p>No ranking pieces found.</p>'
paulslope = 1
paulintercept = 1
p1 = [1,1,1,1]
message = ""
if request.method == 'POST' and "piece" in request.POST:
form = PredictedPieceForm(request.POST)
if form.is_valid():
value = form.cleaned_data['value']
pieceunit = form.cleaned_data['pieceunit']
if pieceunit == 'd':
rankingdistances.append(value)
else:
rankingdurations.append(datetime.time(minute=value))
else:
form = PredictedPieceForm()
rankingdistances.sort()
rankingdurations.sort()
predictions = []
cpredictions = []
for rankingdistance in rankingdistances:
# Paul's model
p = paulslope*np.log10(rankingdistance)+paulintercept
velo = 500./p
t = rankingdistance/velo
pwr = 2.8*(velo**3)
a = {'distance':rankingdistance,
'duration':get_datetimes([t])[0],
'pace':get_datetimes([p])[0],
'power':int(pwr)}
predictions.append(a)
# CP model -
pwr2 = p1[0]/(1+t/p1[2])
pwr2 += p1[1]/(1+t/p1[3])
if pwr2 <= 0:
pwr2 = 50.
velo2 = (pwr2/2.8)**(1./3.)
if np.isnan(velo2) or velo2 <= 0:
velo2 = 1.0
t2 = rankingdistance/velo2
pwr3 = p1[0]/(1+t2/p1[2])
pwr3 += p1[1]/(1+t2/p1[3])
if pwr3 <= 0:
pwr3 = 50.
velo3 = (pwr3/2.8)**(1./3.)
if np.isnan(velo3) or velo3 <= 0:
velo3 = 1.0
t3 = rankingdistance/velo3
p3 = 500./velo3
a = {'distance':rankingdistance,
'duration':get_datetimes([t3])[0],
'pace':get_datetimes([p3])[0],
'power':int(pwr3)}
cpredictions.append(a)
for rankingduration in rankingdurations:
t = 3600.*rankingduration.hour
t += 60.*rankingduration.minute
t += rankingduration.second
t += rankingduration.microsecond/1.e6
# Paul's model
ratio = paulintercept/paulslope
u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/paulslope
d = 500*t*np.log(10.)
d = d/(paulslope*lambertw(u))
d = d.real
velo = d/t
p = 500./velo
pwr = 2.8*(velo**3)
a = {'distance':int(d),
'duration':get_datetimes([t])[0],
'pace':get_datetimes([p])[0],
'power':int(pwr)}
predictions.append(a)
# CP model
pwr = p1[0]/(1+t/p1[2])
pwr += p1[1]/(1+t/p1[3])
if pwr <= 0:
pwr = 50.
velo = (pwr/2.8)**(1./3.)
if np.isnan(velo) or velo <=0:
velo = 1.0
d = t*velo
p = 500./velo
a = {'distance':int(d),
'duration':get_datetimes([t])[0],
'pace':get_datetimes([p])[0],
'power':int(pwr)}
cpredictions.append(a)
return render(request, 'rankings.html',
{'rankingworkouts':theworkouts,
'interactiveplot':script,
'the_div':div,
'predictions':predictions,
'cpredictions':cpredictions,
'nrdata':len(thedistances),
'form':form,
'dateform':dateform,
'deltaform':deltaform,
'id': theuser,
'theuser':uu,
'message':message,
'startdate':startdate,
'enddate':enddate,
})
@login_required()
def workouts_view(request,message='',successmessage=''):
try:
r = Rower.objects.get(user=request.user)
# res = mailprocessing.safeprocessattachments()
#if len(res)>0 and np.cumsum(np.array(res)).max()>0:
# successmessage = 'New Workouts have been created from email'
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
return render(request, 'list_workouts.html',
{'workouts': workouts,
'message': message,
'successmessage':successmessage,
})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
@user_passes_test(promember,login_url="/login")
def workout_comparison_list(request,id=0,message='',successmessage=''):
try:
r = Rower.objects.get(user=request.user)
u = User.objects.get(id=r.user.id)
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime").exclude(id=id)
row = Workout.objects.get(id=id)
return render(request, 'comparison_list.html',
{'id':id,
'workout':row,
'workouts': workouts,
'last_name':u.last_name,
'first_name':u.first_name,
'message': message,
'successmessage':successmessage,
})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
def workout_view(request,id=0):
try:
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
r = Rower.objects.get(id=row.user.id)
u = User.objects.get(id=r.user.id)
# create interactive plot
res = interactive_chart(id)
script = res[0]
div = res[1]
# render page
if (len(g)<=3):
return render(request, 'workout_view.html',
{'workout':row,
'graphs1':g[0:3],
'last_name':u.last_name,
'first_name':u.first_name,
'interactiveplot':script,
'the_div':div})
else:
return render(request, 'workout_view.html',
{'workout':row,
'graphs1':g[0:3],
'graphs2':g[3:6],
'last_name':u.last_name,
'first_name':u.first_name,
'interactiveplot':script,
'the_div':div})
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
@user_passes_test(promember,login_url="/login")
def workout_undo_smoothenpace_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
filename = row.csvfilename
row = rdata(filename)
if row == 0:
return HttpResponse("Error: CSV Data File Not Found")
if 'originalvelo' in row.df:
velo = row.df['originalvelo'].values
row.df[' Stroke500mPace (sec/500m)'] = 500./velo
row.write_csv(filename)
url = "/rowers/workout/"+str(id)+"/advanced"
return HttpResponseRedirect(url)
@user_passes_test(promember,login_url="/login")
def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
filename = row.csvfilename
row = rdata(filename)
if row == 0:
return HttpResponse("Error: CSV Data File Not Found")
pace = row.df[' Stroke500mPace (sec/500m)'].values
velo = 500./pace
if not 'originalvelo' in row.df:
row.df['originalvelo'] = velo
velo2 = stravastuff.ewmovingaverage(velo,5)
pace2 = 500./abs(velo2)
row.df[' Stroke500mPace (sec/500m)'] = pace2
row.df = row.df.fillna(0)
row.write_csv(filename)
url = "/rowers/workout/"+str(id)+"/advanced"
return HttpResponseRedirect(url)
@user_passes_test(promember,login_url="/login")
def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
if request.method == 'POST':
form = CNsummaryForm(request.POST,request.FILES)
if form.is_valid():
f = request.FILES['file']
res = handle_uploaded_file(f)
fname = res[1]
try:
sumd = summarydata(fname)
row.summary = sumd.allstats()
row.save()
os.remove(fname)
successmessage = "CrewNerd summary added"
url = reverse(workout_edit_view,
kwargs = {
'id':str(id),
'successmessage':str(successmessage),
})
return HttpResponseRedirect(url)
except:
os.remove(fname)
message = "Something went wrong (workout_crewnerd_summary_view)"
url = reverse(workout_edit_view,
kwargs = {
'id':str(id),
'message':str(message),
})
return HttpResponseRedirect(url)
else:
return render(request,
"cn_form.html",
{'form':form,
'id':row.id})
else:
form = CNsummaryForm()
return render(request,
"cn_form.html",
{'form':form,
'id':row.id})
@user_passes_test(promember,login_url="/login")
def workout_downloadwind_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
f1 = row.csvfilename
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
# create bearing
rowdata = rdata(f1)
if rowdata == 0:
return HttpResponse("Error: CSV Data File Not Found")
try:
bearing = rowdata.df.ix[:,'bearing'].values
except KeyError:
rowdata.add_bearing()
rowdata.write_csv(f1)
# get wind
try:
avglat = rowdata.df[' latitude'].mean()
avglon = rowdata.df[' longitude'].mean()
avgtime = int(rowdata.df['TimeStamp (sec)'].mean()-rowdata.df.ix[0,'TimeStamp (sec)'])
startdatetime = dateutil.parser.parse("{}, {}".format(row.date,
row.starttime))
starttimeunix = int(mktime(startdatetime.timetuple()))
avgtime = starttimeunix+avgtime
winddata = get_wind_data(avglat,avglon,avgtime)
windspeed = winddata[0]
windbearing = winddata[1]
message = winddata[2]
row.notes += "\n"+message
row.save()
rowdata.add_wind(windspeed,windbearing)
rowdata.write_csv(f1)
kwargs = {'successmessage':str(message),
'id':str(id)}
url = reverse(workout_wind_view,kwargs=kwargs)
response = HttpResponseRedirect(url)
except KeyError:
message = "No latitude/longitude data"
kwargs = {'message':str(message),
'id':str(id)}
url = reverse(workout_wind_view,kwargs=kwargs)
response = HttpResponseRedirect(url)
return response
@user_passes_test(promember,login_url="/login")
def workout_wind_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
# get data
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
# create bearing
rowdata = rdata(f1)
if row == 0:
return HttpResponse("Error: CSV Data File Not Found")
hascoordinates = 1
try:
latitude = rowdata.df.ix[:,' latitude']
except KeyError:
hascoordinates = 0
try:
bearing = rowdata.df.ix[:,'bearing'].values
except KeyError:
rowdata.add_bearing()
rowdata.write_csv(f1)
if request.method == 'POST':
# process form
form = UpdateWindForm(request.POST)
if form.is_valid():
vwind1 = form.cleaned_data['vwind1']
vwind2 = form.cleaned_data['vwind2']
dist1 = form.cleaned_data['dist1']
dist2 = form.cleaned_data['dist2']
winddirection1 = form.cleaned_data['winddirection1']
winddirection2 = form.cleaned_data['winddirection2']
windunit = form.cleaned_data['windunit']
rowdata.update_wind(vwind1,vwind2,
winddirection1,
winddirection2,
dist1,dist2,
units=windunit)
rowdata.write_csv(f1)
else:
message = "Invalid Form"
kwargs = {'message':str(message),
'id':str(id)}
url = reverse(workout_wind_view,kwargs=kwargs)
response = HttpResponseRedirect(url)
else:
form = UpdateWindForm()
# create interactive plot
res = interactive_windchart(id,promember=1)
script = res[0]
div = res[1]
if hascoordinates:
res = googlemap_chart(rowdata.df[' latitude'],
rowdata.df[' longitude'],
row.name)
gmscript = res[0]
gmdiv = res[1]
else:
gmscript = ""
gmdiv = "No GPS data available"
return render(request,
'windedit.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'form':form,
'the_div':div,
'gmap':gmscript,
'gmapdiv':gmdiv})
@user_passes_test(promember,login_url="/login")
def workout_stream_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
# create interactive plot
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
rowdata = rdata(f1)
if rowdata == 0:
return HttpResponse("Error: CSV Data File Not Found")
if request.method == 'POST':
# process form
form = UpdateStreamForm(request.POST)
if form.is_valid():
dist1 = form.cleaned_data['dist1']
dist2 = form.cleaned_data['dist2']
stream1 = form.cleaned_data['stream1']
stream2 = form.cleaned_data['stream2']
streamunit = form.cleaned_data['streamunit']
rowdata.update_stream(stream1,stream2,dist1,dist2,
units=streamunit)
rowdata.write_csv(f1)
else:
message = "Invalid Form"
kwargs = {'message':str(message),
'id':str(id)}
url = reverse(workout_wind_view,kwargs=kwargs)
response = HttpResponseRedirect(url)
else:
form = UpdateStreamForm()
# create interactive plot
res = interactive_streamchart(id,promember=1)
script = res[0]
div = res[1]
return render(request,
'streamedit.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'form':form,
'the_div':div})
@user_passes_test(promember, login_url="/login")
def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
if request.method == 'POST':
# process form
form = AdvancedWorkoutForm(request.POST)
if form.is_valid():
boattype = form.cleaned_data['boattype']
weightvalue = form.cleaned_data['weightvalue']
row.boattype = boattype
row.weightvalue = weightvalue
row.save()
# load row data & create power/wind/bearing columns if not set
f1 = row.csvfilename
rowdata = rdata(f1)
if rowdata == 0:
return HttpResponse("Error: CSV Data File Not Found")
try:
vstream = rowdata.df['vstream']
except KeyError:
rowdata.add_stream(0)
rowdata.write_csv(f1)
try:
bearing = rowdata.df['bearing']
except KeyError:
rowdata.add_bearing()
rowdata.write_csv(f1)
try:
vwind = rowdata.df['vwind']
except KeyError:
rowdata.add_wind(0,0)
rowdata.write_csv(f1)
# do power calculation (asynchronous)
u = request.user
first_name = u.first_name
last_name = u.last_name
emailaddress = u.email
if settings.DEBUG:
res = handle_otwsetpower.delay(f1,boattype,weightvalue,
first_name,last_name,emailaddress,id)
else:
res = queuelow.enqueue(handle_otwsetpower,f1,boattype,
weightvalue,
first_name,last_name,emailaddress,id)
successmessage = "Your calculations have been submitted. You will receive an email when they are done."
kwargs = {'successmessage':str(successmessage),
'id':str(id)}
url = reverse(workout_advanced_view,kwargs=kwargs)
response = HttpResponseRedirect(url)
return response
else:
message = "Invalid Form"
kwargs = {'message':str(message),
'id':str(id)}
url = reverse(workout_otwsetpower_view,kwargs=kwargs)
response = HttpResponseRedirect(url)
else:
form = AdvancedWorkoutForm(instance=row)
return render(request,
'otwsetpower.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'form':form,
})
@login_required()
def workout_geeky_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
form = WorkoutForm(instance=row)
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
# check if user is owner of this workout
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
# create interactive plot
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
# create interactive plot
try:
res = interactive_chart(id,promember=1)
script = res[0]
div = res[1]
except ValueError:
pass
if row.workouttype=='water':
return render(request,
'otwgeeky.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div})
else:
return render(request,
'advancededit.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div})
#@user_passes_test(promember,login_url="/login")
@login_required()
def workout_advanced_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
form = WorkoutForm(instance=row)
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
# check if user is owner of this workout
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
# create interactive plot
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
# create interactive plot
try:
res = interactive_chart(id,promember=1)
script = res[0]
div = res[1]
except ValueError:
pass
if row.workouttype=='water':
return render(request,
'advancedotw.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div})
else:
return render(request,
'advancededit.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div})
def workout_comparison_view(request,id1=0,id2=0,xparam='distance',yparam='spm'):
promember=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
# create interactive plot
res = interactive_comparison_chart(id1,id2,xparam=xparam,yparam=yparam,
promember=promember)
script = res[0]
div = res[1]
return render(request,
'comparisonchart.html',
{'interactiveplot':script,
'the_div':div,
'id1':id1,
'id2':id2,
'xparam':xparam,
'yparam':yparam,
})
def workout_comparison_view2(request,id1=0,id2=0,xparam='distance',
yparam='spm',plottype='line'):
promember=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
# create interactive plot
res = interactive_comparison_chart(id1,id2,xparam=xparam,yparam=yparam,
promember=promember,plottype=plottype)
script = res[0]
div = res[1]
return render(request,
'comparisonchart2.html',
{'interactiveplot':script,
'the_div':div,
'id1':id1,
'id2':id2,
'xparam':xparam,
'yparam':yparam,
'plottype':plottype,
'promember':promember,
})
def workout_flexchart_view(request,id=0,xparam='distance',yparam1='pace',
yparam2='hr',
promember=0):
if request.method == 'POST':
workstrokesonly = request.POST['workstrokesonly']
else:
workstrokesonly = False
row = Workout.objects.get(id=id)
promember=0
mayedit=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if request.user == row.user.user:
mayedit=1
# create interactive plot
res = interactive_flex_chart(id,xparam=xparam,yparam1=yparam1,
yparam2=yparam2,
promember=promember)
script = res[0]
div = res[1]
return render(request,
'flexchart.html',
{'interactiveplot':script,
'the_div':div,
'id':id,
'xparam':xparam,
'yparam1':yparam1,
'yparam2':yparam2,
'mayedit':mayedit,
})
def workout_flexchart2_view(request,id=0,xparam='distance',yparam1='pace',
yparam2='hr',plottype='line',
promember=0):
if request.method == 'POST':
workstrokesonly = request.POST['workstrokesonly']
if workstrokesonly == 'True':
workstrokesonly = True
else:
workstrokesonly = False
else:
workstrokesonly = False
row = Workout.objects.get(id=id)
promember=0
mayedit=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if request.user == row.user.user:
mayedit=1
# create interactive plot
res = interactive_flex_chart(id,xparam=xparam,yparam1=yparam1,
yparam2=yparam2,
promember=promember,plottype=plottype,
workstrokesonly=workstrokesonly)
script = res[0]
div = res[1]
return render(request,
'flexchart2.html',
{'interactiveplot':script,
'the_div':div,
'id':id,
'xparam':xparam,
'yparam1':yparam1,
'yparam2':yparam2,
'plottype':plottype,
'mayedit':mayedit,
'promember':promember,
'workstrokesonly': not workstrokesonly,
})
def workout_flexchart3_view(request,id=0,xparam='distance',yparam1='pace',
yparam2='hr',plottype='line',
promember=0):
if request.method == 'POST':
workstrokesonly = request.POST['workstrokesonly']
if workstrokesonly == 'True':
workstrokesonly = True
else:
workstrokesonly = False
else:
workstrokesonly = False
row = Workout.objects.get(id=id)
promember=0
mayedit=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if request.user == row.user.user:
mayedit=1
# create interactive plot
res = interactive_flex_chart2(id,xparam=xparam,yparam1=yparam1,
yparam2=yparam2,
promember=promember,plottype=plottype,
workstrokesonly=workstrokesonly)
script = res[0]
div = res[1]
widgetscript = res[2]
widgetdiv1 = res[3]
widgetdiv2 = res[4]
return render(request,
'flexchart2.html',
{'interactiveplot':script,
'the_div':div,
'id':id,
'xparam':xparam,
'yparam1':yparam1,
'yparam2':yparam2,
'plottype':plottype,
'mayedit':mayedit,
'promember':promember,
'workstrokesonly': not workstrokesonly,
'widgetscript': widgetscript,
'widgetdiv1': widgetdiv1,
'widgetdiv2': widgetdiv2,
})
def testbokeh(request):
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
x = np.array(range(51))/10.
y = x**2.
z = (2*(x-2.5))**2
data = dict(
x = x,
y = y,
z = z,
)
df = pd.DataFrame(data)
filtered_df = df
source = ColumnDataSource(
df
)
source2 = ColumnDataSource(
filtered_df
)
plot = Figure(tools=TOOLS)
plot.circle('x','y',source=source2)
plot.xaxis.axis_label = "X"
plot.yaxis.axis_label = "Y"
plot.x_range = Range1d(-1,6)
plot.y_range = Range1d(-5,30)
callback = CustomJS(args = dict(source=source,source2=source2), code="""
var data = source.data
var data2 = source2.data
var x1 = data['x']
var y1 = data['y']
var z1 = data['z']
var mina = mina.value
var maxa = maxa.value
var minz = minz.value
var maxz = maxz.value
data2['x'] = []
data2['y'] = []
data2['z'] = []
for (i=0; i<x1.length; i++) {
if (x1[i]>=mina && x1[i]<=maxa && z1[i]<=maxz && z1[i]>=minz) {
data2['x'].push(x1[i])
data2['y'].push(y1[i])
data2['z'].push(z1[i])
}
}
source2.trigger('change');
""")
s1 = Slider(start=0.0, end=5,value=0.0, step=.1,title="Min X Value",callback=callback)
callback.args["mina"] = s1
s2 = Slider(start=0.0, end=5,value=5.0, step=.1,title="Max X Value",callback=callback)
callback.args["maxa"] = s2
s3 = Slider(start=0.0, end=25,value=0.0, step=.1,title="Min Z Value",callback=callback)
callback.args["minz"] = s3
s4 = Slider(start=0.0, end=25,value=25.0, step=.1,title="Max Z Value",callback=callback)
callback.args["maxz"] = s4
hover = plot.select(dict(type=HoverTool))
hover.tooltips = OrderedDict([
('X value','@x'),
('Y value','@y'),
('Z value','@z'),
])
hover.mode = 'mouse'
layout = row([column([s1,s2,s3,s4]),plot])
# widgetbox(s)
script, div = components(layout)
js_resources = INLINE.render_js()
css_resources = INLINE.render_css()
return render(request,
'test.html',
{'the_script': script,
'the_div': div,
'js_res': js_resources,
'css_res':css_resources,
})
#@user_passes_test(promember,login_url="/login")
def workout_biginteractive_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
# check if user is owner of this workout
# create interactive plot
f1 = row.csvfilename
u = request.user
# r = Rower.objects.get(user=u)
promember=0
mayedit=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if request.user == row.user.user:
mayedit=1
# create interactive plot
res = interactive_bar_chart(id,promember=promember)
script = res[0]
div = res[1]
return render(request,
'biginteractive1.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div,
'promember':promember,
'mayedit':mayedit})
def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
row = Workout.objects.get(id=id)
# check if user is owner of this workout
# create interactive plot
f1 = row.csvfilename
u = request.user
# r = Rower.objects.get(user=u)
promember=0
mayedit=0
if not request.user.is_anonymous():
r = Rower.objects.get(user=request.user)
result = request.user.is_authenticated() and r.rowerplan=='pro'
if result:
promember=1
if request.user == row.user.user:
mayedit=1
# create interactive plot
res = interactive_otw_advanced_pace_chart(id,promember=promember)
script = res[0]
div = res[1]
return render(request,
'otwinteractive.html',
{'workout':row,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div,
'mayedit':mayedit})
@login_required()
def workout_export_view(request,id=0, message="", successmessage=""):
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
row = Workout.objects.get(id=id)
form = WorkoutForm(instance=row)
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
# check if user is owner of this workout
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
else:
return render(request,
'export.html',
{'workout':row,
'message':message,
'successmessage':successmessage,
})
@login_required()
def workout_edit_view(request,id=0,message="",successmessage=""):
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
if request.method == 'POST':
# Form was submitted
form = WorkoutForm(request.POST)
if form.is_valid():
# Get values from form
name = form.cleaned_data['name']
date = form.cleaned_data['date']
starttime = form.cleaned_data['starttime']
workouttype = form.cleaned_data['workouttype']
duration = form.cleaned_data['duration']
distance = form.cleaned_data['distance']
notes = form.cleaned_data['notes']
startdatetime = (str(date) + ' ' + str(starttime))
startdatetime = datetime.datetime.strptime(startdatetime,
"%Y-%m-%d %H:%M:%S")
startdatetime = timezone.make_aware(startdatetime)
try:
# check if valid ID exists (workout exists)
row = Workout.objects.get(id=id)
# check if user is owner of this workout
if checkworkoutuser(request.user,row):
row.name = name
row.date = date
row.starttime = starttime
row.startdatetime = startdatetime
row.workouttype = workouttype
row.notes = notes
row.duration = duration
row.distance = distance
row.save()
# change data in csv file
# startdatetime = dateutil.parser.parse("{}, {}".format(date,starttime))
r = rdata(row.csvfilename)
if r == 0:
return HttpResponse("Error: CSV Data File Not Found")
r.rowdatetime = startdatetime
r.write_csv(row.csvfilename)
successmessage = "Changes saved"
url = "/rowers/workout/"+str(row.id)+"/edit"
url = reverse(workout_edit_view,
kwargs = {
'id':str(row.id),
'successmessage':str(successmessage),
})
response = HttpResponseRedirect(url)
else:
message = "You are not allowed to change this workout"
url = reverse(workouts_view,args=[str(message)])
response = HttpResponseRedirect(url)
except Workout.DoesNotExist:
# create new workout
r = Rower.objects.get(user=request.user)
w = Workout(name=name,date=date,workouttype=workouttype,
user=r)
w.save()
successmessage = "New Workout Created"
url = reverse(workouts_view,
kwargs = {
'successmessage':str(successmessage),
})
response = HttpResponseRedirect(url)
else:
message = "Invalid Form"
url = reverse(workouts_view,args=[str(message)])
response = HttpResponseRedirect(url)
return response
else:
try:
row = Workout.objects.get(id=id)
form = WorkoutForm(instance=row)
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
# check if user is owner of this workout
if (checkworkoutuser(request.user,row)==False):
message = "You are not allowed to edit this workout"
url = reverse(workouts_view,args=[str(message)])
return HttpResponseRedirect(url)
else:
# create interactive plot
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
res = interactive_chart(id)
script = res[0]
div = res[1]
rowdata = rdata(f1)
hascoordinates = 1
try:
latitude = rowdata.df[' latitude']
except KeyError:
hascoordinates = 0
if hascoordinates:
res = googlemap_chart(rowdata.df[' latitude'],
rowdata.df[' longitude'],
row.name)
gmscript = res[0]
gmdiv = res[1]
else:
gmscript = ""
gmdiv = ""
# render page
if (len(g)<=3):
return render(request, 'workout_form.html',
{'form':form,
'workout':row,
'graphs1':g[0:3],
'message': message,
'successmessage': successmessage,
'gmscript': gmscript,
'gmdiv': gmdiv,
})
# 'interactiveplot':script,
# 'the_div':div})
else:
return render(request, 'workout_form.html',
{'form':form,
'workout':row,
'graphs1':g[0:3],
'graphs2':g[3:6],
'message': message,
'successmessage': successmessage,
'gmscript': gmscript,
'gmdiv': gmdiv,
})
# 'interactiveplot':script,
# 'the_div':div})
except Workout.DoesNotExist:
form = WorkoutForm(
initial = {'workouttype' : 'rower'}
)
return render(request,
'workout_form.html',
{'form':form})
@user_passes_test(promember,login_url="/login")
def workout_add_otw_powerplot_view(request,id):
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)==False):
return HttpResponse("You are not allowed add plots to this workout")
else:
f1 = w.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = f1+timestr+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=u)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnr = 9
if (w.workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
else:
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i = GraphImage(workout=w,creationdatetime=timezone.now(),
filename=fullpathimagename)
i.save()
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
@login_required()
def workout_add_piechart_view(request,id):
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)==False):
return HttpResponse("You are not allowed add plots to this workout")
else:
f1 = w.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = f1+timestr+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=u)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnr = 3
if (w.workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
else:
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i = GraphImage(workout=w,creationdatetime=timezone.now(),
filename=fullpathimagename)
i.save()
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
@login_required()
def workout_add_timeplot_view(request,id):
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)==False):
return HttpResponse("You are not allowed add plots to this workout")
else:
f1 = w.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = f1+timestr+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=u)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnr = 1
if (w.workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
else:
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
i = GraphImage(workout=w,creationdatetime=timezone.now(),
filename=fullpathimagename)
# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i.save()
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
@login_required()
def workout_add_distanceplot_view(request,id):
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)==False):
return HttpResponse("You are not allowed add plots to this workout")
else:
f1 = w.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = f1+timestr+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=u)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnr = 2
if (w.workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
else:
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
i = GraphImage(workout=w,creationdatetime=timezone.now(),
filename=fullpathimagename)
# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i.save()
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
@user_passes_test(promember,login_url="/login")
def workout_add_distanceplot2_view(request,id):
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)==False):
return HttpResponse("You are not allowed add plots to this workout")
else:
f1 = w.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = f1+timestr+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=u)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnr = 7
if (w.workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
else:
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
i = GraphImage(workout=w,creationdatetime=timezone.now(),
filename=fullpathimagename)
# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i.save()
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
@user_passes_test(promember,login_url="/login")
def workout_add_timeplot2_view(request,id):
w = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,w)==False):
return HttpResponse("You are not allowed add plots to this workout")
else:
f1 = w.csvfilename[6:-4]
timestr = strftime("%Y%m%d-%H%M%S")
imagename = f1+timestr+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
r = Rower.objects.get(user=u)
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnr = 8
if (w.workouttype=='water'):
plotnr = plotnr+3
if settings.DEBUG:
res = handle_makeplot.delay(f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
else:
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
w.name,hrdata,plotnr,imagename)
i = GraphImage(workout=w,creationdatetime=timezone.now(),
filename=fullpathimagename)
# i = GraphImage(workout=w,creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i.save()
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
@login_required()
def workout_stravaimport_view(request,message=""):
res = stravastuff.get_strava_workout_list(request.user)
if (res.status_code != 200):
if (res.status_code == 401):
r = Rower.objects.get(user=request.user)
if (r.stravatoken == '') or (r.stravatoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/stravaauthorize/")
message = "Something went wrong in workout_stravaimport_view"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workouts_view,
kwargs = {
'message': str(message)
})
return HttpResponseRedirect(url)
else:
data = res.json()
return render(request,'strava_list_import.html',
{'data':data,
'message':message,
})
return HttpResponse(res)
@login_required()
def workout_sporttracksimport_view(request,message=""):
res = sporttracksstuff.get_sporttracks_workout_list(request.user)
if (res.status_code != 200):
if (res.status_code == 401):
r = Rower.objects.get(user=request.user)
if (r.sporttrackstoken == '') or (r.sporttrackstoken is None):
s = "Token doesn't exist. Need to authorize"
return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
message = "Something went wrong in workout_sporttracksimport_view"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workouts_view,
kwargs = {
'message': str(message)
})
return HttpResponseRedirect(url)
else:
workouts = []
for item in res.json()['items']:
d = int(float(item['total_distance']))
i = getidfromsturi(item['uri'])
n = item['name']
ttot = str(datetime.timedelta(seconds=int(float(item['duration']))))
s = item['start_time']
r = item['type']
keys = ['id','distance','duration','starttime','type','name']
values = [i,d,ttot,s,r,n]
res = dict(zip(keys,values))
workouts.append(res)
return render(request,'sporttracks_list_import.html',
{'workouts':workouts,
'message':message,
})
return HttpResponse(res)
@login_required()
def c2listdebug_view(request,message=""):
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
r = Rower.objects.get(user=request.user)
#if (r.c2token == '') or (r.c2token is None):
#s = "Token doesn't exist. Need to authorize"
#return HttpResponseRedirect("/rowers/me/c2authorize/")
#elif (timezone.now()>r.tokenexpirydate):
#s = "Token expired. Needs to refresh."
#res = c2stuff.rower_c2_token_refresh(request.user)
res = c2stuff.get_c2_workout_list(request.user)
if (res.status_code != 200):
message = "Something went wrong in workout_c2import_view (C2 token renewal)"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workouts_view,
kwargs = {
'message': str(message)
})
return HttpResponseRedirect(url)
else:
workouts = []
for item in res.json()['data']:
d = item['distance']
i = item['id']
ttot = item['time_formatted']
s = item['date']
r = item['type']
s2 = item['source']
c = item['comments']
keys = ['id','distance','duration','starttime','rowtype','source','comment']
values = [i,d,ttot,s,r,s2,c]
res = dict(zip(keys,values))
workouts.append(res)
return render(request,
'c2_list_import2.html',
{'workouts':workouts,
'message':message})
@login_required()
def workout_c2import_view(request,message=""):
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
#r = Rower.objects.get(user=request.user)
#if (r.c2token == '') or (r.c2token is None):
#s = "Token doesn't exist. Need to authorize"
#return HttpResponseRedirect("/rowers/me/c2authorize/")
#elif (timezone.now()>r.tokenexpirydate):
#s = "Token expired. Needs to refresh."
#res = c2stuff.rower_c2_token_refresh(request.user)
res = c2stuff.get_c2_workout_list(request.user)
if (res.status_code != 200):
message = "Something went wrong in workout_c2import_view (C2 token refresh)"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workouts_view,
kwargs = {
'message': str(message)
})
return HttpResponseRedirect(url)
else:
workouts = []
for item in res.json()['data']:
d = item['distance']
i = item['id']
ttot = item['time_formatted']
s = item['date']
r = item['type']
s2 = item['source']
c = item['comments']
keys = ['id','distance','duration','starttime','rowtype','source','comment']
values = [i,d,ttot,s,r,s2,c]
res = dict(zip(keys,values))
workouts.append(res)
return render(request,
'c2_list_import2.html',
{'workouts':workouts,
'message':message})
@login_required()
def workout_getstravaworkout_view(request,stravaid):
res = stravastuff.get_strava_workout(request.user,stravaid)
strokedata = res[1]
data = res[0]
id = add_workout_from_strokedata(request.user,stravaid,data,strokedata,
source='strava')
w = Workout.objects.get(id=id)
w.uploadedtostrava=stravaid
w.save()
url = "/rowers/workout/"+str(id)+"/edit"
return HttpResponseRedirect(url)
@login_required()
def workout_getsporttracksworkout_view(request,sporttracksid):
res = sporttracksstuff.get_sporttracks_workout(request.user,sporttracksid)
data = res.json()
id = add_workout_from_stdata(request.user,sporttracksid,data)
w = Workout.objects.get(id=id)
w.uploadedtosporttracks=sporttracksid
w.save()
url = "/rowers/workout/"+str(id)+"/edit"
return HttpResponseRedirect(url)
@login_required()
def workout_getc2workout_view(request,c2id):
res = c2stuff.get_c2_workout(request.user,c2id)
if (res.status_code == 200):
data = res.json()['data']
if 'stroke_data' in data:
# test = data['stroke_data']
res2 = c2stuff.get_c2_workout_strokes(request.user,c2id)
# 2016-07-27 added below if statement (balkanboy error report)
if res2.status_code == 200:
strokedata = pd.DataFrame.from_dict(res2.json()['data'])
id = add_workout_from_strokedata(request.user,c2id,data,strokedata,
source='c2')
w = Workout.objects.get(id=id)
w.uploadedtoc2=c2id
w.save()
url = "/rowers/workout/"+str(id)+"/edit"
return HttpResponseRedirect(url)
else:
message = json.loads(s.text)['message']
url = reverse(workout_c2import_view,
kwargs={
'message':message,
})
return HttpResponseRedirect(url)
else:
message = "This workout doesn't contain stroke data"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workout_c2import_view,
kwargs={
'message':message,
})
return HttpResponseRedirect(url)
else:
message = "Received error code from Concept2"
if settings.DEBUG:
return HttpResponse(res)
else:
url = reverse(workout_c2import_view,
kwargs={
'message':message,
})
return HttpResponseRedirect(url)
@login_required()
def workout_upload_view(request,message=""):
if request.method == 'POST':
form = DocumentsForm(request.POST,request.FILES)
optionsform = UploadOptionsForm(request.POST)
if form.is_valid():
f = request.FILES['file']
res = handle_uploaded_file(f)
t = form.cleaned_data['title']
# fileformat = form.cleaned_data['fileformat']
workouttype = form.cleaned_data['workouttype']
notes = form.cleaned_data['notes']
make_plot = request.POST.getlist('make_plot')
plottype = request.POST['plottype']
upload_to_c2 = request.POST.getlist('upload_to_C2')
f1 = res[0] # file name
f2 = res[1] # file name incl media directory
# new
fileformat = get_file_type(f2)
if fileformat == 'unknown':
message = "We couldn't recognize the file type"
url = reverse(workout_upload_view,
args=[str(message)])
response = HttpResponseRedirect(url)
if settings.DEBUG:
res = handle_sendemail_unrecognized.delay(f2,
request.user.email)
else:
res = queuehigh.enqueue(handle_sendemail_unrecognized,
f2,request.user.email)
return response
summary = ''
# handle non-Painsled
try:
if (fileformat != 'csv'):
# handle RowPro:
if (fileformat == 'rp'):
row = RowProParser(f2)
# handle TCX
if (fileformat == 'tcx'):
row = TCXParser(f2)
# handle Mystery
if (fileformat == 'mystery'):
row = MysteryParser(f2)
# handle TCX no HR
if (fileformat == 'tcxnohr'):
row = TCXParserNoHR(f2)
# handle ErgData
if (fileformat == 'ergdata'):
row = ErgDataParser(f2)
# handle painsled desktop
if (fileformat == 'painsleddesktop'):
row = painsledDesktopParser(f2)
# handle speed coach GPS
if (fileformat == 'speedcoach'):
row = speedcoachParser(f2)
# handle speed coach GPS 2
if (fileformat == 'speedcoach2'):
row = SpeedCoach2Parser(f2)
# handle ErgStick
if (fileformat == 'ergstick'):
row = ErgStickParser(f2)
# handle FIT
if (fileformat == 'fit'):
row = FITParser(f2)
s = fitsummarydata(f2)
s.setsummary()
summary = s.summarytext
f_to_be_deleted = f2
# should delete file
f2 = f2[:-4]+'o.csv'
row.write_csv(f2)
os.remove(f_to_be_deleted)
# make workout and put in database
r = Rower.objects.get(user=request.user)
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
row = rdata(f2,rower=rr)
if row == 0:
return HttpResponse("Error: CSV Data File Not Found")
# auto smoothing
pace = row.df[' Stroke500mPace (sec/500m)'].values
velo = 500./pace
f = row.df['TimeStamp (sec)'].diff().mean()
windowsize = 2*(int(10./(f)))+1
if not 'originalvelo' in row.df:
row.df['originalvelo'] = velo
if windowsize > 3:
velo2 = savgol_filter(velo,windowsize,3)
else:
velo2 = velo
pace2 = 500./abs(velo2)
row.df[' Stroke500mPace (sec/500m)'] = pace2
row.df = row.df.fillna(0)
row.write_csv(f2)
# recalculate power data
if workouttype == 'rower' or workouttype == 'dynamic' or workouttype == 'slides':
try:
row.erg_recalculatepower()
# row.spm_fromtimestamps()
row.write_csv(f2)
except:
pass
if fileformat != 'fit':
summary = row.summary()
summary += '\n'
summary += row.intervalstats_painsled()
averagehr = row.df[' HRCur (bpm)'].mean()
maxhr = row.df[' HRCur (bpm)'].max()
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
workoutstartdatetime = thetimezone.localize(row.rowdatetime).astimezone(utc)
# check for duplicate start times
r = Rower.objects.get(user=request.user)
ws = Workout.objects.filter(starttime=workoutstarttime,
user=r)
if (len(ws) != 0):
message = "Warning: This workout probably already exists in the database"
w = Workout(user=r,name=t,date=workoutdate,
workouttype=workouttype,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=f2,notes=notes,summary=summary,
maxhr=maxhr,averagehr=averagehr,
startdatetime=workoutstartdatetime)
w.save()
# Make Plot
if (make_plot):
imagename = f1[:-4]+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnrs = {
'timeplot':1,
'distanceplot':2,
'pieplot':3,
}
plotnr = plotnrs[plottype]
if (workouttype=='water'):
plotnr = plotnr+3
# res = handle_makeplot.delay(f1,f2,t,
# hrdata,plotnr,imagename)
if settings.DEBUG:
res = handle_makeplot.delay(f1,f2,t,
hrdata,plotnr,
imagename)
else:
res = queue.enqueue(handle_makeplot,f1,f2,
t,hrdata,
plotnr,imagename)
i = GraphImage(workout=w,
creationdatetime=timezone.now(),
filename=fullpathimagename)
# i = GraphImage(workout=w,
# creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i.save()
# upload to C2
if (upload_to_c2):
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
#r = Rower.objects.get(user=request.user)
#if (r.c2token == '') or (r.c2token is None):
# s = "Token doesn't exist. Need to authorize"
#return HttpResponseRedirect("/rowers/me/c2authorize/")
#elif (timezone.now()>r.tokenexpirydate):
#s = "Token expired. Needs to refresh."
#res = c2stuff.rower_c2_token_refresh(request.user)
try:
c2userid = c2stuff.get_userid(thetoken)
data = c2stuff.createc2workoutdata(w)
authorizationstring = str('Bearer ' + thetoken)
headers = {'Authorization': authorizationstring,
'user-agent': 'sanderroosendaal',
'Content-Type': 'application/json'}
import urllib
url = "https://log.concept2.com/api/users/%s/results" % (c2userid)
response = requests.post(url,headers=headers,data=json.dumps(data))
# response = c2stuff.workout_c2_upload(request.user,w)
if (response.status_code != 201):
if settings.DEBUG:
return HttpResponse(response)
else:
message = "C2 upload failed"
url = reverse(workout_edit_view,
kwargs={
'message':message,
'id':str(w.id),
})
return HttpResponseRedirect(url)
else:
s= json.loads(response.text)
c2id = s['data']['id']
w.uploadedtoc2 = c2id
w.save()
except:
message = "C2 upload failed"
url = reverse(workout_edit_view,
kwargs={
'message':message,
'id':str(w.id),
})
return HttpResponseRedirect(url)
# redirect to workout edit page
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
except:
message = "something went wrong (workout_upload_view)"
url = reverse(workout_upload_view,
args=[str(message)])
response = HttpResponseRedirect(url)
else:
response = render(request,
'document_form.html',
{'form':form,
'optionsform': optionsform,
'message':message})
return response
else:
form = DocumentsForm()
optionsform = UploadOptionsForm()
return render(request, 'document_form.html',
{'form':form,
'optionsform': optionsform,
'message':message})
@login_required()
def workout_upload_view_debug(request,message=""):
if request.method == 'POST':
form = DocumentsForm(request.POST,request.FILES)
optionsform = UploadOptionsForm(request.POST)
if form.is_valid():
f = request.FILES['file']
res = handle_uploaded_file(f)
t = form.cleaned_data['title']
fileformat = form.cleaned_data['fileformat']
workouttype = form.cleaned_data['workouttype']
notes = form.cleaned_data['notes']
make_plot = request.POST.getlist('make_plot')
plottype = request.POST['plottype']
upload_to_c2 = request.POST.getlist('upload_to_C2')
f1 = res[0] # file name
f2 = res[1] # file name incl media directory
print fileformat
# handle non-Painsled
if (fileformat != 'csv'):
# handle RowPro:
if (fileformat == 'rp'):
row = RowProParser(f2)
# handle TCX
if (fileformat == 'tcx'):
row = TCXParser(f2)
# handle TCX no HR
if (fileformat == 'tcxnohr'):
row = TCXParserNoHR(f2)
# handle ErgData
if (fileformat == 'ergdata'):
row = ErgDataParser(f2)
# handle painsled desktop
if (fileformat == 'painsleddesktop'):
row = painsledDesktopParser(f2)
# handle speed coach
if (fileformat == 'speedcoach'):
row = speedcoachParser(f2)
# handle ErgStick
if (fileformat == 'ergstick'):
row = ErgStickParser(f2)
f_to_be_deleted = f2
# should delete file
f2 = f2[:-4]+'o.csv'
row.write_csv(f2)
os.remove(f_to_be_deleted)
# make workout and put in database
r = Rower.objects.get(user=request.user)
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
row = rdata(f2,rower=rr)
if row == 0:
return HttpResponse("Error: CSV Data File Not Found")
averagehr = row.df[' HRCur (bpm)'].mean()
maxhr = row.df[' HRCur (bpm)'].max()
totaldist = row.df['cum_dist'].max()
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
totaltime = totaltime+row.df.ix[0,' ElapsedTime (sec)']
hours = int(totaltime/3600.)
minutes = int((totaltime - 3600.*hours)/60.)
seconds = int(totaltime - 3600.*hours - 60.*minutes)
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
summary = row.summary()
summary += '\n'
summary += row.intervalstats()
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
# check for duplicate start times
r = Rower.objects.get(user=request.user)
ws = Workout.objects.filter(starttime=workoutstarttime,
user=r)
if (len(ws) != 0):
print "Warning: This workout probably already exists in the database"
w = Workout(user=r,name=t,date=workoutdate,
workouttype=workouttype,
duration=duration,distance=totaldist,
weightcategory=r.weightcategory,
starttime=workoutstarttime,
csvfilename=f2,notes=notes,summary=summary,
averagehr=averagehr,maxhr=maxhr)
w.save()
# Make Plot
if (make_plot):
imagename = f1[:-4]+'.png'
fullpathimagename = 'static/plots/'+imagename
u = request.user
hrdata = {
'hrmax':r.max,
'hrut2':r.ut2,
'hrut1':r.ut1,
'hrat':r.at,
'hrtr':r.tr,
'hran':r.an,
}
# make plot - asynchronous task
plotnrs = {
'timeplot':1,
'distanceplot':2,
'pieplot':3,
}
plotnr = plotnrs[plottype]
if (workouttype=='water'):
plotnr = plotnr+3
# res = handle_makeplot.delay(f1,f2,t,
# hrdata,plotnr,imagename)
if settings.DEBUG:
res = handle_makeplot.delay(f1,f2,t,
hrdata,plotnr,
imagename)
else:
res = queue.enqueue(handle_makeplot,f1,f2,
t,hrdata,
plotnr,imagename)
i = GraphImage(workout=w,
creationdatetime=timezone.now(),
filename=fullpathimagename)
# i = GraphImage(workout=w,
# creationdatetime=datetime.datetime.now(),
# filename=fullpathimagename)
i.save()
# upload to C2
if (upload_to_c2):
try:
thetoken = c2_open(request.user)
except C2NoTokenError:
return HttpResponseRedirect("/rowers/me/c2authorize/")
#r = Rower.objects.get(user=request.user)
#if (r.c2token == '') or (r.c2token is None):
# s = "Token doesn't exist. Need to authorize"
#return HttpResponseRedirect("/rowers/me/c2authorize/")
#elif (timezone.now()>r.tokenexpirydate):
#s = "Token expired. Needs to refresh."
#res = c2stuff.rower_c2_token_refresh(request.user)
try:
response = c2stuff.workout_c2_upload(request.user,w)
if (response.status_code != 201):
if settings.DEBUG:
return HttpResponse(response)
else:
message = "C2 upload failed"
url = reverse(workout_edit_view,
kwargs={
'message':message,
'id':str(w.id),
})
return HttpResponseRedirect(url)
except:
message = "C2 upload failed"
url = reverse(workout_edit_view,
kwargs={
'message':message,
'id':str(w.id),
})
return HttpResponseRedirect(url)
# redirect to workout edit page
url = "/rowers/workout/"+str(w.id)+"/edit"
return HttpResponseRedirect(url)
else:
response = render(request,
'document_form.html',
{'form':form,
'optionsform': optionsform,
'message':message})
return response
else:
form = DocumentsForm()
optionsform = UploadOptionsForm()
return render(request, 'document_form.html',
{'form':form,
'optionsform': optionsform,
'message':message})
@login_required()
def workout_delete_confirm_view(request, id=0):
try:
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to delete this workout")
else:
return render(request,'workout_delete_confirm.html',
{'id':id,
'workout':row})
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
@login_required()
def workout_delete_view(request,id=0):
try:
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to delete this workout")
else:
# files are removed by pre-delete in models.py
row.delete()
url = reverse(workouts_view,kwargs={
'successmessage': "Workout deleted",
}
)
return HttpResponseRedirect(url)
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
@login_required()
def graph_delete_confirm_view(request, id=0):
try:
img = GraphImage.objects.get(id=id)
row = Workout.objects.get(id=img.workout.id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to delete this workout")
else:
return render(request,'graphimage_delete_confirm.html',
{'id':id,
'graph':img})
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
@login_required()
def graph_delete_view(request,id=0):
try:
img = GraphImage.objects.get(id=id)
row = Workout.objects.get(id=img.workout.id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to delete this graph")
else:
img.delete()
url = reverse(workouts_view,kwargs={
'successmessage': "Graph deleted",
}
)
return HttpResponseRedirect(url)
except GraphImage.DoesNotExist:
return HttpResponse("Graph Image doesn't exist")
@login_required()
def dashboard_view(request,message="",successmessage=""):
try:
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
r = Rower.objects.get(user=request.user)
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
if (len(g)<=3):
return render(request,'dashboard.html',
{'workouts':workouts,
'graphs1':g[0:3],
'message':message,
'successmessage':successmessage})
else:
return render(request,'dashboard.html',
{'workouts':workouts,
'graphs1':g[0:3],
'graphs2':g[3:6],
'message':message,
'successmessage':successmessage})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
@login_required()
def graphs_view(request):
try:
r = Rower.objects.get(user=request.user)
workouts = Workout.objects.filter(user=r).order_by("-date", "-starttime")
g = GraphImage.objects.filter(workout__in=workouts).order_by("-creationdatetime")
if (len(g)<=5):
return render(request, 'list_graphs.html',
{'graphs1': g[0:4]})
else:
return render(request, 'list_graphs.html',
{'graphs1': g[0:5],
'graphs2': g[5:10]})
except Rower.DoesNotExist:
return HttpResponse("Admin has no rower instance")
def graph_show_view(request,id):
try:
g = GraphImage.objects.get(id=id)
w = Workout.objects.get(id=g.workout.id)
r = Rower.objects.get(id=w.user.id)
return render(request,'show_graph.html',
{'graph':g,
'workout':w,
'rower':r,})
except GraphImage.DoesNotExist:
return HttpResponse("This graph doesn't exist")
@login_required()
def workout_summary_restore_view(request,id,message="",successmessage=""):
try:
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to edit this workout")
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
s = ""
# still here - this is a workout we may edit
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return HttpResponse("Error: CSV Data File Not Found")
rowdata.restoreintervaldata()
rowdata.write_csv(f1)
intervalstats = rowdata.allstats()
row.summary = intervalstats
row.save()
itime,idist,itype = rowdata.intervalstats_values()
nrintervals = len(idist)
# create interactive plot
try:
res = interactive_chart(id,promember=1)
script = res[0]
div = res[1]
except ValueError:
pass
url = reverse(workout_summary_edit_view,kwargs={
'id':id,
'successmessage': "Original Interval Data Restored",
}
)
return HttpResponseRedirect(url)
@login_required()
def workout_summary_edit_view(request,id,message="",successmessage=""
):
try:
row = Workout.objects.get(id=id)
if (checkworkoutuser(request.user,row)==False):
return HttpResponse("You are not allowed to edit this workout")
except Workout.DoesNotExist:
return HttpResponse("Workout doesn't exist")
s = ""
# still here - this is a workout we may edit
f1 = row.csvfilename
u = request.user
r = Rower.objects.get(user=u)
rr = rrower(hrmax=r.max,hrut2=r.ut2,
hrut1=r.ut1,hrat=r.at,
hrtr=r.tr,hran=r.an)
rowdata = rdata(f1,rower=rr)
if rowdata == 0:
return HttpResponse("Error: CSV Data File Not Found")
intervalstats = rowdata.allstats()
itime,idist,itype = rowdata.intervalstats_values()
nrintervals = len(idist)
# create interactive plot
try:
res = interactive_chart(id,promember=1)
script = res[0]
div = res[1]
except ValueError:
pass
savebutton = 'nosavebutton'
if request.method == 'POST' and "intervalstring" in request.POST:
form = SummaryStringForm(request.POST)
if form.is_valid():
#something
cd = form.cleaned_data
s = cd["intervalstring"]
rowdata.updateinterval_string(s)
intervalstats = rowdata.allstats()
itime,idist,itype = rowdata.intervalstats_values()
nrintervals = len(idist)
savebutton = 'savestringform'
elif request.method == 'POST' and "savestringform" in request.POST:
s = request.POST["savestringform"]
rowdata.updateinterval_string(s)
intervalstats = rowdata.allstats()
itime,idist,itype = rowdata.intervalstats_values()
nrintervals = len(idist)
row.summary = intervalstats
intervalstats = rowdata.allstats()
row.notes += "\n"+s
row.save()
rowdata.write_csv(f1)
data = {'intervalstring':s}
form = SummaryStringForm(initial=data)
savebutton = 'savestringform'
elif request.method == 'POST' and "savedetailform" in request.POST:
savebutton = 'savedetailform'
form = SummaryStringForm()
nrintervals = int(request.POST['nrintervals'])
detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
itime = []
idist = []
itype = []
ivalues = []
iunits = []
itypes = []
iresults = []
for i in range(nrintervals):
try:
t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S.%f")
except ValueError:
t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S")
timesecs = 3600*t.hour+60*t.minute+t.second+t.microsecond/1.e6
itime += [timesecs]
idist += [int(request.POST['intervald_%s' % i])]
itype += [int(request.POST['type_%s' % i])]
if itype[i] == 3: # rest
itypes += ['rest']
ivalues += [timesecs]
iresults += [idist[i]]
iunits += ['seconds']
if itype[i] == 5 or itype[i] == 2: # distance based work
itypes += ['work']
ivalues += [idist[i]]
iresults += [timesecs]
iunits += ['meters']
if itype[i] == 4 or itype[i] == 1: # time based work
itypes += ['work']
ivalues += [timesecs]
iresults += [idist[i]]
iunits += ['seconds']
rowdata.updateintervaldata(ivalues,iunits,itypes,iresults=iresults)
intervalstats = rowdata.allstats()
row.summary = intervalstats
row.notes += "\n"+s
row.save()
rowdata.write_csv(f1)
form = SummaryStringForm()
elif request.method == 'POST' and "nrintervals" in request.POST:
savebutton = 'savedetailform'
nrintervals = int(request.POST['nrintervals'])
detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
if detailform.is_valid():
cd = detailform.cleaned_data
itime = []
idist = []
itype = []
ivalues = []
iunits = []
itypes = []
iresults = []
for i in range(nrintervals):
t = cd['intervalt_%s' % i]
timesecs = t.total_seconds()
itime += [timesecs]
idist += [cd['intervald_%s' % i]]
itype += [cd['type_%s' % i]]
if itype[i] == '3': # rest
itypes += ['rest']
ivalues += [timesecs]
iresults += [idist[i]]
iunits += ['seconds']
if itype[i] == '5' or itype[i] == '2': # distance based work
itypes += ['work']
ivalues += [idist[i]]
iresults += [timesecs]
iunits += ['meters']
if itype[i] == '4' or itype[i] == '1': # time based work
itypes += ['work']
ivalues += [timesecs]
iresults += [idist[i]]
iunits += ['seconds']
rowdata.updateintervaldata(ivalues,iunits,
itypes,iresults=iresults)
intervalstats = rowdata.allstats()
form = SummaryStringForm()
else:
form = SummaryStringForm()
initial = {}
for i in range(nrintervals):
initial['intervald_%s' % i] = idist[i]
initial['intervalt_%s' % i] = get_time(itime[i])
initial['type_%s' % i] = itype[i]
detailform = IntervalUpdateForm(aantal=nrintervals,initial=initial)
# render page
return render(request, 'summary_edit.html',
{'form':form,
'detailform':detailform,
'workout':row,
'intervalstats':intervalstats,
'nrintervals':nrintervals,
'message': message,
'successmessage': successmessage,
'interactiveplot':script,
'the_div':div,
'intervalstring':s,
'savebutton':savebutton,
})
@login_required()
def rower_edit_view(request,message=""):
if request.method == 'POST':
form = RowerForm(request.POST)
if form.is_valid():
# something
cd = form.cleaned_data
hrmax = cd['max']
ut2 = cd['ut2']
ut1 = cd['ut1']
at = cd['at']
tr = cd['tr']
an = cd['an']
rest = cd['rest']
weightcategory = cd['weightcategory']
try:
r = Rower.objects.get(user=request.user)
r.max = max(min(hrmax,250),10)
r.ut2 = max(min(ut2,250),10)
r.ut1 = max(min(ut1,250),10)
r.at = max(min(at,250),10)
r.tr = max(min(tr,250),10)
r.an = max(min(an,250),10)
r.rest = max(min(rest,250),10)
r.weightcategory = weightcategory
r.save()
message = "User data changed"
url = reverse(workouts_view,args=[str(message)])
response = HttpResponseRedirect(url)
except Rower.DoesNotExist:
message = "Funny. This user doesn't exist."
url = reverse(workouts_view,args=[str(message)])
response = HttpResponseRedirect(url)
else:
message = HttpResponse("invalid form")
return render(request, 'rower_form.html',
{'form':form,})
# url = reverse(rower_edit_view,args=[str(message)])
# response = HttpResponseRedirect(url)
return response
else:
try:
r = Rower.objects.get(user=request.user)
form = RowerForm(instance=r)
return render(request, 'rower_form.html',
{'form':form,})
except Rower.DoesNotExist:
return HttpResponse("This user doesn't exist")