Merge branch 'master' into diff-token-var-arg

This commit is contained in:
dgtlmoon
2026-02-24 15:26:19 +01:00
3 changed files with 30 additions and 21 deletions
+6 -19
View File
@@ -63,6 +63,7 @@ class FormattableTimestamp(str):
{{ change_datetime }} → '2024-01-15 10:30:00 UTC'
{{ change_datetime(format='%Y') }} → '2024'
{{ change_datetime(format='%A') }} → 'Monday'
{{ change_datetime(format='%Y-%m-%d') }} → '2024-01-15'
Being a str subclass means it is natively JSON serializable.
"""
@@ -142,9 +143,11 @@ class FormattableDiff(str):
return result
# What is passed around as notification context, also used as the complete list of valid {{ tokens }}
class NotificationContextData(dict):
def __init__(self, initial_data=None, **kwargs):
# ValidateJinja2Template() validates against the keynames of this dict to check for valid tokens in the body (user submission)
super().__init__({
'base_url': None,
'change_datetime': FormattableTimestamp(time.time()),
@@ -161,16 +164,18 @@ class NotificationContextData(dict):
'diff_url': None,
'markup_text_links_to_html_links': False, # If automatic conversion of plaintext to HTML should happen
'notification_timestamp': time.time(),
'prev_snapshot': None,
'preview_url': None,
'screenshot': None,
'triggered_text': None,
'timestamp_from': None,
'timestamp_to': None,
'triggered_text': None,
'uuid': 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', # Converted to 'watch_uuid' in create_notification_parameters
'watch_mime_type': None,
'watch_tag': None,
'watch_title': None,
'watch_url': 'https://WATCH-PLACE-HOLDER/',
'watch_uuid': 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX', # Converted to 'watch_uuid' in create_notification_parameters
})
# Apply any initial data passed in
@@ -204,24 +209,6 @@ class NotificationContextData(dict):
super().__setitem__(key, value)
def timestamp_to_localtime(timestamp):
# Format the date using locale-aware formatting with timezone
dt = datetime.datetime.fromtimestamp(int(timestamp))
dt = dt.replace(tzinfo=pytz.UTC)
# Get local timezone-aware datetime
local_tz = datetime.datetime.now().astimezone().tzinfo
local_dt = dt.astimezone(local_tz)
# Format date with timezone - using strftime for locale awareness
try:
formatted_date = local_dt.strftime('%Y-%m-%d %H:%M:%S %Z')
except:
# Fallback if locale issues
formatted_date = local_dt.isoformat()
return formatted_date
def add_rendered_diff_to_notification_vars(notification_scan_text:str, prev_snapshot:str, current_snapshot:str, word_diff:bool):
"""
Efficiently renders only the diff placeholders that are actually used in the notification text.
@@ -44,6 +44,14 @@
<td><code>{{ '{{preview_url}}' }}</code></td>
<td>{{ _('The URL of the preview page generated by changedetection.io.') }}</td>
</tr>
<tr>
<td><code>{{ '{{change_datetime}}' }}</code></td>
<td>{{ _('Date/time of the change, accepts format=, change_datetime(format=\'%A\')\', default is \'%Y-%m-%d %H:%M:%S %Z\'') }}</td>
</tr>
<tr>
<td><code>{{ '{{diff_url}}' }}</code></td>
<td>{{ _('The URL of the diff output for the watch.') }}</td>
</tr>
<tr>
<td><code>{{ '{{diff_url}}' }}</code></td>
<td>{{ _('The URL of the diff output for the watch.') }}</td>
+16 -2
View File
@@ -17,6 +17,7 @@ from changedetectionio.notification import (
)
from ..diff import HTML_CHANGED_STYLE
from ..model import USE_SYSTEM_DEFAULT_NOTIFICATION_FORMAT_FOR_WATCH
from ..notification_service import FormattableTimestamp
# Hard to just add more live server URLs when one test is already running (I think)
@@ -109,6 +110,9 @@ def test_check_notification(client, live_server, measure_memory_usage, datastore
"Diff Full: {{diff_full}}\n"
"Diff with args: {{diff(context=3)}}"
"Diff as Patch: {{diff_patch}}\n"
"Change datetime: {{change_datetime}}\n"
"Change datetime format: Weekday {{change_datetime(format='%A')}}\n"
"Change datetime format: {{change_datetime(format='%Y-%m-%dT%H:%M:%S%z')}}\n"
":-)",
"notification_screenshot": True,
"notification_format": 'text'}
@@ -136,8 +140,6 @@ def test_check_notification(client, live_server, measure_memory_usage, datastore
assert bytes(notification_url.encode('utf-8')) in res.data
assert bytes("New ChangeDetection.io Notification".encode('utf-8')) in res.data
## Now recheck, and it should have sent the notification
wait_for_all_checks(client)
set_modified_response(datastore_path=datastore_path)
@@ -173,11 +175,23 @@ def test_check_notification(client, live_server, measure_memory_usage, datastore
assert ":-)" in notification_submission
assert "New ChangeDetection.io Notification - {}".format(test_url) in notification_submission
assert test_url in notification_submission
assert ':-)' in notification_submission
# Check the attachment was added, and that it is a JPEG from the original PNG
notification_submission_object = json.loads(notification_submission)
assert notification_submission_object
import time
# Could be from a few seconds ago (when the notification was fired vs in this test checking), so check for any
times_possible = [str(FormattableTimestamp(int(time.time()) - i)) for i in range(15)]
assert any(t in notification_submission for t in times_possible)
txt = f"Weekday {FormattableTimestamp(int(time.time()))(format='%A')}"
assert txt in notification_submission
# We keep PNG screenshots for now
# IF THIS FAILS YOU SHOULD BE TESTING WITH ENV VAR REMOVE_REQUESTS_OLD_SCREENSHOTS=False
assert notification_submission_object['attachments'][0]['filename'] == 'last-screenshot.png'