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
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')
18 def __unicode__ (self
):
22 db_table
= u
'discipline'
25 class SourceActualite(models
.Model
):
26 nom
= models
.CharField(max_length
=255)
27 url
= models
.CharField(max_length
=255)
29 def __unicode__(self
,):
30 return u
"%s" % self
.nom
32 class ActualiteManager(models
.Manager
):
34 def get_query_set(self
):
35 return ActualiteQuerySet(self
.model
)
37 def search(self
, text
):
38 return self
.get_query_set().search(text
)
40 class ActualiteQuerySet(models
.query
.QuerySet
):
42 def search(self
, text
):
43 return self
.filter(titre__icontains
=text
)
45 class Actualite(models
.Model
):
46 id = models
.AutoField(primary_key
=True, db_column
='id_actualite')
47 titre
= models
.CharField(max_length
=765, db_column
='titre_actualite')
48 texte
= models
.TextField(db_column
='texte_actualite')
49 url
= models
.CharField(max_length
=765, db_column
='url_actualite')
50 date
= models
.DateField(db_column
='date_actualite')
51 visible
= models
.BooleanField(db_column
='visible_actualite', default
= False)
52 ancienid
= models
.IntegerField(db_column
='ancienId_actualite', blank
= True, null
= True)
53 source
= models
.ForeignKey(SourceActualite
, blank
= True, null
= True)
55 objects
= ActualiteManager()
57 def __unicode__ (self
):
58 return "%s" % (self
.titre
)
61 db_table
= u
'actualite'
64 class Evenement(models
.Model
):
65 uid
= models
.CharField(max_length
= 255, default
= str(uuid
.uuid1()))
66 approuve
= models
.BooleanField(default
= False)
67 titre
= models
.CharField(max_length
=255)
68 discipline
= models
.ForeignKey('Discipline', related_name
= "discipline",
69 blank
= True, null
= True)
70 discipline_secondaire
= models
.ForeignKey('Discipline', related_name
= \
71 "discipline_secondaire",
73 "Discipline secondaire",
74 blank
= True, null
= True)
75 mots_cles
= models
.TextField('Mots-Clés', blank
= True, null
= True)
76 type = models
.CharField(max_length
= 255, choices
= \
77 (('Colloque', 'Colloque'),
78 ('Conférence', 'Conférence'),
79 ('Appel à contribution', 'Appel à contribution'),
80 ('Journée d\'étude', 'Journée d\'étude'),
83 fuseau
= TimeZoneField(verbose_name
= 'Fuseau horaire')
84 debut
= models
.DateTimeField(default
= datetime
.datetime
.now
)
85 fin
= models
.DateTimeField(default
= datetime
.datetime
.now
)
86 lieu
= models
.TextField()
87 description
= models
.TextField(blank
= True, null
= True)
89 contact
= models
.TextField(blank
= True, null
= True)
90 url
= models
.CharField(max_length
=255, blank
= True, null
= True)
92 def __unicode__(self
,):
93 return "[%s] %s" % (self
.uid
, self
.titre
)
95 def save(self
, *args
, **kwargs
):
96 """Sauvegarde l'objet dans django et le synchronise avec caldav s'il a été
99 super(Evenement
, self
).save(*args
, **kwargs
)
101 # methodes de commnunications avec CALDAV
103 """Retourne l'evenement django sous forme d'objet icalendar"""
104 cal
= vobject
.iCalendar()
107 # fournit son propre uid
108 if self
.uid
in [None, ""]:
109 self
.uid
= str(uuid
.uuid1())
111 cal
.vevent
.add('uid').value
= self
.uid
113 cal
.vevent
.add('summary').value
= self
.titre
115 if self
.mots_cles
is None:
118 kw
= self
.mots_cles
.split(",")
121 kw
.append(self
.discipline
.nom
)
122 kw
.append(self
.discipline_secondaire
.nom
)
126 kw
= [x
.strip() for x
in kw
if len(x
.strip()) > 0 and x
is not None]
128 cal
.vevent
.add('x-auf-keywords').value
= k
130 description
= self
.description
132 if len(self
.description
) > 0:
134 description
+= u
"Mots-clés: " + ", ".join(kw
)
136 cal
.vevent
.add('dtstart').value
= combine(self
.debut
, self
.fuseau
)
137 cal
.vevent
.add('dtend').value
= combine(self
.fin
, self
.fuseau
)
138 cal
.vevent
.add('created').value
= combine(datetime
.datetime
.now(), "UTC")
139 cal
.vevent
.add('dtstamp').value
= combine(datetime
.datetime
.now(), "UTC")
140 if len(description
) > 0:
141 cal
.vevent
.add('description').value
= description
142 if len(self
.contact
) > 0:
143 cal
.vevent
.add('contact').value
= self
.contact
144 if len(self
.url
) > 0:
145 cal
.vevent
.add('url').value
= self
.url
146 if len(self
.lieu
) > 0:
147 cal
.vevent
.add('location').value
= self
.lieu
150 def update_vevent(self
,):
151 """Essaie de créer l'évènement sur le serveur ical.
152 En cas de succès, l'évènement local devient donc inactif et approuvé"""
155 event
= self
.as_ical()
156 client
= caldav
.DAVClient(CALENDRIER_URL
)
157 cal
= caldav
.Calendar(client
, url
= CALENDRIER_URL
)
158 e
= caldav
.Event(client
, parent
= cal
, data
= event
.serialize(), id=self
.uid
)
161 self
.approuve
= False
163 def delete_vevent(self
,):
164 """Supprime l'evenement sur le serveur caldav"""
167 event
= self
.as_ical()
168 client
= caldav
.DAVClient(CALENDRIER_URL
)
169 cal
= caldav
.Calendar(client
, url
= CALENDRIER_URL
)
170 e
= cal
.event(self
.uid
)
172 except error
.NotFoundError
:
176 # Surcharge du comportement de suppression
177 # La méthode de connexion par signals est préférable à surcharger la méthode delete()
178 # car dans le cas de la suppression par lots, cell-ci n'est pas invoquée
179 def delete_vevent(sender
, instance
, *args
, **kwargs
):
180 instance
.delete_vevent()
182 pre_delete
.connect(delete_vevent
, sender
= Evenement
)
185 class ListSet(models
.Model
):
186 spec
= models
.CharField(primary_key
= True, max_length
= 255)
187 name
= models
.CharField(max_length
= 255)
188 server
= models
.CharField(max_length
= 255)
189 validated
= models
.BooleanField(default
= True)
191 def __unicode__(self
,):
194 class RecordManager(models
.Manager
):
196 def get_query_set(self
):
197 return RecordQuerySet(self
.model
)
199 def search(self
, text
):
200 return self
.get_query_set().search(text
)
202 class RecordQuerySet(models
.query
.QuerySet
):
204 def search(self
, text
):
209 score_parts
.append('title LIKE %s')
210 score_params
.append('%' + word
+ '%')
211 score_expr
= ' + '.join(score_parts
)
213 select
={'relevance': score_expr
},
214 select_params
=score_params
,
217 ).order_by('-relevance')
219 class Record(models
.Model
):
221 #fonctionnement interne
222 id = models
.AutoField(primary_key
= True)
223 server
= models
.CharField(max_length
= 255)
224 last_update
= models
.CharField(max_length
= 255)
225 last_checksum
= models
.CharField(max_length
= 255)
226 validated
= models
.BooleanField(default
= True)
229 title
= models
.TextField(null
= True, blank
= True)
230 creator
= models
.TextField(null
= True, blank
= True)
231 description
= models
.TextField(null
= True, blank
= True)
232 modified
= models
.CharField(max_length
= 255, null
= True, blank
= True)
233 identifier
= models
.CharField(max_length
= 255, null
= True, blank
= True, unique
= True)
234 uri
= models
.CharField(max_length
= 255, null
= True, blank
= True, unique
= True)
235 source
= models
.TextField(null
= True, blank
= True)
236 contributor
= models
.TextField(null
= True, blank
= True)
237 subject
= models
.TextField(null
= True, blank
= True)
238 publisher
= models
.TextField(null
= True, blank
= True)
239 type = models
.TextField(null
= True, blank
= True)
240 format
= models
.TextField(null
= True, blank
= True)
241 language
= models
.TextField(null
= True, blank
= True)
243 listsets
= models
.ManyToManyField(ListSet
, null
= True, blank
= True)
245 #SEP 2 (aucune données récoltées)
246 alt_title
= models
.TextField(null
= True, blank
= True)
247 abstract
= models
.TextField(null
= True, blank
= True)
248 creation
= models
.CharField(max_length
= 255, null
= True, blank
= True)
249 issued
= models
.CharField(max_length
= 255, null
= True, blank
= True)
250 isbn
= models
.TextField(null
= True, blank
= True)
251 orig_lang
= models
.TextField(null
= True, blank
= True)
253 # Metadata AUF multivaluées
254 disciplines
= models
.ManyToManyField(Discipline
)
255 thematiques
= models
.ManyToManyField(Thematique
)
256 pays
= models
.ManyToManyField(Pays
)
257 regions
= models
.ManyToManyField(Region
)
260 objects
= RecordManager()
262 def est_complet(self
,):
263 """teste si le record à toutes les données obligatoires"""
264 return self
.disciplines
.count() > 0 and \
265 self
.thematiques
.count() > 0 and \
266 self
.pays
.count() > 0 and \
267 self
.regions
.count() > 0
269 def __unicode__(self
):
270 return "[%s] %s" % (self
.server
, self
.title
)
272 class Serveur(models
.Model
):
273 """Identification d'un serveur d'ou proviennent les références"""
274 nom
= models
.CharField(primary_key
= True, max_length
= 255)
276 def __unicode__(self
,):
279 def conf_2_db(self
,):
280 for k
in RESOURCES
.keys():
281 s
, created
= Serveur
.objects
.get_or_create(nom
=k
)
285 class Profile(models
.Model
):
286 user
= models
.ForeignKey(User
, unique
=True)
287 serveurs
= models
.ManyToManyField(Serveur
, null
= True, blank
= True)
289 class HarvestLog(models
.Model
):
290 context
= models
.CharField(max_length
= 255)
291 name
= models
.CharField(max_length
= 255)
292 date
= models
.DateTimeField(auto_now
= True)
293 added
= models
.IntegerField(null
= True, blank
= True)
294 updated
= models
.IntegerField(null
= True, blank
= True)
295 processed
= models
.IntegerField(null
= True, blank
= True)
296 record
= models
.ForeignKey(Record
, null
= True, blank
= True)
300 logger
= HarvestLog()
301 if message
.has_key('record_id'):
302 message
['record'] = Record
.objects
.get(id=message
['record_id'])
303 del(message
['record_id'])
305 for k
,v
in message
.items():
306 setattr(logger
, k
, v
)