From: olivier <> Date: Mon, 15 Feb 2010 19:57:36 +0000 (+0000) Subject: fix OAI-PMH for new models and dublincore api X-Git-Tag: 1.1~533 X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=95c9b760aed1bbbbe566dd3e2f66b50c9bf4b103;p=telemeta.git fix OAI-PMH for new models and dublincore api --- diff --git a/telemeta/interop/oai.py b/telemeta/interop/oai.py index 64ae6d5b..8524b10e 100644 --- a/telemeta/interop/oai.py +++ b/telemeta/interop/oai.py @@ -54,7 +54,8 @@ class IDataSource(object): [(dublin core element, element value), ...], change time ) - or None if the record doesn't exist. + or None if the record doesn't exist. In case the id isn't wellformed + a BadArgumentError should be raised. The dublin core data must contain an 'identifier' element, which is the same as the id parameter.""" @@ -387,7 +388,11 @@ class Response(object): def get_record(self, id): """Append GetRecord result""" - record = self.datasource.get_record(id) + try: + record = self.datasource.get_record(id) + except BadArgumentError, e: + self.error('badArgument', e.message) + return if not record: self.error('idDoesNotExist') else: @@ -505,3 +510,6 @@ class Response(object): except AttributeError: # Apparently no free/unlink method in libxml2dom pass + +class BadArgumentError(Exception): + pass diff --git a/telemeta/interop/oaidatasource.py b/telemeta/interop/oaidatasource.py index d0ebc578..21a7eab9 100644 --- a/telemeta/interop/oaidatasource.py +++ b/telemeta/interop/oaidatasource.py @@ -29,7 +29,8 @@ # The fact that you are presently reading this means that you have had # knowledge of the CeCILL license and that you accept its terms. -from telemeta.models import MediaCollection, MediaItem, Revision +from telemeta.models import MediaCollection, MediaItem, Revision, dublincore +from telemeta.interop.oai import BadArgumentError from datetime import datetime class TelemetaOAIDataSource(object): @@ -43,41 +44,17 @@ class TelemetaOAIDataSource(object): except IndexError: return datetime.now() - def prepare_record(self, type, record): + def prepare_record(self, record): ctime = record.get_revision().time - dc = [] - _dc = record.to_dublincore().to_list() - for k, v in _dc: - if k == 'identifier': - dc.append((k, type + ':' + v)) # FIXME: type prepended by CREM model - else: - dc.append((k, v)) - return (dc, ctime) + return dublincore.express_resource(record).to_list(), ctime def get_record(self, id): """Return a specific record""" try: - type, id = id.split(':') - except ValueError: - return None - - #FIXME: search by code - if (type == 'collection'): - try: - record = MediaCollection.objects.get(id=id) - except MediaCollection.DoesNotExist: - return None - elif (type == 'item'): - try: - #FIXME: also search by old_code if code is not found - record = MediaItem.objects.get(id=id) - except MediaItem.DoesNotExist: - return None - else: - return None - - return self.prepare_record(type, record) - + record = dublincore.lookup_resource(id) + except dublincore.MalformedMediaIdentifier, e: + raise BadArgumentError(e.message) + return record and self.prepare_record(record) def count_records(self, from_time = None, until_time = None): """Must return the number of records between (optional) from and until change time.""" @@ -95,7 +72,7 @@ class TelemetaOAIDataSource(object): if (offset < nitems): set = query[offset:offset + limit] for record in set: - result.append(self.prepare_record('item', record)) + result.append(self.prepare_record(record)) limit -= len(set) offset = 0 else: @@ -105,6 +82,6 @@ class TelemetaOAIDataSource(object): query = MediaCollection.objects.by_change_time(from_time, until_time) set = query[offset:offset + limit] for record in set: - result.append(self.prepare_record('collection', record)) + result.append(self.prepare_record(record)) return result diff --git a/telemeta/models/core.py b/telemeta/models/core.py index 7db1716c..02c48b5b 100644 --- a/telemeta/models/core.py +++ b/telemeta/models/core.py @@ -432,13 +432,19 @@ class CoreQuerySet(EnhancedQuerySet): def _by_change_time(self, type, from_time = None, until_time = None): "Search between two revision dates" - where = ["element_type = '%s'" % type] + table = self.model._meta.db_table + where = [] if from_time: - where.append("time >= '%s'" % from_time.strftime('%Y-%m-%d %H:%M:%S')) + where.append("revisions.time >= '%s'" % from_time.strftime('%Y-%m-%d %H:%M:%S')) if until_time: - where.append("time <= '%s'" % until_time.strftime('%Y-%m-%d %H:%M:%S')) - return self.extra( - where = ["id IN (SELECT DISTINCT element_id FROM revisions WHERE %s)" % " AND ".join(where)]); + where.append("revisions.time <= '%s'" % until_time.strftime('%Y-%m-%d %H:%M:%S')) + + qs = self + if where: + where.extend(["revisions.element_type = '%s'" % type, "revisions.element_id = %s.id" % table]) + qs = qs.extra(where = [" AND ".join(where)], + tables = ['revisions']).distinct() + return qs class CoreManager(EnhancedManager): "Base class for all models managers" diff --git a/telemeta/models/dublincore.py b/telemeta/models/dublincore.py index b59cca8e..439e7c41 100644 --- a/telemeta/models/dublincore.py +++ b/telemeta/models/dublincore.py @@ -33,6 +33,7 @@ # Author: Olivier Guilyardi from telemeta.models.core import Duration +from telemeta.models.media import MediaItem, MediaCollection from django.conf import settings class Resource(object): @@ -106,8 +107,9 @@ class Element(object): @staticmethod def multiple(name, values, refinement=None): elements = [] - for v in values: - elements.append(Element(name, v, refinement)) + if values: + for v in values: + elements.append(Element(name, v, refinement)) return elements class Date(Element): @@ -211,7 +213,7 @@ def express_item(item): Element('publisher', settings.TELEMETA_ORGANIZATION), date, Date(item.collection.year_published, refinement='issued'), - Element.multiple('coverage', item.location.fullnames(), 'spatial'), + Element.multiple('coverage', item.location and item.location.fullnames(), 'spatial'), Element('coverage', item.location_comment, 'spatial'), Element('rights', item.collection.legal_rights, 'license'), Element('rights', media_access_rights(item.collection), 'accessRights'), @@ -224,4 +226,35 @@ def express_item(item): return resource - +def express_resource(res): + if isinstance(res, MediaItem): + return express_item(res) + elif isinstance(res, MediaCollection): + return express_collection(res) + + raise Exception("Invalid resource type") + +def lookup_resource(media_id): + try: + type, code = media_id.split(':', 1) + except ValueError: + raise MalformedMediaIdentifier("Media identifier must be in type:code format") + + if (type == 'collection'): + try: + return MediaCollection.objects.get(code=code) + except MediaCollection.DoesNotExist: + return None + elif (type == 'item'): + try: + return MediaItem.objects.get(code=code) + except MediaItem.DoesNotExist: + try: + return MediaItem.objects.get(old_code=code) + except MediaItem.DoesNotExist: + return None + else: + raise MalformedMediaIdentifier("No such type in media identifier: " + type) + +class MalformedMediaIdentifier(Exception): + pass