import unicodedata from django import forms from django.contrib.auth.forms import PasswordResetForm from django.utils import timezone from simple_email_confirmation.models import EmailAddress import re from .models import Normalien, Stage, Lieu, AvisLieu, AvisStage, User from .widgets import LatLonField # Sur-classe utile class HTMLTrimmerForm(forms.ModelForm): def clean(self): # Suppression des espaces blanc avant et après le texte pour les champs html leading_white = re.compile( r"^( \t\n)*(

( |[ \n\t]|)*

( \t\n)*)+?", re.IGNORECASE ) trailing_white = re.compile( r"(( \t\n)*

( |[ \n\t]|)*

)+?( \t\n)*$", re.IGNORECASE ) cleaned_data = super(HTMLTrimmerForm, self).clean() for (fname, fval) in cleaned_data.items(): # Heuristique : les champs commençant par "avis_" sont des champs html if fname[:5] == "avis_": cleaned_data[fname] = leading_white.sub( "", trailing_white.sub("", fval) ) return cleaned_data # Infos sur un stage class StageForm(forms.ModelForm): date_widget = forms.DateInput( attrs={"class": "datepicker", "placeholder": "JJ/MM/AAAA"} ) date_debut = forms.DateField( label="Date de début", input_formats=["%d/%m/%Y"], widget=date_widget ) date_fin = forms.DateField( label="Date de fin", input_formats=["%d/%m/%Y"], widget=date_widget ) class Meta: model = Stage fields = [ "sujet", "date_debut", "date_fin", "type_stage", "niveau_scol", "thematiques", "matieres", "structure", "encadrants", ] help_texts = { "thematiques": "Mettez une virgule pour valider votre thématique si la suggestion ne correspond pas ou si elle n'existe pas encore", "structure": "Nom de l'équipe, du laboratoire, de la startup... (si le lieu ne suffit pas)", } labels = { "date_debut": "Date de début", } def __init__(self, *args, **kwargs): # Sauvegarde de la request pour avoir l'user if "request" in kwargs: self.request = kwargs.pop("request") super(StageForm, self).__init__(*args, **kwargs) def save(self, commit=True): # Lors de la création : attribution à l'utilisateur connecté if self.instance.id is None and hasattr(self, "request"): self.instance.auteur = self.request.user.profil # Date de modification self.instance.date_maj = timezone.now() self.instance.update_stats(False) stage = super(StageForm, self).save(commit=commit) return stage # Sous-formulaire des avis sur le stage class AvisStageForm(HTMLTrimmerForm): class Meta: model = AvisStage fields = [ "chapo", "avis_sujet", "avis_ambiance", "avis_admin", "avis_prestage", "les_plus", "les_moins", ] help_texts = { "chapo": '"Trop long, pas lu" : une accroche résumant ce que vous avez pensé de ce séjour', "avis_ambiance": "Avez-vous passé un bon moment à ce travail ? Étiez-vous assez guidé⋅e ? Aviez-vous un bon contact avec vos encadrant⋅e⋅s ? Y avait-il une bonne ambiance dans l'équipe ?", "avis_sujet": "Quelle était votre mission ? Qu'en avez-vous retiré ? Le travail correspondait-il à vos attentes ? Était-ce à votre niveau, trop dur, trop facile ?", "avis_admin": "Avez-vous commencé votre travail à la date prévue ? Était-ce compliqué d'obtenir les documents nécessaires (visa, contrats, etc) ? L'administration de l'établissement vous a-t-elle aidé⋅e ? Étiez-vous rémunéré⋅e ?", "avis_prestage": "Comment avez-vous trouvé où aller pour cette expérience ? À quel moment avez-vous commencé à chercher ? Avez-vous eu des entretiens pour obtenir votre place ? Avez-vous eu d'autres pistes, pourquoi avez-vous choisi cette option ?", "les_plus": "Les principaux points positifs de cette expérience", "les_moins": "Ce qui aurait pu être mieux", } class AvisLieuForm(HTMLTrimmerForm): class Meta: model = AvisLieu fields = [ "lieu", "chapo", "avis_lieustage", "avis_pratique", "avis_tourisme", "les_plus", "les_moins", ] help_texts = { "chapo": '"Trop long, pas lu" : une accroche résumant ce que vous avez pensé de cet endroit', "avis_lieustage": "Qu'avez-vous pensé des lieux où vous travailliez ? Les bâtiments étaient-ils modernes ? Était-il agréable d'y travailler ?", "avis_pratique": "Avez-vous eu du mal à trouver un logement ? Y-a-t-il des choses que vous avez apprises sur place qu'il vous aurait été utile de savoir avant de partir ?", "avis_tourisme": "Y-a-t-il des lieux à visiter dans cette zone ? Avez-vous pratiqué des activités sportives ? Est-il facile de faire des rencontres ?", "les_plus": "Les meilleures raisons de partir à cet endroit", "les_moins": "Ce qui vous a gêné ou manqué là-bas", } widgets = {"lieu": forms.HiddenInput(attrs={"class": "lieu-hidden"})} # Création d'un nouveau lieu class LieuForm(forms.ModelForm): coord = LatLonField() id = forms.IntegerField(widget=forms.widgets.HiddenInput(), required=False) class Meta: model = Lieu fields = ["id", "nom", "type_lieu", "ville", "pays", "coord"] # Widget de feedback class FeedbackForm(forms.Form): objet = forms.CharField(label="Objet", required=True) message = forms.CharField( label="Message", required=True, widget=forms.widgets.Textarea() ) # Nouvelle adresse mail class AdresseEmailForm(forms.Form): def __init__(self, _user, **kwargs): self._user = _user super().__init__(**kwargs) email = forms.EmailField( widget=forms.widgets.EmailInput(attrs={"placeholder": "Nouvelle adresse"}) ) def clean_email(self): email = self.cleaned_data["email"] if EmailAddress.objects.filter(user=self._user, email=email).exists(): raise forms.ValidationError("Cette adresse est déjà associée à ce compte") return email def _unicode_ci_compare(s1, s2): """ Perform case-insensitive comparison of two identifiers, using the recommended algorithm from Unicode Technical Report 36, section 2.11.2(B)(2). """ return ( unicodedata.normalize("NFKC", s1).casefold() == unicodedata.normalize("NFKC", s2).casefold() ) # (Ré)initialisation du mot de passe class ReinitMdpForm(PasswordResetForm): def get_users(self, email): """Override default method to allow unusable passwords""" email_field_name = User.get_email_field_name() active_users = User._default_manager.filter( **{ "%s__iexact" % email_field_name: email, "is_active": True, } ) return ( u for u in active_users if _unicode_ci_compare(email, getattr(u, email_field_name)) )