diff --git a/jabberfr/forms.py b/jabberfr/forms.py
index e586ef3..c37388e 100644
--- a/jabberfr/forms.py
+++ b/jabberfr/forms.py
@@ -1,7 +1,7 @@
from django import forms
from django.utils.safestring import mark_safe
from django.core.validators import RegexValidator, URLValidator
-from jabberfr.validators import validate_jid_userpart
+from jabberfr.validators import validate_jid_userpart, validate_jid
USERNAME_HELP = """
@@ -115,3 +115,45 @@ class InscriptionForm(forms.Form):
super().__init__(*args, **kwargs)
if choices:
self.fields['server'].widget.choices = choices
+
+
+class AdhesionForm(forms.Form):
+ surname = forms.CharField(
+ required=True,
+ label="Nom de famille",
+ )
+ name = forms.CharField(
+ required=True,
+ label='Prénom',
+ )
+ email = forms.EmailField(
+ required=True,
+ label='Adresse email',
+ )
+ jid = forms.CharField(
+ required=True,
+ label='Identififant XMPP (JID)',
+ validators=[validate_jid],
+ )
+ captcha_id = forms.IntegerField(
+ required=True,
+ widget=forms.HiddenInput,
+ )
+ captcha = forms.CharField(
+ required=True,
+ label='Captcha',
+ help_text='',
+ )
+
+ def __init__(self, *args, **kwargs):
+ captcha_id, captcha_question = kwargs.pop('captcha', (0, ''))
+ super().__init__(*args, **kwargs)
+ if captcha_id and captcha_question:
+ self.reset_captcha(captcha_id, captcha_question)
+
+ def reset_captcha(self, captcha_id: int, question: str):
+ self.initial['captcha_id'] = captcha_id
+ self.fields['captcha_id'].initial = captcha_id
+ self.fields['captcha'].help_text = mark_safe(
+ f'\n
Répondez à cette question : {question}'
+ )
diff --git a/jabberfr/settings.py b/jabberfr/settings.py
index 858496c..042f1b2 100644
--- a/jabberfr/settings.py
+++ b/jabberfr/settings.py
@@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
"""
from pathlib import Path
+from random import shuffle
# Build paths inside the project like this: BASE_DIR / 'subdir'.
BASE_DIR = Path(__file__).resolve().parent.parent
@@ -115,3 +116,15 @@ STATIC_URL = '/static/'
STATICFILES_DIRS = [
BASE_DIR / 'static'
]
+
+# To override in local settings
+CAPTCHA_QUESTIONS = [
+ ('1 + 1 ?', '2'),
+]
+
+try:
+ from .local_settings import *
+except ImportError:
+ pass
+
+shuffle(CAPTCHA_QUESTIONS)
diff --git a/jabberfr/templates/adhesion.html b/jabberfr/templates/adhesion.html
new file mode 100644
index 0000000..62305d3
--- /dev/null
+++ b/jabberfr/templates/adhesion.html
@@ -0,0 +1,44 @@
+{% extends "page_model.html" %}
+
+{% block content %}
+ Adhérez à l'association
+
+
+Si vous décidez de soutenir l'association JabberFR afin de l'aider à mener ses objectifs à bien, vous pouvez adhérer ! Le but de notre association est de mettre à disposition des services de messagerie instantanée libres à travers les serveurs gérés par l'association, de promouvoir les applications et services qui y sont liés, notamment grâce au wiki, ou par la présence de ses membres à des évènements publics, et enfin, d'améliorer l'existant en développant des logiciels ou composants lorsque le besoin est ressenti.
+
+
+
+L'adhésion à notre association suppose que vous ayez lu les statuts de l'association et que vous soyez en accord avec notre règlement intérieur.
+
+
+ Formulaire d'adhésion
+
+
+
+ Paiement de la cotisation
+
+
+Attention : pour finaliser votre adhésion et être considéré comme membre à part entière et à jour de sa cotisation, vous devez vous acquiter de la cotisation annuelle : 5€ pour devenir un membre actif, ou 15€ pour devenir un membre bienfaiteur.
+
+
+
+Nous vous contacterons après envoi du formulaire pour vous transmettre les coordonnées bancaires de l'association. Alternativement, vous pouvez payer sur HelloAsso.
+
+
+
+
+Nous vous rappelons que vous disposez d'un droit d'accès, de modification, de rectification et de suppression des données qui vous concernent (art. 34 de la loi « Informatique et Libertés » du 6 janvier 1978).
+
+
+
+{% endblock %}
+
diff --git a/jabberfr/templates/adhesion_success.html b/jabberfr/templates/adhesion_success.html
new file mode 100644
index 0000000..b074552
--- /dev/null
+++ b/jabberfr/templates/adhesion_success.html
@@ -0,0 +1,27 @@
+
+{% extends "page_model.html" %}
+
+{% block content %}
+ Adhérez à l'association
+
+
+ Votre adhésion a été enregistrée. N\'oubliez pas de payer votre cotisation !
+
+ Paiement de la cotisation
+
+
+Attention : pour finaliser votre adhésion et être considéré comme membre à part entière et à jour de sa cotisation, vous devez vous acquiter de la cotisation annuelle : 5€ pour devenir un membre actif, ou 15€ pour devenir un membre bienfaiteur.
+
+
+
+Nous vous contacterons après envoi du formulaire pour vous transmettre les coordonnées bancaires de l'association. Alternativement, vous pouvez payer sur HelloAsso.
+
+
+
+
+Nous vous rappelons que vous disposez d'un droit d'accès, de modification, de rectification et de suppression des données qui vous concernent (art. 34 de la loi « Informatique et Libertés » du 6 janvier 1978).
+
+
+
+{% endblock %}
+
diff --git a/jabberfr/urls.py b/jabberfr/urls.py
index 23a5ca0..5d836a7 100644
--- a/jabberfr/urls.py
+++ b/jabberfr/urls.py
@@ -16,7 +16,7 @@ Including another URLconf
from django.urls import path, re_path
from django.views.generic import TemplateView, RedirectView
-from jabberfr.views import get_root_index, hebergement, inscription
+from jabberfr.views import get_root_index, hebergement, inscription, adhesion
PAGES = [
@@ -30,6 +30,7 @@ urlpatterns = [
re_path('hébergement/?', hebergement),
re_path('hebergement/?', RedirectView.as_view(url='/hébergement')),
re_path('inscription/?', inscription),
+ re_path('adhesion/?', adhesion),
path('inscription/', inscription),
]
diff --git a/jabberfr/utils.py b/jabberfr/utils.py
index 2d7229e..c2fc7cb 100644
--- a/jabberfr/utils.py
+++ b/jabberfr/utils.py
@@ -1,10 +1,12 @@
import logging
import xml.etree.ElementTree as ET
from asyncio import gather, get_event_loop
+from random import randint
from aiodns import DNSResolver
from aiohttp import ClientSession, ClientTimeout
from django import forms
+from django.conf import settings
log = logging.getLogger(__name__)
@@ -113,3 +115,30 @@ def check_passwords(form: forms.Form) -> bool:
)
return False
return True
+
+
+
+def pick_captcha() -> tuple[str, str]:
+ choice = randint(0, len(settings.CAPTCHA_QUESTIONS) - 1)
+ question = settings.CAPTCHA_QUESTIONS[choice][0]
+ return str(choice), question
+
+
+def validate_captcha(form: forms.Form) -> bool:
+ data = form.cleaned_data
+ print(data)
+ try:
+ captcha_id = data['captcha_id']
+ if captcha_id < 0 or captcha_id >= len(settings.CAPTCHA_QUESTIONS):
+ raise ValueError
+ except ValueError:
+ form.add_error('captcha', 'Êtes-vous un robot ?')
+ return False
+ question_tup = settings.CAPTCHA_QUESTIONS[captcha_id]
+ if question_tup is None:
+ form.add_error('captcha', 'Êtes-vous un robot ?')
+ return False
+ if question_tup[1] != data['captcha']:
+ form.add_error('captcha', 'Êtes-vous un robot ?')
+ return False
+ return True
diff --git a/jabberfr/validators.py b/jabberfr/validators.py
index e295752..a7fa8e3 100644
--- a/jabberfr/validators.py
+++ b/jabberfr/validators.py
@@ -13,3 +13,14 @@ def validate_jid_userpart(value):
raise ValidationError(
f'"{value}" n’est pas un nom d’utilisateur valide.'
)
+
+
+def validate_jid(value):
+ try:
+ jid = JID(value)
+ if not jid.user or not jid.server:
+ raise InvalidJID
+ except InvalidJID:
+ raise ValidationError(
+ f'"{value}" n’est pas un identifiant XMPP valide'
+ )
diff --git a/jabberfr/views.py b/jabberfr/views.py
index 562e21d..3e950b0 100644
--- a/jabberfr/views.py
+++ b/jabberfr/views.py
@@ -1,12 +1,14 @@
import logging
from aiohttp import ClientError
from django.shortcuts import render
-from jabberfr.forms import HebergForm, InscriptionForm
+from jabberfr.forms import HebergForm, InscriptionForm, AdhesionForm
from jabberfr.utils import (
get_chatrooms,
get_custom_domains,
check_dns_config,
check_passwords,
+ pick_captcha,
+ validate_captcha
)
log = logging.getLogger(__name__)
@@ -83,3 +85,18 @@ async def inscription(request, domain=None):
form = InscriptionForm(custom_choices=choices)
context['form'] = form
return render(request, 'inscription.html', context=context)
+
+
+async def adhesion(request):
+ context = {}
+ if request.method == 'POST':
+ form = AdhesionForm(request.POST)
+ context['form'] = form
+ if form.is_valid() and validate_captcha(form):
+ return render(request, 'adhesion_success.html', context=context)
+ else:
+ form.reset_captcha(*pick_captcha())
+ else:
+ form = AdhesionForm(captcha=pick_captcha())
+ context['form'] = form
+ return render(request, 'adhesion.html', context=context)