def lookup(cls, edition_or_identifier, data_source, operation=None, collection=None): from datasource import DataSource from edition import Edition from identifier import Identifier _db = Session.object_session(edition_or_identifier) if isinstance(edition_or_identifier, Identifier): identifier = edition_or_identifier elif isinstance(edition_or_identifier, Edition): identifier = edition_or_identifier.primary_identifier else: raise ValueError( "Cannot look up a coverage record for %r." % edition) if isinstance(data_source, basestring): data_source = DataSource.lookup(_db, data_source) return get_one( _db, CoverageRecord, identifier=identifier, data_source=data_source, operation=operation, collection=collection, on_multiple='interchangeable', )
def data_source(self): """Find the data source associated with this Collection. Bibliographic metadata obtained through the collection protocol is recorded as coming from this data source. A LicensePool inserted into this collection will be associated with this data source, unless its bibliographic metadata indicates some other data source. For most Collections, the integration protocol sets the data source. For collections that use the OPDS import protocol, the data source is a Collection-specific setting. """ data_source = None name = ExternalIntegration.DATA_SOURCE_FOR_LICENSE_PROTOCOL.get( self.protocol ) if not name: name = self.external_integration.setting( Collection.DATA_SOURCE_NAME_SETTING ).value _db = Session.object_session(self) if name: data_source = DataSource.lookup(_db, name, autocreate=True) return data_source
def all_from_data_sources(cls, _db, data_sources): """All custom lists from the given data sources.""" if not isinstance(data_sources, list): data_sources = [data_sources] ids = [] for ds in data_sources: if isinstance(ds, basestring): ds = DataSource.lookup(_db, ds) ids.append(ds.id) return _db.query(CustomList).filter(CustomList.data_source_id.in_(ids))
def lookup(self, _db, data_source, type, patron, refresher_method, allow_persistent_token=False, allow_empty_token=False): from datasource import DataSource if isinstance(data_source, basestring): data_source = DataSource.lookup(_db, data_source) credential, is_new = get_one_or_create( _db, Credential, data_source=data_source, type=type, patron=patron) if (is_new or (not credential.expires and not allow_persistent_token) or (not credential.credential and not allow_empty_token) or (credential.expires and credential.expires <= datetime.datetime.utcnow())): if refresher_method: refresher_method(credential) return credential
def unresolved_catalog(self, _db, data_source_name, operation): """Returns a query with all identifiers in a Collection's catalog that have unsuccessfully attempted resolution. This method is used on the metadata wrangler. :return: a sqlalchemy.Query """ coverage_source = DataSource.lookup(_db, data_source_name) is_not_resolved = and_( CoverageRecord.operation == operation, CoverageRecord.data_source_id == coverage_source.id, CoverageRecord.status != CoverageRecord.SUCCESS, ) query = _db.query(Identifier)\ .outerjoin(Identifier.licensed_through)\ .outerjoin(Identifier.coverage_records)\ .outerjoin(LicensePool.work).outerjoin(Identifier.collections)\ .filter( Collection.id==self.id, is_not_resolved, Work.id==None ).order_by(Identifier.id) return query
def data_source(self): """Find the data source associated with this Collection. Bibliographic metadata obtained through the collection protocol is recorded as coming from this data source. A LicensePool inserted into this collection will be associated with this data source, unless its bibliographic metadata indicates some other data source. For most Collections, the integration protocol sets the data source. For collections that use the OPDS import protocol, the data source is a Collection-specific setting. """ data_source = None name = ExternalIntegration.DATA_SOURCE_FOR_LICENSE_PROTOCOL.get( self.protocol) if not name: name = self.external_integration.setting( Collection.DATA_SOURCE_NAME_SETTING).value _db = Session.object_session(self) if name: data_source = DataSource.lookup(_db, name, autocreate=True) return data_source
def unresolved_catalog(self, _db, data_source_name, operation): """Returns a query with all identifiers in a Collection's catalog that have unsuccessfully attempted resolution. This method is used on the metadata wrangler. :return: a sqlalchemy.Query """ coverage_source = DataSource.lookup(_db, data_source_name) is_not_resolved = and_( CoverageRecord.operation==operation, CoverageRecord.data_source_id==coverage_source.id, CoverageRecord.status!=CoverageRecord.SUCCESS, ) query = _db.query(Identifier)\ .outerjoin(Identifier.licensed_through)\ .outerjoin(Identifier.coverage_records)\ .outerjoin(LicensePool.work).outerjoin(Identifier.collections)\ .filter( Collection.id==self.id, is_not_resolved, Work.id==None ).order_by(Identifier.id) return query
def from_metadata_identifier(cls, _db, metadata_identifier, data_source=None): """Finds or creates a Collection on the metadata wrangler, based on its unique metadata_identifier. """ # Decode the metadata identifier into a protocol and an # account ID. If the metadata identifier is invalid, this # will raise an exception. protocol, account_id = cls._decode_metadata_identifier(metadata_identifier) # Now that we know the metadata identifier is valid, try to # look up a collection named after it. collection = get_one(_db, Collection, name=metadata_identifier) is_new = False if not collection: # Create a collection named after the metadata # identifier. Give it an ExternalIntegration with the # corresponding protocol, and set its data source and # external_account_id. collection, is_new = create( _db, Collection, name=metadata_identifier ) collection.create_external_integration(protocol) if protocol == ExternalIntegration.OPDS_IMPORT: # For OPDS Import collections only, we store the URL to # the OPDS feed (the "account ID") and the data source. collection.external_account_id = account_id if data_source and not isinstance(data_source, DataSource): data_source = DataSource.lookup( _db, data_source, autocreate=True ) collection.data_source = data_source return collection, is_new
def restrict_to_ready_deliverable_works( cls, query, work_model, edition_model=None, collection_ids=None, show_suppressed=False, allow_holds=True, ): """Restrict a query to show only presentation-ready works present in an appropriate collection which the default client can fulfill. Note that this assumes the query has an active join against LicensePool. :param query: The query to restrict. :param work_model: Either Work or MaterializedWorkWithGenre :param edition_model: Either Edition or MaterializedWorkWithGenre :param show_suppressed: Include titles that have nothing but suppressed LicensePools. :param collection_ids: Only include titles in the given collections. :param allow_holds: If false, pools with no available copies will be hidden. """ edition_model = edition_model or work_model # Only find presentation-ready works. # # Such works are automatically filtered out of # the materialized view, but we need to filter them out of Work. if work_model == Work: query = query.filter( work_model.presentation_ready == True, ) # Only find books that have some kind of DeliveryMechanism. LPDM = LicensePoolDeliveryMechanism exists_clause = exists().where( and_(LicensePool.data_source_id==LPDM.data_source_id, LicensePool.identifier_id==LPDM.identifier_id) ) query = query.filter(exists_clause) # Some sources of audiobooks may be excluded because the # server can't fulfill them or the expected client can't play # them. _db = query.session excluded = ConfigurationSetting.excluded_audio_data_sources(_db) if excluded: audio_excluded_ids = [ DataSource.lookup(_db, x).id for x in excluded ] query = query.filter( or_(edition_model.medium != EditionConstants.AUDIO_MEDIUM, ~LicensePool.data_source_id.in_(audio_excluded_ids)) ) # Only find books with unsuppressed LicensePools. if not show_suppressed: query = query.filter(LicensePool.suppressed==False) # Only find books with available licenses. query = query.filter( or_(LicensePool.licenses_owned > 0, LicensePool.open_access) ) # Only find books in an appropriate collection. if collection_ids is not None: query = query.filter( LicensePool.collection_id.in_(collection_ids) ) # If we don't allow holds, hide any books with no available copies. if not allow_holds: query = query.filter( or_(LicensePool.licenses_available > 0, LicensePool.open_access) ) return query