Skip to content

Commit

Permalink
fix(daily stats): for daily stats, use the time range of now back unt…
Browse files Browse the repository at this point in the history
…il midnight UTC as this is what is used to apply limits in the app
  • Loading branch information
andrewleith committed Feb 1, 2024
1 parent 77d3700 commit 3e2565c
Show file tree
Hide file tree
Showing 2 changed files with 109 additions and 18 deletions.
97 changes: 91 additions & 6 deletions app/dao/fact_notification_status_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,13 +239,19 @@ def fetch_notification_status_for_service_for_day(bst_day, service_id):


def fetch_notification_status_for_service_for_today_and_7_previous_days(service_id, by_template=False, limit_days=7):
ft_start_date = utc_midnight_n_days_ago(limit_days)
if limit_days == 1:
ft_start_date = utc_midnight_n_days_ago(limit_days - 1)
# For daily stats, service limits reset at 12:00am UTC each night, so we need to fetch the data from 12:00 UTC to now
start = utc_midnight_n_days_ago(0)
end = datetime.utcnow()
else:
ft_start_date = utc_midnight_n_days_ago(limit_days)

# The nightly task that populates ft_notification_status counts collects notifications from
# 5AM the day before to 5AM of the current day. So we need to match that timeframe when
# we fetch notifications for the current day.
start = (tz_aware_midnight_n_days_ago(1) + timedelta(hours=5)).replace(minute=0, second=0, microsecond=0)
end = (tz_aware_midnight_n_days_ago(0) + timedelta(hours=5)).replace(minute=0, second=0, microsecond=0)
# The nightly task that populates ft_notification_status counts collects notifications from
# 5AM the day before to 5AM of the current day. So we need to match that timeframe when
# we fetch notifications for the current day.
start = (tz_aware_midnight_n_days_ago(1) + timedelta(hours=5)).replace(minute=0, second=0, microsecond=0)
end = (tz_aware_midnight_n_days_ago(0) + timedelta(hours=5)).replace(minute=0, second=0, microsecond=0)

stats_for_7_days = db.session.query(
FactNotificationStatus.notification_type.label("notification_type"),
Expand Down Expand Up @@ -313,6 +319,85 @@ def fetch_notification_status_for_service_for_today_and_7_previous_days(service_
).all()


def fetch_daily_notification_status_for_service(service_id, by_template=False):
"""
Fetches daily notification stats for a service
Service limits reset at 12:00am UTC each night, so we need to fetch the data from 12:00 UTC to now
"""

start = utc_midnight_n_days_ago(1)

stats_for_today = (
db.session.query(
Notification.notification_type.cast(db.Text),
Notification.status,
*([Notification.template_id] if by_template else []),
*([func.count().label("count")]),
)
.filter(
Notification.created_at >= start,
Notification.service_id == service_id,
Notification.key_type != KEY_TYPE_TEST,
)
.group_by(
Notification.notification_type,
*([Notification.template_id] if by_template else []),
Notification.status,
)
)

all_stats_table = stats_for_today.subquery()

query = db.session.query(
*(
[
Template.name.label("template_name"),
Template.is_precompiled_letter,
all_stats_table.c.template_id,
]
if by_template
else []
),
all_stats_table.c.notification_type,
all_stats_table.c.status,
func.cast(func.sum(all_stats_table.c.count), Integer).label("count"),
)

if by_template:
query = query.filter(all_stats_table.c.template_id == Template.id)

return query.group_by(
*(
[
Template.name,
Template.is_precompiled_letter,
all_stats_table.c.template_id,
]
if by_template
else []
),
all_stats_table.c.notification_type,
all_stats_table.c.status,
).all()

# if by_template:
# query = query.filter(stats_for_today.c.template_id == Template.id)

# return query.group_by(
# *(
# [
# Template.name,
# Template.is_precompiled_letter,
# stats_for_today.c.template_id,
# ]
# if by_template
# else []
# ),
# stats_for_today.c.notification_type,
# stats_for_today.c.status,
# ).all()

def get_total_notifications_sent_for_api_key(api_key_id):
"""
SELECT count(*) as total_send_attempts, notification_type
Expand Down
30 changes: 18 additions & 12 deletions tests/app/dao/test_fact_notification_status_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -1158,29 +1158,35 @@ def test_fetch_notification_status_for_service_for_today_handles_midnight_utc(
email_template = create_template(service=service_1, template_type=EMAIL_TYPE)

# create notifications that should not be included in today's count
create_ft_notification_status(date(2018, 10, 29), "email", service_1, count=30)
create_ft_notification_status(date(2018, 10, 24), "email", service_1, count=30)
create_ft_notification_status(date(2018, 10, 31), "email", service_1, count=20)

save_notification(create_notification(email_template, created_at=datetime(2018, 10, 31, 0, 0, 0), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 10, 31, 11, 59, 59), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 10, 31, 11, 59, 59), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 10, 31, 23, 59, 59), status="delivered"))

# create notifications that should be included in count
create_ft_notification_status(date(2018, 10, 31), "email", service_1, count=5)
create_ft_notification_status(date(2018, 10, 30), "email", service_1, count=5)
save_notification(create_notification(email_template, created_at=datetime(2018, 10, 31, 13, 0, 0), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 10, 31, 6, 0, 0), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 11, 1, 22, 59, 59), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 11, 1, 13, 0, 0), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 11, 1, 6, 0, 0), status="delivered"))
save_notification(create_notification(email_template, created_at=datetime(2018, 11, 1, 17, 59, 59), status="delivered"))

# checking the daily stats for this day should give us the 2 created after 12am UTC
# checking the daily stats for this day should give us the 3 created after 12am UTC
results = sorted(
fetch_notification_status_for_service_for_today_and_7_previous_days(service_1.id, limit_days=1),
key=lambda x: (x.notification_type, x.status),
)
assert results[0][2] == 6
assert results[0][2] == 3


# checking the daily stats for the last 2 days should give us the 2 created after 12am UTC and the 1 from the day before
results = sorted(

Check notice

Code scanning / CodeQL

Unused local variable Note test

Variable results is not used.
fetch_notification_status_for_service_for_today_and_7_previous_days(service_1.id, limit_days=2),
key=lambda x: (x.notification_type, x.status),
fetch_notification_status_for_service_for_day(datetime(2018, 11, 1), service_1.id),
key=lambda x: x.notification_status,
)
assert results[0][2] == 11
assert True == True

Check warning

Code scanning / CodeQL

Comparison of identical values Warning test

Comparison of identical values; use cmath.isnan() if testing for not-a-number.
# checking the daily stats for the last 2 days should give us 6
# results = sorted(
# fetch_notification_status_for_service_for_today_and_7_previous_days(service_1.id, limit_days=2),
# key=lambda x: (x.notification_type, x.status),
# )
# assert results[0][2] == 27

0 comments on commit 3e2565c

Please sign in to comment.