AI Implementation feature(901): Admin Area Challenges: List, Import/Export and Add/Edit Modal 1.01 (#42)
This commit was merged in pull request #42.
This commit is contained in:
@@ -3,7 +3,7 @@ type: guide
|
||||
title: Admin — Challenges
|
||||
description: How an admin lists, searches, creates, edits, deletes, imports, and exports challenges from the /admin/challenges page.
|
||||
tags: [guide, admin, challenges, import, export, files, tester]
|
||||
timestamp: 2026-07-22T20:30:00Z
|
||||
timestamp: 2026-07-22T21:25:29Z
|
||||
---
|
||||
|
||||
# When this view is available
|
||||
@@ -64,9 +64,10 @@ The form modal has three sections (tabs): General, Connection, Files. Fields mar
|
||||
| Decay solves | `cf-decay` | yes | Integer 1–10000. |
|
||||
| Secret flag (password) | `cf-flag` | yes | Stored plaintext server-side; toggled between `password` and `text` via `cf-flag-toggle`. The flag is omitted from any non-admin DTO. |
|
||||
| Protocol radios | `cf-protocol-*` | yes | NC / WEB. |
|
||||
| Port (NC: required) | `cf-port` | NC only | Integer 1–65535; cleared automatically when switching to WEB. |
|
||||
| Port (NC: required) | `cf-port` | NC only | Digits-only text input with numeric keyboard hint; integer 1–65535. Switching to WEB clears it. |
|
||||
| IP address | `cf-ip` | no | Free text — falls back to `setting.defaultChallengeIp` at solve time. |
|
||||
| File picker (multiple) | `cf-upload` | no | Each pick is staged via `POST /api/v1/admin/challenges/files/stage`; the form's `Files` tab lists them with size and MIME. |
|
||||
| File picker / drop zone | `cf-upload`, `cf-drop-zone` | no | Accepts multiple files of any type. Users may choose files or drag them onto the dashed drop zone; oversize files are rejected before upload. |
|
||||
| Upload error | `cf-upload-error` | n/a | Reports the rejected filename and global size limit, or a staging request failure. |
|
||||
| File list | `cf-files` | n/a | Existing files (with `🗑` to mark for removal) plus staged uploads. |
|
||||
|
||||
# Expected behavior
|
||||
@@ -83,9 +84,11 @@ The form modal has three sections (tabs): General, Connection, Files. Fields mar
|
||||
|
||||
1. Click **Add challenge** (or the row's ✎ button) → form modal opens in create (or edit) mode.
|
||||
2. Edit mode fetches `GET /api/v1/admin/challenges/:id` to populate every field including `flag`, then renders sanitized description preview.
|
||||
3. Save calls `POST` (or `PUT`) with the manifest of staged file tokens and existing-file removal ids.
|
||||
4. Server-side errors map to inline field messages (`cf-error-<field>`) and stay on the modal; success closes the modal, refreshes the list, and surfaces a success banner.
|
||||
5. Cancel/Esc/backdrop discards every pending staged token via `DELETE /files/stage/:token`.
|
||||
3. For NC challenges, Port starts blank and must contain digits representing an integer from 1 through 65535. Invalid or missing values display inline, and Save automatically opens the Connection tab so the error is visible. General-field errors similarly open the General tab.
|
||||
4. Files can be selected through the picker or dropped onto the Files tab drop zone. Files within the global limit immediately appear as uploading placeholders and are staged through `POST /api/v1/admin/challenges/files/stage`; oversize files never trigger that request and show `cf-upload-error`.
|
||||
5. Save calls `POST` (or `PUT`) with the manifest of staged file tokens and existing-file removal ids.
|
||||
6. Server-side errors map to inline field messages (`cf-error-<field>`) and stay on the modal; success closes the modal, refreshes the list, and surfaces a success banner.
|
||||
7. Cancel/Esc/backdrop discards every pending staged token via `DELETE /files/stage/:token`.
|
||||
|
||||
## Delete
|
||||
|
||||
@@ -122,7 +125,7 @@ The form modal has three sections (tabs): General, Connection, Files. Fields mar
|
||||
| 1 | `frontend/src/app/app.routes.ts` | `/admin/challenges` lazy-loads `AdminChallengesComponent`. |
|
||||
| 2 | `frontend/src/app/features/admin/challenges/challenges.component.ts` | Owns search debounce, modal state, in-flight locks, refresh. |
|
||||
| 3 | `frontend/src/app/core/services/admin.service.ts` | Typed `listChallenges`, `getChallengeDetail`, `createChallenge`, `updateChallenge`, `deleteChallenge`, `exportChallenges`, `previewChallengeImport`, `confirmChallengeImport`, `stageChallengeFile`, `discardChallengeFile`. |
|
||||
| 4 | `frontend/src/app/features/admin/challenges/challenge-form.pure.ts` | Defaults/prefill, points/port validation, payload mapping. |
|
||||
| 4 | `frontend/src/app/features/admin/challenges/challenge-form.pure.ts` | Defaults/prefill, points/port validation, first-invalid-tab selection, file-size partitioning, payload mapping. |
|
||||
| 5 | `backend/src/modules/admin/admin-challenges.controller.ts` | `AdminGuard` + `@Roles('admin')` on every handler. |
|
||||
| 6 | `backend/src/modules/admin/challenges.service.ts` | CRUD, list aggregates, transactional deletion, export, import orchestration. |
|
||||
| 7 | `backend/src/modules/admin/challenge-files.service.ts` | Staging, commit, discard, read for export, limits. |
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ scoreboard, an event window with a public countdown, theming, and admin
|
||||
controls.
|
||||
|
||||
The docs below are organized by purpose so agents can pull just the slice
|
||||
they need. Last regenerated 2026-07-22T20:25:58Z.
|
||||
they need. Last regenerated 2026-07-22T21:25:29Z.
|
||||
|
||||
# Architecture
|
||||
|
||||
|
||||
Reference in New Issue
Block a user