4339 lines
117 KiB
Python
4339 lines
117 KiB
Python
import time
|
|
import operator
|
|
from django.views.generic.base import TemplateView
|
|
from django.db.models import Q
|
|
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.core.paginator import Paginator, EmptyPage, PageNotAnInteger
|
|
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
|
|
from rowers.models import RowerPowerForm,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
|
|
|
|
from dataprep import timedeltaconv
|
|
|
|
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:
|
|
title = 'Imported'
|
|
|
|
starttimeunix = mktime(rowdatetime.timetuple())
|
|
|
|
res = make_cumvalues(0.1*strokedata['t'])
|
|
cum_time = res[0]
|
|
lapidx = res[1]
|
|
|
|
unixtime = cum_time+starttimeunix
|
|
# unixtime[0] = starttimeunix
|
|
seconds = 0.1*strokedata.ix[:,'t']
|
|
|
|
nr_rows = len(unixtime)
|
|
|
|
try:
|
|
latcoord = strokedata.ix[:,'lat']
|
|
loncoord = strokedata.ix[:,'lon']
|
|
except:
|
|
latcoord = np.zeros(nr_rows)
|
|
loncoord = np.zeros(nr_rows)
|
|
|
|
|
|
try:
|
|
strokelength = strokedata.ix[:,'strokelength']
|
|
except:
|
|
strokelength = np.zeros(nr_rows)
|
|
|
|
dist2 = 0.1*strokedata.ix[:,'d']
|
|
|
|
spm = strokedata.ix[:,'spm']
|
|
hr = strokedata.ix[:,'hr']
|
|
pace = strokedata.ix[:,'p']/10.
|
|
|
|
velo = 500./pace
|
|
# if (source=='c2' or source=='strava'):
|
|
power = 2.8*velo**3
|
|
# else:
|
|
# power = 0.0*velo
|
|
|
|
# save csv
|
|
# Create data frame with all necessary data to write to csv
|
|
df = pd.DataFrame({'TimeStamp (sec)':unixtime,
|
|
' Horizontal (meters)': dist2,
|
|
' Cadence (stokes/min)':spm,
|
|
' HRCur (bpm)':hr,
|
|
' longitude':loncoord,
|
|
' latitude':latcoord,
|
|
' Stroke500mPace (sec/500m)':pace,
|
|
' Power (watts)':power,
|
|
' DragFactor':np.zeros(nr_rows),
|
|
' DriveLength (meters)':np.zeros(nr_rows),
|
|
' StrokeDistance (meters)':strokelength,
|
|
' DriveTime (ms)':np.zeros(nr_rows),
|
|
' StrokeRecoveryTime (ms)':np.zeros(nr_rows),
|
|
' AverageDriveForce (lbs)':np.zeros(nr_rows),
|
|
' PeakDriveForce (lbs)':np.zeros(nr_rows),
|
|
' lapIdx':lapidx,
|
|
' ElapsedTime (sec)':seconds
|
|
})
|
|
|
|
# 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
|
|
|
|
velo3 = pd.Series(velo2)
|
|
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
|
velo3 = velo3.fillna(method='ffill')
|
|
|
|
pace2 = 500./abs(velo3)
|
|
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,ftp=r.ftp)
|
|
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
|
|
|
|
velo3 = pd.Series(velo2)
|
|
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
|
velo3 = velo3.fillna(method='ffill')
|
|
|
|
pace2 = 500./abs(velo3)
|
|
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,ftp=r.ftp)
|
|
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):
|
|
try:
|
|
code = request.GET['code']
|
|
res = c2stuff.get_token(code)
|
|
except MultiValueDictKeyError:
|
|
message = "The resource owner or authorization server denied the request"
|
|
return imports_view(request,message=message)
|
|
|
|
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="",message=""):
|
|
return render(request,"imports.html",
|
|
{'successmessage': successmessage,
|
|
'message': message,
|
|
})
|
|
|
|
@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=10),
|
|
enddate=timezone.now()+datetime.timedelta(days=1),
|
|
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_chart2(allergworkouts,xparam=xparam,
|
|
yparam1=yparam1,
|
|
yparam2=yparam2,
|
|
promember=promember)
|
|
script = res[0]
|
|
div = res[1]
|
|
js_resources = res[2]
|
|
css_resources = res[3]
|
|
else:
|
|
script = ''
|
|
div = '<p>No erg pieces uploaded for this date range.</p>'
|
|
js_resources = ''
|
|
css_resources = ''
|
|
|
|
return render(request, 'cum_flex.html',
|
|
{'interactiveplot':script,
|
|
'the_div':div,
|
|
'js_res': js_resources,
|
|
'css_res':css_resources,
|
|
'id':theuser,
|
|
'theuser':u,
|
|
'startdate':startdate,
|
|
'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':timedeltaconv(t),
|
|
'pace':timedeltaconv(p),
|
|
'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':timedeltaconv(t3),
|
|
'pace':timedeltaconv(p3),
|
|
'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':timedeltaconv(t),
|
|
'pace':timedeltaconv(p),
|
|
'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':timedeltaconv(t),
|
|
'pace':timedeltaconv(p),
|
|
'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 workout_recalcsummary_view(request,id=0):
|
|
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
|
|
rowdata = rdata(filename)
|
|
row.summary = rowdata.allstats()
|
|
row.save()
|
|
successmessage = "Summary Updated"
|
|
url = reverse(workout_edit_view,
|
|
kwargs = {
|
|
'id':str(id),
|
|
'successmessage':str(successmessage),
|
|
})
|
|
|
|
return HttpResponseRedirect(url)
|
|
|
|
|
|
@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")
|
|
query = request.GET.get('q')
|
|
if query:
|
|
query_list = query.split()
|
|
workouts = workouts.filter(
|
|
reduce(operator.and_,
|
|
(Q(name__icontains=q) for q in query_list)) |
|
|
reduce(operator.and_,
|
|
(Q(notes__icontains=q) for q in query_list))
|
|
)
|
|
|
|
paginator = Paginator(workouts,25) # show 25 workouts per page
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
workouts = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
workouts = paginator.page(1)
|
|
except EmptyPage:
|
|
workouts = paginator.page(paginator.num_pages)
|
|
|
|
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)
|
|
|
|
query = request.GET.get('q')
|
|
if query:
|
|
query_list = query.split()
|
|
workouts = workouts.filter(
|
|
reduce(operator.and_,
|
|
(Q(name__icontains=q) for q in query_list)) |
|
|
reduce(operator.and_,
|
|
(Q(notes__icontains=q) for q in query_list))
|
|
)
|
|
|
|
paginator = Paginator(workouts,15) # show 25 workouts per page
|
|
page = request.GET.get('page')
|
|
|
|
try:
|
|
workouts = paginator.page(page)
|
|
except PageNotAnInteger:
|
|
workouts = paginator.page(1)
|
|
except EmptyPage:
|
|
workouts = paginator.page(paginator.num_pages)
|
|
|
|
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_flexchart3_view(request,id=0,xparam='distance',yparam1='pace',
|
|
yparam2='hr',plottype='line',
|
|
promember=0):
|
|
|
|
if request.method == 'POST':
|
|
workstrokesonly = request.POST['workstrokesonly']
|
|
if workstrokesonly == 'True':
|
|
workstrokesonly = True
|
|
else:
|
|
workstrokesonly = False
|
|
else:
|
|
workstrokesonly = False
|
|
|
|
row = Workout.objects.get(id=id)
|
|
promember=0
|
|
mayedit=0
|
|
if not request.user.is_anonymous():
|
|
r = Rower.objects.get(user=request.user)
|
|
result = request.user.is_authenticated() and r.rowerplan=='pro'
|
|
if result:
|
|
promember=1
|
|
if request.user == row.user.user:
|
|
mayedit=1
|
|
|
|
# create interactive plot
|
|
res = interactive_flex_chart2(id,xparam=xparam,yparam1=yparam1,
|
|
yparam2=yparam2,
|
|
promember=promember,plottype=plottype,
|
|
workstrokesonly=workstrokesonly)
|
|
script = res[0]
|
|
div = res[1]
|
|
js_resources = res[2]
|
|
css_resources = res[3]
|
|
|
|
return render(request,
|
|
'flexchart3.html',
|
|
{'the_script':script,
|
|
'the_div':div,
|
|
'js_res': js_resources,
|
|
'css_res':css_resources,
|
|
'id':id,
|
|
'xparam':xparam,
|
|
'yparam1':yparam1,
|
|
'yparam2':yparam2,
|
|
'plottype':plottype,
|
|
'mayedit':mayedit,
|
|
'promember':promember,
|
|
'workstrokesonly': not workstrokesonly,
|
|
})
|
|
|
|
def testbokeh(request):
|
|
|
|
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair'
|
|
|
|
x = np.array(range(51))/10.
|
|
y = x**2.
|
|
z = (2*(x-2.5))**2
|
|
data = dict(
|
|
x = x,
|
|
y = y,
|
|
z = z,
|
|
)
|
|
|
|
df = pd.DataFrame(data)
|
|
filtered_df = df
|
|
|
|
source = ColumnDataSource(
|
|
df
|
|
)
|
|
|
|
source2 = ColumnDataSource(
|
|
filtered_df
|
|
)
|
|
|
|
plot = Figure(tools=TOOLS)
|
|
plot.circle('x','y',source=source2)
|
|
plot.xaxis.axis_label = "X"
|
|
plot.yaxis.axis_label = "Y"
|
|
plot.x_range = Range1d(-1,6)
|
|
plot.y_range = Range1d(-5,30)
|
|
|
|
callback = CustomJS(args = dict(source=source,source2=source2), code="""
|
|
var data = source.data
|
|
var data2 = source2.data
|
|
var x1 = data['x']
|
|
var y1 = data['y']
|
|
var z1 = data['z']
|
|
var mina = mina.value
|
|
var maxa = maxa.value
|
|
var minz = minz.value
|
|
var maxz = maxz.value
|
|
data2['x'] = []
|
|
data2['y'] = []
|
|
data2['z'] = []
|
|
|
|
for (i=0; i<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 = layoutrow([layoutcolumn([s1,s2,s3,s4]),plot])
|
|
# widgetbox(s)
|
|
script, div = components(layout)
|
|
js_resources = INLINE.render_js()
|
|
css_resources = INLINE.render_css()
|
|
return render(request,
|
|
'test.html',
|
|
{'the_script': script,
|
|
'the_div': div,
|
|
'js_res': js_resources,
|
|
'css_res':css_resources,
|
|
})
|
|
|
|
#@user_passes_test(promember,login_url="/login")
|
|
def workout_biginteractive_view(request,id=0,message="",successmessage=""):
|
|
row = Workout.objects.get(id=id)
|
|
# check if user is owner of this workout
|
|
|
|
|
|
# create interactive plot
|
|
f1 = row.csvfilename
|
|
u = request.user
|
|
# r = Rower.objects.get(user=u)
|
|
|
|
promember=0
|
|
mayedit=0
|
|
if not request.user.is_anonymous():
|
|
r = Rower.objects.get(user=request.user)
|
|
result = request.user.is_authenticated() and r.rowerplan=='pro'
|
|
if result:
|
|
promember=1
|
|
if request.user == row.user.user:
|
|
mayedit=1
|
|
|
|
|
|
# create interactive plot
|
|
res = interactive_bar_chart(id,promember=promember)
|
|
script = res[0]
|
|
div = res[1]
|
|
|
|
return render(request,
|
|
'biginteractive1.html',
|
|
{'workout':row,
|
|
'message': message,
|
|
'successmessage': successmessage,
|
|
'interactiveplot':script,
|
|
'the_div':div,
|
|
'promember':promember,
|
|
'mayedit':mayedit})
|
|
|
|
def workout_otwpowerplot_view(request,id=0,message="",successmessage=""):
|
|
row = Workout.objects.get(id=id)
|
|
# check if user is owner of this workout
|
|
|
|
|
|
# create interactive plot
|
|
f1 = row.csvfilename
|
|
u = request.user
|
|
# r = Rower.objects.get(user=u)
|
|
|
|
promember=0
|
|
mayedit=0
|
|
if not request.user.is_anonymous():
|
|
r = Rower.objects.get(user=request.user)
|
|
result = request.user.is_authenticated() and r.rowerplan=='pro'
|
|
if result:
|
|
promember=1
|
|
if request.user == row.user.user:
|
|
mayedit=1
|
|
|
|
# create interactive plot
|
|
res = interactive_otw_advanced_pace_chart(id,promember=promember)
|
|
script = res[0]
|
|
div = res[1]
|
|
|
|
|
|
return render(request,
|
|
'otwinteractive.html',
|
|
{'workout':row,
|
|
'message': message,
|
|
'successmessage': successmessage,
|
|
'interactiveplot':script,
|
|
'the_div':div,
|
|
'mayedit':mayedit})
|
|
|
|
@login_required()
|
|
def workout_export_view(request,id=0, message="", successmessage=""):
|
|
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
|
|
|
|
row = Workout.objects.get(id=id)
|
|
form = WorkoutForm(instance=row)
|
|
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
|
|
# check if user is owner of this workout
|
|
|
|
if (checkworkoutuser(request.user,row)==False):
|
|
message = "You are not allowed to edit this workout"
|
|
url = reverse(workouts_view,args=[str(message)])
|
|
|
|
return HttpResponseRedirect(url)
|
|
|
|
else:
|
|
return render(request,
|
|
'export.html',
|
|
{'workout':row,
|
|
'message':message,
|
|
'successmessage':successmessage,
|
|
})
|
|
|
|
@login_required()
|
|
def workout_edit_view(request,id=0,message="",successmessage=""):
|
|
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
|
|
|
|
if request.method == 'POST':
|
|
# Form was submitted
|
|
form = WorkoutForm(request.POST)
|
|
if form.is_valid():
|
|
# Get values from form
|
|
name = form.cleaned_data['name']
|
|
date = form.cleaned_data['date']
|
|
starttime = form.cleaned_data['starttime']
|
|
workouttype = form.cleaned_data['workouttype']
|
|
duration = form.cleaned_data['duration']
|
|
distance = form.cleaned_data['distance']
|
|
notes = form.cleaned_data['notes']
|
|
startdatetime = (str(date) + ' ' + str(starttime))
|
|
startdatetime = datetime.datetime.strptime(startdatetime,
|
|
"%Y-%m-%d %H:%M:%S")
|
|
startdatetime = timezone.make_aware(startdatetime)
|
|
try:
|
|
# check if valid ID exists (workout exists)
|
|
row = Workout.objects.get(id=id)
|
|
# check if user is owner of this workout
|
|
if checkworkoutuser(request.user,row):
|
|
row.name = name
|
|
row.date = date
|
|
row.starttime = starttime
|
|
row.startdatetime = startdatetime
|
|
row.workouttype = workouttype
|
|
row.notes = notes
|
|
row.duration = duration
|
|
row.distance = distance
|
|
row.save()
|
|
# change data in csv file
|
|
# startdatetime = dateutil.parser.parse("{}, {}".format(date,starttime))
|
|
r = rdata(row.csvfilename)
|
|
if r == 0:
|
|
return HttpResponse("Error: CSV Data File Not Found")
|
|
r.rowdatetime = startdatetime
|
|
r.write_csv(row.csvfilename)
|
|
successmessage = "Changes saved"
|
|
url = "/rowers/workout/"+str(row.id)+"/edit"
|
|
url = reverse(workout_edit_view,
|
|
kwargs = {
|
|
'id':str(row.id),
|
|
'successmessage':str(successmessage),
|
|
})
|
|
response = HttpResponseRedirect(url)
|
|
else:
|
|
message = "You are not allowed to change this workout"
|
|
url = reverse(workouts_view,args=[str(message)])
|
|
|
|
response = HttpResponseRedirect(url)
|
|
except Workout.DoesNotExist:
|
|
# create new workout
|
|
r = Rower.objects.get(user=request.user)
|
|
w = Workout(name=name,date=date,workouttype=workouttype,
|
|
user=r)
|
|
w.save()
|
|
successmessage = "New Workout Created"
|
|
url = reverse(workouts_view,
|
|
kwargs = {
|
|
'successmessage':str(successmessage),
|
|
})
|
|
|
|
response = HttpResponseRedirect(url)
|
|
else:
|
|
message = "Invalid Form"
|
|
url = reverse(workouts_view,args=[str(message)])
|
|
response = HttpResponseRedirect(url)
|
|
|
|
return response
|
|
else:
|
|
try:
|
|
row = Workout.objects.get(id=id)
|
|
form = WorkoutForm(instance=row)
|
|
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
|
|
# check if user is owner of this workout
|
|
|
|
if (checkworkoutuser(request.user,row)==False):
|
|
message = "You are not allowed to edit this workout"
|
|
url = reverse(workouts_view,args=[str(message)])
|
|
|
|
return HttpResponseRedirect(url)
|
|
|
|
else:
|
|
# create interactive plot
|
|
f1 = row.csvfilename
|
|
u = request.user
|
|
r = Rower.objects.get(user=u)
|
|
|
|
res = interactive_chart(id)
|
|
script = res[0]
|
|
div = res[1]
|
|
|
|
rowdata = rdata(f1)
|
|
hascoordinates = 1
|
|
try:
|
|
latitude = rowdata.df[' latitude']
|
|
except KeyError:
|
|
hascoordinates = 0
|
|
|
|
if hascoordinates:
|
|
res = googlemap_chart(rowdata.df[' latitude'],
|
|
rowdata.df[' longitude'],
|
|
row.name)
|
|
gmscript = res[0]
|
|
gmdiv = res[1]
|
|
else:
|
|
gmscript = ""
|
|
gmdiv = ""
|
|
|
|
|
|
# render page
|
|
if (len(g)<=3):
|
|
return render(request, 'workout_form.html',
|
|
{'form':form,
|
|
'workout':row,
|
|
'graphs1':g[0:3],
|
|
'message': message,
|
|
'successmessage': successmessage,
|
|
'gmscript': gmscript,
|
|
'gmdiv': gmdiv,
|
|
})
|
|
# 'interactiveplot':script,
|
|
# 'the_div':div})
|
|
else:
|
|
return render(request, 'workout_form.html',
|
|
{'form':form,
|
|
'workout':row,
|
|
'graphs1':g[0:3],
|
|
'graphs2':g[3:6],
|
|
'message': message,
|
|
'successmessage': successmessage,
|
|
'gmscript': gmscript,
|
|
'gmdiv': gmdiv,
|
|
})
|
|
# 'interactiveplot':script,
|
|
# 'the_div':div})
|
|
|
|
except Workout.DoesNotExist:
|
|
form = WorkoutForm(
|
|
initial = {'workouttype' : 'rower'}
|
|
)
|
|
return render(request,
|
|
'workout_form.html',
|
|
{'form':form})
|
|
|
|
@user_passes_test(promember,login_url="/login")
|
|
def workout_add_otw_powerplot_view(request,id):
|
|
w = Workout.objects.get(id=id)
|
|
if (checkworkoutuser(request.user,w)==False):
|
|
return HttpResponse("You are not allowed add plots to this workout")
|
|
else:
|
|
f1 = w.csvfilename[6:-4]
|
|
timestr = strftime("%Y%m%d-%H%M%S")
|
|
imagename = f1+timestr+'.png'
|
|
fullpathimagename = 'static/plots/'+imagename
|
|
u = request.user
|
|
r = Rower.objects.get(user=u)
|
|
hrpwrdata = {
|
|
'hrmax':r.max,
|
|
'hrut2':r.ut2,
|
|
'hrut1':r.ut1,
|
|
'hrat':r.at,
|
|
'hrtr':r.tr,
|
|
'hran':r.an,
|
|
'ftp':r.ftp,
|
|
}
|
|
|
|
# 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,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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)
|
|
hrpwrdata = {
|
|
'hrmax':r.max,
|
|
'hrut2':r.ut2,
|
|
'hrut1':r.ut1,
|
|
'hrat':r.at,
|
|
'hrtr':r.tr,
|
|
'hran':r.an,
|
|
'ftp':r.ftp,
|
|
}
|
|
|
|
# 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,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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_power_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)
|
|
hrpwrdata = {
|
|
'hrmax':r.max,
|
|
'hrut2':r.ut2,
|
|
'hrut1':r.ut1,
|
|
'hrat':r.at,
|
|
'hrtr':r.tr,
|
|
'hran':r.an,
|
|
'ftp':r.ftp,
|
|
}
|
|
|
|
# make plot - asynchronous task
|
|
plotnr = 13
|
|
|
|
if (w.workouttype=='water'):
|
|
plotnr = plotnr+3
|
|
|
|
if settings.DEBUG:
|
|
res = handle_makeplot.delay(f1,w.csvfilename,
|
|
w.name,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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)
|
|
hrpwrdata = {
|
|
'hrmax':r.max,
|
|
'hrut2':r.ut2,
|
|
'hrut1':r.ut1,
|
|
'hrat':r.at,
|
|
'hrtr':r.tr,
|
|
'hran':r.an,
|
|
'ftp':r.ftp,
|
|
}
|
|
|
|
# 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,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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)
|
|
hrpwrdata = {
|
|
'hrmax':r.max,
|
|
'hrut2':r.ut2,
|
|
'hrut1':r.ut1,
|
|
'hrat':r.at,
|
|
'hrtr':r.tr,
|
|
'hran':r.an,
|
|
'ftp':r.ftp,
|
|
}
|
|
|
|
# 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,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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)
|
|
hrpwrdata = {
|
|
'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,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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)
|
|
hrpwrdata = {
|
|
'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,hrpwrdata,plotnr,imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,w.csvfilename,
|
|
w.name,hrpwrdata,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,ftp=r.ftp)
|
|
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
|
|
|
|
velo3 = pd.Series(velo2)
|
|
velo3 = velo3.replace([-np.inf,np.inf],np.nan)
|
|
velo3 = velo3.fillna(method='ffill')
|
|
|
|
pace2 = 500./abs(velo3)
|
|
|
|
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
|
|
hrpwrdata = {
|
|
'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,
|
|
# hrpwrdata,plotnr,imagename)
|
|
if settings.DEBUG:
|
|
res = handle_makeplot.delay(f1,f2,t,
|
|
hrpwrdata,plotnr,
|
|
imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,f2,
|
|
t,hrpwrdata,
|
|
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
|
|
|
|
|
|
# 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,ftp=r.ftp)
|
|
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
|
|
hrpwrdata = {
|
|
'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,
|
|
# hrpwrdata,plotnr,imagename)
|
|
if settings.DEBUG:
|
|
res = handle_makeplot.delay(f1,f2,t,
|
|
hrpwrdata,plotnr,
|
|
imagename)
|
|
else:
|
|
res = queue.enqueue(handle_makeplot,f1,f2,
|
|
t,hrpwrdata,
|
|
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")
|
|
query = request.GET.get('q')
|
|
if query:
|
|
query_list = query.split()
|
|
workouts = workouts.filter(
|
|
reduce(operator.and_,
|
|
(Q(name__icontains=q) for q in query_list)) |
|
|
reduce(operator.and_,
|
|
(Q(notes__icontains=q) for q in query_list))
|
|
)
|
|
|
|
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,ftp=r.ftp)
|
|
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,ftp=r.ftp)
|
|
rowdata = rdata(f1,rower=rr)
|
|
if rowdata == 0:
|
|
return HttpResponse("Error: CSV Data File Not Found")
|
|
intervalstats = rowdata.allstats()
|
|
itime,idist,itype = rowdata.intervalstats_values()
|
|
nrintervals = len(idist)
|
|
|
|
# create interactive plot
|
|
try:
|
|
res = interactive_chart(id,promember=1)
|
|
script = res[0]
|
|
div = res[1]
|
|
except ValueError:
|
|
pass
|
|
|
|
savebutton = 'nosavebutton'
|
|
|
|
# We have submitted the mini language interpreter
|
|
if request.method == 'POST' and "intervalstring" in request.POST:
|
|
form = SummaryStringForm(request.POST)
|
|
if form.is_valid():
|
|
cd = form.cleaned_data
|
|
s = cd["intervalstring"]
|
|
rowdata.updateinterval_string(s)
|
|
intervalstats = rowdata.allstats()
|
|
itime,idist,itype = rowdata.intervalstats_values()
|
|
nrintervals = len(idist)
|
|
savebutton = 'savestringform'
|
|
|
|
# we are saving the results obtained from the mini language interpreter
|
|
elif request.method == 'POST' and "savestringform" in request.POST:
|
|
s = request.POST["savestringform"]
|
|
rowdata.updateinterval_string(s)
|
|
intervalstats = rowdata.allstats()
|
|
itime,idist,itype = rowdata.intervalstats_values()
|
|
nrintervals = len(idist)
|
|
row.summary = intervalstats
|
|
#intervalstats = rowdata.allstats()
|
|
row.notes += "\n"+s
|
|
row.save()
|
|
rowdata.write_csv(f1)
|
|
data = {'intervalstring':s}
|
|
form = SummaryStringForm(initial=data)
|
|
savebutton = 'savestringform'
|
|
|
|
# we are saving the results obtained from the detailed form
|
|
elif request.method == 'POST' and "savedetailform" in request.POST:
|
|
savebutton = 'savedetailform'
|
|
form = SummaryStringForm()
|
|
nrintervals = int(request.POST['nrintervals'])
|
|
detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
|
|
itime = []
|
|
idist = []
|
|
itype = []
|
|
ivalues = []
|
|
iunits = []
|
|
itypes = []
|
|
iresults = []
|
|
for i in range(nrintervals):
|
|
try:
|
|
t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S.%f")
|
|
except ValueError:
|
|
t = datetime.datetime.strptime(request.POST['intervalt_%s' % i],"%H:%M:%S")
|
|
|
|
timesecs = 3600*t.hour+60*t.minute+t.second+t.microsecond/1.e6
|
|
itime += [timesecs]
|
|
idist += [int(request.POST['intervald_%s' % i])]
|
|
itype += [int(request.POST['type_%s' % i])]
|
|
|
|
if itype[i] == 3: # rest
|
|
itypes += ['rest']
|
|
ivalues += [timesecs]
|
|
iresults += [idist[i]]
|
|
iunits += ['seconds']
|
|
if itype[i] == 5 or itype[i] == 2: # distance based work
|
|
itypes += ['work']
|
|
ivalues += [idist[i]]
|
|
iresults += [timesecs]
|
|
iunits += ['meters']
|
|
if itype[i] == 4 or itype[i] == 1: # time based work
|
|
itypes += ['work']
|
|
ivalues += [timesecs]
|
|
iresults += [idist[i]]
|
|
iunits += ['seconds']
|
|
|
|
|
|
rowdata.updateintervaldata(ivalues,iunits,itypes,iresults=iresults)
|
|
intervalstats = rowdata.allstats()
|
|
row.summary = intervalstats
|
|
row.notes += "\n"+s
|
|
row.save()
|
|
rowdata.write_csv(f1)
|
|
|
|
|
|
form = SummaryStringForm()
|
|
|
|
# we are processing the details form
|
|
elif request.method == 'POST' and "nrintervals" in request.POST:
|
|
savebutton = 'savedetailform'
|
|
nrintervals = int(request.POST['nrintervals'])
|
|
detailform = IntervalUpdateForm(request.POST,aantal=nrintervals)
|
|
if detailform.is_valid():
|
|
cd = detailform.cleaned_data
|
|
itime = []
|
|
idist = []
|
|
itype = []
|
|
ivalues = []
|
|
iunits = []
|
|
itypes = []
|
|
iresults = []
|
|
for i in range(nrintervals):
|
|
t = cd['intervalt_%s' % i]
|
|
timesecs = t.total_seconds()
|
|
itime += [timesecs]
|
|
idist += [cd['intervald_%s' % i]]
|
|
itype += [cd['type_%s' % i]]
|
|
|
|
if itype[i] == '3': # rest
|
|
itypes += ['rest']
|
|
ivalues += [timesecs]
|
|
iresults += [idist[i]]
|
|
iunits += ['seconds']
|
|
if itype[i] == '5' or itype[i] == '2': # distance based work
|
|
itypes += ['work']
|
|
ivalues += [idist[i]]
|
|
iresults += [timesecs]
|
|
iunits += ['meters']
|
|
if itype[i] == '4' or itype[i] == '1': # time based work
|
|
itypes += ['work']
|
|
ivalues += [timesecs]
|
|
iresults += [idist[i]]
|
|
iunits += ['seconds']
|
|
|
|
rowdata.updateintervaldata(ivalues,iunits,
|
|
itypes,iresults=iresults)
|
|
intervalstats = rowdata.allstats()
|
|
|
|
|
|
form = SummaryStringForm()
|
|
|
|
else:
|
|
form = SummaryStringForm()
|
|
|
|
initial = {}
|
|
for i in range(nrintervals):
|
|
initial['intervald_%s' % i] = idist[i]
|
|
initial['intervalt_%s' % i] = get_time(itime[i])
|
|
initial['type_%s' % i] = itype[i]
|
|
|
|
|
|
detailform = IntervalUpdateForm(aantal=nrintervals,initial=initial)
|
|
|
|
# render page
|
|
return render(request, 'summary_edit.html',
|
|
{'form':form,
|
|
'detailform':detailform,
|
|
'workout':row,
|
|
'intervalstats':intervalstats,
|
|
'nrintervals':nrintervals,
|
|
'message': message,
|
|
'successmessage': successmessage,
|
|
'interactiveplot':script,
|
|
'the_div':div,
|
|
'intervalstring':s,
|
|
'savebutton':savebutton,
|
|
})
|
|
|
|
|
|
|
|
@login_required()
|
|
def rower_edit_view(request,message=""):
|
|
if request.method == 'POST' and "ut2" in request.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
|
|
elif request.method == 'POST' and "ftp" in request.POST:
|
|
form = RowerPowerForm(request.POST)
|
|
if form.is_valid():
|
|
cd = form.cleaned_data
|
|
ftp = cd['ftp']
|
|
try:
|
|
r = Rower.objects.get(user=request.user)
|
|
r.ftp = max(min(ftp,650),50)
|
|
r.save()
|
|
message = "Functional Threshold Value 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,
|
|
'powerform':powerform,
|
|
})
|
|
|
|
|
|
return response
|
|
else:
|
|
try:
|
|
r = Rower.objects.get(user=request.user)
|
|
form = RowerForm(instance=r)
|
|
powerform = RowerPowerForm(instance=r)
|
|
return render(request, 'rower_form.html',
|
|
{
|
|
'form':form,
|
|
'powerform':powerform,
|
|
})
|
|
except Rower.DoesNotExist:
|
|
return HttpResponse("This user doesn't exist")
|
|
|
|
|