Private
Public Access
1
0

Merge branch 'feature/alertstats' into develop

This commit is contained in:
Sander Roosendaal
2019-08-29 15:11:50 +02:00
8 changed files with 140 additions and 24 deletions
+8 -1
View File
@@ -169,6 +169,10 @@ def alert_get_stats(alert,nperiod=0):
percentage = int(100.*nr_strokes_qualifying/nr_strokes) percentage = int(100.*nr_strokes_qualifying/nr_strokes)
else: else:
percentage = 0 percentage = 0
median_q = df2[alert.measured.metric].median()
median = df[alert.measured.metric].median()
std = df[alert.measured.metric].std()
return { return {
'workouts':len(workouts), 'workouts':len(workouts),
@@ -177,7 +181,10 @@ def alert_get_stats(alert,nperiod=0):
'nr_strokes':nr_strokes, 'nr_strokes':nr_strokes,
'nr_strokes_qualifying':nr_strokes_qualifying, 'nr_strokes_qualifying':nr_strokes_qualifying,
'percentage': percentage, 'percentage': percentage,
'nperiod':nperiod, 'nperiod':nperiod,
'median':median,
'median_q':median_q,
'standard_dev':std,
} }
# run alert report # run alert report
+29 -3
View File
@@ -881,9 +881,12 @@ class Rower(models.Model):
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
try: try:
for group in self.coachinggroups.all(): for group in self.coachinggroups.all():
coach = Rower.objects.get(mycoachgroup=group) try:
if coach.rowerplan == 'freecoach': coach = Rower.objects.get(mycoachgroup=group)
self.coachinggroups.remove(group) if coach.rowerplan == 'freecoach':
self.coachinggroups.remove(group)
except Rower.DoesNotExist:
pass
except ValueError: except ValueError:
pass pass
@@ -1093,6 +1096,11 @@ class Alert(models.Model):
return stri return stri
def metricname(self):
metricdict = {key:value for (key,value) in parchoicesy1}
return metricdict[self.measured.metric]
def description(self): def description(self):
metricdict = {key:value for (key,value) in parchoicesy1} metricdict = {key:value for (key,value) in parchoicesy1}
@@ -1115,6 +1123,24 @@ class Alert(models.Model):
return description return description
def shortdescription(self):
metricdict = {key:value for (key,value) in parchoicesy1}
if self.measured.condition == 'between':
description = '{value1} < {metric} < {value2}'.format(
metric = self.measured.metric,
value1 = self.measured.value1,
value2 = self.measured.value2,
)
else:
description = '{metric} {condition} {value1}'.format(
metric = self.measured.metric,
value1 = self.measured.value1,
condition = self.measured.condition
)
return description
class AlertEditForm(ModelForm): class AlertEditForm(ModelForm):
class Meta: class Meta:
+33 -2
View File
@@ -756,6 +756,26 @@ def handle_updatedps(useremail, workoutids, debug=False,**kwargs):
return 1 return 1
import math
def sigdig(value, digits = 3):
try:
order = int(math.floor(math.log10(math.fabs(value))))
except (ValueError,TypeError):
return value
# return integers as is
if value % 1 == 0:
return value
places = digits - order - 1
if places > 0:
fmtstr = "%%.%df" % (places)
else:
fmtstr = "%.0f"
return fmtstr % (round(value, places))
@app.task @app.task
def handle_send_email_alert( def handle_send_email_alert(
useremail, userfirstname, userlastname, rowerfirstname, alertname, stats, **kwargs): useremail, userfirstname, userlastname, rowerfirstname, alertname, stats, **kwargs):
@@ -770,15 +790,26 @@ def handle_send_email_alert(
else: else:
othertexts = None othertexts = None
subject = "Your rowing performance on rowsandall.com ({startdate} to {enddate})".format( report = {}
report['Percentage'] = int(stats['percentage'])
report['Number of workouts'] = int(stats['workouts'])
report['Data set'] = "{a} strokes out of {b}".format(
a = stats['nr_strokes_qualifying'],
b = stats['nr_strokes']
)
report['Median'] = sigdig(stats['median'])
report['Median of qualifying strokes'] = sigdig(stats['median_q'])
subject = "Rowsandall.com: {alertname} ({startdate} to {enddate})".format(
startdate = stats['startdate'], startdate = stats['startdate'],
enddate = stats['enddate'], enddate = stats['enddate'],
alertname=alertname,
) )
from_email = 'Rowsandall <info@rowsandall.com>' from_email = 'Rowsandall <info@rowsandall.com>'
d = { d = {
'report':stats, 'report':report,
'first_name':userfirstname, 'first_name':userfirstname,
'last_name':userlastname, 'last_name':userlastname,
'siteurl':siteurl, 'siteurl':siteurl,
+22 -7
View File
@@ -1,5 +1,6 @@
{% extends "newbase.html" %} {% extends "newbase.html" %}
{% load staticfiles %} {% load staticfiles %}
{% load rowerfilters %}
{% block title %}Metric Alert{% endblock %} {% block title %}Metric Alert{% endblock %}
@@ -13,19 +14,33 @@
</p> </p>
<ul class="main-content"> <ul class="main-content">
<li>
{{ stats|lookuplong:'startdate' }} - {{ stats|lookuplong:'enddate' }}
</li>
<li class="grid_4"> <li class="grid_4">
<h2>Alert</h2> <h2>{{ alert.name }}</h2>
<p>{{ alert }}</p> <p>{{ alert }}</p>
<p>{{ alert.description }}</p> <p>{{ alert.description }}</p>
<p>This is a page under construction. Currently with minimal information</p> <p>This is a page under construction. Currently with minimal information</p>
</li> </li>
{% for key, value in stats.items %} <li class="rounder">
<li> <h2>Score</h2>
<h2>{{ key }}</h2> <hr>
<p>{{ value }}</p> <h2>{{ stats|lookup:'percentage' }}%</h2>
</li>
<li class="rounder">
<h2>Data set</h2>
<hr>
<p>{{ stats|lookup:'workouts' }} workouts</p>
<p>{{ stats|lookup:'nr_strokes_qualifying' }} strokes out of {{ stats|lookup:'nr_strokes' }}</p>
</li>
<li class="rounder">
<h2>Statistics</h2>
<hr>
<p>Median {{ alert.metricname }}: {{ stats|lookup:'median'|sigdig }}</p>
<p>Median {{ alert.metricname }}: {{ stats|lookup:'median_q'|sigdig }} ({{ alert.shortdescription }})</p>
</li> </li>
{% endfor %}
</ul> </ul>
+14 -6
View File
@@ -1,14 +1,22 @@
<!doctype html>
<html> <html>
<head>
<meta name="viewport" content="width=device-width">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Rowsandall</title>
<style>
</style>
</head>
<body> <body>
<font face="verdana, sans-serif"> <font face="verdana, sans-serif">
<img src="https://rowsandall.com/static/img/logoemail.png" height="50"> <img src="https://rowsandall.com/static/img/logoemail.png" height="50">
<font face="verdana, sans-serif"> <font face="verdana, sans-serif">
{% block body %} {% block body %}
{% endblock %} {% endblock %}
</font> </font>
</body> </body>
</html> </html>
+32 -4
View File
@@ -4,6 +4,7 @@ from time import strftime
from django.utils import timezone from django.utils import timezone
import dateutil.parser import dateutil.parser
import json import json
import math
import datetime import datetime
import re import re
register = template.Library() register = template.Library()
@@ -37,6 +38,25 @@ from django.template.defaultfilters import stringfilter
from six import string_types from six import string_types
@register.filter
def sigdig(value, digits = 3):
try:
order = int(math.floor(math.log10(math.fabs(value))))
except (ValueError,TypeError):
return value
# return integers as is
if value % 1 == 0:
return value
places = digits - order - 1
if places > 0:
fmtstr = "%%.%df" % (places)
else:
fmtstr = "%.0f"
return fmtstr % (round(value, places))
@register.filter(is_safe=True, needs_autoescape=True) @register.filter(is_safe=True, needs_autoescape=True)
@stringfilter @stringfilter
def urlshorten(value, limit,autoescape=None): def urlshorten(value, limit,autoescape=None):
@@ -278,18 +298,26 @@ def jsdict(dict,key):
s = dict.get(key) s = dict.get(key)
return mark_safe(json.dumps(s)) return mark_safe(json.dumps(s))
@register.filter @register.filter
def lookup(dict, key): def lookup(dict, key):
s = dict.get(key) try:
s = dict.get(key)
except KeyError:
return None
if isinstance(s,string_types) and len(s) > 22: if isinstance(s,string_types) and len(s) > 22:
s = s[:22] s = s[:22]
return s return s
@register.filter @register.filter
def lookuplong(dict, key): def lookuplong(dict, key):
s = dict.get(key) try:
s = dict.get(key)
except KeyError:
return None
return s return s
@register.filter @register.filter
Binary file not shown.
+2 -1
View File
@@ -4328,7 +4328,8 @@ def alerts_view(request,userid=0):
for alert in alerts: for alert in alerts:
stats.append(alert_get_stats(alert)) stats.append(alert_get_stats(alert))
breadcrumbs = [ breadcrumbs = [
{ {
'url':'/rowers/analysis', 'url':'/rowers/analysis',