diff --git a/website_membership_signup_required/__manifest__.py b/website_membership_signup_required/__manifest__.py index c59a65c..0ec11e6 100644 --- a/website_membership_signup_required/__manifest__.py +++ b/website_membership_signup_required/__manifest__.py @@ -3,7 +3,7 @@ { # noqa: B018 "name": "Website Membership Signup Required", - "version": "18.0.1.0.0", + "version": "18.0.1.0.1", "category": "Website/Sale", "summary": "Force a clean /web/signup step before adding membership " "products to cart on a b2b website (EMES-style flow).", diff --git a/website_membership_signup_required/controllers/main.py b/website_membership_signup_required/controllers/main.py index 38ce0c0..b6de11b 100644 --- a/website_membership_signup_required/controllers/main.py +++ b/website_membership_signup_required/controllers/main.py @@ -32,7 +32,18 @@ class AuthSignupHomeMembership(AuthSignupHome): # it as `qcontext['error']` which the template renders as a red # alert above the form, so no extra plumbing is needed). The browser # also enforces it client-side via `required="required"`. - if qcontext.get("accepted_terms") != "accepted": + # + # `_prepare_signup_values` is also invoked by the core during the + # password reset flow (`/web/reset_password`). That form does NOT + # render the terms checkbox, so we must skip the validation there. + # Existing users resetting their password already accepted the terms + # when they signed up. We detect the reset flow primarily by the + # request path and secondarily by the qcontext flag set by core. + is_reset_password = ( + request.httprequest.path == "/web/reset_password" + or qcontext.get("reset_password") + ) + if not is_reset_password and qcontext.get("accepted_terms") != "accepted": raise UserError(_("You must accept the terms and conditions.")) # partner_firstname: the signup form collects `firstname` / `lastname` # separately. We inject both into the signup values so the resulting diff --git a/website_membership_signup_required/tests/test_membership_signup.py b/website_membership_signup_required/tests/test_membership_signup.py index 0216cb5..b3d059b 100644 --- a/website_membership_signup_required/tests/test_membership_signup.py +++ b/website_membership_signup_required/tests/test_membership_signup.py @@ -137,7 +137,6 @@ class TestMembershipSignup(TransactionCase): """Signup must be rejected if the legal terms checkbox is not checked (`accepted_terms` missing or not 'accepted'). """ - import unittest controller = AuthSignupHome() base_qcontext = { "login": "no.terms@example.com", @@ -161,6 +160,41 @@ class TestMembershipSignup(TransactionCase): values = controller._prepare_signup_values(qcontext) self.assertEqual(values.get("firstname"), "No") + def test_07c_prepare_signup_values_reset_password_allows_missing_terms(self): + """Password reset (`/web/reset_password`) reuses core's + `_prepare_signup_values`. The reset form intentionally does not + include the legal terms checkbox, so our override must not reject + the submission when `accepted_terms` is absent. + """ + controller = AuthSignupHome() + base_qcontext = { + "login": "reset.me@example.com", + "password": "newverystrongpwd", + "confirm_password": "newverystrongpwd", + "firstname": "Reset", + "lastname": "User", + "token": "dummy-reset-token", + } + # Missing `accepted_terms` on the reset path must NOT raise. + with MockRequest( + self.env, website=self.website, path="/web/reset_password" + ) as mock_request: + # The helper accepts `path=` but the underlying httprequest mock + # also exposes the path attribute; double-check alignment. + self.assertEqual(mock_request.httprequest.path, "/web/reset_password") + values = controller._prepare_signup_values(dict(base_qcontext)) + self.assertEqual(values.get("firstname"), "Reset") + self.assertEqual(values.get("lastname"), "User") + self.assertIn("name", values) + # Same protection when the qcontext exposes the core reset flag. + qcontext_flag = { + key: value for key, value in base_qcontext.items() if key != "token" + } + qcontext_flag["reset_password"] = True + with MockRequest(self.env, website=self.website, path="/web/signup"): + values = controller._prepare_signup_values(qcontext_flag) + self.assertEqual(values.get("firstname"), "Reset") + # -- RF-08 ------------------------------------------------------------- def test_08_backend_sale_order_with_membership_product_without_user(self):