forked from syntaxbullet/aurorabot
The web/ folder contains the REST API, WebSocket server, and OAuth routes — not a web frontend. Renaming to api/ clarifies this distinction since the actual web frontend lives in panel/. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
156 lines
4.9 KiB
TypeScript
156 lines
4.9 KiB
TypeScript
/**
|
|
* @fileoverview Class management endpoints for Aurora API.
|
|
* Provides CRUD operations for player classes/guilds.
|
|
*/
|
|
|
|
import type { RouteContext, RouteModule } from "./types";
|
|
import {
|
|
jsonResponse,
|
|
errorResponse,
|
|
parseBody,
|
|
parseStringIdFromPath,
|
|
withErrorHandling
|
|
} from "./utils";
|
|
import { CreateClassSchema, UpdateClassSchema } from "./schemas";
|
|
|
|
/**
|
|
* Classes routes handler.
|
|
*
|
|
* Endpoints:
|
|
* - GET /api/classes - List all classes
|
|
* - POST /api/classes - Create a new class
|
|
* - PUT /api/classes/:id - Update a class
|
|
* - DELETE /api/classes/:id - Delete a class
|
|
*/
|
|
async function handler(ctx: RouteContext): Promise<Response | null> {
|
|
const { pathname, method, req } = ctx;
|
|
|
|
// Only handle requests to /api/classes*
|
|
if (!pathname.startsWith("/api/classes")) {
|
|
return null;
|
|
}
|
|
|
|
const { classService } = await import("@shared/modules/class/class.service");
|
|
|
|
/**
|
|
* @route GET /api/classes
|
|
* @description Returns all classes/guilds in the system.
|
|
*
|
|
* @response 200 - `{ classes: Class[] }`
|
|
* @response 500 - Error fetching classes
|
|
*
|
|
* @example
|
|
* // Response
|
|
* {
|
|
* "classes": [
|
|
* { "id": "1", "name": "Warrior", "balance": "5000", "roleId": "123456789" }
|
|
* ]
|
|
* }
|
|
*/
|
|
if (pathname === "/api/classes" && method === "GET") {
|
|
return withErrorHandling(async () => {
|
|
const classes = await classService.getAllClasses();
|
|
return jsonResponse({ classes });
|
|
}, "fetch classes");
|
|
}
|
|
|
|
/**
|
|
* @route POST /api/classes
|
|
* @description Creates a new class/guild.
|
|
*
|
|
* @body {
|
|
* id: string | number (required) - Unique class identifier,
|
|
* name: string (required) - Class display name,
|
|
* balance?: string | number - Initial class balance (default: 0),
|
|
* roleId?: string - Associated Discord role ID
|
|
* }
|
|
* @response 201 - `{ success: true, class: Class }`
|
|
* @response 400 - Missing required fields
|
|
* @response 500 - Error creating class
|
|
*
|
|
* @example
|
|
* // Request
|
|
* POST /api/classes
|
|
* { "id": "2", "name": "Mage", "balance": "0", "roleId": "987654321" }
|
|
*/
|
|
if (pathname === "/api/classes" && method === "POST") {
|
|
return withErrorHandling(async () => {
|
|
const data = await req.json() as Record<string, any>;
|
|
|
|
if (!data.id || !data.name || typeof data.name !== 'string') {
|
|
return errorResponse("Missing required fields: id and name are required", 400);
|
|
}
|
|
|
|
const newClass = await classService.createClass({
|
|
id: BigInt(data.id),
|
|
name: data.name,
|
|
balance: data.balance ? BigInt(data.balance) : 0n,
|
|
roleId: data.roleId || null,
|
|
});
|
|
|
|
return jsonResponse({ success: true, class: newClass }, 201);
|
|
}, "create class");
|
|
}
|
|
|
|
/**
|
|
* @route PUT /api/classes/:id
|
|
* @description Updates an existing class.
|
|
*
|
|
* @param id - Class ID
|
|
* @body {
|
|
* name?: string - Updated class name,
|
|
* balance?: string | number - Updated balance,
|
|
* roleId?: string - Updated Discord role ID
|
|
* }
|
|
* @response 200 - `{ success: true, class: Class }`
|
|
* @response 404 - Class not found
|
|
* @response 500 - Error updating class
|
|
*/
|
|
if (pathname.match(/^\/api\/classes\/\d+$/) && method === "PUT") {
|
|
const id = parseStringIdFromPath(pathname);
|
|
if (!id) return null;
|
|
|
|
return withErrorHandling(async () => {
|
|
const data = await req.json() as Record<string, any>;
|
|
|
|
const updateData: any = {};
|
|
if (data.name !== undefined) updateData.name = data.name;
|
|
if (data.balance !== undefined) updateData.balance = BigInt(data.balance);
|
|
if (data.roleId !== undefined) updateData.roleId = data.roleId;
|
|
|
|
const updatedClass = await classService.updateClass(BigInt(id), updateData);
|
|
|
|
if (!updatedClass) {
|
|
return errorResponse("Class not found", 404);
|
|
}
|
|
|
|
return jsonResponse({ success: true, class: updatedClass });
|
|
}, "update class");
|
|
}
|
|
|
|
/**
|
|
* @route DELETE /api/classes/:id
|
|
* @description Deletes a class. Users assigned to this class will need to be reassigned.
|
|
*
|
|
* @param id - Class ID
|
|
* @response 204 - Class deleted (no content)
|
|
* @response 500 - Error deleting class
|
|
*/
|
|
if (pathname.match(/^\/api\/classes\/\d+$/) && method === "DELETE") {
|
|
const id = parseStringIdFromPath(pathname);
|
|
if (!id) return null;
|
|
|
|
return withErrorHandling(async () => {
|
|
await classService.deleteClass(BigInt(id));
|
|
return new Response(null, { status: 204 });
|
|
}, "delete class");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export const classesRoutes: RouteModule = {
|
|
name: "classes",
|
|
handler
|
|
};
|