142 lines
3.9 KiB
TypeScript
142 lines
3.9 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server'
|
|
import connectDB from '@/lib/mongodb'
|
|
import TopicModel, { transformToTopics } from '@/models/topic'
|
|
import { authMiddleware } from '@/lib/auth-middleware'
|
|
import { ZodError } from 'zod'
|
|
|
|
export async function GET(request: NextRequest) {
|
|
try {
|
|
await connectDB()
|
|
const searchParams = request.nextUrl.searchParams
|
|
const page = parseInt(searchParams.get('page') || '1')
|
|
const limit = parseInt(searchParams.get('limit') || '10')
|
|
const search = searchParams.get('q') || ''
|
|
const tag = searchParams.get('tag') || ''
|
|
const authorId = searchParams.get('authorId') || '' // For filtering by user's topics
|
|
const includeDrafts = searchParams.get('includeDrafts') === 'true' // For user's own topics
|
|
const fetchAll = searchParams.get('fetchAll') // Admin panel support
|
|
const skip = (page - 1) * limit
|
|
|
|
// Build query based on parameters
|
|
const query: any = {}
|
|
|
|
// Authentication check for private operations (drafts or admin)
|
|
let user = null
|
|
try {
|
|
user = await authMiddleware(request)
|
|
} catch (error) {
|
|
// Non-authenticated request - that's okay for public topic listing
|
|
}
|
|
|
|
// If requesting user's own topics with drafts, verify authentication
|
|
if (includeDrafts && !user) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: { message: 'Authentication required to view drafts', code: 'AUTH_REQUIRED' },
|
|
},
|
|
{ status: 401 }
|
|
)
|
|
}
|
|
|
|
// Filter by author if specified
|
|
if (authorId) {
|
|
query.authorId = authorId
|
|
}
|
|
|
|
// Handle draft filtering
|
|
if (fetchAll === 'true') {
|
|
// Admin panel - show all posts (drafts and published)
|
|
// No draft filtering applied
|
|
} else if (includeDrafts && user && (authorId === user.id || !authorId)) {
|
|
// User requesting their own topics (including drafts)
|
|
if (!authorId) {
|
|
query.authorId = user.id
|
|
}
|
|
} else {
|
|
// Public topic listing - only published topics
|
|
query.isDraft = false
|
|
}
|
|
|
|
// Search functionality
|
|
if (search) {
|
|
query.$or = [
|
|
{ title: { $regex: search, $options: 'i' } },
|
|
{ excerpt: { $regex: search, $options: 'i' } },
|
|
{ content: { $regex: search, $options: 'i' } },
|
|
]
|
|
}
|
|
|
|
// Filter by tag
|
|
if (tag) {
|
|
query['tags.name'] = { $regex: new RegExp(tag, 'i') }
|
|
}
|
|
|
|
// Get total count with same filters
|
|
const totalTopics = await TopicModel.countDocuments(query)
|
|
|
|
// Get paginated topics sorted by publishedAt
|
|
const topics = await TopicModel.find(query)
|
|
.sort({ publishedAt: -1 })
|
|
.skip(skip)
|
|
.limit(limit)
|
|
.lean()
|
|
|
|
if (!topics || topics.length === 0) {
|
|
return NextResponse.json(
|
|
{
|
|
success: true,
|
|
data: [],
|
|
pagination: {
|
|
total: 0,
|
|
page,
|
|
limit,
|
|
totalPages: 0,
|
|
},
|
|
},
|
|
{ status: 200 }
|
|
)
|
|
}
|
|
|
|
// Transform the topics using our utility function
|
|
const transformedTopics = transformToTopics(topics)
|
|
|
|
return NextResponse.json(
|
|
{
|
|
success: true,
|
|
data: transformedTopics,
|
|
pagination: {
|
|
total: totalTopics,
|
|
page,
|
|
limit,
|
|
totalPages: Math.ceil(totalTopics / limit),
|
|
},
|
|
},
|
|
{ status: 200 }
|
|
)
|
|
} catch (error) {
|
|
console.error('Error fetching topics:', error)
|
|
|
|
if (error instanceof ZodError) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: {
|
|
message: 'Data validation failed',
|
|
code: 'VALIDATION_ERROR',
|
|
details: error.issues,
|
|
},
|
|
},
|
|
{ status: 400 }
|
|
)
|
|
}
|
|
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: { message: 'Failed to fetch topics', code: 'SERVER_ERROR' },
|
|
},
|
|
{ status: 500 }
|
|
)
|
|
}
|
|
} |