Merge branch 'release/v8.49'
This commit is contained in:
@@ -44,7 +44,8 @@ class RowerInline(admin.StackedInline):
|
||||
'polartoken','polartokenexpirydate',
|
||||
'polarrefreshtoken','polaruserid',
|
||||
'polar_auto_import',
|
||||
'stravatoken','stravaexportas','strava_auto_export',
|
||||
'stravatoken','stravatokenexpirydate','stravarefreshtoken',
|
||||
'stravaexportas','strava_auto_export',
|
||||
'strava_auto_import',
|
||||
'runkeepertoken','runkeeper_auto_export',)}),
|
||||
('Team',
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
from rowers.imports import *
|
||||
import datetime
|
||||
from requests import Request, Session
|
||||
|
||||
import mytypes
|
||||
from rowers.mytypes import otwtypes
|
||||
from iso8601 import ParseError
|
||||
|
||||
@@ -428,7 +428,7 @@ def createc2workoutdata(w):
|
||||
startdate = datetime.datetime.combine(w.date,datetime.time())
|
||||
|
||||
data = {
|
||||
"type": workouttype,
|
||||
"type": mytypes.c2mapping[workouttype],
|
||||
"date": w.startdatetime.isoformat(),
|
||||
"timezone": w.timezone,
|
||||
"distance": int(w.distance),
|
||||
@@ -684,6 +684,12 @@ def process_callback(request):
|
||||
# Uploading workout
|
||||
def workout_c2_upload(user,w):
|
||||
message = 'trying C2 upload'
|
||||
try:
|
||||
if mytypes.c2mapping[w.workouttype] is None:
|
||||
return "This workout type cannot be uploaded to Concept2",0
|
||||
except KeyError:
|
||||
return "This workout type cannot be uploaded to Concept2",0
|
||||
|
||||
thetoken = c2_open(user)
|
||||
|
||||
r = Rower.objects.get(user=user)
|
||||
@@ -755,7 +761,7 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
source='c2',splitdata=None,
|
||||
workoutsource='concept2'):
|
||||
try:
|
||||
workouttype = data['type']
|
||||
workouttype = mytypes.c2mappinginv[data['type']]
|
||||
except KeyError:
|
||||
workouttype = 'rower'
|
||||
|
||||
|
||||
@@ -741,6 +741,7 @@ def fetchcp(rower,theworkouts,table='cpdata'):
|
||||
def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
||||
avghr=None,avgpwr=None,avgspm=None,
|
||||
rankingpiece = False,
|
||||
duplicate=False,
|
||||
title='Manual entry',notes='',weightcategory='hwt'):
|
||||
|
||||
|
||||
@@ -813,6 +814,7 @@ def create_row_df(r,distance,duration,startdatetime,workouttype='rower',
|
||||
title=title,
|
||||
notes=notes,
|
||||
rankingpiece=rankingpiece,
|
||||
duplicate=duplicate,
|
||||
dosmooth=False,
|
||||
workouttype=workouttype,
|
||||
consistencychecks=False,
|
||||
@@ -829,6 +831,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
workoutsource='unknown',
|
||||
notes='', totaldist=0, totaltime=0,
|
||||
rankingpiece=False,
|
||||
duplicate=False,
|
||||
summary='',
|
||||
makeprivate=False,
|
||||
oarlength=2.89, inboard=0.88,
|
||||
@@ -999,13 +1002,30 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
maxhr = np.nan_to_num(maxhr)
|
||||
averagehr = np.nan_to_num(averagehr)
|
||||
|
||||
|
||||
t = datetime.datetime.strptime(duration,"%H:%M:%S.%f")
|
||||
delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)
|
||||
|
||||
workoutenddatetime = workoutstartdatetime+delta
|
||||
|
||||
# check for duplicate start times and duration
|
||||
ws = Workout.objects.filter(startdatetime=workoutstartdatetime,
|
||||
distance=totaldist,
|
||||
user=r)
|
||||
if (len(ws) != 0):
|
||||
message = "Warning: This workout probably already exists in the database"
|
||||
privacy = 'hidden'
|
||||
ws = Workout.objects.filter(user=r,date=workoutdate,duplicate=False).exclude(
|
||||
startdatetime__gt=workoutenddatetime
|
||||
)
|
||||
|
||||
ws2 = []
|
||||
|
||||
for ww in ws:
|
||||
t = ww.duration
|
||||
delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)
|
||||
enddatetime = ww.startdatetime+delta
|
||||
if enddatetime > workoutstartdatetime:
|
||||
ws2.append(ww)
|
||||
|
||||
|
||||
if (len(ws2) != 0):
|
||||
message = "Warning: This workout overlaps with an existing one and was marked as a duplicate"
|
||||
duplicate = True
|
||||
|
||||
|
||||
w = Workout(user=r, name=title, date=workoutdate,
|
||||
@@ -1014,6 +1034,7 @@ def save_workout_database(f2, r, dosmooth=True, workouttype='rower',
|
||||
duration=duration, distance=totaldist,
|
||||
weightcategory=r.weightcategory,
|
||||
starttime=workoutstarttime,
|
||||
duplicate=duplicate,
|
||||
workoutsource=workoutsource,
|
||||
rankingpiece=rankingpiece,
|
||||
forceunit=forceunit,
|
||||
|
||||
@@ -866,6 +866,8 @@ def update_agegroup_db(age,sex,weightcategory,wcdurations,wcpower,
|
||||
df['sex'] = sex
|
||||
df['age'] = age
|
||||
df['weightcategory'] = weightcategory
|
||||
df.replace([np.inf,-np.inf],np.nan,inplace=True)
|
||||
df.dropna(axis=0,inplace=True)
|
||||
|
||||
if debug:
|
||||
engine = create_engine(database_url_debug, echo=False)
|
||||
|
||||
@@ -94,7 +94,7 @@ def imports_open(user,oauth_data):
|
||||
tokenname = oauth_data['tokenname']
|
||||
refreshtokenname = oauth_data['refreshtokenname']
|
||||
expirydatename = oauth_data['expirydatename']
|
||||
if tokenexpirydate and timezone.now()>tokenexpirydate:
|
||||
if tokenexpirydate and timezone.now()+timedelta(seconds=3599)>tokenexpirydate:
|
||||
token = imports_token_refresh(
|
||||
user,
|
||||
tokenname,
|
||||
@@ -102,6 +102,15 @@ def imports_open(user,oauth_data):
|
||||
expirydatename,
|
||||
oauth_data,
|
||||
)
|
||||
elif tokenexpirydate is None and expirydatename is not None and 'strava' in expirydatename:
|
||||
token = imports_token_refresh(
|
||||
user,
|
||||
tokenname,
|
||||
refreshtokenname,
|
||||
expirydatename,
|
||||
oauth_data,
|
||||
)
|
||||
|
||||
|
||||
return token
|
||||
|
||||
@@ -156,7 +165,11 @@ def imports_do_refresh_token(refreshtoken,oauth_data,access_token=''):
|
||||
try:
|
||||
expires_in = token_json['expires_in']
|
||||
except KeyError:
|
||||
expires_in = 0
|
||||
try:
|
||||
expires_at = arrow.get(token_json['expires_at']).timestamp
|
||||
expires_in = expires_at - arrow.now().timestamp
|
||||
except KeyError:
|
||||
expires_in = 0
|
||||
try:
|
||||
refresh_token = token_json['refresh_token']
|
||||
except KeyError:
|
||||
@@ -267,6 +280,11 @@ def imports_token_refresh(user,tokenname,refreshtokenname,expirydatename,oauth_d
|
||||
|
||||
refreshtoken = getattr(r,refreshtokenname)
|
||||
|
||||
# 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]
|
||||
|
||||
@@ -237,8 +237,6 @@ def interactive_boxchart(datadf,fieldname,extratitle=''):
|
||||
|
||||
|
||||
def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
||||
if len(workouts) == 0:
|
||||
return "",""
|
||||
|
||||
dates = []
|
||||
dates_sorting = []
|
||||
@@ -316,7 +314,10 @@ def interactive_activitychart(workouts,startdate,enddate,stack='type'):
|
||||
label = CatAttr(columns=['date'], sort=False),
|
||||
xlabel='Date',
|
||||
ylabel='Time',
|
||||
title='Activity',
|
||||
title='Activity {d1} to {d2}'.format(
|
||||
d1 = startdate.strftime("%Y-%m-%d"),
|
||||
d2 = enddate.strftime("%Y-%m-%d"),
|
||||
),
|
||||
stack=stack,
|
||||
plot_width=350,
|
||||
plot_height=250,
|
||||
|
||||
@@ -653,6 +653,9 @@ class Rower(models.Model):
|
||||
polar_auto_import = models.BooleanField(default=False)
|
||||
|
||||
stravatoken = models.CharField(default='',max_length=200,blank=True,null=True)
|
||||
stravatokenexpirydate = models.DateTimeField(blank=True,null=True)
|
||||
stravarefreshtoken = models.CharField(default='',max_length=1000,
|
||||
blank=True,null=True)
|
||||
stravaexportas = models.CharField(default="Rowing",
|
||||
max_length=30,
|
||||
choices=stravatypes,
|
||||
@@ -2131,6 +2134,7 @@ class Workout(models.Model):
|
||||
privacy = models.CharField(default='visible',max_length=30,
|
||||
choices=privacychoices)
|
||||
rankingpiece = models.BooleanField(default=False,verbose_name='Ranking Piece')
|
||||
duplicate = models.BooleanField(default=False,verbose_name='Duplicate Workout')
|
||||
|
||||
def __unicode__(self):
|
||||
|
||||
@@ -2179,6 +2183,41 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||
if os.path.isfile(instance.csvfilename+'.gz'):
|
||||
os.remove(instance.csvfilename+'.gz')
|
||||
|
||||
@receiver(models.signals.post_delete,sender=Workout)
|
||||
def update_duplicates_on_delete(sender, instance, **kwargs):
|
||||
if instance.id:
|
||||
|
||||
duplicates = Workout.objects.filter(
|
||||
user=instance.user,date=instance.date,
|
||||
duplicate=True)
|
||||
|
||||
for d in duplicates:
|
||||
t = d.duration
|
||||
delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)
|
||||
workoutenddatetime = d.startdatetime+delta
|
||||
ws = Workout.objects.filter(
|
||||
user=d.user,date=d.date,
|
||||
).exclude(
|
||||
pk__in=[instance.pk,d.pk]
|
||||
).exclude(
|
||||
startdatetime__gt=workoutenddatetime
|
||||
)
|
||||
|
||||
|
||||
ws2 = []
|
||||
|
||||
for ww in ws:
|
||||
t = ww.duration
|
||||
delta = datetime.timedelta(hours=t.hour, minutes=t.minute, seconds=t.second)
|
||||
enddatetime = ww.startdatetime+delta
|
||||
if enddatetime > d.startdatetime:
|
||||
ws2.append(ww)
|
||||
|
||||
if len(ws2) == 0:
|
||||
d.duplicate=False
|
||||
d.save()
|
||||
|
||||
|
||||
# Delete stroke data from the database when a workout is deleted
|
||||
@receiver(models.signals.post_delete,sender=Workout)
|
||||
def auto_delete_strokedata_on_delete(sender, instance, **kwargs):
|
||||
@@ -2401,7 +2440,7 @@ class WorkoutForm(ModelForm):
|
||||
# duration = forms.TimeInput(format='%H:%M:%S.%f')
|
||||
class Meta:
|
||||
model = Workout
|
||||
fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece']
|
||||
fields = ['name','date','starttime','timezone','duration','distance','workouttype','boattype','weightcategory','notes','rankingpiece','duplicate']
|
||||
widgets = {
|
||||
'date': AdminDateWidget(),
|
||||
'notes': forms.Textarea,
|
||||
|
||||
@@ -10,9 +10,214 @@ workouttypes = (
|
||||
('coastal','Coastal'),
|
||||
('c-boat','Dutch C boat'),
|
||||
('churchboat','Finnish Church boat'),
|
||||
('Ride','Ride'),
|
||||
('Run','Run'),
|
||||
('NordicSki','NordicSki'),
|
||||
('Swim','Swim'),
|
||||
('Hike','Hike'),
|
||||
('Walk','Walk'),
|
||||
('Canoeing','Canoeing'),
|
||||
('Crossfit','Crossfit'),
|
||||
('StandUpPaddling','StandUpPaddling'),
|
||||
('IceSkate','IceSkate'),
|
||||
('WeightTraining','WeightTraining'),
|
||||
('InlineSkate','InlineSkate'),
|
||||
('Kayaking','Kayaking'),
|
||||
('Workout','Workout'),
|
||||
('other','Other'),
|
||||
)
|
||||
|
||||
stravamapping = {
|
||||
'water':'Rowing',
|
||||
'rower':'Rowing',
|
||||
'skierg':'NordicSki',
|
||||
'bike':'Ride',
|
||||
'dynamic':'Rowing',
|
||||
'slides':'Rowing',
|
||||
'paddle':'StandUpPaddling',
|
||||
'snow':'NordicSki',
|
||||
'coastal':'Rowing',
|
||||
'c-boat':'Rowing',
|
||||
'churchboat':'Rowing',
|
||||
'Ride':'Ride',
|
||||
'Run':'Run',
|
||||
'NordicSki':'NordicSki',
|
||||
'Swim':'Swim',
|
||||
'Hike':'Hike',
|
||||
'Walk':'Walk',
|
||||
'Canoeing':'Canoeing',
|
||||
'Crossfit':'Crossfit',
|
||||
'StandUpPaddling':'StandUpPaddling',
|
||||
'IceSkate':'IceSkate',
|
||||
'WeightTraining':'WeightTraining',
|
||||
'InlineSkate':'InlineSkate',
|
||||
'Kayaking':'Kayaking',
|
||||
'Workout':'Workout',
|
||||
'other':'Workout',
|
||||
|
||||
}
|
||||
|
||||
stmapping = {
|
||||
'water':'Rowing',
|
||||
'rower':'Rowing',
|
||||
'skierg':'Skiing:Nordic',
|
||||
'bike':'Cycling',
|
||||
'dynamic':'Rowing',
|
||||
'slides':'Rowing',
|
||||
'paddle':'Other:Paddling',
|
||||
'snow':'Skiing:Nordic',
|
||||
'coastal':'Rowing',
|
||||
'c-boat':'Rowing',
|
||||
'churchboat':'Rowing',
|
||||
'Ride':'Cycling',
|
||||
'Run':'Running',
|
||||
'NordicSki':'Skiing:Nordic',
|
||||
'Swim':'Swimming',
|
||||
'Hike':'Hiking',
|
||||
'RollerSki':'Other:RollerSki',
|
||||
'Walk':'Other:Walk',
|
||||
'Canoeing':'Other:Canoeing',
|
||||
'Crossfit':'Other:Crossfit',
|
||||
'StandUpPaddling':'Other:StandUpPaddling',
|
||||
'IceSkate':'Skating',
|
||||
'WeightTraining':'Other:WeightTraining',
|
||||
'InlineSkate':'Skating:InlineSkate',
|
||||
'Kayaking':'Other:Kayaking',
|
||||
'Workout':'Other:Workout',
|
||||
'other':'Other',
|
||||
|
||||
}
|
||||
|
||||
rkmapping = {
|
||||
'water':'Rowing',
|
||||
'rower':'Rowing',
|
||||
'skierg':'Cross-Country Skiing',
|
||||
'bike':'Cycling',
|
||||
'dynamic':'Rowing',
|
||||
'slides':'Rowing',
|
||||
'paddle':'Other:Paddling',
|
||||
'snow':'Cross-Country Skiing',
|
||||
'coastal':'Rowing',
|
||||
'c-boat':'Rowing',
|
||||
'churchboat':'Rowing',
|
||||
'Ride':'Cycling',
|
||||
'Run':'Running',
|
||||
'NordicSki':'Cross-Country Skiing',
|
||||
'Swim':'Swimming',
|
||||
'Hike':'Hiking',
|
||||
'Walk':'Walking',
|
||||
'Canoeing':'Other',
|
||||
'Crossfit':'CrossFit',
|
||||
'StandUpPaddling':'Other',
|
||||
'IceSkate':'Skating',
|
||||
'WeightTraining':'Other',
|
||||
'InlineSkate':'Skating',
|
||||
'Kayaking':'Other',
|
||||
'Workout':'Other',
|
||||
'other':'Other',
|
||||
|
||||
}
|
||||
|
||||
polarmapping = {
|
||||
'water':'Rowing',
|
||||
'rower':'Rowing',
|
||||
'skierg':'Skiing',
|
||||
'bike':'Cycling',
|
||||
'dynamic':'Rowing',
|
||||
'slides':'Rowing',
|
||||
'paddle':'Other Outdoor',
|
||||
'snow':'Skiing',
|
||||
'coastal':'Rowing',
|
||||
'c-boat':'Rowing',
|
||||
'churchboat':'Rowing',
|
||||
'Ride':'Cycling',
|
||||
'Run':'Running',
|
||||
'NordicSki':'Skiing',
|
||||
'Swim':'Swimming',
|
||||
'Hike':'Hiking',
|
||||
'Walk':'Walking',
|
||||
'Canoeing':'Canoeing',
|
||||
'Crossfit':'Crossfit',
|
||||
'StandUpPaddling':'Other Outdoor',
|
||||
'IceSkate':'Skating',
|
||||
'WeightTraining':'Strength training',
|
||||
'InlineSkate':'Skating',
|
||||
'Kayaking':'Kayaking',
|
||||
'Workout':'Other Indoor',
|
||||
'other':'Other Indoor',
|
||||
|
||||
}
|
||||
|
||||
tpmapping = {
|
||||
'water':'rowing',
|
||||
'rower':'rowing',
|
||||
'skierg':'xc-ski',
|
||||
'bike':'bike',
|
||||
'dynamic':'rowing',
|
||||
'slides':'rowing',
|
||||
'paddle':'other',
|
||||
'snow':'xc-ski',
|
||||
'coastal':'rowing',
|
||||
'c-boat':'rowing',
|
||||
'churchboat':'rowing',
|
||||
'Ride':'cycling',
|
||||
'Run':'run',
|
||||
'NordicSki':'xc-ski',
|
||||
'Swim':'swim',
|
||||
'Hike':'other',
|
||||
'Walk':'walk',
|
||||
'Canoeing':'other',
|
||||
'Crossfit':'other',
|
||||
'StandUpPaddling':'other',
|
||||
'IceSkate':'other',
|
||||
'WeightTraining':'strength',
|
||||
'InlineSkate':'other',
|
||||
'Kayaking':'other',
|
||||
'Workout':'other',
|
||||
'other':'other',
|
||||
|
||||
}
|
||||
|
||||
c2mapping = {
|
||||
'water':'water',
|
||||
'rower':'rower',
|
||||
'skierg':'skierg',
|
||||
'bike':'bike',
|
||||
'dynamic':'dynamic',
|
||||
'slides':'slides',
|
||||
'paddle':'paddle',
|
||||
'snow':'snow',
|
||||
'coastal':'water',
|
||||
'c-boat':'water',
|
||||
'churchboat':'water',
|
||||
'Ride':'bike',
|
||||
'Run':None,
|
||||
'NordicSki':'snow',
|
||||
'Swim':None,
|
||||
'Hike':None,
|
||||
'Walk':None,
|
||||
'Canoeing':'paddle',
|
||||
'Crossfit':None,
|
||||
'StandUpPaddling':None,
|
||||
'IceSkate':None,
|
||||
'WeightTraining':None,
|
||||
'InlineSkate':None,
|
||||
'Kayaking':None,
|
||||
'Workout':None,
|
||||
'other':None,
|
||||
|
||||
}
|
||||
|
||||
c2mappinginv = {value:key for key,value in c2mapping.iteritems() if value is not None}
|
||||
|
||||
stravamappinginv = {value:key for key,value in stravamapping.iteritems() if value is not None}
|
||||
|
||||
stmappinginv = {value:key for key,value in stmapping.iteritems() if value is not None}
|
||||
|
||||
rkmappinginv = {value:key for key,value in rkmapping.iteritems() if value is not None}
|
||||
|
||||
polarmappinginv = {value:key for key,value in polarmapping.iteritems() if value is not None}
|
||||
|
||||
otwtypes = (
|
||||
'water',
|
||||
'coastal',
|
||||
@@ -20,6 +225,17 @@ otwtypes = (
|
||||
'churchboat'
|
||||
)
|
||||
|
||||
rowtypes = (
|
||||
'water',
|
||||
'rower',
|
||||
'dynamic',
|
||||
'slides',
|
||||
'coastal',
|
||||
'c-boat',
|
||||
'churchboat'
|
||||
)
|
||||
|
||||
|
||||
checktypes = [i[0] for i in workouttypes]
|
||||
|
||||
workoutsources = (
|
||||
|
||||
@@ -52,7 +52,7 @@ baseurl = 'https://polaraccesslink.com/v3'
|
||||
|
||||
|
||||
from utils import NoTokenError, custom_exception_handler
|
||||
|
||||
import mytypes
|
||||
|
||||
# Exchange access code for long-lived access token
|
||||
def get_token(code):
|
||||
|
||||
@@ -18,7 +18,7 @@ from stravalib.exc import ActivityUploadFailed,TimeoutExceeded
|
||||
from iso8601 import ParseError
|
||||
from utils import myqueue
|
||||
|
||||
|
||||
import mytypes
|
||||
import gzip
|
||||
|
||||
from rowsandall_app.settings import (
|
||||
@@ -40,11 +40,11 @@ oauth_data = {
|
||||
'autorization_uri': "https://www.strava.com/oauth/authorize",
|
||||
'content_type': 'application/json',
|
||||
'tokenname': 'stravatoken',
|
||||
'refreshtokenname': '',
|
||||
'expirydatename': '',
|
||||
'refreshtokenname': 'stravarefreshtoken',
|
||||
'expirydatename': 'stravatokenexpirydate',
|
||||
'bearer_auth': True,
|
||||
'base_url': "https://www.strava.com/oauth/token",
|
||||
'grant_type': None,
|
||||
'grant_type': 'refresh_token',
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,27 @@ oauth_data = {
|
||||
def get_token(code):
|
||||
return imports_get_token(code, oauth_data)
|
||||
|
||||
def strava_open(user):
|
||||
return imports_open(user, oauth_data)
|
||||
|
||||
def do_refresh_token(refreshtoken):
|
||||
return imports_do_refresh_token(refreshtoken, oauth_data)
|
||||
|
||||
def rower_strava_token_refresh(user):
|
||||
r = Rower.objects.get(user=user)
|
||||
res = do_refresh_token(r.stravarefreshtoken)
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
expirydatetime = timezone.now()+timedelta(seconds=expires_in)
|
||||
|
||||
r.stravatoken = access_token
|
||||
r.stravatokenexpirydate = expirydatetime
|
||||
r.stravarefreshtoken = refresh_token
|
||||
r.save()
|
||||
|
||||
return r.stravatoken
|
||||
|
||||
# Make authorization URL including random string
|
||||
def make_authorization_url(request):
|
||||
return imports_make_authorization_url(oauth_data)
|
||||
@@ -62,6 +83,9 @@ def get_strava_workout_list(user,limit_n=0):
|
||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (r.stravatokenexpirydate is None or timezone.now()+timedelta(seconds=3599)>r.stravatokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
authorizationstring = str('Bearer ' + r.stravatoken)
|
||||
@@ -78,6 +102,7 @@ def get_strava_workout_list(user,limit_n=0):
|
||||
|
||||
s = requests.get(url,headers=headers,params=params)
|
||||
|
||||
|
||||
return s
|
||||
|
||||
|
||||
@@ -87,9 +112,12 @@ def get_strava_workouts(rower):
|
||||
if not isprorower(rower):
|
||||
return 0
|
||||
|
||||
res = get_strava_workout_list(rower.user,limit_n=10)
|
||||
try:
|
||||
thetoken = strava_open(rower.user)
|
||||
except NoTokenError:
|
||||
return 0
|
||||
|
||||
print res.status_code
|
||||
res = get_strava_workout_list(rower.user,limit_n=10)
|
||||
|
||||
if (res.status_code != 200):
|
||||
return 0
|
||||
@@ -135,9 +163,9 @@ def create_async_workout(alldata,user,stravaid,debug=False):
|
||||
distance = data['distance']
|
||||
stravaid = data['id']
|
||||
try:
|
||||
workouttype = data['type']
|
||||
workouttype = mytypes.stravamappinginv[data['type']]
|
||||
except:
|
||||
workouttype = 'rower'
|
||||
workouttype = 'other'
|
||||
|
||||
if workouttype.lower() == 'rowing':
|
||||
workouttype = 'rower'
|
||||
@@ -227,6 +255,9 @@ def get_workout(user,stravaid):
|
||||
if (r.stravatoken == '') or (r.stravatoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return custom_exception_handler(401,s)
|
||||
elif (r.stravatokenexpirydate is not None and timezone.now()>r.stravatokenexpirydate):
|
||||
s = "Token expired. Needs to refresh."
|
||||
return custom_exception_handler(401,s)
|
||||
else:
|
||||
# ready to fetch. Hurray
|
||||
fetchresolution = 'high'
|
||||
@@ -413,14 +444,15 @@ def add_workout_from_data(user,importid,data,strokedata,
|
||||
source='strava',splitdata=None,
|
||||
workoutsource='strava'):
|
||||
try:
|
||||
workouttype = data['type']
|
||||
workouttype = mytypes.stravamappinginv[data['type']]
|
||||
except KeyError:
|
||||
workouttype = 'rower'
|
||||
workouttype = 'other'
|
||||
|
||||
if workouttype.lower() == 'rowing':
|
||||
workouttype = 'rower'
|
||||
if 'summary_polyline' in data['map']:
|
||||
workouttype = 'water'
|
||||
|
||||
if 'summary_polyline' in data['map'] and workouttype=='rower':
|
||||
workouttype = 'water'
|
||||
|
||||
if workouttype not in [x[0] for x in Workout.workouttypes]:
|
||||
workouttype = 'other'
|
||||
|
||||
@@ -83,18 +83,15 @@
|
||||
$( document ).ready(function() {
|
||||
$('#id_workouttype').on('change', function(){
|
||||
if (
|
||||
$(this).val() == 'rower'
|
||||
|| $(this).val() == 'skierg'
|
||||
|| $(this).val() == 'dynamic'
|
||||
|| $(this).val() == 'slides'
|
||||
|| $(this).val() == 'paddle'
|
||||
|| $(this).val() == 'bike'
|
||||
|| $(this).val() == 'snow'
|
||||
$(this).val() == 'water'
|
||||
|| $(this).val() == 'coastal'
|
||||
|| $(this).val() == 'c-boat'
|
||||
|| $(this).val() == 'churchboat'
|
||||
) {
|
||||
$('#id_boattype').toggle(true);
|
||||
} else {
|
||||
$('#id_boattype').toggle(false);
|
||||
$('#id_boattype').val('1x');
|
||||
} else {
|
||||
$('#id_boattype').toggle(true);
|
||||
}
|
||||
});
|
||||
$('#id_workouttype').change();
|
||||
|
||||
@@ -16,18 +16,15 @@
|
||||
$( document ).ready(function() {
|
||||
$('#id_workouttype').on('change', function(){
|
||||
if (
|
||||
$(this).val() == 'rower'
|
||||
|| $(this).val() == 'skierg'
|
||||
|| $(this).val() == 'dynamic'
|
||||
|| $(this).val() == 'slides'
|
||||
|| $(this).val() == 'paddle'
|
||||
|| $(this).val() == 'bike'
|
||||
|| $(this).val() == 'snow'
|
||||
$(this).val() == 'water'
|
||||
|| $(this).val() == 'coastal'
|
||||
|| $(this).val() == 'c-boat'
|
||||
|| $(this).val() == 'churchboat'
|
||||
) {
|
||||
$('#id_boattype').toggle(true);
|
||||
} else {
|
||||
$('#id_boattype').toggle(false);
|
||||
$('#id_boattype').val('1x');
|
||||
} else {
|
||||
$('#id_boattype').toggle(true);
|
||||
}
|
||||
});
|
||||
$('#id_workouttype').change();
|
||||
|
||||
@@ -89,6 +89,9 @@
|
||||
</td>
|
||||
<td> {{ workout.distance }}m</td>
|
||||
<td> {{ workout.duration |durationprint:"%H:%M:%S.%f" }} </td>
|
||||
<td>
|
||||
<a href="/rowers/sessions/{{ psdict.id.1 }}/detach/{{ workout.id }}/">Detach</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
@@ -127,6 +130,10 @@
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
<p>
|
||||
<a href="/rowers/sessions/{{ psdict.id.1 }}/compare"
|
||||
title="Compare the workouts of all athletes who did this session">Compare Workouts</a>
|
||||
</p>
|
||||
</li>
|
||||
{% if coursescript %}
|
||||
<li class="grid_2">
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
<li class="grid_2 maxheight">
|
||||
{% if workouts %}
|
||||
<form enctype="multipart/form-data"
|
||||
action="/rowers/multi-compare"
|
||||
action="/rowers/multi-compare/"
|
||||
method="post">
|
||||
|
||||
<input type="checkbox" onClick="toggle(this)" /> Toggle All<br/>
|
||||
|
||||
@@ -76,25 +76,22 @@
|
||||
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
|
||||
<script>
|
||||
$( document ).ready(function() {
|
||||
$('#id_workouttype').on('change', function(){
|
||||
if (
|
||||
$(this).val() == 'rower'
|
||||
|| $(this).val() == 'skierg'
|
||||
|| $(this).val() == 'dynamic'
|
||||
|| $(this).val() == 'slides'
|
||||
|| $(this).val() == 'paddle'
|
||||
|| $(this).val() == 'bike'
|
||||
|| $(this).val() == 'snow'
|
||||
) {
|
||||
$('#id_boattype').toggle(false);
|
||||
$('#id_boattype').val('1x');
|
||||
} else {
|
||||
$('#id_boattype').toggle(true);
|
||||
}
|
||||
});
|
||||
$('#id_workouttype').change();
|
||||
});
|
||||
$( document ).ready(function() {
|
||||
$('#id_workouttype').on('change', function(){
|
||||
if (
|
||||
$(this).val() == 'water'
|
||||
|| $(this).val() == 'coastal'
|
||||
|| $(this).val() == 'c-boat'
|
||||
|| $(this).val() == 'churchboat'
|
||||
) {
|
||||
$('#id_boattype').toggle(true);
|
||||
} else {
|
||||
$('#id_boattype').toggle(false);
|
||||
$('#id_boattype').val('1x');
|
||||
}
|
||||
});
|
||||
$('#id_workouttype').change();
|
||||
});
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -23,18 +23,15 @@
|
||||
$( document ).ready(function() {
|
||||
$('#id_workouttype').on('change', function(){
|
||||
if (
|
||||
$(this).val() == 'rower'
|
||||
|| $(this).val() == 'skierg'
|
||||
|| $(this).val() == 'dynamic'
|
||||
|| $(this).val() == 'slides'
|
||||
|| $(this).val() == 'paddle'
|
||||
|| $(this).val() == 'snow'
|
||||
|| $(this).val() == 'bike'
|
||||
$(this).val() == 'water'
|
||||
|| $(this).val() == 'coastal'
|
||||
|| $(this).val() == 'c-boat'
|
||||
|| $(this).val() == 'churchboat'
|
||||
) {
|
||||
$('#id_boattype').toggle(true);
|
||||
} else {
|
||||
$('#id_boattype').toggle(false);
|
||||
$('#id_boattype').val('1x');
|
||||
} else {
|
||||
$('#id_boattype').toggle(true);
|
||||
}
|
||||
});
|
||||
$('#id_workouttype').change();
|
||||
|
||||
@@ -321,6 +321,15 @@ def mocked_requests(*args, **kwargs):
|
||||
return MockResponse(json_data,200)
|
||||
elif stravasummarytester.match(args[0]):
|
||||
return MockResponse(stravasummaryjson,200)
|
||||
elif 'token' in args[0]:
|
||||
json_data = {
|
||||
"token_type": "Bearer",
|
||||
"access_token": "987654321234567898765432123456789",
|
||||
"refresh_token": "1234567898765432112345678987654321",
|
||||
"expires_at": 1531385304
|
||||
}
|
||||
return MockResponse(json_data,200)
|
||||
|
||||
|
||||
if c2tester.match(args[0]):
|
||||
if c2uploadtester.match(args[0]):
|
||||
@@ -403,7 +412,7 @@ class C2Objects(DjangoTestCase):
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='On-water',
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
@@ -574,7 +583,7 @@ class STObjects(DjangoTestCase):
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='On-water',
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
@@ -690,7 +699,7 @@ class RunKeeperObjects(DjangoTestCase):
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='On-water',
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
@@ -782,7 +791,7 @@ class UAObjects(DjangoTestCase):
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='On-water',
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
@@ -882,7 +891,7 @@ class TPObjects(DjangoTestCase):
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
self.w = Workout.objects.create(
|
||||
name='testworkout',workouttype='On-water',
|
||||
name='testworkout',workouttype='water',
|
||||
user=self.r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
startdatetime=row.rowdatetime,
|
||||
@@ -1074,7 +1083,7 @@ class WorkoutTests(TestCase):
|
||||
)
|
||||
nu = datetime.datetime.now()
|
||||
self.w = Workout.objects.create(name='testworkout',
|
||||
workouttype='On-water',
|
||||
workouttype='water',
|
||||
user=self.r,date=nu.strftime('%Y-%m-%d'),
|
||||
starttime=nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000)
|
||||
@@ -1092,7 +1101,7 @@ class C2Tests(TestCase):
|
||||
gdproptindate=timezone.now()
|
||||
)
|
||||
self.nu = datetime.datetime.now()
|
||||
self.w = Workout.objects.create(name='testworkout',workouttype='On-water',
|
||||
self.w = Workout.objects.create(name='testworkout',workouttype='water',
|
||||
user=r,date=nu.strftime('%Y-%m-%d'),
|
||||
starttime=nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000)
|
||||
@@ -1255,7 +1264,7 @@ class DataTest(TestCase):
|
||||
workoutdate = row.rowdatetime.strftime('%Y-%m-%d')
|
||||
workoutstarttime = row.rowdatetime.strftime('%H:%M:%S')
|
||||
|
||||
w = Workout.objects.create(name='testworkout',workouttype='On-water',
|
||||
w = Workout.objects.create(name='testworkout',workouttype='water',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=workoutstarttime,
|
||||
duration=duration,distance=totaldist,
|
||||
@@ -1999,7 +2008,7 @@ class URLTests(TestCase):
|
||||
self.nu = datetime.datetime.now()
|
||||
filename = 'rowers/testdata/testdata.csv'
|
||||
self.wotw = Workout.objects.create(name='testworkout',
|
||||
workouttype='On-water',
|
||||
workouttype='water',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=self.nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
@@ -2241,7 +2250,7 @@ class subroutinetests(TestCase):
|
||||
nu = datetime.datetime.now()
|
||||
filename = 'rowers/testdata/testdata.csv'
|
||||
self.w = Workout.objects.create(name='testworkout',
|
||||
workouttype='On-water',
|
||||
workouttype='water',
|
||||
user=r,date=nu.strftime('%Y-%m-%d'),
|
||||
starttime=nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
@@ -2266,7 +2275,7 @@ class PlotTests(TestCase):
|
||||
self.nu = datetime.datetime.now()
|
||||
filename = 'rowers/testdata/testdata.csv'
|
||||
self.wotw = Workout.objects.create(name='testworkout',
|
||||
workouttype='On-water',
|
||||
workouttype='water',
|
||||
user=r,date=self.nu.strftime('%Y-%m-%d'),
|
||||
starttime=self.nu.strftime('%H:%M:%S'),
|
||||
duration="0:55:00",distance=8000,
|
||||
|
||||
@@ -342,8 +342,9 @@ urlpatterns = [
|
||||
url(r'^workout/(?P<id>\d+)/runkeeperuploadw/$',views.workout_runkeeper_upload_view),
|
||||
url(r'^workout/(?P<id>\d+)/underarmouruploadw/$',views.workout_underarmour_upload_view),
|
||||
url(r'^workout/(?P<id>\d+)/tpuploadw/$',views.workout_tp_upload_view),
|
||||
url(r'^multi-compare/workout/(?P<id>\d+)$',views.multi_compare_view),
|
||||
url(r'^multi-compare$',views.multi_compare_view),
|
||||
url(r'^multi-compare/workout/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.multi_compare_view),
|
||||
url(r'^multi-compare/workout/(?P<id>\d+)/$',views.multi_compare_view),
|
||||
url(r'^multi-compare/$',views.multi_compare_view),
|
||||
url(r'^user-boxplot/user/(?P<userid>\d+)$',views.boxplot_view),
|
||||
url(r'^user-boxplot$',views.boxplot_view),
|
||||
url(r'^user-boxplot-data$',views.boxplot_view_data),
|
||||
@@ -486,12 +487,16 @@ urlpatterns = [
|
||||
url(r'^sessions/multicreate/user/(?P<userid>\d+)/$',
|
||||
views.plannedsession_multicreate_view),
|
||||
url(r'^sessions/(?P<id>\d+)/edit/$',views.plannedsession_edit_view),
|
||||
url(r'^sessions/(?P<id>\d+)/compare/$',views.plannedsession_compare_view),
|
||||
url(r'^sessions/(?P<id>\d+)/compare/user/(?P<userid>\d+)/$',views.plannedsession_compare_view),
|
||||
url(r'^sessions/(?P<id>\d+)/edit/user/(?P<userid>\d+)/$',views.plannedsession_edit_view),
|
||||
url(r'^sessions/(?P<id>\d+)/clone/user/(?P<userid>\d+)/$',views.plannedsession_clone_view),
|
||||
url(r'^sessions/(?P<id>\d+)/clone/$',views.plannedsession_clone_view),
|
||||
url(r'^sessions/(?P<id>\d+)$',views.plannedsession_view,
|
||||
url(r'^sessions/(?P<psid>\d+)/detach/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.plannedsession_detach_view),
|
||||
url(r'^sessions/(?P<psid>\d+)/detach/(?P<id>\d+)/$',views.plannedsession_detach_view),
|
||||
url(r'^sessions/(?P<id>\d+)/$',views.plannedsession_view,
|
||||
name='plannedsession_view'),
|
||||
url(r'^sessions/(?P<id>\d+)/user/(?P<userid>\d+)$',views.plannedsession_view,
|
||||
url(r'^sessions/(?P<id>\d+)/user/(?P<userid>\d+)/$',views.plannedsession_view,
|
||||
name='plannedsession_view'),
|
||||
url(r'^sessions/(?P<pk>\d+)/deleteconfirm$',views.PlannedSessionDelete.as_view()),
|
||||
url(r'^sessions/(?P<pk>\d+)/delete$',views.PlannedSessionDelete.as_view(),
|
||||
|
||||
312
rowers/views.py
312
rowers/views.py
@@ -116,6 +116,7 @@ from sporttracksstuff import sporttracks_open
|
||||
from tpstuff import tp_open
|
||||
from iso8601 import ParseError
|
||||
import stravastuff
|
||||
from stravastuff import strava_open
|
||||
import polarstuff
|
||||
import sporttracksstuff
|
||||
import underarmourstuff
|
||||
@@ -1732,6 +1733,12 @@ def workout_strava_upload_view(request,id=0):
|
||||
message = ""
|
||||
r = getrower(request.user)
|
||||
res = -1
|
||||
|
||||
try:
|
||||
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/")
|
||||
@@ -1748,11 +1755,16 @@ def workout_strava_upload_view(request,id=0):
|
||||
newnotes = w.notes+'\n from '+w.workoutsource+' via rowsandall.com'
|
||||
except TypeError:
|
||||
newnotes = 'from '+w.workoutsource+' via rowsandall.com'
|
||||
activity_type = r.stravaexportas
|
||||
res,mes = stravastuff.handle_stravaexport(f,w.name,
|
||||
r.stravatoken,
|
||||
description=newnotes,
|
||||
activity_type=activity_type)
|
||||
if w.workouttype in mytypes.rowtypes:
|
||||
activity_type = r.stravaexportas
|
||||
else:
|
||||
activity_type = mytypes.stravamapping[w.workouttype]
|
||||
|
||||
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
|
||||
@@ -2421,15 +2433,22 @@ def rower_process_stravacallback(request):
|
||||
|
||||
if res[0]:
|
||||
access_token = res[0]
|
||||
expires_in = res[1]
|
||||
refresh_token = res[2]
|
||||
|
||||
expirydatetime = timezone.now()+datetime.timedelta(seconds=expires_in)
|
||||
|
||||
r = getrower(request.user)
|
||||
r.stravatoken = access_token
|
||||
r.stravatokenexpirydate = expirydatetime
|
||||
r.stravarefreshtoken = refresh_token
|
||||
|
||||
r.save()
|
||||
|
||||
successmessage = "Tokens stored. Good to go"
|
||||
messages.info(request,successmessage)
|
||||
return imports_view(request)
|
||||
url = reverse(workouts_view)
|
||||
return HttpResponseRedirect(url)
|
||||
else:
|
||||
message = "Something went wrong with the Strava authorization"
|
||||
messages.error(request,message)
|
||||
@@ -3373,6 +3392,11 @@ def addmanual_view(request):
|
||||
except KeyError:
|
||||
rankingpiece = False
|
||||
|
||||
try:
|
||||
duplicate = form.cleaned_data['duplicate']
|
||||
except KeyError:
|
||||
duplicate = False
|
||||
|
||||
if private:
|
||||
privacy = 'private'
|
||||
else:
|
||||
@@ -3395,6 +3419,7 @@ def addmanual_view(request):
|
||||
avghr=avghr,
|
||||
rankingpiece=rankingpiece,
|
||||
avgpwr=avgpwr,
|
||||
duplicate=duplicate,
|
||||
avgspm=avgspm,
|
||||
title = name,
|
||||
notes=notes,
|
||||
@@ -5325,6 +5350,8 @@ def team_comparison_select(request,
|
||||
r = getrequestrower(request,userid=userid)
|
||||
requestrower = getrower(request.user)
|
||||
|
||||
request.session.pop('ps',None)
|
||||
|
||||
if 'waterboattype' in request.session:
|
||||
waterboattype = request.session['waterboattype']
|
||||
else:
|
||||
@@ -5521,10 +5548,53 @@ def team_comparison_select(request,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
|
||||
@login_required()
|
||||
def plannedsession_compare_view(request,id=0,userid=0):
|
||||
r = getrequestrower(request,userid=userid)
|
||||
|
||||
try:
|
||||
ps = PlannedSession.objects.get(id=id)
|
||||
except PlannedSession.DoesNotExist:
|
||||
raise Http404("Planned session does not exist")
|
||||
|
||||
m = ps.manager
|
||||
mm = m.rower
|
||||
|
||||
if ps.manager != request.user:
|
||||
if r.rowerplan == 'coach':
|
||||
teams = Team.objects.filter(manager=request.user)
|
||||
members = Rower.objects.filter(team__in=teams).distinct()
|
||||
teamusers = [m.user for m in members]
|
||||
if ps.manager not in teamusers:
|
||||
raise PermissionDenied("You do not have access to this session")
|
||||
elif r not in ps.rower.all():
|
||||
raise PermissionDenied("You do not have access to this session")
|
||||
|
||||
workouts = Workout.objects.filter(plannedsession=ps)
|
||||
|
||||
ids = [int(w.id) for w in workouts]
|
||||
|
||||
labeldict = {
|
||||
int(w.id): w.__unicode__() for w in workouts
|
||||
}
|
||||
|
||||
xparam = 'time'
|
||||
yparam = 'hr'
|
||||
plottype = 'line'
|
||||
|
||||
request.session['ids'] = ids
|
||||
request.session['xparam'] = xparam
|
||||
request.session['yparam'] = yparam
|
||||
request.session['plottype'] = plottype
|
||||
request.session['ps'] = ps.id
|
||||
|
||||
url = reverse(multi_compare_view,kwargs={'userid':userid,'id':ids[0]})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Team comparison
|
||||
@login_required()
|
||||
def multi_compare_view(request,id=0):
|
||||
def multi_compare_view(request,id=0,userid=0):
|
||||
promember=0
|
||||
if not request.user.is_anonymous():
|
||||
r = getrower(request.user)
|
||||
@@ -5549,45 +5619,9 @@ def multi_compare_view(request,id=0):
|
||||
int(w.id): w.__unicode__() for w in workouts
|
||||
}
|
||||
|
||||
res = interactive_multiple_compare_chart(ids,xparam,yparam,
|
||||
promember=promember,
|
||||
plottype=plottype,
|
||||
labeldict=labeldict)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
errormessage = res[3]
|
||||
if errormessage != '':
|
||||
messages.error(request,errormessage)
|
||||
|
||||
r = getrower(request.user)
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url':'/rowers/list-workouts',
|
||||
'name':'Workouts'
|
||||
},
|
||||
{
|
||||
'url':reverse(team_comparison_select,kwargs={'teamid':teamid}),
|
||||
'name': 'Compare Select'
|
||||
},
|
||||
{
|
||||
'url':reverse(multi_compare_view),
|
||||
'name': 'Comparison Chart'
|
||||
}
|
||||
]
|
||||
return render(request,'multicompare.html',
|
||||
{'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
'rower':r,
|
||||
'active':'nav-workouts',
|
||||
'promember':promember,
|
||||
'teamid':teamid,
|
||||
'chartform':chartform,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
else:
|
||||
return HttpResponse("Form is not valid")
|
||||
if request.method == 'POST' and 'ids' in request.session:
|
||||
elif request.method == 'POST' and 'ids' in request.session:
|
||||
chartform = ChartParamChoiceForm(request.POST)
|
||||
if chartform.is_valid():
|
||||
xparam = chartform.cleaned_data['xparam']
|
||||
@@ -5601,42 +5635,24 @@ def multi_compare_view(request,id=0):
|
||||
labeldict = {
|
||||
int(w.id): w.__unicode__() for w in workouts
|
||||
}
|
||||
|
||||
res = interactive_multiple_compare_chart(ids,xparam,yparam,
|
||||
promember=promember,
|
||||
plottype=plottype,
|
||||
labeldict=labeldict)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
|
||||
r = getrower(request.user)
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url':'/rowers/list-workouts',
|
||||
'name':'Workouts'
|
||||
},
|
||||
{
|
||||
'url':reverse(team_comparison_select,kwargs={'teamid':teamid}),
|
||||
'name': 'Compare Select'
|
||||
},
|
||||
{
|
||||
'url':reverse(multi_compare_view),
|
||||
'name': 'Comparison Chart'
|
||||
elif 'ids' in request.session and 'plottype' in request.session:
|
||||
xparam = request.session['xparam']
|
||||
yparam = request.session['yparam']
|
||||
plottype = request.session['plottype']
|
||||
teamid = 0
|
||||
ids = request.session['ids']
|
||||
workouts = [Workout.objects.get(id=id) for id in ids]
|
||||
labeldict = {
|
||||
int(w.id): w.__unicode__() for w in workouts
|
||||
}
|
||||
chartform = ChartParamChoiceForm(
|
||||
initial = {
|
||||
'xparam':xparam,
|
||||
'yparam':yparam,
|
||||
'plottype':plottype,
|
||||
'teamid':teamid
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
return render(request,'multicompare.html',
|
||||
{'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
'rower':r,
|
||||
'active':'nav-workouts',
|
||||
'promember':promember,
|
||||
'teamid':teamid,
|
||||
'chartform':chartform,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
)
|
||||
|
||||
else:
|
||||
url = reverse(team_comparison_select,
|
||||
@@ -5645,6 +5661,76 @@ def multi_compare_view(request,id=0):
|
||||
'teamid':0})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
|
||||
res = interactive_multiple_compare_chart(ids,xparam,yparam,
|
||||
promember=promember,
|
||||
plottype=plottype,
|
||||
labeldict=labeldict)
|
||||
script = res[0]
|
||||
div = res[1]
|
||||
errormessage = res[3]
|
||||
if errormessage != '':
|
||||
messages.error(request,errormessage)
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url':'/rowers/list-workouts',
|
||||
'name':'Workouts'
|
||||
},
|
||||
{
|
||||
'url':reverse(team_comparison_select,kwargs={'teamid':teamid}),
|
||||
'name': 'Compare Select'
|
||||
},
|
||||
{
|
||||
'url':reverse(multi_compare_view),
|
||||
'name': 'Comparison Chart'
|
||||
}
|
||||
]
|
||||
|
||||
if 'ps' in request.session:
|
||||
ps = PlannedSession.objects.get(id=int(request.session['ps']))
|
||||
breadcrumbs = [
|
||||
{
|
||||
'url': reverse(plannedsessions_view,
|
||||
kwargs={'userid':userid}),
|
||||
'name': 'Sessions'
|
||||
},
|
||||
{
|
||||
'url':reverse(plannedsession_view,
|
||||
kwargs={
|
||||
'userid':userid,
|
||||
'id':ps.id,
|
||||
}
|
||||
),
|
||||
'name': ps.id
|
||||
},
|
||||
{
|
||||
'url':reverse(plannedsession_compare_view,
|
||||
kwargs={
|
||||
'userid':userid,
|
||||
'id':ps.id,
|
||||
}
|
||||
),
|
||||
'name': 'Compare'
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
return render(request,'multicompare.html',
|
||||
{'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'breadcrumbs':breadcrumbs,
|
||||
'rower':r,
|
||||
'active':'nav-workouts',
|
||||
'promember':promember,
|
||||
'teamid':teamid,
|
||||
'chartform':chartform,
|
||||
'teams':get_my_teams(request.user),
|
||||
})
|
||||
|
||||
|
||||
# Multi Flex Chart with Grouping
|
||||
@user_passes_test(ispromember,login_url="/rowers/promembership",
|
||||
message="This functionality requires a Pro plan or higher",
|
||||
@@ -6740,6 +6826,7 @@ def workouts_view(request,message='',successmessage='',
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
|
||||
|
||||
startdatestring = startdate.strftime('%Y-%m-%d')
|
||||
enddatestring = enddate.strftime('%Y-%m-%d')
|
||||
|
||||
@@ -6755,6 +6842,10 @@ def workouts_view(request,message='',successmessage='',
|
||||
except ValueError:
|
||||
activity_enddate = enddate
|
||||
|
||||
g_startdate = activity_startdate
|
||||
g_enddate = activity_enddate
|
||||
|
||||
|
||||
if teamid:
|
||||
try:
|
||||
theteam = Team.objects.get(id=teamid)
|
||||
@@ -6771,6 +6862,7 @@ def workouts_view(request,message='',successmessage='',
|
||||
team=theteam,
|
||||
startdatetime__gte=activity_startdate,
|
||||
startdatetime__lte=activity_enddate,
|
||||
duplicate=False,
|
||||
privacy='visible').order_by("-date", "-starttime")
|
||||
elif theteam.viewing == 'coachonly':
|
||||
workouts = Workout.objects.filter(
|
||||
@@ -6782,6 +6874,7 @@ def workouts_view(request,message='',successmessage='',
|
||||
team=theteam,user=r,
|
||||
startdatetime__gte=activity_startdate,
|
||||
enddatetime__lte=activity_enddate,
|
||||
duplicate=False,
|
||||
privacy='visible').order_by("-startdatetime")
|
||||
|
||||
|
||||
@@ -6797,6 +6890,7 @@ def workouts_view(request,message='',successmessage='',
|
||||
user=r,
|
||||
startdatetime__gte=activity_startdate,
|
||||
startdatetime__lte=activity_enddate,
|
||||
duplicate=False,
|
||||
privacy='visible').order_by("-startdatetime")
|
||||
else:
|
||||
theteam = None
|
||||
@@ -6806,9 +6900,18 @@ def workouts_view(request,message='',successmessage='',
|
||||
startdatetime__lte=enddate).order_by("-date", "-starttime")
|
||||
g_workouts = Workout.objects.filter(
|
||||
user=r,
|
||||
duplicate=False,
|
||||
startdatetime__gte=activity_startdate,
|
||||
startdatetime__lte=activity_enddate).order_by("-startdatetime")
|
||||
|
||||
|
||||
if len(g_workouts) == 0:
|
||||
g_workouts = Workout.objects.filter(
|
||||
user=r,
|
||||
startdatetime__gte=timezone.now()-timedelta(days=15)).order_by("-startdatetime")
|
||||
g_enddate = timezone.now()
|
||||
g_startdate = (timezone.now()-timedelta(days=15))
|
||||
|
||||
if rankingonly:
|
||||
workouts = workouts.exclude(rankingpiece=False)
|
||||
|
||||
@@ -6846,9 +6949,10 @@ def workouts_view(request,message='',successmessage='',
|
||||
else:
|
||||
stack='type'
|
||||
|
||||
|
||||
script,div = interactive_activitychart(g_workouts,
|
||||
activity_startdate,
|
||||
activity_enddate,
|
||||
g_startdate,
|
||||
g_enddate,
|
||||
stack=stack)
|
||||
|
||||
messages.info(request,successmessage)
|
||||
@@ -9845,6 +9949,11 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
except KeyError:
|
||||
rankingpiece =- Workout.objects.get(id=id).rankingpiece
|
||||
|
||||
try:
|
||||
duplicate = form.cleaned_data['duplicate']
|
||||
except KeyError:
|
||||
duplicate = Workout.objects.get(id=id).duplicate
|
||||
|
||||
if private:
|
||||
privacy = 'private'
|
||||
else:
|
||||
@@ -9884,6 +9993,7 @@ def workout_edit_view(request,id=0,message="",successmessage=""):
|
||||
row.duration = duration
|
||||
row.distance = distance
|
||||
row.boattype = boattype
|
||||
row.duplicate = duplicate
|
||||
row.privacy = privacy
|
||||
row.rankingpiece = rankingpiece
|
||||
row.timezone = thetimezone
|
||||
@@ -10268,6 +10378,11 @@ def workout_add_chart_view(request,id,plotnr=1):
|
||||
# The page where you select which Strava workout to import
|
||||
@login_required()
|
||||
def workout_stravaimport_view(request,message="",userid=0):
|
||||
try:
|
||||
thetoken = strava_open(request.user)
|
||||
except NoTokenError:
|
||||
return HttpResponseRedirect("/rowers/me/stravaauthorize/")
|
||||
|
||||
res = stravastuff.get_strava_workout_list(request.user)
|
||||
|
||||
r = getrequestrower(request,userid=userid)
|
||||
@@ -10277,6 +10392,7 @@ def workout_stravaimport_view(request,message="",userid=0):
|
||||
|
||||
r = getrower(request.user)
|
||||
|
||||
|
||||
if (res.status_code != 200):
|
||||
if (res.status_code == 401):
|
||||
r = getrower(request.user)
|
||||
@@ -10420,15 +10536,7 @@ def workout_runkeeperimport_view(request,message="",userid=0):
|
||||
def workout_underarmourimport_view(request,message="",userid=0):
|
||||
res = underarmourstuff.get_underarmour_workout_list(request.user)
|
||||
if (res.status_code != 200):
|
||||
if (res.status_code == 401):
|
||||
r = getrower(request.user)
|
||||
if (r.underarmourtoken == '') or (r.underarmourtoken is None):
|
||||
s = "Token doesn't exist. Need to authorize"
|
||||
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
|
||||
message = "Something went wrong in workout_underarmourimport_view"
|
||||
messages.error(request,message)
|
||||
url = reverse(workouts_view)
|
||||
return HttpResponseRedirect(url)
|
||||
return HttpResponseRedirect("/rowers/me/underarmourauthorize/")
|
||||
|
||||
workouts = []
|
||||
items = res.json()['_embedded']['workouts']
|
||||
@@ -10778,7 +10886,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
if strokedata.empty:
|
||||
distance = data['distance']
|
||||
c2id = data['id']
|
||||
workouttype = data['type']
|
||||
workouttype = mytypes.c2mappinginv[data['type']]
|
||||
verified = data['verified']
|
||||
startdatetime = iso8601.parse_date(data['date'])
|
||||
weightclass = data['weight_class']
|
||||
@@ -10827,7 +10935,7 @@ def workout_getimportview(request,externalid,source = 'c2'):
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# strokdata not empty - continue
|
||||
# strokedata not empty - continue
|
||||
id,message = importsources[source].add_workout_from_data(
|
||||
request.user,
|
||||
externalid,data,
|
||||
@@ -15302,6 +15410,26 @@ def plannedsession_edit_view(request,id=0,userid=0):
|
||||
})
|
||||
|
||||
|
||||
@login_required()
|
||||
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")
|
||||
|
||||
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})
|
||||
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
@login_required()
|
||||
def plannedsession_view(request,id=0,userid=0):
|
||||
|
||||
Reference in New Issue
Block a user