From 1698841f6d0b5fea6d0a2107636e88702a05e22c Mon Sep 17 00:00:00 2001 From: Alexis Metaireau Date: Thu, 25 Nov 2021 00:44:21 +0100 Subject: [PATCH] Do not require a captcha when using the API (#931) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Do not require a captcha when using the API This was trickier than expected, due to some side effects : when the captcha is set to `True` via configuration, it doesn't change the behavior directly of the ProjectForm class, but does so only when the project form is used in the `web.py` module. So, when just using the API (and not using the web.py module, for instance during tests — manual or functional), no problem was shown, and everything was working properly. But at soon as somebody sees the "/" endpoint, the captcha was required, by both the API and the `web.py` module. This fixes it by adding a way to bypass the captcha with a new `bypass_captcha` property on the form. Prior to this commit, things were done by activating or deactivating a "captcha" property on the class on-the-fly, which caused side-effects. This is now using subclasses, which makes the code simpler to understand, and less prone to side-effects. Thanks @zorun for the idea. --- ihatemoney/forms.py | 12 +++++------- ihatemoney/tests/main_test.py | 1 + ihatemoney/web.py | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/ihatemoney/forms.py b/ihatemoney/forms.py index a55166e8..4e241c86 100644 --- a/ihatemoney/forms.py +++ b/ihatemoney/forms.py @@ -228,13 +228,11 @@ class ProjectForm(EditProjectForm): ) raise ValidationError(Markup(message)) - @classmethod - def enable_captcha(cls): - captchaField = StringField( - _("Which is a real currency: Euro or Petro dollar?"), - validators=[DataRequired()], - ) - setattr(cls, "captcha", captchaField) + +class ProjectFormWithCaptcha(ProjectForm): + captcha = StringField( + _("Which is a real currency: Euro or Petro dollar?"), + ) def validate_captcha(form, field): if not field.data.lower() == _("euro"): diff --git a/ihatemoney/tests/main_test.py b/ihatemoney/tests/main_test.py index 3efc4bf2..9707bd8a 100644 --- a/ihatemoney/tests/main_test.py +++ b/ihatemoney/tests/main_test.py @@ -286,6 +286,7 @@ class CaptchaTestCase(IhatemoneyTestCase): assert len(models.Project.query.all()) == 1 def test_api_project_creation_does_not_need_captcha(self): + self.client.get("/") resp = self.client.post( "/api/projects", data={ diff --git a/ihatemoney/web.py b/ihatemoney/web.py index 2b38bfc9..fd9bafa2 100644 --- a/ihatemoney/web.py +++ b/ihatemoney/web.py @@ -47,6 +47,7 @@ from ihatemoney.forms import ( MemberForm, PasswordReminder, ProjectForm, + ProjectFormWithCaptcha, ResetPasswordForm, UploadForm, get_billform_for, @@ -264,8 +265,7 @@ def authenticate(project_id=None): def get_project_form(): if current_app.config.get("ENABLE_CAPTCHA", False): - ProjectForm.enable_captcha() - + return ProjectFormWithCaptcha() return ProjectForm()