mirror of
https://github.com/n08i40k/schedule-parser-next.git
synced 2025-12-06 09:47:46 +03:00
1.4.0
Энд-поинт schedule/get-group-names теперь не требует авторизации (для формы регистрации). Энд-поинт schedule/get-group теперь не требует указания группы. Она берётся из данных пользователя. Энд-поинт auth/sign-in теперь может возвращать группу пользователя начиная с версии 1.
This commit is contained in:
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "schedule-parser-next",
|
"name": "schedule-parser-next",
|
||||||
"version": "1.3.5",
|
"version": "1.4.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "schedule-parser-next",
|
"name": "schedule-parser-next",
|
||||||
"version": "1.3.5",
|
"version": "1.4.0",
|
||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nestjs/cache-manager": "^2.2.2",
|
"@nestjs/cache-manager": "^2.2.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "schedule-parser-next",
|
"name": "schedule-parser-next",
|
||||||
"version": "1.3.5",
|
"version": "1.4.0",
|
||||||
"description": "",
|
"description": "",
|
||||||
"author": "N08I40K",
|
"author": "N08I40K",
|
||||||
"private": true,
|
"private": true,
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ import { Reflector } from "@nestjs/core";
|
|||||||
import { UserRoleDto } from "../dto/user.dto";
|
import { UserRoleDto } from "../dto/user.dto";
|
||||||
|
|
||||||
export const AuthRoles = Reflector.createDecorator<UserRoleDto[]>();
|
export const AuthRoles = Reflector.createDecorator<UserRoleDto[]>();
|
||||||
|
export const AuthUnauthorized = Reflector.createDecorator<true>();
|
||||||
|
|||||||
@@ -26,10 +26,13 @@ import {
|
|||||||
ChangePasswordReqDto,
|
ChangePasswordReqDto,
|
||||||
UpdateTokenReqDto,
|
UpdateTokenReqDto,
|
||||||
UpdateTokenResDto,
|
UpdateTokenResDto,
|
||||||
|
SignInResDtoV0,
|
||||||
|
SignInResDtoV1,
|
||||||
} from "../dto/auth.dto";
|
} from "../dto/auth.dto";
|
||||||
import { ResultDto } from "../utility/validation/class-validator.interceptor";
|
import { ResultDto } from "../utility/validation/class-validator.interceptor";
|
||||||
import { ScheduleService } from "../schedule/schedule.service";
|
import { ScheduleService } from "../schedule/schedule.service";
|
||||||
import { UserToken } from "./auth.decorator";
|
import { UserToken } from "./auth.decorator";
|
||||||
|
import { ResponseVersion } from "../version/response-version.decorator";
|
||||||
|
|
||||||
@Controller("api/v1/auth")
|
@Controller("api/v1/auth")
|
||||||
export class AuthController {
|
export class AuthController {
|
||||||
@@ -39,21 +42,30 @@ export class AuthController {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
@ApiExtraModels(SignInReqDto)
|
@ApiExtraModels(SignInReqDto)
|
||||||
@ApiExtraModels(SignInResDto)
|
@ApiExtraModels(SignInResDtoV0)
|
||||||
|
@ApiExtraModels(SignInResDtoV1)
|
||||||
@ApiOperation({ summary: "Авторизация по логину и паролю", tags: ["auth"] })
|
@ApiOperation({ summary: "Авторизация по логину и паролю", tags: ["auth"] })
|
||||||
@ApiBody({ schema: refs(SignInReqDto)[0] })
|
@ApiBody({ schema: refs(SignInReqDto)[0] })
|
||||||
@ApiOkResponse({
|
@ApiOkResponse({
|
||||||
description: "Авторизация прошла успешно",
|
description: "Авторизация прошла успешно",
|
||||||
schema: refs(SignInResDto)[0],
|
schema: refs(SignInResDtoV0)[0],
|
||||||
|
})
|
||||||
|
@ApiOkResponse({
|
||||||
|
description: "Авторизация прошла успешно",
|
||||||
|
schema: refs(SignInResDtoV1)[0],
|
||||||
})
|
})
|
||||||
@ApiUnauthorizedResponse({
|
@ApiUnauthorizedResponse({
|
||||||
description: "Некорректное имя пользователя или пароль",
|
description: "Некорректное имя пользователя или пароль",
|
||||||
})
|
})
|
||||||
@ResultDto(SignInResDto)
|
@ResultDto([SignInResDtoV0, SignInResDtoV1])
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("sign-in")
|
@Post("sign-in")
|
||||||
signIn(@Body() signInDto: SignInReqDto) {
|
async signIn(
|
||||||
return this.authService.signIn(signInDto);
|
@Body() signInDto: SignInReqDto,
|
||||||
|
@ResponseVersion() responseVersion: number,
|
||||||
|
): Promise<SignInResDtoV1 | SignInResDtoV0> {
|
||||||
|
const data = await this.authService.signIn(signInDto);
|
||||||
|
return SignInResDto.stripVersion(data, responseVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiExtraModels(SignUpReqDto)
|
@ApiExtraModels(SignUpReqDto)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { JwtService } from "@nestjs/jwt";
|
|||||||
import { Request } from "express";
|
import { Request } from "express";
|
||||||
import { UsersService } from "../users/users.service";
|
import { UsersService } from "../users/users.service";
|
||||||
import { Reflector } from "@nestjs/core";
|
import { Reflector } from "@nestjs/core";
|
||||||
import { AuthRoles } from "../auth-role/auth-role.decorator";
|
import { AuthRoles, AuthUnauthorized } from "../auth-role/auth-role.decorator";
|
||||||
import { isJWT } from "class-validator";
|
import { isJWT } from "class-validator";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -30,6 +30,9 @@ export class AuthGuard implements CanActivate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||||
|
if (this.reflector.get(AuthUnauthorized, context.getHandler()))
|
||||||
|
return true;
|
||||||
|
|
||||||
const request = context.switchToHttp().getRequest();
|
const request = context.switchToHttp().getRequest();
|
||||||
const token = AuthGuard.extractTokenFromRequest(request);
|
const token = AuthGuard.extractTokenFromRequest(request);
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ export class AuthService {
|
|||||||
data: { accessToken: accessToken },
|
data: { accessToken: accessToken },
|
||||||
});
|
});
|
||||||
|
|
||||||
return { id: user.id, accessToken: accessToken };
|
return { id: user.id, accessToken: accessToken, group: user.group };
|
||||||
}
|
}
|
||||||
|
|
||||||
async updateToken(
|
async updateToken(
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import {
|
|||||||
PickType,
|
PickType,
|
||||||
} from "@nestjs/swagger";
|
} from "@nestjs/swagger";
|
||||||
import { UserDto } from "./user.dto";
|
import { UserDto } from "./user.dto";
|
||||||
import { IsString } from "class-validator";
|
import { IsJWT, IsMongoId, IsString } from "class-validator";
|
||||||
import { Expose } from "class-transformer";
|
import { Expose, instanceToPlain, plainToClass } from "class-transformer";
|
||||||
|
|
||||||
// SignIn
|
// SignIn
|
||||||
export class SignInReqDto extends PickType(UserDto, ["username"]) {
|
export class SignInReqDto extends PickType(UserDto, ["username"]) {
|
||||||
@@ -18,7 +18,50 @@ export class SignInReqDto extends PickType(UserDto, ["username"]) {
|
|||||||
password: string;
|
password: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SignInResDto extends PickType(UserDto, ["id", "accessToken"]) {}
|
export class SignInResDtoV0 {
|
||||||
|
@ApiProperty({
|
||||||
|
example: "66e1b7e255c5d5f1268cce90",
|
||||||
|
description: "Идентификатор (ObjectId)",
|
||||||
|
})
|
||||||
|
@IsMongoId()
|
||||||
|
@Expose()
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@ApiProperty({
|
||||||
|
example: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||||||
|
description: "Последний токен доступа",
|
||||||
|
})
|
||||||
|
@IsJWT()
|
||||||
|
@Expose()
|
||||||
|
accessToken: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignInResDtoV1 extends SignInResDtoV0 {
|
||||||
|
@ApiProperty({
|
||||||
|
example: "ИС-214/23",
|
||||||
|
description: "Группа",
|
||||||
|
})
|
||||||
|
@IsString()
|
||||||
|
@Expose()
|
||||||
|
group: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SignInResDto extends SignInResDtoV1 {
|
||||||
|
public static stripVersion(
|
||||||
|
instance: SignInResDto,
|
||||||
|
version: number,
|
||||||
|
): SignInResDtoV0 | SignInResDtoV1 {
|
||||||
|
switch (version) {
|
||||||
|
default:
|
||||||
|
return instance;
|
||||||
|
case 0: {
|
||||||
|
return plainToClass(SignInResDtoV0, instanceToPlain(instance), {
|
||||||
|
excludeExtraneousValues: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// SignUp
|
// SignUp
|
||||||
export class SignUpReqDto extends IntersectionType(
|
export class SignUpReqDto extends IntersectionType(
|
||||||
@@ -27,7 +70,10 @@ export class SignUpReqDto extends IntersectionType(
|
|||||||
PartialType(PickType(UserDto, ["version"])),
|
PartialType(PickType(UserDto, ["version"])),
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
export class SignUpResDto extends SignInResDto {}
|
export class SignUpResDto extends PickType(SignInResDto, [
|
||||||
|
"id",
|
||||||
|
"accessToken",
|
||||||
|
]) {}
|
||||||
|
|
||||||
// Update token
|
// Update token
|
||||||
export class UpdateTokenReqDto extends PickType(UserDto, ["accessToken"]) {}
|
export class UpdateTokenReqDto extends PickType(UserDto, ["accessToken"]) {}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator";
|
} from "class-validator";
|
||||||
import { ApiProperty, OmitType, PickType } from "@nestjs/swagger";
|
import { ApiProperty, OmitType, PartialType, PickType } from "@nestjs/swagger";
|
||||||
import {
|
import {
|
||||||
Expose,
|
Expose,
|
||||||
instanceToPlain,
|
instanceToPlain,
|
||||||
@@ -296,7 +296,9 @@ export class ScheduleDto {
|
|||||||
lastChangedDays: Array<Array<number>>;
|
lastChangedDays: Array<Array<number>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class GroupScheduleRequestDto extends PickType(GroupDto, ["name"]) {}
|
export class GroupScheduleReqDto extends PartialType(
|
||||||
|
PickType(GroupDto, ["name"]),
|
||||||
|
) {}
|
||||||
|
|
||||||
export class ScheduleGroupsDto {
|
export class ScheduleGroupsDto {
|
||||||
@ApiProperty({
|
@ApiProperty({
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ import {
|
|||||||
CacheStatusV0Dto,
|
CacheStatusV0Dto,
|
||||||
CacheStatusV1Dto,
|
CacheStatusV1Dto,
|
||||||
GroupScheduleDto,
|
GroupScheduleDto,
|
||||||
GroupScheduleRequestDto,
|
GroupScheduleReqDto,
|
||||||
ScheduleDto,
|
ScheduleDto,
|
||||||
ScheduleGroupsDto,
|
ScheduleGroupsDto,
|
||||||
SiteMainPageDto,
|
SiteMainPageDto,
|
||||||
@@ -28,7 +28,11 @@ import {
|
|||||||
ApiOperation,
|
ApiOperation,
|
||||||
refs,
|
refs,
|
||||||
} from "@nestjs/swagger";
|
} from "@nestjs/swagger";
|
||||||
import { ClientVersion } from "../version/client-version.decorator";
|
import { ResponseVersion } from "../version/response-version.decorator";
|
||||||
|
import { AuthRoles, AuthUnauthorized } from "../auth-role/auth-role.decorator";
|
||||||
|
import { UserDto, UserRoleDto } from "../dto/user.dto";
|
||||||
|
import { UserToken } from "../auth/auth.decorator";
|
||||||
|
import { UserFromTokenPipe } from "../auth/auth.pipe";
|
||||||
|
|
||||||
@Controller("api/v1/schedule")
|
@Controller("api/v1/schedule")
|
||||||
@UseGuards(AuthGuard)
|
@UseGuards(AuthGuard)
|
||||||
@@ -36,12 +40,16 @@ export class ScheduleController {
|
|||||||
constructor(private readonly scheduleService: ScheduleService) {}
|
constructor(private readonly scheduleService: ScheduleService) {}
|
||||||
|
|
||||||
@ApiExtraModels(ScheduleDto)
|
@ApiExtraModels(ScheduleDto)
|
||||||
@ApiOperation({ summary: "Получение расписания", tags: ["schedule"] })
|
@ApiOperation({
|
||||||
|
summary: "Получение расписания",
|
||||||
|
tags: ["schedule", "admin"],
|
||||||
|
})
|
||||||
@ApiOkResponse({
|
@ApiOkResponse({
|
||||||
description: "Расписание получено успешно",
|
description: "Расписание получено успешно",
|
||||||
schema: refs(ScheduleDto)[0],
|
schema: refs(ScheduleDto)[0],
|
||||||
})
|
})
|
||||||
@ResultDto(ScheduleDto)
|
@ResultDto(ScheduleDto)
|
||||||
|
@AuthRoles([UserRoleDto.ADMIN])
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Get("get")
|
@Get("get")
|
||||||
async getSchedule(): Promise<ScheduleDto> {
|
async getSchedule(): Promise<ScheduleDto> {
|
||||||
@@ -62,9 +70,10 @@ export class ScheduleController {
|
|||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Post("get-group")
|
@Post("get-group")
|
||||||
async getGroupSchedule(
|
async getGroupSchedule(
|
||||||
@Body() groupDto: GroupScheduleRequestDto,
|
@Body() groupDto: GroupScheduleReqDto,
|
||||||
|
@UserToken(UserFromTokenPipe) user: UserDto,
|
||||||
): Promise<GroupScheduleDto> {
|
): Promise<GroupScheduleDto> {
|
||||||
return await this.scheduleService.getGroup(groupDto.name);
|
return await this.scheduleService.getGroup(groupDto.name ?? user.group);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ApiExtraModels(ScheduleGroupsDto)
|
@ApiExtraModels(ScheduleGroupsDto)
|
||||||
@@ -78,6 +87,7 @@ export class ScheduleController {
|
|||||||
})
|
})
|
||||||
@ApiNotFoundResponse({ description: "Требуемая группа не найдена" })
|
@ApiNotFoundResponse({ description: "Требуемая группа не найдена" })
|
||||||
@ResultDto(ScheduleGroupsDto)
|
@ResultDto(ScheduleGroupsDto)
|
||||||
|
@AuthUnauthorized()
|
||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Get("get-group-names")
|
@Get("get-group-names")
|
||||||
async getGroupNames(): Promise<ScheduleGroupsDto> {
|
async getGroupNames(): Promise<ScheduleGroupsDto> {
|
||||||
@@ -107,7 +117,7 @@ export class ScheduleController {
|
|||||||
@Post("update-site-main-page")
|
@Post("update-site-main-page")
|
||||||
async updateSiteMainPage(
|
async updateSiteMainPage(
|
||||||
@Body() siteMainPageDto: SiteMainPageDto,
|
@Body() siteMainPageDto: SiteMainPageDto,
|
||||||
@ClientVersion() version: number,
|
@ResponseVersion() version: number,
|
||||||
): Promise<CacheStatusV0Dto> {
|
): Promise<CacheStatusV0Dto> {
|
||||||
return CacheStatusDto.stripVersion(
|
return CacheStatusDto.stripVersion(
|
||||||
await this.scheduleService.updateSiteMainPage(siteMainPageDto),
|
await this.scheduleService.updateSiteMainPage(siteMainPageDto),
|
||||||
@@ -133,7 +143,7 @@ export class ScheduleController {
|
|||||||
@HttpCode(HttpStatus.OK)
|
@HttpCode(HttpStatus.OK)
|
||||||
@Get("cache-status")
|
@Get("cache-status")
|
||||||
getCacheStatus(
|
getCacheStatus(
|
||||||
@ClientVersion() version: number,
|
@ResponseVersion() version: number,
|
||||||
): CacheStatusV0Dto | CacheStatusV1Dto {
|
): CacheStatusV0Dto | CacheStatusV1Dto {
|
||||||
return CacheStatusDto.stripVersion(
|
return CacheStatusDto.stripVersion(
|
||||||
this.scheduleService.getCacheStatus(),
|
this.scheduleService.getCacheStatus(),
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { createParamDecorator, ExecutionContext } from "@nestjs/common";
|
import { createParamDecorator, ExecutionContext } from "@nestjs/common";
|
||||||
|
|
||||||
export const ClientVersion = createParamDecorator(
|
export const ResponseVersion = createParamDecorator(
|
||||||
(_, context: ExecutionContext) => {
|
(_, context: ExecutionContext) => {
|
||||||
const sourceVersion: string | null = context.switchToHttp().getRequest()
|
const sourceVersion: string | null = context.switchToHttp().getRequest()
|
||||||
.headers.version;
|
.headers.version;
|
||||||
Reference in New Issue
Block a user