moved user and workout permission checks to rules
updated workoutviews, rest of views not done doesn't pass tests
This commit is contained in:
@@ -14,6 +14,7 @@ import datetime
|
||||
from requests import Request, Session
|
||||
import rowers.mytypes as mytypes
|
||||
from rowers.mytypes import otwtypes
|
||||
from rowers.rower_rules import is_workout_user
|
||||
from iso8601 import ParseError
|
||||
|
||||
import numpy
|
||||
@@ -863,7 +864,7 @@ def workout_c2_upload(user,w):
|
||||
r = Rower.objects.get(user=user)
|
||||
|
||||
# ready to upload. Hurray
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (is_workout_user(user,w)):
|
||||
c2userid = get_userid(r.c2token)
|
||||
if not c2userid:
|
||||
raise NoTokenError("User has no token")
|
||||
|
||||
@@ -43,7 +43,7 @@ from django.contrib.auth.decorators import login_required
|
||||
# from .models import Profile
|
||||
from rowingdata import rowingdata, make_cumvalues
|
||||
import pandas as pd
|
||||
from rowers.models import Rower,Workout,checkworkoutuser,TombStone
|
||||
from rowers.models import Rower,Workout,TombStone
|
||||
import rowers.mytypes as mytypes
|
||||
from rowsandall_app.settings import (
|
||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||
@@ -54,7 +54,7 @@ from rowsandall_app.settings import (
|
||||
|
||||
from rowers.utils import (
|
||||
NoTokenError, custom_exception_handler, ewmovingaverage,
|
||||
geo_distance,isprorower,uniqify
|
||||
geo_distance,uniqify
|
||||
)
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
else:
|
||||
grant_type = post_data.pop('grant_type',None)
|
||||
|
||||
if oauth_data['bearer_auth']:
|
||||
if oauth_data['bearer_auth']:
|
||||
headers['authorization'] = 'Bearer %s' % access_token
|
||||
|
||||
baseurl = oauth_data['base_url']
|
||||
@@ -159,7 +159,7 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
headers=headers)
|
||||
|
||||
|
||||
|
||||
|
||||
if response.status_code == 200 or response.status_code == 201:
|
||||
token_json = response.json()
|
||||
else:
|
||||
@@ -186,7 +186,7 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
expires_in = int(expires_in)
|
||||
except (TypeError,ValueError):
|
||||
expires_in = 0
|
||||
|
||||
|
||||
|
||||
return [thetoken,expires_in,refresh_token]
|
||||
|
||||
@@ -199,20 +199,20 @@ def imports_get_token(
|
||||
client_secret = oauth_data['client_secret']
|
||||
client_id = oauth_data['client_id']
|
||||
base_uri = oauth_data['base_url']
|
||||
|
||||
|
||||
|
||||
client_auth = requests.auth.HTTPBasicAuth(
|
||||
client_id,client_secret
|
||||
)
|
||||
|
||||
|
||||
|
||||
post_data = {"grant_type": "authorization_code",
|
||||
"code": code,
|
||||
"redirect_uri": redirect_uri,
|
||||
"client_secret": client_secret,
|
||||
"client_id": client_id,
|
||||
}
|
||||
|
||||
|
||||
try:
|
||||
headers = oauth_data['headers']
|
||||
except KeyError:
|
||||
@@ -229,7 +229,7 @@ def imports_get_token(
|
||||
else:
|
||||
grant_type = post_data.pop('grant_type',None)
|
||||
|
||||
|
||||
|
||||
if 'json' in oauth_data['content_type']:
|
||||
response = requests.post(
|
||||
base_uri,
|
||||
@@ -262,7 +262,7 @@ def imports_get_token(
|
||||
else:
|
||||
return [0,0,0]
|
||||
|
||||
|
||||
|
||||
return [thetoken,expires_in,refresh_token]
|
||||
|
||||
# Make authorization URL including random string
|
||||
@@ -293,8 +293,8 @@ def imports_token_refresh(user,tokenname,refreshtokenname,expirydatename,oauth_d
|
||||
# for Strava transition
|
||||
if not refreshtoken:
|
||||
refreshtoken = getattr(r,tokenname)
|
||||
|
||||
|
||||
|
||||
|
||||
res = imports_do_refresh_token(refreshtoken,oauth_data)
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
@@ -309,4 +309,3 @@ def imports_token_refresh(user,tokenname,refreshtokenname,expirydatename,oauth_d
|
||||
|
||||
r.save()
|
||||
return access_token
|
||||
|
||||
|
||||
@@ -666,6 +666,9 @@ class CoachingGroup(models.Model):
|
||||
rs = Rower.objects.filter(coachinggroups__in=[self])
|
||||
return rs.count()
|
||||
|
||||
def get_coaches(self):
|
||||
return Rower.objects.filter(mycoachgroup=self)
|
||||
|
||||
# Extension of User with rowing specific data
|
||||
@python_2_unicode_compatible
|
||||
class Rower(models.Model):
|
||||
@@ -1173,95 +1176,7 @@ class BasePlannedSessionFormSet(BaseFormSet):
|
||||
return
|
||||
|
||||
|
||||
# Check if workout is owned by this user
|
||||
def checkworkoutuser(user,workout):
|
||||
if user.is_anonymous:
|
||||
return False
|
||||
try:
|
||||
r = Rower.objects.get(user=user)
|
||||
if workout.user == r:
|
||||
return True
|
||||
coaches = []
|
||||
for group in workout.user.coachinggroups.all():
|
||||
coach = Rower.objects.get(mycoachgroup=group)
|
||||
coaches.append(coach)
|
||||
for coach in coaches:
|
||||
if user.rower == coach and workout.privacy == 'visible':
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Rower.DoesNotExist:
|
||||
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:
|
||||
r = user.rower
|
||||
if rower == r:
|
||||
return True
|
||||
teams = Team.objects.filter(manager=user)
|
||||
|
||||
if rower in Rower.objects.filter(team__in=teams):
|
||||
return True
|
||||
|
||||
if rower in Rower.objects.filter(coachinggroups__in=[user.rower.mycoachgroup]):
|
||||
return True
|
||||
|
||||
|
||||
except Rower.DoesNotExist:
|
||||
return False
|
||||
|
||||
# check if user is plan and rower is in his group
|
||||
def checkaccessplanuser(user,rower):
|
||||
try:
|
||||
r = Rower.objects.get(user=user)
|
||||
if rower == r:
|
||||
return True
|
||||
team_managers = [t.manager for t in rower.team.all() if t.manager.rower.rowerplan in ['plan','coach','freecoach']]
|
||||
if user.rower.rowerplan != 'basic':
|
||||
return user in team_managers
|
||||
else:
|
||||
return False
|
||||
|
||||
return False
|
||||
except Rower.DoesNotExist:
|
||||
return False
|
||||
|
||||
# Check if user is coach or rower
|
||||
def checkaccessuser(user,rower):
|
||||
try:
|
||||
r = Rower.objects.get(user=user)
|
||||
if rower == r:
|
||||
return True
|
||||
coaches = []
|
||||
for group in rower.coachinggroups.all():
|
||||
coach = Rower.objects.get(mycoachgroup=group)
|
||||
coaches.append(coach)
|
||||
for coach in coaches:
|
||||
if user.rower == coach:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
except Rower.DoesNotExist:
|
||||
return False
|
||||
|
||||
timezones = (
|
||||
(x,x) for x in pytz.common_timezones
|
||||
|
||||
@@ -38,7 +38,7 @@ from django.contrib.auth.decorators import login_required
|
||||
from rowingdata import rowingdata
|
||||
import pandas as pd
|
||||
from rowers.models import Rower,Workout
|
||||
from rowers.models import checkworkoutuser
|
||||
|
||||
import rowers.dataprep as dataprep
|
||||
from rowers.dataprep import columndict
|
||||
|
||||
@@ -50,7 +50,7 @@ from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
|
||||
from django_mailbox.models import Message,Mailbox,MessageAttachment
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET,
|
||||
POLAR_CLIENT_ID, POLAR_REDIRECT_URI, POLAR_CLIENT_SECRET,
|
||||
)
|
||||
|
||||
#baseurl = 'https://polaraccesslink.com/v3-example'
|
||||
@@ -79,7 +79,7 @@ def get_token(code):
|
||||
except TypeError:
|
||||
headers = { 'Authorization': 'Basic %s' % base64.b64encode(
|
||||
bytes(auth_string,'utf-8')).decode('utf-8') }
|
||||
|
||||
|
||||
response = requests.post("https://polarremote.com/v2/oauth2/token",
|
||||
data=post_data,
|
||||
headers=headers)
|
||||
@@ -110,7 +110,7 @@ def make_authorization_url():
|
||||
import urllib
|
||||
url = "https://flow.polar.com/oauth2/authorization" +urllib.parse.urlencode(params)
|
||||
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
def get_polar_notifications():
|
||||
@@ -130,13 +130,13 @@ def get_polar_notifications():
|
||||
response = requests.get(url, headers=headers)
|
||||
|
||||
available_data = []
|
||||
|
||||
|
||||
if response.status_code == 200:
|
||||
available_data = response.json()['available-user-data']
|
||||
|
||||
|
||||
return available_data
|
||||
|
||||
from rowers.utils import isprorower
|
||||
from rowers.rower_rules import ispromember
|
||||
|
||||
def get_all_new_workouts(available_data,testing=False):
|
||||
for record in available_data:
|
||||
@@ -146,7 +146,7 @@ def get_all_new_workouts(available_data,testing=False):
|
||||
try:
|
||||
r = Rower.objects.get(polaruserid=record['user-id'])
|
||||
u = r.user
|
||||
if r.polar_auto_import and isprorower(r):
|
||||
if r.polar_auto_import and ispromember(u):
|
||||
exercise_list = get_polar_workouts(u)
|
||||
if testing:
|
||||
print(exercise_list)
|
||||
@@ -154,13 +154,13 @@ def get_all_new_workouts(available_data,testing=False):
|
||||
pass
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
|
||||
def get_polar_workouts(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
|
||||
exercise_list = []
|
||||
|
||||
|
||||
if (r.polartoken == '') or (r.polartoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
@@ -195,7 +195,7 @@ def get_polar_workouts(user):
|
||||
uploadoptions,
|
||||
default_flow_style=False
|
||||
)
|
||||
|
||||
|
||||
transactionid = response.json()['transaction-id']
|
||||
url = baseurl+'/users/{userid}/exercise-transactions/{transactionid}'.format(
|
||||
transactionid = transactionid,
|
||||
@@ -229,11 +229,11 @@ def get_polar_workouts(user):
|
||||
|
||||
a = MessageAttachment(message=msg,document=filename[6:])
|
||||
a.save()
|
||||
|
||||
|
||||
exercise_dict['filename'] = filename
|
||||
else:
|
||||
exercise_dict['filename'] = ''
|
||||
|
||||
|
||||
exercise_list.append(exercise_dict)
|
||||
|
||||
# commit transaction
|
||||
@@ -280,7 +280,7 @@ def get_polar_user_info(user,physical=False):
|
||||
|
||||
|
||||
def get_polar_workout(user,id,transactionid):
|
||||
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
if (r.polartoken == '') or (r.polartoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
@@ -326,7 +326,7 @@ def get_polar_workout(user,id,transactionid):
|
||||
)
|
||||
|
||||
response = requests.get(url,headers = headers2)
|
||||
|
||||
|
||||
if response.status_code == 200:
|
||||
result = response.text
|
||||
# commit transaction
|
||||
@@ -337,7 +337,3 @@ def get_polar_workout(user,id,transactionid):
|
||||
return result
|
||||
|
||||
return None
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,154 @@ def user_is_not_basic(user):
|
||||
def is_coach(user):
|
||||
return user.rower.rowerplan in ['coach','freecoach']
|
||||
|
||||
@rules.predicate
|
||||
def is_promember(user):
|
||||
try:
|
||||
r = user.rower
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
return r.rowerplan in ['pro','coach','plan']
|
||||
|
||||
@rules.predicate
|
||||
def is_protrial(user):
|
||||
try:
|
||||
r = user.rower
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
if r.rowerplan == 'basic':
|
||||
return r.protrialexpires >= datetime.date.today()
|
||||
if r.rowerplan == 'freecoach':
|
||||
if r.mycoachgroup is not None:
|
||||
return len(r.mycoachgroup)>=4
|
||||
|
||||
return False
|
||||
|
||||
ispromember = is_promember | is_protrial
|
||||
|
||||
# User / Coach relationships (Rower object)
|
||||
|
||||
@rules.predicate
|
||||
def can_plan(user):
|
||||
return user.rower.rowerplan in ['plan','coach','freecoach']
|
||||
|
||||
@rules.predicate
|
||||
def is_coach_user(user,rower):
|
||||
try:
|
||||
r = user.rower
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
if rower == r:
|
||||
return True
|
||||
|
||||
coaches = []
|
||||
|
||||
for group in r.coachinggroups.all():
|
||||
newcoaches = group.get_coaches()
|
||||
for coach in newcoaches:
|
||||
coaches.append(coach)
|
||||
print(coaches)
|
||||
for coach in coaches:
|
||||
if rower == coach:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@rules.predicate
|
||||
def is_rower_team_member(user,rower):
|
||||
if user.rower == rower:
|
||||
return True
|
||||
|
||||
teams = user.rower.team.all()
|
||||
|
||||
for team in teams:
|
||||
if team.private == 'open':
|
||||
if team in rower.team.all():
|
||||
return True
|
||||
if team.manager == rower.user:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@rules.predicate
|
||||
def can_plan_user(user,rower):
|
||||
try:
|
||||
r = user.rower
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
if rower == r:
|
||||
return True
|
||||
|
||||
# below
|
||||
team_managers = [t.manager for t in rower.team.all() and can_plan(t.manager)]
|
||||
if user_is_not_basic(user):
|
||||
return user in team_managers
|
||||
|
||||
return False
|
||||
|
||||
rules.add_perm('rower.can_plan',can_plan_user) # replaces checkaccessplanuser
|
||||
rules.add_perm('rower.is_coach',is_coach_user) # replaces checkaccessuser
|
||||
|
||||
|
||||
# WORKOUT permissions
|
||||
|
||||
@rules.predicate
|
||||
def is_workout_user(user,workout):
|
||||
if user.is_anonymous:
|
||||
return False
|
||||
|
||||
try:
|
||||
r = user.rower
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
if workout.user == r:
|
||||
return True
|
||||
|
||||
coaches = []
|
||||
for group in workout.user.coachinggroups.all():
|
||||
coach = group.coachingrole
|
||||
coaches.append(coach)
|
||||
for coach in coaches:
|
||||
if r == coach and workout.privacy == 'visible':
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@rules.predicate
|
||||
def can_view_workout(user,workout):
|
||||
if user.is_anonymous:
|
||||
if workout.privacy != 'private':
|
||||
return True
|
||||
return False
|
||||
|
||||
try:
|
||||
r = user.rower
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
teams = workout.user.team.all()
|
||||
|
||||
for team in teams:
|
||||
if team in r.team.all():
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
rules.add_perm('workout.change_workout',is_workout_user) # replaces checkworkoutuser
|
||||
rules.add_perm('workout.view_workout',can_view_workout) # replaces checkworkoutuserview
|
||||
|
||||
|
||||
|
||||
# checkviewworkouts
|
||||
|
||||
# PLANNING permissions
|
||||
|
||||
# checkaccessplanuser (models.py)
|
||||
|
||||
# TEAM permissions
|
||||
|
||||
@rules.predicate
|
||||
|
||||
@@ -7,6 +7,8 @@ from __future__ import unicode_literals, absolute_import
|
||||
from rowers.imports import *
|
||||
import re
|
||||
|
||||
from rowers.rower_rules import is_workout_user
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SECRET,
|
||||
STRAVA_CLIENT_ID, STRAVA_REDIRECT_URI, STRAVA_CLIENT_SECRET,
|
||||
@@ -285,7 +287,7 @@ def workout_runkeeper_upload(user,w):
|
||||
|
||||
# ready to upload. Hurray
|
||||
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (is_workout_user(user,w)):
|
||||
data = createrunkeeperworkoutdata(w)
|
||||
if not data:
|
||||
message = "Data error in Runkeeper Upload"
|
||||
|
||||
@@ -18,6 +18,7 @@ from rowsandall_app.settings import (
|
||||
)
|
||||
|
||||
import rowers.mytypes as mytypes
|
||||
from rowers.rower_rules import is_workout_user
|
||||
|
||||
oauth_data = {
|
||||
'client_id': SPORTTRACKS_CLIENT_ID,
|
||||
@@ -265,7 +266,7 @@ def workout_sporttracks_upload(user,w):
|
||||
|
||||
thetoken = sporttracks_open(user)
|
||||
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (is_workout_user(user,w)):
|
||||
data = createsporttracksworkoutdata(w)
|
||||
if not data:
|
||||
message = "Data error"
|
||||
|
||||
@@ -18,6 +18,8 @@ queuehigh = django_rq.get_queue('low')
|
||||
|
||||
from rowers.dataprep import columndict
|
||||
|
||||
from rowers.rower_rules import is_workout_user
|
||||
|
||||
import stravalib
|
||||
from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
|
||||
|
||||
@@ -632,7 +634,7 @@ def workout_strava_upload(user,w):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
raise NoTokenError("Your hovercraft is full of eels")
|
||||
else:
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (is_workout_user(user,w)):
|
||||
try:
|
||||
tcxfile,tcxmesg = createstravaworkoutdata(w)
|
||||
if tcxfile:
|
||||
|
||||
@@ -21,7 +21,7 @@ from rowers.plannedsessions import (
|
||||
from rowers import c2stuff, runkeeperstuff
|
||||
from rowers.c2stuff import c2_open
|
||||
from rowers.runkeeperstuff import runkeeper_open
|
||||
from rowers.models import checkaccessuser
|
||||
from rowers.rower_rules import is_coach_user, is_workout_user
|
||||
from rowers.mytypes import otwtypes
|
||||
from rowers.utils import NoTokenError
|
||||
|
||||
@@ -385,14 +385,13 @@ def is_session_manager(id,user):
|
||||
|
||||
return ps.manager == user
|
||||
|
||||
from rowers.models import checkworkoutuser
|
||||
|
||||
@register.filter
|
||||
def may_edit(workout,request):
|
||||
mayedit = 0
|
||||
if request.user == workout.user.user:
|
||||
mayedit = True
|
||||
if checkworkoutuser(request.user,workout):
|
||||
if is_workout_user(request.user,workout):
|
||||
mayedit = True
|
||||
|
||||
return mayedit
|
||||
@@ -413,7 +412,7 @@ def mayeditplan(obj,request):
|
||||
return request.user == obj.manager.user
|
||||
|
||||
rr = Rower.objects.get(user=request.user)
|
||||
if checkaccessuser(request.user,obj.rower) and rr.rowerplan not in ['basic','pro']:
|
||||
if is_coach_user(request.user,obj.rower) and rr.rowerplan not in ['basic','pro']:
|
||||
mayedit = True
|
||||
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ from django.test import TestCase, Client,override_settings
|
||||
from django.core.management import call_command
|
||||
from django.utils.six import StringIO
|
||||
from django.test.client import RequestFactory
|
||||
from rowers.views import checkworkoutuser,c2_open
|
||||
from rowers.views import c2_open
|
||||
from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage
|
||||
from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail
|
||||
import rowers.plots as plots
|
||||
|
||||
@@ -7,12 +7,12 @@ try:
|
||||
FileNotFoundError
|
||||
except NameError:
|
||||
FileNotFoundError = None
|
||||
|
||||
|
||||
try:
|
||||
OSError
|
||||
except NameError:
|
||||
OSError = None
|
||||
|
||||
|
||||
import pytest
|
||||
|
||||
pytestmark = pytest.mark.django_db
|
||||
@@ -26,7 +26,7 @@ from django.core.management import call_command
|
||||
from django.core.files.uploadedfile import SimpleUploadedFile
|
||||
from django.utils.six import StringIO
|
||||
from django.test.client import RequestFactory
|
||||
from rowers.views import checkworkoutuser,c2_open, multi_compare_view
|
||||
from rowers.views import c2_open, multi_compare_view
|
||||
|
||||
from rowers.forms import (
|
||||
DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail,
|
||||
@@ -101,22 +101,22 @@ def get_random_file(filename='rowers/tests/testdata/testdata.csv',name=''):
|
||||
fromstring = 'test_%s_' % mod.__name__
|
||||
except AttributeError:
|
||||
fromstring = 'none_'
|
||||
|
||||
|
||||
row = rdata(filename)
|
||||
totaldist = row.df['cum_dist'].max()
|
||||
totaltime = row.df['TimeStamp (sec)'].max()-row.df['TimeStamp (sec)'].min()
|
||||
totaltime = totaltime+row.df.loc[row.df.index[0],' ElapsedTime (sec)']
|
||||
|
||||
|
||||
|
||||
|
||||
hours = int(totaltime/3600.)
|
||||
|
||||
minutes = int((totaltime - 3600.*hours)/60.)
|
||||
seconds = int(totaltime - 3600.*hours - 60.*minutes)
|
||||
tenths = int(10*(totaltime - 3600.*hours - 60.*minutes - seconds))
|
||||
|
||||
|
||||
duration = "%s:%s:%s.%s" % (hours,minutes,seconds,tenths)
|
||||
duration = datetime.time(hour=hours,minute=minutes,second=seconds)
|
||||
|
||||
|
||||
workoutdate = row.rowdatetime.date()
|
||||
workoutstarttime = row.rowdatetime
|
||||
|
||||
@@ -139,7 +139,7 @@ def get_random_file(filename='rowers/tests/testdata/testdata.csv',name=''):
|
||||
'duration':duration,
|
||||
'totaldist':totaldist,
|
||||
}
|
||||
|
||||
|
||||
return thedict
|
||||
|
||||
class UserFactory(factory.DjangoModelFactory):
|
||||
@@ -168,11 +168,11 @@ class RaceFactory(factory.DjangoModelFactory):
|
||||
sessiontype = 'indoorrace'
|
||||
sessionvalue = 1
|
||||
sessionmode = 'time'
|
||||
|
||||
|
||||
class WorkoutFactory(factory.DjangoModelFactory):
|
||||
class Meta:
|
||||
model = Workout
|
||||
|
||||
|
||||
name = factory.LazyAttribute(lambda _: faker.word())
|
||||
notes = faker.text()
|
||||
startdatetime = get_random_file(name=faker.word())['startdatetime']
|
||||
@@ -220,5 +220,3 @@ def cleanup(request):
|
||||
|
||||
|
||||
request.addfinalizer(remove_test_files)
|
||||
|
||||
|
||||
|
||||
@@ -209,7 +209,6 @@ class URLTests(TestCase):
|
||||
'/rowers/workout/'+encoded1+'/editintervals/',
|
||||
'/rowers/workout/'+encoded1+'/flexchart/',
|
||||
'/rowers/workout/'+encoded1+'/forcecurve/',
|
||||
'/rowers/workout/'+encoded1+'/get-testscript/',
|
||||
'/rowers/workout/'+encoded1+'/get-thumbnails/',
|
||||
'/rowers/workout/'+encoded1+'/histo/',
|
||||
'/rowers/workout/'+encoded1+'/image/',
|
||||
|
||||
@@ -42,6 +42,8 @@ oauth_data = {
|
||||
'scope':'write',
|
||||
}
|
||||
|
||||
from rowers.rower_rules import is_workout_user
|
||||
|
||||
|
||||
# Checks if user has UnderArmour token, renews them if they are expired
|
||||
def tp_open(user):
|
||||
@@ -171,7 +173,7 @@ def workout_tp_upload(user,w):
|
||||
# need some code if token doesn't refresh
|
||||
|
||||
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (is_workout_user(user,w)):
|
||||
tcxfile = createtpworkoutdata(w)
|
||||
if tcxfile:
|
||||
res,reason,status_code,headers = uploadactivity(
|
||||
|
||||
@@ -9,7 +9,7 @@ from django.test import TestCase, Client,override_settings
|
||||
from django.core.management import call_command
|
||||
from django.utils.six import StringIO
|
||||
from django.test.client import RequestFactory
|
||||
from .views import checkworkoutuser,c2_open
|
||||
from .views import c2_open
|
||||
from rowers.models import Workout, User, Rower, WorkoutForm,RowerForm,GraphImage
|
||||
from rowers.forms import DocumentsForm,CNsummaryForm,RegistrationFormUniqueEmail
|
||||
import rowers.plots as plots
|
||||
@@ -55,12 +55,12 @@ class TraverseLinksTest(TestCase):
|
||||
name='testworkout',workouttype='On-water',
|
||||
user=self.r,date=nu.strftime('%Y-%m-%d'),
|
||||
starttime=nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000)
|
||||
duration="0:55:00",distance=8000)
|
||||
self.w2 = Workout.objects.create(
|
||||
name='testworkout 2',workouttype='On-water',
|
||||
user=self.r,date=nu.strftime('%Y-%m-%d'),
|
||||
starttime=nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000)
|
||||
duration="0:55:00",distance=8000)
|
||||
if self.client.login(
|
||||
username="superuser1", password="pwd"):
|
||||
if VERBOSE:
|
||||
|
||||
@@ -9,6 +9,7 @@ import numpy
|
||||
|
||||
import rowers.mytypes as mytypes
|
||||
from rowers.mytypes import otwtypes
|
||||
from rowers.rower_rules import is_workout_user
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
UNDERARMOUR_CLIENT_KEY,
|
||||
@@ -331,7 +332,7 @@ def workout_ua_upload(user,w):
|
||||
|
||||
# ready to upload. Hurray
|
||||
|
||||
if (checkworkoutuser(user,w)):
|
||||
if (is_workout_user(user,w)):
|
||||
data = createunderarmourworkoutdata(w)
|
||||
# return HttpResponse(json.dumps(data))
|
||||
if not data:
|
||||
|
||||
@@ -14,6 +14,8 @@ from rowers.tasks import (
|
||||
|
||||
from rowers.models import GraphImage
|
||||
|
||||
from rowers.rower_rules import ispromember
|
||||
|
||||
from PIL import Image
|
||||
|
||||
import numpy as np
|
||||
@@ -472,6 +474,8 @@ import rowers.runkeeperstuff as runkeeperstuff
|
||||
import rowers.underarmourstuff as underarmourstuff
|
||||
import rowers.tpstuff as tpstuff
|
||||
|
||||
from rowers.rower_rules import is_promember
|
||||
|
||||
def set_workouttype(w,options):
|
||||
try:
|
||||
w.workouttype = options['workouttype']
|
||||
@@ -500,8 +504,6 @@ def make_private(w,options):
|
||||
|
||||
return 1
|
||||
|
||||
from rowers.utils import isprorower
|
||||
|
||||
def do_sync(w,options):
|
||||
try:
|
||||
if options['stravaid'] != 0:
|
||||
@@ -511,7 +513,7 @@ def do_sync(w,options):
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
if ('upload_to_C2' in options and options['upload_to_C2']) or (w.user.c2_auto_export and isprorower(w.user)):
|
||||
if ('upload_to_C2' in options and options['upload_to_C2']) or (w.user.c2_auto_export and ispromember(w.user)):
|
||||
if ('upload_to_C2' in options and not options['upload_to_C2']):
|
||||
pass
|
||||
else:
|
||||
@@ -521,7 +523,7 @@ def do_sync(w,options):
|
||||
id = 0
|
||||
message = "Something went wrong with the Concept2 sync"
|
||||
|
||||
if ('upload_to_Strava' in options and options['upload_to_Strava']) or (w.user.strava_auto_export and isprorower(w.user)):
|
||||
if ('upload_to_Strava' in options and options['upload_to_Strava']) or (w.user.strava_auto_export and ispromember(w.user)):
|
||||
if ('upload_to_Strava' in options and not options['upload_to_Strava']):
|
||||
pass
|
||||
else:
|
||||
@@ -534,7 +536,7 @@ def do_sync(w,options):
|
||||
message = "Please connect to Strava first"
|
||||
|
||||
|
||||
if ('upload_to_SportTracks' in options and options['upload_to_SportTracks']) or (w.user.sporttracks_auto_export and isprorower(w.user)):
|
||||
if ('upload_to_SportTracks' in options and options['upload_to_SportTracks']) or (w.user.sporttracks_auto_export and ispromember(w.user)):
|
||||
if ('upload_to_SportTracks' in options and not options['upload_to_SportTracks']):
|
||||
pass
|
||||
else:
|
||||
@@ -548,7 +550,7 @@ def do_sync(w,options):
|
||||
id = 0
|
||||
|
||||
|
||||
if ('upload_to_RunKeeper' in options and options['upload_to_RunKeeper']) or (w.user.runkeeper_auto_export and isprorower(w.user)):
|
||||
if ('upload_to_RunKeeper' in options and options['upload_to_RunKeeper']) or (w.user.runkeeper_auto_export and ispromember(w.user)):
|
||||
if ('upload_to_RunKeeper' in options and not options['upload_to_RunKeeper']):
|
||||
pass
|
||||
else:
|
||||
@@ -561,7 +563,7 @@ def do_sync(w,options):
|
||||
message = "Please connect to Runkeeper first"
|
||||
id = 0
|
||||
|
||||
if ('upload_to_MapMyFitness' in options and options['upload_to_MapMyFitness']) or (w.user.mapmyfitness_auto_export and isprorower(w.user)):
|
||||
if ('upload_to_MapMyFitness' in options and options['upload_to_MapMyFitness']) or (w.user.mapmyfitness_auto_export and ispromember(w.user)):
|
||||
if ('upload_to_MapMyFitness' in options and not options['upload_to_MapMyFitness']):
|
||||
pass
|
||||
else:
|
||||
@@ -574,7 +576,7 @@ def do_sync(w,options):
|
||||
id = 0
|
||||
|
||||
|
||||
if ('upload_to_TrainingPeaks' in options and options['upload_to_TrainingPeaks']) or (w.user.trainingpeaks_auto_export and isprorower(w.user)):
|
||||
if ('upload_to_TrainingPeaks' in options and options['upload_to_TrainingPeaks']) or (w.user.trainingpeaks_auto_export and ispromember(w.user)):
|
||||
if ('upload_to_TrainingPeaks' in options and not options['upload_to_TrainingPeaks']):
|
||||
pass
|
||||
else:
|
||||
|
||||
@@ -289,8 +289,6 @@ urlpatterns = [
|
||||
name='otw_use_gps'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/toggle-ranking/$',views.workout_toggle_ranking,
|
||||
name='workout_toggle_ranking'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/get-testscript/$',views.get_testscript,
|
||||
name='get_testscript'),
|
||||
re_path(r'^workout/upload/team/$',views.team_workout_upload_view,name='team_workout_upload_view'),
|
||||
re_path(r'^workout/upload/$',views.workout_upload_view,name='workout_upload_view'),
|
||||
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/histo/$',views.workout_histo_view,
|
||||
|
||||
@@ -109,7 +109,7 @@ def get_call():
|
||||
</p>
|
||||
</div>
|
||||
""" % (call1, call2)
|
||||
|
||||
|
||||
return call
|
||||
|
||||
def absolute(request):
|
||||
@@ -131,7 +131,7 @@ def trcolors(r1,g1,b1,r2,g2,b2):
|
||||
h1,s1,v1 = colorsys.rgb_to_hsv(r1,g1,b1)
|
||||
h2,s2,v2 = colorsys.rgb_to_hsv(r2,g2,b2)
|
||||
|
||||
|
||||
|
||||
return 360*h1,360*(h2-h1),s1,(s2-s1),v1,(v2-v1)
|
||||
|
||||
palettes = {
|
||||
@@ -167,7 +167,7 @@ def is_ranking_piece(workout):
|
||||
return True
|
||||
elif workout.duration in rankingdurations:
|
||||
return True
|
||||
|
||||
|
||||
return False
|
||||
|
||||
def range_to_color_hex(groupcols,palette='monochrome_blue'):
|
||||
@@ -176,20 +176,20 @@ def range_to_color_hex(groupcols,palette='monochrome_blue'):
|
||||
plt = palettes[palette]
|
||||
except KeyError:
|
||||
plt = palettes['monochrome_blue']
|
||||
|
||||
|
||||
rgb = [colorsys.hsv_to_rgb((plt[0]+plt[1]*x)/360.,
|
||||
plt[2]+plt[3]*x,
|
||||
plt[4]+plt[5]*x) for x in groupcols]
|
||||
|
||||
RGB = [(int(255.*r),int(255.*g),int(255.*b)) for (r, g, b) in rgb]
|
||||
colors = ["#%02x%02x%02x" % (r, g, b) for (r, g, b) in RGB]
|
||||
|
||||
|
||||
return colors
|
||||
|
||||
def str2bool(v):
|
||||
return v.lower() in ("yes", "true", "t", "1")
|
||||
|
||||
def uniqify(seq, idfun=None):
|
||||
def uniqify(seq, idfun=None):
|
||||
# order preserving
|
||||
if idfun is None:
|
||||
def idfun(x): return x
|
||||
@@ -222,12 +222,12 @@ def geo_distance(lat1,lon1,lat2,lon2):
|
||||
This is a slight underestimate but is close enough for our purposes,
|
||||
We're never moving more than 10 meters between trackpoints
|
||||
|
||||
Bearing calculation fails if one of the points is a pole.
|
||||
(Hey, from the North pole you can walk South, East, North and end up
|
||||
Bearing calculation fails if one of the points is a pole.
|
||||
(Hey, from the North pole you can walk South, East, North and end up
|
||||
on the same spot!)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# radius of our earth in km --> should be moved to settings if
|
||||
# rowing takes off on other planets
|
||||
R = 6373.0
|
||||
@@ -257,7 +257,7 @@ def geo_distance(lat1,lon1,lat2,lon2):
|
||||
|
||||
return [distance,bearing]
|
||||
|
||||
|
||||
|
||||
|
||||
def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
|
||||
pwr = abs(p0)/(1+(delta/abs(p2)))
|
||||
@@ -268,7 +268,7 @@ def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
|
||||
|
||||
pwr *= ratio
|
||||
|
||||
|
||||
|
||||
delta = delta.values.astype(int)
|
||||
cpvalues = cpvalues.values.astype(int)
|
||||
pwr = pwr.astype(int)
|
||||
@@ -276,7 +276,7 @@ def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
|
||||
res = np.sum(cpvalues>pwr)
|
||||
res2 = np.sum(cpvalues>pwr2)
|
||||
|
||||
|
||||
|
||||
btdf = pd.DataFrame(
|
||||
{
|
||||
'delta':delta[cpvalues>pwr],
|
||||
@@ -288,7 +288,7 @@ def isbreakthrough(delta,cpvalues,p0,p1,p2,p3,ratio):
|
||||
|
||||
btdf.sort_values('delta',axis=0,inplace=True)
|
||||
|
||||
|
||||
|
||||
return res>1,btdf,res2>1
|
||||
|
||||
|
||||
@@ -300,7 +300,7 @@ def myqueue(queue,function,*args,**kwargs):
|
||||
|
||||
def revoke(self):
|
||||
return 1
|
||||
|
||||
|
||||
if settings.TESTING:
|
||||
return MockJob()
|
||||
elif settings.CELERY:
|
||||
@@ -310,7 +310,7 @@ def myqueue(queue,function,*args,**kwargs):
|
||||
else:
|
||||
if settings.DEBUG:
|
||||
kwargs['debug'] = True
|
||||
|
||||
|
||||
job_id = str(uuid.uuid4())
|
||||
kwargs['job_id'] = job_id
|
||||
kwargs['jobkey'] = job_id
|
||||
@@ -335,7 +335,7 @@ def my_dict_from_instance(instance,model):
|
||||
thedict['id'] = instance.id
|
||||
|
||||
for f in instance._meta.fields:
|
||||
|
||||
|
||||
fname = f.name
|
||||
|
||||
try:
|
||||
@@ -405,24 +405,13 @@ def totaltime_sec_to_string(totaltime):
|
||||
|
||||
return duration
|
||||
|
||||
def isprorower(r):
|
||||
result = False
|
||||
result = r.rowerplan in ['pro','coach','plan']
|
||||
|
||||
if not result and r.protrialexpires:
|
||||
result = r.rowerplan == 'basic' and r.protrialexpires >= datetime.date.today()
|
||||
if not result and r.rowerplan == 'freecoach':
|
||||
if r.mycoachgroup is not None:
|
||||
result = len(r.mycoachgroup)>=4
|
||||
|
||||
return result
|
||||
|
||||
def iscoach(m,r):
|
||||
result = False
|
||||
result = m in r.coaches
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# Exponentially weighted moving average
|
||||
# Used for data smoothing of the jagged data obtained by Strava
|
||||
# See bitbucket issue 72
|
||||
@@ -433,7 +422,7 @@ def ewmovingaverage(interval,window_size):
|
||||
intervaldf = pd.DataFrame({'v':interval})
|
||||
idf_ewma1 = intervaldf.ewm(span=window_size)
|
||||
idf_ewma2 = intervaldf[::-1].ewm(span=window_size)
|
||||
|
||||
|
||||
i_ewma1 = idf_ewma1.mean().loc[:,'v']
|
||||
i_ewma2 = idf_ewma2.mean().loc[:,'v']
|
||||
|
||||
@@ -478,7 +467,7 @@ def custom_exception_handler(exc,message):
|
||||
res.json = json.dumps(response)
|
||||
|
||||
return res
|
||||
|
||||
|
||||
def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high'):
|
||||
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
@@ -503,7 +492,7 @@ def get_strava_stream(r,metric,stravaid,series_type='time',fetchresolution='high
|
||||
return np.array(data['data'])
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
|
||||
return None
|
||||
|
||||
def allmonths(startdate,enddate):
|
||||
@@ -518,4 +507,3 @@ def allsundays(startdate,enddate):
|
||||
while d<=enddate:
|
||||
yield d
|
||||
d += datetime.timedelta(days=7)
|
||||
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
from rowers.views.statements import *
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# Export workout to TCX and send to user's email address
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_tcxemail_view(request,id=0):
|
||||
r = getrower(request.user)
|
||||
w = get_workout(id)
|
||||
|
||||
if not checkworkoutuser(request.user,w):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
|
||||
|
||||
row = rdata(w.csvfilename)
|
||||
@@ -31,8 +30,8 @@ def workout_tcxemail_view(request,id=0):
|
||||
return response
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@login_required()
|
||||
def plannedsessions_icsemail_view(request,userid=0):
|
||||
@@ -66,7 +65,7 @@ def plannedsessions_icsemail_view(request,userid=0):
|
||||
d1 = startdate.strftime("%Y%m%d"),
|
||||
d2 = enddate.strftime("%Y%m%d"),
|
||||
)
|
||||
|
||||
|
||||
response['Content-Type'] = 'application/octet-stream'
|
||||
|
||||
return response
|
||||
@@ -96,7 +95,7 @@ def plannedsessions_coach_icsemail_view(request,userid=0):
|
||||
rowers += ps.rower.filter(team__in=rteams).exclude(rowerplan='freecoach')
|
||||
|
||||
rowers = list(set(rowers))
|
||||
|
||||
|
||||
cal = Calendar()
|
||||
cal.add('prodid','rowsandall')
|
||||
cal.add('version','1.0')
|
||||
@@ -169,13 +168,12 @@ def course_kmldownload_view(request,id=0):
|
||||
|
||||
|
||||
# Export workout to GPX and send to user's email address
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_gpxemail_view(request,id=0):
|
||||
r = getrower(request.user)
|
||||
w = get_workout(id)
|
||||
|
||||
if not checkworkoutuser(request.user,w):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
|
||||
|
||||
row = rdata(w.csvfilename)
|
||||
@@ -233,17 +231,16 @@ def workouts_summaries_email_view(request):
|
||||
{
|
||||
'form':form
|
||||
})
|
||||
|
||||
|
||||
|
||||
# Get Workout CSV file and send it to user's email address
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_csvemail_view(request,id=0):
|
||||
r = getrower(request.user)
|
||||
|
||||
w = get_workout(id)
|
||||
|
||||
if not checkworkoutuser(request.user,w):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
|
||||
rowdata = rdata(w.csvfilename)
|
||||
code = str(uuid4())
|
||||
@@ -254,13 +251,13 @@ def workout_csvemail_view(request,id=0):
|
||||
df = rowdata.df
|
||||
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
|
||||
df['TimeStamp (sec)'] = df['TimeStamp (sec)'] + starttimeunix
|
||||
|
||||
|
||||
response = HttpResponse(df.to_csv())
|
||||
response['Content-Disposition'] = 'attachment; filename="%s"' % filename
|
||||
response['Content-Type'] = 'application/octet-stream'
|
||||
|
||||
return response
|
||||
|
||||
|
||||
|
||||
# Get Workout CSV file and send it to user's email address
|
||||
@login_required()
|
||||
|
||||
@@ -8,14 +8,14 @@ from rowers.views.statements import *
|
||||
import numpy
|
||||
|
||||
def default(o):
|
||||
if isinstance(o, numpy.int64): return int(o)
|
||||
if isinstance(o, numpy.int64): return int(o)
|
||||
raise TypeError
|
||||
|
||||
|
||||
# Send workout to TP
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_tp_upload_view(request,id=0):
|
||||
|
||||
|
||||
message = ""
|
||||
r = getrower(request.user)
|
||||
res = -1
|
||||
@@ -25,52 +25,48 @@ def workout_tp_upload_view(request,id=0):
|
||||
return HttpResponseRedirect("/rowers/me/tpauthorize/")
|
||||
|
||||
# ready to upload. Hurray
|
||||
w = get_workout_permitted(request.user,id)
|
||||
w = get_object_or_404(Workout,pk=id)
|
||||
r = w.user
|
||||
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
tcxfile = tpstuff.createtpworkoutdata(w)
|
||||
if tcxfile:
|
||||
res,reason,status_code,headers = tpstuff.uploadactivity(
|
||||
r.tptoken,tcxfile,
|
||||
name=w.name
|
||||
)
|
||||
if res == 0:
|
||||
message = "Upload to TrainingPeaks failed with status code "+str(status_code)+": "+reason
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
messages.error(request,message)
|
||||
|
||||
else: # res != 0
|
||||
w.uploadedtotp = res
|
||||
w.save()
|
||||
tcxfile = tpstuff.createtpworkoutdata(w)
|
||||
if tcxfile:
|
||||
res,reason,status_code,headers = tpstuff.uploadactivity(
|
||||
r.tptoken,tcxfile,
|
||||
name=w.name
|
||||
)
|
||||
if res == 0:
|
||||
message = "Upload to TrainingPeaks failed with status code "+str(status_code)+": "+reason
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
messages.info(request,'Uploaded to TrainingPeaks')
|
||||
except WindowsError:
|
||||
pass
|
||||
|
||||
else: # no tcxfile
|
||||
message = "Upload to TrainingPeaks failed"
|
||||
w.uploadedtotp = -1
|
||||
w.save()
|
||||
messages.error(request,message)
|
||||
|
||||
else: # not allowed to upload
|
||||
message = "You are not allowed to export this workout to TP"
|
||||
else: # res != 0
|
||||
w.uploadedtotp = res
|
||||
w.save()
|
||||
os.remove(tcxfile)
|
||||
messages.info(request,'Uploaded to TrainingPeaks')
|
||||
|
||||
else: # no tcxfile
|
||||
message = "Upload to TrainingPeaks failed"
|
||||
w.uploadedtotp = -1
|
||||
w.save()
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':encoder.encode_hex(w.id),
|
||||
})
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
|
||||
# Send workout to Strava
|
||||
# abundance of error logging here because there were/are some bugs
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_strava_upload_view(request,id=0):
|
||||
message = ""
|
||||
r = getrower(request.user)
|
||||
@@ -80,7 +76,7 @@ def workout_strava_upload_view(request,id=0):
|
||||
thetoken = strava_open(request.user)
|
||||
except NoTokenError:
|
||||
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/")
|
||||
@@ -88,94 +84,94 @@ def workout_strava_upload_view(request,id=0):
|
||||
# ready to upload. Hurray
|
||||
w = get_workout_permitted(request.user,id)
|
||||
r = w.user
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
try:
|
||||
tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w)
|
||||
if tcxfile:
|
||||
with open(tcxfile,'rb') as f:
|
||||
|
||||
try:
|
||||
tcxfile,tcxmessg = stravastuff.createstravaworkoutdata(w)
|
||||
if tcxfile:
|
||||
with open(tcxfile,'rb') as f:
|
||||
try:
|
||||
newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
|
||||
except TypeError:
|
||||
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
|
||||
if w.workouttype in mytypes.rowtypes:
|
||||
activity_type = r.stravaexportas
|
||||
else:
|
||||
try:
|
||||
newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
|
||||
except TypeError:
|
||||
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
|
||||
if w.workouttype in mytypes.rowtypes:
|
||||
activity_type = r.stravaexportas
|
||||
else:
|
||||
try:
|
||||
activity_type = mytypes.stravamapping[w.workouttype]
|
||||
except KeyError:
|
||||
activity_type = 'Ride'
|
||||
|
||||
res,mes = stravastuff.handle_stravaexport(
|
||||
f,w.name,
|
||||
r.stravatoken,
|
||||
description=newnotes,
|
||||
activity_type=activity_type)
|
||||
if res==0:
|
||||
messages.error(request,mes)
|
||||
w.uploadedtostrava = -1
|
||||
w.save()
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':encoder.encode_hex(w.id),
|
||||
})
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
activity_type = mytypes.stravamapping[w.workouttype]
|
||||
except KeyError:
|
||||
activity_type = 'Ride'
|
||||
|
||||
res,mes = stravastuff.handle_stravaexport(
|
||||
f,w.name,
|
||||
r.stravatoken,
|
||||
description=newnotes,
|
||||
activity_type=activity_type)
|
||||
if res==0:
|
||||
messages.error(request,mes)
|
||||
w.uploadedtostrava = -1
|
||||
w.save()
|
||||
try:
|
||||
w.uploadedtostrava = res
|
||||
w.save()
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
url = reverse('workout_edit_view',kwargs={'id':w.id})
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':encoder.encode_hex(w.id),
|
||||
})
|
||||
response = HttpResponseRedirect(url)
|
||||
return response
|
||||
|
||||
try:
|
||||
w.uploadedtostrava = res
|
||||
w.save()
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
url = reverse('workout_edit_view',kwargs={'id':w.id})
|
||||
|
||||
|
||||
messages.info(request,mes)
|
||||
except:
|
||||
with open("media/stravaerrors.log","a") as errorlog:
|
||||
errorstring = str(sys.exc_info()[0])
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
errorlog.write(timestr+errorstring+"\r\n")
|
||||
errorlog.write("views.py line 826\r\n")
|
||||
message = 'Error: '+errorstring
|
||||
messages.error(request,message)
|
||||
else: # No tcxfile
|
||||
message = "Strava Data error "+tcxmessg
|
||||
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)
|
||||
except ActivityUploadFailed as e:
|
||||
message = "Strava Upload error: %s" % e
|
||||
messages.info(request,mes)
|
||||
except:
|
||||
with open("media/stravaerrors.log","a") as errorlog:
|
||||
errorstring = str(sys.exc_info()[0])
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
errorlog.write(timestr+errorstring+"\r\n")
|
||||
errorlog.write("views.py line 826\r\n")
|
||||
message = 'Error: '+errorstring
|
||||
messages.error(request,message)
|
||||
else: # No tcxfile
|
||||
message = "Strava Data error "+tcxmessg
|
||||
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)
|
||||
|
||||
return response
|
||||
|
||||
|
||||
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)
|
||||
|
||||
return response
|
||||
|
||||
# Upload workout to Concept2 logbook
|
||||
@login_required()
|
||||
def workout_c2_upload_view(request,id=0):
|
||||
@@ -183,7 +179,7 @@ def workout_c2_upload_view(request,id=0):
|
||||
# ready to upload. Hurray
|
||||
w = get_workout(id)
|
||||
r = w.user
|
||||
|
||||
|
||||
try:
|
||||
message,c2id = c2stuff.workout_c2_upload(request.user,w)
|
||||
except NoTokenError:
|
||||
@@ -199,14 +195,14 @@ def workout_c2_upload_view(request,id=0):
|
||||
kwargs = {
|
||||
'id':encoder.encode_hex(w.id)
|
||||
})
|
||||
|
||||
|
||||
|
||||
response = HttpResponseRedirect(url)
|
||||
|
||||
return response
|
||||
|
||||
# Upload workout to RunKeeper
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_runkeeper_upload_view(request,id=0):
|
||||
message = ""
|
||||
w = get_workout(id)
|
||||
@@ -219,48 +215,45 @@ def workout_runkeeper_upload_view(request,id=0):
|
||||
|
||||
# ready to upload. Hurray
|
||||
|
||||
if (checkworkoutuser(request.user,w)):
|
||||
data = runkeeperstuff.createrunkeeperworkoutdata(w)
|
||||
if not data:
|
||||
message = "Data error"
|
||||
messages.error(request,message)
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
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,default=default))
|
||||
|
||||
# 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()
|
||||
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)
|
||||
messages.error(request,message)
|
||||
|
||||
else:
|
||||
message = "You are not authorized to upload this workout"
|
||||
data = runkeeperstuff.createrunkeeperworkoutdata(w)
|
||||
if not data:
|
||||
message = "Data error"
|
||||
messages.error(request,message)
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':id,
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
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,default=default))
|
||||
|
||||
# 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()
|
||||
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)
|
||||
messages.error(request,message)
|
||||
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
@@ -270,7 +263,7 @@ def workout_runkeeper_upload_view(request,id=0):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Upload workout to Underarmour
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_underarmour_upload_view(request,id=0):
|
||||
message = ""
|
||||
w = get_workout(id)
|
||||
@@ -282,48 +275,45 @@ def workout_underarmour_upload_view(request,id=0):
|
||||
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
|
||||
|
||||
# ready to upload. Hurray
|
||||
|
||||
if (checkworkoutuser(request.user,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),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'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,default=default))
|
||||
|
||||
|
||||
# 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()
|
||||
url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)})
|
||||
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),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
s = response
|
||||
message = "Something went wrong in workout_underarmour_upload_view: %s " % s.reason
|
||||
messages.error(request,message)
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'Api-Key': UNDERARMOUR_CLIENT_KEY,
|
||||
'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,default=default))
|
||||
|
||||
|
||||
# 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()
|
||||
url = reverse('workout_edit_view',kwargs={'id':encoder.encode_hex(w.id)})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
message = "You are not authorized to upload this workout"
|
||||
s = response
|
||||
message = "Something went wrong in workout_underarmour_upload_view: %s " % s.reason
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
@@ -334,7 +324,7 @@ def workout_underarmour_upload_view(request,id=0):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Upload workout to SportTracks
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def workout_sporttracks_upload_view(request,id=0):
|
||||
message = ""
|
||||
# ready to upload. Hurray
|
||||
@@ -347,49 +337,46 @@ def workout_sporttracks_upload_view(request,id=0):
|
||||
return HttpResponseRedirect("/rowers/me/sporttracksauthorize/")
|
||||
|
||||
|
||||
if (checkworkoutuser(request.user,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),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
data = sporttracksstuff.createsporttracksworkoutdata(w)
|
||||
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
if not data:
|
||||
message = "Data error"
|
||||
messages.error(request,message)
|
||||
url = reverse(r.defaultlandingpage,
|
||||
kwargs = {
|
||||
'id':encoder.encode_hex(w.id),
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
|
||||
authorizationstring = str('Bearer ' + thetoken)
|
||||
headers = {'Authorization': authorizationstring,
|
||||
'user-agent': 'sanderroosendaal',
|
||||
'Content-Type': 'application/json'}
|
||||
|
||||
|
||||
# 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()
|
||||
message = "Upload to SportTracks was successful"
|
||||
messages.info(request,message)
|
||||
url = "https://api.sporttracks.mobi/api/v2/fitnessActivities.json"
|
||||
response = requests.post(url,headers=headers,data=json.dumps(data,default=default))
|
||||
|
||||
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)
|
||||
|
||||
# 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()
|
||||
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:
|
||||
message = "You are not authorized to upload this workout"
|
||||
s = response
|
||||
message = "Something went wrong in workout_sporttracks_upload_view: %s" % s.reason
|
||||
messages.error(request,message)
|
||||
|
||||
url = reverse(r.defaultlandingpage,
|
||||
@@ -399,7 +386,7 @@ def workout_sporttracks_upload_view(request,id=0):
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Concept2 authorization
|
||||
# Concept2 authorization
|
||||
@login_required()
|
||||
def rower_c2_authorize(request):
|
||||
# Generate a random string for the state parameter
|
||||
@@ -444,10 +431,10 @@ def rower_polar_authorize(request):
|
||||
# "scope":"accesslink.read_all"
|
||||
}
|
||||
url = "https://flow.polar.com/oauth2/authorization?" +urllib.parse.urlencode(params)
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
|
||||
# Runkeeper authorization
|
||||
@login_required()
|
||||
@@ -494,7 +481,7 @@ def rower_underarmour_authorize(request):
|
||||
state = str(uuid4())
|
||||
|
||||
redirect_uri = UNDERARMOUR_REDIRECT_URI
|
||||
|
||||
|
||||
url = 'https://www.mapmyfitness.com/v7.1/oauth2/authorize/?' \
|
||||
'client_id={0}&response_type=code&redirect_uri={1}'.format(
|
||||
UNDERARMOUR_CLIENT_KEY, redirect_uri
|
||||
@@ -647,7 +634,7 @@ def rower_process_callback(request):
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
access_token = res[0]
|
||||
if access_token == 0:
|
||||
message = res[1]
|
||||
@@ -657,8 +644,8 @@ def rower_process_callback(request):
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
@@ -674,12 +661,12 @@ def rower_process_callback(request):
|
||||
messages.info(request,successmessage)
|
||||
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
# dummy
|
||||
# dummy
|
||||
@login_required()
|
||||
def rower_process_twittercallback(request):
|
||||
return "dummy"
|
||||
@@ -697,13 +684,13 @@ def rower_process_polarcallback(request):
|
||||
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
access_token, expires_in, user_id = polarstuff.get_token(code)
|
||||
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
r.polartoken = access_token
|
||||
r.polartokenexpirydate = expirydatetime
|
||||
@@ -714,7 +701,7 @@ def rower_process_polarcallback(request):
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
messages.info(request,successmessage)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -734,10 +721,10 @@ def rower_process_stravacallback(request):
|
||||
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
res = stravastuff.get_token(code)
|
||||
|
||||
if res[0]:
|
||||
@@ -762,7 +749,7 @@ def rower_process_stravacallback(request):
|
||||
message = "Something went wrong with the Strava authorization"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -776,7 +763,7 @@ def rower_process_runkeepercallback(request):
|
||||
if access_token == 0:
|
||||
messages.error(request,"Something went wrong importing the token")
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -789,7 +776,7 @@ def rower_process_runkeepercallback(request):
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
messages.info(request,successmessage)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -806,7 +793,7 @@ def rower_process_sporttrackscallback(request):
|
||||
refresh_token = res[2]
|
||||
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
r.sporttrackstoken = access_token
|
||||
r.sporttrackstokenexpirydate = expirydatetime
|
||||
@@ -817,7 +804,7 @@ def rower_process_sporttrackscallback(request):
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
messages.info(request,successmessage)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -833,7 +820,7 @@ def rower_process_underarmourcallback(request):
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
r.underarmourtoken = access_token
|
||||
r.underarmourtokenexpirydate = expirydatetime
|
||||
@@ -844,7 +831,7 @@ def rower_process_underarmourcallback(request):
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
messages.info(request,successmessage)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -859,7 +846,7 @@ def rower_process_tpcallback(request):
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
r.tptoken = access_token
|
||||
r.tptokenexpirydate = expirydatetime
|
||||
@@ -870,7 +857,7 @@ def rower_process_tpcallback(request):
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
messages.info(request,successmessage)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
@@ -892,7 +879,7 @@ def rower_process_testcallback(request):
|
||||
|
||||
text += "\n\nRefresh Token:\n"
|
||||
text += refresh_token
|
||||
|
||||
|
||||
return HttpResponse(text)
|
||||
|
||||
|
||||
@@ -909,10 +896,10 @@ def workout_stravaimport_view(request,message="",userid=0):
|
||||
except NoTokenError:
|
||||
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)
|
||||
@@ -950,7 +937,7 @@ def workout_stravaimport_view(request,message="",userid=0):
|
||||
w.uploadedtostrava = int(stravaid)
|
||||
w.save()
|
||||
|
||||
|
||||
|
||||
knownstravaids = uniqify([
|
||||
w.uploadedtostrava for w in Workout.objects.filter(user=r)
|
||||
])
|
||||
@@ -985,7 +972,7 @@ def workout_stravaimport_view(request,message="",userid=0):
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
|
||||
return render(request,'strava_list_import.html',
|
||||
{'workouts':workouts,
|
||||
'rower':r,
|
||||
@@ -1024,7 +1011,7 @@ def workout_runkeeperimport_view(request,message="",userid=0):
|
||||
r = item['type']
|
||||
keys = ['id','distance','duration','starttime','type']
|
||||
values = [i,d,ttot,s,r]
|
||||
|
||||
|
||||
res = dict(zip(keys,values))
|
||||
workouts.append(res)
|
||||
|
||||
@@ -1072,11 +1059,11 @@ def workout_underarmourimport_view(request,message="",userid=0):
|
||||
ttot = item['aggregates']['active_time_total']
|
||||
except KeyError:
|
||||
ttot = 0
|
||||
|
||||
|
||||
keys = ['id','distance','duration','starttime','type']
|
||||
values = [i,d,ttot,s,r]
|
||||
thedict = dict(zip(keys,values))
|
||||
|
||||
|
||||
workouts.append(thedict)
|
||||
|
||||
rower = getrower(request.user)
|
||||
@@ -1090,7 +1077,7 @@ def workout_underarmourimport_view(request,message="",userid=0):
|
||||
'name':'Concept2'
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
return render(request,'underarmour_list_import.html',
|
||||
{'workouts':workouts,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
@@ -1115,13 +1102,13 @@ def workout_polarimport_view(request,userid=0):
|
||||
return HttpResponseRedirect(url)
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
for exercise in exercises:
|
||||
try:
|
||||
d = exercise['distance']
|
||||
except KeyError:
|
||||
d = 0
|
||||
|
||||
|
||||
i = exercise['id']
|
||||
transactionid = exercise['transaction-id']
|
||||
starttime = exercise['start-time']
|
||||
@@ -1156,13 +1143,13 @@ def workout_polarimport_view(request,userid=0):
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# The page where you select which SportTracks workout to import
|
||||
@login_required()
|
||||
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):
|
||||
@@ -1215,7 +1202,7 @@ def workout_sporttracksimport_view(request,message="",userid=0):
|
||||
'name':'SportTracks'
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
return render(request,'sporttracks_list_import.html',
|
||||
{'workouts':workouts,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
@@ -1225,7 +1212,7 @@ def workout_sporttracksimport_view(request,message="",userid=0):
|
||||
})
|
||||
|
||||
return HttpResponse(res)
|
||||
|
||||
|
||||
# List of workouts on Concept2 logbook. This view only used for debugging
|
||||
@login_required()
|
||||
def c2listdebug_view(request,page=1,message=""):
|
||||
@@ -1262,7 +1249,7 @@ def c2listdebug_view(request,page=1,message=""):
|
||||
res = dict(zip(keys,values))
|
||||
workouts.append(res)
|
||||
|
||||
|
||||
|
||||
return render(request,
|
||||
'c2_list_import2.html',
|
||||
{'workouts':workouts,
|
||||
@@ -1288,20 +1275,20 @@ def workout_getc2workout_all(request,page=1,message=""):
|
||||
alldata = {}
|
||||
for item in res.json()['data']:
|
||||
alldata[item['id']] = item
|
||||
|
||||
|
||||
knownc2ids = uniqify([
|
||||
w.uploadedtoc2 for w in Workout.objects.filter(user=r)
|
||||
])
|
||||
newids = [c2id for c2id in c2ids if not c2id in knownc2ids]
|
||||
|
||||
|
||||
for c2id in newids:
|
||||
workoutid = c2stuff.create_async_workout(alldata,
|
||||
request.user,c2id)
|
||||
|
||||
url = reverse('workouts_view')
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
|
||||
# List of workouts available on Concept2 logbook - for import
|
||||
@login_required()
|
||||
def workout_c2import_view(request,page=1,userid=0,message=""):
|
||||
@@ -1312,7 +1299,7 @@ def workout_c2import_view(request,page=1,userid=0,message=""):
|
||||
messages.info(request,"You cannot import other people's workouts from Concept2")
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
|
||||
try:
|
||||
thetoken = c2_open(request.user)
|
||||
except NoTokenError:
|
||||
@@ -1366,7 +1353,7 @@ def workout_c2import_view(request,page=1,userid=0,message=""):
|
||||
]
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
|
||||
return render(request,
|
||||
'c2_list_import2.html',
|
||||
{'workouts':workouts,
|
||||
@@ -1394,14 +1381,14 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
if not res[0]:
|
||||
messages.error(request,res[1])
|
||||
url = reverse('workouts_view')
|
||||
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
strokedata = res[1]
|
||||
data = res[0]
|
||||
|
||||
|
||||
|
||||
# Now works only for C2
|
||||
try:
|
||||
if strokedata == 0:
|
||||
@@ -1433,16 +1420,16 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
|
||||
if timezone_str is None:
|
||||
timezone_str = 'UTC'
|
||||
|
||||
|
||||
workoutdate = startdatetime.astimezone(
|
||||
pytz.timezone(timezone_str)
|
||||
).strftime('%Y-%m-%d')
|
||||
starttime = startdatetime.astimezone(
|
||||
pytz.timezone(timezone_str)
|
||||
).strftime('%H:%M:%S')
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
|
||||
id, message = dataprep.create_row_df(r,
|
||||
distance,
|
||||
duration,
|
||||
@@ -1463,7 +1450,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
# strokedata not empty - continue
|
||||
id,message = importsources[source].add_workout_from_data(
|
||||
request.user,
|
||||
@@ -1504,7 +1491,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
rowdata.write_csv(w.csvfilename,gzip=True)
|
||||
dataprep.update_strokedata(w.id,rowdata.df)
|
||||
|
||||
|
||||
|
||||
|
||||
if source == 'strava':
|
||||
w.uploadedtostrava = externalid
|
||||
@@ -1534,7 +1521,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1599,7 +1586,7 @@ def workout_getstravaworkout_next(request):
|
||||
alldata = {}
|
||||
for item in res.json():
|
||||
alldata[item['id']] = item
|
||||
|
||||
|
||||
knownstravaids = uniqify([
|
||||
w.uploadedtostrava for w in Workout.objects.filter(user=r)
|
||||
])
|
||||
@@ -1608,10 +1595,8 @@ def workout_getstravaworkout_next(request):
|
||||
theid = newids[0]
|
||||
|
||||
workoutid = stravastuff.create_async_workout(alldata,r.user,stravaid,debug=True)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
url = reverse('workouts_view')
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
|
||||
@@ -1697,21 +1697,16 @@ def plannedsession_edit_view(request,id=0,userid=0):
|
||||
})
|
||||
|
||||
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=objectgetter(Workout, 'id'))
|
||||
def plannedsession_detach_view(request,id=0,psid=0):
|
||||
|
||||
r = getrequestrower(request)
|
||||
|
||||
try:
|
||||
ps = PlannedSession.objects.get(id=psid)
|
||||
except PlannedSession.DoesNotExist:
|
||||
raise Http404("Planned Session does not exist")
|
||||
|
||||
ps = get_object_or_404(PlannedSession,pk=psid)
|
||||
|
||||
w = get_workout(id)
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
return HttpResponseForbidden("Permission Error")
|
||||
|
||||
remove_workout_plannedsession(w,ps)
|
||||
|
||||
url = reverse(plannedsession_view,kwargs={'id':psid})
|
||||
|
||||
@@ -32,10 +32,17 @@ from icalendar import Calendar, Event
|
||||
|
||||
from functools import reduce
|
||||
|
||||
from rules.contrib.views import PermissionRequiredMixin
|
||||
|
||||
import rowers.braintreestuff as braintreestuff
|
||||
import rowers.payments as payments
|
||||
from rowers.opaque import encoder
|
||||
|
||||
from rowers.rower_rules import (
|
||||
ispromember,is_coach_user,is_team_member,is_rower_team_member,
|
||||
is_workout_user
|
||||
)
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
@@ -98,7 +105,7 @@ from rowers.models import (
|
||||
TrainingMesoCycleForm, TrainingMicroCycleForm,
|
||||
RaceLogo,RowerBillingAddressForm,PaidPlan,
|
||||
AlertEditForm, ConditionEditForm,
|
||||
PlannedSessionComment,CoachRequest,CoachOffer,checkaccessplanuser,
|
||||
PlannedSessionComment,CoachRequest,CoachOffer,
|
||||
VideoAnalysis
|
||||
)
|
||||
from rowers.models import (
|
||||
@@ -275,6 +282,11 @@ def getfavorites(r,row):
|
||||
|
||||
return favorites,maxfav
|
||||
|
||||
def get_workout_by_opaqueid(request,id,**kwargs):
|
||||
pk = encoder.decode_hex(id)
|
||||
return get_object_or_404(Workout,pk=pk)
|
||||
|
||||
|
||||
def get_workout_default_page(request,id):
|
||||
if request.user.is_anonymous:
|
||||
return reverse('workout_view',kwargs={'id':id})
|
||||
@@ -310,7 +322,7 @@ def getrequestrower(request,rowerid=0,userid=0,notpermanent=False):
|
||||
except Rower.DoesNotExist:
|
||||
raise Http404("Rower doesn't exist")
|
||||
|
||||
if not checkaccessuser(request.user,r):
|
||||
if userid != 0 and not is_coach_user(u,r):
|
||||
raise PermissionDenied("You have no access to this user")
|
||||
|
||||
if notpermanent == False:
|
||||
@@ -343,7 +355,7 @@ def getrequestplanrower(request,rowerid=0,userid=0,notpermanent=False):
|
||||
except Rower.DoesNotExist:
|
||||
raise Http404("Rower doesn't exist")
|
||||
|
||||
if not checkaccessplanuser(request.user,r):
|
||||
if not is_coach_user(request.user,r):
|
||||
raise PermissionDenied("You have no access to this user")
|
||||
|
||||
if notpermanent == False:
|
||||
@@ -377,21 +389,6 @@ def get_workout(id):
|
||||
|
||||
return w
|
||||
|
||||
def get_workout_permitted(user,id):
|
||||
w = get_workout(id)
|
||||
|
||||
if (checkworkoutuser(user,w)==False):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
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
|
||||
@@ -774,9 +771,9 @@ def get_stored_tasks_status(request):
|
||||
|
||||
return taskstatus
|
||||
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def get_thumbnails(request,id):
|
||||
row = get_workout_permitted(request.user,id)
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
|
||||
|
||||
r = getrower(request.user)
|
||||
@@ -861,27 +858,6 @@ def get_blog_posts_old(request):
|
||||
|
||||
|
||||
|
||||
@login_required()
|
||||
def get_testscript(request,id):
|
||||
row = get_workout_permitted(request.user,id)
|
||||
r = getrower(request.user)
|
||||
|
||||
object = {
|
||||
"script":"""
|
||||
<div id="id_script">
|
||||
<script>alert("hi")</script>
|
||||
</div>
|
||||
""",
|
||||
"div":"""
|
||||
<div id="id_div">
|
||||
Hoi
|
||||
</div>
|
||||
"""
|
||||
}
|
||||
|
||||
|
||||
return JSONResponse([object,object])
|
||||
|
||||
@login_required()
|
||||
def session_jobs_view(request):
|
||||
taskstatus = get_stored_tasks_status(request)
|
||||
@@ -990,10 +966,6 @@ from rowers.utils import (
|
||||
|
||||
import rowers.datautils as datautils
|
||||
|
||||
from rowers.models import (
|
||||
checkworkoutuser,checkaccessuser,checkviewworkouts,checkworkoutuserview
|
||||
)
|
||||
|
||||
# Check if a user is a Coach member
|
||||
def iscoachmember(user):
|
||||
if not user.is_anonymous:
|
||||
@@ -1044,21 +1016,7 @@ def hasplannedsessions(user):
|
||||
return result
|
||||
|
||||
from rowers.utils import ProcessorCustomerError
|
||||
from rowers.utils import isprorower
|
||||
|
||||
# Check if a user is a Pro member
|
||||
def ispromember(user):
|
||||
if user and not user.is_anonymous:
|
||||
try:
|
||||
r = Rower.objects.get(user=user)
|
||||
except Rower.DoesNotExist:
|
||||
r = Rower(user=user)
|
||||
r.save()
|
||||
|
||||
result = user.is_authenticated and isprorower(r)
|
||||
else:
|
||||
result = False
|
||||
return result
|
||||
|
||||
# More User/Rower utils
|
||||
def add_defaultfavorites(r):
|
||||
|
||||
@@ -64,8 +64,10 @@ def workout_video_view_mini(request,id=''):
|
||||
else:
|
||||
mode = 'erg'
|
||||
|
||||
|
||||
|
||||
if request.user.is_authenticated:
|
||||
mayedit = checkworkoutuser(request.user,w) and isprorower(request.user.rower)
|
||||
mayedit = is_workout_user(request.user,w) and is_promember(request.user)
|
||||
rower = request.user.rower
|
||||
else:
|
||||
mayedit = False
|
||||
@@ -176,7 +178,7 @@ def workout_video_view(request,id=''):
|
||||
mode = 'erg'
|
||||
|
||||
if request.user.is_authenticated:
|
||||
mayedit = checkworkoutuser(request.user,w) and isprorower(request.user.rower)
|
||||
mayedit = is_promember(request.user) and is_workout_user(request.user,w)
|
||||
rower = request.user.rower
|
||||
else:
|
||||
mayedit = False
|
||||
@@ -271,20 +273,18 @@ def workout_video_view(request,id=''):
|
||||
|
||||
|
||||
# Create a video compared with data
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans/",
|
||||
message="This functionality requires a Pro plan or higher",
|
||||
redirect_field_name=None)
|
||||
def workout_video_create_view(request,id=0):
|
||||
# get workout
|
||||
w = get_workout_permitted(request.user,id)
|
||||
w = get_workout_by_opaqueid(request,id)
|
||||
if w.workouttype in mytypes.otwtypes:
|
||||
mode = 'water'
|
||||
else:
|
||||
mode = 'erg'
|
||||
|
||||
|
||||
mayedit = checkworkoutuser(request.user,w) and isprorower(request.user.rower)
|
||||
|
||||
# get video ID and offset
|
||||
if request.method == 'POST':
|
||||
form = VideoAnalysisCreateForm(request.POST)
|
||||
@@ -457,12 +457,10 @@ def workout_forcecurve_view(request,id=0,workstrokesonly=False):
|
||||
})
|
||||
|
||||
# Switch from GPS to Impeller (only for SpeedCoach 2, if impeller data)
|
||||
@login_required
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def otw_use_impeller(request,id=0):
|
||||
w = get_workout(id)
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
row = rdata(w.csvfilename)
|
||||
success = row.use_impellerdata()
|
||||
@@ -481,12 +479,10 @@ def otw_use_impeller(request,id=0):
|
||||
|
||||
|
||||
# Switch from Impeller to GPS (only for SpeedCoach 2, if impeller data)
|
||||
@login_required
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def otw_use_gps(request,id=0):
|
||||
w = get_workout(id)
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
row = rdata(w.csvfilename)
|
||||
success = row.use_gpsdata()
|
||||
@@ -748,20 +744,13 @@ def fitness_metric_view(request,mode='rower',days=42):
|
||||
return HttpResponse("job queued")
|
||||
|
||||
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
|
||||
redirect_field_name=None)
|
||||
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"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
row.rankingpiece = True
|
||||
row.save()
|
||||
|
||||
@@ -778,17 +767,10 @@ def workout_update_cp_view(request,id=0):
|
||||
|
||||
|
||||
# Reload the workout and calculate the summary from the stroke data (lapIDx)
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
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"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
filename = row.csvfilename
|
||||
rowdata = rdata(filename)
|
||||
if rowdata:
|
||||
@@ -1359,7 +1341,7 @@ def team_comparison_select(request,
|
||||
|
||||
if id:
|
||||
firstworkout = get_workout(id)
|
||||
if not checkworkoutuserview(request.user,firstworkout):
|
||||
if not is_workout_user(request.user,firstworkout):
|
||||
raise PermissionDenied("You are not allowed to use this workout")
|
||||
|
||||
firstworkoutquery = Workout.objects.filter(id=encoder.decode_hex(id))
|
||||
@@ -1791,7 +1773,7 @@ def workouts_view(request,message='',successmessage='',
|
||||
|
||||
|
||||
# check if access is allowed
|
||||
if not checkviewworkouts(request.user,r):
|
||||
if not is_rower_team_member(request.user,r):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
|
||||
@@ -2104,6 +2086,7 @@ def workout_fusion_list(request,id=0,message='',successmessage='',
|
||||
})
|
||||
|
||||
# Basic view of workout
|
||||
@permission_required('workout.view_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_view(request,id=0):
|
||||
request.session['referer'] = absolute(request)['PATH']
|
||||
|
||||
@@ -2112,19 +2095,13 @@ def workout_view(request,id=0):
|
||||
else:
|
||||
rower = None
|
||||
|
||||
try:
|
||||
row = Workout.objects.get(id=encoder.decode_hex(id))
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
|
||||
comments = WorkoutComment.objects.filter(workout=row)
|
||||
|
||||
aantalcomments = len(comments)
|
||||
|
||||
|
||||
if row.privacy == 'private' and not checkworkoutuser(request.user,row):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
|
||||
for i in g:
|
||||
try:
|
||||
@@ -2204,6 +2181,7 @@ def workout_view(request,id=0):
|
||||
|
||||
|
||||
# Resets stroke data to raw data (pace)
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
|
||||
redirect_field_name=None)
|
||||
@@ -2213,13 +2191,6 @@ def workout_undo_smoothenpace_view(
|
||||
row = get_workout(id)
|
||||
r = getrower(request.user)
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
filename = row.csvfilename
|
||||
row = rdata(filename)
|
||||
if row == 0:
|
||||
@@ -2243,6 +2214,7 @@ def workout_undo_smoothenpace_view(
|
||||
|
||||
|
||||
# Data smoothing of pace data
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality. If you are already a Pro user, please log in to access this functionality",
|
||||
redirect_field_name=None)
|
||||
@@ -2253,12 +2225,6 @@ def workout_smoothenpace_view(request,id=0,message="",successmessage=""):
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
filename = row.csvfilename
|
||||
row = rdata(filename)
|
||||
@@ -2373,6 +2339,7 @@ def workout_crewnerd_summary_view(request,id=0,message="",successmessage=""):
|
||||
'id':row.id})
|
||||
|
||||
# Get weather for given location and date/time
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
|
||||
redirect_field_name=None)
|
||||
@@ -2382,12 +2349,6 @@ def workout_downloadwind_view(request,id=0,
|
||||
row = get_workout(id)
|
||||
|
||||
f1 = row.csvfilename
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# create bearing
|
||||
rowdata = rdata(f1)
|
||||
@@ -2448,6 +2409,7 @@ def workout_downloadwind_view(request,id=0,
|
||||
return response
|
||||
|
||||
# Get weather for given location and date/time
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
|
||||
def workout_downloadmetar_view(request,id=0,
|
||||
airportcode=None,
|
||||
@@ -2455,12 +2417,7 @@ def workout_downloadmetar_view(request,id=0,
|
||||
row = get_workout(id)
|
||||
|
||||
f1 = row.csvfilename
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# create bearing
|
||||
rowdata = rdata(f1)
|
||||
@@ -2523,6 +2480,7 @@ def workout_downloadmetar_view(request,id=0,
|
||||
|
||||
|
||||
# Show form to update wind data
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
|
||||
def workout_wind_view(request,id=0,message="",successmessage=""):
|
||||
row = get_workout(id)
|
||||
@@ -2543,13 +2501,6 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
|
||||
|
||||
]
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
# get data
|
||||
f1 = row.csvfilename
|
||||
@@ -2659,17 +2610,13 @@ def workout_wind_view(request,id=0,message="",successmessage=""):
|
||||
|
||||
|
||||
# Show form to update River stream data (for river dwellers)
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",redirect_field_name=None)
|
||||
def workout_stream_view(request,id=0,message="",successmessage=""):
|
||||
row = get_workout(id)
|
||||
r = getrower(request.user)
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
# create interactive plot
|
||||
@@ -2745,23 +2692,15 @@ def workout_stream_view(request,id=0,message="",successmessage=""):
|
||||
'the_div':div})
|
||||
|
||||
# Form to set average crew weight and boat type, then run power calcs
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember, login_url="/rowers/paidplans",redirect_field_name=None)
|
||||
def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
|
||||
w = get_workout(id)
|
||||
r = getrower(request.user)
|
||||
|
||||
mayedit = 0
|
||||
if request.user == w.user.user:
|
||||
mayedit=1
|
||||
if checkworkoutuser(request.user,w):
|
||||
mayedit=1
|
||||
mayedit = 1
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
if request.method == 'POST':
|
||||
@@ -2879,15 +2818,11 @@ def workout_otwsetpower_view(request,id=0,message="",successmessage=""):
|
||||
'form':form,
|
||||
})
|
||||
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def instroke_view(request,id=0):
|
||||
w = get_workout(id)
|
||||
r = getrower(request.user)
|
||||
mayedit = 0
|
||||
if request.user == w.user.user:
|
||||
mayedit=1
|
||||
if checkworkoutuser(request.user,w):
|
||||
mayedit=1
|
||||
mayedit = 1
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
@@ -2909,12 +2844,7 @@ def instroke_view(request,id=0):
|
||||
g = GraphImage.objects.filter(workout=w).order_by("-creationdatetime")
|
||||
# check if user is owner of this workout
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
rowdata = rrdata(csvfile=w.csvfilename)
|
||||
try:
|
||||
@@ -2937,16 +2867,11 @@ def instroke_view(request,id=0):
|
||||
|
||||
|
||||
# generate instroke chart
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def instroke_chart(request,id=0,metric=''):
|
||||
w = get_workout(id)
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
message = "You are not allowed to edit this workout"
|
||||
messages.error(request,message)
|
||||
url = reverse('workouts_view')
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
rowdata = rrdata(csvfile=w.csvfilename)
|
||||
instrokemetrics = rowdata.get_instroke_columns()
|
||||
@@ -2995,14 +2920,12 @@ def instroke_chart(request,id=0,metric=''):
|
||||
|
||||
|
||||
# data explorer
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_data_view(request, id=0):
|
||||
|
||||
r = getrower(request.user)
|
||||
w = get_workout(id)
|
||||
|
||||
if not checkworkoutuser(request.user,w):
|
||||
raise PermissionDenied('Access Denied')
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
@@ -3100,7 +3023,7 @@ def workout_data_view(request, id=0):
|
||||
|
||||
|
||||
# Stats page
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_stats_view(request,id=0,message="",successmessage=""):
|
||||
|
||||
r = getrower(request.user)
|
||||
@@ -3109,7 +3032,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
||||
mayedit = 0
|
||||
if request.user == w.user.user:
|
||||
mayedit=1
|
||||
if checkworkoutuser(request.user,w):
|
||||
if is_workout_user(request.user,w):
|
||||
mayedit=1
|
||||
|
||||
breadcrumbs = [
|
||||
@@ -3135,8 +3058,7 @@ def workout_stats_view(request,id=0,message="",successmessage=""):
|
||||
|
||||
# prepare data frame
|
||||
datadf,row = dataprep.getrowdata_db(id=encoder.decode_hex(id))
|
||||
if (checkworkoutuserview(request.user,row)==False):
|
||||
raise PermissionDenied('Access Denied')
|
||||
|
||||
|
||||
datadf = dataprep.clean_df_stats(datadf,workstrokesonly=workstrokesonly,
|
||||
ignoreadvanced=False)
|
||||
@@ -3377,11 +3299,12 @@ def workout_workflow_config2_view(request,userid=0):
|
||||
|
||||
# Workflow View
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_workflow_view(request,id):
|
||||
request.session['referer'] = absolute(request)['PATH']
|
||||
request.session['lastworkout'] = id
|
||||
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
|
||||
row = get_workout_permittedview(request.user,id)
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
|
||||
r = getrower(request.user)
|
||||
result = request.user.is_authenticated and ispromember(request.user)
|
||||
@@ -3463,7 +3386,7 @@ def workout_workflow_view(request,id):
|
||||
})
|
||||
|
||||
# The famous flex chart
|
||||
@login_required()
|
||||
@permission_required('workout.view_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_flexchart3_view(request,*args,**kwargs):
|
||||
|
||||
try:
|
||||
@@ -3487,12 +3410,12 @@ def workout_flexchart3_view(request,*args,**kwargs):
|
||||
mayedit=0
|
||||
if not request.user.is_anonymous:
|
||||
r = getrower(request.user)
|
||||
result = request.user.is_authenticated and ispromember(request.user)
|
||||
result = ispromember(request.user)
|
||||
if result:
|
||||
promember=1
|
||||
if request.user == row.user.user:
|
||||
mayedit=1
|
||||
if checkworkoutuser(request.user,row):
|
||||
if is_workout_user(request.user,row):
|
||||
mayedit=1
|
||||
|
||||
workouttype = 'ote'
|
||||
@@ -3977,7 +3900,7 @@ def workout_comment_view(request,id=0):
|
||||
|
||||
|
||||
# The basic edit page
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
request.session[translation.LANGUAGE_SESSION_KEY] = USER_LANGUAGE
|
||||
request.session['referer'] = absolute(request)['PATH']
|
||||
@@ -3986,8 +3909,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
row = get_workout(id)
|
||||
|
||||
|
||||
if (checkworkoutuser(request.user,row)==False):
|
||||
raise PermissionDenied("Access denied")
|
||||
|
||||
|
||||
if request.user.rower.rowerplan == 'basic' and 'speedcoach2' in row.workoutsource:
|
||||
data = getsmallrowdata_db(['wash'],ids=[encoder.decode_hex(id)])
|
||||
@@ -4293,7 +4215,7 @@ def workout_map_view(request,id=0):
|
||||
|
||||
|
||||
# Image upload
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_uploadimage_view(request,id):
|
||||
is_ajax = False
|
||||
if request.is_ajax():
|
||||
@@ -4319,8 +4241,7 @@ def workout_uploadimage_view(request,id):
|
||||
|
||||
]
|
||||
|
||||
if not checkworkoutuser(request.user,w):
|
||||
raise PermissionDenied("You are not allowed to edit this workout")
|
||||
|
||||
|
||||
images = GraphImage.objects.filter(workout=w)
|
||||
|
||||
@@ -4398,7 +4319,7 @@ def workout_uploadimage_view(request,id):
|
||||
|
||||
|
||||
# Generic chart creation
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_add_chart_view(request,id,plotnr=1):
|
||||
|
||||
w = get_workout(id)
|
||||
@@ -4406,26 +4327,24 @@ def workout_add_chart_view(request,id,plotnr=1):
|
||||
|
||||
plotnr = int(plotnr)
|
||||
|
||||
if (checkworkoutuser(request.user,w)==False):
|
||||
raise PermissionDenied("You are not allowed add plots to this workout")
|
||||
|
||||
f1 = w.csvfilename[6:-4]
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
imagename = f1+timestr+'.png'
|
||||
u = w.user.user
|
||||
r = getrower(u)
|
||||
title = w.name
|
||||
res,jobid = uploads.make_plot(
|
||||
r,w,f1,w.csvfilename,'timeplot',title,plotnr=plotnr,
|
||||
imagename=imagename
|
||||
)
|
||||
if res == 0:
|
||||
messages.error(request,jobid)
|
||||
else:
|
||||
f1 = w.csvfilename[6:-4]
|
||||
timestr = strftime("%Y%m%d-%H%M%S")
|
||||
imagename = f1+timestr+'.png'
|
||||
u = w.user.user
|
||||
r = getrower(u)
|
||||
title = w.name
|
||||
res,jobid = uploads.make_plot(
|
||||
r,w,f1,w.csvfilename,'timeplot',title,plotnr=plotnr,
|
||||
imagename=imagename
|
||||
)
|
||||
if res == 0:
|
||||
messages.error(request,jobid)
|
||||
else:
|
||||
try:
|
||||
request.session['async_tasks'] += [(jobid,'make_plot')]
|
||||
except KeyError:
|
||||
request.session['async_tasks'] = [(jobid,'make_plot')]
|
||||
try:
|
||||
request.session['async_tasks'] += [(jobid,'make_plot')]
|
||||
except KeyError:
|
||||
request.session['async_tasks'] = [(jobid,'make_plot')]
|
||||
|
||||
|
||||
url = reverse(r.defaultlandingpage,kwargs={'id':encoder.encode_hex(w.id)})
|
||||
@@ -4437,12 +4356,13 @@ def workout_add_chart_view(request,id,plotnr=1):
|
||||
|
||||
|
||||
@login_required
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_toggle_ranking(request,id=0):
|
||||
is_ajax = False
|
||||
if request.is_ajax():
|
||||
is_ajax = True
|
||||
|
||||
row = get_workout_permitted(request.user,id)
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
|
||||
row.rankingpiece = not row.rankingpiece
|
||||
row.save()
|
||||
@@ -5237,9 +5157,9 @@ def graph_show_view(request,id):
|
||||
raise Http404("This workout doesn't exist")
|
||||
|
||||
# Restore original stroke data and summary
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_summary_restore_view(request,id,message="",successmessage=""):
|
||||
row = get_workout_permitted(request.user,id)
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
|
||||
s = ""
|
||||
# still here - this is a workout we may edit
|
||||
@@ -5287,11 +5207,12 @@ def workout_summary_restore_view(request,id,message="",successmessage=""):
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Split a workout
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
@user_passes_test(ispromember,login_url="/rowers/paidplans",
|
||||
message="This functionality requires a Pro plan or higher. If you are already a Pro user, please log in to access this functionality",
|
||||
redirect_field_name=None)
|
||||
def workout_split_view(request,id=0):
|
||||
row = get_workout_permitted(request.user,id)
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
|
||||
r = row.user
|
||||
|
||||
@@ -5398,8 +5319,8 @@ def workout_fusion_view(request,id1=0,id2=1):
|
||||
w1 = Workout.objects.get(id=id1)
|
||||
w2 = Workout.objects.get(id=id2)
|
||||
r = w1.user
|
||||
if (checkworkoutuser(request.user,w1)==False) or \
|
||||
(checkworkoutuser(request.user,w2)==False):
|
||||
if (is_workout_user(request.user,w1)==False) or \
|
||||
(is_workout_user(request.user,w2)==False):
|
||||
raise PermissionDenied("You are not allowed to use these workouts")
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("One of the workouts doesn't exist")
|
||||
@@ -5475,10 +5396,10 @@ def workout_fusion_view(request,id1=0,id2=1):
|
||||
|
||||
|
||||
# Edit the splits/summary
|
||||
@login_required()
|
||||
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
|
||||
def workout_summary_edit_view(request,id,message="",successmessage=""
|
||||
):
|
||||
row = get_workout_permitted(request.user,id)
|
||||
row = get_workout_by_opaqueid(request,id)
|
||||
r = getrower(request.user)
|
||||
breadcrumbs = [
|
||||
{
|
||||
@@ -6024,10 +5945,11 @@ def workout_code_delete_view(request,id=0):
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
class WorkoutDelete(DeleteView):
|
||||
class WorkoutDelete(PermissionRequiredMixin,DeleteView):
|
||||
login_required = True
|
||||
model = Workout
|
||||
template_name = 'workout_delete_confirm.html'
|
||||
permission_required = 'workout.change_workout'
|
||||
|
||||
# extra parameters
|
||||
def get_context_data(self, **kwargs):
|
||||
@@ -6082,7 +6004,6 @@ class WorkoutDelete(DeleteView):
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("One of the workouts doesn't exist")
|
||||
# obj = super(WorkoutDelete, self).get_object(*args, **kwargs)
|
||||
if not checkaccessuser(self.request.user,obj.user):
|
||||
raise PermissionDenied('You are not allowed to delete this workout')
|
||||
|
||||
|
||||
return obj
|
||||
|
||||
Reference in New Issue
Block a user