", methods=['POST'])
@login_optionally_required
def unlink(uuid):
# Unlink tag from all watches in background thread to avoid blocking
@@ -117,7 +117,7 @@ def construct_blueprint(datastore: ChangeDetectionStore):
flash(gettext("Unlinking tag from watches in background"))
return redirect(url_for('tags.tags_overview_page'))
- @tags_blueprint.route("/delete_all", methods=['GET'])
+ @tags_blueprint.route("/delete_all", methods=['POST'])
@login_optionally_required
def delete_all():
diff --git a/changedetectionio/blueprint/tags/templates/groups-overview.html b/changedetectionio/blueprint/tags/templates/groups-overview.html
index 769fdb4d..f82e2c9c 100644
--- a/changedetectionio/blueprint/tags/templates/groups-overview.html
+++ b/changedetectionio/blueprint/tags/templates/groups-overview.html
@@ -72,9 +72,13 @@ html[data-darkmode="true"] .watch-tag-list.tag-{{ class_name }} {
| {{ tag.title }} |
{{ _('Edit') }}
- {{ _('Recheck') }}
+
{{ _('Delete') }}
", methods=['GET'])
+ @ui_blueprint.route("/clear_history/", methods=['POST'])
@login_optionally_required
def clear_watch_history(uuid):
try:
@@ -227,7 +227,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_pool,
return output
# Clear all statuses, so we do not see the 'unviewed' class
- @ui_blueprint.route("/form/mark-all-viewed", methods=['GET'])
+ @ui_blueprint.route("/form/mark-all-viewed", methods=['POST'])
@login_optionally_required
def mark_all_viewed():
# Save the current newest history as the most recently viewed. Operate on
@@ -267,7 +267,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_pool,
return redirect(url_for('watchlist.index', **wl_filters.filter_query_args(request.args)))
- @ui_blueprint.route("/delete", methods=['GET'])
+ @ui_blueprint.route("/delete", methods=['POST'])
@login_optionally_required
def form_delete():
uuid = request.args.get('uuid')
@@ -284,7 +284,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_pool,
return redirect(url_for('watchlist.index'))
- @ui_blueprint.route("/clone", methods=['GET'])
+ @ui_blueprint.route("/clone", methods=['POST'])
@login_optionally_required
def form_clone():
uuid = request.args.get('uuid')
@@ -301,7 +301,7 @@ def construct_blueprint(datastore: ChangeDetectionStore, update_q, worker_pool,
return redirect(url_for("ui.ui_edit.edit_page", uuid=new_uuid))
- @ui_blueprint.route("/checknow", methods=['GET'])
+ @ui_blueprint.route("/checknow", methods=['POST'])
@login_optionally_required
def form_watch_checknow():
# Forced recheck will skip the 'skip if content is the same' rule (, 'reprocess_existing_data': True})))
diff --git a/changedetectionio/blueprint/ui/templates/edit.html b/changedetectionio/blueprint/ui/templates/edit.html
index aead58ad..0c2ae1eb 100644
--- a/changedetectionio/blueprint/ui/templates/edit.html
+++ b/changedetectionio/blueprint/ui/templates/edit.html
@@ -540,6 +540,7 @@ Math: {{ 1 + 1 }}") }}
{{ render_button(form.save_button) }}
{{ _('Delete') }}
{% if watch.history_n %}{{ _('Clear History') }}{% endif %}
{{ _('Clone & Edit') }}
diff --git a/changedetectionio/blueprint/watchlist/templates/watch-overview.html b/changedetectionio/blueprint/watchlist/templates/watch-overview.html
index 0c747694..204fe94c 100644
--- a/changedetectionio/blueprint/watchlist/templates/watch-overview.html
+++ b/changedetectionio/blueprint/watchlist/templates/watch-overview.html
@@ -272,8 +272,14 @@ window.watchOverviewI18n = {
It used to be {% if unread_count %}-gated, which meant it could not exist in the DOM
of another open tab — so marking viewed (or a new change arriving) in one tab could
never show/hide it in the other. Presence in the DOM is what lets realtime toggle it. #}
- {{ _('Mark all viewed') }}
- {{ _('Recheck all') }} {% if active_tag_uuid %}{{ _("in '%(title)s'", title=active_tag.title) }}{% endif %}
+ {# Submit button rather than a link: these mutate state, so they must not be
+ reachable by GET (an would fire them). formaction/formmethod
+ retarget the enclosing #watch-list-form, whose csrf_token comes along - and
+ avoids a nested |