v1.4.5: 게시물 작성자·편집 링크·목록 요약 보정

- posts.author_id 마이그레이션 및 owner/admin 단일 계정 환경에서만 기존 글 backfill
- 공개 상세: 글쓴이 본인일 때만 공유 옆 수정 링크 표시, 수정 시각 제거
- 목록 요약: excerpt 없을 때 본문 fallback, post-summary-clamp로 말줄임 처리
- 회원 세션 API에 isAdmin·role 추가
This commit is contained in:
2026-05-22 14:43:22 +09:00
parent 8f53210756
commit 38ca3a4709
16 changed files with 215 additions and 47 deletions

View File

@@ -4,7 +4,7 @@ import { requireMemberSession } from '../../utils/member-auth'
/**
* 회원 세션 조회 API
* @param {import('h3').H3Event} event - 요청 이벤트
* @returns {Promise<{ id: string, username: string, email: string, avatarUrl: string }>} 회원 정보
* @returns {Promise<{ id: string, username: string, email: string, avatarUrl: string, isAdmin: boolean, role: string }>} 회원 정보
*/
export default defineEventHandler(async (event) => {
const session = requireMemberSession(event)
@@ -15,7 +15,9 @@ export default defineEventHandler(async (event) => {
id: session.userId,
username: '',
email: session.email,
avatarUrl: ''
avatarUrl: '',
isAdmin: false,
role: 'member'
}
}
@@ -23,6 +25,8 @@ export default defineEventHandler(async (event) => {
id: user.id,
username: user.username,
email: user.email,
avatarUrl: user.avatarUrl || ''
avatarUrl: user.avatarUrl || '',
isAdmin: Boolean(user.isAdmin),
role: user.role || 'member'
}
})

View File

@@ -24,6 +24,7 @@ const mapPostRow = (row) => ({
id: row.id,
title: row.title,
slug: row.slug,
authorId: row.author_id || null,
content: row.content,
excerpt: row.excerpt,
featuredImage: row.featured_image,
@@ -308,9 +309,10 @@ export const getAdminPostById = async (id) => {
/**
* 관리자 게시물 생성
* @param {Object} input - 게시물 입력값
* @param {string} authorId - 작성자 회원 ID
* @returns {Promise<Object>} 생성된 게시물
*/
export const createAdminPost = async (input) => {
export const createAdminPost = async (input, authorId) => {
const sql = getPostgresClient()
if (!sql) {
@@ -322,6 +324,7 @@ export const createAdminPost = async (input) => {
INSERT INTO posts (
title,
slug,
author_id,
content,
excerpt,
featured_image,
@@ -337,6 +340,7 @@ export const createAdminPost = async (input) => {
VALUES (
${input.title},
${input.slug},
${authorId || null},
${input.content},
${input.excerpt},
${input.featuredImage},
@@ -364,9 +368,10 @@ export const createAdminPost = async (input) => {
* 관리자 게시물 수정
* @param {string} id - 게시물 ID
* @param {Object} input - 게시물 입력값
* @param {string} editorId - 수정자 회원 ID
* @returns {Promise<Object | null>} 수정된 게시물
*/
export const updateAdminPost = async (id, input) => {
export const updateAdminPost = async (id, input, editorId) => {
const sql = getPostgresClient()
if (!sql) {
@@ -379,6 +384,7 @@ export const updateAdminPost = async (id, input) => {
SET
title = ${input.title},
slug = ${input.slug},
author_id = COALESCE(author_id, ${editorId || null}),
content = ${input.content},
excerpt = ${input.excerpt},
featured_image = ${input.featuredImage},

View File

@@ -9,7 +9,7 @@ import { createAdminPost } from '../../../repositories/content-repository'
* @returns {Promise<Object>} 생성된 게시물
*/
export default defineEventHandler(async (event) => {
requireAdminSession(event)
const adminSession = requireAdminSession(event)
const parsedBody = parseAdminPostInput(await readBody(event))
@@ -21,7 +21,7 @@ export default defineEventHandler(async (event) => {
}
try {
return await createAdminPost(parsedBody.data)
return await createAdminPost(parsedBody.data, adminSession.userId)
} catch (error) {
if (error?.code === '23505') {
throw createError({

View File

@@ -9,7 +9,7 @@ import { updateAdminPost } from '../../../../repositories/content-repository'
* @returns {Promise<Object>} 수정된 게시물
*/
export default defineEventHandler(async (event) => {
requireAdminSession(event)
const adminSession = requireAdminSession(event)
const id = getRouterParam(event, 'id')
const parsedBody = parseAdminPostInput(await readBody(event))
@@ -22,7 +22,7 @@ export default defineEventHandler(async (event) => {
}
try {
const post = await updateAdminPost(id, parsedBody.data)
const post = await updateAdminPost(id, parsedBody.data, adminSession.userId)
if (!post) {
throw createError({