ferme #503, rss agenda et intégration frontend
[auf_savoirs_en_partage_django.git] / auf_savoirs_en_partage / savoirs / models.py
1 # -*- encoding: utf-8 -*-
2 import simplejson, uuid, datetime, caldav, vobject, uuid
3 from django.contrib.auth.models import User
4 from django.db import models
5 from django.db.models.signals import pre_delete
6 from timezones.fields import TimeZoneField
7 from auf_savoirs_en_partage.backend_config import RESOURCES
8 from savoirs.globals import META
9 from settings import CALENDRIER_URL
10 from datamaster_modeles.models import Thematique, Pays, Region
11 from lib.calendrier import combine
12 from caldav.lib import error
13
14 class Discipline(models.Model):
15 id = models.IntegerField(primary_key=True, db_column='id_discipline')
16 nom = models.CharField(max_length=765, db_column='nom_discipline')
17
18 def __unicode__ (self):
19 return self.nom
20
21 class Meta:
22 db_table = u'discipline'
23 ordering = ["nom",]
24
25 class SourceActualite(models.Model):
26 nom = models.CharField(max_length=255)
27 url = models.CharField(max_length=255)
28
29 def __unicode__(self,):
30 return u"%s" % self.nom
31
32 class Actualite(models.Model):
33 id = models.AutoField(primary_key=True, db_column='id_actualite')
34 titre = models.CharField(max_length=765, db_column='titre_actualite')
35 texte = models.TextField(db_column='texte_actualite')
36 url = models.CharField(max_length=765, db_column='url_actualite')
37 date = models.DateField(db_column='date_actualite')
38 visible = models.BooleanField(db_column='visible_actualite', default = False)
39 ancienid = models.IntegerField(db_column='ancienId_actualite', blank = True, null = True)
40 source = models.ForeignKey(SourceActualite, blank = True, null = True)
41
42 def __unicode__ (self):
43 return "%s" % (self.titre)
44
45 class Meta:
46 db_table = u'actualite'
47 ordering = ["-date",]
48
49 class Evenement(models.Model):
50 uid = models.CharField(max_length = 255, default = None)
51 approuve = models.BooleanField(default = False)
52 titre = models.CharField(max_length=255)
53 discipline = models.ForeignKey('Discipline', related_name = "discipline",
54 blank = True, null = True)
55 discipline_secondaire = models.ForeignKey('Discipline', related_name = \
56 "discipline_secondaire",
57 verbose_name = \
58 "Discipline secondaire",
59 blank = True, null = True)
60 mots_cles = models.TextField('Mots-Clés', blank = True, null = True)
61 type = models.CharField(max_length = 255, choices = \
62 (('Colloque', 'Colloque'),
63 ('Conférence', 'Conférence'),
64 ('Appel à contribution', 'Appel à contribution'),
65 ('Journée d\'étude', 'Journée d\'étude'),
66 (None, 'Autre')
67 )) #TODO: choices
68 fuseau = TimeZoneField(verbose_name = 'Fuseau horaire')
69 debut = models.DateTimeField(default = datetime.datetime.now)
70 fin = models.DateTimeField(default = datetime.datetime.now)
71 lieu = models.TextField()
72 description = models.TextField(blank = True, null = True)
73 #fichiers = TODO?
74 contact = models.TextField(blank = True, null = True)
75 url = models.CharField(max_length=255, blank = True, null = True)
76
77 def __unicode__(self,):
78 return "[%s] %s" % (self.uid, self.titre)
79
80 def save(self, *args, **kwargs):
81 """Sauvegarde l'objet dans django et le synchronise avec caldav s'il a été
82 approuvé"""
83 self.update_vevent()
84 super(Evenement, self).save(*args, **kwargs)
85
86 # methodes de commnunications avec CALDAV
87 def as_ical(self,):
88 """Retourne l'evenement django sous forme d'objet icalendar"""
89 cal = vobject.iCalendar()
90 cal.add('vevent')
91
92 # fournit son propre uid
93 if self.uid in [None, ""]:
94 self.uid = str(uuid.uuid1())
95
96 cal.vevent.add('uid').value = self.uid
97
98 cal.vevent.add('summary').value = self.titre
99
100 if self.mots_cles is None:
101 kw = []
102 else:
103 kw = self.mots_cles.split(",")
104
105 try:
106 kw.append(self.discipline.nom)
107 kw.append(self.discipline_secondaire.nom)
108 kw.append(self.type)
109 except: pass
110
111 kw = [x.strip() for x in kw if len(x.strip()) > 0 and x is not None]
112 for k in kw:
113 cal.vevent.add('x-auf-keywords').value = k
114
115 description = self.description
116 if len(kw) > 0:
117 if len(self.description) > 0:
118 description += "\n"
119 description += u"Mots-clés: " + ", ".join(kw)
120
121 cal.vevent.add('dtstart').value = combine(self.debut, self.fuseau)
122 cal.vevent.add('dtend').value = combine(self.fin, self.fuseau)
123 cal.vevent.add('created').value = combine(datetime.datetime.now(), "UTC")
124 cal.vevent.add('dtstamp').value = combine(datetime.datetime.now(), "UTC")
125 if len(description) > 0:
126 cal.vevent.add('description').value = description
127 if len(self.contact) > 0:
128 cal.vevent.add('contact').value = self.contact
129 if len(self.url) > 0:
130 cal.vevent.add('url').value = self.url
131 if len(self.lieu) > 0:
132 cal.vevent.add('location').value = self.lieu
133 return cal
134
135 def update_vevent(self,):
136 """Essaie de créer l'évènement sur le serveur ical.
137 En cas de succès, l'évènement local devient donc inactif et approuvé"""
138 try:
139 if self.approuve:
140 event = self.as_ical()
141 client = caldav.DAVClient(CALENDRIER_URL)
142 cal = caldav.Calendar(client, url = CALENDRIER_URL)
143 e = caldav.Event(client, parent = cal, data = event.serialize(), id=self.uid)
144 e.save()
145 except:
146 self.approuve = False
147
148 def delete_vevent(self,):
149 """Supprime l'evenement sur le serveur caldav"""
150 try:
151 if self.approuve:
152 event = self.as_ical()
153 client = caldav.DAVClient(CALENDRIER_URL)
154 cal = caldav.Calendar(client, url = CALENDRIER_URL)
155 e = cal.event(self.uid)
156 e.delete()
157 except error.NotFoundError:
158 pass
159
160
161 # Surcharge du comportement de suppression
162 # La méthode de connexion par signals est préférable à surcharger la méthode delete()
163 # car dans le cas de la suppression par lots, cell-ci n'est pas invoquée
164 def delete_vevent(sender, instance, *args, **kwargs):
165 instance.delete_vevent()
166
167 pre_delete.connect(delete_vevent, sender = Evenement)
168
169
170 class ListSet(models.Model):
171 spec = models.CharField(primary_key = True, max_length = 255)
172 name = models.CharField(max_length = 255)
173 server = models.CharField(max_length = 255)
174 validated = models.BooleanField(default = True)
175
176 def __unicode__(self,):
177 return self.name
178
179 class Record(models.Model):
180
181 #fonctionnement interne
182 id = models.AutoField(primary_key = True)
183 server = models.CharField(max_length = 255)
184 last_update = models.CharField(max_length = 255)
185 last_checksum = models.CharField(max_length = 255)
186 validated = models.BooleanField(default = True)
187
188 #OAI
189 title = models.TextField(null = True, blank = True)
190 creator = models.TextField(null = True, blank = True)
191 description = models.TextField(null = True, blank = True)
192 modified = models.CharField(max_length = 255, null = True, blank = True)
193 identifier = models.CharField(max_length = 255, null = True, blank = True, unique = True)
194 uri = models.CharField(max_length = 255, null = True, blank = True, unique = True)
195 source = models.TextField(null = True, blank = True)
196 contributor = models.TextField(null = True, blank = True)
197 subject = models.TextField(null = True, blank = True)
198 publisher = models.TextField(null = True, blank = True)
199 type = models.TextField(null = True, blank = True)
200 format = models.TextField(null = True, blank = True)
201 language = models.TextField(null = True, blank = True)
202
203 listsets = models.ManyToManyField(ListSet, null = True, blank = True)
204
205 #SEP 2 (aucune données récoltées)
206 alt_title = models.TextField(null = True, blank = True)
207 abstract = models.TextField(null = True, blank = True)
208 creation = models.CharField(max_length = 255, null = True, blank = True)
209 issued = models.CharField(max_length = 255, null = True, blank = True)
210 isbn = models.TextField(null = True, blank = True)
211 orig_lang = models.TextField(null = True, blank = True)
212
213 # Metadata AUF multivaluées
214 disciplines = models.ManyToManyField(Discipline)
215 thematiques = models.ManyToManyField(Thematique)
216 pays = models.ManyToManyField(Pays)
217 regions = models.ManyToManyField(Region)
218
219 def est_complet(self,):
220 """teste si le record à toutes les données obligatoires"""
221 return self.disciplines.count() > 0 and \
222 self.thematiques.count() > 0 and \
223 self.pays.count() > 0 and \
224 self.regions.count() > 0
225
226 def __unicode__(self):
227 return "[%s] %s" % (self.server, self.title)
228
229 class Serveur(models.Model):
230 """Identification d'un serveur d'ou proviennent les références"""
231 nom = models.CharField(primary_key = True, max_length = 255)
232
233 def __unicode__(self,):
234 return self.nom
235
236 def conf_2_db(self,):
237 for k in RESOURCES.keys():
238 s, created = Serveur.objects.get_or_create(nom=k)
239 s.nom = k
240 s.save()
241
242 class Profile(models.Model):
243 user = models.ForeignKey(User, unique=True)
244 serveurs = models.ManyToManyField(Serveur, null = True, blank = True)
245
246 class HarvestLog(models.Model):
247 context = models.CharField(max_length = 255)
248 name = models.CharField(max_length = 255)
249 date = models.DateTimeField(auto_now = True)
250 added = models.IntegerField(null = True, blank = True)
251 updated = models.IntegerField(null = True, blank = True)
252 processed = models.IntegerField(null = True, blank = True)
253 record = models.ForeignKey(Record, null = True, blank = True)
254
255 @staticmethod
256 def add(message):
257 logger = HarvestLog()
258 if message.has_key('record_id'):
259 message['record'] = Record.objects.get(id=message['record_id'])
260 del(message['record_id'])
261
262 for k,v in message.items():
263 setattr(logger, k, v)
264 logger.save()