@7365admin1/core 3.32.2-staging.77 → 3.32.2-staging.79
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/.changeset/site-name-similarity-check.md +26 -0
- package/dist/index.d.ts +14 -9
- package/dist/index.js +251 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +251 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/test/site-name.util.test.mjs +146 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
"@7365admin1/core": patch
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
Stop rejecting site names that only differ by their building number
|
|
6
|
+
|
|
7
|
+
Adding a site refused any name within a Levenshtein distance of 2 of an
|
|
8
|
+
existing site in the same organisation, and told the user to contact support.
|
|
9
|
+
That is exactly one character, so "Winsland House II" could not be added next
|
|
10
|
+
to "Winsland House I". The same rule blocked "Tower A" beside "Tower B",
|
|
11
|
+
"Phase 2" beside "Phase 1" and "Block 15" beside "Block 5" — the standard way
|
|
12
|
+
buildings are named here.
|
|
13
|
+
|
|
14
|
+
The check now treats trailing numbers, Roman numerals and single letters as the
|
|
15
|
+
part that tells two buildings apart: if they differ, the names are different
|
|
16
|
+
sites and the distance is never measured. Real duplicates are still refused —
|
|
17
|
+
an exact repeat, a different capitalisation, stray or doubled whitespace,
|
|
18
|
+
punctuation-only differences, and a one or two character typo within the same
|
|
19
|
+
building. "House 1" and "House I" are still read as the same building.
|
|
20
|
+
|
|
21
|
+
The refusal now names the site it matched and says what to do about it instead
|
|
22
|
+
of pointing the user at support.
|
|
23
|
+
|
|
24
|
+
`site.repo.getByExactName` also built its case-insensitive regex from the raw
|
|
25
|
+
name; a name containing regex characters either threw or matched a site it is
|
|
26
|
+
not. It is escaped.
|
package/dist/index.d.ts
CHANGED
|
@@ -9209,7 +9209,7 @@ type HidObjectBatch = {
|
|
|
9209
9209
|
};
|
|
9210
9210
|
type HidObjectQuery = {
|
|
9211
9211
|
object: string;
|
|
9212
|
-
where?:
|
|
9212
|
+
where?: UnknownRecord;
|
|
9213
9213
|
fields?: string[];
|
|
9214
9214
|
order?: string[];
|
|
9215
9215
|
limit?: number;
|
|
@@ -9241,14 +9241,19 @@ declare function useHidAmicoService(): {
|
|
|
9241
9241
|
message: string;
|
|
9242
9242
|
results: Record<string, any>[];
|
|
9243
9243
|
}>;
|
|
9244
|
-
receiveNotification: (readerId: string, type: string, payload:
|
|
9245
|
-
|
|
9246
|
-
|
|
9247
|
-
|
|
9248
|
-
|
|
9249
|
-
|
|
9250
|
-
|
|
9251
|
-
|
|
9244
|
+
receiveNotification: (readerId: string, type: string, payload: UnknownRecord) => Promise<{
|
|
9245
|
+
event: {
|
|
9246
|
+
_id: bson.ObjectId;
|
|
9247
|
+
reader: bson.ObjectId;
|
|
9248
|
+
site: bson.ObjectId | undefined;
|
|
9249
|
+
type: string;
|
|
9250
|
+
payload: Record<string, any>;
|
|
9251
|
+
status: "failed" | "received" | "processed";
|
|
9252
|
+
createdAt: string | Date;
|
|
9253
|
+
};
|
|
9254
|
+
response: {
|
|
9255
|
+
result: UnknownRecord;
|
|
9256
|
+
} | null;
|
|
9252
9257
|
}>;
|
|
9253
9258
|
listLogs: (value: {
|
|
9254
9259
|
reader: string;
|
package/dist/index.js
CHANGED
|
@@ -11811,8 +11811,9 @@ function useSiteRepo() {
|
|
|
11811
11811
|
} catch (error2) {
|
|
11812
11812
|
throw new import_node_server_utils19.BadRequestError("Invalid org ID format.");
|
|
11813
11813
|
}
|
|
11814
|
+
const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
11814
11815
|
const query2 = {
|
|
11815
|
-
name: { $regex: new RegExp(`^${
|
|
11816
|
+
name: { $regex: new RegExp(`^${escapedName}$`, "i") },
|
|
11816
11817
|
// Case-insensitive exact match
|
|
11817
11818
|
orgId,
|
|
11818
11819
|
status: { $ne: "deleted" }
|
|
@@ -35083,7 +35084,57 @@ function useCustomerSiteRepo() {
|
|
|
35083
35084
|
|
|
35084
35085
|
// src/services/customer-site.service.ts
|
|
35085
35086
|
var import_node_server_utils98 = require("@7365admin1/node-server-utils");
|
|
35087
|
+
|
|
35088
|
+
// src/utils/site-name.util.ts
|
|
35086
35089
|
var import_fast_levenshtein = __toESM(require("fast-levenshtein"));
|
|
35090
|
+
var ROMAN = /^(?=[ivx])(x{0,3})(ix|iv|v?i{0,3})$/;
|
|
35091
|
+
var ROMAN_VALUE = { i: 1, v: 5, x: 10 };
|
|
35092
|
+
function normalizeSiteName(name) {
|
|
35093
|
+
return String(name ?? "").normalize("NFKC").toLowerCase().replace(/[‘’']/g, "").replace(/[^a-z0-9]+/g, " ").trim();
|
|
35094
|
+
}
|
|
35095
|
+
function romanToNumber(token) {
|
|
35096
|
+
let total = 0;
|
|
35097
|
+
for (let i = 0; i < token.length; i++) {
|
|
35098
|
+
const value = ROMAN_VALUE[token[i]];
|
|
35099
|
+
const next = ROMAN_VALUE[token[i + 1]];
|
|
35100
|
+
total += next && next > value ? -value : value;
|
|
35101
|
+
}
|
|
35102
|
+
return total;
|
|
35103
|
+
}
|
|
35104
|
+
function distinguishingTokens(normalized) {
|
|
35105
|
+
if (!normalized)
|
|
35106
|
+
return [];
|
|
35107
|
+
return normalized.split(" ").filter((t) => /^\d+$/.test(t) || ROMAN.test(t) || /^[a-z]$/.test(t)).map((t) => ROMAN.test(t) ? String(romanToNumber(t)) : t);
|
|
35108
|
+
}
|
|
35109
|
+
function matchSiteName(candidate, existing) {
|
|
35110
|
+
const a = normalizeSiteName(candidate);
|
|
35111
|
+
const b = normalizeSiteName(existing);
|
|
35112
|
+
if (!a || !b)
|
|
35113
|
+
return null;
|
|
35114
|
+
if (a === b)
|
|
35115
|
+
return "duplicate";
|
|
35116
|
+
const tokensA = distinguishingTokens(a).join(" ");
|
|
35117
|
+
const tokensB = distinguishingTokens(b).join(" ");
|
|
35118
|
+
if (tokensA !== tokensB)
|
|
35119
|
+
return null;
|
|
35120
|
+
return import_fast_levenshtein.default.get(a, b) <= 2 ? "near-duplicate" : null;
|
|
35121
|
+
}
|
|
35122
|
+
function findSiteNameClash(candidate, existingNames) {
|
|
35123
|
+
for (const name of existingNames) {
|
|
35124
|
+
const match = matchSiteName(candidate, name);
|
|
35125
|
+
if (match)
|
|
35126
|
+
return { name, match };
|
|
35127
|
+
}
|
|
35128
|
+
return null;
|
|
35129
|
+
}
|
|
35130
|
+
function siteNameClashMessage(existingName, match) {
|
|
35131
|
+
if (match === "duplicate") {
|
|
35132
|
+
return `A site called "${existingName}" already exists in this organisation. Give the new site a different name, or edit "${existingName}" instead.`;
|
|
35133
|
+
}
|
|
35134
|
+
return `This name is within a character or two of "${existingName}", which already exists in this organisation. If it is the same property, edit "${existingName}" instead. If it is a different one, include what tells them apart \u2014 the block, tower, phase, or number \u2014 and save again.`;
|
|
35135
|
+
}
|
|
35136
|
+
|
|
35137
|
+
// src/services/customer-site.service.ts
|
|
35087
35138
|
function useCustomerSiteService() {
|
|
35088
35139
|
const { add: _add, updateCustomerSiteById, getById: _getById } = useCustomerSiteRepo();
|
|
35089
35140
|
const {
|
|
@@ -35105,20 +35156,18 @@ function useCustomerSiteService() {
|
|
|
35105
35156
|
const exactMatches = await getSiteByExactName(value.name, value.siteOrg);
|
|
35106
35157
|
if (exactMatches && exactMatches.length > 0) {
|
|
35107
35158
|
throw new import_node_server_utils98.BadRequestError(
|
|
35108
|
-
|
|
35159
|
+
siteNameClashMessage(exactMatches[0].name, "duplicate")
|
|
35109
35160
|
);
|
|
35110
35161
|
}
|
|
35111
|
-
const threshold = 2;
|
|
35112
35162
|
const sites = await getSiteByName(value.name);
|
|
35113
|
-
|
|
35114
|
-
|
|
35115
|
-
|
|
35116
|
-
|
|
35117
|
-
|
|
35118
|
-
|
|
35119
|
-
|
|
35120
|
-
|
|
35121
|
-
}
|
|
35163
|
+
const candidates = (sites ?? []).filter(
|
|
35164
|
+
(doc) => doc.orgId && doc.name && doc.orgId.toString() === value.siteOrg.toString()
|
|
35165
|
+
).map((doc) => doc.name);
|
|
35166
|
+
const clash = findSiteNameClash(value.name, candidates);
|
|
35167
|
+
if (clash) {
|
|
35168
|
+
throw new import_node_server_utils98.BadRequestError(
|
|
35169
|
+
siteNameClashMessage(clash.name, clash.match)
|
|
35170
|
+
);
|
|
35122
35171
|
}
|
|
35123
35172
|
const siteId = await createSite(
|
|
35124
35173
|
{
|
|
@@ -74389,6 +74438,8 @@ var schemaHidAmicoNotificationParams = import_joi153.default.object({
|
|
|
74389
74438
|
"secbox",
|
|
74390
74439
|
"access_photo",
|
|
74391
74440
|
"new_user_identified",
|
|
74441
|
+
"new_qrcode",
|
|
74442
|
+
"new_card",
|
|
74392
74443
|
"push_result"
|
|
74393
74444
|
).required()
|
|
74394
74445
|
});
|
|
@@ -75220,6 +75271,8 @@ async function configureVisitorQrReader(client, qrFormat) {
|
|
|
75220
75271
|
}
|
|
75221
75272
|
async function ensureVisitorAccessAuthorization(client, readerId, readerLocation, hidUserId) {
|
|
75222
75273
|
const accessRuleId = createStableHidId(`visitor-access-rule:${readerId}`);
|
|
75274
|
+
const timeZoneId = createStableHidId(`visitor-time-zone:${readerId}`);
|
|
75275
|
+
const timeSpanId = createStableHidId(`visitor-time-span:${readerId}`);
|
|
75223
75276
|
const existingRuleResponse = await client.loadObjects({
|
|
75224
75277
|
object: "access_rules",
|
|
75225
75278
|
where: { access_rules: { id: accessRuleId } },
|
|
@@ -75247,6 +75300,74 @@ async function ensureVisitorAccessAuthorization(client, readerId, readerLocation
|
|
|
75247
75300
|
}]
|
|
75248
75301
|
});
|
|
75249
75302
|
}
|
|
75303
|
+
const existingTimeZoneResponse = await client.loadObjects({
|
|
75304
|
+
object: "time_zones",
|
|
75305
|
+
where: { time_zones: { id: timeZoneId } },
|
|
75306
|
+
limit: 1,
|
|
75307
|
+
offset: 0
|
|
75308
|
+
});
|
|
75309
|
+
if (getHidObjectRows(existingTimeZoneResponse, "time_zones").length) {
|
|
75310
|
+
await client.modifyObjects({
|
|
75311
|
+
object: "time_zones",
|
|
75312
|
+
where: { time_zones: { id: timeZoneId } },
|
|
75313
|
+
values: { name: "iService365 Visitor Schedule" }
|
|
75314
|
+
});
|
|
75315
|
+
} else {
|
|
75316
|
+
await client.createObjects({
|
|
75317
|
+
object: "time_zones",
|
|
75318
|
+
values: [{ id: timeZoneId, name: "iService365 Visitor Schedule" }]
|
|
75319
|
+
});
|
|
75320
|
+
}
|
|
75321
|
+
const visitorTimeSpan = {
|
|
75322
|
+
time_zone_id: timeZoneId,
|
|
75323
|
+
start: 0,
|
|
75324
|
+
end: 86399,
|
|
75325
|
+
sun: 1,
|
|
75326
|
+
mon: 1,
|
|
75327
|
+
tue: 1,
|
|
75328
|
+
wed: 1,
|
|
75329
|
+
thu: 1,
|
|
75330
|
+
fri: 1,
|
|
75331
|
+
sat: 1,
|
|
75332
|
+
hol1: 1,
|
|
75333
|
+
hol2: 1,
|
|
75334
|
+
hol3: 1
|
|
75335
|
+
};
|
|
75336
|
+
const existingTimeSpanResponse = await client.loadObjects({
|
|
75337
|
+
object: "time_spans",
|
|
75338
|
+
where: { time_spans: { id: timeSpanId } },
|
|
75339
|
+
limit: 1,
|
|
75340
|
+
offset: 0
|
|
75341
|
+
});
|
|
75342
|
+
if (getHidObjectRows(existingTimeSpanResponse, "time_spans").length) {
|
|
75343
|
+
await client.modifyObjects({
|
|
75344
|
+
object: "time_spans",
|
|
75345
|
+
where: { time_spans: { id: timeSpanId } },
|
|
75346
|
+
values: visitorTimeSpan
|
|
75347
|
+
});
|
|
75348
|
+
} else {
|
|
75349
|
+
await client.createObjects({
|
|
75350
|
+
object: "time_spans",
|
|
75351
|
+
values: [{ id: timeSpanId, ...visitorTimeSpan }]
|
|
75352
|
+
});
|
|
75353
|
+
}
|
|
75354
|
+
const accessRuleTimeZoneResponse = await client.loadObjects({
|
|
75355
|
+
object: "access_rule_time_zones",
|
|
75356
|
+
where: {
|
|
75357
|
+
access_rule_time_zones: {
|
|
75358
|
+
access_rule_id: accessRuleId,
|
|
75359
|
+
time_zone_id: timeZoneId
|
|
75360
|
+
}
|
|
75361
|
+
},
|
|
75362
|
+
limit: 1,
|
|
75363
|
+
offset: 0
|
|
75364
|
+
});
|
|
75365
|
+
if (!getHidObjectRows(accessRuleTimeZoneResponse, "access_rule_time_zones").length) {
|
|
75366
|
+
await client.createObjects({
|
|
75367
|
+
object: "access_rule_time_zones",
|
|
75368
|
+
values: [{ access_rule_id: accessRuleId, time_zone_id: timeZoneId }]
|
|
75369
|
+
});
|
|
75370
|
+
}
|
|
75250
75371
|
const portalsResponse = await client.loadObjects({
|
|
75251
75372
|
object: "portals",
|
|
75252
75373
|
limit: 100,
|
|
@@ -75301,7 +75422,7 @@ async function ensureVisitorAccessAuthorization(client, readerId, readerLocation
|
|
|
75301
75422
|
values: missingPortalLinks
|
|
75302
75423
|
});
|
|
75303
75424
|
}
|
|
75304
|
-
return { accessRuleId, portalIds };
|
|
75425
|
+
return { accessRuleId, portalIds, timeZoneId };
|
|
75305
75426
|
}
|
|
75306
75427
|
function getRelayAuth() {
|
|
75307
75428
|
const username = process.env.HID_AMICO_RELAY_USERNAME;
|
|
@@ -75639,19 +75760,95 @@ function normalizeBatches(payload) {
|
|
|
75639
75760
|
function firstValue(payload, keys) {
|
|
75640
75761
|
for (const key of keys) {
|
|
75641
75762
|
const value = payload?.[key];
|
|
75642
|
-
if (value
|
|
75763
|
+
if ((typeof value === "string" || typeof value === "number") && value !== "") {
|
|
75643
75764
|
return value;
|
|
75644
75765
|
}
|
|
75645
75766
|
}
|
|
75646
75767
|
return void 0;
|
|
75647
75768
|
}
|
|
75648
75769
|
function extractIdentityKeys(payload) {
|
|
75649
|
-
const
|
|
75770
|
+
const nestedCandidate = payload.user || payload.person || payload.data;
|
|
75771
|
+
const nested = isUnknownRecord(nestedCandidate) ? nestedCandidate : {};
|
|
75650
75772
|
const merged = { ...payload, ...nested };
|
|
75773
|
+
const hidUserId = firstValue(merged, ["hidUserId", "hid_user_id", "user_id", "userId", "id", "user"]);
|
|
75774
|
+
const registration = firstValue(merged, ["registration", "register", "employeeNo", "staffNo", "memberNo"]);
|
|
75775
|
+
const cardNo = firstValue(merged, [
|
|
75776
|
+
"qrcode_value",
|
|
75777
|
+
"qrCodeValue",
|
|
75778
|
+
"qr_code_value",
|
|
75779
|
+
"card_value",
|
|
75780
|
+
"cardNo",
|
|
75781
|
+
"card_no",
|
|
75782
|
+
"card",
|
|
75783
|
+
"cardNumber",
|
|
75784
|
+
"value"
|
|
75785
|
+
]);
|
|
75651
75786
|
return {
|
|
75652
|
-
hidUserId
|
|
75653
|
-
registration:
|
|
75654
|
-
cardNo:
|
|
75787
|
+
hidUserId,
|
|
75788
|
+
registration: registration === void 0 ? void 0 : String(registration),
|
|
75789
|
+
cardNo: cardNo === void 0 ? void 0 : String(cardNo)
|
|
75790
|
+
};
|
|
75791
|
+
}
|
|
75792
|
+
function toPositiveInteger(value) {
|
|
75793
|
+
const parsed = Number(value);
|
|
75794
|
+
return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : null;
|
|
75795
|
+
}
|
|
75796
|
+
function toDateTimestamp(value) {
|
|
75797
|
+
if (value instanceof Date)
|
|
75798
|
+
return value.getTime();
|
|
75799
|
+
if (typeof value !== "string" && typeof value !== "number")
|
|
75800
|
+
return null;
|
|
75801
|
+
const parsed = new Date(value).getTime();
|
|
75802
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
75803
|
+
}
|
|
75804
|
+
function buildOnlineIdentificationResponse(identity, payload) {
|
|
75805
|
+
const metadata = identity && isUnknownRecord(identity.metadata) ? identity.metadata : {};
|
|
75806
|
+
const requestedPortalId = toPositiveInteger(payload.portal_id ?? payload.portalId);
|
|
75807
|
+
const configuredPortalIds = Array.isArray(metadata.portalIds) ? metadata.portalIds.map(toPositiveInteger).filter((value) => value !== null) : [];
|
|
75808
|
+
const portalId = requestedPortalId ?? (configuredPortalIds.length === 1 ? configuredPortalIds[0] : null);
|
|
75809
|
+
const now = Date.now();
|
|
75810
|
+
const issuedAt = toDateTimestamp(metadata.issuedAt);
|
|
75811
|
+
const expiresAt = toDateTimestamp(metadata.expiresAt);
|
|
75812
|
+
let deniedReason = "User is not registered for this reader.";
|
|
75813
|
+
if (identity) {
|
|
75814
|
+
deniedReason = "Access denied.";
|
|
75815
|
+
if (identity.type === "visitor" && issuedAt !== null && now < issuedAt) {
|
|
75816
|
+
deniedReason = "Visitor pass is not active yet.";
|
|
75817
|
+
} else if (identity.type === "visitor" && expiresAt !== null && now > expiresAt) {
|
|
75818
|
+
deniedReason = "Visitor pass has expired.";
|
|
75819
|
+
} else if (identity.type === "visitor" && configuredPortalIds.length > 0 && requestedPortalId !== null && !configuredPortalIds.includes(requestedPortalId)) {
|
|
75820
|
+
deniedReason = "Visitor is not permitted to use this portal.";
|
|
75821
|
+
} else {
|
|
75822
|
+
const userId = toPositiveInteger(identity.hidUserId ?? payload.user_id);
|
|
75823
|
+
const userName = String(metadata.name ?? payload.user_name ?? "").trim();
|
|
75824
|
+
const result = {
|
|
75825
|
+
event: 7,
|
|
75826
|
+
user_id: userId ?? 0,
|
|
75827
|
+
user_name: userName,
|
|
75828
|
+
user_image: Boolean(metadata.facialEnrolled),
|
|
75829
|
+
portal_id: portalId === null ? "" : String(portalId),
|
|
75830
|
+
message: "Access granted"
|
|
75831
|
+
};
|
|
75832
|
+
if (portalId !== null) {
|
|
75833
|
+
result.actions = [{ action: "door", parameters: `door=${portalId}` }];
|
|
75834
|
+
}
|
|
75835
|
+
return { granted: true, reason: "Access granted", response: { result } };
|
|
75836
|
+
}
|
|
75837
|
+
}
|
|
75838
|
+
return {
|
|
75839
|
+
granted: false,
|
|
75840
|
+
reason: deniedReason,
|
|
75841
|
+
response: {
|
|
75842
|
+
result: {
|
|
75843
|
+
event: 6,
|
|
75844
|
+
user_id: toPositiveInteger(identity?.hidUserId ?? payload.user_id) ?? 0,
|
|
75845
|
+
user_name: String(metadata.name ?? payload.user_name ?? "").trim(),
|
|
75846
|
+
user_image: Boolean(metadata.facialEnrolled),
|
|
75847
|
+
portal_id: portalId === null ? "" : String(portalId),
|
|
75848
|
+
actions: [],
|
|
75849
|
+
message: deniedReason
|
|
75850
|
+
}
|
|
75851
|
+
}
|
|
75655
75852
|
};
|
|
75656
75853
|
}
|
|
75657
75854
|
function useHidAmicoService() {
|
|
@@ -75805,6 +76002,7 @@ function useHidAmicoService() {
|
|
|
75805
76002
|
reader: readerId,
|
|
75806
76003
|
...identityKeys
|
|
75807
76004
|
});
|
|
76005
|
+
const authorization = ["new_user_identified", "new_qrcode", "new_card"].includes(type) ? buildOnlineIdentificationResponse(identity, payload) : null;
|
|
75808
76006
|
const enrichedPayload = identity ? {
|
|
75809
76007
|
...payload,
|
|
75810
76008
|
identity: {
|
|
@@ -75817,20 +76015,33 @@ function useHidAmicoService() {
|
|
|
75817
76015
|
user: identity.user,
|
|
75818
76016
|
member: identity.member,
|
|
75819
76017
|
visitor: identity.visitor
|
|
75820
|
-
}
|
|
76018
|
+
},
|
|
76019
|
+
...authorization ? {
|
|
76020
|
+
authorization: {
|
|
76021
|
+
granted: authorization.granted,
|
|
76022
|
+
reason: authorization.reason
|
|
76023
|
+
}
|
|
76024
|
+
} : {}
|
|
75821
76025
|
} : {
|
|
75822
76026
|
...payload,
|
|
75823
76027
|
identity: null,
|
|
75824
|
-
identityLookup: identityKeys
|
|
76028
|
+
identityLookup: identityKeys,
|
|
76029
|
+
...authorization ? {
|
|
76030
|
+
authorization: {
|
|
76031
|
+
granted: authorization.granted,
|
|
76032
|
+
reason: authorization.reason
|
|
76033
|
+
}
|
|
76034
|
+
} : {}
|
|
75825
76035
|
};
|
|
75826
76036
|
await repo.updateById(readerId, { lastSeenAt: /* @__PURE__ */ new Date() });
|
|
75827
|
-
|
|
76037
|
+
const event = await repo.addEvent({
|
|
75828
76038
|
reader: readerId,
|
|
75829
76039
|
site: reader.site,
|
|
75830
76040
|
type,
|
|
75831
76041
|
payload: enrichedPayload,
|
|
75832
|
-
status: identity ? "processed" : "received"
|
|
76042
|
+
status: authorization ? authorization.granted ? "processed" : "failed" : identity ? "processed" : "received"
|
|
75833
76043
|
});
|
|
76044
|
+
return { event, response: authorization?.response ?? null };
|
|
75834
76045
|
}
|
|
75835
76046
|
async function listLogs(value) {
|
|
75836
76047
|
return repo.listEvents(value);
|
|
@@ -75972,6 +76183,7 @@ function useHidAmicoService() {
|
|
|
75972
76183
|
const identityPayload = {
|
|
75973
76184
|
hidUserId: String(hidUserId),
|
|
75974
76185
|
registration,
|
|
76186
|
+
cardNo: credential.qrValue,
|
|
75975
76187
|
visitor: value.visitorId,
|
|
75976
76188
|
type: "visitor",
|
|
75977
76189
|
status: "active",
|
|
@@ -75981,8 +76193,10 @@ function useHidAmicoService() {
|
|
|
75981
76193
|
qrFormat: value.qrFormat,
|
|
75982
76194
|
credentialObject: credential.object,
|
|
75983
76195
|
credentialId: credential.credentialId,
|
|
76196
|
+
qrValue: credential.qrValue,
|
|
75984
76197
|
accessRuleId: authorization.accessRuleId,
|
|
75985
76198
|
portalIds: authorization.portalIds,
|
|
76199
|
+
timeZoneId: authorization.timeZoneId,
|
|
75986
76200
|
issuedAt: issuedAt.toISOString(),
|
|
75987
76201
|
expiresAt: expiresAt.toISOString()
|
|
75988
76202
|
}
|
|
@@ -76008,6 +76222,7 @@ function useHidAmicoService() {
|
|
|
76008
76222
|
credentialObject: credential.object,
|
|
76009
76223
|
accessRuleId: authorization.accessRuleId,
|
|
76010
76224
|
portalIds: authorization.portalIds,
|
|
76225
|
+
timeZoneId: authorization.timeZoneId,
|
|
76011
76226
|
issuedAt: issuedAt.toISOString(),
|
|
76012
76227
|
expiresAt: expiresAt.toISOString()
|
|
76013
76228
|
}
|
|
@@ -76779,18 +76994,28 @@ function useHidAmicoController() {
|
|
|
76779
76994
|
}
|
|
76780
76995
|
}
|
|
76781
76996
|
async function receiveNotification(req, res, next) {
|
|
76782
|
-
const
|
|
76997
|
+
const type = String(req.params.type ?? "").replace(/\.fcgi$/i, "");
|
|
76998
|
+
const validation = schemaHidAmicoNotificationParams.validate({
|
|
76999
|
+
...req.params,
|
|
77000
|
+
type
|
|
77001
|
+
});
|
|
76783
77002
|
if (validation.error) {
|
|
76784
77003
|
next(new import_node_server_utils267.BadRequestError(validation.error.message));
|
|
76785
77004
|
return;
|
|
76786
77005
|
}
|
|
76787
77006
|
try {
|
|
76788
|
-
const
|
|
77007
|
+
const queryPayload = req.query && typeof req.query === "object" ? req.query : {};
|
|
77008
|
+
const bodyPayload = req.body && typeof req.body === "object" ? req.body : {};
|
|
77009
|
+
const notification = await service.receiveNotification(
|
|
76789
77010
|
validation.value.readerId,
|
|
76790
77011
|
validation.value.type,
|
|
76791
|
-
|
|
77012
|
+
{ ...queryPayload, ...bodyPayload }
|
|
76792
77013
|
);
|
|
76793
|
-
|
|
77014
|
+
if (notification.response) {
|
|
77015
|
+
res.status(200).json(notification.response);
|
|
77016
|
+
return;
|
|
77017
|
+
}
|
|
77018
|
+
res.status(202).json({ data: notification.event });
|
|
76794
77019
|
} catch (error) {
|
|
76795
77020
|
next(error);
|
|
76796
77021
|
}
|