package com.TinyPro.service.imp;
import com.TinyPro.entity.contants.Contants;
import com.TinyPro.entity.dto.*;
import com.TinyPro.entity.page.PageWrapper;
import com.TinyPro.entity.po.I18;
import com.TinyPro.entity.po.Permission;
import com.TinyPro.entity.po.Role;
import com.TinyPro.entity.po.User;
import com.TinyPro.entity.vo.RoleSimpleVo;
import com.TinyPro.entity.vo.UserVo;
import com.TinyPro.exception.BusinessException;
import com.TinyPro.redis.RedisUtil;
import com.TinyPro.service.IAuthService;
import com.TinyPro.service.IUserService;
import com.TinyPro.jpa.IRoleRepository;
import com.TinyPro.jpa.IUserRepository;
import com.TinyPro.utils.Sha256Utils;
import jakarta.persistence.criteria.*;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
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 org.springframework.web.server.ResponseStatusException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class IUserServiceImpl implements IUserService {
@Autowired
private IUserRepository iUserRepository;
@Autowired
private IRoleRepository iRoleRepository;
@Autowired
private RedisUtil redisUtil;
@Autowired
private IAuthService authService;
@Transactional
@Override
public ResponseEntity<UserVo> create(CreateUserDto createUserDto, boolean isInit) {
Optional<User> existingUser = iUserRepository.findByEmail(createUserDto.getEmail());
if (isInit && existingUser.isPresent()) {
return ResponseEntity.ok(UserVo.fromEntity(existingUser.get()));
}
if (!existingUser.isEmpty()) {
throw new BusinessException("exception.user.userExists", HttpStatus.BAD_REQUEST, null);
}
List<Role> roles = iRoleRepository.findAllById(createUserDto.getRoleIds());
try {
User user = new User();
user.setEmail(createUserDto.getEmail());
user.setPassword(Sha256Utils.encry(createUserDto.getPassword(), Contants.PUBLICK_SALT));
user.setName(createUserDto.getName());
user.setRole(roles);
user.setSalt(Contants.PUBLICK_SALT);
user.setDepartment(createUserDto.getDepartment());
user.setEmployee_type(createUserDto.getEmployeeType());
if (StringUtils.isNotEmpty(createUserDto.getProbationStart())) {
user.setProbation_start(toStandardDateFormat(createUserDto.getProbationStart()));
}
if (StringUtils.isNotEmpty(createUserDto.getProbationEnd())) {
user.setProbation_end(toStandardDateFormat(createUserDto.getProbationEnd()));
}
user.setProbation_duration(createUserDto.getProbationDuration());
if (StringUtils.isNotEmpty(createUserDto.getProtocolStart())) {
user.setProtocol_start(toStandardDateFormat(createUserDto.getProtocolStart()));
}
if (StringUtils.isNotEmpty(createUserDto.getProtocolEnd())) {
user.setProtocol_end(toStandardDateFormat(createUserDto.getProtocolEnd()));
}
user.setAddress(createUserDto.getAddress());
user.setStatus(createUserDto.getStatus());
return ResponseEntity.ok(UserVo.fromEntity(iUserRepository.save(user)));
} catch (Exception e) {
throw new ResponseStatusException(
HttpStatus.INTERNAL_SERVER_ERROR,
e.getMessage()
);
}
}
@Override
public List<Permission> getRoleByUserId(User user) {
User result = iUserRepository.findByIdWithRoles(user.getId()).orElseThrow(() -> new BusinessException("exception.user.userExists",HttpStatus.NOT_FOUND,null));
List<Permission> resultList = new ArrayList<>();
result.getRole()
.stream()
.map(item -> {
Set<Permission> permission = item.getPermission();
resultList.addAll(permission.stream().toList());
return item;
})
.collect(Collectors.toList());
return resultList;
}
@Override
public ResponseEntity<User> getUserInfo(String email) {
User user = iUserRepository.findByEmail(email).orElseThrow(() -> new BusinessException("exception.common.unauth",HttpStatus.NOT_FOUND,null));
return ResponseEntity.ok(user);
}
@Override
@Transactional
public ResponseEntity<UserVo> removeUserInfo(String email) {
try {
User user = iUserRepository.findByEmail(email).orElseThrow(() -> new BusinessException("exception.user.userNotFound", HttpStatus.NOT_FOUND, null));
iUserRepository.delete(user);
UserVo result = UserVo.fromEntity(user);
return ResponseEntity.ok(result);
} catch (Exception e) {
throw new BusinessException("exception.user.userNumberNull",HttpStatus.BAD_REQUEST,null);
}
}
@Override
@Transactional
public ResponseEntity<UserVo> updateUserInfo(UpdateUserDto updateUserDto) {
User user = iUserRepository.findByEmail(updateUserDto.getEmail())
.orElseThrow(() -> new BusinessException("exception.user.userNotFound",HttpStatus.NOT_FOUND,null));
String originalRoleIds = user.getRole().stream()
.map(role -> role.getId().toString())
.collect(Collectors.joining());
List<Role> newRoles = iRoleRepository.findAllById(updateUserDto.getRoleIds());
List<RoleSimpleVo> roleSimpleVos = newRoles.stream()
.map(RoleSimpleVo::fromEntity)
.collect(Collectors.toList());
user.setName(updateUserDto.getName());
user.setDepartment(updateUserDto.getDepartment());
user.setEmployee_type(updateUserDto.getEmployeeType());
if (!StringUtils.equals(updateUserDto.getProbationStart(), "NaN-NaN-NaN") && StringUtils.isNotEmpty(updateUserDto.getProbationStart())) {
user.setProbation_start(toStandardDateFormat(updateUserDto.getProbationStart()));
}
if (!StringUtils.equals(updateUserDto.getProbationEnd(), "NaN-NaN-NaN") && StringUtils.isNotEmpty(updateUserDto.getProbationEnd())) {
user.setProbation_end(toStandardDateFormat(updateUserDto.getProbationEnd()));
}
user.setProbation_duration(updateUserDto.getProbationDuration());
if (!StringUtils.equals(updateUserDto.getProtocolStart(), "NaN-NaN-NaN") && StringUtils.isNotEmpty(updateUserDto.getProtocolStart()) && !StringUtils.equals(updateUserDto.getProtocolStart(), "NaN-NaN-NaN")) {
user.setProtocol_start(toStandardDateFormat(updateUserDto.getProtocolStart()));
}
if (!StringUtils.equals(updateUserDto.getProtocolEnd(), "NaN-NaN-NaN") && StringUtils.isNotEmpty(updateUserDto.getProtocolEnd())) {
user.setProtocol_end(toStandardDateFormat(updateUserDto.getProtocolEnd()));
}
user.setAddress(updateUserDto.getAddress());
user.setStatus(updateUserDto.getStatus());
user.setRole(newRoles);
User updatedUser = iUserRepository.save(user);
UserVo result = UserVo.fromEntity(updatedUser);
String newRoleIds = updateUserDto.getRoleIds().stream()
.map(Object::toString)
.collect(Collectors.joining());
if (!originalRoleIds.equals(newRoleIds)) {
authService.logout(updateUserDto.getEmail());
}
return ResponseEntity.ok(result);
}
@Override
public PageWrapper<UserVo> getAllUser(PaginationQueryDto paginationQuery, String name, Integer[] role, String email) {
Pageable pageable = PageRequest.of(
paginationQuery.getPage() - 1,
paginationQuery.getLimit(),
Sort.by("id").ascending()
);
Specification<User> spec = (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
List<Predicate> predicates = new ArrayList<>();
if (StringUtils.isNoneBlank(name)) {
Predicate namePredicate = buildLikePredicate(root, cb, "name", name);
predicates.add(namePredicate);
}
if (role != null && role.length > 0) {
Join<User, Role> roleJoin = root.join("role", JoinType.INNER);
predicates.add(roleJoin.get("id").in((Object[]) role));
}
if (StringUtils.isNoneBlank(email)) {
Predicate emailPredicate = buildLikePredicate(root, cb, "email", email);
predicates.add(emailPredicate);
}
return cb.and(predicates.toArray(new Predicate[0]));
};
Page<User> page = iUserRepository.findAll(spec, pageable);
page.getContent().forEach(user -> {
user.setProbation_start(user.getProbation_start());
user.setProbation_end(user.getProbation_end());
user.setProtocol_start(user.getProtocol_start());
user.setProtocol_end(user.getProtocol_end());
});
Page<UserVo> result = convertToUserVoPage(page);
return PageWrapper.of(result);
}
@Override
@Transactional
public ResponseEntity<?> updatePwdAdmin(UpdatePwdAdminDto dto) {
Optional<User> userOpt = iUserRepository.findByEmail(dto.getEmail());
if (userOpt.isPresent()) {
User user = userOpt.get();
String encryptedPwd = encryptPassword(dto.getNewPassword(), user.getSalt());
user.setPassword(encryptedPwd);
iUserRepository.save(user);
redisUtil.deleteValue(Contants.UserJwtTop + user.getEmail() + Contants.UserJwtbt);
} else {
throw new BusinessException("exception.user.userNotFound",HttpStatus.NOT_FOUND,null);
}
return ResponseEntity.ok(null);
}
@Override
@Transactional
public void updatePwdUser(UpdatePwdUserDto dto) {
User user = iUserRepository.findByEmail(dto.getEmail())
.orElseThrow(() -> new BusinessException("exception.user.userNotFound",HttpStatus.NOT_FOUND,null));
if (!verifyPassword(dto.getOldPassword(), user.getPassword(), user.getSalt())) {
throw new BusinessException("exception.user.oldPasswordError",HttpStatus.BAD_REQUEST,null);
}
String encryptedPwd = encryptPassword(dto.getNewPassword(), user.getSalt());
user.setPassword(encryptedPwd);
iUserRepository.save(user);
redisUtil.deleteValue(Contants.UserJwtTop + user.getEmail() + Contants.UserJwtbt);
}
@Override
@Transactional
public ResponseEntity<List<UserVo>> batchDeleteUser(List<String> emails) {
List<UserVo> result = new ArrayList<>();
iUserRepository.finByEmailBatch(emails).stream().map(item -> {
UserVo userVo = new UserVo();
BeanUtils.copyProperties(item, userVo);
result.add(userVo);
return item;
}).collect(Collectors.toList());
iUserRepository.deleteByEmailIn(emails);
return ResponseEntity.ok(result);
}
private boolean verifyPassword(String inputPassword, String storedPassword, String salt) {
String encryptedInput = encryptPassword(inputPassword, salt);
return encryptedInput.equals(storedPassword);
}
private String encryptPassword(String rawPassword, String salt) {
try {
return Sha256Utils.encry(rawPassword, salt);
} catch (Exception e) {
throw new BusinessException("exception.user.oldPasswordError",HttpStatus.BAD_REQUEST,null);
}
}
private LocalDate toStandardDateFormat(String dateTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d");
return LocalDate.parse(dateTime, formatter);
}
private Page<UserVo> convertToUserVoPage(Page<User> userPage) {
List<UserVo> userVoList = userPage.getContent()
.stream()
.map(UserVo::fromEntity)
.collect(Collectors.toList());
return new PageImpl<>(
userVoList,
userPage.getPageable(),
userPage.getTotalElements()
);
}
private Predicate buildLikePredicate(Root<User> 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);
}
}
}