diff --git a/.env.template b/.env.template index b3bd7fe8..97f5604c 100644 --- a/.env.template +++ b/.env.template @@ -87,6 +87,15 @@ REVERSE_PROXY_AUTH=0 # when unset: 0 (false) # ENABLE_SIGNUP=0 +# If signup is enabled you might want to add a captcha to it to prevent spam +# HCAPTCHA_SITEKEY= +# HCAPTCHA_SECRET= + +# if signup is enabled you might want to provide urls to data protection policies or terms and conditions +# TERMS_URL= +# PRIVACY_URL= +# IMPRINT_URL= + # enable serving of prometheus metrics under the /metrics path # ATTENTION: view is not secured (as per the prometheus default way) so make sure to secure it # trough your web server (or leave it open of you dont care if the stats are exposed) diff --git a/cookbook/forms.py b/cookbook/forms.py index b1d9b172..801ff5fb 100644 --- a/cookbook/forms.py +++ b/cookbook/forms.py @@ -1,10 +1,12 @@ from django import forms +from django.conf import settings from django.core.exceptions import ValidationError from django.forms import widgets from django.utils.translation import gettext_lazy as _ from django_scopes import scopes_disabled from django_scopes.forms import SafeModelChoiceField, SafeModelMultipleChoiceField from emoji_picker.widgets import EmojiPickerTextInput +from hcaptcha.fields import hCaptchaField from .models import (Comment, Food, InviteLink, Keyword, MealPlan, Recipe, RecipeBook, RecipeBookEntry, Storage, Sync, Unit, User, @@ -68,6 +70,21 @@ class UserPreferenceForm(forms.ModelForm): } +class AllAuthSignupForm(forms.Form): + captcha = hCaptchaField() + terms = forms.BooleanField(label=_('Accept Terms and Privacy')) + + def __init__(self, **kwargs): + super(AllAuthSignupForm, self).__init__(**kwargs) + if settings.PRIVACY_URL == '' and settings.TERMS_URL == '': + self.fields.pop('terms') + if settings.HCAPTCHA_SECRET == '': + self.fields.pop('captcha') + + def signup(self, request, user): + pass + + class UserNameForm(forms.ModelForm): prefix = 'name' diff --git a/cookbook/helper/context_processors.py b/cookbook/helper/context_processors.py new file mode 100644 index 00000000..a558f81b --- /dev/null +++ b/cookbook/helper/context_processors.py @@ -0,0 +1,12 @@ +from django.conf import settings + + +def context_settings(request): + return { + 'EMAIL_ENABLED': settings.EMAIL_HOST != '', + 'SIGNUP_ENABLED': settings.ENABLE_SIGNUP, + 'CAPTCHA_ENABLED': settings.HCAPTCHA_SITEKEY != '', + 'TERMS_URL': settings.TERMS_URL, + 'PRIVACY_URL': settings.PRIVACY_URL, + 'IMPRINT_URL': settings.IMPRINT_URL, + } diff --git a/cookbook/templates/account/login.html b/cookbook/templates/account/login.html index 6034a76f..0e830030 100644 --- a/cookbook/templates/account/login.html +++ b/cookbook/templates/account/login.html @@ -28,7 +28,7 @@ {% trans "Sign Up" %} - {% if settings.EMAIL_HOST != '' %} + {% if EMAIL_ENABLED %} {% trans "Reset Password" %} {% endif %} diff --git a/cookbook/templates/account/password_reset.html b/cookbook/templates/account/password_reset.html index 3db14cd3..1071dee0 100644 --- a/cookbook/templates/account/password_reset.html +++ b/cookbook/templates/account/password_reset.html @@ -13,7 +13,7 @@ {% include "account/snippets/already_logged_in.html" %} {% endif %} - {% if settings.EMAIL_HOST != '' %} + {% if EMAIL_ENABLED %}

{% trans "Forgotten your password? Enter your e-mail address below, and we'll send you an e-mail allowing you to reset it." %}

diff --git a/cookbook/templates/account/signup.html b/cookbook/templates/account/signup.html index 88e6a8ea..1c8f28ec 100644 --- a/cookbook/templates/account/signup.html +++ b/cookbook/templates/account/signup.html @@ -1,5 +1,6 @@ {% extends "base.html" %} {% load crispy_forms_filters %} +{% load crispy_forms_filters %} {% load i18n %} {% block title %}{% trans 'Register' %}{% endblock %} @@ -10,7 +11,45 @@ {% csrf_token %} - {{ form|crispy }} + +
+ {{ form.username |as_crispy_field }} +
+
+ {{ form.email |as_crispy_field }} +
+
+ {{ form.password1 |as_crispy_field }} +
+
+ {{ form.password2 |as_crispy_field }} +
+ + {% if TERMS_URL != '' or PRIVACY_URL != '' %} +
+ {{ form.terms |as_crispy_field }} + + {% trans 'I accept the follwoing' %} + {% if TERMS_URL != '' %} + {% trans 'Terms and Conditions' %} + {% endif %} + {% if TERMS_URL != '' or PRIVACY_URL != '' %} + {% trans 'and' %} + {% endif %} + {% if PRIVACY_URL != '' %} + {% trans 'Privacy Policy' %} + {% endif %} + +
+ {% endif %} + + {% if CAPTCHA_ENABLED %} +
+ {{ form.captcha.errors }} + {{ form.captcha }} +
+ {% endif %} +
diff --git a/recipes/settings.py b/recipes/settings.py index 31928ad0..c22d0940 100644 --- a/recipes/settings.py +++ b/recipes/settings.py @@ -64,6 +64,16 @@ CRISPY_TEMPLATE_PACK = 'bootstrap4' DJANGO_TABLES2_TEMPLATE = 'cookbook/templates/generic/table_template.html' DJANGO_TABLES2_PAGE_RANGE = 8 +HCAPTCHA_SITEKEY = '' # os.getenv('HCAPTCHA_SITEKEY', '') +HCAPTCHA_SECRET = '' # os.getenv('HCAPTCHA_SECRET', '') + + +ACCOUNT_SIGNUP_FORM_CLASS = 'cookbook.forms.AllAuthSignupForm' + +TERMS_URL = os.getenv('TERMS_URL', '') +PRIVACY_URL = os.getenv('PRIVACY_URL', '') +IMPRINT_URL = os.getenv('IMPRINT_URL', '') + MESSAGE_TAGS = { messages.ERROR: 'danger' } @@ -92,6 +102,7 @@ INSTALLED_APPS = [ 'django_cleanup.apps.CleanupConfig', 'webpack_loader', 'django_js_reverse', + 'hcaptcha', 'allauth', 'allauth.account', 'allauth.socialaccount', @@ -185,6 +196,7 @@ TEMPLATES = [ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', 'django.template.context_processors.media', + 'cookbook.helper.context_processors.context_settings', ], }, }, diff --git a/requirements.txt b/requirements.txt index 21fecd8e..bb982bf4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,4 +38,5 @@ pytest-django==4.3.0 django-cors-headers==3.7.0 django-storages==1.11.1 boto3==1.17.84 -django-prometheus==2.1.0 \ No newline at end of file +django-prometheus==2.1.0 +django-hCaptcha==0.1.0 \ No newline at end of file