2b189e615edc4fa9b22a44f594419a36502aae1f
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / chercheurs / models.py
1 # -*- encoding: utf-8 -*-
2 import hashlib
3 from datamaster_modeles.models import *
4 from django.conf import settings
5 from django.db import models
6 from django.db.models import Q
7 from django.utils.encoding import smart_str
8 from django.utils.hashcompat import sha_constructor
9 from djangosphinx.models import SphinxSearch
10 from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySet
11
12 GENRE_CHOICES = (('m', 'Homme'), ('f', 'Femme'))
13 class Personne(models.Model):
14 salutation = models.CharField(max_length=128, null=True, blank=True)
15 nom = models.CharField(max_length=255)
16 prenom = models.CharField(max_length=128, verbose_name='prénom')
17 courriel = models.EmailField(max_length=128, verbose_name="adresse électronique")
18 fonction = models.CharField(max_length=128, null=True, blank=True)
19 date_naissance = models.DateField(null=True, blank=True)
20 sousfonction = models.CharField(max_length=128, null=True, blank=True, verbose_name='sous-fonction')
21 mobile = models.CharField(max_length=32, null=True, blank=True, verbose_name='numéro de téléphone portable')
22 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
23 commentaire = models.TextField(verbose_name='commentaires', null=True, blank=True)
24 actif = models.BooleanField(editable=False, default=True)
25
26 def __unicode__(self):
27 return u"%s %s, %s" % (self.prenom, self.nom, self.courriel)
28
29 class Meta:
30 ordering = ["nom", "prenom"]
31
32 class ChercheurQuerySet(SEPQuerySet):
33
34 def filter_groupe(self, groupe):
35 return self.filter(groupes=groupe)
36
37 def filter_pays(self, pays):
38 return self.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
39
40 def filter_region(self, region):
41 return self.filter(Q(etablissement__pays__region=region) | Q(etablissement_autre_pays__region=region))
42
43 def filter_nord_sud(self, nord_sud):
44 return self.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud))
45
46 def filter_statut(self, statut):
47 return self.filter(statut=statut)
48
49 def filter_expert(self):
50 return self.exclude(expertises=None)
51
52 def order_by_nom(self, direction=''):
53 return self.order_by(direction + 'nom', direction + 'prenom', '-date_modification')
54
55 def order_by_etablissement(self, direction=''):
56 return self.extra(select=dict(nom_etablissement='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
57 order_by=[direction + 'nom_etablissement', '-date_modification'])
58
59 def order_by_pays(self, direction=''):
60 return self.extra(select=dict(
61 pays_etablissement='''(SELECT nom FROM ref_pays
62 WHERE ref_pays.code = IFNULL(ref_etablissement.pays, chercheurs_chercheur.etablissement_autre_pays))'''
63 ), order_by=[direction + 'pays_etablissement', '-date_modification'])
64
65 class ChercheurSphinxQuerySet(SEPSphinxQuerySet):
66
67 def __init__(self, model=None):
68 return SEPSphinxQuerySet.__init__(self, model=model, index='savoirsenpartage_chercheurs',
69 weights=dict(nom=2, prenom=2))
70
71 def filter_region(self, region):
72 return self.filter(region_id=region.id)
73
74 def filter_groupe(self, groupe):
75 return self.filter(groupe_ids=groupe.id)
76
77 def filter_pays(self, pays):
78 return self.filter(pays_id=pays.id)
79
80 NORD_SUD_CODES = {'Nord': 1, 'Sud': 2}
81 def filter_nord_sud(self, nord_sud):
82 return self.filter(nord_sud=self.NORD_SUD_CODES[nord_sud])
83
84 STATUT_CODES = {'enseignant': 1, 'etudiant': 2, 'independant': 3}
85 def filter_statut(self, statut):
86 return self.filter(statut=self.STATUT_CODES[statut])
87
88 def filter_expert(self):
89 return self.filter(expert=True)
90
91 def order_by_nom(self, direction=''):
92 return self.order_by(direction + 'nom_complet', '-date_modification')
93
94 def order_by_etablissement(self, direction=''):
95 return self.order_by(direction + 'etablissement_attr', '-date_modification')
96
97 def order_by_pays(self, direction=''):
98 return self.order_by(direction + 'pays_attr', '-date_modification')
99
100 class ChercheurManager(SEPManager):
101
102 def get_query_set(self):
103 return ChercheurQuerySet(self.model).filter(actif=True)
104
105 def get_sphinx_query_set(self):
106 return ChercheurSphinxQuerySet(self.model).order_by('-date_modification')
107
108 def filter_region(self, region):
109 """Le filtrage de chercheurs par région n'est pas une recherche texte."""
110 return self.get_query_set().filter_region(region)
111
112 def filter_groupe(self, groupe):
113 return self.get_query_set().filter_groupe(groupe)
114
115 def filter_pays(self, pays):
116 return self.get_query_set().filter_pays(pays)
117
118 def filter_nord_sud(self, nord_sud):
119 return self.get_query_set().filter_nord_sud(nord_sud)
120
121 def filter_statut(self, statut):
122 return self.get_query_set().filter_statut(statut)
123
124 def filter_expert(self):
125 return self.get_query_set().filter_expert()
126
127 def order_by_nom(self, direction=''):
128 return self.get_query_set().order_by_nom(self, direction=direction)
129
130 def order_by_etablissement(self, direction=''):
131 return self.get_query_set().order_by_etablissement(self, direction=direction)
132
133 def order_by_pays(self, direction=''):
134 return self.get_query_set().order_by_pays(self, direction=direction)
135
136 STATUT_CHOICES = (
137 ('enseignant', 'Enseignant-chercheur dans un établissement'),
138 ('etudiant', 'Étudiant-chercheur doctorant'),
139 ('independant', 'Chercheur indépendant docteur')
140 )
141
142 class Chercheur(Personne):
143 RESEAU_INSTITUTIONNEL_CHOICES = (
144 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
145 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
146 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
147 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
148 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
149 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
150 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
151 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
152 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
153 ('CIDEFA', 'Conférence internationale des directeurs et doyens des établissements supérieurs d’expression française des sciences de l’agriculture et de l’alimentation (CIDEFA)'),
154 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
155 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
156 )
157 INSTANCE_AUF_CHOICES = (
158 ('CASSOC', 'Conseil associatif'),
159 ('CA', "Conseil d'administration"),
160 ('CS', 'Conseil scientifique'),
161 ('CRE', "Commission régionale d'experts")
162 )
163
164 nationalite = models.ForeignKey(Pays, null = True, db_column='nationalite', to_field='code',
165 verbose_name = 'nationalité', related_name='nationalite')
166 statut = models.CharField(max_length=36, choices=STATUT_CHOICES)
167 diplome = models.CharField(max_length=255, null=True, verbose_name = 'diplôme le plus élevé')
168 etablissement = models.ForeignKey(Etablissement, db_column='etablissement', null=True, blank=True)
169 etablissement_autre_nom = models.CharField(max_length=255, null=True, blank=True, verbose_name = 'autre établissement')
170 etablissement_autre_pays = models.ForeignKey(Pays, null = True, blank=True, db_column='etablissement_autre_pays',
171 to_field='code', related_name='etablissement_autre_pays',
172 verbose_name = "pays de l'établissement")
173 attestation = models.BooleanField()
174
175 #Domaine
176 thematique = models.ForeignKey(Thematique, db_column='thematique', null=True, verbose_name='thematique')
177 mots_cles = models.CharField(max_length=255, null=True, verbose_name='mots-clés')
178 discipline = models.ForeignKey(Discipline, db_column='discipline', null=True, verbose_name='Discipline')
179 theme_recherche = models.TextField(null=True, blank=True, verbose_name='thèmes de recherche')
180 groupe_recherche = models.CharField(max_length=255, blank=True, verbose_name='groupe de recherche')
181 url_site_web = models.URLField(max_length=255, null=True, blank=True,
182 verbose_name='adresse site Internet', verify_exists=False)
183 url_blog = models.URLField(max_length=255, null=True, blank=True, verbose_name='blog',
184 verify_exists=False)
185 url_reseau_social = models.URLField(
186 max_length=255, null=True, blank=True, verbose_name='Réseau social',
187 verify_exists=False,
188 help_text=u"Vous pouvez indiquer ici l'adresse de votre page personnelle dans votre réseau social préféré (e.g. Facebook, LinkedIn, Twitter, Identica, ...)"
189 )
190
191 groupes = models.ManyToManyField('Groupe', through='ChercheurGroupe', blank=True, verbose_name='Domaines de recherche')
192
193 # Activités en francophonie
194 membre_instance_auf = models.BooleanField(default=False, verbose_name="est ou a déjà été membre d'une instance de l'AUF")
195 membre_instance_auf_nom = models.CharField(max_length=10, blank=True, choices=INSTANCE_AUF_CHOICES, verbose_name="instance")
196 membre_instance_auf_fonction = models.CharField(max_length=255, blank=True, verbose_name="fonction")
197 membre_instance_auf_dates = models.CharField(max_length=255, blank=True, verbose_name="dates")
198 expert_oif = models.BooleanField(default=False, verbose_name="a été sollicité par l'OIF")
199 expert_oif_details = models.CharField(max_length=255, blank=True, verbose_name="détails")
200 expert_oif_dates = models.CharField(max_length=255, blank=True, verbose_name="dates")
201 membre_association_francophone = models.BooleanField(default=False, verbose_name="est membre d'une association francophone")
202 membre_association_francophone_details = models.CharField(max_length=255, blank=True, verbose_name="nom de l'association")
203 membre_reseau_institutionnel = models.BooleanField(
204 default=False, verbose_name="est membre des instances d'un réseau institutionnel de l'AUF"
205 )
206 membre_reseau_institutionnel_nom = models.CharField(
207 max_length=15, choices=RESEAU_INSTITUTIONNEL_CHOICES, blank=True,
208 verbose_name="réseau institutionnel"
209 )
210 membre_reseau_institutionnel_fonction = models.CharField(
211 max_length=255, blank=True, verbose_name="fonction"
212 )
213 membre_reseau_institutionnel_dates = models.CharField(
214 max_length=255, blank=True, verbose_name="dates"
215 )
216
217 # Expertises
218 expertises_auf = models.BooleanField(verbose_name="est disposé à réaliser des expertises pour l'AUF")
219
220 #meta
221 date_creation = models.DateField(auto_now_add=True, db_column='date_creation')
222 date_modification = models.DateField(auto_now=True, db_column='date_modification')
223
224 # Manager
225 objects = ChercheurManager()
226 all_objects = models.Manager()
227
228 def __unicode__(self):
229 return u"%s %s" % (self.nom.upper(), self.prenom.title())
230
231 def statut_display(self):
232 for s in STATUT_CHOICES:
233 if self.statut == s[0]:
234 return s[1]
235 return "-"
236
237 @property
238 def etablissement_display(self):
239 if self.etablissement:
240 return self.etablissement.nom + ', ' + self.etablissement.pays.nom
241 else:
242 return self.etablissement_autre_nom + ', ' + self.etablissement_autre_pays.nom
243
244 @property
245 def pays(self):
246 return self.etablissement.pays if self.etablissement else self.etablissement_autre_pays
247
248 @property
249 def region(self):
250 return self.pays.region
251
252 def save(self):
253 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
254 if self.etablissement:
255 self.etablissement_autre_nom = None
256 self.etablissement_autre_pays = None
257 super(Chercheur, self).save()
258
259 def activation_token(self):
260 return sha_constructor(settings.SECRET_KEY + unicode(self.id)).hexdigest()[::2]
261
262 class Publication(models.Model):
263 chercheur = models.ForeignKey(Chercheur, related_name='publications')
264 auteurs = models.CharField(max_length=255, blank=True, verbose_name='auteur(s)')
265 titre = models.CharField(max_length=255, null=True, blank=True, verbose_name='titre')
266 revue = models.CharField(max_length=255, null=True, blank=True, verbose_name='revue')
267 annee = models.IntegerField(null=True, blank=True, verbose_name='année de publication')
268 editeur = models.CharField(max_length=255, null=True, blank=True, verbose_name='éditeur')
269 lieu_edition = models.CharField(max_length=255, null=True, blank=True, verbose_name="lieu d'édition")
270 nb_pages = models.CharField(max_length=255, null=True, blank=True, verbose_name='nombre de pages')
271 url = models.URLField(max_length=255, null=True, blank=True, verbose_name='lien vers la publication', verify_exists=False)
272 #Migration des publications depuis l'ancien repertoire de chercheurs
273 publication_affichage = models.TextField(verbose_name='publication', null=True, blank=True)
274 actif = models.BooleanField(editable=False)
275
276 def __unicode__(self):
277 return self.titre or '(Aucun)'
278
279 def save(self):
280 if self.publication_affichage and (self.auteurs or self.titre or
281 self.revue or self.annee or
282 self.editeur or self.lieu_edition
283 or self.nb_pages or self.url):
284 self.publication_affichage = ''
285 super(Publication, self).save()
286
287 class These(models.Model):
288 chercheur = models.OneToOneField(Chercheur, primary_key=True)
289 titre = models.CharField(max_length=255, verbose_name='Titre')
290 annee = models.IntegerField(verbose_name='Année de soutenance (réalisée ou prévue)')
291 directeur = models.CharField(max_length=255, verbose_name='Directeur')
292 etablissement = models.CharField(max_length=255, verbose_name='Établissement de soutenance')
293 nb_pages = models.IntegerField(verbose_name='Nombre de pages', blank=True, null=True)
294 url = models.URLField(max_length=255, verbose_name='Lien vers la publication', blank=True, verify_exists=False)
295
296 def __unicode__(self):
297 return self.titre
298
299 class Expertise(models.Model):
300 id = models.AutoField(primary_key=True, db_column='id')
301 chercheur = models.ForeignKey(Chercheur, related_name='expertises')
302 nom = models.CharField(max_length=255, null=True, blank=True, verbose_name = "Objet de l'expertise")
303 date = models.CharField(max_length=255, blank=True)
304 lieu = models.CharField(max_length=255, null=True, blank=True, verbose_name = "Lieu de l'expertise")
305 organisme_demandeur = models.CharField(max_length=255, null=True, blank=True, verbose_name = 'Organisme demandeur')
306 organisme_demandeur_visible = models.BooleanField(verbose_name="Afficher l'organisme demandeur")
307 actif = models.BooleanField(editable = False, db_column='actif')
308
309 def __unicode__(self):
310 return u"%s" % (self.nom)
311
312 class Groupe(models.Model):
313 id = models.AutoField(primary_key=True, db_column='id')
314 nom = models.CharField(max_length=255, db_column='nom')
315 url = models.URLField(max_length=255, null=True, blank=True,
316 verbose_name='Site web')
317 liste_diffusion = models.URLField(max_length=255, null=True, blank=True,
318 verbose_name='Liste de diffusion')
319 bulletin = models.URLField(max_length=255, null=True, blank=True,
320 verbose_name='Bulletin')
321 actif = models.BooleanField(editable = False, db_column='actif')
322
323 class Meta:
324 verbose_name = 'domaine de recherche'
325 verbose_name_plural = 'domaines de recherche'
326
327 def __unicode__(self):
328 return u"%s" % (self.nom)
329
330 class ChercheurGroupe(models.Model):
331 id = models.AutoField(primary_key=True, db_column='id')
332 chercheur = models.ForeignKey('Chercheur', db_column='chercheur', editable=False)
333 groupe = models.ForeignKey('Groupe', db_column='groupe')
334 date_inscription = models.DateField(auto_now_add=True)
335 date_modification = models.DateField(auto_now=True)
336 actif = models.BooleanField(editable = False, db_column='actif')
337
338 class Meta:
339 verbose_name = 'adhésion'
340
341 def __unicode__(self):
342 return u"%s - %s" % (self.chercheur, self.groupe)