webhook_server 1.0.0__tar.gz → 1.0.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webhook_server
3
- Version: 1.0.0
3
+ Version: 1.0.2
4
4
  Summary: Create a webhook server with Flask to forward Datadog alerts to Telegram
5
5
  Keywords: datadog,webhook,telegram
6
6
  Author: daisukixci
@@ -88,6 +88,13 @@ curl -X POST -H "Content-Type: application/json"\
88
88
 
89
89
  ### Documentation
90
90
 
91
+ #### publish
92
+ ```
93
+ uv version VERSION
94
+ uv build
95
+ uv publish --token=$(op read "op://Private/PyPI/publish_token")
96
+ ```
97
+
91
98
  ### Contribute
92
99
  Open to any PR/comments/issues
93
100
 
@@ -61,6 +61,13 @@ curl -X POST -H "Content-Type: application/json"\
61
61
 
62
62
  ### Documentation
63
63
 
64
+ #### publish
65
+ ```
66
+ uv version VERSION
67
+ uv build
68
+ uv publish --token=$(op read "op://Private/PyPI/publish_token")
69
+ ```
70
+
64
71
  ### Contribute
65
72
  Open to any PR/comments/issues
66
73
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "webhook_server"
3
- version = "1.0.0"
3
+ version = "1.0.2"
4
4
  description = "Create a webhook server with Flask to forward Datadog alerts to Telegram"
5
5
  authors = [{ name = "daisukixci", email = "piquenot.gaetan+pip@gmail.com" }]
6
6
  requires-python = ">=3.10,<4"
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+ from dataclasses import dataclass, asdict
3
+ from datetime import datetime, UTC
4
+ import re
5
+
6
+
7
+ @dataclass
8
+ class DatadogOrg:
9
+ id: int
10
+ name: str
11
+
12
+
13
+ @dataclass
14
+ class DatadogAlertContent:
15
+ title: str
16
+ event_type: str
17
+ body: str
18
+ date: int
19
+ org: DatadogOrg
20
+ id: int
21
+ last_updated: int
22
+
23
+ def to_dict(self) -> dict:
24
+ return asdict(self)
25
+
26
+
27
+ class DatadogAlert:
28
+ def __init__(self, alert: DatadogAlertContent):
29
+ self._alert = alert
30
+
31
+ def get_message(self) -> str:
32
+ message = f"""<b>{self._alert.title}</b>
33
+ In Org <b>{self._alert.org['name']}</b>({self._alert.org['id']})
34
+ At {datetime.fromtimestamp(int(self._alert.date), tz=UTC).strftime("%Y/%m/%d %H:%M")}
35
+ {_clean_msg(self._alert.body)}"""
36
+ return message
37
+
38
+
39
+ def _markdown_to_html_links(markdown_text):
40
+ pattern = r"\[([^\]]+)\]\(([^)]+)\)"
41
+ html_text = re.sub(pattern, r'<a href="\2">\1</a>', markdown_text)
42
+ return html_text
43
+
44
+
45
+ def _clean_msg(msg: str) -> str:
46
+ return _markdown_to_html_links(msg.strip("%"))
@@ -3,12 +3,9 @@ from flask.typing import ResponseReturnValue
3
3
  import requests
4
4
 
5
5
  from flask import request, jsonify
6
- import logger
7
6
  from . import app, basic_auth
8
7
  from .datadog import DatadogAlert, DatadogAlertContent
9
8
 
10
- webhookLogger = logger.get_json_logger(__name__)
11
-
12
9
 
13
10
  @app.route("/")
14
11
  def ping() -> ResponseReturnValue:
@@ -21,13 +18,13 @@ def webhookHandler(chat_id) -> ResponseReturnValue:
21
18
  try:
22
19
  content = request.get_json()
23
20
  except requests.exceptions.RequestException:
24
- webhookLogger.exception("failed to parse request payload")
21
+ app.logger.exception("failed to parse request payload")
25
22
  return jsonify({"message": "Bad request"}), HTTPStatus.BAD_REQUEST
26
23
 
27
24
  try:
28
25
  alert = DatadogAlert(DatadogAlertContent(**content))
29
26
  except TypeError:
30
- webhookLogger.exception("failed to build DatadogAlert")
27
+ app.logger.exception("failed to build DatadogAlert")
31
28
  return jsonify({"message": "Bad request"}), HTTPStatus.BAD_REQUEST
32
29
 
33
30
  url = (
@@ -40,12 +37,11 @@ def webhookHandler(chat_id) -> ResponseReturnValue:
40
37
  payload = {
41
38
  "chat_id": chat_id,
42
39
  "text": alert.get_message(),
43
- "parse_mode": "MarkdownV2",
40
+ "parse_mode": "HTML",
44
41
  }
45
- print(payload)
46
42
  req = requests.post(url=url, data=payload, timeout=5)
47
43
  telegram_response = req.json()
48
44
  return jsonify(telegram_response)
49
45
  except requests.exceptions.RequestException:
50
- webhookLogger.exception("failed to post to Telegram")
46
+ app.logger.exception("failed to post to Telegram")
51
47
  return jsonify({"message": "Bad request"}), HTTPStatus.BAD_REQUEST
@@ -1,79 +0,0 @@
1
- from __future__ import annotations
2
- from dataclasses import dataclass, asdict
3
- from datetime import datetime, UTC
4
- import re
5
-
6
-
7
- @dataclass
8
- class DatadogOrg:
9
- id: int
10
- name: str
11
-
12
-
13
- @dataclass
14
- class DatadogAlertContent:
15
- title: str
16
- event_type: str
17
- body: str
18
- date: int
19
- org: DatadogOrg
20
- id: int
21
- last_updated: int
22
-
23
- def to_dict(self) -> dict:
24
- return asdict(self)
25
-
26
-
27
- class DatadogAlert:
28
- def __init__(self, alert: DatadogAlertContent):
29
- self._alert = alert
30
-
31
- def get_message(self) -> str:
32
- message = f"""*{_datadog_to_telegram_md(self._alert.title)}*
33
- In Org {_escape_md(self._alert.org['name'])}\({_escape_md(self._alert.org['id'])}\)
34
- At {_escape_md(datetime.fromtimestamp(int(self._alert.date), tz=UTC).strftime("%Y/%m/%d %H:%M"))}
35
- {_datadog_to_telegram_md(self._alert.body)}"""
36
- return message
37
-
38
-
39
- def _escape_md(text: str) -> str:
40
- return re.sub(r"([_*\[\]()~`>#+\-=|{}.!])", r"\\\1", text)
41
-
42
-
43
- def _datadog_to_telegram_md(text: str) -> str:
44
- text = text.strip().strip("%").strip()
45
-
46
- links = []
47
-
48
- def extract_link(match):
49
- links.append((match.group(1), match.group(2)))
50
- return f"LINKTOKEN{len(links)-1}END"
51
-
52
- text = re.sub(r"\[\[(.*?)\]\((.*?)\)\]", extract_link, text)
53
-
54
- # Process lines
55
- lines = text.splitlines()
56
- result = []
57
-
58
- for line in lines:
59
- line = line.strip()
60
-
61
- if line.startswith("## "):
62
- content = _escape_md(line[3:])
63
- result.append(f"*{content}*")
64
- continue
65
-
66
- if line.startswith("- - -"):
67
- continue
68
-
69
- result.append(_escape_md(line))
70
-
71
- text = "\n".join(result)
72
-
73
- # Restore links
74
- for i, (label, url) in enumerate(links):
75
- safe_label = _escape_md(label)
76
- print(safe_label + " " + url)
77
- text = text.replace(f"LINKTOKEN{i}END", f"[{safe_label}]({url})")
78
-
79
- return text