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 = getsmallrowdata_pd(columns, ids=ids, doclean=True, workstrokesonly=workstrokesonly) df.dropna(axis=1,how='all',inplace=True) df.dropna(axis=0,how='all',inplace=True) 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