diff --git a/.gitignore b/.gitignore index 1151be7e..332c344d 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ conftest.py # temporary test files /rowers/tests/testdata/temp +/rowers/tests/testdata/testdata.csv.gz rowers/tests/testdata/testdata.csv.gz /rowers/tests/testdata/testdata.tcx diff --git a/cvkbrno/models.py b/cvkbrno/models.py index d8b0900f..6fe437a1 100644 --- a/cvkbrno/models.py +++ b/cvkbrno/models.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- Coding: utf-8 -*- from __future__ import unicode_literals from django.db import models @@ -18,86 +18,86 @@ class BoatCategory(models.Model): club = models.CharField(_("Club"),max_length=30) class Meta: - verbose_name = _("boat category") - verbose_name_plural = _("boat categories") - ordering = ['name'] + verbose_name = _("boat category") + verbose_name_plural = _("boat categories") + ordering = ['name'] def __str__(self): - str = self.name + str = self.name - return str + return str def __unicode__(self): - str = self.name + str = self.name - return str + return str class Member(models.Model): statuses = ( - ("coach", _("coach")), - ("member", _("member")), - ("administrator", _("administrator")), - ) + ("coach", _("coach")), + ("member", _("member")), + ("administrator", _("administrator")), + ) class Meta: - verbose_name = _("member") - verbose_name_plural = _("members") - ordering = ['user'] + verbose_name = _("member") + verbose_name_plural = _("members") + ordering = ['user'] - user = models.OneToOneField(User) + user = models.OneToOneField(User,on_delete=models.CASCADE) contributions = models.BooleanField(default=True) status = models.CharField(default="member", - choices=statuses, - max_length=30) + choices=statuses, + max_length=30) categories = models.ManyToManyField(BoatCategory, - verbose_name=_("Boat Categories")) + verbose_name=_("Boat Categories")) club = models.CharField(_("Club"),max_length=30) hoursworked = models.FloatField(_("Hours Worked")) def __str__(self): - str = self.user.first_name+' '+self.user.last_name - return str + str = self.user.first_name+' '+self.user.last_name + return str def __unicode__(self): - str = self.user.first_name+' '+self.user.last_name - return str + str = self.user.first_name+' '+self.user.last_name + return str class Boat(models.Model): class Meta: - verbose_name = _("boat") - verbose_name_plural = _("boats") - ordering = ['boatcode'] + verbose_name = _("boat") + verbose_name_plural = _("boats") + ordering = ['boatcode'] boatname = models.CharField(_("Boat Name"),max_length=30) boatcode = models.CharField(_("Boat Code"),max_length=10) categories = models.ManyToManyField(BoatCategory) nrseats = models.IntegerField(_("Nr of Seats")) statuses = ( - ("water",_("water")), - ("hangar",_("hangar")), - ("damaged",_("damaged")), - ("races",_("races")), - ) + ("water",_("water")), + ("hangar",_("hangar")), + ("damaged",_("damaged")), + ("races",_("races")), + ) status = models.CharField(default="hangar", - choices=statuses, - max_length=30) + choices=statuses, + max_length=30) comment = models.CharField(_("Comment"),blank=True,max_length=100) def __str__(self): - str = self.boatcode+' '+self.boatname + str = self.boatcode+' '+self.boatname - return str + return str def __unicode__(self): - str = self.boatcode+' '+self.boatname + str = self.boatcode+' '+self.boatname - return str + return str class MemberWork(models.Model): class Meta: - verbose_name = _("member work") - verbose_name_plural = _("member work") + verbose_name = _("member work") + verbose_name_plural = _("member work") date = models.DateField(_("Date")) hours = models.FloatField(_("Hours")) @@ -105,16 +105,16 @@ class MemberWork(models.Model): comment = models.CharField(_("Comment"),blank=True,max_length=100) worker = models.ManyToManyField(Member,_("Worker")) statuses = ( - ("planned",_("planned")), - ("executed",_("executed")) - ) + ("planned",_("planned")), + ("executed",_("executed")) + ) status = models.CharField(default="planned", - choices=statuses, - max_length=30) + choices=statuses, + max_length=30) class Races(models.Model): class Meta: - verbose_name = _("race") - verbose_name_plural = _("races") + verbose_name = _("race") + verbose_name_plural = _("races") name = models.CharField(max_length = 30) @@ -124,20 +124,20 @@ class Races(models.Model): transportboats = models.ManyToManyField(Boat) def __str__(self): - str = self.name - str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S') - return str + str = self.name + str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S') + return str def __unicode__(self): - str = self.name - str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S') - return str + str = self.name + str = str+' '+self.startdatetime.strftime('%Y-%m-%d %H:%M:%S') + return str class Outing(models.Model): class Meta: - verbose_name = _("outing") - verbose_name_plural = _("outings") + verbose_name = _("outing") + verbose_name_plural = _("outings") starttime = models.DateTimeField(verbose_name = _("Start Time"),default=timezone.now) @@ -145,27 +145,27 @@ class Outing(models.Model): distance = models.FloatField(_("Distance (km)"),default=12) comment = models.CharField(_("Comment"),blank=True,max_length=100) statuses = ( - ("reservation",_("reservation")), - ("active", _("active")), - ("completed", _("completed")), - ("race", _("race")), - ) - boat = models.ForeignKey(Boat) - rower = models.ForeignKey(Member) + ("reservation",_("reservation")), + ("active", _("active")), + ("completed", _("completed")), + ("race", _("race")), + ) + boat = models.ForeignKey(Boat,on_delete=models.CASCADE) + rower = models.ForeignKey(Member,on_delete=models.CASCADE) race = models.ManyToManyField(Races,blank=True) otherrowers = models.ManyToManyField(Member,related_name="otherrowers") status = models.CharField(_("Status"),default="active", - choices=statuses, - max_length=30) + choices=statuses, + max_length=30) def __str__(self): - str = self.boat.boatcode - str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S') - return str + str = self.boat.boatcode + str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S') + return str def __unicode__(self): - str = self.boat.boatcode - str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S') - return str + str = self.boat.boatcode + str = str+' '+self.starttime.strftime('%Y-%m-%d %H:%M:%S') + return str diff --git a/cvkbrno/tasks.py b/cvkbrno/tasks.py index 751a2f12..c507f6e8 100644 --- a/cvkbrno/tasks.py +++ b/cvkbrno/tasks.py @@ -1,4 +1,4 @@ -from celery import Celery,app +from .celery import Celery,app import os import time import gc diff --git a/rowers/__init__.py b/rowers/__init__.py index 03d28f5e..4a44fb0d 100644 --- a/rowers/__init__.py +++ b/rowers/__init__.py @@ -1,5 +1,5 @@ -from __future__ import absolute_import - -from .tasks import app as celery_app +from __future__ import absolute_import, unicode_literals +from rowers.celery import app as celery_app +__all__ = ('celery_app',) diff --git a/rowers/c2stuff.py b/rowers/c2stuff.py index 88e7d46e..d69960f1 100644 --- a/rowers/c2stuff.py +++ b/rowers/c2stuff.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # The interactions with the Concept2 logbook API # All C2 related functions should be defined here # (There is still some stuff defined directly in views.py. Need to @@ -6,7 +7,7 @@ from rowers.imports import * import datetime from requests import Request, Session -import mytypes +import rowers.mytypes as mytypes from rowers.mytypes import otwtypes from iso8601 import ParseError @@ -19,7 +20,7 @@ import django_rq queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') -from utils import myqueue +from rowers.utils import myqueue oauth_data = { 'client_id': C2_CLIENT_ID, @@ -41,19 +42,19 @@ oauth_data = { def c2_open(user): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): - s = "Token doesn't exist. Need to authorize" - raise NoTokenError("User has no token") + s = "Token doesn't exist. Need to authorize" + raise NoTokenError("User has no token") else: - if (timezone.now()>r.tokenexpirydate): - res = rower_c2_token_refresh(user) + if (timezone.now()>r.tokenexpirydate): + res = rower_c2_token_refresh(user) if res == None: raise NoTokenError("User has no token") if res[0] != None: thetoken = res[0] else: raise NoTokenError("User has no token") - else: - thetoken = r.c2token + else: + thetoken = r.c2token return thetoken @@ -61,11 +62,11 @@ def add_stroke_data(user,c2id,workoutid,startdatetime,csvfilename, workouttype='rower'): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): - return custom_exception_handler(401,s) - s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" elif (timezone.now()>r.tokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: starttimeunix = arrow.get(startdatetime).timestamp @@ -179,9 +180,9 @@ def makeseconds(t): # convert our weight class code to Concept2 weight class code def c2wc(weightclass): if (weightclass=="lwt"): - res = "L" + res = "L" else: - res = "H" + res = "H" return res @@ -343,17 +344,17 @@ def createc2workoutdata_as_splits(w): hr = df[' HRCur (bpm)'].astype(int) split_data = [] for i in range(len(t)): - thisrecord = {"time":t[i],"distance":d[i],"stroke_rate":spm[i], - "heart_rate":{ - "average:":hr[i] - } - } - split_data.append(thisrecord) + thisrecord = {"time":t[i],"distance":d[i],"stroke_rate":spm[i], + "heart_rate":{ + "average:":hr[i] + } + } + split_data.append(thisrecord) try: - durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f") + durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f") except ValueError: - durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S") + durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S") try: newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com' @@ -365,19 +366,19 @@ def createc2workoutdata_as_splits(w): wtype = 'water' data = { - "type": wtype, - "date": w.startdatetime.isoformat(), - "distance": int(w.distance), - "time": int(10*makeseconds(durationstr)), - "timezone": w.timezone, - "weight_class": c2wc(w.weightcategory), - "comments": newnotes, - "heart_rate": { - "average": averagehr, - "max": maxhr, - }, - "splits": split_data, - } + "type": wtype, + "date": w.startdatetime.isoformat(), + "distance": int(w.distance), + "time": int(10*makeseconds(durationstr)), + "timezone": w.timezone, + "weight_class": c2wc(w.weightcategory), + "comments": newnotes, + "heart_rate": { + "average": averagehr, + "max": maxhr, + }, + "splits": split_data, + } return data @@ -418,13 +419,13 @@ def createc2workoutdata(w): hr = 0*d stroke_data = [] for i in range(len(t)): - thisrecord = {"t":t[i],"d":d[i],"p":p[i],"spm":spm[i],"hr":hr[i]} - stroke_data.append(thisrecord) + thisrecord = {"t":t[i],"d":d[i],"p":p[i],"spm":spm[i],"hr":hr[i]} + stroke_data.append(thisrecord) try: - durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f") + durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S.%f") except ValueError: - durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S") + durationstr = datetime.datetime.strptime(str(w.duration),"%H:%M:%S") workouttype = w.workouttype if workouttype in otwtypes: @@ -436,19 +437,19 @@ def createc2workoutdata(w): startdate = datetime.datetime.combine(w.date,datetime.time()) data = { - "type": mytypes.c2mapping[workouttype], - "date": w.startdatetime.isoformat(), - "timezone": w.timezone, - "distance": int(w.distance), - "time": int(10*makeseconds(durationstr)), - "weight_class": c2wc(w.weightcategory), - "comments": w.notes, - "heart_rate": { - "average": averagehr, - "max": maxhr, - }, - "stroke_data": stroke_data, - } + "type": mytypes.c2mapping[workouttype], + "date": w.startdatetime.isoformat(), + "timezone": w.timezone, + "distance": int(w.distance), + "time": int(10*makeseconds(durationstr)), + "weight_class": c2wc(w.weightcategory), + "comments": w.notes, + "heart_rate": { + "average": averagehr, + "max": maxhr, + }, + "stroke_data": stroke_data, + } return data @@ -458,10 +459,10 @@ def do_refresh_token(refreshtoken): scope = "results:write,user:read" client_auth = requests.auth.HTTPBasicAuth(C2_CLIENT_ID, C2_CLIENT_SECRET) post_data = {"grant_type": "refresh_token", - "client_secret": C2_CLIENT_SECRET, - "client_id":C2_CLIENT_ID, - "refresh_token": refreshtoken, - } + "client_secret": C2_CLIENT_SECRET, + "client_id":C2_CLIENT_ID, + "refresh_token": refreshtoken, + } headers = {'user-agent': 'sanderroosendaal'} url = "https://log.concept2.com/oauth/access_token" s = Session() @@ -498,9 +499,9 @@ def get_token(code): post_data = {"grant_type": "authorization_code", "code": code, "redirect_uri": C2_REDIRECT_URI, - "client_secret": C2_CLIENT_SECRET, - "client_id":C2_CLIENT_ID, - } + "client_secret": C2_CLIENT_SECRET, + "client_id":C2_CLIENT_ID, + } headers = {'user-agent': 'sanderroosendaal'} url = "https://log.concept2.com/oauth/access_token" s = Session() @@ -554,19 +555,19 @@ def make_authorization_url(request): def get_workout(user,c2id): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) ,0 + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) ,0 elif (timezone.now()>r.tokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s),0 + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s),0 else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.c2token) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://log.concept2.com/api/users/me/results/"+str(c2id) - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.c2token) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://log.concept2.com/api/users/me/results/"+str(c2id) + s = requests.get(url,headers=headers) data = s.json()['data'] @@ -583,9 +584,9 @@ def get_workout(user,c2id): # Check if workout has stroke data, and get the stroke data if data['stroke_data']: - res2 = get_c2_workout_strokes(user,c2id) - if res2.status_code == 200: - strokedata = pd.DataFrame.from_dict(res2.json()['data']) + res2 = get_c2_workout_strokes(user,c2id) + if res2.status_code == 200: + strokedata = pd.DataFrame.from_dict(res2.json()['data']) else: strokedata = pd.DataFrame() else: @@ -597,19 +598,19 @@ def get_workout(user,c2id): def get_c2_workout_strokes(user,c2id): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): - return custom_exception_handler(401,s) - s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" elif (timezone.now()>r.tokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.c2token) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes" - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.c2token) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://log.concept2.com/api/users/me/results/"+str(c2id)+"/strokes" + s = requests.get(url,headers=headers) return s @@ -618,21 +619,21 @@ def get_c2_workout_strokes(user,c2id): def get_c2_workout_list(user,page=1): r = Rower.objects.get(user=user) if (r.c2token == '') or (r.c2token is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) elif (timezone.now()>r.tokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.c2token) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://log.concept2.com/api/users/me/results" + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.c2token) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://log.concept2.com/api/users/me/results" url += "?page={page}".format(page=page) - s = requests.get(url,headers=headers) + s = requests.get(url,headers=headers) return s @@ -642,8 +643,8 @@ def get_c2_workout_list(user,page=1): def get_username(access_token): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} import urllib url = "https://log.concept2.com/api/users/me" response = requests.get(url,headers=headers) @@ -664,8 +665,8 @@ def get_username(access_token): def get_userid(access_token): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} import urllib url = "https://log.concept2.com/api/users/me" response = requests.get(url,headers=headers) @@ -706,40 +707,40 @@ def workout_c2_upload(user,w): # ready to upload. Hurray if (checkworkoutuser(user,w)): - c2userid = get_userid(r.c2token) + c2userid = get_userid(r.c2token) if not c2userid: raise NoTokenError - data = createc2workoutdata(w) + data = createc2workoutdata(w) if data == 0: return "Error: No data file. Contact info@rowsandall.com if the problem persists",0 - authorizationstring = str('Bearer ' + r.c2token) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - import urllib - url = "https://log.concept2.com/api/users/%s/results" % (c2userid) - response = requests.post(url,headers=headers,data=json.dumps(data)) + authorizationstring = str('Bearer ' + r.c2token) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + import urllib + url = "https://log.concept2.com/api/users/%s/results" % (c2userid) + response = requests.post(url,headers=headers,data=json.dumps(data)) if (response.status_code == 409 ): - message = "Concept2 Duplicate error" - w.uploadedtoc2 = -1 + message = "Concept2 Duplicate error" + w.uploadedtoc2 = -1 c2id = -1 - w.save() + w.save() elif (response.status_code == 201 or response.status_code == 200): try: -# s= json.loads(response.text) +# s= json.loads(response.text) s = response.json() - c2id = s['data']['id'] - w.uploadedtoc2 = c2id - w.save() + c2id = s['data']['id'] + w.uploadedtoc2 = c2id + w.save() message = "Upload to Concept2 was successful" except: message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text c2id = 0 - else: + else: message = "Something went wrong in workout_c2_upload_view. Response code 200/201 but C2 sync failed: "+response.text c2id = 0 @@ -776,41 +777,41 @@ def add_workout_from_data(user,importid,data,strokedata, workouttype = 'rower' if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' + workouttype = 'other' try: - comments = data['comments'] + comments = data['comments'] except: - comments = ' ' + comments = ' ' try: - thetimezone = tz(data['timezone']) + thetimezone = tz(data['timezone']) except: - thetimezone = 'UTC' + thetimezone = 'UTC' r = Rower.objects.get(user=user) try: - rowdatetime = iso8601.parse_date(data['date_utc']) + rowdatetime = iso8601.parse_date(data['date_utc']) except KeyError: - rowdatetime = iso8601.parse_date(data['start_date']) + rowdatetime = iso8601.parse_date(data['start_date']) except ParseError: - rowdatetime = iso8601.parse_date(data['date']) + rowdatetime = iso8601.parse_date(data['date']) - + try: c2intervaltype = data['workout_type'] - + except KeyError: - c2intervaltype = '' - + c2intervaltype = '' + try: - title = data['name'] + title = data['name'] except KeyError: - title = "" - try: - t = data['comments'].split('\n', 1)[0] - title += t[:20] - except: - title = 'Imported' + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:20] + except: + title = 'Imported' starttimeunix = arrow.get(rowdatetime).timestamp @@ -825,17 +826,17 @@ def add_workout_from_data(user,importid,data,strokedata, nr_rows = len(unixtime) try: - latcoord = strokedata.loc[:,'lat'] - loncoord = strokedata.loc[:,'lon'] + latcoord = strokedata.loc[:,'lat'] + loncoord = strokedata.loc[:,'lon'] except: - latcoord = np.zeros(nr_rows) - loncoord = np.zeros(nr_rows) + latcoord = np.zeros(nr_rows) + loncoord = np.zeros(nr_rows) try: - strokelength = strokedata.loc[:,'strokelength'] + strokelength = strokedata.loc[:,'strokelength'] except: - strokelength = np.zeros(nr_rows) + strokelength = np.zeros(nr_rows) dist2 = 0.1*strokedata.loc[:,'d'] @@ -862,27 +863,27 @@ def add_workout_from_data(user,importid,data,strokedata, # 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 - }) + ' 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 + }) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") diff --git a/rowers/courses.py b/rowers/courses.py index 606e9471..f89dabb2 100644 --- a/rowers/courses.py +++ b/rowers/courses.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # All the Courses related methods # Python @@ -28,7 +29,7 @@ import pandas as pd import numpy as np from timezonefinder import TimezoneFinder -import dataprep +import rowers.dataprep as dataprep from rowers.utils import geo_distance ns = {'opengis': 'http://www.opengis.net/kml/2.2'} @@ -47,7 +48,7 @@ from rowers.models import ( polygon_to_path,coordinate_in_path ) -from utils import geo_distance + from rowers.courseutils import coursetime_paths, coursetime_first,time_in_path diff --git a/rowers/courseutils.py b/rowers/courseutils.py index 2ce31fb3..37686b27 100644 --- a/rowers/courseutils.py +++ b/rowers/courseutils.py @@ -5,10 +5,10 @@ def coordinate_in_path(latitude,longitude, p): class InvalidTrajectoryError(Exception): def __init__(self,value): - self.value=value + self.value=value def __str__(self): - return repr(self.value) + return repr(self.value) def time_in_path(df,p,maxmin='max',getall=False): diff --git a/rowers/dataprep.py b/rowers/dataprep.py index 066a4579..31b18475 100644 --- a/rowers/dataprep.py +++ b/rowers/dataprep.py @@ -1,5 +1,6 @@ # All the data preparation, data cleaning and data mangling should # be defined here +from __future__ import unicode_literals, absolute_import from rowers.models import Workout, StrokeData,Team import pytz @@ -55,7 +56,7 @@ import pandas as pd import numpy as np import itertools import math -from tasks import ( +from rowers.tasks import ( handle_sendemail_unrecognized, handle_sendemail_breakthrough, handle_sendemail_hard, handle_updatecp,handle_updateergcp, handle_calctrimp, @@ -65,9 +66,9 @@ from django.conf import settings from sqlalchemy import create_engine import sqlalchemy as sa import sys -import utils -import datautils -from utils import lbstoN,myqueue,is_ranking_piece,wavg +import rowers.utils as utils +import rowers.datautils as datautils +from rowers.utils import lbstoN,myqueue,is_ranking_piece,wavg from timezonefinder import TimezoneFinder @@ -638,7 +639,7 @@ def deletecpdata_sql(rower_id,table='cpdata'): try: result = conn.execute(query) except: - print "Database locked" + print("Database locked") conn.close() engine.dispose() @@ -855,7 +856,7 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower', return (id, message) -from utils import totaltime_sec_to_string +from rowers.utils import totaltime_sec_to_string # Processes painsled CSV file to database def save_workout_database(f2, r, dosmooth=True, workouttype='rower', @@ -1564,7 +1565,7 @@ def compare_data(id): res = conn.execute(query) l2 = res.fetchall()[0][0] except: - print "Database Locked" + print("Database Locked") conn.close() engine.dispose() lfile = l1 @@ -1583,13 +1584,13 @@ def repair_data(verbose=False): test, ldb, lfile = compare_data(w.id) if not test: if verbose: - print w.id, lfile, ldb + print(w.id, lfile, ldb) try: rowdata = rdata(w.csvfilename) if rowdata and len(rowdata.df): update_strokedata(w.id, rowdata.df) - except IOError, AttributeError: + except (IOError, AttributeError): pass if lfile == 0: @@ -1618,10 +1619,10 @@ def repair_data(verbose=False): def rdata(file, rower=rrower()): try: res = rrdata(csvfile=file, rower=rower) - except IOError, IndexError: + except (IOError, IndexError): try: res = rrdata(csvfile=file + '.gz', rower=rower) - except IOError, IndexError: + except (IOError, IndexError): res = rrdata() except: res = rrdata() @@ -1640,7 +1641,7 @@ def delete_strokedata(id): try: result = conn.execute(query) except: - print "Database Locked" + print("Database Locked") conn.close() engine.dispose() @@ -1792,7 +1793,7 @@ def prepmultipledata(ids, verbose=False): for id in res: rowdata, row = getrowdata(id=id) if verbose: - print id + print(id) if rowdata and len(rowdata.df): data = dataprep(rowdata.df, id=id, bands=True, barchart=True, otwpower=True) @@ -2029,7 +2030,7 @@ def fix_newtons(id=0, limit=3000): peakforce = rowdata['peakforce'] if peakforce.mean() > limit: w = Workout.objects.get(id=id) - print "fixing ", id + print("fixing ", id) rowdata = rdata(w.csvfilename) if rowdata and len(rowdata.df): update_strokedata(w.id, rowdata.df) diff --git a/rowers/dataprepnodjango.py b/rowers/dataprepnodjango.py index a6e23bf0..6e742590 100644 --- a/rowers/dataprepnodjango.py +++ b/rowers/dataprepnodjango.py @@ -18,7 +18,7 @@ import sqlalchemy as sa from rowsandall_app.settings import DATABASES from rowsandall_app.settings_dev import DATABASES as DEV_DATABASES -from utils import lbstoN +from rowers.utils import lbstoN try: @@ -83,33 +83,33 @@ import datetime def niceformat(values): out = [] for v in values: - formattedv = strfdelta(v) - out.append(formattedv) - + formattedv = strfdelta(v) + out.append(formattedv) + return out def strfdelta(tdelta): try: - minutes,seconds = divmod(tdelta.seconds,60) - tenths = int(tdelta.microseconds/1e5) + minutes,seconds = divmod(tdelta.seconds,60) + tenths = int(tdelta.microseconds/1e5) except AttributeError: - minutes,seconds = divmod(tdelta.view(np.int64),60e9) - seconds,rest = divmod(seconds,1e9) - tenths = int(rest/1e8) + minutes,seconds = divmod(tdelta.view(np.int64),60e9) + seconds,rest = divmod(seconds,1e9) + tenths = int(rest/1e8) res = "{minutes:0>2}:{seconds:0>2}.{tenths:0>1}".format( - minutes=minutes, - seconds=seconds, - tenths=tenths, - ) + minutes=minutes, + seconds=seconds, + tenths=tenths, + ) return res def nicepaceformat(values): out = [] for v in values: - formattedv = strfdelta(v) - out.append(formattedv) - + formattedv = strfdelta(v) + out.append(formattedv) + return out @@ -124,16 +124,16 @@ def timedeltaconv(x): def rdata(file,rower=rrower()): try: - res = rrdata(file,rower=rower) + res = rrdata(file,rower=rower) except IOError: try: res = rrdata(file+'.gz',rower=rower) except IOError: - res = 0 + res = 0 return res -from utils import totaltime_sec_to_string +from rowers.utils import totaltime_sec_to_string # Creates C2 stroke data @@ -175,22 +175,22 @@ def create_c2_stroke_data_db( df = pd.DataFrame({ 'TimeStamp (sec)': unixtime, - ' Horizontal (meters)': d, + ' Horizontal (meters)': d, ' Cadence (stokes/min)': spm, ' Stroke500mPace (sec/500m)':pace, ' ElapsedTime (sec)':elapsed, ' Power (watts)':power, - ' HRCur (bpm)':np.zeros(nr_strokes), - ' longitude':np.zeros(nr_strokes), - ' latitude':np.zeros(nr_strokes), - ' DragFactor':np.zeros(nr_strokes), - ' DriveLength (meters)':np.zeros(nr_strokes), - ' StrokeDistance (meters)':np.zeros(nr_strokes), - ' DriveTime (ms)':np.zeros(nr_strokes), - ' StrokeRecoveryTime (ms)':np.zeros(nr_strokes), - ' AverageDriveForce (lbs)':np.zeros(nr_strokes), - ' PeakDriveForce (lbs)':np.zeros(nr_strokes), - ' lapIdx':np.zeros(nr_strokes), + ' HRCur (bpm)':np.zeros(nr_strokes), + ' longitude':np.zeros(nr_strokes), + ' latitude':np.zeros(nr_strokes), + ' DragFactor':np.zeros(nr_strokes), + ' DriveLength (meters)':np.zeros(nr_strokes), + ' StrokeDistance (meters)':np.zeros(nr_strokes), + ' DriveTime (ms)':np.zeros(nr_strokes), + ' StrokeRecoveryTime (ms)':np.zeros(nr_strokes), + ' AverageDriveForce (lbs)':np.zeros(nr_strokes), + ' PeakDriveForce (lbs)':np.zeros(nr_strokes), + ' lapIdx':np.zeros(nr_strokes), 'cum_dist': d }) @@ -220,17 +220,17 @@ def add_c2_stroke_data_db(strokedata,workoutid,starttimeunix,csvfilename, nr_rows = len(unixtime) try: - latcoord = strokedata.ix[:,'lat'] - loncoord = strokedata.ix[:,'lon'] + latcoord = strokedata.ix[:,'lat'] + loncoord = strokedata.ix[:,'lon'] except: - latcoord = np.zeros(nr_rows) - loncoord = np.zeros(nr_rows) + latcoord = np.zeros(nr_rows) + loncoord = np.zeros(nr_rows) try: - strokelength = strokedata.ix[:,'strokelength'] + strokelength = strokedata.ix[:,'strokelength'] except: - strokelength = np.zeros(nr_rows) + strokelength = np.zeros(nr_rows) dist2 = 0.1*strokedata.ix[:,'d'] @@ -258,28 +258,28 @@ def add_c2_stroke_data_db(strokedata,workoutid,starttimeunix,csvfilename, # 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, + ' 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, 'cum_dist': dist2 - }) + }) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") @@ -312,8 +312,8 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', # make workout and put in database rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an,ftp=r.ftp, + hrut1=r.ut1,hrat=r.at, + hrtr=r.tr,hran=r.an,ftp=r.ftp, powerperc=powerperc,powerzones=r.powerzones) row = rdata(f2,rower=rr) @@ -329,7 +329,7 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', if row == 0: - return (0,'Error: CSV data file not found') + return (0,'Error: CSV data file not found') if dosmooth: # auto smoothing @@ -342,12 +342,12 @@ def save_workout_database(f2,r,dosmooth=True,workouttype='rower', else: windowsize = 1 if not 'originalvelo' in row.df: - row.df['originalvelo'] = velo + row.df['originalvelo'] = velo if windowsize > 3 and windowsize 3 and windowsize=4: try: - p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) + p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) except: - factor = fitfunc(p0,thesecs.mean())/theavpower.mean() - p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] + factor = fitfunc(p0,thesecs.mean())/theavpower.mean() + p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] else: - factor = fitfunc(p0,thesecs.mean())/theavpower.mean() - p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] + factor = fitfunc(p0,thesecs.mean())/theavpower.mean() + p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] p1 = [abs(p) for p in p1] diff --git a/rowers/forms.py b/rowers/forms.py index acabc5b4..5dd3d149 100644 --- a/rowers/forms.py +++ b/rowers/forms.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import from django import forms from django.contrib.admin.widgets import FilteredSelectMultiple from rowers.models import ( @@ -9,15 +10,16 @@ from rowers.rows import validate_file_extension,must_be_csv,validate_image_exten from django.contrib.auth.forms import UserCreationForm from django.contrib.auth.models import User from django.contrib.admin.widgets import AdminDateWidget -from django.forms.extras.widgets import SelectDateWidget +from django.forms.widgets import SelectDateWidget +#from django.forms.extras.widgets import SelectDateWidget from django.utils import timezone,translation from django.forms import ModelForm, Select -import dataprep -import mytypes +import rowers.dataprep as dataprep +import rowers.mytypes as mytypes import datetime from django.forms import formset_factory -from utils import landingpages -from metrics import axes +from rowers.utils import landingpages +from rowers.metrics import axes class FlexibleDecimalField(forms.DecimalField): @@ -84,7 +86,7 @@ for key, value in disqualificationreasons: class DisqualificationForm(forms.Form): reason = forms.ChoiceField(required=True, - choices=disqualificationreasons, + choices=disqualificationreasons, widget = forms.RadioSelect,) message = forms.CharField(required=True,widget=forms.Textarea) @@ -139,10 +141,10 @@ class CourseForm(forms.Form): class DocumentsForm(forms.Form): title = forms.CharField(required=False) file = forms.FileField(required=False, - validators=[validate_file_extension]) + validators=[validate_file_extension]) workouttype = forms.ChoiceField(required=True, - choices=Workout.workouttypes) + choices=Workout.workouttypes) boattype = forms.ChoiceField(required=True, choices=mytypes.boattypes, @@ -150,19 +152,19 @@ class DocumentsForm(forms.Form): notes = forms.CharField(required=False, - widget=forms.Textarea) + widget=forms.Textarea) offline = forms.BooleanField(initial=False,required=False, label='Process in Background') class Meta: - fields = ['title','file','workouttype','boattype','fileformat','offline'] + fields = ['title','file','workouttype','boattype','fileformat','offline'] def __init__(self, *args, **kwargs): from django.forms.widgets import HiddenInput super(DocumentsForm, self).__init__(*args, **kwargs) # self.fields['offline'].widget = HiddenInput() -from utils import ( +from rowers.utils import ( workflowleftpanel,workflowmiddlepanel, defaultleft,defaultmiddle ) @@ -267,14 +269,14 @@ class LandingPageForm(forms.Form): class UploadOptionsForm(forms.Form): plotchoices = ( - ('timeplot','Time Plot'), - ('distanceplot','Distance Plot'), - ('pieplot','Heart Rate Pie Chart'), - ) + ('timeplot','Time Plot'), + ('distanceplot','Distance Plot'), + ('pieplot','Heart Rate Pie Chart'), + ) make_plot = forms.BooleanField(initial=False,required=False) plottype = forms.ChoiceField(required=False, - choices=plotchoices, - initial='timeplot', + choices=plotchoices, + initial='timeplot', label='Plot Type') upload_to_C2 = forms.BooleanField(initial=False,required=False, label='Export to Concept2 logbook') @@ -303,7 +305,7 @@ class UploadOptionsForm(forms.Form): label='After Upload, go to') class Meta: - fields = ['make_plot','plottype','upload_toc2','makeprivate'] + fields = ['make_plot','plottype','upload_toc2','makeprivate'] def __init__(self, *args, **kwargs): self.request = kwargs.pop('request',None) @@ -332,18 +334,18 @@ class UploadOptionsForm(forms.Form): # a team member class TeamUploadOptionsForm(forms.Form): plotchoices = ( - ('timeplot','Time Plot'), - ('distanceplot','Distance Plot'), - ('pieplot','Pie Chart'), - ) + ('timeplot','Time Plot'), + ('distanceplot','Distance Plot'), + ('pieplot','Pie Chart'), + ) make_plot = forms.BooleanField(initial=False,required=False) plottype = forms.ChoiceField(required=False, - choices=plotchoices, - initial='timeplot', + choices=plotchoices, + initial='timeplot', label='Plot Type') class Meta: - fields = ['make_plot','plottype'] + fields = ['make_plot','plottype'] # This form is used on the Workout Split page class WorkoutSplitForm(forms.Form): @@ -392,9 +394,9 @@ class OteWorkoutTypeForm(forms.Form): class PredictedPieceForm(forms.Form): unitchoices = ( - ('t','minutes'), - ('d','meters'), - ) + ('t','minutes'), + ('d','meters'), + ) rankingdistancechoices = [] rankingdurationchoices = [] @@ -422,10 +424,10 @@ class PredictedPieceForm(forms.Form): value = forms.FloatField(initial=10,label='Free ranking piece (minutes)') pieceunit = forms.ChoiceField(required=True,choices=unitchoices, - initial='t',label='Unit') + initial='t',label='Unit') class Meta: - fields = ['value','pieceunit'] + fields = ['value','pieceunit'] class PredictedPieceFormNoDistance(forms.Form): @@ -450,76 +452,76 @@ class PredictedPieceFormNoDistance(forms.Form): # On the Geeky side, to update stream information for river dwellers class UpdateStreamForm(forms.Form): unitchoices = ( - ('m','m/s'), - ('f','foot/s'), - ('k','knots'), - ('p','pace difference (sec/500m)'), - ) + ('m','m/s'), + ('f','foot/s'), + ('k','knots'), + ('p','pace difference (sec/500m)'), + ) dist1 = forms.FloatField(initial=0,label = 'Distance 1') dist2 = forms.FloatField(initial=1000,label = 'Distance 2') stream1 = forms.FloatField(initial=0,label = 'Stream velocity 1') stream2 = forms.FloatField(initial=0,label = 'Stream velocity 2') streamunit = forms.ChoiceField(required=True, - choices=unitchoices, - initial='m', - label='Unit') + choices=unitchoices, + initial='m', + label='Unit') class Meta: - fields = ['dist1','dist2','stream1', 'stream2','streamunit'] + fields = ['dist1','dist2','stream1', 'stream2','streamunit'] # add wind information to your workout class UpdateWindForm(forms.Form): unitchoices = ( - ('m','m/s'), - ('k','knots'), - ('b','beaufort'), - ('kmh','km/h'), - ('mph','miles/hour'), - ) + ('m','m/s'), + ('k','knots'), + ('b','beaufort'), + ('kmh','km/h'), + ('mph','miles/hour'), + ) dist1 = forms.FloatField(initial=0,label = 'Distance 1') dist2 = forms.FloatField(initial=1000,label = 'Distance 2') vwind1 = forms.FloatField(initial=0,required=False,label = 'Wind Speed 1') vwind2 = forms.FloatField(initial=0,required=False,label = 'Wind Speed 2') windunit = forms.ChoiceField(required=True, - choices=unitchoices, - initial='m', - label='Unit') + choices=unitchoices, + initial='m', + label='Unit') winddirection1 = forms.IntegerField(initial=0,required=False, - label = 'Wind Direction 1') + label = 'Wind Direction 1') winddirection2 = forms.IntegerField(initial=0,required=False, - label = 'Wind Direction 2') + label = 'Wind Direction 2') class Meta: - fields = ['dist1','dist2', - 'vwind1','vwind2', - 'windunit', - 'winddirection1','winddirection2'] + fields = ['dist1','dist2', + 'vwind1','vwind2', + 'windunit', + 'winddirection1','winddirection2'] # Form to select a data range to show workouts from a certain time period class DateRangeForm(forms.Form): startdate = forms.DateField( initial=timezone.now()-datetime.timedelta(days=365), - # widget=SelectDateWidget(years=range(1990,2050)), + # widget=SelectDateWidget(years=range(1990,2050)), widget=AdminDateWidget(), - label='Start Date') + label='Start Date') enddate = forms.DateField( initial=timezone.now(), widget=AdminDateWidget(), - label='End Date') + label='End Date') class Meta: - fields = ['startdate','enddate'] + fields = ['startdate','enddate'] class FitnessMetricForm(forms.Form): startdate = forms.DateField( initial=timezone.now()-datetime.timedelta(days=365), - # widget=SelectDateWidget(years=range(1990,2050)), + # widget=SelectDateWidget(years=range(1990,2050)), widget=AdminDateWidget(), - label='Start Date') + label='Start Date') enddate = forms.DateField( initial=timezone.now(), widget=AdminDateWidget(), - label='End Date') + label='End Date') modechoices = ( ('rower','indoor rower'), @@ -533,7 +535,7 @@ class FitnessMetricForm(forms.Form): ) class Meta: - fields = ['startdate','enddate','mode'] + fields = ['startdate','enddate','mode'] class SessionDateShiftForm(forms.Form): shiftstartdate = forms.DateField( @@ -599,7 +601,7 @@ class RegistrationFormSex(RegistrationFormUniqueEmail): weightcategories = ( ('hwt','heavy-weight'), - ('lwt','light-weight'), + ('lwt','light-weight'), ) adaptivecategories = mytypes.adaptivetypes @@ -637,8 +639,8 @@ class RegistrationFormSex(RegistrationFormUniqueEmail): class MyTimeField(forms.TimeField): def __init__(self, *args, **kwargs): - super(MyTimeField, self).__init__(*args, **kwargs) - supports_microseconds = True + super(MyTimeField, self).__init__(*args, **kwargs) + supports_microseconds = True # Form used to automatically define intervals by pace or power class PowerIntervalUpdateForm(forms.Form): @@ -660,28 +662,28 @@ class PowerIntervalUpdateForm(forms.Form): class IntervalUpdateForm(forms.Form): def __init__(self, *args, **kwargs): - typechoices = ( - (1,'single time'), - (2,'single distance'), - (3,'rest (time based)'), - (3,'rest (distance based)'), - (4,'work (time based)'), - (5,'work (distance based)'), - ) - aantal = int(kwargs.pop('aantal')) - super(IntervalUpdateForm, self).__init__(*args, **kwargs) + typechoices = ( + (1,'single time'), + (2,'single distance'), + (3,'rest (time based)'), + (3,'rest (distance based)'), + (4,'work (time based)'), + (5,'work (distance based)'), + ) + aantal = int(kwargs.pop('aantal')) + super(IntervalUpdateForm, self).__init__(*args, **kwargs) - for i in range(aantal): - self.fields['intervalt_%s' % i] = forms.DurationField(label='Time '+str(i+1)) - self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1)) - self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices, - required=True, - initial=4, - label = 'Type '+str(i+1)) - self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;' - self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;' - self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;' - self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f') + for i in range(aantal): + self.fields['intervalt_%s' % i] = forms.DurationField(label='Time '+str(i+1)) + self.fields['intervald_%s' % i] = forms.IntegerField(label='Distance '+str(i+1)) + self.fields['type_%s' % i] = forms.ChoiceField(choices=typechoices, + required=True, + initial=4, + label = 'Type '+str(i+1)) + self.fields['intervalt_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;' + self.fields['intervald_%s' % i].widget.attrs['style'] = 'width:76px; height: 16px;' + self.fields['type_%s' % i].widget.attrs['style'] = 'width:156px; height: 22px;' + self.fields['intervald_%s' % i].widget = forms.TimeInput(format='%H:%M:%S.%f') boattypes = mytypes.boattypes workouttypes = mytypes.workouttypes @@ -824,7 +826,7 @@ formaxlabelsmultiflex.pop('distance') formaxlabelsmultiflex['workoutid'] = 'Workout' parchoicesmultiflex = list(sorted(formaxlabelsmultiflex.items(), key = lambda x:x[1])) -from utils import palettes +from rowers.utils import palettes palettechoices = tuple((p,p) for p in palettes.keys()) @@ -950,7 +952,7 @@ class RaceResultFilterForm(forms.Form): weightcategories = ( ('hwt','heavy-weight'), - ('lwt','light-weight'), + ('lwt','light-weight'), ) adaptivecategories = mytypes.adaptivetypes diff --git a/rowers/imports.py b/rowers/imports.py index d49625f3..c39064e6 100644 --- a/rowers/imports.py +++ b/rowers/imports.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # All the functionality to connect to SportTracks # Python @@ -16,7 +17,7 @@ from dateutil import parser import time from time import strftime -import dataprep +import rowers.dataprep as dataprep import math from math import sin,cos,atan2,sqrt import os,sys @@ -38,7 +39,7 @@ from django.contrib.auth.decorators import login_required from rowingdata import rowingdata, make_cumvalues import pandas as pd from rowers.models import Rower,Workout,checkworkoutuser -from rowers import mytypes +import rowers.mytypes as mytypes from rowsandall_app.settings import ( C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET, STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, @@ -46,7 +47,7 @@ from rowsandall_app.settings import ( SPORTTRACKS_CLIENT_ID, SPORTTRACKS_REDIRECT_URI ) -from utils import ( +from rowers.utils import ( NoTokenError, custom_exception_handler, ewmovingaverage, geo_distance,isprorower,uniqify ) @@ -59,9 +60,9 @@ def splitstdata(lijst): t = [] latlong = [] while len(lijst)>=2: - t.append(lijst[0]) - latlong.append(lijst[1]) - lijst = lijst[2:] + t.append(lijst[0]) + latlong.append(lijst[1]) + lijst = lijst[2:] return [np.array(t),np.array(latlong)] @@ -103,7 +104,6 @@ def imports_open(user,oauth_data): oauth_data, ) elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename: - print 'noot' token = imports_token_refresh( user, tokenname, @@ -124,13 +124,13 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''): ) post_data = {"grant_type": "refresh_token", - "client_secret": oauth_data['client_secret'], - "client_id": oauth_data['client_id'], - "refresh_token": refreshtoken, - } + "client_secret": oauth_data['client_secret'], + "client_id": oauth_data['client_id'], + "refresh_token": refreshtoken, + } headers = {'user-agent': 'sanderroosendaal', - 'Accept': 'application/json', - 'Content-Type': oauth_data['content_type']} + 'Accept': 'application/json', + 'Content-Type': oauth_data['content_type']} # for Strava if 'grant_type' in oauth_data: @@ -147,11 +147,11 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''): if 'json' in oauth_data['content_type']: response = requests.post(baseurl, data=json.dumps(post_data), - headers=headers) + headers=headers) else: response = requests.post(baseurl, data=post_data, - headers=headers) + headers=headers) @@ -174,9 +174,9 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''): except KeyError: expires_in = 0 try: - refresh_token = token_json['refresh_token'] + refresh_token = token_json['refresh_token'] except KeyError: - refresh_token = refreshtoken + refresh_token = refreshtoken try: expires_in = int(expires_in) except (TypeError,ValueError): @@ -204,16 +204,16 @@ def imports_get_token( post_data = {"grant_type": "authorization_code", "code": code, "redirect_uri": redirect_uri, - "client_secret": client_secret, - "client_id": client_id, - } + "client_secret": client_secret, + "client_id": client_id, + } try: headers = oauth_data['headers'] except KeyError: headers = {'Accept': 'application/json', 'Api-Key': client_id, - 'Content-Type': 'application/json', + 'Content-Type': 'application/json', 'user-agent': 'sanderroosendaal'} if 'grant_type' in oauth_data: @@ -229,12 +229,12 @@ def imports_get_token( response = requests.post( base_uri, data=json.dumps(post_data), - headers=headers) + headers=headers) else: response = requests.post( base_uri, data=post_data, - headers=headers) + headers=headers) if response.status_code == 200 or response.status_code == 201: token_json = response.json() @@ -243,9 +243,9 @@ def imports_get_token( except KeyError: return [0,0,0] try: - refresh_token = token_json['refresh_token'] + refresh_token = token_json['refresh_token'] except KeyError: - refresh_token = '' + refresh_token = '' try: expires_in = token_json['expires_in'] except KeyError: @@ -270,8 +270,8 @@ def imports_make_authorization_url(oauth_data): params = {"client_id": oauth_data['client_id'], "response_type": "code", "redirect_uri": oauth_data['redirect_uri'], - "scope":oauth_data['scope'], - "state":state} + "scope":oauth_data['scope'], + "state":state} import urllib diff --git a/rowers/interactiveplots.py b/rowers/interactiveplots.py index b17fdc7d..3e95147a 100644 --- a/rowers/interactiveplots.py +++ b/rowers/interactiveplots.py @@ -27,7 +27,7 @@ from bokeh.io import output_file, show, vplot from bokeh.models import ( GMapPlot, GMapOptions, ColumnDataSource, Circle, DataRange1d, PanTool, WheelZoomTool, BoxSelectTool, - SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool, + SaveTool, ResizeTool, ResetTool, TapTool,CrosshairTool,BoxZoomTool, Span, Label ) from bokeh.models.glyphs import ImageURL @@ -38,7 +38,7 @@ from bokeh.core.properties import value from collections import OrderedDict from django.conf import settings -from courses import ( +from rowers.courses import ( course_coord_center,course_coord_maxmin, polygon_coord_center ) @@ -62,7 +62,7 @@ from scipy.signal import savgol_filter from scipy.interpolate import griddata -import stravastuff +import rowers.stravastuff as stravastuff from rowers.dataprep import rdata import rowers.dataprep as dataprep @@ -70,9 +70,9 @@ import rowers.metrics as metrics from rowers.metrics import axes,axlabels,yaxminima,yaxmaxima -from utils import lbstoN -from datautils import p0 -import datautils +from rowers.utils import lbstoN +from rowers.datautils import p0 +import rowers.datautils as datautils watermarkurl = "/static/img/logo7.png" watermarksource = ColumnDataSource(dict( @@ -180,7 +180,7 @@ def interactive_boxchart(datadf,fieldname,extratitle=''): title=axlabels[fieldname]+' '+extratitle, outliers=False, tools=TOOLS, - toolbar_location="above", + toolbar_location="above", toolbar_sticky=False, x_mapper_type='datetime',plot_width=920) @@ -215,10 +215,10 @@ def interactive_boxchart(datadf,fieldname,extratitle=''): ) if fieldname == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) plot.xaxis.major_label_orientation = pi/4 @@ -226,9 +226,9 @@ def interactive_boxchart(datadf,fieldname,extratitle=''): hover = plot.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ - ('Value','@y'), + ('Value','@y'), ('Date','@x'), - ]) + ]) hover.mode = 'mouse' @@ -320,8 +320,8 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'): d2 = enddate.strftime("%Y-%m-%d"), ), stack=stack, - plot_width=350, - plot_height=250, + plot_width=350, + plot_height=250, toolbar_location = None, ) @@ -369,13 +369,13 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): workoutstatetransition = [0,2,10,11,12,13] if workstrokesonly: - try: - rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] - except KeyError: - pass + try: + rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] + except KeyError: + pass if rowdata.empty: - return "","No Valid Data Available","","" + return "","No Valid Data Available","","" try: catchav = rowdata['catch'].mean() @@ -435,7 +435,7 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): ) plot = Figure(tools=TOOLS, - toolbar_sticky=False) + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -577,20 +577,20 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): for (i=0; i=minspm && spm1[i]<=maxspm) { - if (distance1[i]>=mindist && distance1[i]<=maxdist) { + if (spm1[i]>=minspm && spm1[i]<=maxspm) { + if (distance1[i]>=mindist && distance1[i]<=maxdist) { if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { - catchav += c[i] - finishav += finish[i] - slipav += slip[i] - washav += wash[i] - peakforceangleav += peakforceangle[i] - averageforceav += averageforce[i] + catchav += c[i] + finishav += finish[i] + slipav += slip[i] + washav += wash[i] + peakforceangleav += peakforceangle[i] + averageforceav += averageforce[i] peakforceav += peakforce[i] count += 1 } - } - } + } + } } catchav /= count @@ -617,43 +617,43 @@ def interactive_forcecurve(theworkouts,workstrokesonly=False): """) slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1, - title="Min SPM",callback=callback) + title="Min SPM",callback=callback) callback.args["minspm"] = slider_spm_min slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1, - title="Max SPM",callback=callback) + title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max slider_work_min = Slider(start=0, end=1500,value=0, step=10, - title="Min Work per Stroke",callback=callback) + title="Min Work per Stroke",callback=callback) callback.args["minwork"] = slider_work_min slider_work_max = Slider(start=0, end=1500,value=1500, step=10, - title="Max Work per Stroke",callback=callback) + title="Max Work per Stroke",callback=callback) callback.args["maxwork"] = slider_work_max distmax = 100+100*int(rowdata['distance'].max()/100.) slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, - title="Min Distance",callback=callback) + title="Min Distance",callback=callback) callback.args["mindist"] = slider_dist_min slider_dist_max = Slider(start=0,end=distmax,value=distmax, - step=1, - title="Max Distance",callback=callback) + step=1, + title="Max Distance",callback=callback) callback.args["maxdist"] = slider_dist_max layout = layoutrow([layoutcolumn([slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, + slider_spm_max, + slider_dist_min, + slider_dist_max, slider_work_min, slider_work_max, - ], - ), - plot]) + ], + ), + plot]) layout.sizing_mode = 'scale_width' @@ -814,7 +814,7 @@ def interactive_histoall(theworkouts): rowdata.dropna(axis=0,how='any',inplace=True) if rowdata.empty: - return "","No Valid Data Available","","" + return "","No Valid Data Available","","" try: histopwr = rowdata['power'].values @@ -829,9 +829,9 @@ def interactive_histoall(theworkouts): histopwr = histopwr[histopwr < 1000] plot = Figure(tools=TOOLS,plot_width=900, - toolbar_sticky=False, - toolbar_location="above" - ) + toolbar_sticky=False, + toolbar_location="above" + ) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -856,13 +856,13 @@ def interactive_histoall(theworkouts): hist_norm = 100.*hist/float(hist.sum()) source = ColumnDataSource( - data = dict( - left = edges[:-1], - right = edges[1:], - histsum = histsum, - hist_norm = hist_norm, - ) - ) + data = dict( + left = edges[:-1], + right = edges[1:], + histsum = histsum, + hist_norm = hist_norm, + ) + ) # plot.quad(top='hist_norm',bottom=0,left=edges[:-1],right=edges[1:]) @@ -876,18 +876,18 @@ def interactive_histoall(theworkouts): hover = plot.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ - ('Power(W)','@left{int}'), - ('% of strokes','@hist_norm'), - ('Cumulative %','@histsum{int}'), - ]) + ('Power(W)','@left{int}'), + ('% of strokes','@hist_norm'), + ('Cumulative %','@histsum{int}'), + ]) hover.mode = 'mouse' plot.extra_y_ranges["fraction"] = Range1d(start=0,end=105) plot.line('right','histsum',source=source,color="red", - y_range_name="fraction") + y_range_name="fraction") plot.add_layout(LinearAxis(y_range_name="fraction", - axis_label="Cumulative % of strokes"),'right') + axis_label="Cumulative % of strokes"),'right') plot.sizing_mode = 'scale_width' script, div = components(plot) @@ -958,18 +958,18 @@ def course_map(course): var streets = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.streets' + maxZoom: 18, + id: 'mapbox.streets' }}), satellite = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.satellite' + maxZoom: 18, + id: 'mapbox.satellite' }}), outdoors = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.outdoors' + maxZoom: 18, + id: 'mapbox.outdoors' }}); @@ -1076,18 +1076,18 @@ def leaflet_chart(lat,lon,name=""): var streets = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.streets' + maxZoom: 18, + id: 'mapbox.streets' }}), satellite = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.satellite' + maxZoom: 18, + id: 'mapbox.satellite' }}), outdoors = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.outdoors' + maxZoom: 18, + id: 'mapbox.outdoors' }}); @@ -1197,18 +1197,18 @@ def leaflet_chart2(lat,lon,name=""): var streets = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.streets' + maxZoom: 18, + id: 'mapbox.streets' }}), satellite = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.satellite' + maxZoom: 18, + id: 'mapbox.satellite' }}), outdoors = L.tileLayer('https://api.tiles.mapbox.com/v4/{{id}}/{{z}}/{{x}}/{{y}}.png?access_token=pk.eyJ1Ijoic2FuZGVycm9vc2VuZGFhbCIsImEiOiJjajY3aTRkeWQwNmx6MzJvMTN3andlcnBlIn0.MFG8Xt0kDeSA9j7puZQ9hA', {{ - maxZoom: 18, - id: 'mapbox.outdoors' + maxZoom: 18, + id: 'mapbox.outdoors' }}); @@ -1272,7 +1272,7 @@ def leaflet_chart2(lat,lon,name=""): return script,div - + def interactive_agegroupcpchart(age,normalized=False): durations = [1,4,30,60] distances = [100,500,1000,2000,5000,6000,10000,21097,42195] @@ -1531,9 +1531,9 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""): powerdf = powerdf[~(powerdf == 0).any(axis=1)] # plot tools if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' x_axis_type = 'log' @@ -1556,7 +1556,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""): message = "" #if len(fitpower[fitpower<0]) > 0: - # message = "CP model fit didn't give correct results" + # message = "CP model fit didn't give correct results" deltas = fitt.apply(lambda x: timedeltaconv(x)) @@ -1573,9 +1573,9 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""): # making the plot plot = Figure(tools=TOOLS,x_axis_type=x_axis_type, - plot_width=900, - toolbar_location="above", - toolbar_sticky=False) + plot_width=900, + toolbar_location="above", + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -1592,7 +1592,7 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""): ) plot.circle('Delta','CP',source=source,fill_color='red',size=15, - legend='Power Data') + legend='Power Data') plot.xaxis.axis_label = "Duration (seconds)" plot.yaxis.axis_label = "Power (W)" @@ -1604,18 +1604,18 @@ def interactive_otwcpchart(powerdf,promember=0,rowername=""): hover = plot.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ - ('Duration ','@ftime'), - ('Power (W)','@CP{int}'), - ('Power (W) upper','@CPmax{int}'), - ]) + ('Duration ','@ftime'), + ('Power (W)','@CP{int}'), + ('Power (W) upper','@CPmax{int}'), + ]) hover.mode = 'mouse' plot.line('duration','CP',source=sourcecomplex,legend="CP Model", - color='green') + color='green') plot.line('duration','CPmax',source=sourcecomplex,legend="CP Model", - color='red') + color='red') script, div = components(plot) @@ -1693,15 +1693,15 @@ def interactive_agegroup_plot(df,distance=2000,duration=None, return script,div def interactive_cpchart(rower,thedistances,thesecs,theavpower, - theworkouts,promember=0, + theworkouts,promember=0, wcpower=[],wcdurations=[]): message = 0 # plot tools if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' x_axis_type = 'log' @@ -1715,25 +1715,25 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) source = ColumnDataSource( - data = dict( - dist = thedistances, - duration = thesecs, - spm = 0*theavpower, - tim = niceformat( - thesecs.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) - ), - - power = theavpower, - fpace = nicepaceformat(p2), - ) - ) + data = dict( + dist = thedistances, + duration = thesecs, + spm = 0*theavpower, + tim = niceformat( + thesecs.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) + ), + + power = theavpower, + fpace = nicepaceformat(p2), + ) + ) # fitting the data to Paul if len(thedistances)>=2: - paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p) + paulslope, paulintercept,r,p,stderr = linregress(np.log10(thedistances),p) else: - paulslope = 5.0/np.log10(2.0) - paulintercept = p[0]-paulslope*np.log10(thedistances[0]) + paulslope = 5.0/np.log10(2.0) + paulintercept = p[0]-paulslope*np.log10(thedistances[0]) fitx = pd.Series(np.arange(100)*2*max(np.log10(thedistances))/100.) @@ -1747,17 +1747,17 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, sourcepaul = ColumnDataSource( - data = dict( - dist = 10**fitx, - duration = fitt, - power = fitpower, - spm = 0*fitpower, - tim = niceformat( - fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) - ), - fpace = nicepaceformat(fitp2), - ) - ) + data = dict( + dist = 10**fitx, + duration = fitt, + power = fitpower, + spm = 0*fitpower, + tim = niceformat( + fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) + ), + fpace = nicepaceformat(fitp2), + ) + ) fitfunc = lambda pars,x: pars[0]/(1+(x/pars[2])) + pars[1]/(1+(x/pars[3])) @@ -1779,10 +1779,10 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, success = 0 p1 = p0 if len(thesecs)>=4: - p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) + p1, success = optimize.leastsq(errfunc, p0[:], args = (thesecs,theavpower)) else: - factor = fitfunc(p0,thesecs.mean())/theavpower.mean() - p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] + factor = fitfunc(p0,thesecs.mean())/theavpower.mean() + p1 = [p0[0]/factor,p0[1]/factor,p0[2],p0[3]] success = 0 @@ -1833,7 +1833,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, message = "" if len(fitpower[fitpower<0]) > 0: - message = "CP model fit didn't give correct results" + message = "CP model fit didn't give correct results" fitvelo = (fitpower/2.8)**(1./3.) fitdist = fitt*fitvelo @@ -1841,30 +1841,30 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, fitp2 = fitp.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) sourcecomplex = ColumnDataSource( - data = dict( - dist = fitdist, - duration = fitt, - tim = niceformat( - fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) - ), - spm = 0*fitpower, - power = fitpower, + data = dict( + dist = fitdist, + duration = fitt, + tim = niceformat( + fitt.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) + ), + spm = 0*fitpower, + power = fitpower, fitpowerwc = fitpowerwc, fitpowerexcellent = fitpowerexcellent, fitpowergood = fitpowergood, fitpowerfair = fitpowerfair, fitpoweraverage = fitpoweraverage, - fpace = nicepaceformat(fitp2), - ) - ) + fpace = nicepaceformat(fitp2), + ) + ) # making the plot plot = Figure(tools=TOOLS,x_axis_type=x_axis_type, - plot_width=900, - toolbar_location="above", - toolbar_sticky=False) + plot_width=900, + toolbar_location="above", + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -1881,7 +1881,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, ) plot.circle('duration','power',source=source,fill_color='red',size=15, - legend='Power') + legend='Power') plot.xaxis.axis_label = "Duration (seconds)" plot.yaxis.axis_label = "Power (W)" @@ -1915,29 +1915,29 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, p2 = p.fillna(method='ffill').apply(lambda x: timedeltaconv(x)) source2 = ColumnDataSource( - data = dict( - duration = cpdata['delta'], - power = cpdata['cp'], - tim = niceformat( - cpdata['delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x)) - ), - dist = cpdata['distance'], - pace = nicepaceformat(p2), - ) - ) + data = dict( + duration = cpdata['delta'], + power = cpdata['cp'], + tim = niceformat( + cpdata['delta'].fillna(method='ffill').apply(lambda x: timedeltaconv(x)) + ), + dist = cpdata['distance'], + pace = nicepaceformat(p2), + ) + ) plot.circle('duration','power',source=source2, - fill_color='blue',size=3, - legend = 'Power from segments') + fill_color='blue',size=3, + legend = 'Power from segments') hover = plot.select(dict(type=HoverTool)) hover.tooltips = OrderedDict([ - ('Duration ','@tim'), - ('Power (W)','@power{int}'), - ('Distance (m)','@dist{int}'), - ('Pace (/500m)','@fpace'), - ]) + ('Duration ','@tim'), + ('Power (W)','@power{int}'), + ('Distance (m)','@dist{int}'), + ('Pace (/500m)','@fpace'), + ]) hover.mode = 'mouse' @@ -1948,7 +1948,7 @@ def interactive_cpchart(rower,thedistances,thesecs,theavpower, plot.line('duration','power',source=sourcepaul,legend="Paul's Law") plot.line('duration','power',source=sourcecomplex,legend="CP Model", - color='green') + color='green') if p1wc is not None: plot.line('duration','fitpowerwc',source=sourcecomplex, legend="World Class", @@ -1982,7 +1982,7 @@ def interactive_windchart(id=0,promember=0): # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") f1 = row.csvfilename - + # create interactive plot plot = Figure(plot_width=400,plot_height=300) @@ -1994,26 +1994,26 @@ def interactive_windchart(id=0,promember=0): rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an,ftp=r.ftp) + hrut1=r.ut1,hrat=r.at, + hrtr=r.tr,hran=r.an,ftp=r.ftp) rowdata = rdata(f1,rower=rr) if rowdata == 0: - return 0 + return 0 dist = rowdata.df.loc[:,'cum_dist'] try: - vwind = rowdata.df.loc[:,'vwind'] - winddirection = rowdata.df.loc[:,'winddirection'] - bearing = rowdata.df.loc[:,'bearing'] + vwind = rowdata.df.loc[:,'vwind'] + winddirection = rowdata.df.loc[:,'winddirection'] + bearing = rowdata.df.loc[:,'bearing'] except KeyError: - rowdata.add_wind(0,0) - rowdata.add_bearing() - vwind = rowdata.df.loc[:,'vwind'] - winddirection = rowdata.df.loc[:,'winddirection'] - bearing = rowdata.df.loc[:,'winddirection'] - rowdata.write_csv(f1,gzip=True) + rowdata.add_wind(0,0) + rowdata.add_bearing() + vwind = rowdata.df.loc[:,'vwind'] + winddirection = rowdata.df.loc[:,'winddirection'] + bearing = rowdata.df.loc[:,'winddirection'] + rowdata.write_csv(f1,gzip=True) dataprep.update_strokedata(id,rowdata.df) winddirection = winddirection % 360 @@ -2023,27 +2023,27 @@ def interactive_windchart(id=0,promember=0): source = ColumnDataSource( - data = dict( - dist=dist, - vwind=vwind, - tw=tw, - winddirection=winddirection, - ) - ) + data = dict( + dist=dist, + vwind=vwind, + tw=tw, + winddirection=winddirection, + ) + ) # plot tools if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' # making the plot plot = Figure(tools=TOOLS,plot_width=400,height=500, -# toolbar_location="below", - toolbar_sticky=False, - ) +# toolbar_location="below", + toolbar_sticky=False, + ) plot.line('dist','vwind',source=source,legend="Wind Speed (m/s)") plot.line('dist','tw',source=source,legend="Tail (+)/Head (-) Wind (m/s)",color='black') plot.title.text = row.name @@ -2057,8 +2057,8 @@ def interactive_windchart(id=0,promember=0): plot.extra_y_ranges = {"winddirection": Range1d(start=0,end=360)} plot.line('dist','winddirection',source=source, - legend='Wind Direction',color="red", - y_range_name="winddirection") + legend='Wind Direction',color="red", + y_range_name="winddirection") plot.add_layout(LinearAxis(y_range_name="winddirection",axis_label="Wind Direction (degree)"),'right') @@ -2072,10 +2072,10 @@ def interactive_streamchart(id=0,promember=0): # g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime") f1 = row.csvfilename - + # create interactive plot plot = Figure(plot_width=400, - ) + ) # get user # u = User.objects.get(id=row.user.id) r = row.user @@ -2084,36 +2084,36 @@ def interactive_streamchart(id=0,promember=0): rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an,ftp=r.ftp) + hrut1=r.ut1,hrat=r.at, + hrtr=r.tr,hran=r.an,ftp=r.ftp) rowdata = rdata(f1,rower=rr) if rowdata == 0: - return "","No Valid Data Available" + return "","No Valid Data Available" dist = rowdata.df.loc[:,'cum_dist'] try: - vstream = rowdata.df.loc[:,'vstream'] + vstream = rowdata.df.loc[:,'vstream'] except KeyError: - rowdata.add_stream(0) - vstream = rowdata.df.loc[:,'vstream'] - rowdata.write_csv(f1,gzip=True) + rowdata.add_stream(0) + vstream = rowdata.df.loc[:,'vstream'] + rowdata.write_csv(f1,gzip=True) dataprep.update_strokedata(id,rowdata.df) # plot tools if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' # making the plot plot = Figure(tools=TOOLS,plot_width=400,height=500, -# toolbar_location="below", - toolbar_sticky=False, - ) +# toolbar_location="below", + toolbar_sticky=False, + ) plot.line(dist,vstream,legend="River Stream Velocity (m/s)") plot.title.text = row.name plot.title.text_font_size=value("1.0em") @@ -2130,9 +2130,9 @@ def interactive_streamchart(id=0,promember=0): def interactive_chart(id=0,promember=0,intervaldata = {}): # Add hover to this comma-separated string and see what changes if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' columns = ['time','pace','hr','fpace','ftime'] @@ -2142,7 +2142,7 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): row = Workout.objects.get(id=id) if datadf.empty: - return "","No Valid Data Available" + return "","No Valid Data Available" else: try: datadf.sort_values(by='time',ascending=True,inplace=True) @@ -2161,17 +2161,17 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): #datadf,row = dataprep.getrowdata_db(id=id) #if datadf.empty: - #return "","No Valid Data Available" + #return "","No Valid Data Available" source = ColumnDataSource( - datadf - ) + datadf + ) plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - plot_width=400, - plot_height=400, - toolbar_sticky=False, - tools=TOOLS) + plot_width=400, + plot_height=400, + toolbar_sticky=False, + tools=TOOLS) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -2195,30 +2195,30 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): plot.xaxis.axis_label = "Time" plot.yaxis.axis_label = "Pace (/500m)" plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + seconds = ["%S"], + minutes = ["%M"] + ) ymax = 90. ymin = 150. if row.workouttype == 'water': - ymax = 90. - ymin = 210. + ymax = 90. + ymin = 210. plot.y_range = Range1d(1.e3*ymin,1.e3*ymax) plot.extra_y_ranges["spmax"] = Range1d(start=10,end=45) plot.line('time','spm',source=source,color="red", - y_range_name="spmax", legend="Stroke Rate",name="spm") + y_range_name="spmax", legend="Stroke Rate",name="spm") plot.add_layout(LinearAxis(y_range_name="spmax",axis_label="SPM"),'right') plot.legend.location = "bottom_right" @@ -2250,11 +2250,11 @@ def interactive_chart(id=0,promember=0,intervaldata = {}): hover.tooltips = OrderedDict([ - ('Time','@ftime'), - ('Pace','@fpace'), - ('HR','@hr{int}'), - ('SPM','@spm{1.1}'), - ]) + ('Time','@ftime'), + ('Pace','@fpace'), + ('HR','@hr{int}'), + ('SPM','@spm{1.1}'), + ]) hover.mode = 'mouse' hover.names = ["spm","pace"] @@ -2297,8 +2297,8 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', if xparam=='distance': - xaxmax = datadf[xparam].max() - xaxmin = datadf[xparam].min() + xaxmax = datadf[xparam].max() + xaxmin = datadf[xparam].min() elif xparam=='time': tseconds = datadf.loc[:,'time'] xaxmax = tseconds.max() @@ -2307,12 +2307,12 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', xaxmax = datadf[xparam].max()-5 xaxmin = datadf[xparam].min()+5 else: - xaxmax = yaxmaxima[xparam] - xaxmin = yaxminima[xparam] + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] if yparam=='distance': - yaxmax = datadf[yparam].max() - yaxmin = datadf[yparam].min() + yaxmax = datadf[yparam].max() + yaxmin = datadf[yparam].min() elif yparam=='time': tseconds = datadf.loc[:,'time'] yaxmax = tseconds.max() @@ -2321,8 +2321,8 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', yaxmax = datadf[yparam].max()-5 yaxmin = datadf[yparam].min()+5 else: - yaxmax = yaxmaxima[yparam] - yaxmin = yaxminima[yparam] + yaxmax = yaxmaxima[yparam] + yaxmin = yaxminima[yparam] x_axis_type = 'linear' y_axis_type = 'linear' @@ -2362,9 +2362,9 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - toolbar_location="above", - toolbar_sticky=False,plot_width=920) + tools=TOOLS, + toolbar_location="above", + toolbar_sticky=False,plot_width=920) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -2453,10 +2453,10 @@ def interactive_multiflex(datadf,xparam,yparam,groupby,extratitle='', plot.x_range = xrange1 if yparam == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) script,div = components(plot) @@ -2513,7 +2513,7 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, # check if dataframe not empty if datadf.empty: - return ['','

No non-zero data in selection

','',''] + return ['','

No non-zero data in selection

','',''] try: @@ -2536,37 +2536,37 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, return ['','

No non-zero data in selection

','',''] if yparam2 != 'None': try: - datadf['y2'] = datadf.loc[:,yparam2] + datadf['y2'] = datadf.loc[:,yparam2] except KeyError: datadf['y2'] = datadf['y1'] else: - datadf['y2'] = datadf['y1'] + datadf['y2'] = datadf['y1'] if xparam=='distance': - xaxmax = datadf['x1'].max() - xaxmin = datadf['x1'].min() + xaxmax = datadf['x1'].max() + xaxmin = datadf['x1'].min() else: - xaxmax = yaxmaxima[xparam] - xaxmin = yaxminima[xparam] + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] # average values x1mean = datadf['x1'].mean() - + y1mean = datadf['y1'].mean() y2mean = datadf['y2'].mean() xvals = pd.Series(xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.) - + x_axis_type = 'linear' y_axis_type = 'linear' if xparam == 'time': - x_axis_type = 'datetime' + x_axis_type = 'datetime' if yparam1 == 'pace': - y_axis_type = 'datetime' - y1mean = datadf.loc[:,'pace'].mean() + y_axis_type = 'datetime' + y1mean = datadf.loc[:,'pace'].mean() datadf['xname'] = axlabels[xparam] datadf['yname1'] = axlabels[yparam1] @@ -2577,23 +2577,23 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, source = ColumnDataSource( - datadf - ) + datadf + ) source2 = ColumnDataSource( - datadf.copy() - ) + datadf.copy() + ) # Add hover to this comma-separated string and see what changes if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - toolbar_location="above", - toolbar_sticky=False) + tools=TOOLS, + toolbar_location="above", + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -2612,10 +2612,10 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, ) x1means = Span(location=x1mean,dimension='height',line_color='green', - line_dash=[6,6], line_width=2) + line_dash=[6,6], line_width=2) y1means = Span(location=y1mean,dimension='width',line_color='blue', - line_dash=[6,6],line_width=2) + line_dash=[6,6],line_width=2) y2means = y1means xlabel = Label(x=100,y=130,x_units='screen',y_units='screen', @@ -2643,9 +2643,9 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, y2label = y1label plot.circle('x1','y1',source=source2,fill_alpha=0.3,line_color=None, - legend=yparamname1, - ) - + legend=yparamname1, + ) + plot.xaxis.axis_label = axlabels[xparam] plot.yaxis.axis_label = axlabels[yparam1] @@ -2657,27 +2657,27 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, plot.x_range = xrange1 if yparam1 == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) if yparam2 != 'None': - yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) - plot.extra_y_ranges["yax2"] = yrange2 + yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) + plot.extra_y_ranges["yax2"] = yrange2 - plot.circle('x1','y2',color="red",y_range_name="yax2", - legend=yparamname2, - source=source2,fill_alpha=0.3,line_color=None) - - plot.add_layout(LinearAxis(y_range_name="yax2", - axis_label=axlabels[yparam2]),'right') + plot.circle('x1','y2',color="red",y_range_name="yax2", + legend=yparamname2, + source=source2,fill_alpha=0.3,line_color=None) + + plot.add_layout(LinearAxis(y_range_name="yax2", + axis_label=axlabels[yparam2]),'right') - y2means = Span(location=y2mean,dimension='width',line_color='red', - line_dash=[6,6],line_width=2,y_range_name="yax2") + y2means = Span(location=y2mean,dimension='width',line_color='red', + line_dash=[6,6],line_width=2,y_range_name="yax2") - plot.add_layout(y2means) + plot.add_layout(y2means) y2label = Label(x=100,y=70,x_units='screen',y_units='screen', text=axlabels[yparam2]+": {y2mean:6.2f}".format(y2mean=y2mean), background_fill_alpha=.7, @@ -2689,12 +2689,12 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, callback = CustomJS(args = dict(source=source,source2=source2, - x1means=x1means, - y1means=y1means, + x1means=x1means, + y1means=y1means, y1label=y1label, y2label=y2label, xlabel=xlabel, - y2means=y2means), code=""" + y2means=y2means), code=""" var data = source.data var data2 = source2.data var x1 = data['x1'] @@ -2730,21 +2730,21 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, data2['y2vals'] = [] for (i=0; i=minspm && spm1[i]<=maxspm) { - if (distance1[i]>=mindist && distance1[i]<=maxdist) { + if (spm1[i]>=minspm && spm1[i]<=maxspm) { + if (distance1[i]>=mindist && distance1[i]<=maxdist) { if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { - data2['x1'].push(x1[i]) - data2['y1'].push(y1[i]) - data2['y2'].push(y2[i]) - data2['spm'].push(spm1[i]) - data2['distance'].push(distance1[i]) + data2['x1'].push(x1[i]) + data2['y1'].push(y1[i]) + data2['y2'].push(y2[i]) + data2['spm'].push(spm1[i]) + data2['distance'].push(distance1[i]) - xm += x1[i] - ym1 += y1[i] - ym2 += y2[i] + xm += x1[i] + ym1 += y1[i] + ym2 += y2[i] } - } - } + } + } } xm /= data2['x1'].length @@ -2765,21 +2765,21 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, """) slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1, - title="Min SPM",callback=callback) + title="Min SPM",callback=callback) callback.args["minspm"] = slider_spm_min slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1, - title="Max SPM",callback=callback) + title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10, - title="Min Work per Stroke",callback=callback) + title="Min Work per Stroke",callback=callback) callback.args["minwork"] = slider_work_min slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10, - title="Max Work per Stroke",callback=callback) + title="Max Work per Stroke",callback=callback) callback.args["maxwork"] = slider_work_max try: @@ -2788,23 +2788,23 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, distmax = 1000. slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, - title="Min Distance",callback=callback) + title="Min Distance",callback=callback) callback.args["mindist"] = slider_dist_min slider_dist_max = Slider(start=0,end=distmax,value=distmax, - step=1, - title="Max Distance",callback=callback) + step=1, + title="Max Distance",callback=callback) callback.args["maxdist"] = slider_dist_max layout = layoutrow([layoutcolumn([slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, + slider_spm_max, + slider_dist_min, + slider_dist_max, slider_work_min, slider_work_max, - ], - ), - plot]) + ], + ), + plot]) layout.sizing_mode = 'scale_width' @@ -2820,11 +2820,11 @@ def interactive_cum_flex_chart2(theworkouts,promember=0, def interactive_flex_chart2(id=0,promember=0, - xparam='time', - yparam1='pace', - yparam2='hr', - plottype='line', - workstrokesonly=False): + xparam='time', + yparam1='pace', + yparam2='hr', + plottype='line', + workstrokesonly=False): #rowdata,row = dataprep.getrowdata_db(id=id) columns = [xparam,yparam1,yparam2, @@ -2878,7 +2878,7 @@ def interactive_flex_chart2(id=0,promember=0, row = Workout.objects.get(id=id) if rowdata.empty: - return "","No valid data",'','',workstrokesonly + return "","No valid data",'','',workstrokesonly else: try: rowdata.sort_values(by='time',ascending=True,inplace=True) @@ -2890,10 +2890,10 @@ def interactive_flex_chart2(id=0,promember=0, workoutstatetransition = [0,2,10,11,12,13] if workstrokesonly: - try: - rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] - except KeyError: - pass + try: + rowdata = rowdata[~rowdata['workoutstate'].isin(workoutstatesrest)] + except KeyError: + pass try: tseconds = rowdata.loc[:,'time'] @@ -2916,59 +2916,59 @@ def interactive_flex_chart2(id=0,promember=0, if yparam2 != 'None': try: - rowdata['y2'] = rowdata.loc[:,yparam2] + rowdata['y2'] = rowdata.loc[:,yparam2] rowmin = rowdata[yparam2].min() except KeyError: rowdata['y2'] = 0*rowdata.loc[:,'time'] rowdata[yparam2] = rowdata['y2'] else: - rowdata['y2'] = rowdata['y1'] + rowdata['y2'] = rowdata['y1'] if xparam=='time': - xaxmax = tseconds.max() - xaxmin = tseconds.min() + xaxmax = tseconds.max() + xaxmin = tseconds.min() elif xparam=='distance' or xparam=='cumdist': - xaxmax = rowdata['x1'].max() - xaxmin = rowdata['x1'].min() + xaxmax = rowdata['x1'].max() + xaxmin = rowdata['x1'].min() else: try: - xaxmax = yaxmaxima[xparam] - xaxmin = yaxminima[xparam] + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] except KeyError: - xaxmax = rowdata['x1'].max() - xaxmin = rowdata['x1'].min() + xaxmax = rowdata['x1'].max() + xaxmin = rowdata['x1'].min() # average values if xparam != 'time': try: - x1mean = rowdata['x1'].mean() + x1mean = rowdata['x1'].mean() except TypeError: x1mean = 0 else: - x1mean = 0 - + x1mean = 0 + y1mean = rowdata['y1'].mean() y2mean = rowdata['y2'].mean() if xparam != 'time': - xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100. + xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100. else: - xvals = np.arange(100) + xvals = np.arange(100) # constant power plot if yparam1 == 'driveenergy': - if xparam == 'spm': - yconstantpower = rowdata['y1'].mean()*rowdata['x1'].mean()/xvals - + if xparam == 'spm': + yconstantpower = rowdata['y1'].mean()*rowdata['x1'].mean()/xvals + x_axis_type = 'linear' y_axis_type = 'linear' if xparam == 'time': - x_axis_type = 'datetime' + x_axis_type = 'datetime' if yparam1 == 'pace': - y_axis_type = 'datetime' + y_axis_type = 'datetime' try: - y1mean = rowdata.loc[:,'pace'].mean() + y1mean = rowdata.loc[:,'pace'].mean() except KeyError: y1mean = 0 @@ -2991,26 +2991,26 @@ def interactive_flex_chart2(id=0,promember=0, # prepare data source = ColumnDataSource( - rowdata - ) + rowdata + ) # second source for filtering source2 = ColumnDataSource( - rowdata.copy() - ) + rowdata.copy() + ) # Add hover to this comma-separated string and see what changes if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - toolbar_sticky=False - ) + tools=TOOLS, + toolbar_sticky=False + ) @@ -3031,10 +3031,10 @@ def interactive_flex_chart2(id=0,promember=0, ) x1means = Span(location=x1mean,dimension='height',line_color='green', - line_dash=[6,6], line_width=2) + line_dash=[6,6], line_width=2) y1means = Span(location=y1mean,dimension='width',line_color='blue', - line_dash=[6,6],line_width=2) + line_dash=[6,6],line_width=2) y2means = y1means try: @@ -3060,7 +3060,7 @@ def interactive_flex_chart2(id=0,promember=0, if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): - plot.add_layout(x1means) + plot.add_layout(x1means) plot.add_layout(xlabel) @@ -3089,14 +3089,14 @@ def interactive_flex_chart2(id=0,promember=0, # average values if yparam1 == 'driveenergy': - if xparam == 'spm': - plot.line(xvals,yconstantpower,color="green",legend="Constant Power") + if xparam == 'spm': + plot.line(xvals,yconstantpower,color="green",legend="Constant Power") if plottype=='line': - plot.line('x1','y1',source=source2,legend=yaxlabel) + plot.line('x1','y1',source=source2,legend=yaxlabel) elif plottype=='scatter': - plot.scatter('x1','y1',source=source2,legend=yaxlabel,fill_alpha=0.4, - line_color=None) + plot.scatter('x1','y1',source=source2,legend=yaxlabel,fill_alpha=0.4, + line_color=None) plot.title.text = row.name plot.title.text_font_size=value("1.0em") @@ -3109,7 +3109,7 @@ def interactive_flex_chart2(id=0,promember=0, try: - yrange1 = Range1d(start=yaxminima[yparam1], + yrange1 = Range1d(start=yaxminima[yparam1], end=yaxmaxima[yparam1]) except KeyError: yrange1 = Range1d(start=rowdata[yparam1].min(), @@ -3119,67 +3119,67 @@ def interactive_flex_chart2(id=0,promember=0, if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): try: - xrange1 = Range1d(start=yaxminima[xparam], + xrange1 = Range1d(start=yaxminima[xparam], end=yaxmaxima[xparam]) except KeyError: xrange1 = Range1d(start=rowdata[xparam].min(), end=rowdata[xparam].max()) - plot.x_range = xrange1 + plot.x_range = xrange1 if xparam == 'time': - xrange1 = Range1d(start=xaxmin,end=xaxmax) - plot.x_range = xrange1 - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + xrange1 = Range1d(start=xaxmin,end=xaxmax) + plot.x_range = xrange1 + plot.xaxis[0].formatter = DatetimeTickFormatter( + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) if yparam1 == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) if yparam2 != 'None': try: - yrange2 = Range1d(start=yaxminima[yparam2], + yrange2 = Range1d(start=yaxminima[yparam2], end=yaxmaxima[yparam2]) except KeyError: yrange2 = Range1d(start=rowdata[yparam2].min(), end=rowdata[yparam2].max()) - plot.extra_y_ranges["yax2"] = yrange2 + plot.extra_y_ranges["yax2"] = yrange2 #= {"yax2": yrange2} try: axlegend = axlabels[yparam2] except KeyError: axlegend = str(yparam2)+' ' - if plottype=='line': - plot.line('x1','y2',color="red",y_range_name="yax2", - legend=axlegend, - source=source2) + if plottype=='line': + plot.line('x1','y2',color="red",y_range_name="yax2", + legend=axlegend, + source=source2) - elif plottype=='scatter': - plot.scatter('x1','y2',source=source2,legend=axlegend, - fill_alpha=0.4, - line_color=None,color="red",y_range_name="yax2") - - plot.add_layout(LinearAxis(y_range_name="yax2", - axis_label=axlegend),'right') + elif plottype=='scatter': + plot.scatter('x1','y2',source=source2,legend=axlegend, + fill_alpha=0.4, + line_color=None,color="red",y_range_name="yax2") + + plot.add_layout(LinearAxis(y_range_name="yax2", + axis_label=axlegend),'right') - y2means = Span(location=y2mean,dimension='width',line_color='red', - line_dash=[6,6],line_width=2,y_range_name="yax2") + y2means = Span(location=y2mean,dimension='width',line_color='red', + line_dash=[6,6],line_width=2,y_range_name="yax2") - plot.add_layout(y2means) + plot.add_layout(y2means) y2label = Label(x=100,y=70,x_units='screen',y_units='screen', text=axlegend+": {y2mean:6.2f}".format(y2mean=y2mean), background_fill_alpha=.7, @@ -3193,25 +3193,25 @@ def interactive_flex_chart2(id=0,promember=0, hover.tooltips = OrderedDict([ - ('Time','@ftime'), - ('Distance','@distance{int}'), - ('Pace','@fpace'), - ('HR','@hr{int}'), - ('SPM','@spm{1.1}'), - ('Power','@power{int}'), - ]) + ('Time','@ftime'), + ('Distance','@distance{int}'), + ('Pace','@fpace'), + ('HR','@hr{int}'), + ('SPM','@spm{1.1}'), + ('Power','@power{int}'), + ]) hover.mode = 'mouse' callback = CustomJS(args = dict(source=source,source2=source2, - x1means=x1means, - y1means=y1means, + x1means=x1means, + y1means=y1means, y1label=y1label, y2label=y2label, xlabel=xlabel, annolabel=annolabel, - y2means=y2means, + y2means=y2means, ), code=""" var data = source.data var data2 = source2.data @@ -3259,26 +3259,26 @@ def interactive_flex_chart2(id=0,promember=0, data2['y2vals'] = [] for (i=0; i=minspm && spm1[i]<=maxspm) { - if (distance1[i]>=mindist && distance1[i]<=maxdist) { + if (spm1[i]>=minspm && spm1[i]<=maxspm) { + if (distance1[i]>=mindist && distance1[i]<=maxdist) { if (driveenergy1[i]>=minwork && driveenergy1[i]<=maxwork) { - data2['x1'].push(x1[i]) - data2['y1'].push(y1[i]) - data2['y2'].push(y2[i]) - data2['spm'].push(spm1[i]) - data2['time'].push(time1[i]) + data2['x1'].push(x1[i]) + data2['y1'].push(y1[i]) + data2['y2'].push(y2[i]) + data2['spm'].push(spm1[i]) + data2['time'].push(time1[i]) data2['fpace'].push(fpace1[i]) - data2['pace'].push(pace1[i]) - data2['hr'].push(hr1[i]) - data2['distance'].push(distance1[i]) - data2['power'].push(power1[i]) + data2['pace'].push(pace1[i]) + data2['hr'].push(hr1[i]) + data2['distance'].push(distance1[i]) + data2['power'].push(power1[i]) - xm += x1[i] - ym1 += y1[i] - ym2 += y2[i] + xm += x1[i] + ym1 += y1[i] + ym2 += y2[i] } - } - } + } + } } xm /= data2['x1'].length @@ -3304,21 +3304,21 @@ def interactive_flex_chart2(id=0,promember=0, callback.args["annotation"] = annotation slider_spm_min = Slider(start=15.0, end=55,value=15.0, step=.1, - title="Min SPM",callback=callback) + title="Min SPM",callback=callback) callback.args["minspm"] = slider_spm_min slider_spm_max = Slider(start=15.0, end=55,value=55.0, step=.1, - title="Max SPM",callback=callback) + title="Max SPM",callback=callback) callback.args["maxspm"] = slider_spm_max slider_work_min = Slider(start=0.0, end=1500,value=0.0, step=10, - title="Min Work per Stroke",callback=callback) + title="Min Work per Stroke",callback=callback) callback.args["minwork"] = slider_work_min slider_work_max = Slider(start=0.0, end=1500,value=1500.0, step=10, - title="Max Work per Stroke",callback=callback) + title="Max Work per Stroke",callback=callback) callback.args["maxwork"] = slider_work_max try: @@ -3327,22 +3327,22 @@ def interactive_flex_chart2(id=0,promember=0, distmax = 100 slider_dist_min = Slider(start=0,end=distmax,value=0,step=1, - title="Min Distance",callback=callback) + title="Min Distance",callback=callback) callback.args["mindist"] = slider_dist_min slider_dist_max = Slider(start=0,end=distmax,value=distmax, - step=1, - title="Max Distance",callback=callback) + step=1, + title="Max Distance",callback=callback) callback.args["maxdist"] = slider_dist_max thesliders = layoutcolumn([annotation, slider_spm_min, - slider_spm_max, - slider_dist_min, - slider_dist_max, + slider_spm_max, + slider_dist_min, + slider_dist_max, slider_work_min, slider_work_max, - ]) + ]) thesliders.sizing_mode = 'scale_width' @@ -3369,7 +3369,7 @@ def thumbnails_set(r,id,favorites): try: rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=True) except: - return [ + return [ {'script':"", 'div':"", 'notes':"" @@ -3383,7 +3383,7 @@ def thumbnails_set(r,id,favorites): rowdata = dataprep.getsmallrowdata_db(columns,ids=[id],doclean=False, workstrokesonly=False) except: - return [ + return [ {'script':"", 'div':"", 'notes':"" @@ -3430,11 +3430,11 @@ def thumbnails_set(r,id,favorites): def thumbnail_flex_chart(rowdata,id=0,promember=0, - xparam='time', - yparam1='pace', - yparam2='hr', - plottype='line', - workstrokesonly=False): + xparam='time', + yparam1='pace', + yparam2='hr', + plottype='line', + workstrokesonly=False): try: @@ -3467,30 +3467,30 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, if yparam2 != 'None': try: - rowdata['y2'] = rowdata.loc[:,yparam2] + rowdata['y2'] = rowdata.loc[:,yparam2] except KeyError: rowdata['y2'] = 0*rowdata.loc[:,'time'] else: - rowdata['y2'] = rowdata['y1'] + rowdata['y2'] = rowdata['y1'] if xparam=='time': - xaxmax = tseconds.max() - xaxmin = tseconds.min() + xaxmax = tseconds.max() + xaxmin = tseconds.min() elif xparam=='distance' or xparam=='cumdist': - xaxmax = rowdata['x1'].max() - xaxmin = rowdata['x1'].min() + xaxmax = rowdata['x1'].max() + xaxmin = rowdata['x1'].min() else: - xaxmax = yaxmaxima[xparam] - xaxmin = yaxminima[xparam] + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] x_axis_type = 'linear' y_axis_type = 'linear' if xparam == 'time': - x_axis_type = 'datetime' + x_axis_type = 'datetime' if yparam1 == 'pace': - y_axis_type = 'datetime' - y1mean = rowdata.loc[:,'pace'].mean() + y_axis_type = 'datetime' + y1mean = rowdata.loc[:,'pace'].mean() rowdata['xname'] = axlabels[xparam] @@ -3506,14 +3506,14 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, # prepare data source = ColumnDataSource( - rowdata - ) + rowdata + ) sizing_mode = 'fixed' # 'scale_width' also looks nice with this example plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, plot_width=200,plot_height=150, - ) + ) @@ -3528,10 +3528,10 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, plot.yaxis.major_label_text_font_size = "7pt" if plottype=='line': - plot.line('x1','y1',source=source) + plot.line('x1','y1',source=source) elif plottype=='scatter': - plot.scatter('x1','y1',source=source,fill_alpha=0.4, - line_color=None) + plot.scatter('x1','y1',source=source,fill_alpha=0.4, + line_color=None) try: plot.xaxis.axis_label = axlabels[xparam] @@ -3551,45 +3551,45 @@ def thumbnail_flex_chart(rowdata,id=0,promember=0, plot.y_range = yrange1 if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): - xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) - plot.x_range = xrange1 + xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) + plot.x_range = xrange1 if xparam == 'time': - xrange1 = Range1d(start=xaxmin,end=xaxmax) - plot.x_range = xrange1 - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + xrange1 = Range1d(start=xaxmin,end=xaxmax) + plot.x_range = xrange1 + plot.xaxis[0].formatter = DatetimeTickFormatter( + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) if yparam1 == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) if yparam2 != 'None': - yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) - plot.extra_y_ranges["yax2"] = yrange2 + yrange2 = Range1d(start=yaxminima[yparam2],end=yaxmaxima[yparam2]) + plot.extra_y_ranges["yax2"] = yrange2 #= {"yax2": yrange2} - if plottype=='line': - plot.line('x1','y2',color="red",y_range_name="yax2", - source=source) + if plottype=='line': + plot.line('x1','y2',color="red",y_range_name="yax2", + source=source) - elif plottype=='scatter': - plot.scatter('x1','y2',source=source, - fill_alpha=0.4, - line_color=None,color="red",y_range_name="yax2") - - plot.add_layout(LinearAxis(y_range_name="yax2", - axis_label=axlabels[yparam2], + elif plottype=='scatter': + plot.scatter('x1','y2',source=source, + fill_alpha=0.4, + line_color=None,color="red",y_range_name="yax2") + + plot.add_layout(LinearAxis(y_range_name="yax2", + axis_label=axlabels[yparam2], major_label_text_font_size="7pt", axis_label_text_font_size="7pt", ),'right', @@ -3608,22 +3608,22 @@ def interactive_bar_chart(id=0,promember=0): rowdata.dropna(axis=0,how='any',inplace=True) if rowdata.empty: - return "","No Valid Data Available" + return "","No Valid Data Available" # Add hover to this comma-separated string and see what changes if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' source = ColumnDataSource( - rowdata - ) + rowdata + ) plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - toolbar_sticky=False, - plot_width=920, - tools=TOOLS) + toolbar_sticky=False, + plot_width=920, + tools=TOOLS) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -3646,25 +3646,25 @@ def interactive_bar_chart(id=0,promember=0): plot.xaxis.axis_label = "Time" plot.yaxis.axis_label = "Pace (/500m)" plot.xaxis[0].formatter = DatetimeTickFormatter( - hours ="", - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + hours ="", + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) plot.yaxis[0].formatter = DatetimeTickFormatter( - hours = "", - seconds = ["%S"], - minutes = ["%M"], - ) + hours = "", + seconds = ["%S"], + minutes = ["%M"], + ) ymax = 1.0e3*90 ymin = 1.0e3*180 if row.workouttype == 'water': - ymax = 1.0e3*90 - ymin = 1.0e3*210 + ymax = 1.0e3*90 + ymin = 1.0e3*210 plot.y_range = Range1d(ymin,ymax) @@ -3673,33 +3673,33 @@ def interactive_bar_chart(id=0,promember=0): hover.tooltips = OrderedDict([ - ('Time','@ftime'), - ('Pace','@fpace'), - ('HR','@hr{int}'), - ('SPM','@spm{1.1}'), - ]) + ('Time','@ftime'), + ('Pace','@fpace'), + ('HR','@hr{int}'), + ('SPM','@spm{1.1}'), + ]) hover.mode = 'mouse' plot.extra_y_ranges["hr"] = Range1d(start=100,end=200) plot.quad(left='time',top='hr_ut2',bottom='hr_bottom', - right='x_right',source=source,color="gray", - y_range_name="hr", legend=" 0] - + #datadf = datadf[datadf[xparam] > 0] - + # check if dataframe not empty if datadf.empty: - return ['','

No non-zero data in selection

','','No non-zero data in selection'] + return ['','

No non-zero data in selection

','','No non-zero data in selection'] if xparam != 'distance' and xparam != 'time' and xparam != 'cumdist': - xaxmax = yaxmaxima[xparam] - xaxmin = yaxminima[xparam] + xaxmax = yaxmaxima[xparam] + xaxmin = yaxminima[xparam] elif xparam == 'time': - xaxmax = tseconds.max() - xaxmin = tseconds.min() + xaxmax = tseconds.max() + xaxmin = tseconds.min() else: xaxmax = datadf['distance'].max() - xaxmin = datadf['distance'].min() + xaxmin = datadf['distance'].min() if yparam == 'distance': yaxmin = datadf['distance'].min() @@ -3771,28 +3771,28 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', # Add hover to this comma-separated string and see what changes if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair' if yparam == 'pace': - y_axis_type = 'datetime' + y_axis_type = 'datetime' yaxmax = 90.*1e3 yaxmin = 150.*1e3 if xparam == 'time': - x_axis_type = 'datetime' + x_axis_type = 'datetime' if xparam != 'time': - xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100. + xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100. else: - xvals = np.arange(100) + xvals = np.arange(100) plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - toolbar_location="above", + tools=TOOLS, + toolbar_location="above", plot_width=920,plot_height=500, - toolbar_sticky=False) + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -3848,12 +3848,12 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', ) TIPS = OrderedDict([ - ('time','@ftime'), + ('time','@ftime'), ('pace','@fpace'), - ('hr','@hr'), - ('spm','@spm{1.1}'), - ('distance','@distance{5}'), - ]) + ('hr','@hr'), + ('spm','@spm{1.1}'), + ('distance','@distance{5}'), + ]) hover = plot.select(type=HoverTool) hover.tooltips = TIPS @@ -3877,30 +3877,30 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', plot.yaxis.axis_label = axlabels[yparam] if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'): - xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) - plot.x_range = xrange1 + xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam]) + plot.x_range = xrange1 yrange1 = Range1d(start=yaxmin,end=yaxmax) plot.y_range = yrange1 if xparam == 'time': - xrange1 = Range1d(start=xaxmin,end=xaxmax) - plot.x_range = xrange1 - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + xrange1 = Range1d(start=xaxmin,end=xaxmax) + plot.x_range = xrange1 + plot.xaxis[0].formatter = DatetimeTickFormatter( + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) if yparam == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) script, div = components(plot) @@ -3909,7 +3909,7 @@ def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line', def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', - promember=0,plottype='line'): + promember=0,plottype='line'): @@ -3944,12 +3944,12 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', row2 = Workout.objects.get(id=id2) if rowdata1.empty: - return "","No Valid Data Available" + return "","No Valid Data Available" else: rowdata1.sort_values(by='time',ascending=True,inplace=True) if rowdata2.empty: - return "","No Valid Data Available" + return "","No Valid Data Available" else: rowdata2.sort_values(by='time',ascending=True,inplace=True) @@ -3965,16 +3965,16 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', x_axis_type = 'linear' y_axis_type = 'linear' if xparam == 'time': - x_axis_type = 'datetime' + x_axis_type = 'datetime' if yparam == 'pace': - y_axis_type = 'datetime' - ymax = 1.0e3*90 - ymin = 1.0e3*180 + y_axis_type = 'datetime' + ymax = 1.0e3*90 + ymin = 1.0e3*180 - if row1.workouttype == 'water': - ymax = 1.0e3*90 - ymin = 1.0e3*210 + if row1.workouttype == 'water': + ymax = 1.0e3*90 + ymin = 1.0e3*210 ftime1 = rowdata1.loc[:,'ftime'] ftime2 = rowdata2.loc[:,'ftime'] @@ -3993,53 +3993,53 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', spm2 = rowdata2.loc[:,'spm'] if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' data1 = pd.DataFrame( - dict( - x1=x1, - y1=y1, - ftime1=ftime1, - fpace1=fpace1, - hr1 = hr1, - spm1 = spm1, - distance1=distance1, - ) - ).dropna() + dict( + x1=x1, + y1=y1, + ftime1=ftime1, + fpace1=fpace1, + hr1 = hr1, + spm1 = spm1, + distance1=distance1, + ) + ).dropna() data2 = pd.DataFrame( - dict( - x2=x2, - y2=y2, - ftime2=ftime2, - fpace2=fpace2, - hr2 = hr2, - spm2 = spm2, - distance2=distance2, - ) - ).dropna() + dict( + x2=x2, + y2=y2, + ftime2=ftime2, + fpace2=fpace2, + hr2 = hr2, + spm2 = spm2, + distance2=distance2, + ) + ).dropna() source1 = ColumnDataSource( - data1 - ) + data1 + ) source2 = ColumnDataSource( - data2 - ) + data2 + ) ymean1 = data1['y1'].mean() ymean2 = data2['y2'].mean() # create interactive plot plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type, - tools=TOOLS, - plot_width=920, - toolbar_sticky=False) + tools=TOOLS, + plot_width=920, + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -4058,19 +4058,19 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', ) TIPS = OrderedDict([ - ('time','@ftime1'), + ('time','@ftime1'), ('pace','@fpace1'), - ('hr','@hr1'), - ('spm','@spm1{1.1}'), - ('distance','@distance1{5}'), - ]) + ('hr','@hr1'), + ('spm','@spm1{1.1}'), + ('distance','@distance1{5}'), + ]) TIPS2 = OrderedDict([ - ('time','@ftime2'), + ('time','@ftime2'), ('pace','@fpace2'), - ('hr','@hr2'), - ('spm','@spm2{1.1}'), - ('distance','@distance2{5}'), - ]) + ('hr','@hr2'), + ('spm','@spm2{1.1}'), + ('distance','@distance2{5}'), + ]) @@ -4081,19 +4081,19 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', if plottype=='line': - l1 = plot.line('x1','y1',source=source1, + l1 = plot.line('x1','y1',source=source1, color="blue",legend=row1.name, ) - l2 = plot.line('x2','y2',source=source2, + l2 = plot.line('x2','y2',source=source2, color="red",legend=row2.name, ) elif plottype=='scatter': - l1 = plot.scatter('x1','y1',source=source1,legend=row1.name, + l1 = plot.scatter('x1','y1',source=source1,legend=row1.name, fill_alpha=0.4, - line_color=None) - l2 = plot.scatter('x2','y2',source=source2,legend=row2.name, + line_color=None) + l2 = plot.scatter('x2','y2',source=source2,legend=row2.name, fill_alpha=0.4, - line_color=None,color="red") + line_color=None,color="red") plot.add_tools(HoverTool(renderers=[l1],tooltips=TIPS)) plot.add_tools(HoverTool(renderers=[l2],tooltips=TIPS2)) @@ -4124,21 +4124,21 @@ def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm', plot.add_layout(ylabel2) if xparam == 'time': - plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + plot.xaxis[0].formatter = DatetimeTickFormatter( + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) if yparam == 'pace': - plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + plot.yaxis[0].formatter = DatetimeTickFormatter( + seconds = ["%S"], + minutes = ["%M"] + ) plot.y_range = Range1d(ymin,ymax) @@ -4154,23 +4154,23 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0): rowdata.dropna(axis=0,how='any',inplace=True) if rowdata.empty: - return "","No Valid Data Available" + return "","No Valid Data Available" # Add hover to this comma-separated string and see what changes if (promember==1): - TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' + TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,hover,resize,crosshair' else: - TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' + TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,hover,crosshair' source = ColumnDataSource( - rowdata - ) + rowdata + ) plot = Figure(x_axis_type="datetime",y_axis_type="datetime", - tools=TOOLS, - plot_width=920, - toolbar_sticky=False) + tools=TOOLS, + plot_width=920, + toolbar_sticky=False) # add watermark plot.extra_y_ranges = {"watermark": watermarkrange} @@ -4193,17 +4193,17 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0): plot.xaxis.axis_label = "Time" plot.yaxis.axis_label = "Pace (/500m)" plot.xaxis[0].formatter = DatetimeTickFormatter( - hours = ["%H"], - minutes = ["%M"], - seconds = ["%S"], - days = ["0"], - months = [""], - years = [""] - ) + hours = ["%H"], + minutes = ["%M"], + seconds = ["%S"], + days = ["0"], + months = [""], + years = [""] + ) plot.yaxis[0].formatter = DatetimeTickFormatter( - seconds = ["%S"], - minutes = ["%M"] - ) + seconds = ["%S"], + minutes = ["%M"] + ) ymax = 1.0e3*90 ymin = 1.0e3*210 @@ -4217,12 +4217,12 @@ def interactive_otw_advanced_pace_chart(id=0,promember=0): plot.line('time','nowindpace',source=source,legend="Corrected Pace",color="red") hover.tooltips = OrderedDict([ - ('Time','@ftime'), - ('Pace','@fpace'), - ('Corrected Pace','@fnowindpace'), - ('HR','@hr{int}'), - ('SPM','@spm{1.1}'), - ]) + ('Time','@ftime'), + ('Pace','@fpace'), + ('Corrected Pace','@fnowindpace'), + ('HR','@hr{int}'), + ('SPM','@spm{1.1}'), + ]) hover.mode = 'mouse' diff --git a/rowers/longtask.py b/rowers/longtask.py index fda8bf90..c9380bea 100644 --- a/rowers/longtask.py +++ b/rowers/longtask.py @@ -72,7 +72,7 @@ def longtask2(aantal,jobid=None,debug=False,secret=''): counter = 0 progress = int(100.*i/aantal) if debug: - print progress + print(progress) if jobid != None: if debug: url = SITE_URL_DEV @@ -83,8 +83,8 @@ def longtask2(aantal,jobid=None,debug=False,secret=''): post_data = {"secret":secret} s = requests.post(url, data=post_data) if debug: - print url - print s + print(url) + print(s) return 1 diff --git a/rowers/mailprocessing.py b/rowers/mailprocessing.py index 95077670..ade6419d 100644 --- a/rowers/mailprocessing.py +++ b/rowers/mailprocessing.py @@ -92,7 +92,7 @@ def make_new_workout_from_email(rower, datafile, name, cntr=0,testing=False): fileformat = fileformat[2] if testing: - print 'Fileformat = ',fileformat + print('Fileformat = ',fileformat) if fileformat == 'unknown': # extension = datafilename[-4:].lower() diff --git a/rowers/management/commands/processemail.py b/rowers/management/commands/processemail.py index 52022e06..7bf213f7 100644 --- a/rowers/management/commands/processemail.py +++ b/rowers/management/commands/processemail.py @@ -188,7 +188,7 @@ class Command(BaseCommand): res = polarstuff.get_all_new_workouts(polar_available) # Concept2 - rowers = Rower.objects.filter(c2_auto_import=True) + rowers = Rower.objects.filter(c2_auto_import=True).exclude(rowerplan='basic') for r in rowers: c2stuff.get_c2_workouts(r) @@ -287,7 +287,7 @@ class Command(BaseCommand): message.delete() # Strava - rowers = Rower.objects.filter(strava_auto_import=True) + rowers = Rower.objects.filter(strava_auto_import=True).exclude(rowerplan='basic') for r in rowers: stravastuff.get_strava_workouts(r) diff --git a/rowers/metrics.py b/rowers/metrics.py index f2a53c0f..c5682b0e 100644 --- a/rowers/metrics.py +++ b/rowers/metrics.py @@ -1,6 +1,7 @@ -from utils import lbstoN +from __future__ import absolute_import +from rowers.utils import lbstoN import numpy as np -from models import C2WorldClassAgePerformance +from rowers.models import C2WorldClassAgePerformance import pandas as pd from scipy import optimize from django.utils import timezone diff --git a/rowers/models.py b/rowers/models.py index 93dcfa58..016db05e 100644 --- a/rowers/models.py +++ b/rowers/models.py @@ -1,4 +1,4 @@ -from __future__ import unicode_literals +from __future__ import unicode_literals, absolute_import from django.db import models,IntegrityError from django.contrib.auth.models import User @@ -7,8 +7,8 @@ from django.core.exceptions import ValidationError from django import forms from django.forms import ModelForm from django.dispatch import receiver -from django.forms.widgets import SplitDateTimeWidget -from django.forms.extras.widgets import SelectDateWidget +from django.forms.widgets import SplitDateTimeWidget,SelectDateWidget +#from django.forms.extras.widgets import SelectDateWidget from django.forms.formsets import BaseFormSet from django.contrib.admin.widgets import AdminDateWidget,AdminTimeWidget,AdminSplitDateTime from datetimewidget.widgets import DateTimeWidget @@ -35,7 +35,7 @@ from rowers.rows import validate_file_extension from collections import OrderedDict from timezonefinder import TimezoneFinder -import mytypes +import rowers.mytypes as mytypes from matplotlib import path from rowsandall_app.settings import ( @@ -108,7 +108,7 @@ class TemplateListField(models.TextField): def get_db_prep_value(self, value, connection, prepared=False): if not value: return assert(isinstance(value, list) or isinstance(value, tuple)) - return self.token.join([unicode(s) for s in value]) + return self.token.join([str(s) for s in value]) def value_to_string(self, obj): value = self._get_val_from_obj(obj) @@ -151,7 +151,7 @@ class PowerZonesField(models.TextField): def get_db_prep_value(self, value, connection, prepared=False): if not value: return assert(isinstance(value, list) or isinstance(value, tuple)) - return self.token.join([unicode(s) for s in value]) + return self.token.join([str(s) for s in value]) def value_to_string(self, obj): value = self._get_val_from_obj(obj) @@ -216,7 +216,7 @@ def update_records(url=c2url,verbose=True): ) try: if verbose: - print record + print(record) record.save() except: if verbose: @@ -228,9 +228,9 @@ def update_records(url=c2url,verbose=True): class CalcAgePerformance(models.Model): weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) + ('hwt','heavy-weight'), + ('lwt','light-weight'), + ) sexcategories = ( ('male','male'), @@ -261,7 +261,7 @@ class PowerTimeFitnessMetric(models.Model): date = models.DateField(default=current_day) last_workout = models.IntegerField(default=0) - user = models.ForeignKey(User) + user = models.ForeignKey(User,on_delete=models.CASCADE) PowerFourMin = models.FloatField(default=0) PowerTwoK = models.FloatField(default=0) PowerOneHour = models.FloatField(default=0) @@ -272,9 +272,9 @@ class PowerTimeFitnessMetric(models.Model): class C2WorldClassAgePerformance(models.Model): weightcategories = ( - ('hwt','heavy-weight'), - ('lwt','light-weight'), - ) + ('hwt','heavy-weight'), + ('lwt','light-weight'), + ) sexcategories = ( ('male','male'), @@ -334,7 +334,7 @@ class Team(models.Model): name = models.CharField(max_length=150,unique=True,verbose_name='Team Name') notes = models.CharField(blank=True,max_length=200,verbose_name='Team Purpose') - manager = models.ForeignKey(User, null=True,) # validators=[is_not_basic]) + manager = models.ForeignKey(User, null=True,on_delete=models.CASCADE) # validators=[is_not_basic]) private = models.CharField(max_length=30,choices=choices,default='open', verbose_name='Team Type') @@ -366,13 +366,13 @@ class TeamForm(ModelForm): class Meta: model = Team fields = ['name','notes','private','viewing'] - widgets = { - 'notes': forms.Textarea, - } + widgets = { + 'notes': forms.Textarea, + } class TeamInvite(models.Model): - team = models.ForeignKey(Team) - user = models.ForeignKey(User,null=True) + team = models.ForeignKey(Team,on_delete=models.CASCADE) + user = models.ForeignKey(User,null=True,on_delete=models.CASCADE) issuedate = models.DateField(default=current_day) code = models.CharField(max_length=150,unique=True) email = models.CharField(max_length=150,null=True,blank=True) @@ -388,17 +388,17 @@ class TeamInviteForm(ModelForm): class TeamRequest(models.Model): - team = models.ForeignKey(Team) - user = models.ForeignKey(User,null=True) + team = models.ForeignKey(Team,on_delete=models.CASCADE) + user = models.ForeignKey(User,null=True,on_delete=models.CASCADE) issuedate = models.DateField(default=current_day) code = models.CharField(max_length=150,unique=True) -from utils import ( +from rowers.utils import ( workflowleftpanel,workflowmiddlepanel, defaultleft,defaultmiddle,landingpages ) -from utils import geo_distance +from rowers.utils import geo_distance def polygon_coord_center(polygon): @@ -675,7 +675,7 @@ class Rower(models.Model): ('Workout','Workout'), ('Yoga','Yoga'), ) - user = models.OneToOneField(User) + user = models.OneToOneField(User,on_delete=models.CASCADE) #billing details country = CountryField(default=None, null=True, blank=True) @@ -688,7 +688,7 @@ class Rower(models.Model): blank=True,max_length=200) rowerplan = models.CharField(default='basic',max_length=30, - choices=plans) + choices=plans) paymenttype = models.CharField( default='single',max_length=30, verbose_name='Payment Type', @@ -699,7 +699,7 @@ class Rower(models.Model): null=True,blank=True, default='braintree') - paidplan = models.ForeignKey(PaidPlan,null=True,default=None) + paidplan = models.ForeignKey(PaidPlan,null=True,default=None,on_delete=models.SET_NULL) planexpires = models.DateField(default=current_day) teamplanexpires = models.DateField(default=current_day) @@ -726,8 +726,8 @@ class Rower(models.Model): # Weight Category (for sync to C2) weightcategory = models.CharField(default="hwt", - max_length=30, - choices=weightcategories) + max_length=30, + choices=weightcategories) sex = models.CharField(default="not specified", max_length=30, @@ -788,23 +788,23 @@ class Rower(models.Model): sporttrackstoken = models.CharField(default='',max_length=200,blank=True,null=True) sporttrackstokenexpirydate = models.DateTimeField(blank=True,null=True) sporttracksrefreshtoken = models.CharField(default='',max_length=200, - blank=True,null=True) + blank=True,null=True) sporttracks_auto_export = models.BooleanField(default=False) underarmourtoken = models.CharField(default='',max_length=200,blank=True,null=True) underarmourtokenexpirydate = models.DateTimeField(blank=True,null=True) underarmourrefreshtoken = models.CharField(default='',max_length=200, - blank=True,null=True) + blank=True,null=True) mapmyfitness_auto_export = models.BooleanField(default=False) tptoken = models.CharField(default='',max_length=1000,blank=True,null=True) tptokenexpirydate = models.DateTimeField(blank=True,null=True) tprefreshtoken = models.CharField(default='',max_length=1000, - blank=True,null=True) + blank=True,null=True) trainingpeaks_auto_export = models.BooleanField(default=False) polartoken = models.CharField(default='',max_length=1000,blank=True,null=True) polartokenexpirydate = models.DateTimeField(blank=True,null=True) polarrefreshtoken = models.CharField(default='',max_length=1000, - blank=True,null=True) + blank=True,null=True) polaruserid = models.IntegerField(default=0) polar_auto_import = models.BooleanField(default=False) @@ -813,8 +813,8 @@ class Rower(models.Model): stravarefreshtoken = models.CharField(default='',max_length=1000, blank=True,null=True) stravaexportas = models.CharField(default="Rowing", - max_length=30, - choices=stravatypes, + max_length=30, + choices=stravatypes, verbose_name="Export Workouts to Strava as") strava_auto_export = models.BooleanField(default=False) @@ -840,7 +840,7 @@ class Rower(models.Model): # Friends/Team friends = models.ManyToManyField("self",blank=True) - mycoachgroup = models.ForeignKey(CoachingGroup,related_name='coachingrole',null=True) + mycoachgroup = models.ForeignKey(CoachingGroup,related_name='coachingrole',null=True,on_delete=models.SET_NULL) coachinggroups = models.ManyToManyField(CoachingGroup,related_name='coaches') privacy = models.CharField(default='visible',max_length=30, choices=privacychoices) @@ -857,7 +857,7 @@ class Rower(models.Model): verbose_name='Show Notes for Favorite Charts') def __str__(self): - return self.user.first_name+' '+self.user.last_name + return self.user.first_name+' '+self.user.last_name def __unicode__(self): return self.user.first_name+' '+self.user.last_name @@ -881,15 +881,15 @@ class DeleteUserForm(forms.ModelForm): # requestor is user class CoachRequest(models.Model): - coach = models.ForeignKey(Rower) - user = models.ForeignKey(User,null=True) + coach = models.ForeignKey(Rower,on_delete=models.CASCADE) + user = models.ForeignKey(User,null=True,on_delete=models.CASCADE) issuedate = models.DateField(default=current_day) code = models.CharField(max_length=150,unique=True) # requestor is coach class CoachOffer(models.Model): - coach = models.ForeignKey(Rower) - user = models.ForeignKey(User,null=True) + coach = models.ForeignKey(Rower,on_delete=models.CASCADE) + user = models.ForeignKey(User,null=True,on_delete=models.CASCADE) issuedate = models.DateField(default=current_day) code = models.CharField(max_length=150,unique=True) @@ -956,7 +956,7 @@ class FavoriteChart(models.Model): reststrokes = models.BooleanField(default=True,verbose_name="Incl. Rest") notes = models.CharField(max_length=300,verbose_name='Chart Notes', default='Flex Chart Notes',blank=True) - user = models.ForeignKey(Rower) + user = models.ForeignKey(Rower,on_delete=models.CASCADE) class FavoriteForm(ModelForm): @@ -965,8 +965,8 @@ class FavoriteForm(ModelForm): fields = ['xparam','yparam1','yparam2', 'plottype','workouttype','reststrokes','notes'] # widgets = { -# 'notes': forms.Textarea, -# } +# 'notes': forms.Textarea, +# } # To generate favorite chart forms on the fly @@ -1009,7 +1009,7 @@ def checkworkoutuser(user,workout): if user.is_anonymous(): return False try: - r = Rower.objects.get(user=user) + r = Rower.objects.get(user=user) if workout.user == r: return True coaches = [] @@ -1022,7 +1022,26 @@ def checkworkoutuser(user,workout): else: return False except Rower.DoesNotExist: - return False + return False + +# Check if workout may be viewed by this user +def checkworkoutuserview(user,workout): + if user.is_anonymous(): + return False + try: + r = Rower.objects.get(user=user) + if workout.user == r: + return True + teams = workout.user.team.all() + + for team in teams: + if team in r.team.all(): + return True + return False + except Rower.DoesNotExist: + return False + + return False def checkviewworkouts(user,rower): try: @@ -1030,7 +1049,7 @@ def checkviewworkouts(user,rower): if rower == r: return True teams = Team.objects.filter(manager=user) - print Rower.objects.filter(team__in=teams) + print(Rower.objects.filter(team__in=teams)) if rower in Rower.objects.filter(team__in=teams): return True except Rower.DoesNotExist: @@ -1068,7 +1087,7 @@ def checkaccessuser(user,rower): else: return False except Rower.DoesNotExist: - return False + return False timezones = ( (x,x) for x in pytz.common_timezones @@ -1077,7 +1096,7 @@ timezones = ( # models related to geo data (points, polygon, courses) class GeoCourse(models.Model): - manager = models.ForeignKey(Rower) + manager = models.ForeignKey(Rower,null=True,on_delete=models.SET_NULL) distance = models.IntegerField(default=0) name = models.CharField(max_length=150,blank=True) country = models.CharField(max_length=150,blank=True) @@ -1108,7 +1127,7 @@ class GeoCourseEditForm(ModelForm): class GeoPolygon(models.Model): name = models.CharField(max_length=150,blank=True) - course = models.ForeignKey(GeoCourse, blank=True) + course = models.ForeignKey(GeoCourse, blank=True,on_delete=models.CASCADE) order_in_course = models.IntegerField(default=0) def __unicode__(self): @@ -1127,7 +1146,7 @@ class GeoPolygon(models.Model): class GeoPoint(models.Model): latitude = models.FloatField(default=0) longitude = models.FloatField(default=0) - polygon = models.ForeignKey(GeoPolygon,blank=True) + polygon = models.ForeignKey(GeoPolygon,blank=True,on_delete=models.CASCADE) order_in_poly = models.IntegerField(default=0) # need error checking to "insert" new point into existing polygon? This affects order_in_poly @@ -1140,7 +1159,7 @@ class GeoPoint(models.Model): class TrainingTarget(models.Model): rowers = models.ManyToManyField(Rower, related_name='targetathletes', verbose_name='Athletes') - manager = models.ForeignKey(Rower,related_name='targetmanager',null=True) + manager = models.ForeignKey(Rower,related_name='targetmanager',null=True,on_delete=models.CASCADE) name = models.CharField(max_length=150,blank=True) date = models.DateField( default=half_year_from_now) @@ -1172,9 +1191,9 @@ class TrainingTargetForm(ModelForm): model = TrainingTarget fields = ['name','date','notes','rowers'] - widgets = { - 'date': AdminDateWidget() - } + widgets = { + 'date': AdminDateWidget() + } def __init__(self,*args, **kwargs): user = kwargs.pop('user',None) @@ -1208,10 +1227,10 @@ class TrainingPlan(models.Model): rowers = models.ManyToManyField(Rower,related_name='planathletes', verbose_name='Athletes') - manager = models.ForeignKey(Rower,related_name='planmanager',null=True) + manager = models.ForeignKey(Rower,related_name='planmanager',null=True,on_delete=models.SET_NULL) name = models.CharField(max_length=150,blank=True) status = models.BooleanField(default=True,verbose_name='Active') - target = models.ForeignKey(TrainingTarget,blank=True,null=True) + target = models.ForeignKey(TrainingTarget,blank=True,null=True,on_delete=models.SET_NULL) startdate = models.DateField(default=current_day) enddate = models.DateField( default=half_year_from_now) @@ -1291,10 +1310,10 @@ class TrainingPlanForm(ModelForm): model = TrainingPlan fields = ['name','target','startdate','enddate','status','rowers'] - widgets = { - 'startdate': AdminDateWidget(), - 'enddate': AdminDateWidget() - } + widgets = { + 'startdate': AdminDateWidget(), + 'enddate': AdminDateWidget() + } def __init__(self,*args, **kwargs): targets = kwargs.pop('targets',None) @@ -1581,7 +1600,7 @@ def macrocyclecheckdates(plan): cycles = cycles[1:] class TrainingMacroCycle(models.Model): - plan = models.ForeignKey(TrainingPlan) + plan = models.ForeignKey(TrainingPlan,on_delete=models.CASCADE) name = models.CharField(max_length=150,blank=True) startdate = models.DateField(default=current_day) enddate = models.DateField( @@ -1663,13 +1682,13 @@ class TrainingMacroCycleForm(ModelForm): model = TrainingMacroCycle fields = ['name','startdate','enddate','notes'] - widgets = { - 'startdate': AdminDateWidget(), - 'enddate': AdminDateWidget() - } + widgets = { + 'startdate': AdminDateWidget(), + 'enddate': AdminDateWidget() + } class TrainingMesoCycle(models.Model): - plan = models.ForeignKey(TrainingMacroCycle) + plan = models.ForeignKey(TrainingMacroCycle,on_delete=models.CASCADE) name = models.CharField(max_length=150,blank=True) startdate = models.DateField(default=current_day) enddate = models.DateField( @@ -1745,7 +1764,7 @@ class TrainingMesoCycle(models.Model): class TrainingMicroCycle(models.Model): - plan = models.ForeignKey(TrainingMesoCycle) + plan = models.ForeignKey(TrainingMesoCycle,on_delete=models.CASCADE) name = models.CharField(max_length=150,blank=True) startdate = models.DateField(default=current_day) enddate = models.DateField( @@ -1815,20 +1834,20 @@ class TrainingMesoCycleForm(ModelForm): model = TrainingMesoCycle fields = ['name','startdate','enddate','notes'] - widgets = { - 'startdate': AdminDateWidget(), - 'enddate': AdminDateWidget() - } + widgets = { + 'startdate': AdminDateWidget(), + 'enddate': AdminDateWidget() + } class TrainingMicroCycleForm(ModelForm): class Meta: model = TrainingMicroCycle fields = ['name','startdate','enddate','notes'] - widgets = { - 'startdate': AdminDateWidget(), - 'enddate': AdminDateWidget() - } + widgets = { + 'startdate': AdminDateWidget(), + 'enddate': AdminDateWidget() + } regularsessiontypechoices = ( ('session','Training Session'), @@ -1884,9 +1903,9 @@ class PlannedSession(models.Model): ('None',None), ) - manager = models.ForeignKey(User) + manager = models.ForeignKey(User,on_delete=models.PROTECT) course = models.ForeignKey(GeoCourse,blank=True,null=True, - verbose_name='OTW Course') + verbose_name='OTW Course',on_delete=models.SET_NULL) name = models.CharField(max_length=150,blank=True, verbose_name='Name') @@ -1953,7 +1972,7 @@ class PlannedSession(models.Model): n = name, ) - return stri + return stri def save(self, *args, **kwargs): if self.sessionvalue <= 0: @@ -2056,7 +2075,7 @@ class VirtualRace(PlannedSession): n = name, ) - return stri + return stri def save(self, *args, **kwargs): @@ -2092,7 +2111,7 @@ class VirtualRace(PlannedSession): class RaceLogo(models.Model): filename = models.CharField(default='',max_length=150) creationdatetime = models.DateTimeField() - user = models.ForeignKey(User) + user = models.ForeignKey(User,on_delete=models.PROTECT) width = models.IntegerField(default=1200) height = models.IntegerField(default=600) race = models.ManyToManyField(VirtualRace,related_name='logos') @@ -2102,7 +2121,7 @@ class RaceLogo(models.Model): def delete(self, *args, **kwargs): os.remove(self.filename) - print 'file deleted' + print('file deleted') super(RaceLogo,self).delete(*args, **kwargs) # Date input utility @@ -2131,12 +2150,12 @@ class PlannedSessionForm(ModelForm): 'autoclose': True, } - widgets = { - 'comment': forms.Textarea, - 'startdate': AdminDateWidget(), - 'enddate': AdminDateWidget(), - 'preferreddate': AdminDateWidget(), - } + widgets = { + 'comment': forms.Textarea, + 'startdate': AdminDateWidget(), + 'enddate': AdminDateWidget(), + 'preferreddate': AdminDateWidget(), + } def __init__(self,*args,**kwargs): super(PlannedSessionForm, self).__init__(*args, **kwargs) @@ -2331,15 +2350,15 @@ class VirtualRaceForm(ModelForm): 'autoclose': True, } - widgets = { - 'comment': forms.Textarea, - 'startdate': AdminDateWidget(), - 'enddate': AdminDateWidget(), + widgets = { + 'comment': forms.Textarea, + 'startdate': AdminDateWidget(), + 'enddate': AdminDateWidget(), 'start_time': AdminTimeWidget(), 'end_time': AdminTimeWidget(), 'registration_closure':AdminSplitDateTime(), 'evaluation_closure':AdminSplitDateTime(), - } + } def __init__(self,*args,**kwargs): super(VirtualRaceForm, self).__init__(*args, **kwargs) @@ -2450,10 +2469,10 @@ class PlannedSessionFormSmall(ModelForm): 'autoclose': True, } - widgets = { - 'startdate': DateInput(attrs={'size':10}), - 'enddate': DateInput(attrs={'size':10}), - 'preferreddate': DateInput(attrs={'size':10}), + widgets = { + 'startdate': DateInput(attrs={'size':10}), + 'enddate': DateInput(attrs={'size':10}), + 'preferreddate': DateInput(attrs={'size':10}), 'name': forms.TextInput(attrs={'size':10}), 'sessionvalue': forms.TextInput(attrs={'style':'width:5em', 'type':'number'}), @@ -2473,10 +2492,10 @@ class Workout(models.Model): privacychoices = mytypes.privacychoices adaptivetypes = mytypes.adaptivetypes - user = models.ForeignKey(Rower) + user = models.ForeignKey(Rower,on_delete=models.CASCADE) team = models.ManyToManyField(Team,blank=True) plannedsession = models.ForeignKey(PlannedSession, blank=True,null=True, - verbose_name='Session') + verbose_name='Session',on_delete=models.SET_NULL) name = models.CharField(max_length=150,blank=True,null=True) date = models.DateField() workouttype = models.CharField(choices=workouttypes,max_length=50, @@ -2484,8 +2503,8 @@ class Workout(models.Model): workoutsource = models.CharField(max_length=100, default='unknown') boattype = models.CharField(choices=boattypes,max_length=50, - default='1x', - verbose_name = 'Boat Type') + default='1x', + verbose_name = 'Boat Type') adaptiveclass = models.CharField(choices=adaptivetypes,max_length=50, default='None', verbose_name='Adaptive Classification') @@ -2538,8 +2557,8 @@ class Workout(models.Model): def __unicode__(self): - date = self.date - name = self.name + date = self.date + name = self.name distance = str(self.distance) ownerfirst = self.user.user.first_name ownerlast = self.user.user.last_name @@ -2569,7 +2588,7 @@ class Workout(models.Model): ownerlast = ownerlast, ) - return stri + return stri # delete files belonging to workout instance # related GraphImage objects should be deleted automatically @@ -2577,11 +2596,11 @@ class Workout(models.Model): def auto_delete_file_on_delete(sender, instance, **kwargs): # delete CSV file if instance.csvfilename: - if os.path.isfile(instance.csvfilename): - os.remove(instance.csvfilename) + if os.path.isfile(instance.csvfilename): + os.remove(instance.csvfilename) if instance.csvfilename+'.gz': - if os.path.isfile(instance.csvfilename+'.gz'): - os.remove(instance.csvfilename+'.gz') + if os.path.isfile(instance.csvfilename+'.gz'): + os.remove(instance.csvfilename+'.gz') @receiver(models.signals.post_delete,sender=Workout) def update_duplicates_on_delete(sender, instance, **kwargs): @@ -2630,7 +2649,7 @@ def auto_delete_strokedata_on_delete(sender, instance, **kwargs): try: result = conn.execute(query) except: - print "Database Locked" + print("Database Locked") conn.close() engine.dispose() @@ -2648,7 +2667,7 @@ class VirtualRaceResult(models.Model): adaptiveclass = models.CharField(default="None",max_length=50, choices=mytypes.adaptivetypes, verbose_name="Adaptive Class") - race = models.ForeignKey(VirtualRace) + race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, @@ -2707,7 +2726,7 @@ class IndoorVirtualRaceResult(models.Model): adaptiveclass = models.CharField(default="None",max_length=50, choices=mytypes.adaptivetypes, verbose_name="Adaptive Class") - race = models.ForeignKey(VirtualRace) + race = models.ForeignKey(VirtualRace,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) boatclass = models.CharField(choices=boatclasses, @@ -2750,15 +2769,15 @@ class IndoorVirtualRaceResult(models.Model): class CourseTestResult(models.Model): userid = models.IntegerField(default=0) workoutid = models.IntegerField(null=True) - plannedsession = models.ForeignKey(PlannedSession) + plannedsession = models.ForeignKey(PlannedSession,on_delete=models.CASCADE) duration = models.TimeField(default=datetime.time(1,0)) distance = models.IntegerField(default=0) coursecompleted = models.BooleanField(default=False) class IndoorVirtualRaceResultForm(ModelForm): class Meta: - model = IndoorVirtualRaceResult - fields = ['teamname','weightcategory','boatclass','age','adaptiveclass'] + model = IndoorVirtualRaceResult + fields = ['teamname','weightcategory','boatclass','age','adaptiveclass'] def __init__(self, *args, **kwargs): @@ -2767,8 +2786,8 @@ class IndoorVirtualRaceResultForm(ModelForm): class VirtualRaceResultForm(ModelForm): class Meta: - model = VirtualRaceResult - fields = ['teamname','weightcategory','boatclass','boattype', + model = VirtualRaceResult + fields = ['teamname','weightcategory','boatclass','boattype', 'age','adaptiveclass'] @@ -2884,32 +2903,32 @@ class ergcpdata(models.Model): class GraphImage(models.Model): filename = models.CharField(default='',max_length=150,blank=True,null=True) creationdatetime = models.DateTimeField() - workout = models.ForeignKey(Workout) + workout = models.ForeignKey(Workout,on_delete=models.CASCADE) width = models.IntegerField(default=1200) height = models.IntegerField(default=600) def __str__(self): - return self.filename + return self.filename # delete related file object when image is deleted @receiver(models.signals.post_delete,sender=GraphImage) def auto_delete_image_on_delete(sender,instance, **kwargs): if instance.filename: - if os.path.isfile(instance.filename): + if os.path.isfile(instance.filename): others = GraphImage.objects.filter(filename=instance.filename) if len(others) == 0: - os.remove(instance.filename) - else: - print "couldn't find the file "+instance.filename + os.remove(instance.filename) + else: + print("couldn't find the file "+instance.filename) # Form to update Workout data class WorkoutForm(ModelForm): # duration = forms.TimeInput(format='%H:%M:%S.%f') class Meta: - model = Workout - fields = ['name', + model = Workout + fields = ['name', 'date', 'starttime', 'timezone', @@ -2923,11 +2942,11 @@ class WorkoutForm(ModelForm): 'rankingpiece', 'duplicate', 'plannedsession'] - widgets = { - 'date': AdminDateWidget(), - 'notes': forms.Textarea, - 'duration': forms.TimeInput(format='%H:%M:%S.%f'), - } + widgets = { + 'date': AdminDateWidget(), + 'notes': forms.Textarea, + 'duration': forms.TimeInput(format='%H:%M:%S.%f'), + } def __init__(self, *args, **kwargs): super(WorkoutForm, self).__init__(*args, **kwargs) @@ -2965,8 +2984,8 @@ class AdvancedWorkoutForm(ModelForm): quick_calc = forms.BooleanField(initial=True,required=False) class Meta: - model = Workout - fields = ['boattype','weightvalue','quick_calc'] + model = Workout + fields = ['boattype','weightvalue','quick_calc'] class RowerExportForm(ModelForm): class Meta: @@ -2987,8 +3006,8 @@ class RowerExportForm(ModelForm): # Simple form to set rower's Functional Threshold Power class RowerPowerForm(ModelForm): class Meta: - model = Rower - fields = ['hrftp','ftp','otwslack'] + model = Rower + fields = ['hrftp','ftp','otwslack'] # Form to set rower's Power zones, including test routines # to enable consistency @@ -3190,8 +3209,8 @@ class AccountRowerForm(ModelForm): 'defaultlandingpage', 'offercoaching'] - widgets = { - 'birthdate': SelectDateWidget( + widgets = { + 'birthdate': SelectDateWidget( years=range( timezone.now().year-100,timezone.now().year-10)), } @@ -3240,165 +3259,165 @@ class UserForm(ModelForm): # to enable consistency class RowerForm(ModelForm): class Meta: - model = Rower - fields = ['rest','ut2','ut1','at','tr','an','max'] + model = Rower + fields = ['rest','ut2','ut1','at','tr','an','max'] def clean_rest(self): - rest = self.cleaned_data['rest'] + rest = self.cleaned_data['rest'] - if rest<10: - self.data['rest']=10 - raise forms.ValidationError("Resting heart rate should be higher than 10 bpm") - + if rest<10: + self.data['rest']=10 + raise forms.ValidationError("Resting heart rate should be higher than 10 bpm") + - if rest>250: - self.data['rest'] = 250 - raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") + if rest>250: + self.data['rest'] = 250 + raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") - return rest + return rest def clean_ut2(self): - ut2 = self.cleaned_data['ut2'] + ut2 = self.cleaned_data['ut2'] - if ut2<10: - raise forms.ValidationError("UT2 heart rate should be higher than 10 bpm") + if ut2<10: + raise forms.ValidationError("UT2 heart rate should be higher than 10 bpm") - if ut2>250: - raise forms.ValidationError("UT2 heart rate should be lower than 250 bpm") + if ut2>250: + raise forms.ValidationError("UT2 heart rate should be lower than 250 bpm") - return ut2 + return ut2 def clean_ut1(self): - ut1 = self.cleaned_data['ut1'] + ut1 = self.cleaned_data['ut1'] - if ut1<10: - raise forms.ValidationError("UT1 heart rate should be higher than 10 bpm") + if ut1<10: + raise forms.ValidationError("UT1 heart rate should be higher than 10 bpm") - if ut1>250: - raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") + if ut1>250: + raise forms.ValidationError("Resting heart rate should be lower than 250 bpm") - return ut1 + return ut1 def clean_at(self): - at = self.cleaned_data['at'] + at = self.cleaned_data['at'] - if at<10: - raise forms.ValidationError("AT heart rate should be higher than 10 bpm") + if at<10: + raise forms.ValidationError("AT heart rate should be higher than 10 bpm") - if at>250: - raise forms.ValidationError("AT heart rate should be lower than 250 bpm") + if at>250: + raise forms.ValidationError("AT heart rate should be lower than 250 bpm") - return at + return at def clean_tr(self): - tr = self.cleaned_data['tr'] + tr = self.cleaned_data['tr'] - if tr<10: - raise forms.ValidationError("TR heart rate should be higher than 10 bpm") + if tr<10: + raise forms.ValidationError("TR heart rate should be higher than 10 bpm") - if tr>250: - raise forms.ValidationError("TR heart rate should be lower than 250 bpm") + if tr>250: + raise forms.ValidationError("TR heart rate should be lower than 250 bpm") - return tr + return tr def clean_an(self): - an = self.cleaned_data['an'] + an = self.cleaned_data['an'] - if an<10: - raise forms.ValidationError("AN heart rate should be higher than 10 bpm") + if an<10: + raise forms.ValidationError("AN heart rate should be higher than 10 bpm") - if an>250: - raise forms.ValidationError("AN heart rate should be lower than 250 bpm") + if an>250: + raise forms.ValidationError("AN heart rate should be lower than 250 bpm") - return an + return an def clean_max(self): - max = self.cleaned_data['max'] + max = self.cleaned_data['max'] - if max<10: - raise forms.ValidationError("Max heart rate should be higher than 10 bpm") + if max<10: + raise forms.ValidationError("Max heart rate should be higher than 10 bpm") - if max>250: - raise forms.ValidationError("Max heart rate should be lower than 250 bpm") + if max>250: + raise forms.ValidationError("Max heart rate should be lower than 250 bpm") - return max + return max def clean(self): - - try: - rest = self.cleaned_data['rest'] - except: + + try: + rest = self.cleaned_data['rest'] + except: try: - rest = int(self.data['rest']) + rest = int(self.data['rest']) except ValueError: rest = 0 - try: - ut2 = self.cleaned_data['ut2'] - except: + try: + ut2 = self.cleaned_data['ut2'] + except: try: - ut2 = self.data['ut2'] + ut2 = self.data['ut2'] except ValueError: ut2 = 0 - try: - ut1 = self.cleaned_data['ut1'] - except: + try: + ut1 = self.cleaned_data['ut1'] + except: try: - ut1 = self.data['ut1'] + ut1 = self.data['ut1'] except ValueError: ut1 = 0 - try: - at = self.cleaned_data['at'] - except: + try: + at = self.cleaned_data['at'] + except: try: - at = self.data['at'] + at = self.data['at'] except ValueError: at = 0 - try: - an = self.cleaned_data['an'] - except: + try: + an = self.cleaned_data['an'] + except: try: - an = self.data['an'] + an = self.data['an'] except ValueError: an = 0 - try: - tr = self.cleaned_data['tr'] - except: + try: + tr = self.cleaned_data['tr'] + except: try: - tr = self.data['tr'] + tr = self.data['tr'] except ValueError: tr = 0 - try: - max = self.cleaned_data['max'] - except: + try: + max = self.cleaned_data['max'] + except: try: - max = self.data['max'] + max = self.data['max'] except ValueError: max = 0 - - if rest>=ut2: - raise forms.ValidationError("Resting heart rate should be lower than UT2") - if ut2>=ut1: - raise forms.ValidationError("UT2 should be lower than UT1") - if ut2>=ut1: - raise forms.ValidationError("UT2 should be lower than UT1") - if ut1>=at: - raise forms.ValidationError("UT1 should be lower than AT") - if at>=tr: - raise forms.ValidationError("AT should be lower than TR") - if tr>=an: - raise forms.ValidationError("TR should be lower than AN") - if an>=max: - raise forms.ValidationError("AN should be lower than Max") + + if rest>=ut2: + raise forms.ValidationError("Resting heart rate should be lower than UT2") + if ut2>=ut1: + raise forms.ValidationError("UT2 should be lower than UT1") + if ut2>=ut1: + raise forms.ValidationError("UT2 should be lower than UT1") + if ut1>=at: + raise forms.ValidationError("UT1 should be lower than AT") + if at>=tr: + raise forms.ValidationError("AT should be lower than TR") + if tr>=an: + raise forms.ValidationError("TR should be lower than AN") + if an>=max: + raise forms.ValidationError("AN should be lower than Max") # An announcement that goes to the right of the workouts list @@ -3431,8 +3450,8 @@ class WorkoutComment(models.Model): created = models.DateTimeField(default=timezone.now) read = models.BooleanField(default=False) notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications") - user = models.ForeignKey(User) - workout = models.ForeignKey(Workout) + user = models.ForeignKey(User,on_delete=models.PROTECT) + workout = models.ForeignKey(Workout,on_delete=models.CASCADE) def __unicode__(self): return u'Comment to: {w} by {u1} {u2}'.format( @@ -3446,9 +3465,9 @@ class WorkoutCommentForm(ModelForm): class Meta: model = WorkoutComment fields = ['comment','notification'] - widgets = { - 'comment': forms.Textarea, - } + widgets = { + 'comment': forms.Textarea, + } # A comment by a user on a training class PlannedSessionComment(models.Model): @@ -3456,8 +3475,8 @@ class PlannedSessionComment(models.Model): created = models.DateTimeField(default=timezone.now) read = models.BooleanField(default=False) notification = models.BooleanField(default=True,verbose_name="Subscribe to new comment notifications") - user = models.ForeignKey(User) - plannedsession = models.ForeignKey(PlannedSession) + user = models.ForeignKey(User,on_delete=models.PROTECT) + plannedsession = models.ForeignKey(PlannedSession,on_delete=models.CASCADE) def __unicode__(self): return u'Comment to: {w} by {u1} {u2}'.format( @@ -3471,8 +3490,8 @@ class PlannedSessionCommentForm(ModelForm): class Meta: model = PlannedSessionComment fields = ['comment','notification'] - widgets = { - 'comment': forms.Textarea, - } + widgets = { + 'comment': forms.Textarea, + } diff --git a/rowers/mytypes.py b/rowers/mytypes.py index 662481a9..3eb903d2 100644 --- a/rowers/mytypes.py +++ b/rowers/mytypes.py @@ -1,3 +1,5 @@ +from six import iteritems + workouttypes = ( ('water','Standard Racing Shell'), ('rower','Indoor Rower'), @@ -208,15 +210,15 @@ c2mapping = { } -c2mappinginv = {value:key for key,value in c2mapping.iteritems() if value is not None} +c2mappinginv = {value:key for key,value in iteritems(c2mapping) if value is not None} -stravamappinginv = {value:key for key,value in stravamapping.iteritems() if value is not None} +stravamappinginv = {value:key for key,value in iteritems(stravamapping) if value is not None} -stmappinginv = {value:key for key,value in stmapping.iteritems() if value is not None} +stmappinginv = {value:key for key,value in iteritems(stmapping) if value is not None} -rkmappinginv = {value:key for key,value in rkmapping.iteritems() if value is not None} +rkmappinginv = {value:key for key,value in iteritems(rkmapping) if value is not None} -polarmappinginv = {value:key for key,value in polarmapping.iteritems() if value is not None} +polarmappinginv = {value:key for key,value in iteritems(polarmapping) if value is not None} otwtypes = ( 'water', diff --git a/rowers/ownapistuff.py b/rowers/ownapistuff.py index 8f5ec305..2164b2cb 100644 --- a/rowers/ownapistuff.py +++ b/rowers/ownapistuff.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # Interactions with Rowsandall.com API. Not fully complete. # Python @@ -15,7 +16,7 @@ import math from math import sin,cos,atan2,sqrt import urllib -import c2stuff +import rowers.c2stuff as c2stuff # Django from django.shortcuts import render_to_response @@ -41,13 +42,13 @@ TEST_REDIRECT_URI = "http://localhost:8000/rowers/test_callback" def custom_exception_handler(exc,message): response = { - "errors": [ - { - "code": str(exc), - "detail": message, - } - ] - } + "errors": [ + { + "code": str(exc), + "detail": message, + } + ] + } res = HttpResponse(message) res.status_code = 401 @@ -58,27 +59,27 @@ def custom_exception_handler(exc,message): def do_refresh_token(refreshtoken): client_auth = requests.auth.HTTPBasicAuth(TEST_CLIENT_ID, TEST_CLIENT_SECRET) post_data = {"grant_type": "refresh_token", - "client_secret": TEST_CLIENT_SECRET, - "client_id":TEST_CLIENT_ID, - "refresh_token": refreshtoken, - } + "client_secret": TEST_CLIENT_SECRET, + "client_id":TEST_CLIENT_ID, + "refresh_token": refreshtoken, + } headers = {'user-agent': 'sanderroosendaal', - 'Accept': 'application/json', - 'Content-Type': 'application/json'} + 'Accept': 'application/json', + 'Content-Type': 'application/json'} url = "http://localhost:8000/rowers/o/token" response = requests.post(url, data=json.dumps(post_data), - headers=headers) + headers=headers) token_json = response.json() thetoken = token_json['access_token'] expires_in = token_json['expires_in'] try: - refresh_token = token_json['refresh_token'] + refresh_token = token_json['refresh_token'] except KeyError: - refresh_token = refreshtoken + refresh_token = refreshtoken return [thetoken,expires_in,refresh_token] @@ -88,18 +89,18 @@ def get_token(code): post_data = {"grant_type": "authorization_code", "code": code, "redirect_uri": "http://localhost:8000/rowers/test_callback", - "client_secret": "aapnootmies", - "client_id":1, - } + "client_secret": "aapnootmies", + "client_id":1, + } headers = {'Accept': 'application/json', - 'Content-Type': 'application/json'} + 'Content-Type': 'application/json'} url = "http://localhost:8000/rowers/o/token/" response = requests.post(url, data=json.dumps(post_data), - headers=headers) + headers=headers) token_json = response.json() thetoken = token_json['access_token'] @@ -118,8 +119,8 @@ def make_authorization_url(request): params = {"client_id": TEST_CLIENT_ID, "response_type": "code", "redirect_uri": TEST_REDIRECT_URI, - "scope":"write", - "state":state} + "scope":"write", + "state":state} import urllib @@ -147,19 +148,19 @@ def rower_ownapi_token_refresh(user): def get_ownapi_workout_list(user): r = Rower.objects.get(user=user) if (r.ownapitoken == '') or (r.ownapitoken is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) elif (timezone.now()>r.ownapitokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.ownapitoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.ownapi.mobi/api/v2/fitnessActivities" - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.ownapitoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.ownapi.mobi/api/v2/fitnessActivities" + s = requests.get(url,headers=headers) return s @@ -167,19 +168,19 @@ def get_ownapi_workout_list(user): def get_ownapi_workout(user,ownapiid): r = Rower.objects.get(user=user) if (r.ownapitoken == '') or (r.ownapitoken is None): - return custom_exception_handler(401,s) - s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" elif (timezone.now()>r.ownapitokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.ownapitoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.ownapi.mobi/api/v2/fitnessActivities/"+str(ownapiid) - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.ownapitoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.ownapi.mobi/api/v2/fitnessActivities/"+str(ownapiid) + s = requests.get(url,headers=headers) return s @@ -203,16 +204,16 @@ def createownapiworkoutdata(w): haslatlon=1 try: - lat = row.df[' latitude'].values - lon = row.df[' longitude'].values + lat = row.df[' latitude'].values + lon = row.df[' longitude'].values except KeyError: - haslatlon = 0 + haslatlon = 0 haspower = 1 try: - power = row.df[' Power (watts)'].values + power = row.df[' Power (watts)'].values except KeyError: - haspower = 0 + haspower = 0 locdata = [] hrdata = [] @@ -221,54 +222,54 @@ def createownapiworkoutdata(w): powerdata = [] for i in range(len(t)): - hrdata.append(t[i]) - hrdata.append(hr[i]) - distancedata.append(t[i]) - distancedata.append(d[i]) - spmdata.append(t[i]) - spmdata.append(spm[i]) - if haslatlon: - locdata.append(t[i]) - locdata.append([lat[i],lon[i]]) - if haspower: - powerdata.append(t[i]) - powerdata.append(power[i]) + hrdata.append(t[i]) + hrdata.append(hr[i]) + distancedata.append(t[i]) + distancedata.append(d[i]) + spmdata.append(t[i]) + spmdata.append(spm[i]) + if haslatlon: + locdata.append(t[i]) + locdata.append([lat[i],lon[i]]) + if haspower: + powerdata.append(t[i]) + powerdata.append(power[i]) if haslatlon: - data = { - "type": "Rowing", - "name": w.name, -# "start_time": str(w.date)+"T"+str(w.starttime)+"Z", - "start_time": w.startdatetime.isoformat(), - "total_distance": int(w.distance), - "duration": int(max(t)), - "notes": w.notes, - "avg_heartrate": averagehr, - "max_heartrate": maxhr, - "location": locdata, - "distance": distancedata, - "cadence": spmdata, - "heartrate": hrdata, - } + data = { + "type": "Rowing", + "name": w.name, +# "start_time": str(w.date)+"T"+str(w.starttime)+"Z", + "start_time": w.startdatetime.isoformat(), + "total_distance": int(w.distance), + "duration": int(max(t)), + "notes": w.notes, + "avg_heartrate": averagehr, + "max_heartrate": maxhr, + "location": locdata, + "distance": distancedata, + "cadence": spmdata, + "heartrate": hrdata, + } else: - data = { - "type": "Rowing", - "name": w.name, -# "start_time": str(w.date)+"T"+str(w.starttime)+"Z", - "start_time": w.startdatetime.isoformat(), - "total_distance": int(w.distance), - "duration": int(max(t)), - "notes": w.notes, - "avg_heartrate": averagehr, - "max_heartrate": maxhr, - "distance": distancedata, - "cadence": spmdata, - "heartrate": hrdata, - } + data = { + "type": "Rowing", + "name": w.name, +# "start_time": str(w.date)+"T"+str(w.starttime)+"Z", + "start_time": w.startdatetime.isoformat(), + "total_distance": int(w.distance), + "duration": int(max(t)), + "notes": w.notes, + "avg_heartrate": averagehr, + "max_heartrate": maxhr, + "distance": distancedata, + "cadence": spmdata, + "heartrate": hrdata, + } if haspower: - data['power'] = powerdata + data['power'] = powerdata return data diff --git a/rowers/plannedsessions.py b/rowers/plannedsessions.py index 756cf751..76ffccd6 100644 --- a/rowers/plannedsessions.py +++ b/rowers/plannedsessions.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # Python from django.utils import timezone from datetime import datetime @@ -10,7 +11,7 @@ import uuid from django.conf import settings import pytz from dateutil import parser -from utils import myqueue,calculate_age,totaltime_sec_to_string +from rowers.utils import myqueue,calculate_age,totaltime_sec_to_string import re import django_rq queue = django_rq.get_queue('default') @@ -30,10 +31,10 @@ from rowers.emails import htmlstrip,htmlstripnobr import rowers.mytypes as mytypes -import metrics +import rowers.metrics as metrics import numpy as np -import dataprep -import courses +import rowers.dataprep as dataprep +import rowers.courses as courses import iso8601 from iso8601 import ParseError from rowers.tasks import handle_check_race_course @@ -473,13 +474,14 @@ def remove_rower_session(r,ps): return 1 -def get_dates_timeperiod(request,startdatestring='',enddatestring=''): +def get_dates_timeperiod(request,startdatestring='',enddatestring='', + defaulttimeperiod='thisweek'): # set start end date according timeperiod timeperiod = request.GET.get('when') if not timeperiod: - timeperiod = 'thisweek' + timeperiod = defaulttimeperiod startdatestring = request.GET.get('startdate') enddatestring = request.GET.get('enddate') @@ -536,6 +538,10 @@ def get_dates_timeperiod(request,startdatestring='',enddatestring=''): enddate = startdate+timezone.timedelta(days=32) enddate = enddate.replace(day=1) enddate = enddate-timezone.timedelta(days=1) + elif timeperiod=='lastyear': + today = date.today() + startdate = today-timezone.timedelta(days=365) + enddate = today+timezone.timedelta(days=1) elif daterangetester.match(timeperiod): tstartdatestring = daterangetester.match(timeperiod).group(1) tenddatestring = daterangetester.match(timeperiod).group(2) diff --git a/rowers/plots.py b/rowers/plots.py index 7760346c..bdd216c1 100644 --- a/rowers/plots.py +++ b/rowers/plots.py @@ -2,14 +2,14 @@ from matplotlib.ticker import MultipleLocator,FuncFormatter,NullFormatter import matplotlib.pyplot as plt import numpy as np -from rows import format_pace_tick, format_pace, format_time, format_time_tick +from rowers.rows import format_pace_tick, format_pace, format_time, format_time_tick # Formatting the distance tick marks #def format_dist_tick(x,pos=None): -# km = x/1000. -# template='%6.3f' -# return template % (km) +# km = x/1000. +# template='%6.3f' +# return template % (km) # Utility to select reasonable y axis range @@ -32,23 +32,23 @@ def y_axis_range(ydata,miny=0,padding=.1,ultimate=[-1e9,1e9]): if (yrange == 0): - if ymin == 0: - yrangemin = -padding - else: - yrangemin = ymin-ymin*padding - if ymax == 0: - yrangemax = padding - else: - yrangemax = ymax+ymax*padding + if ymin == 0: + yrangemin = -padding + else: + yrangemin = ymin-ymin*padding + if ymax == 0: + yrangemax = padding + else: + yrangemax = ymax+ymax*padding else: - yrangemin = ymin-padding*yrange - yrangemax = ymax+padding*yrange + yrangemin = ymin-padding*yrange + yrangemax = ymax+padding*yrange if (yrangemin < ultimate[0]): - yrangemin = ultimate[0] + yrangemin = ultimate[0] if (yrangemax > ultimate[1]): - yrangemax = ultimate[1] + yrangemax = ultimate[1] @@ -70,7 +70,7 @@ def mkplot(row,title): ax1.set_ylabel('(sec/500)') yrange = y_axis_range(df.loc[:,' Stroke500mPace (sec/500m)'], - ultimate = [85,190]) + ultimate = [85,190]) plt.axis([0,end_time,yrange[1],yrange[0]]) ax1.set_xticks(range(1000,end_time,1000)) @@ -80,11 +80,11 @@ def mkplot(row,title): majorFormatter = FuncFormatter(format_pace_tick) majorLocator = (5) timeTickFormatter = NullFormatter() - + ax1.yaxis.set_major_formatter(majorFormatter) for tl in ax1.get_yticklabels(): - tl.set_color('b') + tl.set_color('b') ax2 = ax1.twinx() ax2.plot(t,hr,'r-') @@ -94,7 +94,7 @@ def mkplot(row,title): ax2.xaxis.set_major_formatter(majorTimeFormatter) ax2.patch.set_alpha(0.0) for tl in ax2.get_yticklabels(): - tl.set_color('r') + tl.set_color('r') plt.subplots_adjust(hspace=0) diff --git a/rowers/polarstuff.py b/rowers/polarstuff.py index 83c1b6d1..3793fa28 100644 --- a/rowers/polarstuff.py +++ b/rowers/polarstuff.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # All the functionality needed to connect to Strava # Python @@ -33,8 +34,8 @@ from rowingdata import rowingdata import pandas as pd from rowers.models import Rower,Workout from rowers.models import checkworkoutuser -import dataprep -from dataprep import columndict +import rowers.dataprep as dataprep +from rowers.dataprep import columndict from io import StringIO @@ -51,8 +52,8 @@ from rowsandall_app.settings import ( baseurl = 'https://polaraccesslink.com/v3' -from utils import NoTokenError, custom_exception_handler -import mytypes +from rowers.utils import NoTokenError, custom_exception_handler +import rowers.mytypes as mytypes # Exchange access code for long-lived access token def get_token(code): @@ -126,7 +127,7 @@ from rowers.utils import isprorower def get_all_new_workouts(available_data,testing=False): for record in available_data: if testing: - print record + print(record) if record['data-type'] == 'EXERCISE': try: r = Rower.objects.get(polaruserid=record['user-id']) @@ -134,7 +135,7 @@ def get_all_new_workouts(available_data,testing=False): if r.polar_auto_import and isprorower(r): exercise_list = get_polar_workouts(u) if testing: - print exercise_list + print(exercise_list) except Rower.DoesNotExist: pass @@ -313,8 +314,6 @@ def get_polar_workout(user,id,transactionid): response = requests.get(url,headers = headers2) if response.status_code == 200: - print response.text - result = response.text # commit transaction response = requests.put(url,headers=headers) diff --git a/rowers/rows.py b/rowers/rows.py index 642b0593..faba7aee 100644 --- a/rowers/rows.py +++ b/rowers/rows.py @@ -6,29 +6,29 @@ from django.core.exceptions import ValidationError def format_pace_tick(x,pos=None): minu=int(x/60) - sec=int(x-minu*60.) - sec_str=str(sec).zfill(2) - template='%d:%s' - return template % (minu,sec_str) + sec=int(x-minu*60.) + sec_str=str(sec).zfill(2) + template='%d:%s' + return template % (minu,sec_str) def format_time_tick(x,pos=None): - hour=int(x/3600) - min=int((x-hour*3600.)/60) - min_str=str(min).zfill(2) - template='%d:%s' - return template % (hour,min_str) + hour=int(x/3600) + min=int((x-hour*3600.)/60) + min_str=str(min).zfill(2) + template='%d:%s' + return template % (hour,min_str) def format_pace(x,pos=None): if isinf(x) or isnan(x): - x=0 - + x=0 + min=int(x/60) sec=(x-min*60.) str1 = "{min:0>2}:{sec:0>4.1f}".format( - min = min, - sec = sec - ) + min = min, + sec = sec + ) return str1 @@ -39,9 +39,9 @@ def format_time(x,pos=None): sec = int(x-min*60) str1 = "{min:0>2}:{sec:0>4.1f}".format( - min=min, - sec=sec, - ) + min=min, + sec=sec, + ) return str1 @@ -67,14 +67,14 @@ def must_be_csv(value): ext = os.path.splitext(value.name)[1] valid_extensions = ['.csv','.CSV'] if not ext in valid_extensions: - raise ValidationError(u'File not supported!') + raise ValidationError(u'File not supported!') def validate_kml(value): import os ext = os.path.splitext(value.name)[1] valid_extensions = ['.kml','.KML'] if not ext in valid_extensions: - raise ValidationError(u'File not supported!') + raise ValidationError(u'File not supported!') def handle_uploaded_image(i): @@ -83,7 +83,7 @@ def handle_uploaded_image(i): import os from django.core.files import File image_str = "" - for chunk in i.chunks(): + for chunk in i.chunks(): image_str += chunk imagefile = StringIO.StringIO(image_str) @@ -133,8 +133,8 @@ def handle_uploaded_file(f): fname = timestr+'-'+fname fname2 = 'media/'+fname with open(fname2,'wb+') as destination: - for chunk in f.chunks(): - destination.write(chunk) + for chunk in f.chunks(): + destination.write(chunk) return fname,fname2 diff --git a/rowers/runkeeperstuff.py b/rowers/runkeeperstuff.py index 7bfa2207..83f7060a 100644 --- a/rowers/runkeeperstuff.py +++ b/rowers/runkeeperstuff.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # All the functionality needed to connect to Runkeeper from rowers.imports import * import re @@ -61,16 +62,16 @@ def make_authorization_url(request): def get_runkeeper_workout_list(user): r = Rower.objects.get(user=user) if (r.runkeepertoken == '') or (r.runkeepertoken is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.runkeepertoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.runkeeper.com/fitnessActivities" - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.runkeepertoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.runkeeper.com/fitnessActivities" + s = requests.get(url,headers=headers) return s @@ -78,16 +79,16 @@ def get_runkeeper_workout_list(user): def get_workout(user,runkeeperid): r = Rower.objects.get(user=user) if (r.runkeepertoken == '') or (r.runkeepertoken is None): - return custom_exception_handler(401,s) - s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.runkeepertoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid) - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.runkeepertoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.runkeeper.com/fitnessActivities/"+str(runkeeperid) + s = requests.get(url,headers=headers) try: data = s.json() @@ -131,12 +132,12 @@ def createrunkeeperworkoutdata(w): haslatlon=1 try: - lat = row.df[' latitude'].values - lon = row.df[' longitude'].values + lat = row.df[' latitude'].values + lon = row.df[' longitude'].values if not lat.std() and not lon.std(): haslatlon = 0 except KeyError: - haslatlon = 0 + haslatlon = 0 # path data if haslatlon: @@ -172,32 +173,32 @@ def createrunkeeperworkoutdata(w): newnotes = 'from '+w.workoutsource+' via rowsandall.com' if haslatlon: - data = { - "type": "Rowing", - "start_time": start_time, - "total_distance": int(w.distance), - "duration": duration, - "notes": newnotes, - "average_heart_rate": averagehr, - "path": locdata, - "distance": distancedata, - "heart_rate": hrdata, + data = { + "type": "Rowing", + "start_time": start_time, + "total_distance": int(w.distance), + "duration": duration, + "notes": newnotes, + "average_heart_rate": averagehr, + "path": locdata, + "distance": distancedata, + "heart_rate": hrdata, "post_to_twitter":"false", "post_to_facebook":"false", - } + } else: - data = { - "type": "Rowing", - "start_time": start_time, - "total_distance": int(w.distance), - "duration": duration, - "notes": newnotes, - "avg_heartrate": averagehr, - "distance": distancedata, - "heart_rate": hrdata, + data = { + "type": "Rowing", + "start_time": start_time, + "total_distance": int(w.distance), + "duration": duration, + "notes": newnotes, + "avg_heartrate": averagehr, + "distance": distancedata, + "heart_rate": hrdata, "post_to_twitter":"false", "post_to_facebook":"false", - } + } return data @@ -215,8 +216,8 @@ def getidfromresponse(response): def geturifromid(access_token,id): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} import urllib url = "https://api.runkeeper.com/fitnessActivities/"+str(id) response = requests.get(url,headers=headers) @@ -238,8 +239,8 @@ def geturifromid(access_token,id): def get_userid(access_token): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} import urllib url = "https://api.runkeeper.com/user" response = requests.get(url,headers=headers) @@ -269,42 +270,42 @@ def workout_runkeeper_upload(user,w): # ready to upload. Hurray if (checkworkoutuser(user,w)): - data = createrunkeeperworkoutdata(w) + data = createrunkeeperworkoutdata(w) if not data: message = "Data error in Runkeeper Upload" rkid = 0 return message, rkid - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json', + authorizationstring = str('Bearer ' + thetoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json', 'Content-Length':'nnn'} - url = "https://api.runkeeper.com/fitnessActivities" - response = requests.post(url,headers=headers,data=json.dumps(data)) + url = "https://api.runkeeper.com/fitnessActivities" + response = requests.post(url,headers=headers,data=json.dumps(data)) - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" - w.uploadedtorunkeeper = -1 + # check for duplicate error first + if (response.status_code == 409 ): + message = "Duplicate error" + w.uploadedtorunkeeper = -1 rkid = -1 - w.save() + w.save() return message, rkid - elif (response.status_code == 201 or response.status_code==200): - rkid = getidfromresponse(response) + elif (response.status_code == 201 or response.status_code==200): + rkid = getidfromresponse(response) rkuri = geturifromid(thetoken,rkid) - w.uploadedtorunkeeper = rkid - w.save() + w.uploadedtorunkeeper = rkid + w.save() return 'Successfully synchronized to Runkeeper',rkid - else: - s = response - message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text) + else: + s = response + message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text) rkid = 0 return message, rkid - + else: - message = "You are not authorized to upload this workout" + message = "You are not authorized to upload this workout" rkid = 0 return message, rkid @@ -316,41 +317,41 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper', # To Do - add utcoffset to time workouttype = data['type'] if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' + workouttype = 'other' try: - comments = data['notes'] + comments = data['notes'] except: - comments = '' + comments = '' try: - utcoffset = tz(data['utcoffset']) + utcoffset = tz(data['utcoffset']) except: - utcoffset = 0 + utcoffset = 0 r = Rower.objects.get(user=user) try: - rowdatetime = iso8601.parse_date(data['start_time']) + rowdatetime = iso8601.parse_date(data['start_time']) except iso8601.ParseError: - try: - rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except ValueError: - try: - rowdatetime = parser.parse(data['start_time']) - #rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + try: + rowdatetime = datetime.strptime(data['start_time'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except ValueError: + try: + rowdatetime = parser.parse(data['start_time']) + #rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except: + rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) starttimeunix = arrow.get(rowdatetime).timestamp #starttimeunix = mktime(rowdatetime.utctimetuple()) starttimeunix += utcoffset*3600 - + try: - title = data['name'] + title = data['name'] except: - title = "Imported data" + title = "Imported data" @@ -360,35 +361,35 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper', times_distance = res[0] try: - l = data['path'] + l = data['path'] - res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude') - times_location = res[0] - latcoord = res[1] - loncoord = res[2] + res = splitrunkeeperlatlongdata(l,'timestamp','latitude','longitude') + times_location = res[0] + latcoord = res[1] + loncoord = res[2] except: - times_location = times_distance - latcoord = np.zeros(len(times_distance)) - loncoord = np.zeros(len(times_distance)) + times_location = times_distance + latcoord = np.zeros(len(times_distance)) + loncoord = np.zeros(len(times_distance)) if workouttype in types.otwtypes: workouttype = 'rower' - + try: - res = splitrunkeeperdata(data['cadence'],'timestamp','cadence') - times_spm = res[0] - spm = res[1] + res = splitrunkeeperdata(data['cadence'],'timestamp','cadence') + times_spm = res[0] + spm = res[1] except KeyError: - times_spm = times_distance - spm = 0*times_distance + times_spm = times_distance + spm = 0*times_distance try: - res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate') - hr = res[1] - times_hr = res[0] + res = splitrunkeeperdata(data['heart_rate'],'timestamp','heart_rate') + hr = res[1] + times_hr = res[0] except KeyError: - times_hr = times_distance - hr = 0*times_distance + times_hr = times_distance + hr = 0*times_distance # create data series and remove duplicates @@ -417,12 +418,12 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper', # Create dicts and big dataframe d = { - ' Horizontal (meters)': distseries, - ' latitude': latseries, - ' longitude': lonseries, - ' Cadence (stokes/min)': spmseries, - ' HRCur (bpm)' : hrseries, - } + ' Horizontal (meters)': distseries, + ' latitude': latseries, + ' longitude': lonseries, + ' Cadence (stokes/min)': spmseries, + ' HRCur (bpm)' : hrseries, + } @@ -469,7 +470,7 @@ def add_workout_from_data(user,importid,data,strokedata,source='runkeeper', df = df.fillna(0) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") # csvfilename ='media/Import_'+str(importid)+'.csv' diff --git a/rowers/serializers.py b/rowers/serializers.py index 3ecbdd49..6ecef2a3 100644 --- a/rowers/serializers.py +++ b/rowers/serializers.py @@ -74,20 +74,20 @@ class WorkoutSerializer(serializers.ModelSerializer): t.second) w = Workout(user=r, name=validated_data['name'], - date=validated_data['date'], + date=validated_data['date'], workouttype=validated_data['workouttype'], - duration=validated_data['duration'], + duration=validated_data['duration'], distance=validated_data['distance'], - weightcategory=r.weightcategory, - adaptiveclass=r.adaptiveclass, - starttime=validated_data['starttime'], - csvfilename='', + weightcategory=r.weightcategory, + adaptiveclass=r.adaptiveclass, + starttime=validated_data['starttime'], + csvfilename='', notes=validated_data['notes'], - uploadedtoc2=0, + uploadedtoc2=0, summary=validated_data['summary'], - averagehr=validated_data['averagehr'], + averagehr=validated_data['averagehr'], maxhr=validated_data['maxhr'], - startdatetime=rowdatetime, + startdatetime=rowdatetime, timezone=validated_data['timezone'], forceunit=validated_data['forceunit'], inboard=validated_data['inboard'], @@ -109,16 +109,16 @@ class WorkoutSerializer(serializers.ModelSerializer): instance.name=validated_data['name'] - instance.date=validated_data['date'] + instance.date=validated_data['date'] instance.workouttype=validated_data['workouttype'] - instance.duration=validated_data['duration'] + instance.duration=validated_data['duration'] instance.distance=validated_data['distance'] - instance.starttime=validated_data['starttime'] + instance.starttime=validated_data['starttime'] instance.notes=validated_data['notes'] instance.summary=validated_data['summary'] - instance.averagehr=validated_data['averagehr'] + instance.averagehr=validated_data['averagehr'] instance.maxhr=validated_data['maxhr'] - instance.startdatetime=rowdatetime + instance.startdatetime=rowdatetime instance.timezone=validated_data['timezone'] instance.forceunit=validated_data['forceunit'] instance.inboard=validated_data['inboard'] @@ -140,7 +140,6 @@ class StrokeDataSerializer(serializers.Serializer): """ # do something - print "fake serializer" return 1 diff --git a/rowers/sporttracksstuff.py b/rowers/sporttracksstuff.py index 4cf0e668..191f8e01 100644 --- a/rowers/sporttracksstuff.py +++ b/rowers/sporttracksstuff.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # All the functionality to connect to SportTracks from rowers.imports import * @@ -9,7 +10,7 @@ from rowsandall_app.settings import ( SPORTTRACKS_REDIRECT_URI ) -import mytypes +import rowers.mytypes as mytypes oauth_data = { 'client_id': SPORTTRACKS_CLIENT_ID, @@ -64,19 +65,19 @@ def rower_sporttracks_token_refresh(user): def get_sporttracks_workout_list(user): r = Rower.objects.get(user=user) if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) elif (timezone.now()>r.sporttrackstokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.sporttrackstoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.sporttracks.mobi/api/v2/fitnessActivities" - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.sporttrackstoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.sporttracks.mobi/api/v2/fitnessActivities" + s = requests.get(url,headers=headers) return s @@ -84,19 +85,19 @@ def get_sporttracks_workout_list(user): def get_workout(user,sporttracksid): r = Rower.objects.get(user=user) if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): - return custom_exception_handler(401,s) - s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" elif (timezone.now()>r.sporttrackstokenexpirydate): - s = "Token expired. Needs to refresh." - return custom_exception_handler(401,s) + s = "Token expired. Needs to refresh." + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.sporttrackstoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/"+str(sporttracksid) - s = requests.get(url,headers=headers) + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.sporttrackstoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.sporttracks.mobi/api/v2/fitnessActivities/"+str(sporttracksid) + s = requests.get(url,headers=headers) data = s.json() @@ -139,19 +140,19 @@ def createsporttracksworkoutdata(w): haslatlon=1 try: - lat = row.df[' latitude'].values - lon = row.df[' longitude'].values + lat = row.df[' latitude'].values + lon = row.df[' longitude'].values if not lat.std() and not lon.std(): haslatlon = 0 except KeyError: - haslatlon = 0 + haslatlon = 0 haspower = 1 try: - power = row.df[' Power (watts)'].astype(int).values + power = row.df[' Power (watts)'].astype(int).values except KeyError: - haspower = 0 + haspower = 0 locdata = [] hrdata = [] @@ -160,18 +161,18 @@ def createsporttracksworkoutdata(w): powerdata = [] for i in range(len(t)): - hrdata.append(t[i]) - hrdata.append(hr[i]) - distancedata.append(t[i]) - distancedata.append(d[i]) - spmdata.append(t[i]) - spmdata.append(spm[i]) - if haslatlon: - locdata.append(t[i]) - locdata.append([lat[i],lon[i]]) - if haspower: - powerdata.append(t[i]) - powerdata.append(power[i]) + hrdata.append(t[i]) + hrdata.append(hr[i]) + distancedata.append(t[i]) + distancedata.append(d[i]) + spmdata.append(t[i]) + spmdata.append(spm[i]) + if haslatlon: + locdata.append(t[i]) + locdata.append([lat[i],lon[i]]) + if haspower: + powerdata.append(t[i]) + powerdata.append(power[i]) try: @@ -183,37 +184,37 @@ def createsporttracksworkoutdata(w): st = st.replace(microsecond=0) if haslatlon: - data = { - "type": "Rowing", - "name": w.name, - "start_time": st.isoformat(), - "total_distance": int(w.distance), - "duration": duration, - "notes": w.notes, - "avg_heartrate": averagehr, - "max_heartrate": maxhr, - "location": locdata, - "distance": distancedata, - "cadence": spmdata, - "heartrate": hrdata, - } + data = { + "type": "Rowing", + "name": w.name, + "start_time": st.isoformat(), + "total_distance": int(w.distance), + "duration": duration, + "notes": w.notes, + "avg_heartrate": averagehr, + "max_heartrate": maxhr, + "location": locdata, + "distance": distancedata, + "cadence": spmdata, + "heartrate": hrdata, + } else: - data = { - "type": "Rowing", - "name": w.name, - "start_time": st.isoformat(), - "total_distance": int(w.distance), - "duration": duration, - "notes": w.notes, - "avg_heartrate": averagehr, - "max_heartrate": maxhr, - "distance": distancedata, - "cadence": spmdata, - "heartrate": hrdata, - } + data = { + "type": "Rowing", + "name": w.name, + "start_time": st.isoformat(), + "total_distance": int(w.distance), + "duration": duration, + "notes": w.notes, + "avg_heartrate": averagehr, + "max_heartrate": maxhr, + "distance": distancedata, + "cadence": spmdata, + "heartrate": hrdata, + } if haspower: - data['power'] = powerdata + data['power'] = powerdata return data @@ -239,41 +240,41 @@ def workout_sporttracks_upload(user,w): thetoken = sporttracks_open(user) if (checkworkoutuser(user,w)): - data = createsporttracksworkoutdata(w) + data = createsporttracksworkoutdata(w) if not data: message = "Data error" stid = 0 return message,stid - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + authorizationstring = str('Bearer ' + thetoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} - url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json" - response = requests.post(url,headers=headers,data=json.dumps(data)) + 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 + # check for duplicate error first + if (response.status_code == 409 ): + message = "Duplicate error" + w.uploadedtosporttracks = -1 stid = -1 - w.save() + w.save() return message, stid - elif (response.status_code == 201 or response.status_code==200): - s= response.json() - stid = getidfromresponse(response) - w.uploadedtosporttracks = stid - w.save() + elif (response.status_code == 201 or response.status_code==200): + s= response.json() + stid = getidfromresponse(response) + w.uploadedtosporttracks = stid + w.save() return 'Successfully synced to SportTracks',stid - else: - s = response - message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason + else: + s = response + message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason stid = 0 return message,stid - + else: - message = "You are not authorized to upload this workout" + message = "You are not authorized to upload this workout" stid = 0 return message,stid @@ -289,33 +290,33 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks', workouttype = 'other' if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' + workouttype = 'other' try: - comments = data['comments'] + comments = data['comments'] except: - comments = '' + comments = '' r = Rower.objects.get(user=user) try: - rowdatetime = iso8601.parse_date(data['start_time']) + 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: + 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) starttimeunix = arrow.get(rowdatetime).timestamp try: - title = data['name'] + title = data['name'] except: - title = "Imported data" + title = "Imported data" try: res = splitstdata(data['distance']) @@ -331,41 +332,41 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks', try: - l = data['location'] + l = data['location'] - res = splitstdata(l) - times_location = res[0] - latlong = res[1] - latcoord = [] - loncoord = [] + 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) + 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)) + times_location = times_distance + latcoord = np.zeros(len(times_distance)) + loncoord = np.zeros(len(times_distance)) if workouttype in mytypes.otwtypes: workouttype = 'rower' - + try: - res = splitstdata(data['cadence']) - times_spm = res[0] - spm = res[1] + res = splitstdata(data['cadence']) + times_spm = res[0] + spm = res[1] except KeyError: - times_spm = times_distance - spm = 0*times_distance + times_spm = times_distance + spm = 0*times_distance try: - res = splitstdata(data['heartrate']) - hr = res[1] - times_hr = res[0] + res = splitstdata(data['heartrate']) + hr = res[1] + times_hr = res[0] except KeyError: - times_hr = times_distance - hr = 0*times_distance + times_hr = times_distance + hr = 0*times_distance # create data series and remove duplicates @@ -383,12 +384,12 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks', # Create dicts and big dataframe d = { - ' Horizontal (meters)': distseries, - ' latitude': latseries, - ' longitude': lonseries, - ' Cadence (stokes/min)': spmseries, - ' HRCur (bpm)' : hrseries, - } + ' Horizontal (meters)': distseries, + ' latitude': latseries, + ' longitude': lonseries, + ' Cadence (stokes/min)': spmseries, + ' HRCur (bpm)' : hrseries, + } @@ -432,7 +433,7 @@ def add_workout_from_data(user,importid,data,strokedata,source='sporttracks', df = df.fillna(0) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") # csvfilename ='media/Import_'+str(importid)+'.csv' diff --git a/rowers/stravastuff.py b/rowers/stravastuff.py index 2c8a9505..c8fc5e40 100644 --- a/rowers/stravastuff.py +++ b/rowers/stravastuff.py @@ -1,3 +1,5 @@ +from __future__ import unicode_literals, absolute_import + # All the functionality needed to connect to Strava from scipy import optimize from scipy.signal import savgol_filter @@ -10,15 +12,15 @@ queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') -from dataprep import columndict +from rowers.dataprep import columndict import stravalib from stravalib.exc import ActivityUploadFailed,TimeoutExceeded from iso8601 import ParseError -from utils import myqueue +from rowers.utils import myqueue -import mytypes +import rowers.mytypes as mytypes import gzip from rowsandall_app.settings import ( @@ -35,7 +37,7 @@ from rowers.imports import * headers = {'Accept': 'application/json', 'Api-Key': STRAVA_CLIENT_ID, - 'Content-Type': 'application/json', + 'Content-Type': 'application/json', 'user-agent': 'sanderroosendaal'} @@ -89,26 +91,26 @@ def make_authorization_url(request): def get_strava_workout_list(user,limit_n=0): r = Rower.objects.get(user=user) if (r.stravatoken == '') or (r.stravatoken is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) elif (r.stravatokenexpirydate is None or timezone.now()+timedelta(seconds=3599)>r.stravatokenexpirydate): s = "Token expired. Needs to refresh." return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.stravatoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.stravatoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} - url = "https://www.strava.com/api/v3/athlete/activities" + url = "https://www.strava.com/api/v3/athlete/activities" if limit_n==0: params = {} else: params = {'per_page':limit_n} - s = requests.get(url,headers=headers,params=params) + s = requests.get(url,headers=headers,params=params) return s @@ -200,27 +202,27 @@ def create_async_workout(alldata,user,stravaid,debug=False): thetimezone = 'UTC' try: - rowdatetime = iso8601.parse_date(data['date_utc']) + rowdatetime = iso8601.parse_date(data['date_utc']) except KeyError: - rowdatetime = iso8601.parse_date(data['start_date']) + rowdatetime = iso8601.parse_date(data['start_date']) except ParseError: - rowdatetime = iso8601.parse_date(data['date']) + rowdatetime = iso8601.parse_date(data['date']) try: c2intervaltype = data['workout_type'] - + except KeyError: - c2intervaltype = '' - + c2intervaltype = '' + try: - title = data['name'] + title = data['name'] except KeyError: - title = "" - try: - t = data['comments'].split('\n', 1)[0] - title += t[:20] - except: - title = 'Imported' + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:20] + except: + title = 'Imported' workoutdate = rowdatetime.astimezone( pytz.timezone(thetimezone) @@ -259,7 +261,7 @@ def create_async_workout(alldata,user,stravaid,debug=False): return 1 -from utils import get_strava_stream +from rowers.utils import get_strava_stream @@ -273,26 +275,26 @@ def get_workout(user,stravaid): r = Rower.objects.get(user=user) if (r.stravatoken == '') or (r.stravatoken is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) elif (r.stravatokenexpirydate is not None and timezone.now()>r.stravatokenexpirydate): s = "Token expired. Needs to refresh." return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - fetchresolution = 'high' + # ready to fetch. Hurray + fetchresolution = 'high' series_type = 'time' - authorizationstring = str('Bearer ' + r.stravatoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json', - 'resolution': 'medium',} - url = "https://www.strava.com/api/v3/activities/"+str(stravaid) - workoutsummary = requests.get(url,headers=headers).json() + authorizationstring = str('Bearer ' + r.stravatoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json', + 'resolution': 'medium',} + url = "https://www.strava.com/api/v3/activities/"+str(stravaid) + workoutsummary = requests.get(url,headers=headers).json() - workoutsummary['timezone'] = "Etc/UTC" + workoutsummary['timezone'] = "Etc/UTC" try: - startdatetime = workoutsummary['start_date'] + startdatetime = workoutsummary['start_date'] except KeyError: startdatetime = timezone.now() @@ -306,9 +308,9 @@ def get_workout(user,stravaid): try: - t = np.array(timejson.json()[0]['data']) - nr_rows = len(t) - d = np.array(distancejson.json()[1]['data']) + t = np.array(timejson.json()[0]['data']) + nr_rows = len(t) + d = np.array(distancejson.json()[1]['data']) if nr_rows == 0: return (0,"Error: Time data had zero length") @@ -318,70 +320,70 @@ def get_workout(user,stravaid): except KeyError: return (0,"something went wrong with the Strava import") - try: - spm = np.array(spmjson.json()[1]['data']) - except: - spm = np.zeros(nr_rows) + try: + spm = np.array(spmjson.json()[1]['data']) + except: + spm = np.zeros(nr_rows) try: power = np.array(powerjson.json()[1]['data']) except IndexError: power = np.zeros(nr_rows) - try: - hr = np.array(hrjson.json()[1]['data']) - except IndexError: - hr = np.zeros(nr_rows) + try: + hr = np.array(hrjson.json()[1]['data']) + except IndexError: + hr = np.zeros(nr_rows) except KeyError: - hr = np.zeros(nr_rows) + hr = np.zeros(nr_rows) - try: - velo = np.array(velojson.json()[1]['data']) - except IndexError: - velo = np.zeros(nr_rows) + try: + velo = np.array(velojson.json()[1]['data']) + except IndexError: + velo = np.zeros(nr_rows) except KeyError: velo = np.zeros(nr_rows) - dt = np.diff(t).mean() - wsize = round(5./dt) + dt = np.diff(t).mean() + wsize = round(5./dt) - velo2 = ewmovingaverage(velo,wsize) - coords = np.array(latlongjson.json()[0]['data']) - try: - lat = coords[:,0] - lon = coords[:,1] - except IndexError: - lat = np.zeros(len(t)) - lon = np.zeros(len(t)) + velo2 = ewmovingaverage(velo,wsize) + coords = np.array(latlongjson.json()[0]['data']) + try: + lat = coords[:,0] + lon = coords[:,1] + except IndexError: + lat = np.zeros(len(t)) + lon = np.zeros(len(t)) except KeyError: - lat = np.zeros(len(t)) - lon = np.zeros(len(t)) + lat = np.zeros(len(t)) + lon = np.zeros(len(t)) - strokelength = velo*60./(spm) - strokelength[np.isinf(strokelength)] = 0.0 + strokelength = velo*60./(spm) + strokelength[np.isinf(strokelength)] = 0.0 - pace = 500./(1.0*velo2) - pace[np.isinf(pace)] = 0.0 + pace = 500./(1.0*velo2) + pace[np.isinf(pace)] = 0.0 - df = pd.DataFrame({'t':10*t, - 'd':10*d, - 'p':10*pace, - 'spm':spm, - 'hr':hr, - 'lat':lat, - 'lon':lon, + df = pd.DataFrame({'t':10*t, + 'd':10*d, + 'p':10*pace, + 'spm':spm, + 'hr':hr, + 'lat':lat, + 'lon':lon, 'power':power, - 'strokelength':strokelength, - }) + 'strokelength':strokelength, + }) - # startdatetime = datetime.datetime.strptime(startdatetime,"%Y-%m-%d-%H:%M:%S") + # startdatetime = datetime.datetime.strptime(startdatetime,"%Y-%m-%d-%H:%M:%S") - return [workoutsummary,df] + return [workoutsummary,df] # Generate Workout data for Strava (a TCX file) def createstravaworkoutdata(w,dozip=True): @@ -478,41 +480,41 @@ def add_workout_from_data(user,importid,data,strokedata, workouttype = 'water' if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' + workouttype = 'other' try: - comments = data['comments'] + comments = data['comments'] except: - comments = ' ' + comments = ' ' try: - thetimezone = tz(data['timezone']) + thetimezone = tz(data['timezone']) except: - thetimezone = 'UTC' + thetimezone = 'UTC' r = Rower.objects.get(user=user) try: - rowdatetime = iso8601.parse_date(data['date_utc']) + rowdatetime = iso8601.parse_date(data['date_utc']) except KeyError: - rowdatetime = iso8601.parse_date(data['start_date']) + rowdatetime = iso8601.parse_date(data['start_date']) except ParseError: - rowdatetime = iso8601.parse_date(data['date']) + rowdatetime = iso8601.parse_date(data['date']) - + try: intervaltype = data['workout_type'] - + except KeyError: - intervaltype = '' - + intervaltype = '' + try: - title = data['name'] + title = data['name'] except KeyError: - title = "" - try: - t = data['comments'].split('\n', 1)[0] - title += t[:20] - except: - title = 'Imported' + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:20] + except: + title = 'Imported' starttimeunix = arrow.get(rowdatetime).timestamp @@ -526,17 +528,17 @@ def add_workout_from_data(user,importid,data,strokedata, nr_rows = len(unixtime) try: - latcoord = strokedata.loc[:,'lat'] - loncoord = strokedata.loc[:,'lon'] + latcoord = strokedata.loc[:,'lat'] + loncoord = strokedata.loc[:,'lon'] except: - latcoord = np.zeros(nr_rows) - loncoord = np.zeros(nr_rows) + latcoord = np.zeros(nr_rows) + loncoord = np.zeros(nr_rows) try: - strokelength = strokedata.loc[:,'strokelength'] + strokelength = strokedata.loc[:,'strokelength'] except: - strokelength = np.zeros(nr_rows) + strokelength = np.zeros(nr_rows) dist2 = 0.1*strokedata.loc[:,'d'] @@ -566,28 +568,28 @@ def add_workout_from_data(user,importid,data,strokedata, # 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 - }) + ' 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 + }) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") @@ -623,34 +625,34 @@ def workout_strava_upload(user,w): r = Rower.objects.get(user=user) res = -1 if (r.stravatoken == '') or (r.stravatoken is None): - s = "Token doesn't exist. Need to authorize" + s = "Token doesn't exist. Need to authorize" raise NoTokenError("Your hovercraft is full of eels") else: - if (checkworkoutuser(user,w)): + if (checkworkoutuser(user,w)): try: - tcxfile,tcxmesg = createstravaworkoutdata(w) + tcxfile,tcxmesg = createstravaworkoutdata(w) if tcxfile: - with open(tcxfile,'rb') as f: - res,mes = handle_stravaexport( + with open(tcxfile,'rb') as f: + res,mes = handle_stravaexport( f,w.name, - r.stravatoken, - description=w.notes+'\n from '+w.workoutsource+' via rowsandall.com', + r.stravatoken, + description=w.notes+'\n from '+w.workoutsource+' via rowsandall.com', activity_type=r.stravaexportas) if res==0: - message = mes - w.uploadedtostrava = -1 + message = mes + w.uploadedtostrava = -1 stravaid = -1 - w.save() + w.save() try: - os.remove(tcxfile) + os.remove(tcxfile) except WindowsError: pass return message,stravaid - w.uploadedtostrava = res - w.save() + w.uploadedtostrava = res + w.save() try: - os.remove(tcxfile) + os.remove(tcxfile) except WindowsError: pass message = mes @@ -663,14 +665,14 @@ def workout_strava_upload(user,w): w.save() return message, stravaid - except ActivityUploadFailed as e: - message = "Strava Upload error: %s" % e - w.uploadedtostrava = -1 + except ActivityUploadFailed as e: + message = "Strava Upload error: %s" % e + w.uploadedtostrava = -1 stravaid = -1 - w.save() - os.remove(tcxfile) + w.save() + os.remove(tcxfile) return message,stravaid - return message,stravaid + return message,stravaid return message,stravaid @@ -688,9 +690,9 @@ def handle_strava_import_stroke_data(title, series_type = 'time' authorizationstring = str('Bearer ' + stravatoken) headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json', - 'resolution': 'medium',} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json', + 'resolution': 'medium',} url = "https://www.strava.com/api/v3/activities/"+str(stravaid) workoutsummary = requests.get(url,headers=headers).json() @@ -708,9 +710,9 @@ def handle_strava_import_stroke_data(title, wattsjson = get_strava_stream(r,'watts',stravaid) try: - t = np.array(timejson.json()[0]['data']) - nr_rows = len(t) - d = np.array(distancejson.json()[1]['data']) + t = np.array(timejson.json()[0]['data']) + nr_rows = len(t) + d = np.array(distancejson.json()[1]['data']) if nr_rows == 0: return 0 except IndexError: @@ -720,9 +722,9 @@ def handle_strava_import_stroke_data(title, return 0 try: - spm = np.array(spmjson.json()[1]['data']) + spm = np.array(spmjson.json()[1]['data']) except: - spm = np.zeros(nr_rows) + spm = np.zeros(nr_rows) try: watts = np.array(wattsjson.json()[1]['data']) @@ -730,16 +732,16 @@ def handle_strava_import_stroke_data(title, watts = np.zeros(nr_rows) try: - hr = np.array(hrjson.json()[1]['data']) + hr = np.array(hrjson.json()[1]['data']) except IndexError: - hr = np.zeros(nr_rows) + hr = np.zeros(nr_rows) except KeyError: - hr = np.zeros(nr_rows) + hr = np.zeros(nr_rows) try: - velo = np.array(velojson.json()[1]['data']) + velo = np.array(velojson.json()[1]['data']) except IndexError: - velo = np.zeros(nr_rows) + velo = np.zeros(nr_rows) except KeyError: velo = np.zeros(nr_rows) @@ -756,14 +758,14 @@ def handle_strava_import_stroke_data(title, coords = np.array(latlongjson.json()[0]['data']) try: - lat = coords[:,0] - lon = coords[:,1] + lat = coords[:,0] + lon = coords[:,1] except IndexError: - lat = np.zeros(len(t)) - lon = np.zeros(len(t)) + lat = np.zeros(len(t)) + lon = np.zeros(len(t)) except KeyError: - lat = np.zeros(len(t)) - lon = np.zeros(len(t)) + lat = np.zeros(len(t)) + lon = np.zeros(len(t)) strokelength = velo*60./(spm) strokelength[np.isinf(strokelength)] = 0.0 @@ -779,22 +781,22 @@ def handle_strava_import_stroke_data(title, df = pd.DataFrame({'TimeStamp (sec)':unixtime, ' ElapsedTime (sec)':t, - ' Horizontal (meters)':d, - ' Stroke500mPace (sec/500m)':pace, - ' Cadence (stokes/min)':spm, - ' HRCur (bpm)':hr, - ' latitude':lat, - ' longitude':lon, - ' StrokeDistance (meters)':strokelength, + ' Horizontal (meters)':d, + ' Stroke500mPace (sec/500m)':pace, + ' Cadence (stokes/min)':spm, + ' HRCur (bpm)':hr, + ' latitude':lat, + ' longitude':lon, + ' StrokeDistance (meters)':strokelength, 'cum_dist':d, - ' DragFactor':np.zeros(nr_strokes), - ' DriveLength (meters)':np.zeros(nr_strokes), - ' StrokeDistance (meters)':strokedistance, - ' DriveTime (ms)':np.zeros(nr_strokes), - ' StrokeRecoveryTime (ms)':np.zeros(nr_strokes), - ' AverageDriveForce (lbs)':np.zeros(nr_strokes), - ' PeakDriveForce (lbs)':np.zeros(nr_strokes), - ' lapIdx':np.zeros(nr_strokes), + ' DragFactor':np.zeros(nr_strokes), + ' DriveLength (meters)':np.zeros(nr_strokes), + ' StrokeDistance (meters)':strokedistance, + ' DriveTime (ms)':np.zeros(nr_strokes), + ' StrokeRecoveryTime (ms)':np.zeros(nr_strokes), + ' AverageDriveForce (lbs)':np.zeros(nr_strokes), + ' PeakDriveForce (lbs)':np.zeros(nr_strokes), + ' lapIdx':np.zeros(nr_strokes), ' Power (watts)':watts, }) diff --git a/rowers/tasks.py b/rowers/tasks.py index cbf98d8d..3d33c34d 100644 --- a/rowers/tasks.py +++ b/rowers/tasks.py @@ -1,4 +1,5 @@ """ Background tasks done by Celery (develop) or QR (production) """ +from __future__ import absolute_import import os import time import gc @@ -16,7 +17,10 @@ from rowingdata import rowingdata as rdata from datetime import timedelta from sqlalchemy import create_engine -from celery import app +#from celery import app +from rowers.celery import app +from celery import shared_task + import datetime import pytz import iso8601 @@ -39,10 +43,11 @@ from django_rq import job from django.utils import timezone from django.utils.html import strip_tags -from utils import deserialize_list,ewmovingaverage,wavg -from emails import htmlstrip +from rowers.utils import deserialize_list,ewmovingaverage,wavg +from rowers.emails import htmlstrip -from HTMLParser import HTMLParser +#from HTMLParser import HTMLParser +from html.parser import HTMLParser class MLStripper(HTMLParser): def __init__(self): self.reset() @@ -68,6 +73,7 @@ from rowers.dataprepnodjango import ( # create_strava_stroke_data_db ) +from rowers.opaque import encoder from django.core.mail import ( send_mail, @@ -79,13 +85,13 @@ from django.db.utils import OperationalError from jinja2 import Template,Environment,FileSystemLoader env = Environment(loader = FileSystemLoader(["rowers/templates"])) -import datautils -import utils +import rowers.datautils as datautils +import rowers.utils as utils import requests -import longtask +import rowers.longtask as longtask import arrow -from utils import get_strava_stream +from rowers.utils import get_strava_stream siteurl = SITE_URL @@ -127,9 +133,9 @@ def handle_c2_import_stroke_data(c2token, return 1 else: - url = "https://log.concept2.com/api/users/me/results/"+str(c2id) + url = "https://log.concept2.com/api/users/me/results/{id}".format(id=c2id) - s = requests.get(url,headers=headers) + s = requests.get(url,headers=headers) if s.status_code == 200: workoutdata = s.json()['data'] @@ -1237,21 +1243,21 @@ def handle_zip_file(emailfrom, subject, file,**kwargs): debug = False if debug: - print message + print(message) email = EmailMessage(subject, message, emailfrom, ['workouts@rowsandall.com']) email.attach_file(file) if debug: - print "attaching" + print("attaching") res = email.send() if debug: - print "sent" + print("sent") time.sleep(60) return 1 @@ -1489,9 +1495,8 @@ def handle_updateergcp(rower_id,workoutfilenames,debug=False,**kwargs): rowdata = rdata(f1 + '.gz') except IOError: rowdata = 0 - - if rowdata != 0: - therows.append(rowdata) + if rowdata != 0: + therows.append(rowdata) cpdata = rowingdata.cumcpdata(therows) cpdata.columns = cpdata.columns.str.lower() @@ -1822,7 +1827,7 @@ def handle_sendemail_coacheerequest(email,name,code,coachname, debug=False,**kwargs): fullemail = email - subject = '{n} asks coach access to your data on rowsandall.com'.format(n=coachname) + subject = '{n} requests coach access to your data on rowsandall.com'.format(n=coachname) from_email = 'Rowsandall ' siteurl = SITE_URL if debug: @@ -1890,7 +1895,8 @@ def handle_sendemailnewresponse(first_name, last_name, if 'sessiontype' in kwargs: sessiontype=kwargs.pop('sessiontype') - commentlink = '/rowers/workout/{workoutid}/comment/'.format(workoutid=workoutid) + commentlink = '/rowers/workout/{workoutid}/comment/'.format( + workoutid=encoder.encode_hex(workoutid)) if 'commentlink' in kwargs: commentlink = kwargs.pop('commentlink') @@ -1940,7 +1946,8 @@ def handle_sendemailnewcomment(first_name, if 'sessiontype' in kwargs: sessiontype=kwargs.pop('sessiontype') - commentlink = '/rowers/workout/{workoutid}/comment/'.format(workoutid=workoutid) + commentlink = '/rowers/workout/{workoutid}/comment/'.format( + workoutid=encoder.encode_hex(workoutid)) if 'commentlink' in kwargs: commentlink = kwargs.pop('commentlink') @@ -1951,7 +1958,7 @@ def handle_sendemailnewcomment(first_name, 'comment':comment, 'workoutname':workoutname, 'siteurl':siteurl, - 'workoutid':workoutid, + 'workoutid':encoder.encode_hex(workoutid), 'sessiontype':sessiontype, 'commentlink':commentlink, } diff --git a/rowers/teams.py b/rowers/teams.py index 8980e8a8..8d2dfbce 100644 --- a/rowers/teams.py +++ b/rowers/teams.py @@ -10,7 +10,7 @@ from django.db import IntegrityError import uuid from django.conf import settings -from utils import myqueue +from rowers.utils import myqueue import django_rq queue = django_rq.get_queue('default') diff --git a/rowers/templates/coacheerequestemail.html b/rowers/templates/coacheerequestemail.html index 27f0bea4..9dc9c52b 100644 --- a/rowers/templates/coacheerequestemail.html +++ b/rowers/templates/coacheerequestemail.html @@ -4,10 +4,10 @@

Dear {{ name }},

- {{ coachname }} is offering to become your coach on rowsandall.com. + {{ coach }} is offering to become your coach on rowsandall.com.

- By accepting the invite, {{ coachname }} will have access to your + By accepting the invite, {{ coach }} will have access to your data and will be able to upload workouts and run analysis on rowsandall.com on behalf of you.

diff --git a/rowers/templates/list_workouts.html b/rowers/templates/list_workouts.html index bfac39a8..b4066432 100644 --- a/rowers/templates/list_workouts.html +++ b/rowers/templates/list_workouts.html @@ -129,7 +129,7 @@ {% if workouts.has_next %} {% if request.GET.q %} - + {% else %} - + @@ -216,7 +216,7 @@ {% if team %} {% if workout|may_edit:request %} - + {{ workout.user.user.first_name }} {{ workout.user.user.last_name }} @@ -245,18 +245,14 @@ - {% if workout|may_edit:request %} - {% else %} -   - {% endif %} - {% if workout.user.user == user or user == team.manager %} + {% if workout|may_edit:request %} diff --git a/rowers/templates/menu_plan.html b/rowers/templates/menu_plan.html index d6a448ec..7177f790 100644 --- a/rowers/templates/menu_plan.html +++ b/rowers/templates/menu_plan.html @@ -63,7 +63,7 @@
  • -  Add Team Session +  Add Group Session
  • diff --git a/rowers/templates/menu_workout.html b/rowers/templates/menu_workout.html index 84ff5c97..b87876bb 100644 --- a/rowers/templates/menu_workout.html +++ b/rowers/templates/menu_workout.html @@ -41,7 +41,7 @@
  • - +  Compare
  • diff --git a/rowers/templates/paidplans.html b/rowers/templates/paidplans.html index b091b9e5..52b03cdf 100644 --- a/rowers/templates/paidplans.html +++ b/rowers/templates/paidplans.html @@ -94,7 +94,14 @@ ✔ - Create Training plans, tests and challenges for yourself. Track your performance + Create and manage groups. +   + ✔ + ✔ + ✔ + + + Create Training plans, tests and challenges for yourself and your training group. Track your performance against plan.     @@ -110,14 +117,21 @@ ✔ - Create and manage teams. + Manage your athlete's workouts       ✔ - Manage your athlete's workouts + Run analytics for your athletes +   +   +   + ✔ + + + Change zone intensities and other workout related settings for your athletes       @@ -126,8 +140,8 @@ Pricing FREE - From 15€/year - From 65€/year + From 25€/year + From 75€/year From 90€/year diff --git a/rowers/templates/plannedsessionsmanage.html b/rowers/templates/plannedsessionsmanage.html index 0e12facf..fa78f7b1 100644 --- a/rowers/templates/plannedsessionsmanage.html +++ b/rowers/templates/plannedsessionsmanage.html @@ -90,7 +90,7 @@
  • {% csrf_token %} - +
  • diff --git a/rowers/templates/plannedsessionview.html b/rowers/templates/plannedsessionview.html index ee840e64..f5aa1c88 100644 --- a/rowers/templates/plannedsessionview.html +++ b/rowers/templates/plannedsessionview.html @@ -96,6 +96,10 @@ {% endfor %} +

    + + Add, remove or change workouts for this session +

  • {{ rower.user.first_name }} {{ rower.user.last_name }}

    diff --git a/rowers/templates/rower_exportsettings.html b/rowers/templates/rower_exportsettings.html index 8e4fd953..5138566c 100644 --- a/rowers/templates/rower_exportsettings.html +++ b/rowers/templates/rower_exportsettings.html @@ -4,6 +4,11 @@ {% block main %}

    Import and Export Settings for {{ rower.user.first_name }} {{ rower.user.last_name }}

    + +{% if user.rower.rowerplan == 'basic' %} +The auto import and export settings only work on a paid plan. +{% endif %} + {% if form.errors %}

    Please correct the error{{ form.errors|pluralize }} below. diff --git a/rowers/templatetags/rowerfilters.py b/rowers/templatetags/rowerfilters.py index 83269444..e44015eb 100644 --- a/rowers/templatetags/rowerfilters.py +++ b/rowers/templatetags/rowerfilters.py @@ -470,7 +470,7 @@ def userurl(path,member): userstring = 'user/%s/' % member.id # remove team - tpattern = re.compile('\/team\/\d+/') + tpattern = re.compile('team\/\d+/') if tpattern.search(path) is not None: path = tpattern.sub('',path) @@ -478,7 +478,7 @@ def userurl(path,member): replaced = pattern.sub(userstring,path) else: replaced = path+userstring - + return replaced @register.filter @@ -489,7 +489,7 @@ def teamurl(path,team): # remove user upattern = re.compile('\/user\/\d+/') if upattern.search(path) is not None: - path = upattern.sub('',path) + path = upattern.sub('/',path) if pattern.search(path) is not None: @@ -497,6 +497,7 @@ def teamurl(path,team): else: replaced = path+teamstring + return replaced @register.filter diff --git a/rowers/tests/statements.py b/rowers/tests/statements.py index 8fcf1307..1f607745 100644 --- a/rowers/tests/statements.py +++ b/rowers/tests/statements.py @@ -145,8 +145,8 @@ class UserFactory(factory.DjangoModelFactory): email = factory.LazyAttribute(lambda _: faker.email()) username = factory.LazyAttribute(lambda _: faker.profile()['username']) - first_name = faker.name().split(' ')[0] - last_name = faker.name().split(' ')[0] + first_name = factory.LazyAttribute(lambda _:faker.name().split(' ')[0]) + last_name = factory.LazyAttribute(lambda _:faker.name().split(' ')[0]) class RaceFactory(factory.DjangoModelFactory): class Meta: diff --git a/rowers/tests/test_permissions.py b/rowers/tests/test_permissions.py index a902d2fb..a84f7982 100644 --- a/rowers/tests/test_permissions.py +++ b/rowers/tests/test_permissions.py @@ -958,6 +958,31 @@ class PermissionsViewTests(TestCase): response = self.c.get(url) self.assertEqual(response.status_code,200) + + # stats + url = reverse('workout_view', + kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)} + ) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + # workflow + url = reverse('workout_workflow_view', + kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)} + ) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + + # stats + url = reverse('workout_stats_view', + kwargs={'id':encoder.encode_hex(self.uplan2_workouts[0].id)} + ) + + response = self.c.get(url) + self.assertEqual(response.status_code,200) + ## Pro users (and higher) can join group led by other Pro (or higher) user def test_team_member_request_pro_pro(self): @@ -1416,8 +1441,7 @@ class PermissionsCoachingTests(TestCase): ## Basic users can subscribe to any race -# group related -## group members can see but not edit each other's workouts and charts +### ## group members can see but not edit each other's plans diff --git a/rowers/tpstuff.py b/rowers/tpstuff.py index 776b5722..442bd820 100644 --- a/rowers/tpstuff.py +++ b/rowers/tpstuff.py @@ -1,3 +1,4 @@ +from __future__ import unicode_literals, absolute_import # All the functionality needed to connect to Runkeeper from rowers.imports import * @@ -149,12 +150,6 @@ def uploadactivity(access_token,filename,description='', headers=headers) if resp.status_code != 200: - if settings.DEBUG: - print resp.status_code - print resp.reason - print "" - print headers - print "" return 0,resp.reason,resp.status_code,headers else: return resp.json()[0]["Id"],"ok",200,"" diff --git a/rowers/underarmourstuff.py b/rowers/underarmourstuff.py index f5169f45..cbe1db96 100644 --- a/rowers/underarmourstuff.py +++ b/rowers/underarmourstuff.py @@ -1,6 +1,7 @@ +from __future__ import unicode_literals, absolute_import from rowers.imports import * -import mytypes +import rowers.mytypes as mytypes from rowers.mytypes import otwtypes from rowsandall_app.settings import ( @@ -45,18 +46,18 @@ def make_authorization_url(request): def get_underarmour_workout_list(user): r = Rower.objects.get(user=user) if (r.underarmourtoken == '') or (r.underarmourtoken is None): - s = "Token doesn't exist. Need to authorize" - return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.underarmourtoken) - headers = {'Authorization': authorizationstring, + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.underarmourtoken) + headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime" + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.ua.com/v7.1/workout/?user="+str(get_userid(r.underarmourtoken))+"&order_by=-start_datetime" - s = requests.get(url,headers=headers) + s = requests.get(url,headers=headers) return s @@ -65,17 +66,17 @@ def get_underarmour_workout_list(user): def get_workout(user,underarmourid): r = Rower.objects.get(user=user) if (r.underarmourtoken == '') or (r.underarmourtoken is None): - return custom_exception_handler(401,s) - s = "Token doesn't exist. Need to authorize" + return custom_exception_handler(401,s) + s = "Token doesn't exist. Need to authorize" else: - # ready to fetch. Hurray - authorizationstring = str('Bearer ' + r.underarmourtoken) - headers = {'Authorization': authorizationstring, + # ready to fetch. Hurray + authorizationstring = str('Bearer ' + r.underarmourtoken) + headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} - url = "https://api.ua.com/v7.1/workout/"+str(underarmourid)+"/?field_set=time_series" - s = requests.get(url,headers=headers) + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} + url = "https://api.ua.com/v7.1/workout/"+str(underarmourid)+"/?field_set=time_series" + s = requests.get(url,headers=headers) data = s.json() @@ -135,12 +136,12 @@ def createunderarmourworkoutdata(w): haslatlon=1 try: - lat = row.df[' latitude'] - lon = row.df[' longitude'] + lat = row.df[' latitude'] + lon = row.df[' longitude'] if not lat.std() and not lon.std(): haslatlon = 0 except KeyError: - haslatlon = 0 + haslatlon = 0 @@ -201,7 +202,7 @@ def createunderarmourworkoutdata(w): timeseries["position"] = locdata data = { - "start_datetime": start_time, + "start_datetime": start_time, "name": name, "has_time_series": True, "time_series": timeseries, @@ -236,8 +237,8 @@ def refresh_ua_actlist(user): authorizationstring = str('Bearer ' + r.underarmourtoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/activity_type/" response = requests.get(url,headers=headers) @@ -263,8 +264,8 @@ def get_typefromid(typeid,user): authorizationstring = str('Bearer ' + r.underarmourtoken) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/activity_type/"+str(typeid) response = requests.get(url,headers=headers) @@ -285,8 +286,8 @@ def get_userid(access_token): authorizationstring = str('Bearer ' + access_token) headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} url = "https://api.ua.com/v7.1/user/self/" response = requests.get(url,headers=headers) @@ -311,42 +312,42 @@ def workout_ua_upload(user,w): # ready to upload. Hurray if (checkworkoutuser(user,w)): - data = createunderarmourworkoutdata(w) + data = createunderarmourworkoutdata(w) # return HttpResponse(json.dumps(data)) if not data: message = "Data error" uaid = 0 return message, uaid - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, + authorizationstring = str('Bearer ' + thetoken) + headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json', + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json', } - url = "https://api.ua.com/v7.1/workout/" - response = requests.post(url,headers=headers,data=json.dumps(data)) + url = "https://api.ua.com/v7.1/workout/" + response = requests.post(url,headers=headers,data=json.dumps(data)) - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" - w.uploadedtounderarmour = -1 + # check for duplicate error first + if (response.status_code == 409 ): + message = "Duplicate error" + w.uploadedtounderarmour = -1 uaid = -1 - w.save() - elif (response.status_code == 201 or response.status_code==200): - uaid = getidfromresponse(response) - w.uploadedtounderarmour = uaid - w.save() + w.save() + elif (response.status_code == 201 or response.status_code==200): + uaid = getidfromresponse(response) + w.uploadedtounderarmour = uaid + w.save() return 'Successfully synchronized with MapMyFitness',uaid - else: - s = response - message = "Something went wrong in workout_underarmour_upload_view: %s - %s" % (s.reason,s.text) + else: + s = response + message = "Something went wrong in workout_underarmour_upload_view: %s - %s" % (s.reason,s.text) uaid = 0 return message, uaid - + else: - message = "You are not authorized to upload this workout" + message = "You are not authorized to upload this workout" uaid = 0 return message, uaid @@ -360,36 +361,36 @@ def add_workout_from_data(user,importid,data,strokedata, workouttype = 'water' try: - comments = data['notes'] + comments = data['notes'] except: - comments = '' + comments = '' try: - thetimezone = tz(data['start_locale_timezone']) + thetimezone = tz(data['start_locale_timezone']) except: - thetimezone = 'UTC' + thetimezone = 'UTC' r = Rower.objects.get(user=user) try: - rowdatetime = iso8601.parse_date(data['start_datetime']) + rowdatetime = iso8601.parse_date(data['start_datetime']) except iso8601.ParseError: - try: - rowdatetime = datetime.strptime(data['start_datetime'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - try: - rowdatetime = parser.parse(data['start_datetime']) - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) - except: - rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") - rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + try: + rowdatetime = datetime.strptime(data['start_datetime'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except: + try: + rowdatetime = parser.parse(data['start_datetime']) + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) + except: + rowdatetime = datetime.strptime(data['date'],"%Y-%m-%d %H:%M:%S") + rowdatetime = thetimezone.localize(rowdatetime).astimezone(utc) starttimeunix = arrow.get(rowdatetime).timestamp - + try: - title = data['name'] + title = data['name'] except: - title = "Imported data" + title = "Imported data" timeseries = data['time_series'] @@ -403,41 +404,41 @@ def add_workout_from_data(user,importid,data,strokedata, try: - l = timeseries['position'] + l = timeseries['position'] - res = splituadata(l) - times_location = res[0] - latlong = res[1] - latcoord = [] - loncoord = [] + res = splituadata(l) + times_location = res[0] + latlong = res[1] + latcoord = [] + loncoord = [] - for coord in latlong: - lat = coord['lat'] - lon = coord['lng'] - latcoord.append(lat) - loncoord.append(lon) + for coord in latlong: + lat = coord['lat'] + lon = coord['lng'] + latcoord.append(lat) + loncoord.append(lon) except: - times_location = times_distance - latcoord = np.zeros(len(times_distance)) - loncoord = np.zeros(len(times_distance)) + times_location = times_distance + latcoord = np.zeros(len(times_distance)) + loncoord = np.zeros(len(times_distance)) if workouttype in otwtypes: workouttype = 'rower' - + try: - res = splituadata(timeseries['cadence']) - times_spm = res[0] - spm = res[1] + res = splituadata(timeseries['cadence']) + times_spm = res[0] + spm = res[1] except KeyError: - times_spm = times_distance - spm = 0*times_distance + times_spm = times_distance + spm = 0*times_distance try: - res = splituadata(timeseries['heartrate']) - hr = res[1] - times_hr = res[0] + res = splituadata(timeseries['heartrate']) + hr = res[1] + times_hr = res[0] except KeyError: - times_hr = times_distance - hr = 0*times_distance + times_hr = times_distance + hr = 0*times_distance # create data series and remove duplicates @@ -455,12 +456,12 @@ def add_workout_from_data(user,importid,data,strokedata, # Create dicts and big dataframe d = { - ' Horizontal (meters)': distseries, - ' latitude': latseries, - ' longitude': lonseries, - ' Cadence (stokes/min)': spmseries, - ' HRCur (bpm)' : hrseries, - } + ' Horizontal (meters)': distseries, + ' latitude': latseries, + ' longitude': lonseries, + ' Cadence (stokes/min)': spmseries, + ' HRCur (bpm)' : hrseries, + } @@ -499,7 +500,7 @@ def add_workout_from_data(user,importid,data,strokedata, df = df.fillna(0) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") csvfilename ='media/{code}_{importid}.csv'.format( diff --git a/rowers/uploads.py b/rowers/uploads.py index 06f2f43e..ae86ae2c 100644 --- a/rowers/uploads.py +++ b/rowers/uploads.py @@ -26,12 +26,13 @@ queue = django_rq.get_queue('default') queuelow = django_rq.get_queue('low') queuehigh = django_rq.get_queue('low') -from mytypes import workouttypes,boattypes,otwtypes,workoutsources +from rowers.mytypes import workouttypes,boattypes,otwtypes,workoutsources try: from cStringIO import StringIO except: - from StringIO import StringIO + from io import StringIO + from rowers.utils import ( geo_distance,serialize_list,deserialize_list,uniqify, @@ -403,34 +404,34 @@ def make_plot(r,w,f1,f2,plottype,title,imagename='',plotnr=0): ftp = ftp*(100.-r.otwslack)/100. hrpwrdata = { - 'hrmax':r.max, - 'hrut2':r.ut2, - 'hrut1':r.ut1, - 'hrat':r.at, - 'hrtr':r.tr, - 'hran':r.an, - 'ftp':ftp, + 'hrmax':r.max, + 'hrut2':r.ut2, + 'hrut1':r.ut1, + 'hrat':r.at, + 'hrtr':r.tr, + 'hran':r.an, + 'ftp':ftp, 'powerperc':serialize_list(powerperc), 'powerzones':serialize_list(r.powerzones), } # make plot - asynchronous task plotnrs = { - 'timeplot':1, - 'distanceplot':2, - 'pieplot':3, + 'timeplot':1, + 'distanceplot':2, + 'pieplot':3, } if plotnr == 0: plotnr = plotnrs[plottype] if w.workouttype in otwtypes: - plotnr = plotnr+3 + plotnr = plotnr+3 job = myqueue(queue,handle_makeplot,f1,f2, - title,hrpwrdata, - plotnr,imagename) + title,hrpwrdata, + plotnr,imagename) try: width,height = Image.open(fullpathimagename).size @@ -451,8 +452,12 @@ def make_plot(r,w,f1,f2,plottype,title,imagename='',plotnr=0): return i.id,job.id -import c2stuff,stravastuff,sporttracksstuff,runkeeperstuff -import underarmourstuff,tpstuff +import rowers.c2stuff as c2stuff +import rowers.stravastuff as stravastuff +import rowers.sporttracksstuff as sporttracksstuff +import rowers.runkeeperstuff as runkeeperstuff +import rowers.underarmourstuff as underarmourstuff +import rowers.tpstuff as tpstuff def set_workouttype(w,options): try: diff --git a/rowers/urls.py b/rowers/urls.py index d517f694..60287e59 100644 --- a/rowers/urls.py +++ b/rowers/urls.py @@ -2,7 +2,7 @@ from django.conf import settings from django.conf.urls import url, include from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required, permission_required -from models import Workout,Rower,StrokeData,FavoriteChart +from rowers.models import Workout,Rower,StrokeData,FavoriteChart from rest_framework import routers, serializers, viewsets,permissions from rest_framework.urlpatterns import format_suffix_patterns diff --git a/rowers/utils.py b/rowers/utils.py index 11905555..6b5484a8 100644 --- a/rowers/utils.py +++ b/rowers/utils.py @@ -439,10 +439,10 @@ def ewmovingaverage(interval,window_size): # Custom error class - to raise a NoTokenError class NoTokenError(Exception): def __init__(self,value): - self.value=value + self.value=value def __str__(self): - return repr(self.value) + return repr(self.value) class ProcessorCustomerError(Exception): def __init__(self, value): diff --git a/rowers/views/analysisviews.py b/rowers/views/analysisviews.py index 6cc5bf52..1bda5a80 100644 --- a/rowers/views/analysisviews.py +++ b/rowers/views/analysisviews.py @@ -1,13 +1,14 @@ -from statements import * +from __future__ import unicode_literals, absolute_import +from rowers.views.statements import * # Histogram for a date/time range @user_passes_test(ispromember,login_url="/rowers/paidplans", message="This functionality requires a Pro plan or higher", redirect_field_name=None) def histo(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - deltadays=-1, + startdate=timezone.now()-datetime.timedelta(days=365), + enddate=timezone.now(), + deltadays=-1, enddatestring=timezone.now().strftime("%Y-%m-%d"), startdatestring=(timezone.now()-datetime.timedelta(days=30)).strftime("%Y-%m-%d"), options={ @@ -59,30 +60,30 @@ def histo(request,theuser=0, if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s - + # get all indoor rows of in date range # process form if request.method == 'POST': - form = DateRangeForm(request.POST) + form = DateRangeForm(request.POST) modalityform = TrendFlexModalForm(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 + if form.is_valid(): + startdate = form.cleaned_data['startdate'] + enddate = form.cleaned_data['enddate'] + if startdate > enddate: + s = enddate + enddate = startdate + startdate = s startdatestring = startdate.strftime('%Y-%m-%d') enddatestring = enddate.strftime('%Y-%m-%d') if modalityform.is_valid(): @@ -102,14 +103,14 @@ def histo(request,theuser=0, request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + 'startdate': startdate, + 'enddate': enddate, + }) else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + form = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) includereststrokes = False workstrokesonly = not includereststrokes @@ -159,18 +160,18 @@ def histo(request,theuser=0, request.session['options'] = options return render(request, 'histo.html', - {'interactiveplot':script, - 'the_div':div, - 'id':theuser, + {'interactiveplot':script, + 'the_div':div, + 'id':theuser, 'active':'nav-analysis', - 'theuser':theuser, + 'theuser':theuser, 'rower':r, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, + 'startdate':startdate, + 'enddate':enddate, + 'form':form, 'optionsform':modalityform, 'teams':get_my_teams(request.user), - }) + }) # The Flex plot for a large selection of workouts @login_required() @@ -226,19 +227,19 @@ def cum_flex_data( if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s promember=0 if theuser == 0: - theuser = request.user.id + theuser = request.user.id if not request.user.is_anonymous(): - r = getrower(request.user) - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 r2 = getrower(theuser) @@ -248,24 +249,24 @@ def cum_flex_data( rankingpiece = [True,False] allworkouts = Workout.objects.filter(user=r2, - workouttype__in=modalities, + workouttype__in=modalities, boattype__in=waterboattype, - startdatetime__gte=startdate, - startdatetime__lte=enddate, + startdatetime__gte=startdate, + startdatetime__lte=enddate, rankingpiece__in=rankingpiece) if allworkouts: - res = interactive_cum_flex_chart2(allworkouts,xparam=xparam, - yparam1=yparam1, - yparam2=yparam2, - promember=promember, + res = interactive_cum_flex_chart2(allworkouts,xparam=xparam, + yparam1=yparam1, + yparam2=yparam2, + promember=promember, workstrokesonly=workstrokesonly, ) - script = res[0] - div = res[1] + script = res[0] + div = res[1] else: - script = '' - div = '

    No pieces uploaded for this date range.

    ' + script = '' + div = '

    No pieces uploaded for this date range.

    ' scripta = script.split('\n')[2:-1] script = ''.join(scripta) @@ -324,19 +325,19 @@ def histo_data( if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s promember=0 if theuser == 0: - theuser = request.user.id + theuser = request.user.id if not request.user.is_anonymous(): - r = getrower(request.user) - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 r2 = getrower(theuser) @@ -346,19 +347,19 @@ def histo_data( rankingpiece = [True,False] allworkouts = Workout.objects.filter(user=r2, - workouttype__in=modalities, + workouttype__in=modalities, boattype__in=waterboattype, - startdatetime__gte=startdate, - startdatetime__lte=enddate, + startdatetime__gte=startdate, + startdatetime__lte=enddate, rankingpiece__in=rankingpiece) if allworkouts: res = interactive_histoall(allworkouts) - script = res[0] - div = res[1] + script = res[0] + div = res[1] else: - script = '' - div = '

    No pieces uploaded for this date range.

    ' + script = '' + div = '

    No pieces uploaded for this date range.

    ' scripta = script.split('\n')[2:-1] script = ''.join(scripta) @@ -375,12 +376,12 @@ def histo_data( @login_required() def cum_flex(request,theuser=0, - xparam='spm', - yparam1='power', - yparam2='None', - startdate=timezone.now()-datetime.timedelta(days=10), - enddate=timezone.now(), - deltadays=-1, + xparam='spm', + yparam1='power', + yparam2='None', + startdate=timezone.now()-datetime.timedelta(days=10), + enddate=timezone.now(), + deltadays=-1, enddatestring=timezone.now().strftime("%Y-%m-%d"), startdatestring=(timezone.now()-datetime.timedelta(days=30)).strftime("%Y-%m-%d"), options={ @@ -433,31 +434,31 @@ def cum_flex(request,theuser=0, if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s - + # get all indoor rows of in date range # process form if request.method == 'POST': - form = DateRangeForm(request.POST) + form = DateRangeForm(request.POST) modalityform = TrendFlexModalForm(request.POST) flexaxesform = FlexAxesForm(request,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 + if form.is_valid(): + startdate = form.cleaned_data['startdate'] + enddate = form.cleaned_data['enddate'] + if startdate > enddate: + s = enddate + enddate = startdate + startdate = s startdatestring = startdate.strftime('%Y-%m-%d') enddatestring = enddate.strftime('%Y-%m-%d') if modalityform.is_valid(): @@ -477,18 +478,18 @@ def cum_flex(request,theuser=0, request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + 'startdate': startdate, + 'enddate': enddate, + }) if flexaxesform.is_valid(): xparam = flexaxesform.cleaned_data['xaxis'] yparam1 = flexaxesform.cleaned_data['yaxis1'] yparam2 = flexaxesform.cleaned_data['yaxis2'] else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + form = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) includereststrokes = False workstrokesonly = not includereststrokes @@ -548,25 +549,25 @@ def cum_flex(request,theuser=0, return render(request, 'cum_flex.html', - {'interactiveplot':script, - 'the_div':div, - 'js_res': js_resources, - 'css_res':css_resources, - 'id':theuser, + {'interactiveplot':script, + 'the_div':div, + 'js_res': js_resources, + 'css_res':css_resources, + 'id':theuser, 'rower':r, 'active':'nav-analysis', - 'theuser':theuser, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, + 'theuser':theuser, + 'startdate':startdate, + 'enddate':enddate, + 'form':form, 'optionsform':modalityform, - 'xparam':xparam, - 'yparam1':yparam1, - 'yparam2':yparam2, - 'promember':promember, + 'xparam':xparam, + 'yparam1':yparam1, + 'yparam2':yparam2, + 'promember':promember, 'teams':get_my_teams(request.user), 'flexaxesform':flexaxesform, - }) + }) def planrequired_view(request): @@ -619,32 +620,32 @@ def fitnessmetric_view(request,id=0,mode='rower', # Show ranking distances including predicted paces @login_required() def rankings_view(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring=""): + startdate=timezone.now()-datetime.timedelta(days=365), + enddate=timezone.now(), + deltadays=-1, + startdatestring="", + enddatestring=""): if deltadays>0: - startdate = enddate-datetime.timedelta(days=int(deltadays)) + startdate = enddate-datetime.timedelta(days=int(deltadays)) if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s if theuser == 0: - theuser = request.user.id + theuser = request.user.id promember=0 if not request.user.is_anonymous(): - r = getrower(request.user) + r = getrower(request.user) if r.birthdate: age = calculate_age(r.birthdate) worldclasspower = int(metrics.getagegrouprecord( @@ -655,61 +656,61 @@ def rankings_view(request,theuser=0, else: worldclasspower = None - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 # get all indoor rows 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 + 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: - 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, - }) + deltaform = DeltaDaysForm(request.POST) + if deltaform.is_valid(): + deltadays = deltaform.cleaned_data['deltadays'] + if deltadays: + 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() deltaform = DeltaDaysForm() else: - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - deltaform = DeltaDaysForm() + dateform = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) + deltaform = DeltaDaysForm() # get all 2k (if any) - this rower, in date range try: - r = getrower(theuser) + r = getrower(theuser) except Rower.DoesNotExist: - allergworkouts = [] - r=0 + allergworkouts = [] + r=0 - + try: - uu = User.objects.get(id=theuser) + uu = User.objects.get(id=theuser) except User.DoesNotExist: - uu = '' + uu = '' # test to fix bug @@ -726,43 +727,43 @@ def rankings_view(request,theuser=0, for rankingdistance in rankingdistances: - workouts = Workout.objects.filter( + workouts = Workout.objects.filter( user=r,distance=rankingdistance, - workouttype__in=['rower','dynamic','slides'], + workouttype__in=['rower','dynamic','slides'], rankingpiece=True, - startdatetime__gte=startdate, - startdatetime__lte=enddate + startdatetime__gte=startdate, + startdatetime__lte=enddate ).order_by('duration') - if workouts: - thedistances.append(rankingdistance) - theworkouts.append(workouts[0]) + 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) + 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( + workouts = Workout.objects.filter( user=r,duration=rankingduration, - workouttype='rower', + workouttype='rower', rankingpiece=True, - startdatetime__gte=startdate, - startdatetime__lte=enddate + startdatetime__gte=startdate, + startdatetime__lte=enddate ).order_by('-distance') - if workouts: - thedistances.append(workouts[0].distance) - theworkouts.append(workouts[0]) + 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) + 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) @@ -773,39 +774,39 @@ def rankings_view(request,theuser=0, # create interactive plot if len(thedistances) !=0 : - res = interactive_cpchart( + res = interactive_cpchart( r,thedistances,thesecs,theavpower, - theworkouts,promember=promember + theworkouts,promember=promember ) - script = res[0] - div = res[1] - paulslope = res[2] - paulintercept = res[3] - p1 = res[4] - message = res[5] + 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 = "" + 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'] + form = PredictedPieceForm(request.POST) + if form.is_valid(): + value = form.cleaned_data['value'] hourvalue,value = divmod(value,60) if hourvalue >= 24: hourvalue = 23 - pieceunit = form.cleaned_data['pieceunit'] - if pieceunit == 'd': - rankingdistances.append(value) - else: - rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue))) + pieceunit = form.cleaned_data['pieceunit'] + if pieceunit == 'd': + rankingdistances.append(value) + else: + rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue))) else: - form = PredictedPieceForm() + form = PredictedPieceForm() rankingdistances.sort() rankingdurations.sort() @@ -816,118 +817,118 @@ def rankings_view(request,theuser=0, 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) + # 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]) + # 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 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 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 + 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) + 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 + t = 3600.*rankingduration.hour + t += 60.*rankingduration.minute + t += rankingduration.second + t += rankingduration.microsecond/1.e6 - # Paul's model - ratio = paulintercept/paulslope + # Paul's model + ratio = paulintercept/paulslope - u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/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 + 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) + 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]) + # CP model + pwr = p1[0]/(1+t/p1[2]) + pwr += p1[1]/(1+t/p1[3]) - if pwr <= 0: - pwr = 50. + if pwr <= 0: + pwr = 50. - velo = (pwr/2.8)**(1./3.) + 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) + 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) messages.error(request,message) return render(request, 'rankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, - 'predictions':predictions, - 'cpredictions':cpredictions, - 'nrdata':len(thedistances), - 'form':form, + {'rankingworkouts':theworkouts, + 'interactiveplot':script, + 'the_div':div, + 'predictions':predictions, + 'cpredictions':cpredictions, + 'nrdata':len(thedistances), + 'form':form, 'rower':r, 'active':'nav-analysis', - 'dateform':dateform, - 'deltaform':deltaform, + 'dateform':dateform, + 'deltaform':deltaform, 'worldclasspower':worldclasspower, - 'id': theuser, - 'theuser':uu, - 'startdate':startdate, - 'enddate':enddate, + 'id': theuser, + 'theuser':uu, + 'startdate':startdate, + 'enddate':enddate, 'teams':get_my_teams(request.user), - }) + }) @login_required() def ajax_agegrouprecords(request, @@ -969,28 +970,28 @@ def ajax_agegrouprecords(request, # Show ranking distances including predicted paces @login_required() def rankings_view2(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring=""): + startdate=timezone.now()-datetime.timedelta(days=365), + enddate=timezone.now(), + deltadays=-1, + startdatestring="", + enddatestring=""): if deltadays>0: - startdate = enddate-datetime.timedelta(days=int(deltadays)) + startdate = enddate-datetime.timedelta(days=int(deltadays)) if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s if theuser == 0: - theuser = request.user.id + theuser = request.user.id else: lastupdated = "01-01-1900" @@ -1063,61 +1064,61 @@ def rankings_view2(request,theuser=0, request.session['options'] = options - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 # get all indoor rows 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 + 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: - 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, - }) + deltaform = DeltaDaysForm(request.POST) + if deltaform.is_valid(): + deltadays = deltaform.cleaned_data['deltadays'] + if deltadays: + 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() deltaform = DeltaDaysForm() else: - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) - deltaform = DeltaDaysForm() + dateform = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) + deltaform = DeltaDaysForm() # get all 2k (if any) - this rower, in date range try: - r = getrower(theuser) + r = getrower(theuser) except Rower.DoesNotExist: - allergworkouts = [] - r=0 + allergworkouts = [] + r=0 - + try: - uu = User.objects.get(id=theuser) + uu = User.objects.get(id=theuser) except User.DoesNotExist: - uu = '' + uu = '' # test to fix bug @@ -1137,41 +1138,41 @@ def rankings_view2(request,theuser=0, for rankingdistance in rankingdistances: - workouts = Workout.objects.filter( + workouts = Workout.objects.filter( user=r,distance=rankingdistance, - workouttype__in=['rower','dynamic','slides'], + workouttype__in=['rower','dynamic','slides'], rankingpiece=True, - startdatetime__gte=startdate, - startdatetime__lte=enddate).order_by('duration') - if workouts: - thedistances.append(rankingdistance) - theworkouts.append(workouts[0]) + 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) + 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( + workouts = Workout.objects.filter( user=r,duration=rankingduration, - workouttype='rower', + workouttype='rower', rankingpiece=True, - startdatetime__gte=startdate, - startdatetime__lte=enddate).order_by('-distance') - if workouts: - thedistances.append(workouts[0].distance) - theworkouts.append(workouts[0]) + 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) + 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) @@ -1182,45 +1183,45 @@ def rankings_view2(request,theuser=0, # create interactive plot if len(thedistances) !=0 : - res = interactive_cpchart( + res = interactive_cpchart( r,thedistances,thesecs,theavpower, - theworkouts,promember=promember, + theworkouts,promember=promember, wcdurations=wcdurations,wcpower=wcpower ) - script = res[0] - div = res[1] - paulslope = res[2] - paulintercept = res[3] - p1 = res[4] - message = res[5] + script = res[0] + div = res[1] + paulslope = res[2] + paulintercept = res[3] + p1 = res[4] + message = res[5] try: testcalc = pd.Series(res[6])*3 except TypeError: age = 0 else: - script = '' - div = '

    No ranking pieces found.

    ' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" + 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'] + form = PredictedPieceForm(request.POST) + if form.is_valid(): + value = form.cleaned_data['value'] hourvalue,value = divmod(value,60) if hourvalue >= 24: hourvalue = 23 - pieceunit = form.cleaned_data['pieceunit'] - if pieceunit == 'd': - rankingdistances.append(value) - else: - rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue))) + pieceunit = form.cleaned_data['pieceunit'] + if pieceunit == 'd': + rankingdistances.append(value) + else: + rankingdurations.append(datetime.time(minute=int(value),hour=int(hourvalue))) else: - form = PredictedPieceForm() + form = PredictedPieceForm() rankingdistances.sort() rankingdurations.sort() @@ -1231,99 +1232,99 @@ def rankings_view2(request,theuser=0, 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) + # 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]) + # 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 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 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 + 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) + 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 + t = 3600.*rankingduration.hour + t += 60.*rankingduration.minute + t += rankingduration.second + t += rankingduration.microsecond/1.e6 - # Paul's model - ratio = paulintercept/paulslope + # Paul's model + ratio = paulintercept/paulslope - u = ((2**(2+ratio))*(5.**(3+ratio))*t*np.log(10))/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 + 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) + velo = d/t + p = 500./velo + pwr = 2.8*(velo**3) try: - a = {'distance':int(d), - 'duration':timedeltaconv(t), - 'pace':timedeltaconv(p), - 'power':int(pwr)} - predictions.append(a) + a = {'distance':int(d), + 'duration':timedeltaconv(t), + 'pace':timedeltaconv(p), + 'power':int(pwr)} + predictions.append(a) except: pass - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) + # CP model + pwr = p1[0]/(1+t/p1[2]) + pwr += p1[1]/(1+t/p1[3]) - if pwr <= 0: - pwr = 50. + if pwr <= 0: + pwr = 50. - velo = (pwr/2.8)**(1./3.) + 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) + 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) if recalc: wcdurations = [] @@ -1354,27 +1355,27 @@ def rankings_view2(request,theuser=0, messages.error(request,message) 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, + {'rankingworkouts':theworkouts, + 'interactiveplot':script, + 'the_div':div, + 'predictions':predictions, + 'cpredictions':cpredictions, + 'nrdata':len(thedistances), + 'form':form, + 'dateform':dateform, + 'deltaform':deltaform, + 'id': theuser, + 'theuser':uu, 'rower':r, 'active':'nav-analysis', 'age':age, 'sex':r.sex, 'recalc':recalc, 'weightcategory':r.weightcategory, - 'startdate':startdate, - 'enddate':enddate, + 'startdate':startdate, + 'enddate':enddate, 'teams':get_my_teams(request.user), - }) + }) # Show ranking distances including predicted paces @@ -1382,27 +1383,27 @@ def rankings_view2(request,theuser=0, message="This functionality requires a Pro plan or higher", redirect_field_name=None) def otwrankings_view(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - startdatestring="", - enddatestring=""): + startdate=timezone.now()-datetime.timedelta(days=365), + enddate=timezone.now(), + startdatestring="", + enddatestring=""): if startdatestring != "": try: - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) except ParseError: pass if enddatestring != "": try: - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) except ParseError: pass if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s if theuser == 0: if 'rowerid' in request.session: @@ -1412,30 +1413,30 @@ def otwrankings_view(request,theuser=0, except Rower.DoesNotExist: theuser = request.user.id else: - theuser = request.user.id + 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 ispromember(request.user) - if result: - promember=1 + r = Rower.objects.get(user=request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 # get all OTW rows in date range # process form if request.method == 'POST': - dateform = DateRangeForm(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 - form = PredictedPieceFormNoDistance(request.POST) + dateform = DateRangeForm(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 + form = PredictedPieceFormNoDistance(request.POST) if form.is_valid(): - value = form.cleaned_data['value'] + value = form.cleaned_data['value'] else: value = None trankingdurations = form.cleaned_data['trankingdurations'] @@ -1449,34 +1450,34 @@ def otwrankings_view(request,theuser=0, tvalue = int(60*(tvalue-minutevalue)) if hourvalue >= 24: hourvalue = 23 - trankingdurations.append(datetime.time( + trankingdurations.append(datetime.time( minute=minutevalue, hour=hourvalue, second=tvalue )) else: - form = PredictedPieceFormNoDistance() - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + form = PredictedPieceFormNoDistance() + dateform = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) workouttypes = ['rower','slides','dynamic'] trankingdurations = rankingdurations # get all 2k (if any) - this rower, in date range try: - r = Rower.objects.get(user=theuser) + r = Rower.objects.get(user=theuser) request.session['rowerid'] = r.id except Rower.DoesNotExist: - raise Http404("Rower doesn't exist") - + raise Http404("Rower doesn't exist") + - + try: - uu = User.objects.get(id=theuser) + uu = User.objects.get(id=theuser) except User.DoesNotExist: - uu = '' + uu = '' # test to fix bug @@ -1492,9 +1493,9 @@ def otwrankings_view(request,theuser=0, theworkouts = Workout.objects.filter( user=r,rankingpiece=True, - workouttype='water', - startdatetime__gte=startdate, - startdatetime__lte=enddate + workouttype='water', + startdatetime__gte=startdate, + startdatetime__lte=enddate ).order_by( "-startdatetime" ) @@ -1557,10 +1558,10 @@ def otwrankings_view(request,theuser=0, rowername = r.user.first_name+" "+r.user.last_name # create interactive plot if len(powerdf) !=0 : - res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername) - script = res[0] - div = res[1] - p1 = res[2] + res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername) + script = res[0] + div = res[1] + p1 = res[2] ratio = res[3] r.p0 = p1[0] r.p1 = p1[1] @@ -1570,14 +1571,14 @@ def otwrankings_view(request,theuser=0, r.save() paulslope = 1 paulintercept = 1 - message = res[4] + message = res[4] else: - script = '' - div = '

    No ranking pieces found.

    ' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" + script = '' + div = '

    No ranking pieces found.

    ' + paulslope = 1 + paulintercept = 1 + p1 = [1,1,1,1] + message = "" @@ -1585,19 +1586,19 @@ def otwrankings_view(request,theuser=0, cpredictions = [] for rankingduration in trankingdurations: - t = 3600.*rankingduration.hour - t += 60.*rankingduration.minute - t += rankingduration.second - t += rankingduration.microsecond/1.e6 + t = 3600.*rankingduration.hour + t += 60.*rankingduration.minute + t += rankingduration.second + t += rankingduration.microsecond/1.e6 - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) + # CP model + pwr = p1[0]/(1+t/p1[2]) + pwr += p1[1]/(1+t/p1[3]) - if pwr <= 0: - pwr = 50. + if pwr <= 0: + pwr = 50. if not np.isnan(pwr): @@ -1607,10 +1608,10 @@ def otwrankings_view(request,theuser=0, pwr2 = pwr a = { - 'duration':timedeltaconv(t), - 'power':int(pwr), + 'duration':timedeltaconv(t), + 'power':int(pwr), 'upper':int(pwr2)} - cpredictions.append(a) + cpredictions.append(a) @@ -1621,22 +1622,22 @@ def otwrankings_view(request,theuser=0, messages.error(request,message) return render(request, 'otwrankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, - 'cpredictions':cpredictions, + {'rankingworkouts':theworkouts, + 'interactiveplot':script, + 'the_div':div, + 'cpredictions':cpredictions, 'rower':r, 'active':'nav-analysis', 'avgpower':avgpower, - 'form':form, - 'dateform':dateform, - 'id': theuser, - 'theuser':uu, - 'startdate':startdate, - 'enddate':enddate, + 'form':form, + 'dateform':dateform, + 'id': theuser, + 'theuser':uu, + 'startdate':startdate, + 'enddate':enddate, 'teams':get_my_teams(request.user), 'workouttype':'water', - }) + }) @login_required() def otecp_toadmin_view(request,theuser=0, @@ -1648,13 +1649,13 @@ def otecp_toadmin_view(request,theuser=0, if startdatestring != "": try: - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) except ParseError: pass if enddatestring != "": try: - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) except ParseError: pass @@ -1669,13 +1670,13 @@ def otecp_toadmin_view(request,theuser=0, theworkouts = Workout.objects.filter( user=r,rankingpiece=True, - workouttype__in=[ + workouttype__in=[ 'rower', 'dynamic', 'slides' ], - startdatetime__gte=startdate, - startdatetime__lte=enddate + startdatetime__gte=startdate, + startdatetime__lte=enddate ).order_by("-startdatetime") @@ -1722,13 +1723,13 @@ def otwcp_toadmin_view(request,theuser=0, if startdatestring != "": try: - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) except ParseError: pass if enddatestring != "": try: - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) except ParseError: pass @@ -1744,8 +1745,8 @@ def otwcp_toadmin_view(request,theuser=0, theworkouts = Workout.objects.filter( user=r,rankingpiece=True, workouttype='water', - startdatetime__gte=startdate, - startdatetime__lte=enddate + startdatetime__gte=startdate, + startdatetime__lte=enddate ).order_by("-startdatetime") @@ -1787,27 +1788,27 @@ def otwcp_toadmin_view(request,theuser=0, message="This functionality requires a Pro plan or higher", redirect_field_name=None) def oterankings_view(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=365), - enddate=timezone.now(), - startdatestring="", - enddatestring=""): + startdate=timezone.now()-datetime.timedelta(days=365), + enddate=timezone.now(), + startdatestring="", + enddatestring=""): if startdatestring != "": try: - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) except ParseError: pass if enddatestring != "": try: - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) except ParseError: pass if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s if theuser == 0: if 'rowerid' in request.session: @@ -1817,34 +1818,34 @@ def oterankings_view(request,theuser=0, except Rower.DoesNotExist: theuser = request.user.id else: - theuser = request.user.id + 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 ispromember(request.user) - if result: - promember=1 + r = Rower.objects.get(user=request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 # get all OTW rows in date range # process form if request.method == 'POST': - dateform = DateRangeForm(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 + dateform = DateRangeForm(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 workouttypeform = OteWorkoutTypeForm(request.POST) if workouttypeform.is_valid(): workouttypes = workouttypeform.cleaned_data['workouttypes'] - form = PredictedPieceForm(request.POST) + form = PredictedPieceForm(request.POST) if form.is_valid(): - value = form.cleaned_data['value'] + value = form.cleaned_data['value'] pieceunit = form.cleaned_data['pieceunit'] else: value = None @@ -1874,17 +1875,17 @@ def oterankings_view(request,theuser=0, if pieceunit == 'd': trankingdistances.append(value) else: - trankingdurations.append(datetime.time( + trankingdurations.append(datetime.time( minute=minutevalue, hour=hourvalue, second=tvalue )) else: - form = PredictedPieceForm() - dateform = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + form = PredictedPieceForm() + dateform = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) workouttypeform = OteWorkoutTypeForm() workouttypes = ['rower','slides','dynamic'] trankingdistances = rankingdistances @@ -1892,17 +1893,17 @@ def oterankings_view(request,theuser=0, # get all 2k (if any) - this rower, in date range try: - r = Rower.objects.get(user=theuser) + r = Rower.objects.get(user=theuser) request.session['rowerid'] = r.id except Rower.DoesNotExist: - allergworkouts = [] + allergworkouts = [] raise Http404("Rower doesn't exist") - + try: - uu = User.objects.get(id=theuser) + uu = User.objects.get(id=theuser) except User.DoesNotExist: - uu = '' + uu = '' # test to fix bug @@ -1917,9 +1918,9 @@ def oterankings_view(request,theuser=0, theworkouts = Workout.objects.filter( user=r,rankingpiece=True, - workouttype__in=workouttypes, - startdatetime__gte=startdate, - startdatetime__lte=enddate + workouttype__in=workouttypes, + startdatetime__gte=startdate, + startdatetime__lte=enddate ).order_by("-startdatetime") @@ -1980,10 +1981,10 @@ def oterankings_view(request,theuser=0, rowername = r.user.first_name+" "+r.user.last_name # create interactive plot if len(powerdf) !=0 : - res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername) - script = res[0] - div = res[1] - p1 = res[2] + res = interactive_otwcpchart(powerdf,promember=promember,rowername=rowername) + script = res[0] + div = res[1] + p1 = res[2] ratio = res[3] r.ep0 = p1[0] r.ep1 = p1[1] @@ -1993,15 +1994,15 @@ def oterankings_view(request,theuser=0, r.save() paulslope = 1 paulintercept = 1 - message = res[4] + message = res[4] else: ratio = 1 - script = '' - div = '

    No ranking pieces found.

    ' - paulslope = 1 - paulintercept = 1 - p1 = [1,1,1,1] - message = "" + script = '' + div = '

    No ranking pieces found.

    ' + paulslope = 1 + paulintercept = 1 + p1 = [1,1,1,1] + message = "" @@ -2012,22 +2013,22 @@ def oterankings_view(request,theuser=0, for rankingduration in trankingdurations: - t = 3600.*rankingduration.hour - t += 60.*rankingduration.minute - t += rankingduration.second - t += rankingduration.microsecond/1.e6 + t = 3600.*rankingduration.hour + t += 60.*rankingduration.minute + t += rankingduration.second + t += rankingduration.microsecond/1.e6 - # CP model - pwr = p1[0]/(1+t/p1[2]) - pwr += p1[1]/(1+t/p1[3]) + # CP model + pwr = p1[0]/(1+t/p1[2]) + pwr += p1[1]/(1+t/p1[3]) velo = (pwr/2.8)**(1./3.) p = 500./velo d = t*velo - if pwr <= 0: - pwr = 50. + if pwr <= 0: + pwr = 50. if not np.isnan(pwr): @@ -2038,12 +2039,12 @@ def oterankings_view(request,theuser=0, a = { 'distance':int(d), - 'duration':timedeltaconv(t), - 'power':int(pwr), + 'duration':timedeltaconv(t), + 'power':int(pwr), 'upper':int(pwr2), 'pace':timedeltaconv(p)} - cpredictions.append(a) + cpredictions.append(a) # initiation - get 10 min power, then use Paul's law @@ -2067,43 +2068,43 @@ def oterankings_view(request,theuser=0, velo = 500./p t = rankingdistance/velo - pwr2 = p1[0]/(1+t/p1[2]) - pwr2 += p1[1]/(1+t/p1[3]) + pwr2 = p1[0]/(1+t/p1[2]) + pwr2 += p1[1]/(1+t/p1[3]) try: pwr2 *= ratio except UnboundLocalError: pass - if pwr2 <= 0: - pwr2 = 50. - - velo2 = (pwr2/2.8)**(1./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 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]) pwr3 *= ratio - 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 + 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 = { + a = { 'distance':rankingdistance, - 'duration':timedeltaconv(t3), - 'power':'--', - 'upper':int(pwr3), + 'duration':timedeltaconv(t3), + 'power':'--', + 'upper':int(pwr3), 'pace':timedeltaconv(p3)} cpredictions.append(a) @@ -2113,23 +2114,23 @@ def oterankings_view(request,theuser=0, messages.error(request,message) return render(request, 'oterankings.html', - {'rankingworkouts':theworkouts, - 'interactiveplot':script, - 'the_div':div, + {'rankingworkouts':theworkouts, + 'interactiveplot':script, + 'the_div':div, 'rower':r, 'active':'nav-analysis', - 'cpredictions':cpredictions, + 'cpredictions':cpredictions, 'avgpower':avgpower, - 'form':form, - 'dateform':dateform, + 'form':form, + 'dateform':dateform, 'workouttypeform':workouttypeform, - 'id': theuser, - 'theuser':uu, - 'startdate':startdate, - 'enddate':enddate, + 'id': theuser, + 'theuser':uu, + 'startdate':startdate, + 'enddate':enddate, 'teams':get_my_teams(request.user), 'workouttype':'rower', - }) + }) @@ -2807,15 +2808,15 @@ def user_boxplot_select(request, if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s if request.method == 'POST': @@ -3199,11 +3200,11 @@ def boxplot_view(request,userid=0, # Cumulative stats page @user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher",redirect_field_name=None) def cumstats(request,theuser=0, - startdate=timezone.now()-datetime.timedelta(days=30), - enddate=timezone.now(), - deltadays=-1, - startdatestring="", - enddatestring="", + startdate=timezone.now()-datetime.timedelta(days=30), + enddate=timezone.now(), + deltadays=-1, + startdatestring="", + enddatestring="", options={ 'includereststrokes':False, 'workouttypes':['rower','dynamic','slides'], @@ -3253,30 +3254,30 @@ def cumstats(request,theuser=0, if startdatestring != "": - startdate = iso8601.parse_date(startdatestring) + startdate = iso8601.parse_date(startdatestring) if enddatestring != "": - enddate = iso8601.parse_date(enddatestring) + enddate = iso8601.parse_date(enddatestring) if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s - + # get all indoor rows of in date range # process form if request.method == 'POST': - form = DateRangeForm(request.POST) + form = DateRangeForm(request.POST) modalityform = TrendFlexModalForm(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 + if form.is_valid(): + startdate = form.cleaned_data['startdate'] + enddate = form.cleaned_data['enddate'] + if startdate > enddate: + s = enddate + enddate = startdate + startdate = s startdatestring = startdate.strftime('%Y-%m-%d') enddatestring = enddate.strftime('%Y-%m-%d') if modalityform.is_valid(): @@ -3296,14 +3297,14 @@ def cumstats(request,theuser=0, request.session['waterboattype'] = waterboattype request.session['rankingonly'] = rankingonly form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + 'startdate': startdate, + 'enddate': enddate, + }) else: - form = DateRangeForm(initial={ - 'startdate': startdate, - 'enddate': enddate, - }) + form = DateRangeForm(initial={ + 'startdate': startdate, + 'enddate': enddate, + }) includereststrokes = False workstrokesonly = not includereststrokes @@ -3358,19 +3359,19 @@ def cumstats(request,theuser=0, if enddate < startdate: - s = enddate - enddate = startdate - startdate = s + s = enddate + enddate = startdate + startdate = s promember=0 if theuser == 0: - theuser = request.user.id + theuser = request.user.id if not request.user.is_anonymous(): - r = getrower(request.user) - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 r2 = getrower(theuser) @@ -3381,10 +3382,10 @@ def cumstats(request,theuser=0, allworkouts = Workout.objects.filter( user=r2, - workouttype__in=modalities, + workouttype__in=modalities, boattype__in=waterboattype, - startdatetime__gte=startdate, - startdatetime__lte=enddate, + startdatetime__gte=startdate, + startdatetime__lte=enddate, rankingpiece__in=rankingpiece ).order_by("-date", "-starttime") @@ -3410,18 +3411,18 @@ def cumstats(request,theuser=0, cordict = {} response = render(request, - 'cumstats.html', - { + 'cumstats.html', + { 'stats':stats, 'teams':get_my_teams(request.user), 'options':options, 'active':'nav-analysis', 'rower':r, - 'id':theuser, - 'theuser':theuser, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, + 'id':theuser, + 'theuser':theuser, + 'startdate':startdate, + 'enddate':enddate, + 'form':form, 'optionsform':modalityform, 'cordict':cordict, }) @@ -3472,18 +3473,18 @@ def cumstats(request,theuser=0, response = render(request, - 'cumstats.html', - { + 'cumstats.html', + { 'stats':stats, 'teams':get_my_teams(request.user), 'active':'nav-analysis', 'rower':r, 'options':options, - 'id':theuser, - 'theuser':theuser, - 'startdate':startdate, - 'enddate':enddate, - 'form':form, + 'id':theuser, + 'theuser':theuser, + 'startdate':startdate, + 'enddate':enddate, + 'form':form, 'optionsform':modalityform, 'cordict':cordict, }) @@ -3536,8 +3537,8 @@ def agegrouprecordview(request,sex='male',weightcategory='hwt', weightcategory=weightcategory) return render(request, 'agegroupchart.html', - { - 'interactiveplot':script, + { + 'interactiveplot':script, 'active':'nav-analysis', - 'the_div':div, - }) + 'the_div':div, + }) diff --git a/rowers/views/apiviews.py b/rowers/views/apiviews.py index 1a0271c9..180e1e9a 100644 --- a/rowers/views/apiviews.py +++ b/rowers/views/apiviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * # Stroke data form to test API upload @@ -18,22 +18,22 @@ def strokedataform(request,id=0): if request.method == 'GET': form = StrokeDataForm() return render(request, 'strokedata_form.html', - { - 'form':form, + { + 'form':form, 'teams':get_my_teams(request.user), 'id':id, 'workout':w, - }) + }) elif request.method == 'POST': form = StrokeDataForm() return render(request, 'strokedata_form.html', - { - 'form':form, + { + 'form':form, 'teams':get_my_teams(request.user), 'id':id, 'workout':w, - }) + }) # Process the POSTed stroke data according to the API definition # Return the GET stroke data according to the API definition @@ -124,30 +124,30 @@ def strokedatajson(request,id): logfile.write(request.user.username+"(POST) \r\n") data = pd.DataFrame({'TimeStamp (sec)':unixtime, - ' Horizontal (meters)': distance, - ' Cadence (stokes/min)':spm, - ' HRCur (bpm)':hr, - ' DragFactor':dragfactor, - ' Stroke500mPace (sec/500m)':pace, - ' Power (watts)':power, - ' DriveLength (meters)':drivelength, - ' DriveTime (ms)':drivetime, - ' StrokeRecoveryTime (ms)':strokerecoverytime, - ' AverageDriveForce (lbs)':averagedriveforce, - ' PeakDriveForce (lbs)':peakdriveforce, - ' lapIdx':lapidx, - ' ElapsedTime (sec)':time, + ' Horizontal (meters)': distance, + ' Cadence (stokes/min)':spm, + ' HRCur (bpm)':hr, + ' DragFactor':dragfactor, + ' Stroke500mPace (sec/500m)':pace, + ' Power (watts)':power, + ' DriveLength (meters)':drivelength, + ' DriveTime (ms)':drivetime, + ' StrokeRecoveryTime (ms)':strokerecoverytime, + ' AverageDriveForce (lbs)':averagedriveforce, + ' PeakDriveForce (lbs)':peakdriveforce, + ' lapIdx':lapidx, + ' ElapsedTime (sec)':time, 'catch':catch, 'slip':slip, 'finish':finish, 'wash':wash, 'driveenergy':driveenergy, 'peakforceangle':peakforceangle, - }) + }) # Following part should be replaced with dataprep.new_workout_from_df - r = getrower(request.user) + r = getrower(request.user) timestr = row.startdatetime.strftime("%Y%m%d-%H%M%S") csvfilename ='media/Import_'+timestr+'.csv' @@ -167,8 +167,8 @@ def strokedatajson(request,id): ftp = ftp*(100.-r.otwslack)/100. rr = rrower(hrmax=r.max,hrut2=r.ut2, - hrut1=r.ut1,hrat=r.at, - hrtr=r.tr,hran=r.an,ftp=ftp, + hrut1=r.ut1,hrat=r.at, + hrtr=r.tr,hran=r.an,ftp=ftp, powerperc=powerperc,powerzones=r.powerzones) rowdata = rdata(row.csvfilename,rower=rr).df diff --git a/rowers/views/errorviews.py b/rowers/views/errorviews.py index a1c31901..2a46209f 100644 --- a/rowers/views/errorviews.py +++ b/rowers/views/errorviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * # Custom error pages with Rowsandall headers def error500_view(request): diff --git a/rowers/views/exportviews.py b/rowers/views/exportviews.py index a71d9a4f..4c953375 100644 --- a/rowers/views/exportviews.py +++ b/rowers/views/exportviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * diff --git a/rowers/views/importviews.py b/rowers/views/importviews.py index dfe4b936..5ae430da 100644 --- a/rowers/views/importviews.py +++ b/rowers/views/importviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * # Send workout to TP @@ -71,17 +71,17 @@ def workout_strava_upload_view(request,id=0): return HttpResponseRedirect("/rowers/me/stravaauthorize/") if (r.stravatoken == '') or (r.stravatoken is None): - s = "Token doesn't exist. Need to authorize" - return HttpResponseRedirect("/rowers/me/stravaauthorize/") + s = "Token doesn't exist. Need to authorize" + return HttpResponseRedirect("/rowers/me/stravaauthorize/") else: - # ready to upload. Hurray + # ready to upload. Hurray w = get_workout_permitted(request.user,id) r = w.user - if (checkworkoutuser(request.user,w)): + if (checkworkoutuser(request.user,w)): try: - tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w) + tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w) if tcxfile: - with open(tcxfile,'rb') as f: + with open(tcxfile,'rb') as f: try: newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com' except TypeError: @@ -91,38 +91,38 @@ def workout_strava_upload_view(request,id=0): else: activity_type = mytypes.stravamapping[w.workouttype] - res,mes = stravastuff.handle_stravaexport( + res,mes = stravastuff.handle_stravaexport( f,w.name, - r.stravatoken, - description=newnotes, + r.stravatoken, + description=newnotes, activity_type=activity_type) if res==0: messages.error(request,mes) - w.uploadedtostrava = -1 - w.save() + w.uploadedtostrava = -1 + w.save() try: - os.remove(tcxfile) + os.remove(tcxfile) except WindowsError: pass - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) - response = HttpResponseRedirect(url) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':encoder.encode_hex(w.id), + }) + response = HttpResponseRedirect(url) return response try: - w.uploadedtostrava = res - w.save() + w.uploadedtostrava = res + w.save() try: - os.remove(tcxfile) + os.remove(tcxfile) except WindowsError: pass url = reverse('workout_edit_view',kwargs={'id':w.id}) messages.info(request,mes) - except: + except: with open("media/stravaerrors.log","a") as errorlog: errorstring = str(sys.exc_info()[0]) timestr = strftime("%Y%m%d-%H%M%S") @@ -135,33 +135,33 @@ def workout_strava_upload_view(request,id=0): messages.error(request,message) w.uploadedtostrava = -1 w.save() - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) - response = HttpResponseRedirect(url) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':encoder.encode_hex(w.id), + }) + response = HttpResponseRedirect(url) - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - } - ) - response = HttpResponseRedirect(url) - except ActivityUploadFailed as e: - message = "Strava Upload error: %s" % e + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':encoder.encode_hex(w.id), + } + ) + response = HttpResponseRedirect(url) + except ActivityUploadFailed as e: + message = "Strava Upload error: %s" % e messages.error(request,message) - w.uploadedtostrava = -1 - w.save() - os.remove(tcxfile) - url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) - response = HttpResponseRedirect(url) + w.uploadedtostrava = -1 + w.save() + os.remove(tcxfile) + url = reverse(r.defaultlandingpage, + kwargs = { + 'id':encoder.encode_hex(w.id), + }) + response = HttpResponseRedirect(url) - return response - + return response + # Upload workout to Concept2 logbook @login_required() def workout_c2_upload_view(request,id=0): @@ -199,59 +199,59 @@ def workout_runkeeper_upload_view(request,id=0): r = w.user try: - thetoken = runkeeper_open(r.user) + thetoken = runkeeper_open(r.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/runkeeperauthorize/") + return HttpResponseRedirect("/rowers/me/runkeeperauthorize/") # ready to upload. Hurray if (checkworkoutuser(request.user,w)): - data = runkeeperstuff.createrunkeeperworkoutdata(w) + data = runkeeperstuff.createrunkeeperworkoutdata(w) if not data: message = "Data error" messages.error(request,message) url = reverse(r.defaultlandingpage, - kwargs = { - 'id':id, - }) + kwargs = { + 'id':id, + }) return HttpResponseRedirect(url) - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json', + authorizationstring = str('Bearer ' + thetoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/vnd.com.runkeeper.NewFitnessActivity+json', 'Content-Length':'nnn'} - url = "https://api.runkeeper.com/fitnessActivities" - response = requests.post(url,headers=headers,data=json.dumps(data)) + url = "https://api.runkeeper.com/fitnessActivities" + response = requests.post(url,headers=headers,data=json.dumps(data)) - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" + # check for duplicate error first + if (response.status_code == 409 ): + message = "Duplicate error" messages.error(request,message) - w.uploadedtorunkeeper = -1 - w.save() - elif (response.status_code == 201 or response.status_code==200): - runkeeperid = runkeeperstuff.getidfromresponse(response) - w.uploadedtorunkeeper = runkeeperid - w.save() + w.uploadedtorunkeeper = -1 + w.save() + elif (response.status_code == 201 or response.status_code==200): + runkeeperid = runkeeperstuff.getidfromresponse(response) + w.uploadedtorunkeeper = runkeeperid + w.save() url = reverse('workout_edit_view', kwargs={'id':encoder.encode_hex(w.id)}) - return HttpResponseRedirect(url) - else: - s = response - message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text) + return HttpResponseRedirect(url) + else: + s = response + message = "Something went wrong in workout_runkeeper_upload_view: %s - %s" % (s.reason,s.text) messages.error(request,message) - + else: - message = "You are not authorized to upload this workout" + message = "You are not authorized to upload this workout" messages.error(request,message) url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) + kwargs = { + 'id':encoder.encode_hex(w.id), + }) return HttpResponseRedirect(url) @@ -263,59 +263,59 @@ def workout_underarmour_upload_view(request,id=0): r = w.user try: - thetoken = underarmour_open(r.user) + thetoken = underarmour_open(r.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/underarmourauthorize/") + return HttpResponseRedirect("/rowers/me/underarmourauthorize/") # ready to upload. Hurray if (checkworkoutuser(request.user,w)): - data = underarmourstuff.createunderarmourworkoutdata(w) + data = underarmourstuff.createunderarmourworkoutdata(w) if not data: message = "Data error" messages.error(request,message) url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) + kwargs = { + 'id':encoder.encode_hex(w.id), + }) return HttpResponseRedirect(url) - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, + authorizationstring = str('Bearer ' + thetoken) + headers = {'Authorization': authorizationstring, 'Api-Key': UNDERARMOUR_CLIENT_KEY, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json', + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json', } - url = "https://api.ua.com/v7.1/workout/" - response = requests.post(url,headers=headers,data=json.dumps(data)) + url = "https://api.ua.com/v7.1/workout/" + response = requests.post(url,headers=headers,data=json.dumps(data)) - # check for duplicate error first - if (response.status_code == 409 ): - message = "Duplicate error" + # check for duplicate error first + if (response.status_code == 409 ): + message = "Duplicate error" messages.error(request,message) - w.uploadedtounderarmour = -1 - w.save() - elif (response.status_code == 201 or response.status_code==200): - underarmourid = underarmourstuff.getidfromresponse(response) - w.uploadedtounderarmour = underarmourid - w.save() + w.uploadedtounderarmour = -1 + w.save() + elif (response.status_code == 201 or response.status_code==200): + underarmourid = underarmourstuff.getidfromresponse(response) + w.uploadedtounderarmour = underarmourid + w.save() url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)}) - return HttpResponseRedirect(url) - else: - s = response - message = "Something went wrong in workout_underarmour_upload_view: %s " % s.reason - messages.error(request,message) + return HttpResponseRedirect(url) + else: + s = response + message = "Something went wrong in workout_underarmour_upload_view: %s " % s.reason + messages.error(request,message) else: - message = "You are not authorized to upload this workout" + message = "You are not authorized to upload this workout" messages.error(request,message) url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) + kwargs = { + 'id':encoder.encode_hex(w.id), + }) return HttpResponseRedirect(url) @@ -328,64 +328,64 @@ def workout_sporttracks_upload_view(request,id=0): r = w.user try: - thetoken = sporttracks_open(r.user) + thetoken = sporttracks_open(r.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") + return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") if (checkworkoutuser(request.user,w)): - data = sporttracksstuff.createsporttracksworkoutdata(w) + data = sporttracksstuff.createsporttracksworkoutdata(w) if not data: message = "Data error" messages.error(request,message) url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) + kwargs = { + 'id':encoder.encode_hex(w.id), + }) return HttpResponseRedirect(url) - authorizationstring = str('Bearer ' + thetoken) - headers = {'Authorization': authorizationstring, - 'user-agent': 'sanderroosendaal', - 'Content-Type': 'application/json'} + authorizationstring = str('Bearer ' + thetoken) + headers = {'Authorization': authorizationstring, + 'user-agent': 'sanderroosendaal', + 'Content-Type': 'application/json'} - url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json" - response = requests.post(url,headers=headers,data=json.dumps(data)) + 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" + # check for duplicate error first + if (response.status_code == 409 ): + message = "Duplicate error" messages.error(request,message) - w.uploadedtosporttracks = -1 - w.save() - elif (response.status_code == 201 or response.status_code==200): - s= response.json() - sporttracksid = sporttracksstuff.getidfromresponse(response) - w.uploadedtosporttracks = sporttracksid - w.save() + w.uploadedtosporttracks = -1 + w.save() + elif (response.status_code == 201 or response.status_code==200): + s= response.json() + sporttracksid = sporttracksstuff.getidfromresponse(response) + w.uploadedtosporttracks = sporttracksid + w.save() message = "Upload to SportTracks was successful" messages.info(request,message) url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)}) - return HttpResponseRedirect(url) - else: - s = response - message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason - messages.error(request,message) + return HttpResponseRedirect(url) + else: + s = response + message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason + messages.error(request,message) else: - message = "You are not authorized to upload this workout" + message = "You are not authorized to upload this workout" messages.error(request,message) url = reverse(r.defaultlandingpage, - kwargs = { - 'id':encoder.encode_hex(w.id), - }) + kwargs = { + 'id':encoder.encode_hex(w.id), + }) return HttpResponseRedirect(url) -# Concept2 authorization +# Concept2 authorization @login_required() def rower_c2_authorize(request): # Generate a random string for the state parameter @@ -411,7 +411,7 @@ def rower_strava_authorize(request): params = {"client_id": STRAVA_CLIENT_ID, "response_type": "code", "redirect_uri": STRAVA_REDIRECT_URI, - "scope": "activity:write,activity:read_all"} + "scope": "activity:write,activity:read_all"} url = "https://www.strava.com/oauth/authorize?"+ urllib.urlencode(params) @@ -427,7 +427,7 @@ def rower_polar_authorize(request): "response_type": "code", "redirect_uri": POLAR_REDIRECT_URI, "state": state, -# "scope":"accesslink.read_all" +# "scope":"accesslink.read_all" } url = "https://flow.polar.com/oauth2/authorization?" +urllib.urlencode(params) @@ -445,7 +445,7 @@ def rower_runkeeper_authorize(request): params = {"client_id": RUNKEEPER_CLIENT_ID, "response_type": "code", - "state": state, + "state": state, "redirect_uri": RUNKEEPER_REDIRECT_URI} url = "https://runkeeper.com/apps/authorize?"+ urllib.urlencode(params) @@ -463,7 +463,7 @@ def rower_sporttracks_authorize(request): params = {"client_id": SPORTTRACKS_CLIENT_ID, "response_type": "code", - "state": state, + "state": state, "redirect_uri": SPORTTRACKS_REDIRECT_URI} url = "https://api.sporttracks.mobi/oauth2/authorize?"+ urllib.urlencode(params) @@ -499,7 +499,7 @@ def rower_tp_authorize(request): "response_type": "code", "redirect_uri": TP_REDIRECT_URI, "scope": "file:write", - } + } url = "https://oauth.trainingpeaks.com/oauth/authorize/?" +urllib.urlencode(params) return HttpResponseRedirect(url) @@ -624,16 +624,16 @@ def rower_sporttracks_token_refresh(request): @login_required() def rower_process_callback(request): try: - code = request.GET['code'] - res = c2stuff.get_token(code) + code = request.GET['code'] + res = c2stuff.get_token(code) except MultiValueDictKeyError: - message = "The resource owner or authorization server denied the request" + message = "The resource owner or authorization server denied the request" messages.error(request,message) url = reverse('workouts_view') return HttpResponseRedirect(url) - + access_token = res[0] if access_token == 0: message = res[1] @@ -643,7 +643,7 @@ def rower_process_callback(request): url = reverse('workouts_view') return HttpResponseRedirect(url) - + expires_in = res[1] refresh_token = res[2] @@ -893,24 +893,24 @@ def workout_stravaimport_view(request,message="",userid=0): messages.info(request,"You cannot import other people's workouts from Strava") try: - thetoken = strava_open(request.user) + thetoken = strava_open(request.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/stravaauthorize/") + return HttpResponseRedirect("/rowers/me/stravaauthorize/") res = stravastuff.get_strava_workout_list(request.user) if (res.status_code != 200): - if (res.status_code == 401): - r = getrower(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 (res.status_code == 401): + r = getrower(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" messages.error(request,message) - url = reverse('workouts_view') - return HttpResponseRedirect(url) + url = reverse('workouts_view') + return HttpResponseRedirect(url) else: workouts = [] r = getrower(request.user) @@ -944,7 +944,7 @@ def workout_stravaimport_view(request,message="",userid=0): ]) newids = [stravaid for stravaid in stravaids if not stravaid in knownstravaids] - for item in res.json(): + for item in res.json(): d = int(float(item['distance'])) i = item['id'] if i in knownstravaids: @@ -956,9 +956,9 @@ def workout_stravaimport_view(request,message="",userid=0): s = item['start_date'] r = item['type'] keys = ['id','distance','duration','starttime','type','name','new'] - values = [i,d,ttot,s,r,n,nnn] - res = dict(zip(keys,values)) - workouts.append(res) + values = [i,d,ttot,s,r,n,nnn] + res = dict(zip(keys,values)) + workouts.append(res) breadcrumbs = [ { @@ -974,13 +974,13 @@ def workout_stravaimport_view(request,message="",userid=0): r = getrower(request.user) - return render(request,'strava_list_import.html', - {'workouts':workouts, + return render(request,'strava_list_import.html', + {'workouts':workouts, 'rower':r, 'active':'nav-workouts', 'breadcrumbs':breadcrumbs, 'teams':get_my_teams(request.user), - }) + }) return HttpResponse(res) @@ -989,32 +989,32 @@ def workout_stravaimport_view(request,message="",userid=0): def workout_runkeeperimport_view(request,message="",userid=0): res = runkeeperstuff.get_runkeeper_workout_list(request.user) if (res.status_code != 200): - if (res.status_code == 401): - r = getrower(request.user) - if (r.runkeepertoken == '') or (r.runkeepertoken is None): - s = "Token doesn't exist. Need to authorize" - return HttpResponseRedirect("/rowers/me/runkeeperauthorize/") - message = "Something went wrong in workout_runkeeperimport_view" + if (res.status_code == 401): + r = getrower(request.user) + if (r.runkeepertoken == '') or (r.runkeepertoken is None): + s = "Token doesn't exist. Need to authorize" + return HttpResponseRedirect("/rowers/me/runkeeperauthorize/") + message = "Something went wrong in workout_runkeeperimport_view" messages.error(request,message) - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse('workouts_view') - return HttpResponseRedirect(url) + if settings.DEBUG: + return HttpResponse(res) + else: + url = reverse('workouts_view') + return HttpResponseRedirect(url) workouts = [] for item in res.json()['items']: - d = int(float(item['total_distance'])) - i = getidfromuri(item['uri']) + d = int(float(item['total_distance'])) + i = getidfromuri(item['uri']) ttot = str(datetime.timedelta(seconds=int(float(item['duration'])))) s = item['start_time'] r = item['type'] - keys = ['id','distance','duration','starttime','type'] - values = [i,d,ttot,s,r] + keys = ['id','distance','duration','starttime','type'] + values = [i,d,ttot,s,r] - res = dict(zip(keys,values)) - workouts.append(res) + res = dict(zip(keys,values)) + workouts.append(res) breadcrumbs = [ { @@ -1030,12 +1030,12 @@ def workout_runkeeperimport_view(request,message="",userid=0): r = getrower(request.user) return render(request,'runkeeper_list_import.html', - {'workouts':workouts, + {'workouts':workouts, 'rower':r, 'active':'nav-workouts', 'breadcrumbs':breadcrumbs, 'teams':get_my_teams(request.user), - }) + }) return HttpResponse(res) @@ -1044,14 +1044,14 @@ def workout_runkeeperimport_view(request,message="",userid=0): def workout_underarmourimport_view(request,message="",userid=0): res = underarmourstuff.get_underarmour_workout_list(request.user) if (res.status_code != 200): - return HttpResponseRedirect("/rowers/me/underarmourauthorize/") + return HttpResponseRedirect("/rowers/me/underarmourauthorize/") workouts = [] items = res.json()['_embedded']['workouts'] for item in items: - s = item['start_datetime'] + s = item['start_datetime'] i,r = underarmourstuff.get_idfromuri(request.user,item['_links']) - n = item['name'] + n = item['name'] try: d = item['aggregates']['distance_total'] except KeyError: @@ -1061,11 +1061,11 @@ def workout_underarmourimport_view(request,message="",userid=0): except KeyError: ttot = 0 - keys = ['id','distance','duration','starttime','type'] - values = [i,d,ttot,s,r] - thedict = dict(zip(keys,values)) + keys = ['id','distance','duration','starttime','type'] + values = [i,d,ttot,s,r] + thedict = dict(zip(keys,values)) - workouts.append(thedict) + workouts.append(thedict) rower = getrower(request.user) breadcrumbs = [ @@ -1080,12 +1080,12 @@ def workout_underarmourimport_view(request,message="",userid=0): ] return render(request,'underarmour_list_import.html', - {'workouts':workouts, + {'workouts':workouts, 'breadcrumbs':breadcrumbs, 'rower':rower, 'active':'nav-workouts', 'teams':get_my_teams(request.user), - }) + }) return HttpResponse(res) @@ -1153,20 +1153,20 @@ def workout_sporttracksimport_view(request,message="",userid=0): res = sporttracksstuff.get_sporttracks_workout_list(request.user) if (res.status_code != 200): - if (res.status_code == 401): - r = getrower(request.user) - if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): - s = "Token doesn't exist. Need to authorize" - return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") + if (res.status_code == 401): + r = getrower(request.user) + if (r.sporttrackstoken == '') or (r.sporttrackstoken is None): + s = "Token doesn't exist. Need to authorize" + return HttpResponseRedirect("/rowers/me/sporttracksauthorize/") else: return HttpResponseRedirect("/rowers/me/sporttracksrefresh/") - message = "Something went wrong in workout_sporttracksimport_view" + message = "Something went wrong in workout_sporttracksimport_view" messages.error(request,message) - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse('workouts_view') - return HttpResponseRedirect(url) + if settings.DEBUG: + return HttpResponse(res) + else: + url = reverse('workouts_view') + return HttpResponseRedirect(url) workouts = [] r = getrower(request.user) @@ -1177,19 +1177,19 @@ def workout_sporttracksimport_view(request,message="",userid=0): newids = [stid for stid in stids if not stid in knownstids] for item in res.json()['items']: d = int(float(item['total_distance'])) - i = int(getidfromuri(item['uri'])) + i = int(getidfromuri(item['uri'])) if i in knownstids: nnn = '' else: nnn = 'NEW' - 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','new'] - values = [i,d,ttot,s,r,n,nnn] - res = dict(zip(keys,values)) - workouts.append(res) + 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','new'] + values = [i,d,ttot,s,r,n,nnn] + res = dict(zip(keys,values)) + workouts.append(res) r = getrower(request.user) @@ -1205,55 +1205,55 @@ def workout_sporttracksimport_view(request,message="",userid=0): ] return render(request,'sporttracks_list_import.html', - {'workouts':workouts, + {'workouts':workouts, 'breadcrumbs':breadcrumbs, 'active':'nav-workouts', 'rower':r, 'teams':get_my_teams(request.user), - }) + }) return HttpResponse(res) - + # List of workouts on Concept2 logbook. This view only used for debugging @login_required() def c2listdebug_view(request,page=1,message=""): try: - thetoken = c2_open(request.user) + thetoken = c2_open(request.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") + return HttpResponseRedirect("/rowers/me/c2authorize/") r = getrower(request.user) res = c2stuff.get_c2_workout_list(request.user,page=page) if (res.status_code != 200): - message = "Something went wrong in workout_c2import_view (C2 token renewal)" + message = "Something went wrong in workout_c2import_view (C2 token renewal)" messages.error(request,message) - if settings.DEBUG: - return HttpResponse(res) - else: - url = reverse('workouts_view') - return HttpResponseRedirect(url) + if settings.DEBUG: + return HttpResponse(res) + else: + url = reverse('workouts_view') + return HttpResponseRedirect(url) else: - workouts = [] + 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) + 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, + + return render(request, + 'c2_list_import2.html', + {'workouts':workouts, 'teams':get_my_teams(request.user), }) @@ -1261,14 +1261,14 @@ def c2listdebug_view(request,page=1,message=""): @login_required() def workout_getc2workout_all(request,page=1,message=""): try: - thetoken = c2_open(request.user) + thetoken = c2_open(request.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") + return HttpResponseRedirect("/rowers/me/c2authorize/") res = c2stuff.get_c2_workout_list(request.user,page=page) if (res.status_code != 200): - message = "Something went wrong in workout_c2import_view (C2 token refresh)" + message = "Something went wrong in workout_c2import_view (C2 token refresh)" messages.error(request,message) else: r = getrower(request.user) @@ -1302,17 +1302,17 @@ def workout_c2import_view(request,page=1,userid=0,message=""): r = getrower(request.user) try: - thetoken = c2_open(request.user) + thetoken = c2_open(request.user) except NoTokenError: - return HttpResponseRedirect("/rowers/me/c2authorize/") + return HttpResponseRedirect("/rowers/me/c2authorize/") res = c2stuff.get_c2_workout_list(request.user,page=page) if (res.status_code != 200): - message = "Something went wrong in workout_c2import_view (C2 token refresh)" + message = "Something went wrong in workout_c2import_view (C2 token refresh)" messages.error(request,message) - url = reverse('workouts_view') - return HttpResponseRedirect(url) + url = reverse('workouts_view') + return HttpResponseRedirect(url) workouts = [] c2ids = [item['id'] for item in res.json()['data']] @@ -1321,21 +1321,21 @@ def workout_c2import_view(request,page=1,userid=0,message=""): ]) newids = [c2id for c2id in c2ids if not c2id in knownc2ids] 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'] + d = item['distance'] + i = item['id'] + ttot = item['time_formatted'] + s = item['date'] + r = item['type'] + s2 = item['source'] + c = item['comments'] if i in knownc2ids: nnn = '' else: nnn = 'NEW' - keys = ['id','distance','duration','starttime','rowtype','source','comment','new'] - values = [i,d,ttot,s,r,s2,c,nnn] - res = dict(zip(keys,values)) - workouts.append(res) + keys = ['id','distance','duration','starttime','rowtype','source','comment','new'] + values = [i,d,ttot,s,r,s2,c,nnn] + res = dict(zip(keys,values)) + workouts.append(res) breadcrumbs = [ @@ -1356,8 +1356,8 @@ def workout_c2import_view(request,page=1,userid=0,message=""): r = getrower(request.user) return render(request, - 'c2_list_import2.html', - {'workouts':workouts, + 'c2_list_import2.html', + {'workouts':workouts, 'rower':r, 'active':'nav-workouts', 'breadcrumbs':breadcrumbs, @@ -1449,7 +1449,7 @@ def workout_getimportview(request,externalid,source = 'c2'): 'id':encoder.encode_hex(w.id), }) - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) # strokedata not empty - continue id,message = importsources[source].add_workout_from_data( diff --git a/rowers/views/otherviews.py b/rowers/views/otherviews.py index 1b1764d6..4cd0ef48 100644 --- a/rowers/views/otherviews.py +++ b/rowers/views/otherviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * @login_required() diff --git a/rowers/views/paymentviews.py b/rowers/views/paymentviews.py index 03887525..b820b30d 100644 --- a/rowers/views/paymentviews.py +++ b/rowers/views/paymentviews.py @@ -1,5 +1,5 @@ -from statements import * +from rowers.views.statements import * def paidplans_view(request): if not request.user.is_anonymous(): @@ -478,32 +478,32 @@ def rower_register_view(request): nextpage = '/rowers/list-workouts/' if request.method == 'POST': - #form = RegistrationFormUniqueEmail(request.POST) - form = RegistrationFormSex(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'] + #form = RegistrationFormUniqueEmail(request.POST) + form = RegistrationFormSex(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'] sex = form.cleaned_data['sex'] birthdate = form.cleaned_data['birthdate'] weightcategory = form.cleaned_data['weightcategory'] adaptiveclass = form.cleaned_data['adaptiveclass'] nextpage = request.POST['next'] - theuser = User.objects.create_user(username,password=password) - theuser.first_name = first_name - theuser.last_name = last_name - theuser.email = email - theuser.save() + theuser = User.objects.create_user(username,password=password) + theuser.first_name = first_name + theuser.last_name = last_name + theuser.email = email + theuser.save() birthdate = birthdate.replace(tzinfo=None) - therower = Rower(user=theuser,sex=sex,birthdate=birthdate, + therower = Rower(user=theuser,sex=sex,birthdate=birthdate, weightcategory=weightcategory, adaptiveclass=adaptiveclass) - therower.save() + therower.save() # create default favorite charts add_defaultfavorites(therower) @@ -523,8 +523,8 @@ def rower_register_view(request): w.save() # Create and send email - fullemail = first_name + " " + last_name + " " + "<" + email + ">" - subject = "Thank you for registering on rowsandall.com" + fullemail = first_name + " " + last_name + " " + "<" + email + ">" + subject = "Thank you for registering on rowsandall.com" from_address = 'Sander Roosendaal ' d = {'first_name':theuser.first_name} @@ -533,31 +533,31 @@ def rower_register_view(request): subject,'registeremail.html',d) - subject2 = "New User" - message2 = "New user registered.\n" - message2 += fullemail + "\n" - message2 += "User name: "+username + subject2 = "New User" + message2 = "New user registered.\n" + message2 += fullemail + "\n" + message2 += "User name: "+username - send_mail(subject2, message2, - 'Rowsandall Server ', - ['roosendaalsander@gmail.com']) + send_mail(subject2, message2, + 'Rowsandall Server ', + ['roosendaalsander@gmail.com']) theuser = authenticate(username=username,password=password) login(request,theuser) - return HttpResponseRedirect(nextpage) + return HttpResponseRedirect(nextpage) # '/rowers/register/thankyou/') - else: - return render(request, - "registration_form.html", - {'form':form, + else: + return render(request, + "registration_form.html", + {'form':form, 'next':nextpage,}) else: - form = RegistrationFormSex() - return render(request, - "registration_form.html", - {'form':form, + form = RegistrationFormSex() + return render(request, + "registration_form.html", + {'form':form, 'next':nextpage,}) @login_required() diff --git a/rowers/views/planviews.py b/rowers/views/planviews.py index 83f1678a..ba23042d 100644 --- a/rowers/views/planviews.py +++ b/rowers/views/planviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * @login_required() def plannedsession_comment_view(request,id=0,userid=0): @@ -496,8 +496,6 @@ def plannedsession_multicreate_view(request, for obj in ps_formset.deleted_objects: messages.info(request,"Deleted Planned Session "+str(obj)) obj.delete() - else: - print ps_formset.errors url = reverse(plannedsession_multicreate_view, kwargs = { @@ -716,7 +714,7 @@ def plannedsession_teamcreate_view(request, }) # Manager edits sessions for entire team -@user_passes_test(iscoachmember,login_url="/rowers/paidplans/", +@user_passes_test(hasplannedsessions,login_url="/rowers/paidplans/", message="This functionality requires a Coach or Self-Coach plan", redirect_field_name=None) def plannedsession_teamedit_view(request, diff --git a/rowers/views/racesviews.py b/rowers/views/racesviews.py index 438f9033..c74e6059 100644 --- a/rowers/views/racesviews.py +++ b/rowers/views/racesviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * # List Courses @@ -653,7 +653,7 @@ def virtualevent_disqualify_view(request,raceid=0,recordid=0): latitude = rowdata.df[' latitude'] if not latitude.std(): hascoordinates = 0 - except KeyError, AttributeError: + except (KeyError, AttributeError): hascoordinates = 0 else: hascoordinates = 0 diff --git a/rowers/views/statements.py b/rowers/views/statements.py index e7e2305e..93f4edb8 100644 --- a/rowers/views/statements.py +++ b/rowers/views/statements.py @@ -1,7 +1,7 @@ import time import colorsys -import timestring + import zipfile import bleach import arrow @@ -56,7 +56,11 @@ from rowers.forms import ( MetricsForm,DisqualificationForm,disqualificationreasons, disqualifiers,SearchForm,BillingForm,PlanSelectForm ) -from django.core.urlresolvers import reverse, reverse_lazy + +try: + from django.core.urlresolvers import reverse, reverse_lazy +except ModuleNotFoundError: + from django.urls import reverse, reverse_lazy from django.core.exceptions import PermissionDenied from django.template import RequestContext @@ -181,7 +185,10 @@ from rowers.tasks import ( from scipy.signal import savgol_filter from django.shortcuts import render_to_response -from Cookie import SimpleCookie +try: + from Cookie import SimpleCookie +except ModuleNotFoundError: + from http.cookies import SimpleCookie from shutil import copyfile,move import rowers.mytypes as mytypes from rowingdata import rower as rrower @@ -287,7 +294,7 @@ def getrequestrower(request,rowerid=0,userid=0,notpermanent=False): u = User.objects.get(id=userid) r = getrower(u) else: - r = getrower(request.user) + r = getrower(request.user) except Rower.DoesNotExist: raise Http404("Rower doesn't exist") @@ -320,7 +327,7 @@ def getrequestplanrower(request,rowerid=0,userid=0,notpermanent=False): u = User.objects.get(id=userid) r = getrower(u) else: - r = getrower(request.user) + r = getrower(request.user) except Rower.DoesNotExist: raise Http404("Rower doesn't exist") @@ -367,6 +374,14 @@ def get_workout_permitted(user,id): return w +def get_workout_permittedview(user,id): + w = get_workout(id) + + if (checkworkoutuserview(user,w)==False): + raise PermissionDenied("Access denied") + + return w + def getvalue(data): perc = 0 total = 1 @@ -407,7 +422,7 @@ class SessionTaskListener(threading.Thread): for item in self.pubsub.listen(): if item['data'] == "KILL": self.pubsub.unsubscribe() - print self, "unsubscribed and finished" + print(self, "unsubscribed and finished") break else: self.work(item) @@ -429,14 +444,23 @@ rq_registrylow = StartedJobRegistry(queuelow.name,connection=redis_connection) from rq.job import Job -from rest_framework_swagger.views import get_swagger_view +try: + from rest_framework_swagger.views import get_swagger_view +except ImportError: + pass + 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 +try: + from rest_framework import status,permissions,generics +except ImportError: + pass + from rest_framework.decorators import api_view, renderer_classes + from rowers.permissions import IsOwnerOrNot import rowers.plots as plots @@ -457,7 +481,10 @@ from rowers.interactiveplots import * from rowers.celery import result as celery_result # Define the API documentation -schema_view = get_swagger_view(title='Rowsandall API') +try: + schema_view = get_swagger_view(title='Rowsandall API') +except NameError: + pass def remove_asynctask(request,id): try: @@ -732,9 +759,9 @@ def get_thumbnails(request,id): r = getrower(request.user) result = request.user.is_authenticated() and ispromember(request.user) if result: - promember=1 + promember=1 if request.user == row.user.user: - mayedit=1 + mayedit=1 comments = WorkoutComment.objects.filter(workout=row) @@ -864,7 +891,7 @@ def rowhascoordinates(row): if not latitude.std(): hascoordinates = 0 - except KeyError,AttributeError: + except (KeyError,AttributeError): hascoordinates = 0 else: @@ -877,11 +904,11 @@ def rowhascoordinates(row): # Checks for CSV file, then for gzipped CSV file, and if all fails, returns 0 def rdata(file,rower=rrower()): try: - res = rrdata(csvfile=file,rower=rower) - except IOError, IndexError: + res = rrdata(csvfile=file,rower=rower) + except (IOError, IndexError): try: res = rrdata(csvfile=file+'.gz',rower=rower) - except IOError, IndexError: + except (IOError, IndexError): res = 0 return res @@ -905,24 +932,24 @@ def get_my_teams(user): # Used for the interval editor - translates seconds to a time object def get_time(second): if (second<=0) or (second>1e9): - hours = 0 - minutes=0 - sec=0 - microsecond = 0 + hours = 0 + minutes=0 + sec=0 + microsecond = 0 elif math.isnan(second): - hours = 0 - minutes=0 - sec=0 - microsecond = 0 + 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)) + 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) - + # get the workout ID from the SportTracks URI def getidfromsturi(uri,length=8): return uri[len(uri)-length:] @@ -934,7 +961,7 @@ def getidfromuri(uri): return m.group(2) - + from rowers.utils import ( geo_distance,serialize_list,deserialize_list,uniqify, str2bool,range_to_color_hex,absolute,myqueue,get_call, @@ -944,7 +971,9 @@ from rowers.utils import ( import rowers.datautils as datautils -from rowers.models import checkworkoutuser,checkaccessuser,checkviewworkouts +from rowers.models import ( + checkworkoutuser,checkaccessuser,checkviewworkouts,checkworkoutuserview + ) # Check if a user is a Coach member def iscoachmember(user): @@ -1031,24 +1060,24 @@ 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: + 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: messages.error(request,'You have to answer YES to the question') - return HttpResponseRedirect('/rowers/email/') - else: - return HttpResponseRedirect('/rowers/email/') + return HttpResponseRedirect('/rowers/email/') + else: + return HttpResponseRedirect('/rowers/email/') else: return HttpResponseRedirect('/rowers/email/') @@ -1064,43 +1093,43 @@ def add_workout_from_strokedata(user,importid,data,strokedata, workouttype = 'rower' if workouttype not in [x[0] for x in Workout.workouttypes]: - workouttype = 'other' + workouttype = 'other' try: - comments = data['comments'] + comments = data['comments'] except: - comments = ' ' + comments = ' ' # comments = "Imported data \n %s" % comments # comments = "Imported data \n"+comments # str(comments) try: - thetimezone = tz(data['timezone']) + thetimezone = tz(data['timezone']) except: - thetimezone = 'UTC' + thetimezone = 'UTC' r = getrower(user) try: - rowdatetime = iso8601.parse_date(data['date_utc']) + rowdatetime = iso8601.parse_date(data['date_utc']) except KeyError: - rowdatetime = iso8601.parse_date(data['start_date']) + rowdatetime = iso8601.parse_date(data['start_date']) except ParseError: - rowdatetime = iso8601.parse_date(data['date']) + rowdatetime = iso8601.parse_date(data['date']) - + try: c2intervaltype = data['workout_type'] - + except KeyError: - c2intervaltype = '' - + c2intervaltype = '' + try: - title = data['name'] + title = data['name'] except KeyError: - title = "" - try: - t = data['comments'].split('\n', 1)[0] - title += t[:20] - except: - title = 'Imported' + title = "" + try: + t = data['comments'].split('\n', 1)[0] + title += t[:20] + except: + title = 'Imported' starttimeunix = arrow.get(rowdatetime).timestamp @@ -1115,17 +1144,17 @@ def add_workout_from_strokedata(user,importid,data,strokedata, nr_rows = len(unixtime) try: - latcoord = strokedata.loc[:,'lat'] - loncoord = strokedata.loc[:,'lon'] + latcoord = strokedata.loc[:,'lat'] + loncoord = strokedata.loc[:,'lon'] except: - latcoord = np.zeros(nr_rows) - loncoord = np.zeros(nr_rows) + latcoord = np.zeros(nr_rows) + loncoord = np.zeros(nr_rows) try: - strokelength = strokedata.loc[:,'strokelength'] + strokelength = strokedata.loc[:,'strokelength'] except: - strokelength = np.zeros(nr_rows) + strokelength = np.zeros(nr_rows) dist2 = 0.1*strokedata.loc[:,'d'] @@ -1149,27 +1178,27 @@ def add_workout_from_strokedata(user,importid,data,strokedata, # 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 - }) + ' 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 + }) df.sort_values(by='TimeStamp (sec)',ascending=True) - + timestr = strftime("%Y%m%d-%H%M%S") diff --git a/rowers/views/teamviews.py b/rowers/views/teamviews.py index 0fff0eb4..f8a8429e 100644 --- a/rowers/views/teamviews.py +++ b/rowers/views/teamviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * @login_required() @@ -205,7 +205,7 @@ def rower_teams_view(request,message='',successmessage=''): potentialcoaches = [c for c in potentialcoaches if teams.get_coach_club_size(c.rower)', - ['roosendaalsander@gmail.com']) + 'Rowsandall Server ', + ['roosendaalsander@gmail.com']) return HttpResponseRedirect(url) @@ -50,8 +50,8 @@ def start_plantrial_view(request): message2 += "User name: "+request.user.username send_mail(subject2, message2, - 'Rowsandall Server ', - ['roosendaalsander@gmail.com']) + 'Rowsandall Server ', + ['roosendaalsander@gmail.com']) return HttpResponseRedirect(url) @@ -151,7 +151,7 @@ def rower_exportsettings_view(request,userid=0): ] return render(request, 'rower_exportsettings.html', - {'form':form, + {'form':form, 'rower':r, 'breadcrumbs': breadcrumbs, }) @@ -242,14 +242,14 @@ def rower_edit_view(request,rowerid=0,userid=0,message=""): grants = AccessToken.objects.filter(user=request.user) return render(request, 'rower_form.html', - { + { 'teams':get_my_teams(request.user), 'breadcrumbs':breadcrumbs, 'grants':grants, 'userform':userform, 'accountform':accountform, 'rower':r, - }) + }) # Page where user can set his details @@ -276,43 +276,43 @@ def rower_prefs_view(request,userid=0,message=""): powerzonesform = RowerPowerZonesForm(instance=r) if request.method == 'POST' and "ut2" in request.POST: - form = RowerForm(request.POST) - if form.is_valid(): - # something - cd = form.cleaned_data - hrmax = cd['max'] - ut2 = cd['ut2'] - ut1 = cd['ut1'] - at = cd['at'] - tr = cd['tr'] - an = cd['an'] - rest = cd['rest'] + form = RowerForm(request.POST) + if form.is_valid(): + # something + cd = form.cleaned_data + hrmax = cd['max'] + ut2 = cd['ut2'] + ut1 = cd['ut1'] + at = cd['at'] + tr = cd['tr'] + an = cd['an'] + rest = cd['rest'] - r.max = max(min(hrmax,250),10) - r.ut2 = max(min(ut2,250),10) - r.ut1 = max(min(ut1,250),10) - r.at = max(min(at,250),10) - r.tr = max(min(tr,250),10) - r.an = max(min(an,250),10) - r.rest = max(min(rest,250),10) - r.save() + r.max = max(min(hrmax,250),10) + r.ut2 = max(min(ut2,250),10) + r.ut1 = max(min(ut1,250),10) + r.at = max(min(at,250),10) + r.tr = max(min(tr,250),10) + r.an = max(min(an,250),10) + r.rest = max(min(rest,250),10) + r.save() successmessage = "Your Heart Rate data were changed" messages.info(request,successmessage) elif request.method == 'POST' and "ftp" in request.POST: - powerform = RowerPowerForm(request.POST) - if powerform.is_valid(): - cd = powerform.cleaned_data + powerform = RowerPowerForm(request.POST) + if powerform.is_valid(): + cd = powerform.cleaned_data hrftp = cd['hrftp'] if hrftp == 0: hrftp = int((r.an+r.tr)/2.) - ftp = cd['ftp'] + ftp = cd['ftp'] otwslack = cd['otwslack'] powerfrac = 100*np.array([r.pw_ut2, r.pw_ut1, r.pw_at, r.pw_tr,r.pw_an])/r.ftp - r.ftp = max(min(ftp,650),50) + r.ftp = max(min(ftp,650),50) r.otwslack = max(min(otwslack,50),0) ut2,ut1,at,tr,an = (r.ftp*powerfrac/100.).astype(int) r.pw_ut2 = ut2 @@ -321,14 +321,14 @@ def rower_prefs_view(request,userid=0,message=""): r.pw_tr = tr r.pw_an = an r.hrftp = hrftp - r.save() - message = "FTP and/or OTW slack values changed." + r.save() + message = "FTP and/or OTW slack values changed." messages.info(request,message) elif request.method == 'POST' and "ut3name" in request.POST: - powerzonesform = RowerPowerZonesForm(request.POST) - if powerzonesform.is_valid(): - cd = powerzonesform.cleaned_data + powerzonesform = RowerPowerZonesForm(request.POST) + if powerzonesform.is_valid(): + cd = powerzonesform.cleaned_data pw_ut2 = cd['pw_ut2'] pw_ut1 = cd['pw_ut1'] pw_at = cd['pw_at'] @@ -353,14 +353,14 @@ def rower_prefs_view(request,userid=0,message=""): messages.info(request,successmessage) return render(request, 'rower_preferences.html', - { - 'form':form, + { + 'form':form, 'teams':get_my_teams(request.user), - 'powerform':powerform, + 'powerform':powerform, 'powerzonesform':powerzonesform, 'breadcrumbs':breadcrumbs, 'rower':r, - }) + }) # Revoke an app that you granted access through the API. diff --git a/rowers/views/workoutviews.py b/rowers/views/workoutviews.py index b49af87d..120683d9 100644 --- a/rowers/views/workoutviews.py +++ b/rowers/views/workoutviews.py @@ -1,4 +1,4 @@ -from statements import * +from rowers.views.statements import * import rowers.teams as teams # Show the EMpower Oarlock generated Stroke Profile @@ -11,22 +11,22 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False): promember=0 mayedit=0 if not request.user.is_anonymous(): - r = getrower(request.user) - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 - if request.user == row.user.user: - mayedit=1 + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 + if request.user == row.user.user: + mayedit=1 if not promember: - return HttpResponseRedirect("/rowers/about/") + 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 + if workstrokesonly == 'True': + workstrokesonly = True + else: + workstrokesonly = False script,div,js_resources,css_resources = interactive_forcecurve([row], workstrokesonly=workstrokesonly) @@ -58,8 +58,8 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False): 'breadcrumbs':breadcrumbs, 'active':'nav-workouts', 'the_div':div, - 'js_res': js_resources, - 'css_res':css_resources, + 'js_res': js_resources, + 'css_res':css_resources, 'id':id, 'mayedit':mayedit, 'workstrokesonly': not workstrokesonly, @@ -87,15 +87,15 @@ def workout_histo_view(request,id=0): promember=0 mayedit=0 if not request.user.is_anonymous(): - r = getrower(request.user) - result = request.user.is_authenticated() and ispromember(request.user) - if result: - promember=1 - if request.user == w.user.user: - mayedit=1 + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: + promember=1 + if request.user == w.user.user: + mayedit=1 if not promember: - return HttpResponseRedirect("/rowers/about/") + return HttpResponseRedirect("/rowers/about/") res = interactive_histoall([w]) script = res[0] @@ -120,16 +120,16 @@ def workout_histo_view(request,id=0): return render(request, 'histo_single.html', - {'interactiveplot':script, + {'interactiveplot':script, 'breadcrumbs':breadcrumbs, 'active':'nav-workouts', 'workout':w, 'rower':r, - 'the_div':div, + 'the_div':div, 'id':id, 'mayedit':mayedit, 'teams':get_my_teams(request.user), - }) + }) @@ -156,17 +156,17 @@ def addmanual_view(request): metricsform = MetricsForm(request.POST) if form.is_valid() and metricsform.is_valid(): # Get values from form - name = form.cleaned_data['name'] + name = form.cleaned_data['name'] if name == '': name = 'Manual Entry' - date = form.cleaned_data['date'] - starttime = form.cleaned_data['starttime'] - workouttype = form.cleaned_data['workouttype'] - duration = form.cleaned_data['duration'] + date = form.cleaned_data['date'] + starttime = form.cleaned_data['starttime'] + workouttype = form.cleaned_data['workouttype'] + duration = form.cleaned_data['duration'] weightcategory = form.cleaned_data['weightcategory'] adaptiveclass = form.cleaned_data['adaptiveclass'] - distance = form.cleaned_data['distance'] - notes = form.cleaned_data['notes'] + distance = form.cleaned_data['distance'] + notes = form.cleaned_data['notes'] thetimezone = form.cleaned_data['timezone'] private = form.cleaned_data['private'] avghr = metricsform.cleaned_data['avghr'] @@ -200,10 +200,10 @@ def addmanual_view(request): else: privacy = 'visible' - startdatetime = (str(date) + ' ' + str(starttime)) - startdatetime = datetime.datetime.strptime(startdatetime, - "%Y-%m-%d %H:%M:%S") - startdatetime = timezone.make_aware(startdatetime) + startdatetime = (str(date) + ' ' + str(starttime)) + startdatetime = datetime.datetime.strptime(startdatetime, + "%Y-%m-%d %H:%M:%S") + startdatetime = timezone.make_aware(startdatetime) startdatetime = startdatetime.astimezone( pytz.timezone(thetimezone) ) @@ -329,11 +329,11 @@ def workout_update_cp_view(request,id=0): row = get_workout(id) if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" + message = "You are not allowed to edit this workout" messages.error(request,message) - url = reverse('workouts_view') + url = reverse('workouts_view') - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) row.rankingpiece = True row.save() @@ -356,11 +356,11 @@ def workout_recalcsummary_view(request,id=0): row = get_workout(id) if (checkworkoutuser(request.user,row)==False): - message = "You are not allowed to edit this workout" + message = "You are not allowed to edit this workout" messages.error(request,message) - url = reverse('workouts_view') + url = reverse('workouts_view') - return HttpResponseRedirect(url) + return HttpResponseRedirect(url) filename = row.csvfilename rowdata = rdata(filename) @@ -370,9 +370,9 @@ def workout_recalcsummary_view(request,id=0): successmessage = "Summary Updated" messages.info(request,successmessage) url = reverse('workout_edit_view', - kwargs = { - 'id':id, - }) + kwargs = { + 'id':id, + }) else: message = "Something went wrong. Could not update summary" messages.error(request,message) @@ -391,9 +391,9 @@ def workout_recalcsummary_view(request,id=0): def workouts_join_view(request): promember=0 if not request.user.is_anonymous(): - r = getrower(request.user) - result = request.user.is_authenticated() and ispromember(request.user) - if result: + r = getrower(request.user) + result = request.user.is_authenticated() and ispromember(request.user) + if result: promember=1 @@ -444,7 +444,7 @@ def workouts_join_select(request, teamid=0): try: - r = getrower(request.user) + r = getrower(request.user) except Rower.DoesNotExist: raise Http404("Rower doesn't exist") @@ -590,7 +590,9 @@ def workouts_join_select(request, }) # Team comparison -@login_required() +@user_passes_test(ispromember,login_url='/rowers/paidplans/', + message="This functionality requires a Pro plan or higher", + redirect_field_name=None) def team_comparison_select(request, startdatestring="", enddatestring="", @@ -695,11 +697,6 @@ def team_comparison_select(request, except Team.DoesNotExist: theteam = 0 - if requestrower.rowerplan == 'basic' and theteam==0: - if requestrower.protrialexpires is None or requestrower.protrialexpires[0-9A-Za-z_\-]+)/(?P.+)/$', auth_views.password_reset_confirm, +# auth_views.PasswordResetConfirmView, name='password_reset_confirm'), - url(r'^reset/done/$', auth_views.password_reset_complete, + url(r'^reset/done/$', + auth_views.password_reset_complete, +# auth_views.PasswordResetCompleteView, name='password_reset_complete'), ] @@ -55,11 +62,16 @@ urlpatterns += [ url(r'^robots\.txt$', TemplateView.as_view(template_name='robots.txt', content_type='text/plain')), url(r'^admin/', admin.site.urls), - url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), + url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework2')), url(r'^$',rootview), url(r'^getblogs/$',rowersviews.get_blog_posts), - url(r'^login/',auth_views.login, name='login'), - url(r'^logout/$',auth_views.logout, + url(r'^login/', + auth_views.login, +# auth_views.LoginView, + name='login'), + url(r'^logout/$', + auth_views.logout, +# auth_views.LogoutView, {'next_page': '/'}, name='logout',), url(r'^rowers/',include('rowers.urls')), @@ -75,7 +87,7 @@ urlpatterns += [ url(r'^twitter\_callback',rowersviews.rower_process_twittercallback), url(r'^i18n/', include('django.conf.urls.i18n')), url(r'^tz_detect/', include('tz_detect.urls')), - url(r'^jsi18n/', 'django.views.i18n.javascript_catalog',name='jsi18n'), +# url(r'^jsi18n/', 'django.views.i18n.javascript_catalog',name='jsi18n'), ] @@ -83,7 +95,7 @@ if settings.DEBUG: import debug_toolbar import django urlpatterns += [ - url(r'^__debug__/',include(debug_toolbar.urls)), +# url(r'^__debug__/','debug_toolbar.urls'), url(r'^static/(?P.*)$', django.views.static.serve, kwargs={'document_root': settings.STATIC_ROOT,}