Bug: le serveur plantait lorsqu'on avait une confirmation de mot de passe sans
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / chercheurs / forms.py
1 # -*- encoding: utf-8 -*-
2 import hashlib
3 from django import forms
4 from django.db.models import Q
5 from django.forms.models import inlineformset_factory
6 from itertools import chain
7 from models import *
8
9 OUI_NON_CHOICES = (('1', 'Oui'), ('0', 'Non'))
10
11 class PersonneForm(forms.ModelForm):
12 genre = forms.ChoiceField(widget=forms.RadioSelect(), choices=GENRE_CHOICES)
13
14 class Meta:
15 model = Utilisateur
16 fields = ('nom', 'prenom', 'courriel', 'genre')
17
18 class PersonneInscriptionForm(PersonneForm):
19 password = forms.CharField(widget=forms.PasswordInput(), label="Mot de passe")
20 password_confirmation = forms.CharField(widget=forms.PasswordInput(), label="Confirmez votre mot de passe")
21
22 class Meta(PersonneForm.Meta):
23 fields = ('nom', 'prenom', 'courriel', 'password', 'password_confirmation', 'genre')
24
25 def clean_password(self):
26 """Encrypter le mot de passe avant de le mettre dans la BD."""
27 self.clear_password = self.cleaned_data['password']
28 return hashlib.md5(self.cleaned_data['password']).hexdigest()
29
30 def clean_password_confirmation(self):
31 """S'assurer que le mot de passe et la confirmation sont identiques."""
32 password = self.cleaned_data.get('password')
33 confirmation = hashlib.md5(self.cleaned_data['password_confirmation']).hexdigest()
34 if password != confirmation:
35 raise forms.ValidationError('Les deux mots de passe ne correspondent pas.')
36 return self.cleaned_data['password_confirmation']
37
38 class ChercheurForm(forms.ModelForm):
39 """Formulaire d'édition d'un chercheur."""
40 ETABLISSEMENT_CHOICES = ((id, nom if len(nom) < 80 else nom[:80] + '...')
41 for id, nom in Etablissement.objects.filter(membre=True).values_list('id', 'nom'))
42
43 membre_instance_auf = forms.ChoiceField(
44 label="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
45 help_text="e.g. conseil scientifique, conseil associatif, commission régionale d'experts",
46 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
47 )
48 membre_instance_auf_details = forms.CharField(label="Préciser laquelle et votre fonction", required=False)
49 membre_instance_auf_dates = forms.CharField(label="Préciser les dates", required=False)
50 expert_oif = forms.ChoiceField(label="Avez-vous déjà été sollicité par l'OIF?", choices=OUI_NON_CHOICES, widget=forms.RadioSelect())
51 expert_oif_details = forms.CharField(label="Préciser à quel titre", required=False,
52 help_text="Fonction dans l'organisation, participation à une étude ou à une action, etc.")
53 expert_oif_dates = forms.CharField(label="Préciser les dates", required=False)
54 membre_association_francophone = forms.ChoiceField(
55 label="Êtes-vous membre d'une association ou d'une société savante francophone?",
56 help_text="e.g. FIPF, Collège international de philosophie, AISLF, etc.",
57 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
58 )
59 membre_association_francophone_details = forms.CharField(label="Préciser laquelle", required=False)
60 membre_reseau_institutionnel = forms.ChoiceField(
61 label="Avez-vous fait partie des instances d'un réseau institutionnel de l'AUF?",
62 help_text="e.g. AFELSH, RIFFEF, CIDMEF, etc.",
63 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
64 )
65 membre_reseau_institutionnel_details = forms.CharField(required=False, label="Préciser lesquelles et votre fonction")
66 membre_reseau_institutionnel_dates = forms.CharField(required=False, label="Préciser les dates")
67
68 etablissement = forms.ChoiceField(label='Etablissement', required=False, choices=chain([('', '---------')], ETABLISSEMENT_CHOICES))
69
70 class Meta:
71 model = Chercheur
72 fields = ('statut', 'diplome', 'etablissement',
73 'etablissement_autre_nom', 'etablissement_autre_pays',
74 'discipline', 'theme_recherche', 'groupe_recherche', 'mots_cles',
75 'url_site_web', 'url_blog', 'url_reseau_social',
76 'membre_instance_auf', 'membre_instance_auf_details', 'membre_instance_auf_dates',
77 'expert_oif', 'expert_oif_details', 'expert_oif_dates',
78 'membre_association_francophone',
79 'membre_association_francophone_details',
80 'membre_reseau_institutionnel', 'membre_reseau_institutionnel_details',
81 'membre_reseau_institutionnel_dates')
82
83 def clean_membre_instance_auf(self):
84 return bool(int(self.cleaned_data['membre_instance_auf']))
85
86 def clean_membre_instance_auf_details(self):
87 membre = self.cleaned_data.get('membre_instance_auf')
88 details = self.cleaned_data.get('membre_instance_auf_details')
89 if membre and not details:
90 raise forms.ValidationError('Veuillez préciser')
91 return details
92
93 def clean_membre_instance_auf_dates(self):
94 membre = self.cleaned_data.get('membre_instance_auf')
95 dates = self.cleaned_data.get('membre_instance_auf_dates')
96 if membre and not dates:
97 raise forms.ValidationError('Veuillez préciser les dates')
98 return dates
99
100 def clean_expert_oif(self):
101 return bool(int(self.cleaned_data['expert_oif']))
102
103 def clean_expert_oif_details(self):
104 expert = self.cleaned_data.get('expert_oif')
105 details = self.cleaned_data.get('expert_oif_details')
106 if expert and not details:
107 raise forms.ValidationError('Veuillez préciser')
108 return details
109
110 def clean_expert_oif_dates(self):
111 expert = self.cleaned_data.get('expert_oif')
112 dates = self.cleaned_data.get('expert_oif_dates')
113 if expert and not dates:
114 raise forms.ValidationError('Veuillez préciser les dates')
115 return dates
116
117 def clean_membre_association_francophone(self):
118 return bool(int(self.cleaned_data['membre_association_francophone']))
119
120 def clean_membre_association_francophone_details(self):
121 membre = self.cleaned_data.get('membre_association_francophone')
122 details = self.cleaned_data.get('membre_association_francophone_details')
123 if membre and not details:
124 raise forms.ValidationError('Veuillez préciser')
125 return details
126
127 def clean_membre_reseau_institutionnel(self):
128 return bool(int(self.cleaned_data['membre_reseau_institutionnel']))
129
130 def clean_membre_reseau_institutionnel_details(self):
131 membre = self.cleaned_data.get('membre_reseau_institutionnel')
132 details = self.cleaned_data.get('membre_reseau_institutionnel_details')
133 if membre and not details:
134 raise forms.ValidationError('Veuillez préciser')
135 return details
136
137 def clean_membre_reseau_institutionnel_dates(self):
138 membre = self.cleaned_data.get('membre_reseau_institutionnel')
139 dates = self.cleaned_data.get('membre_reseau_institutionnel_dates')
140 if membre and not dates:
141 raise forms.ValidationError('Veuillez préciser les dates')
142 return dates
143
144 def clean_etablissement(self):
145 etablissement = self.cleaned_data['etablissement']
146 if etablissement:
147 return Etablissement.objects.get(id=etablissement)
148
149 def clean(self):
150 etablissement = self.cleaned_data['etablissement']
151 etablissement_autre_nom = self.cleaned_data['etablissement_autre_nom']
152 etablissement_autre_pays = self.cleaned_data['etablissement_autre_pays']
153 if not etablissement:
154 if not etablissement_autre_nom:
155 self._errors['etablissement'] = self.error_class([u"Vous devez renseigner l'établissement"])
156 elif not etablissement_autre_pays:
157 self._errors['etablissement_autre_pays'] = self.error_class([u"Vous devez renseigner le pays de l'établissement"])
158 return self.cleaned_data
159
160 class GroupesForm(forms.Form):
161 """Formulaire qui associe des groupes à un chercheur."""
162 groupes = forms.ModelMultipleChoiceField(
163 queryset=Groupe.objects.all(),
164 label='Domaines de recherche', required=False,
165 help_text="Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs."
166 )
167
168 def __init__(self, data=None, prefix=None, chercheur=None):
169 self.chercheur = chercheur
170 initial = {}
171 if chercheur:
172 initial['groupes'] = chercheur.groupes.values_list('id', flat=True)
173 super(GroupesForm, self).__init__(data=data, prefix=prefix, initial=initial)
174
175 def save(self):
176 if self.is_valid():
177 groupes = self.cleaned_data['groupes']
178 ChercheurGroupe.objects.filter(chercheur=self.chercheur).exclude(groupe__in=groupes).delete()
179 for g in groupes:
180 ChercheurGroupe.objects.get_or_create(chercheur=self.chercheur, groupe=g, actif=1)
181
182 class PublicationForm(forms.ModelForm):
183 class Meta:
184 model = Publication
185 fields = ('titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
186
187 class TheseForm(PublicationForm):
188 titre = forms.CharField(required=True, label="Titre de la thèse ou du mémoire")
189 annee = forms.IntegerField(required=True, label="Année de soutenance (réalisée ou prévue)")
190 editeur = forms.CharField(required=True, label="Directeur de thèse ou de mémoire")
191 lieu_edition = forms.CharField(required=True, label="Établissement de soutenance")
192 class Meta:
193 model = Publication
194 fields = ('titre', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
195
196 class ExpertiseForm(forms.ModelForm):
197 organisme_demandeur_visible = forms.ChoiceField(
198 label="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
199 choices=OUI_NON_CHOICES, widget=forms.RadioSelect(), required=False
200 )
201 class Meta:
202 model = Expertise
203 fields = ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
204
205 def clean_organisme_demandeur_visible(self):
206 value = self.cleaned_data['organisme_demandeur_visible']
207 return bool(int(value)) if value else False
208
209 ExpertiseFormSet = inlineformset_factory(Chercheur, Expertise, form=ExpertiseForm, extra=1)
210
211 class ChercheurFormGroup(object):
212 """Groupe de formulaires nécessaires pour l'inscription et l'édition
213 d'un chercheur."""
214
215 def __init__(self, data=None, chercheur=None):
216 personne_form_class = PersonneInscriptionForm if chercheur is None else PersonneForm
217 self.chercheur = ChercheurForm(data=data, prefix='chercheur', instance=chercheur)
218 self.groupes = GroupesForm(data=data, prefix='chercheur', chercheur=chercheur)
219 self.personne = personne_form_class(data=data, prefix='personne', instance=chercheur and chercheur.personne)
220 self.publication1 = PublicationForm(data=data, prefix='publication1', instance=chercheur and chercheur.publication1)
221 self.publication2 = PublicationForm(data=data, prefix='publication2', instance=chercheur and chercheur.publication2)
222 self.publication3 = PublicationForm(data=data, prefix='publication3', instance=chercheur and chercheur.publication3)
223 self.publication4 = PublicationForm(data=data, prefix='publication4', instance=chercheur and chercheur.publication4)
224 self.these = TheseForm(data=data, prefix='these', instance=chercheur and chercheur.these)
225 self.expertises = ExpertiseFormSet(data=data, prefix='expertise', instance=chercheur)
226
227 @property
228 def has_errors(self):
229 return bool(self.chercheur.errors or self.personne.errors or self.groupes.errors or
230 self.publication1.errors or self.publication2.errors or self.publication3.errors or
231 self.publication4.errors or self.these.errors or self.expertises.errors)
232
233 def is_valid(self):
234 return self.chercheur.is_valid() and self.personne.is_valid() and self.groupes.is_valid() and \
235 self.publication1.is_valid() and self.publication2.is_valid() and \
236 self.publication3.is_valid() and self.publication4.is_valid() and \
237 self.these.is_valid() and self.expertises.is_valid()
238
239 def save(self):
240 if self.is_valid():
241
242 chercheur = self.chercheur.instance
243
244 # Enregistrer d'abord les clés étrangères car on doit les stocker dans
245 # l'objet chercheur.
246 chercheur.personne = self.personne.save()
247 if self.publication1.cleaned_data['titre']:
248 chercheur.publication1 = self.publication1.save()
249 if self.publication2.cleaned_data['titre']:
250 chercheur.publication2 = self.publication2.save()
251 if self.publication3.cleaned_data['titre']:
252 chercheur.publication3 = self.publication3.save()
253 if self.publication4.cleaned_data['titre']:
254 chercheur.publication4 = self.publication4.save()
255 chercheur.these = self.these.save()
256
257 # Puis enregistrer le chercheur lui-même.
258 self.chercheur.save()
259
260 # Puis les many-to-many puisqu'on a besoin d'un id.
261 self.groupes.chercheur = chercheur
262 self.groupes.save()
263 self.expertises.instance = chercheur
264 self.expertises.save()
265
266 class RepertoireSearchForm (forms.Form):
267 q = forms.CharField(required=False, label="Rechercher dans tous les champs")
268 nom = forms.CharField(required=False, label="Nom")
269 domaine = forms.ModelChoiceField(queryset=Groupe.objects.all(), required=False, label="Domaine de recherche", empty_label="Tous")
270 groupe_recherche = forms.CharField(required=False, label="Groupe de recherche",
271 help_text="ou Laboratoire, ou Groupement inter-universitaire")
272 statut = forms.ChoiceField(choices=(('','Tous'),)+STATUT_CHOICES+(('expert','Expert'),), required=False, label="Statut")
273 discipline = forms.ModelChoiceField(queryset=Discipline.objects.all(), required=False, label="Discipline", empty_label="Toutes")
274 pays = forms.ModelChoiceField(queryset=Pays.objects.all(), required=False, label="Pays", empty_label="Tous")
275 region = forms.ModelChoiceField(queryset=Region.objects.all(), required=False, label="Région", empty_label="Toutes",
276 help_text="La région est ici définie au sens, non strictement géographique, du Bureau régional de l'AUF de référence.")
277 nord_sud = forms.ChoiceField(choices=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required=False, label="Nord/Sud",
278 help_text="Distinction d'ordre géopolitique et économique, non géographique, qui conditionne souvent l'attribution de soutiens par les agences internationales: on entend par Nord les pays les plus développés, par Sud les pays en voie de développement.")
279
280 def __init__(self, data=None, region=None):
281 super(RepertoireSearchForm, self).__init__(data)
282 if region:
283 pays = self.fields['pays']
284 pays.queryset = pays.queryset.filter(region=region)
285
286 def get_query_set(self):
287 qs = Chercheur.objects.all()
288 if self.is_valid():
289 nom = self.cleaned_data['nom']
290 if nom:
291 qs = qs.search_nom(nom)
292 domaine = self.cleaned_data["domaine"]
293 if domaine:
294 qs = qs.filter(groupes=domaine)
295 groupe_recherche = self.cleaned_data['groupe_recherche']
296 if groupe_recherche:
297 for word in groupe_recherche.split():
298 qs = qs.filter(groupe_recherche__icontains=word)
299 q = self.cleaned_data["q"]
300 if q:
301 qs = qs.search(q)
302 statut = self.cleaned_data["statut"]
303 if statut:
304 if statut == "expert":
305 qs = qs.exclude(expertises=None)
306 else:
307 qs = qs.filter(statut=statut)
308 discipline = self.cleaned_data['discipline']
309 if discipline:
310 qs = qs.filter_discipline(discipline)
311 region = self.cleaned_data['region']
312 if region:
313 qs = qs.filter_region(region)
314 pays = self.cleaned_data["pays"]
315 if pays:
316 qs = qs.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
317 nord_sud = self.cleaned_data['nord_sud']
318 if nord_sud:
319 qs = qs.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud))
320 return qs
321
322 class SendPasswordForm(forms.Form):
323 email = forms.EmailField(required=True, label="Adresse électronique")
324 def clean_email(self):
325 cleaned_data = self.cleaned_data
326 email = cleaned_data.get("email")
327 if email:
328 try:
329 Utilisateur.objects.get(courriel=email)
330 except:
331 raise forms.ValidationError("Cette adresse n'existe pas dans notre base de données.")
332 return email
333
334 class NewPasswordForm(forms.Form):
335 password = forms.CharField(widget=forms.PasswordInput(), required=True, label="Mot de passe")
336 password_repeat = forms.CharField(widget=forms.PasswordInput(), required=True, label="Confirmez mot de passe")
337 def clean_password_repeat(self):
338 cleaned_data = self.cleaned_data
339 password = cleaned_data.get("password")
340 password_repeat = cleaned_data.get("password_repeat")
341 if password and password_repeat:
342 if password != password_repeat:
343 raise forms.ValidationError("Les mots de passe ne concordent pas")
344 return password_repeat
345