Compare commits

...

1 Commits

Author SHA1 Message Date
dgtlmoon
62e1259750 refactor attempt 2026-03-12 15:24:19 +01:00
3 changed files with 86 additions and 34 deletions

View File

@@ -6,6 +6,7 @@ Extracted from update_worker.py to provide standalone notification functionality
for both sync and async workers for both sync and async workers
""" """
import datetime import datetime
from copy import deepcopy
import pytz import pytz
from loguru import logger from loguru import logger
@@ -352,7 +353,7 @@ class NotificationService:
""" """
Send notification when content changes are detected Send notification when content changes are detected
""" """
n_object = NotificationContextData()
watch = self.datastore.data['watching'].get(watch_uuid) watch = self.datastore.data['watching'].get(watch_uuid)
if not watch: if not watch:
return return
@@ -369,21 +370,51 @@ class NotificationService:
# Should be a better parent getter in the model object # Should be a better parent getter in the model object
# Prefer - Individual watch settings > Tag settings > Global settings (in that order) # Prefer - Individual watch settings > Tag settings > Global settings (in that order)
# this change probably not needed? # If the watch has no notification_body for example, it will try to get from the first matching group or system setting
n_object['notification_urls'] = _check_cascading_vars(self.datastore, 'notification_urls', watch)
# Should be, if none in the watch, and no group tag ones found, then use system ones at the end
#n_object['notification_urls'] = _check_cascading_vars(self.datastore, 'notification_urls', watch)
n_object = NotificationContextData()
n_object['notification_title'] = _check_cascading_vars(self.datastore,'notification_title', watch) n_object['notification_title'] = _check_cascading_vars(self.datastore,'notification_title', watch)
n_object['notification_body'] = _check_cascading_vars(self.datastore,'notification_body', watch) n_object['notification_body'] = _check_cascading_vars(self.datastore,'notification_body', watch)
n_object['notification_format'] = _check_cascading_vars(self.datastore,'notification_format', watch) n_object['notification_format'] = _check_cascading_vars(self.datastore,'notification_format', watch)
notification_objects = []
if n_object.get('notification_urls'):
notification_objects.append(n_object)
# LOGIC SHOULD BE something that all tests currently pass too
# !!! _check_cascading_vars is not really used much, only used here..
#
# If any related group/tag has a notification_url set, then we fan out horizontally and collect it as extra notifications
tags = self.datastore.get_all_tags_for_watch(uuid=watch.get('uuid'))
logger.debug(f'{len(tags)} related to this watch')
if tags:
for tag_uuid, tag in tags.items():
logger.debug(f"Checking group/tag for notification URLs '{tag['title']}' Muted? '{tag.get('notification_muted')}', URLs {tag.get('notification_urls')}")
v = tag.get('notification_urls')
if v and not tag.get('notification_muted'):
logger.debug("OK MAN")
next_n_object = deepcopy(n_object)
next_n_object['notification_urls'] = v
next_n_object['notification_title'] = _check_cascading_vars(self.datastore, 'notification_title', watch)
next_n_object['notification_body'] = _check_cascading_vars(self.datastore, 'notification_body', watch)
next_n_object['notification_format'] = _check_cascading_vars(self.datastore, 'notification_format', watch)
notification_objects.append(next_n_object)
logger.debug(f"Adding notification from group/tag {tag['title']}")
# (Individual watch) Only prepare to notify if the rules above matched # (Individual watch) Only prepare to notify if the rules above matched
queued = False queued = False
if n_object and n_object.get('notification_urls'): if notification_objects:
queued = True queued = True
count = watch.get('notification_alert_count', 0) + 1 count = watch.get('notification_alert_count', 0) + 1
self.datastore.update_watch(uuid=watch_uuid, update_obj={'notification_alert_count': count}) self.datastore.update_watch(uuid=watch_uuid, update_obj={'notification_alert_count': count})
for n_object in notification_objects:
self.queue_notification_for_watch(n_object=n_object, watch=watch) self.queue_notification_for_watch(n_object=n_object, watch=watch)
return queued return queued

View File

@@ -171,6 +171,7 @@ def test_group_tag_notification(client, live_server, measure_memory_usage, datas
delete_all_watches(client) delete_all_watches(client)
set_original_response(datastore_path=datastore_path) set_original_response(datastore_path=datastore_path)
notification_url_endpoint = url_for('test_notification_endpoint', _external=True).replace('http', 'post')
test_url = url_for('test_endpoint', _external=True) test_url = url_for('test_endpoint', _external=True)
res = client.post( res = client.post(
@@ -181,35 +182,50 @@ def test_group_tag_notification(client, live_server, measure_memory_usage, datas
assert b"Watch added" in res.data assert b"Watch added" in res.data
notification_url = url_for('test_notification_endpoint', _external=True).replace('http', 'json') client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
notification_form_data = {"notification_urls": notification_url, wait_for_all_checks(client)
"notification_title": "New GROUP TAG ChangeDetection.io Notification - {{watch_url}}",
"notification_body": "BASE URL: {{base_url}}\n"
"Watch URL: {{watch_url}}\n"
"Watch UUID: {{watch_uuid}}\n"
"Watch title: {{watch_title}}\n"
"Watch tag: {{watch_tag}}\n"
"Preview: {{preview_url}}\n"
"Diff URL: {{diff_url}}\n"
"Snapshot: {{current_snapshot}}\n"
"Diff: {{diff}}\n"
"Diff Added: {{diff_added}}\n"
"Diff Removed: {{diff_removed}}\n"
"Diff Full: {{diff_full}}\n"
"Diff as Patch: {{diff_patch}}\n"
":-)",
"notification_screenshot": True,
"notification_format": 'text',
"title": "test-tag"}
group_tag_form_data = {
"notification_title": "New GROUP TAG ChangeDetection.io Notification - {{watch_url}}",
"notification_body": "BASE URL: {{base_url}}\n"
"Watch URL: {{watch_url}}\n"
"Watch UUID: {{watch_uuid}}\n"
"Watch title: {{watch_title}}\n"
"Watch tag: {{watch_tag}}\n"
"Preview: {{preview_url}}\n"
"Diff URL: {{diff_url}}\n"
"Snapshot: {{current_snapshot}}\n"
"Diff: {{diff}}\n"
"Diff Added: {{diff_added}}\n"
"Diff Removed: {{diff_removed}}\n"
"Diff Full: {{diff_full}}\n"
"Diff as Patch: {{diff_patch}}\n"
":-)",
"notification_screenshot": True,
"notification_format": 'text',
}
# Setup for test-tag
group_tag_form_data['notification_urls'] = notification_url_endpoint+"?outputfilename=test-tag.txt"
group_tag_form_data['title'] = 'test-tag'
res = client.post( res = client.post(
url_for("tags.form_tag_edit_submit", uuid=get_UUID_for_tag_name(client, name="test-tag")), url_for("tags.form_tag_edit_submit", uuid=get_UUID_for_tag_name(client, name="test-tag")),
data=notification_form_data, data=group_tag_form_data,
follow_redirects=True
)
assert b"Updated" in res.data
# Setup for other-tag, we only add notifications-urls
group_tag_form_data['notification_urls'] = notification_url_endpoint+"?outputfilename=other-tag.txt"
group_tag_form_data['title'] = 'other-tag'
res = client.post(
url_for("tags.form_tag_edit_submit", uuid=get_UUID_for_tag_name(client, name="other-tag")),
data=group_tag_form_data,
follow_redirects=True follow_redirects=True
) )
assert b"Updated" in res.data assert b"Updated" in res.data
wait_for_all_checks(client)
set_modified_response(datastore_path=datastore_path) set_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True) client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
@@ -217,12 +233,14 @@ def test_group_tag_notification(client, live_server, measure_memory_usage, datas
time.sleep(3) time.sleep(3)
assert os.path.isfile(os.path.join(datastore_path, "notification.txt")) assert os.path.isfile(os.path.join(datastore_path, "test-tag.txt"))
assert os.path.isfile(os.path.join(datastore_path, "other-tag.txt"))
# @todo assert the group name or other unique body is in other-tag.txt
# Verify what was sent as a notification, this file should exist # Verify what was sent as a notification, this file should exist
with open(os.path.join(datastore_path, "notification.txt"), "r") as f: with open(os.path.join(datastore_path, "test-tag.txt"), "r") as f:
notification_submission = f.read() notification_submission = f.read()
os.unlink(os.path.join(datastore_path, "notification.txt")) os.unlink(os.path.join(datastore_path, "test-tag.txt"))
# Did we see the URL that had a change, in the notification? # Did we see the URL that had a change, in the notification?
# Diff was correctly executed # Diff was correctly executed

View File

@@ -343,8 +343,11 @@ def new_live_server_setup(live_server):
@live_server.app.route('/test_notification_endpoint', methods=['POST', 'GET']) @live_server.app.route('/test_notification_endpoint', methods=['POST', 'GET'])
def test_notification_endpoint(): def test_notification_endpoint():
datastore_path = current_app.config.get('TEST_DATASTORE_PATH', 'test-datastore') datastore_path = current_app.config.get('TEST_DATASTORE_PATH', 'test-datastore')
from loguru import logger
with open(os.path.join(datastore_path, "notification.txt"), "wb") as f: # @todo make safe
fname = request.args.get('outputfilename', "notification.txt")
logger.debug(f"Writing test notification endpoint data to '{fname}' - {request.args}")
with open(os.path.join(datastore_path, fname), "wb") as f:
# Debug method, dump all POST to file also, used to prove #65 # Debug method, dump all POST to file also, used to prove #65
data = request.stream.read() data = request.stream.read()
if data != None: if data != None: