feat(admin): rename series route and add tags review page
Rename /admin/series-management to /admin/series so it follows the /admin/<section> convention; the breadcrumb's auto-derived parent link is now a real route (was a dead /admin/series link). Add an /admin/tags page to review pending TagSuggestions — list, approve (creates the Tag), reject — backed by new admin endpoints and a tagSuggestionReviewSchema. Resolves the dead /admin/tags alert link.
This commit is contained in:
parent
7beb86b430
commit
151481f1ec
9 changed files with 358 additions and 9 deletions
43
server/api/admin/tag-suggestions/[id].patch.js
Normal file
43
server/api/admin/tag-suggestions/[id].patch.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
import TagSuggestion from '../../../models/tagSuggestion.js'
|
||||
import Tag from '../../../models/tag.js'
|
||||
import { connectDB } from '../../../utils/mongoose.js'
|
||||
import { requireAdmin } from '../../../utils/auth.js'
|
||||
import { validateBody } from '../../../utils/validateBody.js'
|
||||
import { tagSuggestionReviewSchema } 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 id = getRouterParam(event, 'id')
|
||||
const { action } = await validateBody(event, tagSuggestionReviewSchema)
|
||||
|
||||
const suggestion = await TagSuggestion.findById(id).lean()
|
||||
if (!suggestion) {
|
||||
throw createError({ statusCode: 404, statusMessage: 'Tag suggestion not found' })
|
||||
}
|
||||
if (suggestion.status !== 'pending') {
|
||||
throw createError({ statusCode: 409, statusMessage: 'Tag suggestion already reviewed' })
|
||||
}
|
||||
|
||||
if (action === 'approve') {
|
||||
const slug = slugify(suggestion.label)
|
||||
if (slug && !(await Tag.findOne({ slug }))) {
|
||||
await Tag.create({ slug, label: suggestion.label, pool: suggestion.pool, active: true })
|
||||
}
|
||||
}
|
||||
|
||||
const status = action === 'approve' ? 'approved' : 'rejected'
|
||||
await TagSuggestion.findByIdAndUpdate(id, { status }, { runValidators: false })
|
||||
|
||||
return { suggestion: { id, status } }
|
||||
})
|
||||
23
server/api/admin/tag-suggestions/index.get.js
Normal file
23
server/api/admin/tag-suggestions/index.get.js
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
import TagSuggestion from '../../../models/tagSuggestion.js'
|
||||
import { connectDB } from '../../../utils/mongoose.js'
|
||||
import { requireAdmin } from '../../../utils/auth.js'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
await requireAdmin(event)
|
||||
await connectDB()
|
||||
|
||||
const suggestions = await TagSuggestion.find({ status: 'pending' })
|
||||
.sort({ createdAt: 1 })
|
||||
.populate('suggestedBy', 'name')
|
||||
.lean()
|
||||
|
||||
return {
|
||||
suggestions: suggestions.map((s) => ({
|
||||
id: String(s._id),
|
||||
label: s.label,
|
||||
pool: s.pool,
|
||||
suggestedBy: s.suggestedBy?.name || 'Unknown',
|
||||
createdAt: s.createdAt
|
||||
}))
|
||||
}
|
||||
})
|
||||
|
|
@ -388,6 +388,10 @@ export const adminTagCreateSchema = z.object({
|
|||
pool: z.enum(['craft', 'cooperative'])
|
||||
})
|
||||
|
||||
export const tagSuggestionReviewSchema = z.object({
|
||||
action: z.enum(['approve', 'reject'])
|
||||
})
|
||||
|
||||
// --- Board post / channel schemas ---
|
||||
|
||||
export const boardPostCreateSchema = z.object({
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue