-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathroute.ts
More file actions
187 lines (164 loc) · 5 KB
/
route.ts
File metadata and controls
187 lines (164 loc) · 5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
// GET /api/posts - 모든 글 조회 (페이지네이션 지원)
import { QuerySelector } from 'mongoose';
import Series from '@/app/models/Series';
import dbConnect from '@/app/lib/dbConnect';
import Post from '@/app/models/Post';
import { getServerSession } from 'next-auth';
import { generateUniqueSlug } from '@/app/lib/utils/post';
import { getThumbnailInMarkdown } from '@/app/lib/utils/parse';
export async function GET(req: Request) {
try {
await dbConnect();
const { searchParams } = new URL(req.url);
// 기존 파라미터
const query = searchParams.get('query') || '';
const seriesSlug = searchParams.get('series') || '';
const isCompact = searchParams.get('compact') === 'true';
const isCanViewPrivate = searchParams.get('private') === 'true';
// const sortBy: 'date' | 'view' | string = searchParams.get('sort') || 'date';
// 페이지네이션 파라미터
const page = parseInt(searchParams.get('page') || '1');
const limit = parseInt(searchParams.get('limit') || '12');
// 유효한 페이지 및 제한 확인
const validPage = page > 0 ? page : 1;
const validLimit = limit > 0 && limit <= 50 ? limit : 12;
// 건너뛸 문서 수 계산
const skip = (validPage - 1) * validLimit;
const seriesId = seriesSlug
? await Series.findOne({ slug: seriesSlug }, '_id')
: null;
// 검색 조건 구성
const searchConditions = {
$or: [
{ title: { $regex: query, $options: 'i' } },
{ content: { $regex: query, $options: 'i' } },
{ subTitle: { $regex: query, $options: 'i' } },
],
$and: [
...(isCanViewPrivate
? []
: [
{
$or: [{ isPrivate: false }, { isPrivate: { $exists: false } }],
},
]),
],
};
if (seriesId) {
(searchConditions.$and as QuerySelector<string>[]).push({
seriesId: seriesId._id,
} as QuerySelector<string>);
}
// 검색 조건을 만족하는 총 문서 수 계산
const totalPosts = await Post.countDocuments(searchConditions);
// 페이지네이션된 쿼리 구성
let q = Post.find(searchConditions);
if (isCompact) {
q = q.select(
'slug title _id subTitle author date tags thumbnailImage seriesId timeToRead createdAt updatedAt'
);
}
const posts = await q.sort({ date: -1 }).skip(skip).limit(validLimit);
return Response.json(
{
success: true,
posts: posts,
pagination: {
totalPosts,
currentPage: validPage,
totalPages: Math.ceil(totalPosts / validLimit),
hasNextPage: skip + posts.length < totalPosts,
hasPrevPage: validPage > 1,
limit: validLimit,
},
},
{
status: 200,
headers: {
'Cache-Control': 'public, max-age=60',
},
}
);
} catch (error) {
console.error(error);
return Response.json(
{ success: false, error: '포스트 목록 불러오기 실패', detail: error },
{ status: 500 }
);
}
}
// POST /api/posts - 글 작성 API
export async function POST(req: Request) {
try {
const session = await getServerSession();
if (!session) {
return new Response('Unauthorized', { status: 401 });
}
await dbConnect();
const {
title,
subTitle,
author,
content,
profileImage,
seriesId,
tags,
isPrivate,
} = await req.json();
if (!title || !content || !author || !content) {
return Response.json(
{ success: false, error: '제목, 소제목, 작성자, 내용은 필수입니다' },
{ status: 400 }
);
}
let thumbnailOfPost = getThumbnailInMarkdown(content);
if (!thumbnailOfPost) {
const defaultSeriesThumbnail =
await Series.findById(seriesId).select('thumbnailImage');
thumbnailOfPost =
defaultSeriesThumbnail?.thumbnailImage ||
'/images/placeholder/thumbnail_example2.webp';
}
const post = {
slug: await generateUniqueSlug(title, Post),
title,
subTitle,
author,
content,
timeToRead: Math.ceil(content.length / 500),
profileImage,
thumbnailImage: thumbnailOfPost,
seriesId: seriesId || null,
tags: tags || [],
isPrivate: isPrivate || false,
};
const newPost = await Post.create(post);
if (!newPost) {
return Response.json(
{ success: false, error: '글 작성 실패' },
{ status: 500 }
);
}
if (post.seriesId) {
await Series.findByIdAndUpdate(post.seriesId, {
$push: { posts: newPost._id },
$inc: { postCount: 1 }, // postCount 1 증가
});
}
return Response.json(
{
success: true,
post: newPost,
},
{
status: 201,
}
);
} catch (error) {
console.error('Post creation error:', error);
return Response.json(
{ success: false, error: 'Invalid Post Request' },
{ status: 500 }
);
}
}