79 lines
2.5 KiB
TypeScript
79 lines
2.5 KiB
TypeScript
import { Router } from 'express';
|
|
import bcrypt from 'bcrypt';
|
|
import { prisma } from '../lib/prisma';
|
|
import { authenticate, requireAdmin } from '../middleware/auth';
|
|
import { AppError } from '../middleware/errorHandler';
|
|
|
|
const router = Router();
|
|
router.use(authenticate);
|
|
|
|
// GET /api/users — 전체 목록 (관리자)
|
|
router.get('/', requireAdmin, async (_req, res, next) => {
|
|
try {
|
|
const users = await prisma.user.findMany({
|
|
select: { id: true, email: true, name: true, role: true, department: true, isActive: true, createdAt: true },
|
|
orderBy: { name: 'asc' },
|
|
});
|
|
res.json(users);
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
// POST /api/users — 사용자 생성 (관리자)
|
|
router.post('/', requireAdmin, async (req, res, next) => {
|
|
try {
|
|
const { email, password, name, role, department } = req.body as Record<string, string>;
|
|
|
|
if (!email || !password || !name) {
|
|
throw new AppError(400, '이메일, 비밀번호, 이름은 필수입니다.');
|
|
}
|
|
|
|
const exists = await prisma.user.findUnique({ where: { email } });
|
|
if (exists) throw new AppError(409, '이미 사용 중인 이메일입니다.');
|
|
|
|
const hashed = await bcrypt.hash(password, 12);
|
|
const user = await prisma.user.create({
|
|
data: { email, password: hashed, name, role: (role as any) || 'MEMBER', department },
|
|
select: { id: true, email: true, name: true, role: true, department: true },
|
|
});
|
|
|
|
res.status(201).json(user);
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
// PATCH /api/users/:id — 정보 수정
|
|
router.patch('/:id', async (req, res, next) => {
|
|
try {
|
|
const isAdmin = req.user!.role === 'ADMIN';
|
|
const isSelf = req.user!.userId === req.params.id;
|
|
|
|
if (!isAdmin && !isSelf) {
|
|
throw new AppError(403, '권한이 없습니다.');
|
|
}
|
|
|
|
const { name, department, password, role, isActive } = req.body as Record<string, string>;
|
|
|
|
const data: Record<string, unknown> = {};
|
|
if (name) data.name = name;
|
|
if (department !== undefined) data.department = department;
|
|
if (password) data.password = await bcrypt.hash(password, 12);
|
|
if (isAdmin && role) data.role = role;
|
|
if (isAdmin && isActive !== undefined) data.isActive = isActive === 'true';
|
|
|
|
const user = await prisma.user.update({
|
|
where: { id: req.params.id },
|
|
data,
|
|
select: { id: true, email: true, name: true, role: true, department: true, isActive: true },
|
|
});
|
|
|
|
res.json(user);
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
export default router;
|