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)
else:
percentage = 0
median_q = df2[alert.measured.metric].median()
median = df[alert.measured.metric].median()
std = df[alert.measured.metric].std()
return {
'workouts':len(workouts),
@@ -177,7 +181,10 @@ def alert_get_stats(alert,nperiod=0):
'nr_strokes':nr_strokes,
'nr_strokes_qualifying':nr_strokes_qualifying,
'percentage': percentage,
'nperiod':nperiod,
'nperiod':nperiod,
'median':median,
'median_q':median_q,
'standard_dev':std,
}
# run alert report
+29 -3
View File
@@ -881,9 +881,12 @@ class Rower(models.Model):
def save(self, *args, **kwargs):
try:
for group in self.coachinggroups.all():
coach = Rower.objects.get(mycoachgroup=group)
if coach.rowerplan == 'freecoach':
self.coachinggroups.remove(group)
try:
coach = Rower.objects.get(mycoachgroup=group)
if coach.rowerplan == 'freecoach':
self.coachinggroups.remove(group)
except Rower.DoesNotExist:
pass
except ValueError:
pass
@@ -1093,6 +1096,11 @@ class Alert(models.Model):
return stri
def metricname(self):
metricdict = {key:value for (key,value) in parchoicesy1}
return metricdict[self.measured.metric]
def description(self):
metricdict = {key:value for (key,value) in parchoicesy1}
@@ -1115,6 +1123,24 @@ class Alert(models.Model):
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 Meta:
+33 -2
View File
@@ -756,6 +756,26 @@ def handle_updatedps(useremail, workoutids, debug=False,**kwargs):
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
def handle_send_email_alert(
useremail, userfirstname, userlastname, rowerfirstname, alertname, stats, **kwargs):
@@ -770,15 +790,26 @@ def handle_send_email_alert(
else:
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'],
enddate = stats['enddate'],
alertname=alertname,
)
from_email = 'Rowsandall <info@rowsandall.com>'
d = {
'report':stats,
'report':report,
'first_name':userfirstname,
'last_name':userlastname,
'siteurl':siteurl,
+22 -7
View File
@@ -1,5 +1,6 @@
{% extends "newbase.html" %}
{% load staticfiles %}
{% load rowerfilters %}
{% block title %}Metric Alert{% endblock %}
@@ -13,19 +14,33 @@
</p>
<ul class="main-content">
<li>
{{ stats|lookuplong:'startdate' }} - {{ stats|lookuplong:'enddate' }}
</li>
<li class="grid_4">
<h2>Alert</h2>
<h2>{{ alert.name }}</h2>
<p>{{ alert }}</p>
<p>{{ alert.description }}</p>
<p>This is a page under construction. Currently with minimal information</p>
</li>
{% for key, value in stats.items %}
<li>
<h2>{{ key }}</h2>
<p>{{ value }}</p>
<li class="rounder">
<h2>Score</h2>
<hr>
<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>
{% endfor %}
</ul>
+14 -6
View File
@@ -1,14 +1,22 @@
<!doctype 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>
<font face="verdana, sans-serif">
<img src="https://rowsandall.com/static/img/logoemail.png" height="50">
<font face="verdana, sans-serif">
{% block body %}
{% endblock %}
<img src="https://rowsandall.com/static/img/logoemail.png" height="50">
<font face="verdana, sans-serif">
{% block body %}
{% endblock %}
</font>
</body>
</html>
+32 -4
View File
@@ -4,6 +4,7 @@ from time import strftime
from django.utils import timezone
import dateutil.parser
import json
import math
import datetime
import re
register = template.Library()
@@ -37,6 +38,25 @@ from django.template.defaultfilters import stringfilter
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)
@stringfilter
def urlshorten(value, limit,autoescape=None):
@@ -278,18 +298,26 @@ def jsdict(dict,key):
s = dict.get(key)
return mark_safe(json.dumps(s))
@register.filter
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:
s = s[:22]
return s
@register.filter
def lookuplong(dict, key):
s = dict.get(key)
try:
s = dict.get(key)
except KeyError:
return None
return s
@register.filter
Binary file not shown.
+2 -1
View File
@@ -4328,7 +4328,8 @@ def alerts_view(request,userid=0):
for alert in alerts:
stats.append(alert_get_stats(alert))
breadcrumbs = [
{
'url':'/rowers/analysis',