@7365admin1/core 3.47.1-staging.133 → 3.47.1-staging.135

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,40 @@
1
+ ---
2
+ "@7365admin1/core": minor
3
+ ---
4
+
5
+ Scope the member list and the member suspend/reactivate write to their own organisation.
6
+
7
+ `GET /api/members` took its `org` and `siteId` straight out of the query string,
8
+ and `PUT /api/members/:id/:status` took the member id straight out of the URL.
9
+ Both carried `requireAuth` and nothing more. So any signed-in account on the
10
+ platform could list another client's staff, and suspend or reactivate any member
11
+ of any client.
12
+
13
+ `GET /api/members` also had a hole in its own scope requirement. Line 170 refused
14
+ a query that named neither an organisation nor a user — **unless**
15
+ `type === "admin"`, which then listed Seven365's own staff to anybody signed in.
16
+
17
+ Both now decide from the session:
18
+
19
+ - `type=admin` requires Seven365 staff. That query belongs to the staff console
20
+ (`web-app-org pages/super-admin`), so it is gated rather than removed.
21
+ - a caller-supplied `org` is checked with `requireOrgAccess` before it is used —
22
+ Seven365 staff, or a live member of that organisation.
23
+ - `user` on its own stays open for the caller's OWN id, because "which
24
+ organisations am I a member of" is every service app's landing page
25
+ (`web-app-security pages/index.vue:118` and its siblings). Asking it about
26
+ somebody else now requires staff.
27
+ - `PUT /api/members/:id/:status` loads the stored membership and authorises on
28
+ the organisation recorded on it — never one from the request. A membership with
29
+ no organisation is a platform staff row, and only Seven365 staff may touch it;
30
+ a missing org is refused, not waved through.
31
+
32
+ Service providers are not special-cased and do not need to be: a provider holds a
33
+ membership in the organisation whose site it works on — that is how
34
+ `GET /api/members/user/:id/app/:type?org=` finds its own row at sign-in — so the
35
+ guard app's member list (`isecure365-mobile-app
36
+ src/features/patrol/use-patrol.ts:180`, which sends `org: site.org` with a
37
+ `siteId`) passes on the ordinary rule.
38
+
39
+ Nothing changes for a permitted caller: same response shape, same fields, same
40
+ status.
@@ -0,0 +1,40 @@
1
+ ---
2
+ "@7365admin1/core": minor
3
+ ---
4
+
5
+ Scope `GET /api/people` to a site the caller can actually reach.
6
+
7
+ The endpoint returns resident and visitor records — name, NRIC, contact number,
8
+ unit, plate numbers — and filters on NRIC, contact and plate number. It carried
9
+ `requireAuth` and nothing more, and took its `org` and `site` from the query
10
+ string (`person.controller.ts:79-80, 93`). So any signed-in account on the
11
+ platform could page through another estate's residents, or look a person up by
12
+ NRIC across every client at once.
13
+
14
+ The caller is now resolved from the session and the scope decided before
15
+ anything is read:
16
+
17
+ - a named `site` is checked with `entitleSite` — the same site-reach rule the
18
+ camera and HID modules already use: a membership at the site, an org-wide
19
+ membership at the site's owning organisation, or an ACTIVE `customer.sites`
20
+ engagement. Reusing it matters rather than being tidy: an agency contracted to
21
+ an estate holds no membership in that estate's organisation, so an
22
+ org-membership check would have locked every guard out of the site they work
23
+ at. A site the caller cannot reach answers exactly as a site that does not
24
+ exist, so site ids cannot be enumerated.
25
+ - a named `org` is checked against the caller's own memberships.
26
+ - naming neither — the NRIC, contact and plate lookups — is narrowed to the
27
+ caller's own organisations instead of searching the whole platform.
28
+ - Seven365 staff keep cross-tenant reach, unchanged.
29
+
30
+ Every live caller passes a site: `layer-common` `VisitorForm.vue`,
31
+ `MemberInformation.vue` and `VehicleForm.vue` all pass the site the screen is
32
+ open on, and the People list passes org and site from its route. The two
33
+ composable functions that pass neither — `usePeople().findPersonByContact` and
34
+ `findUsersByPlateNumber` — have no caller in any repository.
35
+
36
+ `person.repo.getAll` gains an optional `orgs` filter for the last case. It
37
+ applies only when no explicit `org` was given, so it cannot fight one, and its
38
+ absence means "no restriction", which is what staff get.
39
+
40
+ No response shape, status code or field changed for a permitted caller.
package/dist/index.d.ts CHANGED
@@ -4570,7 +4570,7 @@ declare function useGuestManagementController(): {
4570
4570
  declare const site_people_namespace_collection = "site.people";
4571
4571
  declare function usePersonRepo(): {
4572
4572
  add: (value: TPerson, session?: ClientSession) => Promise<ObjectId>;
4573
- getAll: ({ search, page, limit, sort, status, dateFrom, dateTo, org, site, type, nric, contact, plateNumber, }: {
4573
+ getAll: ({ search, page, limit, sort, status, dateFrom, dateTo, org, orgs, site, type, nric, contact, plateNumber, }: {
4574
4574
  search?: string | undefined;
4575
4575
  page?: number | undefined;
4576
4576
  limit?: number | undefined;
@@ -4579,6 +4579,13 @@ declare function usePersonRepo(): {
4579
4579
  dateFrom?: string | undefined;
4580
4580
  dateTo?: string | undefined;
4581
4581
  org?: string | undefined;
4582
+ /**
4583
+ * The organisations the CALLER may see, when they have named neither an
4584
+ * organisation nor a site. Resolved from the session by the controller,
4585
+ * never from the request. Absent means "no restriction" — which is what
4586
+ * Seven365 staff get.
4587
+ */
4588
+ orgs?: string[] | undefined;
4582
4589
  site?: string | undefined;
4583
4590
  type?: string | undefined;
4584
4591
  nric?: string | undefined;