Implements admin approval workflow for user requests with global and per-user auto-approve controls. Adds new request statuses ('awaiting_approval', 'denied'), related API endpoints, and UI for pending approvals. Introduces configurable audiobook organization path template with validation and preview in settings, updates database schema and migrations for new fields.
5.4 KiB
Request Approval System
Status: ✅ Implemented | Admin approval workflow for user requests with global & per-user auto-approve controls
Overview
Allows admins to review and approve/deny user requests before they are processed. Supports global auto-approve toggle and per-user auto-approve overrides.
Key Details
Request Statuses
- awaiting_approval - New status for requests pending admin approval
- denied - New status for requests rejected by admin
- pending - Status after approval (triggers search job)
- Applies to all existing statuses: pending, searching, downloading, processing, downloaded, available, failed, cancelled, awaiting_search, awaiting_import, warn
Configuration Keys
auto_approve_requests(Configuration table) - Global setting (true/false string)User.autoApproveRequests(User table) - Per-user override (boolean, nullable)null= Use global settingtrue= Always auto-approve for this userfalse= Always require approval for this user
Approval Logic
When user creates request:
- Check
User.autoApproveRequests:- If
true→ Set status to 'pending', trigger search job - If
false→ Set status to 'awaiting_approval', wait for admin - If
null→ Check globalauto_approve_requestssetting- If 'true' → Auto-approve (status: 'pending')
- Otherwise → Require approval (status: 'awaiting_approval')
- If
Admin approval actions:
- Approve → Change status to 'pending', trigger search job
- Deny → Change status to 'denied', no further processing
API Endpoints
GET /api/admin/requests/pending-approval
Fetch all requests with status 'awaiting_approval'
Auth: Admin only
Response:
{
"success": true,
"requests": [
{
"id": "uuid",
"createdAt": "2026-01-15T12:00:00Z",
"audiobook": {
"title": "Book Title",
"author": "Author Name",
"coverArtUrl": "https://..."
},
"user": {
"id": "uuid",
"plexUsername": "username",
"avatarUrl": "https://..."
}
}
],
"count": 5
}
POST /api/admin/requests/[id]/approve
Approve or deny a specific request
Auth: Admin only
Request:
{
"action": "approve" | "deny"
}
Response (approve):
{
"success": true,
"message": "Request approved and search job triggered",
"request": { /* full request object */ }
}
Response (deny):
{
"success": true,
"message": "Request denied",
"request": { /* full request object */ }
}
Errors:
404- Request not found400- Request not in 'awaiting_approval' status400- Invalid action (must be 'approve' or 'deny')
GET /api/admin/settings/auto-approve
Get global auto-approve setting
Auth: Admin only
Response:
{
"autoApproveRequests": true
}
PATCH /api/admin/settings/auto-approve
Update global auto-approve setting
Auth: Admin only
Request:
{
"autoApproveRequests": true
}
Response:
{
"autoApproveRequests": true
}
PUT /api/admin/users/[id]
Update user (includes autoApproveRequests field)
Auth: Admin only
Request:
{
"autoApproveRequests": true | false | null
}
UI Features
Admin Dashboard (/admin)
Requests Awaiting Approval Section:
- Shows only when pending approval requests exist
- Grid layout with book cards (3 columns on desktop)
- Each card displays:
- Book cover image
- Title and author
- User avatar and username
- Request timestamp (relative: "2 hours ago")
- Approve button (green, checkmark icon)
- Deny button (red, X icon)
- Auto-refreshes every 10 seconds (SWR)
- Loading states on buttons during approval/denial
- Success/error toast notifications
- Mutates multiple caches on action: pending-approval, recent requests, metrics
Admin Users Page (/admin/users)
Global Auto-Approve Toggle:
- Checkbox at top of page
- Label: "Auto-approve all requests by default"
- Updates
auto_approve_requestsconfiguration - Optimistic UI update with revert on error
- Toast notification on success/error
Per-User Auto-Approve Control:
- Each user row has toggle dropdown:
- "Use Global Setting" (null, default)
- "Always Auto-Approve" (true)
- "Always Require Approval" (false)
- Updates
User.autoApproveRequestsfield - Shows current effective setting (considers global + per-user)
- Optimistic UI update
User Request Flow
When creating request (POST /api/requests):
- System checks approval logic (see above)
- If awaiting approval → User sees status "Awaiting Approval" on request card
- If auto-approved → User sees status "Pending" and processing begins
Request Status Badges
- awaiting_approval → Amber badge with warning icon
- denied → Red badge with X icon
- All other statuses → Existing badge colors
Database Schema
User Table
autoApproveRequests: Boolean (nullable, default null)
- null: Use global setting
- true: Always auto-approve
- false: Always require approval
Request Table
status: Enum (includes 'awaiting_approval', 'denied')
Configuration Table
key: 'auto_approve_requests'
value: 'true' | 'false' (string)
Related
- Admin Dashboard - Dashboard UI features
- Database Schema - User and Request tables
- Settings Pages - Global settings management