Private
Public Access
1
0
Files
rowsandall/rowers/alerts.py

241 lines
7.2 KiB
Python

from rowers.models import Alert, Condition, User, Rower, Workout
from rowers.teams import coach_getcoachees
from rowers.dataprep import getrowdata_db, read_data, remove_nulls_pl
import datetime
import numpy as np
import math
def create_alert(manager, rower, measured, period=7, emailalert=True,
reststrokes=False, workouttype='water', boattype='1x',
name='', **kwargs):
# check if manager is coach of rower. If not return 0
if manager.rower != rower: # pragma: no cover
if rower not in coach_getcoachees(manager.rower):
return 0, 'You are not allowed to create this alert'
m = Condition(
metric=measured['metric'],
value1=measured['value1'],
value2=measured['value2'],
condition=measured['condition']
)
m.save()
alert = Alert(name=name,
manager=manager,
rower=rower,
measured=m,
reststrokes=reststrokes,
period=period,
emailalert=emailalert,
workouttype=workouttype,
boattype=boattype,
)
alert.save()
if 'filter' in kwargs:
filters = kwargs['filter']
for f in filters:
if f['metric'] and f['condition']:
m = Condition(
metric=f['metric'],
value1=f['value1'],
value2=f['value2'],
condition=f['condition']
)
m.save()
alert.filter.add(m)
return alert.id, 'Your alert was created'
# update alert
def alert_add_filters(alert, filters):
for f in alert.filter.all():
alert.filter.remove(f)
f.delete()
for f in filters:
metric = f['metric']
value1 = f['value1']
condition = f['condition']
if condition and metric and value1:
m = Condition(
metric=f['metric'],
value1=f['value1'],
value2=f['value2'],
condition=f['condition']
)
m.save()
alert.filter.add(m)
return 1
# get alert stats
# nperiod = 0: current period, i.e. next_run - n days to today
# nperiod = 1: 1 period ago , i.e. next_run -2n days to next_run -n days
def alert_get_stats(alert, nperiod=0): # pragma: no cover
# get strokes
workstrokesonly = not alert.reststrokes
startdate = (alert.next_run -
datetime.timedelta(days=(nperiod+1)*alert.period-1))
enddate = alert.next_run - datetime.timedelta(days=(nperiod)*alert.period)
columns = [alert.measured.metric]
for condition in alert.filter.all():
columns.append(condition.metric)
workouts = Workout.objects.filter(date__gte=startdate, date__lte=enddate, user=alert.rower,
workouttype=alert.workouttype, duplicate=False,
boattype=alert.boattype)
ids = [w.id for w in workouts]
try:
df = read_data(columns, ids=ids, doclean=True,
workstrokesonly=workstrokesonly)
df = remove_nulls_pl(df)
except:
return {
'workouts': workouts.count(),
'startdate': startdate,
'enddate': enddate,
'nr_strokes': 0,
'nr_strokes_qualifying': 0,
'percentage': 0,
'nperiod': nperiod,
'median': 0,
'median_q': 0,
'standard_dev': 0,
}
if df.empty:
return {
'workouts': workouts.count(),
'startdate': startdate,
'enddate': enddate,
'nr_strokes': 0,
'nr_strokes_qualifying': 0,
'percentage': 0,
'nperiod': nperiod,
'median': 0,
'median_q': 0,
'standard_dev': 0,
}
# check if filters are in columns list
pdcolumns = set(df.columns) # pragma: no cover
# drop strokes through filter
if set(columns) <= pdcolumns: # pragma: no cover
for condition in alert.filter.all():
if condition.condition == '>':
mask = df[condition.metric] > condition.value1
df.loc[mask, alert.measured.metric] = np.nan
elif condition.condition == '<':
mask = df[condition.metric] < condition.value1
df.loc[mask, alert.measured.metric] = np.nan
elif condition.condition == 'between':
mask = df[condition.metric] > condition.value1
mask2 = df[condition.metric] < condition.value2
df.loc[mask & mask2, alert.measured.metric] = np.nan
elif condition.condition == '=':
mask = df[condition.metric] == condition.value1
df.loc[mask, alert.measured.metric] = np.nan
df.dropna(inplace=True, axis=0)
else: # pragma: no cover
return {
'workouts': workouts.count(),
'startdate': startdate,
'enddate': enddate,
'nr_strokes': 0,
'nr_strokes_qualifying': 0,
'percentage': 0,
'nperiod': nperiod,
'median': 0,
'median_q': 0,
'standard_dev': 0,
}
# count strokes
nr_strokes = len(df)
# count qualifying
if alert.measured.condition == '>':
mask = df[alert.measured.metric] > alert.measured.value1
df2 = df[mask].copy()
elif alert.measured.condition == '<':
mask = df[alert.measured.metric] < alert.measured.value1
df2 = df[mask].copy()
elif alert.measured.condition == 'between':
mask = df[alert.measured.metric] > alert.measured.value1
mask2 = df[alert.measured.metric] < alert.measured.value2
df2 = df[mask & mask2].copy()
else:
mask = df[alert.measured.metric] == alert.measured.value1
df2 = df[mask].copy()
nr_strokes_qualifying = len(df2)
if nr_strokes > 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()
data = {
'workouts': workouts.count(),
'startdate': startdate,
'enddate': enddate,
'nr_strokes': nr_strokes,
'nr_strokes_qualifying': nr_strokes_qualifying,
'percentage': percentage,
'nperiod': nperiod,
'median': median,
'median_q': median_q,
'standard_dev': std,
}
data_clean = {}
for k in data:
data_clean[k] = data[k]
try:
if math.isnan(data[k]):
data_clean[k] = 0
except TypeError:
pass
return data_clean
# run alert report
# check alert permission
from django.utils import timezone
def checkalertowner(alert, user):
if alert.manager == user:
return True
if alert.rower.user == user: # pragma: no cover
return True
coaches = alert.manager.rower.get_coaches()
for coach in coaches:
if coach.rowerplan == 'coach':
return True
if coach.coachtrialexpires >= timezone.now().date():
return True
return False # pragma: no cover