Private
Public Access
1
0

Merge branch 'release/v15.46'

This commit is contained in:
Sander Roosendaal
2021-02-09 18:48:44 +01:00
10 changed files with 263 additions and 24 deletions

View File

@@ -64,6 +64,20 @@ def process_webhook(notification):
f.write(timestamp+' '+notification.kind+'\n')
if notification.kind == 'subscription_charged_successfully':
return send_invoice(notification.subscription)
if notification.kind == 'subscription_canceled':
subscription = notification.subscription
rs = Rower.objects.filter(subscription_id=subscription.id)
if rs.count() == 0:
return 0
r = rs[0]
result,mesg,errormsg = cancel_subscription(r,subscription.id)
if result:
with open('braintreewebhooks.log','a') as f:
f.write('Subscription canceled: '+subscription.id+'\n')
return subscription.id
with open('braintreewebhooks.log','a') as f:
f.write('Could not cancel Subscription: '+subscription.id+'\n')
return 0
return 0
def send_invoice(subscription):

View File

@@ -1061,8 +1061,8 @@ def get_workoutsummaries(userid,startdate):
return df
def workout_goldmedalstandard(workout):
if workout.goldmedalstandard > 0:
def workout_goldmedalstandard(workout,reset=False):
if workout.goldmedalstandard > 0 and not reset:
return workout.goldmedalstandard,workout.goldmedalseconds
if workout.workouttype in rowtypes:
goldmedalstandard,goldmedalseconds = calculate_goldmedalstandard(workout.user,workout)
@@ -2255,6 +2255,7 @@ def new_workout_from_df(r, df,
boattype = parent.boattype
notes = parent.notes
summary = parent.summary
rpe = parent.rpe
if parent.privacy == 'hidden':
makeprivate = True
else:
@@ -2267,6 +2268,7 @@ def new_workout_from_df(r, df,
notes = ''
summary = ''
makeprivate = False
rpe = 0
if startdatetime == '':
startdatetime = timezone.now()
@@ -2305,6 +2307,7 @@ def new_workout_from_df(r, df,
inboard=inboard,
makeprivate=makeprivate,
dosmooth=False,
rpe=rpe,
consistencychecks=False)
job = myqueue(queuehigh,handle_calctrimp,id,csvfilename,r.ftp,r.sex,r.hrftp,r.max,r.rest)
@@ -3015,10 +3018,10 @@ def dataprep(rowdatadf, id=0, bands=True, barchart=True, otwpower=True,
def workout_trimp(w):
def workout_trimp(w,reset=False):
r = w.user
if w.trimp > 0:
if w.trimp > 0 and not reset:
return w.trimp,w.hrtss
r = w.user
@@ -3059,8 +3062,8 @@ def workout_trimp(w):
return 0,0
def workout_rscore(w):
if w.rscore > 0:
def workout_rscore(w,reset=False):
if w.rscore > 0 and not reset:
return w.rscore,w.normp
r = w.user

View File

@@ -230,7 +230,7 @@ def interactive_hr_piechart(df,rower,title,totalseconds=0):
if totalseconds == 0:
totalseconds = sumtimehr
hrzones = rower.hrzones
qry = 'hr < {ut2}'.format(ut2=rower.ut2)
qrydata = df.query(qry)
@@ -253,12 +253,12 @@ def interactive_hr_piechart(df,rower,title,totalseconds=0):
frac_an = totalseconds*df.query(qry)['deltat'].sum()/sumtimehr
datadict = {
'<ut2':frac_lut2,
'ut2': frac_ut2,
'ut1': frac_ut1,
'at': frac_at,
'tr': frac_tr,
'an': frac_an,
'<{ut2}'.format(ut2=hrzones[1]):frac_lut2,
'{ut2}'.format(ut2=hrzones[1]): frac_ut2,
'{ut1}'.format(ut1=hrzones[2]): frac_ut1,
'{at}'.format(at=hrzones[3]): frac_at,
'{tr}'.format(tr=hrzones[4]): frac_tr,
'{an}'.format(an=hrzones[5]): frac_an,
}
@@ -270,7 +270,15 @@ def interactive_hr_piechart(df,rower,title,totalseconds=0):
data = pd.Series(datadict).reset_index(name='value').rename(columns={'index':'zone'})
data['angle'] = data['value']/data['value'].sum() * 2*pi
data['color'] = colors
data['zone'] = ['<ut2','ut2','ut1','at','tr','an']
data['zone'] = [
'<{ut2}'.format(ut2=hrzones[1]),
'{ut2}'.format(ut2=hrzones[1]),
'{ut1}'.format(ut1=hrzones[2]),
'{at}'.format(at=hrzones[3]),
'{tr}'.format(tr=hrzones[4]),
'{an}'.format(an=hrzones[5])
]
data['totaltime'] = pd.Series([pretty_timedelta(v) for v in data['value']])

View File

@@ -21,11 +21,11 @@
<p>
{% if workout|previousworkout:rower.user %}
<a href="/rowers/workout/{{ workout|previousworkout:rower.user }}/flexchart/"
<a href="/rowers/workout/{{ workout|previousworkout:rower.user }}/flexchartstacked/"
title="Jump to preceding workout"><em>Previous</em></a>&nbsp;
{% endif %}
{% if workout|nextworkout:rower.user %}
<a href="/rowers/workout/{{ workout|nextworkout:rower.user }}/flexchart/"
<a href="/rowers/workout/{{ workout|nextworkout:rower.user }}/flexchartstacked/"
title="Jump to following workout"><em>Next</em></a>
{% endif %}
</p>

View File

@@ -7,7 +7,7 @@
{% block main %}
<h1>Split Workout</h1>
{% localtime on %}
<ul class="main-content">
<li class="grid_2">
@@ -17,19 +17,19 @@
{{ form.as_table }}
</table>
{% csrf_token %}
<input class="button green" type="submit" value="Split">
<input class="button" type="submit" value="Split">
</form>
</p>
</li>
<li class="grid_2">
<script src="https://cdn.pydata.org/bokeh/release/bokeh-2.2.3.min.js"></script>
<script async="true" type="text/javascript">
Bokeh.set_log_level("info");
</script>
{{ thescript |safe }}
{{ thediv |safe }}
<table width=100%>
@@ -67,7 +67,7 @@
</p>
</li>
</ul>
{% endblock %}

View File

@@ -17,8 +17,24 @@
</form>
</p>
</li>
<li class="grid_4">
{{ htmltable|safe }}
<li class="maxheight grid_4">
<table width=100% class="listtable shortpadded">
<th>
{% for i in cols %}
<td><strong>{{i}}</strong> <a href="/rowers/workout/{{ workout.id|encode }}/{{i}}/erase/">erase</a></td>
{% endfor %}
</th>
{% for row in data.values.tolist %}
<tr>
<td>
{{ forloop.counter0 }}
</td>
{% for value in row %}
<td>{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
</li>
</ul>

View File

@@ -0,0 +1,44 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Workout Data{% endblock %}
{% block main %}
<h1>Erase {{ column }} for {{ workout.name }}</h1>
<ul class="main-content">
<li class="grid_4">
<p>
This will erase column {{ column }} from the following workout:
</p>
<table width=100%>
<tr>
<th>Name:</th><td>{{ workout.name }}</td>
</tr><tr>
<th>Date:</th><td>{{ workout.date }}</td>
</tr><tr>
<th>Time:</th><td>{{ workout.starttime }}</td>
</tr><tr>
<th>Distance:</th><td>{{ workout.distance }}m</td>
</tr><tr>
<th>Duration:</th><td>{{ workout.duration |durationprint:"%H:%M:%S.%f" }}</td>
</tr>
</table>
<p>
The data cannot be recovered. If you are sure, please confirm.
</p>
</li>
<li class="grid_2">
<form action="" method="post">
{% csrf_token %}
<input type="submit" value="Confirm">
</form>
</li>
</ul>
{% endblock %}
{% block sidebar %}
{% include 'menu_workout.html' %}
{% endblock %}

View File

@@ -85,6 +85,10 @@ def icon(s):
except KeyError:
return 'fa-chart-line'
@register.filter
def datarows(data):
return range(len(data))
@register.filter
def adaptive(s):
u = s
@@ -519,11 +523,18 @@ def mayeditplan(obj,request):
return mayedit
@register.filter
def iterrows(df):
return df.iterrows()
@register.filter(name='times')
def times(number):
return range(number)
@register.simple_tag
def get_df_iloc(data,i,j):
return data.iloc(i,j)
@register.simple_tag
def get_field_id(id,s,form):
field_name = s+str(id)

View File

@@ -463,6 +463,8 @@ urlpatterns = [
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/stats/$',views.workout_stats_view,name='workout_stats_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/data/$',views.workout_data_view,
name='workout_data_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/(?P<column>\w+)/erase/$',views.workout_erase_column_view,
name='workout_erase_column_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower-confirm/$',views.remove_power_confirm_view,
name='remove_power_confirm_view'),
re_path(r'^workout/(?P<id>\b[0-9A-Fa-f]+\b)/zeropower/$',views.remove_power_view,

View File

@@ -3166,6 +3166,145 @@ def instroke_chart(request,id=0,metric=''):
return HttpResponseRedirect(url)
# erase column
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
def workout_erase_column_view(request, id=0,column=''):
r = getrower(request.user)
w = get_workoutuser(id,request)
protected = ['time','pace','velo','cumdist','ftime','fpace',]
if column in protected:
messages.error(request,'You cannot erase this protected column')
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
try:
data = dataprep.getsmallrowdata_db([column],ids=[w.id])
except:
messages.error(request,'Invalid column')
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
try:
cdata = data[column]
except KeyError:
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
if not column:
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
if request.method == 'POST':
mms = {}
for m in rowingmetrics:
mms[m[0]] = m[1]
try:
defaultvalue = mms[column]['default']
except KeyError:
if not mms[column]['null']:
messages.error(request,'You cannot erase this protected column')
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
defaultvalue = 0
try:
columnl = dataprep.columndict[column]
except KeyError:
messages.error(request,'You cannot erase this column')
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
row,workout = dataprep.getrowdata(id=w.id)
row.df[columnl] = defaultvalue
os.remove(w.csvfilename+'.gz')
row.write_csv(w.csvfilename,gzip=True)
row,workout = dataprep.getrowdata(id=w.id)
datadf = dataprep.dataprep(row.df,id=w.id)
if column == 'hr':
w.hrtss = 0
w.trimp = 0
w.save()
if column == 'power':
w.rscore = 0
w.normp = 0
w.goldmedalstandard = -1
w.goldmedalseconds = 0
w.save()
trimp,hrtss = dataprep.workout_trimp(w,reset=True)
rscore,normp = dataprep.workout_rscore(w,reset=True)
goldstandard,goldstandardduration = dataprep.workout_goldmedalstandard(w,reset=True)
messages.info(request,'Data for column '+column+' have been erased')
url = reverse('workout_data_view',kwargs={
'id':encoder.encode_hex(w.id)
})
return HttpResponseRedirect(url)
breadcrumbs = [
{
'url':'/rowers/list-workouts/',
'name':'Workouts'
},
{
'url':get_workout_default_page(request,id),
'name': w.name
},
{
'url':reverse('workout_data_view',kwargs={'id':id}),
'name': 'Data Explorer'
}
]
return render(request,
'workout_erase_column.html',
{
'column':column,
'teams':get_my_teams(request.user),
'workout': w,
'breadcrumbs': breadcrumbs,
}
)
# data explorer
@permission_required('workout.change_workout',fn=get_workout_by_opaqueid,raise_exception=True)
@@ -3268,6 +3407,8 @@ def workout_data_view(request, id=0):
'workout_data.html',
{
'htmltable': htmltable,
'data':datadf,
'cols':datadf.columns,
'form':form,
'teams':get_my_teams(request.user),
'workout': w,