Commit | Line | Data |
---|---|---|
932eef9a | 1 | # -*- encoding: utf-8 -*- |
a7b16ec9 | 2 | import hashlib |
932eef9a | 3 | from django import forms |
3efbacbe | 4 | from django.db.models import Q |
ee8b3a49 | 5 | from django.forms.models import inlineformset_factory |
fbcbdde0 | 6 | from itertools import chain |
932eef9a | 7 | from models import * |
13146d99 | 8 | |
c073c94d EMS |
9 | OUI_NON_CHOICES = (('1', 'Oui'), ('0', 'Non')) |
10 | ||
932eef9a | 11 | class PersonneForm(forms.ModelForm): |
c18af6bd | 12 | genre = forms.ChoiceField(widget=forms.RadioSelect(), choices=GENRE_CHOICES) |
e4d01d1d | 13 | |
932eef9a | 14 | class Meta: |
dab519fa | 15 | model = Utilisateur |
e4d01d1d EMS |
16 | fields = ('nom', 'prenom', 'courriel', 'genre') |
17 | ||
18 | class PersonneInscriptionForm(PersonneForm): | |
19 | password = forms.CharField(widget=forms.PasswordInput(), label="Mot de passe") | |
ea51135b | 20 | password_confirmation = forms.CharField(widget=forms.PasswordInput(), label="Confirmez votre mot de passe") |
e4d01d1d EMS |
21 | |
22 | class Meta(PersonneForm.Meta): | |
ea51135b | 23 | fields = ('nom', 'prenom', 'courriel', 'password', 'password_confirmation', 'genre') |
5ecd9e43 | 24 | |
ea51135b EMS |
25 | def clean_password_confirmation(self): |
26 | """S'assurer que le mot de passe et la confirmation sont identiques.""" | |
fd559765 | 27 | password = self.cleaned_data.get('password') |
92990258 | 28 | confirmation = self.cleaned_data.get('password_confirmation') |
ea51135b EMS |
29 | if password != confirmation: |
30 | raise forms.ValidationError('Les deux mots de passe ne correspondent pas.') | |
92990258 EMS |
31 | return confirmation |
32 | ||
33 | def save(self): | |
34 | self.instance.set_password(self.cleaned_data['password']) | |
35 | return super(PersonneInscriptionForm, self).save() | |
ea51135b | 36 | |
932eef9a | 37 | class ChercheurForm(forms.ModelForm): |
a7b16ec9 | 38 | """Formulaire d'édition d'un chercheur.""" |
1de0a686 | 39 | ETABLISSEMENT_CHOICES = ((id, nom if len(nom) < 80 else nom[:80] + '...') |
d84e8b50 | 40 | for id, nom in Etablissement.objects.filter(membre=True).values_list('id', 'nom')) |
a7b16ec9 EMS |
41 | |
42 | membre_instance_auf = forms.ChoiceField( | |
a7b16ec9 EMS |
43 | label="Êtes-vous (ou avez-vous déjà été) membre d'une instance de l'AUF?", |
44 | help_text="e.g. conseil scientifique, conseil associatif, commission régionale d'experts", | |
c073c94d | 45 | choices=OUI_NON_CHOICES, widget=forms.RadioSelect() |
a7b16ec9 | 46 | ) |
614b3269 | 47 | membre_instance_auf_details = forms.CharField(label="Préciser laquelle et votre fonction", required=False) |
a7b16ec9 | 48 | membre_instance_auf_dates = forms.CharField(label="Préciser les dates", required=False) |
614b3269 EMS |
49 | expert_oif = forms.ChoiceField(label="Avez-vous déjà été sollicité par l'OIF?", choices=OUI_NON_CHOICES, widget=forms.RadioSelect()) |
50 | expert_oif_details = forms.CharField(label="Préciser à quel titre", required=False, | |
51 | help_text="Fonction dans l'organisation, participation à une étude ou à une action, etc.") | |
52 | expert_oif_dates = forms.CharField(label="Préciser les dates", required=False) | |
c073c94d EMS |
53 | membre_association_francophone = forms.ChoiceField( |
54 | label="Êtes-vous membre d'une association ou d'une société savante francophone?", | |
55 | help_text="e.g. FIPF, Collège international de philosophie, AISLF, etc.", | |
56 | choices=OUI_NON_CHOICES, widget=forms.RadioSelect() | |
57 | ) | |
58 | membre_association_francophone_details = forms.CharField(label="Préciser laquelle", required=False) | |
59 | membre_reseau_institutionnel = forms.ChoiceField( | |
60 | label="Avez-vous fait partie des instances d'un réseau institutionnel de l'AUF?", | |
61 | help_text="e.g. AFELSH, RIFFEF, CIDMEF, etc.", | |
62 | choices=OUI_NON_CHOICES, widget=forms.RadioSelect() | |
63 | ) | |
64 | membre_reseau_institutionnel_details = forms.CharField(required=False, label="Préciser lesquelles et votre fonction") | |
65 | membre_reseau_institutionnel_dates = forms.CharField(required=False, label="Préciser les dates") | |
66 | ||
fbcbdde0 | 67 | etablissement = forms.ChoiceField(label='Etablissement', required=False, choices=chain([('', '---------')], ETABLISSEMENT_CHOICES)) |
a7b16ec9 | 68 | |
932eef9a AJ |
69 | class Meta: |
70 | model = Chercheur | |
a7b16ec9 EMS |
71 | fields = ('statut', 'diplome', 'etablissement', |
72 | 'etablissement_autre_nom', 'etablissement_autre_pays', | |
0b0fbbd7 | 73 | 'discipline', 'theme_recherche', 'groupe_recherche', 'mots_cles', |
a7b16ec9 | 74 | 'url_site_web', 'url_blog', 'url_reseau_social', |
614b3269 EMS |
75 | 'membre_instance_auf', 'membre_instance_auf_details', 'membre_instance_auf_dates', |
76 | 'expert_oif', 'expert_oif_details', 'expert_oif_dates', | |
77 | 'membre_association_francophone', | |
78 | 'membre_association_francophone_details', | |
c073c94d EMS |
79 | 'membre_reseau_institutionnel', 'membre_reseau_institutionnel_details', |
80 | 'membre_reseau_institutionnel_dates') | |
7c596de2 | 81 | |
c073c94d EMS |
82 | def clean_membre_instance_auf(self): |
83 | return bool(int(self.cleaned_data['membre_instance_auf'])) | |
84 | ||
614b3269 EMS |
85 | def clean_membre_instance_auf_details(self): |
86 | membre = self.cleaned_data.get('membre_instance_auf') | |
87 | details = self.cleaned_data.get('membre_instance_auf_details') | |
88 | if membre and not details: | |
89 | raise forms.ValidationError('Veuillez préciser') | |
90 | return details | |
91 | ||
c073c94d EMS |
92 | def clean_membre_instance_auf_dates(self): |
93 | membre = self.cleaned_data.get('membre_instance_auf') | |
94 | dates = self.cleaned_data.get('membre_instance_auf_dates') | |
95 | if membre and not dates: | |
96 | raise forms.ValidationError('Veuillez préciser les dates') | |
97 | return dates | |
98 | ||
99 | def clean_expert_oif(self): | |
100 | return bool(int(self.cleaned_data['expert_oif'])) | |
101 | ||
614b3269 EMS |
102 | def clean_expert_oif_details(self): |
103 | expert = self.cleaned_data.get('expert_oif') | |
104 | details = self.cleaned_data.get('expert_oif_details') | |
105 | if expert and not details: | |
106 | raise forms.ValidationError('Veuillez préciser') | |
107 | return details | |
108 | ||
109 | def clean_expert_oif_dates(self): | |
110 | expert = self.cleaned_data.get('expert_oif') | |
111 | dates = self.cleaned_data.get('expert_oif_dates') | |
112 | if expert and not dates: | |
113 | raise forms.ValidationError('Veuillez préciser les dates') | |
114 | return dates | |
115 | ||
c073c94d EMS |
116 | def clean_membre_association_francophone(self): |
117 | return bool(int(self.cleaned_data['membre_association_francophone'])) | |
118 | ||
119 | def clean_membre_association_francophone_details(self): | |
120 | membre = self.cleaned_data.get('membre_association_francophone') | |
121 | details = self.cleaned_data.get('membre_association_francophone_details') | |
122 | if membre and not details: | |
123 | raise forms.ValidationError('Veuillez préciser') | |
124 | return details | |
125 | ||
126 | def clean_membre_reseau_institutionnel(self): | |
127 | return bool(int(self.cleaned_data['membre_reseau_institutionnel'])) | |
128 | ||
129 | def clean_membre_reseau_institutionnel_details(self): | |
130 | membre = self.cleaned_data.get('membre_reseau_institutionnel') | |
131 | details = self.cleaned_data.get('membre_reseau_institutionnel_details') | |
132 | if membre and not details: | |
133 | raise forms.ValidationError('Veuillez préciser') | |
134 | return details | |
135 | ||
136 | def clean_membre_reseau_institutionnel_dates(self): | |
137 | membre = self.cleaned_data.get('membre_reseau_institutionnel') | |
138 | dates = self.cleaned_data.get('membre_reseau_institutionnel_dates') | |
139 | if membre and not dates: | |
140 | raise forms.ValidationError('Veuillez préciser les dates') | |
141 | return dates | |
142 | ||
1de0a686 | 143 | def clean_etablissement(self): |
fbcbdde0 EMS |
144 | etablissement = self.cleaned_data['etablissement'] |
145 | if etablissement: | |
146 | return Etablissement.objects.get(id=etablissement) | |
1de0a686 | 147 | |
a7b16ec9 EMS |
148 | def clean(self): |
149 | etablissement = self.cleaned_data['etablissement'] | |
150 | etablissement_autre_nom = self.cleaned_data['etablissement_autre_nom'] | |
151 | etablissement_autre_pays = self.cleaned_data['etablissement_autre_pays'] | |
152 | if not etablissement: | |
153 | if not etablissement_autre_nom: | |
154 | self._errors['etablissement'] = self.error_class([u"Vous devez renseigner l'établissement"]) | |
155 | elif not etablissement_autre_pays: | |
156 | self._errors['etablissement_autre_pays'] = self.error_class([u"Vous devez renseigner le pays de l'établissement"]) | |
157 | return self.cleaned_data | |
158 | ||
a7b16ec9 EMS |
159 | class GroupesForm(forms.Form): |
160 | """Formulaire qui associe des groupes à un chercheur.""" | |
e4d01d1d EMS |
161 | groupes = forms.ModelMultipleChoiceField( |
162 | queryset=Groupe.objects.all(), | |
163 | label='Domaines de recherche', required=False, | |
164 | help_text="Maintenez appuyé « Ctrl », ou « Commande (touche pomme) » sur un Mac, pour en sélectionner plusieurs." | |
165 | ) | |
a7b16ec9 EMS |
166 | |
167 | def __init__(self, data=None, prefix=None, chercheur=None): | |
168 | self.chercheur = chercheur | |
169 | initial = {} | |
170 | if chercheur: | |
171 | initial['groupes'] = chercheur.groupes.values_list('id', flat=True) | |
172 | super(GroupesForm, self).__init__(data=data, prefix=prefix, initial=initial) | |
173 | ||
174 | def save(self): | |
175 | if self.is_valid(): | |
176 | groupes = self.cleaned_data['groupes'] | |
177 | ChercheurGroupe.objects.filter(chercheur=self.chercheur).exclude(groupe__in=groupes).delete() | |
178 | for g in groupes: | |
179 | ChercheurGroupe.objects.get_or_create(chercheur=self.chercheur, groupe=g, actif=1) | |
180 | ||
00755d9b AJ |
181 | class PublicationForm(forms.ModelForm): |
182 | class Meta: | |
183 | model = Publication | |
5fb54817 | 184 | fields = ('titre', 'revue', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url') |
f810842d AJ |
185 | |
186 | class TheseForm(PublicationForm): | |
2a36714f | 187 | titre = forms.CharField(required=True, label="Titre de la thèse ou du mémoire") |
a4e383ac | 188 | annee = forms.IntegerField(required=True, label="Année de soutenance (réalisée ou prévue)") |
dbade9d7 | 189 | editeur = forms.CharField(required=True, label="Directeur de thèse ou de mémoire") |
29f922e0 | 190 | lieu_edition = forms.CharField(required=True, label="Établissement de soutenance") |
e8e9e4fd AJ |
191 | class Meta: |
192 | model = Publication | |
2a36714f AJ |
193 | fields = ('titre', 'annee', 'editeur', 'lieu_edition', 'nb_pages', 'url') |
194 | ||
5b9abc81 | 195 | class ExpertiseForm(forms.ModelForm): |
c073c94d EMS |
196 | organisme_demandeur_visible = forms.ChoiceField( |
197 | label="Voulez-vous que l'organisme demandeur soit visible sur votre fiche?", | |
198 | choices=OUI_NON_CHOICES, widget=forms.RadioSelect(), required=False | |
199 | ) | |
5b9abc81 AJ |
200 | class Meta: |
201 | model = Expertise | |
202 | fields = ('nom', 'date', 'organisme_demandeur', 'organisme_demandeur_visible') | |
dab519fa | 203 | |
b16bcbaf | 204 | def clean_organisme_demandeur_visible(self): |
6504a7e5 EMS |
205 | value = self.cleaned_data['organisme_demandeur_visible'] |
206 | return bool(int(value)) if value else False | |
b16bcbaf | 207 | |
ee8b3a49 EMS |
208 | ExpertiseFormSet = inlineformset_factory(Chercheur, Expertise, form=ExpertiseForm, extra=1) |
209 | ||
a7b16ec9 EMS |
210 | class ChercheurFormGroup(object): |
211 | """Groupe de formulaires nécessaires pour l'inscription et l'édition | |
212 | d'un chercheur.""" | |
00755d9b | 213 | |
a7b16ec9 | 214 | def __init__(self, data=None, chercheur=None): |
e4d01d1d | 215 | personne_form_class = PersonneInscriptionForm if chercheur is None else PersonneForm |
a7b16ec9 EMS |
216 | self.chercheur = ChercheurForm(data=data, prefix='chercheur', instance=chercheur) |
217 | self.groupes = GroupesForm(data=data, prefix='chercheur', chercheur=chercheur) | |
92990258 | 218 | self.personne = personne_form_class(data=data, prefix='personne', instance=chercheur and chercheur.personne.utilisateur) |
a7b16ec9 EMS |
219 | self.publication1 = PublicationForm(data=data, prefix='publication1', instance=chercheur and chercheur.publication1) |
220 | self.publication2 = PublicationForm(data=data, prefix='publication2', instance=chercheur and chercheur.publication2) | |
221 | self.publication3 = PublicationForm(data=data, prefix='publication3', instance=chercheur and chercheur.publication3) | |
222 | self.publication4 = PublicationForm(data=data, prefix='publication4', instance=chercheur and chercheur.publication4) | |
223 | self.these = TheseForm(data=data, prefix='these', instance=chercheur and chercheur.these) | |
ee8b3a49 | 224 | self.expertises = ExpertiseFormSet(data=data, prefix='expertise', instance=chercheur) |
a7b16ec9 EMS |
225 | |
226 | @property | |
227 | def has_errors(self): | |
228 | return bool(self.chercheur.errors or self.personne.errors or self.groupes.errors or | |
229 | self.publication1.errors or self.publication2.errors or self.publication3.errors or | |
ee8b3a49 | 230 | self.publication4.errors or self.these.errors or self.expertises.errors) |
a7b16ec9 EMS |
231 | |
232 | def is_valid(self): | |
233 | return self.chercheur.is_valid() and self.personne.is_valid() and self.groupes.is_valid() and \ | |
234 | self.publication1.is_valid() and self.publication2.is_valid() and \ | |
235 | self.publication3.is_valid() and self.publication4.is_valid() and \ | |
ee8b3a49 | 236 | self.these.is_valid() and self.expertises.is_valid() |
a7b16ec9 EMS |
237 | |
238 | def save(self): | |
239 | if self.is_valid(): | |
240 | ||
241 | chercheur = self.chercheur.instance | |
242 | ||
243 | # Enregistrer d'abord les clés étrangères car on doit les stocker dans | |
244 | # l'objet chercheur. | |
245 | chercheur.personne = self.personne.save() | |
246 | if self.publication1.cleaned_data['titre']: | |
247 | chercheur.publication1 = self.publication1.save() | |
248 | if self.publication2.cleaned_data['titre']: | |
249 | chercheur.publication2 = self.publication2.save() | |
250 | if self.publication3.cleaned_data['titre']: | |
251 | chercheur.publication3 = self.publication3.save() | |
252 | if self.publication4.cleaned_data['titre']: | |
253 | chercheur.publication4 = self.publication4.save() | |
254 | chercheur.these = self.these.save() | |
a7b16ec9 EMS |
255 | |
256 | # Puis enregistrer le chercheur lui-même. | |
257 | self.chercheur.save() | |
258 | ||
259 | # Puis les many-to-many puisqu'on a besoin d'un id. | |
260 | self.groupes.chercheur = chercheur | |
261 | self.groupes.save() | |
3820b46e EMS |
262 | self.expertises.instance = chercheur |
263 | self.expertises.save() | |
5b9abc81 | 264 | |
13146d99 | 265 | class RepertoireSearchForm (forms.Form): |
f0692c02 | 266 | q = forms.CharField(required=False, label="Rechercher dans tous les champs") |
3efbacbe | 267 | nom = forms.CharField(required=False, label="Nom") |
0e9597af | 268 | domaine = forms.ModelChoiceField(queryset=Groupe.objects.all(), required=False, label="Domaine de recherche", empty_label="Tous") |
bc415771 EMS |
269 | groupe_recherche = forms.CharField(required=False, label="Groupe de recherche", |
270 | help_text="ou Laboratoire, ou Groupement inter-universitaire") | |
6bd49ff1 | 271 | statut = forms.ChoiceField(choices=(('','Tous'),)+STATUT_CHOICES+(('expert','Expert'),), required=False, label="Statut") |
f0692c02 | 272 | discipline = forms.ModelChoiceField(queryset=Discipline.objects.all(), required=False, label="Discipline", empty_label="Toutes") |
3eba0476 | 273 | pays = forms.ModelChoiceField(queryset=Pays.objects.all(), required=False, label="Pays", empty_label="Tous") |
bc415771 EMS |
274 | region = forms.ModelChoiceField(queryset=Region.objects.all(), required=False, label="Région", empty_label="Toutes", |
275 | 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 EMS |
276 | nord_sud = forms.ChoiceField(choices=(('', 'Tous'), ('Nord', 'Nord'), ('Sud', 'Sud')), required=False, label="Nord/Sud", |
277 | 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.") | |
c548d94a EMS |
278 | |
279 | def __init__(self, data=None, region=None): | |
280 | super(RepertoireSearchForm, self).__init__(data) | |
281 | if region: | |
282 | pays = self.fields['pays'] | |
283 | pays.queryset = pays.queryset.filter(region=region) | |
284 | ||
3efbacbe | 285 | def get_query_set(self): |
116db1fd | 286 | qs = Chercheur.objects.all() |
3efbacbe EMS |
287 | if self.is_valid(): |
288 | nom = self.cleaned_data['nom'] | |
289 | if nom: | |
116db1fd EMS |
290 | qs = qs.search_nom(nom) |
291 | domaine = self.cleaned_data["domaine"] | |
292 | if domaine: | |
293 | qs = qs.filter(groupes=domaine) | |
d087521a EMS |
294 | groupe_recherche = self.cleaned_data['groupe_recherche'] |
295 | if groupe_recherche: | |
116db1fd EMS |
296 | for word in groupe_recherche.split(): |
297 | qs = qs.filter(groupe_recherche__icontains=word) | |
298 | q = self.cleaned_data["q"] | |
299 | if q: | |
300 | qs = qs.search(q) | |
5212238e EMS |
301 | statut = self.cleaned_data["statut"] |
302 | if statut: | |
303 | if statut == "expert": | |
116db1fd | 304 | qs = qs.exclude(expertises=None) |
5212238e | 305 | else: |
116db1fd EMS |
306 | qs = qs.filter(statut=statut) |
307 | discipline = self.cleaned_data['discipline'] | |
308 | if discipline: | |
309 | qs = qs.filter_discipline(discipline) | |
310 | region = self.cleaned_data['region'] | |
311 | if region: | |
312 | qs = qs.filter_region(region) | |
62eece34 EMS |
313 | pays = self.cleaned_data["pays"] |
314 | if pays: | |
116db1fd | 315 | qs = qs.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays)) |
62eece34 EMS |
316 | nord_sud = self.cleaned_data['nord_sud'] |
317 | if nord_sud: | |
116db1fd EMS |
318 | qs = qs.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud)) |
319 | return qs | |
3efbacbe | 320 | |
0e9597af | 321 | class SendPasswordForm(forms.Form): |
89da853e | 322 | email = forms.EmailField(required=True, label="Adresse électronique") |
0e9597af AJ |
323 | def clean_email(self): |
324 | cleaned_data = self.cleaned_data | |
325 | email = cleaned_data.get("email") | |
326 | if email: | |
327 | try: | |
328 | Utilisateur.objects.get(courriel=email) | |
329 | except: | |
89da853e | 330 | raise forms.ValidationError("Cette adresse n'existe pas dans notre base de données.") |
e427f068 AJ |
331 | return email |
332 | ||
333 | class NewPasswordForm(forms.Form): | |
334 | password = forms.CharField(widget=forms.PasswordInput(), required=True, label="Mot de passe") | |
335 | password_repeat = forms.CharField(widget=forms.PasswordInput(), required=True, label="Confirmez mot de passe") | |
92990258 | 336 | |
e427f068 AJ |
337 | def clean_password_repeat(self): |
338 | cleaned_data = self.cleaned_data | |
339 | password = cleaned_data.get("password") | |
340 | password_repeat = cleaned_data.get("password_repeat") | |
341 | if password and password_repeat: | |
342 | if password != password_repeat: | |
343 | raise forms.ValidationError("Les mots de passe ne concordent pas") | |
344 | return password_repeat | |
0e9597af | 345 |