-# -*- coding: utf-8 -*-
-# This file is part of Wolnelektury, licensed under GNU Affero GPLv3 or later.
-# Copyright © Fundacja Nowoczesna Polska. See NOTICE for more information.
+# This file is part of Wolne Lektury, licensed under GNU Affero GPLv3 or later.
+# Copyright © Fundacja Wolne Lektury. See NOTICE for more information.
#
-from oaipmh import server, common, metadata, error
-from catalogue.models import Book, Tag
-from api.models import Deleted
-from api.handlers import WL_BASE
-from librarian import WLURI
from datetime import datetime
from lxml import etree
+
from django.conf import settings
+from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.utils import timezone
+from oaipmh import server, common, metadata, error
+
+from api.handlers import WL_BASE
+from api.models import Deleted
+from catalogue.models import Book
+from librarian import WLURI
def make_time_naive(d):
return '{%s}%s' % (NS_DCTERMS, name)
-# WTF
class Catalogue(common.ResumptionOAIPMH):
TAG_CATEGORIES = ['author', 'epoch', 'kind', 'genre']
year_zero = timezone.make_aware(datetime(1990, 1, 1, 0, 0, 0), timezone.utc)
try:
- earliest_change = Book.objects.order_by('changed_at')[0].changed_at
+ earliest_change = Book.objects.filter(findable=True, preview=False).order_by('changed_at')[0].changed_at
except IndexError:
earliest_change = year_zero
try:
earliest_delete = \
- Deleted.objects.exclude(slug__exact=u'').order_by('deleted_at')[0].deleted_at
+ Deleted.objects.exclude(slug__exact='').order_by('deleted_at')[0].deleted_at
except IndexError:
earliest_delete = year_zero
self.earliest_datestamp = earliest_change if earliest_change <= earliest_delete else earliest_delete
- # @staticmethod
- # def metadata(book):
- # try:
- # xml = etree.parse(book.xml_file)
- # finally:
- # book.xml_file.close()
- # md = wl_dc_reader(xml)
- # m = md.getMap()
- # if book.parent:
- # m['isPartOf'] = [str(WLURI.from_slug(book.parent.slug))]
- # return m
-
- # WTF
- # def record_for_book(self, book, headers_only=False):
- # meta = None
- # identifier = self.slug_to_identifier(book.slug)
- # if isinstance(book, Book):
- # # setSpec = map(self.tag_to_setspec, book.tags.filter(category__in=self.TAG_CATEGORIES))
- # header = common.Header(identifier, make_time_naive(book.changed_at), [], False)
- # if not headers_only:
- # meta = common.Metadata(self.metadata(book))
- # about = None
- # elif isinstance(book, Deleted):
- # header = common.Header(identifier, make_time_naive(book.deleted_at), [], True)
- # if not headers_only:
- # meta = common.Metadata({})
- # about = None
- # if headers_only:
- # return header
- # return header, meta, about
-
- # def identify(self, **kw):
- # ident = common.Identify(
- # 'Wolne Lektury', # generate
- # '%s/oaipmh' % unicode(WL_BASE), # generate
- # '2.0', # version
- # [m[1] for m in settings.MANAGERS], # adminEmails
- # make_time_naive(self.earliest_datestamp), # earliest datestamp of any change
- # 'persistent', # deletedRecord
- # 'YYYY-MM-DDThh:mm:ssZ', # granularity
- # ['identity'], # compression
- # [] # descriptions
- # )
- # return ident
-
- # def books(self, tag, from_, until):
- # if tag:
- # # we do not support sets, since they are problematic for deleted books.
- # raise error.NoSetHierarchyError("Wolne Lektury does not support sets.")
- # # books = Book.tagged.with_all([tag])
- # else:
- # books = Book.objects.all()
- # deleted = Deleted.objects.exclude(slug__exact=u'')
- #
- # books = books.order_by('changed_at')
- # deleted = deleted.order_by('deleted_at')
- # if from_:
- # books = books.filter(changed_at__gte=from_)
- # deleted = deleted.filter(deleted_at__gte=from_)
- # if until:
- # books = books.filter(changed_at__lte=until)
- # deleted = deleted.filter(deleted_at__lte=until)
- # return list(books) + list(deleted)
+ @staticmethod
+ def metadata(book):
+ try:
+ xml = etree.parse(book.xml_file)
+ finally:
+ book.xml_file.close()
+ md = wl_dc_reader(xml)
+ m = md.getMap()
+ if book.parent:
+ m['isPartOf'] = [str(WLURI(book.parent.slug))]
+ return m
+
+ def record_for_book(self, book, headers_only=False):
+ meta = None
+ identifier = self.slug_to_identifier(book.slug)
+ if isinstance(book, Book):
+ # setSpec = map(self.tag_to_setspec, book.tags.filter(category__in=self.TAG_CATEGORIES))
+ header = common.Header(None, identifier, make_time_naive(book.changed_at), [], False)
+ if not headers_only:
+ meta = common.Metadata(None, self.metadata(book))
+ about = None
+ elif isinstance(book, Deleted):
+ header = common.Header(None, identifier, make_time_naive(book.deleted_at), [], True)
+ if not headers_only:
+ meta = common.Metadata(None, {})
+ about = None
+ else:
+ raise TypeError('Unknown book class')
+ if headers_only:
+ return header
+ return header, meta, about
+
+ def identify(self, **kw):
+ ident = common.Identify(
+ 'Wolne Lektury', # generate
+ '%s/oaipmh' % str(WL_BASE), # generate
+ '2.0', # version
+ [m[1] for m in settings.MANAGERS], # adminEmails
+ make_time_naive(self.earliest_datestamp), # earliest datestamp of any change
+ 'persistent', # deletedRecord
+ 'YYYY-MM-DDThh:mm:ssZ', # granularity
+ ['identity'], # compression
+ [] # descriptions
+ )
+ return ident
+
+ def books(self, tag, from_, until):
+ if tag:
+ # we do not support sets, since they are problematic for deleted books.
+ raise error.NoSetHierarchyError("Wolne Lektury does not support sets.")
+ # books = Book.tagged.with_all([tag])
+ else:
+ books = Book.objects.filter(findable=True, preview=False)
+ deleted = Deleted.objects.exclude(slug__exact='')
+
+ books = books.order_by('changed_at')
+ deleted = deleted.order_by('deleted_at')
+ if from_:
+ books = books.filter(changed_at__gte=from_)
+ deleted = deleted.filter(deleted_at__gte=from_)
+ if until:
+ books = books.filter(changed_at__lte=until)
+ deleted = deleted.filter(deleted_at__lte=until)
+ return list(books) + list(deleted)
# @staticmethod
# def tag_to_setspec(tag):
# return tag
# raise error.NoSetHierarchyError("Setspec should have two components: category:slug")
- # def getRecord(self, **kw):
- # """Returns (header, metadata, about) for given record."""
- # slug = self.identifier_to_slug(kw['identifier'])
- # try:
- # book = Book.objects.get(slug=slug)
- # return self.record_for_book(book)
- # except Book.DoesNotExist:
- # book_type = ContentType.objects.get_for_model(Book)
- # try:
- # deleted_book = Deleted.objects.get(content_type=book_type,
- # slug=slug)
- # except:
- # raise error.IdDoesNotExistError("No item for this identifier")
- # return self.record_for_book(deleted_book)
-
- # def validate_kw(self, kw):
- # if 'resumptionToken' in kw:
- # raise error.BadResumptionTokenError("No resumption token support at this point")
- # if 'metadataPrefix' in kw and not self.metadata_registry.hasWriter(kw['metadataPrefix']):
- # raise error.CannotDisseminateFormatError("This format is not supported")
-
- # def identifier_to_slug(self, ident):
- # return ident.split(':')[-1]
-
- # def slug_to_identifier(self, slug):
- # return self.oai_id % slug
-
- # def listIdentifiers(self, **kw):
- # self.validate_kw(kw)
- # records = [self.record_for_book(book, headers_only=True) for
- # book in self.books(None,
- # kw.get('from_', None),
- # kw.get('until', None))]
- # return records, None
-
- # def listRecords(self, **kw):
- # """
- # can get a resumptionToken kw.
- # returns result, token
- # """
- # self.validate_kw(kw)
- # records = [self.record_for_book(book) for
- # book in self.books(None,
- # kw.get('from_', None),
- # kw.get('until', None))]
- #
- # return records, None
-
- # def listMetadataFormats(self, **kw):
- # formats = [
- # ('oai_dc',
- # 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
- # server.NS_OAIDC),
- # ('qdc',
- # 'http://dublincore.org/schemas/xmls/qdc/2006/01/06/dcterms.xsd',
- # NS_DCTERMS)]
- # if 'identifier' in kw:
- # slug = self.identifier_to_slug(kw['identifier'])
- # try:
- # b = Book.objects.get(slug=slug)
- # return formats
- # except:
- # try:
- # d = Deleted.objects.get(slug=slug)
- # return []
- # except:
- # raise error.IdDoesNotExistError("This id does not exist")
- # else:
- # return formats
-
- # def listSets(self, **kw):
- # raise error.NoSetHierarchyError("Wolne Lektury does not support sets.")
- # # tags = []
- # # for category in Catalogue.TAG_CATEGORIES:
- # # for tag in Tag.objects.filter(category=category):
- # # tags.append(("%s:%s" % (tag.category, tag.slug),
- # # tag.name,
- # # tag.description))
- # # return tags, None
+ def getRecord(self, **kw):
+ """Returns (header, metadata, about) for given record."""
+ slug = self.identifier_to_slug(kw['identifier'])
+ try:
+ book = Book.objects.get(slug=slug)
+ return self.record_for_book(book)
+ except Book.DoesNotExist:
+ book_type = ContentType.objects.get_for_model(Book)
+ try:
+ deleted_book = Deleted.objects.get(content_type=book_type, slug=slug)
+ except:
+ raise error.IdDoesNotExistError("No item for this identifier")
+ return self.record_for_book(deleted_book)
+
+ def validate_kw(self, kw):
+ if 'resumptionToken' in kw:
+ raise error.BadResumptionTokenError("No resumption token support at this point")
+ if 'metadataPrefix' in kw and not self.metadata_registry.hasWriter(kw['metadataPrefix']):
+ raise error.CannotDisseminateFormatError("This format is not supported")
+
+ def identifier_to_slug(self, ident):
+ return ident.split(':')[-1]
+
+ def slug_to_identifier(self, slug):
+ return self.oai_id % slug
+
+ def listIdentifiers(self, **kw):
+ self.validate_kw(kw)
+ records = [self.record_for_book(book, headers_only=True) for
+ book in self.books(None, kw.get('from_'), kw.get('until'))]
+ return records, None
+
+ def listRecords(self, **kw):
+ """
+ can get a resumptionToken kw.
+ returns result, token
+ """
+ self.validate_kw(kw)
+ records = [self.record_for_book(book) for
+ book in self.books(None,
+ kw.get('from_', None),
+ kw.get('until', None))]
+
+ return records, None
+
+ def listMetadataFormats(self, **kw):
+ formats = [
+ ('oai_dc',
+ 'http://www.openarchives.org/OAI/2.0/oai_dc.xsd',
+ server.NS_OAIDC),
+ ('qdc',
+ 'http://dublincore.org/schemas/xmls/qdc/2006/01/06/dcterms.xsd',
+ NS_DCTERMS)]
+ if 'identifier' in kw:
+ slug = self.identifier_to_slug(kw['identifier'])
+ try:
+ Book.objects.get(slug=slug)
+ return formats
+ except Book.DoesNotExist:
+ try:
+ Deleted.objects.get(slug=slug)
+ return []
+ except Deleted.DoesNotExist:
+ raise error.IdDoesNotExistError("This id does not exist")
+ else:
+ return formats
+
+ def listSets(self, **kw):
+ raise error.NoSetHierarchyError("Wolne Lektury does not support sets.")
+ # tags = []
+ # for category in Catalogue.TAG_CATEGORIES:
+ # for tag in Tag.objects.filter(category=category):
+ # tags.append(("%s:%s" % (tag.category, tag.slug),
+ # tag.name,
+ # tag.description))
+ # return tags, None