package com.goldenchart.service; import com.goldenchart.auth.MenuIds; import com.goldenchart.auth.UserRole; import com.goldenchart.dto.MenuPermissionsResponse; import com.goldenchart.dto.RolePermissionsUpdateRequest; import com.goldenchart.entity.GcRoleMenuPermission; import com.goldenchart.entity.GcUser; import com.goldenchart.repository.GcRoleMenuPermissionRepository; import com.goldenchart.repository.GcUserRepository; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; import java.util.*; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class RolePermissionService { private final GcRoleMenuPermissionRepository permRepo; private final GcUserRepository userRepo; @Transactional(readOnly = true) public MenuPermissionsResponse resolveForUserId(Long userId) { if (userId == null) { return buildForRole(UserRole.GUEST.name()); } GcUser user = userRepo.findById(userId) .filter(u -> Boolean.TRUE.equals(u.getEnabled())) .orElse(null); if (user == null) { return buildForRole(UserRole.GUEST.name()); } String role = user.getRole() != null ? user.getRole() : UserRole.USER.name(); return buildForRole(role); } @Transactional(readOnly = true) public MenuPermissionsResponse buildForRole(String role) { String r = UserRole.fromString(role).name(); Map map = defaultMap(); for (GcRoleMenuPermission p : permRepo.findByRole(r)) { map.put(p.getMenuId(), Boolean.TRUE.equals(p.getAllowed())); } return MenuPermissionsResponse.builder().role(r).permissions(map).build(); } @Transactional(readOnly = true) public Map> listAllRolePermissions() { Map> out = new LinkedHashMap<>(); for (UserRole role : UserRole.values()) { out.put(role.name(), buildForRole(role.name()).getPermissions()); } return out; } @Transactional public void updateRolePermissions(RolePermissionsUpdateRequest req) { if (req == null || req.getRole() == null || req.getPermissions() == null) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "role과 permissions가 필요합니다."); } String role = UserRole.fromString(req.getRole()).name(); permRepo.deleteByRole(role); List rows = new ArrayList<>(); for (String menuId : MenuIds.ALL) { Boolean allowed = req.getPermissions().getOrDefault(menuId, false); rows.add(GcRoleMenuPermission.builder() .role(role) .menuId(menuId) .allowed(allowed) .build()); } permRepo.saveAll(rows); } @Transactional(readOnly = true) public void requireAdmin(Long userId) { GcUser user = userRepo.findById(userId) .orElseThrow(() -> new ResponseStatusException(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다.")); if (!UserRole.ADMIN.name().equalsIgnoreCase(user.getRole())) { throw new ResponseStatusException(HttpStatus.FORBIDDEN, "관리자 권한이 필요합니다."); } if (!Boolean.TRUE.equals(user.getEnabled())) { throw new ResponseStatusException(HttpStatus.FORBIDDEN, "비활성화된 계정입니다."); } } private static Map defaultMap() { return MenuIds.ALL.stream().collect(Collectors.toMap(id -> id, id -> false, (a, b) -> b, LinkedHashMap::new)); } }