게시물 Export 기간 선택과 삭제 추가 v1.5.23
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { readBody } from 'h3'
|
||||
import { createError, readBody } from 'h3'
|
||||
import { z } from 'zod'
|
||||
import { requireAdminSession } from '../../../../utils/admin-auth'
|
||||
import {
|
||||
@@ -7,10 +7,101 @@ import {
|
||||
} from '../../../../repositories/post-export-repository'
|
||||
|
||||
const postExportJobInputSchema = z.object({
|
||||
dateRangeMode: z.enum(['all', 'year', 'month', 'custom']).optional().default('all'),
|
||||
year: z.number().int().min(1970).max(9999).optional(),
|
||||
month: z.number().int().min(1).max(12).optional(),
|
||||
dateFrom: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
||||
dateTo: z.string().regex(/^\d{4}-\d{2}-\d{2}$/).optional(),
|
||||
chunkSize: z.number().int().min(1).max(500).optional(),
|
||||
retentionDays: z.number().int().min(1).max(100).optional()
|
||||
}).default({})
|
||||
|
||||
/**
|
||||
* KST 기준 날짜 시작 시각을 만든다.
|
||||
* @param {string} value - YYYY-MM-DD 날짜
|
||||
* @returns {Date} 날짜 시작 시각
|
||||
*/
|
||||
const createKstDateStart = (value) => new Date(`${value}T00:00:00+09:00`)
|
||||
|
||||
/**
|
||||
* KST 기준 다음 날짜 시작 시각을 만든다.
|
||||
* @param {string} value - YYYY-MM-DD 날짜
|
||||
* @returns {Date} 다음 날짜 시작 시각
|
||||
*/
|
||||
const createKstNextDateStart = (value) => {
|
||||
const date = createKstDateStart(value)
|
||||
date.setUTCDate(date.getUTCDate() + 1)
|
||||
return date
|
||||
}
|
||||
|
||||
/**
|
||||
* 두 자리 숫자 문자열을 만든다.
|
||||
* @param {number} value - 숫자
|
||||
* @returns {string} 두 자리 문자열
|
||||
*/
|
||||
const pad2 = (value) => String(value).padStart(2, '0')
|
||||
|
||||
/**
|
||||
* 요청 입력에서 Export 날짜 범위를 만든다.
|
||||
* @param {z.infer<typeof postExportJobInputSchema>} input - 요청 입력
|
||||
* @returns {{ dateFrom: Date|null, dateTo: Date|null, rangeLabel: string }} 날짜 범위
|
||||
*/
|
||||
const createExportDateRange = (input) => {
|
||||
if (input.dateRangeMode === 'year') {
|
||||
const year = input.year || new Date().getFullYear()
|
||||
return {
|
||||
dateFrom: createKstDateStart(`${year}-01-01`),
|
||||
dateTo: createKstDateStart(`${year + 1}-01-01`),
|
||||
rangeLabel: `${year}`
|
||||
}
|
||||
}
|
||||
|
||||
if (input.dateRangeMode === 'month') {
|
||||
const now = new Date()
|
||||
const year = input.year || now.getFullYear()
|
||||
const month = input.month || now.getMonth() + 1
|
||||
const nextYear = month === 12 ? year + 1 : year
|
||||
const nextMonth = month === 12 ? 1 : month + 1
|
||||
|
||||
return {
|
||||
dateFrom: createKstDateStart(`${year}-${pad2(month)}-01`),
|
||||
dateTo: createKstDateStart(`${nextYear}-${pad2(nextMonth)}-01`),
|
||||
rangeLabel: `${year}-${pad2(month)}`
|
||||
}
|
||||
}
|
||||
|
||||
if (input.dateRangeMode === 'custom') {
|
||||
if (!input.dateFrom || !input.dateTo) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: '날짜 범위를 선택해 주세요.'
|
||||
})
|
||||
}
|
||||
|
||||
const dateFrom = createKstDateStart(input.dateFrom)
|
||||
const dateTo = createKstNextDateStart(input.dateTo)
|
||||
|
||||
if (dateFrom >= dateTo) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: '시작일은 종료일보다 늦을 수 없습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
dateFrom,
|
||||
dateTo,
|
||||
rangeLabel: `${input.dateFrom}_${input.dateTo}`
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
dateFrom: null,
|
||||
dateTo: null,
|
||||
rangeLabel: '전체'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 관리자 게시물 Export 작업 요청 API
|
||||
* @param {import('h3').H3Event} event - 요청 이벤트
|
||||
@@ -19,11 +110,15 @@ const postExportJobInputSchema = z.object({
|
||||
export default defineEventHandler(async (event) => {
|
||||
const adminSession = requireAdminSession(event)
|
||||
const input = postExportJobInputSchema.parse(await readBody(event))
|
||||
const dateRange = createExportDateRange(input)
|
||||
|
||||
const job = await createPostExportJob({
|
||||
requestedBy: adminSession.userId,
|
||||
requestedEmail: adminSession.email,
|
||||
scope: 'all',
|
||||
dateFrom: dateRange.dateFrom,
|
||||
dateTo: dateRange.dateTo,
|
||||
rangeLabel: dateRange.rangeLabel,
|
||||
chunkSize: input.chunkSize,
|
||||
retentionDays: input.retentionDays
|
||||
})
|
||||
|
||||
32
server/routes/admin/api/posts/export-jobs/[jobId].delete.js
Normal file
32
server/routes/admin/api/posts/export-jobs/[jobId].delete.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import { createError, getRouterParam } from 'h3'
|
||||
import { requireAdminSession } from '../../../../../utils/admin-auth'
|
||||
import { deletePostExportJob } from '../../../../../repositories/post-export-repository'
|
||||
|
||||
/**
|
||||
* 관리자 게시물 Export 작업 삭제 API
|
||||
* @param {import('h3').H3Event} event - 요청 이벤트
|
||||
* @returns {Promise<{ ok: boolean }>} 삭제 결과
|
||||
*/
|
||||
export default defineEventHandler(async (event) => {
|
||||
requireAdminSession(event)
|
||||
|
||||
const jobId = getRouterParam(event, 'jobId')
|
||||
|
||||
if (!jobId) {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'Export 작업 ID가 필요합니다.'
|
||||
})
|
||||
}
|
||||
|
||||
const deleted = await deletePostExportJob(jobId)
|
||||
|
||||
if (!deleted) {
|
||||
throw createError({
|
||||
statusCode: 404,
|
||||
statusMessage: 'Export 작업을 찾을 수 없습니다.'
|
||||
})
|
||||
}
|
||||
|
||||
return { ok: true }
|
||||
})
|
||||
Reference in New Issue
Block a user