Merge branch 'release/v3.61'
This commit is contained in:
@@ -91,7 +91,7 @@ columndict = {
|
|||||||
'finish':'finish',
|
'finish':'finish',
|
||||||
'peakforceangle':'peakforceangle',
|
'peakforceangle':'peakforceangle',
|
||||||
'wash':'wash',
|
'wash':'wash',
|
||||||
'slip':'wash',
|
'slip':'slip',
|
||||||
'workoutstate':' WorkoutState',
|
'workoutstate':' WorkoutState',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,13 +107,17 @@ def get_latlon(id):
|
|||||||
|
|
||||||
rowdata = rdata(w.csvfilename)
|
rowdata = rdata(w.csvfilename)
|
||||||
try:
|
try:
|
||||||
latitude = rowdata.df.ix[:,' latitude']
|
try:
|
||||||
longitude = rowdata.df.ix[:,' longitude']
|
latitude = rowdata.df.ix[:,' latitude']
|
||||||
except KeyError:
|
longitude = rowdata.df.ix[:,' longitude']
|
||||||
latitude = 0*rowdata.df.ix[:,'TimeStamp (sec)']
|
except KeyError:
|
||||||
latitude = 0*rowdata.df.ix[:,'TimeStamp (sec)']
|
latitude = 0*rowdata.df.ix[:,'TimeStamp (sec)']
|
||||||
|
longitude = 0*rowdata.df.ix[:,'TimeStamp (sec)']
|
||||||
return [latitude,longitude]
|
return [latitude,longitude]
|
||||||
|
except AttributeError:
|
||||||
|
return [pd.Series([]),pd.Series([])]
|
||||||
|
|
||||||
|
return [pd.Series([]),pd.Series([])]
|
||||||
|
|
||||||
def get_workouts(ids,userid):
|
def get_workouts(ids,userid):
|
||||||
goodids = []
|
goodids = []
|
||||||
@@ -820,12 +824,102 @@ def new_workout_from_file(r,f2,
|
|||||||
|
|
||||||
return (id,message,f2)
|
return (id,message,f2)
|
||||||
|
|
||||||
|
def split_workout(r,parent,splitsecond,splitmode):
|
||||||
|
data,row = getrowdata_db(id=parent.id)
|
||||||
|
latitude,longitude = get_latlon(parent.id)
|
||||||
|
if not latitude.empty and not longitude.empty:
|
||||||
|
data[' latitude'] = latitude
|
||||||
|
data[' longitude'] = longitude
|
||||||
|
|
||||||
|
data['time'] = data['time']/1000.
|
||||||
|
|
||||||
|
data1 = data[data['time']<=splitsecond].copy()
|
||||||
|
data2 = data[data['time']>splitsecond].copy()
|
||||||
|
|
||||||
|
data1 = data1.sort_values(['time'])
|
||||||
|
data1 = data1.interpolate(method='linear',axis=0,limit_direction='both',
|
||||||
|
limit=10)
|
||||||
|
data1.fillna(method='bfill',inplace=True)
|
||||||
|
|
||||||
|
# Some new stuff to try out
|
||||||
|
data1 = data1.groupby('time',axis=0).mean()
|
||||||
|
data1['time'] = data1.index
|
||||||
|
data1.reset_index(drop=True,inplace=True)
|
||||||
|
|
||||||
|
|
||||||
|
data2 = data2.sort_values(['time'])
|
||||||
|
data2 = data2.interpolate(method='linear',axis=0,limit_direction='both',
|
||||||
|
limit=10)
|
||||||
|
data2.fillna(method='bfill',inplace=True)
|
||||||
|
|
||||||
|
# Some new stuff to try out
|
||||||
|
data2 = data2.groupby('time',axis=0).mean()
|
||||||
|
data2['time'] = data2.index
|
||||||
|
data2.reset_index(drop=True,inplace=True)
|
||||||
|
|
||||||
|
data1['pace'] = data1['pace']/1000.
|
||||||
|
data2['pace'] = data2['pace']/1000.
|
||||||
|
|
||||||
|
|
||||||
|
data1.drop_duplicates(subset='time',inplace=True)
|
||||||
|
data2.drop_duplicates(subset='time',inplace=True)
|
||||||
|
|
||||||
|
messages = []
|
||||||
|
ids = []
|
||||||
|
|
||||||
|
if 'keep first' in splitmode:
|
||||||
|
if 'secondprivate' in splitmode:
|
||||||
|
setprivate = True
|
||||||
|
else:
|
||||||
|
setprivate = False
|
||||||
|
|
||||||
|
id,message = new_workout_from_df(r,data1,
|
||||||
|
title=parent.name+' First Part',
|
||||||
|
parent=parent,
|
||||||
|
setprivate=setprivate)
|
||||||
|
messages.append(message)
|
||||||
|
ids.append(id)
|
||||||
|
if 'keep second' in splitmode:
|
||||||
|
data2['cumdist'] = data2['cumdist'] - data2.ix[0,'cumdist']
|
||||||
|
data2['distance'] = data2['distance'] - data2.ix[0,'distance']
|
||||||
|
data2['time'] = data2['time'] - data2.ix[0,'time']
|
||||||
|
if 'secondprivate' in splitmode:
|
||||||
|
setprivate = True
|
||||||
|
else:
|
||||||
|
setprivate = False
|
||||||
|
|
||||||
|
dt = datetime.timedelta(seconds=splitsecond)
|
||||||
|
|
||||||
|
id,message = new_workout_from_df(r,data2,
|
||||||
|
title=parent.name+' Second Part',
|
||||||
|
parent=parent,
|
||||||
|
setprivate=setprivate,
|
||||||
|
dt=dt)
|
||||||
|
messages.append(message)
|
||||||
|
ids.append(id)
|
||||||
|
|
||||||
|
|
||||||
|
if not 'keep original' in splitmode:
|
||||||
|
if 'keep second' in splitmode or 'keep first' in splitmode:
|
||||||
|
parent.delete()
|
||||||
|
messages.append('Deleted Workout: '+parent.name)
|
||||||
|
else:
|
||||||
|
messages.append('That would delete your workout')
|
||||||
|
ids.append(parent.id)
|
||||||
|
elif 'originalprivate' in splitmode:
|
||||||
|
parent.privacy = 'hidden'
|
||||||
|
parent.save()
|
||||||
|
|
||||||
|
return ids,messages
|
||||||
|
|
||||||
# Create new workout from data frame and store it in the database
|
# Create new workout from data frame and store it in the database
|
||||||
# This routine should be used everywhere in views.py and mailprocessing.py
|
# This routine should be used everywhere in views.py and mailprocessing.py
|
||||||
# Currently there is code duplication
|
# Currently there is code duplication
|
||||||
def new_workout_from_df(r,df,
|
def new_workout_from_df(r,df,
|
||||||
title='New Workout',
|
title='New Workout',
|
||||||
parent=None):
|
parent=None,
|
||||||
|
setprivate=False,
|
||||||
|
dt=datetime.timedelta()):
|
||||||
|
|
||||||
message = None
|
message = None
|
||||||
|
|
||||||
@@ -837,7 +931,7 @@ def new_workout_from_df(r,df,
|
|||||||
notes=parent.notes
|
notes=parent.notes
|
||||||
summary=parent.summary
|
summary=parent.summary
|
||||||
makeprivate=parent.privacy
|
makeprivate=parent.privacy
|
||||||
startdatetime=parent.startdatetime
|
startdatetime=parent.startdatetime+dt
|
||||||
else:
|
else:
|
||||||
oarlength = 2.89
|
oarlength = 2.89
|
||||||
inboard = 0.88
|
inboard = 0.88
|
||||||
@@ -847,14 +941,19 @@ def new_workout_from_df(r,df,
|
|||||||
makeprivate=False
|
makeprivate=False
|
||||||
startdatetime = timezone.now()
|
startdatetime = timezone.now()
|
||||||
|
|
||||||
|
if setprivate:
|
||||||
|
makeprivate=True
|
||||||
|
|
||||||
timestr = strftime("%Y%m%d-%H%M%S")
|
timestr = strftime("%Y%m%d-%H%M%S")
|
||||||
|
|
||||||
csvfilename ='media/df_'+timestr+'.csv'
|
csvfilename ='media/df_'+timestr+'.csv'
|
||||||
|
|
||||||
|
|
||||||
df.rename(columns = columndict,inplace=True)
|
df.rename(columns = columndict,inplace=True)
|
||||||
|
|
||||||
starttimeunix = mktime(startdatetime.utctimetuple())
|
starttimeunix = mktime(startdatetime.utctimetuple())
|
||||||
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
|
df[' ElapsedTime (sec)'] = df['TimeStamp (sec)']
|
||||||
|
|
||||||
df['TimeStamp (sec)'] = df['TimeStamp (sec)']+starttimeunix
|
df['TimeStamp (sec)'] = df['TimeStamp (sec)']+starttimeunix
|
||||||
|
|
||||||
row = rrdata(df=df)
|
row = rrdata(df=df)
|
||||||
|
|||||||
@@ -110,6 +110,33 @@ class TeamUploadOptionsForm(forms.Form):
|
|||||||
class Meta:
|
class Meta:
|
||||||
fields = ['make_plot','plottype']
|
fields = ['make_plot','plottype']
|
||||||
|
|
||||||
|
# This form is used on the Workout Split page
|
||||||
|
class WorkoutSplitForm(forms.Form):
|
||||||
|
splitchoices = (
|
||||||
|
('keep original','Keep Original'),
|
||||||
|
('keep first','Keep First Part'),
|
||||||
|
('keep second','Keep Second Part'),
|
||||||
|
('firstprivate','Set First Part Private'),
|
||||||
|
('secondprivate','Set Second Part Private'),
|
||||||
|
('originalprivate','Set Original Private'),
|
||||||
|
)
|
||||||
|
splittime = forms.TimeField(input_formats=['%H:%M:%S.%f',
|
||||||
|
'%H:%M:%S',
|
||||||
|
'%H:%M:%S',
|
||||||
|
'%M:%S.%f',
|
||||||
|
'%M:%S',
|
||||||
|
'%M'],
|
||||||
|
label = 'Split Time')
|
||||||
|
splitmode = forms.MultipleChoiceField(
|
||||||
|
initial=['keep original',
|
||||||
|
'keep first',
|
||||||
|
'keep second',
|
||||||
|
'firstprivate',
|
||||||
|
'secondprivate'],
|
||||||
|
label='Split Mode',
|
||||||
|
choices=splitchoices,
|
||||||
|
widget = forms.CheckboxSelectMultiple())
|
||||||
|
|
||||||
# This form is used on the Analysis page to add a custom distance/time
|
# This form is used on the Analysis page to add a custom distance/time
|
||||||
# trial and predict the pace
|
# trial and predict the pace
|
||||||
class PredictedPieceForm(forms.Form):
|
class PredictedPieceForm(forms.Form):
|
||||||
|
|||||||
@@ -133,18 +133,30 @@
|
|||||||
Plot the Power Histogram of this workout
|
Plot the Power Histogram of this workout
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_2 suffix_2 omega">
|
<div class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id }}/">Sensor Fusion</a>
|
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id }}/">Sensor Fusion</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Sensor Fusion</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Merge data from another source into this workout
|
Merge data from another source into this workout
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid_2 omega">
|
||||||
|
<p>
|
||||||
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/split">Split Workout</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="button blue small" href="/rowers/promembership">Split Workout</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Split workout into two seperate workouts
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="advancedplots" class="grid_6 omega">
|
<div id="advancedplots" class="grid_6 omega">
|
||||||
|
|||||||
@@ -190,18 +190,30 @@
|
|||||||
See (and save) the big interactive plot
|
See (and save) the big interactive plot
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid_2 suffix_2 omega">
|
<div class="grid_2">
|
||||||
<p>
|
<p>
|
||||||
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id }}/">Sensor Fusion</a>
|
<a class="button blue small" href="/rowers/workout/fusion/{{ workout.id }}/">Sensor Fusion</a>
|
||||||
{% else %}
|
{% else %}
|
||||||
<a class="button blue small" href="/rowers/promembership">Dist Metrics Plot</a>
|
<a class="button blue small" href="/rowers/promembership">Sensor Fusion</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
Merge data from another source into this workout
|
Merge data from another source into this workout
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid_2 omega">
|
||||||
|
<p>
|
||||||
|
{% if user.rower.rowerplan == 'pro' or user.rower.rowerplan == 'coach' %}
|
||||||
|
<a class="button blue small" href="/rowers/workout/{{ workout.id }}/split">Split Workout</a>
|
||||||
|
{% else %}
|
||||||
|
<a class="button blue small" href="/rowers/promembership">Split Workout</a>
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Split workout into two seperate workouts
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
131
rowers/templates/splitworkout.html
Normal file
131
rowers/templates/splitworkout.html
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
{% extends "base.html" %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load rowerfilters %}
|
||||||
|
{% load tz %}
|
||||||
|
|
||||||
|
{% block title %}Change Workout {% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="workouts" class="grid_6 alpha">
|
||||||
|
|
||||||
|
{% if form.errors %}
|
||||||
|
<p style="color: red;">
|
||||||
|
Please correct the error{{ form.errors|pluralize }} below.
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
<h1>Edit Workout Interval Data</h1>
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
<div class="grid_2 alpha">
|
||||||
|
<p>
|
||||||
|
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/edit">Edit</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid_2">
|
||||||
|
<p>
|
||||||
|
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/export">Export</a>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="grid_2 omega tooltip">
|
||||||
|
<p>
|
||||||
|
<a class="button gray small" href="/rowers/workout/{{ workout.id }}/advanced">Advanced</a>
|
||||||
|
</p>
|
||||||
|
<span class="tooltiptext">Advanced Functionality (More interactive Charts)</span>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% localtime on %}
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<form enctype="multipart/form-data" action="/rowers/workout/{{ workout.id }}/split" method="post">
|
||||||
|
<table width=100%>
|
||||||
|
{{ form.as_table }}
|
||||||
|
</table>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div id="formbutton" class="grid_1 prefix_4 suffix_1">
|
||||||
|
<input class="button green" type="submit" value="Split">
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</p>
|
||||||
|
<h1>Workout Split</h1>
|
||||||
|
<p>Split your workout in half at the given time using the form above.
|
||||||
|
Use the chart on
|
||||||
|
the right to find the point where you want to split.</p>
|
||||||
|
<p>Use any of the following formats:
|
||||||
|
<ul>
|
||||||
|
<li>H:MM:SS.d, e.g. 1:45:00.0 for one hour and 45 minutes</li>
|
||||||
|
<li>H:MM:SS, e.g. 1:45:00 for one hour and 45 minutes</li>
|
||||||
|
<li>MM:SS.d, e.g. 30:00.0 for thirty minutes</li>
|
||||||
|
<li>MM, e.g. 30 for thirty minutes</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<p>Warning: If you deselect, "Keep Original", the original workout
|
||||||
|
cannot be restored afterwards.</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="advancedplots" class="grid_6 omega">
|
||||||
|
<div class="grid_6 alpha">
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/static/js/bokeh-0.12.3.min.js"></script>
|
||||||
|
<script async="true" type="text/javascript">
|
||||||
|
Bokeh.set_log_level("info");
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{{ thescript |safe }}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// Set things up to resize the plot on a window resize. You can play with
|
||||||
|
// the arguments of resize_width_height() to change the plot's behavior.
|
||||||
|
var plot_resize_setup = function () {
|
||||||
|
var plotid = Object.keys(Bokeh.index)[0]; // assume we have just one plot
|
||||||
|
var plot = Bokeh.index[plotid];
|
||||||
|
var plotresizer = function() {
|
||||||
|
// arguments: use width, use height, maintain aspect ratio
|
||||||
|
plot.resize_width_height(true, true, true);
|
||||||
|
};
|
||||||
|
window.addEventListener('resize', plotresizer);
|
||||||
|
plotresizer();
|
||||||
|
};
|
||||||
|
window.addEventListener('load', plot_resize_setup);
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
/* Need this to get the page in "desktop mode"; not having an infinite height.*/
|
||||||
|
html, body {height: 100%; margin:5px;}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
<div id="interactiveplot" class="grid_6 omega">
|
||||||
|
{{ thediv |safe }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table width=100%>
|
||||||
|
<tr>
|
||||||
|
<th>Date/Time:</th><td>{{ workout.startdatetime }}</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><tr>
|
||||||
|
<th>Public link to this workout</th>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/{{ workout.id }}">https://rowsandall.com/rowers/workout/{{ workout.id }}</a>
|
||||||
|
<td>
|
||||||
|
</tr><tr>
|
||||||
|
<th>Public link to interactive chart</th>
|
||||||
|
<td>
|
||||||
|
<a href="/rowers/workout/{{ workout.id }}/interactiveplot">https://rowsandall.com/rowers/workout/{{ workout.id }}/interactiveplot</a>
|
||||||
|
<td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
{% endlocaltime %}
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
@@ -202,6 +202,7 @@ urlpatterns = [
|
|||||||
url(r'^workout/(?P<id>\d+)/crewnerdsummary$',views.workout_crewnerd_summary_view),
|
url(r'^workout/(?P<id>\d+)/crewnerdsummary$',views.workout_crewnerd_summary_view),
|
||||||
url(r'^workout/(?P<id>\d+)/editintervals$',views.workout_summary_edit_view),
|
url(r'^workout/(?P<id>\d+)/editintervals$',views.workout_summary_edit_view),
|
||||||
url(r'^workout/(?P<id>\d+)/restore$',views.workout_summary_restore_view),
|
url(r'^workout/(?P<id>\d+)/restore$',views.workout_summary_restore_view),
|
||||||
|
url(r'^workout/(?P<id>\d+)/split$',views.workout_split_view),
|
||||||
url(r'^workout/(?P<id>\d+)/interactiveplot$',views.workout_biginteractive_view),
|
url(r'^workout/(?P<id>\d+)/interactiveplot$',views.workout_biginteractive_view),
|
||||||
url(r'^workout/(?P<id>\d+)/view$',views.workout_view),
|
url(r'^workout/(?P<id>\d+)/view$',views.workout_view),
|
||||||
url(r'^workout/(?P<id>\d+)$',views.workout_view),
|
url(r'^workout/(?P<id>\d+)$',views.workout_view),
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ from rowers.forms import (
|
|||||||
RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,
|
RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,
|
||||||
UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm,
|
UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm,
|
||||||
FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm,
|
FusionMetricChoiceForm,BoxPlotChoiceForm,MultiFlexChoiceForm,
|
||||||
TrendFlexModalForm,
|
TrendFlexModalForm,WorkoutSplitForm,
|
||||||
)
|
)
|
||||||
from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
|
from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
|
||||||
from rowers.models import (
|
from rowers.models import (
|
||||||
@@ -7773,6 +7773,8 @@ def workout_delete_view(request,id=0):
|
|||||||
messages.info(request,'Workout deleted')
|
messages.info(request,'Workout deleted')
|
||||||
try:
|
try:
|
||||||
url = request.session['referer']
|
url = request.session['referer']
|
||||||
|
if 'rowers/workout/' in url:
|
||||||
|
url = reverse(workouts_view)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
url = reverse(workouts_view)
|
url = reverse(workouts_view)
|
||||||
|
|
||||||
@@ -7877,7 +7879,7 @@ def graph_show_view(request,id):
|
|||||||
raise Http404("This graph doesn't exist")
|
raise Http404("This graph doesn't exist")
|
||||||
except Workout.DoesNotExist:
|
except Workout.DoesNotExist:
|
||||||
raise Http404("This workout doesn't exist")
|
raise Http404("This workout doesn't exist")
|
||||||
|
|
||||||
# Restore original stroke data and summary
|
# Restore original stroke data and summary
|
||||||
@login_required()
|
@login_required()
|
||||||
def workout_summary_restore_view(request,id,message="",successmessage=""):
|
def workout_summary_restore_view(request,id,message="",successmessage=""):
|
||||||
@@ -7935,6 +7937,55 @@ def workout_summary_restore_view(request,id,message="",successmessage=""):
|
|||||||
)
|
)
|
||||||
return HttpResponseRedirect(url)
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
# Split a workout
|
||||||
|
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||||
|
def workout_split_view(request,id=id):
|
||||||
|
try:
|
||||||
|
row = Workout.objects.get(id=id)
|
||||||
|
if (checkworkoutuser(request.user,row)==False):
|
||||||
|
raise PermissionDenied("You are not allowed to edit this workout")
|
||||||
|
except Workout.DoesNotExist:
|
||||||
|
raise Http404("Workout doesn't exist")
|
||||||
|
|
||||||
|
r = getrower(request.user)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
form = WorkoutSplitForm(request.POST)
|
||||||
|
if form.is_valid():
|
||||||
|
splittime = form.cleaned_data['splittime']
|
||||||
|
splitsecond = splittime.hour*3600
|
||||||
|
splitsecond += splittime.minute*60
|
||||||
|
splitsecond += splittime.second
|
||||||
|
splitsecond += splittime.microsecond/1.e6
|
||||||
|
splitmode = form.cleaned_data['splitmode']
|
||||||
|
ids,mesgs = dataprep.split_workout(r,row,splitsecond,splitmode)
|
||||||
|
for message in mesgs:
|
||||||
|
messages.info(request,message)
|
||||||
|
|
||||||
|
url = reverse(workouts_view)
|
||||||
|
qdict = {'q':row.name}
|
||||||
|
url+='?'+urllib.urlencode(qdict)
|
||||||
|
|
||||||
|
return HttpResponseRedirect(url)
|
||||||
|
|
||||||
|
form = WorkoutSplitForm()
|
||||||
|
|
||||||
|
# create interactive plot
|
||||||
|
try:
|
||||||
|
res = interactive_chart(id,promember=1)
|
||||||
|
script = res[0]
|
||||||
|
div = res[1]
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
return render(request, 'splitworkout.html',
|
||||||
|
{'form':form,
|
||||||
|
'workout':row,
|
||||||
|
'thediv':script,
|
||||||
|
'thescript':div,
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
# Fuse two workouts
|
# Fuse two workouts
|
||||||
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
@user_passes_test(ispromember,login_url="/",redirect_field_name=None)
|
||||||
def workout_fusion_view(request,id1=0,id2=1):
|
def workout_fusion_view(request,id1=0,id2=1):
|
||||||
|
|||||||
Reference in New Issue
Block a user