Initial profile site commit

This commit is contained in:
2026-05-31 21:05:59 +09:00
commit db81f0e4a4
49 changed files with 18829 additions and 0 deletions
+210
View File
@@ -0,0 +1,210 @@
<?php
require_once 'config.php';
require_once __DIR__ . '/error_config.php';
session_start();
set_json_headers();
define('CATEGORIES_FILE', DATA_DIR . '/categories.json');
$method = $_SERVER['REQUEST_METHOD'];
// 카테고리 정규화 (parent_id 필드 보장)
function normalize_category($cat) {
if (!isset($cat['parent_id'])) $cat['parent_id'] = null;
if (!isset($cat['order'])) $cat['order'] = 0;
if (!isset($cat['color'])) $cat['color'] = '#00f2ff';
return $cat;
}
// =====================================================
// GET: 카테고리 목록
// =====================================================
if ($method === 'GET') {
$categories = read_json_safe(CATEGORIES_FILE) ?? [];
$categories = array_map('normalize_category', $categories);
usort($categories, function($a, $b) {
// parent끼리 먼저 정렬되도록
$aParent = $a['parent_id'] ?? 0;
$bParent = $b['parent_id'] ?? 0;
if ($aParent !== $bParent) return $aParent - $bParent;
return ($a['order'] ?? 0) - ($b['order'] ?? 0);
});
json_response($categories);
}
require_auth();
// =====================================================
// POST: 카테고리 추가
// =====================================================
if ($method === 'POST') {
$input = get_json_input();
$name = trim($input['name'] ?? '');
$color = trim($input['color'] ?? '#00f2ff');
$parentId = isset($input['parent_id']) && $input['parent_id'] !== '' && $input['parent_id'] !== null
? intval($input['parent_id'])
: null;
if (empty($name)) {
json_response(['error' => '카테고리 이름은 필수입니다'], 400);
}
$categories = read_json_safe(CATEGORIES_FILE) ?? [];
// parent_id 유효성 검증
if ($parentId !== null) {
$parentFound = false;
foreach ($categories as $c) {
if (($c['id'] ?? 0) === $parentId) {
// 부모가 또 다른 부모를 가지면 안 됨 (2단계로 제한)
if (!empty($c['parent_id'])) {
json_response(['error' => '서브 카테고리 아래에는 카테고리를 만들 수 없습니다'], 400);
}
$parentFound = true;
break;
}
}
if (!$parentFound) {
json_response(['error' => '부모 카테고리를 찾을 수 없습니다'], 400);
}
}
$maxId = 0;
$maxOrder = 0;
foreach ($categories as $c) {
if (($c['id'] ?? 0) > $maxId) $maxId = $c['id'];
// 같은 부모 내에서 max order
if (($c['parent_id'] ?? null) === $parentId && ($c['order'] ?? 0) > $maxOrder) {
$maxOrder = $c['order'];
}
}
$newCategory = [
'id' => $maxId + 1,
'name' => $name,
'color' => $color,
'parent_id' => $parentId,
'order' => $maxOrder + 1
];
$categories[] = $newCategory;
if (write_json_safe(CATEGORIES_FILE, $categories)) {
json_response(['success' => true, 'category' => $newCategory]);
} 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);
}
$categories = read_json_safe(CATEGORIES_FILE) ?? [];
$found = false;
foreach ($categories as $key => $cat) {
if ($cat['id'] === $id) {
if (isset($input['name'])) $categories[$key]['name'] = trim($input['name']);
if (isset($input['color'])) $categories[$key]['color'] = trim($input['color']);
if (isset($input['order'])) $categories[$key]['order'] = intval($input['order']);
// parent_id 변경은 허용하되, 자식이 있는 경우 자식으로 만들지 못하게
if (array_key_exists('parent_id', $input)) {
$newParent = $input['parent_id'];
$newParent = ($newParent === '' || $newParent === null) ? null : intval($newParent);
// 자기 자신을 부모로 설정 불가
if ($newParent === $id) {
json_response(['error' => '자기 자신을 부모로 설정할 수 없습니다'], 400);
}
// 자식이 있는 카테고리는 다른 카테고리의 자식이 될 수 없음
$hasChildren = false;
foreach ($categories as $c) {
if (($c['parent_id'] ?? null) === $id) {
$hasChildren = true;
break;
}
}
if ($newParent !== null && $hasChildren) {
json_response(['error' => '하위 카테고리가 있는 카테고리는 다른 카테고리의 하위로 이동할 수 없습니다'], 400);
}
$categories[$key]['parent_id'] = $newParent;
}
$found = true;
break;
}
}
if (!$found) {
json_response(['error' => '카테고리를 찾을 수 없습니다'], 404);
}
if (write_json_safe(CATEGORIES_FILE, $categories)) {
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);
}
$categories = read_json_safe(CATEGORIES_FILE) ?? [];
// 자식 카테고리 ID 수집
$allIdsToDelete = [$id];
foreach ($categories as $c) {
if (($c['parent_id'] ?? null) === $id) {
$allIdsToDelete[] = $c['id'];
}
}
// 해당 카테고리(들)을 사용하는 글이 있는지 확인
$learnings = read_json_safe(DATA_DIR . '/learning.json') ?? [];
$usedCount = 0;
foreach ($learnings as $l) {
if (in_array(($l['category_id'] ?? 0), $allIdsToDelete)) $usedCount++;
}
if ($usedCount > 0) {
$isParent = count($allIdsToDelete) > 1;
$msg = $isParent
? "이 카테고리(또는 하위 카테고리)를 사용하는 글이 {$usedCount}개 있습니다. 먼저 해당 글들을 다른 카테고리로 옮기거나 삭제해주세요."
: "이 카테고리를 사용하는 글이 {$usedCount}개 있습니다. 먼저 해당 글들을 다른 카테고리로 옮기거나 삭제해주세요.";
json_response(['error' => $msg], 400);
}
$filtered = array_values(array_filter($categories, function($c) use ($allIdsToDelete) {
return !in_array(($c['id'] ?? 0), $allIdsToDelete);
}));
if (count($filtered) === count($categories)) {
json_response(['error' => '카테고리를 찾을 수 없습니다'], 404);
}
if (write_json_safe(CATEGORIES_FILE, $filtered)) {
json_response(['success' => true, 'deleted_count' => count($allIdsToDelete)]);
} else {
json_response(['error' => '삭제에 실패했습니다'], 500);
}
}
json_response(['error' => 'Method not allowed'], 405);