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.exceptions import NotFound
|
||||||
from max.views import BaseTemplateGetView
|
from max.views import BaseTemplateGetView
|
||||||
|
|
||||||
|
from .return_to_mixin import RETURN_DETAIL, ReturnToMixin
|
||||||
|
|
||||||
|
|
||||||
class FetchAliasMixin:
|
class FetchAliasMixin:
|
||||||
def before_handler(self):
|
def before_handler(self):
|
||||||
@@ -21,9 +23,9 @@ class FetchAliasTemplateGetView(FetchAliasMixin, BaseTemplateGetView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class BackToAliasesMixin:
|
class BackToAliasesMixin(ReturnToMixin):
|
||||||
def get_back_text_and_url(self):
|
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)
|
return self.user.email, url_for("alias-detail", alias_id=self.alias.id)
|
||||||
else:
|
else:
|
||||||
return self.user.email, url_for("user-detail", user_id=self.user.id)
|
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.translations import t
|
||||||
from max.views import BaseTemplateGetView
|
from max.views import BaseTemplateGetView
|
||||||
|
|
||||||
|
from .return_to_mixin import RETURN_DETAIL, ReturnToMixin
|
||||||
|
|
||||||
|
|
||||||
class FetchUserMixin:
|
class FetchUserMixin:
|
||||||
def before_handler(self):
|
def before_handler(self):
|
||||||
@@ -20,9 +22,9 @@ class FetchUserTemplateGetView(FetchUserMixin, BaseTemplateGetView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class BackToUsersMixin:
|
class BackToUsersMixin(ReturnToMixin):
|
||||||
def get_back_text_and_url(self):
|
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)
|
return self.user.email, url_for("user-detail", user_id=self.user.id)
|
||||||
else:
|
else:
|
||||||
return t("User list"), url_for("user-list")
|
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" %}
|
{% 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>
|
<button type="submit" class="pure-button button-error">{{ t("Delete") }}</button>
|
||||||
<a href="{{ back_url }}" class="pure-button">{{ t("Cancel") }}</a>
|
<a href="{{ back_url }}" class="pure-button">{{ t("Cancel") }}</a>
|
||||||
{% include "csrf.html" %}
|
{% include "csrf.html" %}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{% include "alerts.html" %}
|
{% 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>
|
<label for="note">{{ t("Note") }}</label>
|
||||||
<textarea id="note" name="note" form="form">{{ alias.note }}</textarea>
|
<textarea id="note" name="note" form="form">{{ alias.note }}</textarea>
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{% include "alerts.html" %}
|
{% 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">
|
<div class="pure-control-group">
|
||||||
<label for="password1">{{ t("Password") }}</label>
|
<label for="password1">{{ t("Password") }}</label>
|
||||||
<input id="password1" type="password" name="password1" placeholder="{{ t("New password") }}">
|
<input id="password1" type="password" name="password1" placeholder="{{ t("New password") }}">
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{% include "alerts.html" %}
|
{% 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>
|
<button type="submit" class="pure-button button-error">{{ t("Delete") }}</button>
|
||||||
<a href="{{ back_url }}" class="pure-button">{{ t("Cancel") }}</a>
|
<a href="{{ back_url }}" class="pure-button">{{ t("Cancel") }}</a>
|
||||||
{% include "csrf.html" %}
|
{% include "csrf.html" %}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
{% include "alerts.html" %}
|
{% 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>
|
<label for="note">{{ t("Note") }}</label>
|
||||||
<textarea id="note" name="note" form="form">{{ user.note }}</textarea>
|
<textarea id="note" name="note" form="form">{{ user.note }}</textarea>
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user