teams-alerter 0.2.2__py3-none-any.whl → 0.2.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- teams_alerter/core.py +31 -2
- teams_alerter/utils.py +80 -70
- {teams_alerter-0.2.2.dist-info → teams_alerter-0.2.4.dist-info}/METADATA +1 -1
- teams_alerter-0.2.4.dist-info/RECORD +9 -0
- {teams_alerter-0.2.2.dist-info → teams_alerter-0.2.4.dist-info}/top_level.txt +1 -0
- tests/__init__.py +0 -0
- tests/test_core.py +51 -0
- teams_alerter-0.2.2.dist-info/RECORD +0 -7
- {teams_alerter-0.2.2.dist-info → teams_alerter-0.2.4.dist-info}/WHEEL +0 -0
teams_alerter/core.py
CHANGED
@@ -2,7 +2,7 @@ import json
|
|
2
2
|
import traceback
|
3
3
|
|
4
4
|
from google.cloud import pubsub_v1
|
5
|
-
from .utils import ErrorUtils, DateUtils,
|
5
|
+
from .utils import ErrorUtils, DateUtils, format_email_template
|
6
6
|
|
7
7
|
|
8
8
|
class TeamsAlerter:
|
@@ -91,4 +91,33 @@ class TeamsAlerter:
|
|
91
91
|
|
92
92
|
def format_email_template(self):
|
93
93
|
self.payload["alert_type"].append("email")
|
94
|
-
|
94
|
+
|
95
|
+
if self.utils["app_name"] == "health_check_check_horses_stats":
|
96
|
+
error_info_list = json.loads(self.payload["detail"]["message"])
|
97
|
+
table_data = [("ID CHEVAL", "CHAMP", "POSTGRES", "MONGO", "DIFFERENCE")]
|
98
|
+
for error_info in error_info_list["data"]:
|
99
|
+
table_data.append(
|
100
|
+
(
|
101
|
+
error_info["idCheval"],
|
102
|
+
error_info["champ"],
|
103
|
+
error_info["postgres"],
|
104
|
+
error_info["mongo"],
|
105
|
+
error_info["difference"],
|
106
|
+
)
|
107
|
+
)
|
108
|
+
|
109
|
+
email_object = "Contrôle DATASTREAM - Fiche cheval"
|
110
|
+
email_messages = [
|
111
|
+
"""
|
112
|
+
Bonjour, <br>
|
113
|
+
Veuillez trouver ci-dessous le tableau récapitulatif du contrôle effectué sur la fiche cheval dans Datastream.
|
114
|
+
""",
|
115
|
+
f"""
|
116
|
+
Env: <strong>{self.utils["env"]}</strong> <br>
|
117
|
+
Timestamp: {DateUtils.get_str_utc_timestamp()} <br>
|
118
|
+
Champs: <strong>formFigs et/ou totalPrize</strong>
|
119
|
+
""",
|
120
|
+
]
|
121
|
+
|
122
|
+
self.payload["email_template_html"] = format_email_template(email_object, email_messages, table_data)
|
123
|
+
print(self.payload["email_template_html"])
|
teams_alerter/utils.py
CHANGED
@@ -31,84 +31,94 @@ class DateUtils:
|
|
31
31
|
return dt.strftime("%Y-%m-%dT%H:%M:%S") + ".000000000Z"
|
32
32
|
|
33
33
|
|
34
|
-
def
|
35
|
-
email_object = "Contrôle DATASTREAM - Fiche cheval"
|
36
|
-
email_message = """
|
37
|
-
Bonjour, <br>
|
38
|
-
Veuillez trouver ci-dessous le tableau récapitulatif du contrôle effectué sur la fiche cheval dans Datastream (champs formFigs et totalPrize) le 25/08/2025 à 13:15:00 UTC.
|
39
|
-
"""
|
34
|
+
def format_email_template(email_object, email_messages, table_data):
|
40
35
|
html = f"""
|
41
|
-
|
42
|
-
<
|
43
|
-
<
|
44
|
-
<
|
36
|
+
<html>
|
37
|
+
<head lang="fr">
|
38
|
+
<meta charset="utf-8">
|
39
|
+
<meta name="x-apple-disable-message-reformatting">
|
40
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
41
|
+
<title>Contrôle datastream</title>
|
42
|
+
</head>
|
43
|
+
<body style="margin:0; padding:0; background:#f5f7fb;">
|
44
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="background:#f5f7fb;">
|
45
45
|
<tr>
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
<td align="center" style="padding:24px;">
|
47
|
+
<table role="presentation" cellpadding="0" cellspacing="0" border="0" style="max-width:100%; background:#ffffff; border-radius:8px; border:1px solid #e6e9ef;">
|
48
|
+
<tr>
|
49
|
+
<td style="text-align: center; padding-top: 12px;">
|
50
|
+
<img style="height: 24px;" src="https://upload.wikimedia.org/wikipedia/fr/f/fd/Logo_Paris_Turf.svg" alt="" srcset="">
|
51
|
+
</td>
|
52
|
+
</tr>
|
50
53
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
<tr>
|
55
|
+
<td style="padding:24px 24px 12px 24px; font-family:Segoe UI, Arial, sans-serif; font-size:20px; line-height:26px; color:#111827; font-weight:700;">
|
56
|
+
Objet : {email_object}
|
57
|
+
</td>
|
58
|
+
</tr>
|
56
59
|
|
57
|
-
|
58
|
-
<td style="padding:0 24px 16px 24px; font-family:Segoe UI, Arial, sans-serif; font-size:14px; line-height:20px; color:#4b5563;">
|
59
|
-
{email_message}
|
60
|
-
</td>
|
61
|
-
</tr>
|
60
|
+
{build_html_message(email_messages)}
|
62
61
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
<th align="left" style="padding:12px 10px; font-size:12px; line-height:16px; color:#374151; text-transform:uppercase; letter-spacing:.5px; border-bottom:2px solid #e5e7eb; background:#f9fafb;">ID cheval</th>
|
69
|
-
<th align="left" style="padding:12px 10px; font-size:12px; line-height:16px; color:#374151; text-transform:uppercase; letter-spacing:.5px; border-bottom:2px solid #e5e7eb; background:#f9fafb;">Champ</th>
|
70
|
-
<th align="left" style="padding:12px 10px; font-size:12px; line-height:16px; color:#374151; text-transform:uppercase; letter-spacing:.5px; border-bottom:2px solid #e5e7eb; background:#f9fafb;">Postgres</th>
|
71
|
-
<th align="left" style="padding:12px 10px; font-size:12px; line-height:16px; color:#374151; text-transform:uppercase; letter-spacing:.5px; border-bottom:2px solid #e5e7eb; background:#f9fafb;">Mongo</th>
|
72
|
-
<th align="left" style="padding:12px 10px; font-size:12px; line-height:16px; color:#374151; text-transform:uppercase; letter-spacing:.5px; border-bottom:2px solid #e5e7eb; background:#f9fafb;">Différence</th>
|
73
|
-
</tr>
|
74
|
-
<!-- Row 1 -->
|
75
|
-
<tr>
|
76
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">12345</td>
|
77
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">formFigs</td>
|
78
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">8a 6a Da (24) 7a 8a 10a ...</td>
|
79
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">Da (24) 7a 8a 10a ...</td>
|
80
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">Début tronqué (8a 6a manquants)</td>
|
81
|
-
</tr>
|
82
|
-
<!-- Row 2 -->
|
83
|
-
<tr>
|
84
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827;">123456</td>
|
85
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827;">totalPrize</td>
|
86
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827;">108220</td>
|
87
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827;">108222</td>
|
88
|
-
<td style="padding:10px; font-size:14px; line-height:20px; color:#111827;">-2</td>
|
89
|
-
</tr>
|
90
|
-
</table>
|
91
|
-
</td>
|
92
|
-
</tr>
|
62
|
+
<tr>
|
63
|
+
<td style="padding:0 16px 24px 16px;">
|
64
|
+
{build_html_table(table_data)}
|
65
|
+
</td>
|
66
|
+
</tr>
|
93
67
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
68
|
+
<tr>
|
69
|
+
<td style="padding:0 24px 16px 24px; font-family:Segoe UI, Arial, sans-serif; font-size:14px; line-height:20px; color:#4b5563;">
|
70
|
+
Cordialement,
|
71
|
+
</td>
|
72
|
+
</tr>
|
99
73
|
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
74
|
+
<tr>
|
75
|
+
<td style="padding:0 24px 24px 24px; font-family:Segoe UI, Arial, sans-serif; font-size:12px; line-height:18px; color:#6b7280;">
|
76
|
+
<div style="border-top:1px solid #eef2f7; padding-top:12px;text-align: center;">
|
77
|
+
Message automatique – ne pas répondre. <br>
|
78
|
+
© 2025 Paris-Turf – Tous droits réservés <br>
|
79
|
+
<a href="https://www.paris-turf.com">www.paris-turf.com</a>
|
80
|
+
</div>
|
81
|
+
</td>
|
82
|
+
</tr>
|
83
|
+
</table>
|
84
|
+
</td>
|
108
85
|
</tr>
|
109
86
|
</table>
|
110
|
-
|
111
|
-
|
112
|
-
</table>
|
87
|
+
</body>
|
88
|
+
</html>
|
113
89
|
"""
|
114
90
|
return html
|
91
|
+
|
92
|
+
|
93
|
+
def build_html_table(table_data: list):
|
94
|
+
html_table = '<table role="presentation" cellpadding="0" cellspacing="0" border="0" width="100%" style="border-collapse:collapse; font-family:Segoe UI, Arial, sans-serif;">'
|
95
|
+
|
96
|
+
# format header
|
97
|
+
html_table += "<tr>"
|
98
|
+
for header in table_data[0]:
|
99
|
+
html_table += f'<th style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">{header}</th>'
|
100
|
+
html_table += "</tr>"
|
101
|
+
|
102
|
+
# format rows
|
103
|
+
for row in table_data[1:]:
|
104
|
+
html_table += "<tr>"
|
105
|
+
for cell in row:
|
106
|
+
html_table += f'<td style="padding:10px; font-size:14px; line-height:20px; color:#111827; border-bottom:1px solid #bbbbbb;">{cell}</td>'
|
107
|
+
html_table += "</tr>"
|
108
|
+
|
109
|
+
html_table += "</table>"
|
110
|
+
|
111
|
+
return html_table
|
112
|
+
|
113
|
+
|
114
|
+
def build_html_message(email_messages: list[str]):
|
115
|
+
content = ""
|
116
|
+
for email_message in email_messages:
|
117
|
+
content += f"""
|
118
|
+
<tr>
|
119
|
+
<td style="padding:0 24px 16px 24px; font-family:Segoe UI, Arial, sans-serif; font-size:14px; line-height:20px; color:#4b5563;">
|
120
|
+
{email_message}
|
121
|
+
</td>
|
122
|
+
</tr>
|
123
|
+
"""
|
124
|
+
return content
|
@@ -0,0 +1,9 @@
|
|
1
|
+
teams_alerter/__init__.py,sha256=J6zyyTfUNVElXD0wsTqBwp-VtcApbzYGUPpChrdcbpY,131
|
2
|
+
teams_alerter/core.py,sha256=oWKn8tNNDJ6Vd-2wFyAZHjoo_stU1PcyY_M5KRaKyjc,4964
|
3
|
+
teams_alerter/utils.py,sha256=jP3JTnrOmriz60aWbmzc76P_xrETxvJNsUS1TCcz94Y,5342
|
4
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
|
+
tests/test_core.py,sha256=Bd3rxUUXAYM3oKK4Gs5u2AF4-Di5oSmXsMeHINfEHyM,3089
|
6
|
+
teams_alerter-0.2.4.dist-info/METADATA,sha256=vdBtGz_LIMdnGoEv4UPR0CQG_nOSSgcAZv2y855yQgU,2194
|
7
|
+
teams_alerter-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
8
|
+
teams_alerter-0.2.4.dist-info/top_level.txt,sha256=eLk39V0LcwZmxaC5MkgLKvTLeBaox3XkfSvXxm7GVik,20
|
9
|
+
teams_alerter-0.2.4.dist-info/RECORD,,
|
tests/__init__.py
ADDED
File without changes
|
tests/test_core.py
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
import pytest
|
2
|
+
import os
|
3
|
+
import json
|
4
|
+
|
5
|
+
from teams_alerter.core import TeamsAlerter
|
6
|
+
|
7
|
+
|
8
|
+
def test_error_handler():
|
9
|
+
env = "dev"
|
10
|
+
ERROR_UTILS = {
|
11
|
+
"env": env,
|
12
|
+
"app_project_id": os.environ.get("ERROR_HANDLER_APP_PROJECT_ID", "betin-horse-datastream-" + env),
|
13
|
+
"topic_project_id": os.environ.get("ERROR_HANDLER_TOPIC_PROJECT_ID", "betin-horse-datastream-" + env),
|
14
|
+
"topic_id": os.environ.get("ERROR_HANDLER_TOPIC_ID", "topic-datastream-errors-" + env),
|
15
|
+
"app_name": "health_check_check_horses_stats",
|
16
|
+
"teams_channel": "datastream-alerts-" + env,
|
17
|
+
}
|
18
|
+
diffs_list = [
|
19
|
+
{
|
20
|
+
"idCheval": 1338148,
|
21
|
+
"champ": "formFigs",
|
22
|
+
"postgres": '<span style="background-color:yellow; color:#000;">5a</span> 8a 8a 3a (24) 13a 12a 9a 10a Da 7a 7m 9a 10a 8m 6a 0a Da 10a 7a 7a (23) 11a 1a 2a 5a 10a 4a Aa 3a 10a Aa 3a 10a 2a 3a 3a 3a Da 4a 7a (22) 7a 3a 3a 1a 12a 6a 1a 1a 2a 7a 1a 4a 4a 1a 6a 1a 4a 10a (21) 14a 4a 5a 4a 1a 3a 2a 4a 7a 3a 5a 4a 6a 2a 2a 7a 7a 7a (20) 1a 1a 2a 4a 6a 1a 3a 5a 1a 1a 4a 1a 3a 4a 2a 2a (19) 4a 5a Da Da 4a 5Da 3a 5a 1a 4a (18) Da Da 5a 2a',
|
23
|
+
"mongo": "8a 8a 3a (24) 13a 12a 9a 10a Da 7a 7m 9a 10a 8m 6a 0a Da 10a 7a 7a (23) 11a 1a 2a 5a 10a 4a Aa 3a 10a Aa 3a 10a 2a 3a 3a 3a Da 4a 7a (22) 7a 3a 3a 1a 12a 6a 1a 1a 2a 7a 1a 4a 4a 1a 6a 1a 4a 10a (21) 14a 4a 5a 4a 1a 3a 2a 4a 7a 3a 5a 4a 6a 2a 2a 7a 7a 7a (20) 1a 1a 2a 4a 6a 1a 3a 5a 1a 1a 4a 1a 3a 4a 2a 2a (19) 4a 5a Da Da 4a 5Da 3a 5a 1a 4a (18) Da Da 5a 2a",
|
24
|
+
"difference": "5a manquants dans Mongo",
|
25
|
+
},
|
26
|
+
{
|
27
|
+
"idCheval": 1338148,
|
28
|
+
"champ": "totalPrize",
|
29
|
+
"postgres": 308670,
|
30
|
+
"mongo": 304920,
|
31
|
+
"difference": "3750 de moins dans Mongo",
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"idCheval": 1343727,
|
35
|
+
"champ": "formFigs",
|
36
|
+
"postgres": '<span style="background-color:yellow; color:#000;">4a</span> <span style="background-color:yellow; color:#000;">4a</span> 4m 9m 7a Da 9a 3m (24) 6a 1a 1a 5a 6a 1a Da 4a 6a 4a 3a 5a 2a 0a (23) 9a 6a Da Aa 1a 0a 3a Da 4m 7a 7a Da 3a 4Dista 5a 9a (22) 13a 11a 6a Aa 4a 8a 3a 2a 3a 4a 4a 3a 6a 8a (21) 1a Da 11a 9a 6a 3a 3a 5a 3a Da 2a 4a 1a 11a Da 6a 2a (20) 1a 11a Da 3a Aa 3a 3a 9a 1a 8a 5a (19) 4a 2a 5a 4a 1a 7a',
|
37
|
+
"mongo": "4m 9m 7a Da 9a 3m (24) 6a 1a 1a 5a 6a 1a Da 4a 6a 4a 3a 5a 2a 0a (23) 9a 6a Da Aa 1a 0a 3a Da 4m 7a 7a Da 3a 4Dista 5a 9a (22) 13a 11a 6a Aa 4a 8a 3a 2a 3a 4a 4a 3a 6a 8a (21) 1a Da 11a 9a 6a 3a 3a 5a 3a Da 2a 4a 1a 11a Da 6a 2a (20) 1a 11a Da 3a Aa 3a 3a 9a 1a 8a 5a (19) 4a 2a 5a 4a 1a 7a",
|
38
|
+
"difference": "4a 4a manquants dans Mongo",
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"idCheval": 1343727,
|
42
|
+
"champ": "totalPrize",
|
43
|
+
"postgres": 163935,
|
44
|
+
"mongo": 159775,
|
45
|
+
"difference": "4160 de moins dans Mongo",
|
46
|
+
},
|
47
|
+
]
|
48
|
+
error = ValueError(
|
49
|
+
ValueError(json.dumps({"data": diffs_list, "message": f"[Vérification horses_stats du 2025-08-29]"}))
|
50
|
+
)
|
51
|
+
TeamsAlerter.handle_error(error, ERROR_UTILS)
|
@@ -1,7 +0,0 @@
|
|
1
|
-
teams_alerter/__init__.py,sha256=J6zyyTfUNVElXD0wsTqBwp-VtcApbzYGUPpChrdcbpY,131
|
2
|
-
teams_alerter/core.py,sha256=5KEH5BxAhRizcsAq7oSzdgrRMFsBqMPW577trAdchfE,3653
|
3
|
-
teams_alerter/utils.py,sha256=YxFujHeq64EbB-ra3ShSM-0SrCsXxWODlAn7Wy6oxzY,6687
|
4
|
-
teams_alerter-0.2.2.dist-info/METADATA,sha256=6DemT05MGWOGxLDGxqyQ29bPtlR2M9SifPh-FASRAYA,2194
|
5
|
-
teams_alerter-0.2.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
6
|
-
teams_alerter-0.2.2.dist-info/top_level.txt,sha256=Qt8-VgHT7YPTbMzYkAomK9itC-w4YpV7IJ5X6b-TC-4,14
|
7
|
-
teams_alerter-0.2.2.dist-info/RECORD,,
|
File without changes
|