ai-wpa/app/api/topic/[id]/route.ts

262 lines
6.5 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server'
import TopicModel, { transformToTopic } from '@/models/topic'
import { authMiddleware } from '@/lib/auth-middleware'
import { uploadFile, moveToPermStorage, getFileUrl, generateUniqueFilename } from '@/lib/file-vault'
import { z } from 'zod'
// Validation schema for topic updates
const topicUpdateSchema = z.object({
title: z.string().min(1).max(100).optional(),
author: z.string().min(1).optional(),
excerpt: z.string().min(1).max(200).optional(),
content: z.string().min(1).optional(),
contentRTE: z.unknown().optional(),
contentImages: z.array(z.string()).optional(),
tags: z
.array(
z.object({
id: z.string().optional(),
name: z.string(),
})
)
.min(1)
.optional(),
featured: z.boolean().optional(),
isDraft: z.boolean().optional(),
coverImage: z.string().url().optional(),
coverImageKey: z.string().optional(),
})
// GET /api/topic/[id] - Get topic by ID
export async function GET(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params
const topic = await TopicModel.findOne({ id }).lean()
if (!topic) {
return NextResponse.json(
{
success: false,
error: { message: 'Topic not found', code: 'NOT_FOUND' },
},
{ status: 404 }
)
}
// Check if topic is draft and user is not the owner
if (topic.isDraft) {
const user = await authMiddleware(request)
if (!user || user.id !== topic.authorId) {
return NextResponse.json(
{
success: false,
error: { message: 'Topic not found', code: 'NOT_FOUND' },
},
{ status: 404 }
)
}
}
const transformedTopic = transformToTopic(topic)
return NextResponse.json(
{
success: true,
data: transformedTopic,
},
{ status: 200 }
)
} catch (error) {
console.error('Error fetching topic:', error)
return NextResponse.json(
{
success: false,
error: { message: 'Failed to fetch topic', code: 'SERVER_ERROR' },
},
{ status: 500 }
)
}
}
// PUT /api/topic/[id] - Update topic by ID
export async function PUT(request: NextRequest, { params }: { params: Promise<{ id: string }> }) {
try {
// Authentication required for updating topics
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json(
{
success: false,
error: { message: 'Authentication required', code: 'AUTH_REQUIRED' },
},
{ status: 401 }
)
}
const { id } = await params
// Find the topic first
const existingTopic = await TopicModel.findOne({ id })
if (!existingTopic) {
return NextResponse.json(
{
success: false,
error: { message: 'Topic not found', code: 'NOT_FOUND' },
},
{ status: 404 }
)
}
// Check ownership - users can only update their own topics
if (existingTopic.authorId !== user.id) {
return NextResponse.json(
{
success: false,
error: { message: 'You can only edit your own topics', code: 'FORBIDDEN' },
},
{ status: 403 }
)
}
const body = await request.json()
// Validate request body
const validatedData = topicUpdateSchema.parse(body)
console.log('Updating topic for user:', user.id, 'Topic ID:', id)
try {
// Update the topic with new data
Object.assign(existingTopic, validatedData)
existingTopic.publishedAt = Date.now() // Update timestamp
const updatedTopic = await existingTopic.save()
console.log('Topic updated successfully:', updatedTopic.id)
return NextResponse.json(
{
success: true,
data: updatedTopic,
},
{ status: 200 }
)
} catch (error) {
console.error('Failed to update topic:', error)
if (error.code === 11000) {
return NextResponse.json(
{
success: false,
error: { message: 'A topic with this slug already exists', code: 'DUPLICATE_SLUG' },
},
{ status: 409 }
)
}
throw error
}
} catch (error) {
console.error('Error updating topic:', error)
if (error instanceof z.ZodError) {
return NextResponse.json(
{
success: false,
error: {
message: 'Validation failed',
code: 'VALIDATION_ERROR',
details: error.issues,
},
},
{ status: 400 }
)
}
return NextResponse.json(
{
success: false,
error: { message: 'Failed to update topic', code: 'SERVER_ERROR' },
},
{ status: 500 }
)
}
}
// DELETE /api/topic/[id] - Delete topic by ID
export async function DELETE(
request: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
try {
// Authentication required for deleting topics
const user = await authMiddleware(request)
if (!user) {
return NextResponse.json(
{
success: false,
error: { message: 'Authentication required', code: 'AUTH_REQUIRED' },
},
{ status: 401 }
)
}
const { id } = await params
// Find the topic first
const existingTopic = await TopicModel.findOne({ id })
if (!existingTopic) {
return NextResponse.json(
{
success: false,
error: { message: 'Topic not found', code: 'NOT_FOUND' },
},
{ status: 404 }
)
}
// Check ownership - users can only delete their own topics
if (existingTopic.authorId !== user.id) {
return NextResponse.json(
{
success: false,
error: { message: 'You can only delete your own topics', code: 'FORBIDDEN' },
},
{ status: 403 }
)
}
console.log('Deleting topic for user:', user.id, 'Topic ID:', id)
try {
await TopicModel.deleteOne({ id })
console.log('Topic deleted successfully:', id)
return NextResponse.json(
{
success: true,
message: 'Topic deleted successfully',
},
{ status: 200 }
)
} catch (error) {
console.error('Failed to delete topic:', error)
throw error
}
} catch (error) {
console.error('Error deleting topic:', error)
return NextResponse.json(
{
success: false,
error: { message: 'Failed to delete topic', code: 'SERVER_ERROR' },
},
{ status: 500 }
)
}
}