feat(admin-tags): POST /api/admin/tags to create craft/cooperative tags
Admin-only route that validates a label + pool via zod, slugifies the label, returns the existing tag if the slug already exists, otherwise creates a new active Tag document.
This commit is contained in:
parent
4a05e91715
commit
384d3197ce
2 changed files with 45 additions and 0 deletions
40
server/api/admin/tags/index.post.js
Normal file
40
server/api/admin/tags/index.post.js
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
import Tag from '../../../models/tag.js'
|
||||||
|
import { adminTagCreateSchema } from '../../../utils/schemas.js'
|
||||||
|
|
||||||
|
const slugify = (s) =>
|
||||||
|
s
|
||||||
|
.toLowerCase()
|
||||||
|
.trim()
|
||||||
|
.replace(/\s+/g, '-')
|
||||||
|
.replace(/[^a-z0-9-]/g, '')
|
||||||
|
.replace(/-+/g, '-')
|
||||||
|
.replace(/^-|-$/g, '')
|
||||||
|
|
||||||
|
export default defineEventHandler(async (event) => {
|
||||||
|
await requireAdmin(event)
|
||||||
|
await connectDB()
|
||||||
|
|
||||||
|
const body = await validateBody(event, adminTagCreateSchema)
|
||||||
|
const slug = slugify(body.label)
|
||||||
|
|
||||||
|
if (!slug) {
|
||||||
|
throw createError({
|
||||||
|
statusCode: 400,
|
||||||
|
statusMessage: 'Tag label must contain at least one alphanumeric character'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = await Tag.findOne({ slug })
|
||||||
|
if (existing) {
|
||||||
|
return { tag: { slug: existing.slug, label: existing.label, pool: existing.pool } }
|
||||||
|
}
|
||||||
|
|
||||||
|
const tag = await Tag.create({
|
||||||
|
slug,
|
||||||
|
label: body.label,
|
||||||
|
pool: body.pool,
|
||||||
|
active: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return { tag: { slug: tag.slug, label: tag.label, pool: tag.pool } }
|
||||||
|
})
|
||||||
|
|
@ -383,6 +383,11 @@ export const tagSuggestionSchema = z.object({
|
||||||
pool: z.enum(['craft', 'cooperative'])
|
pool: z.enum(['craft', 'cooperative'])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const adminTagCreateSchema = z.object({
|
||||||
|
label: z.string().trim().min(1).max(100),
|
||||||
|
pool: z.enum(['craft', 'cooperative'])
|
||||||
|
})
|
||||||
|
|
||||||
// --- Board post / channel schemas ---
|
// --- Board post / channel schemas ---
|
||||||
|
|
||||||
export const boardPostCreateSchema = z.object({
|
export const boardPostCreateSchema = z.object({
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue