package com.TinyPro.service.imp;
import com.TinyPro.entity.dto.CreateRoleDto;
import com.TinyPro.entity.dto.UpdateRoleDto;
import com.TinyPro.entity.page.PageWrapper;
import com.TinyPro.entity.po.Menu;
import com.TinyPro.entity.po.Permission;
import com.TinyPro.entity.po.Role;
import com.TinyPro.entity.po.User;
import com.TinyPro.entity.vo.MenuTreeVo;
import com.TinyPro.entity.vo.RolePMVo;
import com.TinyPro.entity.vo.RoleSimpleVo;
import com.TinyPro.exception.BusinessException;
import com.TinyPro.service.IRoleService;
import com.TinyPro.jpa.IMenuRepository;
import com.TinyPro.jpa.IPermissionRepository;
import com.TinyPro.jpa.IRoleRepository;
import com.TinyPro.jpa.IUserRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.Predicate;
import jakarta.persistence.criteria.Root;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Service
public class IRoleServiceImpl implements IRoleService {
@Autowired
private IRoleRepository iRoleRepository;
@Autowired
private IPermissionRepository permissionService;
@Autowired
private IMenuRepository menuService;
@Autowired
private IUserRepository iUserRepository;
@PersistenceContext
private EntityManager entityManager;
@Override
@Transactional
public ResponseEntity<Role> createRole(CreateRoleDto createRoleDto, boolean isInit) {
Optional<Role> existingRole = iRoleRepository.findByName(createRoleDto.getName());
if (isInit && existingRole.isPresent()) {
return ResponseEntity.ok(existingRole.get());
}
if (existingRole.isPresent()) {
throw new BusinessException("exception.role.exists", HttpStatus.BAD_REQUEST, null);
}
Set<Permission> permissions = permissionService.findAllById(
createRoleDto.getPermissionIds() != null ? createRoleDto.getPermissionIds() : Collections.emptyList()
).stream().collect(Collectors.toSet());
Set<Menu> menus = menuService.findAllById(
createRoleDto.getMenuIds() != null ? createRoleDto.getMenuIds() : Collections.emptyList()
).stream().collect(Collectors.toSet());
Role newRole = new Role();
newRole.setName(createRoleDto.getName());
newRole.setPermission(permissions);
newRole.setMenus(menus);
return ResponseEntity.ok(iRoleRepository.save(newRole));
}
@Override
public ResponseEntity<RolePMVo> findAllDetail(Integer page, Integer limit, String name) {
Pageable pageable = PageRequest.of(
page == null || page <= 0 ? 0 : page - 1,
limit == null || limit <= 0 ? 10 : limit
);
Specification<Role> spec = (root, query, cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNotEmpty(name)) {
Predicate namePreidcate = buildLikePredicate(root, cb, "name", name);
predicates.add(namePreidcate);
}
return cb.and(predicates.toArray(new Predicate[0]));
};
Page<Role> rolePage = iRoleRepository.findAll(spec, pageable);
List<Menu> menuList = menuService.findAll();
PageWrapper<Role> rolePageWrapper = PageWrapper.of(rolePage);
MenuTreeVo menuTreeVo = convertToTree(menuList);
RolePMVo rolePMVo = new RolePMVo();
rolePMVo.setRoleInfo(rolePageWrapper);
rolePMVo.setMenuTree(menuTreeVo);
return ResponseEntity.ok(rolePMVo);
}
private MenuTreeVo convertToTree(List<Menu> menus) {
if (menus == null || menus.isEmpty()) {
return null;
}
Map<Integer, MenuTreeVo> map = new HashMap<>();
MenuTreeVo root = null;
for (Menu menu : menus) {
MenuTreeVo node = new MenuTreeVo();
node.setId(menu.getId());
node.setLabel(menu.getName());
node.setUrl(menu.getPath());
node.setComponent(menu.getComponent());
node.setCustomIcon(menu.getIcon());
node.setMenuType(menu.getMenuType());
node.setParentId(menu.getParentId());
node.setOrder(menu.getOrder());
node.setLocale(menu.getLocale());
map.put(menu.getId(), node);
if (menu.getParentId() == null) {
root = node;
}
}
for (Menu menu : menus) {
if (menu.getParentId() != null) {
MenuTreeVo parent = map.get(menu.getParentId());
if (parent != null) {
if (parent.getChildren() == null) {
parent.setChildren(new ArrayList<>());
}
parent.getChildren().add(map.get(menu.getId()));
}
}
}
return root;
}
@Override
@Transactional
public ResponseEntity<Role> updateRole(UpdateRoleDto updateRoleDto) {
Role role = iRoleRepository.findById(Long.valueOf(updateRoleDto.getId())) .orElseThrow(() -> new BusinessException("exception.role.notExists", HttpStatus.BAD_REQUEST, null));
if (updateRoleDto.getPermissionIds() != null) {
List<Permission> permissionList = permissionService.findAllById(updateRoleDto.getPermissionIds());
role.setPermission(permissionList.stream().collect(Collectors.toSet()));
}
if (updateRoleDto.getMenuIds() != null) {
List<Menu> menuList = menuService.findAllById(updateRoleDto.getMenuIds());
role.setMenus(menuList.stream().collect(Collectors.toSet()));
}
if (StringUtils.isNotEmpty(updateRoleDto.getName())) {
role.setName(updateRoleDto.getName());
}
return ResponseEntity.ok(iRoleRepository.save(role));
}
@Override
@Transactional
public ResponseEntity<Map<String, String>> removeRoleById(Integer id) {
Role role = iRoleRepository.findById(Long.valueOf(id)).orElseThrow(() -> new BusinessException("exception.role.notExists",HttpStatus.NOT_FOUND,null));
List<User> usersWithRole = iUserRepository.findByRoleId(Long.valueOf(id));
if (!usersWithRole.isEmpty()){
throw new BusinessException("exception.role.conflict",HttpStatus.CONFLICT,null);
}
iRoleRepository.delete(role);
Map<String, String> result = new HashMap<>();
result.put("name",role.getName());
return ResponseEntity.ok(result);
}
@Override
public ResponseEntity<List<RoleSimpleVo>> findAllRole() {
List<Role> roles = iRoleRepository.findAll();
List<RoleSimpleVo> result = roles.stream()
.map(RoleSimpleVo::fromEntity)
.collect(Collectors.toList());
return ResponseEntity.ok(result);
}
@Override
public ResponseEntity<Role> findOne(Integer id) {
Role role = iRoleRepository.findById(Long.valueOf(id)).orElseThrow(() -> new BusinessException("exception.role.notExists", HttpStatus.NOT_FOUND, null));
return ResponseEntity.ok(role);
}
private Predicate buildLikePredicate(Root<Role> root, CriteriaBuilder cb, String field, String input) {
if (input.contains("%")) {
if (input.startsWith("%") && input.endsWith("%")) {
String value = input.substring(1, input.length() - 1);
return cb.like(root.get(field), "%" + value + "%");
} else if (input.startsWith("%")) {
String value = input.substring(1);
return cb.like(root.get(field), "%" + value);
} else if (input.endsWith("%")) {
String value = input.substring(0, input.length() - 1);
return cb.like(root.get(field), value + "%");
} else {
return cb.like(root.get(field), input);
}
} else {
return cb.equal(root.get(field), input);
}
}
}