Files
tk-factory-services/user-management/api/controllers/userController.js
Hyungi Ahn 3cc29c03a8 feat: 권한 탭 분리 + 부서 인원 표시 + 다수 시스템 개선
- tkuser: 권한 관리를 별도 탭으로 분리, 부서 클릭 시 소속 인원 목록 표시
- system1: 모바일 UI 개선, nginx 권한 보정, 신고 카테고리 타입 마이그레이션
- system2: 신고 상세/보고서 개선, 내 보고서 페이지 추가
- system3: 이슈 뷰/수신함/관리함 개선
- gateway: 포털 라우팅 수정
- user-management API: 부서별 권한 벌크 설정 추가

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 14:12:57 +09:00

148 lines
3.9 KiB
JavaScript

/**
* User Controller
*
* 사용자 CRUD + 비밀번호 관리
*/
const userModel = require('../models/userModel');
/**
* GET /api/users - 전체 사용자 목록
*/
async function getUsers(req, res, next) {
try {
const users = await userModel.findAll();
res.json({ success: true, data: users });
} catch (err) {
next(err);
}
}
/**
* POST /api/users - 사용자 생성
*/
async function createUser(req, res, next) {
try {
const { username, password, name, full_name, department, department_id, role } = req.body;
if (!username || !password) {
return res.status(400).json({ success: false, error: '사용자명과 비밀번호는 필수입니다' });
}
const existing = await userModel.findByUsername(username);
if (existing) {
return res.status(409).json({ success: false, error: '이미 존재하는 사용자명입니다' });
}
const user = await userModel.create({
username,
password,
name: name || full_name,
department,
department_id: department_id || null,
role
});
res.status(201).json({ success: true, data: user });
} catch (err) {
next(err);
}
}
/**
* PUT /api/users/:id - 사용자 수정
*/
async function updateUser(req, res, next) {
try {
const userId = parseInt(req.params.id);
const data = { ...req.body };
// full_name → name 매핑
if (data.full_name !== undefined && data.name === undefined) {
data.name = data.full_name;
delete data.full_name;
}
const user = await userModel.update(userId, data);
if (!user) {
return res.status(404).json({ success: false, error: '사용자를 찾을 수 없습니다' });
}
res.json({ success: true, data: user });
} catch (err) {
next(err);
}
}
/**
* DELETE /api/users/:id - 사용자 비활성화
*/
async function deleteUser(req, res, next) {
try {
const userId = parseInt(req.params.id);
await userModel.deleteUser(userId);
res.json({ success: true, message: '사용자가 비활성화되었습니다' });
} catch (err) {
next(err);
}
}
/**
* POST /api/users/:id/reset-password - 비밀번호 초기화 (admin)
*/
async function resetPassword(req, res, next) {
try {
const userId = parseInt(req.params.id);
const { new_password } = req.body;
const password = new_password || '000000';
const user = await userModel.update(userId, { password });
if (!user) {
return res.status(404).json({ success: false, error: '사용자를 찾을 수 없습니다' });
}
res.json({ success: true, message: '비밀번호가 초기화되었습니다' });
} catch (err) {
next(err);
}
}
/**
* POST /api/users/change-password - 본인 비밀번호 변경
*/
async function changePassword(req, res, next) {
try {
const { current_password, new_password } = req.body;
const userId = req.user.user_id || req.user.id;
if (!current_password || !new_password) {
return res.status(400).json({ success: false, error: '현재 비밀번호와 새 비밀번호를 입력하세요' });
}
if (new_password.length < 6) {
return res.status(400).json({ success: false, error: '새 비밀번호는 최소 6자 이상이어야 합니다' });
}
const user = await userModel.findById(userId);
if (!user) {
return res.status(404).json({ success: false, error: '사용자를 찾을 수 없습니다' });
}
const valid = await userModel.verifyPassword(current_password, user.password_hash);
if (!valid) {
return res.status(401).json({ success: false, error: '현재 비밀번호가 올바르지 않습니다' });
}
await userModel.update(userId, { password: new_password });
res.json({ success: true, message: '비밀번호가 변경되었습니다' });
} catch (err) {
next(err);
}
}
module.exports = {
getUsers,
createUser,
updateUser,
deleteUser,
resetPassword,
changePassword
};