@oondemand/oon-core-back 0.3.65 → 0.3.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const express = require("express");
|
|
4
|
+
const mongoose = require("mongoose");
|
|
4
5
|
const GenericError = require("../../core/errors/GenericError");
|
|
5
6
|
const auth = require("../../core/middlewares/auth");
|
|
6
7
|
const { rbac } = require("../../core/middlewares/rbac");
|
|
7
8
|
const { asyncHandler } = require("../../core/utils/helpers");
|
|
8
|
-
const { getIntegrationModels } = require("./models");
|
|
9
|
+
const { getIntegrationModels, OUTBOX_STATUSES } = require("./models");
|
|
9
10
|
const { getIntegrationProvider, listIntegrationProviders } = require("./registry");
|
|
10
11
|
const {
|
|
11
12
|
archiveIntegrationTicket,
|
|
@@ -33,6 +34,48 @@ function pagination(query = {}) {
|
|
|
33
34
|
return { limit, page, skip: (page - 1) * limit };
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
function escapeRegExp(value) {
|
|
38
|
+
return String(value).replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function buildQueueFilter(query = {}, options = {}) {
|
|
42
|
+
const includeStatus = options.includeStatus !== false;
|
|
43
|
+
const filter = {};
|
|
44
|
+
for (const field of ["provider", "resource", "operation", "aggregateType", "aggregateId"]) {
|
|
45
|
+
if (query[field]) filter[field] = String(query[field]);
|
|
46
|
+
}
|
|
47
|
+
if (includeStatus && query.status) filter.status = String(query.status);
|
|
48
|
+
|
|
49
|
+
const search = String(query.search || "").trim().slice(0, 160);
|
|
50
|
+
if (search) {
|
|
51
|
+
const pattern = new RegExp(escapeRegExp(search), "i");
|
|
52
|
+
const clauses = [
|
|
53
|
+
{ handler: pattern },
|
|
54
|
+
{ resource: pattern },
|
|
55
|
+
{ operation: pattern },
|
|
56
|
+
{ aggregateType: pattern },
|
|
57
|
+
{ aggregateId: pattern },
|
|
58
|
+
{ idempotencyKey: pattern },
|
|
59
|
+
];
|
|
60
|
+
if (mongoose.isValidObjectId(search)) clauses.unshift({ _id: new mongoose.Types.ObjectId(search) });
|
|
61
|
+
filter.$or = clauses;
|
|
62
|
+
}
|
|
63
|
+
return filter;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function queueStatusSummary(Outbox, filter = {}) {
|
|
67
|
+
const rows = await Outbox.aggregate([
|
|
68
|
+
{ $match: filter },
|
|
69
|
+
{ $group: { _id: "$status", count: { $sum: 1 } } },
|
|
70
|
+
]);
|
|
71
|
+
const statuses = Object.fromEntries(OUTBOX_STATUSES.map((status) => [status, 0]));
|
|
72
|
+
for (const row of rows) statuses[String(row._id)] = Number(row.count || 0);
|
|
73
|
+
return {
|
|
74
|
+
total: Object.values(statuses).reduce((sum, count) => sum + Number(count || 0), 0),
|
|
75
|
+
statuses,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
36
79
|
function requireProviderExtension(provider, method, message) {
|
|
37
80
|
if (typeof provider[method] !== "function") {
|
|
38
81
|
throw new GenericError(message || `O provedor ${provider.label} não oferece ${method}.`, {
|
|
@@ -144,16 +187,16 @@ function buildIntegrationRouter() {
|
|
|
144
187
|
router.get("/queue", rbac(READ_ROLES), asyncHandler(async (req, res) => {
|
|
145
188
|
const { Outbox } = getIntegrationModels();
|
|
146
189
|
const { limit, page, skip } = pagination(req.query);
|
|
147
|
-
const filter =
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
const [results, totalItems] = await Promise.all([
|
|
190
|
+
const filter = buildQueueFilter(req.query);
|
|
191
|
+
const summaryFilter = buildQueueFilter(req.query, { includeStatus: false });
|
|
192
|
+
const [results, totalItems, summary] = await Promise.all([
|
|
152
193
|
Outbox.find(filter).sort({ createdAt: -1 }).skip(skip).limit(limit).lean(),
|
|
153
194
|
Outbox.countDocuments(filter),
|
|
195
|
+
queueStatusSummary(Outbox, summaryFilter),
|
|
154
196
|
]);
|
|
155
197
|
res.json({
|
|
156
198
|
results: sanitizeIntegrationValue(results),
|
|
199
|
+
summary,
|
|
157
200
|
pagination: {
|
|
158
201
|
currentPage: page,
|
|
159
202
|
totalItems,
|
|
@@ -222,4 +265,4 @@ function buildIntegrationRouter() {
|
|
|
222
265
|
return router;
|
|
223
266
|
}
|
|
224
267
|
|
|
225
|
-
module.exports = { buildIntegrationRouter };
|
|
268
|
+
module.exports = { buildIntegrationRouter, buildQueueFilter, queueStatusSummary };
|
|
@@ -13,6 +13,21 @@ function truncate(value, limit) {
|
|
|
13
13
|
return `${value.slice(0, limit)}…[truncado:${value.length - limit}]`;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
function binarySummary(value) {
|
|
17
|
+
const size = Number(value?.byteLength ?? value?.length ?? 0);
|
|
18
|
+
const type = value?.constructor?.name || "Binary";
|
|
19
|
+
return `[${type}:${size} bytes]`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function bsonObjectId(value) {
|
|
23
|
+
if (!value || typeof value !== "object") return null;
|
|
24
|
+
const isObjectId = value._bsontype === "ObjectId" || value.constructor?.name === "ObjectId";
|
|
25
|
+
if (!isObjectId) return null;
|
|
26
|
+
if (typeof value.toHexString === "function") return value.toHexString();
|
|
27
|
+
const text = String(value);
|
|
28
|
+
return /^[a-f\d]{24}$/i.test(text) ? text : null;
|
|
29
|
+
}
|
|
30
|
+
|
|
16
31
|
function sanitizeIntegrationValue(value, options = {}, state = { depth: 0, seen: new WeakSet() }) {
|
|
17
32
|
const config = { ...DEFAULTS, ...options };
|
|
18
33
|
if (value == null || typeof value === "boolean" || typeof value === "number") return value;
|
|
@@ -28,6 +43,12 @@ function sanitizeIntegrationValue(value, options = {}, state = { depth: 0, seen:
|
|
|
28
43
|
};
|
|
29
44
|
}
|
|
30
45
|
if (typeof value !== "object") return truncate(String(value), config.maxStringLength);
|
|
46
|
+
|
|
47
|
+
const objectId = bsonObjectId(value);
|
|
48
|
+
if (objectId) return objectId;
|
|
49
|
+
if (Buffer.isBuffer(value) || ArrayBuffer.isView(value)) return binarySummary(value);
|
|
50
|
+
if (value instanceof ArrayBuffer) return binarySummary(value);
|
|
51
|
+
|
|
31
52
|
if (state.depth >= config.maxDepth) return "[limite-de-profundidade]";
|
|
32
53
|
if (state.seen.has(value)) return "[referência-circular]";
|
|
33
54
|
state.seen.add(value);
|