mirror of
https://github.com/sergeyyarkov/asu_tools_service.git
synced 2026-10-11 10:29:22 +03:00
upd
This commit is contained in:
parent
8c5d52926d
commit
7529760dfb
@ -1,3 +1,3 @@
|
|||||||
import { AsyncLocalStorage } from "node:async_hooks";
|
import { AsyncLocalStorage } from "node:async_hooks";
|
||||||
|
|
||||||
export const httpStorage = new AsyncLocalStorage();
|
export const ctxStorage = new AsyncLocalStorage();
|
||||||
|
|||||||
6
db.js
6
db.js
@ -5,12 +5,12 @@ const connectionConfig = {
|
|||||||
user: process.env.MSSQL_USER,
|
user: process.env.MSSQL_USER,
|
||||||
password: process.env.MSSQL_PASSWORD,
|
password: process.env.MSSQL_PASSWORD,
|
||||||
database: process.env.MSSQL_DB,
|
database: process.env.MSSQL_DB,
|
||||||
server: process.env.MSSQL_HOST,
|
server: process.env.MSSQL_HOST || "localhost",
|
||||||
port: Number.parseInt(process.env.MSSQL_PORT, 10) || 1433,
|
port: Number.parseInt(process.env.MSSQL_PORT || "1433", 10),
|
||||||
pool: {
|
pool: {
|
||||||
max: 10,
|
max: 10,
|
||||||
min: 0,
|
min: 0,
|
||||||
idleTimeoutMillis: 5000
|
idleTimeoutMillis: 30000
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
trustServerCertificate: true
|
trustServerCertificate: true
|
||||||
|
|||||||
37
errors/index.js
Normal file
37
errors/index.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
export class HttpError extends Error {
|
||||||
|
/**
|
||||||
|
* @param {{ name?: string, message: string, statusCode: number }} msg
|
||||||
|
*/
|
||||||
|
constructor({ name, message, statusCode = 500 }) {
|
||||||
|
super(message);
|
||||||
|
this.name = name || this.constructor.name;
|
||||||
|
this.statusCode = statusCode;
|
||||||
|
Error.captureStackTrace(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BadRequestError extends HttpError {
|
||||||
|
/**
|
||||||
|
* @param {string} [message]
|
||||||
|
*/
|
||||||
|
constructor(message) {
|
||||||
|
super({
|
||||||
|
name: "E_BAD_REQUEST",
|
||||||
|
message: message || "Bad Request",
|
||||||
|
statusCode: 400
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NotFoundError extends HttpError {
|
||||||
|
/**
|
||||||
|
* @param {string} [message]
|
||||||
|
*/
|
||||||
|
constructor(message) {
|
||||||
|
super({
|
||||||
|
name: "E_NOT_FOUND",
|
||||||
|
message: message || "Not found",
|
||||||
|
statusCode: 404
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
1
index.d.ts
vendored
1
index.d.ts
vendored
@ -19,6 +19,7 @@ declare global {
|
|||||||
|
|
||||||
type HTTPResponse = {
|
type HTTPResponse = {
|
||||||
sendJson: (data: Record<string, unknown>, statusCode?: number = 200) => http.ServerResponse;
|
sendJson: (data: Record<string, unknown>, statusCode?: number = 200) => http.ServerResponse;
|
||||||
|
sendSSEJson: (data: Record<string, unknown>, eventName: string, statusCode?: number = 200) => void;
|
||||||
sendText: (text: string, statusCode?: number = 200) => http.ServerResponse;
|
sendText: (text: string, statusCode?: number = 200) => http.ServerResponse;
|
||||||
res: http.ServerResponse;
|
res: http.ServerResponse;
|
||||||
};
|
};
|
||||||
|
|||||||
41
index.js
41
index.js
@ -1,31 +1,26 @@
|
|||||||
import http from "node:http";
|
import http from "node:http";
|
||||||
import { routeHandler } from "./router/index.js";
|
import { routeHandler } from "./router/index.js";
|
||||||
import packageJson from "./package.json" with { type: "json" };
|
import packageJson from "./package.json" with { type: "json" };
|
||||||
import { httpStorage } from "./context.js";
|
import { ctxStorage } from "./context.js";
|
||||||
// import db from "./db.js";
|
import db from "./db.js";
|
||||||
import response from "./response.js";
|
import { createResponse } from "./response.js";
|
||||||
import request from "./request.js";
|
import { createRequest } from "./request.js";
|
||||||
|
|
||||||
const SERVER_PORT = 3000;
|
const SERVER_PORT = 3000;
|
||||||
|
|
||||||
// await db.connect().then(() => console.log("Database connected!"));
|
function application() {
|
||||||
|
const server = http.createServer((req, res) => {
|
||||||
http
|
|
||||||
.createServer((req, res) => {
|
|
||||||
try {
|
try {
|
||||||
const url = new URL(`http://localhost:${SERVER_PORT}${req.url}`);
|
const url = new URL(`http://localhost:${SERVER_PORT}${req.url}`);
|
||||||
|
|
||||||
/** @type {HTTPContext} */
|
/** @type {HTTPContext} */
|
||||||
const ctx = {
|
const ctx = {
|
||||||
data: null,
|
data: null,
|
||||||
req: Object.create(request),
|
req: createRequest(req),
|
||||||
res: Object.create(response)
|
res: createResponse(res)
|
||||||
};
|
};
|
||||||
|
|
||||||
ctx.req.req = req;
|
ctxStorage.run(ctx, () =>
|
||||||
ctx.res.res = res;
|
|
||||||
|
|
||||||
httpStorage.run(ctx, () =>
|
|
||||||
routeHandler(url).then(() => {
|
routeHandler(url).then(() => {
|
||||||
console.log(`${new Date().toISOString()} Request: ${url.pathname}`);
|
console.log(`${new Date().toISOString()} Request: ${url.pathname}`);
|
||||||
})
|
})
|
||||||
@ -33,7 +28,19 @@ http
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.listen(SERVER_PORT, () => {
|
|
||||||
console.log(`Service ${packageJson.name} is running at port ${SERVER_PORT}.`);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
/**
|
||||||
|
* @param {number} port
|
||||||
|
*/
|
||||||
|
async run(port = 3000) {
|
||||||
|
await db.connect().then(() => console.log("Database connected!"));
|
||||||
|
server.listen(port, () => {
|
||||||
|
console.log(`Service ${packageJson.name} is running at port ${SERVER_PORT}.`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
application().run(SERVER_PORT);
|
||||||
|
|||||||
56
package-lock.json
generated
56
package-lock.json
generated
@ -11,6 +11,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"formidable": "^3.5.4",
|
"formidable": "^3.5.4",
|
||||||
"mssql": "^12.2.0",
|
"mssql": "^12.2.0",
|
||||||
|
"serialize-error": "^13.0.1",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
"yup": "^1.7.1"
|
"yup": "^1.7.1"
|
||||||
},
|
},
|
||||||
@ -1612,6 +1613,18 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/non-error": {
|
||||||
|
"version": "0.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/non-error/-/non-error-0.1.0.tgz",
|
||||||
|
"integrity": "sha512-TMB1uHiGsHRGv1uYclfhivcnf0/PdFp2pNqRxXjncaAsjYMoisaQJI+SSZCqRq+VliwRTC8tsMQfmrWjDMhkPQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/once": {
|
"node_modules/once": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
@ -1839,6 +1852,37 @@
|
|||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/serialize-error": {
|
||||||
|
"version": "13.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-13.0.1.tgz",
|
||||||
|
"integrity": "sha512-bBZaRwLH9PN5HbLCjPId4dP5bNGEtumcErgOX952IsvOhVPrm3/AeK1y0UHA/QaPG701eg0yEnOKsCOC6X/kaA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"non-error": "^0.1.0",
|
||||||
|
"type-fest": "^5.4.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/serialize-error/node_modules/type-fest": {
|
||||||
|
"version": "5.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-5.4.4.tgz",
|
||||||
|
"integrity": "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw==",
|
||||||
|
"license": "(MIT OR CC0-1.0)",
|
||||||
|
"dependencies": {
|
||||||
|
"tagged-tag": "^1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/shebang-command": {
|
"node_modules/shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
@ -1905,6 +1949,18 @@
|
|||||||
"url": "https://opencollective.com/synckit"
|
"url": "https://opencollective.com/synckit"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tagged-tag": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=20"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tarn": {
|
"node_modules/tarn": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
|
||||||
|
|||||||
@ -15,6 +15,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"formidable": "^3.5.4",
|
"formidable": "^3.5.4",
|
||||||
"mssql": "^12.2.0",
|
"mssql": "^12.2.0",
|
||||||
|
"serialize-error": "^13.0.1",
|
||||||
"xlsx": "^0.18.5",
|
"xlsx": "^0.18.5",
|
||||||
"yup": "^1.7.1"
|
"yup": "^1.7.1"
|
||||||
},
|
},
|
||||||
|
|||||||
46
request.js
46
request.js
@ -1,19 +1,29 @@
|
|||||||
/** @type {HTTPRequest} */
|
/**
|
||||||
export default {
|
* @param {import('node:http').IncomingMessage} req
|
||||||
req: null,
|
* @returns {HTTPRequest}
|
||||||
async parseJson() {
|
*/
|
||||||
return new Promise((resolve, reject) => {
|
export function createRequest(req) {
|
||||||
let body = [];
|
return {
|
||||||
this.req.on("data", (chunk) => body.push(chunk));
|
get req() {
|
||||||
this.req.on("end", () => {
|
return req;
|
||||||
try {
|
},
|
||||||
const parsedJson = JSON.parse(Buffer.concat(body).toString());
|
|
||||||
resolve(parsedJson);
|
async parseJson() {
|
||||||
} catch (error) {
|
return new Promise((resolve, reject) => {
|
||||||
reject(error);
|
/** @type {Buffer[]} */
|
||||||
}
|
const body = [];
|
||||||
|
|
||||||
|
this.req.on("data", (chunk) => body.push(chunk));
|
||||||
|
this.req.on("end", () => {
|
||||||
|
try {
|
||||||
|
const parsedJson = JSON.parse(Buffer.concat(body).toString());
|
||||||
|
resolve(parsedJson);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.req.on("error", (err) => reject(err));
|
||||||
});
|
});
|
||||||
this.req.on("error", (err) => reject(err));
|
}
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|||||||
43
response.js
43
response.js
@ -1,14 +1,29 @@
|
|||||||
/** @type {HTTPResponse} */
|
/**
|
||||||
export default {
|
* @param {import('node:http').ServerResponse} res
|
||||||
res: null,
|
* @returns {HTTPResponse}
|
||||||
sendJson(data, statusCode = 200) {
|
*/
|
||||||
this.res.writeHead(statusCode, { "content-type": "application/json" });
|
export function createResponse(res) {
|
||||||
return this.res.end(JSON.stringify(data, null, 2));
|
return {
|
||||||
},
|
get res() {
|
||||||
sendText(text, statusCode = 200) {
|
return res;
|
||||||
this.res.writeHead(statusCode, {
|
},
|
||||||
"content-type": "text/plain; charset=utf-8"
|
|
||||||
});
|
sendSSEJson(data, eventName) {
|
||||||
return this.res.end(text);
|
this.res.write(`event: ${eventName}\n`);
|
||||||
}
|
this.res.write(`data: ${JSON.stringify(data)}`);
|
||||||
};
|
this.res.write("\n\n");
|
||||||
|
},
|
||||||
|
|
||||||
|
sendJson(data, statusCode = 200) {
|
||||||
|
this.res.writeHead(statusCode, { "content-type": "application/json" });
|
||||||
|
return this.res.end(JSON.stringify(data, null, 2));
|
||||||
|
},
|
||||||
|
|
||||||
|
sendText(text, statusCode = 200) {
|
||||||
|
this.res.writeHead(statusCode, {
|
||||||
|
"content-type": "text/plain; charset=utf-8"
|
||||||
|
});
|
||||||
|
return this.res.end(text);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import formidable from "formidable";
|
import formidable from "formidable";
|
||||||
import { httpStorage } from "#root/context.js";
|
import { ctxStorage } from "#root/context.js";
|
||||||
import { handlers as reportsHandlers } from "./reports/index.js";
|
import { handlers as reportsHandlers } from "./reports/index.js";
|
||||||
|
import { BadRequestError, HttpError, NotFoundError } from "#root/errors/index.js";
|
||||||
|
import { serializeError } from "serialize-error";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @type {HTTPRouteMap}
|
* @type {HTTPRouteMap}
|
||||||
@ -16,7 +18,7 @@ export const ROUTE_MAP = {
|
|||||||
filename: (_, ext) => `gpp-reports${ext}`,
|
filename: (_, ext) => `gpp-reports${ext}`,
|
||||||
keepExtensions: true,
|
keepExtensions: true,
|
||||||
uploadDir: path.join(process.cwd(), "./uploads"),
|
uploadDir: path.join(process.cwd(), "./uploads"),
|
||||||
filter: ({ mimetype }) => mimetype && mimetype.includes("application/vnd.ms-excel")
|
filter: ({ mimetype }) => !!mimetype && mimetype.includes("application/vnd.ms-excel")
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
"/api/reports_sync": {
|
"/api/reports_sync": {
|
||||||
@ -30,7 +32,7 @@ export const ROUTE_MAP = {
|
|||||||
*/
|
*/
|
||||||
export async function routeHandler(url) {
|
export async function routeHandler(url) {
|
||||||
/** @type {HTTPContext} */
|
/** @type {HTTPContext} */
|
||||||
const ctx = httpStorage.getStore();
|
const ctx = ctxStorage.getStore();
|
||||||
const { req, res } = ctx;
|
const { req, res } = ctx;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -42,28 +44,47 @@ export async function routeHandler(url) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.req.headers["content-type"]?.includes("multipart/form-data")) {
|
if (req.req.headers["content-type"]?.includes("multipart/form-data")) {
|
||||||
if (!route.incomingForm) throw new Error("Request cannot be processed without defined incoming form.");
|
if (!route.incomingForm) {
|
||||||
|
throw new BadRequestError("Request cannot be processed without defined incoming form.");
|
||||||
|
}
|
||||||
|
|
||||||
ctx.data = await route.incomingForm.parse(req.req);
|
ctx.data = await route.incomingForm.parse(req.req);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (route.method === req.req.method) {
|
if (route.method === req.req.method) {
|
||||||
await route.handle(ctx);
|
await route.handle(ctx);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotFoundError("Route not found");
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
if (error instanceof HttpError) {
|
||||||
|
res.sendJson(
|
||||||
|
{
|
||||||
|
error: {
|
||||||
|
name: error.name,
|
||||||
|
message: error.message || "Internal Server Error",
|
||||||
|
stack: error.stack || null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
error.statusCode || 500
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
res.sendJson({ error: { message: "Route not found." } }, 404);
|
const serializedError = serializeError(error);
|
||||||
} catch (error) {
|
|
||||||
console.error(error);
|
|
||||||
res.sendJson(
|
res.sendJson(
|
||||||
{
|
{
|
||||||
error: {
|
error: {
|
||||||
message: error?.message || "Internal Server Error",
|
...serializedError,
|
||||||
stack: error?.stack || null
|
stack: process.env.NODE_ENV !== "production" ? serializedError.stack : undefined
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
error?.cause?.statusCode || 500
|
500
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
import { BadRequestError } from "#root/errors/index.js";
|
||||||
|
import db from "#root/db.js";
|
||||||
import xlsx from "xlsx";
|
import xlsx from "xlsx";
|
||||||
|
|
||||||
const sheetName = "Отчеты";
|
const sheetName = "Отчеты";
|
||||||
@ -12,18 +14,34 @@ const xlsxParseOptions = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Читает Excel файл отчетов и возвращает его в формате JSON
|
* URL: /api/reports_excel_file_parse
|
||||||
|
* Method: POST
|
||||||
|
* Description: Читает Excel файл отчетов и возвращает его в формате JSON. Принимает на вход файл
|
||||||
|
* отчетов в формате Excel.
|
||||||
*
|
*
|
||||||
* @type {HTTPRouteHandler}
|
* @type {HTTPRouteHandler}
|
||||||
*/
|
*/
|
||||||
export default async (ctx) => {
|
export default async (ctx) => {
|
||||||
const { res } = ctx;
|
const { res } = ctx;
|
||||||
|
|
||||||
|
if (!ctx.data) throw new BadRequestError("Cannot proceed uploaded file");
|
||||||
|
|
||||||
const [, files] = ctx.data;
|
const [, files] = ctx.data;
|
||||||
const excelFilePath = files?.report?.at(0)?.filepath;
|
const excelFilePath = files?.report?.at(0)?.filepath;
|
||||||
|
|
||||||
/** @type {{ markedReports: ReportModel[], reports: ReportModel[] }} */
|
/** @type {{ markedReports: ReportModel[], reports: ReportModel[] }} */
|
||||||
const ret = { reports: [], markedReports: [] };
|
const ret = { reports: [], markedReports: [] };
|
||||||
|
|
||||||
|
let foundEqupments = 0;
|
||||||
|
|
||||||
|
ctx.res.res.setHeaders(
|
||||||
|
new Headers({
|
||||||
|
Connection: "keep-alive",
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
"Content-Type": "text/event-stream"
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
if (excelFilePath) {
|
if (excelFilePath) {
|
||||||
const workbook = xlsx.readFile(excelFilePath, xlsxParseOptions);
|
const workbook = xlsx.readFile(excelFilePath, xlsxParseOptions);
|
||||||
const sheet = workbook.Sheets[sheetName];
|
const sheet = workbook.Sheets[sheetName];
|
||||||
@ -63,11 +81,29 @@ export default async (ctx) => {
|
|||||||
executorNames: parseNames(data[i][cols[4]])
|
executorNames: parseNames(data[i][cols[4]])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param {ReportModel} report */
|
||||||
|
const checkReportAssigments = async (report) => {
|
||||||
|
const equipment = await db
|
||||||
|
.request()
|
||||||
|
.query(`select id, name from dbo.asu_system_api_subsystemlist where name like N'%${report.equipment}%';`);
|
||||||
|
|
||||||
|
if (equipment.recordset.length !== 0) foundEqupments++;
|
||||||
|
|
||||||
|
res.sendSSEJson(report, "reportParseProgress");
|
||||||
|
|
||||||
|
return equipment;
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log("Total reports:", ret.reports.concat(ret.markedReports).length);
|
||||||
|
await Promise.allSettled(ret.reports.concat(ret.markedReports).map((r) => checkReportAssigments(r)));
|
||||||
|
ctx.res.sendSSEJson({ foundEqupments }, "reportParseDone");
|
||||||
|
console.log("Parse done");
|
||||||
} else {
|
} else {
|
||||||
throw new Error("Bad request", { cause: { statusCode: 400 } });
|
throw new BadRequestError();
|
||||||
}
|
}
|
||||||
|
|
||||||
res.sendJson({ data: ret });
|
res.res.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
function parseReasonCallAndJobDesc(str = "") {
|
function parseReasonCallAndJobDesc(str = "") {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user