mirror of
https://github.com/DorkSquadRR/DorkNet.git
synced 2026-10-26 07:28:45 -07:00
e002b88d71
- Implemented Charades word lists management in the admin UI, allowing for unlimited named word lists with difficulty settings. - Added functionality to bind live card slots to specific word lists, with automatic fallback to built-in lists. - Introduced a profanity filter toggle in server settings, enabling or disabling the server-side profanity filter. - Updated database schema to support new features, including additional columns for profanity filter status and charades slot bindings. - Enhanced documentation to reflect new features and their usage.
170 lines
6.7 KiB
Markdown
170 lines
6.7 KiB
Markdown
# DorkNet Admin Page
|
|
|
|
The admin page is the browser operations console for DorkNet. In the
|
|
microservices deployment it lives at `https://admin.<domain>/` and is
|
|
served by the `web` service from the built Vite SPA assets.
|
|
|
|
The admin backend endpoints are under `/api/admin/v1`. Requests from the
|
|
SPA are same-origin, so `https://admin.<domain>/api/admin/v1/*` is also
|
|
handled by the `web` service route on the admin host. The same
|
|
`/api/admin/*` route family is available as a path-owned moderation slice
|
|
for non-admin-host routing, so `/internal/routes` can show moderation as
|
|
the owner for that path family.
|
|
|
|
## Runtime Routing
|
|
|
|
| Item | Value |
|
|
|---|---|
|
|
| SPA source | `DorkNet.Server/admin-ui` |
|
|
| Build output | `DorkNet.Server/wwwroot/admin` |
|
|
| Container path | `/app/wwwroot/admin` |
|
|
| Public browser host | `admin.<domain>` |
|
|
| API base used by the SPA | `/api/admin/v1` |
|
|
| Login endpoint | `POST /api/admin/v1/login` |
|
|
| Same-origin admin-host service | `web` |
|
|
| Path-routed admin API slice | `moderation` |
|
|
|
|
`DorkNet.Gateway` preserves the original Host header when it proxies to
|
|
backend services. That matters for the admin page: the `admin.<domain>`
|
|
host route must reach `web`, and `web` must contain
|
|
`/app/wwwroot/admin/index.html`.
|
|
|
|
## Authentication
|
|
|
|
The first account created on a fresh database is promoted to admin so
|
|
there is always a bootstrap operator. The login form posts to
|
|
`/api/admin/v1/login`; the SPA stores the returned values in browser
|
|
`localStorage`:
|
|
|
|
| Key | Contents |
|
|
|---|---|
|
|
| `dorknet.admin.token` | DorkNet admin JWT |
|
|
| `dorknet.admin.me` | Admin identity object used by the layout |
|
|
|
|
Every admin API request sends `Authorization: Bearer <token>`. Protected
|
|
actions are guarded by `AdminOnlyAttribute`, which checks the resolved
|
|
player row still has `IsAdmin = true`. A `401` clears the local session
|
|
and sends the browser back to login.
|
|
|
|
If the admin host is public, put it behind Cloudflare Access or an
|
|
equivalent outer access control. The DorkNet JWT is still required after
|
|
that outer check.
|
|
|
|
## Navigation
|
|
|
|
| Section | Routes | Workflows |
|
|
|---|---|---|
|
|
| Overview | `/` | Live ops dashboard, online players, active sessions, quick kick/ban/broadcast actions |
|
|
| Moderation | `/players` | Player directory, bans, reports, per-player ban/grant/gift/password/avatar/account actions |
|
|
| Activity | `/activity` | Admin audit log and per-player request logs |
|
|
| Content | `/rooms`, `/rooms/:id`, `/import-room`, `/content` | Room list/detail, room import, instances, leaderboards, community board, loading tips, 3D Charades word lists |
|
|
| Operations | `/broadcast`, `/settings` | Server broadcast, server toggles (signups, everyone-is-friends, profanity filter), signup codes, weekly challenges, Play menu tags, Rec Center doors, game config values |
|
|
|
|
Several older admin URLs are kept as redirects:
|
|
|
|
| Old route | Current route |
|
|
|---|---|
|
|
| `/bans` | `/players?tab=bans` |
|
|
| `/reports` | `/players?tab=reports` |
|
|
| `/gift`, `/passwords`, `/grants` | `/players` |
|
|
| `/audit` | `/activity?tab=audit` |
|
|
| `/logs` | `/activity?tab=logs` |
|
|
| `/rr-originals`, `/instances`, `/leaderboards` | `/rooms` |
|
|
| `/community` | `/content?tab=community` |
|
|
| `/loading-tips` | `/content?tab=tips` |
|
|
| `/signup-codes` | `/settings?tab=signup` |
|
|
|
|
`/import-room-legacy` still exists for the legacy room importer.
|
|
|
|
## 3D Charades word lists (`/content?tab=charades`)
|
|
|
|
The March 2023 client fetches a charades deck at card-box spawn from
|
|
`GET api/activities/charades/v1/words/{source}`, where `{source}` is one
|
|
of three baked `CardBox.cardSource` slots — `Charades`,
|
|
`CharadesAprilFoolsDay`, and `Icebreakers` (verified in the 2023.03.21
|
|
il2cpp dump). The response is a JSON array of
|
|
`{ "EN_US": "<phrase>", "Difficulty": <int> }` (`Difficulty` is the client
|
|
`CNMMMNJJDMM` enum: 0 easy, 1 hard, 10 very hard, 20 icebreaker).
|
|
|
|
The admin tab exposes:
|
|
|
|
- A **library** of unlimited named word lists (`CharadesWordListEntity`
|
|
rows), each with a per-card difficulty. Paste-import accepts one phrase
|
|
per line with an optional `| easy|hard|veryhard|icebreaker` suffix.
|
|
- **Live card slots** — three dropdowns binding each client slot to any
|
|
library list. Switching a slot just repoints its binding
|
|
(`ServerSettingsEntity.CharadesSlotBindingsJson`); it takes effect on the
|
|
next card-box refresh (room rejoin). An unbound slot falls back to the
|
|
built-in list seeded for it.
|
|
|
|
Three built-in lists (Default / April Fools / Icebreakers) are seeded on
|
|
first boot and bound to their slots. Seeding is idempotent — admin edits
|
|
survive restarts.
|
|
|
|
## Profanity filter toggle (`/settings`)
|
|
|
|
`ServerSettingsEntity.ProfanityFilterDisabled` gates the server-side
|
|
`api/sanitize/*` filter. When on, every sanitize route returns input
|
|
unchanged and treats all text as clean, so room/invention names and chat
|
|
are never censored. Off by default; checked per request so it takes effect
|
|
immediately.
|
|
|
|
## Build And Deploy
|
|
|
|
The service Dockerfile builds the admin SPA for service images that need
|
|
static assets. In the microservices stack the `web` image must include:
|
|
|
|
```text
|
|
/app/wwwroot/admin/index.html
|
|
/app/wwwroot/admin/assets/*
|
|
```
|
|
|
|
The admin SPA calls relative URLs, so it does not need a configured API
|
|
origin as long as the browser is opened on `https://admin.<domain>/`.
|
|
|
|
The native admin mobile app points at the same public admin host; see
|
|
[`../DorkNet.AdminMobile/README.md`](../DorkNet.AdminMobile/README.md).
|
|
|
|
## Smoke Checks
|
|
|
|
Check the static host:
|
|
|
|
```bash
|
|
curl -I https://admin.yourdomain.com/
|
|
```
|
|
|
|
Check that protected admin API routing is alive. A `401` is expected
|
|
without a valid admin token:
|
|
|
|
```bash
|
|
curl -i https://admin.yourdomain.com/api/admin/v1/stats
|
|
```
|
|
|
|
Check the built assets inside the running `web` container:
|
|
|
|
```bash
|
|
docker exec <web-container> sh -lc 'find /app/wwwroot/admin -maxdepth 2 -type f | sort | head -50'
|
|
```
|
|
|
|
Useful logs:
|
|
|
|
```bash
|
|
docker logs <stack>-gateway-1 --tail=200
|
|
docker logs <stack>-web-1 --tail=200
|
|
docker logs <stack>-moderation-1 --tail=200
|
|
```
|
|
|
|
For normal browser admin traffic, start with `gateway` and `web`.
|
|
Check `moderation` when you are testing `/api/admin/*` through a
|
|
non-admin host such as `api.<domain>`.
|
|
|
|
## Troubleshooting
|
|
|
|
| Symptom | Check |
|
|
|---|---|
|
|
| `admin.<domain>/` returns 404 | `web` logs for `probe="/app/wwwroot/admin/index.html" exists=False`; rebuild/redeploy the `web` image |
|
|
| Admin page loads but actions 404 | Gateway `/internal/routes`, then whether the request host is `admin.<domain>` or a path-routed host |
|
|
| Login or actions return 401 | Token expired, local session cleared, or the player no longer has `IsAdmin = true` |
|
|
| Browser spins forever | Open the browser network tab, then check `gateway` and `web` logs for the stuck URL |
|
|
| Upload/import fails near 100 MB | Use the chunked importer; the SPA uses 50 MB chunks to stay below Cloudflare request limits |
|