@7365admin1/core 3.59.0 → 3.59.2
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/CHANGELOG.md +20 -0
- package/dist/index.d.ts +13 -5
- package/dist/index.js +35 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/test/e2e/resident-self-signup-pinning.e2e.test.mjs +65 -0
- package/test/self-signup-files.test.mjs +276 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @iservice365/core
|
|
2
2
|
|
|
3
|
+
## 3.59.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- db311b7: Resident self-sign-up: record the documents the app never managed to upload, so a reviewer can see one is missing.
|
|
8
|
+
|
|
9
|
+
Dropping id-less file entries kept the applicant, but it also made the registration indistinguishable from one with nothing attached — the reviewer console renders `Files:` with an empty list either way, and a person was approved in that state without the tenancy agreement it was meant to carry.
|
|
10
|
+
|
|
11
|
+
`unsentFileNames` reports the names of the entries `dropUnsentFiles` throws away, and `addResidentSelfSignUp` pins them onto the person as `filesNotUploaded` — the same way `status` and `platform` are pinned, never accepted from the caller (it is absent from the self-sign-up allow-list, which validates with `stripUnknown`). The key is omitted entirely when every upload landed, so a normal registration is written exactly as it is today. Names are bounded to 10 entries of 120 characters because the route is pre-login.
|
|
12
|
+
|
|
13
|
+
## 3.59.1
|
|
14
|
+
|
|
15
|
+
### Patch Changes
|
|
16
|
+
|
|
17
|
+
- 9daa1cb: Resident self-sign-up: drop file entries the app never managed to upload, instead of refusing the whole registration.
|
|
18
|
+
|
|
19
|
+
The registration wizard lists a document optimistically and patches in the `id` the upload returns. When the upload fails it keeps the entry, with no `id`, and sends it - so `schemaFiles.id.required()` returned 400 `"files[0].id" is required` for the entire sign-up, and the app only logged it. Residents saw a Submit button that did nothing.
|
|
20
|
+
|
|
21
|
+
The self-sign-up path now drops id-less entries before validating. Strictly widening: the authenticated staff path (`schemaPerson`) and `schemaFiles` itself are unchanged, an entry with an `id` is passed through untouched, and a body with no `files` key is unchanged.
|
|
22
|
+
|
|
3
23
|
## 3.59.0
|
|
4
24
|
|
|
5
25
|
### Minor Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -4713,6 +4713,13 @@ type TPerson = {
|
|
|
4713
4713
|
plates?: TPlates[];
|
|
4714
4714
|
isOwner?: boolean;
|
|
4715
4715
|
files?: TFiles[];
|
|
4716
|
+
/**
|
|
4717
|
+
* Attachments the resident-app wizard listed but never actually uploaded, so
|
|
4718
|
+
* they arrived with no `id` and were dropped from `files`. Pinned
|
|
4719
|
+
* server-side on the pre-login self-signup path only - never accepted from a
|
|
4720
|
+
* caller. See `utils/self-signup-files.util.ts`.
|
|
4721
|
+
*/
|
|
4722
|
+
filesNotUploaded?: string[];
|
|
4716
4723
|
plateNumber?: string;
|
|
4717
4724
|
platform?: string;
|
|
4718
4725
|
approvedBy?: TApprover;
|
|
@@ -4772,6 +4779,12 @@ declare function MPerson(value: TPerson): {
|
|
|
4772
4779
|
deletedAt: string | Date | undefined;
|
|
4773
4780
|
acceptedTermsAt: string;
|
|
4774
4781
|
acceptedTerms?: ObjectId | undefined;
|
|
4782
|
+
plateNumber: string;
|
|
4783
|
+
platForm: string;
|
|
4784
|
+
approvedBy: TApprover;
|
|
4785
|
+
countryCode: string;
|
|
4786
|
+
callingCode: string;
|
|
4787
|
+
filesNotUploaded?: string[] | undefined;
|
|
4775
4788
|
_id: ObjectId | undefined;
|
|
4776
4789
|
user: string | ObjectId;
|
|
4777
4790
|
name: string;
|
|
@@ -4794,11 +4807,6 @@ declare function MPerson(value: TPerson): {
|
|
|
4794
4807
|
plates: TPlates[];
|
|
4795
4808
|
isOwner: boolean;
|
|
4796
4809
|
files: TFiles[];
|
|
4797
|
-
plateNumber: string;
|
|
4798
|
-
platForm: string;
|
|
4799
|
-
approvedBy: TApprover;
|
|
4800
|
-
countryCode: string;
|
|
4801
|
-
callingCode: string;
|
|
4802
4810
|
};
|
|
4803
4811
|
type visitorType = "guest" | "walk-in" | "contractor" | "delivery";
|
|
4804
4812
|
type visitorPersonService = {
|
package/dist/index.js
CHANGED
|
@@ -17778,6 +17778,11 @@ var schemaPerson = import_joi17.default.object({
|
|
|
17778
17778
|
plates: import_joi17.default.array().items(schemaPlate).optional().allow(null),
|
|
17779
17779
|
isOwner: import_joi17.default.boolean().required(),
|
|
17780
17780
|
files: import_joi17.default.array().items(schemaFiles).optional().allow(null),
|
|
17781
|
+
// Set by `addResidentSelfSignUp`, not by any caller: it is absent from the
|
|
17782
|
+
// self-signup allow-list, which validates with `stripUnknown`. It is named
|
|
17783
|
+
// here only because `MPerson` runs `schemaPerson` over the finished payload
|
|
17784
|
+
// and Joi refuses unknown keys.
|
|
17785
|
+
filesNotUploaded: import_joi17.default.array().items(import_joi17.default.string()).optional(),
|
|
17781
17786
|
password: import_joi17.default.string().optional().allow(null, ""),
|
|
17782
17787
|
plateNumber: import_joi17.default.string().optional().allow(null, ""),
|
|
17783
17788
|
platform: import_joi17.default.string().valid("web", "mobile").optional().allow(null, ""),
|
|
@@ -17934,6 +17939,11 @@ function MPerson(value) {
|
|
|
17934
17939
|
plates: value.plates ?? [],
|
|
17935
17940
|
isOwner: value.isOwner ?? false,
|
|
17936
17941
|
files: value.files ?? [],
|
|
17942
|
+
// Conditional, because this return is a WHITELIST: everything not named
|
|
17943
|
+
// here is dropped on the way to the database, and a bare
|
|
17944
|
+
// `filesNotUploaded: value.filesNotUploaded` would add an `undefined` key
|
|
17945
|
+
// to every person ever written. Absent when every upload landed.
|
|
17946
|
+
...value.filesNotUploaded?.length ? { filesNotUploaded: value.filesNotUploaded } : {},
|
|
17937
17947
|
plateNumber: value.plateNumber ?? "",
|
|
17938
17948
|
platForm: value.platform ?? "",
|
|
17939
17949
|
approvedBy: value.approvedBy ?? { id: "", name: "" },
|
|
@@ -58521,6 +58531,24 @@ function useGuestManagementController() {
|
|
|
58521
58531
|
var import_joi71 = __toESM(require("joi"));
|
|
58522
58532
|
var import_node_server_utils143 = require("@7365admin1/node-server-utils");
|
|
58523
58533
|
var import_node_server_utils144 = require("@7365admin1/node-server-utils");
|
|
58534
|
+
|
|
58535
|
+
// src/utils/self-signup-files.util.ts
|
|
58536
|
+
function dropUnsentFiles(body) {
|
|
58537
|
+
if (!Array.isArray(body?.files))
|
|
58538
|
+
return body;
|
|
58539
|
+
return { ...body, files: body.files.filter((file) => file?.id) };
|
|
58540
|
+
}
|
|
58541
|
+
var MAX_UNSENT_FILE_NAMES = 10;
|
|
58542
|
+
var MAX_UNSENT_FILE_NAME_LENGTH = 120;
|
|
58543
|
+
function unsentFileNames(body) {
|
|
58544
|
+
if (!body || !Array.isArray(body.files))
|
|
58545
|
+
return [];
|
|
58546
|
+
return body.files.filter((file) => file && !file.id).slice(0, MAX_UNSENT_FILE_NAMES).map(
|
|
58547
|
+
(file) => typeof file.name === "string" && file.name.trim() ? file.name.trim().slice(0, MAX_UNSENT_FILE_NAME_LENGTH) : "Unnamed document"
|
|
58548
|
+
);
|
|
58549
|
+
}
|
|
58550
|
+
|
|
58551
|
+
// src/controllers/person.controller.ts
|
|
58524
58552
|
function usePersonController() {
|
|
58525
58553
|
const {
|
|
58526
58554
|
getAll: _getAll,
|
|
@@ -58559,7 +58587,9 @@ function usePersonController() {
|
|
|
58559
58587
|
return actor;
|
|
58560
58588
|
}
|
|
58561
58589
|
async function addResidentSelfSignUp(req, res, next) {
|
|
58562
|
-
const
|
|
58590
|
+
const body = dropUnsentFiles(req.body);
|
|
58591
|
+
const notUploaded = unsentFileNames(req.body);
|
|
58592
|
+
const { error, value } = schemaResidentSelfSignUp.validate(body, {
|
|
58563
58593
|
abortEarly: false,
|
|
58564
58594
|
stripUnknown: true
|
|
58565
58595
|
});
|
|
@@ -58580,7 +58610,10 @@ function usePersonController() {
|
|
|
58580
58610
|
// "pending" or "active", so a caller who sent `platform: "web"` got a
|
|
58581
58611
|
// live account without anyone reviewing them.
|
|
58582
58612
|
status: SELF_SIGNUP_STATUS,
|
|
58583
|
-
platform: SELF_SIGNUP_PLATFORM
|
|
58613
|
+
platform: SELF_SIGNUP_PLATFORM,
|
|
58614
|
+
// Pinned the same way, and omitted entirely when every upload landed, so
|
|
58615
|
+
// a normal registration is written exactly as it is written today.
|
|
58616
|
+
...notUploaded.length > 0 ? { filesNotUploaded: notUploaded } : {}
|
|
58584
58617
|
};
|
|
58585
58618
|
try {
|
|
58586
58619
|
const data = await _add(payload);
|