관리자 글 목록 API 응답 경량화
This commit is contained in:
@@ -83,6 +83,30 @@ const mapAdminPostRow = (row) => ({
|
||||
title: toAdminPostFormTitle(row.title)
|
||||
})
|
||||
|
||||
/**
|
||||
* 관리자 목록 API용 게시물 요약 행 변환
|
||||
* @param {Object} row - 게시물 행
|
||||
* @returns {Object} 게시물 요약 응답
|
||||
*/
|
||||
const mapAdminPostSummaryRow = (row) => ({
|
||||
id: row.id,
|
||||
title: toAdminPostFormTitle(row.title),
|
||||
slug: row.slug,
|
||||
authorId: row.author_id || null,
|
||||
excerpt: row.excerpt,
|
||||
featuredImage: row.featured_image,
|
||||
featuredImageThumbnail: getExistingPostThumbnailUrl(row.featured_image),
|
||||
showFeaturedImage: Boolean(row.show_featured_image),
|
||||
isFeatured: Boolean(row.is_featured),
|
||||
commentCount: Number(row.comment_count || 0),
|
||||
totalViews: Number(row.total_views || 0),
|
||||
status: row.status,
|
||||
publishedAt: row.published_at ? row.published_at.toISOString() : null,
|
||||
createdAt: row.created_at.toISOString(),
|
||||
updatedAt: row.updated_at.toISOString(),
|
||||
tags: row.tags || []
|
||||
})
|
||||
|
||||
/**
|
||||
* 고정 페이지 행을 API 응답 구조로 변환
|
||||
* @param {Object} row - 고정 페이지 행
|
||||
@@ -438,19 +462,33 @@ export const listPosts = async ({
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 게시물 목록 조회
|
||||
* @returns {Promise<Array>} 관리자 게시물 목록
|
||||
* 관리자 게시물 목록 요약 조회
|
||||
* @returns {Promise<Array>} 관리자 게시물 목록 요약
|
||||
*/
|
||||
export const listAdminPosts = async () => {
|
||||
const sql = getPostgresClient()
|
||||
|
||||
if (!sql) {
|
||||
return getSamplePosts()
|
||||
return getSamplePosts().map((post) => {
|
||||
const { content, ...summary } = post
|
||||
return summary
|
||||
})
|
||||
}
|
||||
|
||||
const rows = await sql`
|
||||
SELECT
|
||||
posts.*,
|
||||
posts.id,
|
||||
posts.title,
|
||||
posts.slug,
|
||||
posts.author_id,
|
||||
posts.excerpt,
|
||||
posts.featured_image,
|
||||
posts.show_featured_image,
|
||||
posts.is_featured,
|
||||
posts.status,
|
||||
posts.published_at,
|
||||
posts.created_at,
|
||||
posts.updated_at,
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM comments
|
||||
@@ -466,11 +504,23 @@ export const listAdminPosts = async () => {
|
||||
FROM posts
|
||||
LEFT JOIN post_tags ON post_tags.post_id = posts.id
|
||||
LEFT JOIN tags ON tags.id = post_tags.tag_id
|
||||
GROUP BY posts.id
|
||||
GROUP BY
|
||||
posts.id,
|
||||
posts.title,
|
||||
posts.slug,
|
||||
posts.author_id,
|
||||
posts.excerpt,
|
||||
posts.featured_image,
|
||||
posts.show_featured_image,
|
||||
posts.is_featured,
|
||||
posts.status,
|
||||
posts.published_at,
|
||||
posts.created_at,
|
||||
posts.updated_at
|
||||
ORDER BY COALESCE(posts.published_at, posts.updated_at) DESC
|
||||
`
|
||||
|
||||
return rows.map(mapAdminPostRow)
|
||||
return rows.map(mapAdminPostSummaryRow)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -628,6 +678,31 @@ export const updateAdminPost = async (id, input, editorId) => {
|
||||
return rows[0] ? getAdminPostById(rows[0].id) : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 게시물 추천 상태 수정
|
||||
* @param {string} id - 게시물 ID
|
||||
* @param {boolean} isFeatured - 추천 여부
|
||||
* @returns {Promise<Object | null>} 수정된 게시물
|
||||
*/
|
||||
export const updateAdminPostFeatured = async (id, isFeatured) => {
|
||||
const sql = getPostgresClient()
|
||||
|
||||
if (!sql) {
|
||||
throw new Error('DATABASE_REQUIRED')
|
||||
}
|
||||
|
||||
const rows = await sql`
|
||||
UPDATE posts
|
||||
SET
|
||||
is_featured = ${Boolean(isFeatured)},
|
||||
updated_at = now()
|
||||
WHERE id = ${id}
|
||||
RETURNING id
|
||||
`
|
||||
|
||||
return rows[0] ? getAdminPostById(rows[0].id) : null
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 게시물 삭제
|
||||
* @param {string} id - 게시물 ID
|
||||
|
||||
45
server/routes/admin/api/posts/[id]/featured.put.js
Normal file
45
server/routes/admin/api/posts/[id]/featured.put.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { createError, getRouterParam, readBody } from 'h3'
|
||||
import { z } from 'zod'
|
||||
import { requireAdminSession } from '../../../../../utils/admin-auth'
|
||||
import { updateAdminPostFeatured } from '../../../../../repositories/content-repository'
|
||||
|
||||
const featuredInputSchema = z.object({
|
||||
isFeatured: z.boolean()
|
||||
})
|
||||
|
||||
/**
|
||||
* 관리자 게시물 추천 상태 변경 API
|
||||
* @param {import('h3').H3Event} event - 요청 이벤트
|
||||
* @returns {Promise<Object>} 수정된 게시물
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
requireAdminSession(event)
|
||||
|
||||
const id = String(getRouterParam(event, 'id') || '').trim()
|
||||
const parsedBody = featuredInputSchema.safeParse(await readBody(event))
|
||||
|
||||
if (!id) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '게시물 ID가 필요합니다.'
|
||||
})
|
||||
}
|
||||
|
||||
if (!parsedBody.success) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
message: '추천 상태 입력 형식이 올바르지 않습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
const post = await updateAdminPostFeatured(id, parsedBody.data.isFeatured)
|
||||
|
||||
if (!post) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
message: '게시물을 찾을 수 없습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
return post
|
||||
})
|
||||
Reference in New Issue
Block a user