mirror of
https://github.com/spiral-project/ihatemoney.git
synced 2025-04-29 09:52:36 +02:00
Add optional support for a simple CAPTCHA. (#844)
* Add optional support for a simple CAPTCHA. * formatting * add test case * Flake8 Co-authored-by: Glandos <bugs-github@antipoul.fr>
This commit is contained in:
parent
e626a1cbea
commit
2bcc41bdb3
8 changed files with 82 additions and 3 deletions
|
@ -155,6 +155,11 @@ Note: this setting is actually interpreted by Flask-Babel, see the
|
||||||
|
|
||||||
.. _Flask-Babel guide for formatting dates: https://pythonhosted.org/Flask-Babel/#formatting-dates
|
.. _Flask-Babel guide for formatting dates: https://pythonhosted.org/Flask-Babel/#formatting-dates
|
||||||
|
|
||||||
|
`ENABLE_CAPTCHA`
|
||||||
|
---------------
|
||||||
|
|
||||||
|
It is possible to add a simple captcha in order to filter out spammer bots on the form creation.
|
||||||
|
In order to do so, you just have to set `ENABLE_CAPTCHA = True`.
|
||||||
|
|
||||||
Configuring emails sending
|
Configuring emails sending
|
||||||
--------------------------
|
--------------------------
|
||||||
|
|
|
@ -42,3 +42,7 @@ ACTIVATE_ADMIN_DASHBOARD = False
|
||||||
# Enable secure cookies. Requires HTTPS. Disable if you run your ihatemoney
|
# Enable secure cookies. Requires HTTPS. Disable if you run your ihatemoney
|
||||||
# service over plain HTTP.
|
# service over plain HTTP.
|
||||||
SESSION_COOKIE_SECURE = True
|
SESSION_COOKIE_SECURE = True
|
||||||
|
|
||||||
|
# You can activate an optional CAPTCHA if you want to. It can be helpful
|
||||||
|
# to filter spammer bots.
|
||||||
|
# ENABLE_CAPTCHA = True
|
||||||
|
|
|
@ -32,3 +32,4 @@ SUPPORTED_LANGUAGES = [
|
||||||
"uk",
|
"uk",
|
||||||
"zh_Hans",
|
"zh_Hans",
|
||||||
]
|
]
|
||||||
|
ENABLE_CAPTCHA = False
|
||||||
|
|
|
@ -221,6 +221,19 @@ class ProjectForm(EditProjectForm):
|
||||||
)
|
)
|
||||||
raise ValidationError(Markup(message))
|
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)
|
||||||
|
|
||||||
|
def validate_captcha(form, field):
|
||||||
|
if not field.data.lower() == _("euro"):
|
||||||
|
message = _("Please, validate the captcha to proceed.")
|
||||||
|
raise ValidationError(Markup(message))
|
||||||
|
|
||||||
|
|
||||||
class DestructiveActionProjectForm(FlaskForm):
|
class DestructiveActionProjectForm(FlaskForm):
|
||||||
"""Used for any important "delete" action linked to a project:
|
"""Used for any important "delete" action linked to a project:
|
||||||
|
|
|
@ -75,6 +75,9 @@
|
||||||
{{ input(form.name) }}
|
{{ input(form.name) }}
|
||||||
{{ input(form.password) }}
|
{{ input(form.password) }}
|
||||||
{{ input(form.contact_email) }}
|
{{ input(form.contact_email) }}
|
||||||
|
{% if config['ENABLE_CAPTCHA'] %}
|
||||||
|
{{ input(form.captcha) }}
|
||||||
|
{% endif %}
|
||||||
{{ input(form.default_currency) }}
|
{{ input(form.default_currency) }}
|
||||||
{% if not home %}
|
{% if not home %}
|
||||||
{{ submit(form.submit, home=True) }}
|
{{ submit(form.submit, home=True) }}
|
||||||
|
@ -171,7 +174,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<details class="mb-3">
|
<details class="mb-3">
|
||||||
<summary class="mb-2">{{ _("More options") }}</summary>
|
<summary class="mb-2">{{ _("More options") }}</summary>
|
||||||
{% if g.project.default_currency != "XXX" %}
|
{% if g.project.default_currency != "XXX" %}
|
||||||
|
|
|
@ -15,6 +15,7 @@ class BaseTestCase(TestCase):
|
||||||
SQLALCHEMY_DATABASE_URI = os.environ.get(
|
SQLALCHEMY_DATABASE_URI = os.environ.get(
|
||||||
"TESTING_SQLALCHEMY_DATABASE_URI", "sqlite://"
|
"TESTING_SQLALCHEMY_DATABASE_URI", "sqlite://"
|
||||||
)
|
)
|
||||||
|
ENABLE_CAPTCHA = False
|
||||||
|
|
||||||
def create_app(self):
|
def create_app(self):
|
||||||
# Pass the test object as a configuration.
|
# Pass the test object as a configuration.
|
||||||
|
|
|
@ -31,6 +31,7 @@ class ConfigurationTestCase(BaseTestCase):
|
||||||
self.assertTrue(self.app.config["ACTIVATE_DEMO_PROJECT"])
|
self.assertTrue(self.app.config["ACTIVATE_DEMO_PROJECT"])
|
||||||
self.assertTrue(self.app.config["ALLOW_PUBLIC_PROJECT_CREATION"])
|
self.assertTrue(self.app.config["ALLOW_PUBLIC_PROJECT_CREATION"])
|
||||||
self.assertFalse(self.app.config["ACTIVATE_ADMIN_DASHBOARD"])
|
self.assertFalse(self.app.config["ACTIVATE_ADMIN_DASHBOARD"])
|
||||||
|
self.assertFalse(self.app.config["ENABLE_CAPTCHA"])
|
||||||
|
|
||||||
def test_env_var_configuration_file(self):
|
def test_env_var_configuration_file(self):
|
||||||
"""Test that settings are loaded from a configuration file specified
|
"""Test that settings are loaded from a configuration file specified
|
||||||
|
@ -241,6 +242,50 @@ class EmailFailureTestCase(IhatemoneyTestCase):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CaptchaTestCase(IhatemoneyTestCase):
|
||||||
|
ENABLE_CAPTCHA = True
|
||||||
|
|
||||||
|
def test_project_creation_with_captcha(self):
|
||||||
|
with self.app.test_client() as c:
|
||||||
|
c.post(
|
||||||
|
"/create",
|
||||||
|
data={
|
||||||
|
"name": "raclette party",
|
||||||
|
"id": "raclette",
|
||||||
|
"password": "party",
|
||||||
|
"contact_email": "raclette@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert len(models.Project.query.all()) == 0
|
||||||
|
|
||||||
|
c.post(
|
||||||
|
"/create",
|
||||||
|
data={
|
||||||
|
"name": "raclette party",
|
||||||
|
"id": "raclette",
|
||||||
|
"password": "party",
|
||||||
|
"contact_email": "raclette@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
"captcha": "nope",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert len(models.Project.query.all()) == 0
|
||||||
|
|
||||||
|
c.post(
|
||||||
|
"/create",
|
||||||
|
data={
|
||||||
|
"name": "raclette party",
|
||||||
|
"id": "raclette",
|
||||||
|
"password": "party",
|
||||||
|
"contact_email": "raclette@notmyidea.org",
|
||||||
|
"default_currency": "USD",
|
||||||
|
"captcha": "euro",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
assert len(models.Project.query.all()) == 1
|
||||||
|
|
||||||
|
|
||||||
class TestCurrencyConverter(unittest.TestCase):
|
class TestCurrencyConverter(unittest.TestCase):
|
||||||
converter = CurrencyConverter()
|
converter = CurrencyConverter()
|
||||||
mock_data = {"USD": 1, "EUR": 0.8, "CAD": 1.2, CurrencyConverter.no_currency: 1}
|
mock_data = {"USD": 1, "EUR": 0.8, "CAD": 1.2, CurrencyConverter.no_currency: 1}
|
||||||
|
|
|
@ -260,9 +260,16 @@ def authenticate(project_id=None):
|
||||||
return render_template("authenticate.html", form=form)
|
return render_template("authenticate.html", form=form)
|
||||||
|
|
||||||
|
|
||||||
|
def get_project_form():
|
||||||
|
if current_app.config.get("ENABLE_CAPTCHA", False):
|
||||||
|
ProjectForm.enable_captcha()
|
||||||
|
|
||||||
|
return ProjectForm()
|
||||||
|
|
||||||
|
|
||||||
@main.route("/", strict_slashes=False)
|
@main.route("/", strict_slashes=False)
|
||||||
def home():
|
def home():
|
||||||
project_form = ProjectForm()
|
project_form = get_project_form()
|
||||||
auth_form = AuthenticationForm()
|
auth_form = AuthenticationForm()
|
||||||
is_demo_project_activated = current_app.config["ACTIVATE_DEMO_PROJECT"]
|
is_demo_project_activated = current_app.config["ACTIVATE_DEMO_PROJECT"]
|
||||||
is_public_project_creation_allowed = current_app.config[
|
is_public_project_creation_allowed = current_app.config[
|
||||||
|
@ -287,7 +294,7 @@ def mobile():
|
||||||
@main.route("/create", methods=["GET", "POST"])
|
@main.route("/create", methods=["GET", "POST"])
|
||||||
@requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True))
|
@requires_admin(bypass=("ALLOW_PUBLIC_PROJECT_CREATION", True))
|
||||||
def create_project():
|
def create_project():
|
||||||
form = ProjectForm()
|
form = get_project_form()
|
||||||
if request.method == "GET" and "project_id" in request.values:
|
if request.method == "GET" and "project_id" in request.values:
|
||||||
form.name.data = request.values["project_id"]
|
form.name.data = request.values["project_id"]
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue