NestJS实战-用户服务

3 阅读2分钟

用户服务 UserService

数据库的操作主要是在 Service 里做,UserService 主要是给 UserController 提供服务,也可以提供给其他模块调用:

import {
  BadRequestException,
  Injectable,
  InternalServerErrorException,
  Logger,
  Req,
} from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Like, Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { Role } from './entities/role.entity';
import { ListUserDto } from './dto/list-user.dto';
import { ResetPasswordDto } from './dto/reset-password.dto';
import {
  removeUnnecessaryData,
  setCreatedUser,
  setDeletedUser,
  setUpdatedUser,
} from 'src/utils';
import { UpdatePasswordDto } from './dto/update-password.dto';

@Injectable()
export class UserService {
  private logger = new Logger('UserService');
  constructor(
    @InjectRepository(User) private readonly userRepository: Repository<User>,
    @InjectRepository(Role) private readonly roleRepository: Repository<Role>,
  ) {}

  // 获取用户权限列表
  roleList() {
    return this.roleRepository.find();
  }

  async findRoleById(id: number): Promise<Role> {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    return await this.roleRepository.findOne({
      where: { id },
    });
  }

  async create(createUserDto: CreateUserDto, @Req() req) {
    this.logger.log('@@@@ 创建用户参数:', createUserDto);
    // 检查roleId是否存在
    const role = await this.findRoleById(createUserDto.roleId || 4);
    if (!role) {
      this.logger.warn(`id为${createUserDto.roleId}的角色没有找到`);
      throw new BadRequestException(
        `id为${createUserDto.roleId}的角色没有找到`,
      );
    }

    // 检查account是否已存在
    const account = await this.userRepository.findOne({
      where: { account: createUserDto.account },
    });

    if (account) {
      this.logger.warn(`账号${createUserDto.account}已存在,不能重复创建`);
      throw new BadRequestException(
        `账号${createUserDto.account}已存在,不能重复创建`,
      );
    }

    // 创建用户实体
    const user = this.userRepository.create(createUserDto);
    user.roleType = role.type;
    user.roleWeight = role.weight;
    user.roleName = role.name;

    // 设置密码哈希
    const passwordHash: string = await user.setPasswordHash(
      createUserDto.password,
    );
    user.passwordHash = passwordHash;

    const createdUser = setCreatedUser(req, user);

    this.logger.log('@@@@ 创建用户实体 createdUser', createdUser);

    try {
      return await this.userRepository.save(createdUser);
    } catch (error) {
      this.logger.error('@@@@ 新建账号失败:', error);
      throw new InternalServerErrorException('新建账号失败');
    }
  }

  async findAll(query: ListUserDto) {
    try {
      const queryParams = {
        account: query?.account || null,
        username: query.username ? Like(`%${query.username}%`) : null,
        roleId: query?.roleId || null,
        isDeleted: 0,
      };
      const data = await this.userRepository.find({
        where: queryParams,
      });

      return removeUnnecessaryData(data);
    } catch (error) {
      this.logger.error('@@@@ 账号列表查询失败:', error);
      throw new InternalServerErrorException('账号列表查询失败');
    }
  }

  async findAllByPage(query: ListUserDto) {
    try {
      const queryParams = {
        id: query?.id || null,
        account: query?.account ? Like(`%${query.account}%`) : null,
        username: query.username ? Like(`%${query.username}%`) : null,
        roleId: query?.roleId || null,
        isDeleted: 0,
      };
      const [data, total] = await this.userRepository.findAndCount({
        where: queryParams,
        order: {
          id: 'DESC',
        },
        skip: (query.pageNum - 1) * query.pageSize,
        take: query.pageSize,
      });

      return {
        list: removeUnnecessaryData(data),
        pageNum: Number(query.pageNum),
        pageSize: Number(query.pageSize),
        total,
      };
    } catch (error) {
      this.logger.error('@@@@ 账号列表查询失败:', error);
      throw new InternalServerErrorException('账号列表查询失败');
    }
  }

  async findOne(id: number) {
    if (!id) {
      throw new BadRequestException('id必填');
    }
    try {
      const data = await this.userRepository.findOne({
        where: { id, isDeleted: 0 },
      });
      delete data.passwordHash;
      delete data.isDeleted;
      return data;
    } catch (error) {
      this.logger.error('@@@@ 账号查询失败:', error);
      throw new InternalServerErrorException('账号查询失败');
    }
  }

  async findByIds(ids: number[]): Promise<User[]> {
    try {
      const data = await this.userRepository.find({
        where: { id: In(ids), isDeleted: 0 },
      });
      return removeUnnecessaryData(data);
    } catch (error) {
      this.logger.error('@@@@ 账号批量查询失败:', error);
      throw new InternalServerErrorException('账号批量查询失败');
    }
  }

  // 更新用户
  async update(id: number, updateUserDto: UpdateUserDto, @Req() req) {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    const user = await this.userRepository.findOneBy({
      id,
    });

    if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
      throw new BadRequestException(
        `当前角色权限过低,无法对${user.account}进行该操作`,
      );
    }

    const role = await this.roleRepository.findOneBy({
      id: updateUserDto.roleId,
    });
    user.roleType = role.type;
    user.roleWeight = role.weight;
    user.roleName = role.name;

    try {
      // 设置更新用户信息
      const updatedUser = setUpdatedUser(req, user);

      this.logger.log('@@@ 更新用户 updatedUser', updatedUser);

      return await this.userRepository.update(id, updatedUser);
    } catch (error) {
      this.logger.error('@@@@ 更新账号失败:', error);
      throw new InternalServerErrorException('更新账号失败');
    }
  }

  // 重置登录密码
  async resetPassword(body: ResetPasswordDto, @Req() req) {
    const user = await this.userRepository.findOneBy({
      id: body.id,
    });

    if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
      throw new BadRequestException(
        `当前角色权限过低,无法对${user.account}进行该操作`,
      );
    }

    if (body.confirmPassword !== body.newPassword) {
      throw new BadRequestException('新密码与确认密码不一致');
    }

    try {
      // 设置密码哈希
      const passwordHash: string = await user.setPasswordHash(body.newPassword);
      user.passwordHash = passwordHash;
      // 设置更新用户信息
      const updatedUser = setUpdatedUser(req, user);

      this.logger.log('@@@ 重置登录密码 updatedUser', updatedUser);

      return await this.userRepository.update(body.id, updatedUser);
    } catch (error) {
      this.logger.error('@@@@ 更新密码失败:', error);
      throw new InternalServerErrorException('更新密码失败');
    }
  }

  // 更新密码
  async userUpdatePassword(body: UpdatePasswordDto, @Req() req) {
    // 旧密码和新密码比较
    if (body.oldPassword === body.newPassword) {
      throw new BadRequestException('旧密码不能和新密码相同');
    }

    // 新密码和确认密码比较
    if (body.confirmPassword !== body.newPassword) {
      throw new BadRequestException('新密码与确认密码不一致');
    }

    // 调用数据库验证用户旧密码
    const user: User = await this.userRepository.findOneBy({
      id: req.user.userId,
    });
    const isPassword = await user.validatePassword(body.oldPassword);
    if (!isPassword) {
      throw new BadRequestException('旧密码错误,请确认后重新输入');
    }

    try {
      this.logger.log('@@@@ 修改账户密码 body', body);
      // 修改账户密码
      const passwordHash: string = await user.setPasswordHash(body.newPassword);
      user.passwordHash = passwordHash;
      // 设置更新用户信息
      const updatedUser = setUpdatedUser(req, user);

      return await this.userRepository.update(user.id, updatedUser);
    } catch (error) {
      this.logger.error('@@@@ 修改账户密码失败:', error);
      throw new InternalServerErrorException('修改账户密码失败');
    }
  }

  // 软删除单个用户
  async softDeleteUser(id: number, @Req() req) {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    const user = await this.userRepository.findOneBy({
      id,
    });

    if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
      throw new BadRequestException(
        `当前角色权限过低,无法对${user.account}进行该操作`,
      );
    }

    try {
      const removedUser = setDeletedUser(req, user);

      this.logger.log('@@@ 软删除单个用户 removedUser', removedUser);

      return await this.userRepository.update(id, removedUser);
    } catch (error) {
      this.logger.error('@@@@ 删除账号失败:', error);
      throw new InternalServerErrorException('删除账号失败');
    }
  }

  // 软删除批量用户
  async softDeleteUsers(ids: number[], @Req() req) {
    for (const id of ids) {
      const user = await this.userRepository.findOneBy({
        id,
      });

      if (req.user.roleWeight >= user.roleWeight && req.user.roleWeight !== 0) {
        throw new BadRequestException(
          `当前角色权限过低,无法对${user.account}进行该操作`,
        );
        break;
      }
    }

    try {
      const user = new User();
      const removedUser = setDeletedUser(req, user);

      this.logger.log('@@@ 软删除批量用户 removedUser', removedUser);

      return await this.userRepository.update(ids, removedUser);
    } catch (error) {
      this.logger.error('@@@@ 批量删除账号失败:', error);
      throw new InternalServerErrorException('批量删除账号失败');
    }
  }
}

用户模型 UserModule

import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';
import { Role } from './entities/role.entity';
import { ExcelModule } from 'src/common/excel/excel.module';
import { MetricsService } from 'src/common/metrics/metrics.service';

@Module({
  imports: [TypeOrmModule.forFeature([User, Role]), ExcelModule],
  controllers: [UserController],
  providers: [UserService, MetricsService],
  exports: [UserService], // 导出UserService以便其他模块可以使用
})
export class UserModule {}