From 144d0242971ae0d18722e8ef094b5341fd19446f Mon Sep 17 00:00:00 2001 From: Krzysztof SOCHA Date: Mon, 19 Aug 2024 14:27:49 +0200 Subject: [PATCH 1/4] Add parameter to Grid class so that URL generation within the grid can be controlled better. --- py4web/utils/grid.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/py4web/utils/grid.py b/py4web/utils/grid.py index 0889df16..56686216 100644 --- a/py4web/utils/grid.py +++ b/py4web/utils/grid.py @@ -318,6 +318,7 @@ def __init__( grid_class_style=GridClassStyle, T=lambda text: text, groupby=None, + use_appname=None, # deprecated fields=None, form_maker=Form, @@ -351,6 +352,8 @@ def __init__( fullpath = request.fullpath.rstrip("/") if path == "index": fullpath = fullpath[:-6] + if use_appname == False: + fullpath = fullpath.replace(f"/{request.app_name}", "") redirect( f"{fullpath}/select" + (f"?{request.query_string}" if request.query_string else "") @@ -403,12 +406,16 @@ def __init__( header_elements=None, footer_elements=None, required_fields=required_fields or [], + use_appname=use_appname ) # instance variables that will be computed self.action = None self.current_page_number = None self.endpoint = request.fullpath[: -len(self.path)].rstrip("/") + if use_appname == False: + self.endpoint = self.endpoint.replace(f"/{request.app_name}", "") + print(f"endpoint = {self.endpoint}") self.hidden_fields = None self.form = None self.number_of_pages = None @@ -940,12 +947,12 @@ def _make_col_header(self, col, index, sort_order): if orderby: if orderby == sort_order: sort_query_parms["orderby"] = "~" + orderby - url = URL(self.endpoint, "select", vars=sort_query_parms) + url = URL(self.endpoint, "select", vars=sort_query_parms, use_appname=self.param.use_appname) attrs = self.attributes_plugin.link(url=url) col_header = A(heading, up, **attrs) else: sort_query_parms["orderby"] = orderby - url = URL(self.endpoint, "select", vars=sort_query_parms) + url = URL(self.endpoint, "select", vars=sort_query_parms, use_appname=self.param.use_appname) attrs = self.attributes_plugin.link(url=url) col_header = A( heading, dw if "~" + orderby == sort_order else "", **attrs @@ -1130,7 +1137,7 @@ def _make_table_pager(self): else "grid-pagination-button" ) attrs = self.attributes_plugin.link( - url=URL(self.endpoint, "select", vars=pager_query_parms) + url=URL(self.endpoint, "select", vars=pager_query_parms, use_appname=self.param.use_appname) ) pager.append( A( From 289675e2a1b085d151b9f00c95c8c4837c1f6a60 Mon Sep 17 00:00:00 2001 From: Krzysztof SOCHA Date: Mon, 26 Aug 2024 15:40:49 +0200 Subject: [PATCH 2/4] Add parameter to Form class so that URL generation for the submit action can be controlled better. --- py4web/utils/form.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/py4web/utils/form.py b/py4web/utils/form.py index fa31a785..b874f702 100644 --- a/py4web/utils/form.py +++ b/py4web/utils/form.py @@ -277,6 +277,7 @@ def __call__( deletable, noncreate, show_id, + use_appname, kwargs=None, ): kwargs = kwargs if kwargs else {} @@ -284,6 +285,8 @@ def __call__( kwargs["_accept-charset"] = "utf8" form_method = "POST" form_action = request.url.split(":", 1)[1] + if use_appname == False: + form_action = form_action.replace(f"/{request.app_name}", "") form_enctype = "multipart/form-data" if "_method" in kwargs: @@ -696,6 +699,7 @@ def __init__( signing_info=None, submit_value="Submit", show_id=False, + use_appname=None, **kwargs, ): self.param = Param( @@ -732,6 +736,7 @@ def __init__( self.lifespan = lifespan self.csrf_protection = csrf_protection self.show_id = show_id + self.use_appname = use_appname # initialized and can change self.vars = {} self.errors = {} @@ -927,6 +932,7 @@ def helper(self): self.deletable, self.noncreate, show_id=self.show_id, + use_appname=self.use_appname, kwargs=self.kwargs, ) for item in self.param.sidecar: From 4d824c03608465c0f5f4a775d782666a2603a35e Mon Sep 17 00:00:00 2001 From: Krzysztof SOCHA Date: Tue, 27 Aug 2024 16:15:51 +0200 Subject: [PATCH 3/4] Ensure the use_appname setting is passed from the Grid to the auto-generated Forms --- py4web/utils/grid.py | 1 + 1 file changed, 1 insertion(+) diff --git a/py4web/utils/grid.py b/py4web/utils/grid.py index 56686216..b65eebf0 100644 --- a/py4web/utils/grid.py +++ b/py4web/utils/grid.py @@ -613,6 +613,7 @@ def compute(row, name=str(col)): formstyle=self.param.formstyle, validation=self.param.validation, show_id=self.param.show_id, + use_appname=self.param.use_appname, **attrs, ) if self.action == "new" and self.param.create: From 89cf31a8bff8d986247a42901c399732b7ff28ab Mon Sep 17 00:00:00 2001 From: Krzysztof SOCHA Date: Thu, 29 Aug 2024 08:45:18 +0200 Subject: [PATCH 4/4] Patch auth.py to use the use the "use_appname_in_redirects" parameter when consturcint "next" links, building forms and when redirecting to "index" --- py4web/utils/auth.py | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/py4web/utils/auth.py b/py4web/utils/auth.py index 0a04d932..fbc47e14 100644 --- a/py4web/utils/auth.py +++ b/py4web/utils/auth.py @@ -69,7 +69,10 @@ def abort_or_redirect(self, page, message=""): if "text/html" not in request.headers.get("accept", ""): raise HTTP(403, body={"message": message}) - redirect_next = request.fullpath + if self.auth.param.use_appname_in_redirects == False: + redirect_next = request.fullpath.replace(f"/{request.app_name}", "") + else: + redirect_next = request.fullpath if request.query_string: redirect_next = redirect_next + "?{}".format(request.query_string) self.auth.flash.set(message) @@ -91,7 +94,10 @@ def goto_login(self, message=""): request.headers.get("json-redirects", "") != "on" ): raise HTTP(403) - redirect_next = request.fullpath + if self.auth.param.use_appname_in_redirects == False: + redirect_next = request.fullpath.replace(f"/{request.app_name}", "") + else: + redirect_next = request.fullpath if request.query_string: redirect_next = redirect_next + "?{}".format(request.query_string) redirect( @@ -1482,7 +1488,10 @@ def register(self, model=False): self.auth.get_or_delete_existing_unverified_account(email) extra_form_fields = self.auth.extra_form_fields.get("register", []) fields += extra_form_fields - form = Form(fields, submit_value=button_name, formstyle=self.formstyle) + form = Form(fields, + submit_value=button_name, + formstyle=self.formstyle, + use_appname=self.auth.param.use_appname_in_redirects) user = None if form.accepted: # notice that here the form is alrealdy validated @@ -1620,6 +1629,7 @@ def login(self, model=False): fields, submit_value=button_name, formstyle=self.formstyle, + use_appname=self.auth.param.use_appname_in_redirects ) user = None next_url = prevent_open_redirect(request.query.get("next")) @@ -1682,7 +1692,7 @@ def two_factor(self): next_url = self.auth.session.get("auth.2fa_next_url") if not user_id: - redirect(URL("index")) + redirect(URL("index", use_appname=self.auth.param.use_appname_in_redirects)) user = self.auth.db.auth_user(user_id) code = self.auth.session.get("auth.2fa_code") @@ -1710,6 +1720,7 @@ def two_factor(self): form_name="auth_2fa", keep_values=True, hidden=dict(next_url=next_url), + use_appname=self.auth.param.use_appname_in_redirects, ) if form.accepted: @@ -1783,6 +1794,7 @@ def request_reset_password(self, model=False): fields, submit_value=button_name, formstyle=self.formstyle, + use_appname=self.auth.param.use_appname_in_redirects ) if form.accepted: email = form.vars.get("email", "") @@ -1851,6 +1863,7 @@ def reset_password(self, model=False): fields, formstyle=self.formstyle, submit_value=button_name, + use_appname=self.auth.param.use_appname_in_redirects ) self._process_change_password_form(form, user, False) if form.accepted: @@ -1896,6 +1909,7 @@ def change_password(self, model=False): fields, formstyle=self.formstyle, submit_value=button_name, + use_appname=self.auth.param.use_appname_in_redirects ) user = self.auth.db.auth_user(self.auth.user_id) self._process_change_password_form(form, user, True) @@ -1959,6 +1973,7 @@ def profile(self, model=False): formstyle=self.formstyle, deletable=deletable, submit_value=button_name, + use_appname=self.auth.param.use_appname_in_redirects ) if form.accepted: self._set_flash("profile-saved") @@ -1996,4 +2011,4 @@ def _postprocessing(self, action, form=None, user=None): if action in self.auth.on_accept: self.auth.on_accept[action](form, user) if not form or form.accepted: - redirect(self.auth.session.get(f"_next_{action}") or URL("index")) + redirect(self.auth.session.get(f"_next_{action}") or URL("index", use_appname=self.auth.param.use_appname_in_redirects))