Skip to content

Commit c966967

Browse files
committed
- Drop inaccessible-follow policy TODO items
- Assert inaccessible volume follows stay persisted while hidden from user surfaces
1 parent 030e5c3 commit c966967

3 files changed

Lines changed: 86 additions & 5 deletions

File tree

TODO.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ This file captures follow-up work that should not get lost between releases.
3636
Current risk: A fresh install with a valid comics mount and no configured libraries can still look superficially similar to a "wrong storage directory" situation.
3737
Follow-up goal: Reassess the signals used for `storage_mismatch_suspected` once we have another real-world report or a better synthetic repro, and tune the messaging so first-run onboarding is not mistaken for a broken upgrade.
3838

39-
- Decide the long-term policy for inaccessible followed volumes.
40-
Context: `user_volume_follows` rows currently remain persisted even if a user's library access or age-rating settings later hide that volume from all user-facing follow surfaces.
41-
Current behavior: The follow is filtered out of the `Following` page, the `New from Following` home rail, and direct volume access checks, but the row is not pruned automatically.
42-
Follow-up goal: Confirm whether Parker should keep this hidden-and-persisted behavior, surface inaccessible follows in a disabled state, or automatically prune them after some explicit rule.
43-
4439
- Plan a replacement for ColorThief before Pillow 14.
4540
Context: Full pytest coverage currently emits `DeprecationWarning` from `colorthief==0.2.1` because it calls Pillow's deprecated `Image.Image.getdata`, which is scheduled for removal in Pillow 14 on 2027-10-15.
4641
Follow-up goal: Decide whether to replace ColorThief, patch/vendor the small palette extraction path, or move Parker's palette generation to a maintained Pillow-based quantization approach before upgrading to Pillow 14.

tests/api/test_home.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,56 @@ def test_home_following_arrivals_respects_baseline_formats_and_progress(auth_cli
609609
assert completed_plain.id not in [item["id"] for item in payload]
610610

611611

612+
def test_home_following_arrivals_hides_inaccessible_follows_without_pruning(auth_client, db, normal_user):
613+
visible_library, _, visible_volume = _create_series_graph(
614+
db,
615+
lib_name="home-follow-visible-lib",
616+
series_name="Home Follow Visible",
617+
)
618+
_, _, hidden_volume = _create_series_graph(
619+
db,
620+
lib_name="home-follow-hidden-lib",
621+
series_name="Home Follow Hidden",
622+
)
623+
624+
normal_user.accessible_libraries.append(visible_library)
625+
baseline = datetime(2026, 7, 1, tzinfo=timezone.utc)
626+
627+
visible_new = _add_comic(
628+
db,
629+
visible_volume,
630+
number="2",
631+
title="Visible Follow New",
632+
created_at=baseline + timedelta(hours=1),
633+
format=None,
634+
)
635+
hidden_new = _add_comic(
636+
db,
637+
hidden_volume,
638+
number="2",
639+
title="Hidden Follow New",
640+
created_at=baseline + timedelta(hours=2),
641+
format=None,
642+
)
643+
644+
db.add_all([
645+
UserVolumeFollow(user_id=normal_user.id, volume_id=visible_volume.id, followed_at=baseline),
646+
UserVolumeFollow(user_id=normal_user.id, volume_id=hidden_volume.id, followed_at=baseline),
647+
])
648+
db.commit()
649+
650+
response = auth_client.get("/api/home/following-arrivals?limit=10")
651+
652+
assert response.status_code == 200
653+
payload = response.json()
654+
assert [item["id"] for item in payload] == [visible_new.id]
655+
assert hidden_new.id not in [item["id"] for item in payload]
656+
assert db.query(UserVolumeFollow).filter_by(
657+
user_id=normal_user.id,
658+
volume_id=hidden_volume.id,
659+
).first() is not None
660+
661+
612662
def test_home_pinned_libraries_returns_recently_updated_series_by_pin_order(auth_client, db, normal_user):
613663
first_library = create_library_with_root(db, "Pinned First", "/tmp/pinned-first")
614664
second_library = create_library_with_root(db, "Pinned Second", "/tmp/pinned-second")

tests/api/test_volumes.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,42 @@ def test_following_list_reports_new_arrivals_and_filters_hidden_volumes(auth_cli
492492
assert item["latest_arrival"]["comic_id"] == new_issue.id
493493
assert item["latest_arrival"]["title"] == "Visible Follow #11"
494494
assert item["latest_arrival"]["number"] == "11"
495+
assert db.query(UserVolumeFollow).filter_by(
496+
user_id=normal_user.id,
497+
volume_id=hidden["volume"].id,
498+
).first() is not None
499+
500+
501+
def test_following_list_filters_age_restricted_volumes_without_pruning_follows(auth_client, db, normal_user):
502+
visible = _create_volume_fixture(db, lib_name="following-safe-lib", series_name="Safe Follow")
503+
restricted = _create_volume_fixture(db, lib_name="following-restricted-lib", series_name="Restricted Follow")
504+
505+
normal_user.accessible_libraries.extend([visible["library"], restricted["library"]])
506+
normal_user.max_age_rating = "Teen"
507+
normal_user.allow_unknown_age_ratings = False
508+
509+
for comic in visible["comics"]:
510+
comic.age_rating = "Teen"
511+
for comic in restricted["comics"]:
512+
comic.age_rating = "Mature 17+"
513+
514+
baseline = datetime(2026, 7, 1, 12, 0, tzinfo=timezone.utc)
515+
db.add_all([
516+
UserVolumeFollow(user_id=normal_user.id, volume_id=visible["volume"].id, followed_at=baseline),
517+
UserVolumeFollow(user_id=normal_user.id, volume_id=restricted["volume"].id, followed_at=baseline),
518+
])
519+
db.commit()
520+
521+
response = auth_client.get("/api/volumes/following")
522+
523+
assert response.status_code == 200
524+
payload = response.json()
525+
assert len(payload) == 1
526+
assert payload[0]["volume_id"] == visible["volume"].id
527+
assert db.query(UserVolumeFollow).filter_by(
528+
user_id=normal_user.id,
529+
volume_id=restricted["volume"].id,
530+
).first() is not None
495531

496532

497533
def test_volume_issues_returns_404_without_access(auth_client, db):

0 commit comments

Comments
 (0)