diff --git a/tone-page-server/src/admin/admin.module.ts b/tone-page-server/src/admin/admin.module.ts index b25f99a..0fce98f 100644 --- a/tone-page-server/src/admin/admin.module.ts +++ b/tone-page-server/src/admin/admin.module.ts @@ -4,12 +4,14 @@ import { AdminUserController } from './controller/admin-user.controller'; import { AdminUserService } from './service/admin-user.service'; import { TypeOrmModule } from '@nestjs/typeorm'; import { User } from 'src/user/entities/user.entity'; +import { UserModule } from 'src/user/user.module'; @Module({ imports: [ TypeOrmModule.forFeature([ User, - ]) + ]), + UserModule, ], controllers: [ AdminController, diff --git a/tone-page-server/src/admin/controller/admin-user.controller.ts b/tone-page-server/src/admin/controller/admin-user.controller.ts index bea4368..4883258 100644 --- a/tone-page-server/src/admin/controller/admin-user.controller.ts +++ b/tone-page-server/src/admin/controller/admin-user.controller.ts @@ -1,12 +1,17 @@ -import { Controller, Get, Query } from "@nestjs/common"; +import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Post, Put, Query } from "@nestjs/common"; import { AdminUserService } from "../service/admin-user.service"; import { ListDto } from "../dto/admin-user/list.dto"; +import { CreateDto } from "../dto/admin-user/create.dto"; +import { UserService } from "src/user/user.service"; +import { UpdateDto } from "../dto/admin-user/update.dto"; +import { UpdatePasswordDto } from "../dto/admin-user/update-password.dto"; @Controller('admin/user') export class AdminUserController { constructor( private readonly adminUserService: AdminUserService, + private readonly userService: UserService, ) { } @Get() @@ -15,4 +20,34 @@ export class AdminUserController { ) { return this.adminUserService.getUser(listDto.page, listDto.pageSize); } + + @Post() + async create( + @Body() createDto: CreateDto + ) { + return this.userService.create(createDto); + } + + @Put(':userId') + async update( + @Param('userId', new ParseUUIDPipe({ version: '4' })) userId: string, + @Body() updateDto: UpdateDto, + ) { + return this.userService.update(userId, updateDto); + } + + @Delete(':userId') + async delete( + @Param('userId', new ParseUUIDPipe({ version: '4' })) userId: string, + ) { + return this.userService.delete(userId); + } + + @Post(':userId/password') + async setPassword( + @Param('userId', new ParseUUIDPipe({ version: '4' })) userId: string, + @Body() updatePasswordDto: UpdatePasswordDto, + ) { + return this.userService.setPassword(userId, updatePasswordDto.password); + } } \ No newline at end of file diff --git a/tone-page-server/src/admin/dto/admin-user/create.dto.ts b/tone-page-server/src/admin/dto/admin-user/create.dto.ts new file mode 100644 index 0000000..94a0b10 --- /dev/null +++ b/tone-page-server/src/admin/dto/admin-user/create.dto.ts @@ -0,0 +1,23 @@ +import { IsOptional, IsString } from "class-validator"; + +export class CreateDto { + @IsOptional() + @IsString() + username?: string; + + @IsOptional() + @IsString() + nickname?: string; + + @IsOptional() + @IsString() + email?: string; + + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + avatar?: string; +} \ No newline at end of file diff --git a/tone-page-server/src/admin/dto/admin-user/update-password.dto.ts b/tone-page-server/src/admin/dto/admin-user/update-password.dto.ts new file mode 100644 index 0000000..2fac29c --- /dev/null +++ b/tone-page-server/src/admin/dto/admin-user/update-password.dto.ts @@ -0,0 +1,8 @@ +import { IsString, Length, Matches } from "class-validator"; + +export class UpdatePasswordDto { + @IsString() + @Length(6, 32) + @Matches(/^(?=.*[a-zA-Z])(?=.*\d)[a-zA-Z\d!@#$%^&*()_+\-=\[\]{};:'",.<>/?]{6,32}$/) + password: string; +} \ No newline at end of file diff --git a/tone-page-server/src/admin/dto/admin-user/update.dto.ts b/tone-page-server/src/admin/dto/admin-user/update.dto.ts new file mode 100644 index 0000000..849ceaa --- /dev/null +++ b/tone-page-server/src/admin/dto/admin-user/update.dto.ts @@ -0,0 +1,23 @@ +import { IsOptional, IsString } from "class-validator"; + +export class UpdateDto { + @IsOptional() + @IsString() + username?: string; + + @IsOptional() + @IsString() + nickname?: string; + + @IsOptional() + @IsString() + email?: string; + + @IsOptional() + @IsString() + phone?: string; + + @IsOptional() + @IsString() + avatar?: string; +} \ No newline at end of file diff --git a/tone-page-server/src/user/user.service.ts b/tone-page-server/src/user/user.service.ts index adbda50..0bf6358 100644 --- a/tone-page-server/src/user/user.service.ts +++ b/tone-page-server/src/user/user.service.ts @@ -1,7 +1,9 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { User } from './entities/user.entity'; import { Repository } from 'typeorm'; +import { createHash } from 'crypto'; +import { v4 as uuid } from 'uuid'; type UserFindOptions = Partial>; @@ -23,4 +25,40 @@ export class UserService { const newUser = this.userRepository.create(user); return this.userRepository.save(newUser); } + + async update(userId: string, user: Partial): Promise { + const existingUser = await this.userRepository.findOne({ where: { userId } }); + if (!existingUser) { + throw new BadRequestException('User not found'); + } + Object.assign(existingUser, user); + return this.userRepository.save(existingUser); + } + + async delete(userId: string): Promise { + const existingUser = await this.userRepository.findOne({ where: { userId } }); + if (!existingUser) { + throw new BadRequestException('User not found'); + } + await this.userRepository.softDelete(existingUser.id); + } + + hashPassword(password: string, salt: string): string { + return createHash('sha256').update(`${password}${salt}`).digest('hex'); + } + + generateSalt(): string { + return uuid().replace(/-/g, ''); + } + + async setPassword(userId: string, password: string): Promise { + const user = await this.userRepository.findOne({ where: { userId } }); + if (!user) { + throw new BadRequestException('User not found'); + } + const salt = this.generateSalt(); + user.password_hash = this.hashPassword(password, salt); + user.salt = salt; + return this.userRepository.save(user); + } }