@7365admin1/core 3.60.0 → 3.60.1-staging.273

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.
@@ -0,0 +1,14 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Say what is wrong when an organisation cannot be saved.
6
+
7
+ `PUT /api/organizations/:id` — the write behind onboarding step 1 and the staff
8
+ Client List edit — collapsed every MongoDB write error into a 500 reading
9
+ "Failed to update organization.", with only `error.message` in the log. A
10
+ duplicate-key refusal (the `organizations` collection still carries a unique
11
+ index an earlier version of this file created and nothing ever dropped) is now
12
+ a 400 naming the field the caller has to change, a typed error raised
13
+ underneath is no longer turned into a 500, and the log line carries the error
14
+ name, code, key and the organisation id.
@@ -0,0 +1,16 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Restore and extend the site scoping on the patrol-log email endpoints.
6
+
7
+ #1967 added a `requireSiteReach` guard to `POST /api/patrol-logs/email`. #1981,
8
+ branched before #1967 landed, rewrote the same controller to add the history
9
+ endpoints and dropped the guard. Neither repo runs its tests in CI, so the e2e
10
+ test #1967 shipped has been failing on `main` unnoticed ever since.
11
+
12
+ All five endpoints now resolve the caller from the session: the two that name a
13
+ site (`send`, `getAll`) check that site, and the three that name a record
14
+ (`resend`, `getById`, `deleteById`) check the site stored on the record. The
15
+ `createdBy` pinning is restored with them, so a send cannot be filed under
16
+ another user's name.
@@ -0,0 +1,5 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Scope `GET /api/roles/id/:id`: a caller may read a role they themselves hold (resolved from the session's own `members` rows), otherwise the role's organisation rule applies. Closes the cross-tenant read of any organisation's role name and permissions.
@@ -0,0 +1,21 @@
1
+ ---
2
+ "@7365admin1/core": patch
3
+ ---
4
+
5
+ Narrow the account-by-e-mail lookup to identity only, and scope the two open subscription reads
6
+
7
+ `GET /api/users/email/:email` and its v2 twin `GET /api/users/v2/email/:email`
8
+ stripped the password hash and session id from the reply but answered every
9
+ other stored field, so any signed-in account could read any other account's
10
+ NRIC, contact number, date of birth, gender, default organisation, status and
11
+ profile just by knowing the e-mail address — across every client on the
12
+ platform. Both now answer `{_id, name, email}` and nothing else. An
13
+ organisation gate would have been the wrong fix: this endpoint exists for the
14
+ invite flow, where the person being looked up is deliberately not in the
15
+ caller's organisation yet.
16
+
17
+ `GET /api/subscriptions/org/:id` answered any organisation's billing record —
18
+ plan, seat count, price, currency, renewal date — to any signed-in account, and
19
+ `GET /api/subscriptions/` answered every subscription on the platform in one
20
+ list. They now carry `requireOrgAccess` and `requirePlatformStaff`, the two
21
+ gates already used elsewhere in the same file.
package/dist/index.d.ts CHANGED
@@ -718,6 +718,8 @@ type TOrg = {
718
718
  nature: string;
719
719
  email?: string;
720
720
  contact?: string;
721
+ /** Chosen by the owner while creating the organisation. */
722
+ country?: string;
721
723
  busInst?: string;
722
724
  status?: string;
723
725
  defaultSite?: string;
@@ -753,6 +755,7 @@ declare const orgSchema: Joi.ObjectSchema<any>;
753
755
  declare function MOrg(value: TOrg): TOrg;
754
756
 
755
757
  declare function useOrgRepo(): {
758
+ getByCreatorAndNature: (createdBy: string | ObjectId, nature: string) => Promise<TOrg | null>;
756
759
  createIndex: () => Promise<void>;
757
760
  createTextIndex: () => Promise<void>;
758
761
  createUniqueIndex: () => Promise<void>;
@@ -10192,6 +10195,13 @@ type TVerificationCode = {
10192
10195
  attempts?: number;
10193
10196
  /** Set when the code was accepted; the code itself is cleared at that point. */
10194
10197
  verifiedAt?: string | null;
10198
+ /**
10199
+ * The PASSWORD gate, used instead of a code when the invitee already has an
10200
+ * account (a second organisation under the same person). Counted per
10201
+ * invitation so a fumbled attempt here never locks the real sign-in.
10202
+ */
10203
+ passwordAttempts?: number;
10204
+ lockedUntil?: string | null;
10195
10205
  };
10196
10206
  /**
10197
10207
  * Where an invitee got to in onboarding, kept on the invitation so it survives
@@ -10338,6 +10348,11 @@ declare function useVerificationRepoV2(): {
10338
10348
  org?: string | ObjectId | null | undefined;
10339
10349
  completed?: boolean | undefined;
10340
10350
  }, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
10351
+ setInvitePasswordGate: ({ _id, attempts, lockedUntil, }: {
10352
+ _id: string | ObjectId;
10353
+ attempts: number;
10354
+ lockedUntil: string | null;
10355
+ }, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
10341
10356
  };
10342
10357
 
10343
10358
  declare function useVerificationServiceV2(): {
@@ -10448,6 +10463,55 @@ declare function useVerificationServiceV2(): {
10448
10463
  org: string;
10449
10464
  completedAt: string | null;
10450
10465
  }>;
10466
+ verifyInvitePassword: ({ inviteId, password, }: {
10467
+ inviteId: string;
10468
+ password: string;
10469
+ }) => Promise<{
10470
+ status: string;
10471
+ lockedUntil: string | null | undefined;
10472
+ secondsRemaining: number;
10473
+ message: string;
10474
+ sid?: undefined;
10475
+ user?: undefined;
10476
+ email?: undefined;
10477
+ name?: undefined;
10478
+ inviteId?: undefined;
10479
+ app?: undefined;
10480
+ attemptsLeft?: undefined;
10481
+ } | {
10482
+ status: string;
10483
+ sid: string;
10484
+ user: string;
10485
+ email: string;
10486
+ name: string;
10487
+ inviteId: string;
10488
+ app: string;
10489
+ message: string;
10490
+ lockedUntil?: undefined;
10491
+ secondsRemaining?: undefined;
10492
+ attemptsLeft?: undefined;
10493
+ } | {
10494
+ status: string;
10495
+ attemptsLeft: number;
10496
+ message: string;
10497
+ lockedUntil?: undefined;
10498
+ secondsRemaining?: undefined;
10499
+ sid?: undefined;
10500
+ user?: undefined;
10501
+ email?: undefined;
10502
+ name?: undefined;
10503
+ inviteId?: undefined;
10504
+ app?: undefined;
10505
+ }>;
10506
+ getInviteAccount: (inviteId: string) => Promise<{
10507
+ inviteId: string;
10508
+ email: string;
10509
+ app: string;
10510
+ role: string;
10511
+ invitedName: string;
10512
+ exists: boolean;
10513
+ name: string;
10514
+ }>;
10451
10515
  };
10452
10516
 
10453
10517
  declare function useVerificationControllerV2(): {
@@ -10463,6 +10527,8 @@ declare function useVerificationControllerV2(): {
10463
10527
  verifyInviteCode: (req: Request, res: Response, next: NextFunction) => Promise<void>;
10464
10528
  getOnboarding: (req: Request, res: Response, next: NextFunction) => Promise<void>;
10465
10529
  updateOnboarding: (req: Request, res: Response, next: NextFunction) => Promise<void>;
10530
+ verifyInvitePassword: (req: Request, res: Response, next: NextFunction) => Promise<void>;
10531
+ getInviteAccount: (req: Request, res: Response, next: NextFunction) => Promise<void>;
10466
10532
  };
10467
10533
 
10468
10534
  /**