From 9c33a4e9b977da75080c5df898476cbe39db887e Mon Sep 17 00:00:00 2001 From: ChickenPige0n <2336983354@qq.com> Date: Sat, 11 Jul 2026 13:15:53 +0800 Subject: [PATCH] feat: validate team slug format and improve error handling in team creation --- .../src/routes/admin/org/[slug]/teams/+page.svelte | 11 +++++++++-- hub/src/admin/errors.ts | 5 ++++- hub/src/admin/routes/teamsRoutes.ts | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/hub/admin-web/src/routes/admin/org/[slug]/teams/+page.svelte b/hub/admin-web/src/routes/admin/org/[slug]/teams/+page.svelte index 96bc22d..3ea7374 100644 --- a/hub/admin-web/src/routes/admin/org/[slug]/teams/+page.svelte +++ b/hub/admin-web/src/routes/admin/org/[slug]/teams/+page.svelte @@ -38,12 +38,19 @@ } } + const SLUG_RE = /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/; + async function createTeam() { if (!newSlug.trim() || !newName.trim()) return; + const teamSlug = newSlug.trim().toLowerCase(); + if (!SLUG_RE.test(teamSlug)) { + toastError('标识须为小写字母数字,可用连字符连接'); + return; + } adding = true; try { await api.createTeam(slug, { - slug: newSlug.trim(), + slug: teamSlug, name: newName.trim(), ...(newDesc.trim() ? { description: newDesc.trim() } : {}) }); @@ -134,7 +141,7 @@

新建团队

- + diff --git a/hub/src/admin/errors.ts b/hub/src/admin/errors.ts index 01ecf26..ee9fbb7 100644 --- a/hub/src/admin/errors.ts +++ b/hub/src/admin/errors.ts @@ -35,9 +35,11 @@ export async function handleRouteError(reply: FastifyReply, err: unknown): Promi await sendError(reply, mapped.statusCode, mapped.code, mapped.message); return; } + reply.log.error({ err }, "unmapped route error"); await sendError(reply, 500, "internal_error", "internal error"); return; } + reply.log.error({ err }, "unmapped route error"); await sendError(reply, 500, "internal_error", "internal error"); } @@ -71,7 +73,8 @@ function mapDomainError(message: string): { statusCode: number; code: string; me lower.includes("is required") || lower.includes("already") || lower.includes("invalid") || - lower.includes("accepts only") + lower.includes("accepts only") || + lower.includes("must be") ) { return { statusCode: 400, code: "bad_request", message }; } diff --git a/hub/src/admin/routes/teamsRoutes.ts b/hub/src/admin/routes/teamsRoutes.ts index 9a76af1..4d34533 100644 --- a/hub/src/admin/routes/teamsRoutes.ts +++ b/hub/src/admin/routes/teamsRoutes.ts @@ -34,7 +34,7 @@ export async function registerTeamsRoutes( const { orgSlug } = request.params as { orgSlug: string }; const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug }); if (auth === null) return; - const body = request.body as { slug?: unknown; name?: unknown; description?: unknown }; + const body = (request.body ?? {}) as { slug?: unknown; name?: unknown; description?: unknown }; if (typeof body.slug !== "string" || typeof body.name !== "string") { return reply.status(400).send({ error: { code: "bad_request", message: "slug and name are required" },