mirror of
				https://gitlab.com/animath/si/plateforme-corres2math.git
				synced 2025-11-04 02:12:13 +01:00 
			
		
		
		
	Confirm email addresses
This commit is contained in:
		@@ -1,9 +1,10 @@
 | 
				
			|||||||
FROM python:3-alpine
 | 
					FROM python:3-alpine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ENV PYTHONUNBUFFERED 1
 | 
					ENV PYTHONUNBUFFERED 1
 | 
				
			||||||
 | 
					ENV DJANGO_ALLOW_ASYNC_UNSAFE 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Install LaTeX requirements
 | 
					# Install LaTeX requirements
 | 
				
			||||||
RUN apk add --no-cache gettext texlive nginx gcc libc-dev libffi-dev postgresql-dev mariadb-connector-c-dev
 | 
					RUN apk add --no-cache gettext texlive nginx gcc libc-dev libffi-dev postgresql-dev
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN apk add --no-cache bash
 | 
					RUN apk add --no-cache bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -20,7 +21,7 @@ RUN ln -sf /dev/stdout /var/log/nginx/access.log && ln -sf /dev/stderr /var/log/
 | 
				
			|||||||
RUN ln -sf /code/nginx_corres2math.conf /etc/nginx/conf.d/corres2math.conf
 | 
					RUN ln -sf /code/nginx_corres2math.conf /etc/nginx/conf.d/corres2math.conf
 | 
				
			||||||
RUN rm /etc/nginx/conf.d/default.conf
 | 
					RUN rm /etc/nginx/conf.d/default.conf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RUN cp /code/corres2math.cron /etc/crontabs/corres2math
 | 
					RUN crontab /code/corres2math.cron
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# With a bashrc, the shell is better
 | 
					# With a bashrc, the shell is better
 | 
				
			||||||
RUN ln -s /code/.bashrc /root/.bashrc
 | 
					RUN ln -s /code/.bashrc /root/.bashrc
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ class RegistrationConfig(AppConfig):
 | 
				
			|||||||
    name = 'registration'
 | 
					    name = 'registration'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def ready(self):
 | 
					    def ready(self):
 | 
				
			||||||
        from registration.signals import set_username, create_admin_registration
 | 
					        from registration.signals import set_username, send_email_link, create_admin_registration
 | 
				
			||||||
        pre_save.connect(set_username, "auth.User")
 | 
					        pre_save.connect(set_username, "auth.User")
 | 
				
			||||||
 | 
					        pre_save.connect(send_email_link, "auth.User")
 | 
				
			||||||
        post_save.connect(create_admin_registration, "auth.User")
 | 
					        post_save.connect(create_admin_registration, "auth.User")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					# Generated by Django 3.1.1 on 2020-09-22 16:56
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from django.db import migrations, models
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Migration(migrations.Migration):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dependencies = [
 | 
				
			||||||
 | 
					        ('registration', '0002_auto_20200921_1948'),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    operations = [
 | 
				
			||||||
 | 
					        migrations.AddField(
 | 
				
			||||||
 | 
					            model_name='registration',
 | 
				
			||||||
 | 
					            name='email_confirmed',
 | 
				
			||||||
 | 
					            field=models.BooleanField(default=False, verbose_name='email confirmed'),
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
@@ -1,7 +1,13 @@
 | 
				
			|||||||
 | 
					from django.contrib.sites.models import Site
 | 
				
			||||||
from django.db import models
 | 
					from django.db import models
 | 
				
			||||||
 | 
					from django.template import loader
 | 
				
			||||||
 | 
					from django.utils.encoding import force_bytes
 | 
				
			||||||
 | 
					from django.utils.http import urlsafe_base64_encode
 | 
				
			||||||
from django.utils.translation import gettext_lazy as _
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
from polymorphic.models import PolymorphicModel
 | 
					from polymorphic.models import PolymorphicModel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from corres2math.tokens import email_validation_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Registration(PolymorphicModel):
 | 
					class Registration(PolymorphicModel):
 | 
				
			||||||
    user = models.OneToOneField(
 | 
					    user = models.OneToOneField(
 | 
				
			||||||
@@ -15,6 +21,36 @@ class Registration(PolymorphicModel):
 | 
				
			|||||||
        verbose_name=_("Grant Animath to contact me in the future about other actions"),
 | 
					        verbose_name=_("Grant Animath to contact me in the future about other actions"),
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    email_confirmed = models.BooleanField(
 | 
				
			||||||
 | 
					        default=False,
 | 
				
			||||||
 | 
					        verbose_name=_("email confirmed"),
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        self.send_email_validation_link()
 | 
				
			||||||
 | 
					        return super().save(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def send_email_validation_link(self):
 | 
				
			||||||
 | 
					        subject = "[Corres2math] " + str(_("Activate your Correspondances account"))
 | 
				
			||||||
 | 
					        token = email_validation_token.make_token(self.user)
 | 
				
			||||||
 | 
					        uid = urlsafe_base64_encode(force_bytes(self.user.pk))
 | 
				
			||||||
 | 
					        site = Site.objects.first()
 | 
				
			||||||
 | 
					        message = loader.render_to_string('registration/mails/email_validation_email.txt',
 | 
				
			||||||
 | 
					                                          {
 | 
				
			||||||
 | 
					                                              'user': self.user,
 | 
				
			||||||
 | 
					                                              'domain': site.domain,
 | 
				
			||||||
 | 
					                                              'token': token,
 | 
				
			||||||
 | 
					                                              'uid': uid,
 | 
				
			||||||
 | 
					                                          })
 | 
				
			||||||
 | 
					        html = loader.render_to_string('registration/mails/email_validation_email.html',
 | 
				
			||||||
 | 
					                                       {
 | 
				
			||||||
 | 
					                                           'user': self.user,
 | 
				
			||||||
 | 
					                                           'domain': site.domain,
 | 
				
			||||||
 | 
					                                           'token': token,
 | 
				
			||||||
 | 
					                                           'uid': uid,
 | 
				
			||||||
 | 
					                                       })
 | 
				
			||||||
 | 
					        self.user.email_user(subject, message, html_message=html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @property
 | 
					    @property
 | 
				
			||||||
    def type(self):
 | 
					    def type(self):
 | 
				
			||||||
        raise NotImplementedError
 | 
					        raise NotImplementedError
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,10 +1,23 @@
 | 
				
			|||||||
from registration.models import AdminRegistration
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from registration.models import AdminRegistration, Registration
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def set_username(instance, **_):
 | 
					def set_username(instance, **_):
 | 
				
			||||||
    instance.username = instance.email
 | 
					    instance.username = instance.email
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def send_email_link(instance, **_):
 | 
				
			||||||
 | 
					    if instance.pk:
 | 
				
			||||||
 | 
					        old_instance = User.objects.get(pk=instance.pk)
 | 
				
			||||||
 | 
					        if old_instance.email != instance.email:
 | 
				
			||||||
 | 
					            registration = Registration.objects.get(user=instance)
 | 
				
			||||||
 | 
					            registration.email_confirmed = False
 | 
				
			||||||
 | 
					            registration.save()
 | 
				
			||||||
 | 
					            registration.user = instance
 | 
				
			||||||
 | 
					            registration.send_email_validation_link()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def create_admin_registration(instance, **_):
 | 
					def create_admin_registration(instance, **_):
 | 
				
			||||||
    if instance.is_superuser:
 | 
					    if instance.is_superuser:
 | 
				
			||||||
        AdminRegistration.objects.get_or_create(user=instance)
 | 
					        AdminRegistration.objects.get_or_create(user=instance)
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,13 @@
 | 
				
			|||||||
from django.urls import path
 | 
					from django.urls import path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from .views import SignupView
 | 
					from .views import SignupView, UserValidationEmailSentView, UserResendValidationEmailView, UserValidateView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app_name = "registration"
 | 
					app_name = "registration"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    path("signup", SignupView.as_view(), name="signup"),
 | 
					    path("signup", SignupView.as_view(), name="signup"),
 | 
				
			||||||
 | 
					    path('validate_email/sent/', UserValidationEmailSentView.as_view(), name='email_validation_sent'),
 | 
				
			||||||
 | 
					    path('validate_email/resend/<int:pk>/', UserResendValidationEmailView.as_view(),
 | 
				
			||||||
 | 
					         name='email_validation_resend'),
 | 
				
			||||||
 | 
					    path('validate_email/<uidb64>/<token>/', UserValidateView.as_view(), name='email_validation'),
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,8 +1,15 @@
 | 
				
			|||||||
 | 
					from django.conf import settings
 | 
				
			||||||
 | 
					from django.contrib.auth.mixins import LoginRequiredMixin
 | 
				
			||||||
from django.contrib.auth.models import User
 | 
					from django.contrib.auth.models import User
 | 
				
			||||||
 | 
					from django.core.exceptions import ValidationError
 | 
				
			||||||
from django.db import transaction
 | 
					from django.db import transaction
 | 
				
			||||||
 | 
					from django.shortcuts import resolve_url, redirect
 | 
				
			||||||
from django.urls import reverse_lazy
 | 
					from django.urls import reverse_lazy
 | 
				
			||||||
from django.views.generic import CreateView
 | 
					from django.utils.http import urlsafe_base64_decode
 | 
				
			||||||
 | 
					from django.utils.translation import gettext_lazy as _
 | 
				
			||||||
 | 
					from django.views.generic import CreateView, TemplateView, DetailView
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from corres2math.tokens import email_validation_token
 | 
				
			||||||
from .forms import SignupForm, StudentRegistrationForm, CoachRegistrationForm
 | 
					from .forms import SignupForm, StudentRegistrationForm, CoachRegistrationForm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -39,3 +46,78 @@ class SignupView(CreateView):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def get_success_url(self):
 | 
					    def get_success_url(self):
 | 
				
			||||||
        return reverse_lazy("index")
 | 
					        return reverse_lazy("index")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserValidateView(TemplateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    A view to validate the email address.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    title = _("Email validation")
 | 
				
			||||||
 | 
					    template_name = 'registration/email_validation_complete.html'
 | 
				
			||||||
 | 
					    extra_context = {"title": _("Validate email")}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        With a given token and user id (in params), validate the email address.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        assert 'uidb64' in kwargs and 'token' in kwargs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.validlink = False
 | 
				
			||||||
 | 
					        user = self.get_user(kwargs['uidb64'])
 | 
				
			||||||
 | 
					        token = kwargs['token']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Validate the token
 | 
				
			||||||
 | 
					        if user is not None and email_validation_token.check_token(user, token):
 | 
				
			||||||
 | 
					            self.validlink = True
 | 
				
			||||||
 | 
					            user.registration.email_confirmed = True
 | 
				
			||||||
 | 
					            user.save()
 | 
				
			||||||
 | 
					        return self.render_to_response(self.get_context_data(), status=200 if self.validlink else 400)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_user(self, uidb64):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Get user from the base64-encoded string.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # urlsafe_base64_decode() decodes to bytestring
 | 
				
			||||||
 | 
					            uid = urlsafe_base64_decode(uidb64).decode()
 | 
				
			||||||
 | 
					            user = User.objects.get(pk=uid)
 | 
				
			||||||
 | 
					        except (TypeError, ValueError, OverflowError, User.DoesNotExist, ValidationError):
 | 
				
			||||||
 | 
					            user = None
 | 
				
			||||||
 | 
					        return user
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
 | 
					        context = super().get_context_data(**kwargs)
 | 
				
			||||||
 | 
					        context['user_object'] = self.get_user(self.kwargs["uidb64"])
 | 
				
			||||||
 | 
					        context['login_url'] = resolve_url(settings.LOGIN_URL)
 | 
				
			||||||
 | 
					        if self.validlink:
 | 
				
			||||||
 | 
					            context['validlink'] = True
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            context.update({
 | 
				
			||||||
 | 
					                'title': _('Email validation unsuccessful'),
 | 
				
			||||||
 | 
					                'validlink': False,
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserValidationEmailSentView(TemplateView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Display the information that the validation link has been sent.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    template_name = 'registration/email_validation_email_sent.html'
 | 
				
			||||||
 | 
					    extra_context = {"title": _('Email validation email sent')}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserResendValidationEmailView(LoginRequiredMixin, DetailView):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Rensend the email validation link.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    model = User
 | 
				
			||||||
 | 
					    extra_context = {"title": _("Resend email validation link")}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, request, *args, **kwargs):
 | 
				
			||||||
 | 
					        user = self.get_object()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        user.profile.send_email_validation_link()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # TODO Change URL
 | 
				
			||||||
 | 
					        return redirect('index')
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
# m  h   dom mon dow     user   command
 | 
					# min   hour    day     month   weekday command
 | 
				
			||||||
# Envoyer les mails en attente
 | 
					# Envoyer les mails en attente
 | 
				
			||||||
 *   *     *   *   *     root   cd /code && python manage.py send_mail -c 1
 | 
					*       *       *       *       *       cd /code && python manage.py send_mail -c 1
 | 
				
			||||||
 *   *     *   *   *     root   cd /code && python manage.py retry_deferred -c 1
 | 
					*       *       *       *       *       cd /code && python manage.py retry_deferred -c 1
 | 
				
			||||||
 00  0     *   *   *     root   cd /code && python manage.py purge_mail_log 7 -c 1
 | 
					0       0       *       *       *       cd /code && python manage.py purge_mail_log 7 -c 1
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,4 @@
 | 
				
			|||||||
# Database
 | 
					# Database
 | 
				
			||||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
 | 
					# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EMAIL_BACKEND = 'mailer.backend.DbBackend'
 | 
					EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 | 
				
			||||||
MAILER_EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
 | 
					 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										26
									
								
								corres2math/tokens.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								corres2math/tokens.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
				
			|||||||
 | 
					from django.contrib.auth.tokens import PasswordResetTokenGenerator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AccountActivationTokenGenerator(PasswordResetTokenGenerator):
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    Create a unique token generator to confirm email addresses.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def _make_hash_value(self, user, timestamp):
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        Hash the user's primary key and some user state that's sure to change
 | 
				
			||||||
 | 
					        after an account validation to produce a token that invalidated when
 | 
				
			||||||
 | 
					        it's used:
 | 
				
			||||||
 | 
					        1. The user.profile.email_confirmed field will change upon an account
 | 
				
			||||||
 | 
					        validation.
 | 
				
			||||||
 | 
					        2. The last_login field will usually be updated very shortly after
 | 
				
			||||||
 | 
					           an account validation.
 | 
				
			||||||
 | 
					        Failing those things, settings.PASSWORD_RESET_TIMEOUT_DAYS eventually
 | 
				
			||||||
 | 
					        invalidates the token.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        # Truncate microseconds so that tokens are consistent even if the
 | 
				
			||||||
 | 
					        # database doesn't support microseconds.
 | 
				
			||||||
 | 
					        login_timestamp = '' if user.last_login is None else user.last_login.replace(microsecond=0, tzinfo=None)
 | 
				
			||||||
 | 
					        return str(user.pk) + str(user.email) + str(login_timestamp) + str(timestamp)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					email_validation_token = AccountActivationTokenGenerator()
 | 
				
			||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
#!/bin/sh
 | 
					#!/bin/sh
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					crond -l 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
python manage.py compilemessages
 | 
					python manage.py compilemessages
 | 
				
			||||||
python manage.py migrate
 | 
					python manage.py migrate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,7 @@ msgid ""
 | 
				
			|||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Project-Id-Version: Corres2math\n"
 | 
					"Project-Id-Version: Corres2math\n"
 | 
				
			||||||
"Report-Msgid-Bugs-To: \n"
 | 
					"Report-Msgid-Bugs-To: \n"
 | 
				
			||||||
"POT-Creation-Date: 2020-09-22 18:21+0200\n"
 | 
					"POT-Creation-Date: 2020-09-22 18:49+0200\n"
 | 
				
			||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
					"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 | 
				
			||||||
"Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n"
 | 
					"Last-Translator: Yohann D'ANELLO <yohann.danello@animath.fr>\n"
 | 
				
			||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
					"Language-Team: LANGUAGE <LL@li.org>\n"
 | 
				
			||||||
@@ -25,7 +25,7 @@ msgstr "API"
 | 
				
			|||||||
msgid "Logs"
 | 
					msgid "Logs"
 | 
				
			||||||
msgstr "Logs"
 | 
					msgstr "Logs"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/logs/models.py:22 apps/registration/models.py:10
 | 
					#: apps/logs/models.py:22 apps/registration/models.py:16
 | 
				
			||||||
msgid "user"
 | 
					msgid "user"
 | 
				
			||||||
msgstr "utilisateur"
 | 
					msgstr "utilisateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -115,7 +115,8 @@ msgid ""
 | 
				
			|||||||
"Give the authorisation to publish the video on the main website to promote "
 | 
					"Give the authorisation to publish the video on the main website to promote "
 | 
				
			||||||
"the action."
 | 
					"the action."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Donner l'autorisation de publier la vidéo sur le site principal pour promouvoir les Correspondances."
 | 
					"Donner l'autorisation de publier la vidéo sur le site principal pour "
 | 
				
			||||||
 | 
					"promouvoir les Correspondances."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/participation/models.py:35
 | 
					#: apps/participation/models.py:35
 | 
				
			||||||
#, python-brace-format
 | 
					#, python-brace-format
 | 
				
			||||||
@@ -123,7 +124,7 @@ msgid "Team {name} ({trigram})"
 | 
				
			|||||||
msgstr "Équipe {name} ({trigram})"
 | 
					msgstr "Équipe {name} ({trigram})"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/participation/models.py:38 apps/participation/models.py:49
 | 
					#: apps/participation/models.py:38 apps/participation/models.py:49
 | 
				
			||||||
#: apps/registration/models.py:38 apps/registration/models.py:71
 | 
					#: apps/registration/models.py:70 apps/registration/models.py:103
 | 
				
			||||||
msgid "team"
 | 
					msgid "team"
 | 
				
			||||||
msgstr "équipe"
 | 
					msgstr "équipe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -202,85 +203,93 @@ msgstr "rôle"
 | 
				
			|||||||
msgid "participant"
 | 
					msgid "participant"
 | 
				
			||||||
msgstr "participant"
 | 
					msgstr "participant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/forms.py:14 apps/registration/models.py:80
 | 
					#: apps/registration/forms.py:14 apps/registration/models.py:112
 | 
				
			||||||
msgid "coach"
 | 
					msgid "coach"
 | 
				
			||||||
msgstr "encadrant"
 | 
					msgstr "encadrant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:15
 | 
					#: apps/registration/models.py:21
 | 
				
			||||||
msgid "Grant Animath to contact me in the future about other actions"
 | 
					msgid "Grant Animath to contact me in the future about other actions"
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
"Autoriser Animath à me recontacter à l'avenir à propos d'autres actions"
 | 
					"Autoriser Animath à me recontacter à l'avenir à propos d'autres actions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:23
 | 
					#: apps/registration/models.py:26
 | 
				
			||||||
 | 
					msgid "email confirmed"
 | 
				
			||||||
 | 
					msgstr "email confirmé"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/registration/models.py:30
 | 
				
			||||||
 | 
					msgid "Activate your Correspondances account"
 | 
				
			||||||
 | 
					msgstr "Activez votre compte des Correspondances"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#: apps/registration/models.py:55
 | 
				
			||||||
#, python-brace-format
 | 
					#, python-brace-format
 | 
				
			||||||
msgid "registration of {first_name} {last_name}"
 | 
					msgid "registration of {first_name} {last_name}"
 | 
				
			||||||
msgstr "inscription de {first_name} {last_name}"
 | 
					msgstr "inscription de {first_name} {last_name}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:27
 | 
					#: apps/registration/models.py:59
 | 
				
			||||||
msgid "registration"
 | 
					msgid "registration"
 | 
				
			||||||
msgstr "inscription"
 | 
					msgstr "inscription"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:28
 | 
					#: apps/registration/models.py:60
 | 
				
			||||||
msgid "registrations"
 | 
					msgid "registrations"
 | 
				
			||||||
msgstr "inscriptions"
 | 
					msgstr "inscriptions"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:43
 | 
					#: apps/registration/models.py:75
 | 
				
			||||||
msgid "12th grade"
 | 
					msgid "12th grade"
 | 
				
			||||||
msgstr "Terminale"
 | 
					msgstr "Terminale"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:44
 | 
					#: apps/registration/models.py:76
 | 
				
			||||||
msgid "11th grade"
 | 
					msgid "11th grade"
 | 
				
			||||||
msgstr "Première"
 | 
					msgstr "Première"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:45
 | 
					#: apps/registration/models.py:77
 | 
				
			||||||
msgid "10th grade or lower"
 | 
					msgid "10th grade or lower"
 | 
				
			||||||
msgstr "Seconde ou inférieur"
 | 
					msgstr "Seconde ou inférieur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:47
 | 
					#: apps/registration/models.py:79
 | 
				
			||||||
msgid "student class"
 | 
					msgid "student class"
 | 
				
			||||||
msgstr "classe"
 | 
					msgstr "classe"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:52
 | 
					#: apps/registration/models.py:84
 | 
				
			||||||
msgid "school"
 | 
					msgid "school"
 | 
				
			||||||
msgstr "école"
 | 
					msgstr "école"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:57
 | 
					#: apps/registration/models.py:89
 | 
				
			||||||
msgid "student"
 | 
					msgid "student"
 | 
				
			||||||
msgstr "étudiant"
 | 
					msgstr "étudiant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:60
 | 
					#: apps/registration/models.py:92
 | 
				
			||||||
msgid "student registration"
 | 
					msgid "student registration"
 | 
				
			||||||
msgstr "inscription d'élève"
 | 
					msgstr "inscription d'élève"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:61
 | 
					#: apps/registration/models.py:93
 | 
				
			||||||
msgid "student registrations"
 | 
					msgid "student registrations"
 | 
				
			||||||
msgstr "inscriptions d'élève"
 | 
					msgstr "inscriptions d'élève"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:75
 | 
					#: apps/registration/models.py:107
 | 
				
			||||||
msgid "professional activity"
 | 
					msgid "professional activity"
 | 
				
			||||||
msgstr "activité professionnelle"
 | 
					msgstr "activité professionnelle"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:83
 | 
					#: apps/registration/models.py:115
 | 
				
			||||||
msgid "coach registration"
 | 
					msgid "coach registration"
 | 
				
			||||||
msgstr "inscription d'encadrant"
 | 
					msgstr "inscription d'encadrant"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:84
 | 
					#: apps/registration/models.py:116
 | 
				
			||||||
msgid "coach registrations"
 | 
					msgid "coach registrations"
 | 
				
			||||||
msgstr "inscriptions d'encadrants"
 | 
					msgstr "inscriptions d'encadrants"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:89
 | 
					#: apps/registration/models.py:121
 | 
				
			||||||
msgid "role of the administrator"
 | 
					msgid "role of the administrator"
 | 
				
			||||||
msgstr "rôle de l'administrateur"
 | 
					msgstr "rôle de l'administrateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:94
 | 
					#: apps/registration/models.py:126
 | 
				
			||||||
msgid "admin"
 | 
					msgid "admin"
 | 
				
			||||||
msgstr "admin"
 | 
					msgstr "admin"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:97
 | 
					#: apps/registration/models.py:129
 | 
				
			||||||
msgid "admin registration"
 | 
					msgid "admin registration"
 | 
				
			||||||
msgstr "inscription d'administrateur"
 | 
					msgstr "inscription d'administrateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: apps/registration/models.py:98
 | 
					#: apps/registration/models.py:130
 | 
				
			||||||
msgid "admin registrations"
 | 
					msgid "admin registrations"
 | 
				
			||||||
msgstr "inscriptions d'administrateur"
 | 
					msgstr "inscriptions d'administrateur"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -443,6 +452,8 @@ msgid ""
 | 
				
			|||||||
"You recently registered on the Correspondances platform. Please click on the "
 | 
					"You recently registered on the Correspondances platform. Please click on the "
 | 
				
			||||||
"link below to confirm your registration."
 | 
					"link below to confirm your registration."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Vous vous êtes inscrits sur la plateforme des Correspondances. Merci de "
 | 
				
			||||||
 | 
					"cliquer sur le lien ci-dessous pour confirmer votre inscription."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/mails/email_validation_email.html:26
 | 
					#: templates/registration/mails/email_validation_email.html:26
 | 
				
			||||||
#: templates/registration/mails/email_validation_email.txt:9
 | 
					#: templates/registration/mails/email_validation_email.txt:9
 | 
				
			||||||
@@ -450,6 +461,8 @@ msgid ""
 | 
				
			|||||||
"This link is only valid for a couple of days, after that you will need to "
 | 
					"This link is only valid for a couple of days, after that you will need to "
 | 
				
			||||||
"contact us to validate your email."
 | 
					"contact us to validate your email."
 | 
				
			||||||
msgstr ""
 | 
					msgstr ""
 | 
				
			||||||
 | 
					"Ce lien n'est valide que pendant quelques jours, après cela vous devrez nous "
 | 
				
			||||||
 | 
					"contacter pour valider votre email."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/mails/email_validation_email.html:30
 | 
					#: templates/registration/mails/email_validation_email.html:30
 | 
				
			||||||
#: templates/registration/mails/email_validation_email.txt:11
 | 
					#: templates/registration/mails/email_validation_email.txt:11
 | 
				
			||||||
@@ -458,8 +471,8 @@ msgstr "Merci"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
#: templates/registration/mails/email_validation_email.html:35
 | 
					#: templates/registration/mails/email_validation_email.html:35
 | 
				
			||||||
#: templates/registration/mails/email_validation_email.txt:13
 | 
					#: templates/registration/mails/email_validation_email.txt:13
 | 
				
			||||||
msgid "The CNO."
 | 
					msgid "The Correspondances team."
 | 
				
			||||||
msgstr ""
 | 
					msgstr "L'équipe des Correspondances"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#: templates/registration/password_change_done.html:8
 | 
					#: templates/registration/password_change_done.html:8
 | 
				
			||||||
msgid "Your password was changed."
 | 
					msgid "Your password was changed."
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -17,8 +17,8 @@
 | 
				
			|||||||
</p>
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<p>
 | 
					<p>
 | 
				
			||||||
    <a href="https://{{ domain }}{% url 'member:email_validation' uidb64=uid token=token %}">
 | 
					    <a href="https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %}">
 | 
				
			||||||
        https://{{ domain }}{% url 'member:email_validation' uidb64=uid token=token %}
 | 
					        https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %}
 | 
				
			||||||
    </a>
 | 
					    </a>
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -32,5 +32,5 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
--
 | 
					--
 | 
				
			||||||
<p>
 | 
					<p>
 | 
				
			||||||
    {% trans "The CNO." %}<br>
 | 
					    {% trans "The Correspondances team." %}<br>
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,10 +4,10 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
{% trans "You recently registered on the Correspondances platform. Please click on the link below to confirm your registration." %}
 | 
					{% trans "You recently registered on the Correspondances platform. Please click on the link below to confirm your registration." %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
https://{{ domain }}{% url 'member:email_validation' uidb64=uid token=token %}
 | 
					https://{{ domain }}{% url 'registration:email_validation' uidb64=uid token=token %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %}
 | 
					{% trans "This link is only valid for a couple of days, after that you will need to contact us to validate your email." %}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% trans "Thanks" %},
 | 
					{% trans "Thanks" %},
 | 
				
			||||||
 | 
					
 | 
				
			||||||
{% trans "The CNO." %}
 | 
					{% trans "The Correspondances team." %}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user