Ejemplo n.º 1
0
    def update_licensepool_with_book_info(self, book, license_pool, is_new_pool):
        """Update a book's LicensePool with information from a JSON
        representation of its circulation info.

        Then, create an Edition and make sure it has bibliographic
        coverage. If the new Edition is the only candidate for the
        pool's presentation_edition, promote it to presentation
        status.
        """
        circulation = OverdriveRepresentationExtractor.book_info_to_circulation(
            book
        )
        license_pool, circulation_changed = circulation.apply(license_pool)

        edition, is_new_edition = Edition.for_foreign_id(
            self._db, self.source, license_pool.identifier.type,
            license_pool.identifier.identifier)

        # If the pool does not already have a presentation edition, 
        # and if this edition is newly made, then associate pool and edition
        # as presentation_edition
        if ((not license_pool.presentation_edition) and is_new_edition): 
            edition_changed = license_pool.set_presentation_edition(
                policy=None
            )

        if is_new_pool:
            license_pool.open_access = False
            self.log.info("New Overdrive book discovered: %r", edition)
        return license_pool, is_new_pool, circulation_changed
Ejemplo n.º 2
0
    def update_formats(self, licensepool):
        """Update the format information for a single book.

        Incidentally updates the metadata, just in case Overdrive has
        changed it.
        """
        info = self.metadata_lookup(licensepool.identifier)

        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(
            info, include_bibliographic=True, include_formats=True)
        if not metadata:
            # No work to be done.
            return

        edition, ignore = self._edition(licensepool)

        replace = ReplacementPolicy.from_license_source(self._db)
        metadata.apply(edition, self.collection, replace=replace)
Ejemplo n.º 3
0
    def update_formats(self, licensepool):
        """Update the format information for a single book.

        Incidentally updates the metadata, just in case Overdrive has
        changed it.
        """
        info = self.metadata_lookup(licensepool.identifier)

        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(
            info, include_bibliographic=True, include_formats=True)
        if not metadata:
            # No work to be done.
            return

        edition, ignore = self._edition(licensepool)

        replace = ReplacementPolicy.from_license_source(self._db)
        metadata.apply(edition, self.collection, replace=replace)
Ejemplo n.º 4
0
    def update_formats(self, licensepool):
        """Update the format information for a single book.
        """
        info = self.metadata_lookup(licensepool.identifier)

        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(
            info, include_bibliographic=False, include_formats=True)
        if not metadata:
            # No work to be done.
            return
        circulation_data = metadata.circulation

        # The identifier in the CirculationData needs to match the
        # identifier associated with the LicensePool -- otherwise
        # a new LicensePool will be created.
        circulation_data._primary_identifier.identifier = licensepool.identifier.identifier
        replace = ReplacementPolicy(formats=True)
        _db = Session.object_session(licensepool)
        circulation_data.apply(_db, licensepool.collection, replace)
Ejemplo n.º 5
0
    def update_licensepool_with_book_info(self, book, license_pool, is_new):
        """Update a book's LicensePool with information from a JSON
        representation of its circulation info.

        Also creates an Edition and gives it very basic bibliographic
        information (the title), if possible.
        """
        circulation = OverdriveRepresentationExtractor.book_info_to_circulation(
            book
        )
        circulation_changed = circulation.update(license_pool, is_new)

        edition, ignore = Edition.for_foreign_id(
            self._db, self.source, license_pool.identifier.type,
            license_pool.identifier.identifier)
        edition.title = edition.title or book.get('title')
        if is_new:
            license_pool.open_access = False
            self.log.info("New Overdrive book discovered: %r", edition)
        return license_pool, is_new, circulation_changed
Ejemplo n.º 6
0
    def test_not_found_error_to_circulationdata(self):
        raw, info = self.sample_json("overdrive_availability_not_found.json")

        # By default, a "NotFound" error can't be converted to a
        # CirculationData object, because we don't know _which_ book it
        # was that wasn't found.
        extractor = OverdriveRepresentationExtractor(self.api)
        m = extractor.book_info_to_circulation
        assert None == m(info)

        # However, if an ID was added to `info` ahead of time (as the
        # circulation code does), we do know, and we can create a
        # CirculationData.
        identifier = self._identifier(identifier_type=Identifier.OVERDRIVE_ID)
        info["id"] = identifier.identifier
        data = m(info)
        assert identifier == data.primary_identifier(self._db)
        assert 0 == data.licenses_owned
        assert 0 == data.licenses_available
        assert 0 == data.patrons_in_hold_queue
Ejemplo n.º 7
0
    def test_book_info_with_sample(self):
        # This book has two samples; one available as a direct download and
        # one available through a manifest file.
        raw, info = self.sample_json("has_sample.json")
        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(info)
        samples = [x for x in metadata.links if x.rel == Hyperlink.SAMPLE]
        epub_sample, manifest_sample = sorted(samples,
                                              key=lambda x: x.media_type)

        # Here's the direct download.
        assert (
            "http://excerpts.contentreserve.com/FormatType-410/1071-1/9BD/24F/82/BridesofConvenienceBundle9781426803697.epub"
            == epub_sample.href)
        assert MediaTypes.EPUB_MEDIA_TYPE == epub_sample.media_type

        # Here's the manifest.
        assert (
            "https://samples.overdrive.com/?crid=9BD24F82-35C0-4E0A-B5E7-BCFED07835CF&.epub-sample.overdrive.com"
            == manifest_sample.href)
        assert (MediaTypes.OVERDRIVE_EBOOK_MANIFEST_MEDIA_TYPE ==
                manifest_sample.media_type)
Ejemplo n.º 8
0
    def update_licensepool_with_book_info(self, book, license_pool, is_new_pool):
        """Update a book's LicensePool with information from a JSON
        representation of its circulation info.

        Then, create an Edition and make sure it has bibliographic
        coverage. If the new Edition is the only candidate for the
        pool's presentation_edition, promote it to presentation
        status.
        """
        circulation = OverdriveRepresentationExtractor.book_info_to_circulation(
            book
        )
        license_pool, circulation_changed = circulation.apply(
            self._db, license_pool.collection
        )

        edition, is_new_edition = self._edition(license_pool)

        if is_new_pool:
            license_pool.open_access = False
            self.log.info("New Overdrive book discovered: %r", edition)
        return license_pool, is_new_pool, circulation_changed
Ejemplo n.º 9
0
    def update_licensepool_with_book_info(self, book, license_pool, is_new_pool):
        """Update a book's LicensePool with information from a JSON
        representation of its circulation info.

        Then, create an Edition and make sure it has bibliographic
        coverage. If the new Edition is the only candidate for the
        pool's presentation_edition, promote it to presentation
        status.
        """
        circulation = OverdriveRepresentationExtractor.book_info_to_circulation(
            book
        )
        license_pool, circulation_changed = circulation.apply(
            self._db, license_pool.collection
        )

        edition, is_new_edition = self._edition(license_pool)

        if is_new_pool:
            license_pool.open_access = False
            self.log.info("New Overdrive book discovered: %r", edition)
        return license_pool, is_new_pool, circulation_changed
Ejemplo n.º 10
0
 def assert_formats(overdrive_name, *expect):
     actual = OverdriveRepresentationExtractor.internal_formats(
         overdrive_name)
     assert list(expect) == list(actual)
Ejemplo n.º 11
0
 def m(link):
     return OverdriveRepresentationExtractor.image_link_to_linkdata(
         link, "rel")
Ejemplo n.º 12
0
    def test_book_info_with_metadata(self):
        # Tests that can convert an overdrive json block into a Metadata object.

        raw, info = self.sample_json("overdrive_metadata.json")
        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(info)

        assert "Agile Documentation" == metadata.title
        assert (
            "Agile Documentation A Pattern Guide to Producing Lightweight Documents for Software Projects"
            == metadata.sort_title)
        assert (
            "A Pattern Guide to Producing Lightweight Documents for Software Projects"
            == metadata.subtitle)
        assert Edition.BOOK_MEDIUM == metadata.medium
        assert "Wiley Software Patterns" == metadata.series
        assert "eng" == metadata.language
        assert "Wiley" == metadata.publisher
        assert "John Wiley & Sons, Inc." == metadata.imprint
        assert 2005 == metadata.published.year
        assert 1 == metadata.published.month
        assert 31 == metadata.published.day

        [author] = metadata.contributors
        assert "Rüping, Andreas" == author.sort_name
        assert "Andreas Rüping" == author.display_name
        assert [Contributor.AUTHOR_ROLE] == author.roles

        subjects = sorted(metadata.subjects, key=lambda x: x.identifier)

        assert [
            ("Computer Technology", Subject.OVERDRIVE, 100),
            ("Nonfiction", Subject.OVERDRIVE, 100),
            ("Object Technologies - Miscellaneous", "tag", 1),
        ] == [(x.identifier, x.type, x.weight) for x in subjects]

        # Related IDs.
        assert (Identifier.OVERDRIVE_ID,
                "3896665d-9d81-4cac-bd43-ffc5066de1f5") == (
                    metadata.primary_identifier.type,
                    metadata.primary_identifier.identifier,
                )

        ids = [(x.type, x.identifier) for x in metadata.identifiers]

        # The original data contains an actual ASIN and ISBN, plus a blank
        # ASIN and three invalid ISBNs: one which is common placeholder
        # text, one which is mis-typed and has a bad check digit, and one
        # which has an invalid character; the bad identifiers do not show
        # up here.
        assert [
            (Identifier.ASIN, "B000VI88N2"),
            (Identifier.ISBN, "9780470856246"),
            (Identifier.OVERDRIVE_ID, "3896665d-9d81-4cac-bd43-ffc5066de1f5"),
        ] == sorted(ids)

        # Available formats.
        [kindle, pdf] = sorted(metadata.circulation.formats,
                               key=lambda x: x.content_type)
        assert DeliveryMechanism.KINDLE_CONTENT_TYPE == kindle.content_type
        assert DeliveryMechanism.KINDLE_DRM == kindle.drm_scheme

        assert Representation.PDF_MEDIA_TYPE == pdf.content_type
        assert DeliveryMechanism.ADOBE_DRM == pdf.drm_scheme

        # Links to various resources.
        shortd, image, longd = sorted(metadata.links, key=lambda x: x.rel)

        assert Hyperlink.DESCRIPTION == longd.rel
        assert longd.content.startswith("<p>Software documentation")

        assert Hyperlink.SHORT_DESCRIPTION == shortd.rel
        assert shortd.content.startswith("<p>Software documentation")
        assert len(shortd.content) < len(longd.content)

        assert Hyperlink.IMAGE == image.rel
        assert (
            "http://images.contentreserve.com/ImageType-100/0128-1/%7B3896665D-9D81-4CAC-BD43-FFC5066DE1F5%7DImg100.jpg"
            == image.href)

        thumbnail = image.thumbnail

        assert Hyperlink.THUMBNAIL_IMAGE == thumbnail.rel
        assert (
            "http://images.contentreserve.com/ImageType-200/0128-1/%7B3896665D-9D81-4CAC-BD43-FFC5066DE1F5%7DImg200.jpg"
            == thumbnail.href)

        # Measurements associated with the book.

        measurements = metadata.measurements
        popularity = [
            x for x in measurements
            if x.quantity_measured == Measurement.POPULARITY
        ][0]
        assert 2 == popularity.value

        rating = [
            x for x in measurements
            if x.quantity_measured == Measurement.RATING
        ][0]
        assert 1 == rating.value

        # Request only the bibliographic information.
        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(
            info, include_bibliographic=True, include_formats=False)

        assert "Agile Documentation" == metadata.title
        assert None == metadata.circulation

        # Request only the format information.
        metadata = OverdriveRepresentationExtractor.book_info_to_metadata(
            info, include_bibliographic=False, include_formats=True)

        assert None == metadata.title

        [kindle, pdf] = sorted(metadata.circulation.formats,
                               key=lambda x: x.content_type)
        assert DeliveryMechanism.KINDLE_CONTENT_TYPE == kindle.content_type
        assert DeliveryMechanism.KINDLE_DRM == kindle.drm_scheme

        assert Representation.PDF_MEDIA_TYPE == pdf.content_type
        assert DeliveryMechanism.ADOBE_DRM == pdf.drm_scheme
Ejemplo n.º 13
0
 def test_link(self):
     data, raw = self.sample_json("overdrive_book_list.json")
     expect = OverdriveAPI.make_link_safe(
         "http://api.overdrive.com/v1/collections/collection-id/products?limit=300&offset=0&lastupdatetime=2014-04-28%2009:25:09&sort=popularity:desc&formats=ebook-epub-open,ebook-epub-adobe,ebook-pdf-adobe,ebook-pdf-open"
     )
     assert expect == OverdriveRepresentationExtractor.link(raw, "first")