95 lines
3.9 KiB
Markdown
95 lines
3.9 KiB
Markdown
# Admin Pages Design
|
|
|
|
## Overview
|
|
|
|
Admin pages for user management in the porchlight OIDC provider. Authenticated users with the `"admin"` group can list, search, view, edit, activate/deactivate, and delete users, manage group memberships, view/delete credentials, create invite links, and re-invite existing users.
|
|
|
|
## Routing & Auth
|
|
|
|
New router at `src/porchlight/admin/routes.py`, mounted at `/admin/` in `app.py`.
|
|
|
|
**Admin guard:** Every admin route fetches the full user via `user_repo.get_by_userid()` and checks `"admin" in user.groups`. Unauthenticated users redirect to `/login`. Non-admin authenticated users get 403.
|
|
|
|
### Endpoints
|
|
|
|
| Method | Path | Purpose |
|
|
|--------|------|---------|
|
|
| GET | `/admin/users` | User list (paginated, searchable) |
|
|
| GET | `/admin/users/{userid}` | User detail page |
|
|
| POST | `/admin/users/{userid}/profile` | Update user profile |
|
|
| POST | `/admin/users/{userid}/groups` | Update group memberships |
|
|
| POST | `/admin/users/{userid}/activate` | Activate user |
|
|
| POST | `/admin/users/{userid}/deactivate` | Deactivate user |
|
|
| DELETE | `/admin/users/{userid}/credentials/password` | Delete user's password |
|
|
| DELETE | `/admin/users/{userid}/credentials/webauthn/{cred_id}` | Delete a WebAuthn key |
|
|
| POST | `/admin/users/{userid}/invite` | Generate re-invite link |
|
|
| DELETE | `/admin/users/{userid}` | Delete user entirely |
|
|
| POST | `/admin/invite` | Create invite for new username |
|
|
|
|
## Templates & UI
|
|
|
|
### Template Structure
|
|
|
|
```
|
|
templates/admin/
|
|
base.html -- extends base.html, adds admin nav + admin label
|
|
users.html -- user list table
|
|
user_detail.html -- single-user detail with sections
|
|
```
|
|
|
|
### User List Page (`/admin/users`)
|
|
|
|
- Search input at top (HTMX GET to filter, targets table body)
|
|
- Table columns: Username, Name, Email, Groups, Status, Created
|
|
- Each row links to detail page
|
|
- Active/inactive toggle button per row (HTMX POST, swaps button)
|
|
- Pagination controls (prev/next, HTMX)
|
|
- "Create Invite" form -- enter username, generates magic link URL
|
|
|
|
### User Detail Page (`/admin/users/{userid}`)
|
|
|
|
Single page with sections, each with its own HTMX form/target:
|
|
|
|
1. **Profile** -- Same editable fields as self-service (given_name, family_name, preferred_username, email, phone_number, picture, locale). Username displayed read-only. HTMX POST.
|
|
|
|
2. **Groups** -- Current groups as removable tags/chips. Text input to add groups. HTMX POST replaces full group list.
|
|
|
|
3. **Credentials** -- Read-only list: password (exists/doesn't), WebAuthn keys (device name, created). Delete buttons per credential (HTMX DELETE with confirmation).
|
|
|
|
4. **Actions** -- Re-invite button (shows generated URL). Delete user button (with confirmation). Activate/deactivate toggle.
|
|
|
|
### New CSS
|
|
|
|
- `.admin-table` -- bordered table with hover rows
|
|
- `.group-tag` -- removable group chips
|
|
- `.status-badge` / `.status-active` / `.status-inactive` -- status indicators
|
|
|
|
## Data Layer Changes
|
|
|
|
### No Schema Changes
|
|
|
|
Existing tables cover all needs: `users`, `user_groups`, `webauthn_credentials`, `password_credentials`, `magic_links`.
|
|
|
|
### Repository Additions
|
|
|
|
Add to `UserRepository` protocol and SQLite implementation:
|
|
|
|
- `search_users(query: str, offset: int, limit: int) -> list[User]` -- SQL LIKE on username and email
|
|
- `count_users(query: str | None) -> int` -- total count for pagination
|
|
|
|
Groups update: fetch user, modify `user.groups`, call `update(user)` (existing method handles group replacement).
|
|
|
|
## Testing
|
|
|
|
### Python Unit Tests
|
|
|
|
- Admin guard (403 for non-admin, redirect for unauthenticated)
|
|
- `search_users()` and `count_users()` repository methods
|
|
- Route handlers: profile update, group update, activate/deactivate, delete, invite
|
|
|
|
### E2E Playwright Tests
|
|
|
|
- Auth guard (non-admin blocked from `/admin/`)
|
|
- User list: pagination, search, inline activate/deactivate
|
|
- User detail: edit profile, manage groups, view credentials, delete credential, re-invite, delete user
|
|
- Create invite from admin UI
|