def lane_for_other_languages(_db, library, exclude_languages): """Make a lane for all books not in one of the given languages.""" language_lanes = [] other_languages = Configuration.tiny_collection_languages(library) if not other_languages: return None for language_set in other_languages: name = LanguageCodes.name_for_languageset(language_set) language_lane = Lane( _db, library, full_name=name, genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION, searchable=True, languages=language_set, ) language_lanes.append(language_lane) lane = Lane( _db, library, full_name="Other Languages", sublanes=language_lanes, exclude_languages=exclude_languages, searchable=True, genres=None, ) lane.default_for_language = True return lane
def test_lane_url(self): everything_lane = Lane(self._db, "Everything", fiction=Lane.BOTH_FICTION_AND_NONFICTION) fantasy_lane_with_sublanes = Lane(self._db, "Fantasy", genres=[Fantasy], languages="eng", subgenre_behavior=Lane.IN_SAME_LANE, sublanes=[Urban_Fantasy], parent=everything_lane) fantasy_lane_without_sublanes = Lane( self._db, "Fantasy", genres=[Fantasy], languages="eng", subgenre_behavior=Lane.IN_SAME_LANE, parent=everything_lane) default_lane_url = self.annotator.lane_url(everything_lane) eq_(default_lane_url, self.annotator.default_lane_url()) groups_url = self.annotator.lane_url(fantasy_lane_with_sublanes) eq_(groups_url, self.annotator.groups_url(fantasy_lane_with_sublanes)) feed_url = self.annotator.lane_url(fantasy_lane_without_sublanes) eq_(feed_url, self.annotator.feed_url(fantasy_lane_without_sublanes))
def test_language_filter(self): script = CacheRepresentationPerLane(self._db, [ "--language=fre", "--language=English", "--language=none", "--min-depth=0" ], testing=True) eq_(['fre', 'eng'], script.languages) english_lane = Lane(self._db, self._default_library, self._str, languages=['eng']) eq_(True, script.should_process_lane(english_lane)) no_english_lane = Lane(self._db, self._default_library, self._str, exclude_languages=['eng']) eq_(True, script.should_process_lane(no_english_lane)) no_english_or_french_lane = Lane(self._db, self._default_library, self._str, exclude_languages=['eng', 'fre']) eq_(False, script.should_process_lane(no_english_or_french_lane))
def setup(self): super(TestOPDS, self).setup() parent = Lane(self._db, self._default_library, "Fiction", languages=["eng"], fiction=True) self.lane = Lane(self._db, self._default_library, "Fantasy", languages=["eng"], genres=[Fantasy], parent=parent) self.annotator = CirculationManagerAnnotator(None, self.lane, self._default_library, test_mode=True) # Initialize library with Adobe Vendor ID details self._default_library.library_registry_short_name = "FAKE" self._default_library.library_registry_shared_secret = "s3cr3t5" # A QueryGeneratedLane to test code that handles it differently. self.contributor_lane = ContributorLane(self._db, self._default_library, "Someone", languages=["eng"], audiences=None)
def setup(self): super(TestOPDS, self).setup() parent = Lane(self._db, "Fiction", languages=["eng"], fiction=True) fantasy_lane = Lane(self._db, "Fantasy", languages=["eng"], genres=[Fantasy], parent=parent) self.lane = fantasy_lane # A QueryGeneratedLane to test code that handles it differently. self.contributor_lane = ContributorLane(self._db, "Someone", languages=["eng"], audiences=None)
def test_max_and_min_depth(self): with self.temp_config() as config: script = CacheRepresentationPerLane( self._db, ["--max-depth=0", "--min-depth=0"], testing=True) eq_(0, script.max_depth) child = Lane(self._db, "sublane") parent = Lane(self._db, "parent", sublanes=[child]) eq_(True, script.should_process_lane(parent)) eq_(False, script.should_process_lane(child)) script = CacheRepresentationPerLane(self._db, ["--min-depth=1"], testing=True) eq_(1, script.min_depth) eq_(False, script.should_process_lane(parent)) eq_(True, script.should_process_lane(child))
def lane_for_other_languages(_db, exclude_languages): """Make a lane for all books not in one of the given languages.""" YA = Classifier.AUDIENCE_YOUNG_ADULT CHILDREN = Classifier.AUDIENCE_CHILDREN common_args = dict( exclude_languages=exclude_languages, genres=None, ) adult_fiction = Lane( _db, full_name="Adult Fiction", display_name="Fiction", fiction=True, audiences=Classifier.AUDIENCES_ADULT, **common_args ) adult_nonfiction = Lane( _db, full_name="Adult Nonfiction", display_name="Nonfiction", fiction=False, audiences=Classifier.AUDIENCES_ADULT, **common_args ) ya_children = Lane( _db, full_name="Children & Young Adult", fiction=Lane.BOTH_FICTION_AND_NONFICTION, audiences=[YA, CHILDREN], **common_args ) lane = Lane( _db, full_name="Other Languages", sublanes=[adult_fiction, adult_nonfiction, ya_children], searchable=True, **common_args ) lane.default_for_language = True return lane
def lane_for_small_collection(_db, languages): YA = Classifier.AUDIENCE_YOUNG_ADULT CHILDREN = Classifier.AUDIENCE_CHILDREN common_args = dict( include_best_sellers=False, include_staff_picks=False, languages=languages, genres=None, ) adult_fiction = Lane( _db, full_name="Adult Fiction", display_name="Fiction", fiction=True, audiences=Classifier.AUDIENCES_ADULT, **common_args ) adult_nonfiction = Lane( _db, full_name="Adult Nonfiction", display_name="Nonfiction", fiction=False, audiences=Classifier.AUDIENCES_ADULT, **common_args ) ya_children = Lane( _db, full_name="Children & Young Adult", fiction=Lane.BOTH_FICTION_AND_NONFICTION, audiences=[YA, CHILDREN], **common_args ) name = LanguageCodes.name_for_languageset(languages) lane = Lane( _db, full_name=name, languages=languages, sublanes=[adult_fiction, adult_nonfiction, ya_children], searchable=True ) lane.default_for_language = True return lane
def get_parsed_feed(self, works, lane=None): if not lane: lane = Lane(self._db, self._default_library, "Main Lane") feed = AcquisitionFeed( self._db, "test", "url", works, CirculationManagerAnnotator(None, lane, self._default_library, test_mode=True)) return feedparser.parse(unicode(feed))
def test_process_lane(self): lane = Lane(self._db, self._default_library, self._str) script = CacheFacetListsPerLane(self._db, [ "--availability=all", "--availability=always", "--collection=main", "--collection=full", "--order=title", "--pages=1" ], testing=True) with script.app.test_request_context("/"): flask.request.library = self._default_library cached_feeds = script.process_lane(lane) # 2 availabilities * 2 collections * 1 order * 1 page = 4 feeds eq_(4, len(cached_feeds))
def test_group_uri_with_flattened_lane(self): spanish_lane = Lane(self._db, "Spanish", languages="spa") flat_spanish_lane = dict({ "lane": spanish_lane, "label": "All Spanish", "link_to_list_feed": True }) spanish_work = self._work(title="Spanish Book", with_license_pool=True, language="spa") lp = spanish_work.license_pools[0] self.annotator.lanes_by_work[spanish_work].append(flat_spanish_lane) feed_url = self.annotator.feed_url(spanish_lane) group_uri = self.annotator.group_uri(spanish_work, lp, lp.identifier) eq_((feed_url, "All Spanish"), group_uri)
def lane_for_small_collection(_db, library, languages): YA = Classifier.AUDIENCE_YOUNG_ADULT CHILDREN = Classifier.AUDIENCE_CHILDREN common_args = dict( include_best_sellers=False, include_staff_picks=False, languages=languages, genres=None, ) adult_fiction = Lane(_db, library, full_name="Adult Fiction", display_name="Fiction", fiction=True, audiences=Classifier.AUDIENCES_ADULT, **common_args) adult_nonfiction = Lane(_db, library, full_name="Adult Nonfiction", display_name="Nonfiction", fiction=False, audiences=Classifier.AUDIENCES_ADULT, **common_args) ya_children = Lane(_db, library, full_name="Children & Young Adult", fiction=Lane.BOTH_FICTION_AND_NONFICTION, audiences=[YA, CHILDREN], **common_args) name = LanguageCodes.name_for_languageset(languages) lane = Lane(_db, library, full_name=name, languages=languages, sublanes=[adult_fiction, adult_nonfiction, ya_children], searchable=True) lane.default_for_language = True return lane
def lanes_for_large_collection(_db, library, languages): YA = Classifier.AUDIENCE_YOUNG_ADULT CHILDREN = Classifier.AUDIENCE_CHILDREN common_args = dict( languages=languages, include_best_sellers=True, include_staff_picks=True, ) adult_fiction = Lane(_db, library, full_name="Adult Fiction", display_name="Fiction", genres=None, sublanes=lanes_from_genres( _db, library, fiction_genres, languages=languages, audiences=Classifier.AUDIENCES_ADULT, ), fiction=True, audiences=Classifier.AUDIENCES_ADULT, **common_args) adult_nonfiction = Lane(_db, library, full_name="Adult Nonfiction", display_name="Nonfiction", genres=None, sublanes=lanes_from_genres( _db, library, nonfiction_genres, languages=languages, audiences=Classifier.AUDIENCES_ADULT, ), fiction=False, audiences=Classifier.AUDIENCES_ADULT, **common_args) ya_common_args = dict( audiences=YA, languages=languages, ) ya_fiction = Lane( _db, library, full_name="Young Adult Fiction", genres=None, fiction=True, include_best_sellers=True, include_staff_picks=True, sublanes=[ Lane(_db, library, full_name="YA Dystopian", display_name="Dystopian", genres=[genres.Dystopian_SF], **ya_common_args), Lane(_db, library, full_name="YA Fantasy", display_name="Fantasy", genres=[genres.Fantasy], subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args), Lane(_db, library, full_name="YA Graphic Novels", display_name="Comics & Graphic Novels", genres=[genres.Comics_Graphic_Novels], **ya_common_args), Lane(_db, library, full_name="YA Literary Fiction", display_name="Contemporary Fiction", genres=[genres.Literary_Fiction], **ya_common_args), Lane(_db, library, full_name="YA LGBTQ Fiction", display_name="LGBTQ Fiction", genres=[genres.LGBTQ_Fiction], **ya_common_args), Lane(_db, library, full_name="Mystery & Thriller", genres=[genres.Suspense_Thriller, genres.Mystery], subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args), Lane(_db, library, full_name="YA Romance", display_name="Romance", genres=[genres.Romance], subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args), Lane(_db, library, full_name="YA Science Fiction", display_name="Science Fiction", genres=[genres.Science_Fiction], subgenre_behavior=Lane.IN_SAME_LANE, exclude_genres=[genres.Dystopian_SF, genres.Steampunk], **ya_common_args), Lane(_db, library, full_name="YA Steampunk", genres=[genres.Steampunk], subgenre_behavior=Lane.IN_SAME_LANE, display_name="Steampunk", **ya_common_args), # TODO: # Paranormal -- what is it exactly? ], **ya_common_args) ya_nonfiction = Lane( _db, library, full_name="Young Adult Nonfiction", genres=None, fiction=False, include_best_sellers=True, include_staff_picks=True, sublanes=[ Lane(_db, library, full_name="YA Biography", genres=genres.Biography_Memoir, display_name="Biography", **ya_common_args), Lane(_db, library, full_name="YA History", genres=[genres.History, genres.Social_Sciences], display_name="History & Sociology", subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args), Lane(_db, library, full_name="YA Life Strategies", display_name="Life Strategies", genres=[genres.Life_Strategies], **ya_common_args), Lane(_db, library, full_name="YA Religion & Spirituality", display_name="Religion & Spirituality", genres=genres.Religion_Spirituality, subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args) ], **ya_common_args) children_common_args = dict( audiences=genres.Classifier.AUDIENCE_CHILDREN, languages=languages, ) children = Lane(_db, library, full_name="Children and Middle Grade", genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION, include_best_sellers=True, include_staff_picks=True, searchable=True, sublanes=[ Lane(_db, library, full_name="Picture Books", age_range=[0, 1, 2, 3, 4], genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION, **children_common_args), Lane(_db, library, full_name="Easy readers", age_range=[5, 6, 7, 8], genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION, **children_common_args), Lane(_db, library, full_name="Chapter books", age_range=[9, 10, 11, 12], genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION, **children_common_args), Lane(_db, library, full_name="Children's Poetry", display_name="Poetry books", genres=[genres.Poetry], **children_common_args), Lane(_db, library, full_name="Children's Folklore", display_name="Folklore", genres=[genres.Folklore], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args), Lane(_db, library, full_name="Children's Fantasy", display_name="Fantasy", fiction=True, genres=[genres.Fantasy], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args), Lane(_db, library, full_name="Children's SF", display_name="Science Fiction", fiction=True, genres=[genres.Science_Fiction], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args), Lane(_db, library, full_name="Realistic fiction", fiction=True, genres=[genres.Literary_Fiction], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args), Lane(_db, library, full_name="Children's Graphic Novels", display_name="Comics & Graphic Novels", genres=[genres.Comics_Graphic_Novels], **children_common_args), Lane(_db, library, full_name="Biography", genres=[genres.Biography_Memoir], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args), Lane(_db, library, full_name="Historical fiction", genres=[genres.Historical_Fiction], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args), Lane(_db, library, full_name="Informational books", genres=None, fiction=False, exclude_genres=[genres.Biography_Memoir], subgenre_behavior=Lane.IN_SAME_LANE, **children_common_args) ], **children_common_args) name = LanguageCodes.name_for_languageset(languages) lane = Lane(_db, library, full_name=name, genres=None, sublanes=[ adult_fiction, adult_nonfiction, ya_fiction, ya_nonfiction, children ], fiction=Lane.BOTH_FICTION_AND_NONFICTION, searchable=True, invisible=True, **common_args) return [lane]
def custom_lists(self, identifier_type, identifier): self.require_librarian(flask.request.library) library = flask.request.library work = self.load_work(library, identifier_type, identifier) if isinstance(work, ProblemDetail): return work staff_data_source = DataSource.lookup(self._db, DataSource.LIBRARY_STAFF) if flask.request.method == "GET": lists = [] for entry in work.custom_list_entries: list = entry.customlist lists.append(dict(id=list.id, name=list.name)) return dict(custom_lists=lists) if flask.request.method == "POST": lists = flask.request.form.get("lists") if lists: lists = json.loads(lists) else: lists = [] affected_lanes = set() # Remove entries for lists that were not in the submitted form. submitted_ids = [l.get("id") for l in lists if l.get("id")] for entry in work.custom_list_entries: if entry.list_id not in submitted_ids: list = entry.customlist list.remove_entry(work) for lane in Lane.affected_by_customlist(list): affected_lanes.add(lane) # Add entries for any new lists. for list_info in lists: id = list_info.get("id") name = list_info.get("name") if id: is_new = False list = get_one(self._db, CustomList, id=int(id), name=name, library=library, data_source=staff_data_source) if not list: self._db.rollback() return MISSING_CUSTOM_LIST.detailed( _("Could not find list \"%(list_name)s\"", list_name=name)) else: list, is_new = create(self._db, CustomList, name=name, data_source=staff_data_source, library=library) list.created = datetime.now() entry, was_new = list.add_entry(work, featured=True) if was_new: for lane in Lane.affected_by_customlist(list): affected_lanes.add(lane) # If any list changes affected lanes, update their sizes. # NOTE: This may not make a difference until the # works are actually re-indexed. for lane in affected_lanes: lane.update_size(self._db, self.search_engine) return Response(unicode(_("Success")), 200)