Example #1
0
    def test_fulfill_link_includes_device_registration_tags(self):
        """Verify that when Adobe Vendor ID delegation is included, the
        fulfill link for an Adobe delivery mechanism includes instructions
        on how to get a Vendor ID.
        """
        [pool] = self.work.license_pools
        identifier = pool.identifier
        patron = self._patron()
        old_credentials = list(patron.credentials)

        loan, ignore = pool.loan_to(patron, start=datetime.datetime.utcnow())
        adobe_delivery_mechanism, ignore = DeliveryMechanism.lookup(
            self._db, "text/html", DeliveryMechanism.ADOBE_DRM)
        other_delivery_mechanism, ignore = DeliveryMechanism.lookup(
            self._db, "text/html", DeliveryMechanism.OVERDRIVE_DRM)

        with self.temp_config() as config:
            # The fulfill link for non-Adobe DRM does not
            # include the drm:licensor tag.
            link = self.annotator.fulfill_link(pool.data_source.name,
                                               pool.identifier, pool, loan,
                                               other_delivery_mechanism)
            for child in link.getchildren():
                assert child.tag != "{http://librarysimplified.org/terms/drm}licensor"

            # No new Credential has been associated with the patron.
            eq_(old_credentials, patron.credentials)

            # The fulfill link for Adobe DRM includes information
            # on how to get an Adobe ID in the drm:licensor tag.
            link = self.annotator.fulfill_link(pool.data_source.name,
                                               pool.identifier, pool, loan,
                                               adobe_delivery_mechanism)
            licensor = link.getchildren()[-1]
            eq_("{http://librarysimplified.org/terms/drm}licensor",
                licensor.tag)

            # An Adobe ID-specific identifier has been created for the patron.
            [adobe_id_identifier
             ] = [x for x in patron.credentials if x not in old_credentials]
            eq_(AuthdataUtility.ADOBE_ACCOUNT_ID_PATRON_IDENTIFIER,
                adobe_id_identifier.type)
            eq_(DataSource.INTERNAL_PROCESSING,
                adobe_id_identifier.data_source.name)
            eq_(None, adobe_id_identifier.expires)

            # The drm:licensor tag is the one we get by calling
            # adobe_id_tags() on that identifier.
            [expect
             ] = self.annotator.adobe_id_tags(self._db,
                                              adobe_id_identifier.credential)
            eq_(etree.tostring(expect), etree.tostring(licensor))
Example #2
0
    def apply(self, loan, autocommit=True):
        """Set an appropriate LicensePoolDeliveryMechanism on the given
        `Loan`, creating a DeliveryMechanism if necessary.

        :param loan: A Loan object.
        :param autocommit: Set this to false if you are in the middle
            of a nested transaction.
        :return: A LicensePoolDeliveryMechanism if one could be set on the
            given Loan; None otherwise.
        """
        _db = Session.object_session(loan)

        # Create or update the DeliveryMechanism.
        delivery_mechanism, is_new = DeliveryMechanism.lookup(
            _db, self.content_type,
            self.drm_scheme
        )

        if (loan.fulfillment
            and loan.fulfillment.delivery_mechanism == delivery_mechanism):
            # The work has already been done. Do nothing.
            return

        # At this point we know we need to update the local delivery
        # mechanism.
        pool = loan.license_pool
        if not pool:
            # This shouldn't happen, but bail out if it does.
            return None

        # Look up the LicensePoolDeliveryMechanism for the way the
        # server says this book is available, creating the object if
        # necessary.
        #
        # We set autocommit=False because we're probably in the middle
        # of a nested transaction.
        lpdm = LicensePoolDeliveryMechanism.set(
            pool.data_source, pool.identifier, self.content_type,
            self.drm_scheme, self.rights_uri, self.resource,
            autocommit=autocommit
        )
        loan.fulfillment = lpdm
        return lpdm
Example #3
0
    def test_add_formats(self):
        edition, pool = self._edition(with_license_pool=True)
        epub_no_drm, ignore = DeliveryMechanism.lookup(
            self._db, Representation.EPUB_MEDIA_TYPE, DeliveryMechanism.NO_DRM)
        pool.delivery_mechanisms[0].delivery_mechanism = epub_no_drm
        LicensePoolDeliveryMechanism.set(
            pool.data_source,
            pool.identifier,
            Representation.PDF_MEDIA_TYPE,
            DeliveryMechanism.ADOBE_DRM,
            RightsStatus.IN_COPYRIGHT,
        )

        record = Record()
        Annotator.add_formats(record, pool)
        fields = record.get_fields("538")
        assert 2 == len(fields)
        [pdf, epub] = sorted(fields, key=lambda x: x.get_subfields("a")[0])
        assert "Adobe PDF eBook" == pdf.get_subfields("a")[0]
        assert [" ", " "] == pdf.indicators
        assert "EPUB eBook" == epub.get_subfields("a")[0]
        assert [" ", " "] == epub.indicators
    def test_fulfill_open_access(self):
        # Here's an open-access title.
        self.pool.open_access = True

        # The patron has the title on loan.
        self.pool.loan_to(self.patron)

        # It has a LicensePoolDeliveryMechanism that is broken (has no
        # associated Resource).
        broken_lpdm = self.delivery_mechanism
        eq_(None, broken_lpdm.resource)
        i_want_an_epub = broken_lpdm.delivery_mechanism

        # fulfill_open_access() and fulfill() will both raise
        # FormatNotAvailable.
        assert_raises(FormatNotAvailable, self.circulation.fulfill_open_access,
                      self.pool, i_want_an_epub)

        assert_raises(FormatNotAvailable, self.circulation.fulfill,
                      self.patron, '1234', self.pool,
                      broken_lpdm,
                      sync_on_failure=False
        )

        # Let's add a second LicensePoolDeliveryMechanism of the same
        # type which has an associated Resource.
        link, new = self.pool.identifier.add_link(
            Hyperlink.OPEN_ACCESS_DOWNLOAD, self._url,
            self.pool.data_source
        )

        working_lpdm = self.pool.set_delivery_mechanism(
            i_want_an_epub.content_type,
            i_want_an_epub.drm_scheme,
            RightsStatus.GENERIC_OPEN_ACCESS,
            link.resource,
        )

        # It's still not going to work because the Resource has no
        # Representation.
        eq_(None, link.resource.representation)
        assert_raises(FormatNotAvailable, self.circulation.fulfill_open_access,
                      self.pool, i_want_an_epub)

        # Let's add a Representation to the Resource.
        representation, is_new = self._representation(
            link.resource.url, i_want_an_epub.content_type,
            "Dummy content", mirrored=True
        )
        link.resource.representation = representation

        # We can finally fulfill a loan.
        result = self.circulation.fulfill_open_access(
            self.pool, broken_lpdm
        )
        assert isinstance(result, FulfillmentInfo)
        eq_(result.content_link, link.resource.representation.public_url)
        eq_(result.content_type, i_want_an_epub.content_type)

        # Now, if we try to call fulfill() with the broken
        # LicensePoolDeliveryMechanism we get a result from the
        # working DeliveryMechanism with the same format.
        result = self.circulation.fulfill(
            self.patron, '1234', self.pool, broken_lpdm
        )
        assert isinstance(result, FulfillmentInfo)
        eq_(result.content_link, link.resource.representation.public_url)
        eq_(result.content_type, i_want_an_epub.content_type)

        # We get the right result even if the code calling
        # fulfill_open_access() is incorrectly written and passes in
        # the broken LicensePoolDeliveryMechanism (as opposed to its
        # generic DeliveryMechanism).
        result = self.circulation.fulfill_open_access(
            self.pool, broken_lpdm
        )
        assert isinstance(result, FulfillmentInfo)
        eq_(result.content_link, link.resource.representation.public_url)
        eq_(result.content_type, i_want_an_epub.content_type)

        # If we change the working LPDM so that it serves a different
        # media type than the one we're asking for, we're back to
        # FormatNotAvailable errors.
        irrelevant_delivery_mechanism, ignore = DeliveryMechanism.lookup(
            self._db, "application/some-other-type",
            DeliveryMechanism.NO_DRM
        )
        working_lpdm.delivery_mechanism = irrelevant_delivery_mechanism
        assert_raises(FormatNotAvailable, self.circulation.fulfill_open_access,
                      self.pool, i_want_an_epub)
    def test_fulfill_open_access(self):
        # Here's an open-access title.
        self.pool.open_access = True

        # The patron has the title on loan.
        self.pool.loan_to(self.patron)

        # It has a LicensePoolDeliveryMechanism that is broken (has no
        # associated Resource).
        broken_lpdm = self.delivery_mechanism
        eq_(None, broken_lpdm.resource)
        i_want_an_epub = broken_lpdm.delivery_mechanism

        # fulfill_open_access() and fulfill() will both raise
        # FormatNotAvailable.
        assert_raises(FormatNotAvailable, self.circulation.fulfill_open_access,
                      self.pool, i_want_an_epub)

        assert_raises(FormatNotAvailable,
                      self.circulation.fulfill,
                      self.patron,
                      '1234',
                      self.pool,
                      broken_lpdm,
                      sync_on_failure=False)

        # Let's add a second LicensePoolDeliveryMechanism of the same
        # type which has an associated Resource.
        link, new = self.pool.identifier.add_link(
            Hyperlink.OPEN_ACCESS_DOWNLOAD, self._url, self.pool.data_source)

        working_lpdm = self.pool.set_delivery_mechanism(
            i_want_an_epub.content_type,
            i_want_an_epub.drm_scheme,
            RightsStatus.GENERIC_OPEN_ACCESS,
            link.resource,
        )

        # It's still not going to work because the Resource has no
        # Representation.
        eq_(None, link.resource.representation)
        assert_raises(FormatNotAvailable, self.circulation.fulfill_open_access,
                      self.pool, i_want_an_epub)

        # Let's add a Representation to the Resource.
        representation, is_new = self._representation(
            link.resource.url,
            i_want_an_epub.content_type,
            "Dummy content",
            mirrored=True)
        link.resource.representation = representation

        # We can finally fulfill a loan.
        result = self.circulation.fulfill_open_access(self.pool, broken_lpdm)
        assert isinstance(result, FulfillmentInfo)
        eq_(result.content_link, link.resource.url)
        eq_(result.content_type, i_want_an_epub.content_type)

        # Now, if we try to call fulfill() with the broken
        # LicensePoolDeliveryMechanism we get a result from the
        # working DeliveryMechanism with the same format.
        result = self.circulation.fulfill(self.patron, '1234', self.pool,
                                          broken_lpdm)
        assert isinstance(result, FulfillmentInfo)
        eq_(result.content_link, link.resource.url)
        eq_(result.content_type, i_want_an_epub.content_type)

        # We get the right result even if the code calling
        # fulfill_open_access() is incorrectly written and passes in
        # the broken LicensePoolDeliveryMechanism (as opposed to its
        # generic DeliveryMechanism).
        result = self.circulation.fulfill_open_access(self.pool, broken_lpdm)
        assert isinstance(result, FulfillmentInfo)
        eq_(result.content_link, link.resource.url)
        eq_(result.content_type, i_want_an_epub.content_type)

        # If we change the working LPDM so that it serves a different
        # media type than the one we're asking for, we're back to
        # FormatNotAvailable errors.
        irrelevant_delivery_mechanism, ignore = DeliveryMechanism.lookup(
            self._db, "application/some-other-type", DeliveryMechanism.NO_DRM)
        working_lpdm.delivery_mechanism = irrelevant_delivery_mechanism
        assert_raises(FormatNotAvailable, self.circulation.fulfill_open_access,
                      self.pool, i_want_an_epub)