Commit | Line | Data |
---|---|---|
92c7413b | 1 | # -*- encoding: utf-8 -*- |
b7a741ad | 2 | import simplejson, uuid, datetime, caldav, vobject, uuid |
6d885e0c | 3 | from django.contrib.auth.models import User |
d15017b2 | 4 | from django.db import models |
b7a741ad | 5 | from django.db.models.signals import pre_delete |
92c7413b | 6 | from timezones.fields import TimeZoneField |
6d885e0c | 7 | from auf_savoirs_en_partage.backend_config import RESOURCES |
da9020f3 | 8 | from savoirs.globals import META |
b7a741ad | 9 | from settings import CALENDRIER_URL |
e3c3296e | 10 | from datamaster_modeles.models import Thematique, Pays, Region |
b7a741ad | 11 | from lib.calendrier import combine |
12 | from caldav.lib import error | |
d15017b2 CR |
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') | |
6ef8ead4 CR |
17 | |
18 | def __unicode__ (self): | |
92c7413b | 19 | return self.nom |
6ef8ead4 | 20 | |
d15017b2 CR |
21 | class Meta: |
22 | db_table = u'discipline' | |
23 | ordering = ["nom",] | |
24 | ||
79c398f6 CR |
25 | class SourceActualite(models.Model): |
26 | nom = models.CharField(max_length=255) | |
27 | url = models.CharField(max_length=255) | |
ccbc4363 | 28 | |
29 | def __unicode__(self,): | |
30 | return u"%s" % self.nom | |
79c398f6 | 31 | |
d15017b2 | 32 | class Actualite(models.Model): |
4f262f90 | 33 | id = models.AutoField(primary_key=True, db_column='id_actualite') |
d15017b2 CR |
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') | |
d15017b2 | 37 | date = models.DateField(db_column='date_actualite') |
f554ef70 | 38 | visible = models.BooleanField(db_column='visible_actualite', default = False) |
3b6456b0 | 39 | ancienid = models.IntegerField(db_column='ancienId_actualite', blank = True, null = True) |
ccbc4363 | 40 | source = models.ForeignKey(SourceActualite, blank = True, null = True) |
6ef8ead4 CR |
41 | |
42 | def __unicode__ (self): | |
f554ef70 | 43 | return "%s" % (self.titre) |
6ef8ead4 | 44 | |
d15017b2 CR |
45 | class Meta: |
46 | db_table = u'actualite' | |
47 | ordering = ["-date",] | |
92c7413b | 48 | |
92c7413b | 49 | class Evenement(models.Model): |
f82cd971 | 50 | uid = models.CharField(max_length = 255, default = None) |
92c7413b CR |
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 | ||
020f79a9 | 77 | def __unicode__(self,): |
78 | return "[%s] %s" % (self.uid, self.titre) | |
79 | ||
b7a741ad | 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 | |
7f56d0d4 | 93 | if self.uid in [None, ""]: |
b7a741ad | 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 | ||
79b400f0 | 111 | kw = [x.strip() for x in kw if len(x.strip()) > 0 and x is not None] |
b7a741ad | 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" | |
028f548f | 119 | description += u"Mots-clés: " + ", ".join(kw) |
b7a741ad | 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") | |
79b400f0 | 125 | if len(description) > 0: |
b7a741ad | 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 | ||
d972b61d | 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) | |
9eda5d6c | 174 | validated = models.BooleanField(default = True) |
d972b61d | 175 | |
10d37e44 | 176 | def __unicode__(self,): |
177 | return self.name | |
178 | ||
0cc5f772 | 179 | class Record(models.Model): |
23b5b3d5 | 180 | |
181 | #fonctionnement interne | |
0cc5f772 | 182 | id = models.AutoField(primary_key = True) |
23b5b3d5 | 183 | server = models.CharField(max_length = 255) |
184 | last_update = models.CharField(max_length = 255) | |
185 | last_checksum = models.CharField(max_length = 255) | |
c88d78dc | 186 | validated = models.BooleanField(default = True) |
23b5b3d5 | 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) | |
da9020f3 | 202 | |
c88d78dc | 203 | listsets = models.ManyToManyField(ListSet, null = True, blank = True) |
d972b61d | 204 | |
da9020f3 | 205 | #SEP 2 (aucune données récoltées) |
23b5b3d5 | 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) | |
da9020f3 | 212 | |
213 | # Metadata AUF multivaluées | |
214 | disciplines = models.ManyToManyField(Discipline) | |
215 | thematiques = models.ManyToManyField(Thematique) | |
e3c3296e | 216 | pays = models.ManyToManyField(Pays) |
217 | regions = models.ManyToManyField(Region) | |
0cc5f772 | 218 | |
6d885e0c | 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 | ||
0cc5f772 | 226 | def __unicode__(self): |
f554ef70 | 227 | return "[%s] %s" % (self.server, self.title) |
da9020f3 | 228 | |
6d885e0c | 229 | class Serveur(models.Model): |
b7a741ad | 230 | """Identification d'un serveur d'ou proviennent les références""" |
6d885e0c | 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) | |
0cc5f772 CR |
245 | |
246 | class HarvestLog(models.Model): | |
23b5b3d5 | 247 | context = models.CharField(max_length = 255) |
248 | name = models.CharField(max_length = 255) | |
0cc5f772 | 249 | date = models.DateTimeField(auto_now = True) |
23b5b3d5 | 250 | added = models.IntegerField(null = True, blank = True) |
251 | updated = models.IntegerField(null = True, blank = True) | |
a85ba76e | 252 | processed = models.IntegerField(null = True, blank = True) |
23b5b3d5 | 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() |