250 lines
8.4 KiB
PHP
250 lines
8.4 KiB
PHP
<?php
|
|
require_once 'config.php';
|
|
require_once __DIR__ . '/error_config.php';
|
|
session_start();
|
|
set_json_headers();
|
|
|
|
define('LEARNING_FILE', DATA_DIR . '/learning.json');
|
|
|
|
$method = $_SERVER['REQUEST_METHOD'];
|
|
|
|
// =====================================================
|
|
// GET: 학습 일지 목록 또는 단일 글 (인증 불필요)
|
|
// =====================================================
|
|
if ($method === 'GET') {
|
|
$learnings = read_json_safe(LEARNING_FILE) ?? [];
|
|
|
|
// 단일 글 조회: ?id=N
|
|
if (isset($_GET['id'])) {
|
|
$id = intval($_GET['id']);
|
|
foreach ($learnings as $l) {
|
|
if (($l['id'] ?? 0) === $id) {
|
|
// is_learning 필드는 더이상 의미 없음 (제거)
|
|
unset($l['is_learning']);
|
|
json_response($l);
|
|
}
|
|
}
|
|
json_response(['error' => '글을 찾을 수 없습니다'], 404);
|
|
}
|
|
|
|
// is_learning 필드 마이그레이션 (제거)
|
|
foreach ($learnings as &$l) {
|
|
unset($l['is_learning']);
|
|
}
|
|
unset($l);
|
|
|
|
// 카테고리 필터: ?category_id=N (단일 또는 카테고리 + 모든 자식)
|
|
if (isset($_GET['category_id'])) {
|
|
$catId = intval($_GET['category_id']);
|
|
$categories = read_json_safe(DATA_DIR . '/categories.json') ?? [];
|
|
|
|
// 자식 카테고리 ID도 포함
|
|
$catIds = [$catId];
|
|
foreach ($categories as $c) {
|
|
if (($c['parent_id'] ?? null) === $catId) {
|
|
$catIds[] = $c['id'];
|
|
}
|
|
}
|
|
|
|
$learnings = array_values(array_filter($learnings, function($l) use ($catIds) {
|
|
return in_array(($l['category_id'] ?? 0), $catIds);
|
|
}));
|
|
}
|
|
|
|
// 최신순 정렬
|
|
usort($learnings, function($a, $b) {
|
|
$aDate = $a['created_at'] ?? '';
|
|
$bDate = $b['created_at'] ?? '';
|
|
if ($aDate !== $bDate) return strcmp($bDate, $aDate);
|
|
return ($b['id'] ?? 0) - ($a['id'] ?? 0);
|
|
});
|
|
|
|
json_response($learnings);
|
|
}
|
|
|
|
require_auth();
|
|
|
|
// =====================================================
|
|
// POST: 새 학습 일지 작성
|
|
// =====================================================
|
|
if ($method === 'POST') {
|
|
$input = get_json_input();
|
|
|
|
$title = trim($input['title'] ?? '');
|
|
$content = trim($input['content'] ?? '');
|
|
$categoryId = intval($input['category_id'] ?? 0);
|
|
|
|
if (empty($title) || empty($content)) {
|
|
json_response(['error' => '제목과 내용은 필수입니다'], 400);
|
|
}
|
|
|
|
if ($categoryId <= 0) {
|
|
json_response(['error' => '카테고리를 선택해주세요'], 400);
|
|
}
|
|
|
|
// 카테고리가 서브 카테고리(parent_id 있음)인지 확인 - 글은 서브 카테고리에만 속해야 함
|
|
$categories = read_json_safe(DATA_DIR . '/categories.json') ?? [];
|
|
$foundCat = null;
|
|
foreach ($categories as $c) {
|
|
if (($c['id'] ?? 0) === $categoryId) {
|
|
$foundCat = $c;
|
|
break;
|
|
}
|
|
}
|
|
if (!$foundCat) {
|
|
json_response(['error' => '카테고리를 찾을 수 없습니다'], 400);
|
|
}
|
|
if (empty($foundCat['parent_id'])) {
|
|
json_response(['error' => '글은 서브 카테고리에만 작성할 수 있습니다 (예: Unity > 학습)'], 400);
|
|
}
|
|
|
|
// 태그 처리
|
|
$tags = [];
|
|
if (isset($input['tags'])) {
|
|
if (is_array($input['tags'])) {
|
|
$tags = array_values(array_filter(
|
|
array_map('trim', $input['tags']),
|
|
fn($v) => $v !== ''
|
|
));
|
|
} elseif (is_string($input['tags'])) {
|
|
$tags = array_values(array_filter(
|
|
array_map('trim', explode(',', $input['tags'])),
|
|
fn($v) => $v !== ''
|
|
));
|
|
}
|
|
}
|
|
|
|
$learnings = read_json_safe(LEARNING_FILE) ?? [];
|
|
|
|
$maxId = 0;
|
|
foreach ($learnings as $l) {
|
|
if (($l['id'] ?? 0) > $maxId) $maxId = $l['id'];
|
|
}
|
|
|
|
$createdAt = trim($input['created_at'] ?? '');
|
|
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $createdAt)) {
|
|
$createdAt = date('Y-m-d');
|
|
}
|
|
|
|
$newLearning = [
|
|
'id' => $maxId + 1,
|
|
'title' => $title,
|
|
'category_id' => $categoryId,
|
|
'tags' => $tags,
|
|
'content' => $content,
|
|
'created_at' => $createdAt,
|
|
'updated_at' => date('Y-m-d')
|
|
];
|
|
|
|
$learnings[] = $newLearning;
|
|
|
|
if (write_json_safe(LEARNING_FILE, $learnings)) {
|
|
json_response(['success' => true, 'learning' => $newLearning]);
|
|
} else {
|
|
json_response(['error' => '저장에 실패했습니다'], 500);
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// PUT: 학습 일지 수정
|
|
// =====================================================
|
|
if ($method === 'PUT') {
|
|
$input = get_json_input();
|
|
$id = intval($input['id'] ?? 0);
|
|
|
|
if ($id <= 0) {
|
|
json_response(['error' => '유효하지 않은 ID'], 400);
|
|
}
|
|
|
|
$learnings = read_json_safe(LEARNING_FILE) ?? [];
|
|
$found = false;
|
|
|
|
foreach ($learnings as $key => $l) {
|
|
if ($l['id'] === $id) {
|
|
// is_learning 필드는 제거
|
|
unset($learnings[$key]['is_learning']);
|
|
|
|
if (isset($input['title'])) {
|
|
$title = trim($input['title']);
|
|
if ($title === '') json_response(['error' => '제목은 비울 수 없습니다'], 400);
|
|
$learnings[$key]['title'] = $title;
|
|
}
|
|
if (isset($input['content'])) {
|
|
$content = trim($input['content']);
|
|
if ($content === '') json_response(['error' => '내용은 비울 수 없습니다'], 400);
|
|
$learnings[$key]['content'] = $content;
|
|
}
|
|
if (isset($input['category_id'])) {
|
|
$catId = intval($input['category_id']);
|
|
if ($catId > 0) {
|
|
// 서브 카테고리 검증
|
|
$categories = read_json_safe(DATA_DIR . '/categories.json') ?? [];
|
|
$foundCat = null;
|
|
foreach ($categories as $c) {
|
|
if (($c['id'] ?? 0) === $catId) { $foundCat = $c; break; }
|
|
}
|
|
if ($foundCat && empty($foundCat['parent_id'])) {
|
|
json_response(['error' => '글은 서브 카테고리에만 속할 수 있습니다'], 400);
|
|
}
|
|
$learnings[$key]['category_id'] = $catId;
|
|
}
|
|
}
|
|
if (isset($input['tags'])) {
|
|
$tags = is_array($input['tags'])
|
|
? array_values(array_filter(array_map('trim', $input['tags']), fn($v) => $v !== ''))
|
|
: (is_string($input['tags'])
|
|
? array_values(array_filter(array_map('trim', explode(',', $input['tags'])), fn($v) => $v !== ''))
|
|
: []);
|
|
$learnings[$key]['tags'] = $tags;
|
|
}
|
|
if (isset($input['created_at'])) {
|
|
$createdAt = trim($input['created_at']);
|
|
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $createdAt)) {
|
|
$learnings[$key]['created_at'] = $createdAt;
|
|
}
|
|
}
|
|
$learnings[$key]['updated_at'] = date('Y-m-d');
|
|
$found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!$found) {
|
|
json_response(['error' => '글을 찾을 수 없습니다'], 404);
|
|
}
|
|
|
|
if (write_json_safe(LEARNING_FILE, $learnings)) {
|
|
json_response(['success' => true]);
|
|
} else {
|
|
json_response(['error' => '저장에 실패했습니다'], 500);
|
|
}
|
|
}
|
|
|
|
// =====================================================
|
|
// DELETE: 학습 일지 삭제
|
|
// =====================================================
|
|
if ($method === 'DELETE') {
|
|
$id = intval($_GET['id'] ?? 0);
|
|
|
|
if ($id <= 0) {
|
|
json_response(['error' => '유효하지 않은 ID'], 400);
|
|
}
|
|
|
|
$learnings = read_json_safe(LEARNING_FILE) ?? [];
|
|
$filtered = array_values(array_filter($learnings, function($l) use ($id) {
|
|
return ($l['id'] ?? 0) !== $id;
|
|
}));
|
|
|
|
if (count($filtered) === count($learnings)) {
|
|
json_response(['error' => '글을 찾을 수 없습니다'], 404);
|
|
}
|
|
|
|
if (write_json_safe(LEARNING_FILE, $filtered)) {
|
|
json_response(['success' => true]);
|
|
} else {
|
|
json_response(['error' => '삭제에 실패했습니다'], 500);
|
|
}
|
|
}
|
|
|
|
json_response(['error' => 'Method not allowed'], 405);
|