feat: implement lootdrop management endpoints and fix class api types

This commit is contained in:
syntaxbullet
2026-02-08 16:56:34 +01:00
parent 4232674494
commit 073348fa55
3 changed files with 154 additions and 4 deletions

View File

@@ -951,7 +951,7 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
const { classService } = await import("@shared/modules/class/class.service");
const data = await req.json() as Record<string, any>;
if (!data.id || !data.name) {
if (!data.id || !data.name || typeof data.name !== 'string') {
return Response.json(
{ error: "Missing required fields: id and name are required" },
{ status: 400 }
@@ -1206,6 +1206,96 @@ export async function createWebServer(config: WebServerConfig = {}): Promise<Web
}
}
// =====================================
// Lootdrops API
// =====================================
// GET /api/lootdrops - List lootdrops
if (url.pathname === "/api/lootdrops" && req.method === "GET") {
try {
const { lootdrops } = await import("../../shared/db/schema");
const { DrizzleClient } = await import("@shared/db/DrizzleClient");
const { desc } = await import("drizzle-orm");
const limit = url.searchParams.get("limit") ? parseInt(url.searchParams.get("limit")!) : 50;
const result = await DrizzleClient.select()
.from(lootdrops)
.orderBy(desc(lootdrops.createdAt))
.limit(limit);
const { jsonReplacer } = await import("@shared/lib/utils");
return new Response(JSON.stringify({ lootdrops: result }, jsonReplacer), {
headers: { "Content-Type": "application/json" }
});
} catch (error) {
logger.error("web", "Error fetching lootdrops", error);
return Response.json(
{ error: "Failed to fetch lootdrops", details: error instanceof Error ? error.message : String(error) },
{ status: 500 }
);
}
}
// POST /api/lootdrops - Spawn lootdrop
if (url.pathname === "/api/lootdrops" && req.method === "POST") {
try {
const { lootdropService } = await import("@shared/modules/economy/lootdrop.service");
const { AuroraClient } = await import("../../bot/lib/BotClient");
const { TextChannel } = await import("discord.js");
const data = await req.json() as Record<string, any>;
if (!data.channelId) {
return Response.json(
{ error: "Missing required field: channelId" },
{ status: 400 }
);
}
const channel = await AuroraClient.channels.fetch(data.channelId);
if (!channel || !(channel instanceof TextChannel)) {
return Response.json(
{ error: "Invalid channel. Must be a TextChannel." },
{ status: 400 }
);
}
await lootdropService.spawnLootdrop(channel, data.amount, data.currency);
return Response.json({ success: true }, { status: 201 });
} catch (error) {
logger.error("web", "Error spawning lootdrop", error);
return Response.json(
{ error: "Failed to spawn lootdrop", details: error instanceof Error ? error.message : String(error) },
{ status: 500 }
);
}
}
// DELETE /api/lootdrops/:id - Cancel/Delete lootdrop
if (url.pathname.match(/^\/api\/lootdrops\/[^\/]+$/) && req.method === "DELETE") {
const messageId = url.pathname.split("/").pop()!;
try {
const { lootdropService } = await import("@shared/modules/economy/lootdrop.service");
const success = await lootdropService.deleteLootdrop(messageId);
if (!success) {
return Response.json({ error: "Lootdrop not found" }, { status: 404 });
}
return new Response(null, { status: 204 });
} catch (error) {
logger.error("web", "Error deleting lootdrop", error);
return Response.json(
{ error: "Failed to delete lootdrop", details: error instanceof Error ? error.message : String(error) },
{ status: 500 }
);
}
}
// No frontend - return 404 for unknown routes
return new Response("Not Found", { status: 404 });
},