requireAuth(); if ($auth instanceof ResponseInterface) { return $auth; } try { $page = $this->request->getGet('page') ?? 1; $perPage = $this->request->getGet('per_page') ?? 10; $offset = ($page - 1) * $perPage; $db = $this->getDB(); $builder = $db->table('admin_users'); // 'admin' 계정 제외 $builder->where('username !=', 'admin'); // 검색 기능 - 아이디, 이름만 LIKE 검색 $search = $this->request->getGet('search'); if (!empty($search)) { $builder->groupStart() ->like('username', $search) ->orLike('name', $search) ->groupEnd(); } // 역할 필터 $role = $this->request->getGet('role'); if (!empty($role)) { $builder->where('role', $role); } // 상태 필터 $status = $this->request->getGet('status'); if (!empty($status)) { $builder->where('status', $status); } // 전체 개수 $total = $builder->countAllResults(false); // 비밀번호 제외하고 조회 (login_attempts 포함) $builder->select('id, username, name, email, department, role, status, COALESCE(login_attempts, 0) as login_attempts, last_failed_login, created_at, updated_at'); $builder->orderBy('id', 'DESC'); $builder->limit($perPage, $offset); // SQL 쿼리 로그 $sql = $builder->getCompiledSelect(false); log_message('debug', 'AdminController SQL: ' . $sql); $items = $builder->get()->getResult(); $result = [ 'items' => $items, 'total' => $total, 'page' => (int)$page, 'per_page' => (int)$perPage, 'total_pages' => ceil($total / $perPage) ]; return $this->respondSuccess($result); } 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, department, role, status, login_attempts, last_failed_login, created_at, updated_at') ->where('id', $id) ->get() ->getRow(); if (!$admin) { return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND); } 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 = $this->request->getGet('username'); if (empty($username)) { return $this->respondError('아이디를 입력하세요.'); } try { $existing = $this->getDB()->table('admin_users') ->where('username', $username) ->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); } } // 중복 체크 $existing = $this->getDB()->table('admin_users') ->where('username', $data['username']) ->orWhere('email', $data['email']) ->get() ->getRow(); if ($existing) { if ($existing->username === $data['username']) { return $this->respondError('이미 사용 중인 아이디입니다.', ResponseInterface::HTTP_BAD_REQUEST); } if ($existing->email === $data['email']) { return $this->respondError('이미 사용 중인 이메일입니다.', ResponseInterface::HTTP_BAD_REQUEST); } } // 비밀번호 해싱 $insertData = [ 'username' => $data['username'], 'password' => password_hash($data['password'], PASSWORD_DEFAULT), 'name' => $data['name'], 'email' => $data['email'], 'department' => $data['department'] ?? '', 'role' => $data['role'] ?? 'admin', 'status' => $data['status'] ?? 'active', 'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s') ]; $builder = $this->getDB()->table('admin_users'); $builder->insert($insertData); $insertId = $this->getDB()->insertID(); // 생성된 관리자 정보 조회 (비밀번호 제외) $admin = $this->getDB()->table('admin_users') ->select('id, username, name, email, department, role, status, login_attempts, last_failed_login, created_at, updated_at') ->where('id', $insertId) ->get() ->getRow(); 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', $id)->get()->getRow(); if (!$existing) { return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND); } $data = $this->request->getJSON(true); // email 중복 체크 (자신 제외) if (!empty($data['email']) && $data['email'] !== $existing->email) { $duplicate = $this->getDB()->table('admin_users') ->where('email', $data['email']) ->where('id !=', $id) ->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'] = $data['name']; } if (isset($data['email'])) { $updateData['email'] = $data['email']; } if (isset($data['department'])) { $updateData['department'] = $data['department']; } if (isset($data['role'])) { $updateData['role'] = $data['role']; } if (isset($data['status'])) { $updateData['status'] = $data['status']; } $builder = $this->getDB()->table('admin_users'); $builder->where('id', $id)->update($updateData); // 업데이트된 관리자 정보 조회 $admin = $this->getDB()->table('admin_users') ->select('id, username, name, email, department, role, status, login_attempts, last_failed_login, created_at, updated_at') ->where('id', $id) ->get() ->getRow(); 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 { $existing = $this->getDB()->table('admin_users')->where('id', $id)->get()->getRow(); if (!$existing) { return $this->respondError('관리자를 찾을 수 없습니다.', ResponseInterface::HTTP_NOT_FOUND); } $builder = $this->getDB()->table('admin_users'); $builder->where('id', $id)->delete(); // 해당 관리자의 토큰도 삭제 $this->getDB()->table('admin_tokens')->where('admin_id', $id)->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', $id)->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', $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', $id)->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', $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); } } }