mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Bug #1924247: Possible to create recursive VL that crashes Calibre
The actual fix is in cache.py line 2218. Another change added the virtual fields to vl:x searches. The rest are improvements to error messages.
This commit is contained in:
parent
caca59de29
commit
a6f4b77cfd
@ -1086,17 +1086,18 @@ class Cache(object):
|
|||||||
return self._search_api(self, query, restriction, virtual_fields=virtual_fields, book_ids=book_ids)
|
return self._search_api(self, query, restriction, virtual_fields=virtual_fields, book_ids=book_ids)
|
||||||
|
|
||||||
@read_api
|
@read_api
|
||||||
def books_in_virtual_library(self, vl, search_restriction=None):
|
def books_in_virtual_library(self, vl, search_restriction=None, virtual_fields=None):
|
||||||
' Return the set of books in the specified virtual library '
|
' Return the set of books in the specified virtual library '
|
||||||
vl = self._pref('virtual_libraries', {}).get(vl) if vl else None
|
vl = self._pref('virtual_libraries', {}).get(vl) if vl else None
|
||||||
if not vl and not search_restriction:
|
if not vl and not search_restriction:
|
||||||
return self.all_book_ids()
|
return self.all_book_ids()
|
||||||
# We utilize the search restriction cache to speed this up
|
# We utilize the search restriction cache to speed this up
|
||||||
|
srch = partial(self._search, virtual_fields=virtual_fields)
|
||||||
if vl:
|
if vl:
|
||||||
if search_restriction:
|
if search_restriction:
|
||||||
return frozenset(self._search('', vl) & self._search('', search_restriction))
|
return frozenset(srch('', vl) & srch('', search_restriction))
|
||||||
return frozenset(self._search('', vl))
|
return frozenset(srch('', vl))
|
||||||
return frozenset(self._search('', search_restriction))
|
return frozenset(srch('', search_restriction))
|
||||||
|
|
||||||
@read_api
|
@read_api
|
||||||
def number_of_books_in_virtual_library(self, vl=None, search_restriction=None):
|
def number_of_books_in_virtual_library(self, vl=None, search_restriction=None):
|
||||||
@ -2214,8 +2215,11 @@ class Cache(object):
|
|||||||
c = defaultdict(list)
|
c = defaultdict(list)
|
||||||
libraries = self._pref('virtual_libraries', {})
|
libraries = self._pref('virtual_libraries', {})
|
||||||
for lib, expr in libraries.items():
|
for lib, expr in libraries.items():
|
||||||
|
try:
|
||||||
for book in self._search(expr, virtual_fields=virtual_fields):
|
for book in self._search(expr, virtual_fields=virtual_fields):
|
||||||
c[book].append(lib)
|
c[book].append(lib)
|
||||||
|
except Exception as e:
|
||||||
|
c[book].append(_('[Error in virtual library {0}: {1}]').format(lib, str(e)))
|
||||||
self.vls_for_books_cache = {b:tuple(sorted(libs, key=sort_key)) for b, libs in c.items()}
|
self.vls_for_books_cache = {b:tuple(sorted(libs, key=sort_key)) for b, libs in c.items()}
|
||||||
if not book_ids:
|
if not book_ids:
|
||||||
book_ids = self._all_book_ids()
|
book_ids = self._all_book_ids()
|
||||||
|
@ -513,7 +513,8 @@ class Parser(SearchQueryParser): # {{{
|
|||||||
if not vl:
|
if not vl:
|
||||||
raise ParseException(_('No such Virtual library: {}').format(query))
|
raise ParseException(_('No such Virtual library: {}').format(query))
|
||||||
try:
|
try:
|
||||||
return candidates & self.dbcache.books_in_virtual_library(query)
|
return candidates & self.dbcache.books_in_virtual_library(
|
||||||
|
query, virtual_fields=self.virtual_fields)
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
raise ParseException(_('Virtual library search is recursive: {}').format(query))
|
raise ParseException(_('Virtual library search is recursive: {}').format(query))
|
||||||
|
|
||||||
|
@ -312,7 +312,7 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
search_item_renamed = pyqtSignal()
|
search_item_renamed = pyqtSignal()
|
||||||
tag_item_renamed = pyqtSignal()
|
tag_item_renamed = pyqtSignal()
|
||||||
refresh_required = pyqtSignal()
|
refresh_required = pyqtSignal()
|
||||||
restriction_error = pyqtSignal()
|
restriction_error = pyqtSignal(object)
|
||||||
drag_drop_finished = pyqtSignal(object)
|
drag_drop_finished = pyqtSignal(object)
|
||||||
user_categories_edited = pyqtSignal(object, object)
|
user_categories_edited = pyqtSignal(object, object)
|
||||||
user_category_added = pyqtSignal()
|
user_category_added = pyqtSignal()
|
||||||
@ -1113,12 +1113,11 @@ class TagsModel(QAbstractItemModel): # {{{
|
|||||||
data = self.db.new_api.get_categories(sort=sort,
|
data = self.db.new_api.get_categories(sort=sort,
|
||||||
book_ids=self.get_book_ids_to_use(),
|
book_ids=self.get_book_ids_to_use(),
|
||||||
first_letter_sort=self.collapse_model == 'first letter')
|
first_letter_sort=self.collapse_model == 'first letter')
|
||||||
except:
|
except Exception as e:
|
||||||
import traceback
|
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
data = self.db.new_api.get_categories(sort=sort,
|
data = self.db.new_api.get_categories(sort=sort,
|
||||||
first_letter_sort=self.collapse_model == 'first letter')
|
first_letter_sort=self.collapse_model == 'first letter')
|
||||||
self.restriction_error.emit()
|
self.restriction_error.emit(str(e))
|
||||||
|
|
||||||
if self.filter_categories_by:
|
if self.filter_categories_by:
|
||||||
if self.filter_categories_by.startswith('='):
|
if self.filter_categories_by.startswith('='):
|
||||||
|
@ -99,9 +99,10 @@ class TagBrowserMixin(object): # {{{
|
|||||||
def user_categories_edited(self):
|
def user_categories_edited(self):
|
||||||
self.library_view.model().refresh()
|
self.library_view.model().refresh()
|
||||||
|
|
||||||
def do_restriction_error(self):
|
def do_restriction_error(self, e):
|
||||||
error_dialog(self.tags_view, _('Invalid search restriction'),
|
error_dialog(self.tags_view, _('Invalid search restriction'),
|
||||||
_('The current search restriction is invalid'), show=True)
|
_('The current search restriction is invalid'),
|
||||||
|
det_msg=str(e) if e else '', show=True)
|
||||||
|
|
||||||
def do_add_subcategory(self, on_category_key, new_category_name=None):
|
def do_add_subcategory(self, on_category_key, new_category_name=None):
|
||||||
'''
|
'''
|
||||||
|
@ -172,7 +172,7 @@ class TagsView(QTreeView): # {{{
|
|||||||
tag_item_renamed = pyqtSignal()
|
tag_item_renamed = pyqtSignal()
|
||||||
search_item_renamed = pyqtSignal()
|
search_item_renamed = pyqtSignal()
|
||||||
drag_drop_finished = pyqtSignal(object)
|
drag_drop_finished = pyqtSignal(object)
|
||||||
restriction_error = pyqtSignal()
|
restriction_error = pyqtSignal(object)
|
||||||
tag_item_delete = pyqtSignal(object, object, object, object, object)
|
tag_item_delete = pyqtSignal(object, object, object, object, object)
|
||||||
tag_identifier_delete = pyqtSignal(object, object)
|
tag_identifier_delete = pyqtSignal(object, object)
|
||||||
apply_tag_to_selected = pyqtSignal(object, object, object)
|
apply_tag_to_selected = pyqtSignal(object, object, object)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user