Merge branch 'release/teamcompare'
This commit is contained in:
@@ -449,6 +449,7 @@ def get_username(access_token):
|
||||
|
||||
try:
|
||||
res = me_json['data']['username']
|
||||
id = me_json['data']['id']
|
||||
except KeyError:
|
||||
res = None
|
||||
|
||||
@@ -482,7 +483,7 @@ def process_callback(request):
|
||||
|
||||
access_token = get_token(code)
|
||||
|
||||
username = get_username(access_token)
|
||||
username,id = get_username(access_token)
|
||||
|
||||
return HttpResponse("got a user name: %s" % username)
|
||||
|
||||
|
||||
@@ -252,3 +252,23 @@ class StatsOptionsForm(forms.Form):
|
||||
paddle = forms.BooleanField(initial=False,required=False)
|
||||
snow = forms.BooleanField(initial=False,required=False)
|
||||
other = forms.BooleanField(initial=False,required=False)
|
||||
|
||||
class WorkoutMultipleCompareForm(forms.Form):
|
||||
workouts = forms.ModelMultipleChoiceField(queryset=Workout.objects.all(),
|
||||
widget=forms.CheckboxSelectMultiple())
|
||||
|
||||
from rowers.interactiveplots import axlabels
|
||||
|
||||
axlabels.pop('None')
|
||||
axlabels = list(axlabels.items())
|
||||
|
||||
|
||||
class ChartParamChoiceForm(forms.Form):
|
||||
plotchoices = (
|
||||
('line','Line Plot'),
|
||||
('scatter','Scatter Plot'),
|
||||
)
|
||||
xparam = forms.ChoiceField(choices=axlabels,initial='distance')
|
||||
yparam = forms.ChoiceField(choices=axlabels,initial='hr')
|
||||
plottype = forms.ChoiceField(choices=plotchoices,initial='scatter')
|
||||
teamid = forms.IntegerField(widget=forms.HiddenInput())
|
||||
|
||||
@@ -8,6 +8,8 @@ from rowingdata import rowingdata as rrdata
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
from bokeh.palettes import Dark2_8 as palette
|
||||
import itertools
|
||||
from bokeh.plotting import figure, ColumnDataSource, Figure,curdoc
|
||||
from bokeh.models import CustomJS,Slider
|
||||
from bokeh.charts import Histogram,HeatMap
|
||||
@@ -52,7 +54,7 @@ import rowers.dataprep as dataprep
|
||||
axlabels = {
|
||||
'time': 'Time',
|
||||
'distance': 'Distance (m)',
|
||||
'cumdist': 'Distance (m)',
|
||||
'cumdist': 'Cumulative Distance (m)',
|
||||
'hr': 'Heart Rate (bpm)',
|
||||
'spm': 'Stroke Rate (spm)',
|
||||
'pace': 'Pace (/500m)',
|
||||
@@ -1579,6 +1581,139 @@ def interactive_bar_chart(id=0,promember=0):
|
||||
|
||||
return [script,div]
|
||||
|
||||
def interactive_multiple_compare_chart(ids,xparam,yparam,plottype='line',
|
||||
promember=0,
|
||||
labeldict=None):
|
||||
columns = [xparam,yparam,
|
||||
'ftime','distance','fpace',
|
||||
'power','hr','spm',
|
||||
'time','pace','workoutstate',
|
||||
'workoutid']
|
||||
|
||||
datadf = dataprep.getsmallrowdata_db(columns,ids=ids)
|
||||
|
||||
yparamname = axlabels[yparam]
|
||||
|
||||
#datadf = datadf[datadf[yparam] > 0]
|
||||
|
||||
#datadf = datadf[datadf[xparam] > 0]
|
||||
|
||||
# check if dataframe not empty
|
||||
if datadf.empty:
|
||||
return ['','<p>No non-zero data in selection</p>','','']
|
||||
|
||||
|
||||
|
||||
if xparam=='distance':
|
||||
xaxmax = datadf['distance'].max()
|
||||
xaxmin = datadf['distance'].min()
|
||||
else:
|
||||
xaxmax = yaxmaxima[xparam]
|
||||
xaxmin = yaxminima[xparam]
|
||||
|
||||
|
||||
x_axis_type = 'linear'
|
||||
y_axis_type = 'linear'
|
||||
|
||||
# Add hover to this comma-separated string and see what changes
|
||||
if (promember==1):
|
||||
TOOLS = 'save,pan,box_zoom,wheel_zoom,reset,tap,resize,crosshair'
|
||||
else:
|
||||
TOOLS = 'pan,box_zoom,wheel_zoom,reset,tap,crosshair'
|
||||
|
||||
if yparam == 'pace':
|
||||
y_axis_type = 'datetime'
|
||||
yaxmax = 90.
|
||||
yaxmin = 150.
|
||||
|
||||
if xparam == 'time':
|
||||
x_axis_type = 'datetime'
|
||||
|
||||
if xparam != 'time':
|
||||
xvals = xaxmin+np.arange(100)*(xaxmax-xaxmin)/100.
|
||||
else:
|
||||
xvals = np.arange(100)
|
||||
|
||||
plot = Figure(x_axis_type=x_axis_type,y_axis_type=y_axis_type,
|
||||
tools=TOOLS,
|
||||
toolbar_location="above",
|
||||
plot_width=920,
|
||||
toolbar_sticky=False)
|
||||
|
||||
colors = itertools.cycle(palette)
|
||||
|
||||
cntr = 0
|
||||
|
||||
for id,color in itertools.izip(ids,colors):
|
||||
group = datadf[datadf['workoutid']==int(id)].copy()
|
||||
group.sort_values(by='time',ascending=True,inplace=True)
|
||||
group['x'] = group[xparam]
|
||||
group['y'] = group[yparam]
|
||||
|
||||
ymean = group['y'].mean()
|
||||
ylabel = Label(x=100,y=70+20*cntr,
|
||||
x_units='screen',y_units='screen',
|
||||
text=yparam+": {ymean:6.2f}".format(ymean=ymean),
|
||||
background_fill_alpha=.7,
|
||||
text_color=color,
|
||||
)
|
||||
if yparam != 'time' and yparam != 'pace':
|
||||
plot.add_layout(ylabel)
|
||||
|
||||
print cntr,id,len(group),ymean
|
||||
|
||||
source = ColumnDataSource(
|
||||
group
|
||||
)
|
||||
|
||||
if labeldict:
|
||||
legend=labeldict[id]
|
||||
else:
|
||||
legend=str(id)
|
||||
|
||||
if plottype=='line':
|
||||
plot.line('x','y',source=source,color=color,legend=legend)
|
||||
else:
|
||||
plot.scatter('x','y',source=source,color=color,legend=legend,
|
||||
fill_alpha=0.4,line_color=None)
|
||||
|
||||
cntr += 1
|
||||
|
||||
plot.legend.location='bottom_right'
|
||||
plot.xaxis.axis_label = axlabels[xparam]
|
||||
plot.yaxis.axis_label = axlabels[yparam]
|
||||
|
||||
if (xparam != 'time') and (xparam != 'distance') and (xparam != 'cumdist'):
|
||||
xrange1 = Range1d(start=yaxminima[xparam],end=yaxmaxima[xparam])
|
||||
plot.x_range = xrange1
|
||||
|
||||
if xparam == 'time':
|
||||
xrange1 = Range1d(start=xaxmin,end=xaxmax)
|
||||
plot.x_range = xrange1
|
||||
plot.xaxis[0].formatter = DatetimeTickFormatter(
|
||||
hours = ["%H"],
|
||||
minutes = ["%M"],
|
||||
seconds = ["%S"],
|
||||
days = ["0"],
|
||||
months = [""],
|
||||
years = [""]
|
||||
)
|
||||
|
||||
|
||||
if yparam == 'pace':
|
||||
plot.yaxis[0].formatter = DatetimeTickFormatter(
|
||||
seconds = ["%S"],
|
||||
minutes = ["%M"]
|
||||
)
|
||||
|
||||
script, div = components(plot)
|
||||
|
||||
|
||||
|
||||
return [script,div]
|
||||
|
||||
|
||||
|
||||
def interactive_comparison_chart(id1=0,id2=0,xparam='distance',yparam='spm',
|
||||
promember=0,plottype='line'):
|
||||
|
||||
|
||||
@@ -398,17 +398,23 @@ class Workout(models.Model):
|
||||
privacy = models.CharField(default='visible',max_length=30,
|
||||
choices=privacychoices)
|
||||
|
||||
def __str__(self):
|
||||
def __unicode__(self):
|
||||
|
||||
date = self.date
|
||||
name = self.name
|
||||
distance = str(self.distance)
|
||||
ownerfirst = self.user.user.first_name
|
||||
ownerlast = self.user.user.last_name
|
||||
duration = self.duration
|
||||
|
||||
try:
|
||||
stri = date.strftime('%Y-%m-%d')+'_'+name
|
||||
except AttributeError:
|
||||
stri = str(date)+'_'+name
|
||||
|
||||
|
||||
stri = u'{d} {n} {dist}m {duration:%H:%M:%S} {ownerfirst} {ownerlast}'.format(
|
||||
d = date.strftime('%Y-%m-%d'),
|
||||
n = name,
|
||||
dist = distance,
|
||||
duration = duration,
|
||||
ownerfirst = ownerfirst,
|
||||
ownerlast = ownerlast,
|
||||
)
|
||||
|
||||
return stri
|
||||
|
||||
@@ -890,7 +896,7 @@ class WorkoutComment(models.Model):
|
||||
|
||||
def __unicode__(self):
|
||||
return u'Comment to: {w} by {u1} {u2}'.format(
|
||||
w=self.workout.name,
|
||||
w=self.workout,
|
||||
u1 = self.user.first_name,
|
||||
u2 = self.user.last_name,
|
||||
)
|
||||
|
||||
@@ -39,6 +39,7 @@ from rowsandall_app.settings import C2_CLIENT_ID, C2_REDIRECT_URI, C2_CLIENT_SEC
|
||||
def ewmovingaverage(interval,window_size):
|
||||
# Experimental code using Exponential Weighted moving average
|
||||
|
||||
try:
|
||||
intervaldf = pd.DataFrame({'v':interval})
|
||||
idf_ewma1 = intervaldf.ewm(span=window_size)
|
||||
idf_ewma2 = intervaldf[::-1].ewm(span=window_size)
|
||||
@@ -48,6 +49,8 @@ def ewmovingaverage(interval,window_size):
|
||||
|
||||
interval2 = np.vstack((i_ewma1,i_ewma2[::-1]))
|
||||
interval2 = np.mean( interval2, axis=0) # average
|
||||
except ValueError:
|
||||
interval2 = interval
|
||||
|
||||
return interval2
|
||||
|
||||
@@ -234,7 +237,7 @@ def handle_stravaexport(f2,workoutname,stravatoken,description=''):
|
||||
|
||||
act = client.upload_activity(f2,'tcx',name=workoutname)
|
||||
try:
|
||||
res = act.wait(poll_interval=5.0)
|
||||
res = act.wait(poll_interval=5.0,timeout=30)
|
||||
message = 'Workout successfully synchronized to Strava'
|
||||
except:
|
||||
res = 0
|
||||
@@ -246,6 +249,7 @@ def handle_stravaexport(f2,workoutname,stravatoken,description=''):
|
||||
act = client.update_activity(res.id,activity_type='Rowing',description=description)
|
||||
else:
|
||||
message = 'Strava upload timed out.'
|
||||
return (0,message)
|
||||
|
||||
return (res.id,message)
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ Click on the icon to upload this workout to your site of choice. A checkmark ind
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="grid_1 alpha">
|
||||
<a href="http://log.concept2.com/profile/{{ c2userid }}/log/{{ workout.uploadedtoc2 }}">
|
||||
<img src="/static/img/c2square_checked.png" alt="Concept2 icon" width="60" height="60"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -59,6 +60,7 @@ Click on the icon to upload this workout to your site of choice. A checkmark ind
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="grid_1">
|
||||
<a href="https://www.strava.com/activities/{{ workout.uploadedtostrava }}">
|
||||
<img src="/static/img/stravasquare_checked.png" alt="Concept2 icon" width="60" height="60"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -76,6 +78,7 @@ Click on the icon to upload this workout to your site of choice. A checkmark ind
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<div class="grid_1">
|
||||
<a href="https://sporttracks.mobi/activity/{{ workout.uploadedtosporttracks }}">
|
||||
<img src="/static/img/sporttrackssquare_checked.png" alt="Concept2 icon" width="60" height="60"></a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
@@ -112,6 +112,13 @@
|
||||
</div>
|
||||
|
||||
<div class="grid_4 omega">
|
||||
{% if team %}
|
||||
<div class="grid_4" id="teambuttons">
|
||||
<div class="grid_3 alpha">
|
||||
<a class="button gray small" href="/rowers/team-compare-select/team/{{ team.id }}/">Multi Workout Compare</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="grid_4" id="announcements">
|
||||
{% if announcements %}
|
||||
<h3>What's New?</h3>
|
||||
|
||||
58
rowers/templates/multicompare.html
Normal file
58
rowers/templates/multicompare.html
Normal file
@@ -0,0 +1,58 @@
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}View Comparison {% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<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>
|
||||
|
||||
{{ interactiveplot |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, false, false);
|
||||
};
|
||||
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="workouts" class="grid_12 alpha">
|
||||
<h1>Interactive Comparison</h1>
|
||||
<div class="grid_2 alpha">
|
||||
<a class="button gray small" href="/rowers/list-workouts/team/{{ teamid }}/">Team Workouts</a>
|
||||
</div>
|
||||
<div class="grid_2">
|
||||
<a class="button gray small" href="/rowers/team-compare-select/team/{{ teamid }}/">Multi Compare</a>
|
||||
</div>
|
||||
<div class="grid_2 suffix_6 omega">
|
||||
<a class="button gray small" href="/rowers/team/{{ teamid }}/">Team Page</a>
|
||||
</div>
|
||||
<div class="grid_12 alpha">
|
||||
|
||||
|
||||
|
||||
<div id="theplot" class="grid_12 alpha flexplot">
|
||||
{{ the_div|safe }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
94
rowers/templates/team_compare_select.html
Normal file
94
rowers/templates/team_compare_select.html
Normal file
@@ -0,0 +1,94 @@
|
||||
{% extends "base.html" %}
|
||||
{% load staticfiles %}
|
||||
{% load rowerfilters %}
|
||||
|
||||
{% block title %}Workouts{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<script>
|
||||
setTimeout("location.reload(true);",60000);
|
||||
</script>
|
||||
|
||||
|
||||
<div class="grid_12">
|
||||
|
||||
<div class="grid_4 alpha">
|
||||
|
||||
{% if team %}
|
||||
<form enctype="multipart/form-data" action="/rowers/team-compare-select/team/{{ team.id }}/" method="post">
|
||||
{% else %}
|
||||
<form enctype="multipart/form-data" action="/rowers/team-compare-select/" method="post">
|
||||
{% endif %}
|
||||
|
||||
<table>
|
||||
{{ dateform.as_table }}
|
||||
</table>
|
||||
{% csrf_token %}
|
||||
</div>
|
||||
<div class="grid_2">
|
||||
<input name='daterange' class="button green" type="submit" value="Submit"> </form>
|
||||
</div>
|
||||
<div class="grid_5 prefix_1 omega">
|
||||
{% if team %}
|
||||
<form id="searchform" action="/rowers/team-compare-select/team/{{ team.id }}/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
|
||||
method="get" accept-charset="utf-8">
|
||||
{% else %}
|
||||
<form id="searchform" action="/rowers/team-compare-select/{{ startdate|date:"Y-m-d" }}/{{ enddate|date:"Y-m-d" }}"
|
||||
method="get" accept-charset="utf-8">
|
||||
{% endif %}
|
||||
<div class="grid_3 prefix_1 alpha">
|
||||
<input class="searchfield" id="searchbox" name="q" type="text" placeholder="Search">
|
||||
</div>
|
||||
<div class="grid_1 omega">
|
||||
<button class="button blue small" type="submit">
|
||||
Search
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="grid_12 alpha">
|
||||
<h3>{{ team.name }} Team Workouts</h3>
|
||||
</div>
|
||||
|
||||
<form enctype="multipart/form-data" action="/rowers/multi-compare" method="post">
|
||||
<div id="workouts_table" class="grid_8 alpha">
|
||||
|
||||
|
||||
{% if workouts %}
|
||||
|
||||
|
||||
<table width="100%" class="listtable">
|
||||
{{ form.as_table }}
|
||||
</table>
|
||||
{% else %}
|
||||
<p> No workouts found </p>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div id="form_settings" class="grid_4 alpha">
|
||||
<p><b>Warning: You are on an experimental part of the site. Use at your own risk.</b></p>
|
||||
<p>Select two or more workouts on the left, set your plot settings below,
|
||||
and press submit"</p>
|
||||
{% csrf_token %}
|
||||
<table>
|
||||
{{ chartform.as_table }}
|
||||
</table>
|
||||
<div class="grid_1 prefix_2 suffix_1">
|
||||
<p>
|
||||
<input name='workoutselectform' class="button green" type="submit" value="Submit">
|
||||
</p>
|
||||
</div>
|
||||
<div class="grid_4">
|
||||
<p>You can use the date and search forms above to search through all
|
||||
workouts from this team.</p>
|
||||
<p>TIP: Agree with your team members to put tags (e.g. '8x500m') in the notes section of
|
||||
your workouts. That makes it easy to search.</p>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
@@ -113,6 +113,13 @@ urlpatterns = [
|
||||
url(r'^list-workouts/team/(?P<teamid>\d+)/$',views.workouts_view),
|
||||
url(r'^list-workouts/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.workouts_view),
|
||||
url(r'^list-workouts/$',views.workouts_view),
|
||||
url(r'^team-compare-select/c/(?P<message>\w+.*)/$',views.team_comparison_select),
|
||||
url(r'^team-compare-select/s/(?P<successmessage>\w+.*)/$',views.team_comparison_select),
|
||||
url(r'^team-compare-select/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.team_comparison_select),
|
||||
url(r'^team-compare-select/team/(?P<teamid>\d+)/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
|
||||
url(r'^team-compare-select/team/(?P<teamid>\d+)/$',views.team_comparison_select),
|
||||
url(r'^team-compare-select/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.team_comparison_select),
|
||||
url(r'^team-compare-select/$',views.team_comparison_select),
|
||||
url(r'^list-graphs/$',views.graphs_view),
|
||||
url(r'^(?P<theuser>\d+)/ote-bests/(?P<startdatestring>\w+.*)/(?P<enddatestring>\w+.*)$',views.rankings_view),
|
||||
url(r'^(?P<theuser>\d+)/ote-bests/(?P<deltadays>\d+)$',views.rankings_view),
|
||||
@@ -204,6 +211,7 @@ urlpatterns = [
|
||||
url(r'^workout/(\d+)/stravauploadw/$',views.workout_strava_upload_view),
|
||||
url(r'^workout/(\d+)/recalcsummary/$',views.workout_recalcsummary_view),
|
||||
url(r'^workout/(\d+)/sporttracksuploadw/$',views.workout_sporttracks_upload_view),
|
||||
url(r'^multi-compare$',views.multi_compare_view),
|
||||
url(r'^me/teams/c/(?P<message>\w+.*)/s/(?P<successmessage>\w+.*)$',views.rower_teams_view),
|
||||
url(r'^me/teams/s/(?P<successmessage>\w+.*)$',views.rower_teams_view),
|
||||
url(r'^me/teams/c/(?P<message>\w+.*)$',views.rower_teams_view),
|
||||
|
||||
147
rowers/views.py
147
rowers/views.py
@@ -26,7 +26,7 @@ from rowers.forms import (
|
||||
StatsOptionsForm,PredictedPieceForm,DateRangeForm,DeltaDaysForm,
|
||||
EmailForm, RegistrationForm, RegistrationFormTermsOfService,
|
||||
RegistrationFormUniqueEmail,CNsummaryForm,UpdateWindForm,
|
||||
UpdateStreamForm
|
||||
UpdateStreamForm,WorkoutMultipleCompareForm,ChartParamChoiceForm
|
||||
)
|
||||
from rowers.models import Workout, User, Rower, WorkoutForm,FavoriteChart
|
||||
from rowers.models import (
|
||||
@@ -810,7 +810,10 @@ def workout_strava_upload_view(request,id=0):
|
||||
message = mes
|
||||
w.uploadedtostrava = -1
|
||||
w.save()
|
||||
try:
|
||||
os.remove(tcxfile)
|
||||
except WindowsError:
|
||||
pass
|
||||
url = reverse(workout_export_view,
|
||||
kwargs = {
|
||||
'id':str(w.id),
|
||||
@@ -1958,6 +1961,137 @@ def workout_setprivate_view(request,id,
|
||||
})
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# Team comparison
|
||||
@login_required()
|
||||
def team_comparison_select(request,
|
||||
startdatestring="",
|
||||
enddatestring="",
|
||||
message='',
|
||||
successmessage='',
|
||||
startdate=timezone.now()-datetime.timedelta(days=30),
|
||||
enddate=timezone.now()+datetime.timedelta(days=1),
|
||||
teamid=0):
|
||||
|
||||
try:
|
||||
r = Rower.objects.get(user=request.user)
|
||||
except Rower.DoesNotExist:
|
||||
raise Http404("Rower doesn't exist")
|
||||
|
||||
if request.method == 'POST':
|
||||
dateform = DateRangeForm(request.POST)
|
||||
if dateform.is_valid():
|
||||
startdate = dateform.cleaned_data['startdate']
|
||||
enddate = dateform.cleaned_data['enddate']
|
||||
else:
|
||||
dateform = DateRangeForm(initial={
|
||||
'startdate':startdate,
|
||||
'enddate':enddate,
|
||||
})
|
||||
|
||||
startdate = datetime.datetime.combine(startdate,datetime.time())
|
||||
enddate = datetime.datetime.combine(enddate,datetime.time(23,59,59))
|
||||
enddate = enddate+datetime.timedelta(days=1)
|
||||
|
||||
if startdatestring:
|
||||
startdate = iso8601.parse_date(startdatestring)
|
||||
if enddatestring:
|
||||
enddate = iso8601.parse_date(enddatestring)
|
||||
|
||||
if enddate < startdate:
|
||||
s = enddate
|
||||
enddate = startdate
|
||||
startdate = s
|
||||
|
||||
try:
|
||||
theteam = Team.objects.get(id=teamid)
|
||||
except Team.DoesNotExist:
|
||||
raise Http404("Team doesn't exist")
|
||||
|
||||
if theteam.viewing == 'allmembers' or theteam.manager == request.user:
|
||||
workouts = Workout.objects.filter(team=theteam,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by("-date", "-starttime")
|
||||
elif theteam.viewing == 'coachonly':
|
||||
workouts = Workout.objects.filter(team=theteam,user=r,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by("-date","-starttime")
|
||||
|
||||
|
||||
else:
|
||||
theteam = None
|
||||
workouts = Workout.objects.filter(user=r,
|
||||
startdatetime__gte=startdate,
|
||||
startdatetime__lte=enddate).order_by("-date", "-starttime")
|
||||
|
||||
query = request.GET.get('q')
|
||||
if query:
|
||||
query_list = query.split()
|
||||
workouts = workouts.filter(
|
||||
reduce(operator.and_,
|
||||
(Q(name__icontains=q) for q in query_list)) |
|
||||
reduce(operator.and_,
|
||||
(Q(notes__icontains=q) for q in query_list))
|
||||
)
|
||||
|
||||
form = WorkoutMultipleCompareForm()
|
||||
form.fields["workouts"].queryset = workouts
|
||||
|
||||
chartform = ChartParamChoiceForm(initial={'teamid':theteam.id})
|
||||
|
||||
return render(request, 'team_compare_select.html',
|
||||
{'workouts': workouts,
|
||||
'message': message,
|
||||
'successmessage':successmessage,
|
||||
'dateform':dateform,
|
||||
'startdate':startdate,
|
||||
'enddate':enddate,
|
||||
'team':theteam,
|
||||
'form':form,
|
||||
'chartform':chartform,
|
||||
})
|
||||
|
||||
@login_required()
|
||||
def multi_compare_view(request):
|
||||
promember=0
|
||||
if not request.user.is_anonymous():
|
||||
r = Rower.objects.get(user=request.user)
|
||||
result = request.user.is_authenticated() and ispromember(request.user)
|
||||
if result:
|
||||
promember=1
|
||||
|
||||
if request.method == 'POST':
|
||||
form = WorkoutMultipleCompareForm(request.POST)
|
||||
chartform = ChartParamChoiceForm(request.POST)
|
||||
if form.is_valid() and chartform.is_valid():
|
||||
cd = form.cleaned_data
|
||||
workouts = cd['workouts']
|
||||
xparam = chartform.cleaned_data['xparam']
|
||||
yparam = chartform.cleaned_data['yparam']
|
||||
plottype = chartform.cleaned_data['plottype']
|
||||
teamid = chartform.cleaned_data['teamid']
|
||||
ids = [w.id for w in workouts]
|
||||
labeldict = {
|
||||
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]
|
||||
|
||||
return render(request,'multicompare.html',
|
||||
{'interactiveplot':script,
|
||||
'the_div':div,
|
||||
'promember':promember,
|
||||
'teamid':teamid,
|
||||
})
|
||||
else:
|
||||
return HttpResponse("Form is not valid")
|
||||
else:
|
||||
url = reverse(workouts_view)
|
||||
return HttpResponseRedirect(url)
|
||||
|
||||
# List Workouts
|
||||
@login_required()
|
||||
@@ -3302,6 +3436,16 @@ def workout_export_view(request,id=0, message="", successmessage=""):
|
||||
row = Workout.objects.get(id=id)
|
||||
except Workout.DoesNotExist:
|
||||
raise Http404("Workout doesn't exist")
|
||||
|
||||
try:
|
||||
thetoken = c2_open(request.user)
|
||||
except C2NoTokenError:
|
||||
thetoken = 0
|
||||
|
||||
if (checkworkoutuser(request.user,row)) and thetoken:
|
||||
c2userid = c2stuff.get_userid(thetoken)
|
||||
else:
|
||||
c2userid = 0
|
||||
|
||||
form = WorkoutForm(instance=row)
|
||||
g = GraphImage.objects.filter(workout=row).order_by("-creationdatetime")
|
||||
@@ -3318,6 +3462,7 @@ def workout_export_view(request,id=0, message="", successmessage=""):
|
||||
'export.html',
|
||||
{'workout':row,
|
||||
'message':message,
|
||||
'successmessage':successmessage,
|
||||
'c2userid':c2userid,
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user