API - DELETE for Watch history #4397 (#4403)

This commit is contained in:
dgtlmoon
2026-09-09 15:46:00 +02:00
committed by GitHub
parent 455e0228ca
commit 7f3645f4a8
4 changed files with 151 additions and 7 deletions
+14
View File
@@ -293,6 +293,20 @@ class WatchHistory(Resource):
abort(404, message='No watch exists with the UUID of {}'.format(uuid))
return watch.history, 200
# Delete all history/snapshots for a watch, but keep the watch itself
# curl -X DELETE http://localhost:5000/api/v1/watch/<uuid_str:uuid>/history
@auth.check_token
@validate_openapi_request('deleteWatchHistory')
def delete(self, uuid):
"""Clear all snapshot history for a watch (the watch itself is kept)."""
if not self.datastore.data['watching'].get(uuid):
abort(404, message='No watch exists with the UUID of {}'.format(uuid))
# Same call as the UI "Clear history" button - wipes snapshots/screenshots and
# resets last_checked etc, while preserving the watch and its processor config
self.datastore.clear_watch_history(uuid)
return 'OK', 204
class WatchSingleHistory(Resource):
def __init__(self, **kwargs):
+78
View File
@@ -338,6 +338,84 @@ def test_api_simple(client, live_server, measure_memory_usage, datastore_path):
)
assert len(res.json) == 0, "Watch list should be empty"
def test_api_delete_watch_history(client, live_server, measure_memory_usage, datastore_path):
"""DELETE /api/v1/watch/<uuid>/history should wipe the snapshots but keep the watch (#4397)"""
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
set_original_response(datastore_path=datastore_path)
test_url = url_for('test_endpoint', _external=True)
res = client.post(
url_for("createwatch"),
data=json.dumps({"url": test_url}),
headers={'content-type': 'application/json', 'x-api-key': api_key},
follow_redirects=True
)
assert res.status_code == 201
watch_uuid = res.json.get('uuid')
wait_for_all_checks(client)
# A second snapshot so we know we're clearing more than one
set_modified_response(datastore_path=datastore_path)
client.get(url_for("watch", uuid=watch_uuid, recheck='1'), headers={'x-api-key': api_key})
wait_for_all_checks(client)
res = client.get(
url_for("watchhistory", uuid=watch_uuid),
headers={'x-api-key': api_key},
)
assert len(res.json) == 2, "Should have two history entries before clearing"
# Unknown watch UUID should 404 and not blow up
res = client.delete(
url_for("watchhistory", uuid='4d8b5b4a-8e0b-4d4a-9f57-3f2b1c0d9e11'),
headers={'x-api-key': api_key},
)
assert res.status_code == 404
# Requires the API key
res = client.delete(url_for("watchhistory", uuid=watch_uuid))
assert res.status_code == 403
# Pause it first - clearing resets last_checked to 0 which otherwise makes the ticker
# queue an instant recheck, and that would race with the assertions below
client.get(url_for("watch", uuid=watch_uuid, paused='paused'), headers={'x-api-key': api_key})
# Now really clear it
res = client.delete(
url_for("watchhistory", uuid=watch_uuid),
headers={'x-api-key': api_key},
)
assert res.status_code == 204
res = client.get(
url_for("watchhistory", uuid=watch_uuid),
headers={'x-api-key': api_key},
)
assert res.json == {}, "History should be empty after DELETE"
# The watch itself must survive, with its state reset
res = client.get(
url_for("watch", uuid=watch_uuid),
headers={'x-api-key': api_key}
)
assert res.status_code == 200
assert res.json.get('url') == test_url
assert res.json.get('history_n') == 0
assert res.json.get('last_checked') == 0
assert res.json.get('previous_md5') == False
# And a snapshot fetch now has nothing to give
res = client.get(
url_for("watchsinglehistory", uuid=watch_uuid, timestamp='latest'),
headers={'x-api-key': api_key},
)
assert res.status_code == 404
delete_all_watches(client)
def test_roundtrip_API(client, live_server, measure_memory_usage, datastore_path):
"""
Test the full round trip, this way we test the default Model fits back into OpenAPI spec
+35 -1
View File
@@ -28,7 +28,7 @@ info:
For example: `x-api-key: YOUR_API_KEY`
version: 0.1.8
version: 0.1.9
contact:
name: ChangeDetection.io
url: https://github.com/dgtlmoon/changedetection.io
@@ -1271,6 +1271,40 @@ paths:
'404':
description: Web page change monitor (watch) not found
delete:
operationId: deleteWatchHistory
tags: [Watch History]
summary: Delete watch history
description: |
Delete/clear all historical snapshots for a web page change monitor (watch), the watch itself is kept.
This also resets the "last checked"/"last changed" state, so the watch will be re-checked on the next cycle.
x-code-samples:
- lang: 'curl'
source: |
curl -X DELETE "http://localhost:5000/api/v1/watch/095be615-a8ad-4c33-8e9c-c7612fbf6c9f/history" \
-H "x-api-key: YOUR_API_KEY"
- lang: 'Python'
source: |
import requests
headers = {'x-api-key': 'YOUR_API_KEY'}
uuid = '095be615-a8ad-4c33-8e9c-c7612fbf6c9f'
response = requests.delete(f'http://localhost:5000/api/v1/watch/{uuid}/history', headers=headers)
print(response.status_code)
parameters:
- name: uuid
in: path
required: true
description: Web page change monitor (watch) unique ID
schema:
type: string
format: uuid
responses:
'204':
description: History deleted successfully
'404':
description: Web page change monitor (watch) not found
/watch/{uuid}/history/{timestamp}:
get:
operationId: getWatchSnapshot
+24 -6
View File
File diff suppressed because one or more lines are too long