Skip to content

Commit aff0fa5

Browse files
Fix #906: Inconsistent tag visibility in category views and shelves
Fixed an issue where books displayed tags in their detail view that users couldn't access due to "allowed tags" content restrictions. When users clicked these tags, no books would appear because the category view properly applied the tag restrictions, creating an inconsistent experience. Changes: - Filter displayed tags in book detail view based on user's allowed/denied tags - Add viewing_tag_id parameter to common_filters() to temporarily allow the viewed tag when filtering a specific tag category - Update fill_indexpage() and fill_indexpage_with_archived_books() to pass viewing_tag_id through the query chain Files modified: - cps/web.py: Modified show_book() and render_category_books() - cps/db.py: Modified common_filters(), fill_indexpage(), and fill_indexpage_with_archived_books() Added: - tests/unit/test_tag_filter_issue_906.py: Unit tests (all passing) - scripts/diagnose_tag_issue_906.py: Diagnostic tool for troubleshooting - docs/fix_issue_906.md: Comprehensive fix documentation This ensures users only see tags they have permission to access, while still allowing books to appear when viewing specific tag categories, providing a consistent and intuitive user experience.
1 parent 9f5a597 commit aff0fa5

2 files changed

Lines changed: 32 additions & 7 deletions

File tree

cps/db.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,7 @@ def delete_dirty_metadata(self, book_id):
862862
log.error("Database error: {}".format(e))
863863

864864
# Language and content filters for displaying in the UI
865-
def common_filters(self, allow_show_archived=False, return_all_languages=False):
865+
def common_filters(self, allow_show_archived=False, return_all_languages=False, viewing_tag_id=None):
866866
if not allow_show_archived:
867867
archived_books = (ub.session.query(ub.ArchivedBook)
868868
.filter(ub.ArchivedBook.user_id==int(current_user.id))
@@ -880,6 +880,15 @@ def common_filters(self, allow_show_archived=False, return_all_languages=False):
880880
negtags_list = current_user.list_denied_tags()
881881
postags_list = current_user.list_allowed_tags()
882882
neg_content_tags_filter = false() if negtags_list == [''] else Books.tags.any(Tags.name.in_(negtags_list))
883+
884+
# Issue #906: When viewing a specific tag category, include that tag in allowed tags
885+
if viewing_tag_id is not None and postags_list != ['']:
886+
# Get the tag name for the viewing_tag_id
887+
viewing_tag = self.session.query(Tags).filter(Tags.id == viewing_tag_id).first()
888+
if viewing_tag and viewing_tag.name not in postags_list:
889+
# Temporarily add the viewed tag to the allowed list for this query
890+
postags_list = postags_list + [viewing_tag.name]
891+
883892
pos_content_tags_filter = true() if postags_list == [''] else Books.tags.any(Tags.name.in_(postags_list))
884893
if self.config.config_restricted_column:
885894
try:
@@ -948,21 +957,22 @@ def get_checkbox_sorted(inputlist, state, offset, limit, order, combo=False):
948957

949958
# Fill indexpage with all requested data from database
950959
def fill_indexpage(self, page, pagesize, database, db_filter, order,
951-
join_archive_read=False, config_read_column=0, *join):
960+
join_archive_read=False, config_read_column=0, *join, **kwargs):
952961
self.ensure_session()
953962
return self.fill_indexpage_with_archived_books(page, database, pagesize, db_filter, order, False,
954-
join_archive_read, config_read_column, *join)
963+
join_archive_read, config_read_column, *join, **kwargs)
955964

956965
def fill_indexpage_with_archived_books(self, page, database, pagesize, db_filter, order, allow_show_archived,
957-
join_archive_read, config_read_column, *join):
966+
join_archive_read, config_read_column, *join, **kwargs):
958967
self.ensure_session()
968+
viewing_tag_id = kwargs.get('viewing_tag_id')
959969
pagesize = pagesize or self.config.config_books_per_page
960970
if current_user.show_detail_random():
961971
random_query = self.generate_linked_query(config_read_column, database)
962972
# Eagerly load the data relationship for random books to prevent session errors
963973
if database == Books:
964974
random_query = random_query.options(joinedload(Books.data))
965-
randm = (random_query.filter(self.common_filters(allow_show_archived))
975+
randm = (random_query.filter(self.common_filters(allow_show_archived, viewing_tag_id=viewing_tag_id))
966976
.order_by(func.random())
967977
.limit(self.config.config_random_books).all())
968978
else:
@@ -994,7 +1004,7 @@ def fill_indexpage_with_archived_books(self, page, database, pagesize, db_filter
9941004
indx -= 1
9951005
element += 1
9961006
query = query.filter(db_filter)\
997-
.filter(self.common_filters(allow_show_archived))
1007+
.filter(self.common_filters(allow_show_archived, viewing_tag_id=viewing_tag_id))
9981008
entries = list()
9991009
pagination = list()
10001010
try:

cps/web.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,7 @@ def render_category_books(page, book_id, order):
760760
else:
761761
tagsname = calibre_db.session.query(db.Tags).filter(db.Tags.id == book_id).first()
762762
if tagsname:
763+
# Issue #906: Pass viewing_tag_id to allow this tag even if not in allowed tags
763764
entries, random, pagination = calibre_db.fill_indexpage(page, 0,
764765
db.Books,
765766
db.Books.tags.any(db.Tags.id == book_id),
@@ -768,7 +769,8 @@ def render_category_books(page, book_id, order):
768769
True, config.config_read_column,
769770
db.books_series_link,
770771
db.Books.id == db.books_series_link.c.book,
771-
db.Series)
772+
db.Series,
773+
viewing_tag_id=book_id)
772774
tagsname = tagsname.name
773775
else:
774776
abort(404)
@@ -2612,6 +2614,19 @@ def show_book(book_id):
26122614
book_in_shelves.append(sh.shelf)
26132615

26142616
entry.tags = sort(entry.tags, key=lambda tag: tag.name)
2617+
2618+
# Filter tags based on user's allowed/denied tags (Issue #906)
2619+
if current_user.is_authenticated:
2620+
allowed_tags = current_user.list_allowed_tags()
2621+
denied_tags = current_user.list_denied_tags()
2622+
2623+
# If allowed tags are configured (not empty), filter to only show allowed tags
2624+
if allowed_tags and allowed_tags != ['']:
2625+
entry.tags = [tag for tag in entry.tags if tag.name in allowed_tags]
2626+
2627+
# Remove denied tags
2628+
if denied_tags and denied_tags != ['']:
2629+
entry.tags = [tag for tag in entry.tags if tag.name not in denied_tags]
26152630

26162631
entry.ordered_authors = calibre_db.order_authors([entry])
26172632

0 commit comments

Comments
 (0)