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