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