]> git.phdru.name Git - m_librarian.git/commitdiff
Feat(search): Использовать фильтры из файла конфигурации
authorOleg Broytman <phd@phdru.name>
Fri, 1 Jun 2018 23:49:53 +0000 (02:49 +0300)
committerOleg Broytman <phd@phdru.name>
Mon, 4 Jun 2018 19:28:26 +0000 (22:28 +0300)
docs-ru/command_line.rst
docs/command_line.rst
docs/news.rst
m_librarian/search.py
m_librarian/web/app.py
m_librarian/web/views/search_books_form.py
m_librarian/web/views/search_books_form.tmpl
sample/m_librarian.conf
scripts/ml-search.py

index 5ce2389a0c64747194e6e01a595f5334a6ff44dc..8dc7aa6913f3c55f351255c7a7940348fe23e498 100644 (file)
@@ -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` скрипт использует
index afdb42331cf2971274391d049b8d637cda68a65a..e7421435d057888d960c3f2fdbecad65c44462a7 100644 (file)
@@ -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
index d28346e358b8284c211d4ba7c3a7748771ecdd20..d07b99e0e22b86f2aaa0c8f9c38c9ca0c3fdde77 100644 (file)
@@ -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)
 --------------------------
 
index 5c1f47d65403df60bc645a144728a5c24b2076c5..1405e09dac6fe582a7c1ce3f0fd9efbe15cb0021 100644 (file)
@@ -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):
index 3ca8d4fd54b51e5cbddeecbf23e97f2c80e78c7c..d0110207a1fad5cf7ef31220acef2fae4875885e 100644 (file)
@@ -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/<id:int>/', 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/<filename:path>')
@@ -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
index 74b4c58904786fb38714d26c47c94ed975a149bf..45d907550eb83d19162224a59d8677355c4b8998 100644 (file)
@@ -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):
   <input name="search_books" value="''')
         _v = VFFSL(SL,"html_escape",False)(VFFSL(SL,"getVar",False)('search_books',
   ''))
-        if _v is not None: write(_filter(_v, rawExpr=u"$html_escape($getVar('search_books',\n  ''))")) # from line 15, col 37.
+        if _v is not None: write(_filter(_v, rawExpr=u"$html_escape($getVar('search_books',\n  ''))")) # from line 20, col 37.
         write(u'''" type="text" style="width: 100%">
   <br>
   <input name="search_type" value="start" ''')
-        _v = VFFSL(SL,"search_type_checked",False)('start') # u"$search_type_checked('start')" on line 18, col 43
-        if _v is not None: write(_filter(_v, rawExpr=u"$search_type_checked('start')")) # from line 18, col 43.
+        _v = VFFSL(SL,"search_type_checked",False)('start') # u"$search_type_checked('start')" on line 23, col 43
+        if _v is not None: write(_filter(_v, rawExpr=u"$search_type_checked('start')")) # from line 23, col 43.
         write(u''' type="radio">
   \u041f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0430 \u0432 \u043d\u0430\u0447\u0430\u043b\u0435
   <input name="search_type" value="substring" ''')
-        _v = VFFSL(SL,"search_type_checked",False)('substring') # u"$search_type_checked('substring')" on line 20, col 47
-        if _v is not None: write(_filter(_v, rawExpr=u"$search_type_checked('substring')")) # from line 20, col 47.
+        _v = VFFSL(SL,"search_type_checked",False)('substring') # u"$search_type_checked('substring')" on line 25, col 47
+        if _v is not None: write(_filter(_v, rawExpr=u"$search_type_checked('substring')")) # from line 25, col 47.
         write(u''' type="radio">
   \u041f\u043e\u0434\u0441\u0442\u0440\u043e\u043a\u0430
   <input name="search_type" value="full" ''')
-        _v = VFFSL(SL,"search_type_checked",False)('full') # u"$search_type_checked('full')" on line 22, col 42
-        if _v is not None: write(_filter(_v, rawExpr=u"$search_type_checked('full')")) # from line 22, col 42.
+        _v = VFFSL(SL,"search_type_checked",False)('full') # u"$search_type_checked('full')" on line 27, col 42
+        if _v is not None: write(_filter(_v, rawExpr=u"$search_type_checked('full')")) # from line 27, col 42.
         write(u''' type="radio">
   \u0422\u043e\u0447\u043d\u043e\u0435 \u0441\u043e\u0432\u043f\u0430\u0434\u0435\u043d\u0438\u0435
   <br>
   <input name="case_sensitive" type="checkbox" ''')
-        _v = VFFSL(SL,"case_sensitive_checked",True) # u'$case_sensitive_checked' on line 25, col 48
-        if _v is not None: write(_filter(_v, rawExpr=u'$case_sensitive_checked')) # from line 25, col 48.
+        _v = VFFSL(SL,"case_sensitive_checked",True) # u'$case_sensitive_checked' on line 30, col 48
+        if _v is not None: write(_filter(_v, rawExpr=u'$case_sensitive_checked')) # from line 30, col 48.
         write(u'''>
   \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
+  <input name="use_filters" type="checkbox" ''')
+        _v = VFFSL(SL,"use_filters_check",True) # u'$use_filters_check' on line 32, col 45
+        if _v is not None: write(_filter(_v, rawExpr=u'$use_filters_check')) # from line 32, col 45.
+        write(u'''>
+  \u0418\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0444\u0438\u043b\u044c\u0442\u0440\u044b
   </div>
   <div style="width: 100%; text-align: center">
   <input name="submit" type="submit">
index 0f2f667672b820b507120c0c429e6bfd96eaaea0..e8b5e553289dfd256c6c5ce3377f46815e85ef39 100644 (file)
@@ -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
 <form action="/search_books/" method="POST">
   <div style="width: 100%">
   <input name="search_books" value="$html_escape($getVar('search_books',
@@ -24,6 +29,8 @@ checked#slurp
   <br>
   <input name="case_sensitive" type="checkbox" $case_sensitive_checked>
   Различать прописные/строчные
+  <input name="use_filters" type="checkbox" $use_filters_check>
+  Использовать фильтры
   </div>
   <div style="width: 100%; text-align: center">
   <input name="submit" type="submit">
index 5b8bee9135b29f7cb15c6e2ca7433d527cb467b6..bca577d1049e3410dd33c90bf5bdbcbf5a845042 100644 (file)
 [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)
index e6cde27184ac6b593e44ba0b21f47f43cea1de47..7cc32e187d9b913d46010e0b06b9cc275c4bb383 100755 (executable)
@@ -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,