1 # -*- encoding: utf-8 -*-
3 from django
import forms
4 from django
.contrib
.auth
.forms
import AuthenticationForm
as DjangoAuthenticationForm
5 from django
.db
.models
import Q
6 from django
.forms
.models
import inlineformset_factory
7 from itertools
import chain
10 OUI_NON_CHOICES
= ((True, 'Oui'), (False, 'Non'))
12 class ChercheurForm(forms
.ModelForm
):
13 """Formulaire d'édition d'un chercheur."""
14 genre
= forms
.ChoiceField(widget
=forms
.RadioSelect(), choices
=GENRE_CHOICES
)
15 afficher_courriel
= forms
.ChoiceField(
16 label
="Afficher mon courriel publiquement sur ce site",
17 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
19 membre_instance_auf
= forms
.ChoiceField(
20 label
="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
21 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
23 membre_instance_auf_nom
= forms
.ChoiceField(
24 choices
= (('', '---------'),) + Chercheur
.INSTANCE_AUF_CHOICES
,
25 label
="Préciser laquelle", required
=False
27 membre_instance_auf_fonction
= forms
.CharField(label
="Préciser votre fonction", required
=False)
28 membre_instance_auf_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
29 expert_oif
= forms
.ChoiceField(label
="Avez-vous déjà été sollicité par l'OIF?", choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect())
30 expert_oif_details
= forms
.CharField(label
="Préciser à quel titre", required
=False,
31 help_text
="Fonction dans l'organisation, participation à une étude ou à une action, etc.")
32 expert_oif_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
33 membre_association_francophone
= forms
.ChoiceField(
34 label
="Êtes-vous membre d'une association ou d'une société savante francophone?",
35 help_text
="e.g. FIPF, Collège international de philosophie, AISLF, etc.",
36 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
38 membre_association_francophone_details
= forms
.CharField(label
="Préciser laquelle", required
=False)
39 membre_reseau_institutionnel
= forms
.ChoiceField(
40 label
="Êtes-vous (ou avez-vous déjà été) membre des instances d'un réseau institutionnel de l'AUF?",
41 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
43 membre_reseau_institutionnel_nom
= forms
.ChoiceField(
44 label
="Préciser le réseau institutionnel",
45 choices
=(('', '---------'),) + Chercheur
.RESEAU_INSTITUTIONNEL_CHOICES
,
48 membre_reseau_institutionnel_fonction
= forms
.CharField(required
=False, label
="Préciser votre fonction")
49 membre_reseau_institutionnel_dates
= forms
.CharField(required
=False, label
="Préciser les dates")
51 pays_etablissement
= forms
.ModelChoiceField(label
="Pays de l'établissement", queryset
=Pays
.objects
.all(), required
=True)
52 etablissement
= forms
.CharField(
53 label
="Nom de l'établissement", required
=True,
54 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."
57 pas_de_sollicitation_expertises
= forms
.BooleanField(
59 label
="Je ne souhaite pas être sollicité par l'AUF pour des missions d'expertise"
62 theme_recherche
= forms
.CharField(
63 max_length
=1000, label
='Thèmes de recherche', help_text
='1000 signes maximum',
64 error_messages
=dict(max_length
="Veuillez entrer au maximum %(limit_value)d signes (vous en avez entré %(show_value)d)."),
65 widget
=forms
.Textarea()
67 attestation
= forms
.BooleanField(
69 label
="J'atteste sur l'honneur l'exactitude des renseignements fournis sur le formulaire d'inscription et j'accepte leur publication en ligne."
71 discipline
= forms
.ModelChoiceField(
72 label
="Discipline", required
=True,
73 queryset
=Discipline
.objects
.all(),
74 help_text
="La liste des disciplines procède d'un choix fait par le conseil scientifique de l'AUF."
76 groupe_recherche
= forms
.CharField(
77 max_length
=255, label
='Groupe de recherche', required
=False,
78 help_text
="Indiquer l'appartenance à un groupe de recherche universitaire ou laboratoire ou groupement inter-universitaire"
80 url_site_web
= forms
.URLField(
81 label
='Adresse site Internet', required
=False,
82 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."
87 fields
= ('nom', 'prenom', 'genre', 'afficher_courriel', 'adresse_postale', 'telephone',
89 'discipline', 'theme_recherche', 'groupe_recherche',
90 'mots_cles', 'url_site_web', 'url_blog',
91 'url_reseau_social', 'attestation', 'membre_instance_auf',
92 'membre_instance_auf_nom', 'membre_instance_auf_fonction',
93 'membre_instance_auf_dates', 'expert_oif',
94 'expert_oif_details', 'expert_oif_dates',
95 'membre_association_francophone',
96 'membre_association_francophone_details',
97 'membre_reseau_institutionnel',
98 'membre_reseau_institutionnel_nom',
99 'membre_reseau_institutionnel_fonction',
100 'membre_reseau_institutionnel_dates')
102 def __init__(self
, data
=None, prefix
=None, instance
=None):
103 if instance
is not None:
105 if instance
.etablissement
:
106 initial
['etablissement'] = instance
.etablissement
.nom
107 initial
['pays_etablissement'] = instance
.etablissement
.pays_id
109 initial
['etablissement'] = instance
.etablissement_autre_nom
110 initial
['pays_etablissement'] = instance
.etablissement_autre_pays_id
111 initial
['pas_de_sollicitation_expertises'] = not instance
.expertises_auf
114 super(ChercheurForm
, self
).__init__(data
=data
, prefix
=prefix
, instance
=instance
, initial
=initial
)
117 nom_etablissement
= self
.cleaned_data
['etablissement']
118 pays_etablissement
= self
.cleaned_data
['pays_etablissement']
119 etablissements
= Etablissement
.objects
.filter(nom
=nom_etablissement
, pays
=pays_etablissement
, actif
=True)
120 if etablissements
.count() > 0:
121 self
.instance
.etablissement
= etablissements
[0]
122 self
.instance
.etablissement_autre
= ''
123 self
.instance
.etablissement_autre_pays
= None
125 self
.instance
.etablissement
= None
126 self
.instance
.etablissement_autre_nom
= nom_etablissement
127 self
.instance
.etablissement_autre_pays
= pays_etablissement
128 self
.instance
.expertises_auf
= not self
.cleaned_data
['pas_de_sollicitation_expertises']
129 super(ChercheurForm
, self
).save()
131 def clean_courriel(self
):
132 """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
133 avec le même courriel."""
134 courriel
= self
.cleaned_data
['courriel']
135 existing
= Chercheur
.objects
.filter(courriel
=courriel
, actif
=True)
136 if self
.instance
and self
.instance
.id:
137 existing
= existing
.exclude(id=self
.instance
.id)
139 raise forms
.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
142 def clean_afficher_courriel(self
):
143 return self
.cleaned_data
['afficher_courriel'] == 'True'
145 def clean_membre_instance_auf(self
):
146 return self
.cleaned_data
['membre_instance_auf'] == 'True'
148 def clean_membre_instance_auf_nom(self
):
149 membre
= self
.cleaned_data
.get('membre_instance_auf')
150 nom
= self
.cleaned_data
.get('membre_instance_auf_nom')
151 if membre
and not nom
:
152 raise forms
.ValidationError('Veuillez préciser')
155 def clean_membre_instance_auf_fonction(self
):
156 membre
= self
.cleaned_data
.get('membre_instance_auf')
157 fonction
= self
.cleaned_data
.get('membre_instance_auf_fonction')
158 if membre
and not fonction
:
159 raise forms
.ValidationError('Veuillez préciser')
162 def clean_membre_instance_auf_dates(self
):
163 membre
= self
.cleaned_data
.get('membre_instance_auf')
164 dates
= self
.cleaned_data
.get('membre_instance_auf_dates')
165 if membre
and not dates
:
166 raise forms
.ValidationError('Veuillez préciser les dates')
169 def clean_expert_oif(self
):
170 return self
.cleaned_data
['expert_oif'] == 'True'
172 def clean_expert_oif_details(self
):
173 expert
= self
.cleaned_data
.get('expert_oif')
174 details
= self
.cleaned_data
.get('expert_oif_details')
175 if expert
and not details
:
176 raise forms
.ValidationError('Veuillez préciser')
179 def clean_expert_oif_dates(self
):
180 expert
= self
.cleaned_data
.get('expert_oif')
181 dates
= self
.cleaned_data
.get('expert_oif_dates')
182 if expert
and not dates
:
183 raise forms
.ValidationError('Veuillez préciser les dates')
186 def clean_membre_association_francophone(self
):
187 return self
.cleaned_data
['membre_association_francophone'] == 'True'
189 def clean_membre_association_francophone_details(self
):
190 membre
= self
.cleaned_data
.get('membre_association_francophone')
191 details
= self
.cleaned_data
.get('membre_association_francophone_details')
192 if membre
and not details
:
193 raise forms
.ValidationError('Veuillez préciser')
196 def clean_membre_reseau_institutionnel(self
):
197 return self
.cleaned_data
['membre_reseau_institutionnel'] == 'True'
199 def clean_membre_reseau_institutionnel_nom(self
):
200 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
201 nom
= self
.cleaned_data
.get('membre_reseau_institutionnel_nom')
202 if membre
and not nom
:
203 raise forms
.ValidationError('Veuillez préciser')
206 def clean_membre_reseau_institutionnel_fonction(self
):
207 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
208 fonction
= self
.cleaned_data
.get('membre_reseau_institutionnel_fonction')
209 if membre
and not fonction
:
210 raise forms
.ValidationError('Veuillez préciser')
213 def clean_membre_reseau_institutionnel_dates(self
):
214 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
215 dates
= self
.cleaned_data
.get('membre_reseau_institutionnel_dates')
216 if membre
and not dates
:
217 raise forms
.ValidationError('Veuillez préciser les dates')
220 class ChercheurInscriptionForm(ChercheurForm
):
222 class Meta(ChercheurForm
.Meta
):
223 fields
= ChercheurForm
.Meta
.fields
+ ('courriel',)
225 class GroupesForm(forms
.Form
):
226 """Formulaire qui associe des domaines de recherche et groupe de chercheur à un chercheur."""
227 domaines_recherche
= forms
.ModelMultipleChoiceField(
228 queryset
=Groupe
.domaine_recherche_objects
.all(),
229 label
='Domaines de recherche', required
=False,
230 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."
233 groupes_chercheur
= forms
.ModelMultipleChoiceField(
234 queryset
=Groupe
.groupe_chercheur_objects
.all(),
235 label
='Groupes de chercheur', required
=False,
236 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."
239 def __init__(self
, data
=None, prefix
=None, chercheur
=None):
240 self
.chercheur
= chercheur
243 initial
['domaines_recherche'] = chercheur
.domaines_recherche
.values_list('id', flat
=True)
244 initial
['groupes_chercheur'] = chercheur
.groupes_chercheur
.values_list('id', flat
=True)
245 super(GroupesForm
, self
).__init__(data
=data
, prefix
=prefix
, initial
=initial
)
249 domaines_recherche
= self
.cleaned_data
['domaines_recherche']
250 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__groupe_chercheur
=True).exclude(groupe__in
=domaines_recherche
).delete()
251 for dr
in domaines_recherche
:
252 cg
, created
= ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=dr
)
257 groupes_chercheur
= self
.cleaned_data
['groupes_chercheur']
258 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__groupe_chercheur
=False).exclude(groupe__in
=groupes_chercheur
).delete()
259 for gc
in groupes_chercheur
:
260 cg
, created
= ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=gc
)
265 class PublicationForm(forms
.ModelForm
):
268 fields
= ('auteurs', 'titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url')
270 PublicationFormSet
= inlineformset_factory(Chercheur
, Publication
, form
=PublicationForm
, extra
=1)
272 class TheseForm(forms
.ModelForm
):
275 fields
= ('titre', 'annee', 'directeur', 'etablissement', 'nb_pages', 'url')
277 class ExpertiseForm(forms
.ModelForm
):
278 organisme_demandeur_visible
= forms
.ChoiceField(
279 label
="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
280 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect(), required
=False
282 nom
= forms
.CharField(label
="Objet de l'expertise", required
=False)
286 fields
= ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
288 def clean_organisme_demandeur_visible(self
):
289 value
= self
.cleaned_data
['organisme_demandeur_visible']
290 return value
== 'True'
292 ExpertiseFormSet
= inlineformset_factory(Chercheur
, Expertise
, form
=ExpertiseForm
, extra
=1)
294 class ChercheurFormGroup(object):
295 """Groupe de formulaires nécessaires pour l'inscription et l'édition
298 def __init__(self
, data
=None, chercheur
=None):
300 these
= chercheur
and chercheur
.these
301 except These
.DoesNotExist
:
303 chercheur_form_class
= ChercheurInscriptionForm
if chercheur
is None else ChercheurForm
304 self
.chercheur
= chercheur_form_class(data
=data
, prefix
='chercheur', instance
=chercheur
)
305 self
.groupes
= GroupesForm(data
=data
, prefix
='chercheur', chercheur
=chercheur
)
306 self
.expertises
= ExpertiseFormSet(data
=data
, prefix
='expertise', instance
=chercheur
)
307 self
.these
= TheseForm(data
=data
, prefix
='these', instance
=these
)
308 self
.publications
= PublicationFormSet(data
=data
, prefix
='publication', instance
=chercheur
)
311 def has_errors(self
):
312 return bool(self
.chercheur
.errors
or self
.groupes
.errors
or
313 self
.these
.errors
or self
.publications
.errors
or
314 self
.expertises
.errors
)
317 return self
.chercheur
.is_valid() and self
.groupes
.is_valid() and \
318 self
.these
.is_valid() and self
.publications
.is_valid() and \
319 self
.expertises
.is_valid()
324 # Enregistrer d'abord le chercheur lui-même.
325 self
.chercheur
.save()
327 # Puis les objets qui ont des clés étrangères vers nous
328 # puisqu'on a besoin d'un id.
329 chercheur
= self
.chercheur
.instance
330 self
.groupes
.chercheur
= chercheur
332 self
.these
.instance
.chercheur
= chercheur
334 self
.publications
.instance
= chercheur
335 self
.publications
.save()
336 self
.expertises
.instance
= chercheur
337 for expertise
in self
.expertises
.save(commit
=False):
342 return self
.chercheur
.instance
344 class GroupeSearchForm(forms
.ModelForm
):
345 """Formulaire de recherche pour les groupes."""
351 class ChercheurSearchForm(forms
.ModelForm
):
352 """Formulaire de recherche pour les chercheurs."""
355 model
= ChercheurSearch
356 fields
= ['q', 'nom_chercheur', 'domaine', 'groupe_chercheur',
357 'groupe_recherche', 'statut', 'discipline', 'pays',
358 'region', 'nord_sud', 'activites_francophonie', 'genre']
360 class ChercheurSearchEditForm(ChercheurSearchForm
):
361 """Formulaire d'édition d'une recherche sauvegardée."""
363 class Meta(ChercheurSearchForm
.Meta
):
364 fields
= ['nom', 'alerte_courriel'] + ChercheurSearchForm
.Meta
.fields
366 class SendPasswordForm(forms
.Form
):
367 email
= forms
.EmailField(required
=True, label
="Adresse électronique")
368 def clean_email(self
):
369 cleaned_data
= self
.cleaned_data
370 email
= cleaned_data
.get("email")
373 Personne
.objects
.get(courriel
=email
)
375 raise forms
.ValidationError("Cette adresse n'existe pas dans notre base de données.")
378 class SetPasswordForm(forms
.Form
):
379 password
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Mot de passe")
380 password_repeat
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Confirmez votre mot de passe")
382 def clean_password_repeat(self
):
383 cleaned_data
= self
.cleaned_data
384 password
= cleaned_data
.get("password")
385 password_repeat
= cleaned_data
.get("password_repeat")
386 if password
and password_repeat
:
387 if password
!= password_repeat
:
388 raise forms
.ValidationError("Les mots de passe ne concordent pas")
389 return password_repeat
391 class AuthenticationForm(DjangoAuthenticationForm
):
392 username
= forms
.CharField(label
='Courriel')
395 class MessageForm(forms
.ModelForm
):
399 exclude
= ('chercheur', 'groupe')