Pass only the return parameter to form actions
Five templates built their form action with url_for(..., **request.args), so every query parameter ended up in the action. This included Flask's special parameters (?_external=1 gave an absolute http:// action in production) and the route parameters (?user_id=... or ?alias_id=... caused a TypeError and HTTP 500). The only parameter needed is return=detail, which sends the user back to the detail page after the POST. ReturnToMixin reads it, passes on only the known value and puts it into the template context as return_to. BackToUsersMixin and BackToAliasesMixin build on it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
53081dd553
commit
91eaef7f93
8 files changed
+30
-9
No files matched your search
@@ -4,6 +4,8 @@ from max.db import get_alias_with_user_by_id
|
||||
from max.exceptions import NotFound
|
||||
from max.views import BaseTemplateGetView
|
||||
|
||||
from .return_to_mixin import RETURN_DETAIL, ReturnToMixin
|
||||
|
||||
|
||||
class FetchAliasMixin:
|
||||
def before_handler(self):
|
||||
@@ -21,9 +23,9 @@ class FetchAliasTemplateGetView(FetchAliasMixin, BaseTemplateGetView):
|
||||
return context
|
||||
|
||||
|
||||
class BackToAliasesMixin:
|
||||
class BackToAliasesMixin(ReturnToMixin):
|
||||
def get_back_text_and_url(self):
|
||||
if self.request.args.get("return") == "detail":
|
||||
if self.get_return_to() == RETURN_DETAIL:
|
||||
return self.user.email, url_for("alias-detail", alias_id=self.alias.id)
|
||||
else:
|
||||
return self.user.email, url_for("user-detail", user_id=self.user.id)
|
||||
@@ -5,6 +5,8 @@ from max.exceptions import NotFound
|
||||
from max.translations import t
|
||||
from max.views import BaseTemplateGetView
|
||||
|
||||
from .return_to_mixin import RETURN_DETAIL, ReturnToMixin
|
||||
|
||||
|
||||
class FetchUserMixin:
|
||||
def before_handler(self):
|
||||
@@ -20,9 +22,9 @@ class FetchUserTemplateGetView(FetchUserMixin, BaseTemplateGetView):
|
||||
return context
|
||||
|
||||
|
||||
class BackToUsersMixin:
|
||||
class BackToUsersMixin(ReturnToMixin):
|
||||
def get_back_text_and_url(self):
|
||||
if self.request.args.get("return") == "detail":
|
||||
if self.get_return_to() == RETURN_DETAIL:
|
||||
return self.user.email, url_for("user-detail", user_id=self.user.id)
|
||||
else:
|
||||
return t("User list"), url_for("user-list")
|
||||
@@ -0,0 +1,17 @@
|
||||
RETURN_DETAIL = "detail"
|
||||
|
||||
|
||||
class ReturnToMixin:
|
||||
"""
|
||||
Reads the `return` query parameter, which tells where to go back to
|
||||
"""
|
||||
|
||||
def get_return_to(self):
|
||||
if self.request.args.get("return") == RETURN_DETAIL:
|
||||
return RETURN_DETAIL
|
||||
return None
|
||||
|
||||
def get_context(self):
|
||||
context = super().get_context()
|
||||
context["return_to"] = self.get_return_to()
|
||||
return context
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{% include "alerts.html" %}
|
||||
|
||||
<form action="{{ url_for('alias-delete', alias_id=alias.id, **request.args) }}" method="post">
|
||||
<form action="{{ url_for('alias-delete', alias_id=alias.id, return=return_to) }}" method="post">
|
||||
<button type="submit" class="pure-button button-error">{{ t("Delete") }}</button>
|
||||
<a href="{{ back_url }}" class="pure-button">{{ t("Cancel") }}</a>
|
||||
{% include "csrf.html" %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{% include "alerts.html" %}
|
||||
|
||||
<form id="form" class="pure-form pure-form-stacked" action="{{ url_for('alias-edit-note', alias_id=alias.id, **request.args) }}" method="post">
|
||||
<form id="form" class="pure-form pure-form-stacked" action="{{ url_for('alias-edit-note', alias_id=alias.id, return=return_to) }}" method="post">
|
||||
<label for="note">{{ t("Note") }}</label>
|
||||
<textarea id="note" name="note" form="form">{{ alias.note }}</textarea>
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{% include "alerts.html" %}
|
||||
|
||||
<form class="pure-form pure-form-aligned" action="{{ url_for('user-change-password', user_id=user.id, **request.args) }}" method="post">
|
||||
<form class="pure-form pure-form-aligned" action="{{ url_for('user-change-password', user_id=user.id, return=return_to) }}" method="post">
|
||||
<div class="pure-control-group">
|
||||
<label for="password1">{{ t("Password") }}</label>
|
||||
<input id="password1" type="password" name="password1" placeholder="{{ t("New password") }}">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{% include "alerts.html" %}
|
||||
|
||||
<form action="{{ url_for('user-delete', user_id=user.id, **request.args) }}" method="post">
|
||||
<form action="{{ url_for('user-delete', user_id=user.id, return=return_to) }}" method="post">
|
||||
<button type="submit" class="pure-button button-error">{{ t("Delete") }}</button>
|
||||
<a href="{{ back_url }}" class="pure-button">{{ t("Cancel") }}</a>
|
||||
{% include "csrf.html" %}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
{% include "alerts.html" %}
|
||||
|
||||
<form id="form" class="pure-form pure-form-stacked" action="{{ url_for('user-edit-note', user_id=user.id, **request.args) }}" method="post">
|
||||
<form id="form" class="pure-form pure-form-stacked" action="{{ url_for('user-edit-note', user_id=user.id, return=return_to) }}" method="post">
|
||||
<label for="note">{{ t("Note") }}</label>
|
||||
<textarea id="note" name="note" form="form">{{ user.note }}</textarea>
|
||||
|
||||
|
||||
Reference in new issue
Block a user