1 # -*- encoding: utf-8 -*-
2 import simplejson
, re
, datetime
, operator
, hashlib
3 from savoirs
.globals import *
4 from savoirs
.models
import Record
, ListSet
8 Classe permettant de d'encoder et de décoder les données moissonnées.
12 def propre(self
, str):
13 """Retoune une chaîne de caractère propre utf-8
14 Elle permet de corrgier les problèmes d'encodage."""
18 if str.__class__
.__name__
== 'str':
19 str = str.decode('utf-8')
21 return str.replace(u
"\x92", u
"´")
23 def encode(self
, field
, data
):
24 """Encode la structure de donnée moissonnée pour la BD"""
25 if field
in META
.keys() and META
[field
]['type'] == 'array':
26 return self
.separator
.join(data
)
30 def decode(self
, field
, data
):
31 """Décode la structure provenant de la BD"""
32 if field
in META
.keys() and META
[field
]['type'] == 'array':
33 return data
.split(self
.separator
)
38 """Applique sur tous les records, la fonction de corrections
39 de string sur les données moissonnées"""
40 for r
in Record
.objects
.all():
41 for k
in META
.keys ():
43 setattr (r
, k
, self
.propre(v
))
48 Classe utilisée pour réaliser manipuler les données moisonnées.
51 encoder
= SEPEncoder()
53 ############################################################################
55 ############################################################################
58 """Recupérer la structure de métadonnées pour un record selon un `id`."""
59 r
= Record
.objects
.get(id = id)
61 for k
in META
.keys ():
65 meta
[k
] = self
.encoder
.decode(k
, v
)
68 # traitement spécial pour certaines clef de la structure
69 def listsets(self
, record
, value
):
71 # doit avoir un id pour créer les relations multivaluées
74 for set in [ls
for ls
in ListSet
.objects
.all() if ls
.spec
in value
]:
75 record
.listsets
.add(set)
77 def _update_record(self
, r
, metadata
):
78 for k
in metadata
.keys ():
80 method
= getattr(self
, k
)
81 method(r
, metadata
[k
])
83 setattr (r
, k
, self
.encoder
.encode(k
, metadata
[k
]))
85 r
.last_checksum
= hashlib
.md5(str(metadata
)).hexdigest()
86 r
.last_update
= datetime
.datetime
.today()
88 # stocke des chaînes de caractères propre en BD en provenance
89 # des données moissonnées
90 for k
in META
.keys ():
92 setattr (r
, k
, self
.encoder
.propre(v
))
96 def _save (self
, metadata
):
98 self
._update_record(r
, metadata
)
101 def _modify (self
, id, metadata
):
102 r
= Record
.objects
.get(id = id)
104 # test si le fichier a été modifié
105 if hashlib
.md5(str(metadata
)).hexdigest() == r
.last_checksum
:
108 self
._update_record(r
, metadata
)
112 def _combine (self
, result_lists
, op
):
116 for list in result_lists
:
117 simple_sets
.append (set([x
[0] for x
in list]))
118 for (id, score
) in list:
119 if scores
.get (id) is None:
124 for s
in simple_sets
:
126 matches
= set(matches
) | s
128 if len (matches
) == 0:
131 matches
= set(matches
) & s
134 return [(x
, scores
[x
]) for x
in matches
]
137 def _text_search (self
, q
, fields
= None):
139 fields
= [x
for x
in META
.keys() if META
[x
].get("text_search", False)]
141 w
= re
.compile (r
'\W+', re
.U
)
146 if len(fields
)==1 and fields
[0] == "subject":
147 suffix
= " IN BOOLEAN MODE"
150 matches
.append ("MATCH(`%s`) AGAINST ('%s'%s)" % (k
, " ".join(words
), suffix
))
151 m
= "+".join (matches
)
153 q
= "SELECT r.id, (%s) AS score FROM savoirs_record AS r \
154 LEFT JOIN savoirs_record_listsets AS rl ON r.id = rl.record_id \
155 JOIN savoirs_listset AS l ON rl.listset_id = l.spec \
156 WHERE (%s) AND r.validated = 1 AND l.validated = 1 \
158 HAVING score > 0 ORDER BY score DESC" % (m
, m
)
160 from django
.db
import connection
, transaction
161 cursor
= connection
.cursor()
163 rc
= cursor
.fetchall()
166 ############################################################################
168 ############################################################################
170 def add (self
, metadata
):
171 """Ajouter la ressource définie par `metadata`. Si on trouve une
172 ressource avec le même `identifier`, on le met a jour.
174 Retourne l'id de la ressource créée ou mise à jour.
176 added
= updated
= False
177 exists
= self
.search (q
= {URI
: metadata
[URI
]})
180 updated
= self
.update (int(id), metadata
)
183 id = self
._save (metadata
)
184 return {'record_id': id, 'added':added
, 'updated':updated
}
186 def delete (self
, id):
187 """Supprime la ressource identifiée par `id`.
189 r
= Record
.objects
.get(id = id)
192 def update (self
, id, metadata
):
193 """Met a jour la ressource identifiée par `id`, avec les données de
194 `metadata`. Une exception est levée si elle n'existe pas.
196 if self
.get (int(id)) is not None:
197 return self
._modify (int(id), metadata
)
199 raise Exception ("Objet inexistant")
203 """Recupérer la structure de métadonnées pour la ressource identifiée
204 par `id`. `id` peut être une liste si on veut les structures de
205 plusieurs ressources.
207 if isinstance (id, tuple) or isinstance (id, list):
213 rc
.append (self
._load (int(i
)))
215 rc
= self
._load (int(id))
219 """ Retourner la liste complète des ids des ressources."""
220 return [x
.id for x
in Record
.objects
.all()]
222 def search (self
, q
):
223 """Effectue une recherche multi-critères, en fonction du dictionnaire
224 `q`. Retourne une list d'`id`s uniquement. Les données pour chaque
225 résultat doivent être chargées ulterieurement.
232 ww
= q
.get ("q", "").strip()
234 s
= self
._text_search (ww
)
238 elif q
.get (URI
) is not None:
241 s
.append((Record
.objects
.get(uri__iexact
= q
.get(URI
)).id, 1))
246 creator
= q
.get ("creator", "")
247 title
= q
.get ("title", "")
248 description
= q
.get ("description", "")
249 subject
= q
.get ("subject", "")
251 if len (creator
) > 0:
252 sets
.append (self
._text_search (creator
, [CREATOR
, CONTRIBUTOR
]))
254 sets
.append (self
._text_search (title
, [TITLE
, ALT_TITLE
]))
255 if len (description
) > 0:
256 sets
.append (self
._text_search (description
, [DESCRIPTION
, ABSTRACT
]))
257 if len (subject
) > 0:
258 sets
.append (self
._text_search (subject
, [SUBJECT
,]))
259 rc
= self
._combine (sets
, q
.get ("operator", "|"))
260 rc
.sort (key
= operator
.itemgetter(1), reverse
= True)
263 rc
= [x
[0] for x
in rc
]