mirror of
https://github.com/n08i40k/schedule-parser-next.git
synced 2025-12-06 09:47:46 +03:00
1.3.0
Добавлена совместимость с Firebase Cloud Messaging. Сервис и контроллер модуля schedule-replacer были перенесены в модуль schedule.
This commit is contained in:
@@ -149,14 +149,8 @@ export class ScheduleParser {
|
||||
!downloadData.new &&
|
||||
this.lastResult &&
|
||||
this.xlsDownloader.getCacheMode() !== XlsDownloaderCacheMode.NONE
|
||||
) {
|
||||
console.debug(
|
||||
"Так как скачанный XLS не новый, присутствует уже готовый результат и кеширование не отключено...",
|
||||
);
|
||||
console.debug("будет возвращён предыдущий результат.");
|
||||
|
||||
)
|
||||
return this.lastResult;
|
||||
}
|
||||
|
||||
const workBook = XLSX.read(downloadData.fileData);
|
||||
const workSheet = workBook.Sheets[workBook.SheetNames[0]];
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
NotAcceptableException,
|
||||
ServiceUnavailableException,
|
||||
} from "@nestjs/common";
|
||||
import { ScheduleReplacerService } from "../../../schedule-replacer/schedule-replacer.service";
|
||||
import { ScheduleReplacerService } from "../../schedule-replacer.service";
|
||||
import { Error } from "mongoose";
|
||||
import * as crypto from "crypto";
|
||||
|
||||
|
||||
20
src/schedule/schedule-replacer.controller.spec.ts
Normal file
20
src/schedule/schedule-replacer.controller.spec.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
import { ScheduleReplacerController } from "./schedule-replacer.controller";
|
||||
|
||||
describe("ScheduleReplacerController", () => {
|
||||
let controller: ScheduleReplacerController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [ScheduleReplacerController],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<ScheduleReplacerController>(
|
||||
ScheduleReplacerController,
|
||||
);
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
106
src/schedule/schedule-replacer.controller.ts
Normal file
106
src/schedule/schedule-replacer.controller.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Controller,
|
||||
Get,
|
||||
HttpCode,
|
||||
HttpStatus,
|
||||
Post,
|
||||
UploadedFile,
|
||||
UseGuards,
|
||||
UseInterceptors,
|
||||
} from "@nestjs/common";
|
||||
import { AuthGuard } from "src/auth/auth.guard";
|
||||
import {
|
||||
ClearScheduleReplacerResDto,
|
||||
ScheduleReplacerResDto,
|
||||
} from "../dto/schedule-replacer.dto";
|
||||
import { AuthRoles } from "../auth-role/auth-role.decorator";
|
||||
import { UserRoleDto } from "../dto/user.dto";
|
||||
import { ScheduleReplacerService } from "./schedule-replacer.service";
|
||||
import { ScheduleService } from "./schedule.service";
|
||||
import { FileInterceptor } from "@nestjs/platform-express";
|
||||
import {
|
||||
ApiExtraModels,
|
||||
ApiOkResponse,
|
||||
ApiOperation,
|
||||
refs,
|
||||
} from "@nestjs/swagger";
|
||||
import { ResultDto } from "src/utility/validation/class-validator.interceptor";
|
||||
|
||||
@Controller("/api/v1/schedule-replacer")
|
||||
@UseGuards(AuthGuard)
|
||||
export class ScheduleReplacerController {
|
||||
constructor(
|
||||
private readonly scheduleService: ScheduleService,
|
||||
private readonly scheduleReplaceService: ScheduleReplacerService,
|
||||
) {}
|
||||
|
||||
@ApiOperation({
|
||||
description: "Замена текущего расписание на новое",
|
||||
tags: ["schedule", "replacer"],
|
||||
})
|
||||
@ApiOkResponse({ description: "Замена прошла успешно" })
|
||||
@Post("set")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@AuthRoles([UserRoleDto.ADMIN])
|
||||
@ResultDto(null)
|
||||
@UseInterceptors(
|
||||
FileInterceptor("file", { limits: { fileSize: 1024 * 1024 } }),
|
||||
)
|
||||
async setSchedule(
|
||||
@UploadedFile() file: Express.Multer.File,
|
||||
): Promise<void> {
|
||||
if (!file) throw new BadRequestException("Файл отсутствует");
|
||||
if (file.mimetype !== "application/vnd.ms-excel")
|
||||
throw new BadRequestException("Некорректный тип файла");
|
||||
|
||||
const etag = (await this.scheduleService.getSourceSchedule()).etag;
|
||||
await this.scheduleReplaceService.setByEtag(etag, file.buffer);
|
||||
await this.scheduleService.refreshCache();
|
||||
}
|
||||
|
||||
@ApiExtraModels(ScheduleReplacerResDto)
|
||||
@ApiOperation({
|
||||
description: "Получение списка заменителей расписания",
|
||||
tags: ["schedule", "replacer"],
|
||||
})
|
||||
@ApiOkResponse({ description: "Список получен успешно" }) // TODO: ааа((((
|
||||
@Get("get")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@AuthRoles([UserRoleDto.ADMIN])
|
||||
@ResultDto(null) // TODO: Как нибудь сделать проверку в таких случаях
|
||||
async getReplacers(): Promise<ScheduleReplacerResDto[]> {
|
||||
const etag = (await this.scheduleService.getSourceSchedule()).etag;
|
||||
|
||||
const replacer = await this.scheduleReplaceService.getByEtag(etag);
|
||||
if (!replacer) return [];
|
||||
|
||||
return [
|
||||
{
|
||||
etag: replacer.etag,
|
||||
size: replacer.data.byteLength,
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@ApiExtraModels(ClearScheduleReplacerResDto)
|
||||
@ApiOperation({
|
||||
description: "Удаление всех замен расписаний",
|
||||
tags: ["schedule", "replacer"],
|
||||
})
|
||||
@ApiOkResponse({
|
||||
description: "Отчистка прошла успешно",
|
||||
schema: refs(ClearScheduleReplacerResDto)[0],
|
||||
})
|
||||
@Post("clear")
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@AuthRoles([UserRoleDto.ADMIN])
|
||||
@ResultDto(ClearScheduleReplacerResDto)
|
||||
async clear(): Promise<ClearScheduleReplacerResDto> {
|
||||
const resDto = { count: await this.scheduleReplaceService.clear() };
|
||||
|
||||
await this.scheduleService.refreshCache();
|
||||
|
||||
return resDto;
|
||||
}
|
||||
}
|
||||
18
src/schedule/schedule-replacer.service.spec.ts
Normal file
18
src/schedule/schedule-replacer.service.spec.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { Test, TestingModule } from "@nestjs/testing";
|
||||
import { ScheduleReplacerService } from "./schedule-replacer.service";
|
||||
|
||||
describe("ScheduleReplacerService", () => {
|
||||
let service: ScheduleReplacerService;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [ScheduleReplacerService],
|
||||
}).compile();
|
||||
|
||||
service = module.get<ScheduleReplacerService>(ScheduleReplacerService);
|
||||
});
|
||||
|
||||
it("should be defined", () => {
|
||||
expect(service).toBeDefined();
|
||||
});
|
||||
});
|
||||
56
src/schedule/schedule-replacer.service.ts
Normal file
56
src/schedule/schedule-replacer.service.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
import { ScheduleReplacerDto } from "../dto/schedule-replacer.dto";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleReplacerService {
|
||||
constructor(private readonly prismaService: PrismaService) {}
|
||||
|
||||
async hasByEtag(etag: string): Promise<boolean> {
|
||||
return (
|
||||
(await this.prismaService.scheduleReplace.count({
|
||||
where: { etag: etag },
|
||||
})) > 0
|
||||
);
|
||||
}
|
||||
|
||||
async getByEtag(etag: string): Promise<ScheduleReplacerDto | null> {
|
||||
const response = await this.prismaService.scheduleReplace.findUnique({
|
||||
where: { etag: etag },
|
||||
});
|
||||
if (response == null) return null;
|
||||
|
||||
return plainToClass(ScheduleReplacerDto, response);
|
||||
}
|
||||
|
||||
async clear(): Promise<number> {
|
||||
const count = await this.prismaService.scheduleReplace.count();
|
||||
await this.prismaService.scheduleReplace.deleteMany({});
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
async setByEtag(etag: string, buffer: Buffer): Promise<void> {
|
||||
if (
|
||||
(await this.prismaService.scheduleReplace.count({
|
||||
where: { etag: etag },
|
||||
})) > 0
|
||||
) {
|
||||
await this.prismaService.scheduleReplace.update({
|
||||
where: { etag: etag },
|
||||
data: {
|
||||
data: buffer,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await this.prismaService.scheduleReplace.create({
|
||||
data: {
|
||||
etag: etag,
|
||||
data: buffer,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,16 @@
|
||||
import { Module } from "@nestjs/common";
|
||||
import { forwardRef, Module } from "@nestjs/common";
|
||||
import { ScheduleService } from "./schedule.service";
|
||||
import { ScheduleController } from "./schedule.controller";
|
||||
import { UsersService } from "../users/users.service";
|
||||
import { PrismaService } from "../prisma/prisma.service";
|
||||
import { ScheduleReplacerService } from "../schedule-replacer/schedule-replacer.service";
|
||||
import { FirebaseAdminModule } from "../firebase-admin/firebase-admin.module";
|
||||
import { UsersModule } from "src/users/users.module";
|
||||
import { ScheduleReplacerService } from "./schedule-replacer.service";
|
||||
import { ScheduleReplacerController } from "./schedule-replacer.controller";
|
||||
|
||||
@Module({
|
||||
providers: [
|
||||
ScheduleService,
|
||||
ScheduleReplacerService,
|
||||
UsersService,
|
||||
PrismaService,
|
||||
],
|
||||
controllers: [ScheduleController],
|
||||
imports: [forwardRef(() => UsersModule), FirebaseAdminModule],
|
||||
providers: [PrismaService, ScheduleService, ScheduleReplacerService],
|
||||
controllers: [ScheduleController, ScheduleReplacerController],
|
||||
exports: [ScheduleService],
|
||||
})
|
||||
export class ScheduleModule {}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { Inject, Injectable, NotFoundException } from "@nestjs/common";
|
||||
import {
|
||||
Inject,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import {
|
||||
ScheduleParser,
|
||||
ScheduleParseResult,
|
||||
@@ -17,7 +21,8 @@ import { Cache, CACHE_MANAGER } from "@nestjs/cache-manager";
|
||||
import { instanceToPlain } from "class-transformer";
|
||||
import { cacheGetOrFill } from "../utility/cache.util";
|
||||
import * as crypto from "crypto";
|
||||
import { ScheduleReplacerService } from "../schedule-replacer/schedule-replacer.service";
|
||||
import { ScheduleReplacerService } from "./schedule-replacer.service";
|
||||
import { FirebaseAdminService } from "../firebase-admin/firebase-admin.service";
|
||||
|
||||
@Injectable()
|
||||
export class ScheduleService {
|
||||
@@ -37,6 +42,7 @@ export class ScheduleService {
|
||||
constructor(
|
||||
@Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
|
||||
private readonly scheduleReplacerService: ScheduleReplacerService,
|
||||
private readonly firebaseAdminService: FirebaseAdminService,
|
||||
) {
|
||||
const xlsDownloader = this.scheduleParser.getXlsDownloader();
|
||||
|
||||
@@ -77,8 +83,26 @@ export class ScheduleService {
|
||||
if (
|
||||
this.scheduleUpdatedAt.valueOf() === 0 ||
|
||||
this.cacheHash !== oldHash
|
||||
)
|
||||
) {
|
||||
if (this.scheduleUpdatedAt.valueOf() !== 0) {
|
||||
const isReplaced =
|
||||
await this.scheduleReplacerService.hasByEtag(
|
||||
schedule.etag,
|
||||
);
|
||||
|
||||
await this.firebaseAdminService.sendByTopic(
|
||||
"schedule-update",
|
||||
{
|
||||
data: {
|
||||
type: "schedule-update",
|
||||
replaced: isReplaced.toString(),
|
||||
etag: schedule.etag,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
this.scheduleUpdatedAt = new Date();
|
||||
}
|
||||
|
||||
return schedule;
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user