def setup(self, os, sql): os.f_format_subtitle = os.format_subtitle os.f_format_url = BaseSearcher.SearchUrlFormatter('author') os.f_format_thumb_url = os.format_none os.sort_orders = ('downloads', 'quantity', 'alpha', 'release_date') os.icon = 'author' os.class_ += 'navlink' os.title = _('All Authors') sql.query = """ SELECT authors.author as title, coalesce (authors.born_floor || '', '') || '-' || coalesce (authors.died_floor || '', '') as subtitle, authors.pk as pk, max (books.release_date) as release_date, sum (books.downloads) as downloads, count (books.pk) as quantity""" sql.from_ = ('authors', 'mn_books_authors as mn', 'books') sql.groupby += ('authors.author', 'subtitle', 'authors.pk') sql.where.append('authors.pk = mn.fk_authors') sql.where.append('books.pk = mn.fk_books') if len(os.query): sql.fulltext('authors.tsvec', os.query) os.title = _("Authors: {author}").format(author=os.query) else: sql.where.append( "authors.author not in ('Various', 'Anonymous', 'Unknown')")
def setup(self, os, sql): os.f_format_url = BaseSearcher.SearchUrlFormatter('bookshelf') os.f_format_thumb_url = os.format_none os.sort_orders = ('downloads', 'quantity', 'alpha', 'release_date', 'authors') os.icon = 'bookshelf' os.class_ += 'navlink' os.title = _('All Bookshelves') sql.query = """ SELECT bookshelves.bookshelf as title, bookshelves.pk as pk, max (books.release_date) as release_date, sum (books.downloads) as downloads, count (books.pk) as quantity""" sql.from_ = ('bookshelves', 'mn_books_bookshelves as mn', 'books') sql.groupby += ('bookshelves.bookshelf', 'bookshelves.pk') sql.where.append('bookshelves.pk = mn.fk_bookshelves') sql.where.append('books.pk = mn.fk_books') if len(os.query): sql.fulltext('bookshelves.tsvec', os.query) os.title = _("Bookshelves: {bookshelf}").format(bookshelf=os.query)
def dummy_text_holder (): """Never gets called. Only holds some gettext messages to translate. Keep this in sync with GutenbergDatabaseDublinCore. """ _('Copyrighted. Read the copyright notice inside this book for details.') _('Public domain in the USA.')
def index(self, **dummy_kwargs): """ Output the start page. """ os = BaseSearcher.OpenSearch() os.log_request('start') os.search_terms = '' os.title = { 'opds': _('Project Gutenberg'), 'stanza': _('Project Gutenberg') }.get(os.format, _('Search Project Gutenberg')) cat = BaseSearcher.Cat() cat.header = _( 'Welcome to Project Gutenberg. Use the search box to find your book or pick a link.' ) cat.title = _('Popular') cat.subtitle = _('Our most popular books.') cat.url = os.url('search', sort_order='downloads') cat.class_ += 'navlink' cat.icon = 'popular' cat.order = 2 os.entries.append(cat) cat = BaseSearcher.Cat() cat.title = _('Latest') cat.subtitle = _('Our latest releases.') cat.url = os.url('search', sort_order='release_date') cat.class_ += 'navlink' cat.icon = 'date' cat.order = 3 os.entries.append(cat) cat = BaseSearcher.Cat() cat.title = _('Random') cat.subtitle = _('Random books.') cat.url = os.url('search', sort_order='random') cat.class_ += 'navlink' cat.icon = 'random' cat.order = 4 os.entries.append(cat) os.total_results = 0 os.template = 'results' os.page = 'start' os.url_share = os.url('/', host=os.file_host) os.twit = os.tagline os.finalize() return self.format(os)
def setup (self, os, sql): os.sort_orders = ('downloads', 'release_date', 'title', 'random') os.icon = 'book' os.class_ += 'booklink' os.f_format_icon = os.format_icon_titles if os.sort_order == 'random': sql.where.append ("pk in (select pk from books order by random() limit 20)") if len (os.query): sql.fulltext ('books.tsvec', os.query) os.title = _("Books: {title}").format (title = os.query) else: os.title = _('All Books')
def setup(self, os, sql): os.sort_orders = ('downloads', ) os.icon = 'book' os.class_ += 'booklink' os.f_format_icon = os.format_icon_titles os.title = _('Readers also downloaded') sql.query = """ SELECT books.pk, books.title, books.filing, books.author, books.release_date, books.fk_categories, books.fk_langs, books.coverpages, d.dl as downloads FROM v_appserver_books_4 as books JOIN ( SELECT s1.fk_books as pk, count (s1.id) as dl FROM scores.also_downloads as s1, scores.also_downloads as s2 WHERE s2.fk_books = %(fk_books)s AND s1.fk_books != %(fk_books)s AND s1.id = s2.id GROUP BY s1.fk_books) as d ON d.pk = books.pk""" sql.from_ = () sql.params['fk_books'] = os.id
def fixup (self, os): if (os.start_index == 1 and len (os.entries) > 0): # browse-by-author page for maintainers if 'is-catalog-maintainer' in cherrypy.request.cookie: cat = BaseSearcher.Cat () cat.type = mt.html cat.rel = 'related' cat.title = _('Browse by Author') cat.url = "/browse/authors/%s#a%d" % (os.author[:1].lower (), os.id) cat.class_ += 'navlink grayed' cat.icon = 'internal' cat.order = 9 os.entries.insert (0, cat) # wikipedia links etc. rows = BaseSearcher.SQLSearcher.execute ( """SELECT url, description AS title FROM author_urls WHERE fk_authors = %(fk_authors)s""", { 'fk_authors': os.id } ) for row in rows: cat = BaseSearcher.Cat () cat.type = mt.html cat.rel = 'related' cat.title = _('See also: {title}').format (title = row.title) cat.url = row.url cat.class_ += 'navlink grayed' cat.icon = 'external' cat.order = 8 os.entries.insert (0, cat) # author aliases if os.format == 'html': rows = BaseSearcher.SQLSearcher.execute ( """SELECT alias AS title FROM aliases WHERE fk_authors = %(fk_authors)s AND alias_heading = 1""", { 'fk_authors': os.id } ) for row in rows: cat = BaseSearcher.Cat () cat.title = _('Alias {alias}').format (alias = row.title) cat.class_ += 'grayed' cat.icon = 'alias' cat.order = 7 os.entries.insert (0, cat)
def index (self, **kwargs): """ Output the page. """ # # OAuth 2.0 flow see: # http://tools.ietf.org/html/rfc6749 # session = self.get_or_create_session () if 'id' in kwargs: session.ebook = EbookMetaData (kwargs) if session.ebook is None: raise cherrypy.HTTPError (400, "No ebook selected. Are your cookies enabled?") name = self.name if 'not_approved' in kwargs or 'error' in kwargs: self._dialog ( _('Sorry. The file could not be sent to {name}.').format (name = name), _('Error')) self.redirect_done (session) try: session.oauth_dance (kwargs) log ("Sending file %s to %s" % ( session.ebook.get_source_url (), name)) with closing (self.request_ebook (session)) as r: r.raise_for_status () self.upload_file (session, r) log ("File %s sent to %s" % ( session.ebook.get_source_url (), name)) self._dialog ( _('The file has been sent to {name}.').format (name = name), _('Sent to {name}').format (name = name)) self.redirect_done (session) except (OAuth2Error, ) as what: session.unauthorized (what) self.unauthorized ('OAuthError: ' + str (what.urlencoded)) except (RequestException, IOError, ValueError) as what: session.unauthorized (what) self.unauthorized ('RequestError: ' + str (what)) raise cherrypy.HTTPError (500, str (what))
def no_records_found(os): """ Message. """ cat = BaseSearcher.Cat() cat.rel = '__notfound__' cat.title = _('No records found.') cat.url = os.url('start') cat.class_ += 'navlink grayed' cat.icon = 'bibrec' cat.order = 11 return cat
def sort_by_downloads(os): """ Append the sort by downloads link. """ cat = BaseSearcher.Cat() cat.rel = 'popular' cat.title = _('Sort by Popularity') cat.url = os.url_carry(sort_order='downloads') cat.class_ += 'navlink grayed' cat.icon = 'popular' cat.order = 4.0 os.entries.insert(0, cat)
def sort_by_quantity(os): """ Append the sort by quantity link. """ cat = BaseSearcher.Cat() cat.rel = 'numerous' cat.title = _('Sort by Quantity') cat.url = os.url_carry(sort_order='quantity') cat.class_ += 'navlink grayed' cat.icon = 'quantity' cat.order = 4.3 os.entries.insert(0, cat)
def sort_by_release_date(os): """ Append the sort by release date link. """ cat = BaseSearcher.Cat() cat.rel = 'new' cat.title = _('Sort by Release Date') cat.url = os.url_carry(sort_order='release_date') cat.class_ += 'navlink grayed' cat.icon = 'date' cat.order = 4.4 os.entries.insert(0, cat)
def sort_by_author(os): """ Append the sort alphabetically by author link. """ cat = BaseSearcher.Cat() cat.rel = 'alphabethical' cat.title = _('Sort Alphabetically by Author') cat.url = os.url_carry(sort_order='author') cat.class_ += 'navlink grayed' cat.icon = 'alpha' cat.order = 4.2 os.entries.insert(0, cat)
def did_you_mean(os, corr, corrected_query): """ Message. """ cat = BaseSearcher.Cat() cat.rel = '__didyoumean__' cat.title = _('Did you mean: {correction}').format(correction=corr) cat.url = os.url('search', query=corrected_query) cat.class_ += 'navlink' cat.icon = 'suggestion' cat.order = 12 return cat
def status_line(os): """ Placeholder for status line. """ cat = BaseSearcher.Cat() cat.rel = '__statusline__' cat.class_ += 'grayed' cat.icon = 'bibrec' cat.order = 10 cat.header = os.title cat.title = _(u"Displaying results {from_}–{to}").format( from_=os.start_index, to=os.end_index) return cat
def translate (self): """ Translate DublinCore struct. """ if self.translated: # already translated return self.hr_release_date = babel.dates.format_date ( self.release_date, locale = str (cherrypy.response.i18n.locale)) if cherrypy.response.i18n.locale.language == 'en': # no translation required return self.rights = _(self.rights) for author in self.authors: author.role = _(author.role) for marc in self.marcs: marc.caption = _(marc.caption) for dcmitype in self.dcmitypes: dcmitype.description = _(dcmitype.description) for lang in self.languages: if lang.id in cherrypy.response.i18n.locale.languages: lang.language = cherrypy.response.i18n.locale.languages[lang.id].capitalize () for file_ in self.files: file_.hr_filetype = _(file_.hr_filetype) for file_ in self.generated_files: file_.hr_filetype = _(file_.hr_filetype) self.translated = True
def setup(self, os, sql): os.sort_orders = ('downloads', 'title', 'author', 'release_date') os.title_icon = 'bookshelf' os.icon = 'book' os.class_ += 'booklink' os.f_format_icon = os.format_icon_titles os.bookshelf = BaseSearcher.sql_get( "select bookshelf from bookshelves where pk = %(pk)s", pk=os.id) os.title = _('Books in {bookshelf}').format(bookshelf=os.bookshelf) sql.from_.append('mn_books_bookshelves as mn') sql.where.append('books.pk = mn.fk_books') sql.where.append("mn.fk_bookshelves = %(fk_bookshelves)s") sql.params['fk_bookshelves'] = os.id
def setup(self, os, sql): os.sort_orders = ('downloads', 'title', 'release_date') os.title_icon = 'subject' os.icon = 'book' os.class_ += 'booklink' os.f_format_icon = os.format_icon_titles os.subject = BaseSearcher.sql_get( "select subject from subjects where pk = %(pk)s", pk=os.id) os.title = _('Books about {subject}').format(subject=os.subject) sql.from_.append('mn_books_subjects as mn') sql.where.append('books.pk = mn.fk_books') sql.where.append("mn.fk_subjects = %(fk_subjects)s") sql.params['fk_subjects'] = os.id
def setup(self, os, sql): os.sort_orders = ('downloads', 'title', 'release_date') os.title_icon = 'author' os.icon = 'book' os.class_ += 'booklink' os.f_format_icon = os.format_icon_titles os.author = BaseSearcher.sql_get( "select author from authors where pk = %(pk)s", pk=os.id) os.title = _('Books by {author}').format(author=os.author) sql.from_.append('mn_books_authors as mn') sql.where.append('books.pk = mn.fk_books') sql.where.append("mn.fk_authors = %(fk_authors)s") sql.params['fk_authors'] = os.id
def fixup(self, os): """ strip marc subfields, add social media hints and facet links """ for e in os.entries: if '$' in e.title: e.title = DublinCore.strip_marc_subfields(e.title) if (os.sort_order == 'release_date' and os.total_results > 0 and os.start_index == 1): cat = BaseSearcher.Cat() cat.title = _('Follow new books on Twitter') cat.subtitle = _("Follow our new books on Twitter.") cat.url = 'https://twitter.com/gutenberg_new' cat.class_ += 'navlink grayed' cat.icon = 'twitter' cat.order = 5 os.entries.insert(0, cat) cat = BaseSearcher.Cat() cat.title = _('Follow new books on Facebook') cat.subtitle = _( "Follow the link and like the page to have us post new books to your wall." ) cat.url = 'https://www.facebook.com/gutenberg.new' cat.class_ += 'navlink grayed' cat.icon = 'facebook' cat.order = 5 os.entries.insert(0, cat) if (len(os.query) and os.start_index == 1): sql2 = BaseSearcher.SQLStatement() sql2.query = "select count (*) from bookshelves" sql2.fulltext('bookshelves.tsvec', os.query) rows = BaseSearcher.SQLSearcher.execute(*sql2.build()) if rows[0][0] > 0: cat = BaseSearcher.Cat() cat.rel = 'related' cat.title = _('Bookshelves') cat.subtitle = __('One bookshelf matches your query.', '{count} bookshelves match your search.', rows[0][0]).format(count=rows[0][0]) cat.url = os.url('bookshelf_search', query=os.query) cat.class_ += 'navlink grayed' cat.icon = 'bookshelf' cat.order = 3 os.entries.insert(0, cat) sql2 = BaseSearcher.SQLStatement() sql2.query = "select count (*) from subjects" sql2.fulltext('subjects.tsvec', os.query) rows = BaseSearcher.SQLSearcher.execute(*sql2.build()) if rows[0][0] > 0: cat = BaseSearcher.Cat() cat.rel = 'related' cat.title = _('Subjects') cat.subtitle = __( 'One subject heading matches your search.', '{count} subject headings match your search.', rows[0][0]).format(count=rows[0][0]) cat.url = os.url('subject_search', query=os.query) cat.class_ += 'navlink grayed' cat.icon = 'subject' cat.order = 3 os.entries.insert(0, cat) sql2 = BaseSearcher.SQLStatement() sql2.query = "select count (*) from authors" sql2.fulltext('authors.tsvec', os.query) rows = BaseSearcher.SQLSearcher.execute(*sql2.build()) if rows[0][0] > 0: cat = BaseSearcher.Cat() cat.rel = 'related' cat.title = _('Authors') cat.subtitle = __('One author name matches your search.', '{count} author names match your search.', rows[0][0]).format(count=rows[0][0]) cat.url = os.url('author_search', query=os.query) cat.class_ += 'navlink grayed' cat.icon = 'author' cat.order = 3 os.entries.insert(0, cat)
def __init__(self): self.format = None self.page = None self.template = None self.query = None self.id = None self.sort_order = None self.search_terms = None self.start_index = 1 self.items_per_page = 1 self.total_results = -1 self.page_mode = 'screen' self.user_dialog = ('', '') self.opensearch_support = 0 # 0 = none, 1 = full, 2 = fake(Stanza, Aldiko, ...) self.books_in_archive = babel.numbers.format_number( books_in_archive, locale=str(cherrypy.response.i18n.locale)) self.breadcrumbs = [ (_('Project Gutenberg'), _('Go to the Main page.'), '/'), (__('1 free ebook', '{count} free ebooks', books_in_archive).format(count=self.books_in_archive), _('Start a new search.'), '/ebooks/'), ] # default output formatting functions self.f_format_title = self.format_title self.f_format_subtitle = self.format_author self.f_format_extra = self.format_none # depends on sort order, set in fix_sortorder () self.f_format_url = self.format_bibrec_url self.f_format_thumb_url = self.format_thumb_url self.f_format_icon = self.format_icon # icon class self.user_agent = cherrypy.request.headers.get('User-Agent', '') cherrypy.request.os = self s = cherrypy.session k = cherrypy.request.params host = cherrypy.request.headers.get('X-Forwarded-Host', cherrypy.config['host']) self.host = host.split(',')[-1].strip() # keep only the last hub # turns out X-Forwarded-Protocol (X-Forwarded-Proto is the defacto standaard) # is not a thing and has to be set in HAProxy self.protocol = cherrypy.request.headers.get('X-Forwarded-Protocol', 'https') # sanity check if self.host not in (cherrypy.config['all_hosts']): self.host = cherrypy.config['host'] if self.protocol not in VALID_PROTOCOLS: self.protocol = 'https' self.urlgen = routes.URLGenerator(cherrypy.routes_mapper, {'HTTP_HOST': self.host}) self.set_format(k.get('format')) # query: this param is set when an actual query is requested self.query = '' if 'query' in k: self.query = SQLStatement.preprocess_query(k['query']) # search_terms: this is used to carry the last query # to display in the search input box self.search_terms = self.query or s.get('search_terms', '') self.sort_order = k.get('sort_order') or s.get( 'sort_order') or USER_SORT_ORDERS[0] if self.sort_order not in USER_SORT_ORDERS: raise cherrypy.HTTPError(400, 'Bad Request. Unknown sort order.') s['sort_order'] = self.sort_order try: self.id = int(k.get('id') or '0') self.start_index = int(k.get('start_index') or '1') self.items_per_page = min(100, int(k.get('items_per_page') or '25')) except ValueError as what: raise cherrypy.HTTPError(400, 'Bad Request. ' + str(what)) self.file_host = cherrypy.config['file_host'] self.now = datetime.datetime.utcnow().replace( microsecond=0).isoformat() + 'Z' self.do_animations = 'Kindle/' not in self.user_agent # no animations on e-ink self.ip = cherrypy.request.remote.ip self.type_opds = 'application/atom+xml;profile=opds-catalog' self.base_url = None self.canonical_url = None self.entries = [] # NOTE: For page titles etc. self.pg = self.title = _('Project Gutenberg') # NOTE: The tagline at the top of every page. self.tagline = _( 'Project Gutenberg offers {count} free ebooks to download.' ).format(count=self.books_in_archive) # NOTE: The site's description in the html meta tags. self.description = _( 'Project Gutenberg offers {count} free ebooks for ' 'Kindle, iPad, Nook, Android, and iPhone.').format( count=self.books_in_archive) # NOTE: The placeholder inside an empty search box. self.placeholder = _('Search Project Gutenberg.') # these need to be here because they have to be localized # NOTE: Msg to user indicating the order of the search results. self.sorted_msgs = { 'downloads': _("sorted by popularity"), 'release_date': _("sorted by release date"), 'quantity': _("sorted by quantity of books"), 'title': _("sorted alphabetically"), 'alpha': _("sorted alphabetically by title"), 'author': _("sorted alphabetically by author"), 'nentry': _("sorted by relevance"), 'random': _("in random order"), } self.snippet_image_url = self.url('/pics/logo-144x144.png', host=self.file_host) self.og_type = 'website' self.class_ = ClassAttr() self.title_icon = None self.icon = None self.sort_orders = [] self.alternate_sort_orders = [] lang = self.lang = s.get('_lang_', 'en_US') if len(lang) == 2: lang = self.lang_to_default_locale.get(lang, 'en_US') lang2 = self.lang[:2] self.paypal_lang = lang if lang in PAYPAL_LANGS else 'en_US' self.flattr_lang = lang if lang in FLATTR_LANGS else 'en_US' lang = lang.replace('_', '-') self.google_lang = lang if lang in GOOGLE_LANGS else ( lang2 if lang2 in GOOGLE_LANGS else 'en-US') lang = lang.lower() self.twitter_lang = lang if lang in TWITTER_LANGS else ( lang2 if lang2 in TWITTER_LANGS else 'en') self.viewport = "width=device-width" # , initial-scale=1.0" self.touch_icon = '/gutenberg/apple-icon.png' self.touch_icon_precomposed = None # not yet used if 'user_dialog' in s: self.user_dialog = s['user_dialog'] del s['user_dialog'] msg = k.get('msg') if msg is not None: if msg == 'welcome_stranger': self.user_dialog = (_( "Welcome to Project Gutenberg. " "You'll find here {count} ebooks completely free of charge." ).format(count=self.books_in_archive), _('Welcome'))