-
Notifications
You must be signed in to change notification settings - Fork 25
/
utils.py
159 lines (120 loc) · 4.86 KB
/
utils.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
from datetime import datetime, timedelta
from typing import Optional
import pytz
from flask import url_for
from notifications_utils.template import (
HTMLEmailTemplate,
LetterPrintTemplate,
SMSMessageTemplate,
)
from notifications_utils.timezones import convert_bst_to_utc
from sqlalchemy import func
from app.constants import (
BROADCAST_TYPE,
EMAIL_TYPE,
LETTER_TYPE,
PRECOMPILED_LETTER,
SMS_TYPE,
UPLOAD_DOCUMENT,
CacheKeys,
)
DATETIME_FORMAT_NO_TIMEZONE = "%Y-%m-%d %H:%M:%S.%f"
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
DATE_FORMAT = "%Y-%m-%d"
local_timezone = pytz.timezone("Europe/London")
def pagination_links(pagination, endpoint, **kwargs):
if "page" in kwargs:
kwargs.pop("page", None)
links = {}
if pagination.has_prev:
links["prev"] = url_for(endpoint, page=pagination.prev_num, **kwargs)
if pagination.has_next:
links["next"] = url_for(endpoint, page=pagination.next_num, **kwargs)
links["last"] = url_for(endpoint, page=pagination.pages, **kwargs)
return links
def get_prev_next_pagination_links(current_page, next_page_exists, endpoint, **kwargs):
if "page" in kwargs:
kwargs.pop("page", None)
links = {}
if current_page > 1:
links["prev"] = url_for(endpoint, page=current_page - 1, **kwargs)
if next_page_exists:
links["next"] = url_for(endpoint, page=current_page + 1, **kwargs)
return links
def url_with_token(data, url, config, base_url=None):
from notifications_utils.url_safe_token import generate_token
token = generate_token(data, config["SECRET_KEY"], config["DANGEROUS_SALT"])
base_url = (base_url or config["ADMIN_BASE_URL"]) + url
return base_url + token
def get_template_instance(template, values):
return {
SMS_TYPE: SMSMessageTemplate,
EMAIL_TYPE: HTMLEmailTemplate,
LETTER_TYPE: LetterPrintTemplate,
BROADCAST_TYPE: SMSMessageTemplate,
}[template["template_type"]](template, values)
def get_london_midnight_in_utc(date):
"""
This function converts date to midnight as BST (British Standard Time) to UTC,
the tzinfo is lastly removed from the datetime because the database stores the timestamps without timezone.
:param date: the day to calculate the London midnight in UTC for
:return: the datetime of London midnight in UTC, for example 2016-06-17 = 2016-06-16 23:00:00
"""
return convert_bst_to_utc(datetime.combine(date, datetime.min.time()))
def get_midnight_for_day_before(date):
day_before = date - timedelta(1)
return get_london_midnight_in_utc(day_before)
def get_london_month_from_utc_column(column):
"""
Where queries need to count notifications by month it needs to be
the month in BST (British Summer Time).
The database stores all timestamps as UTC without the timezone.
- First set the timezone on created_at to UTC
- then convert the timezone to BST (or Europe/London)
- lastly truncate the datetime to month with which we can group
queries
"""
return func.date_trunc("month", func.timezone("Europe/London", func.timezone("UTC", column)))
def get_public_notify_type_text(notify_type, plural=False):
notify_type_text = notify_type
if notify_type == SMS_TYPE:
notify_type_text = "text message"
elif notify_type == UPLOAD_DOCUMENT:
notify_type_text = "document"
elif notify_type == PRECOMPILED_LETTER:
notify_type_text = "precompiled letter"
elif notify_type == BROADCAST_TYPE:
notify_type_text = "broadcast message"
return "{}{}".format(notify_type_text, "s" if plural else "")
def midnight_n_days_ago(number_of_days):
"""
Returns midnight a number of days ago. Takes care of daylight savings etc.
"""
return get_london_midnight_in_utc(datetime.utcnow() - timedelta(days=number_of_days))
def escape_special_characters(string):
for special_character in ("\\", "_", "%", "/"):
string = string.replace(special_character, r"\{}".format(special_character))
return string
def email_address_is_nhs(email_address):
return email_address.lower().endswith(
(
"@nhs.uk",
"@nhs.net",
".nhs.uk",
".nhs.net",
)
)
def get_archived_db_column_value(column):
date = datetime.utcnow().strftime("%Y-%m-%d")
return f"_archived_{date}_{column}"
def get_dt_string_or_none(val):
return val.strftime(DATETIME_FORMAT) if val else None
def get_uuid_string_or_none(val):
return str(val) if val else None
def format_sequential_number(sequential_number):
return format(sequential_number, "x").zfill(8)
def get_ft_billing_data_for_today_updated_at() -> Optional[str]:
from app import redis_store
if updated_at_utc_isoformat := redis_store.get(CacheKeys.FT_BILLING_FOR_TODAY_UPDATED_AT_UTC_ISOFORMAT):
return updated_at_utc_isoformat.decode()
return None