* feat(collections): add profile-scoped display filters
* refactor(collections): dedup display-filter helpers per review
Address code-review feedback on the profile-scoped display filters
without changing behavior:
- Widen CompletedHistoryItemMap to accept ProgressCompletionStore and
drop the duplicate completedHistoryItemMapForProgress copy.
- Extract the duplicated MDBList candidate retry loop into a generic
collectionutil.FetchMDBListWithFallback helper, used by both the user
and library collection syncers, and cover it with unit tests.
- Reuse validateOptionalLibraryIDs in HandleUpdateCollection instead of
an inline positive-ID loop.
- Import the shared COLLECTION_{WATCH,MEDIA}_FILTER_OPTIONS in the
template config form rather than redefining them locally.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* fix(collections): sanitize query_definition library_ids fallback
readSourceConfigLibraryIDs validated source_config.library_ids (finite,
positive, truncated, deduplicated) but returned the query_definition
fallback raw, so legacy rows could surface zero/negative/duplicate IDs
that the backend now rejects on save. Extract a shared sanitizer and
apply it to both paths.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor(docs): This makes the agents annoying to work with
* Improve playback session handling
* Support collection source order in catalog filters
* fix(collections): address display filter review feedback
* refactor(catalog): remove duplicate collection query params
* Hide episode media scope for collection overlays
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
1.8 KiB
Go
57 lines
1.8 KiB
Go
package catalog
|
|
|
|
import (
|
|
"net/url"
|
|
"testing"
|
|
)
|
|
|
|
func TestParseCatalogMediaScope_AllowsEbook(t *testing.T) {
|
|
if got := parseCatalogMediaScope(" ebook "); got != "ebook" {
|
|
t.Fatalf("expected ebook media scope, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestParseCatalogMediaScope_AllowsManga(t *testing.T) {
|
|
if got := parseCatalogMediaScope(" manga "); got != "manga" {
|
|
t.Fatalf("expected manga media scope, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestParseCatalogRequest_AllowsCollectionOverlayParams(t *testing.T) {
|
|
values := url.Values{
|
|
"source": {"user_collection"},
|
|
"collection_id": {"col-7"},
|
|
"type": {"movie"},
|
|
"sort": {"title"},
|
|
"order": {"asc"},
|
|
"groups[0][match]": {"all"},
|
|
"groups[0][rules][0][field]": {"watched"},
|
|
"groups[0][rules][0][op]": {"is"},
|
|
"groups[0][rules][0][value]": {"false"},
|
|
"groups[1][match]": {"all"},
|
|
"groups[1][rules][0][field]": {"resolution"},
|
|
"groups[1][rules][0][op]": {"is"},
|
|
"groups[1][rules][0][value]": {"4K"},
|
|
}
|
|
|
|
req, err := ParseCatalogRequest(values)
|
|
if err != nil {
|
|
t.Fatalf("ParseCatalogRequest returned error: %v", err)
|
|
}
|
|
if req.Source != CatalogSourceUserCollection || req.CollectionID != "col-7" {
|
|
t.Fatalf("unexpected collection source: source=%q collection=%q", req.Source, req.CollectionID)
|
|
}
|
|
if req.UseSourceOrder {
|
|
t.Fatal("explicit sort should opt out of source order")
|
|
}
|
|
if req.Query.MediaScope != "movie" {
|
|
t.Fatalf("media scope = %q, want movie", req.Query.MediaScope)
|
|
}
|
|
if req.Query.Sort != (QuerySort{Field: "title", Order: "asc"}) {
|
|
t.Fatalf("sort = %+v, want title asc", req.Query.Sort)
|
|
}
|
|
if len(req.Query.Groups) != 2 {
|
|
t.Fatalf("groups = %+v, want two overlay groups", req.Query.Groups)
|
|
}
|
|
}
|