Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 38 additions & 7 deletions changedetectionio/notification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
for both sync and async workers
"""
import datetime
from copy import deepcopy

import pytz
from loguru import logger
Expand Down Expand Up @@ -352,7 +353,7 @@ def send_content_changed_notification(self, watch_uuid):
"""
Send notification when content changes are detected
"""
n_object = NotificationContextData()

watch = self.datastore.data['watching'].get(watch_uuid)
if not watch:
return
Expand All @@ -369,21 +370,51 @@ def send_content_changed_notification(self, watch_uuid):
# Should be a better parent getter in the model object

# Prefer - Individual watch settings > Tag settings > Global settings (in that order)
# this change probably not needed?
n_object['notification_urls'] = _check_cascading_vars(self.datastore, 'notification_urls', watch)
# If the watch has no notification_body for example, it will try to get from the first matching group or system setting

# 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_body'] = _check_cascading_vars(self.datastore,'notification_body', 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
queued = False
if n_object and n_object.get('notification_urls'):
if notification_objects:
queued = True

count = watch.get('notification_alert_count', 0) + 1
self.datastore.update_watch(uuid=watch_uuid, update_obj={'notification_alert_count': count})

self.queue_notification_for_watch(n_object=n_object, watch=watch)
for n_object in notification_objects:
self.queue_notification_for_watch(n_object=n_object, watch=watch)

return queued

Expand Down
68 changes: 43 additions & 25 deletions changedetectionio/tests/test_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ def test_group_tag_notification(client, live_server, measure_memory_usage, datas
delete_all_watches(client)

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)
res = client.post(
Expand All @@ -181,48 +182,65 @@ def test_group_tag_notification(client, live_server, measure_memory_usage, datas

assert b"Watch added" in res.data

notification_url = url_for('test_notification_endpoint', _external=True).replace('http', 'json')
notification_form_data = {"notification_urls": notification_url,
"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"}
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)

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(
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
)
assert b"Updated" in res.data

wait_for_all_checks(client)

set_modified_response(datastore_path=datastore_path)
client.get(url_for("ui.form_watch_checknow"), follow_redirects=True)
wait_for_all_checks(client)

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
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()
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?
# Diff was correctly executed
Expand Down
7 changes: 5 additions & 2 deletions changedetectionio/tests/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,11 @@ def test_method():
@live_server.app.route('/test_notification_endpoint', methods=['POST', 'GET'])
def test_notification_endpoint():
datastore_path = current_app.config.get('TEST_DATASTORE_PATH', 'test-datastore')

with open(os.path.join(datastore_path, "notification.txt"), "wb") as f:
from loguru import logger
# @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
data = request.stream.read()
if data != None:
Expand Down
Loading