Coverage for middle_layer/common/application_layer/services/notification_sender_service.py: 84.00%
25 statements
« prev ^ index » next coverage.py v7.10.5, created at 2026-03-09 06:13 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2026-03-09 06:13 +0000
1# Copyright 2024 Associated Universities, Inc.
2#
3# This file is part of Telescope Time Allocation Tools (TTAT).
4#
5# TTAT is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# any later version.
9#
10# TTAT is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with TTAT. If not, see <https://www.gnu.org/licenses/>.
18from time import sleep
20import requests
22from common.utils.gitlab_secret_loader import NOTIFICATION_SERVICE_URL
25def send_notification(template: str, parameters: dict[str, str] | None = None) -> None:
26 """Send an email notification through Workspaces' notification service
28 :param template: Name of mustache template for email, must correspond to entry in Workspaces' template database
29 :param parameters: Parameters for given template
30 :raises RuntimeError: When the notification service fails to send the email
31 """
32 if parameters is None:
33 parameters = dict()
34 url = NOTIFICATION_SERVICE_URL
35 url = f"{url}/notify/{template}/send"
36 response = requests.post(url, json=parameters)
37 if response.status_code != 200:
38 # wait 5 seconds and try again: There is an issue with message collisions in the notification system,
39 # this should be unnecessary once it it resolved.
40 sleep(5)
41 response = requests.post(url, json=parameters)
42 if response.status_code != 200:
43 raise RuntimeError(
44 f"Notification failure: Expected 200 (OK) response, "
45 f"got {response.status_code} response instead: {response.text}"
46 )
47 try:
48 json = response.json()
49 except requests.JSONDecodeError:
50 raise RuntimeError(f"Notification failure: Expected JSON response, instead got: {response.text}")
51 if json["errors"] or json["message"] != "Email sent":
52 raise RuntimeError(f"Notification failure: Expected response with no errors, instead got: {json}")
55def send_basic_notification(
56 message: str, subject: str, primary_recipient: str, cc_recipient: str | None = None
57) -> None:
58 """Send a basic email notification via Workspaces' notification service
60 :param message: Body of the email
61 :param subject: Subject of the email
62 :param primary_recipient: Primary recipient of the email
63 :param cc_recipient: Optional CC recipient for the email
64 :raises RuntimeError: When the notification service fails to send the email
65 """
66 params = {
67 "message": message,
68 "subject": subject,
69 "destination_email": primary_recipient,
70 }
71 if cc_recipient is not None:
72 params["cc_email"] = cc_recipient
73 send_notification(template="email", parameters=params)