| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680 |
- <?php
- namespace App\Controllers\Api;
- use CodeIgniter\HTTP\ResponseInterface;
- class AdminController extends BaseApiController
- {
- protected $format = 'json';
- private const ALLOWED_ROLES = ['super_admin', 'admin'];
- private const ALLOWED_STATUSES = ['active', 'inactive', 'suspended'];
- // 허용 메뉴 권한 (admin.vue의 menuItems id와 동일)
- private const ALLOWED_PERMISSIONS = [
- 'admin', 'field', 'fishing', 'challenge', 'quest', 'item', 'species', 'user',
- ];
- /**
- * 호출한 관리자가 슈퍼관리자인지 확인
- */
- private function isCallerSuperAdmin($authData): bool
- {
- $admin = $this->getDB()->table('admin_users')
- ->select('role')
- ->where('id', (int) $authData->admin_id)
- ->get()->getRow();
- return $admin && $admin->role === 'super_admin';
- }
- // TODO: 권한관리 시스템 구축 후, '관리자관리 권한'을 가진 admin만
- // create/update/delete/changePassword/unlockAccount 가능하도록 가드 재추가
- /**
- * 관리자의 메뉴 권한 동기화 (DELETE + INSERT)
- * - super_admin은 row 박지 않음 (role 자체가 모든 권한)
- * - admin은 검증된 배열만 INSERT
- */
- private function syncPermissions(int $adminId, string $role, $permissions): void
- {
- $db = $this->getDB();
- // 기존 권한 전부 제거
- $db->table('admin_permissions')->where('admin_id', $adminId)->delete();
- if ($role !== 'admin') return;
- if (!is_array($permissions) || empty($permissions)) return;
- // 허용 목록만 INSERT (중복 제거)
- $clean = array_values(array_unique(array_filter(
- $permissions,
- fn($p) => is_string($p) && in_array($p, self::ALLOWED_PERMISSIONS, true)
- )));
- if (empty($clean)) return;
- $rows = array_map(fn($p) => [
- 'admin_id' => $adminId,
- 'permission' => $p,
- 'created_at' => date('Y-m-d H:i:s'),
- ], $clean);
- $db->table('admin_permissions')->insertBatch($rows);
- }
- /**
- * 관리자의 메뉴 권한 배열 반환
- * - super_admin은 'all' 반환
- * - admin은 ['field', 'fishing', ...] 형태
- */
- private function getPermissions(int $adminId, string $role)
- {
- if ($role === 'super_admin') return 'all';
- $rows = $this->getDB()->table('admin_permissions')
- ->select('permission')
- ->where('admin_id', $adminId)
- ->get()->getResult();
- return array_map(fn($r) => $r->permission, $rows);
- }
- /**
- * Get all admins (관리자 목록) — 인증된 모두 가능
- * GET /api/admin
- */
- public function index()
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- try {
- $page = (int) ($this->request->getGet('page') ?? 1);
- $perPage = (int) ($this->request->getGet('per_page') ?? 10);
- if ($page < 1) $page = 1;
- if ($perPage < 1) $perPage = 10;
- $offset = ($page - 1) * $perPage;
- $db = $this->getDB();
- $builder = $db->table('admin_users');
- // 삭제된 계정만 / 활성만 분기 (deleted=1이면 삭제된 것만)
- $showDeleted = $this->request->getGet('deleted') === '1';
- $builder->where('deleted_YN', $showDeleted ? 'Y' : 'N');
- // 검색
- $search = trim((string) $this->request->getGet('search'));
- $searchField = $this->request->getGet('search_field'); // username / name / email / ''
- if ($search !== '') {
- if ($searchField === 'username') {
- $builder->like('username', $search);
- } elseif ($searchField === 'name') {
- $builder->like('name', $search);
- } elseif ($searchField === 'email') {
- $builder->like('email', $search);
- } else {
- $builder->groupStart()
- ->like('username', $search)
- ->orLike('name', $search)
- ->orLike('email', $search)
- ->groupEnd();
- }
- }
- // 역할 필터
- $role = $this->request->getGet('role');
- if (!empty($role) && in_array($role, self::ALLOWED_ROLES, true)) {
- $builder->where('role', $role);
- }
- // 상태 필터
- $status = $this->request->getGet('status');
- if (!empty($status) && in_array($status, self::ALLOWED_STATUSES, true)) {
- $builder->where('status', $status);
- }
- $total = $builder->countAllResults(false);
- $items = $builder
- ->select('id, username, name, email, phone, role, status, COALESCE(login_attempts, 0) as login_attempts, last_failed_login, last_login, created_at, updated_at')
- ->orderBy('id', 'DESC')
- ->limit($perPage, $offset)
- ->get()
- ->getResult();
- // permissions 일괄 조회 후 attach
- if (!empty($items)) {
- $ids = array_map(fn($i) => (int) $i->id, $items);
- $rows = $db->table('admin_permissions')
- ->select('admin_id, permission')
- ->whereIn('admin_id', $ids)
- ->get()->getResult();
- $permsByAdmin = [];
- foreach ($rows as $r) {
- $permsByAdmin[$r->admin_id][] = $r->permission;
- }
- foreach ($items as $item) {
- $item->permissions = $item->role === 'super_admin'
- ? 'all'
- : ($permsByAdmin[$item->id] ?? []);
- }
- }
- return $this->respondSuccess([
- 'items' => $items,
- 'total' => $total,
- 'page' => $page,
- 'per_page' => $perPage,
- 'total_pages' => (int) ceil($total / $perPage),
- ]);
- } catch (\Exception $e) {
- log_message('error', 'AdminController index error: ' . $e->getMessage());
- return $this->respondError('관리자 목록 조회 중 오류가 발생했습니다: ' . $e->getMessage(), ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Get single admin (관리자 상세) — 인증된 모두 가능
- * GET /api/admin/:id
- */
- public function show($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $admin = $this->getDB()->table('admin_users')
- ->select('id, username, name, email, phone, role, status, login_attempts, last_failed_login, last_login, created_at, updated_at')
- ->where('id', (int) $id)
- ->where('deleted_YN', 'N')
- ->get()
- ->getRow();
- if (!$admin) {
- return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
- }
- $admin->permissions = $this->getPermissions((int) $id, $admin->role);
- return $this->respondSuccess($admin);
- } catch (\Exception $e) {
- log_message('error', 'AdminController show error: ' . $e->getMessage());
- return $this->respondError('관리자 조회 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Check if username is available (아이디 중복 체크)
- * GET /api/admin/check-username
- */
- public function checkUsername()
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- $username = trim((string) $this->request->getGet('username'));
- if ($username === '') {
- return $this->respondError('아이디를 입력하세요.');
- }
- try {
- $existing = $this->getDB()->table('admin_users')
- ->where('username', $username)
- ->where('deleted_YN', 'N')
- ->get()
- ->getRow();
- return $this->respondSuccess(['available' => !$existing]);
- } catch (\Exception $e) {
- log_message('error', 'AdminController checkUsername error: ' . $e->getMessage());
- return $this->respondError('중복 체크 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Create new admin (관리자 생성) — 슈퍼 관리자만
- * POST /api/admin
- */
- public function create()
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- try {
- $data = $this->request->getJSON(true) ?? [];
- // 필수 필드 검증
- $required = ['username', 'password', 'name', 'email'];
- foreach ($required as $field) {
- if (empty($data[$field])) {
- return $this->respondError("{$field}는 필수 항목입니다.", ResponseInterface::HTTP_BAD_REQUEST);
- }
- }
- $username = trim((string) $data['username']);
- // role / status 검증
- $role = $data['role'] ?? 'admin';
- if (!in_array($role, self::ALLOWED_ROLES, true)) {
- return $this->respondError('올바르지 않은 역할입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- $status = $data['status'] ?? 'active';
- if (!in_array($status, self::ALLOWED_STATUSES, true)) {
- return $this->respondError('올바르지 않은 상태입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- // 호출자가 슈퍼관리자가 아니면 super_admin 등록 차단
- if ($role === 'super_admin' && !$this->isCallerSuperAdmin($auth)) {
- return $this->respondError('슈퍼 관리자 권한 부여는 슈퍼 관리자만 가능합니다.', ResponseInterface::HTTP_FORBIDDEN);
- }
- // 일반 admin은 권한 1개 이상 필수
- $permissions = $data['permissions'] ?? [];
- if ($role === 'admin') {
- if (!is_array($permissions) || empty($permissions)) {
- return $this->respondError('관리자에게 부여할 메뉴 권한을 1개 이상 선택하세요.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- }
- // 중복 체크 (삭제된 계정 제외 — 재사용 허용)
- $existing = $this->getDB()->table('admin_users')
- ->groupStart()
- ->where('username', $username)
- ->orWhere('email', $data['email'])
- ->groupEnd()
- ->where('deleted_YN', 'N')
- ->get()
- ->getRow();
- if ($existing) {
- if ($existing->username === $username) {
- return $this->respondError('이미 사용 중인 아이디입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- if ($existing->email === $data['email']) {
- return $this->respondError('이미 사용 중인 이메일입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- }
- $insertData = [
- 'username' => $username,
- 'password' => password_hash($data['password'], PASSWORD_DEFAULT),
- 'password_changed_at' => date('Y-m-d H:i:s'),
- 'name' => trim((string) $data['name']),
- 'email' => trim((string) $data['email']),
- 'phone' => trim((string) ($data['phone'] ?? '')),
- 'role' => $role,
- 'status' => $status,
- 'login_attempts' => 0,
- 'deleted_YN' => 'N',
- 'created_at' => date('Y-m-d H:i:s'),
- 'updated_at' => date('Y-m-d H:i:s'),
- ];
- $this->getDB()->table('admin_users')->insert($insertData);
- $insertId = $this->getDB()->insertID();
- // 권한 저장 (super_admin은 row 안 박음)
- $this->syncPermissions((int) $insertId, $role, $permissions);
- $admin = $this->getDB()->table('admin_users')
- ->select('id, username, name, email, phone, role, status, login_attempts, last_failed_login, last_login, created_at, updated_at')
- ->where('id', $insertId)
- ->get()
- ->getRow();
- $admin->permissions = $this->getPermissions((int) $insertId, $admin->role);
- return $this->respondSuccess($admin, '관리자가 생성되었습니다.', ResponseInterface::HTTP_CREATED);
- } catch (\Exception $e) {
- log_message('error', 'AdminController create error: ' . $e->getMessage());
- return $this->respondError('관리자 생성 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Update admin (관리자 수정) — 슈퍼 관리자만
- * PUT /api/admin/:id
- */
- public function update($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $existing = $this->getDB()->table('admin_users')
- ->where('id', (int) $id)
- ->where('deleted_YN', 'N')
- ->get()->getRow();
- if (!$existing) {
- return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
- }
- $data = $this->request->getJSON(true) ?? [];
- // 일반 admin은 role/permissions 변경 불가
- if (isset($data['role']) || array_key_exists('permissions', $data)) {
- if (!$this->isCallerSuperAdmin($auth)) {
- return $this->respondError('권한 변경은 슈퍼 관리자만 가능합니다.', ResponseInterface::HTTP_FORBIDDEN);
- }
- }
- // 이메일 중복 체크 (자신 제외, 삭제된 계정 제외)
- if (!empty($data['email']) && $data['email'] !== $existing->email) {
- $duplicate = $this->getDB()->table('admin_users')
- ->where('email', $data['email'])
- ->where('id !=', (int) $id)
- ->where('deleted_YN', 'N')
- ->get()
- ->getRow();
- if ($duplicate) {
- return $this->respondError('이미 사용 중인 이메일입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- }
- $updateData = ['updated_at' => date('Y-m-d H:i:s')];
- if (isset($data['name'])) $updateData['name'] = trim((string) $data['name']);
- if (isset($data['email'])) $updateData['email'] = trim((string) $data['email']);
- if (isset($data['phone'])) $updateData['phone'] = trim((string) $data['phone']);
- if (isset($data['role'])) {
- if (!in_array($data['role'], self::ALLOWED_ROLES, true)) {
- return $this->respondError('올바르지 않은 역할입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- $updateData['role'] = $data['role'];
- }
- if (isset($data['status'])) {
- if (!in_array($data['status'], self::ALLOWED_STATUSES, true)) {
- return $this->respondError('올바르지 않은 상태입니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- $updateData['status'] = $data['status'];
- }
- $this->getDB()->table('admin_users')->where('id', (int) $id)->update($updateData);
- // 권한 동기화: role 또는 permissions가 들어왔을 때만
- $touchedRole = isset($data['role']);
- $touchedPerms = array_key_exists('permissions', $data);
- if ($touchedRole || $touchedPerms) {
- $finalRole = $touchedRole ? $data['role'] : $existing->role;
- $finalPermissions = $touchedPerms ? ($data['permissions'] ?? []) : [];
- // role='admin'으로 바뀌었는데 권한 비어있으면 차단
- if ($finalRole === 'admin' && $touchedPerms && empty($finalPermissions)) {
- return $this->respondError('관리자에게 부여할 메뉴 권한을 1개 이상 선택하세요.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- // role만 super_admin → admin으로 바꿨는데 permissions 안 보낸 경우도 차단
- if ($touchedRole && $finalRole === 'admin' && !$touchedPerms) {
- return $this->respondError('일반 관리자로 변경 시 메뉴 권한을 함께 지정해야 합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- $this->syncPermissions((int) $id, $finalRole, $finalPermissions);
- }
- $admin = $this->getDB()->table('admin_users')
- ->select('id, username, name, email, phone, role, status, login_attempts, last_failed_login, last_login, created_at, updated_at')
- ->where('id', (int) $id)
- ->where('deleted_YN', 'N')
- ->get()
- ->getRow();
- $admin->permissions = $this->getPermissions((int) $id, $admin->role);
- return $this->respondSuccess($admin, '관리자 정보가 수정되었습니다.');
- } catch (\Exception $e) {
- log_message('error', 'AdminController update error: ' . $e->getMessage());
- return $this->respondError('관리자 수정 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Delete admin (관리자 삭제) — 슈퍼 관리자만, 본인은 삭제 불가
- * DELETE /api/admin/:id
- */
- public function delete($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $targetId = (int) $id;
- // 본인 삭제 방지
- if ((int) $auth->admin_id === $targetId) {
- return $this->respondError('본인 계정은 삭제할 수 없습니다.', ResponseInterface::HTTP_FORBIDDEN);
- }
- $existing = $this->getDB()->table('admin_users')
- ->where('id', $targetId)
- ->where('deleted_YN', 'N')
- ->get()->getRow();
- if (!$existing) {
- return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
- }
- // soft delete — 데이터는 보존, 플래그만 변경
- $this->getDB()->table('admin_users')
- ->where('id', $targetId)
- ->update([
- 'deleted_YN' => 'Y',
- 'updated_at' => date('Y-m-d H:i:s'),
- ]);
- // 토큰만 무효화 (admin_permissions는 복구 시를 위해 보존)
- $this->getDB()->table('admin_tokens')->where('admin_id', $targetId)->delete();
- return $this->respondSuccess(null, '관리자가 삭제되었습니다.');
- } catch (\Exception $e) {
- log_message('error', 'AdminController delete error: ' . $e->getMessage());
- return $this->respondError('관리자 삭제 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Change admin password (비밀번호 변경) — 슈퍼 관리자만
- * POST /api/admin/:id/password
- */
- public function changePassword($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $data = $this->request->getJSON(true) ?? [];
- if (empty($data['new_password'])) {
- return $this->respondError('새 비밀번호가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- $existing = $this->getDB()->table('admin_users')
- ->where('id', (int) $id)
- ->where('deleted_YN', 'N')
- ->get()->getRow();
- if (!$existing) {
- return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
- }
- $updateData = [
- 'password' => password_hash($data['new_password'], PASSWORD_DEFAULT),
- 'password_changed_at' => date('Y-m-d H:i:s'),
- 'updated_at' => date('Y-m-d H:i:s'),
- ];
- $this->getDB()->table('admin_users')->where('id', (int) $id)->update($updateData);
- return $this->respondSuccess(null, '비밀번호가 변경되었습니다.');
- } catch (\Exception $e) {
- log_message('error', 'AdminController changePassword error: ' . $e->getMessage());
- return $this->respondError('비밀번호 변경 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Unlock admin account (계정 잠금 해제) — 슈퍼 관리자만
- * POST /api/admin/:id/unlock
- */
- public function unlockAccount($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $existing = $this->getDB()->table('admin_users')
- ->where('id', (int) $id)
- ->where('deleted_YN', 'N')
- ->get()->getRow();
- if (!$existing) {
- return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
- }
- $updateData = [
- 'login_attempts' => 0,
- 'last_failed_login' => null,
- 'updated_at' => date('Y-m-d H:i:s'),
- ];
- $this->getDB()->table('admin_users')->where('id', (int) $id)->update($updateData);
- return $this->respondSuccess(null, '계정 잠금이 해제되었습니다.');
- } catch (\Exception $e) {
- log_message('error', 'AdminController unlockAccount error: ' . $e->getMessage());
- return $this->respondError('계정 잠금 해제 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Restore deleted admin (삭제된 관리자 복구)
- * POST /api/admin/:id/restore
- */
- public function restore($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $db = $this->getDB();
- $existing = $db->table('admin_users')
- ->where('id', (int) $id)
- ->where('deleted_YN', 'Y')
- ->get()->getRow();
- if (!$existing) {
- return $this->respondError('삭제된 관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND);
- }
- // 동일 아이디 충돌 검사
- $dupeUsername = $db->table('admin_users')
- ->where('username', $existing->username)
- ->where('deleted_YN', 'N')
- ->countAllResults();
- if ($dupeUsername > 0) {
- return $this->respondError(
- "동일 아이디 '{$existing->username}'가 이미 사용 중이라 복구할 수 없습니다.",
- ResponseInterface::HTTP_CONFLICT
- );
- }
- // 이메일 충돌 검사
- $dupeEmail = $db->table('admin_users')
- ->where('email', $existing->email)
- ->where('deleted_YN', 'N')
- ->countAllResults();
- if ($dupeEmail > 0) {
- return $this->respondError(
- "동일 이메일 '{$existing->email}'가 이미 사용 중이라 복구할 수 없습니다.",
- ResponseInterface::HTTP_CONFLICT
- );
- }
- $db->table('admin_users')
- ->where('id', (int) $id)
- ->update([
- 'deleted_YN' => 'N',
- 'updated_at' => date('Y-m-d H:i:s'),
- ]);
- return $this->respondSuccess(null, '관리자가 복구되었습니다.');
- } catch (\Exception $e) {
- log_message('error', 'AdminController restore error: ' . $e->getMessage());
- return $this->respondError('복구 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- /**
- * Hard delete admin (영구 삭제 — 이미 soft 삭제된 계정만)
- * DELETE /api/admin/:id/hard
- */
- public function hardDelete($id = null)
- {
- $auth = $this->requireAuth();
- if ($auth instanceof ResponseInterface) {
- return $auth;
- }
- if (empty($id)) {
- return $this->respondError('관리자 ID가 필요합니다.', ResponseInterface::HTTP_BAD_REQUEST);
- }
- try {
- $targetId = (int) $id;
- // 본인 영구 삭제 방지
- if ((int) $auth->admin_id === $targetId) {
- return $this->respondError('본인 계정은 영구 삭제할 수 없습니다.', ResponseInterface::HTTP_FORBIDDEN);
- }
- $db = $this->getDB();
- $existing = $db->table('admin_users')
- ->where('id', $targetId)
- ->where('deleted_YN', 'Y')
- ->get()->getRow();
- if (!$existing) {
- return $this->respondError('영구 삭제 대상이 없습니다. (이미 삭제된 계정만 영구 삭제 가능)', ResponseInterface::HTTP_NOT_FOUND);
- }
- // 권한 row 정리 (FK CASCADE 있어도 명시적으로)
- $db->table('admin_permissions')->where('admin_id', $targetId)->delete();
- $db->table('admin_tokens')->where('admin_id', $targetId)->delete();
- $db->table('admin_users')->where('id', $targetId)->delete();
- return $this->respondSuccess(null, '관리자가 영구 삭제되었습니다.');
- } catch (\Exception $e) {
- log_message('error', 'AdminController hardDelete error: ' . $e->getMessage());
- return $this->respondError('영구 삭제 중 오류가 발생했습니다.', ResponseInterface::HTTP_INTERNAL_SERVER_ERROR);
- }
- }
- }
|