From 5932dd9301f9820b2b103545593606909f8eceb8 Mon Sep 17 00:00:00 2001 From: Oleg Broytman Date: Sat, 2 Jun 2018 02:49:53 +0300 Subject: [PATCH] =?utf8?q?Feat(search):=20=D0=98=D1=81=D0=BF=D0=BE=D0=BB?= =?utf8?q?=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0=D1=82=D1=8C=20=D1=84=D0=B8=D0=BB?= =?utf8?q?=D1=8C=D1=82=D1=80=D1=8B=20=D0=B8=D0=B7=20=D1=84=D0=B0=D0=B9?= =?utf8?q?=D0=BB=D0=B0=20=D0=BA=D0=BE=D0=BD=D1=84=D0=B8=D0=B3=D1=83=D1=80?= =?utf8?q?=D0=B0=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- docs-ru/command_line.rst | 12 +++++ docs/command_line.rst | 12 +++++ docs/news.rst | 4 +- m_librarian/search.py | 38 +++++++++++-- m_librarian/web/app.py | 38 +++++++++---- m_librarian/web/views/search_books_form.py | 57 +++++++++++++++----- m_librarian/web/views/search_books_form.tmpl | 7 +++ sample/m_librarian.conf | 13 +++++ scripts/ml-search.py | 5 +- 9 files changed, 158 insertions(+), 28 deletions(-) diff --git a/docs-ru/command_line.rst b/docs-ru/command_line.rst index 5ce2389..8dc7aa6 100644 --- a/docs-ru/command_line.rst +++ b/docs-ru/command_line.rst @@ -149,6 +149,7 @@ ml-search.py --gid gid Искать по id жанра -l, --lang lang Искать по языку --lid lid Искать по id языка + --filters Использовать фильтры из файла конфигурации -P, --path path Путь к директории с архивами библиотеки --download-to [path] Путь к директории для сохранения книг -F, --format format Формат имени сохраняемого файла @@ -173,6 +174,17 @@ ml-search.py Опция полезна в ситуации работы с несколькими базами данных (глобальная опция `-D`). +Опция `--filters` включает использование фильтров из файла конфигурации. +Фильтры записываются следующим образом:: + + [filters] + lang = en ru + deleted = 0 + +Фильтр `lang` перечисляет список языков, которыми будет ограничен поиск. +Фильтр `deleted` — это флаг 0/1; 0 означает, что удалённые книги не +будут найдены. + Опция `--download-to` задаёт путь к директории для сохранения книг. По умолчанию скрипт сохраняет книги в текущую директорию. Если опция используется без указания аргумента `path` скрипт использует diff --git a/docs/command_line.rst b/docs/command_line.rst index afdb423..e742143 100644 --- a/docs/command_line.rst +++ b/docs/command_line.rst @@ -146,6 +146,7 @@ Options:: --gid gid Search by genre’s id -l, --lang lang Search by language --lid lid Search by language’s id + --filters Use filters from config -P, --path path Path to the directory with the library archives --download-to [path] Download directory @@ -170,6 +171,17 @@ section `[library]`, key `path`:: The option is useful for multiple databases (global option `-D`). +Option `--filters` turns on using filters from config. Currently there +are two kind of filters: filters on languages and filter on flag +`deleted`. They are defined in the config file the following way:: + + [filters] + lang = en ru + deleted = 0 + +`lang` filters is a list of language codes separated by a space. +`deleted` is a 0/1 flag; 0 hides deleted books from search. + Option `--download-to` provides the path to the download directory. By default the script downloads books to the current directory. If the option is used without `path` argument the path is extracted from diff --git a/docs/news.rst b/docs/news.rst index d28346e..d07b99e 100644 --- a/docs/news.rst +++ b/docs/news.rst @@ -1,11 +1,13 @@ News ==== -Version 0.1.4 (2018-05-??) +Version 0.1.4 (2018-06-??) -------------------------- * Search by book's title. +* Use filters from config. + Version 0.1.3 (2018-05-25) -------------------------- diff --git a/m_librarian/search.py b/m_librarian/search.py index 5c1f47d..1405e09 100644 --- a/m_librarian/search.py +++ b/m_librarian/search.py @@ -1,5 +1,10 @@ +try: + from configparser import NoSectionError, NoOptionError +except ImportError: # Python 2 + from ConfigParser import NoSectionError, NoOptionError -from sqlobject.sqlbuilder import AND, func +from sqlobject.sqlbuilder import AND, OR, func +from .config import get_config from .db import Author, Book, Extension, Genre, Language __all__ = [ @@ -72,9 +77,34 @@ def search_authors(search_type, case_sensitive, values, def search_books(search_type, case_sensitive, values, join_expressions=None, - orderBy=None): - return _search(Book, search_type, case_sensitive, values, - join_expressions=join_expressions, orderBy=orderBy) + orderBy=None, use_filters=False): + if use_filters: + config = get_config() + try: + lang_filter = config.get('filters', 'lang') + except (NoSectionError, NoOptionError): + lang_filter = None + try: + deleted_filter = config.getint('filters', 'deleted') + except (NoSectionError, NoOptionError): + deleted_filter = None + if lang_filter: + if join_expressions is None: + join_expressions = [] + lang_conditions = [] + for lang in lang_filter.split(): + lvalues = {'name': lang} + conditions = mk_search_conditions( + Language, search_type, case_sensitive, lvalues) + lang_conditions.append(conditions) + join_expressions.append(Book.j.language) + join_expressions.append(OR(*lang_conditions)) + conditions = mk_search_conditions( + Book, search_type, case_sensitive, values, + join_expressions=join_expressions) + if use_filters and not deleted_filter: + conditions.append(Book.q.deleted == False) # noqa: E712 + return Book.select(AND(*conditions), orderBy=orderBy) def search_extensions(search_type, case_sensitive, values, orderBy=None): diff --git a/m_librarian/web/app.py b/m_librarian/web/app.py index 3ca8d4f..d011020 100644 --- a/m_librarian/web/app.py +++ b/m_librarian/web/app.py @@ -14,7 +14,9 @@ from m_librarian.search import search_authors, search_books @route('/') @cheetah_view('index.tmpl') def index(): - return {} + return { + 'get_config': get_config, + } @route('/search_authors', method='GET') @@ -68,13 +70,26 @@ def search_authors_post(): @route('/books-by-author//', method='GET') @cheetah_view('books_by_author.tmpl') def books_by_author(id): - return { - 'author': Author.get(id), - 'books': Book.select( - Book.j.authors & (Author.q.id == id), - orderBy=['series', 'ser_no', 'title'], - ) - } + use_filters = get_config().getint('filters', 'use_in_books_list') + if use_filters: + join_expressions = [] + join_expressions.append(Book.j.authors) + join_expressions.append(Author.q.id == id) + books = search_books('full', None, {}, join_expressions, + orderBy=('series', 'ser_no', 'title'), + use_filters=use_filters) + return { + 'author': Author.get(id), + 'books': books, + } + else: + return { + 'author': Author.get(id), + 'books': Book.select( + Book.j.authors & (Author.q.id == id), + orderBy=['series', 'ser_no', 'title'], + ) + } @route('/static/') @@ -113,7 +128,9 @@ def _search_books(): @route('/search_books/', method='GET') @cheetah_view('search_books.tmpl') def search_books_get(): - return {} + return { + 'get_config': get_config, + } @route('/search_books/', method='POST') @@ -129,8 +146,9 @@ def search_books_post(): case_sensitive = request.forms.get('case_sensitive') if case_sensitive is None: case_sensitive = _guess_case_sensitivity(value) + use_filters = request.forms.get('use_filters') books = search_books(search_type, case_sensitive, {'title': value}, None, - orderBy=('title',)) + orderBy=('title',), use_filters=use_filters) books_by_authors = {} for book in books: author = book.authors[0].fullname diff --git a/m_librarian/web/views/search_books_form.py b/m_librarian/web/views/search_books_form.py index 74b4c58..45d9075 100644 --- a/m_librarian/web/views/search_books_form.py +++ b/m_librarian/web/views/search_books_form.py @@ -35,10 +35,10 @@ VFN=valueForName currentTime=time.time __CHEETAH_version__ = '3.1.0' __CHEETAH_versionTuple__ = (3, 1, 0, 'final', 1) -__CHEETAH_genTime__ = 1527354048.844765 -__CHEETAH_genTimestamp__ = 'Sat May 26 20:00:48 2018' +__CHEETAH_genTime__ = 1528138831.71884 +__CHEETAH_genTimestamp__ = 'Mon Jun 4 22:00:31 2018' __CHEETAH_src__ = 'search_books_form.tmpl' -__CHEETAH_srcLastModified__ = 'Sat May 26 20:00:32 2018' +__CHEETAH_srcLastModified__ = 'Mon Jun 4 22:00:29 2018' __CHEETAH_docstring__ = 'Autogenerated by Cheetah: The Python-Powered Template Engine' if __CHEETAH_versionTuple__ < RequiredCheetahVersionTuple: @@ -123,6 +123,34 @@ class search_books_form(Template): return _dummyTrans and trans.response().getvalue() or "" + def use_filters_check(self, **KWS): + + + + ## CHEETAH: generated from #def $use_filters_check at line 13, col 1. + trans = KWS.get("trans") + if (not trans and not self._CHEETAH__isBuffering and not callable(self.transaction)): + trans = self.transaction # is None unless self.awake() was called + if not trans: + trans = DummyTransaction() + _dummyTrans = True + else: _dummyTrans = False + write = trans.response().write + SL = self._CHEETAH__searchList + _filter = self._CHEETAH__currentFilter + + ######################################## + ## START - generated method body + + if VFFSL(SL,"getVar",False)('use_filters', VFN(VFFSL(SL,"get_config",False)(),"getint",False)('filters', 'use_in_search_forms')): # generated from line 14, col 1 + write(u'''checked''') + + ######################################## + ## END - generated method body + + return _dummyTrans and trans.response().getvalue() or "" + + def respond(self, trans=None): @@ -146,30 +174,35 @@ class search_books_form(Template):
\u041f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435 \u041f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0430 \u0422\u043e\u0447\u043d\u043e\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435
\u0420\u0430\u0437\u043b\u0438\u0447\u0430\u0442\u044c \u043f\u0440\u043e\u043f\u0438\u0441\u043d\u044b\u0435/\u0441\u0442\u0440\u043e\u0447\u043d\u044b\u0435 + + \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u044b
diff --git a/m_librarian/web/views/search_books_form.tmpl b/m_librarian/web/views/search_books_form.tmpl index 0f2f667..e8b5e55 100644 --- a/m_librarian/web/views/search_books_form.tmpl +++ b/m_librarian/web/views/search_books_form.tmpl @@ -10,6 +10,11 @@ checked#slurp checked#slurp #end if #end def +#def $use_filters_check +#if $getVar('use_filters', $get_config().getint('filters', 'use_in_search_forms')) +checked#slurp +#end if +#end def
Различать прописные/строчные + + Использовать фильтры
diff --git a/sample/m_librarian.conf b/sample/m_librarian.conf index 5b8bee9..bca577d 100644 --- a/sample/m_librarian.conf +++ b/sample/m_librarian.conf @@ -12,6 +12,19 @@ [library] path = /var/lib/LRE_Flibusta +[filters] +# Space-separated list of language codes +lang = ru en + +# Show/hide deleted books; 0 - hide, 1 - show +deleted = 1 + +# Default value to use filters in search forms +use_in_search_forms = 1 + +# Use filters in lists of books +use_in_books_list = 1 + [download] # Download formats: # %a - author (one of) diff --git a/scripts/ml-search.py b/scripts/ml-search.py index e6cde27..7cc32e1 100755 --- a/scripts/ml-search.py +++ b/scripts/ml-search.py @@ -157,7 +157,8 @@ def _search_books(case_sensitive, search_type, args): Language, search_type, case_sensitive, lvalues) join_expressions.extend(conditions) books = search_books(search_type, case_sensitive, values, join_expressions, - orderBy=('series', 'ser_no', 'title')) + orderBy=('series', 'ser_no', 'title'), + use_filters=args.filters) if args.count: print_count(books.count()) return @@ -332,6 +333,8 @@ if __name__ == '__main__': parser.add_argument('--gid', type=int, help='search by genre\'s id') parser.add_argument('-l', '--lang', help='search by language') parser.add_argument('--lid', type=int, help='search by language\'s id') + parser.add_argument('--filters', action='store_true', + help='use filters from config') parser.add_argument('-P', '--path', help='path to the library archives') parser.add_argument('--download-to', nargs='?', const=None, default=os.path.curdir, -- 2.39.5