Conversation
A requester can only ask, and every ask waits for an admin. With the lean
requester UI that turns into a stream of approvals, which is the opposite
of what the role is for.
Add a per-account setting, off by default so no existing install changes
behaviour. It lives on the user row (migration 090) rather than in the
settings table because it is a per-account permission like role, and it is
set from the Users page or PUT /auth/users/{id}/auto-approve.
When it is on, Create claims the new request and runs the same add an
admin's Approve runs, with no deciding user recorded. The
already-in-the-library check, the stored-payload revalidation and the
pending cap all still apply. A book request searches on add; an author
request runs the ordinary catalogue sync. If the add fails the request
stays pending, so nothing is lost. The switch only affects the next
request; anything already queued stays for a human.
Signed-off-by: Tung Lam <lamphamabtung96@gmail.com>
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A requester can only ask, and every ask waits for an admin. On a lean requester UI that turns into a stream of approvals, which is exactly what the reporter wants to switch off for adults they trust. Closes #2718.
The switch is per account, on the user row (
requests_auto_approve, migration 090), and off by default. An admin sets it from a new Auto-approve requests checkbox on the Users page, orPUT /api/v1/auth/users/{id}/auto-approvewith{"enabled": true}. It sits onusersrather than in the settings table because it is a per-account permission like role, and the admin users API already owns that surface. No existing account changes behaviour.The existing flow, for reference:
RequestHandler.Createstores the row aspendingand that is where it waited.Approveclaims the row with a compare-and-swap on its status, runsrunApproval(which revalidates the stored payload, rechecks "already in the library" and calls the same add cores the Add dialog uses with the requester as owner), thenCompletemarks itapproved. Auto-approval hooks in at that first step:Createnow hands the stored row towriteCreated, which reads the owner's flag and, when it is on, claims the row and runs the same add. There is no second pipeline. I splitApproveso the claim, the renewer, the payload revalidation, the owner in the context and the release-on-failure are one function (runClaimedApproval) that both callers drive.decided_bystays NULL, so the queue can tell an automatic approval from a human one.The approval body is the approve form's own starting point, since there is no form to fill in: a book request searches on add, an author request runs the ordinary catalogue sync. The form defaults author search off too, and auto-approving a batch of author requests with search on add would fan out over every monitored book of each author, so I kept it that way. Easy to flip if you'd rather it always searched.
Boundaries worth knowing:
requestCreatedwebhook fires as before, and the pending cap is unchanged since an auto-approved request never sits inpending.I asked on the issue whether this should be blanket or limited to some other condition; no answer yet, so it is blanket for now, which is what the issue's Seerr comparison implies. I did not touch the wanted/sweep/scoring paths or the narrator token work.
Checklist
git commit -sdocs/DEPLOYMENT.mdupdated if env vars, config, or upgrade path changed (no env or config change; migration 090 only adds a column with a default)changelog.d/docs/multi-user.mdis the reference and is updated)Test plan
Fail-before as a mutation check. With the flag lookup forced to
falseon the branch, the auto-approval tests fail:TestRequestsCreate_WithoutAutoApproveStillWaitsand the failure-fallback test pass either way, which is the point of both. On a cleanmainworktree a probe confirms the current behaviour: a requester's request is storedpendingand the add core never runs.gofmt -l .clean;go build ./...,go vet ./internal/api/... ./internal/db/... ./cmd/...exit 0go test ./cmd/... ./internal/...passes apart from the twelve hardlink/rename/filesystem tests that fail identically on a cleanmainworktree in this sandbox:TestHardlinkFile,TestHardlinkDir,TestDrop_EbookHardlink,TestImportMode_DefaultHardlinkSameDevice,TestImportMode_DefaultHardlinkSameDevice_DstNotExist,TestResolveImportMode,TestStagedImport_RollbackRestoresMoveSourceSameFS,TestFlattenAudiobookDir_Hardlink,TestScannerFlatten_HardlinkMode,TestDiagnose_QbittorrentAllPass,TestMigrateFlatCache_MovesFilesAndSidecars,TestCheckSQLiteFile_AwkwardPath. The failure sets are identical on both trees.npx tsc --noEmitexit 0;npm run lint0 errors (7 pre-existingexhaustive-deps/ unused-disable warnings across the app, one of themUsersPage.tsx);npx vitest run95 files / 1086 tests passed;npm run buildexit 0.I could not run
golangci-lint: the binary available here is v1.64.8 and the repo config is v2, somake lintandmake checkdo not run in this environment. The Go and web steps above are the ones I ran.