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