diff --git a/README.md b/README.md index f8810d79..afec9745 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,9 @@ This proxy support also extends to the notifications https://github.com/caronc/a RaspberriPi and linux/arm/v6 linux/arm/v7 arm64 devices are supported! +### Windows native support? + +Sorry not yet :( https://github.com/dgtlmoon/changedetection.io/labels/windows ### Support us diff --git a/changedetectionio/forms.py b/changedetectionio/forms.py index e8f82bdc..f67d851e 100644 --- a/changedetectionio/forms.py +++ b/changedetectionio/forms.py @@ -116,6 +116,20 @@ class ValidateContentFetcherIsReady(object): raise ValidationError(message % (field.data, e)) +class ValidateTokensList(object): + """ + Validates that a {token} is from a valid set + """ + def __init__(self, message=None): + self.message = message + + def __call__(self, form, field): + from changedetectionio import notification + regex = re.compile('{.*?}') + for p in re.findall(regex, field.data): + if not p.strip('{}') in notification.valid_tokens: + message = field.gettext('Token \'%s\' is not a valid token.') + raise ValidationError(message % (p)) class ValidateListRegex(object): """ @@ -195,5 +209,5 @@ class globalSettingsForm(Form): extract_title_as_title = BooleanField('Extract from document and use as watch title') trigger_check = BooleanField('Send test notification on save') - notification_title = StringField('Notification Title') - notification_body = TextAreaField('Notification Body') + notification_title = StringField('Notification Title', validators=[validators.Optional(), ValidateTokensList()]) + notification_body = TextAreaField('Notification Body', validators=[validators.Optional(), ValidateTokensList()]) diff --git a/changedetectionio/notification.py b/changedetectionio/notification.py index 4db6c589..0772ce55 100644 --- a/changedetectionio/notification.py +++ b/changedetectionio/notification.py @@ -1,6 +1,15 @@ import os import apprise +valid_tokens = { + 'base_url': '', + 'watch_url': '', + 'diff_url': '', + 'preview_url': '', + 'current_snapshot': '' +} + + def process_notification(n_object, datastore): apobj = apprise.Apprise() for url in n_object['notification_urls']: @@ -31,7 +40,7 @@ def process_notification(n_object, datastore): # Notification title + body content parameters get created here. def create_notification_parameters(n_object): - + from copy import deepcopy # in the case we send a test notification from the main settings, there is no UUID. uuid = n_object['uuid'] if 'uuid' in n_object else '' @@ -47,11 +56,19 @@ def create_notification_parameters(n_object): diff_url = "{}/diff/{}".format(base_url, uuid) preview_url = "{}/preview/{}".format(base_url, uuid) - return { + # Not sure deepcopy is needed here, but why not + tokens = deepcopy(valid_tokens) + + # Valid_tokens also used as a field validator + tokens.update( + { 'base_url': base_url, 'watch_url': watch_url, 'diff_url': diff_url, 'preview_url': preview_url, 'current_snapshot': n_object['current_snapshot'] if 'current_snapshot' in n_object else '' - } + }) + + return tokens + diff --git a/changedetectionio/tests/test_notification.py b/changedetectionio/tests/test_notification.py index e13b2ad8..0ad8694a 100644 --- a/changedetectionio/tests/test_notification.py +++ b/changedetectionio/tests/test_notification.py @@ -98,10 +98,15 @@ def test_check_notification(client, live_server): res = client.post( url_for("settings_page"), data={"notification_title": "New ChangeDetection.io Notification - {watch_url}", - "notification_body": "{base_url}\n{watch_url}\n{preview_url}\n{diff_url}\n{current_snapshot}\n:-)", + "notification_body": "BASE URL: {base_url}\n" + "Watch URL: {watch_url}\n" + "Preview: {preview_url}\n" + "Diff URL: {diff_url}\n" + "Snapshot: {current_snapshot}\n" + ":-)", "notification_urls": "json://foobar.com", #Re #143 should not see that it sent without [test checkbox] "minutes_between_check": 180, - "fetch_backend": "html_requests", + "fetch_backend": "html_requests" }, follow_redirects=True ) @@ -145,3 +150,18 @@ def test_check_notification(client, live_server): client.get(url_for("api_watch_checknow"), follow_redirects=True) time.sleep(3) assert os.path.exists("test-datastore/notification.txt") == False + + + # Now adding a wrong token should give us an error + res = client.post( + url_for("settings_page"), + data={"notification_title": "New ChangeDetection.io Notification - {watch_url}", + "notification_body": "Rubbish: {rubbish}\n", + "notification_urls": "json://foobar.com", + "minutes_between_check": 180, + "fetch_backend": "html_requests" + }, + follow_redirects=True + ) + + assert bytes("is not a valid token".encode('utf-8')) in res.data \ No newline at end of file