Чистка.

Удалены неиспользуемые функции.
Были исправлены несоблюдения стиля кода.
This commit is contained in:
2024-09-06 23:32:16 +04:00
parent 31906fbbd1
commit 6b07bd89b8
16 changed files with 50 additions and 177 deletions

View File

@@ -1,85 +1,3 @@
<p align="center"> # Schedule Parser Next
<a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo-small.svg" width="120" alt="Nest Logo" /></a>
</p>
[circleci-image]: https://img.shields.io/circleci/build/github/nestjs/nest/master?token=abc123def456 Based on [Nest](https://github.com/nestjs/nest) framework.
[circleci-url]: https://circleci.com/gh/nestjs/nest
<p align="center">A progressive <a href="http://nodejs.org" target="_blank">Node.js</a> framework for building efficient and scalable server-side applications.</p>
<p align="center">
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a>
<a href="https://www.npmjs.com/~nestjscore" target="_blank"><img src="https://img.shields.io/npm/dm/@nestjs/common.svg" alt="NPM Downloads" /></a>
<a href="https://circleci.com/gh/nestjs/nest" target="_blank"><img src="https://img.shields.io/circleci/build/github/nestjs/nest/master" alt="CircleCI" /></a>
<a href="https://coveralls.io/github/nestjs/nest?branch=master" target="_blank"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#9" alt="Coverage" /></a>
<a href="https://discord.gg/G7Qnnhy" target="_blank"><img src="https://img.shields.io/badge/discord-online-brightgreen.svg" alt="Discord"/></a>
<a href="https://opencollective.com/nest#backer" target="_blank"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a>
<a href="https://paypal.me/kamilmysliwiec" target="_blank"><img src="https://img.shields.io/badge/Donate-PayPal-ff3f59.svg" alt="Donate us"/></a>
<a href="https://opencollective.com/nest#sponsor" target="_blank"><img src="https://img.shields.io/badge/Support%20us-Open%20Collective-41B883.svg" alt="Support us"></a>
<a href="https://twitter.com/nestframework" target="_blank"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow" alt="Follow us on Twitter"></a>
</p>
<!--[![Backers on Open Collective](https://opencollective.com/nest/backers/badge.svg)](https://opencollective.com/nest#backer)
[![Sponsors on Open Collective](https://opencollective.com/nest/sponsors/badge.svg)](https://opencollective.com/nest#sponsor)-->
## Description
[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository.
## Project setup
```bash
$ npm install
```
## Compile and run the project
```bash
# development
$ npm run start
# watch mode
$ npm run start:dev
# production mode
$ npm run start:prod
```
## Run tests
```bash
# unit tests
$ npm run test
# e2e tests
$ npm run test:e2e
# test coverage
$ npm run test:cov
```
## Resources
Check out a few resources that may come in handy when working with NestJS:
- Visit the [NestJS Documentation](https://docs.nestjs.com) to learn more about the framework.
- For questions and support, please visit our [Discord channel](https://discord.gg/G7Qnnhy).
- To dive deeper and get more hands-on experience, check out our official video [courses](https://courses.nestjs.com/).
- Visualize your application graph and interact with the NestJS application in real-time using [NestJS Devtools](https://devtools.nestjs.com).
- Need help with your project (part-time to full-time)? Check out our official [enterprise support](https://enterprise.nestjs.com).
- To stay in the loop and get updates, follow us on [X](https://x.com/nestframework) and [LinkedIn](https://linkedin.com/company/nestjs).
- Looking for a job, or have a job to offer? Check out our official [Jobs board](https://jobs.nestjs.com).
## Support
Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support).
## Stay in touch
- Author - [Kamil Myśliwiec](https://twitter.com/kammysliwiec)
- Website - [https://nestjs.com](https://nestjs.com/)
- Twitter - [@nestframework](https://twitter.com/nestframework)
## License
Nest is [MIT licensed](https://github.com/nestjs/nest/blob/master/LICENSE).

View File

@@ -14,12 +14,12 @@ datasource db {
} }
model user { model user {
id String @id @map("_id") @db.ObjectId id String @id @map("_id") @db.ObjectId
// //
username String @unique username String @unique
// //
salt String salt String
password String password String
// //
access_token String @unique accessToken String @unique
} }

View File

@@ -1,6 +1,8 @@
import { createParamDecorator, ExecutionContext } from "@nestjs/common"; import { createParamDecorator, ExecutionContext } from "@nestjs/common";
import { AuthGuard } from "./auth.guard"; import { AuthGuard } from "./auth.guard";
// TODO: Найти применение этой функции
// noinspection JSUnusedGlobalSymbols
export const UserId = createParamDecorator((_, context: ExecutionContext) => { export const UserId = createParamDecorator((_, context: ExecutionContext) => {
return AuthGuard.extractTokenFromRequest( return AuthGuard.extractTokenFromRequest(
context.switchToHttp().getRequest(), context.switchToHttp().getRequest(),

View File

@@ -29,7 +29,7 @@ export class AuthGuard implements CanActivate {
try { try {
if ( if (
!(await this.jwtService.verifyAsync(token)) || !(await this.jwtService.verifyAsync(token)) ||
!(await this.usersService.has({ access_token: token })) !(await this.usersService.contains({ accessToken: token }))
) { ) {
// noinspection ExceptionCaughtLocallyJS // noinspection ExceptionCaughtLocallyJS
throw new Error(); throw new Error();

View File

@@ -1,5 +1,4 @@
import { import {
ArgumentMetadata,
Injectable, Injectable,
PipeTransform, PipeTransform,
UnauthorizedException, UnauthorizedException,
@@ -16,12 +15,12 @@ export class UserFromTokenPipe implements PipeTransform {
) {} ) {}
async transform(token: string): Promise<user | null> { async transform(token: string): Promise<user | null> {
const jwt_user: { id: string } = await this.jwtService.decode(token); const jwtUser: { id: string } = await this.jwtService.decode(token);
if (!jwt_user) if (!jwtUser)
throw new UnauthorizedException("Передан некорректный токен!"); throw new UnauthorizedException("Передан некорректный токен!");
const user = await this.usersService.findUnique({ id: jwt_user.id }); const user = await this.usersService.findUnique({ id: jwtUser.id });
if (!user) if (!user)
throw new UnauthorizedException("Передан некорректный токен!"); throw new UnauthorizedException("Передан некорректный токен!");

View File

@@ -26,7 +26,7 @@ export class AuthService {
) {} ) {}
async signUp(signUpDto: SignUpDto): Promise<SignUpResultDto> { async signUp(signUpDto: SignUpDto): Promise<SignUpResultDto> {
if (await this.usersService.has({ username: signUpDto.username })) if (await this.usersService.contains({ username: signUpDto.username }))
throw new ConflictException( throw new ConflictException(
"Пользователь с таким именем уже существует!", "Пользователь с таким именем уже существует!",
); );
@@ -39,7 +39,7 @@ export class AuthService {
username: signUpDto.username, username: signUpDto.username,
salt: salt, salt: salt,
password: await hash(signUpDto.password, salt), password: await hash(signUpDto.password, salt),
access_token: await this.jwtService.signAsync({ accessToken: await this.jwtService.signAsync({
id: id, id: id,
}), }),
}; };
@@ -47,7 +47,7 @@ export class AuthService {
return this.usersService.create(input).then((user) => { return this.usersService.create(input).then((user) => {
return { return {
id: user.id, id: user.id,
access_token: user.access_token, accessToken: user.accessToken,
}; };
}); });
} }
@@ -66,21 +66,21 @@ export class AuthService {
); );
} }
const access_token = await this.jwtService.signAsync({ id: user.id }); const accessToken = await this.jwtService.signAsync({ id: user.id });
await this.usersService.update({ await this.usersService.update({
where: { id: user.id }, where: { id: user.id },
data: { access_token: access_token }, data: { accessToken: accessToken },
}); });
return { id: user.id, access_token: access_token }; return { id: user.id, accessToken: accessToken };
} }
async updateToken( async updateToken(
updateTokenDto: UpdateTokenDto, updateTokenDto: UpdateTokenDto,
): Promise<UpdateTokenResultDto> { ): Promise<UpdateTokenResultDto> {
if ( if (
!(await this.jwtService.verifyAsync(updateTokenDto.access_token, { !(await this.jwtService.verifyAsync(updateTokenDto.accessToken, {
ignoreExpiration: true, ignoreExpiration: true,
})) }))
) { ) {
@@ -89,24 +89,24 @@ export class AuthService {
); );
} }
const jwt_user: { id: string } = await this.jwtService.decode( const jwtUser: { id: string } = await this.jwtService.decode(
updateTokenDto.access_token, updateTokenDto.accessToken,
); );
const user = await this.usersService.findUnique({ id: jwt_user.id }); const user = await this.usersService.findUnique({ id: jwtUser.id });
if (!user || user.access_token !== updateTokenDto.access_token) { if (!user || user.accessToken !== updateTokenDto.accessToken) {
throw new NotFoundException( throw new NotFoundException(
"Некорректный или недействительный токен!", "Некорректный или недействительный токен!",
); );
} }
const access_token = await this.jwtService.signAsync({ id: user.id }); const accessToken = await this.jwtService.signAsync({ id: user.id });
await this.usersService.update({ await this.usersService.update({
where: { id: user.id }, where: { id: user.id },
data: { access_token: access_token }, data: { accessToken: accessToken },
}); });
return { access_token: access_token }; return { accessToken: accessToken };
} }
} }

View File

@@ -8,15 +8,12 @@ export class SignInDto extends PickType(UserDto, ["username"]) {
password: string; password: string;
} }
export class SignInResultDto extends PickType(UserDto, [ export class SignInResultDto extends PickType(UserDto, ["id", "accessToken"]) {}
"id",
"access_token",
]) {}
export class SignUpDto extends SignInDto {} export class SignUpDto extends SignInDto {}
export class SignUpResultDto extends SignInResultDto {} export class SignUpResultDto extends SignInResultDto {}
export class UpdateTokenDto extends PickType(UserDto, ["access_token"]) {} export class UpdateTokenDto extends PickType(UserDto, ["accessToken"]) {}
export class UpdateTokenResultDto extends UpdateTokenDto {} export class UpdateTokenResultDto extends UpdateTokenDto {}

View File

@@ -24,11 +24,13 @@ export class UserDto {
password: string; password: string;
@ApiProperty({ description: "Последний токен доступа" }) @ApiProperty({ description: "Последний токен доступа" })
@IsJWT() @IsJWT()
access_token: string; accessToken: string;
} }
// TODO: Доделать пользователей
// noinspection JSUnusedGlobalSymbols
export class ClientUserDto extends OmitType(UserDto, [ export class ClientUserDto extends OmitType(UserDto, [
"password", "password",
"salt", "salt",
"access_token", "accessToken",
]) {} ]) {}

View File

@@ -239,10 +239,6 @@ export class ScheduleParser {
}); });
} }
public getLastResult(): ScheduleParseResult | null {
return this.lastResult;
}
private getAffectedDays( private getAffectedDays(
cachedGroup: GroupDto | null, cachedGroup: GroupDto | null,
group: GroupDto, group: GroupDto,

View File

@@ -28,11 +28,11 @@ ${response.statusText}`);
downloadLink: string; downloadLink: string;
updateDate: string; updateDate: string;
} { } {
const schedule_block = dom.window.document.getElementById("cont-i"); const scheduleBlock = dom.window.document.getElementById("cont-i");
if (schedule_block === null) if (scheduleBlock === null)
throw new Error("Не удалось найти блок расписаний!"); throw new Error("Не удалось найти блок расписаний!");
const schedules = schedule_block.getElementsByTagName("div"); const schedules = scheduleBlock.getElementsByTagName("div");
if (schedules === null || schedules.length === 0) if (schedules === null || schedules.length === 0)
throw new Error("Не удалось найти строку с расписанием!"); throw new Error("Не удалось найти строку с расписанием!");
@@ -40,11 +40,11 @@ ${response.statusText}`);
const link = poltavskaya.getElementsByTagName("a")[0]!; const link = poltavskaya.getElementsByTagName("a")[0]!;
const spans = poltavskaya.getElementsByTagName("span"); const spans = poltavskaya.getElementsByTagName("span");
const update_date = spans[3].textContent!.trimStart(); const updateDate = spans[3].textContent!.trimStart();
return { return {
downloadLink: link.href, downloadLink: link.href,
updateDate: update_date, updateDate: updateDate,
}; };
} }
@@ -64,9 +64,11 @@ ${response.statusText}`);
return this.getCachedXLS(); return this.getCachedXLS();
const dom = await this.getDOM(); const dom = await this.getDOM();
const parse_data = this.parseData(dom); const parseData = this.parseData(dom);
const response = await axios.get(parse_data.downloadLink, { // FIX-ME: Что такое Annotator и почему он выдаёт пустое предупреждение?
// noinspection Annotator
const response = await axios.get(parseData.downloadLink, {
responseType: "arraybuffer", responseType: "arraybuffer",
}); });
if (response.status !== 200) { if (response.status !== 200) {
@@ -77,7 +79,7 @@ ${response.statusText}`);
const result: XlsDownloaderResult = { const result: XlsDownloaderResult = {
fileData: response.data.buffer, fileData: response.data.buffer,
updateDate: parse_data.updateDate, updateDate: parseData.updateDate,
etag: response.headers["etag"], etag: response.headers["etag"],
new: new:
this.cacheMode === XlsDownloaderCacheMode.NONE this.cacheMode === XlsDownloaderCacheMode.NONE

View File

@@ -1,8 +1,5 @@
import { Injectable } from "@nestjs/common"; import { Injectable } from "@nestjs/common";
import { import { ScheduleParser } from "./internal/schedule-parser/schedule-parser";
ScheduleParser,
ScheduleParseResult,
} from "./internal/schedule-parser/schedule-parser";
import { BasicXlsDownloader } from "./internal/xls-downloader/basic-xls-downloader"; import { BasicXlsDownloader } from "./internal/xls-downloader/basic-xls-downloader";
import { XlsDownloaderCacheMode } from "./internal/xls-downloader/xls-downloader.base"; import { XlsDownloaderCacheMode } from "./internal/xls-downloader/xls-downloader.base";
import { ScheduleDto } from "../dto/schedule.dto"; import { ScheduleDto } from "../dto/schedule.dto";

View File

@@ -10,10 +10,6 @@ export class UsersService {
return this.prismaService.user.findUnique({ where: where }); return this.prismaService.user.findUnique({ where: where });
} }
async findOne(where: Prisma.userWhereInput): Promise<user | null> {
return this.prismaService.user.findFirst({ where: where });
}
async update(params: { async update(params: {
where: Prisma.userWhereUniqueInput; where: Prisma.userWhereUniqueInput;
data: Prisma.userUpdateInput; data: Prisma.userUpdateInput;
@@ -25,7 +21,7 @@ export class UsersService {
return this.prismaService.user.create({ data }); return this.prismaService.user.create({ data });
} }
async has(where: Prisma.userWhereUniqueInput): Promise<boolean> { async contains(where: Prisma.userWhereUniqueInput): Promise<boolean> {
return (await this.prismaService.user.count({ where })) > 0; return (await this.prismaService.user.count({ where })) > 0;
} }
} }

View File

@@ -11,10 +11,10 @@ export class ObjectIdPipe implements PipeTransform<any, string> {
) )
throw new BadRequestException("Invalid ObjectId"); throw new BadRequestException("Invalid ObjectId");
const return_string = value.toLowerCase(); const returnString = value.toLowerCase();
if (!/^[0-9a-f]{24}$/.test(return_string)) if (!/^[0-9a-f]{24}$/.test(returnString))
throw new BadRequestException("Invalid ObjectId"); throw new BadRequestException("Invalid ObjectId");
return return_string; return returnString;
} }
} }

View File

@@ -1,9 +0,0 @@
type Nullable<T> = {
[P in keyof T]: T[P] | null | Array<any>;
};
export function convertToPrismaInput<T>(dto: Nullable<T>): T {
return Object.entries(dto)
.filter((x) => x[1] !== undefined)
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}) as T;
}

View File

@@ -1,31 +1,3 @@
export function trimAll(str: string): string { export function trimAll(str: string): string {
return str.replace(/\s\s+/g, " ").trim(); return str.replace(/\s\s+/g, " ").trim();
} }
const customLessonIdxToTextPresets = [
"Первое",
"Второе",
"Третье",
"Четвёртое",
"Пятое",
"Шестое",
"Седьмое",
];
export function customLessonIdxToText(num: number): string {
return customLessonIdxToTextPresets[num];
}
const defaultLessonIdxToTextPresets = [
"Первая",
"Вторая",
"Третья",
"Четвёртая",
"Пятая",
"Шестая",
"Седьмая",
];
export function defaultLessonIdxToText(num: number): string {
return defaultLessonIdxToTextPresets[num];
}

View File

@@ -19,7 +19,7 @@ export class ClassValidatorInterceptor implements NestInterceptor {
intercept( intercept(
context: ExecutionContext, context: ExecutionContext,
next: CallHandler<any>, next: CallHandler,
): Observable<any> | Promise<Observable<any>> { ): Observable<any> | Promise<Observable<any>> {
return next.handle().pipe( return next.handle().pipe(
map(async (returnValue: any) => { map(async (returnValue: any) => {
@@ -71,6 +71,7 @@ export class ClassValidatorInterceptor implements NestInterceptor {
} }
} }
// noinspection FunctionNamingConventionJS
export function ResultDto(type: any) { export function ResultDto(type: any) {
return (target: NonNullable<unknown>, propertyKey: string | symbol) => { return (target: NonNullable<unknown>, propertyKey: string | symbol) => {
Reflect.defineMetadata("design:result-dto", type, target, propertyKey); Reflect.defineMetadata("design:result-dto", type, target, propertyKey);