Skip to content

Commit 7221b4b

Browse files
committed
Keep all local changes while resolving conflicts
1 parent 25a8155 commit 7221b4b

File tree

7 files changed

+723
-77
lines changed

7 files changed

+723
-77
lines changed

docs/NOTIFICATION_TEMPLATES.md

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
# Notification Text Templates
2+
3+
> Customize how devices and events appear in **text** notifications (email previews, push notifications, Apprise messages).
4+
5+
By default, NetAlertX formats each device as a vertical list of `Header: Value` pairs. Text templates let you define a **single-line format per device** using `{FieldName}` placeholders — ideal for mobile notification previews and high-volume alerts.
6+
7+
HTML email tables are **not affected** by these templates.
8+
9+
## Quick Start
10+
11+
1. Go to **Settings → Notification Processing**.
12+
2. Set a template string for the section you want to customize, e.g.:
13+
- **Text Template: New Devices**`{devName} ({eve_MAC}) - {eve_IP}`
14+
3. Save. The next notification will use your format.
15+
16+
**Before (default):**
17+
```
18+
🆕 New devices
19+
---------
20+
devName: MyPhone
21+
eve_MAC: aa:bb:cc:dd:ee:ff
22+
devVendor: Apple
23+
eve_IP: 192.168.1.42
24+
eve_DateTime: 2025-01-15 10:30:00
25+
eve_EventType: New Device
26+
devComments:
27+
```
28+
29+
**After (with template `{devName} ({eve_MAC}) - {eve_IP}`):**
30+
```
31+
🆕 New devices
32+
---------
33+
MyPhone (aa:bb:cc:dd:ee:ff) - 192.168.1.42
34+
```
35+
36+
## Settings Reference
37+
38+
| Setting | Type | Default | Description |
39+
|---------|------|---------|-------------|
40+
| `NTFPRCS_TEXT_SECTION_HEADERS` | Boolean | `true` | Show/hide section titles (e.g. `🆕 New devices \n---------`). |
41+
| `NTFPRCS_TEXT_TEMPLATE_new_devices` | String | *(empty)* | Template for new device rows. |
42+
| `NTFPRCS_TEXT_TEMPLATE_down_devices` | String | *(empty)* | Template for down device rows. |
43+
| `NTFPRCS_TEXT_TEMPLATE_down_reconnected` | String | *(empty)* | Template for reconnected device rows. |
44+
| `NTFPRCS_TEXT_TEMPLATE_events` | String | *(empty)* | Template for event rows. |
45+
| `NTFPRCS_TEXT_TEMPLATE_plugins` | String | *(empty)* | Template for plugin event rows. |
46+
47+
When a template is **empty**, the section uses the original vertical `Header: Value` format (full backward compatibility).
48+
49+
## Template Syntax
50+
51+
Use `{FieldName}` to insert a value from the notification data. Field names are **case-sensitive** and must match the column names exactly.
52+
53+
```
54+
{devName} ({eve_MAC}) connected at {eve_DateTime}
55+
```
56+
57+
- No loops, conditionals, or nesting — just simple string replacement.
58+
- If a `{FieldName}` does not exist in the data, it is left as-is in the output (safe failure). For example, `{NonExistent}` renders literally as `{NonExistent}`.
59+
60+
## Variable Availability by Section
61+
62+
All four device sections (`new_devices`, `down_devices`, `down_reconnected`, `events`) share the same unified field names.
63+
64+
### `new_devices`, `down_devices`, `down_reconnected`, and `events`
65+
66+
| Variable | Description |
67+
|----------|-------------|
68+
| `{devName}` | Device display name |
69+
| `{eve_MAC}` | Device MAC address |
70+
| `{devVendor}` | Device vendor/manufacturer |
71+
| `{eve_IP}` | Device IP address |
72+
| `{eve_DateTime}` | Event timestamp |
73+
| `{eve_EventType}` | Type of event (e.g. `New Device`, `Connected`, `Device Down`) |
74+
| `{devComments}` | Device comments |
75+
76+
**Example (new_devices/events):** `{devName} ({eve_MAC}) - {eve_IP} [{eve_EventType}]`
77+
78+
**Example (down_devices):** `{devName} ({eve_MAC}) {devVendor} - went down at {eve_DateTime}`
79+
80+
**Example (down_reconnected):** `{devName} ({eve_MAC}) reconnected at {eve_DateTime}`
81+
82+
### `plugins`
83+
84+
| Variable | Description |
85+
|----------|-------------|
86+
| `{Plugin}` | Plugin code name |
87+
| `{Object_PrimaryId}` | Primary identifier of the object |
88+
| `{Object_SecondaryId}` | Secondary identifier |
89+
| `{DateTimeChanged}` | Timestamp of change |
90+
| `{Watched_Value1}` | First watched value |
91+
| `{Watched_Value2}` | Second watched value |
92+
| `{Watched_Value3}` | Third watched value |
93+
| `{Watched_Value4}` | Fourth watched value |
94+
| `{Status}` | Plugin event status |
95+
96+
**Example:** `{Plugin}: {Object_PrimaryId} - {Status}`
97+
98+
## Section Headers Toggle
99+
100+
Set **Text Section Headers** (`NTFPRCS_TEXT_SECTION_HEADERS`) to `false` to remove the section title separators from text notifications. This is useful when you want compact output without the `🆕 New devices \n---------` banners.

front/plugins/notification_processing/config.json

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,153 @@
152152
"string": "You can specify a SQL where condition to filter out Events from notifications. For example <code>AND devLastIP NOT LIKE '192.168.3.%'</code> will always exclude any Event notifications for all devices with the IP starting with <code>192.168.3.%</code>."
153153
}
154154
]
155+
<<<<<<< Updated upstream
156+
=======
157+
},
158+
{
159+
"function": "TEXT_SECTION_HEADERS",
160+
"type": {
161+
"dataType": "boolean",
162+
"elements": [
163+
{ "elementType": "input", "elementOptions": [{ "type": "checkbox" }], "transformers": [] }
164+
]
165+
},
166+
"default_value": true,
167+
"options": [],
168+
"localized": ["name", "description"],
169+
"name": [
170+
{
171+
"language_code": "en_us",
172+
"string": "Text Section Headers"
173+
}
174+
],
175+
"description": [
176+
{
177+
"language_code": "en_us",
178+
"string": "Enable or disable section titles (e.g. <code>🆕 New devices \\n---------</code>) in text notifications. Enabled by default for backward compatibility."
179+
}
180+
]
181+
},
182+
{
183+
"function": "TEXT_TEMPLATE_new_devices",
184+
"type": {
185+
"dataType": "string",
186+
"elements": [
187+
{ "elementType": "input", "elementOptions": [], "transformers": [] }
188+
]
189+
},
190+
"default_value": "",
191+
"options": [],
192+
"localized": ["name", "description"],
193+
"name": [
194+
{
195+
"language_code": "en_us",
196+
"string": "Text Template: New Devices"
197+
}
198+
],
199+
"description": [
200+
{
201+
"language_code": "en_us",
202+
"string": "Custom text template for new device notifications. Use <code>{FieldName}</code> placeholders, e.g. <code>{devName} ({eve_MAC}) - {eve_IP}</code>. Leave empty for default formatting. Available fields: <code>{devName}</code>, <code>{eve_MAC}</code>, <code>{devVendor}</code>, <code>{eve_IP}</code>, <code>{eve_DateTime}</code>, <code>{eve_EventType}</code>, <code>{devComments}</code>."
203+
}
204+
]
205+
},
206+
{
207+
"function": "TEXT_TEMPLATE_down_devices",
208+
"type": {
209+
"dataType": "string",
210+
"elements": [
211+
{ "elementType": "input", "elementOptions": [], "transformers": [] }
212+
]
213+
},
214+
"default_value": "",
215+
"options": [],
216+
"localized": ["name", "description"],
217+
"name": [
218+
{
219+
"language_code": "en_us",
220+
"string": "Text Template: Down Devices"
221+
}
222+
],
223+
"description": [
224+
{
225+
"language_code": "en_us",
226+
"string": "Custom text template for down device notifications. Use <code>{FieldName}</code> placeholders, e.g. <code>{devName} ({eve_MAC}) - {eve_IP}</code>. Leave empty for default formatting. Available fields: <code>{devName}</code>, <code>{eve_MAC}</code>, <code>{devVendor}</code>, <code>{eve_IP}</code>, <code>{eve_DateTime}</code>, <code>{eve_EventType}</code>, <code>{devComments}</code>."
227+
}
228+
]
229+
},
230+
{
231+
"function": "TEXT_TEMPLATE_down_reconnected",
232+
"type": {
233+
"dataType": "string",
234+
"elements": [
235+
{ "elementType": "input", "elementOptions": [], "transformers": [] }
236+
]
237+
},
238+
"default_value": "",
239+
"options": [],
240+
"localized": ["name", "description"],
241+
"name": [
242+
{
243+
"language_code": "en_us",
244+
"string": "Text Template: Reconnected"
245+
}
246+
],
247+
"description": [
248+
{
249+
"language_code": "en_us",
250+
"string": "Custom text template for reconnected device notifications. Use <code>{FieldName}</code> placeholders, e.g. <code>{devName} ({eve_MAC}) reconnected at {eve_DateTime}</code>. Leave empty for default formatting. Available fields: <code>{devName}</code>, <code>{eve_MAC}</code>, <code>{devVendor}</code>, <code>{eve_IP}</code>, <code>{eve_DateTime}</code>, <code>{eve_EventType}</code>, <code>{devComments}</code>."
251+
}
252+
]
253+
},
254+
{
255+
"function": "TEXT_TEMPLATE_events",
256+
"type": {
257+
"dataType": "string",
258+
"elements": [
259+
{ "elementType": "input", "elementOptions": [], "transformers": [] }
260+
]
261+
},
262+
"default_value": "",
263+
"options": [],
264+
"localized": ["name", "description"],
265+
"name": [
266+
{
267+
"language_code": "en_us",
268+
"string": "Text Template: Events"
269+
}
270+
],
271+
"description": [
272+
{
273+
"language_code": "en_us",
274+
"string": "Custom text template for event notifications. Use <code>{FieldName}</code> placeholders, e.g. <code>{devName} ({eve_MAC}) {eve_EventType} at {eve_DateTime}</code>. Leave empty for default formatting. Available fields: <code>{devName}</code>, <code>{eve_MAC}</code>, <code>{devVendor}</code>, <code>{eve_IP}</code>, <code>{eve_DateTime}</code>, <code>{eve_EventType}</code>, <code>{devComments}</code>."
275+
}
276+
]
277+
},
278+
{
279+
"function": "TEXT_TEMPLATE_plugins",
280+
"type": {
281+
"dataType": "string",
282+
"elements": [
283+
{ "elementType": "input", "elementOptions": [], "transformers": [] }
284+
]
285+
},
286+
"default_value": "",
287+
"options": [],
288+
"localized": ["name", "description"],
289+
"name": [
290+
{
291+
"language_code": "en_us",
292+
"string": "Text Template: Plugins"
293+
}
294+
],
295+
"description": [
296+
{
297+
"language_code": "en_us",
298+
"string": "Custom text template for plugin event notifications. Use <code>{FieldName}</code> placeholders, e.g. <code>{Plugin}: {Object_PrimaryId} - {Status}</code>. Leave empty for default formatting. Available fields: <code>{Plugin}</code>, <code>{Object_PrimaryId}</code>, <code>{Object_SecondaryId}</code>, <code>{DateTimeChanged}</code>, <code>{Watched_Value1}</code>, <code>{Watched_Value2}</code>, <code>{Watched_Value3}</code>, <code>{Watched_Value4}</code>, <code>{Status}</code>."
299+
}
300+
]
301+
>>>>>>> Stashed changes
155302
}
156303
],
157304

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# -------------------------------------------------------------------------------
2+
# notification_sections.py — Single source of truth for notification section
3+
# metadata: titles, SQL templates, datetime fields, and section ordering.
4+
#
5+
# Both reporting.py and notification_instance.py import from here.
6+
# -------------------------------------------------------------------------------
7+
8+
# Canonical processing order
9+
SECTION_ORDER = [
10+
"new_devices",
11+
"down_devices",
12+
"down_reconnected",
13+
"events",
14+
"plugins",
15+
]
16+
17+
# Section display titles (used in text + HTML notifications)
18+
SECTION_TITLES = {
19+
"new_devices": "🆕 New devices",
20+
"down_devices": "🔴 Down devices",
21+
"down_reconnected": "🔁 Reconnected down devices",
22+
"events": "⚡ Events",
23+
"plugins": "🔌 Plugins",
24+
}
25+
26+
# Which column(s) contain datetime values per section (for timezone conversion)
27+
DATETIME_FIELDS = {
28+
"new_devices": ["eve_DateTime"],
29+
"down_devices": ["eve_DateTime"],
30+
"down_reconnected": ["eve_DateTime"],
31+
"events": ["eve_DateTime"],
32+
"plugins": ["DateTimeChanged"],
33+
}
34+
35+
# ---------------------------------------------------------------------------
36+
# SQL templates
37+
#
38+
# All device sections use unified DB column names so the JSON output
39+
# has consistent field names across new_devices, down_devices,
40+
# down_reconnected, and events.
41+
#
42+
# Placeholders:
43+
# {condition} — optional WHERE clause appended by condition builder
44+
# {alert_down_minutes} — runtime value, only used by down_devices
45+
# ---------------------------------------------------------------------------
46+
SQL_TEMPLATES = {
47+
"new_devices": """
48+
SELECT
49+
devName,
50+
eve_MAC,
51+
devVendor,
52+
devLastIP as eve_IP,
53+
eve_DateTime,
54+
eve_EventType,
55+
devComments
56+
FROM Events_Devices
57+
WHERE eve_PendingAlertEmail = 1
58+
AND eve_EventType = 'New Device' {condition}
59+
ORDER BY eve_DateTime
60+
""",
61+
"down_devices": """
62+
SELECT
63+
devName,
64+
eve_MAC,
65+
devVendor,
66+
eve_IP,
67+
eve_DateTime,
68+
eve_EventType,
69+
devComments
70+
FROM Events_Devices AS down_events
71+
WHERE eve_PendingAlertEmail = 1
72+
AND down_events.eve_EventType = 'Device Down'
73+
AND eve_DateTime < datetime('now', '-{alert_down_minutes} minutes')
74+
AND NOT EXISTS (
75+
SELECT 1
76+
FROM Events AS connected_events
77+
WHERE connected_events.eve_MAC = down_events.eve_MAC
78+
AND connected_events.eve_EventType = 'Connected'
79+
AND connected_events.eve_DateTime > down_events.eve_DateTime
80+
)
81+
ORDER BY down_events.eve_DateTime
82+
""",
83+
"down_reconnected": """
84+
SELECT
85+
devName,
86+
eve_MAC,
87+
devVendor,
88+
eve_IP,
89+
eve_DateTime,
90+
eve_EventType,
91+
devComments
92+
FROM Events_Devices AS reconnected_devices
93+
WHERE reconnected_devices.eve_EventType = 'Down Reconnected'
94+
AND reconnected_devices.eve_PendingAlertEmail = 1
95+
ORDER BY reconnected_devices.eve_DateTime
96+
""",
97+
"events": """
98+
SELECT
99+
devName,
100+
eve_MAC,
101+
devVendor,
102+
devLastIP as eve_IP,
103+
eve_DateTime,
104+
eve_EventType,
105+
devComments
106+
FROM Events_Devices
107+
WHERE eve_PendingAlertEmail = 1
108+
AND eve_EventType IN ('Connected', 'Down Reconnected', 'Disconnected','IP Changed') {condition}
109+
ORDER BY eve_DateTime
110+
""",
111+
"plugins": """
112+
SELECT
113+
Plugin,
114+
Object_PrimaryId,
115+
Object_SecondaryId,
116+
DateTimeChanged,
117+
Watched_Value1,
118+
Watched_Value2,
119+
Watched_Value3,
120+
Watched_Value4,
121+
Status
122+
FROM Plugins_Events
123+
""",
124+
}
125+
126+
# Sections that support user-defined condition filters
127+
SECTIONS_WITH_CONDITIONS = {"new_devices", "events"}
128+
129+
# Legacy setting key mapping for condition filters
130+
SECTION_CONDITION_MAP = {
131+
"new_devices": "NTFPRCS_new_dev_condition",
132+
"events": "NTFPRCS_event_condition",
133+
}

0 commit comments

Comments
 (0)