"Figures de l'État" s'appelle maintenant "Nouvelles figures de l'état"
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / chercheurs / forms.py
CommitLineData
932eef9a 1# -*- encoding: utf-8 -*-
a7b16ec9 2import hashlib
932eef9a 3from django import forms
3efbacbe 4from django.db.models import Q
ee8b3a49 5from django.forms.models import inlineformset_factory
fbcbdde0 6from itertools import chain
932eef9a 7from models import *
13146d99 8
c073c94d
EMS
9OUI_NON_CHOICES = (('1', 'Oui'), ('0', 'Non'))
10
932eef9a 11class ChercheurForm(forms.ModelForm):
a7b16ec9 12 """Formulaire d'édition d'un chercheur."""
13ec4813 13 genre = forms.ChoiceField(widget=forms.RadioSelect(), choices=GENRE_CHOICES)
a7b16ec9 14 membre_instance_auf = forms.ChoiceField(
a7b16ec9 15 label="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
c073c94d 16 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
a7b16ec9 17 )
bc15119b
EMS
18 membre_instance_auf_nom = forms.ChoiceField(
19 choices = (('', '---------'),) + Chercheur.INSTANCE_AUF_CHOICES,
20 label="Préciser laquelle", required=False
21 )
22 membre_instance_auf_fonction = forms.CharField(label="Préciser votre fonction", required=False)
a7b16ec9 23 membre_instance_auf_dates = forms.CharField(label="Préciser les dates", required=False)
614b3269
EMS
24 expert_oif = forms.ChoiceField(label="Avez-vous déjà été sollicité par l'OIF?", choices=OUI_NON_CHOICES, widget=forms.RadioSelect())
25 expert_oif_details = forms.CharField(label="Préciser à quel titre", required=False,
26 help_text="Fonction dans l'organisation, participation à une étude ou à une action, etc.")
27 expert_oif_dates = forms.CharField(label="Préciser les dates", required=False)
c073c94d
EMS
28 membre_association_francophone = forms.ChoiceField(
29 label="Êtes-vous membre d'une association ou d'une société savante francophone?",
30 help_text="e.g. FIPF, Collège international de philosophie, AISLF, etc.",
31 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
32 )
33 membre_association_francophone_details = forms.CharField(label="Préciser laquelle", required=False)
34 membre_reseau_institutionnel = forms.ChoiceField(
9553bf2d 35 label="Êtes-vous (ou avez-vous déjà été) membre des instances d'un réseau institutionnel de l'AUF?",
c073c94d
EMS
36 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
37 )
bc15119b
EMS
38 membre_reseau_institutionnel_nom = forms.ChoiceField(
39 label="Préciser le réseau institutionnel",
40 choices=(('', '---------'),) + Chercheur.RESEAU_INSTITUTIONNEL_CHOICES,
41 required=False
42 )
43 membre_reseau_institutionnel_fonction = forms.CharField(required=False, label="Préciser votre fonction")
c073c94d
EMS
44 membre_reseau_institutionnel_dates = forms.CharField(required=False, label="Préciser les dates")
45
e836f6f7
EMS
46 pays_etablissement = forms.ModelChoiceField(label="Pays de l'établissement", queryset=Pays.objects.all(), required=True)
47 etablissement = forms.CharField(label="Nom de l'établissement", required=True)
a7b16ec9 48
cb591fb3
EMS
49 expertises_auf = forms.ChoiceField(
50 label="Êtes-vous disposé à réaliser des expertises pour l'AUF?",
51 choices=OUI_NON_CHOICES, widget=forms.RadioSelect()
52 )
53
332975c3
EMS
54 theme_recherche = forms.CharField(
55 max_length=1000, label='Thèmes de recherche', help_text='1000 signes maximum',
56 error_messages=dict(max_length="Veuillez entrer au maximum %(max)d signes (vous en avez entré %(length)d)."),
57 widget=forms.Textarea()
58 )
0874e7d1
EMS
59 attestation = forms.BooleanField(
60 required=True,
61 label="J'atteste sur l'honneur l'exactitude des renseignements fournis sur le formulaire d'inscription et j'accepte leur publication en ligne."
62 )
332975c3 63
932eef9a
AJ
64 class Meta:
65 model = Chercheur
bc15119b
EMS
66 fields = ('nom', 'prenom', 'genre', 'statut', 'diplome',
67 'discipline', 'theme_recherche', 'groupe_recherche',
68 'mots_cles', 'url_site_web', 'url_blog',
69 'url_reseau_social', 'attestation', 'membre_instance_auf',
70 'membre_instance_auf_nom', 'membre_instance_auf_fonction',
219710da
EMS
71 'membre_instance_auf_dates', 'expert_oif',
72 'expert_oif_details', 'expert_oif_dates',
614b3269
EMS
73 'membre_association_francophone',
74 'membre_association_francophone_details',
219710da 75 'membre_reseau_institutionnel',
bc15119b
EMS
76 'membre_reseau_institutionnel_nom',
77 'membre_reseau_institutionnel_fonction',
cb591fb3 78 'membre_reseau_institutionnel_dates', 'expertises_auf')
7c596de2 79
219710da
EMS
80 def __init__(self, data=None, prefix=None, instance=None):
81 if instance is not None:
82 initial = {}
83 if instance.etablissement:
84 initial['etablissement'] = instance.etablissement.nom
85 initial['pays_etablissement'] = instance.etablissement.pays_id
86 else:
87 initial['etablissement'] = instance.etablissement_autre_nom
88 initial['pays_etablissement'] = instance.etablissement_autre_pays_id
89 else:
90 initial = None
91 super(ChercheurForm, self).__init__(data=data, prefix=prefix, instance=instance, initial=initial)
92
93 def save(self):
94 nom_etablissement = self.cleaned_data['etablissement']
95 pays_etablissement = self.cleaned_data['pays_etablissement']
e76f8899
EMS
96 etablissements = Etablissement.objects.filter(nom=nom_etablissement, pays=pays_etablissement, actif=True)
97 if etablissements.count() > 0:
98 self.instance.etablissement = etablissements[0]
219710da
EMS
99 self.instance.etablissement_autre = ''
100 self.instance.etablissement_autre_pays = None
e76f8899 101 else:
219710da
EMS
102 self.instance.etablissement = None
103 self.instance.etablissement_autre_nom = nom_etablissement
104 self.instance.etablissement_autre_pays = pays_etablissement
105 super(ChercheurForm, self).save()
106
13ec4813
EMS
107 def clean_courriel(self):
108 """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
109 avec le même courriel."""
110 courriel = self.cleaned_data['courriel']
111 existing = Chercheur.objects.filter(courriel=courriel, actif=True)
112 if self.instance and self.instance.id:
113 existing = existing.exclude(id=self.instance.id)
114 if existing.count():
115 raise forms.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
116 return courriel
117
c073c94d
EMS
118 def clean_membre_instance_auf(self):
119 return bool(int(self.cleaned_data['membre_instance_auf']))
120
bc15119b 121 def clean_membre_instance_auf_nom(self):
614b3269 122 membre = self.cleaned_data.get('membre_instance_auf')
bc15119b
EMS
123 nom = self.cleaned_data.get('membre_instance_auf_nom')
124 if membre and not nom:
614b3269 125 raise forms.ValidationError('Veuillez préciser')
bc15119b
EMS
126 return nom
127
128 def clean_membre_instance_auf_fonction(self):
129 membre = self.cleaned_data.get('membre_instance_auf')
130 fonction = self.cleaned_data.get('membre_instance_auf_fonction')
131 if membre and not fonction:
132 raise forms.ValidationError('Veuillez préciser')
133 return fonction
614b3269 134
c073c94d
EMS
135 def clean_membre_instance_auf_dates(self):
136 membre = self.cleaned_data.get('membre_instance_auf')
137 dates = self.cleaned_data.get('membre_instance_auf_dates')
138 if membre and not dates:
139 raise forms.ValidationError('Veuillez préciser les dates')
140 return dates
141
142 def clean_expert_oif(self):
143 return bool(int(self.cleaned_data['expert_oif']))
144
614b3269
EMS
145 def clean_expert_oif_details(self):
146 expert = self.cleaned_data.get('expert_oif')
147 details = self.cleaned_data.get('expert_oif_details')
148 if expert and not details:
149 raise forms.ValidationError('Veuillez préciser')
150 return details
151
152 def clean_expert_oif_dates(self):
153 expert = self.cleaned_data.get('expert_oif')
154 dates = self.cleaned_data.get('expert_oif_dates')
155 if expert and not dates:
156 raise forms.ValidationError('Veuillez préciser les dates')
157 return dates
158
c073c94d
EMS
159 def clean_membre_association_francophone(self):
160 return bool(int(self.cleaned_data['membre_association_francophone']))
161
162 def clean_membre_association_francophone_details(self):
163 membre = self.cleaned_data.get('membre_association_francophone')
164 details = self.cleaned_data.get('membre_association_francophone_details')
165 if membre and not details:
166 raise forms.ValidationError('Veuillez préciser')
167 return details
168
169 def clean_membre_reseau_institutionnel(self):
170 return bool(int(self.cleaned_data['membre_reseau_institutionnel']))
171
bc15119b 172 def clean_membre_reseau_institutionnel_nom(self):
c073c94d 173 membre = self.cleaned_data.get('membre_reseau_institutionnel')
bc15119b
EMS
174 nom = self.cleaned_data.get('membre_reseau_institutionnel_nom')
175 if membre and not nom:
c073c94d 176 raise forms.ValidationError('Veuillez préciser')
bc15119b
EMS
177 return nom
178
179 def clean_membre_reseau_institutionnel_fonction(self):
180 membre = self.cleaned_data.get('membre_reseau_institutionnel')
181 fonction = self.cleaned_data.get('membre_reseau_institutionnel_fonction')
182 if membre and not fonction:
183 raise forms.ValidationError('Veuillez préciser')
184 return fonction
c073c94d
EMS
185
186 def clean_membre_reseau_institutionnel_dates(self):
187 membre = self.cleaned_data.get('membre_reseau_institutionnel')
188 dates = self.cleaned_data.get('membre_reseau_institutionnel_dates')
189 if membre and not dates:
190 raise forms.ValidationError('Veuillez préciser les dates')
191 return dates
192
cb591fb3
EMS
193 def clean_expertises_auf(self):
194 return bool(int(self.cleaned_data['expertises_auf']))
195
13ec4813 196class ChercheurInscriptionForm(ChercheurForm):
13ec4813
EMS
197
198 class Meta(ChercheurForm.Meta):
43ed73e7 199 fields = ChercheurForm.Meta.fields + ('courriel',)
13ec4813 200
a7b16ec9
EMS
201class GroupesForm(forms.Form):
202 """Formulaire qui associe des groupes à un chercheur."""
e4d01d1d
EMS
203 groupes = forms.ModelMultipleChoiceField(
204 queryset=Groupe.objects.all(),
205 label='Domaines de recherche', required=False,
206 help_text="Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs."
207 )
a7b16ec9
EMS
208
209 def __init__(self, data=None, prefix=None, chercheur=None):
210 self.chercheur = chercheur
211 initial = {}
212 if chercheur:
213 initial['groupes'] = chercheur.groupes.values_list('id', flat=True)
214 super(GroupesForm, self).__init__(data=data, prefix=prefix, initial=initial)
215
216 def save(self):
217 if self.is_valid():
218 groupes = self.cleaned_data['groupes']
219 ChercheurGroupe.objects.filter(chercheur=self.chercheur).exclude(groupe__in=groupes).delete()
220 for g in groupes:
221 ChercheurGroupe.objects.get_or_create(chercheur=self.chercheur, groupe=g, actif=1)
222
00755d9b
AJ
223class PublicationForm(forms.ModelForm):
224 class Meta:
225 model = Publication
3eb41a6d 226 fields = ('auteurs', 'titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
f810842d 227
595ab4d6
EMS
228PublicationFormSet = inlineformset_factory(Chercheur, Publication, form=PublicationForm, extra=1)
229
230class TheseForm(forms.ModelForm):
e8e9e4fd 231 class Meta:
595ab4d6
EMS
232 model = These
233 fields = ('titre', 'annee', 'directeur', 'etablissement', 'nb_pages', 'url')
2a36714f 234
5b9abc81 235class ExpertiseForm(forms.ModelForm):
c073c94d
EMS
236 organisme_demandeur_visible = forms.ChoiceField(
237 label="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
238 choices=OUI_NON_CHOICES, widget=forms.RadioSelect(), required=False
239 )
5b9abc81
AJ
240 class Meta:
241 model = Expertise
242 fields = ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
dab519fa 243
b16bcbaf 244 def clean_organisme_demandeur_visible(self):
6504a7e5
EMS
245 value = self.cleaned_data['organisme_demandeur_visible']
246 return bool(int(value)) if value else False
b16bcbaf 247
ee8b3a49
EMS
248ExpertiseFormSet = inlineformset_factory(Chercheur, Expertise, form=ExpertiseForm, extra=1)
249
a7b16ec9
EMS
250class ChercheurFormGroup(object):
251 """Groupe de formulaires nécessaires pour l'inscription et l'édition
252 d'un chercheur."""
00755d9b 253
a7b16ec9 254 def __init__(self, data=None, chercheur=None):
e61eecfe
EMS
255 try:
256 these = chercheur and chercheur.these
257 except These.DoesNotExist:
258 these = These()
43ed73e7 259 chercheur_form_class = ChercheurInscriptionForm if chercheur is None else ChercheurForm
13ec4813 260 self.chercheur = chercheur_form_class(data=data, prefix='chercheur', instance=chercheur)
a7b16ec9 261 self.groupes = GroupesForm(data=data, prefix='chercheur', chercheur=chercheur)
ee8b3a49 262 self.expertises = ExpertiseFormSet(data=data, prefix='expertise', instance=chercheur)
e61eecfe 263 self.these = TheseForm(data=data, prefix='these', instance=these)
595ab4d6 264 self.publications = PublicationFormSet(data=data, prefix='publication', instance=chercheur)
a7b16ec9
EMS
265
266 @property
267 def has_errors(self):
13ec4813
EMS
268 return bool(self.chercheur.errors or self.groupes.errors or
269 self.these.errors or self.publications.errors or
270 self.expertises.errors)
a7b16ec9
EMS
271
272 def is_valid(self):
13ec4813
EMS
273 return self.chercheur.is_valid() and self.groupes.is_valid() and \
274 self.these.is_valid() and self.publications.is_valid() and \
275 self.expertises.is_valid()
a7b16ec9
EMS
276
277 def save(self):
278 if self.is_valid():
279
13ec4813 280 # Enregistrer d'abord le chercheur lui-même.
a7b16ec9
EMS
281 self.chercheur.save()
282
595ab4d6
EMS
283 # Puis les objets qui ont des clés étrangères vers nous
284 # puisqu'on a besoin d'un id.
13ec4813 285 chercheur = self.chercheur.instance
a7b16ec9
EMS
286 self.groupes.chercheur = chercheur
287 self.groupes.save()
595ab4d6
EMS
288 self.these.instance.chercheur = chercheur
289 self.these.save()
290 self.publications.instance = chercheur
291 self.publications.save()
3820b46e
EMS
292 self.expertises.instance = chercheur
293 self.expertises.save()
43ed73e7 294 return self.chercheur.instance
5b9abc81 295
13146d99 296class RepertoireSearchForm (forms.Form):
f0692c02 297 q = forms.CharField(required=False, label="Rechercher dans tous les champs")
3efbacbe 298 nom = forms.CharField(required=False, label="Nom")
0e9597af 299 domaine = forms.ModelChoiceField(queryset=Groupe.objects.all(), required=False, label="Domaine de recherche", empty_label="Tous")
bc415771
EMS
300 groupe_recherche = forms.CharField(required=False, label="Groupe de recherche",
301 help_text="ou Laboratoire, ou Groupement inter-universitaire")
6bd49ff1 302 statut = forms.ChoiceField(choices=(('','Tous'),)+STATUT_CHOICES+(('expert','Expert'),), required=False, label="Statut")
f0692c02 303 discipline = forms.ModelChoiceField(queryset=Discipline.objects.all(), required=False, label="Discipline", empty_label="Toutes")
3eba0476 304 pays = forms.ModelChoiceField(queryset=Pays.objects.all(), required=False, label="Pays", empty_label="Tous")
bc415771
EMS
305 region = forms.ModelChoiceField(queryset=Region.objects.all(), required=False, label="Région", empty_label="Toutes",
306 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.")
bc415771 307 nord_sud = forms.ChoiceField(choices=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required=False, label="Nord/Sud",
5eecdf3e 308 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 développés, par Sud les pays en développement (pays les moins avancés, pays émergents et pays à économies en transition)")
2e99acab
EMS
309 activites_francophonie = forms.ChoiceField(required=False, label="Activités en Francophonie", choices=(
310 ('', '---------'),
311 ('instance_auf', "Membre d'une instance de l'AUF"),
312 ('expert_oif', "Sollicité par l'OIF"),
313 ('association_francophone', "Membre d'une association ou d'une société savante francophone"),
314 ('reseau_institutionnel', "Membre des instances d'un réseau institutionnel de l'AUF")
315 ))
c548d94a
EMS
316
317 def __init__(self, data=None, region=None):
318 super(RepertoireSearchForm, self).__init__(data)
319 if region:
320 pays = self.fields['pays']
321 pays.queryset = pays.queryset.filter(region=region)
322
3efbacbe 323 def get_query_set(self):
5212238e 324 chercheurs = Chercheur.objects
3efbacbe 325 if self.is_valid():
5212238e
EMS
326 q = self.cleaned_data["q"]
327 if q:
328 chercheurs = chercheurs.search(q)
3efbacbe
EMS
329 nom = self.cleaned_data['nom']
330 if nom:
5212238e 331 chercheurs = chercheurs.add_to_query('@(nom,prenom) ' + nom)
d087521a
EMS
332 groupe_recherche = self.cleaned_data['groupe_recherche']
333 if groupe_recherche:
5212238e 334 chercheurs = chercheurs.add_to_query('@groupe_recherche ' + groupe_recherche)
116db1fd
EMS
335 discipline = self.cleaned_data['discipline']
336 if discipline:
5212238e 337 chercheurs = chercheurs.filter_discipline(discipline)
116db1fd
EMS
338 region = self.cleaned_data['region']
339 if region:
5212238e
EMS
340 chercheurs = chercheurs.filter_region(region)
341 statut = self.cleaned_data["statut"]
342 if statut:
343 if statut == "expert":
344 chercheurs = chercheurs.filter_expert()
345 else:
346 chercheurs = chercheurs.filter_statut(statut)
347 domaine = self.cleaned_data["domaine"]
348 if domaine:
349 chercheurs = chercheurs.filter_groupe(domaine)
62eece34
EMS
350 pays = self.cleaned_data["pays"]
351 if pays:
5212238e 352 chercheurs = chercheurs.filter_pays(pays)
62eece34
EMS
353 nord_sud = self.cleaned_data['nord_sud']
354 if nord_sud:
5212238e 355 chercheurs = chercheurs.filter_nord_sud(nord_sud)
2e99acab
EMS
356 activites_francophonie = self.cleaned_data['activites_francophonie']
357 if activites_francophonie == 'instance_auf':
358 chercheurs = chercheurs.filter(membre_instance_auf=True)
359 elif activites_francophonie == 'expert_oif':
360 chercheurs = chercheurs.filter(expert_oif=True)
361 elif activites_francophonie == 'association_francophone':
362 chercheurs = chercheurs.filter(membre_association_francophone=True)
363 elif activites_francophonie == 'reseau_institutionnel':
364 chercheurs = chercheurs.filter(membre_reseau_institutionnel=True)
5212238e 365 return chercheurs.all()
3efbacbe 366
0e9597af 367class SendPasswordForm(forms.Form):
89da853e 368 email = forms.EmailField(required=True, label="Adresse électronique")
0e9597af
AJ
369 def clean_email(self):
370 cleaned_data = self.cleaned_data
371 email = cleaned_data.get("email")
372 if email:
373 try:
13ec4813 374 Personne.objects.get(courriel=email)
0e9597af 375 except:
89da853e 376 raise forms.ValidationError("Cette adresse n'existe pas dans notre base de données.")
e427f068
AJ
377 return email
378
43ed73e7 379class SetPasswordForm(forms.Form):
e427f068 380 password = forms.CharField(widget=forms.PasswordInput(), required=True, label="Mot de passe")
43ed73e7 381 password_repeat = forms.CharField(widget=forms.PasswordInput(), required=True, label="Confirmez votre mot de passe")
92990258 382
e427f068
AJ
383 def clean_password_repeat(self):
384 cleaned_data = self.cleaned_data
385 password = cleaned_data.get("password")
386 password_repeat = cleaned_data.get("password_repeat")
387 if password and password_repeat:
388 if password != password_repeat:
389 raise forms.ValidationError("Les mots de passe ne concordent pas")
390 return password_repeat