Some checks failed
Release / Test backend (push) Successful in 1m1s
Release / Check ui (push) Successful in 1m0s
Release / Docker (push) Successful in 11m19s
Release / Deploy to prod (push) Successful in 2m10s
Release / Deploy to homelab (push) Failing after 7s
Release / Gitea Release (push) Successful in 2m25s
Content visibility:
- Add `visibility` field to books ("public" | "admin_only"); new migration
backfills all existing scraped books to admin_only
- Meilisearch: add visibility as filterable attribute; catalogue/search
endpoints filter to public-only for non-admin requests
- Admin users identified by bearer token bypass the filter and see all books
- All PocketBase discovery queries (trending, recommended, recently-updated,
audio shelf, discover, subscription feed) now filter to visibility=public
- New scraped books default to admin_only; WriteMetadata preserves existing
visibility on PATCH (never overwrites)
Author submission:
- POST /api/admin/books/submit — creates a public book with submitted_by
- PATCH /api/admin/books/{slug}/publish / unpublish — toggle visibility
- SvelteKit proxies: /api/admin/books/[slug]/publish|unpublish
- /api/books/[slug] endpoint for admin book lookup
Frontend:
- backendFetchAdmin() helper sends admin token on any path
- Catalogue server load uses admin fetch when user is admin
- /submit page: author submission form with genre picker and rights assertion
- "Publish" nav link shown to all logged-in users
- Admin catalogue-tools: visibility management panel (load book by slug, toggle)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
76 lines
2.0 KiB
Go
76 lines
2.0 KiB
Go
// Migration 3 — add visibility + submitted_by fields to books.
|
|
//
|
|
// visibility: "public" | "admin_only"
|
|
// All existing (scraped) books are backfilled to "admin_only".
|
|
// New author-submitted books are created with "public".
|
|
//
|
|
// submitted_by: optional app_users ID for books submitted by a registered author.
|
|
// Empty for scraped books.
|
|
//
|
|
// The backfill iterates books in pages of 200. It is idempotent: books whose
|
|
// visibility is already set are skipped.
|
|
package migrations
|
|
|
|
import (
|
|
"github.com/pocketbase/pocketbase/core"
|
|
m "github.com/pocketbase/pocketbase/migrations"
|
|
)
|
|
|
|
func init() {
|
|
m.Register(func(app core.App) error {
|
|
coll, err := app.FindCollectionByNameOrId("books")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
changed := false
|
|
if coll.Fields.GetByName("visibility") == nil {
|
|
coll.Fields.Add(&core.TextField{Name: "visibility"})
|
|
changed = true
|
|
}
|
|
if coll.Fields.GetByName("submitted_by") == nil {
|
|
coll.Fields.Add(&core.TextField{Name: "submitted_by"})
|
|
changed = true
|
|
}
|
|
if changed {
|
|
if err := app.Save(coll); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
// Backfill: mark all existing books as admin_only where visibility is empty.
|
|
// These are scraped books that pre-date this migration.
|
|
const perPage = 200
|
|
for page := 1; ; page++ {
|
|
records, err := app.FindRecordsByFilter(
|
|
"books", `visibility=""`, "+id", perPage, (page-1)*perPage, nil,
|
|
)
|
|
if err != nil || len(records) == 0 {
|
|
break
|
|
}
|
|
for _, rec := range records {
|
|
rec.Set("visibility", "admin_only")
|
|
// Best-effort: ignore individual save errors (don't abort migration).
|
|
_ = app.Save(rec)
|
|
}
|
|
if len(records) < perPage {
|
|
break
|
|
}
|
|
}
|
|
return nil
|
|
}, func(app core.App) error {
|
|
coll, err := app.FindCollectionByNameOrId("books")
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
for _, name := range []string{"visibility", "submitted_by"} {
|
|
f := coll.Fields.GetByName(name)
|
|
if f == nil {
|
|
continue
|
|
}
|
|
coll.Fields.RemoveById(f.GetId())
|
|
}
|
|
return app.Save(coll)
|
|
})
|
|
}
|