Notification Improvements - New tokens `{{diff_added}}` and `{{diff_removed}}`, removed whitespace around `added` and `into` ( Issue #905 ) (#1454)

pull/1465/head^2
reecespieces 2 years ago committed by GitHub
parent 23476f0e70
commit 0d05ee1586
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -10,7 +10,7 @@ def same_slicer(l, a, b):
return l[a:b] return l[a:b]
# like .compare but a little different output # like .compare but a little different output
def customSequenceMatcher(before, after, include_equal=False): def customSequenceMatcher(before, after, include_equal=False, include_removed=True, include_added=True):
cruncher = difflib.SequenceMatcher(isjunk=lambda x: x in " \\t", a=before, b=after) cruncher = difflib.SequenceMatcher(isjunk=lambda x: x in " \\t", a=before, b=after)
# @todo Line-by-line mode instead of buncghed, including `after` that is not in `before` (maybe unset?) # @todo Line-by-line mode instead of buncghed, including `after` that is not in `before` (maybe unset?)
@ -18,20 +18,20 @@ def customSequenceMatcher(before, after, include_equal=False):
if include_equal and tag == 'equal': if include_equal and tag == 'equal':
g = before[alo:ahi] g = before[alo:ahi]
yield g yield g
elif tag == 'delete': elif include_removed and tag == 'delete':
g = ["(removed) " + i for i in same_slicer(before, alo, ahi)] g = ["(removed) " + i for i in same_slicer(before, alo, ahi)]
yield g yield g
elif tag == 'replace': elif tag == 'replace':
g = ["(changed) " + i for i in same_slicer(before, alo, ahi)] g = ["(changed) " + i for i in same_slicer(before, alo, ahi)]
g += ["(into ) " + i for i in same_slicer(after, blo, bhi)] g += ["(into) " + i for i in same_slicer(after, blo, bhi)]
yield g yield g
elif tag == 'insert': elif include_added and tag == 'insert':
g = ["(added ) " + i for i in same_slicer(after, blo, bhi)] g = ["(added) " + i for i in same_slicer(after, blo, bhi)]
yield g yield g
# only_differences - only return info about the differences, no context # only_differences - only return info about the differences, no context
# line_feed_sep could be "<br/>" or "<li>" or "\n" etc # line_feed_sep could be "<br/>" or "<li>" or "\n" etc
def render_diff(previous_file, newest_file, include_equal=False, line_feed_sep="\n"): def render_diff(previous_file, newest_file, include_equal=False, include_removed=True, include_added=True, line_feed_sep="\n"):
with open(newest_file, 'r') as f: with open(newest_file, 'r') as f:
newest_version_file_contents = f.read() newest_version_file_contents = f.read()
newest_version_file_contents = [line.rstrip() for line in newest_version_file_contents.splitlines()] newest_version_file_contents = [line.rstrip() for line in newest_version_file_contents.splitlines()]
@ -45,7 +45,7 @@ def render_diff(previous_file, newest_file, include_equal=False, line_feed_sep="
rendered_diff = customSequenceMatcher(previous_version_file_contents, rendered_diff = customSequenceMatcher(previous_version_file_contents,
newest_version_file_contents, newest_version_file_contents,
include_equal) include_equal, include_removed, include_added)
# Recursively join lists # Recursively join lists
f = lambda L: line_feed_sep.join([f(x) if type(x) is list else x for x in L]) f = lambda L: line_feed_sep.join([f(x) if type(x) is list else x for x in L])

@ -10,6 +10,8 @@ valid_tokens = {
'watch_title': '', 'watch_title': '',
'watch_tag': '', 'watch_tag': '',
'diff': '', 'diff': '',
'diff_added': '',
'diff_removed': '',
'diff_full': '', 'diff_full': '',
'diff_url': '', 'diff_url': '',
'preview_url': '', 'preview_url': '',
@ -215,6 +217,8 @@ def create_notification_parameters(n_object, datastore):
'watch_tag': watch_tag if watch_tag is not None else '', 'watch_tag': watch_tag if watch_tag is not None else '',
'diff_url': diff_url, 'diff_url': diff_url,
'diff': n_object.get('diff', ''), # Null default in the case we use a test 'diff': n_object.get('diff', ''), # Null default in the case we use a test
'diff_added': n_object.get('diff_added', ''), # Null default in the case we use a test
'diff_removed': n_object.get('diff_removed', ''), # Null default in the case we use a test
'diff_full': n_object.get('diff_full', ''), # Null default in the case we use a test 'diff_full': n_object.get('diff_full', ''), # Null default in the case we use a test
'preview_url': preview_url, 'preview_url': preview_url,
'current_snapshot': n_object['current_snapshot'] if 'current_snapshot' in n_object else '' 'current_snapshot': n_object['current_snapshot'] if 'current_snapshot' in n_object else ''

@ -55,39 +55,51 @@
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><code>{{ '{{ base_url }}' }}</code></td> <td><code>{{ '{{base_url}}' }}</code></td>
<td>The URL of the changedetection.io instance you are running.</td> <td>The URL of the changedetection.io instance you are running.</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ watch_url }}' }}</code></td> <td><code>{{ '{{watch_url}}' }}</code></td>
<td>The URL being watched.</td> <td>The URL being watched.</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ watch_uuid }}' }}</code></td> <td><code>{{ '{{watch_uuid}}' }}</code></td>
<td>The UUID of the watch.</td> <td>The UUID of the watch.</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ watch_title }}' }}</code></td> <td><code>{{ '{{watch_title}}' }}</code></td>
<td>The title of the watch.</td> <td>The title of the watch.</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ watch_tag }}' }}</code></td> <td><code>{{ '{{watch_tag}}' }}</code></td>
<td>The watch label / tag</td> <td>The watch label / tag</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ preview_url }}' }}</code></td> <td><code>{{ '{{preview_url}}' }}</code></td>
<td>The URL of the preview page generated by changedetection.io.</td> <td>The URL of the preview page generated by changedetection.io.</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ diff_url }}' }}</code></td> <td><code>{{ '{{diff_url}}' }}</code></td>
<td>The diff output - differences only</td> <td>The URL of the diff output for the watch.</td>
</tr>
<tr>
<td><code>{{ '{{diff}}' }}</code></td>
<td>The diff output - only changes, additions, and removals</td>
</tr>
<tr>
<td><code>{{ '{{diff_added}}' }}</code></td>
<td>The diff output - only changes and additions</td>
</tr>
<tr>
<td><code>{{ '{{diff_removed}}' }}</code></td>
<td>The diff output - only changes and removals</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ diff_full }}' }}</code></td> <td><code>{{ '{{diff_full}}' }}</code></td>
<td>The diff output - full difference output</td> <td>The diff output - full difference output</td>
</tr> </tr>
<tr> <tr>
<td><code>{{ '{{ current_snapshot }}' }}</code></td> <td><code>{{ '{{current_snapshot}}' }}</code></td>
<td>The current snapshot value, useful when combined with JSON or CSS filters <td>The current snapshot value, useful when combined with JSON or CSS filters
</td> </td>
</tr> </tr>
@ -95,8 +107,10 @@
</table> </table>
<div class="pure-form-message-inline"> <div class="pure-form-message-inline">
<br> <br>
URLs generated by changedetection.io (such as <code>{{ '{{ diff_url }}' }}</code>) require the <code>BASE_URL</code> environment variable set.<br/> URLs generated by changedetection.io (such as <code>{{ '{{diff_url}}' }}</code>) require the <code>BASE_URL</code> environment variable set.<br/>
Your <code>BASE_URL</code> var is currently "{{settings_application['current_base_url']}}" Your <code>BASE_URL</code> var is currently "{{settings_application['current_base_url']}}"
<br>
Warning: Contents of <code>{{ '{{diff}}' }}</code>, <code>{{ '{{diff_removed}}' }}</code>, and <code>{{ '{{diff_added}}' }}</code> depend on how the difference algorithm perceives the change. For example, an addition or removal could be perceived as a change in some cases. <a target="_new" href="https://github.com/dgtlmoon/changedetection.io/wiki/Using-the-%7B%7Bdiff%7D%7D,-%7B%7Bdiff_added%7D%7D,-and-%7B%7Bdiff_removal%7D%7D-notification-tokens">More Here</a> </br>
</div> </div>
</div> </div>
</div> </div>

@ -82,7 +82,7 @@ def test_check_basic_change_detection_functionality(client, live_server):
assert b'<rss' in res.data assert b'<rss' in res.data
# re #16 should have the diff in here too # re #16 should have the diff in here too
assert b'(into ) which has this one new line' in res.data assert b'(into) which has this one new line' in res.data
assert b'CDATA' in res.data assert b'CDATA' in res.data
assert expected_url.encode('utf-8') in res.data assert expected_url.encode('utf-8') in res.data

@ -100,6 +100,8 @@ def test_check_notification(client, live_server):
"Diff URL: {{diff_url}}\n" "Diff URL: {{diff_url}}\n"
"Snapshot: {{current_snapshot}}\n" "Snapshot: {{current_snapshot}}\n"
"Diff: {{diff}}\n" "Diff: {{diff}}\n"
"Diff Added: {{diff_added}}\n"
"Diff Removed: {{diff_removed}}\n"
"Diff Full: {{diff_full}}\n" "Diff Full: {{diff_full}}\n"
":-)", ":-)",
"notification_screenshot": True, "notification_screenshot": True,
@ -147,7 +149,7 @@ def test_check_notification(client, live_server):
assert ':-)' in notification_submission assert ':-)' in notification_submission
assert "Diff Full: Some initial text" in notification_submission assert "Diff Full: Some initial text" in notification_submission
assert "Diff: (changed) Which is across multiple lines" in notification_submission assert "Diff: (changed) Which is across multiple lines" in notification_submission
assert "(into ) which has this one new line" in notification_submission assert "(into) which has this one new line" in notification_submission
# Re #342 - check for accidental python byte encoding of non-utf8/string # Re #342 - check for accidental python byte encoding of non-utf8/string
assert "b'" not in notification_submission assert "b'" not in notification_submission
assert re.search('Watch UUID: [0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}', notification_submission, re.IGNORECASE) assert re.search('Watch UUID: [0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}', notification_submission, re.IGNORECASE)

@ -16,15 +16,30 @@ class TestDiffBuilder(unittest.TestCase):
output = diff.render_diff(previous_file=base_dir + "/test-content/before.txt", newest_file=base_dir + "/test-content/after.txt") output = diff.render_diff(previous_file=base_dir + "/test-content/before.txt", newest_file=base_dir + "/test-content/after.txt")
output = output.split("\n") output = output.split("\n")
self.assertIn('(changed) ok', output) self.assertIn('(changed) ok', output)
self.assertIn('(into ) xok', output) self.assertIn('(into) xok', output)
self.assertIn('(into ) next-x-ok', output) self.assertIn('(into) next-x-ok', output)
self.assertIn('(added ) and something new', output) self.assertIn('(added) and something new', output)
output = diff.render_diff(previous_file=base_dir + "/test-content/before.txt", newest_file=base_dir + "/test-content/after-2.txt") output = diff.render_diff(previous_file=base_dir + "/test-content/before.txt", newest_file=base_dir + "/test-content/after-2.txt")
output = output.split("\n") output = output.split("\n")
self.assertIn('(removed) for having learned computerese,', output) self.assertIn('(removed) for having learned computerese,', output)
self.assertIn('(removed) I continue to examine bits, bytes and words', output) self.assertIn('(removed) I continue to examine bits, bytes and words', output)
#diff_removed
output = diff.render_diff(previous_file=base_dir + "/test-content/before.txt", newest_file=base_dir + "/test-content/after.txt", include_equal=False, include_removed=True, include_added=False)
output = output.split("\n")
self.assertIn('(changed) ok', output)
self.assertIn('(into) xok', output)
self.assertIn('(into) next-x-ok', output)
self.assertNotIn('(added) and something new', output)
#diff_removed
output = diff.render_diff(previous_file=base_dir + "/test-content/before.txt", newest_file=base_dir + "/test-content/after-2.txt", include_equal=False, include_removed=True, include_added=False)
output = output.split("\n")
self.assertIn('(removed) for having learned computerese,', output)
self.assertIn('(removed) I continue to examine bits, bytes and words', output)
# @todo test blocks of changed, blocks of added, blocks of removed # @todo test blocks of changed, blocks of added, blocks of removed

@ -78,7 +78,9 @@ class update_worker(threading.Thread):
'screenshot': watch.get_screenshot_as_jpeg() if watch.get('notification_screenshot') else None, 'screenshot': watch.get_screenshot_as_jpeg() if watch.get('notification_screenshot') else None,
'current_snapshot': snapshot_contents.decode('utf-8'), 'current_snapshot': snapshot_contents.decode('utf-8'),
'diff': diff.render_diff(watch_history[dates[-2]], watch_history[dates[-1]], line_feed_sep=line_feed_sep), 'diff': diff.render_diff(watch_history[dates[-2]], watch_history[dates[-1]], line_feed_sep=line_feed_sep),
'diff_full': diff.render_diff(watch_history[dates[-2]], watch_history[dates[-1]], True, line_feed_sep=line_feed_sep) 'diff_added': diff.render_diff(watch_history[dates[-2]], watch_history[dates[-1]], include_removed=False, line_feed_sep=line_feed_sep),
'diff_removed': diff.render_diff(watch_history[dates[-2]], watch_history[dates[-1]], include_added=False, line_feed_sep=line_feed_sep),
'diff_full': diff.render_diff(watch_history[dates[-2]], watch_history[dates[-1]], include_equal=True, line_feed_sep=line_feed_sep)
}) })
logging.info (">> SENDING NOTIFICATION") logging.info (">> SENDING NOTIFICATION")
self.notification_q.put(n_object) self.notification_q.put(n_object)

Loading…
Cancel
Save