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