#!/usr/bin/env python # -*- mode: python; indent-tabs-mode: nil; -*- coding: utf-8 -*- """ SearchPage.py Copyright 2009-2012 by Marcello Perathoner Distributable under the GNU General Public License Version 3 or newer. The various flavors of search page. """ from __future__ import unicode_literals import cherrypy from libgutenberg.MediaTypes import mediatypes as mt from libgutenberg.DublinCore import DublinCore import BaseSearcher from Page import SearchPage from i18n_tool import ugettext as _ from i18n_tool import ungettext as __ class BookSearchPage (SearchPage): """ search term => list of books """ 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 floor (random () * maxbook)::integer from generate_series (1, 30), (select max (pk) as maxbook from books) xbks1) """) if len (os.query): sql.fulltext ('books.tsvec', os.query) os.title = _("Books: {title}").format (title = os.query) else: os.title = _('All Books') 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) class AuthorSearchPage (SearchPage): """ name => list of authors """ 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')") class SubjectSearchPage (SearchPage): """ term => list of subects """ def setup (self, os, sql): os.f_format_url = BaseSearcher.SearchUrlFormatter ('subject') os.f_format_thumb_url = os.format_none os.sort_orders = ('downloads', 'quantity', 'alpha', 'release_date') os.icon = 'subject' os.class_ += 'navlink' os.title = _('All Subjects') sql.query = """ SELECT subjects.subject as title, subjects.pk as pk, max (books.release_date) as release_date, sum (books.downloads) as downloads, count (books.pk) as quantity""" sql.from_ = ('subjects', 'mn_books_subjects as mn', 'books') sql.groupby += ('subjects.subject', 'subjects.pk') sql.where.append ('subjects.pk = mn.fk_subjects') sql.where.append ('books.pk = mn.fk_books') if len (os.query): sql.fulltext ('subjects.tsvec', os.query) os.title = _("Subjects: {subject}").format (subject = os.query) class BookshelfSearchPage (SearchPage): """ term => list of bookshelves """ 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') 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) class AuthorPage (SearchPage): """ author id => books by author """ 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): 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 in ('html', 'mobile'): 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) class SubjectPage (SearchPage): """ subject id => books about subject """ 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 class BookshelfPage (SearchPage): """ bookshelf id => books on bookshelf """ def setup (self, os, sql): os.sort_orders = ('downloads', 'title', '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 class AlsoDownloadedPage (SearchPage): """ ebook id => books people also downloaded """ 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 finalize (self, os): # one page is enough os.show_next_page_link = False