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 encode(self
, field
, data
):
13 if field
in META
.keys() and META
[field
]['type'] == 'array':
14 return self
.separator
.join(data
)
18 def decode(self
, field
, data
):
19 if field
in META
.keys() and META
[field
]['type'] == 'array':
20 return data
.split(self
.separator
)
25 # for r in Record.objects.all():
26 # for f in META.keys():
27 # json = getattr(r, f)
28 # if json is not None:
29 # normal = simplejson.loads(json)
30 # new = self.encode(f, normal)
36 Classe utilisée pour réaliser manipuler les données moisonnées.
39 encoder
= SEPEncoder()
41 ############################################################################
43 ############################################################################
46 """Recupérer la structure de métadonnées pour un record selon un `id`."""
47 r
= Record
.objects
.get(id = id)
49 for k
in META
.keys ():
53 meta
[k
] = self
.encoder
.decode(k
, v
)
56 # traitement spécial pour certaines clef de la structure
57 def listsets(self
, record
, value
):
59 # doit avoir un id pour créer les relations multivaluées
61 for set in [ls
for ls
in ListSet
.objects
.all() if ls
.spec
in value
]:
62 record
.listsets
.add(set)
64 def _update_record(self
, r
, metadata
):
65 for k
in metadata
.keys ():
67 method
= getattr(self
, k
)
68 method(r
, metadata
[k
])
70 setattr (r
, k
, self
.encoder
.encode(k
, metadata
[k
]))
72 r
.last_checksum
= hashlib
.md5(str(metadata
)).hexdigest()
73 r
.last_update
= datetime
.datetime
.today()
77 def _save (self
, metadata
):
79 self
._update_record(r
, metadata
)
82 def _modify (self
, id, metadata
):
83 r
= Record
.objects
.get(id = id)
85 # test si le fichier a été modifié
86 if hashlib
.md5(str(metadata
)).hexdigest() == r
.last_checksum
:
89 self
._update_record(r
, metadata
)
93 def _combine (self
, result_lists
, op
):
97 for list in result_lists
:
98 simple_sets
.append (set([x
[0] for x
in list]))
99 for (id, score
) in list:
100 if scores
.get (id) is None:
105 for s
in simple_sets
:
107 matches
= set(matches
) | s
109 if len (matches
) == 0:
112 matches
= set(matches
) & s
115 return [(x
, scores
[x
]) for x
in matches
]
118 def _text_search (self
, q
, fields
= None):
120 fields
= [x
for x
in META
.keys() if META
[x
].get("text_search", False)]
122 w
= re
.compile (r
'\W+', re
.U
)
127 if len(fields
)==1 and fields
[0] == "subject":
128 suffix
= " IN BOOLEAN MODE"
131 matches
.append ("MATCH(`%s`) AGAINST ('%s'%s)" % (k
, " ".join(words
), suffix
))
132 m
= "+".join (matches
)
134 q
= "SELECT id, (%s) AS score FROM savoirs_record \
135 WHERE (%s) AND validated = 1 \
136 HAVING score > 0 ORDER BY score DESC" % (m
, m
)
138 from django
.db
import connection
, transaction
139 cursor
= connection
.cursor()
141 rc
= cursor
.fetchall()
144 ############################################################################
146 ############################################################################
148 def add (self
, metadata
):
149 """Ajouter la ressource définie par `metadata`. Si on trouve une
150 ressource avec le même `identifier`, on le met a jour.
152 Retourne l'id de la ressource créée ou mise à jour.
154 added
= updated
= False
155 exists
= self
.search (q
= {URI
: metadata
[URI
]})
158 updated
= self
.update (int(id), metadata
)
161 id = self
._save (metadata
)
162 return {'record_id': id, 'added':added
, 'updated':updated
}
164 def delete (self
, id):
165 """Supprime la ressource identifiée par `id`.
167 r
= Record
.objects
.get(id = id)
170 def update (self
, id, metadata
):
171 """Met a jour la ressource identifiée par `id`, avec les données de
172 `metadata`. Une exception est levée si elle n'existe pas.
174 if self
.get (int(id)) is not None:
175 return self
._modify (int(id), metadata
)
177 raise Exception ("Objet inexistant")
181 """Recupérer la structure de métadonnées pour la ressource identifiée
182 par `id`. `id` peut être une liste si on veut les structures de
183 plusieurs ressources.
185 if isinstance (id, tuple) or isinstance (id, list):
191 rc
.append (self
._load (int(i
)))
193 rc
= self
._load (int(id))
197 """ Retourner la liste complète des ids des ressources."""
198 return [x
.id for x
in Record
.objects
.all()]
200 def search (self
, q
):
201 """Effectue une recherche multi-critères, en fonction du dictionnaire
202 `q`. Retourne une list d'`id`s uniquement. Les données pour chaque
203 résultat doivent être chargées ulterieurement.
210 ww
= q
.get ("q", "").strip()
212 s
= self
._text_search (ww
)
216 elif q
.get (URI
) is not None:
219 s
.append((Record
.objects
.get(uri__iexact
= q
.get(URI
)).id, 1))
224 creator
= q
.get ("creator", "")
225 title
= q
.get ("title", "")
226 description
= q
.get ("description", "")
227 subject
= q
.get ("subject", "")
229 if len (creator
) > 0:
230 sets
.append (self
._text_search (creator
, [CREATOR
, CONTRIBUTOR
]))
232 sets
.append (self
._text_search (title
, [TITLE
, ALT_TITLE
]))
233 if len (description
) > 0:
234 sets
.append (self
._text_search (description
, [DESCRIPTION
, ABSTRACT
]))
235 if len (subject
) > 0:
236 sets
.append (self
._text_search (subject
, [SUBJECT
,]))
237 rc
= self
._combine (sets
, q
.get ("operator", "|"))
238 rc
.sort (key
= operator
.itemgetter(1), reverse
= True)
241 rc
= [x
[0] for x
in rc
]