guardia-hrm/backend/src/main/java/com/zioinfo/hrm/admin/AdminController.java
2026-07-04 08:32:22 +09:00

108 lines
4.1 KiB
Java

package com.zioinfo.hrm.admin;
import com.zioinfo.hrm.auth.HrmUser;
import com.zioinfo.hrm.common.ApiResponse;
import com.zioinfo.hrm.common.AuthSupport;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/hrm/admin")
@RequiredArgsConstructor
public class AdminController {
private final AdminMapper adminMapper;
private final PasswordEncoder passwordEncoder;
@GetMapping("/users")
public ApiResponse<List<HrmUser>> users() {
List<HrmUser> users = adminMapper.findAllUsers();
users.forEach(u -> u.setPasswordHash(null)); // 비밀번호 해시 미노출
return ApiResponse.ok(users);
}
@PostMapping("/users")
public ApiResponse<Void> createUser(@RequestBody HrmUser user) {
user.setPasswordHash(passwordEncoder.encode(user.getPasswordHash()));
user.setActive(true);
adminMapper.insertUser(user);
return ApiResponse.ok(null);
}
@PutMapping("/users/{id}")
public ApiResponse<Void> updateUser(@PathVariable Long id, @RequestBody HrmUser user) {
user.setId(id);
if (user.getPasswordHash() != null && !user.getPasswordHash().isEmpty()) {
user.setPasswordHash(passwordEncoder.encode(user.getPasswordHash()));
}
adminMapper.updateUser(user);
return ApiResponse.ok(null);
}
@PatchMapping("/users/{id}/active")
public ApiResponse<Void> toggleActive(@PathVariable Long id, @RequestParam boolean active) {
adminMapper.updateUserActive(id, active);
return ApiResponse.ok(null);
}
/**
* 관리자 OTP 초기화(SUPERADMIN). 대상 사용자의 OTP 시크릿을 폐기하고 등록을 해제한다.
* 사용자는 다음 로그인 시 OTP_SETUP(QR 재등록) 플로우를 탄다. 시크릿은 응답/로그에 노출하지 않는다.
*/
@PostMapping("/users/{id}/otp-reset")
public ApiResponse<HrmUser> resetOtp(@PathVariable Long id, Authentication auth) {
HrmUser user = adminMapper.findUserById(id);
if (user == null) {
throw new RuntimeException("ERR-HRM-404: 대상 사용자를 찾을 수 없습니다");
}
adminMapper.clearOtp(id);
Map<String, Object> log = new HashMap<>();
log.put("actor", AuthSupport.actor(auth));
log.put("action", "USER_OTP_RESET");
log.put("targetType", "auth.otp");
log.put("targetId", user.getUsername());
log.put("detail", "OTP 초기화(다음 로그인 재등록)");
log.put("ipAddr", null);
adminMapper.insertAuditLog(log);
user.setPasswordHash(null); // 비밀번호 해시 미노출
return ApiResponse.ok(user);
}
@GetMapping("/audit")
public ApiResponse<Map<String, Object>> audit(
@RequestParam(required = false) String actor,
@RequestParam(required = false) String action,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "50") int size) {
int offset = (page - 1) * size;
List<Map<String, Object>> rows = adminMapper.findAuditLogs(actor, action, offset, size);
long total = adminMapper.countAuditLogs(actor, action);
Map<String, Object> r = new HashMap<>();
r.put("items", rows);
r.put("total", total);
return ApiResponse.ok(r);
}
@GetMapping("/settings")
public ApiResponse<List<Map<String, Object>>> settings() {
return ApiResponse.ok(adminMapper.findSettings());
}
@PutMapping("/settings/{key}")
public ApiResponse<Void> upsertSetting(@PathVariable String key,
@RequestBody Map<String, Object> body, Authentication auth) {
body.put("key", key);
body.put("updatedBy", AuthSupport.actor(auth));
adminMapper.upsertSetting(body);
return ApiResponse.ok(null);
}
}