mirror of
https://github.com/n08i40k/schedule-parser-next.git
synced 2025-12-06 17:57:45 +03:00
Добавление теста и некоторые переработки кода.
This commit is contained in:
@@ -33,7 +33,7 @@ export class LessonTimeDto {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static fromString(time: string): LessonTimeDto {
|
static fromString(time: string): LessonTimeDto {
|
||||||
time = time.replaceAll(".", ":");
|
time = time.trim().replaceAll(".", ":");
|
||||||
|
|
||||||
const regex = /(\d+:\d+)-(\d+:\d+)/g;
|
const regex = /(\d+:\d+)-(\d+:\d+)/g;
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
LessonTimeDto,
|
LessonTimeDto,
|
||||||
LessonTypeDto,
|
LessonTypeDto,
|
||||||
} from "../../../dto/schedule.dto";
|
} from "../../../dto/schedule.dto";
|
||||||
import { trimAll } from "../../../utility/string.util";
|
import { toNormalString, trimAll } from "../../../utility/string.util";
|
||||||
|
|
||||||
type InternalId = { row: number; column: number; name: string };
|
type InternalId = { row: number; column: number; name: string };
|
||||||
type InternalDay = InternalId & { lessons: Array<InternalId> };
|
type InternalDay = InternalId & { lessons: Array<InternalId> };
|
||||||
@@ -23,18 +23,22 @@ export class ScheduleParseResult {
|
|||||||
updateRequired: boolean;
|
updateRequired: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CellData = XLSX.CellObject["v"];
|
||||||
|
|
||||||
export class ScheduleParser {
|
export class ScheduleParser {
|
||||||
private lastResult: ScheduleParseResult | null = null;
|
private lastResult: ScheduleParseResult | null = null;
|
||||||
|
|
||||||
public constructor(private readonly xlsDownloader: XlsDownloaderBase) {}
|
public constructor(private readonly xlsDownloader: XlsDownloaderBase) {}
|
||||||
|
|
||||||
private static getCellName(
|
private static getCellData(
|
||||||
worksheet: XLSX.Sheet,
|
worksheet: XLSX.Sheet,
|
||||||
row: number,
|
row: number,
|
||||||
column: number,
|
column: number,
|
||||||
): any | null {
|
): string | null {
|
||||||
const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: column })];
|
const cell: XLSX.CellObject | null =
|
||||||
return cell ? cell.v : null;
|
worksheet[XLSX.utils.encode_cell({ r: row, c: column })];
|
||||||
|
|
||||||
|
return toNormalString(cell?.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
private parseTeacherFullNames(lessonName: string): {
|
private parseTeacherFullNames(lessonName: string): {
|
||||||
@@ -79,7 +83,7 @@ export class ScheduleParser {
|
|||||||
const days: Array<InternalDay> = [];
|
const days: Array<InternalDay> = [];
|
||||||
|
|
||||||
for (let row = range.s.r + 1; row <= range.e.r; ++row) {
|
for (let row = range.s.r + 1; row <= range.e.r; ++row) {
|
||||||
const dayName = ScheduleParser.getCellName(worksheet, row, 0);
|
const dayName = ScheduleParser.getCellData(worksheet, row, 0);
|
||||||
if (!dayName) continue;
|
if (!dayName) continue;
|
||||||
|
|
||||||
if (!isHeaderParsed) {
|
if (!isHeaderParsed) {
|
||||||
@@ -91,7 +95,7 @@ export class ScheduleParser {
|
|||||||
column <= range.e.c;
|
column <= range.e.c;
|
||||||
++column
|
++column
|
||||||
) {
|
) {
|
||||||
const groupName = ScheduleParser.getCellName(
|
const groupName = ScheduleParser.getCellData(
|
||||||
worksheet,
|
worksheet,
|
||||||
row,
|
row,
|
||||||
column,
|
column,
|
||||||
@@ -173,65 +177,67 @@ export class ScheduleParser {
|
|||||||
row < daySkeleton.row + rowDistance;
|
row < daySkeleton.row + rowDistance;
|
||||||
++row
|
++row
|
||||||
) {
|
) {
|
||||||
const time: string | null = ScheduleParser.getCellName(
|
// time
|
||||||
|
const time = ScheduleParser.getCellData(
|
||||||
workSheet,
|
workSheet,
|
||||||
row,
|
row,
|
||||||
lessonTimeColumn,
|
lessonTimeColumn,
|
||||||
)?.replaceAll(" ", "");
|
)?.replaceAll(" ", "");
|
||||||
if (!time || typeof time !== "string") continue;
|
|
||||||
|
|
||||||
const rawName: string | null = ScheduleParser.getCellName(
|
if (!time) continue;
|
||||||
|
|
||||||
|
// name
|
||||||
|
const rawName: CellData = trimAll(
|
||||||
|
ScheduleParser.getCellData(
|
||||||
workSheet,
|
workSheet,
|
||||||
row,
|
row,
|
||||||
groupSkeleton.column,
|
groupSkeleton.column,
|
||||||
|
)?.replaceAll(/[\n\r]/g, "") ?? "",
|
||||||
);
|
);
|
||||||
const cabinets: Array<string> = [];
|
|
||||||
|
|
||||||
const rawCabinets = String(
|
if (rawName.length === 0) {
|
||||||
ScheduleParser.getCellName(
|
|
||||||
workSheet,
|
|
||||||
row,
|
|
||||||
groupSkeleton.column + 1,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (rawCabinets !== "null") {
|
|
||||||
const rawLessonCabinetParts =
|
|
||||||
rawCabinets.split(/(\n|\s)/g);
|
|
||||||
|
|
||||||
for (const cabinet of rawLessonCabinetParts) {
|
|
||||||
if (
|
|
||||||
cabinet.length === 0 ||
|
|
||||||
cabinet === " " ||
|
|
||||||
cabinet === "\n"
|
|
||||||
)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
cabinets.push(cabinet);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!rawName || rawName.length === 0) {
|
|
||||||
day.lessons.push(null);
|
day.lessons.push(null);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const type = time?.includes("пара")
|
// cabinets
|
||||||
|
const cabinets: Array<string> = [];
|
||||||
|
|
||||||
|
const rawCabinets = ScheduleParser.getCellData(
|
||||||
|
workSheet,
|
||||||
|
row,
|
||||||
|
groupSkeleton.column + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (rawCabinets) {
|
||||||
|
const parts = rawCabinets.split(/(\n|\s)/g);
|
||||||
|
|
||||||
|
for (const cabinet of parts) {
|
||||||
|
if (!toNormalString(cabinet)) continue;
|
||||||
|
|
||||||
|
cabinets.push(cabinet.replaceAll(/[\n\s\r]/g, " "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// type
|
||||||
|
const lessonType = time?.includes("пара")
|
||||||
? LessonTypeDto.DEFAULT
|
? LessonTypeDto.DEFAULT
|
||||||
: LessonTypeDto.CUSTOM;
|
: LessonTypeDto.CUSTOM;
|
||||||
|
|
||||||
|
// full names
|
||||||
const { name, teacherFullNames } =
|
const { name, teacherFullNames } =
|
||||||
this.parseTeacherFullNames(
|
this.parseTeacherFullNames(
|
||||||
trimAll(rawName?.replace("\n", "") ?? ""),
|
trimAll(rawName?.replaceAll(/[\n\r]/g, "") ?? ""),
|
||||||
);
|
);
|
||||||
|
|
||||||
day.lessons.push(
|
day.lessons.push(
|
||||||
new LessonDto(
|
new LessonDto(
|
||||||
type,
|
lessonType,
|
||||||
type === LessonTypeDto.DEFAULT
|
lessonType === LessonTypeDto.DEFAULT
|
||||||
? Number.parseInt(time[0])
|
? Number.parseInt(time[0])
|
||||||
: -1,
|
: -1,
|
||||||
LessonTimeDto.fromString(
|
LessonTimeDto.fromString(
|
||||||
type === LessonTypeDto.DEFAULT
|
lessonType === LessonTypeDto.DEFAULT
|
||||||
? time.substring(5)
|
? time.substring(5)
|
||||||
: time,
|
: time,
|
||||||
),
|
),
|
||||||
|
|||||||
35
src/schedule/schedule.service.spec.ts
Normal file
35
src/schedule/schedule.service.spec.ts
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import { Test, TestingModule } from "@nestjs/testing";
|
||||||
|
import { ScheduleService } from "./schedule.service";
|
||||||
|
import * as fs from "node:fs";
|
||||||
|
import { CacheModule } from "@nestjs/cache-manager";
|
||||||
|
|
||||||
|
describe("ScheduleService", () => {
|
||||||
|
let service: ScheduleService;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
const module: TestingModule = await Test.createTestingModule({
|
||||||
|
imports: [CacheModule.register()],
|
||||||
|
providers: [ScheduleService, CacheModule],
|
||||||
|
}).compile();
|
||||||
|
|
||||||
|
service = module.get<ScheduleService>(ScheduleService);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("get group schedule", () => {
|
||||||
|
it("should return group schedule", async () => {
|
||||||
|
const mainPage = fs.readFileSync("./test/mainPage").toString();
|
||||||
|
await service.updateSiteMainPage({ mainPage: mainPage });
|
||||||
|
|
||||||
|
const groupName = "ИС-214/23";
|
||||||
|
|
||||||
|
const schedule = await service.getGroup(groupName);
|
||||||
|
expect(schedule.group.name).toBe(groupName);
|
||||||
|
|
||||||
|
console.log(schedule.group.days);
|
||||||
|
expect(schedule.group.days[2].nonNullIndices.length).toBe(3);
|
||||||
|
expect(schedule.group.days[2].defaultIndices.length).toBe(3);
|
||||||
|
|
||||||
|
expect(schedule.group.days[3]).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,3 +1,13 @@
|
|||||||
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function toNormalString(data: any): string | null {
|
||||||
|
if (typeof data === "number") data = data.toString();
|
||||||
|
|
||||||
|
return typeof data === "string" &&
|
||||||
|
data.length > 0 &&
|
||||||
|
data.replaceAll(/[\s\n\r]/g, "").length > 0
|
||||||
|
? data
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|||||||
1
test/mainPage
Normal file
1
test/mainPage
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user