1 # -*- encoding: utf-8 -*-
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
9 OUI_NON_CHOICES
= (('1', 'Oui'), ('0', 'Non'))
11 class PersonneForm(forms
.ModelForm
):
12 genre
= forms
.ChoiceField(widget
=forms
.RadioSelect(), choices
=GENRE_CHOICES
)
16 fields
= ('nom', 'prenom', 'courriel', 'genre')
18 def clean_courriel(self
):
19 """On veut s'assurer qu'il n'y ait pas d'autre utilisateur actif
20 avec le même courriel."""
21 courriel
= self
.cleaned_data
['courriel']
22 existing
= Personne
.objects
.filter(courriel
=courriel
, actif
=True)
23 if self
.instance
and self
.instance
.id:
24 existing
= existing
.exclude(id=self
.instance
.id)
26 raise forms
.ValidationError('Il existe déjà une fiche pour cette adresse électronique')
29 class PersonneInscriptionForm(PersonneForm
):
30 password
= forms
.CharField(widget
=forms
.PasswordInput(), label
="Mot de passe")
31 password_confirmation
= forms
.CharField(widget
=forms
.PasswordInput(), label
="Confirmez votre mot de passe")
33 class Meta(PersonneForm
.Meta
):
34 fields
= ('nom', 'prenom', 'courriel', 'password', 'password_confirmation', 'genre')
36 def clean_password_confirmation(self
):
37 """S'assurer que le mot de passe et la confirmation sont identiques."""
38 password
= self
.cleaned_data
.get('password')
39 confirmation
= self
.cleaned_data
.get('password_confirmation')
40 if password
!= confirmation
:
41 raise forms
.ValidationError('Les deux mots de passe ne correspondent pas.')
45 self
.instance
.set_password(self
.cleaned_data
['password'])
46 return super(PersonneInscriptionForm
, self
).save()
48 class ChercheurForm(forms
.ModelForm
):
49 """Formulaire d'édition d'un chercheur."""
50 ETABLISSEMENT_CHOICES
= ((id, nom
if len(nom
) < 80 else nom
[:80] + '...')
51 for id, nom
in Etablissement
.objects
.filter(membre
=True).values_list('id', 'nom'))
53 membre_instance_auf
= forms
.ChoiceField(
54 label
="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?",
55 help_text
="e.g. conseil scientifique, conseil associatif, commission régionale d'experts",
56 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
58 membre_instance_auf_details
= forms
.CharField(label
="Préciser laquelle et votre fonction", required
=False)
59 membre_instance_auf_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
60 expert_oif
= forms
.ChoiceField(label
="Avez-vous déjà été sollicité par l'OIF?", choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect())
61 expert_oif_details
= forms
.CharField(label
="Préciser à quel titre", required
=False,
62 help_text
="Fonction dans l'organisation, participation à une étude ou à une action, etc.")
63 expert_oif_dates
= forms
.CharField(label
="Préciser les dates", required
=False)
64 membre_association_francophone
= forms
.ChoiceField(
65 label
="Êtes-vous membre d'une association ou d'une société savante francophone?",
66 help_text
="e.g. FIPF, Collège international de philosophie, AISLF, etc.",
67 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
69 membre_association_francophone_details
= forms
.CharField(label
="Préciser laquelle", required
=False)
70 membre_reseau_institutionnel
= forms
.ChoiceField(
71 label
="Avez-vous fait partie des instances d'un réseau institutionnel de l'AUF?",
72 help_text
="e.g. AFELSH, RIFFEF, CIDMEF, etc.",
73 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
75 membre_reseau_institutionnel_details
= forms
.CharField(required
=False, label
="Préciser lesquelles et votre fonction")
76 membre_reseau_institutionnel_dates
= forms
.CharField(required
=False, label
="Préciser les dates")
78 etablissement
= forms
.ChoiceField(label
='Etablissement', required
=False, choices
=chain([('', '---------')], ETABLISSEMENT_CHOICES
))
80 expertises_auf
= forms
.ChoiceField(
81 label
="Êtes-vous disposé à réaliser des expertises pour l'AUF?",
82 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect()
87 fields
= ('statut', 'diplome', 'etablissement',
88 'etablissement_autre_nom', 'etablissement_autre_pays',
89 'discipline', 'theme_recherche', 'groupe_recherche', 'mots_cles',
90 'url_site_web', 'url_blog', 'url_reseau_social',
91 'membre_instance_auf', 'membre_instance_auf_details', 'membre_instance_auf_dates',
92 'expert_oif', 'expert_oif_details', 'expert_oif_dates',
93 'membre_association_francophone',
94 'membre_association_francophone_details',
95 'membre_reseau_institutionnel', 'membre_reseau_institutionnel_details',
96 'membre_reseau_institutionnel_dates', 'expertises_auf')
98 def clean_membre_instance_auf(self
):
99 return bool(int(self
.cleaned_data
['membre_instance_auf']))
101 def clean_membre_instance_auf_details(self
):
102 membre
= self
.cleaned_data
.get('membre_instance_auf')
103 details
= self
.cleaned_data
.get('membre_instance_auf_details')
104 if membre
and not details
:
105 raise forms
.ValidationError('Veuillez préciser')
108 def clean_membre_instance_auf_dates(self
):
109 membre
= self
.cleaned_data
.get('membre_instance_auf')
110 dates
= self
.cleaned_data
.get('membre_instance_auf_dates')
111 if membre
and not dates
:
112 raise forms
.ValidationError('Veuillez préciser les dates')
115 def clean_expert_oif(self
):
116 return bool(int(self
.cleaned_data
['expert_oif']))
118 def clean_expert_oif_details(self
):
119 expert
= self
.cleaned_data
.get('expert_oif')
120 details
= self
.cleaned_data
.get('expert_oif_details')
121 if expert
and not details
:
122 raise forms
.ValidationError('Veuillez préciser')
125 def clean_expert_oif_dates(self
):
126 expert
= self
.cleaned_data
.get('expert_oif')
127 dates
= self
.cleaned_data
.get('expert_oif_dates')
128 if expert
and not dates
:
129 raise forms
.ValidationError('Veuillez préciser les dates')
132 def clean_membre_association_francophone(self
):
133 return bool(int(self
.cleaned_data
['membre_association_francophone']))
135 def clean_membre_association_francophone_details(self
):
136 membre
= self
.cleaned_data
.get('membre_association_francophone')
137 details
= self
.cleaned_data
.get('membre_association_francophone_details')
138 if membre
and not details
:
139 raise forms
.ValidationError('Veuillez préciser')
142 def clean_membre_reseau_institutionnel(self
):
143 return bool(int(self
.cleaned_data
['membre_reseau_institutionnel']))
145 def clean_membre_reseau_institutionnel_details(self
):
146 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
147 details
= self
.cleaned_data
.get('membre_reseau_institutionnel_details')
148 if membre
and not details
:
149 raise forms
.ValidationError('Veuillez préciser')
152 def clean_membre_reseau_institutionnel_dates(self
):
153 membre
= self
.cleaned_data
.get('membre_reseau_institutionnel')
154 dates
= self
.cleaned_data
.get('membre_reseau_institutionnel_dates')
155 if membre
and not dates
:
156 raise forms
.ValidationError('Veuillez préciser les dates')
159 def clean_etablissement(self
):
160 etablissement
= self
.cleaned_data
['etablissement']
162 return Etablissement
.objects
.get(id=etablissement
)
164 def clean_expertises_auf(self
):
165 return bool(int(self
.cleaned_data
['expertises_auf']))
168 etablissement
= self
.cleaned_data
['etablissement']
169 etablissement_autre_nom
= self
.cleaned_data
['etablissement_autre_nom']
170 etablissement_autre_pays
= self
.cleaned_data
['etablissement_autre_pays']
171 if not etablissement
:
172 if not etablissement_autre_nom
:
173 self
._errors
['etablissement'] = self
.error_class([u
"Vous devez renseigner l'établissement"])
174 elif not etablissement_autre_pays
:
175 self
._errors
['etablissement_autre_pays'] = self
.error_class([u
"Vous devez renseigner le pays de l'établissement"])
176 return self
.cleaned_data
178 class ChercheurInscriptionForm(ChercheurForm
):
179 attestation
= forms
.BooleanField(
181 label
="J'atteste sur l'honneur l'exactitude des renseignements fournis sur le formulaire d'inscription et j'accepte leur publication en ligne."
184 class GroupesForm(forms
.Form
):
185 """Formulaire qui associe des groupes à un chercheur."""
186 groupes
= forms
.ModelMultipleChoiceField(
187 queryset
=Groupe
.objects
.all(),
188 label
='Domaines de recherche', required
=False,
189 help_text
="Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs."
192 def __init__(self
, data
=None, prefix
=None, chercheur
=None):
193 self
.chercheur
= chercheur
196 initial
['groupes'] = chercheur
.groupes
.values_list('id', flat
=True)
197 super(GroupesForm
, self
).__init__(data
=data
, prefix
=prefix
, initial
=initial
)
201 groupes
= self
.cleaned_data
['groupes']
202 ChercheurGroupe
.objects
.filter(chercheur
=self
.chercheur
).exclude(groupe__in
=groupes
).delete()
204 ChercheurGroupe
.objects
.get_or_create(chercheur
=self
.chercheur
, groupe
=g
, actif
=1)
206 class PublicationForm(forms
.ModelForm
):
209 fields
= ('auteurs', 'titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url', 'publication_affichage')
211 PublicationFormSet
= inlineformset_factory(Chercheur
, Publication
, form
=PublicationForm
, extra
=1)
213 class TheseForm(forms
.ModelForm
):
216 fields
= ('titre', 'annee', 'directeur', 'etablissement', 'nb_pages', 'url')
218 class ExpertiseForm(forms
.ModelForm
):
219 organisme_demandeur_visible
= forms
.ChoiceField(
220 label
="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?",
221 choices
=OUI_NON_CHOICES
, widget
=forms
.RadioSelect(), required
=False
225 fields
= ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible')
227 def clean_organisme_demandeur_visible(self
):
228 value
= self
.cleaned_data
['organisme_demandeur_visible']
229 return bool(int(value
)) if value
else False
231 ExpertiseFormSet
= inlineformset_factory(Chercheur
, Expertise
, form
=ExpertiseForm
, extra
=1)
233 class ChercheurFormGroup(object):
234 """Groupe de formulaires nécessaires pour l'inscription et l'édition
237 def __init__(self
, data
=None, chercheur
=None):
238 personne_form_class
= PersonneInscriptionForm
if chercheur
is None else PersonneForm
239 chercheur_form_class
= ChercheurInscriptionForm
if chercheur
is None else ChercheurForm
240 self
.chercheur
= chercheur_form_class(data
=data
, prefix
='chercheur', instance
=chercheur
)
241 self
.groupes
= GroupesForm(data
=data
, prefix
='chercheur', chercheur
=chercheur
)
242 self
.personne
= personne_form_class(data
=data
, prefix
='personne', instance
=chercheur
and chercheur
.personne
.utilisateur
)
243 self
.expertises
= ExpertiseFormSet(data
=data
, prefix
='expertise', instance
=chercheur
)
244 self
.these
= TheseForm(data
=data
, prefix
='these', instance
=chercheur
and chercheur
.these
)
245 self
.publications
= PublicationFormSet(data
=data
, prefix
='publication', instance
=chercheur
)
248 def has_errors(self
):
249 return bool(self
.chercheur
.errors
or self
.personne
.errors
or self
.groupes
.errors
or
250 self
.these
.errors
or self
.publications
.errors
or self
.expertises
.errors
)
253 return self
.chercheur
.is_valid() and self
.personne
.is_valid() and self
.groupes
.is_valid() and \
254 self
.these
.is_valid() and self
.publications
.is_valid() and self
.expertises
.is_valid()
259 chercheur
= self
.chercheur
.instance
261 # Enregistrer d'abord les clés étrangères car on doit les stocker dans
263 chercheur
.personne
= self
.personne
.save()
265 # Puis enregistrer le chercheur lui-même.
266 self
.chercheur
.save()
268 # Puis les objets qui ont des clés étrangères vers nous
269 # puisqu'on a besoin d'un id.
270 self
.groupes
.chercheur
= chercheur
272 self
.these
.instance
.chercheur
= chercheur
274 self
.publications
.instance
= chercheur
275 self
.publications
.save()
276 self
.expertises
.instance
= chercheur
277 self
.expertises
.save()
279 class RepertoireSearchForm (forms
.Form
):
280 q
= forms
.CharField(required
=False, label
="Rechercher dans tous les champs")
281 nom
= forms
.CharField(required
=False, label
="Nom")
282 domaine
= forms
.ModelChoiceField(queryset
=Groupe
.objects
.all(), required
=False, label
="Domaine de recherche", empty_label
="Tous")
283 groupe_recherche
= forms
.CharField(required
=False, label
="Groupe de recherche",
284 help_text
="ou Laboratoire, ou Groupement inter-universitaire")
285 statut
= forms
.ChoiceField(choices
=(('','Tous'),)+STATUT_CHOICES
+(('expert','Expert'),), required
=False, label
="Statut")
286 discipline
= forms
.ModelChoiceField(queryset
=Discipline
.objects
.all(), required
=False, label
="Discipline", empty_label
="Toutes")
287 pays
= forms
.ModelChoiceField(queryset
=Pays
.objects
.all(), required
=False, label
="Pays", empty_label
="Tous")
288 region
= forms
.ModelChoiceField(queryset
=Region
.objects
.all(), required
=False, label
="Région", empty_label
="Toutes",
289 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.")
290 nord_sud
= forms
.ChoiceField(choices
=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required
=False, label
="Nord/Sud",
291 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 les plus développés, par Sud les pays en voie de développement.")
293 def __init__(self
, data
=None, region
=None):
294 super(RepertoireSearchForm
, self
).__init__(data
)
296 pays
= self
.fields
['pays']
297 pays
.queryset
= pays
.queryset
.filter(region
=region
)
299 def get_query_set(self
):
300 chercheurs
= Chercheur
.objects
302 q
= self
.cleaned_data
["q"]
304 chercheurs
= chercheurs
.search(q
)
305 nom
= self
.cleaned_data
['nom']
307 chercheurs
= chercheurs
.add_to_query('@(nom,prenom) ' + nom
)
308 groupe_recherche
= self
.cleaned_data
['groupe_recherche']
310 chercheurs
= chercheurs
.add_to_query('@groupe_recherche ' + groupe_recherche
)
311 discipline
= self
.cleaned_data
['discipline']
313 chercheurs
= chercheurs
.filter_discipline(discipline
)
314 region
= self
.cleaned_data
['region']
316 chercheurs
= chercheurs
.filter_region(region
)
317 statut
= self
.cleaned_data
["statut"]
319 if statut
== "expert":
320 chercheurs
= chercheurs
.filter_expert()
322 chercheurs
= chercheurs
.filter_statut(statut
)
323 domaine
= self
.cleaned_data
["domaine"]
325 chercheurs
= chercheurs
.filter_groupe(domaine
)
326 pays
= self
.cleaned_data
["pays"]
328 chercheurs
= chercheurs
.filter_pays(pays
)
329 nord_sud
= self
.cleaned_data
['nord_sud']
331 chercheurs
= chercheurs
.filter_nord_sud(nord_sud
)
332 return chercheurs
.all()
334 class SendPasswordForm(forms
.Form
):
335 email
= forms
.EmailField(required
=True, label
="Adresse électronique")
336 def clean_email(self
):
337 cleaned_data
= self
.cleaned_data
338 email
= cleaned_data
.get("email")
341 Utilisateur
.objects
.get(courriel
=email
, actif
=True)
343 raise forms
.ValidationError("Cette adresse n'existe pas dans notre base de données.")
346 class NewPasswordForm(forms
.Form
):
347 password
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Mot de passe")
348 password_repeat
= forms
.CharField(widget
=forms
.PasswordInput(), required
=True, label
="Confirmez mot de passe")
350 def clean_password_repeat(self
):
351 cleaned_data
= self
.cleaned_data
352 password
= cleaned_data
.get("password")
353 password_repeat
= cleaned_data
.get("password_repeat")
354 if password
and password_repeat
:
355 if password
!= password_repeat
:
356 raise forms
.ValidationError("Les mots de passe ne concordent pas")
357 return password_repeat