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))
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
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)