@memberjunction/server 2.20.0 → 2.20.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/dist/index.d.ts CHANGED
@@ -22,7 +22,11 @@ export * from './resolvers/DatasetResolver.js';
22
22
  export * from './resolvers/EntityRecordNameResolver.js';
23
23
  export * from './resolvers/MergeRecordsResolver.js';
24
24
  export * from './resolvers/ReportResolver.js';
25
+ export * from './resolvers/SyncRolesUsersResolver.js';
25
26
  export * from './generated/generated.js';
27
+ export type MJServerOptions = {
28
+ onBeforeServe?: () => void | Promise<void>;
29
+ };
26
30
  export declare const createApp: () => import("express-serve-static-core").Express;
27
- export declare const serve: (resolverPaths: Array<string>, app?: import("express-serve-static-core").Express) => Promise<void>;
31
+ export declare const serve: (resolverPaths: Array<string>, app?: import("express-serve-static-core").Express, options?: MJServerOptions) => Promise<void>;
28
32
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,kBAAkB,CAAC;AAqB1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,iDAAiD,CAAC;AAChE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEnE,cAAc,iCAAiC,CAAC;AAChD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAE9C,cAAc,0BAA0B,CAAC;AAYzC,eAAO,MAAM,SAAS,mDAAkB,CAAC;AAEzC,eAAO,MAAM,KAAK,kBAAyB,MAAM,MAAM,CAAC,qEA+FvD,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgBA,OAAO,kBAAkB,CAAC;AAqB1B,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,cAAc,cAAc,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,cAAc,uBAAuB,CAAC;AACtC,cAAc,6CAA6C,CAAC;AAC5D,cAAc,gDAAgD,CAAC;AAC/D,cAAc,iDAAiD,CAAC;AAChE,cAAc,2CAA2C,CAAC;AAC1D,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEnE,cAAc,iCAAiC,CAAC;AAChD,cAAc,2BAA2B,CAAC;AAC1C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,kCAAkC,CAAC;AACjD,cAAc,iCAAiC,CAAC;AAEhD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,8BAA8B,CAAC;AAC7C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,yCAAyC,CAAC;AACxD,cAAc,qCAAqC,CAAC;AACpD,cAAc,+BAA+B,CAAC;AAC9C,cAAc,uCAAuC,CAAC;AAEtD,cAAc,0BAA0B,CAAC;AAIzC,MAAM,MAAM,eAAe,GAAG;IAC5B,aAAa,CAAC,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5C,CAAC;AAUF,eAAO,MAAM,SAAS,mDAAkB,CAAC;AAEzC,eAAO,MAAM,KAAK,kBAAyB,MAAM,MAAM,CAAC,+DAA+B,eAAe,kBAmGrG,CAAC"}
package/dist/index.js CHANGED
@@ -50,6 +50,7 @@ export * from './resolvers/DatasetResolver.js';
50
50
  export * from './resolvers/EntityRecordNameResolver.js';
51
51
  export * from './resolvers/MergeRecordsResolver.js';
52
52
  export * from './resolvers/ReportResolver.js';
53
+ export * from './resolvers/SyncRolesUsersResolver.js';
53
54
  export * from './generated/generated.js';
54
55
  import { resolve } from 'node:path';
55
56
  const localPath = (p) => {
@@ -58,7 +59,7 @@ const localPath = (p) => {
58
59
  return resolvedPath;
59
60
  };
60
61
  export const createApp = () => express();
61
- export const serve = async (resolverPaths, app = createApp()) => {
62
+ export const serve = async (resolverPaths, app = createApp(), options) => {
62
63
  const localResolverPaths = ['resolvers/**/*Resolver.{js,ts}', 'generic/*Resolver.{js,ts}', 'generated/generated.{js,ts}'].map(localPath);
63
64
  const combinedResolverPaths = [...resolverPaths, ...localResolverPaths];
64
65
  const isWindows = sep === '\\';
@@ -114,6 +115,9 @@ export const serve = async (resolverPaths, app = createApp()) => {
114
115
  app.use(graphqlRootPath, cors(), BodyParser.json({ limit: '50mb' }), expressMiddleware(apolloServer, {
115
116
  context: contextFunction({ setupComplete$, dataSource }),
116
117
  }));
118
+ if (options?.onBeforeServe) {
119
+ await Promise.resolve(options.onBeforeServe());
120
+ }
117
121
  await new Promise((resolve) => httpServer.listen({ port: graphqlPort }, resolve));
118
122
  console.log(`🚀 Server ready at http://localhost:${graphqlPort}/`);
119
123
  };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { AppContext } from '../types.js';
2
+ import { RunView, UserInfo } from '@memberjunction/core';
3
+ import { RoleEntity, UserEntity } from '@memberjunction/core-entities';
4
+ export declare class SyncRolesAndUsersResultType {
5
+ Success: boolean;
6
+ }
7
+ export declare class RoleInputType {
8
+ ID: string;
9
+ Name: string;
10
+ Description: string;
11
+ }
12
+ export declare enum UserType {
13
+ Owner = "Owner",
14
+ User = "User"
15
+ }
16
+ export declare class UserInputType {
17
+ ID: string;
18
+ Name: string;
19
+ Email: string;
20
+ Type: UserType;
21
+ FirstName: string;
22
+ LastName: string;
23
+ Title: string;
24
+ Roles?: RoleInputType[];
25
+ }
26
+ export declare class RolesAndUsersInputType {
27
+ Users: UserInputType[];
28
+ Roles: RoleInputType[];
29
+ }
30
+ export declare class SyncRolesAndUsersResolver {
31
+ SyncRolesAndUsers(data: RolesAndUsersInputType, context: AppContext): Promise<SyncRolesAndUsersResultType>;
32
+ SyncRoles(roles: RoleInputType[], context: AppContext): Promise<SyncRolesAndUsersResultType>;
33
+ protected UpdateExistingRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<SyncRolesAndUsersResultType>;
34
+ protected AddNewRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<boolean>;
35
+ protected DeleteRemovedRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<boolean>;
36
+ get StandardRoles(): string[];
37
+ IsStandardRole(roleName: string): boolean;
38
+ protected DeleteSingleRole(role: RoleEntity, rv: RunView, user: UserInfo): Promise<boolean>;
39
+ SyncUsers(users: UserInputType[], context: AppContext): Promise<SyncRolesAndUsersResultType>;
40
+ protected UpdateExistingUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean>;
41
+ protected AddNewUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean>;
42
+ protected DeleteRemovedUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean>;
43
+ protected DeleteSingleUser(user: UserEntity, rv: RunView, u: UserInfo): Promise<boolean>;
44
+ protected SyncUserRoles(users: UserInputType[], u: UserInfo): Promise<boolean>;
45
+ }
46
+ //# sourceMappingURL=SyncRolesUsersResolver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncRolesUsersResolver.d.ts","sourceRoot":"","sources":["../../src/resolvers/SyncRolesUsersResolver.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAsB,OAAO,EAAwB,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAEnG,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,+BAA+B,CAAC;AAEvF,qBACa,2BAA2B;IAEtC,OAAO,EAAE,OAAO,CAAC;CAClB;AAGD,qBACa,aAAa;IAEtB,EAAE,EAAE,MAAM,CAAC;IAGX,IAAI,EAAE,MAAM,CAAC;IAGb,WAAW,EAAE,MAAM,CAAC;CACvB;AAGD,oBAAY,QAAQ;IAClB,KAAK,UAAU;IACf,IAAI,SAAS;CACd;AAOD,qBACa,aAAa;IAEtB,EAAE,EAAG,MAAM,CAAC;IAGZ,IAAI,EAAG,MAAM,CAAC;IAGd,KAAK,EAAG,MAAM,CAAC;IAIf,IAAI,EAAG,QAAQ,CAAC;IAGhB,SAAS,EAAE,MAAM,CAAC;IAGlB,QAAQ,EAAE,MAAM,CAAC;IAGjB,KAAK,EAAE,MAAM,CAAC;IAGd,KAAK,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B;AAGD,qBACa,sBAAsB;IAExB,KAAK,EAAE,aAAa,EAAE,CAAC;IAGvB,KAAK,EAAE,aAAa,EAAE,CAAC;CACjC;AAGD,qBAAa,yBAAyB;IAQ5B,iBAAiB,CACqB,IAAI,EAAE,sBAAsB,EACjE,OAAO,EAAE,UAAU;IAwBpB,SAAS,CACsB,KAAK,EAAE,aAAa,EAAE,EACpD,OAAO,EAAE,UAAU,GACtB,OAAO,CAAC,2BAA2B,CAAC;cA0BxB,mBAAmB,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,2BAA2B,CAAC;cAenI,WAAW,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cAiBvG,kBAAkB,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAe9H,IAAW,aAAa,IAAI,MAAM,EAAE,CAEnC;IACM,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO;cAIhC,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;IAwB3F,SAAS,CACsB,KAAK,EAAE,aAAa,EAAE,EACpD,OAAO,EAAE,UAAU,GACtB,OAAO,CAAC,2BAA2B,CAAC;cA8BxB,mBAAmB,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cAgB5G,WAAW,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cA4BpG,kBAAkB,CAAC,YAAY,EAAE,UAAU,EAAE,EAAE,WAAW,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cAiB3G,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;cAwB9E,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,EAAE,CAAC,EAAE,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC;CAiEvF"}
@@ -0,0 +1,389 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ var __metadata = (this && this.__metadata) || function (k, v) {
8
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
9
+ };
10
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
+ return function (target, key) { decorator(target, key, paramIndex); }
12
+ };
13
+ import { Arg, Ctx, Field, InputType, Mutation, ObjectType, registerEnumType } from 'type-graphql';
14
+ import { LogError, Metadata, RunView } from '@memberjunction/core';
15
+ import { RequireSystemUser } from '../directives/RequireSystemUser.js';
16
+ let SyncRolesAndUsersResultType = class SyncRolesAndUsersResultType {
17
+ Success;
18
+ };
19
+ __decorate([
20
+ Field(() => Boolean),
21
+ __metadata("design:type", Boolean)
22
+ ], SyncRolesAndUsersResultType.prototype, "Success", void 0);
23
+ SyncRolesAndUsersResultType = __decorate([
24
+ ObjectType()
25
+ ], SyncRolesAndUsersResultType);
26
+ export { SyncRolesAndUsersResultType };
27
+ let RoleInputType = class RoleInputType {
28
+ ID;
29
+ Name;
30
+ Description;
31
+ };
32
+ __decorate([
33
+ Field(() => String),
34
+ __metadata("design:type", String)
35
+ ], RoleInputType.prototype, "ID", void 0);
36
+ __decorate([
37
+ Field(() => String),
38
+ __metadata("design:type", String)
39
+ ], RoleInputType.prototype, "Name", void 0);
40
+ __decorate([
41
+ Field(() => String, { nullable: true }),
42
+ __metadata("design:type", String)
43
+ ], RoleInputType.prototype, "Description", void 0);
44
+ RoleInputType = __decorate([
45
+ InputType()
46
+ ], RoleInputType);
47
+ export { RoleInputType };
48
+ export var UserType;
49
+ (function (UserType) {
50
+ UserType["Owner"] = "Owner";
51
+ UserType["User"] = "User";
52
+ })(UserType || (UserType = {}));
53
+ registerEnumType(UserType, {
54
+ name: "UserType",
55
+ description: "Defines whether a user is an Owner or a User",
56
+ });
57
+ let UserInputType = class UserInputType {
58
+ ID;
59
+ Name;
60
+ Email;
61
+ Type;
62
+ FirstName;
63
+ LastName;
64
+ Title;
65
+ Roles;
66
+ };
67
+ __decorate([
68
+ Field(() => String),
69
+ __metadata("design:type", String)
70
+ ], UserInputType.prototype, "ID", void 0);
71
+ __decorate([
72
+ Field(() => String),
73
+ __metadata("design:type", String)
74
+ ], UserInputType.prototype, "Name", void 0);
75
+ __decorate([
76
+ Field(() => String),
77
+ __metadata("design:type", String)
78
+ ], UserInputType.prototype, "Email", void 0);
79
+ __decorate([
80
+ Field(() => UserType),
81
+ __metadata("design:type", String)
82
+ ], UserInputType.prototype, "Type", void 0);
83
+ __decorate([
84
+ Field(() => String, { nullable: true }),
85
+ __metadata("design:type", String)
86
+ ], UserInputType.prototype, "FirstName", void 0);
87
+ __decorate([
88
+ Field(() => String, { nullable: true }),
89
+ __metadata("design:type", String)
90
+ ], UserInputType.prototype, "LastName", void 0);
91
+ __decorate([
92
+ Field(() => String, { nullable: true }),
93
+ __metadata("design:type", String)
94
+ ], UserInputType.prototype, "Title", void 0);
95
+ __decorate([
96
+ Field(() => [RoleInputType], { nullable: true }),
97
+ __metadata("design:type", Array)
98
+ ], UserInputType.prototype, "Roles", void 0);
99
+ UserInputType = __decorate([
100
+ InputType()
101
+ ], UserInputType);
102
+ export { UserInputType };
103
+ let RolesAndUsersInputType = class RolesAndUsersInputType {
104
+ Users;
105
+ Roles;
106
+ };
107
+ __decorate([
108
+ Field(() => [UserInputType]),
109
+ __metadata("design:type", Array)
110
+ ], RolesAndUsersInputType.prototype, "Users", void 0);
111
+ __decorate([
112
+ Field(() => [RoleInputType]),
113
+ __metadata("design:type", Array)
114
+ ], RolesAndUsersInputType.prototype, "Roles", void 0);
115
+ RolesAndUsersInputType = __decorate([
116
+ InputType()
117
+ ], RolesAndUsersInputType);
118
+ export { RolesAndUsersInputType };
119
+ export class SyncRolesAndUsersResolver {
120
+ async SyncRolesAndUsers(data, context) {
121
+ try {
122
+ const roleResult = await this.SyncRoles(data.Roles, context);
123
+ if (roleResult.Success) {
124
+ return await this.SyncUsers(data.Users, context);
125
+ }
126
+ else {
127
+ return roleResult;
128
+ }
129
+ }
130
+ catch (err) {
131
+ LogError(err);
132
+ throw new Error('Error syncing roles and users\n\n' + err);
133
+ }
134
+ }
135
+ async SyncRoles(roles, context) {
136
+ try {
137
+ const rv = new RunView();
138
+ const result = await rv.RunView({
139
+ EntityName: "Roles",
140
+ ResultType: 'entity_object'
141
+ }, context.userPayload.userRecord);
142
+ if (result && result.Success) {
143
+ const currentRoles = result.Results;
144
+ if (await this.DeleteRemovedRoles(currentRoles, roles, context.userPayload.userRecord)) {
145
+ if (await this.AddNewRoles(currentRoles, roles, context.userPayload.userRecord)) {
146
+ return await this.UpdateExistingRoles(currentRoles, roles, context.userPayload.userRecord);
147
+ }
148
+ }
149
+ }
150
+ return { Success: false };
151
+ }
152
+ catch (err) {
153
+ LogError(err);
154
+ throw new Error('Error syncing roles and users\n\n' + err);
155
+ }
156
+ }
157
+ async UpdateExistingRoles(currentRoles, futureRoles, user) {
158
+ const md = new Metadata();
159
+ let ok = true;
160
+ for (const update of futureRoles) {
161
+ const currentRole = currentRoles.find(r => r.Name.trim().toLowerCase() === update.Name.trim().toLowerCase());
162
+ if (currentRole) {
163
+ currentRole.Description = update.Description;
164
+ ok = ok && await currentRole.Save();
165
+ }
166
+ }
167
+ return { Success: ok };
168
+ }
169
+ async AddNewRoles(currentRoles, futureRoles, user) {
170
+ const md = new Metadata();
171
+ let ok = true;
172
+ for (const add of futureRoles) {
173
+ if (!currentRoles.find(r => r.Name.trim().toLowerCase() === add.Name.trim().toLowerCase())) {
174
+ const role = await md.GetEntityObject("Roles", user);
175
+ role.Name = add.Name;
176
+ role.Description = add.Description;
177
+ ok = ok && await role.Save();
178
+ }
179
+ }
180
+ return ok;
181
+ }
182
+ async DeleteRemovedRoles(currentRoles, futureRoles, user) {
183
+ const rv = new RunView();
184
+ let ok = true;
185
+ for (const remove of currentRoles) {
186
+ if (!this.IsStandardRole(remove.Name)) {
187
+ if (!futureRoles.find(r => r.Name.trim().toLowerCase() === remove.Name.trim().toLowerCase())) {
188
+ ok = ok && await this.DeleteSingleRole(remove, rv, user);
189
+ }
190
+ }
191
+ }
192
+ return ok;
193
+ }
194
+ get StandardRoles() {
195
+ return ['Developer', 'Integration', 'UI'];
196
+ }
197
+ IsStandardRole(roleName) {
198
+ return this.StandardRoles.find(r => r.toLowerCase() === roleName.toLowerCase()) !== undefined;
199
+ }
200
+ async DeleteSingleRole(role, rv, user) {
201
+ let ok = true;
202
+ const r2 = await rv.RunView({
203
+ EntityName: "User Roles",
204
+ ExtraFilter: "RoleID = '" + role.ID + "'",
205
+ ResultType: 'entity_object'
206
+ }, user);
207
+ if (r2.Success) {
208
+ for (const ur of r2.Results) {
209
+ ok = ok && await ur.Delete();
210
+ }
211
+ }
212
+ return ok && role.Delete();
213
+ }
214
+ async SyncUsers(users, context) {
215
+ try {
216
+ const rv = new RunView();
217
+ const result = await rv.RunView({
218
+ EntityName: "Users",
219
+ ResultType: 'entity_object'
220
+ }, context.userPayload.userRecord);
221
+ if (result && result.Success) {
222
+ const currentUsers = result.Results;
223
+ if (await this.DeleteRemovedUsers(currentUsers, users, context.userPayload.userRecord)) {
224
+ if (await this.AddNewUsers(currentUsers, users, context.userPayload.userRecord)) {
225
+ if (await this.UpdateExistingUsers(currentUsers, users, context.userPayload.userRecord)) {
226
+ if (await this.SyncUserRoles(users, context.userPayload.userRecord)) {
227
+ return { Success: true };
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ return { Success: false };
234
+ }
235
+ catch (err) {
236
+ LogError(err);
237
+ throw new Error('Error syncing roles and users\n\n' + err);
238
+ }
239
+ }
240
+ async UpdateExistingUsers(currentUsers, futureUsers, u) {
241
+ let ok = true;
242
+ for (const update of futureUsers) {
243
+ const current = currentUsers.find(c => c.Email?.trim().toLowerCase() === update.Email?.trim().toLowerCase());
244
+ if (current) {
245
+ current.Name = update.Name;
246
+ current.Type = update.Type;
247
+ current.FirstName = update.FirstName;
248
+ current.LastName = update.LastName;
249
+ current.Title = update.Title;
250
+ ok = ok && await current.Save();
251
+ }
252
+ }
253
+ return ok;
254
+ }
255
+ async AddNewUsers(currentUsers, futureUsers, u) {
256
+ const md = new Metadata();
257
+ let ok = true;
258
+ for (const add of futureUsers) {
259
+ const match = currentUsers.find(currentUser => currentUser.Email?.trim().toLowerCase() === add.Email?.trim().toLowerCase());
260
+ if (match) {
261
+ match.IsActive = true;
262
+ ok = ok && await match.Save();
263
+ }
264
+ else {
265
+ const user = await md.GetEntityObject("Users", u);
266
+ user.Name = add.Name;
267
+ user.Type = add.Type;
268
+ user.Email = add.Email;
269
+ user.FirstName = add.FirstName;
270
+ user.LastName = add.LastName;
271
+ user.Title = add.Title;
272
+ user.IsActive = true;
273
+ ok = ok && await user.Save();
274
+ }
275
+ }
276
+ return ok;
277
+ }
278
+ async DeleteRemovedUsers(currentUsers, futureUsers, u) {
279
+ const rv = new RunView();
280
+ const md = new Metadata();
281
+ let ok = true;
282
+ for (const remove of currentUsers) {
283
+ if (remove.Type.trim().toLowerCase() !== 'owner') {
284
+ if (!futureUsers.find(r => r.Email.trim().toLowerCase() === remove.Email.trim().toLowerCase())) {
285
+ ok = ok && await this.DeleteSingleUser(remove, rv, u);
286
+ }
287
+ }
288
+ }
289
+ return ok;
290
+ }
291
+ async DeleteSingleUser(user, rv, u) {
292
+ let ok = true;
293
+ const r2 = await rv.RunView({
294
+ EntityName: "User Roles",
295
+ ExtraFilter: "UserID = '" + user.ID + "'",
296
+ ResultType: 'entity_object'
297
+ }, u);
298
+ if (r2.Success) {
299
+ for (const ur of r2.Results) {
300
+ ok = ok && await ur.Delete();
301
+ }
302
+ }
303
+ if (await user.Delete()) {
304
+ return ok;
305
+ }
306
+ else {
307
+ user.IsActive = false;
308
+ return await user.Save() && ok;
309
+ }
310
+ }
311
+ async SyncUserRoles(users, u) {
312
+ const rv = new RunView();
313
+ const md = new Metadata();
314
+ const p1 = rv.RunView({
315
+ EntityName: "Users",
316
+ ResultType: 'entity_object'
317
+ }, u);
318
+ const p2 = rv.RunView({
319
+ EntityName: "Roles",
320
+ ResultType: 'entity_object'
321
+ }, u);
322
+ const p3 = rv.RunView({
323
+ EntityName: "User Roles",
324
+ ResultType: 'entity_object'
325
+ }, u);
326
+ const [uResult, rResult, urResult] = await Promise.all([p1, p2, p3]);
327
+ if (uResult.Success && rResult.Success && urResult.Success) {
328
+ const dbUsers = uResult.Results;
329
+ const dbRoles = rResult.Results;
330
+ const dbUserRoles = urResult.Results;
331
+ let ok = true;
332
+ for (const user of users) {
333
+ const dbUser = dbUsers.find(u => u.Email.trim().toLowerCase() === user.Email.trim().toLowerCase());
334
+ if (dbUser) {
335
+ for (const role of user.Roles) {
336
+ const dbRole = dbRoles.find(r => r.Name.trim().toLowerCase() === role.Name.trim().toLowerCase());
337
+ if (dbRole) {
338
+ if (!dbUserRoles.find(ur => ur.UserID === dbUser.ID && ur.RoleID === dbRole.ID)) {
339
+ const ur = await md.GetEntityObject("User Roles", u);
340
+ ur.UserID = dbUser.ID;
341
+ ur.RoleID = dbRole.ID;
342
+ ok = ok && await ur.Save();
343
+ }
344
+ }
345
+ }
346
+ const thisUserDBRoles = dbUserRoles.filter(ur => ur.UserID === dbUser.ID);
347
+ for (const dbUserRole of thisUserDBRoles) {
348
+ const role = user.Roles.find(r => r.Name.trim().toLowerCase() === dbRoles.find(rr => rr.ID === dbUserRole.RoleID)?.Name.trim().toLowerCase());
349
+ if (!role && !this.IsStandardRole(dbUserRole.Role)) {
350
+ ok = ok && await dbUserRole.Delete();
351
+ }
352
+ }
353
+ }
354
+ }
355
+ return ok;
356
+ }
357
+ else {
358
+ return false;
359
+ }
360
+ }
361
+ }
362
+ __decorate([
363
+ RequireSystemUser(),
364
+ Mutation(() => SyncRolesAndUsersResultType),
365
+ __param(0, Arg('data', () => RolesAndUsersInputType)),
366
+ __param(1, Ctx()),
367
+ __metadata("design:type", Function),
368
+ __metadata("design:paramtypes", [RolesAndUsersInputType, Object]),
369
+ __metadata("design:returntype", Promise)
370
+ ], SyncRolesAndUsersResolver.prototype, "SyncRolesAndUsers", null);
371
+ __decorate([
372
+ RequireSystemUser(),
373
+ Mutation(() => SyncRolesAndUsersResultType),
374
+ __param(0, Arg('roles', () => [RoleInputType])),
375
+ __param(1, Ctx()),
376
+ __metadata("design:type", Function),
377
+ __metadata("design:paramtypes", [Array, Object]),
378
+ __metadata("design:returntype", Promise)
379
+ ], SyncRolesAndUsersResolver.prototype, "SyncRoles", null);
380
+ __decorate([
381
+ RequireSystemUser(),
382
+ Mutation(() => SyncRolesAndUsersResultType),
383
+ __param(0, Arg('users', () => [UserInputType])),
384
+ __param(1, Ctx()),
385
+ __metadata("design:type", Function),
386
+ __metadata("design:paramtypes", [Array, Object]),
387
+ __metadata("design:returntype", Promise)
388
+ ], SyncRolesAndUsersResolver.prototype, "SyncUsers", null);
389
+ //# sourceMappingURL=SyncRolesUsersResolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncRolesUsersResolver.js","sourceRoot":"","sources":["../../src/resolvers/SyncRolesUsersResolver.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/server",
3
- "version": "2.20.0",
3
+ "version": "2.20.2",
4
4
  "description": "MemberJunction: This project provides API access via GraphQL to the common data store.",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./src/index.ts",
@@ -22,27 +22,27 @@
22
22
  "dependencies": {
23
23
  "@apollo/server": "^4.9.1",
24
24
  "@graphql-tools/utils": "^10.0.1",
25
- "@memberjunction/actions": "2.20.0",
26
- "@memberjunction/ai": "2.20.0",
27
- "@memberjunction/ai-mistral": "2.20.0",
28
- "@memberjunction/ai-openai": "2.20.0",
29
- "@memberjunction/ai-vectors-pinecone": "2.20.0",
30
- "@memberjunction/aiengine": "2.20.0",
31
- "@memberjunction/core": "2.20.0",
32
- "@memberjunction/core-actions": "2.20.0",
33
- "@memberjunction/core-entities": "2.20.0",
34
- "@memberjunction/data-context": "2.20.0",
35
- "@memberjunction/data-context-server": "2.20.0",
36
- "@memberjunction/doc-utils": "2.20.0",
37
- "@memberjunction/entity-communications-server": "2.20.0",
38
- "@memberjunction/external-change-detection": "2.20.0",
39
- "@memberjunction/global": "2.20.0",
40
- "@memberjunction/graphql-dataprovider": "2.20.0",
41
- "@memberjunction/queue": "2.20.0",
42
- "@memberjunction/skip-types": "2.20.0",
43
- "@memberjunction/sqlserver-dataprovider": "2.20.0",
44
- "@memberjunction/storage": "2.20.0",
45
- "@memberjunction/templates": "2.20.0",
25
+ "@memberjunction/actions": "2.20.2",
26
+ "@memberjunction/ai": "2.20.2",
27
+ "@memberjunction/ai-mistral": "2.20.2",
28
+ "@memberjunction/ai-openai": "2.20.2",
29
+ "@memberjunction/ai-vectors-pinecone": "2.20.2",
30
+ "@memberjunction/aiengine": "2.20.2",
31
+ "@memberjunction/core": "2.20.2",
32
+ "@memberjunction/core-actions": "2.20.2",
33
+ "@memberjunction/core-entities": "2.20.2",
34
+ "@memberjunction/data-context": "2.20.2",
35
+ "@memberjunction/data-context-server": "2.20.2",
36
+ "@memberjunction/doc-utils": "2.20.2",
37
+ "@memberjunction/entity-communications-server": "2.20.2",
38
+ "@memberjunction/external-change-detection": "2.20.2",
39
+ "@memberjunction/global": "2.20.2",
40
+ "@memberjunction/graphql-dataprovider": "2.20.2",
41
+ "@memberjunction/queue": "2.20.2",
42
+ "@memberjunction/skip-types": "2.20.2",
43
+ "@memberjunction/sqlserver-dataprovider": "2.20.2",
44
+ "@memberjunction/storage": "2.20.2",
45
+ "@memberjunction/templates": "2.20.2",
46
46
  "@types/cors": "^2.8.13",
47
47
  "@types/jsonwebtoken": "9.0.6",
48
48
  "@types/node": "20.14.2",
package/src/index.ts CHANGED
@@ -60,11 +60,16 @@ export * from './resolvers/DatasetResolver.js';
60
60
  export * from './resolvers/EntityRecordNameResolver.js';
61
61
  export * from './resolvers/MergeRecordsResolver.js';
62
62
  export * from './resolvers/ReportResolver.js';
63
+ export * from './resolvers/SyncRolesUsersResolver.js';
63
64
 
64
65
  export * from './generated/generated.js';
65
66
 
66
67
  import { resolve } from 'node:path';
67
68
 
69
+ export type MJServerOptions = {
70
+ onBeforeServe?: () => void | Promise<void>;
71
+ };
72
+
68
73
  const localPath = (p: string) => {
69
74
  // Convert import.meta.url to a local directory path
70
75
  const dirname = fileURLToPath(new URL('.', import.meta.url));
@@ -75,7 +80,7 @@ const localPath = (p: string) => {
75
80
 
76
81
  export const createApp = () => express();
77
82
 
78
- export const serve = async (resolverPaths: Array<string>, app = createApp()) => {
83
+ export const serve = async (resolverPaths: Array<string>, app = createApp(), options?: MJServerOptions) => {
79
84
  const localResolverPaths = ['resolvers/**/*Resolver.{js,ts}', 'generic/*Resolver.{js,ts}', 'generated/generated.{js,ts}'].map(localPath);
80
85
 
81
86
  const combinedResolverPaths = [...resolverPaths, ...localResolverPaths];
@@ -168,6 +173,10 @@ export const serve = async (resolverPaths: Array<string>, app = createApp()) =>
168
173
  })
169
174
  );
170
175
 
176
+ if (options?.onBeforeServe) {
177
+ await Promise.resolve(options.onBeforeServe());
178
+ }
179
+
171
180
  await new Promise<void>((resolve) => httpServer.listen({ port: graphqlPort }, resolve));
172
181
  console.log(`🚀 Server ready at http://localhost:${graphqlPort}/`);
173
182
  };
@@ -0,0 +1,401 @@
1
+ import { Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, Query, Resolver, registerEnumType } from 'type-graphql';
2
+ import { AppContext } from '../types.js';
3
+ import { LogError, Metadata, RunView, TransactionGroupBase, UserInfo } from '@memberjunction/core';
4
+ import { RequireSystemUser } from '../directives/RequireSystemUser.js';
5
+ import { RoleEntity, UserEntity, UserRoleEntity } from '@memberjunction/core-entities';
6
+
7
+ @ObjectType()
8
+ export class SyncRolesAndUsersResultType {
9
+ @Field(() => Boolean)
10
+ Success: boolean;
11
+ }
12
+
13
+
14
+ @InputType()
15
+ export class RoleInputType {
16
+ @Field(() => String)
17
+ ID: string;
18
+
19
+ @Field(() => String)
20
+ Name: string;
21
+
22
+ @Field(() => String, {nullable: true})
23
+ Description: string;
24
+ }
25
+
26
+
27
+ export enum UserType {
28
+ Owner = "Owner",
29
+ User = "User",
30
+ }
31
+
32
+ registerEnumType(UserType, {
33
+ name: "UserType", // GraphQL Enum Name
34
+ description: "Defines whether a user is an Owner or a User",
35
+ });
36
+
37
+ @InputType()
38
+ export class UserInputType {
39
+ @Field(() => String)
40
+ ID!: string;
41
+
42
+ @Field(() => String)
43
+ Name!: string;
44
+
45
+ @Field(() => String)
46
+ Email!: string;
47
+
48
+ // the next field needs to have GraphQL enum with only Owner or User being allowed
49
+ @Field(() => UserType)
50
+ Type!: UserType;
51
+
52
+ @Field(() => String, {nullable: true})
53
+ FirstName: string;
54
+
55
+ @Field(() => String, {nullable: true})
56
+ LastName: string;
57
+
58
+ @Field(() => String, {nullable: true})
59
+ Title: string;
60
+
61
+ @Field(() => [RoleInputType], {nullable: true})
62
+ Roles?: RoleInputType[];
63
+ }
64
+
65
+
66
+ @InputType()
67
+ export class RolesAndUsersInputType {
68
+ @Field(() => [UserInputType])
69
+ public Users: UserInputType[];
70
+
71
+ @Field(() => [RoleInputType])
72
+ public Roles: RoleInputType[];
73
+ }
74
+
75
+
76
+ export class SyncRolesAndUsersResolver {
77
+ /**
78
+ * This mutation will sync both the roles and the users, and the user/role relationships in the system with the data provided in the input.
79
+ * Roles are matched by the name (case insensitive) and users are matched by email
80
+ * @param data
81
+ */
82
+ @RequireSystemUser()
83
+ @Mutation(() => SyncRolesAndUsersResultType)
84
+ async SyncRolesAndUsers(
85
+ @Arg('data', () => RolesAndUsersInputType ) data: RolesAndUsersInputType,
86
+ @Ctx() context: AppContext
87
+ ) {
88
+ try {
89
+ // first we sync the roles, then the users
90
+ const roleResult = await this.SyncRoles(data.Roles, context);
91
+ if (roleResult.Success) {
92
+ return await this.SyncUsers(data.Users, context);
93
+ }
94
+ else {
95
+ return roleResult;
96
+ }
97
+ }
98
+ catch (err) {
99
+ LogError(err);
100
+ throw new Error('Error syncing roles and users\n\n' + err);
101
+ }
102
+ }
103
+
104
+ /**
105
+ * This mutation will sync the roles in the system with the data provided in the input, using the role name for matching (case insensitive)
106
+ * @param data
107
+ */
108
+ @RequireSystemUser()
109
+ @Mutation(() => SyncRolesAndUsersResultType)
110
+ async SyncRoles(
111
+ @Arg('roles', () => [RoleInputType]) roles: RoleInputType[],
112
+ @Ctx() context: AppContext
113
+ ) : Promise<SyncRolesAndUsersResultType> {
114
+ try {
115
+ // we iterate through the provided roles and we remove roles that are not in the input and add roles that are new
116
+ // and update roles that already exist
117
+ const rv = new RunView();
118
+ const result = await rv.RunView<RoleEntity>({
119
+ EntityName: "Roles",
120
+ ResultType: 'entity_object'
121
+ }, context.userPayload.userRecord);
122
+
123
+ if (result && result.Success) {
124
+ const currentRoles = result.Results;
125
+ if (await this.DeleteRemovedRoles(currentRoles, roles, context.userPayload.userRecord)) {
126
+ if ( await this.AddNewRoles(currentRoles, roles, context.userPayload.userRecord)) {
127
+ return await this.UpdateExistingRoles(currentRoles, roles, context.userPayload.userRecord);
128
+ }
129
+ }
130
+ }
131
+
132
+ return { Success: false }; // if we get here, something went wrong
133
+ } catch (err) {
134
+ LogError(err);
135
+ throw new Error('Error syncing roles and users\n\n' + err);
136
+ }
137
+ }
138
+
139
+ protected async UpdateExistingRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<SyncRolesAndUsersResultType> {
140
+ // go through the future roles and update any that are in the current roles
141
+ const md = new Metadata();
142
+ let ok: boolean = true;
143
+
144
+ for (const update of futureRoles) {
145
+ const currentRole = currentRoles.find(r => r.Name.trim().toLowerCase() === update.Name.trim().toLowerCase());
146
+ if (currentRole) {
147
+ currentRole.Description = update.Description;
148
+ ok = ok && await currentRole.Save(); // no await, we do that with submit below
149
+ }
150
+ }
151
+ return { Success: ok };
152
+ }
153
+
154
+ protected async AddNewRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<boolean> {
155
+ // go through the future roles and add any that are not in the current roles
156
+ const md = new Metadata();
157
+ let ok: boolean = true;
158
+
159
+ for (const add of futureRoles) {
160
+ if (!currentRoles.find(r => r.Name.trim().toLowerCase() === add.Name.trim().toLowerCase())) {
161
+ const role = await md.GetEntityObject<RoleEntity>("Roles", user);
162
+ role.Name = add.Name;
163
+ role.Description = add.Description;
164
+ ok = ok && await role.Save(); // no await, we do that with submit below
165
+ }
166
+ }
167
+ return ok;
168
+ }
169
+
170
+
171
+ protected async DeleteRemovedRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<boolean> {
172
+ const rv = new RunView();
173
+ let ok: boolean = true;
174
+
175
+ // iterate through the existing roles and remove any that are not in the input
176
+ for (const remove of currentRoles) {
177
+ if (!this.IsStandardRole(remove.Name)) {
178
+ if (!futureRoles.find(r => r.Name.trim().toLowerCase() === remove.Name.trim().toLowerCase())) {
179
+ ok = ok && await this.DeleteSingleRole(remove, rv, user);
180
+ }
181
+ }
182
+ }
183
+ return ok;
184
+ }
185
+
186
+ public get StandardRoles(): string[] {
187
+ return ['Developer', 'Integration', 'UI']
188
+ }
189
+ public IsStandardRole(roleName: string): boolean {
190
+ return this.StandardRoles.find(r => r.toLowerCase() === roleName.toLowerCase()) !== undefined;
191
+ }
192
+
193
+ protected async DeleteSingleRole(role: RoleEntity, rv: RunView, user: UserInfo): Promise<boolean> {
194
+ // first, remove all the UserRole records that match this role
195
+ let ok: boolean = true;
196
+ const r2 = await rv.RunView<UserRoleEntity>({
197
+ EntityName: "User Roles",
198
+ ExtraFilter: "RoleID = '" + role.ID + "'",
199
+ ResultType: 'entity_object'
200
+ }, user);
201
+ if (r2.Success) {
202
+ for (const ur of r2.Results) {
203
+ ok = ok && await ur.Delete(); // remove the user role
204
+ }
205
+ }
206
+
207
+ return ok && role.Delete(); // remove the role
208
+ }
209
+
210
+ /**
211
+ * This mutation will sync the just the users in the system with the data provided in the input, matches existing users by email
212
+ * @important This method will NOT work if the roles are not already in sync, meaning if User/Role relationships exist in the input data where the Role doesn't already exist in this system the sync will fail
213
+ * @param data
214
+ */
215
+ @RequireSystemUser()
216
+ @Mutation(() => SyncRolesAndUsersResultType)
217
+ async SyncUsers(
218
+ @Arg('users', () => [UserInputType]) users: UserInputType[],
219
+ @Ctx() context: AppContext
220
+ ) : Promise<SyncRolesAndUsersResultType> {
221
+ try {
222
+ // first, we sync up the users and then the user roles.
223
+ // for syncing users we first remove users that are no longer in the input, then we add new users and update existing users
224
+ const rv = new RunView();
225
+ const result = await rv.RunView<UserEntity>({
226
+ EntityName: "Users",
227
+ ResultType: 'entity_object'
228
+ }, context.userPayload.userRecord);
229
+ if (result && result.Success) {
230
+ // go through current users and remove those that are not in the input
231
+ const currentUsers = result.Results;
232
+ if (await this.DeleteRemovedUsers(currentUsers, users, context.userPayload.userRecord)) {
233
+ if (await this.AddNewUsers(currentUsers, users, context.userPayload.userRecord)) {
234
+ if (await this.UpdateExistingUsers(currentUsers, users, context.userPayload.userRecord)) {
235
+ if (await this.SyncUserRoles(users, context.userPayload.userRecord)) {
236
+ return { Success: true };
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+
243
+ return { Success: false }; // if we get here, something went wrong
244
+ } catch (err) {
245
+ LogError(err);
246
+ throw new Error('Error syncing roles and users\n\n' + err);
247
+ }
248
+ }
249
+
250
+ protected async UpdateExistingUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean> {
251
+ // go through the future users and update any that are in the current users
252
+ let ok: boolean = true;
253
+ for (const update of futureUsers) {
254
+ const current = currentUsers.find(c => c.Email?.trim().toLowerCase() === update.Email?.trim().toLowerCase());
255
+ if (current) {
256
+ current.Name = update.Name;
257
+ current.Type = update.Type;
258
+ current.FirstName = update.FirstName;
259
+ current.LastName = update.LastName;
260
+ current.Title = update.Title;
261
+ ok = ok && await current.Save();
262
+ }
263
+ }
264
+ return ok;
265
+ }
266
+ protected async AddNewUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean> {
267
+ // add users that are not in the current users
268
+ const md = new Metadata();
269
+ let ok: boolean = true;
270
+
271
+ for (const add of futureUsers) {
272
+ const match = currentUsers.find(currentUser => currentUser.Email?.trim().toLowerCase() === add.Email?.trim().toLowerCase());
273
+ if (match) {
274
+ // make sure the IsActive bit is set to true
275
+ match.IsActive = true;
276
+ ok = ok && await match.Save();
277
+ }
278
+ else {
279
+ const user = await md.GetEntityObject<UserEntity>("Users", u);
280
+ user.Name = add.Name;
281
+ user.Type = add.Type;
282
+ user.Email = add.Email;
283
+ user.FirstName = add.FirstName;
284
+ user.LastName = add.LastName;
285
+ user.Title = add.Title;
286
+ user.IsActive = true;
287
+
288
+ ok = ok && await user.Save();
289
+ }
290
+ }
291
+ return ok;
292
+ }
293
+
294
+ protected async DeleteRemovedUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean> {
295
+ // remove users that are not in the future users
296
+ const rv = new RunView();
297
+ const md = new Metadata();
298
+
299
+ let ok: boolean = true;
300
+ //const tg = await md.CreateTransactionGroup(); HAVING PROBLEMS with this, so skipping for now, I think the entire thing is wrapped in a transaction and that's causing issues with two styles of trans wrappers
301
+ for (const remove of currentUsers) {
302
+ if (remove.Type.trim().toLowerCase() !== 'owner') {
303
+ if (!futureUsers.find(r => r.Email.trim().toLowerCase() === remove.Email.trim().toLowerCase())) {
304
+ ok = ok && await this.DeleteSingleUser(remove, rv, u);
305
+ }
306
+ }
307
+ }
308
+ return ok;
309
+ }
310
+
311
+ protected async DeleteSingleUser(user: UserEntity, rv: RunView, u: UserInfo): Promise<boolean> {
312
+ // first, remove all the UserRole records that match this user
313
+ let ok: boolean = true;
314
+ const r2 = await rv.RunView<UserRoleEntity>({
315
+ EntityName: "User Roles",
316
+ ExtraFilter: "UserID = '" + user.ID + "'",
317
+ ResultType: 'entity_object'
318
+ }, u);
319
+ if (r2.Success) {
320
+ for (const ur of r2.Results) {
321
+ //ur.TransactionGroup = tg;
322
+ ok = ok && await ur.Delete(); // remove the user role
323
+ }
324
+ }
325
+ if (await user.Delete()) {
326
+ return ok;
327
+ }
328
+ else {
329
+ // in some cases there are a lot of fkey constraints that prevent the user from being deleted, so we mark the user as inactive instead
330
+ user.IsActive = false;
331
+ return await user.Save() && ok;
332
+ }
333
+ }
334
+
335
+ protected async SyncUserRoles(users: UserInputType[], u: UserInfo): Promise<boolean> {
336
+ // for each user in the users array, make sure there is a User Role that matches. First, get a list of all DATABASE user and roels so we have that for fast lookup in memory
337
+ const rv = new RunView();
338
+ const md = new Metadata();
339
+
340
+ const p1 = rv.RunView<UserEntity>({
341
+ EntityName: "Users",
342
+ ResultType: 'entity_object'
343
+ }, u);
344
+ const p2 = rv.RunView<RoleEntity>({
345
+ EntityName: "Roles",
346
+ ResultType: 'entity_object'
347
+ }, u);
348
+ const p3 = rv.RunView<UserRoleEntity>({
349
+ EntityName: "User Roles",
350
+ ResultType: 'entity_object'
351
+ }, u);
352
+
353
+ // await both
354
+ const [uResult,rResult, urResult] = await Promise.all([p1, p2, p3]);
355
+
356
+ if (uResult.Success && rResult.Success && urResult.Success) {
357
+ // we have the DB users and roles, and user roles
358
+ const dbUsers = uResult.Results;
359
+ const dbRoles = rResult.Results;
360
+ const dbUserRoles = urResult.Results;
361
+ let ok: boolean = true;
362
+
363
+ // now, we can do lookups in memory from those DB roles and Users for their ID values
364
+ // now we will iterate through the users input type and for each role, make sure it is in there
365
+ //const tg = await md.CreateTransactionGroup();
366
+ for (const user of users) {
367
+ const dbUser = dbUsers.find(u => u.Email.trim().toLowerCase() === user.Email.trim().toLowerCase());
368
+ if (dbUser) {
369
+ for (const role of user.Roles) {
370
+ const dbRole = dbRoles.find(r => r.Name.trim().toLowerCase() === role.Name.trim().toLowerCase());
371
+ if (dbRole) {
372
+ // now we need to make sure there is a user role that matches this user and role
373
+ if (!dbUserRoles.find(ur => ur.UserID === dbUser.ID && ur.RoleID === dbRole.ID)) {
374
+ // we need to add a user role
375
+ const ur = await md.GetEntityObject<UserRoleEntity>("User Roles", u);
376
+ ur.UserID = dbUser.ID;
377
+ ur.RoleID = dbRole.ID;
378
+ ok = ok && await ur.Save(); // no await, we do that with submit below
379
+ }
380
+ }
381
+ }
382
+ // now, we check for DB user roles that are NOT in the user.Roles property as they are no longer part of the user's roles
383
+ const thisUserDBRoles = dbUserRoles.filter(ur => ur.UserID === dbUser.ID);
384
+ for (const dbUserRole of thisUserDBRoles) {
385
+ const role = user.Roles.find(r => r.Name.trim().toLowerCase() === dbRoles.find(rr => rr.ID === dbUserRole.RoleID)?.Name.trim().toLowerCase());
386
+ if (!role && !this.IsStandardRole(dbUserRole.Role)) {
387
+ // this user role is no longer in the user's roles, we need to remove it
388
+ //dbUserRole.TransactionGroup = tg;
389
+ ok = ok && await dbUserRole.Delete(); // remove the user role - we use await for the DELETE, not the save
390
+ }
391
+ }
392
+ }
393
+ }
394
+ return ok;
395
+ }
396
+ else {
397
+ return false;
398
+ }
399
+ }
400
+ }
401
+