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