Optimisation de la requête des ressources valides
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / chercheurs / models.py
CommitLineData
932eef9a 1# -*- encoding: utf-8 -*-
92990258 2import hashlib
fdcf5874 3
693c606b 4from auf.django.references.models import *
43ed73e7 5from django.conf import settings
fdcf5874
EMS
6from django.contrib.auth.models import User
7from django.core.urlresolvers import reverse as url
932eef9a 8from django.db import models
a2c6bb72 9from django.db.models import Q
92990258 10from django.utils.encoding import smart_str
43ed73e7 11from django.utils.hashcompat import sha_constructor
0827a595 12from django.db.models.signals import post_save
5212238e 13from djangosphinx.models import SphinxSearch
fdcf5874
EMS
14
15from savoirs.models import Discipline, SEPManager, SEPSphinxQuerySet, SEPQuerySet, Search
932eef9a 16
13146d99 17GENRE_CHOICES = (('m', 'Homme'), ('f', 'Femme'))
932eef9a 18class Personne(models.Model):
ece89aca 19 user = models.OneToOneField(User, related_name="chercheur", verbose_name="utilisateur", null=True, blank=True)
595ab4d6 20 salutation = models.CharField(max_length=128, null=True, blank=True)
932eef9a 21 nom = models.CharField(max_length=255)
595ab4d6 22 prenom = models.CharField(max_length=128, verbose_name='prénom')
165da916
EMS
23 courriel = models.EmailField(max_length=128, verbose_name="courriel")
24 afficher_courriel = models.BooleanField(default=True)
595ab4d6 25 fonction = models.CharField(max_length=128, null=True, blank=True)
c18af6bd 26 date_naissance = models.DateField(null=True, blank=True)
595ab4d6 27 sousfonction = models.CharField(max_length=128, null=True, blank=True, verbose_name='sous-fonction')
0a379c77
EMS
28 telephone = models.CharField(max_length=32, null=True, blank=True, verbose_name='numéro de téléphone')
29 adresse_postale = models.TextField(blank=True)
932eef9a 30 genre = models.CharField(max_length=1, choices=GENRE_CHOICES)
595ab4d6 31 commentaire = models.TextField(verbose_name='commentaires', null=True, blank=True)
3e556e66 32 actif = models.BooleanField(editable=False, default=False)
932eef9a
AJ
33
34 def __unicode__(self):
35 return u"%s %s, %s" % (self.prenom, self.nom, self.courriel)
36
37 class Meta:
13ec4813 38 ordering = ["nom", "prenom"]
92990258 39
a00480ad
PP
40 def save(self, *args, **kwargs):
41
6adcf00f
PP
42 try:
43 old_instance = Personne.objects.get(pk=self.pk)
44 if self.courriel != old_instance.courriel:
45 try:
46 user = User.objects.get(email=old_instance.courriel)
47 user.email = self.courriel
48 user.save()
49 except User.DoesNotExist:
50 pass
51 except Personne.DoesNotExist:
52 pass
a00480ad
PP
53
54 super(Personne, self).save(*args, **kwargs)
55
120891b9
PP
56 def delete(self):
57 self.actif = False
58 self.save()
59
705013cb
EMS
60 @property
61 def civilite(self):
62 if self.genre == 'm':
63 return 'M.'
64 elif self.genre == 'f':
65 return 'Mme'
66 else:
67 return ''
68
bd93f955
PP
69 @property
70 def prenom_nom(self):
71 return u"%s %s" % (self.prenom, self.nom)
72
3a3d9c6f
EMS
73 def courriel_display(self):
74 return self.courriel.replace(u'@', u' (à) ')
75
0827a595
PP
76
77def change_personne_courriel(sender, **kwargs):
78 user = kwargs['instance']
79 try:
80 if user.chercheur:
81 if user.email != user.chercheur.courriel:
82 chercheur = user.chercheur
83 chercheur.courriel = user.email
84 chercheur.save()
85 except:
86 pass
87
88post_save.connect(change_personne_courriel, sender=User)
89
90
5212238e 91class ChercheurQuerySet(SEPQuerySet):
a2c6bb72 92
5212238e
EMS
93 def filter_groupe(self, groupe):
94 return self.filter(groupes=groupe)
95
96 def filter_pays(self, pays):
f41337c8
OL
97 """
98 Filtre sur un ou plusieurs pays.
99 """
100 if hasattr(pays, "__getitem__") or hasattr(pays, "__iter__"):
101 pays_ids = [p.id for p in pays]
102 return self.filter(Q(etablissement__pays__id__in=pays_ids) |
103 Q(etablissement_autre_pays__id__in=pays_ids))
104 else:
105 return self.filter(Q(etablissement__pays=pays) | Q(etablissement_autre_pays=pays))
5212238e
EMS
106
107 def filter_region(self, region):
108 return self.filter(Q(etablissement__pays__region=region) | Q(etablissement_autre_pays__region=region))
a2c6bb72 109
5212238e
EMS
110 def filter_nord_sud(self, nord_sud):
111 return self.filter(Q(etablissement__pays__nord_sud=nord_sud) | Q(etablissement_autre_pays__nord_sud=nord_sud))
116db1fd 112
5c9bae2d
OL
113 def filter_genre(self, genre):
114 return self.filter(genre=genre)
115
5212238e
EMS
116 def filter_statut(self, statut):
117 return self.filter(statut=statut)
118
119 def filter_expert(self):
120 return self.exclude(expertises=None)
121
230671ff
EMS
122 def filter_date_modification(self, min=None, max=None):
123 return self._filter_date('date_modification', min=min, max=max)
124
acd5cd8f 125 def order_by_nom(self, direction=''):
3648b3d6 126 return self.order_by(direction + 'nom', direction + 'prenom', '-date_modification')
acd5cd8f
EMS
127
128 def order_by_etablissement(self, direction=''):
1760a3e9
EMS
129 return self.extra(select=dict(etablissement_nom='IFNULL(ref_etablissement.nom, chercheurs_chercheur.etablissement_autre_nom)'),
130 order_by=[direction + 'etablissement_nom', '-date_modification'])
acd5cd8f
EMS
131
132 def order_by_pays(self, direction=''):
133 return self.extra(select=dict(
134 pays_etablissement='''(SELECT nom FROM ref_pays
135 WHERE ref_pays.code = IFNULL(ref_etablissement.pays, chercheurs_chercheur.etablissement_autre_pays))'''
136 ), order_by=[direction + 'pays_etablissement', '-date_modification'])
137
5212238e
EMS
138class ChercheurSphinxQuerySet(SEPSphinxQuerySet):
139
140 def __init__(self, model=None):
4134daa0 141 return SEPSphinxQuerySet.__init__(self, model=model, index='savoirsenpartage_chercheurs',
acd5cd8f 142 weights=dict(nom=2, prenom=2))
d9da735f 143
c1b134f8 144 def filter_region(self, region):
5212238e
EMS
145 return self.filter(region_id=region.id)
146
27effd89
PP
147 def filter_discipline(self, discipline):
148 return self.filter(discipline_id=discipline.id)
149
5212238e
EMS
150 def filter_groupe(self, groupe):
151 return self.filter(groupe_ids=groupe.id)
152
153 def filter_pays(self, pays):
f41337c8
OL
154 """
155 Filtre sur un ou plusieurs pays.
156 """
157 if hasattr(pays, "__getitem__") or hasattr(pays, "__iter__"):
158 return self.filter(pays_id__in=[p.id for p in pays])
159 else:
160 return self.filter(pays_id=pays.id)
c1b134f8 161
5212238e
EMS
162 NORD_SUD_CODES = {'Nord': 1, 'Sud': 2}
163 def filter_nord_sud(self, nord_sud):
164 return self.filter(nord_sud=self.NORD_SUD_CODES[nord_sud])
165
c6efde25
OL
166 GENRE_CODES = dict([(k, i+1) for i, (k, v) in enumerate(GENRE_CHOICES)])
167 def filter_genre(self, genre):
168 return self.filter(genre=self.GENRE_CODES[genre])
169
5212238e
EMS
170 STATUT_CODES = {'enseignant': 1, 'etudiant': 2, 'independant': 3}
171 def filter_statut(self, statut):
172 return self.filter(statut=self.STATUT_CODES[statut])
173
d9da735f
EMS
174 def filter_expert(self):
175 return self.filter(expert=True)
176
230671ff 177 def filter_date_modification(self, min=None, max=None):
7ed3ee8f 178 return self._filter_date('date_modification', min=min, max=max)
230671ff 179
acd5cd8f
EMS
180 def order_by_nom(self, direction=''):
181 return self.order_by(direction + 'nom_complet', '-date_modification')
182
183 def order_by_etablissement(self, direction=''):
184 return self.order_by(direction + 'etablissement_attr', '-date_modification')
185
186 def order_by_pays(self, direction=''):
187 return self.order_by(direction + 'pays_attr', '-date_modification')
188
5212238e 189class ChercheurManager(SEPManager):
a2c6bb72
EMS
190
191 def get_query_set(self):
695930dd 192 return ChercheurQuerySet(self.model).filter(actif=True)
a2c6bb72 193
5212238e
EMS
194 def get_sphinx_query_set(self):
195 return ChercheurSphinxQuerySet(self.model).order_by('-date_modification')
5212238e 196
116db1fd 197 def filter_region(self, region):
5212238e 198 """Le filtrage de chercheurs par région n'est pas une recherche texte."""
c1b134f8
EMS
199 return self.get_query_set().filter_region(region)
200
5212238e
EMS
201 def filter_groupe(self, groupe):
202 return self.get_query_set().filter_groupe(groupe)
bae03b7b 203
5212238e
EMS
204 def filter_pays(self, pays):
205 return self.get_query_set().filter_pays(pays)
206
207 def filter_nord_sud(self, nord_sud):
208 return self.get_query_set().filter_nord_sud(nord_sud)
209
a7bf6c5a 210 def filter_genre(self, genre):
634d46da 211 return self.get_query_set().filter_genre(genre=genre)
a7bf6c5a 212
5212238e
EMS
213 def filter_statut(self, statut):
214 return self.get_query_set().filter_statut(statut)
215
216 def filter_expert(self):
217 return self.get_query_set().filter_expert()
3efbacbe 218
230671ff
EMS
219 def filter_date_modification(self, min=None, max=None):
220 return self.get_query_set().filter_date_modification(min=min, max=max)
221
acd5cd8f
EMS
222 def order_by_nom(self, direction=''):
223 return self.get_query_set().order_by_nom(self, direction=direction)
224
225 def order_by_etablissement(self, direction=''):
226 return self.get_query_set().order_by_etablissement(self, direction=direction)
227
228 def order_by_pays(self, direction=''):
229 return self.get_query_set().order_by_pays(self, direction=direction)
230
4d42b353
PP
231class ChercheurInactifManager(SEPManager):
232
233 def get_query_set(self):
234 return ChercheurQuerySet(self.model).filter(actif=False)
235
236
bc15119b
EMS
237STATUT_CHOICES = (
238 ('enseignant', 'Enseignant-chercheur dans un établissement'),
239 ('etudiant', 'Étudiant-chercheur doctorant'),
240 ('independant', 'Chercheur indépendant docteur')
241)
242
13ec4813 243class Chercheur(Personne):
bc15119b
EMS
244 RESEAU_INSTITUTIONNEL_CHOICES = (
245 ('AFELSH', 'Association des facultés ou établissements de lettres et sciences humaines des universités d’expression française (AFELSH)'),
246 ('CIDEGEF', 'Conférence internationale des dirigeants des institutions d’enseignement supérieur et de recherche de gestion d’expression française (CIDEGEF)'),
247 ('RIFEFF', 'Réseau international francophone des établissements de formation de formateurs (RIFEFF)'),
248 ('CIDMEF', 'Conférence internationale des doyens des facultés de médecine d’expression française (CIDMEF)'),
249 ('CIDCDF', 'Conférence internationale des doyens des facultés de chirurgie dentaire d’expression totalement ou partiellement française (CIDCDF)'),
250 ('CIFDUF', 'Conférence internationale des facultés de droit ayant en commun l’usage du français (CIFDUF)'),
251 ('CIRUISEF', 'Conférence internationale des responsables des universités et institutions à dominante scientifique et technique d’expression française (CIRUISEF)'),
252 ('Theophraste', 'Réseau Théophraste (Réseau de centres francophones de formation au journalisme)'),
253 ('CIDPHARMEF', 'Conférence internationale des doyens des facultés de pharmacie d’expression française (CIDPHARMEF)'),
254 ('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)'),
255 ('CITEF', 'Conférence internationale des formations d’ingénieurs et techniciens d’expression française (CITEF)'),
256 ('APERAU', 'Association pour la promotion de l’enseignement et de la recherche en aménagement et urbanisme (APERAU)'),
257 )
258 INSTANCE_AUF_CHOICES = (
259 ('CASSOC', 'Conseil associatif'),
260 ('CA', "Conseil d'administration"),
261 ('CS', 'Conseil scientifique'),
2fcf82c9
EMS
262 ('CRE', "Commission régionale d'experts"),
263 ('CR', 'Conférence des recteurs'),
264 ('CNO', "Conseil national d'orientation")
bc15119b
EMS
265 )
266
00755d9b 267 nationalite = models.ForeignKey(Pays, null = True, db_column='nationalite', to_field='code',
0b0fbbd7 268 verbose_name = 'nationalité', related_name='nationalite')
a4e383ac 269 statut = models.CharField(max_length=36, choices=STATUT_CHOICES)
0b0fbbd7 270 diplome = models.CharField(max_length=255, null=True, verbose_name = 'diplôme le plus élevé')
73cabd75 271 etablissement = models.ForeignKey(Etablissement, db_column='etablissement', null=True, blank=True)
0b0fbbd7 272 etablissement_autre_nom = models.CharField(max_length=255, null=True, blank=True, verbose_name = 'autre établissement')
00755d9b 273 etablissement_autre_pays = models.ForeignKey(Pays, null = True, blank=True, db_column='etablissement_autre_pays',
0b0fbbd7
EMS
274 to_field='code', related_name='etablissement_autre_pays',
275 verbose_name = "pays de l'établissement")
0874e7d1 276 attestation = models.BooleanField()
73cabd75 277
0b0fbbd7 278 #Domaine
602e4194 279 thematique = models.ForeignKey(Thematique, db_column='thematique', blank=True, null=True, verbose_name='thematique')
518d0b44 280 mots_cles = models.CharField(max_length=255, null=True, verbose_name='mots-clés')
0b0fbbd7 281 discipline = models.ForeignKey(Discipline, db_column='discipline', null=True, verbose_name='Discipline')
518d0b44 282 theme_recherche = models.TextField(null=True, blank=True, verbose_name='thèmes de recherche')
35b0778c 283 equipe_recherche = models.CharField(max_length=255, blank=True, verbose_name='équipe de recherche')
219710da
EMS
284 url_site_web = models.URLField(max_length=255, null=True, blank=True,
285 verbose_name='adresse site Internet', verify_exists=False)
286 url_blog = models.URLField(max_length=255, null=True, blank=True, verbose_name='blog',
287 verify_exists=False)
3c576696
EMS
288 url_reseau_social = models.URLField(
289 max_length=255, null=True, blank=True, verbose_name='Réseau social',
219710da 290 verify_exists=False,
3c576696
EMS
291 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, ...)"
292 )
00755d9b 293
18407f73 294 groupes = models.ManyToManyField('Groupe', through='AdhesionGroupe', related_name='membres', blank=True, verbose_name='groupes')
932eef9a 295
a7b16ec9 296 # Activités en francophonie
121d9439 297 membre_instance_auf = models.NullBooleanField(verbose_name="est ou a déjà été membre d'une instance de l'AUF")
bc15119b
EMS
298 membre_instance_auf_nom = models.CharField(max_length=10, blank=True, choices=INSTANCE_AUF_CHOICES, verbose_name="instance")
299 membre_instance_auf_fonction = models.CharField(max_length=255, blank=True, verbose_name="fonction")
a7b16ec9 300 membre_instance_auf_dates = models.CharField(max_length=255, blank=True, verbose_name="dates")
121d9439 301 expert_oif = models.NullBooleanField(verbose_name="a été sollicité par l'OIF")
614b3269
EMS
302 expert_oif_details = models.CharField(max_length=255, blank=True, verbose_name="détails")
303 expert_oif_dates = models.CharField(max_length=255, blank=True, verbose_name="dates")
121d9439 304 membre_association_francophone = models.NullBooleanField(verbose_name="est membre d'une association francophone")
c073c94d 305 membre_association_francophone_details = models.CharField(max_length=255, blank=True, verbose_name="nom de l'association")
121d9439
EMS
306 membre_reseau_institutionnel = models.NullBooleanField(
307 verbose_name="est membre des instances d'un réseau institutionnel de l'AUF"
bc15119b
EMS
308 )
309 membre_reseau_institutionnel_nom = models.CharField(
310 max_length=15, choices=RESEAU_INSTITUTIONNEL_CHOICES, blank=True,
311 verbose_name="réseau institutionnel"
c073c94d 312 )
bc15119b
EMS
313 membre_reseau_institutionnel_fonction = models.CharField(
314 max_length=255, blank=True, verbose_name="fonction"
c073c94d
EMS
315 )
316 membre_reseau_institutionnel_dates = models.CharField(
317 max_length=255, blank=True, verbose_name="dates"
318 )
a7b16ec9 319
cb591fb3 320 # Expertises
121d9439 321 expertises_auf = models.NullBooleanField(verbose_name="est disposé à réaliser des expertises pour l'AUF")
cb591fb3 322
00755d9b
AJ
323 #meta
324 date_creation = models.DateField(auto_now_add=True, db_column='date_creation')
325 date_modification = models.DateField(auto_now=True, db_column='date_modification')
326
a2c6bb72
EMS
327 # Manager
328 objects = ChercheurManager()
c59dba82 329 all_objects = models.Manager()
a2c6bb72 330
588d6b93 331 def __unicode__(self):
13ec4813 332 return u"%s %s" % (self.nom.upper(), self.prenom.title())
e427f068 333
b57a7362
AJ
334 def statut_display(self):
335 for s in STATUT_CHOICES:
336 if self.statut == s[0]:
337 return s[1]
e427f068 338 return "-"
588d6b93 339
e4d01d1d
EMS
340 @property
341 def etablissement_display(self):
230671ff 342 return (self.nom_etablissement or '') + (', ' + self.pays.nom if self.pays else '')
e4d01d1d 343
d32102bd
EMS
344 @property
345 def pays(self):
346 return self.etablissement.pays if self.etablissement else self.etablissement_autre_pays
347
348 @property
d264c787
EMS
349 def nom_etablissement(self):
350 return self.etablissement.nom if self.etablissement else self.etablissement_autre_nom
351
352 @property
d32102bd 353 def region(self):
a716d071 354 return self.etablissement.region if self.etablissement else self.etablissement_autre_pays.region
d32102bd 355
5b55252d
PP
356 @property
357 def domaines_recherche(self):
358 return self.groupes.filter(groupe_chercheur=False)
359
360 @property
361 def groupes_chercheur(self):
362 return self.groupes.filter(groupe_chercheur=True)
363
71e3d741
EMS
364 def save(self):
365 """Si on a donné un établissement membre, on laisse tomber l'autre établissement."""
366 if self.etablissement:
367 self.etablissement_autre_nom = None
368 self.etablissement_autre_pays = None
369 super(Chercheur, self).save()
370
43ed73e7
EMS
371 def activation_token(self):
372 return sha_constructor(settings.SECRET_KEY + unicode(self.id)).hexdigest()[::2]
373
4b89a7df
EMS
374 def get_absolute_url(self):
375 return url('chercheur', kwargs={'id': self.id})
376
81fe476e
PP
377class ChercheurVoir(Chercheur):
378
379 class Meta:
380 proxy = True
429222f1
PP
381 verbose_name = 'chercheur (visualisation)'
382 verbose_name_plural = 'chercheur (visualisation)'
81fe476e 383
4d42b353
PP
384class ChercheurInactif(Chercheur):
385 objects = ChercheurInactifManager()
386
387 class Meta:
388 proxy = True
389 verbose_name = 'chercheur (inactif)'
390 verbose_name_plural = 'chercheur (inactif)'
391
00755d9b 392class Publication(models.Model):
595ab4d6 393 chercheur = models.ForeignKey(Chercheur, related_name='publications')
1df3737b 394 auteurs = models.CharField(max_length=255, blank=True, verbose_name='auteur(s)')
595ab4d6 395 titre = models.CharField(max_length=255, null=True, blank=True, verbose_name='titre')
1df3737b
EMS
396 revue = models.CharField(max_length=255, null=True, blank=True, verbose_name='revue')
397 annee = models.IntegerField(null=True, blank=True, verbose_name='année de publication')
398 editeur = models.CharField(max_length=255, null=True, blank=True, verbose_name='éditeur')
399 lieu_edition = models.CharField(max_length=255, null=True, blank=True, verbose_name="lieu d'édition")
400 nb_pages = models.CharField(max_length=255, null=True, blank=True, verbose_name='nombre de pages')
912e3c6c 401 url = models.URLField(max_length=255, null=True, blank=True, verbose_name='lien vers la publication', verify_exists=False)
6befc7c9 402 #Migration des publications depuis l'ancien repertoire de chercheurs
1df3737b 403 publication_affichage = models.TextField(verbose_name='publication', null=True, blank=True)
595ab4d6 404 actif = models.BooleanField(editable=False)
2a36714f
AJ
405
406 def __unicode__(self):
c59dba82 407 return self.titre or '(Aucun)'
2a36714f 408
3eb41a6d
EMS
409 def save(self):
410 if self.publication_affichage and (self.auteurs or self.titre or
411 self.revue or self.annee or
412 self.editeur or self.lieu_edition
413 or self.nb_pages or self.url):
414 self.publication_affichage = ''
415 super(Publication, self).save()
416
595ab4d6
EMS
417class These(models.Model):
418 chercheur = models.OneToOneField(Chercheur, primary_key=True)
14fd1c3f 419 titre = models.CharField(max_length=255, verbose_name='Titre')
595ab4d6 420 annee = models.IntegerField(verbose_name='Année de soutenance (réalisée ou prévue)')
14fd1c3f 421 directeur = models.CharField(max_length=255, verbose_name='Directeur')
595ab4d6
EMS
422 etablissement = models.CharField(max_length=255, verbose_name='Établissement de soutenance')
423 nb_pages = models.IntegerField(verbose_name='Nombre de pages', blank=True, null=True)
912e3c6c 424 url = models.URLField(max_length=255, verbose_name='Lien vers la publication', blank=True, verify_exists=False)
595ab4d6
EMS
425
426 def __unicode__(self):
427 return self.titre
428
2a36714f
AJ
429class Expertise(models.Model):
430 id = models.AutoField(primary_key=True, db_column='id')
ee8b3a49 431 chercheur = models.ForeignKey(Chercheur, related_name='expertises')
356cc691 432 nom = models.CharField(max_length=255, verbose_name = "Objet de l'expertise")
c1234eb8 433 date = models.CharField(max_length=255, blank=True)
ee8b3a49 434 lieu = models.CharField(max_length=255, null=True, blank=True, verbose_name = "Lieu de l'expertise")
b16bcbaf
EMS
435 organisme_demandeur = models.CharField(max_length=255, null=True, blank=True, verbose_name = 'Organisme demandeur')
436 organisme_demandeur_visible = models.BooleanField(verbose_name="Afficher l'organisme demandeur")
2a36714f 437 actif = models.BooleanField(editable = False, db_column='actif')
5b9abc81
AJ
438
439 def __unicode__(self):
440 return u"%s" % (self.nom)
2a36714f 441
057c3327
PP
442class GroupeManager(models.Manager):
443 def search(self, text):
444 return self.get_query_set().filter(nom__icontains=text)
445
446class GroupeChercheurManager(GroupeManager):
5b55252d
PP
447 def get_query_set(self):
448 return super(GroupeChercheurManager, self).get_query_set().filter(groupe_chercheur=True)
449
057c3327 450class DomaineRechercheManager(GroupeManager):
5b55252d
PP
451 def get_query_set(self):
452 return super(DomaineRechercheManager, self).get_query_set().filter(groupe_chercheur=False)
453
932eef9a
AJ
454class Groupe(models.Model):
455 id = models.AutoField(primary_key=True, db_column='id')
456 nom = models.CharField(max_length=255, db_column='nom')
00755d9b
AJ
457 url = models.URLField(max_length=255, null=True, blank=True,
458 verbose_name='Site web')
459 liste_diffusion = models.URLField(max_length=255, null=True, blank=True,
460 verbose_name='Liste de diffusion')
461 bulletin = models.URLField(max_length=255, null=True, blank=True,
462 verbose_name='Bulletin')
932eef9a 463 actif = models.BooleanField(editable = False, db_column='actif')
04985abd 464 groupe_chercheur = models.BooleanField(default=False, editable=False, verbose_name='Groupe de chercheur')
5b55252d 465
34d0147e 466 responsables = models.ManyToManyField(User, related_name='responsable_groupe', verbose_name='gestionnaire de communauté', blank=True)
cec3f8db 467
2094c7e5
PP
468 recherches = models.ManyToManyField(Search, related_name='recherche_groupe', verbose_name='recherches prédéfinies', blank=True)
469
0c0d997c 470 page_accueil = models.TextField(null=True, blank=True)
5b55252d 471
057c3327 472 objects = GroupeManager()
5b55252d
PP
473 groupe_chercheur_objects = GroupeChercheurManager()
474 domaine_recherche_objects = DomaineRechercheManager()
932eef9a 475
55ef8558 476 class Meta:
b803eb99 477 ordering = ['nom']
55ef8558
EMS
478 verbose_name = 'domaine de recherche'
479 verbose_name_plural = 'domaines de recherche'
480
932eef9a
AJ
481 def __unicode__(self):
482 return u"%s" % (self.nom)
5b55252d 483
bf2904f0
PP
484 def get_absolute_url(self):
485 return url('groupe_retrieve', kwargs={'id': self.id})
486
e7db286c
PP
487 def membres_actif(self):
488 return self.membership.filter(statut="accepte")
489
bf2904f0 490
5b55252d
PP
491class GroupeChercheur(Groupe):
492 objects = GroupeChercheurManager()
493
494 class Meta:
495 proxy = True
5c9d31cf
PP
496 verbose_name = 'communauté de chercheurs'
497 verbose_name_plural = 'communautés de chercheurs'
5b55252d 498
04985abd
PP
499 def save(self, *args, **kwargs):
500 self.groupe_chercheur = True
501 super(GroupeChercheur, self).save(*args, **kwargs)
502
5b55252d
PP
503class DomaineRecherche(Groupe):
504 objects = DomaineRechercheManager()
505
506 class Meta:
507 proxy = True
508 verbose_name = 'domaine de recherche'
509 verbose_name_plural = 'domaines de recherche'
510
04985abd
PP
511 def save(self, *args, **kwargs):
512 self.groupe_chercheur = False
513 super(DomaineRecherche, self).save(*args, **kwargs)
514
e548663a
PP
515CG_STATUT_CHOICES = (
516 ('nouveau', 'Nouveau'),
517 ('refuse', 'Refusé'),
518 ('accepte', 'Accepté'),
519 ('resilie', 'Résilié'),
520 ('exclus', 'Exclus'),
521)
dd70b25a 522
dca3ff65
PP
523class AdhesionCommunauteManager(GroupeManager):
524 def get_query_set(self):
525 return super(AdhesionCommunauteManager, self).get_query_set().filter(groupe__groupe_chercheur=True)
526
527class AdhesionDomaineRechercheManager(GroupeManager):
528 def get_query_set(self):
529 return super(AdhesionDomaineRechercheManager, self).get_query_set().filter(groupe__groupe_chercheur=False)
530
18407f73 531class AdhesionGroupe(models.Model):
73cabd75 532 id = models.AutoField(primary_key=True, db_column='id')
6d5279ff 533 chercheur = models.ForeignKey('Chercheur', db_column='chercheur')
0c0d997c 534 groupe = models.ForeignKey('Groupe', db_column='groupe', related_name="membership")
00755d9b
AJ
535 date_inscription = models.DateField(auto_now_add=True)
536 date_modification = models.DateField(auto_now=True)
dd70b25a 537 statut = models.CharField(max_length=100, choices=CG_STATUT_CHOICES, default='nouveau')
2a36714f 538
55ef8558 539 class Meta:
80da57fc
PP
540 verbose_name = 'adhésion aux groupes'
541 verbose_name_plural = 'adhésions aux groupes'
542 ordering = ['chercheur']
55ef8558 543
c3d51177
PP
544 def save(self, *args, **kwargs):
545 if self.pk:
546 old_instance = AdhesionGroupe.objects.get(pk=self.pk)
547 if old_instance.statut=='nouveau' and self.statut=='accepte':
548 from django.template.loader import get_template
549 from django.template import Context
550 from django.core.mail import send_mail
551 from django.conf import settings
552
553 template = get_template('chercheurs/groupe_confirmation.txt')
554 domain = settings.SITE_DOMAIN
555 message = template.render(Context(dict(groupe=self.groupe, domain=domain)))
556 send_mail('Votre inscription à Savoirs en partage', message, None, [self.chercheur.courriel])
557
558 super(AdhesionGroupe, self).save(*args, **kwargs)
559
2a36714f
AJ
560 def __unicode__(self):
561 return u"%s - %s" % (self.chercheur, self.groupe)
fdcf5874 562
dca3ff65
PP
563class AdhesionCommunaute(AdhesionGroupe):
564 objects = AdhesionCommunauteManager()
565
566 class Meta:
567 proxy = True
568 verbose_name = 'adhésion aux communautés de chercheurs'
569 verbose_name_plural = 'adhésion aux communautés de chercheurs'
570
571class AdhesionDomaineRecherche(AdhesionGroupe):
572 objects = AdhesionDomaineRechercheManager()
573
574 class Meta:
575 proxy = True
576 verbose_name = 'adhésion aux domaines de recherche'
577 verbose_name_plural = 'adhésion aux domaines de recherche'
578
fdcf5874
EMS
579class ChercheurSearch(Search):
580 nom_chercheur = models.CharField(max_length=100, blank=True, verbose_name='nom')
5b55252d 581 domaine = models.ForeignKey(DomaineRecherche, blank=True, null=True, verbose_name='domaine de recherche')
35b0778c
PP
582 equipe_recherche = models.CharField(max_length=100, blank=True, null=True,
583 verbose_name='Équipe de recherche',
fdcf5874
EMS
584 help_text='ou Laboratoire, ou Groupement inter-universitaire')
585 statut = models.CharField(max_length=100, blank=True, choices=STATUT_CHOICES + (('expert', 'Expert'),))
586 pays = models.ForeignKey(Pays, blank=True, null=True)
587 nord_sud = models.CharField(max_length=4, blank=True, choices=(('Nord', 'Nord'), ('Sud', 'Sud')),
588 verbose_name='Nord/Sud',
589 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)")
590 activites_francophonie = models.CharField(
591 max_length=25, blank=True, verbose_name='activités en Francophonie',
592 choices=(('instance_auf', "Membre d'une instance de l'AUF"),
593 ('expert_oif', "Sollicité par l'OIF"),
594 ('association_francophone', "Membre d'une association ou d'une société savante francophone"),
595 ('reseau_institutionnel', "Membre des instances d'un réseau institutionnel de l'AUF"))
596 )
597 genre = models.CharField(max_length=1, blank=True, choices=GENRE_CHOICES)
598
599 class Meta:
600 verbose_name = 'recherche de chercheurs'
601 verbose_name_plural = 'recherches de chercheurs'
602
4b89a7df 603 def run(self, min_date=None, max_date=None):
fdcf5874
EMS
604 results = Chercheur.objects
605 if self.q:
606 results = results.search(self.q)
607 if self.nom_chercheur:
608 results = results.add_to_query('@(nom,prenom) ' + self.nom_chercheur)
35b0778c
PP
609 if self.equipe_recherche:
610 results = results.add_to_query('@equipe_recherche ' + self.equipe_recherche)
fdcf5874
EMS
611 if self.discipline:
612 results = results.filter_discipline(self.discipline)
613 if self.region:
614 results = results.filter_region(self.region)
615 if self.statut:
616 if self.statut == "expert":
617 results = results.filter_expert()
618 else:
619 results = results.filter_statut(self.statut)
620 if self.domaine:
621 results = results.filter_groupe(self.domaine)
622 if self.pays:
623 results = results.filter_pays(self.pays)
624 if self.nord_sud:
625 results = results.filter_nord_sud(self.nord_sud)
626 if self.genre:
627 results = results.filter_genre(self.genre)
628 if self.activites_francophonie == 'instance_auf':
629 results = results.filter(membre_instance_auf=True)
630 elif self.activites_francophonie == 'expert_oif':
631 results = results.filter(expert_oif=True)
632 elif self.activites_francophonie == 'association_francophone':
633 results = results.filter(membre_association_francophone=True)
634 elif self.activites_francophonie == 'reseau_institutionnel':
635 results = results.filter(membre_reseau_institutionnel=True)
4b89a7df
EMS
636 if min_date:
637 results = results.filter_date_modification(min=min_date)
638 if max_date:
639 results = results.filter_date_modification(max=max_date)
fdcf5874
EMS
640 return results.all()
641
642 def url(self):
643 qs = self.query_string()
644 return url('chercheurs') + ('?' + qs if qs else '')
da5bf7e9
EMS
645
646 def rss_url(self):
647 qs = self.query_string()
648 return url('rss_chercheurs') + ('?' + qs if qs else '')
4b89a7df
EMS
649
650 def get_email_alert_content(self, results):
651 content = ''
652 for chercheur in results:
653 content += u'- [%s %s](%s%s) \n' % (chercheur.nom.upper(),
654 chercheur.prenom,
655 settings.SITE_ROOT_URL,
656 chercheur.get_absolute_url())
657 content += u' %s\n\n' % chercheur.etablissement_display
658 return content
cdaadee3
PP
659
660class GroupeSearch(Search):
661
662 class Meta:
663 verbose_name = 'recherche de groupe'
664 verbose_name_plural = 'recherches de groupes'
665
666 def run(self):
3e04a423 667 results = Groupe.groupe_chercheur_objects
cdaadee3
PP
668 if self.q:
669 results = results.search(self.q)
670 return results.all()
671
672 #def url(self):
673 # qs = self.query_string()
674 # return url('groupes') + ('?' + qs if qs else '')
675
676 #def rss_url(self):
677 # qs = self.query_string()
678 # return url('rss_groupes') + ('?' + qs if qs else '')
2048049e
PP
679
680class Message(models.Model):
681
682 chercheur = models.ForeignKey('Chercheur', db_column='chercheur')
683 groupe = models.ForeignKey('Groupe', db_column='groupe')
684 titre = models.CharField(max_length=255)
685 contenu = models.TextField()
686
fd6352ea 687 date_creation = models.DateTimeField(auto_now_add=True, db_column='date_creation')
2048049e 688
bf2904f0
PP
689 class Meta:
690 ordering = ['-date_creation']
691
2048049e
PP
692 def __unicode__(self):
693 return u"%s - %s" % (self.chercheur, self.titre)
c8d6b979 694
bf2904f0
PP
695 def get_absolute_url(self):
696 return url('groupe_messages', kwargs={'id': self.groupe.id})
697
544dec4f
PP
698
699class AuthLDAP(models.Model):
700 username = models.CharField('utilisateur', max_length=255, unique=True)
701 ldap_hash = models.CharField('hash LDAP', max_length=255)
702 date_modification = models.DateTimeField(auto_now=True)
703
704 def __unicode__(self):
705 return self.username