BE: conditional device import support, notification supression support during scan #1721

This commit is contained in:
jokob-sk committed 2026-09-10 21:00:50 +10:00
1 parent de730e85e9
commit d9947a2829
6 files changed
+43 -5

No files matched your search

+1 -1
View File
@@ -1 +1 @@
Plugins docs have been relocated. Check the new [Plugins Overview location](./PLUGINS_OVERVIEW.md).
Plugins docs have been relocated. Check the new [Plugins Overview location](../../docs/PLUGINS_OVERVIEW.md).
+1 -1
View File
@@ -1,6 +1,6 @@
## Overview
A simple EMail (SMTP) notification gateway publisher. Check the [SMTP docs](./SMTP.md) for additional help.
A simple EMail (SMTP) notification gateway publisher. Check the [SMTP docs](https://docs.netalertx.com/SMTP) for additional help.
### Usage
+1 -1
View File
@@ -7,7 +7,7 @@ The synchronization plugin is designed to synchronize data across multiple insta
> [!TIP]
> This plugin is usually used if you need to monitor inaccessible networks (WAN, VLAN etc.). Read the [Remote networks documentation](./REMOTE_NETWORKS.md) for more details about these scenarios.
> This plugin is usually used if you need to monitor inaccessible networks (WAN, VLAN etc.). Read the [Remote networks documentation](https://docs.netalertx.com/REMOTE_NETWORKS) for more details about these scenarios.
### Synchronization Modes
@@ -149,7 +149,7 @@ def get_device_data(site, api):
wifi_broadcasts = wifi_broadcasts_resp.get("data", [])
mylog(
'verbose',
'trace',
[f'[{pluginName}] WIFI BROADCASTS: '
f'{json.dumps(wifi_broadcasts_resp, indent=2)}']
)
+6 -1
View File
@@ -21,8 +21,13 @@ class Condition:
appEvent_value = (
trigger.event[self.field] if self.field in trigger.event.keys() else None
)
# trigger.object is None when the referenced Devices/Plugins_Objects row no
# longer exists by the time this event is processed (e.g. deleted between
# AppEvent creation and workflow processing) - fall back to the event value only.
eveObj_value = (
trigger.object[self.field] if self.field in trigger.object.keys() else None
trigger.object[self.field]
if trigger.object is not None and self.field in trigger.object.keys()
else None
)
# proceed only if value found
+33
View File
@@ -432,5 +432,38 @@ class TestCascadePrevention(unittest.TestCase):
self.assertIn("guid-mutated", mgr._mutated_guids)
class TestConditionHandlesMissingTriggerObject(unittest.TestCase):
"""Regression test: trigger.object is None whenever the AppEvent's
objectGuid no longer matches any Devices/Plugins_Objects row by the time
the event is processed (e.g. the device was deleted between AppEvent
creation and workflow processing - see workflows/triggers.py's own None
branches). Condition.evaluate() must not crash on it."""
def _make_trigger(self, event, obj=None):
from types import SimpleNamespace
return SimpleNamespace(event=event, object=obj)
def test_condition_on_missing_field_returns_false_not_crash(self):
from workflows.conditions import Condition
event = _make_app_event()
trigger = self._make_trigger(event, obj=None)
condition = Condition({"field": "devLocation", "operator": "equals", "value": "Office"})
# must not raise AttributeError: 'NoneType' object has no attribute 'keys'
self.assertFalse(condition.evaluate(trigger))
def test_condition_on_event_field_still_works_when_object_missing(self):
"""A field present on the AppEvent itself must still evaluate correctly
even when trigger.object is None."""
from workflows.conditions import Condition
event = _make_app_event(event_type="update")
trigger = self._make_trigger(event, obj=None)
condition = Condition({"field": "appEventType", "operator": "equals", "value": "update"})
self.assertTrue(condition.evaluate(trigger))
if __name__ == "__main__":
unittest.main()