Beispiel #1
0
def create_lane_for_tiny_collection(_db,
                                    library,
                                    parent,
                                    languages,
                                    priority=0):
    """Create a single lane for a tiny collection based on language.

    :param parent: The parent of the new lane.
    """
    if not languages:
        return None

    if isinstance(languages, basestring):
        languages = [languages]

    name = LanguageCodes.name_for_languageset(languages)
    language_lane, ignore = create(
        _db,
        Lane,
        library=library,
        display_name=name,
        parent=parent,
        genres=[],
        media=[Edition.BOOK_MEDIUM],
        fiction=None,
        priority=priority,
        languages=languages,
    )
    return priority + 1
Beispiel #2
0
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 library_configuration_settings(self, library, validator):
        for setting in Configuration.LIBRARY_SETTINGS:
            if setting.get("format") == "geographic":
                locations = validator.validate_geographic_areas(
                    self.list_setting(setting), self._db)
                if isinstance(locations, ProblemDetail):
                    return locations
                value = locations or self.current_value(setting, library)
            elif setting.get("type") == "list":
                value = self.list_setting(setting) or self.current_value(
                    setting, library)
                if setting.get("format") == "language-code":
                    value = json.dumps([
                        LanguageCodes.string_to_alpha_3(language)
                        for language in json.loads(value)
                    ])
            elif setting.get("type") == "image":
                value = self.image_setting(setting) or self.current_value(
                    setting, library)
            else:
                default = setting.get('default')
                value = flask.request.form.get(setting['key'], default)

            ConfigurationSetting.for_library(setting['key'],
                                             library).value = value
Beispiel #4
0
 def languages(self, library):
     ":yield: A list of output lines, one per language."
     for abbreviation, count in library.estimated_holdings_by_language(
         include_open_access=False
     ).most_common():
         display_name = LanguageCodes.name_for_languageset(abbreviation)
         yield "%s %i (%s)" % (abbreviation, count, display_name)
Beispiel #5
0
def create_lane_for_tiny_collection(_db, library, parent, languages, priority=0):
    """Create a single lane for a tiny collection based on language,
    if the language exists in the lookup table.

    :param parent: The parent of the new lane.
    """
    if not languages:
        return None

    if isinstance(languages, basestring):
        languages = [languages]
    
    try:
        name = LanguageCodes.name_for_languageset(languages)
    except ValueError as e:
        logging.getLogger().warn(
            "Could not create a lane for tiny collection with languages %s", languages
        )
        return 0

    language_lane, ignore = create(
        _db, Lane, library=library,
        display_name=name,
        parent=parent,
        genres=[],
        media=[Edition.BOOK_MEDIUM],
        fiction=None,
        priority=priority,
        languages=languages,
    )
    return priority + 1
Beispiel #6
0
def create_lane_for_small_collection(_db, library, parent, languages, priority=0):
    """Create a lane (with sublanes) for a small collection based on language.

    :param parent: The parent of the new lane.
    """
    if isinstance(languages, basestring):
        languages = [languages]

    ADULT = Classifier.AUDIENCES_ADULT
    YA_CHILDREN = [Classifier.AUDIENCE_YOUNG_ADULT, Classifier.AUDIENCE_CHILDREN]

    common_args = dict(
        languages=languages,
        media=[Edition.BOOK_MEDIUM],
        genres=[],
    )
    language_identifier = LanguageCodes.name_for_languageset(languages)
    sublane_priority = 0

    adult_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Fiction",
        fiction=True,
        audiences=ADULT,
        priority=sublane_priority,
        **common_args
    )
    sublane_priority += 1

    adult_nonfiction, ignore = create(
        _db, Lane, library=library,
        display_name="Nonfiction",
        fiction=False,
        audiences=ADULT,
        priority=sublane_priority,
        **common_args
    )
    sublane_priority += 1

    ya_children, ignore = create(
        _db, Lane, library=library,
        display_name="Children & Young Adult",
        fiction=None,
        audiences=YA_CHILDREN,
        priority=sublane_priority,
        **common_args
    )
    sublane_priority += 1

    lane, ignore = create(
        _db, Lane, library=library,
        display_name=language_identifier,
        parent=parent,
        sublanes=[adult_fiction, adult_nonfiction, ya_children],
        priority=priority,
        **common_args
    )
    priority += 1
    return priority
Beispiel #7
0
def create_lane_for_small_collection(_db, library, parent, languages, priority=0):
    """Create a lane (with sublanes) for a small collection based on language.

    :param parent: The parent of the new lane.
    """
    if isinstance(languages, basestring):
        languages = [languages]

    ADULT = Classifier.AUDIENCES_ADULT
    YA_CHILDREN = [Classifier.AUDIENCE_YOUNG_ADULT, Classifier.AUDIENCE_CHILDREN]

    common_args = dict(
        languages=languages,
        media=[Edition.BOOK_MEDIUM],
        genres=[],
    )
    language_identifier = LanguageCodes.name_for_languageset(languages)
    sublane_priority = 0

    adult_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Fiction",
        fiction=True,
        audiences=ADULT,
        priority=sublane_priority,
        **common_args
    )
    sublane_priority += 1

    adult_nonfiction, ignore = create(
        _db, Lane, library=library,
        display_name="Nonfiction",
        fiction=False,
        audiences=ADULT,
        priority=sublane_priority,
        **common_args
    )
    sublane_priority += 1

    ya_children, ignore = create(
        _db, Lane, library=library,
        display_name="Children & Young Adult",
        fiction=None,
        audiences=YA_CHILDREN,
        priority=sublane_priority,
        **common_args
    )
    sublane_priority += 1

    lane, ignore = create(
        _db, Lane, library=library,
        display_name=language_identifier,
        parent=parent,
        sublanes=[adult_fiction, adult_nonfiction, ya_children],
        priority=priority,
        **common_args
    )
    priority += 1
    return priority
    def parse(cls, file, data_source_name):
        metadata_records = []
        reader = csv.DictReader(file)

        for row in reader:
            publisher = unicode(row.get('Sello Editorial'), 'utf-8')
            title = unicode(row.get('Title'), 'utf-8')

            # The spreadsheet's identifier column is labeled ISBN, but
            # contains custom eLiburutegia IDs, like "ELIB201600288".
            identifier = row.get('ISBN')
            primary_identifier = IdentifierData(
                Identifier.ELIB_ID, identifier)

            issued_date = datetime.datetime.strptime(row.get('Publication Date'), "%m/%d/%Y")

            author = unicode(row.get('Author'), 'utf-8')
            contributors = [ContributorData(
                sort_name=author,
                roles=[Contributor.AUTHOR_ROLE]
            )]
            
            subjects = []
            bisac = row.get('BISAC')
            if bisac:
                subjects.append(SubjectData(Classifier.BISAC, bisac))

            ibic = row.get('IBIC')
            if ibic:
                # I haven't found any documentation on IBIC, so I am
                # treating it as BIC for now. It's possible that some
                # of the codes won't be valid BIC codes, but they'll
                # just be ignored.
                subjects.append(SubjectData(Classifier.BIC, ibic))

            age = row.get('Age')
            if age:
                age_re = re.compile(".*\(([\d-]+)\)")
                match = age_re.match(age)
                if match:
                    subjects.append(SubjectData(Classifier.AGE_RANGE, match.groups()[0]))            

            language = row.get('Language')
            if language:
                language = LanguageCodes.string_to_alpha_3(language)

            metadata_records.append(Metadata(
                data_source=data_source_name,
                title=title,
                language=language,
                medium=Edition.BOOK_MEDIUM,
                publisher=publisher,
                issued=issued_date,
                primary_identifier=primary_identifier,
                contributors=contributors,
                subjects=subjects,
            ))
        return metadata_records
Beispiel #9
0
    def parse_args(self, cmd_args=None):
        parser = self.arg_parser(self._db)
        parsed = parser.parse_args(cmd_args)
        self.languages = []
        if parsed.language:
            for language in parsed.language:
                alpha = LanguageCodes.string_to_alpha_3(language)
                if alpha:
                    self.languages.append(alpha)
                else:
                    self.log.warn("Ignored unrecognized language code %s", alpha)
        self.max_depth = parsed.max_depth
        self.min_depth = parsed.min_depth

        # Return the parsed arguments in case a subclass needs to
        # process more args.
        return parsed
    def _validate_setting(self, library, setting, validator=None):
        """Validate the incoming value for a single library setting.

        :param library: A Library
        :param setting: Configuration data for one of the library's settings.
        :param validator: A validation object for data of this type.
        """
        # TODO: there are some opportunities for improvement here:
        # * There's no standard interface for validators.
        # * We can handle settings that are lists of certain types (language codes,
        #   geographic areas), but not settings that are a single value of that type
        #   (_one_ language code or geographic area). Sometimes there's even an implication
        #   that a certain data type ('geographic') _must_ mean a list.
        # * A list value is returned as a JSON-encoded string. It
        #   would be better to keep that as a list for longer in case
        #   controller code needs to look at it.
        format = setting.get("format")
        type = setting.get("type")

        # In some cases, if there is no incoming value we can use a
        # default value or the current value.
        #
        # When the configuration item is a list, we can't do this
        # because an empty list may be a valid value.
        current_value = self.current_value(setting, library)
        default_value = setting.get("default") or current_value

        if format == "geographic":
            value = self.list_setting(setting)
            value = validator.validate_geographic_areas(value, self._db)
        elif type == "announcements":
            value = self.list_setting(setting, json_objects=True)
            value = validator.validate_announcements(value)
        elif type == "list":
            value = self.list_setting(setting)
            if format == "language-code":
                value = json.dumps([
                    LanguageCodes.string_to_alpha_3(language)
                    for language in json.loads(value)
                ])
        else:
            if type == "image":
                value = self.image_setting(setting) or default_value
            else:
                value = self.scalar_setting(setting) or default_value
        return value
    def library_configuration_settings(self, library, validator):
        for setting in Configuration.LIBRARY_SETTINGS:
            if setting.get("format") == "geographic":
                locations = validator.validate_geographic_areas(self.list_setting(setting), self._db)
                if isinstance(locations, ProblemDetail):
                    return locations
                value = locations or self.current_value(setting, library)
            elif setting.get("type") == "list":
                value = self.list_setting(setting) or self.current_value(setting, library)
                if setting.get("format") == "language-code":
                    value = json.dumps([LanguageCodes.string_to_alpha_3(language) for language in json.loads(value)])
            elif setting.get("type") == "image":
                value = self.image_setting(setting) or self.current_value(setting, library)
            else:
                default = setting.get('default')
                value = flask.request.form.get(setting['key'], default)

            ConfigurationSetting.for_library(setting['key'], library).value = value
Beispiel #12
0
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
Beispiel #13
0
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
Beispiel #14
0
def create_lane_for_tiny_collection(_db, library, parent, languages, priority=0):
    """Create a single lane for a tiny collection based on language.

    :param parent: The parent of the new lane.
    """
    if not languages:
        return None

    if isinstance(languages, basestring):
        languages = [languages]

    name = LanguageCodes.name_for_languageset(languages)
    language_lane, ignore = create(
        _db, Lane, library=library,
        display_name=name,
        parent=parent,
        genres=[],
        media=[Edition.BOOK_MEDIUM],
        fiction=None,
        priority=priority,
        languages=languages,
    )
    return priority + 1
Beispiel #15
0
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]
Beispiel #16
0
 def _is_language(self, language):
     # Check that the input string is in the list of recognized language codes.
     return LanguageCodes.string_to_alpha_3(language)
Beispiel #17
0
def lanes_for_large_collection(_db, 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, full_name="Adult Fiction", display_name="Fiction",
        genres=None,
        sublanes=lanes_from_genres(
            _db, fiction_genres, languages=languages,
            audiences=Classifier.AUDIENCES_ADULT,
        ),
        fiction=True, 
        audiences=Classifier.AUDIENCES_ADULT,
        **common_args
    )
    adult_nonfiction = Lane(
        _db, full_name="Adult Nonfiction", display_name="Nonfiction",
        genres=None,
        sublanes=lanes_from_genres(
            _db, 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, full_name="Young Adult Fiction", genres=None, fiction=True,
        include_best_sellers=True,
        include_staff_picks=True,        
        sublanes=[
            Lane(_db, full_name="YA Dystopian",
                 display_name="Dystopian", genres=[genres.Dystopian_SF],
                 **ya_common_args),
            Lane(_db, full_name="YA Fantasy", display_name="Fantasy",
                 genres=[genres.Fantasy], 
                 subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args),
            Lane(_db, full_name="YA Graphic Novels",
                 display_name="Comics & Graphic Novels",
                 genres=[genres.Comics_Graphic_Novels], **ya_common_args),
            Lane(_db, full_name="YA Literary Fiction",
                 display_name="Contemporary Fiction",
                 genres=[genres.Literary_Fiction], **ya_common_args),
            Lane(_db, full_name="YA LGBTQ Fiction", 
                 display_name="LGBTQ Fiction",
                 genres=[genres.LGBTQ_Fiction],
                 **ya_common_args),
            Lane(_db, full_name="Mystery & Thriller",
                 genres=[genres.Suspense_Thriller, genres.Mystery],
                 subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args),
            Lane(_db, full_name="YA Romance", display_name="Romance",
                 genres=[genres.Romance],
                 subgenre_behavior=Lane.IN_SAME_LANE, **ya_common_args),
            Lane(_db, 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, 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, full_name="Young Adult Nonfiction", genres=None, fiction=False,
        include_best_sellers=True,
        include_staff_picks=True,
        sublanes=[
            Lane(_db, full_name="YA Biography", 
                 genres=genres.Biography_Memoir,
                 display_name="Biography",
                 **ya_common_args
                 ),
            Lane(_db, 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, full_name="YA Life Strategies",
                 display_name="Life Strategies",
                 genres=[genres.Life_Strategies], 
                 **ya_common_args
                 ),
            Lane(_db, 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, full_name="Children and Middle Grade", genres=None,
        fiction=Lane.BOTH_FICTION_AND_NONFICTION,
        include_best_sellers=True,
        include_staff_picks=True,
        sublanes=[
            Lane(_db, full_name="Picture Books", age_range=[0,1,2,3,4],
                 genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION,
                 **children_common_args
             ),
            Lane(_db, full_name="Easy readers", age_range=[5,6,7,8],
                 genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION,
                 **children_common_args
             ),
            Lane(_db, full_name="Chapter books", age_range=[9,10,11,12],
                 genres=None, fiction=Lane.BOTH_FICTION_AND_NONFICTION,
                 **children_common_args
             ),
            Lane(_db, full_name="Children's Poetry", 
                 display_name="Poetry books", genres=[genres.Poetry],
                 **children_common_args
             ),
            Lane(_db, full_name="Children's Folklore", display_name="Folklore",
                 genres=[genres.Folklore],
                 subgenre_behavior=Lane.IN_SAME_LANE,
                 **children_common_args
             ),
            Lane(_db, full_name="Children's Fantasy", display_name="Fantasy",
                 fiction=True,
                 genres=[genres.Fantasy], 
                 subgenre_behavior=Lane.IN_SAME_LANE,
                 **children_common_args
             ),
            Lane(_db, 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, full_name="Realistic fiction", 
                 fiction=True, genres=[genres.Literary_Fiction],
                 subgenre_behavior=Lane.IN_SAME_LANE,
                 **children_common_args
             ),
            Lane(_db, full_name="Children's Graphic Novels",
                 display_name="Comics & Graphic Novels",
                 genres=[genres.Comics_Graphic_Novels],
                 **children_common_args
             ),
            Lane(_db, full_name="Biography", 
                 genres=[genres.Biography_Memoir],
                 subgenre_behavior=Lane.IN_SAME_LANE,
                 **children_common_args
             ),
            Lane(_db, full_name="Historical fiction", 
                 genres=[genres.Historical_Fiction],
                 subgenre_behavior=Lane.IN_SAME_LANE, 
                 **children_common_args
             ),
            Lane(_db, full_name="Informational books", genres=None,
                 fiction=False, exclude_genres=[genres.Biography_Memoir],
                 **children_common_args
             )
        ],
        **children_common_args
    )

    name = LanguageCodes.name_for_languageset(languages)
    lane = Lane(
        _db, 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]
Beispiel #18
0
def create_lanes_for_large_collection(_db, library, languages, priority=0):
    """Ensure that the lanes appropriate to a large collection are all
    present.

    This means:

    * A "%(language)s Adult Fiction" lane containing sublanes for each fiction
    genre.

    * A "%(language)s Adult Nonfiction" lane containing sublanes for
    each nonfiction genre.

    * A "%(language)s YA Fiction" lane containing sublanes for the
      most popular YA fiction genres.

    * A "%(language)s YA Nonfiction" lane containing sublanes for the
      most popular YA fiction genres.

    * A "%(language)s Children and Middle Grade" lane containing
      sublanes for childrens' books at different age levels.

    :param library: Newly created lanes will be associated with this
        library.
    :param languages: Newly created lanes will contain only books
        in these languages.
    :return: A list of top-level Lane objects.

    TODO: If there are multiple large collections, their top-level lanes do
    not have distinct display names.
    """
    if isinstance(languages, basestring):
        languages = [languages]

    ADULT = Classifier.AUDIENCES_ADULT
    YA = [Classifier.AUDIENCE_YOUNG_ADULT]
    CHILDREN = [Classifier.AUDIENCE_CHILDREN]

    common_args = dict(
        languages=languages,
        media=None
    )
    adult_common_args = dict(common_args)
    adult_common_args['audiences'] = ADULT

    include_best_sellers = False
    nyt_data_source = DataSource.lookup(_db, DataSource.NYT)
    nyt_integration = get_one(
        _db, ExternalIntegration,
        goal=ExternalIntegration.METADATA_GOAL,
        protocol=ExternalIntegration.NYT,
    )
    if nyt_integration:
        include_best_sellers = True

    language_identifier = LanguageCodes.name_for_languageset(languages)

    sublanes = []
    if include_best_sellers:
        best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            priority=priority,
            **common_args
        )
        priority += 1
        best_sellers.list_datasource = nyt_data_source
        sublanes.append(best_sellers)


    adult_fiction_sublanes = []
    adult_fiction_priority = 0
    if include_best_sellers:
        adult_fiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=True,
            priority=adult_fiction_priority,
            **adult_common_args
        )
        adult_fiction_priority += 1
        adult_fiction_best_sellers.list_datasource = nyt_data_source
        adult_fiction_sublanes.append(adult_fiction_best_sellers)

    for genre in fiction_genres:
        if isinstance(genre, basestring):
            genre_name = genre
        else:
            genre_name = genre.get("name")
        genre_lane = lane_from_genres(
            _db, library, [genre],
            priority=adult_fiction_priority,
            **adult_common_args)
        adult_fiction_priority += 1
        adult_fiction_sublanes.append(genre_lane)

    adult_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Fiction",
        genres=[],
        sublanes=adult_fiction_sublanes,
        fiction=True,
        priority=priority,
        **adult_common_args
    )
    priority += 1
    sublanes.append(adult_fiction)

    adult_nonfiction_sublanes = []
    adult_nonfiction_priority = 0
    if include_best_sellers:
        adult_nonfiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=False,
            priority=adult_nonfiction_priority,
            **adult_common_args
        )
        adult_nonfiction_priority += 1
        adult_nonfiction_best_sellers.list_datasource = nyt_data_source
        adult_nonfiction_sublanes.append(adult_nonfiction_best_sellers)

    for genre in nonfiction_genres:
        # "Life Strategies" is a YA-specific genre that should not be
        # included in the Adult Nonfiction lane.
        if genre != genres.Life_Strategies:
            if isinstance(genre, basestring):
                genre_name = genre
            else:
                genre_name = genre.get("name")
            genre_lane = lane_from_genres(
                _db, library, [genre],
                priority=adult_nonfiction_priority,
                **adult_common_args)
            adult_nonfiction_priority += 1
            adult_nonfiction_sublanes.append(genre_lane)

    adult_nonfiction, ignore = create(
        _db, Lane, library=library,
        display_name="Nonfiction",
        genres=[],
        sublanes=adult_nonfiction_sublanes,
        fiction=False,
        priority=priority,
        **adult_common_args
    )
    priority += 1
    sublanes.append(adult_nonfiction)

    ya_common_args = dict(common_args)
    ya_common_args['audiences'] = YA

    ya_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Young Adult Fiction",
        genres=[], fiction=True,
        sublanes=[],
        priority=priority,
        **ya_common_args
    )
    priority += 1
    sublanes.append(ya_fiction)

    ya_fiction_priority = 0
    if include_best_sellers:
        ya_fiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=True,
            priority=ya_fiction_priority,
            **ya_common_args
        )
        ya_fiction_priority += 1
        ya_fiction_best_sellers.list_datasource = nyt_data_source
        ya_fiction.sublanes.append(ya_fiction_best_sellers)

    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Dystopian_SF],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Fantasy],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Comics_Graphic_Novels],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Literary_Fiction],
                         display_name="Contemporary Fiction",
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.LGBTQ_Fiction],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Suspense_Thriller, genres.Mystery],
                         display_name="Mystery & Thriller",
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Romance],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Science_Fiction],
                         exclude_genres=[genres.Dystopian_SF, genres.Steampunk],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Steampunk],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1

    ya_nonfiction, ignore = create(
        _db, Lane, library=library,
        display_name="Young Adult Nonfiction",
        genres=[], fiction=False,
        sublanes=[],
        priority=priority,
        **ya_common_args
    )
    priority += 1
    sublanes.append(ya_nonfiction)

    ya_nonfiction_priority = 0
    if include_best_sellers:
        ya_nonfiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=False,
            priority=ya_nonfiction_priority,
            **ya_common_args
        )
        ya_nonfiction_priority += 1
        ya_nonfiction_best_sellers.list_datasource = nyt_data_source
        ya_nonfiction.sublanes.append(ya_nonfiction_best_sellers)

    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Biography_Memoir],
                         display_name="Biography",
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1
    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.History, genres.Social_Sciences],
                         display_name="History & Sociology",
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1
    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Life_Strategies],
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1
    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Religion_Spirituality],
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1


    children_common_args = dict(common_args)
    children_common_args['audiences'] = CHILDREN

    children, ignore = create(
        _db, Lane, library=library,
        display_name="Children and Middle Grade",
        genres=[], fiction=None,
        sublanes=[],
        priority=priority,
        **children_common_args
    )
    priority += 1
    sublanes.append(children)

    children_priority = 0
    if include_best_sellers:
        children_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            priority=children_priority,
            **children_common_args
        )
        children_priority += 1
        children_best_sellers.list_datasource = nyt_data_source
        children.sublanes.append(children_best_sellers)

    picture_books, ignore = create(
        _db, Lane, library=library,
        display_name="Picture Books",
        target_age=(0,4), genres=[], fiction=None,
        priority=children_priority,
        languages=languages,
    )
    children_priority += 1
    children.sublanes.append(picture_books)

    easy_readers, ignore = create(
        _db, Lane, library=library,
        display_name="Easy Readers",
        target_age=(5,8), genres=[], fiction=None,
        priority=children_priority,
        languages=languages,
    )
    children_priority += 1
    children.sublanes.append(easy_readers)

    chapter_books, ignore = create(
        _db, Lane, library=library,
        display_name="Chapter Books",
        target_age=(9,12), genres=[], fiction=None,
        priority=children_priority,
        languages=languages,
    )
    children_priority += 1
    children.sublanes.append(chapter_books)

    children_poetry, ignore = create(
        _db, Lane, library=library,
        display_name="Poetry Books",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_poetry.add_genre(genres.Poetry.name)
    children.sublanes.append(children_poetry)

    children_folklore, ignore = create(
        _db, Lane, library=library,
        display_name="Folklore",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_folklore.add_genre(genres.Folklore.name)
    children.sublanes.append(children_folklore)

    children_fantasy, ignore = create(
        _db, Lane, library=library,
        display_name="Fantasy",
        fiction=True,
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_fantasy.add_genre(genres.Fantasy.name)
    children.sublanes.append(children_fantasy)

    children_sf, ignore = create(
        _db, Lane, library=library,
        display_name="Science Fiction",
        fiction=True,
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_sf.add_genre(genres.Science_Fiction.name)
    children.sublanes.append(children_sf)

    realistic_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Realistic Fiction",
        fiction=True,
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    realistic_fiction.add_genre(genres.Literary_Fiction.name)
    children.sublanes.append(realistic_fiction)

    children_graphic_novels, ignore = create(
        _db, Lane, library=library,
        display_name="Comics & Graphic Novels",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_graphic_novels.add_genre(genres.Comics_Graphic_Novels.name)
    children.sublanes.append(children_graphic_novels)

    children_biography, ignore = create(
        _db, Lane, library=library,
        display_name="Biography",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_biography.add_genre(genres.Biography_Memoir.name)
    children.sublanes.append(children_biography)

    children_historical_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Historical Fiction",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_historical_fiction.add_genre(genres.Historical_Fiction.name)
    children.sublanes.append(children_historical_fiction)

    informational, ignore = create(
        _db, Lane, library=library,
        display_name="Informational Books",
        fiction=False, genres=[],
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    informational.add_genre(genres.Biography_Memoir.name, inclusive=False)
    children.sublanes.append(informational)

    return priority
Beispiel #19
0
def create_lanes_for_large_collection(_db, library, languages, priority=0):
    """Ensure that the lanes appropriate to a large collection are all
    present.

    This means:

    * A "%(language)s Adult Fiction" lane containing sublanes for each fiction
        genre.
    * A "%(language)s Adult Nonfiction" lane containing sublanes for
        each nonfiction genre.
    * A "%(language)s YA Fiction" lane containing sublanes for the
        most popular YA fiction genres.
    * A "%(language)s YA Nonfiction" lane containing sublanes for the
        most popular YA fiction genres.
    * A "%(language)s Children and Middle Grade" lane containing
        sublanes for childrens' books at different age levels.

    :param library: Newly created lanes will be associated with this
        library.
    :param languages: Newly created lanes will contain only books
        in these languages.
    :return: A list of top-level Lane objects.

    TODO: If there are multiple large collections, their top-level lanes do
    not have distinct display names.
    """
    if isinstance(languages, basestring):
        languages = [languages]

    ADULT = Classifier.AUDIENCES_ADULT
    YA = [Classifier.AUDIENCE_YOUNG_ADULT]
    CHILDREN = [Classifier.AUDIENCE_CHILDREN]

    common_args = dict(
        languages=languages,
        media=None
    )
    adult_common_args = dict(common_args)
    adult_common_args['audiences'] = ADULT

    include_best_sellers = False
    nyt_data_source = DataSource.lookup(_db, DataSource.NYT)
    nyt_integration = get_one(
        _db, ExternalIntegration,
        goal=ExternalIntegration.METADATA_GOAL,
        protocol=ExternalIntegration.NYT,
    )
    if nyt_integration:
        include_best_sellers = True

    language_identifier = LanguageCodes.name_for_languageset(languages)

    sublanes = []
    if include_best_sellers:
        best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            priority=priority,
            **common_args
        )
        priority += 1
        best_sellers.list_datasource = nyt_data_source
        sublanes.append(best_sellers)


    adult_fiction_sublanes = []
    adult_fiction_priority = 0
    if include_best_sellers:
        adult_fiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=True,
            priority=adult_fiction_priority,
            **adult_common_args
        )
        adult_fiction_priority += 1
        adult_fiction_best_sellers.list_datasource = nyt_data_source
        adult_fiction_sublanes.append(adult_fiction_best_sellers)

    for genre in fiction_genres:
        if isinstance(genre, basestring):
            genre_name = genre
        else:
            genre_name = genre.get("name")
        genre_lane = lane_from_genres(
            _db, library, [genre],
            priority=adult_fiction_priority,
            **adult_common_args)
        adult_fiction_priority += 1
        adult_fiction_sublanes.append(genre_lane)

    adult_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Fiction",
        genres=[],
        sublanes=adult_fiction_sublanes,
        fiction=True,
        priority=priority,
        **adult_common_args
    )
    priority += 1
    sublanes.append(adult_fiction)

    adult_nonfiction_sublanes = []
    adult_nonfiction_priority = 0
    if include_best_sellers:
        adult_nonfiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=False,
            priority=adult_nonfiction_priority,
            **adult_common_args
        )
        adult_nonfiction_priority += 1
        adult_nonfiction_best_sellers.list_datasource = nyt_data_source
        adult_nonfiction_sublanes.append(adult_nonfiction_best_sellers)

    for genre in nonfiction_genres:
        # "Life Strategies" is a YA-specific genre that should not be
        # included in the Adult Nonfiction lane.
        if genre != genres.Life_Strategies:
            if isinstance(genre, basestring):
                genre_name = genre
            else:
                genre_name = genre.get("name")
            genre_lane = lane_from_genres(
                _db, library, [genre],
                priority=adult_nonfiction_priority,
                **adult_common_args)
            adult_nonfiction_priority += 1
            adult_nonfiction_sublanes.append(genre_lane)

    adult_nonfiction, ignore = create(
        _db, Lane, library=library,
        display_name="Nonfiction",
        genres=[],
        sublanes=adult_nonfiction_sublanes,
        fiction=False,
        priority=priority,
        **adult_common_args
    )
    priority += 1
    sublanes.append(adult_nonfiction)

    ya_common_args = dict(common_args)
    ya_common_args['audiences'] = YA

    ya_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Young Adult Fiction",
        genres=[], fiction=True,
        sublanes=[],
        priority=priority,
        **ya_common_args
    )
    priority += 1
    sublanes.append(ya_fiction)

    ya_fiction_priority = 0
    if include_best_sellers:
        ya_fiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=True,
            priority=ya_fiction_priority,
            **ya_common_args
        )
        ya_fiction_priority += 1
        ya_fiction_best_sellers.list_datasource = nyt_data_source
        ya_fiction.sublanes.append(ya_fiction_best_sellers)

    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Dystopian_SF],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Fantasy],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Comics_Graphic_Novels],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Literary_Fiction],
                         display_name="Contemporary Fiction",
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.LGBTQ_Fiction],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Suspense_Thriller, genres.Mystery],
                         display_name="Mystery & Thriller",
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Romance],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Science_Fiction],
                         exclude_genres=[genres.Dystopian_SF, genres.Steampunk],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1
    ya_fiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Steampunk],
                         priority=ya_fiction_priority, **ya_common_args))
    ya_fiction_priority += 1

    ya_nonfiction, ignore = create(
        _db, Lane, library=library,
        display_name="Young Adult Nonfiction",
        genres=[], fiction=False,
        sublanes=[],
        priority=priority,
        **ya_common_args
    )
    priority += 1
    sublanes.append(ya_nonfiction)

    ya_nonfiction_priority = 0
    if include_best_sellers:
        ya_nonfiction_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            fiction=False,
            priority=ya_nonfiction_priority,
            **ya_common_args
        )
        ya_nonfiction_priority += 1
        ya_nonfiction_best_sellers.list_datasource = nyt_data_source
        ya_nonfiction.sublanes.append(ya_nonfiction_best_sellers)

    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Biography_Memoir],
                         display_name="Biography",
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1
    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.History, genres.Social_Sciences],
                         display_name="History & Sociology",
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1
    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Life_Strategies],
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1
    ya_nonfiction.sublanes.append(
        lane_from_genres(_db, library, [genres.Religion_Spirituality],
                         priority=ya_nonfiction_priority, **ya_common_args))
    ya_nonfiction_priority += 1


    children_common_args = dict(common_args)
    children_common_args['audiences'] = CHILDREN

    children, ignore = create(
        _db, Lane, library=library,
        display_name="Children and Middle Grade",
        genres=[], fiction=None,
        sublanes=[],
        priority=priority,
        **children_common_args
    )
    priority += 1
    sublanes.append(children)

    children_priority = 0
    if include_best_sellers:
        children_best_sellers, ignore = create(
            _db, Lane, library=library,
            display_name="Best Sellers",
            priority=children_priority,
            **children_common_args
        )
        children_priority += 1
        children_best_sellers.list_datasource = nyt_data_source
        children.sublanes.append(children_best_sellers)

    picture_books, ignore = create(
        _db, Lane, library=library,
        display_name="Picture Books",
        target_age=(0,4), genres=[], fiction=None,
        priority=children_priority,
        languages=languages,
    )
    children_priority += 1
    children.sublanes.append(picture_books)

    easy_readers, ignore = create(
        _db, Lane, library=library,
        display_name="Easy Readers",
        target_age=(5,8), genres=[], fiction=None,
        priority=children_priority,
        languages=languages,
    )
    children_priority += 1
    children.sublanes.append(easy_readers)

    chapter_books, ignore = create(
        _db, Lane, library=library,
        display_name="Chapter Books",
        target_age=(9,12), genres=[], fiction=None,
        priority=children_priority,
        languages=languages,
    )
    children_priority += 1
    children.sublanes.append(chapter_books)

    children_poetry, ignore = create(
        _db, Lane, library=library,
        display_name="Poetry Books",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_poetry.add_genre(genres.Poetry.name)
    children.sublanes.append(children_poetry)

    children_folklore, ignore = create(
        _db, Lane, library=library,
        display_name="Folklore",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_folklore.add_genre(genres.Folklore.name)
    children.sublanes.append(children_folklore)

    children_fantasy, ignore = create(
        _db, Lane, library=library,
        display_name="Fantasy",
        fiction=True,
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_fantasy.add_genre(genres.Fantasy.name)
    children.sublanes.append(children_fantasy)

    children_sf, ignore = create(
        _db, Lane, library=library,
        display_name="Science Fiction",
        fiction=True,
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_sf.add_genre(genres.Science_Fiction.name)
    children.sublanes.append(children_sf)

    realistic_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Realistic Fiction",
        fiction=True,
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    realistic_fiction.add_genre(genres.Literary_Fiction.name)
    children.sublanes.append(realistic_fiction)

    children_graphic_novels, ignore = create(
        _db, Lane, library=library,
        display_name="Comics & Graphic Novels",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_graphic_novels.add_genre(genres.Comics_Graphic_Novels.name)
    children.sublanes.append(children_graphic_novels)

    children_biography, ignore = create(
        _db, Lane, library=library,
        display_name="Biography",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_biography.add_genre(genres.Biography_Memoir.name)
    children.sublanes.append(children_biography)

    children_historical_fiction, ignore = create(
        _db, Lane, library=library,
        display_name="Historical Fiction",
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    children_historical_fiction.add_genre(genres.Historical_Fiction.name)
    children.sublanes.append(children_historical_fiction)

    informational, ignore = create(
        _db, Lane, library=library,
        display_name="Informational Books",
        fiction=False, genres=[],
        priority=children_priority,
        **children_common_args
    )
    children_priority += 1
    informational.add_genre(genres.Biography_Memoir.name, inclusive=False)
    children.sublanes.append(informational)

    return priority
Beispiel #20
0
    def edit(self, identifier_type, identifier):
        """Edit a work's metadata."""
        self.require_librarian(flask.request.library)

        # TODO: It would be nice to use the metadata layer for this, but
        # this code handles empty values differently than other metadata
        # sources. When a staff member deletes a value, that indicates
        # they think it should be empty. This needs to be indicated in the
        # db so that it can overrule other data sources that set a value,
        # unlike other sources which set empty fields to None.

        work = self.load_work(flask.request.library, identifier_type,
                              identifier)
        if isinstance(work, ProblemDetail):
            return work

        changed = False

        staff_data_source = DataSource.lookup(self._db,
                                              DataSource.LIBRARY_STAFF)
        primary_identifier = work.presentation_edition.primary_identifier
        staff_edition, is_new = get_one_or_create(
            self._db,
            Edition,
            primary_identifier_id=primary_identifier.id,
            data_source_id=staff_data_source.id)
        self._db.expire(primary_identifier)

        new_title = flask.request.form.get("title")
        if new_title and work.title != new_title:
            staff_edition.title = unicode(new_title)
            changed = True

        new_subtitle = flask.request.form.get("subtitle")
        if work.subtitle != new_subtitle:
            if work.subtitle and not new_subtitle:
                new_subtitle = NO_VALUE
            staff_edition.subtitle = unicode(new_subtitle)
            changed = True

        # The form data includes roles and names for contributors in the same order.
        new_contributor_roles = flask.request.form.getlist("contributor-role")
        new_contributor_names = [
            unicode(n) for n in flask.request.form.getlist("contributor-name")
        ]
        # The first author in the form is considered the primary author, even
        # though there's no separate MARC code for that.
        for i, role in enumerate(new_contributor_roles):
            if role == Contributor.AUTHOR_ROLE:
                new_contributor_roles[i] = Contributor.PRIMARY_AUTHOR_ROLE
                break
        roles_and_names = zip(new_contributor_roles, new_contributor_names)

        # Remove any contributions that weren't in the form, and remove contributions
        # that already exist from the list so they won't be added again.
        deleted_contributions = False
        for contribution in staff_edition.contributions:
            if (contribution.role, contribution.contributor.display_name
                ) not in roles_and_names:
                self._db.delete(contribution)
                deleted_contributions = True
                changed = True
            else:
                roles_and_names.remove(
                    (contribution.role, contribution.contributor.display_name))
        if deleted_contributions:
            # Ensure the staff edition's contributions are up-to-date when
            # calculating the presentation edition later.
            self._db.refresh(staff_edition)

        # Any remaining roles and names are new contributions.
        for role, name in roles_and_names:
            # There may be one extra role at the end from the input for
            # adding a contributor, in which case it will have no
            # corresponding name and can be ignored.
            if name:
                if role not in Contributor.MARC_ROLE_CODES.keys():
                    self._db.rollback()
                    return UNKNOWN_ROLE.detailed(
                        _("Role %(role)s is not one of the known contributor roles.",
                          role=role))
                contributor = staff_edition.add_contributor(name=name,
                                                            roles=[role])
                contributor.display_name = name
                changed = True

        new_series = flask.request.form.get("series")
        if work.series != new_series:
            if work.series and not new_series:
                new_series = NO_VALUE
            staff_edition.series = unicode(new_series)
            changed = True

        new_series_position = flask.request.form.get("series_position")
        if new_series_position != None and new_series_position != '':
            try:
                new_series_position = int(new_series_position)
            except ValueError:
                self._db.rollback()
                return INVALID_SERIES_POSITION
        else:
            new_series_position = None
        if work.series_position != new_series_position:
            if work.series_position and new_series_position == None:
                new_series_position = NO_NUMBER
            staff_edition.series_position = new_series_position
            changed = True

        new_medium = flask.request.form.get("medium")
        if new_medium:
            if new_medium not in Edition.medium_to_additional_type.keys():
                self._db.rollback()
                return UNKNOWN_MEDIUM.detailed(
                    _("Medium %(medium)s is not one of the known media.",
                      medium=new_medium))
            staff_edition.medium = new_medium
            changed = True

        new_language = flask.request.form.get("language")
        if new_language != None and new_language != '':
            new_language = LanguageCodes.string_to_alpha_3(new_language)
            if not new_language:
                self._db.rollback()
                return UNKNOWN_LANGUAGE
        else:
            new_language = None
        if new_language != staff_edition.language:
            staff_edition.language = new_language
            changed = True

        new_publisher = flask.request.form.get("publisher")
        if new_publisher != staff_edition.publisher:
            if staff_edition.publisher and not new_publisher:
                new_publisher = NO_VALUE
            staff_edition.publisher = unicode(new_publisher)
            changed = True

        new_imprint = flask.request.form.get("imprint")
        if new_imprint != staff_edition.imprint:
            if staff_edition.imprint and not new_imprint:
                new_imprint = NO_VALUE
            staff_edition.imprint = unicode(new_imprint)
            changed = True

        new_issued = flask.request.form.get("issued")
        if new_issued != None and new_issued != '':
            try:
                new_issued = datetime.strptime(new_issued, '%Y-%m-%d')
            except ValueError:
                self._db.rollback()
                return INVALID_DATE_FORMAT
        else:
            new_issued = None
        if new_issued != staff_edition.issued:
            staff_edition.issued = new_issued
            changed = True

        # TODO: This lets library staff add a 1-5 rating, which is used in the
        # quality calculation. However, this doesn't work well if there are any
        # other measurements that contribute to the quality. The form will show
        # the calculated quality rather than the staff rating, which will be
        # confusing. It might also be useful to make it more clear how this
        # relates to the quality threshold in the library settings.
        changed_rating = False
        new_rating = flask.request.form.get("rating")
        if new_rating != None and new_rating != '':
            try:
                new_rating = float(new_rating)
            except ValueError:
                self._db.rollback()
                return INVALID_RATING
            scale = Measurement.RATING_SCALES[DataSource.LIBRARY_STAFF]
            if new_rating < scale[0] or new_rating > scale[1]:
                self._db.rollback()
                return INVALID_RATING.detailed(
                    _("The rating must be a number between %(low)s and %(high)s.",
                      low=scale[0],
                      high=scale[1]))
            if (new_rating - scale[0]) / (scale[1] - scale[0]) != work.quality:
                primary_identifier.add_measurement(
                    staff_data_source,
                    Measurement.RATING,
                    new_rating,
                    weight=WorkController.STAFF_WEIGHT)
                changed = True
                changed_rating = True

        changed_summary = False
        new_summary = flask.request.form.get("summary") or ""
        if new_summary != work.summary_text:
            old_summary = None
            if work.summary and work.summary.data_source == staff_data_source:
                old_summary = work.summary

            work.presentation_edition.primary_identifier.add_link(
                Hyperlink.DESCRIPTION,
                None,
                staff_data_source,
                content=new_summary)

            # Delete previous staff summary
            if old_summary:
                for link in old_summary.links:
                    self._db.delete(link)
                self._db.delete(old_summary)

            changed = True
            changed_summary = True

        if changed:
            # Even if the presentation doesn't visibly change, we want
            # to regenerate the OPDS entries and update the search
            # index for the work, because that might be the 'real'
            # problem the user is trying to fix.
            policy = PresentationCalculationPolicy(
                classify=True,
                regenerate_opds_entries=True,
                regenerate_marc_record=True,
                update_search_index=True,
                calculate_quality=changed_rating,
                choose_summary=changed_summary,
            )
            work.calculate_presentation(policy=policy)

        return Response("", 200)
 def _is_language(self, language):
     # Check that the input string is in the list of recognized language codes.
     return LanguageCodes.string_to_alpha_3(language)