Compare commits

..

1 Commits

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

View File

@@ -103,14 +103,6 @@ jobs:
ghcr.io/${{ github.repository }}
tags: |
type=raw,value=dev
labels: |
org.opencontainers.image.created=${{ github.event.release.published_at }}
org.opencontainers.image.description=Website, webpage change detection, monitoring and notifications.
org.opencontainers.image.documentation=https://changedetection.io
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.source=https://github.com/dgtlmoon/changedetection.io
org.opencontainers.image.title=changedetection.io
org.opencontainers.image.url=https://changedetection.io
- name: Build and push :dev
id: docker_build
@@ -136,7 +128,7 @@ jobs:
echo "Release tag: ${{ github.event.release.tag_name }}"
echo "Github ref: ${{ github.ref }}"
echo "Github ref name: ${{ github.ref_name }}"
- name: Docker meta :tag
if: github.event_name == 'release' && startsWith(github.event.release.tag_name, '0.')
uses: docker/metadata-action@v6
@@ -150,15 +142,6 @@ jobs:
type=semver,pattern={{major}}.{{minor}},value=${{ github.event.release.tag_name }}
type=semver,pattern={{major}},value=${{ github.event.release.tag_name }}
type=raw,value=latest
labels: |
org.opencontainers.image.created=${{ github.event.release.published_at }}
org.opencontainers.image.description=Website, webpage change detection, monitoring and notifications.
org.opencontainers.image.documentation=https://changedetection.io
org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.source=https://github.com/dgtlmoon/changedetection.io
org.opencontainers.image.title=changedetection.io
org.opencontainers.image.url=https://changedetection.io
org.opencontainers.image.version=${{ github.event.release.tag_name }}
- name: Build and push :tag
id: docker_build_tag_release

View File

@@ -2,7 +2,7 @@
# Read more https://github.com/dgtlmoon/changedetection.io/wiki
# Semver means never use .01, or 00. Should be .1.
__version__ = '0.54.5'
__version__ = '0.54.4'
from changedetectionio.strtobool import strtobool
from json.decoder import JSONDecodeError

View File

@@ -338,7 +338,7 @@ class WatchHistoryDiff(Resource):
word_diff = True
# Get boolean diff preferences with defaults from DIFF_PREFERENCES_CONFIG
changes_only = strtobool(request.args.get('changesOnly', 'false'))
changes_only = strtobool(request.args.get('changesOnly', 'true'))
ignore_whitespace = strtobool(request.args.get('ignoreWhitespace', 'false'))
include_removed = strtobool(request.args.get('removed', 'true'))
include_added = strtobool(request.args.get('added', 'true'))
@@ -349,7 +349,7 @@ class WatchHistoryDiff(Resource):
previous_version_file_contents=from_version_file_contents,
newest_version_file_contents=to_version_file_contents,
ignore_junk=ignore_whitespace,
include_equal=not changes_only,
include_equal=changes_only,
include_removed=include_removed,
include_added=include_added,
include_replaced=include_replaced,
@@ -567,4 +567,4 @@ class CreateWatch(Resource):
return {'status': f'OK, queueing {len(watches_to_queue)} watches in background'}, 202
return list, 200
return list, 200

View File

@@ -6,6 +6,7 @@ Extracted from update_worker.py to provide standalone notification functionality
for both sync and async workers
"""
import datetime
from copy import deepcopy
import pytz
from loguru import logger
@@ -352,7 +353,7 @@ class NotificationService:
"""
Send notification when content changes are detected
"""
n_object = NotificationContextData()
watch = self.datastore.data['watching'].get(watch_uuid)
if not watch:
return
@@ -369,21 +370,51 @@ class NotificationService:
# 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

View File

@@ -170,14 +170,6 @@ def test_api_simple(client, live_server, measure_memory_usage, datastore_path):
headers={'x-api-key': api_key},
)
assert b'(changed) Which is across' in res.data
assert b'Some text thats the same' in res.data
# Fetch the difference between two versions (default text format)
res = client.get(
url_for("watchhistorydiff", uuid=watch_uuid, from_timestamp='previous', to_timestamp='latest')+"?changesOnly=true",
headers={'x-api-key': api_key},
)
assert b'Some text thats the same' not in res.data
# Test htmlcolor format
res = client.get(

View File

@@ -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(
@@ -181,35 +182,50 @@ 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)
@@ -217,12 +233,14 @@ def test_group_tag_notification(client, live_server, measure_memory_usage, datas
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

View File

@@ -343,8 +343,11 @@ def new_live_server_setup(live_server):
@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: