def to_delegated_patron_identifier_uuid(self,
                                            library_uri,
                                            foreign_patron_identifier,
                                            value_generator=None):
        """Create or lookup a DelegatedPatronIdentifier containing an Adobe
        account ID for the given library and foreign patron ID.

        :return: A 2-tuple (UUID, label)
        """
        if not library_uri or not foreign_patron_identifier:
            return None, None
        value_generator = value_generator or self.uuid
        identifier, is_new = DelegatedPatronIdentifier.get_one_or_create(
            self._db,
            library_uri,
            foreign_patron_identifier,
            DelegatedPatronIdentifier.ADOBE_ACCOUNT_ID,
            value_generator,
        )

        if identifier is None:
            return None, None
        return (
            identifier.delegated_identifier,
            self.urn_to_label(identifier.delegated_identifier),
        )
示例#2
0
    def test_migrate_adobe_id_success(self):
        from api.opds import CirculationManagerAnnotator
        patron = self._patron()

        # This patron has a Credential containing their Adobe ID
        data_source = DataSource.lookup(self._db, DataSource.ADOBE)
        adobe_id = Credential(
            patron=patron, data_source=data_source,
            type=AdobeVendorIDModel.VENDOR_ID_UUID_TOKEN_TYPE,
            credential="My Adobe ID"
        )

        # Run the migration.
        new_credential, delegated_identifier = self.authdata.migrate_adobe_id(patron)
        
        # The patron now has _two_ Credentials -- the old one
        # containing the Adobe ID, and a new one.
        eq_(set([new_credential, adobe_id]), set(patron.credentials))

        # The new credential contains an anonymized patron identifier
        # used solely to connect the patron to their Adobe ID.
        eq_(AuthdataUtility.ADOBE_ACCOUNT_ID_PATRON_IDENTIFIER,
            new_credential.type)

        # We can use that identifier to look up a DelegatedPatronIdentifier
        # 
        def explode():
            # This method won't be called because the
            # DelegatedPatronIdentifier already exists.
            raise Exception()
        identifier, is_new = DelegatedPatronIdentifier.get_one_or_create(
            self._db, self.authdata.library_uri, new_credential.credential,
            DelegatedPatronIdentifier.ADOBE_ACCOUNT_ID, explode
        )
        eq_(delegated_identifier, identifier)
        eq_(False, is_new)
        eq_("My Adobe ID", identifier.delegated_identifier)

        # An integration-level test:
        # AdobeVendorIDModel.to_delegated_patron_identifier_uuid works
        # now.
        model = AdobeVendorIDModel(self._default_library, None, None)
        uuid, label = model.to_delegated_patron_identifier_uuid(
            self.authdata.library_uri, new_credential.credential
        )
        eq_("My Adobe ID", uuid)
        eq_('Delegated account ID My Adobe ID', label)
        
        # If we run the migration again, nothing new happens.
        new_credential_2, delegated_identifier_2 = self.authdata.migrate_adobe_id(patron)
        eq_(new_credential, new_credential_2)
        eq_(delegated_identifier, delegated_identifier_2)
        eq_(2, len(patron.credentials))
        uuid, label = model.to_delegated_patron_identifier_uuid(
            self.authdata.library_uri, new_credential.credential
        )
        eq_("My Adobe ID", uuid)
        eq_('Delegated account ID My Adobe ID', label)
    def migrate_adobe_id(self, patron):
        """If the given patron has an Adobe ID stored as a Credential, also
        store it as a DelegatedPatronIdentifier.

        This method and its test should be removed once all instances have
        run the migration script
        20161102-adobe-id-is-delegated-patron-identifier.py.
        """

        _db = Session.object_session(patron)
        credential = get_one(
            _db,
            Credential,
            patron=patron,
            type=AdobeVendorIDModel.VENDOR_ID_UUID_TOKEN_TYPE,
        )
        if not credential:
            # This patron has no Adobe ID. Do nothing.
            return None, None
        adobe_id = credential.credential

        # Create a new Credential containing an anonymized patron ID.
        patron_identifier_credential = (
            AdobeVendorIDModel.get_or_create_patron_identifier_credential(
                patron))

        # Then create a DelegatedPatronIdentifier mapping that
        # anonymized patron ID to the patron's Adobe ID.
        def create_function():
            """This will be called as the DelegatedPatronIdentifier
            is created. We already know the patron's Adobe ID and just
            want to store it in the DPI.
            """
            return adobe_id

        delegated_identifier, is_new = DelegatedPatronIdentifier.get_one_or_create(
            _db,
            self.library_uri,
            patron_identifier_credential.credential,
            DelegatedPatronIdentifier.ADOBE_ACCOUNT_ID,
            create_function,
        )
        return patron_identifier_credential, delegated_identifier