@7365admin1/core 3.68.2 → 3.68.3
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 +6 -0
- package/dist/index.d.ts +56 -51
- package/dist/index.js +51 -18
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/test/e2e/user-invite-dedupe.e2e.test.mjs +138 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @iservice365/core
|
|
2
2
|
|
|
3
|
+
## 3.68.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 1d5050b: Re-inviting the same person to the same app, organisation and site now re-sends the pending invitation instead of adding a duplicate; invite request logs no longer record the invitee's e-mail address.
|
|
8
|
+
|
|
3
9
|
## 3.68.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import * as mongodb from 'mongodb';
|
|
2
2
|
import { ObjectId, ClientSession, Db, Collection, Document, AggregateOptions } from 'mongodb';
|
|
3
3
|
import Joi from 'joi';
|
|
4
|
-
import { Request, Response, NextFunction } from 'express';
|
|
4
|
+
import { Request, Response, NextFunction, RequestHandler } from 'express';
|
|
5
5
|
import * as bson from 'bson';
|
|
6
|
-
import * as qs from 'qs';
|
|
7
|
-
import * as express_serve_static_core from 'express-serve-static-core';
|
|
8
6
|
import { z } from 'zod';
|
|
9
7
|
import { Server } from 'socket.io';
|
|
10
8
|
|
|
@@ -971,24 +969,25 @@ type TMemberModulesDeps = {
|
|
|
971
969
|
requireSelfOrPlatformStaff: typeof requireSelfOrPlatformStaff;
|
|
972
970
|
gateData?: TModuleGateData;
|
|
973
971
|
};
|
|
972
|
+
type MemberController = {
|
|
973
|
+
createMember: RequestHandler;
|
|
974
|
+
getByUserId: RequestHandler;
|
|
975
|
+
getByUserIdType: RequestHandler;
|
|
976
|
+
getModulesByUserIdType: RequestHandler;
|
|
977
|
+
getAll: RequestHandler;
|
|
978
|
+
getAllByUser: RequestHandler;
|
|
979
|
+
getOrgsByMembership: RequestHandler;
|
|
980
|
+
updateMemberStatus: RequestHandler;
|
|
981
|
+
updateRoleById: RequestHandler;
|
|
982
|
+
createMemberDirect: RequestHandler;
|
|
983
|
+
updateSiteById: RequestHandler;
|
|
984
|
+
getByUserIdTypeOrg: RequestHandler;
|
|
985
|
+
completeOnboarding: RequestHandler;
|
|
986
|
+
};
|
|
974
987
|
declare function memberModulesHandlers({ requireSelfOrPlatformStaff, gateData, }: TMemberModulesDeps): {
|
|
975
988
|
getModulesByUserIdType: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
976
989
|
};
|
|
977
|
-
declare function useMemberController():
|
|
978
|
-
createMember: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
979
|
-
getByUserId: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
980
|
-
getByUserIdType: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
981
|
-
getModulesByUserIdType: (req: Request<express_serve_static_core.ParamsDictionary, any, any, qs.ParsedQs, Record<string, any>>, res: Response<any, Record<string, any>>, next: NextFunction) => Promise<void>;
|
|
982
|
-
getAll: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
983
|
-
getAllByUser: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
984
|
-
getOrgsByMembership: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
985
|
-
updateMemberStatus: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
986
|
-
updateRoleById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
987
|
-
createMemberDirect: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
988
|
-
updateSiteById: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
989
|
-
getByUserIdTypeOrg: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
990
|
-
completeOnboarding: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
991
|
-
};
|
|
990
|
+
declare function useMemberController(): MemberController;
|
|
992
991
|
|
|
993
992
|
declare function useMemberService(): {
|
|
994
993
|
createMember: (id: string) => Promise<{
|
|
@@ -1057,6 +1056,10 @@ declare class MVerification implements TVerification {
|
|
|
1057
1056
|
constructor(value: TVerification);
|
|
1058
1057
|
}
|
|
1059
1058
|
|
|
1059
|
+
type TKeyValuePair<K extends string | number | symbol = string, V = any> = {
|
|
1060
|
+
[key in K]: V;
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1060
1063
|
declare function useVerificationRepo(): {
|
|
1061
1064
|
createIndex: () => Promise<void>;
|
|
1062
1065
|
createTextIndex: () => Promise<void>;
|
|
@@ -1076,6 +1079,10 @@ declare function useVerificationRepo(): {
|
|
|
1076
1079
|
}) => Promise<{}>;
|
|
1077
1080
|
getByIdByType: (type: string) => Promise<TVerification[]>;
|
|
1078
1081
|
updateStatusById: (_id: string | ObjectId, status: string, session?: ClientSession) => Promise<mongodb.UpdateResult<bson.Document>>;
|
|
1082
|
+
reissuePendingById: (_id: string | ObjectId, { metadata, expireAt }: {
|
|
1083
|
+
metadata: TKeyValuePair;
|
|
1084
|
+
expireAt: string;
|
|
1085
|
+
}) => Promise<number>;
|
|
1079
1086
|
getByStatus: (status: string) => Promise<TVerification[]>;
|
|
1080
1087
|
findOne: (query: any) => Promise<mongodb.WithId<bson.Document> | null>;
|
|
1081
1088
|
completePendingInvites: ({ email, orgId, siteId, app, session, }: {
|
|
@@ -1087,10 +1094,6 @@ declare function useVerificationRepo(): {
|
|
|
1087
1094
|
}) => Promise<mongodb.UpdateResult<bson.Document>>;
|
|
1088
1095
|
};
|
|
1089
1096
|
|
|
1090
|
-
type TKeyValuePair<K extends string | number | symbol = string, V = any> = {
|
|
1091
|
-
[key in K]: V;
|
|
1092
|
-
};
|
|
1093
|
-
|
|
1094
1097
|
declare function useVerificationService(): {
|
|
1095
1098
|
createUserInvite: ({ email, metadata, }: {
|
|
1096
1099
|
email: string;
|
|
@@ -1560,22 +1563,23 @@ type TOrgOwnerRepairDeps = {
|
|
|
1560
1563
|
declare function orgOwnerRepairHandlers({ requireConsolePermission, getOrgUncached, countOrgMembers, claim, release, holdsClaim, findUserByEmail, confirmOwnership, findOwnerRoleId, healDefaultRoles, createMemberDirect, recordConsoleAction, gateOn, }: TOrgOwnerRepairDeps): {
|
|
1561
1564
|
repairOwnerMembership: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
1562
1565
|
};
|
|
1563
|
-
|
|
1564
|
-
add:
|
|
1565
|
-
addOnboardingOrg:
|
|
1566
|
-
getAll:
|
|
1567
|
-
getOrgsByUserId:
|
|
1568
|
-
getByName:
|
|
1569
|
-
getById:
|
|
1570
|
-
getByEmail:
|
|
1571
|
-
update:
|
|
1572
|
-
getOrgsByEmail:
|
|
1573
|
-
getAdminOrgForResident:
|
|
1574
|
-
updateStatus:
|
|
1575
|
-
updateModules:
|
|
1576
|
-
previewOrgModules:
|
|
1577
|
-
repairOwnerMembership:
|
|
1578
|
-
};
|
|
1566
|
+
type OrgController = {
|
|
1567
|
+
add: RequestHandler;
|
|
1568
|
+
addOnboardingOrg: RequestHandler;
|
|
1569
|
+
getAll: RequestHandler;
|
|
1570
|
+
getOrgsByUserId: RequestHandler;
|
|
1571
|
+
getByName: RequestHandler;
|
|
1572
|
+
getById: RequestHandler;
|
|
1573
|
+
getByEmail: RequestHandler;
|
|
1574
|
+
update: RequestHandler;
|
|
1575
|
+
getOrgsByEmail: RequestHandler;
|
|
1576
|
+
getAdminOrgForResident: RequestHandler;
|
|
1577
|
+
updateStatus: RequestHandler;
|
|
1578
|
+
updateModules: RequestHandler;
|
|
1579
|
+
previewOrgModules: RequestHandler;
|
|
1580
|
+
repairOwnerMembership: RequestHandler;
|
|
1581
|
+
};
|
|
1582
|
+
declare function useOrgController(): OrgController;
|
|
1579
1583
|
|
|
1580
1584
|
/**
|
|
1581
1585
|
* V2 organization HTTP surface — new handlers; v1 `useOrgController` remains unchanged.
|
|
@@ -3163,19 +3167,20 @@ declare function siteModulesHandlers({ requireSiteWrite, _getSiteById, _getOrgBy
|
|
|
3163
3167
|
updateSiteModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
3164
3168
|
previewSiteModules: (req: Request, res: Response, next: NextFunction) => Promise<void>;
|
|
3165
3169
|
};
|
|
3166
|
-
|
|
3167
|
-
createSite:
|
|
3168
|
-
getSites:
|
|
3169
|
-
getSiteById:
|
|
3170
|
-
updateSiteBlock:
|
|
3171
|
-
deleteSite:
|
|
3172
|
-
updateById:
|
|
3173
|
-
updateSiteModules:
|
|
3174
|
-
previewSiteModules:
|
|
3175
|
-
updateGuardPostsById:
|
|
3176
|
-
siteInformation:
|
|
3177
|
-
getAllSitesForResidentCreation:
|
|
3178
|
-
};
|
|
3170
|
+
type SiteController = {
|
|
3171
|
+
createSite: RequestHandler;
|
|
3172
|
+
getSites: RequestHandler;
|
|
3173
|
+
getSiteById: RequestHandler;
|
|
3174
|
+
updateSiteBlock: RequestHandler;
|
|
3175
|
+
deleteSite: RequestHandler;
|
|
3176
|
+
updateById: RequestHandler;
|
|
3177
|
+
updateSiteModules: RequestHandler;
|
|
3178
|
+
previewSiteModules: RequestHandler;
|
|
3179
|
+
updateGuardPostsById: RequestHandler;
|
|
3180
|
+
siteInformation: RequestHandler;
|
|
3181
|
+
getAllSitesForResidentCreation: RequestHandler;
|
|
3182
|
+
};
|
|
3183
|
+
declare function useSiteController(): SiteController;
|
|
3179
3184
|
|
|
3180
3185
|
type TChat = {
|
|
3181
3186
|
_id?: ObjectId;
|
package/dist/index.js
CHANGED
|
@@ -11268,9 +11268,6 @@ var import_node_server_utils45 = require("@7365admin1/node-server-utils");
|
|
|
11268
11268
|
// src/services/verification.service.ts
|
|
11269
11269
|
var import_node_server_utils41 = require("@7365admin1/node-server-utils");
|
|
11270
11270
|
|
|
11271
|
-
// src/repositories/verification.repo.ts
|
|
11272
|
-
var import_node_server_utils19 = require("@7365admin1/node-server-utils");
|
|
11273
|
-
|
|
11274
11271
|
// src/models/verification.model.ts
|
|
11275
11272
|
var import_node_server_utils18 = require("@7365admin1/node-server-utils");
|
|
11276
11273
|
var import_mongodb16 = require("mongodb");
|
|
@@ -11319,6 +11316,7 @@ var MVerification = class {
|
|
|
11319
11316
|
};
|
|
11320
11317
|
|
|
11321
11318
|
// src/repositories/verification.repo.ts
|
|
11319
|
+
var import_node_server_utils19 = require("@7365admin1/node-server-utils");
|
|
11322
11320
|
var import_mongodb17 = require("mongodb");
|
|
11323
11321
|
function useVerificationRepo() {
|
|
11324
11322
|
const db2 = import_node_server_utils19.useAtlas.getDb();
|
|
@@ -11548,6 +11546,28 @@ function useVerificationRepo() {
|
|
|
11548
11546
|
throw new import_node_server_utils19.InternalServerError("Error updating verification status.");
|
|
11549
11547
|
}
|
|
11550
11548
|
}
|
|
11549
|
+
async function reissuePendingById(_id, { metadata, expireAt }) {
|
|
11550
|
+
try {
|
|
11551
|
+
_id = new import_mongodb17.ObjectId(_id);
|
|
11552
|
+
} catch (error) {
|
|
11553
|
+
throw new import_node_server_utils19.BadRequestError("Invalid verification ID format.");
|
|
11554
|
+
}
|
|
11555
|
+
try {
|
|
11556
|
+
const result = await collection.updateOne(
|
|
11557
|
+
{ _id, status: "pending" },
|
|
11558
|
+
{ $set: { metadata, expireAt, updatedAt: (/* @__PURE__ */ new Date()).toISOString() } }
|
|
11559
|
+
);
|
|
11560
|
+
delNamespace().catch(
|
|
11561
|
+
(err) => import_node_server_utils19.logger.error(`Failed to clear cache for namespace: ${namespace_collection3}`, err)
|
|
11562
|
+
);
|
|
11563
|
+
delCache((0, import_node_server_utils19.makeCacheKey)(namespace_collection3, { _id })).catch(
|
|
11564
|
+
(err) => import_node_server_utils19.logger.error(`Failed to delete cache for verification ${_id}`, err)
|
|
11565
|
+
);
|
|
11566
|
+
return result.modifiedCount;
|
|
11567
|
+
} catch (error) {
|
|
11568
|
+
throw new import_node_server_utils19.InternalServerError("Error re-sending the invitation.");
|
|
11569
|
+
}
|
|
11570
|
+
}
|
|
11551
11571
|
async function getByStatus(status) {
|
|
11552
11572
|
try {
|
|
11553
11573
|
const data = await collection.find({ status }).toArray();
|
|
@@ -11617,6 +11637,7 @@ function useVerificationRepo() {
|
|
|
11617
11637
|
getVerifications,
|
|
11618
11638
|
getByIdByType,
|
|
11619
11639
|
updateStatusById,
|
|
11640
|
+
reissuePendingById,
|
|
11620
11641
|
getByStatus,
|
|
11621
11642
|
findOne,
|
|
11622
11643
|
completePendingInvites
|
|
@@ -17606,7 +17627,8 @@ function useVerificationService() {
|
|
|
17606
17627
|
add,
|
|
17607
17628
|
getById: _getById,
|
|
17608
17629
|
updateStatusById: _updateStatusById,
|
|
17609
|
-
getByStatus: _getByStatus
|
|
17630
|
+
getByStatus: _getByStatus,
|
|
17631
|
+
reissuePendingById
|
|
17610
17632
|
} = useVerificationRepo();
|
|
17611
17633
|
const { getUserByEmail } = useUserRepo();
|
|
17612
17634
|
const { getById: getOrgById, getByEmail: getOrgByEmail } = useOrgRepo();
|
|
@@ -17681,13 +17703,6 @@ function useVerificationService() {
|
|
|
17681
17703
|
}
|
|
17682
17704
|
const verificationIds = [];
|
|
17683
17705
|
for (const app of apps) {
|
|
17684
|
-
await useVerificationRepo().findOne({
|
|
17685
|
-
type,
|
|
17686
|
-
email,
|
|
17687
|
-
"metadata.app": app,
|
|
17688
|
-
"metadata.org": metadata.org,
|
|
17689
|
-
"metadata.siteId": metadata.siteId
|
|
17690
|
-
});
|
|
17691
17706
|
const value = {
|
|
17692
17707
|
type,
|
|
17693
17708
|
email,
|
|
@@ -17698,7 +17713,24 @@ function useVerificationService() {
|
|
|
17698
17713
|
expireAt: new Date(Date.now() + 72 * 60 * 60 * 1e3).toISOString(),
|
|
17699
17714
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
17700
17715
|
};
|
|
17701
|
-
const
|
|
17716
|
+
const stored = new MVerification({
|
|
17717
|
+
...value,
|
|
17718
|
+
metadata: { ...value.metadata }
|
|
17719
|
+
}).metadata;
|
|
17720
|
+
const pending = await useVerificationRepo().findOne({
|
|
17721
|
+
type,
|
|
17722
|
+
// same address in any letter case, as `completePendingInvites` reads it
|
|
17723
|
+
email: new RegExp(`^${email.replace(/[.*+?^$()|[\]{}\\]/g, "\\$&")}$`, "i"),
|
|
17724
|
+
status: "pending",
|
|
17725
|
+
"metadata.app": app,
|
|
17726
|
+
"metadata.org": stored.org,
|
|
17727
|
+
"metadata.siteId": stored.siteId
|
|
17728
|
+
});
|
|
17729
|
+
const reissued = pending?._id && await reissuePendingById(pending._id, {
|
|
17730
|
+
metadata: stored,
|
|
17731
|
+
expireAt: value.expireAt
|
|
17732
|
+
});
|
|
17733
|
+
const createdId = reissued ? pending._id : await add(value);
|
|
17702
17734
|
verificationIds.push(createdId.toString());
|
|
17703
17735
|
const link = `${APP_MAIN}/verify/invitation/${createdId}`;
|
|
17704
17736
|
const emailContent = (0, import_node_server_utils41.compileHandlebar)({
|
|
@@ -29782,6 +29814,7 @@ function useMemberController() {
|
|
|
29782
29814
|
// src/controllers/verification.controller.ts
|
|
29783
29815
|
var import_node_server_utils66 = require("@7365admin1/node-server-utils");
|
|
29784
29816
|
var import_joi28 = __toESM(require("joi"));
|
|
29817
|
+
var withoutEmail = (payload) => JSON.stringify({ ...payload, email: payload?.email ? "[redacted]" : void 0 });
|
|
29785
29818
|
function callerId2(req) {
|
|
29786
29819
|
const user = req.user;
|
|
29787
29820
|
return user?.user?.toString?.() || user?._id?.toString?.();
|
|
@@ -29848,7 +29881,7 @@ function useVerificationController() {
|
|
|
29848
29881
|
const payload = { ...req.body };
|
|
29849
29882
|
import_node_server_utils66.logger.log({
|
|
29850
29883
|
level: "info",
|
|
29851
|
-
message: `[invite/user] payload: ${
|
|
29884
|
+
message: `[invite/user] payload: ${withoutEmail(payload)}`
|
|
29852
29885
|
});
|
|
29853
29886
|
const validation = import_joi28.default.object({
|
|
29854
29887
|
email: import_joi28.default.string().email().required(),
|
|
@@ -29904,7 +29937,7 @@ function useVerificationController() {
|
|
|
29904
29937
|
} catch (error2) {
|
|
29905
29938
|
import_node_server_utils66.logger.log({
|
|
29906
29939
|
level: "error",
|
|
29907
|
-
message: `[invite/user] error for payload ${
|
|
29940
|
+
message: `[invite/user] error for payload ${withoutEmail(payload)}: ${error2.message}`
|
|
29908
29941
|
});
|
|
29909
29942
|
next(error2);
|
|
29910
29943
|
return;
|
|
@@ -29914,7 +29947,7 @@ function useVerificationController() {
|
|
|
29914
29947
|
const payload = { ...req.body };
|
|
29915
29948
|
import_node_server_utils66.logger.log({
|
|
29916
29949
|
level: "info",
|
|
29917
|
-
message: `[invite/member] payload: ${
|
|
29950
|
+
message: `[invite/member] payload: ${withoutEmail(payload)}`
|
|
29918
29951
|
});
|
|
29919
29952
|
const validation = import_joi28.default.object({
|
|
29920
29953
|
email: import_joi28.default.string().email().required(),
|
|
@@ -29966,7 +29999,7 @@ function useVerificationController() {
|
|
|
29966
29999
|
} catch (error2) {
|
|
29967
30000
|
import_node_server_utils66.logger.log({
|
|
29968
30001
|
level: "error",
|
|
29969
|
-
message: `[invite/member] error for payload ${
|
|
30002
|
+
message: `[invite/member] error for payload ${withoutEmail(payload)}: ${error2.message}`
|
|
29970
30003
|
});
|
|
29971
30004
|
next(error2);
|
|
29972
30005
|
return;
|
|
@@ -29976,7 +30009,7 @@ function useVerificationController() {
|
|
|
29976
30009
|
const payload = req.body;
|
|
29977
30010
|
import_node_server_utils66.logger.log({
|
|
29978
30011
|
level: "info",
|
|
29979
|
-
message: `[service-providers/invite] payload: ${
|
|
30012
|
+
message: `[service-providers/invite] payload: ${withoutEmail(payload)}`
|
|
29980
30013
|
});
|
|
29981
30014
|
const validation = import_joi28.default.object({
|
|
29982
30015
|
email: import_joi28.default.string().email().required(),
|
|
@@ -30033,7 +30066,7 @@ function useVerificationController() {
|
|
|
30033
30066
|
} catch (error2) {
|
|
30034
30067
|
import_node_server_utils66.logger.log({
|
|
30035
30068
|
level: "error",
|
|
30036
|
-
message: `[service-providers/invite] error for payload ${
|
|
30069
|
+
message: `[service-providers/invite] error for payload ${withoutEmail(payload)}: ${error2.message}`
|
|
30037
30070
|
});
|
|
30038
30071
|
next(error2);
|
|
30039
30072
|
return;
|