content: package com.aizuda.snailjob.server.web.service.impl;
  
  import cn.hutool.core.collection.CollUtil;
  import cn.hutool.core.lang.Assert;
  import cn.hutool.core.util.StrUtil;
  import cn.hutool.crypto.SecureUtil;
  import com.aizuda.snailjob.common.core.util.JsonUtil;
  import com.aizuda.snailjob.common.core.util.StreamUtils;
  import com.aizuda.snailjob.server.common.exception.SnailJobServerException;
  import com.aizuda.snailjob.server.web.model.request.UserSessionVO;
  import com.aizuda.snailjob.server.web.annotation.RoleEnum;
  import com.aizuda.snailjob.server.web.model.base.PageResult;
  import com.aizuda.snailjob.server.web.model.request.*;
  import com.aizuda.snailjob.server.web.model.response.PermissionsResponseVO;
  import com.aizuda.snailjob.server.web.model.response.SystemUserResponseVO;
  import com.aizuda.snailjob.server.web.service.SystemUserService;
  import com.aizuda.snailjob.server.web.service.convert.NamespaceResponseVOConverter;
  import com.aizuda.snailjob.server.web.service.convert.PermissionsResponseVOConverter;
  import com.aizuda.snailjob.server.web.service.convert.SystemUserResponseVOConverter;
  import com.aizuda.snailjob.server.web.util.UserSessionUtils;
  import com.aizuda.snailjob.template.datasource.persistence.mapper.NamespaceMapper;
  import com.aizuda.snailjob.template.datasource.persistence.mapper.SystemUserMapper;
  import com.aizuda.snailjob.template.datasource.persistence.mapper.SystemUserPermissionMapper;
  import com.aizuda.snailjob.template.datasource.persistence.po.Namespace;
  import com.aizuda.snailjob.template.datasource.persistence.po.SystemUser;
  import com.aizuda.snailjob.template.datasource.persistence.po.SystemUserPermission;
  import com.auth0.jwt.JWT;
  import com.auth0.jwt.algorithms.Algorithm;
  import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
  import com.baomidou.mybatisplus.core.toolkit.Wrappers;
  import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
  import com.google.common.collect.Lists;
  import lombok.RequiredArgsConstructor;
  import org.springframework.stereotype.Service;
  import org.springframework.transaction.annotation.Transactional;
  
  import java.util.*;
  
  /**
   * <p>
   * 系统用户表 服务实现类
   * </p>
   *
   * @author opensnail
   * @since 2022-03-05
   */
  @Service
  @RequiredArgsConstructor
  public class SystemUserServiceImpl implements SystemUserService {
      public static final long EXPIRE_TIME = 3600 * 24 * 1000;
  
      private final SystemUserMapper systemUserMapper;
      private final SystemUserPermissionMapper systemUserPermissionMapper;
      private final NamespaceMapper namespaceMapper;
  
      private static void validateUserPassword(SystemUserRequestVO requestVO, SystemUser systemUser) {
          if (Objects.isNull(systemUser)) {
              throw new SnailJobServerException("Incorrect username or password");
          }
  
          if (!SecureUtil.sha256(requestVO.getPassword()).equals(systemUser.getPassword())) {
              throw new SnailJobServerException("Incorrect username or password");
          }
      }
  
      @Override
      public SystemUserResponseVO login(SystemUserRequestVO requestVO) {
  
          SystemUser systemUser = systemUserMapper.selectOne(
                  new LambdaQueryWrapper<SystemUser>()
                          .eq(SystemUser::getUsername, requestVO.getUsername().trim()));
          validateUserPassword(requestVO, systemUser);
  
          String token = getToken(systemUser);
  
          SystemUserResponseVO systemUserResponseVO = SystemUserResponseVOConverter.INSTANCE.convert(systemUser);
          systemUserResponseVO.setToken(token);
  
          getPermission(systemUser.getRole(), systemUser.getId(), systemUserResponseVO);
  
          return systemUserResponseVO;
      }
  
      private void getPermission(Integer role, Long userId, final SystemUserResponseVO systemUserResponseVO) {
  
          LambdaQueryWrapper<Namespace> queryWrapper = new LambdaQueryWrapper<>();
          queryWrapper.select(Namespace::getId, Namespace::getUniqueId, Namespace::getName);
          if (RoleEnum.USER.getRoleId().equals(role)) {
              List<SystemUserPermission> systemUserPermissions = systemUserPermissionMapper.selectList(
                      new LambdaQueryWrapper<SystemUserPermission>()
                              .select(SystemUserPermission::getNamespaceId)
                              .eq(SystemUserPermission::getSystemUserId, userId)
                              .groupBy(SystemUserPermission::getNamespaceId));
              queryWrapper.in(Namespace::getUniqueId, StreamUtils.toSet(systemUserPermissions, SystemUserPermission::getNamespaceId));
          }
  
          List<Namespace> namespaces = namespaceMapper.selectList(queryWrapper);
          systemUserResponseVO.setNamespaceIds(
                  NamespaceResponseVOConverter.INSTANCE.convertList(namespaces));
      }
  
      @Override
      public SystemUserResponseVO getUserInfo(UserSessionVO systemUser) {
          SystemUserResponseVO systemUserResponseVO = SystemUserResponseVOConverter.INSTANCE.convert(systemUser);
  
          getPermission(systemUser.getRole(), systemUser.getId(), systemUserResponseVO);
  
          return systemUserResponseVO;
      }
  
      @Override
      @Transactional
      public void addUser(SystemUserRequestVO requestVO) {
          long count = systemUserMapper.selectCount(
                  new LambdaQueryWrapper<SystemUser>().eq(SystemUser::getUsername, requestVO.getUsername()));
          if (count > 0) {
              throw new SnailJobServerException("User already exists");
          }
  
          SystemUser systemUser = new SystemUser();
          systemUser.setUsername(requestVO.getUsername());
          systemUser.setPassword(SecureUtil.sha256(requestVO.getPassword()));
          systemUser.setRole(requestVO.getRole());
  
          Assert.isTrue(1 == systemUserMapper.insert(systemUser), () -> new SnailJobServerException("Failed to add user"));
  
          // 只添加为普通用户添加权限
          List<UserPermissionRequestVO> groupNameList = requestVO.getPermissions();
          if (CollUtil.isEmpty(groupNameList) || RoleEnum.ADMIN.getRoleId().equals(requestVO.getRole())) {
              return;
          }
  
          for (UserPermissionRequestVO permission : groupNameList) {
              SystemUserPermission systemUserPermission = new SystemUserPermission();
              systemUserPermission.setSystemUserId(systemUser.getId());
              systemUserPermission.setGroupName(permission.getGroupName());
              systemUserPermission.setNamespaceId(permission.getNamespaceId());
              Assert.isTrue(1 == systemUserPermissionMapper.insert(systemUserPermission),
                      () -> new SnailJobServerException("Failed to add user permissions"));
          }
  
      }
  
      @Override
      @Transactional
      public void update(SystemUserRequestVO requestVO) {
          SystemUser systemUser = systemUserMapper.selectOne(
                  new LambdaQueryWrapper<SystemUser>().eq(SystemUser::getId, requestVO.getId()));
          if (Objects.isNull(systemUser)) {
              throw new SnailJobServerException("User does not exist");
          }
  
          if (!systemUser.getUsername().equals(requestVO.getUsername())) {
              long count = systemUserMapper.selectCount(
                      new LambdaQueryWrapper<SystemUser>().eq(SystemUser::getUsername, requestVO.getUsername()));
              if (count > 0) {
                  throw new SnailJobServerException("User already exists");
              }
          }
  
          systemUser.setUsername(requestVO.getUsername());
          if (StrUtil.isNotBlank(requestVO.getPassword())) {
              systemUser.setPassword(SecureUtil.sha256(requestVO.getPassword()));
          }
  
          systemUser.setRole(requestVO.getRole());
  
          Assert.isTrue(1 == systemUserMapper.updateById(systemUser), () -> new SnailJobServerException("Failed to update user"));
  
          // 只添加为普通用户添加权限
          List<UserPermissionRequestVO> permissions = requestVO.getPermissions();
          if (CollUtil.isEmpty(permissions) || RoleEnum.ADMIN.getRoleId().equals(requestVO.getRole())) {
              return;
          }
  
          systemUserPermissionMapper.delete(new LambdaQueryWrapper<SystemUserPermission>()
                  .eq(SystemUserPermission::getSystemUserId, systemUser.getId()));
  
          for (UserPermissionRequestVO permission : permissions) {
              SystemUserPermission systemUserPermission = new SystemUserPermission();
              systemUserPermission.setSystemUserId(systemUser.getId());
              systemUserPermission.setGroupName(permission.getGroupName());
              systemUserPermission.setNamespaceId(permission.getNamespaceId());
              Assert.isTrue(1 == systemUserPermissionMapper.insert(systemUserPermission),
                      () -> new SnailJobServerException("Failed to update user permissions"));
          }
      }
  
      @Override
      public PageResult<List<SystemUserResponseVO>> getSystemUserPageList(SystemUserQueryVO queryVO) {
          PageDTO<SystemUser> userPageDTO = new PageDTO<>(queryVO.getPage(), queryVO.getSize());
          userPageDTO = systemUserMapper.selectPage(userPageDTO,
                  Wrappers.<SystemUser>lambdaQuery()
                          .likeRight(StrUtil.isNotBlank(queryVO.getUsername()), SystemUser::getUsername, queryVO.getUsername())
                          .orderByDesc(SystemUser::getId));
  
          if (CollUtil.isEmpty(userPageDTO.getRecords())) {
              return new PageResult<>(userPageDTO, Collections.emptyList());
          }
  
          List<SystemUserResponseVO> userResponseVOList = SystemUserResponseVOConverter.INSTANCE.convertList(
                  userPageDTO.getRecords());
          List<SystemUserPermission> userPermissions = systemUserPermissionMapper.selectList(
                  Wrappers.<SystemUserPermission>lambdaQuery()
                          .in(SystemUserPermission::getSystemUserId,
                                  StreamUtils.toSet(userResponseVOList, SystemUserResponseVO::getId)));
  
          Set<String> uniqueIds = StreamUtils.toSet(userPermissions, SystemUserPermission::getNamespaceId);
  
          List<Namespace> namespaces = Lists.newArrayList();
          if (CollUtil.isNotEmpty(uniqueIds)) {
              namespaces = namespaceMapper.selectList(Wrappers.<Namespace>lambdaQuery()
                      .select(Namespace::getId, Namespace::getUniqueId, Namespace::getName)
                      .in(Namespace::getUniqueId, uniqueIds));
          }
  
          Map<String, String> namespaceMap = StreamUtils.toMap(namespaces, Namespace::getUniqueId, Namespace::getName);
  
          Map<Long, List<SystemUserPermission>> userPermissionsMap = StreamUtils.groupByKey(userPermissions, SystemUserPermission::getSystemUserId);
          userResponseVOList.stream()
                  .filter(systemUserResponseVO -> systemUserResponseVO.getRole().equals(RoleEnum.USER.getRoleId()))
                  .forEach(systemUserResponseVO -> {
                      List<SystemUserPermission> userPermissions1 = userPermissionsMap.getOrDefault(systemUserResponseVO.getId(), Lists.newArrayList());
  
                      List<PermissionsResponseVO> permissionsResponseVOS = Lists.newArrayList();
                      for (SystemUserPermission systemUserPermission : userPermissions1) {
                          PermissionsResponseVO responseVO = new PermissionsResponseVO();
                          responseVO.setGroupName(systemUserPermission.getGroupName());
                          responseVO.setNamespaceId(systemUserPermission.getNamespaceId());
                          responseVO.setNamespaceName(namespaceMap.get(systemUserPermission.getNamespaceId()));
                          permissionsResponseVOS.add(responseVO);
                      }
  
                      systemUserResponseVO.setPermissions(permissionsResponseVOS);
                  });
  
          return new PageResult<>(userPageDTO, userResponseVOList);
      }
  
      @Override
      public SystemUserResponseVO getSystemUserByUserName(String username) {
          SystemUser systemUser = systemUserMapper.selectOne(
                  new LambdaQueryWrapper<SystemUser>().eq(SystemUser::getUsername, username));
          if (Objects.isNull(systemUser)) {
              throw new SnailJobServerException("User does not exist");
          }
  
          SystemUserResponseVO responseVO = SystemUserResponseVOConverter.INSTANCE.convert(systemUser);
          getPermission(systemUser.getRole(), systemUser.getId(), responseVO);
  
          List<SystemUserPermission> systemUserPermissions = systemUserPermissionMapper.selectList(
                  new LambdaQueryWrapper<SystemUserPermission>()
                          .select(SystemUserPermission::getNamespaceId, SystemUserPermission::getGroupName)
                          .eq(SystemUserPermission::getSystemUserId, responseVO.getId()));
          responseVO.setPermissions(PermissionsResponseVOConverter.INSTANCE.convertList(systemUserPermissions));
  
  
          return responseVO;
      }
  
      @Override
      public List<PermissionsResponseVO> getSystemUserPermissionByUserName(Long id) {
  
          List<SystemUserPermission> systemUserPermissions = systemUserPermissionMapper.selectList(
                  new LambdaQueryWrapper<SystemUserPermission>()
                          .select(SystemUserPermission::getNamespaceId, SystemUserPermission::getGroupName)
                          .eq(SystemUserPermission::getSystemUserId, id));
  
          if (CollUtil.isEmpty(systemUserPermissions)) {
              return Lists.newArrayList();
          }
  
          Map<String, List<SystemUserPermission>> permissionsMap = StreamUtils.groupByKey(
                  systemUserPermissions, SystemUserPermission::getNamespaceId);
  
          List<Namespace> namespaces = namespaceMapper.selectList(new LambdaQueryWrapper<Namespace>()
                  .select(Namespace::getId, Namespace::getUniqueId, Namespace::getName)
                  .in(Namespace::getUniqueId, permissionsMap.keySet()));
          Map<String, String> map = StreamUtils.toMap(namespaces, Namespace::getUniqueId, Namespace::getName);
  
          List<PermissionsResponseVO> response = new ArrayList<>();
          permissionsMap.forEach((namespaceId, values) -> {
              PermissionsResponseVO responseVO = new PermissionsResponseVO();
              responseVO.setNamespaceName(map.get(namespaceId));
              responseVO.setNamespaceId(namespaceId);
              responseVO.setGroupNames(StreamUtils.toSet(values, SystemUserPermission::getGroupName));
              response.add(responseVO);
          });
  
          return response;
      }
  
      @Override
      public void updateUserPassword(SystemUpdateUserPasswordRequestVO requestVO) {
          Long userId = UserSessionUtils.currentUserSession().getId();
          SystemUser systemUser = systemUserMapper.selectOne(
                  new LambdaQueryWrapper<SystemUser>().eq(SystemUser::getId, userId));
          if (Objects.isNull(systemUser)) {
              throw new SnailJobServerException("User does not exist");
          }
          if (!SecureUtil.sha256(requestVO.getOldPassword()).equals(systemUser.getPassword())) {
              throw new SnailJobServerException("Incorrect original user password");
          }
          systemUser.setPassword(SecureUtil.sha256(requestVO.getNewPassword()));
          Assert.isTrue(1 == systemUserMapper.updateById(systemUser), () -> new SnailJobServerException("Failed to update user password"));
      }
  
      @Override
      public List<SystemUserResponseVO> getSystemUserList() {
          List<SystemUser> systemUsers = systemUserMapper.selectList(new LambdaQueryWrapper<SystemUser>().select(SystemUser::getId, SystemUser::getUsername));
          return SystemUserResponseVOConverter.INSTANCE.convertList(systemUsers);
      }
  
      @Override
      @Transactional
      public boolean delUser(final Long id) {
          systemUserPermissionMapper.delete(
                  new LambdaQueryWrapper<SystemUserPermission>()
                          .eq(SystemUserPermission::getSystemUserId, id)
          );
          return 1 == systemUserMapper.deleteById(id);
      }
  
      /**
       * 生成Token
       */
      private String getToken(SystemUser systemUser) {
          String sign = systemUser.getPassword();
          return JWT.create().withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_TIME))
                  .withAudience(JsonUtil.toJsonString(SystemUserResponseVOConverter.INSTANCE.convert(systemUser)))
                  .sign(Algorithm.HMAC256(sign));
      }
  }
  