chrore: Integrate Class CRUD & Service
refactor: user CRUD & Service
This commit is contained in:
parent
238b01f5f3
commit
161b01d8cb
@ -35,7 +35,7 @@ model UserMessage {
|
|||||||
|
|
||||||
model Class {
|
model Class {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
name String
|
name String @unique
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
ClassRoom Room[]
|
ClassRoom Room[]
|
||||||
@ -96,4 +96,4 @@ model RoomSurveyAnswerUser {
|
|||||||
enum Role {
|
enum Role {
|
||||||
STUDENT
|
STUDENT
|
||||||
ADMIN
|
ADMIN
|
||||||
}
|
}
|
||||||
|
9
src/ApiResponses/UnauthorizedResponse.ts
Normal file
9
src/ApiResponses/UnauthorizedResponse.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { ApiResponseNoStatusOptions } from "@nestjs/swagger";
|
||||||
|
|
||||||
|
export const UnauthorizedResponse = {
|
||||||
|
description: "Unauthorized",
|
||||||
|
example: {
|
||||||
|
message: "Unauthorized",
|
||||||
|
statusCode: 401,
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
@ -13,29 +13,33 @@ export class RolesGuard implements CanActivate {
|
|||||||
constructor(private readonly reflector: Reflector) {}
|
constructor(private readonly reflector: Reflector) {}
|
||||||
|
|
||||||
canActivate(context: ExecutionContext): boolean {
|
canActivate(context: ExecutionContext): boolean {
|
||||||
const Roles = this.reflector.get<string[]>(
|
const RolesHandler = this.reflector.get<string[]>(
|
||||||
"roles",
|
"roles",
|
||||||
context.getHandler(),
|
context.getHandler(),
|
||||||
);
|
);
|
||||||
if (!Roles) {
|
const RolesClass = this.reflector.get<string[]>(
|
||||||
return true;
|
"roles",
|
||||||
}
|
context.getClass(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!RolesHandler && !RolesClass) return true;
|
||||||
|
|
||||||
const request = context.switchToHttp().getRequest() as Request;
|
const request = context.switchToHttp().getRequest() as Request;
|
||||||
const user = request.user;
|
const user = request.user;
|
||||||
|
|
||||||
if (!user) {
|
if (!user) throw new ForbiddenException("User not authenticated");
|
||||||
throw new ForbiddenException("User not authenticated");
|
|
||||||
}
|
|
||||||
|
|
||||||
const hasRole = Roles.some((role) => user.role?.includes(role));
|
const hasRoleHandler =
|
||||||
|
RolesHandler?.some((role) => user.role?.includes(role)) ??
|
||||||
|
false,
|
||||||
|
hasRoleClass =
|
||||||
|
RolesClass?.some((role) => user.role?.includes(role)) ?? false;
|
||||||
|
|
||||||
if (!hasRole) {
|
if (hasRoleHandler) return true;
|
||||||
|
else if (hasRoleClass) return true;
|
||||||
|
else
|
||||||
throw new UnauthorizedException(
|
throw new UnauthorizedException(
|
||||||
`You need to have the role ${Roles.map((role) => role).join(" or ")}`,
|
`User doesn't have the right role, expected: ${RolesHandler ?? RolesClass}`,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ export class JWTStrategy extends PassportStrategy(Strategy, "jwt") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: JwtPayload): Promise<User> {
|
async validate(payload: JwtPayload): Promise<User> {
|
||||||
const user = await this.userService.findById(payload.id);
|
const user = await this.userService.findOne(payload.id);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new UnauthorizedException("User not found");
|
throw new UnauthorizedException("User not found");
|
||||||
|
@ -56,9 +56,7 @@ export class Oauth2Strategy extends PassportStrategy(Strategy, "oauth2") {
|
|||||||
_refreshToken: string,
|
_refreshToken: string,
|
||||||
profile: Oauth2Profile,
|
profile: Oauth2Profile,
|
||||||
): Promise<{ accessToken: string; refreshToken: string }> {
|
): Promise<{ accessToken: string; refreshToken: string }> {
|
||||||
const user = await this.userSerivce.findOne({
|
const user = await this.userSerivce.findByProviderId(profile.sub ?? profile.id);
|
||||||
providerId: profile.sub ?? profile.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (!user) throw new UnauthorizedException("User not found");
|
if (!user) throw new UnauthorizedException("User not found");
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ export class RefreshJWTStrategy extends PassportStrategy(Strategy, "refresh") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async validate(payload: JwtPayload): Promise<User> {
|
async validate(payload: JwtPayload): Promise<User> {
|
||||||
const user = await this.userService.findById(payload.id);
|
const user = await this.userService.findOne(payload.id);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
throw new UnauthorizedException("User not found");
|
throw new UnauthorizedException("User not found");
|
||||||
|
40
src/modules/class/ApiResponses/ClassResponse.ts
Normal file
40
src/modules/class/ApiResponses/ClassResponse.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import { ApiResponseNoStatusOptions } from "@nestjs/swagger";
|
||||||
|
import { ClassEntity } from "../entities/class.entity";
|
||||||
|
|
||||||
|
export const ClassResponse = {
|
||||||
|
type: ClassEntity,
|
||||||
|
examples: {
|
||||||
|
example: {
|
||||||
|
summary: "A class",
|
||||||
|
value: {
|
||||||
|
id: "1",
|
||||||
|
name: "Sigyn",
|
||||||
|
createdAt: new Date(),
|
||||||
|
} as ClassEntity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
||||||
|
|
||||||
|
export const ClassesResponse = {
|
||||||
|
type: ClassEntity,
|
||||||
|
isArray: true,
|
||||||
|
examples: {
|
||||||
|
example: {
|
||||||
|
summary: "A list of classes",
|
||||||
|
value: [
|
||||||
|
{ id: "1", name: "Sigyn", createdAt: new Date() },
|
||||||
|
{ id: "2", name: "Loki", createdAt: new Date() },
|
||||||
|
] as ClassEntity[],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
||||||
|
|
||||||
|
export const ClassCountResponse = {
|
||||||
|
description: "The class count",
|
||||||
|
examples: {
|
||||||
|
example: {
|
||||||
|
summary: "A count of classes",
|
||||||
|
value: { count: 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
@ -1,42 +1,95 @@
|
|||||||
|
import { UnauthorizedResponse } from "@/ApiResponses/UnauthorizedResponse";
|
||||||
import {
|
import {
|
||||||
Controller,
|
|
||||||
Get,
|
|
||||||
Post,
|
|
||||||
Body,
|
Body,
|
||||||
Patch,
|
Controller,
|
||||||
Param,
|
|
||||||
Delete,
|
Delete,
|
||||||
|
Get,
|
||||||
|
Param,
|
||||||
|
Patch,
|
||||||
|
Post,
|
||||||
|
Query,
|
||||||
|
UseGuards,
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
|
import {
|
||||||
|
ClassCountResponse,
|
||||||
|
ClassesResponse,
|
||||||
|
ClassResponse,
|
||||||
|
} from "./ApiResponses/ClassResponse";
|
||||||
import { ClassService } from "./class.service";
|
import { ClassService } from "./class.service";
|
||||||
|
|
||||||
import { CreateClassDto } from "./dto/create-class.dto";
|
import { CreateClassDto } from "./dto/create-class.dto";
|
||||||
import { UpdateClassDto } from "./dto/update-class.dto";
|
import { UpdateClassDto } from "./dto/update-class.dto";
|
||||||
|
|
||||||
|
import { Roles } from "@/modules/auth/decorators/roles.decorator";
|
||||||
|
import { JwtAuthGuard } from "@/modules/auth/guards/jwt.guard";
|
||||||
|
import { RolesGuard } from "@/modules/auth/guards/role.guard";
|
||||||
|
import {
|
||||||
|
ApiBearerAuth,
|
||||||
|
ApiOkResponse,
|
||||||
|
ApiQuery,
|
||||||
|
ApiUnauthorizedResponse,
|
||||||
|
} from "@nestjs/swagger";
|
||||||
|
import { ClassEntity } from "./entities/class.entity";
|
||||||
|
|
||||||
@Controller("class")
|
@Controller("class")
|
||||||
|
@UseGuards(RolesGuard)
|
||||||
|
@UseGuards(JwtAuthGuard)
|
||||||
|
@ApiBearerAuth()
|
||||||
|
@Roles(["ADMIN"])
|
||||||
|
@ApiUnauthorizedResponse(UnauthorizedResponse)
|
||||||
export class ClassController {
|
export class ClassController {
|
||||||
constructor(private readonly classService: ClassService) {}
|
constructor(private readonly classService: ClassService) {}
|
||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
create(@Body() createClassDto: CreateClassDto) {
|
@ApiOkResponse(ClassResponse)
|
||||||
return this.classService.create(createClassDto);
|
async create(@Body() createClassDto: CreateClassDto) {
|
||||||
|
return await this.classService.create(createClassDto).then((class_) => {
|
||||||
|
return new ClassEntity(class_);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get()
|
@Get()
|
||||||
findAll() {
|
@ApiOkResponse(ClassesResponse)
|
||||||
return this.classService.findAll();
|
async findAll() {
|
||||||
|
return await this.classService
|
||||||
|
.findAll({})
|
||||||
|
.then((classes) =>
|
||||||
|
classes.map((class_) => new ClassEntity(class_)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get(":id")
|
@Get(":id")
|
||||||
findOne(@Param("id") id: string) {
|
@ApiOkResponse(ClassResponse)
|
||||||
return this.classService.findOne(+id);
|
async findOne(@Param("id") id: string) {
|
||||||
|
return await this.classService
|
||||||
|
.findOne(id)
|
||||||
|
.then((class_) => new ClassEntity(class_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Patch(":id")
|
@Patch(":id")
|
||||||
update(@Param("id") id: string, @Body() updateClassDto: UpdateClassDto) {
|
@ApiOkResponse(ClassResponse)
|
||||||
return this.classService.update(+id, updateClassDto);
|
async update(
|
||||||
|
@Param("id") id: string,
|
||||||
|
@Body() updateClassDto: UpdateClassDto,
|
||||||
|
) {
|
||||||
|
return await this.classService
|
||||||
|
.update(id, updateClassDto)
|
||||||
|
.then((class_) => new ClassEntity(class_));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete(":id")
|
@Delete(":id")
|
||||||
remove(@Param("id") id: string) {
|
@ApiOkResponse(ClassResponse)
|
||||||
return this.classService.remove(+id);
|
async remove(@Param("id") id: string) {
|
||||||
|
return await this.classService
|
||||||
|
.remove(id)
|
||||||
|
.then((class_) => new ClassEntity(class_));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Delete()
|
||||||
|
@ApiOkResponse(ClassCountResponse)
|
||||||
|
@ApiQuery({ name: "ids", required: true, type: [String] })
|
||||||
|
async bulkRemove(@Query("ids") ids: string | string[]) {
|
||||||
|
if (typeof ids === "string") ids = [ids];
|
||||||
|
return await this.classService.bulkRemove(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ import { Injectable } from "@nestjs/common";
|
|||||||
import { CreateClassDto } from "./dto/create-class.dto";
|
import { CreateClassDto } from "./dto/create-class.dto";
|
||||||
import { UpdateClassDto } from "./dto/update-class.dto";
|
import { UpdateClassDto } from "./dto/update-class.dto";
|
||||||
import { PrismaService } from "nestjs-prisma";
|
import { PrismaService } from "nestjs-prisma";
|
||||||
|
import { Prisma } from "@prisma/client";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ClassService {
|
export class ClassService {
|
||||||
@ -11,12 +12,30 @@ export class ClassService {
|
|||||||
return await this.prisma.class.create({ data: createClassDto });
|
return await this.prisma.class.create({ data: createClassDto });
|
||||||
}
|
}
|
||||||
|
|
||||||
async findAll({ name }: { name: string }) {
|
async findAll({
|
||||||
return await this.prisma.class.create({ data: { name } });
|
skip,
|
||||||
|
take,
|
||||||
|
cursor,
|
||||||
|
where,
|
||||||
|
orderBy,
|
||||||
|
}: {
|
||||||
|
skip?: number;
|
||||||
|
take?: number;
|
||||||
|
cursor?: Prisma.ClassWhereUniqueInput;
|
||||||
|
where?: Prisma.ClassWhereInput;
|
||||||
|
orderBy?: Record<string, unknown>;
|
||||||
|
}) {
|
||||||
|
return await this.prisma.class.findMany({
|
||||||
|
skip,
|
||||||
|
take,
|
||||||
|
cursor,
|
||||||
|
where,
|
||||||
|
orderBy,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(id: string) {
|
async findOne(id: string) {
|
||||||
return await this.prisma.class.findUnique({ where: { id } });
|
return await this.prisma.class.findUniqueOrThrow({ where: { id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(id: string, updateClassDto: UpdateClassDto) {
|
async update(id: string, updateClassDto: UpdateClassDto) {
|
||||||
@ -29,4 +48,10 @@ export class ClassService {
|
|||||||
async remove(id: string) {
|
async remove(id: string) {
|
||||||
return await this.prisma.class.delete({ where: { id } });
|
return await this.prisma.class.delete({ where: { id } });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async bulkRemove(ids: string[]) {
|
||||||
|
return await this.prisma.class.deleteMany({
|
||||||
|
where: { id: { in: ids } },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsString } from "class-validator";
|
||||||
|
|
||||||
export class CreateClassDto {
|
export class CreateClassDto {
|
||||||
|
@IsString()
|
||||||
|
@ApiProperty()
|
||||||
name: string;
|
name: string;
|
||||||
}
|
}
|
||||||
|
41
src/modules/user/ApiResponses/UserReponse.ts
Normal file
41
src/modules/user/ApiResponses/UserReponse.ts
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import { ApiResponseNoStatusOptions } from "@nestjs/swagger";
|
||||||
|
import { UserEntity } from "../entities/user.entity";
|
||||||
|
|
||||||
|
export const UserResponse = {
|
||||||
|
type: UserEntity,
|
||||||
|
description: "The user has been successfully found.",
|
||||||
|
examples: {
|
||||||
|
example: {
|
||||||
|
summary: "A user example",
|
||||||
|
value: {
|
||||||
|
id: "1",
|
||||||
|
role: "ADMIN",
|
||||||
|
username: "admin",
|
||||||
|
} as UserEntity,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
||||||
|
|
||||||
|
export const UsersResponse = {
|
||||||
|
type: UserEntity,
|
||||||
|
isArray: true,
|
||||||
|
examples: {
|
||||||
|
example: {
|
||||||
|
summary: "A list of users",
|
||||||
|
value: [
|
||||||
|
{ id: "1", role: "ADMIN", username: "admin" },
|
||||||
|
{ id: "2", role: "STUDENT", username: "student" },
|
||||||
|
] as UserEntity[],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
||||||
|
|
||||||
|
export const UserCountResponse = {
|
||||||
|
description: "The users count",
|
||||||
|
examples: {
|
||||||
|
example: {
|
||||||
|
summary: "A count of users",
|
||||||
|
value: { count: 2 },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as ApiResponseNoStatusOptions;
|
@ -1,11 +0,0 @@
|
|||||||
import { ApiProperty } from "@nestjs/swagger";
|
|
||||||
import { ArrayMaxSize, ArrayMinSize, IsArray, IsString } from "class-validator";
|
|
||||||
|
|
||||||
export class BulkDeleteUserDTO {
|
|
||||||
@IsArray()
|
|
||||||
@IsString({ each: true })
|
|
||||||
@ArrayMinSize(1)
|
|
||||||
@ArrayMaxSize(10)
|
|
||||||
@ApiProperty()
|
|
||||||
ids: string[];
|
|
||||||
}
|
|
@ -1,12 +1,5 @@
|
|||||||
import { PartialType } from "@nestjs/mapped-types";
|
import { PartialType } from "@nestjs/mapped-types";
|
||||||
import { IsString } from "class-validator";
|
|
||||||
|
|
||||||
import { CreateUserDTO } from "./create-user.dto";
|
import { CreateUserDTO } from "./create-user.dto";
|
||||||
|
|
||||||
export class UpdateUserDTO extends PartialType(CreateUserDTO) {
|
export class UpdateUserDTO extends PartialType(CreateUserDTO) {}
|
||||||
@IsString()
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
@IsString()
|
|
||||||
username: string;
|
|
||||||
}
|
|
||||||
|
@ -1,167 +1,87 @@
|
|||||||
|
import { UnauthorizedResponse } from "@/ApiResponses/UnauthorizedResponse";
|
||||||
|
import { Roles } from "@/modules/auth/decorators/roles.decorator";
|
||||||
|
import { JwtAuthGuard } from "@/modules/auth/guards/jwt.guard";
|
||||||
|
import { RolesGuard } from "@/modules/auth/guards/role.guard";
|
||||||
import {
|
import {
|
||||||
Body,
|
Body,
|
||||||
Controller,
|
Controller,
|
||||||
Delete,
|
Delete,
|
||||||
Get,
|
Get,
|
||||||
Post,
|
Param,
|
||||||
|
Patch,
|
||||||
Query,
|
Query,
|
||||||
UseGuards,
|
UseGuards
|
||||||
} from "@nestjs/common";
|
} from "@nestjs/common";
|
||||||
import {
|
import {
|
||||||
ApiBearerAuth,
|
ApiBearerAuth,
|
||||||
ApiBody,
|
|
||||||
ApiOkResponse,
|
ApiOkResponse,
|
||||||
|
ApiParam,
|
||||||
ApiQuery,
|
ApiQuery,
|
||||||
ApiUnauthorizedResponse,
|
ApiUnauthorizedResponse
|
||||||
} from "@nestjs/swagger";
|
} from "@nestjs/swagger";
|
||||||
|
import {
|
||||||
import { Roles } from "@/modules/auth/decorators/roles.decorator";
|
UserCountResponse,
|
||||||
import { JwtAuthGuard } from "@/modules/auth/guards/jwt.guard";
|
UserResponse,
|
||||||
import { RolesGuard } from "@/modules/auth/guards/role.guard";
|
UsersResponse,
|
||||||
|
} from "./ApiResponses/UserReponse";
|
||||||
import { BulkDeleteUserDTO } from "./dto/bulk-delete-user.dto";
|
import { UpdateUserDTO } from "./dto/update-user.dto";
|
||||||
import { CreateUserDTO } from "./dto/create-user.dto";
|
|
||||||
|
|
||||||
import { UserEntity } from "./entities/user.entity";
|
import { UserEntity } from "./entities/user.entity";
|
||||||
import { UserService } from "./user.service";
|
import { UserService } from "./user.service";
|
||||||
|
|
||||||
@Controller()
|
@Controller("user")
|
||||||
@UseGuards(RolesGuard)
|
@UseGuards(RolesGuard)
|
||||||
@UseGuards(JwtAuthGuard)
|
@UseGuards(JwtAuthGuard)
|
||||||
@ApiBearerAuth()
|
@ApiBearerAuth()
|
||||||
@ApiUnauthorizedResponse({
|
@Roles(["ADMIN"])
|
||||||
description: "Unauthorized",
|
@ApiUnauthorizedResponse(UnauthorizedResponse)
|
||||||
example: {
|
|
||||||
message: "Unauthorized",
|
|
||||||
statusCode: 401,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
export class UserController {
|
export class UserController {
|
||||||
constructor(private readonly userService: UserService) {}
|
constructor(private readonly userService: UserService) {}
|
||||||
|
|
||||||
@Get("users")
|
@Get()
|
||||||
@Roles(["ADMIN"])
|
@ApiOkResponse(UsersResponse)
|
||||||
@ApiOkResponse({
|
|
||||||
type: UserEntity,
|
|
||||||
isArray: true,
|
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A list of users",
|
|
||||||
value: [
|
|
||||||
{ id: "1", role: "ADMIN", username: "admin" },
|
|
||||||
{ id: "2", role: "STUDENT", username: "student" },
|
|
||||||
] as UserEntity[],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
async findAll(): Promise<UserEntity[]> {
|
async findAll(): Promise<UserEntity[]> {
|
||||||
return await this.userService
|
return await this.userService
|
||||||
.findAll()
|
.findAll()
|
||||||
.then((users) => users.map((user) => new UserEntity(user)));
|
.then((users) => users.map((user) => new UserEntity(user)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get("user")
|
@Get(":id")
|
||||||
@Roles(["ADMIN"])
|
@ApiOkResponse(UserResponse)
|
||||||
@ApiOkResponse({
|
async findOne(@Param("id") id: string): Promise<UserEntity> {
|
||||||
type: UserEntity,
|
|
||||||
description: "The user has been successfully found.",
|
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A user example",
|
|
||||||
value: {
|
|
||||||
id: "1",
|
|
||||||
role: "ADMIN",
|
|
||||||
username: "admin",
|
|
||||||
} as UserEntity,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
async findById(@Query("id") id: string): Promise<UserEntity> {
|
|
||||||
return this.userService
|
return this.userService
|
||||||
.findById(id)
|
.findOne(id)
|
||||||
.then((user) => new UserEntity(user));
|
.then((user) => new UserEntity(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Post("user")
|
@Patch(":id")
|
||||||
@Roles(["ADMIN"])
|
async update(
|
||||||
@ApiOkResponse({
|
@Param("id") id: string,
|
||||||
type: UserEntity,
|
@Body() updateUserDto: UpdateUserDTO,
|
||||||
description: "The user has been successfully created.",
|
): Promise<UserEntity> {
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A user example",
|
|
||||||
value: {
|
|
||||||
id: "1",
|
|
||||||
role: "ADMIN",
|
|
||||||
username: "admin",
|
|
||||||
} as UserEntity,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@ApiBody({
|
|
||||||
type: CreateUserDTO,
|
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A user example",
|
|
||||||
value: { username: "admin" },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
async create(@Body() createUserInput: CreateUserDTO): Promise<UserEntity> {
|
|
||||||
return this.userService
|
return this.userService
|
||||||
.create(createUserInput)
|
.update(id, updateUserDto)
|
||||||
.then((user) => new UserEntity(user));
|
.then((user) => new UserEntity(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete("user")
|
@Delete(":id")
|
||||||
@Roles(["ADMIN"])
|
@ApiOkResponse(UserResponse)
|
||||||
@ApiOkResponse({
|
@ApiParam({
|
||||||
type: UserEntity,
|
|
||||||
description: "The user has been successfully deleted.",
|
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A user example",
|
|
||||||
value: {
|
|
||||||
id: "1",
|
|
||||||
role: "ADMIN",
|
|
||||||
username: "admin",
|
|
||||||
} as UserEntity,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@ApiQuery({
|
|
||||||
name: "id",
|
name: "id",
|
||||||
type: String,
|
type: String,
|
||||||
description: "The user id",
|
description: "The user id",
|
||||||
example: "1",
|
example: "1",
|
||||||
})
|
})
|
||||||
async delete(@Query("id") id: string): Promise<UserEntity> {
|
async remove(@Param("id") id: string): Promise<UserEntity> {
|
||||||
return this.userService.delete(id).then((user) => new UserEntity(user));
|
return this.userService.remove(id).then((user) => new UserEntity(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Delete("users")
|
@Delete()
|
||||||
@Roles(["ADMIN"])
|
@ApiOkResponse(UserCountResponse)
|
||||||
@ApiOkResponse({
|
@ApiQuery({ name: "ids", required: true, type: [String] })
|
||||||
description: "The users have been successfully deleted.",
|
bulkRemove(@Query("ids") ids: string | string[]): Promise<{
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A count of deleted users",
|
|
||||||
value: { count: 2 },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@ApiBody({
|
|
||||||
type: BulkDeleteUserDTO,
|
|
||||||
examples: {
|
|
||||||
example: {
|
|
||||||
summary: "A list of user ids",
|
|
||||||
value: { ids: ["1", "2"] },
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
bulkDelete(@Body() { ids }: BulkDeleteUserDTO): Promise<{
|
|
||||||
count: number;
|
count: number;
|
||||||
}> {
|
}> {
|
||||||
return this.userService.bulkDelete(ids);
|
if (typeof ids === "string") ids = [ids];
|
||||||
|
return this.userService.bulkRemove(ids);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ export class UserGateway implements OnGatewayConnection, OnGatewayDisconnect {
|
|||||||
return client.disconnect();
|
return client.disconnect();
|
||||||
}
|
}
|
||||||
|
|
||||||
const user = await this.userService.findById(jwtDecoded.id);
|
const user = await this.userService.findOne(jwtDecoded.id);
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
client.emit("auth", "User not found");
|
client.emit("auth", "User not found");
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Injectable, NotFoundException } from "@nestjs/common";
|
import { Injectable } from "@nestjs/common";
|
||||||
import { Prisma } from "@prisma/client";
|
import { Prisma } from "@prisma/client";
|
||||||
import { PrismaService } from "nestjs-prisma";
|
import { PrismaService } from "nestjs-prisma";
|
||||||
|
|
||||||
@ -10,61 +10,66 @@ export class UserService {
|
|||||||
constructor(private readonly prisma: PrismaService) {}
|
constructor(private readonly prisma: PrismaService) {}
|
||||||
|
|
||||||
async findAll({
|
async findAll({
|
||||||
include,
|
skip,
|
||||||
cursor,
|
|
||||||
take,
|
take,
|
||||||
|
cursor,
|
||||||
|
where,
|
||||||
|
orderBy,
|
||||||
}: {
|
}: {
|
||||||
include?: Prisma.UserInclude;
|
skip?: number;
|
||||||
cursor?: string;
|
|
||||||
take?: number;
|
take?: number;
|
||||||
|
cursor?: Prisma.UserWhereUniqueInput;
|
||||||
|
where?: Prisma.UserWhereInput;
|
||||||
|
orderBy?: Record<string, unknown>;
|
||||||
} = {}) {
|
} = {}) {
|
||||||
return await this.prisma.user.findMany({
|
return await this.prisma.user.findMany({
|
||||||
include,
|
skip,
|
||||||
cursor: cursor ? { id: cursor } : undefined,
|
take,
|
||||||
take: take || 10,
|
cursor,
|
||||||
|
where,
|
||||||
|
orderBy,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async findById(id: string = null) {
|
async findOne(id: string) {
|
||||||
return await this.prisma.user.findUnique({
|
return await this.prisma.user.findUniqueOrThrow({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async findOne(where: Prisma.UserWhereInput) {
|
async findByProviderId(providerId: string) {
|
||||||
return await this.prisma.user.findFirst({
|
return await this.prisma.user.findUniqueOrThrow({
|
||||||
where,
|
where: {
|
||||||
});
|
providerId,
|
||||||
}
|
|
||||||
|
|
||||||
async create(createUserInput: CreateUserDTO) {
|
|
||||||
return await this.prisma.user.create({
|
|
||||||
data: {
|
|
||||||
username: createUserInput.username,
|
|
||||||
providerId: createUserInput.providerId,
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async update(updateUserInput: UpdateUserDTO) {
|
async create(createUserDto: CreateUserDTO) {
|
||||||
|
return await this.prisma.user.create({
|
||||||
|
data: {
|
||||||
|
username: createUserDto.username,
|
||||||
|
providerId: createUserDto.providerId,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, updateUserInput: UpdateUserDTO) {
|
||||||
return await this.prisma.user.update({
|
return await this.prisma.user.update({
|
||||||
where: { id: updateUserInput.id },
|
where: { id },
|
||||||
data: {
|
data: {
|
||||||
username: updateUserInput.username,
|
username: updateUserInput.username,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async delete(id: string) {
|
async remove(id: string) {
|
||||||
const exist = await this.prisma.user.findUnique({ where: { id } });
|
|
||||||
if (!exist) throw new NotFoundException("User not found");
|
|
||||||
|
|
||||||
return await this.prisma.user.delete({
|
return await this.prisma.user.delete({
|
||||||
where: { id },
|
where: { id },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async bulkDelete(ids: string[]) {
|
async bulkRemove(ids: string[]) {
|
||||||
return await this.prisma.user.deleteMany({
|
return await this.prisma.user.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
id: {
|
id: {
|
||||||
|
Loading…
Reference in New Issue
Block a user