def order(facet, work, edition, ascending=None): f = Facets( collection=Facets.COLLECTION_FULL, availability=Facets.AVAILABLE_ALL, order=facet, order_ascending=ascending, ) return f.order_by(work, edition)[0]
def test_refusal_to_create_expensive_feed(self): facets = Facets.default() pagination = Pagination.default() lane = Lane(self._db, "My Lane", languages=['eng', 'chi']) args = (self._db, lane, CachedFeed.PAGE_TYPE, facets, pagination, None) # If we ask for a group feed that will be cached forever, and it's # not around, we'll get a page feed instead. feed, fresh = CachedFeed.fetch(*args, max_age=Configuration.CACHE_FOREVER) eq_(CachedFeed.PAGE_TYPE, feed.type) # If we ask for the same feed, but we don't say it must be cached # forever, it'll be created. feed, fresh = CachedFeed.fetch(*args, max_age=0) # Or if we explicitly demand that the feed be created, it will # be created. feed, fresh = CachedFeed.fetch(*args, force_refresh=True, max_age=Configuration.CACHE_FOREVER) feed.update("Cache this forever!") # Once the feed has content associated with it, we can ask for # it in cached-forever mode and no longer get the exception. feed, fresh = CachedFeed.fetch(*args, max_age=Configuration.CACHE_FOREVER) eq_("Cache this forever!", feed.content)
def test_lifecycle(self): facets = Facets.default() pagination = Pagination.default() lane = Lane(self._db, "My Lane", languages=['eng', 'chi']) # Fetch a cached feed from the database--it's empty. args = (self._db, lane, CachedFeed.PAGE_TYPE, facets, pagination, None) feed, fresh = CachedFeed.fetch(*args, max_age=0) eq_(False, fresh) eq_(None, feed.content) eq_(pagination.query_string, feed.pagination) eq_(facets.query_string, feed.facets) eq_(lane.name, feed.lane_name) eq_('eng,chi', feed.languages) # Update the content feed.update("The content") self._db.commit() # Fetch it again. feed, fresh = CachedFeed.fetch(*args, max_age=0) # Now it's cached! But not fresh, because max_age is zero eq_("The content", feed.content) eq_(False, fresh) # Lower our standards, and it's fresh! feed, fresh = CachedFeed.fetch(*args, max_age=1000) eq_("The content", feed.content) eq_(True, fresh)
def test_fetch_ignores_feeds_without_content(self): facets = Facets.default(self._default_library) pagination = Pagination.default() lane = self._lane(u"My Lane", languages=['eng', 'chi']) # Create a feed without content (i.e. don't update it) contentless_feed = get_one_or_create( self._db, CachedFeed, lane_id=lane.id, type=CachedFeed.PAGE_TYPE, facets=unicode(facets.query_string), pagination=unicode(pagination.query_string))[0] # It's not returned because it hasn't been updated. args = (self._db, lane, CachedFeed.PAGE_TYPE, facets, pagination, None) feed, fresh = CachedFeed.fetch(*args) eq_(True, feed != contentless_feed) eq_(False, fresh) # But if the feed is updated, we get it back. feed.update(self._db, u"Just feedy things") result, fresh = CachedFeed.fetch(*args) eq_(True, fresh) eq_(feed, result)
def test_lifecycle_with_worklist(self): facets = Facets.default(self._default_library) pagination = Pagination.default() lane = WorkList() lane.initialize(self._default_library) # Fetch a cached feed from the database--it's empty. args = (self._db, lane, CachedFeed.PAGE_TYPE, facets, pagination, None) feed, fresh = CachedFeed.fetch(*args, max_age=0) eq_(False, fresh) eq_(None, feed.content) eq_(pagination.query_string, feed.pagination) eq_(facets.query_string, feed.facets) eq_(None, feed.lane_id) # Update the content feed.update(self._db, u"The content") self._db.commit() # Fetch it again. feed, fresh = CachedFeed.fetch(*args, max_age=0) # Now it's cached! But not fresh, because max_age is zero eq_("The content", feed.content) eq_(False, fresh) # Lower our standards, and it's fresh! feed, fresh = CachedFeed.fetch(*args, max_age=1000) eq_("The content", feed.content) eq_(True, fresh)
def load_facets(order, availability, collection, config=Configuration): """Turn user input into a Facets object.""" order_facets = config.enabled_facets(Facets.ORDER_FACET_GROUP_NAME) if order and not order in order_facets: return INVALID_INPUT.detailed( _("I don't know how to order a feed by '%(order)s'", order=order), 400) availability_facets = config.enabled_facets( Facets.AVAILABILITY_FACET_GROUP_NAME) if availability and not availability in availability_facets: return INVALID_INPUT.detailed( _("I don't understand the availability term '%(availability)s'", availability=availability), 400) collection_facets = config.enabled_facets( Facets.COLLECTION_FACET_GROUP_NAME) if collection and not collection in collection_facets: return INVALID_INPUT.detailed( _("I don't understand which collection '%(collection)s' refers to.", collection=collection), 400) enabled_facets = { Facets.ORDER_FACET_GROUP_NAME: order_facets, Facets.AVAILABILITY_FACET_GROUP_NAME: availability_facets, Facets.COLLECTION_FACET_GROUP_NAME: collection_facets, } return Facets(collection=collection, availability=availability, order=order, enabled_facets=enabled_facets)
def test_facet_groups(self): facets = Facets( Facets.COLLECTION_MAIN, Facets.AVAILABLE_ALL, Facets.ORDER_TITLE ) all_groups = list(facets.facet_groups) # By default, there are a 9 facet transitions: three groups of three. eq_(9, len(all_groups)) # available=all, collection=main, and order=title are the selected # facets. selected = sorted([x[:2] for x in all_groups if x[-1] == True]) eq_( [('available', 'all'), ('collection', 'main'), ('order', 'title')], selected ) test_facet_policy = { "enabled" : { Facets.ORDER_FACET_GROUP_NAME : [ Facets.ORDER_WORK_ID, Facets.ORDER_TITLE ], Facets.COLLECTION_FACET_GROUP_NAME : [Facets.COLLECTION_FULL], Facets.AVAILABILITY_FACET_GROUP_NAME : [Facets.AVAILABLE_ALL], }, "default" : { Facets.ORDER_FACET_GROUP_NAME : Facets.ORDER_TITLE, Facets.COLLECTION_FACET_GROUP_NAME : Facets.COLLECTION_FULL, Facets.AVAILABILITY_FACET_GROUP_NAME : Facets.AVAILABLE_ALL, } } with temp_config() as config: config['policies'] = { Configuration.FACET_POLICY : test_facet_policy } facets = Facets(None, None, Facets.ORDER_TITLE) all_groups = list(facets.facet_groups) # We have disabled almost all the facets, so the list of # facet transitions includes only two items. # # 'Sort by title' was selected, and it shows up as the selected # item in this facet group. expect = [['order', 'title', True], ['order', 'work_id', False]] eq_(expect, sorted([list(x[:2]) + [x[-1]] for x in all_groups]))
def test_facets_can_be_enabled_at_initialization(self): enabled_facets = { Facets.ORDER_FACET_GROUP_NAME: [ Facets.ORDER_TITLE, Facets.ORDER_AUTHOR, ], Facets.COLLECTION_FACET_GROUP_NAME: [Facets.COLLECTION_MAIN], Facets.AVAILABILITY_FACET_GROUP_NAME: [Facets.AVAILABLE_OPEN_ACCESS] } # Create a new Facets object with these facets enabled, # no matter the Configuration. facets = Facets(Facets.COLLECTION_MAIN, Facets.AVAILABLE_OPEN_ACCESS, Facets.ORDER_TITLE, enabled_facets=enabled_facets) all_groups = list(facets.facet_groups) expect = [['order', 'author', False], ['order', 'title', True]] eq_(expect, sorted([list(x[:2]) + [x[-1]] for x in all_groups]))
def facetify(collection=Facets.COLLECTION_FULL, available=Facets.AVAILABLE_ALL, order=Facets.ORDER_TITLE): f = Facets(collection, available, order) return f.apply(self._db, qu)
def fields(facet): return [ Facets.order_facet_to_database_field(facet, w, e) for w, e in ((Work, Edition), (mw, mw), (mwg, mwg)) ]
def page(cls, _db, title, url, lane, annotator=None, facets=None, pagination=None, cache_type=None, force_refresh=False, use_materialized_works=True ): """Create a feed representing one page of works from a given lane.""" facets = facets or Facets.default() pagination = pagination or Pagination.default() cache_type = cache_type or CachedFeed.PAGE_TYPE # Find or create a CachedFeed. cached, usable = CachedFeed.fetch( _db, lane=lane, type=cache_type, facets=facets, pagination=pagination, annotator=annotator, force_refresh=force_refresh ) if usable: return cached if use_materialized_works: works_q = lane.materialized_works(facets, pagination) else: works_q = lane.works(facets, pagination) if not works_q: works = [] else: works = works_q.all() feed = cls(_db, title, url, works, annotator) # Add URLs to change faceted views of the collection. for args in cls.facet_links(annotator, facets): OPDSFeed.add_link_to_feed(feed=feed.feed, **args) if len(works) > 0: # There are works in this list. Add a 'next' link. OPDSFeed.add_link_to_feed(feed=feed.feed, rel="next", href=annotator.feed_url(lane, facets, pagination.next_page)) if pagination.offset > 0: OPDSFeed.add_link_to_feed(feed=feed.feed, rel="first", href=annotator.feed_url(lane, facets, pagination.first_page)) previous_page = pagination.previous_page if previous_page: OPDSFeed.add_link_to_feed(feed=feed.feed, rel="previous", href=annotator.feed_url(lane, facets, previous_page)) # Add "up" link and breadcrumbs top_level_title = annotator.top_level_title() or "Collection Home" visible_parent = lane.visible_parent() if isinstance(visible_parent, Lane): title = visible_parent.display_name else: title = top_level_title if visible_parent: up_uri = annotator.lane_url(visible_parent) OPDSFeed.add_link_to_feed(feed=feed.feed, href=up_uri, rel="up", title=title) feed.add_breadcrumbs(lane, annotator) OPDSFeed.add_link_to_feed(feed=feed.feed, rel='start', href=annotator.default_lane_url(), title=top_level_title) annotator.annotate_feed(feed, lane) content = unicode(feed) cached.update(content) return cached