import time import zipfile import operator from django.views.generic.base import TemplateView from django.db.models import Q from django.db import IntegrityError, transaction from django.shortcuts import render from django.http import ( HttpResponse, HttpResponseRedirect, HttpResponseForbidden, HttpResponseNotAllowed, HttpResponseNotFound, ) 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,StrokeDataForm from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart from rowers.models import RowerPowerForm,RowerForm,GraphImage,AdvancedWorkoutForm from rowers.models import FavoriteForm,BaseFavoriteFormSet,SiteAnnouncement from django.forms.formsets import formset_factory 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 import ownapistuff from ownapistuff import TEST_CLIENT_ID, TEST_CLIENT_SECRET, TEST_REDIRECT_URI 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 rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser 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 shutil import copyfile 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 BoatCoachParser,RowPerfectParser 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 from oauth2_provider.models import Application,Grant,AccessToken import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') from rest_framework_swagger.views import get_swagger_view from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from rest_framework.response import Response from rowers.serializers import RowerSerializer,WorkoutSerializer from rest_framework import status,permissions,generics from rest_framework.decorators import api_view, renderer_classes from permissions import IsOwnerOrNot 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 * schema_view = get_swagger_view(title='Rowsandall API (Unstable)') 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: try: res = rrdata(file+'.gz',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() # Create Sample workout f = 'media/testdata.csv.gz' timestr = strftime("%Y%m%d-%H%M%S") f2 = f[:-7]+timestr+'.csv.gz' copyfile(f,f2) response = dataprep.new_workout_from_file(therower,f2, title='New User Sample Data', notes='This is an example workout to get you started') # Create and send email fullemail = first_name + " " + last_name + " " + "<" + email + ">" subject = "Thank you for registering on rowsandall.com" message = "Thank you for registering on rowsandall.com. You can now login using the credentials you provided.\n" message += "The first thing you might want to do is check and edit the heart rate band values. After logging in, click the button with your first name.\n" message += "You can also check our videos page at http://rowsandall.com/rowers/videos for some helpful instruction videos.\n\n" message += "User name:"+username+"\n" message += "Password :"+password+"\n\n" message += "For all your questions, just reply to this email.\n\n" message += "Happy rowing!\n\n\n" message += "Oh, one more thing. The site is currently in beta and is developing fast. Bear with us. Don't hesitate to contact me if anything is broken or doesn't seem to work as advertised." send_mail(subject, message, 'Sander Roosendaal ', [fullemail]) subject2 = "New User" message2 = "New user registered.\n" message2 += fullemail + "\n" message2 += "User name: "+username send_mail(subject2, message2, 'Rowsandall Server ', ['roosendaalsander@gmail.com']) return HttpResponseRedirect('/rowers/register/thankyou/') else: return render(request, "registration_form.html", {'form':form}) else: form = RegistrationFormUniqueEmail() return render(request, "registration_form.html", {'form':form,}) def sendmail(request): if request.method == 'POST': form = EmailForm(request.POST) if form.is_valid(): firstname = form.cleaned_data['firstname'] lastname = form.cleaned_data['lastname'] email = form.cleaned_data['email'] subject = form.cleaned_data['subject'] botcheck = form.cleaned_data['botcheck'].lower() message = form.cleaned_data['message'] if botcheck == 'yes': try: fullemail = firstname + " " + lastname + " " + "<" + email + ">" send_mail(subject, message, fullemail, ['info@rowsandall.com']) return HttpResponseRedirect('/rowers/email/thankyou/') except: return HttpResponseRedirect('/rowers/email/') else: return HttpResponseRedirect('/rowers/email/') else: return HttpResponseRedirect('/rowers/email/') def checkworkoutuser(user,workout): try: r = Rower.objects.get(user=user) return (workout.user == r) except Rower.DoesNotExist: return(False) def add_workout_from_strokedata(user,importid,data,strokedata,source='c2'): workouttype = data['type'] if workouttype not in [x[0] for x in Workout.workouttypes]: workouttype = 'water' try: comments = data['comments'] except: comments = ' ' # comments = "Imported data \n %s" % comments # comments = "Imported data \n"+comments # str(comments) try: thetimezone = tz(data['timezone']) except: thetimezone = 'UTC' r = Rower.objects.get(user=user) try: rowdatetime = iso8601.parse_date(data['date_utc']) except KeyError: rowdatetime = iso8601.parse_date(data['start_date']) except ParseError: rowdatetime = iso8601.parse_date(data['date']) try: 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 and windowsize < len(velo): 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+'.gz',index_label='index', compression='gzip') 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 and windowsizer.tokenexpirydate): res = c2stuff.rower_c2_token_refresh(user) if res[0] != None: thetoken = res[0] else: thetoken = r.c2token 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 = "" successmessage = "" r = Rower.objects.get(user=request.user) w = Workout.objects.get(id=id) if (checkworkoutuser(request.user,w)): try: 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, }) except: successmessage = "" message = "Something went wrong (TCX export) "+str(sys.exc_info()[0]) with open("media/c2errors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") errorlog.write(timestr+errorstring+"\r\n") url = reverse(workout_export_view, kwargs = { 'id':str(w.id), 'message':message, }) 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) res = -1 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)): try: tcxfile = stravastuff.createstravaworkoutdata(w) with open(tcxfile,'rb') as f: try: 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.' except: with open("media/stravaerrors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") errorlog.write(timestr+errorstring+"\r\n") errorlog.write("views.py line 946\r\n") message = 'Error: '+errorstring 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), }) 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 try: url = "https://log.concept2.com/api/users/%s/results" % (c2userid) response = requests.post(url,headers=headers,data=json.dumps(data)) except: message = "Unexpected Error: "+str(sys.exc_info()[0]) with open("media/c2errors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") errorlog.write(timestr+errorstring+"\r\n") # 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 with open("media/c2errors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") errorlog.write(timestr+errorstring+"\r\n") else: s = response message = "Something went wrong in workout_c2_upload_view. C2 sync failed." with open("media/c2errors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") errorlog.write(timestr+errorstring+"\r\n") 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.reason 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()) scope = "user:read,results:write" 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) url += "&scope="+scope 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) if res[0] != None: 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" message = "" else: successmessage = "" message = "Something went wrong (refreshing tokens). Please reauthorize:" return imports_view(request,successmessage=successmessage,message=message) @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_twittercallback(request): return "dummy" @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 rower_process_testcallback(request): code = request.GET['code'] res = ownapistuff.get_token(code) access_token = res[0] expires_in = res[1] refresh_token = res[2] expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in) text = "Access Token:\n" text += access_token text += "\n\nRefresh Token:\n" text += refresh_token return HttpResponse(text) @login_required() def histo_all(request,theuser=0): promember=0 if theuser == 0: theuser = request.user.id if not request.user.is_anonymous(): r = Rower.objects.get(user=request.user) result = request.user.is_authenticated() and r.rowerplan=='pro' if result: promember=1 if not promember: return HttpResponseRedirect("/rowers/about/") # get all indoor rows of past 12 months ayearago = timezone.now()-datetime.timedelta(days=365) try: r2 = Rower.objects.get(user=theuser) allergworkouts = Workout.objects.filter(user=r2, workouttype__in=['rower','dynamic','slides'], startdatetime__gte=ayearago) except Rower.DoesNotExist: allergworkouts = [] r2=0 try: u = User.objects.get(id=theuser) except User.DoesNotExist: u = '' if allergworkouts: res = interactive_histoall(allergworkouts) script = res[0] div = res[1] else: script = '' div = '

No erg pieces uploaded yet.

' return render(request, 'histoall.html', {'interactiveplot':script, 'the_div':div, 'id':theuser, 'theuser':u, }) @login_required() def cum_flex(request,theuser=0, xparam='spm', yparam1='power', yparam2='None', startdate=timezone.now()-datetime.timedelta(days=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 = '

No erg pieces uploaded for this date range.

' js_resources = '' css_resources = '' return render(request, 'cum_flex.html', {'interactiveplot':script, 'the_div':div, 'js_res': js_resources, 'css_res':css_resources, 'id':theuser, 'theuser':u, 'startdate':startdate, 'enddate':enddate, 'form':form, 'deltaform':deltaform, 'xparam':xparam, 'yparam1':yparam1, 'yparam2':yparam2, 'promember':promember, }) @user_passes_test(promember,login_url="/",redirect_field_name=None) def workout_forcecurve_view(request,id=0,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 if not promember: return HttpResponseRedirect("/rowers/about/") if request.method == 'POST' and 'workstrokesonly' in request.POST: workstrokesonly = request.POST['workstrokesonly'] if workstrokesonly == 'True': workstrokesonly = True else: workstrokesonly = False script,div,js_resources,css_resources = interactive_forcecurve([row], workstrokesonly=workstrokesonly) return render(request, 'forcecurve_single.html', { 'the_script':script, 'the_div':div, 'js_res': js_resources, 'css_res':css_resources, 'id':id, 'mayedit':mayedit, 'workstrokesonly': not workstrokesonly, }) @login_required() def workout_histo_view(request,id=0): 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 if not promember: return HttpResponseRedirect("/rowers/about/") res = interactive_histoall([row]) script = res[0] div = res[1] return render(request, 'histo_single.html', {'interactiveplot':script, 'the_div':div, 'id':id, 'mayedit':mayedit, }) @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/promembership/") # get all indoor rows of in date range # process form if request.method == 'POST' and "daterange" in request.POST: form = DateRangeForm(request.POST) deltaform = DeltaDaysForm(request.POST) if form.is_valid(): startdate = form.cleaned_data['startdate'] enddate = form.cleaned_data['enddate'] if startdate > enddate: s = enddate enddate = startdate startdate = s elif request.method == 'POST' and "datedelta" in request.POST: deltaform = DeltaDaysForm(request.POST) if deltaform.is_valid(): deltadays = deltaform.cleaned_data['deltadays'] if deltadays != 0: enddate = timezone.now() startdate = enddate-datetime.timedelta(days=deltadays) if startdate > enddate: s = enddate enddate = startdate startdate = s form = DateRangeForm(initial={ 'startdate': startdate, 'enddate': enddate, }) else: form = DateRangeForm(initial={ 'startdate': startdate, 'enddate': enddate, }) deltaform = DeltaDaysForm() try: r2 = Rower.objects.get(user=theuser) allergworkouts = Workout.objects.filter(user=r2, workouttype__in=['rower','dynamic','slides'], startdatetime__gte=startdate, startdatetime__lte=enddate) except Rower.DoesNotExist: allergworkouts = [] r2=0 try: u = User.objects.get(id=theuser) except User.DoesNotExist: u = '' if allergworkouts: res = interactive_histoall(allergworkouts) script = res[0] div = res[1] else: script = '' div = '

No erg pieces uploaded for this date range.

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

No ranking pieces found.

' paulslope = 1 paulintercept = 1 p1 = [1,1,1,1] message = "" if request.method == 'POST' and "piece" in request.POST: form = PredictedPieceForm(request.POST) if form.is_valid(): value = form.cleaned_data['value'] pieceunit = form.cleaned_data['pieceunit'] if pieceunit == 'd': rankingdistances.append(value) else: rankingdurations.append(datetime.time(minute=value)) else: form = PredictedPieceForm() rankingdistances.sort() rankingdurations.sort() predictions = [] cpredictions = [] for rankingdistance in rankingdistances: # Paul's model p = paulslope*np.log10(rankingdistance)+paulintercept velo = 500./p t = rankingdistance/velo pwr = 2.8*(velo**3) a = {'distance':rankingdistance, 'duration':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='', startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), enddate=timezone.now()+datetime.timedelta(days=1)): 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' if request.method == 'POST': dateform = DateRangeForm(request.POST) if dateform.is_valid(): startdate = dateform.cleaned_data['startdate'] enddate = dateform.cleaned_data['enddate'] else: dateform = DateRangeForm(initial={ 'startdate':startdate, 'enddate':enddate, }) startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) enddate = enddate+datetime.timedelta(days=1) if startdatestring: startdate = iso8601.parse_date(startdatestring) if enddatestring: enddate = iso8601.parse_date(enddatestring) if enddate < startdate: s = enddate enddate = startdate startdate = s workouts = Workout.objects.filter(user=r, startdatetime__gte=startdate, startdatetime__lte=enddate).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,20) # 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) today = timezone.now() announcements = SiteAnnouncement.objects.filter( expires__gte=today ).order_by( "-created", "-id" ) return render(request, 'list_workouts.html', {'workouts': workouts, 'message': message, 'successmessage':successmessage, 'dateform':dateform, 'startdate':startdate, 'enddate':enddate, 'announcements':announcements[0:4], }) except Rower.DoesNotExist: return HttpResponse("User has no rower instance") @user_passes_test(promember,login_url="/",redirect_field_name=None) def workout_comparison_list(request,id=0,message='',successmessage='', startdatestring="",enddatestring="", startdate=timezone.now()-datetime.timedelta(days=365), enddate=timezone.now()): try: r = Rower.objects.get(user=request.user) u = User.objects.get(id=r.user.id) if request.method == 'POST': dateform = DateRangeForm(request.POST) if dateform.is_valid(): startdate = dateform.cleaned_data['startdate'] enddate = dateform.cleaned_data['enddate'] else: dateform = DateRangeForm(initial={ 'startdate':startdate, 'enddate':enddate, }) if startdatestring: startdate = iso8601.parse_date(startdatestring) if enddatestring: enddate = iso8601.parse_date(enddatestring) startdate = datetime.datetime.combine(startdate,datetime.time()) enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59)) enddate = enddate+datetime.timedelta(days=1) if enddate < startdate: s = enddate enddate = startdate startdate = s workouts = Workout.objects.filter(user=r, startdatetime__gte=startdate, startdatetime__lte=enddate).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, 'dateform':dateform, 'startdate':startdate, 'enddate':enddate, }) except Rower.DoesNotExist: return HttpResponse("User 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 HttpResponseNotFound("Workout doesn't exist") @user_passes_test(promember,login_url="/",redirect_field_name=None) 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,gzip=True) dataprep.update_strokedata(id,row.df) url = "/rowers/workout/"+str(id)+"/advanced" return HttpResponseRedirect(url) @user_passes_test(promember,login_url="/",redirect_field_name=None) 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,gzip=True) dataprep.update_strokedata(id,row.df) url = "/rowers/workout/"+str(id)+"/advanced" return HttpResponseRedirect(url) @user_passes_test(promember,login_url="/",redirect_field_name=None) 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="/",redirect_field_name=None) 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,gzip=True) # 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,gzip=True) 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="/",redirect_field_name=None) 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 if not latitude.std(): hascoordinates = 0 try: bearing = rowdata.df.ix[:,'bearing'].values except KeyError: rowdata.add_bearing() rowdata.write_csv(f1,gzip=True) 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,gzip=True) 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="/",redirect_field_name=None) 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,gzip=True) 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="/",redirect_field_name=None) 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,gzip=True) try: bearing = rowdata.df['bearing'] except KeyError: rowdata.add_bearing() rowdata.write_csv(f1,gzip=True) try: vwind = rowdata.df['vwind'] except KeyError: rowdata.add_wind(0,0) rowdata.write_csv(f1,gzip=True) # 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="/",redirect_field_name=None) @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,*args,**kwargs): try: id = kwargs['id'] except KeyError: return HttpResponse("Invalid workout number") if 'promember' in kwargs: promember = kwargs['promember'] else: promember = 0 try: favoritenr = int(request.GET['favoritechart']) except: favoritenr = 0 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 workouttype = 'ote' if row.workouttype == 'water': workouttype = 'otw' favorites = FavoriteChart.objects.filter(user=r, workouttype__in=[workouttype,'both']).order_by("id") maxfav = len(favorites)-1 # check if favoritenr is not out of range if favorites: try: t = favorites[favoritenr].xparam except IndexError: favoritenr=0 if 'xparam' in kwargs: xparam = kwargs['xparam'] else: if favorites: xparam = favorites[favoritenr].xparam else: xparam = 'distance' if 'yparam1' in kwargs: yparam1 = kwargs['yparam1'] else: if favorites: yparam1 = favorites[favoritenr].yparam1 else: yparam1 = 'pace' if 'yparam2' in kwargs: yparam2 = kwargs['yparam2'] if yparam2 == '': yparam2 = 'None' else: if favorites: yparam2 = favorites[favoritenr].yparam2 if yparam2 == '': yparam2 = 'None' else: yparam2 = 'hr' if 'plottype' in kwargs: plottype = kwargs['plottype'] else: if favorites: plottype = favorites[favoritenr].plottype else: plottype = 'line' if 'workstrokesonly' in kwargs: workstrokesonly = kwargs['workstrokesonly'] else: if favorites: workstrokesonly = not favorites[favoritenr].reststrokes else: workstrokesonly = False if request.method == 'POST' and 'savefavorite' in request.POST: workstrokesonly = request.POST['workstrokesonlysave'] reststrokes = not workstrokesonly f = FavoriteChart(user=r,xparam=xparam, yparam1=yparam1,yparam2=yparam2, plottype=plottype,workouttype=workouttype, reststrokes=reststrokes) f.save() if request.method == 'POST' and 'workstrokesonly' in request.POST: workstrokesonly = request.POST['workstrokesonly'] if workstrokesonly == 'True': workstrokesonly = True else: workstrokesonly = False # create interactive plot try: script,div,js_resources,css_resources = interactive_flex_chart2(id,xparam=xparam,yparam1=yparam1, yparam2=yparam2, promember=promember,plottype=plottype, workstrokesonly=workstrokesonly) except ValueError: script,div = interactive_flex_chart2(id,xparam=xparam,yparam1=yparam1, yparam2=yparam2, promember=promember,plottype=plottype, workstrokesonly=workstrokesonly) js_resources = "" css_resources = "" # script = res[0] # div = res[1] # js_resources = res[2] # css_resources = res[3] if row.workouttype == 'water': return render(request, 'flexchart3otw.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, 'favoritenr':favoritenr, 'maxfav':maxfav, }) else: 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, 'favoritenr':favoritenr, 'maxfav':maxfav, }) def testbokeh(request): TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' x = np.array(range(51))/10. y = x**2. z = (2*(x-2.5))**2 data = dict( x = x, y = y, z = z, ) df = pd.DataFrame(data) filtered_df = df source = ColumnDataSource( df ) source2 = ColumnDataSource( filtered_df ) plot = Figure(tools=TOOLS) plot.circle('x','y',source=source2) plot.xaxis.axis_label = "X" plot.yaxis.axis_label = "Y" plot.x_range = Range1d(-1,6) plot.y_range = Range1d(-5,30) callback = CustomJS(args = dict(source=source,source2=source2), code=""" var data = source.data var data2 = source2.data var x1 = data['x'] var y1 = data['y'] var z1 = data['z'] var mina = mina.value var maxa = maxa.value var minz = minz.value var maxz = maxz.value data2['x'] = [] data2['y'] = [] data2['z'] = [] for (i=0; i=mina && x1[i]<=maxa && z1[i]<=maxz && z1[i]>=minz) { data2['x'].push(x1[i]) data2['y'].push(y1[i]) data2['z'].push(z1[i]) } } source2.trigger('change'); """) s1 = Slider(start=0.0, end=5,value=0.0, step=.1,title="Min X Value",callback=callback) callback.args["mina"] = s1 s2 = Slider(start=0.0, end=5,value=5.0, step=.1,title="Max X Value",callback=callback) callback.args["maxa"] = s2 s3 = Slider(start=0.0, end=25,value=0.0, step=.1,title="Min Z Value",callback=callback) callback.args["minz"] = s3 s4 = Slider(start=0.0, end=25,value=25.0, step=.1,title="Max Z Value",callback=callback) callback.args["maxz"] = s4 hover = plot.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ ('X value','@x'), ('Y value','@y'), ('Z value','@z'), ]) hover.mode = 'mouse' layout = layoutrow([layoutcolumn([s1,s2,s3,s4]),plot]) # widgetbox(s) script, div = components(layout) js_resources = INLINE.render_js() css_resources = INLINE.render_css() return render(request, 'test.html', {'the_script': script, 'the_div': div, 'js_res': js_resources, 'css_res':css_resources, }) #@user_passes_test(promember,login_url="/",redirect_field_name=None) 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'] try: boattype = request.POST['boattype'] except KeyError: boattype = Workout.objects.get(id=id).boattype 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.boattype = boattype 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,gzip=True) dataprep.update_strokedata(id,r.df) 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) rowdata = rdata(f1) hascoordinates = 1 if rowdata != 0: try: latitude = rowdata.df[' latitude'] except KeyError,AttributeError: hascoordinates = 0 else: hascoordinates = 0 if not latitude.std(): 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, }) 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, }) except Workout.DoesNotExist: message = "workout doesn't exist" url = reverse(workouts_view, kwargs = { 'message': str(message) }) return HttpResponseRedirect(url) @user_passes_test(promember,login_url="/",redirect_field_name=None) 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="/",redirect_field_name=None) 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="/",redirect_field_name=None) 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) 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/") 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): try: thetoken = c2_open(request.user) except C2NoTokenError: return HttpResponseRedirect("/rowers/me/c2authorize/") res = c2stuff.get_c2_workout(request.user,c2id) if (res.status_code == 200): data = res.json()['data'] if data['stroke_data']: res2 = c2stuff.get_c2_workout_strokes(request.user,c2id) else: message = "This workout does not have any stroke data associated with it" url = reverse(workout_c2import_view, kwargs={ 'message':message, }) return HttpResponseRedirect(url) 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'] message = json.loads(res2.text)['message'] url = reverse(workout_c2import_view, kwargs={ 'message':message, }) return HttpResponseRedirect(url) 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 len(fileformat)==3 and fileformat[0]=='zip': f_to_be_deleted = f2 with zipfile.ZipFile(f2) as z: f2 = z.extract(z.namelist()[0],path='media/') fileformat = fileformat[2] os.remove(f_to_be_deleted) if fileformat == 'c2log': message = "This C2 logbook summary does not contain stroke data. Please download the Export Stroke Data file from the workout details on the C2 logbook." url = reverse(workout_upload_view, args=[str(message)]) response = HttpResponseRedirect(url) return response if fileformat == 'rowprolog': message = "This RowPro logbook summary does not contain stroke data. Please use the Stroke Data CSV file for the individual workout in your log." url = reverse(workout_upload_view, args=[str(message)]) response = HttpResponseRedirect(url) return response 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 RowPerfect if (fileformat == 'rowperfect3'): row = RowPerfectParser(f2) # handle TCX no HR if (fileformat == 'tcxnohr'): row = TCXParserNoHR(f2) # handle ErgData if (fileformat == 'ergdata'): row = ErgDataParser(f2) # handle BoatCoach if (fileformat == 'boatcoach'): row = BoatCoachParser(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) try: summary = row.allstats() except: pass # 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,gzip=True) #os.remove(f2) try: os.remove(f_to_be_deleted) except: os.remove(f_to_be_deleted+'.gz') # 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 and windowsize