Skip to content

[Feature] ReadMeABook Admin Approvals + Request Notifications - #294

Draft
NichCodes wants to merge 7 commits into
pounat:mainfrom
NichCodes:rmab-admin-approvals
Draft

[Feature] ReadMeABook Admin Approvals + Request Notifications#294
NichCodes wants to merge 7 commits into
pounat:mainfrom
NichCodes:rmab-admin-approvals

Conversation

@NichCodes

@NichCodes NichCodes commented Jun 23, 2026

Copy link
Copy Markdown

NOTE:

I'm keeping this as a draft as it's dependent on ReadMeABook adding the request and approve API calls to the token allowlist. I've got a PR to add it (among other things) on their GitHub page, but this feature won't work until it's approved. I'll try to remember to come back and pull it out of draft if/when it's added.

Also I haven't been able to really put the notifications through their paces, especially on non-iOS platforms. I can cut the notifications stuff from this PR if you'd rather implement proper push notifications later (which this is not). Just lemme know either way.


Summary

  • Add an Approvals tab to the RMAB drawer, visible only to admin-scoped tokens, where admins can review, approve, or deny pending audiobook requests
  • Badge the RMAB settings tile with a live count of pending approvals so admins notice new requests without opening the drawer
  • Re-verify the admin role via me() each time the drawer opens, so promotions/demotions take effect without reconnecting
  • Opt-in background notifications (background_fetch + flutter_local_notifications) that poll for new pending approvals and fire a local notification when new requests appear — tapping the notification opens the drawer directly on the Approvals tab

Details

Service Layer (rmab_service.dart):

  • listPendingApprovals() — GET /api/admin/requests/pending-approval
  • respondToApproval(id, approve:) — POST /api/admin/requests/:id/approve
  • New models: RmabPendingApproval, RmabApprovalRequester

Approvals Tab (rmab_config_sheet.dart):

  • Card per request showing cover art, title, author, and requesting user's avatar + username
  • Approve (one tap) and Deny (with confirmation dialog) actions, with per-row loading spinners
  • Pull-to-refresh, error/empty states

Background Notifier (rmab_approvals_notifier.dart):

  • Opt-in toggle in Settings (only shown to admins)
  • Tracks previously-seen request IDs so only genuinely new requests trigger a notification
  • Seeds the baseline on opt-in so the existing backlog doesn't fire immediately
  • Android headless entry-point for terminated-app execution
  • iOS execution is best-effort (OS-throttled); the in-app badge is the reliable surface

Settings Screen:

  • Pending-approval badge on the RMAB tile (via _refreshRmabApprovalsBadge)
  • Notification toggle (SwitchListTile) conditionally shown for admin tokens
  • Badge refreshes both on settings load and when returning from the RMAB drawer

Screenshot

image image image

Adds an admin-only "Approvals" tab to the ReadMeABook config drawer so
RMAB admins can review and approve/deny pending requests directly from
Absorb instead of the RMAB web UI.

- rmab_service: listPendingApprovals() + respondToApproval(), plus
  RmabPendingApproval/RmabApprovalRequester models.
- rmab_config_sheet: cache the connected token's RMAB role (with a me()
  backfill for existing connections) and gate a third Approvals tab on
  it. New _ApprovalsTab with one-tap approve, deny-with-confirm,
  optimistic row removal, per-row spinners, and friendly forbidden/stale
  handling. The tab uses its own scroll controller to avoid sharing the
  sheet's.
- l10n: new rmabApproval* strings.

Requires the RMAB server to allowlist GET /api/admin/requests/
pending-approval and POST /api/admin/requests/:id/approve for API
tokens (admin-gated).
The Approvals tab is gated on the connected token's RMAB role, cached at
connect time. Refresh it via me() on every open so a server-side role
change is reflected without reconnecting (demoted admin loses the tab,
promoted user gains it). Fails closed on error.
Shows admins a count badge + subtitle on the ReadMeABook settings tile so
pending approvals are visible without opening the drawer. The count comes
from listPendingApprovals() (admin-only, so a 403 just clears the badge);
refreshed on settings load and whenever the drawer closes.
Periodically polls pending approvals in the background (background_fetch:
iOS BGTaskScheduler / Android WorkManager) and fires a local notification
when new requests appear since the last check. Tapping it opens the RMAB
drawer on the Approvals tab. Opt-in via a toggle on the ReadMeABook settings
tile (shown only to RMAB admins); off by default.

iOS background execution is throttled by the OS, so delivery is best-effort
— the in-app badge and Approvals tab remain the reliable surface.

- rmab_approvals_notifier: notifications init, background_fetch config +
  headless task, new-id baseline diff, and deep-link routing.
- rmab_config_sheet: initialApprovals opens the drawer on the Approvals tab.
- settings: admin-only toggle with permission handling.
- ios: BGTaskSchedulerPermittedIdentifiers + static pod linkage for the
  TSBackgroundFetch xcframework.
Prevent path traversal via malformed ids in getRequest and
respondToApproval, and replace the hardcoded English count string in the
Approvals tab with the existing adminRmabApprovalsPending l10n entry.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant