Demander au chercheur s'il veut afficher son adresse courriel ou non.
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / savoirs / models.py
CommitLineData
92c7413b 1# -*- encoding: utf-8 -*-
db2999fa
EMS
2import caldav
3import datetime
4import feedparser
5import operator
6import os
7import pytz
8import random
9import uuid
10import vobject
5212238e 11from backend_config import RESOURCES
86983865 12from babel.dates import get_timezone_name
5212238e 13from caldav.lib import error
2b564f72
EMS
14from babel.dates import get_timezone_name
15from datamaster_modeles.models import Region, Pays, Thematique
6d885e0c 16from django.contrib.auth.models import User
d15017b2 17from django.db import models
15261361 18from django.db.models import Q, Max
b7a741ad 19from django.db.models.signals import pre_delete
5212238e 20from django.utils.encoding import smart_unicode
122c4c3d 21from djangosphinx.models import SphinxQuerySet, SearchError
da9020f3 22from savoirs.globals import META
74b087e5 23from settings import CALENDRIER_URL, SITE_ROOT_URL
5212238e
EMS
24
25# Fonctionnalités communes à tous les query sets
d15017b2 26
15261361
EMS
27class RandomQuerySetMixin(object):
28 """Mixin pour les modèles.
29
30 ORDER BY RAND() est très lent sous MySQL. On a besoin d'une autre
31 méthode pour récupérer des objets au hasard.
32 """
33
34 def random(self, n=1):
35 """Récupère aléatoirement un nombre donné d'objets."""
bae03b7b
EMS
36 count = self.count()
37 positions = random.sample(xrange(count), min(n, count))
38 return [self[p] for p in positions]
15261361 39
5212238e
EMS
40class SEPQuerySet(models.query.QuerySet, RandomQuerySetMixin):
41 pass
42
43class SEPSphinxQuerySet(SphinxQuerySet, RandomQuerySetMixin):
44 """Fonctionnalités communes aux query sets de Sphinx."""
45
46 def __init__(self, model=None, index=None, weights=None):
47 SphinxQuerySet.__init__(self, model=model, index=index,
48 mode='SPH_MATCH_EXTENDED2',
49 rankmode='SPH_RANK_PROXIMITY_BM25',
50 weights=weights)
51
52 def add_to_query(self, query):
53 """Ajoute une partie à la requête texte."""
6c78c673
EMS
54
55 # Assurons-nous qu'il y a un nombre pair de guillemets
56 if query.count('"') % 2 != 0:
57 # Sinon, on enlève le dernier (faut choisir...)
58 i = query.rindex('"')
59 query = query[:i] + query[i+1:]
60
5212238e
EMS
61 new_query = smart_unicode(self._query) + ' ' + query if self._query else query
62 return self.query(new_query)
63
64 def search(self, text):
65 """Recherche ``text`` dans tous les champs."""
66 return self.add_to_query('@* ' + text)
67
68 def filter_discipline(self, discipline):
69 """Par défaut, le filtre par discipline cherche le nom de la
70 discipline dans tous les champs."""
71 return self.search('"%s"' % discipline.nom)
72
73 def filter_region(self, region):
74 """Par défaut, le filtre par région cherche le nom de la région dans
75 tous les champs."""
76 return self.search('"%s"' % region.nom)
77
122c4c3d
EMS
78 def _get_sphinx_results(self):
79 try:
80 return SphinxQuerySet._get_sphinx_results(self)
81 except SearchError:
82 # Essayons d'enlever les caractères qui peuvent poser problème.
83 for c in '|!@()~/<=^$':
84 self._query = self._query.replace(c, ' ')
85 try:
86 return SphinxQuerySet._get_sphinx_results(self)
87 except SearchError:
88 # Ça ne marche toujours pas. Enlevons les guillemets et les
89 # tirets.
90 for c in '"-':
91 self._query = self._query.replace(c, ' ')
92 return SphinxQuerySet._get_sphinx_results(self)
93
5212238e
EMS
94class SEPManager(models.Manager):
95 """Lorsque les méthodes ``search``, ``filter_region`` et
96 ``filter_discipline`` sont appelées sur ce manager, le query set
97 Sphinx est créé, sinon, c'est le query set Django qui est créé."""
98
99 def query(self, query):
100 return self.get_sphinx_query_set().query(query)
101
102 def add_to_query(self, query):
103 return self.get_sphinx_query_set().add_to_query(query)
104
105 def search(self, text):
106 return self.get_sphinx_query_set().search(text)
107
108 def filter_region(self, region):
109 return self.get_sphinx_query_set().filter_region(region)
110
111 def filter_discipline(self, discipline):
112 return self.get_sphinx_query_set().filter_discipline(discipline)
113
114# Disciplines
115
d15017b2
CR
116class Discipline(models.Model):
117 id = models.IntegerField(primary_key=True, db_column='id_discipline')
118 nom = models.CharField(max_length=765, db_column='nom_discipline')
6ef8ead4
CR
119
120 def __unicode__ (self):
92c7413b 121 return self.nom
6ef8ead4 122
d15017b2
CR
123 class Meta:
124 db_table = u'discipline'
125 ordering = ["nom",]
126
5212238e
EMS
127# Actualités
128
79c398f6 129class SourceActualite(models.Model):
011804bb
EMS
130 TYPE_CHOICES = (
131 ('actu', 'Actualités'),
132 ('appels', "Appels d'offres"),
133 )
134
79c398f6 135 nom = models.CharField(max_length=255)
011804bb
EMS
136 url = models.CharField(max_length=255, verbose_name='URL', blank=True)
137 type = models.CharField(max_length=10, default='actu', choices=TYPE_CHOICES)
ccbc4363 138
db2999fa
EMS
139 class Meta:
140 verbose_name = u'fil RSS syndiqué'
141 verbose_name_plural = u'fils RSS syndiqués'
142
ccbc4363 143 def __unicode__(self,):
011804bb 144 return u"%s (%s)" % (self.nom, self.get_type_display())
79c398f6 145
db2999fa
EMS
146 def update(self):
147 """Mise à jour du fil RSS."""
011804bb
EMS
148 if not self.url:
149 return
db2999fa
EMS
150 feed = feedparser.parse(self.url)
151 for entry in feed.entries:
152 if Actualite.all_objects.filter(url=entry.link).count() == 0:
153 ts = entry.updated_parsed
154 date = datetime.date(ts.tm_year, ts.tm_mon, ts.tm_mday)
155 a = self.actualites.create(titre=entry.title,
156 texte=entry.summary_detail.value,
157 url=entry.link, date=date)
158
5212238e 159class ActualiteQuerySet(SEPQuerySet):
2f9c4d6c 160
5212238e
EMS
161 def filter_date(self, min=None, max=None):
162 qs = self
163 if min:
164 qs = qs.filter(date__gte=min)
165 if max:
166 qs = qs.filter(date__lte=max)
167 return qs
da44ce68 168
011804bb
EMS
169 def filter_type(self, type):
170 return self.filter(source__type=type)
171
5212238e 172class ActualiteSphinxQuerySet(SEPSphinxQuerySet):
c1b134f8 173
5212238e 174 def __init__(self, model=None):
4134daa0 175 SEPSphinxQuerySet.__init__(self, model=model, index='savoirsenpartage_actualites',
5212238e 176 weights=dict(titre=3))
c1b134f8 177
7fb6bd61
EMS
178 def filter_date(self, min=None, max=None):
179 qs = self
180 if min:
181 qs = qs.filter(date__gte=min.toordinal()+365)
182 if max:
183 qs = qs.filter(date__lte=max.toordinal()+365)
184 return qs
185
011804bb
EMS
186 TYPE_CODES = {'actu': 1, 'appels': 2}
187 def filter_type(self, type):
188 return self.filter(type=self.TYPE_CODES[type])
189
5212238e
EMS
190class ActualiteManager(SEPManager):
191
192 def get_query_set(self):
193 return ActualiteQuerySet(self.model).filter(visible=True)
2f9c4d6c 194
5212238e
EMS
195 def get_sphinx_query_set(self):
196 return ActualiteSphinxQuerySet(self.model).order_by('-date')
2f9c4d6c 197
5212238e
EMS
198 def filter_date(self, min=None, max=None):
199 return self.get_query_set().filter_date(min=min, max=max)
bae03b7b 200
011804bb
EMS
201 def filter_type(self, type):
202 return self.get_query_set().filter_type(type)
203
d15017b2 204class Actualite(models.Model):
4f262f90 205 id = models.AutoField(primary_key=True, db_column='id_actualite')
d15017b2
CR
206 titre = models.CharField(max_length=765, db_column='titre_actualite')
207 texte = models.TextField(db_column='texte_actualite')
208 url = models.CharField(max_length=765, db_column='url_actualite')
d15017b2 209 date = models.DateField(db_column='date_actualite')
db2999fa
EMS
210 visible = models.BooleanField(db_column='visible_actualite', default=False)
211 ancienid = models.IntegerField(db_column='ancienId_actualite', blank=True, null=True)
011804bb 212 source = models.ForeignKey(SourceActualite, related_name='actualites')
3a45eb64 213 disciplines = models.ManyToManyField(Discipline, blank=True, related_name="actualites")
a5f76eb4 214 regions = models.ManyToManyField(Region, blank=True, related_name="actualites", verbose_name='régions')
6ef8ead4 215
2f9c4d6c 216 objects = ActualiteManager()
c59dba82 217 all_objects = models.Manager()
2f9c4d6c 218
d15017b2
CR
219 class Meta:
220 db_table = u'actualite'
7020ea3d 221 ordering = ["-date"]
92c7413b 222
264a3210
EMS
223 def __unicode__ (self):
224 return "%s" % (self.titre)
225
226 def assigner_disciplines(self, disciplines):
227 self.disciplines.add(*disciplines)
228
229 def assigner_regions(self, regions):
230 self.regions.add(*regions)
231
5212238e 232# Agenda
4101cfc0 233
5212238e 234class EvenementQuerySet(SEPQuerySet):
4101cfc0 235
5212238e
EMS
236 def filter_type(self, type):
237 return self.filter(type=type)
c1b134f8 238
5212238e
EMS
239 def filter_debut(self, min=None, max=None):
240 qs = self
241 if min:
242 qs = qs.filter(debut__gte=min)
243 if max:
244 qs = qs.filter(debut__lt=max+datetime.timedelta(days=1))
245 return qs
c1b134f8 246
5212238e 247class EvenementSphinxQuerySet(SEPSphinxQuerySet):
4101cfc0 248
5212238e 249 def __init__(self, model=None):
4134daa0 250 SEPSphinxQuerySet.__init__(self, model=model, index='savoirsenpartage_evenements',
5212238e 251 weights=dict(titre=3))
116db1fd 252
5212238e
EMS
253 def filter_type(self, type):
254 return self.add_to_query('@type "%s"' % type)
255
256 def filter_debut(self, min=None, max=None):
7bbf600c 257 qs = self
5212238e
EMS
258 if min:
259 qs = qs.filter(debut__gte=min.toordinal()+365)
260 if max:
261 qs = qs.filter(debut__lte=max.toordinal()+365)
7bbf600c
EMS
262 return qs
263
5212238e 264class EvenementManager(SEPManager):
5212238e 265
5212238e
EMS
266 def get_query_set(self):
267 return EvenementQuerySet(self.model).filter(approuve=True)
268
269 def get_sphinx_query_set(self):
270 return EvenementSphinxQuerySet(self.model).order_by('-debut')
271
272 def filter_type(self, type):
273 return self.get_query_set().filter_type(type)
274
275 def filter_debut(self, min=None, max=None):
276 return self.get_query_set().filter_debut(min=min, max=max)
bae03b7b 277
1719bf4e 278def build_time_zone_choices(pays=None):
1719bf4e
EMS
279 timezones = pytz.country_timezones[pays] if pays else pytz.common_timezones
280 result = []
86983865 281 now = datetime.datetime.now()
1719bf4e 282 for tzname in timezones:
86983865
EMS
283 tz = pytz.timezone(tzname)
284 fr_name = get_timezone_name(tz, locale='fr_FR')
86983865
EMS
285 offset = tz.utcoffset(now)
286 seconds = offset.seconds + offset.days * 86400
287 (hours, minutes) = divmod(seconds // 60, 60)
288 offset_str = 'UTC%+d:%d' % (hours, minutes) if minutes else 'UTC%+d' % hours
1719bf4e
EMS
289 result.append((seconds, tzname, '%s - %s' % (offset_str, fr_name)))
290 result.sort()
291 return [(x[1], x[2]) for x in result]
86983865 292
92c7413b 293class Evenement(models.Model):
7bbf600c
EMS
294 TYPE_CHOICES = ((u'Colloque', u'Colloque'),
295 (u'Conférence', u'Conférence'),
296 (u'Appel à contribution', u'Appel à contribution'),
297 (u'Journée d\'étude', u'Journée d\'étude'),
ec81ec66 298 (u'Autre', u'Autre'))
86983865
EMS
299 TIME_ZONE_CHOICES = build_time_zone_choices()
300
74b087e5 301 uid = models.CharField(max_length=255, default=str(uuid.uuid1()))
a5f76eb4 302 approuve = models.BooleanField(default=False, verbose_name=u'approuvé')
92c7413b
CR
303 titre = models.CharField(max_length=255)
304 discipline = models.ForeignKey('Discipline', related_name = "discipline",
305 blank = True, null = True)
a5f76eb4
EMS
306 discipline_secondaire = models.ForeignKey('Discipline', related_name="discipline_secondaire",
307 verbose_name=u"discipline secondaire",
308 blank=True, null=True)
74b087e5 309 mots_cles = models.TextField('Mots-Clés', blank=True, null=True)
7bbf600c 310 type = models.CharField(max_length=255, choices=TYPE_CHOICES)
731ef7ab
EMS
311 adresse = models.TextField()
312 ville = models.CharField(max_length=100)
313 pays = models.ForeignKey(Pays, null=True, related_name='evenements')
74b087e5
EMS
314 debut = models.DateTimeField(default=datetime.datetime.now)
315 fin = models.DateTimeField(default=datetime.datetime.now)
86983865 316 fuseau = models.CharField(max_length=100, choices=TIME_ZONE_CHOICES, verbose_name='fuseau horaire')
74b087e5 317 description = models.TextField(blank=True, null=True)
731ef7ab
EMS
318 contact = models.TextField(null=True) # champ obsolète
319 prenom = models.CharField('prénom', max_length=100)
320 nom = models.CharField(max_length=100)
321 courriel = models.EmailField()
74b087e5
EMS
322 url = models.CharField(max_length=255, blank=True, null=True)
323 piece_jointe = models.FileField(upload_to='agenda/pj', blank=True, verbose_name='pièce jointe')
a5f76eb4 324 regions = models.ManyToManyField(Region, blank=True, related_name="evenements", verbose_name='régions')
92c7413b 325
4101cfc0 326 objects = EvenementManager()
c59dba82 327 all_objects = models.Manager()
4101cfc0
EMS
328
329 class Meta:
330 ordering = ['-debut']
331
020f79a9 332 def __unicode__(self,):
333 return "[%s] %s" % (self.uid, self.titre)
334
8dfe5efa
EMS
335 def duration_display(self):
336 delta = self.fin - self.debut
337 minutes, seconds = divmod(delta.seconds, 60)
338 hours, minutes = divmod(minutes, 60)
339 days = delta.days
340 parts = []
341 if days == 1:
342 parts.append('1 jour')
343 elif days > 1:
344 parts.append('%d jours' % days)
345 if hours == 1:
346 parts.append('1 heure')
347 elif hours > 1:
348 parts.append('%d heures' % hours)
349 if minutes == 1:
350 parts.append('1 minute')
351 elif minutes > 1:
352 parts.append('%d minutes' % minutes)
353 return ' '.join(parts)
354
27fe0d70
EMS
355 def piece_jointe_display(self):
356 return self.piece_jointe and os.path.basename(self.piece_jointe.name)
357
73309469 358 def clean(self):
359 from django.core.exceptions import ValidationError
360 if self.debut > self.fin:
361 raise ValidationError('La date de fin ne doit pas être antérieure à la date de début')
362
b7a741ad 363 def save(self, *args, **kwargs):
364 """Sauvegarde l'objet dans django et le synchronise avec caldav s'il a été
365 approuvé"""
731ef7ab 366 self.contact = '' # Vider ce champ obsolète à la première occasion...
73309469 367 self.clean()
b7a741ad 368 super(Evenement, self).save(*args, **kwargs)
acd5cd8f 369 self.update_vevent()
b7a741ad 370
371 # methodes de commnunications avec CALDAV
372 def as_ical(self,):
373 """Retourne l'evenement django sous forme d'objet icalendar"""
374 cal = vobject.iCalendar()
375 cal.add('vevent')
376
377 # fournit son propre uid
7f56d0d4 378 if self.uid in [None, ""]:
b7a741ad 379 self.uid = str(uuid.uuid1())
380
381 cal.vevent.add('uid').value = self.uid
382
383 cal.vevent.add('summary').value = self.titre
384
385 if self.mots_cles is None:
386 kw = []
387 else:
388 kw = self.mots_cles.split(",")
389
390 try:
391 kw.append(self.discipline.nom)
392 kw.append(self.discipline_secondaire.nom)
393 kw.append(self.type)
394 except: pass
395
79b400f0 396 kw = [x.strip() for x in kw if len(x.strip()) > 0 and x is not None]
b7a741ad 397 for k in kw:
398 cal.vevent.add('x-auf-keywords').value = k
399
400 description = self.description
401 if len(kw) > 0:
402 if len(self.description) > 0:
403 description += "\n"
028f548f 404 description += u"Mots-clés: " + ", ".join(kw)
b7a741ad 405
7f214e0f
EMS
406 cal.vevent.add('dtstart').value = combine(self.debut, pytz.timezone(self.fuseau))
407 cal.vevent.add('dtend').value = combine(self.fin, pytz.timezone(self.fuseau))
b7a741ad 408 cal.vevent.add('created').value = combine(datetime.datetime.now(), "UTC")
409 cal.vevent.add('dtstamp').value = combine(datetime.datetime.now(), "UTC")
79b400f0 410 if len(description) > 0:
b7a741ad 411 cal.vevent.add('description').value = description
412 if len(self.contact) > 0:
413 cal.vevent.add('contact').value = self.contact
414 if len(self.url) > 0:
415 cal.vevent.add('url').value = self.url
416 if len(self.lieu) > 0:
417 cal.vevent.add('location').value = self.lieu
74b087e5
EMS
418 if self.piece_jointe:
419 url = self.piece_jointe.url
420 if not url.startswith('http://'):
421 url = SITE_ROOT_URL + url
422 cal.vevent.add('attach').value = url
b7a741ad 423 return cal
424
425 def update_vevent(self,):
426 """Essaie de créer l'évènement sur le serveur ical.
427 En cas de succès, l'évènement local devient donc inactif et approuvé"""
428 try:
429 if self.approuve:
430 event = self.as_ical()
431 client = caldav.DAVClient(CALENDRIER_URL)
432 cal = caldav.Calendar(client, url = CALENDRIER_URL)
433 e = caldav.Event(client, parent = cal, data = event.serialize(), id=self.uid)
434 e.save()
435 except:
436 self.approuve = False
437
438 def delete_vevent(self,):
439 """Supprime l'evenement sur le serveur caldav"""
440 try:
441 if self.approuve:
442 event = self.as_ical()
443 client = caldav.DAVClient(CALENDRIER_URL)
444 cal = caldav.Calendar(client, url = CALENDRIER_URL)
445 e = cal.event(self.uid)
446 e.delete()
447 except error.NotFoundError:
448 pass
449
264a3210
EMS
450 def assigner_regions(self, regions):
451 self.regions.add(*regions)
452
453 def assigner_disciplines(self, disciplines):
454 if len(disciplines) == 1:
455 if self.discipline:
456 self.discipline_secondaire = disciplines[0]
457 else:
458 self.discipline = disciplines[0]
459 elif len(disciplines) >= 2:
460 self.discipline = disciplines[0]
461 self.discipline_secondaire = disciplines[1]
462
b7a741ad 463def delete_vevent(sender, instance, *args, **kwargs):
5212238e
EMS
464 # Surcharge du comportement de suppression
465 # La méthode de connexion par signals est préférable à surcharger la méthode delete()
466 # car dans le cas de la suppression par lots, cell-ci n'est pas invoquée
b7a741ad 467 instance.delete_vevent()
5212238e 468pre_delete.connect(delete_vevent, sender=Evenement)
b7a741ad 469
5212238e 470# Ressources
b7a741ad 471
d972b61d 472class ListSet(models.Model):
473 spec = models.CharField(primary_key = True, max_length = 255)
474 name = models.CharField(max_length = 255)
475 server = models.CharField(max_length = 255)
9eda5d6c 476 validated = models.BooleanField(default = True)
d972b61d 477
10d37e44 478 def __unicode__(self,):
479 return self.name
480
5212238e 481class RecordSphinxQuerySet(SEPSphinxQuerySet):
f153be1b 482
5212238e 483 def __init__(self, model=None):
4134daa0 484 SEPSphinxQuerySet.__init__(self, model=model, index='savoirsenpartage_ressources',
5212238e 485 weights=dict(title=3))
c1b134f8 486
5212238e 487class RecordManager(SEPManager):
f12cc7fb 488
5212238e 489 def get_query_set(self):
f153be1b
EMS
490 """Ne garder que les ressources validées et qui sont soit dans aucun
491 listset ou au moins dans un listset validé."""
5212238e
EMS
492 qs = SEPQuerySet(self.model)
493 qs = qs.filter(validated=True)
82f25472
EMS
494 qs = qs.filter(Q(listsets__isnull=True) | Q(listsets__validated=True))
495 return qs.distinct()
f153be1b 496
5212238e
EMS
497 def get_sphinx_query_set(self):
498 return RecordSphinxQuerySet(self.model)
77b0fac0 499
0cc5f772 500class Record(models.Model):
23b5b3d5 501
502 #fonctionnement interne
0cc5f772 503 id = models.AutoField(primary_key = True)
a5f76eb4 504 server = models.CharField(max_length = 255, verbose_name=u'serveur')
23b5b3d5 505 last_update = models.CharField(max_length = 255)
506 last_checksum = models.CharField(max_length = 255)
a5f76eb4 507 validated = models.BooleanField(default=True, verbose_name=u'validé')
23b5b3d5 508
509 #OAI
18dbd2cf
EMS
510 title = models.TextField(null=True, blank=True, verbose_name=u'titre')
511 creator = models.TextField(null=True, blank=True, verbose_name=u'auteur')
512 description = models.TextField(null=True, blank=True)
513 modified = models.CharField(max_length=255, null=True, blank=True)
23b5b3d5 514 identifier = models.CharField(max_length = 255, null = True, blank = True, unique = True)
515 uri = models.CharField(max_length = 255, null = True, blank = True, unique = True)
516 source = models.TextField(null = True, blank = True)
517 contributor = models.TextField(null = True, blank = True)
18dbd2cf 518 subject = models.TextField(null=True, blank=True, verbose_name='sujet')
23b5b3d5 519 publisher = models.TextField(null = True, blank = True)
520 type = models.TextField(null = True, blank = True)
521 format = models.TextField(null = True, blank = True)
522 language = models.TextField(null = True, blank = True)
da9020f3 523
c88d78dc 524 listsets = models.ManyToManyField(ListSet, null = True, blank = True)
d972b61d 525
da9020f3 526 #SEP 2 (aucune données récoltées)
23b5b3d5 527 alt_title = models.TextField(null = True, blank = True)
528 abstract = models.TextField(null = True, blank = True)
529 creation = models.CharField(max_length = 255, null = True, blank = True)
530 issued = models.CharField(max_length = 255, null = True, blank = True)
531 isbn = models.TextField(null = True, blank = True)
532 orig_lang = models.TextField(null = True, blank = True)
da9020f3 533
534 # Metadata AUF multivaluées
a342f93a
EMS
535 disciplines = models.ManyToManyField(Discipline, blank=True)
536 thematiques = models.ManyToManyField(Thematique, blank=True, verbose_name='thématiques')
537 pays = models.ManyToManyField(Pays, blank=True)
538 regions = models.ManyToManyField(Region, blank=True, verbose_name='régions')
0cc5f772 539
5212238e 540 # Managers
da44ce68 541 objects = RecordManager()
c59dba82 542 all_objects = models.Manager()
da44ce68 543
18dbd2cf
EMS
544 class Meta:
545 verbose_name = 'ressource'
546
264a3210
EMS
547 def __unicode__(self):
548 return "[%s] %s" % (self.server, self.title)
549
550 def getServeurURL(self):
f98ad449 551 """Retourne l'URL du serveur de provenance"""
552 return RESOURCES[self.server]['url']
553
264a3210 554 def est_complet(self):
6d885e0c 555 """teste si le record à toutes les données obligatoires"""
556 return self.disciplines.count() > 0 and \
557 self.thematiques.count() > 0 and \
558 self.pays.count() > 0 and \
559 self.regions.count() > 0
560
264a3210
EMS
561 def assigner_regions(self, regions):
562 self.regions.add(*regions)
da9020f3 563
264a3210
EMS
564 def assigner_disciplines(self, disciplines):
565 self.disciplines.add(*disciplines)
264a3210 566
6d885e0c 567class Serveur(models.Model):
b7a741ad 568 """Identification d'un serveur d'ou proviennent les références"""
6d885e0c 569 nom = models.CharField(primary_key = True, max_length = 255)
570
571 def __unicode__(self,):
572 return self.nom
573
574 def conf_2_db(self,):
575 for k in RESOURCES.keys():
576 s, created = Serveur.objects.get_or_create(nom=k)
577 s.nom = k
578 s.save()
579
580class Profile(models.Model):
581 user = models.ForeignKey(User, unique=True)
582 serveurs = models.ManyToManyField(Serveur, null = True, blank = True)
0cc5f772
CR
583
584class HarvestLog(models.Model):
23b5b3d5 585 context = models.CharField(max_length = 255)
586 name = models.CharField(max_length = 255)
0cc5f772 587 date = models.DateTimeField(auto_now = True)
23b5b3d5 588 added = models.IntegerField(null = True, blank = True)
589 updated = models.IntegerField(null = True, blank = True)
a85ba76e 590 processed = models.IntegerField(null = True, blank = True)
23b5b3d5 591 record = models.ForeignKey(Record, null = True, blank = True)
592
593 @staticmethod
594 def add(message):
595 logger = HarvestLog()
596 if message.has_key('record_id'):
d566e9c1 597 message['record'] = Record.all_objects.get(id=message['record_id'])
23b5b3d5 598 del(message['record_id'])
599
600 for k,v in message.items():
601 setattr(logger, k, v)
602 logger.save()
f09bc1c6
EMS
603
604# Pages statiques
605
606class PageStatique(models.Model):
20430b8a 607 id = models.CharField(max_length=32, primary_key=True)
f09bc1c6
EMS
608 titre = models.CharField(max_length=100)
609 contenu = models.TextField()
610
611 class Meta:
612 verbose_name_plural = 'pages statiques'