@memberjunction/server 2.76.0 → 2.78.0
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/README.md +61 -2
- package/dist/apolloServer/index.d.ts.map +1 -1
- package/dist/apolloServer/index.js +1 -3
- package/dist/apolloServer/index.js.map +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts +1 -1
- package/dist/auth/exampleNewUserSubClass.d.ts.map +1 -1
- package/dist/auth/exampleNewUserSubClass.js +1 -1
- package/dist/auth/exampleNewUserSubClass.js.map +1 -1
- package/dist/auth/newUsers.js.map +1 -1
- package/dist/context.d.ts +5 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +34 -3
- package/dist/context.js.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.d.ts +2 -2
- package/dist/entitySubclasses/entityPermissions.server.d.ts.map +1 -1
- package/dist/entitySubclasses/entityPermissions.server.js +2 -2
- package/dist/entitySubclasses/entityPermissions.server.js.map +1 -1
- package/dist/generated/generated.d.ts +1781 -1738
- package/dist/generated/generated.d.ts.map +1 -1
- package/dist/generated/generated.js +6073 -5327
- package/dist/generated/generated.js.map +1 -1
- package/dist/generic/ResolverBase.d.ts +20 -21
- package/dist/generic/ResolverBase.d.ts.map +1 -1
- package/dist/generic/ResolverBase.js +75 -59
- package/dist/generic/ResolverBase.js.map +1 -1
- package/dist/generic/RunViewResolver.d.ts +8 -8
- package/dist/generic/RunViewResolver.d.ts.map +1 -1
- package/dist/generic/RunViewResolver.js +50 -48
- package/dist/generic/RunViewResolver.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/resolvers/AskSkipResolver.d.ts +6 -6
- package/dist/resolvers/AskSkipResolver.d.ts.map +1 -1
- package/dist/resolvers/AskSkipResolver.js +33 -21
- package/dist/resolvers/AskSkipResolver.js.map +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts +1 -1
- package/dist/resolvers/CreateQueryResolver.d.ts.map +1 -1
- package/dist/resolvers/CreateQueryResolver.js +15 -9
- package/dist/resolvers/CreateQueryResolver.js.map +1 -1
- package/dist/resolvers/EntityResolver.d.ts +1 -2
- package/dist/resolvers/EntityResolver.d.ts.map +1 -1
- package/dist/resolvers/EntityResolver.js +17 -9
- package/dist/resolvers/EntityResolver.js.map +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts +1 -1
- package/dist/resolvers/FileCategoryResolver.d.ts.map +1 -1
- package/dist/resolvers/FileCategoryResolver.js +9 -9
- package/dist/resolvers/FileCategoryResolver.js.map +1 -1
- package/dist/resolvers/FileResolver.d.ts.map +1 -1
- package/dist/resolvers/FileResolver.js +3 -1
- package/dist/resolvers/FileResolver.js.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.d.ts.map +1 -1
- package/dist/resolvers/MergeRecordsResolver.js +2 -1
- package/dist/resolvers/MergeRecordsResolver.js.map +1 -1
- package/dist/resolvers/ReportResolver.js.map +1 -1
- package/dist/resolvers/SyncDataResolver.d.ts +8 -8
- package/dist/resolvers/SyncDataResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncDataResolver.js +19 -19
- package/dist/resolvers/SyncDataResolver.js.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.d.ts +10 -10
- package/dist/resolvers/SyncRolesUsersResolver.d.ts.map +1 -1
- package/dist/resolvers/SyncRolesUsersResolver.js +19 -19
- package/dist/resolvers/SyncRolesUsersResolver.js.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.d.ts.map +1 -1
- package/dist/resolvers/TransactionGroupResolver.js.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.d.ts +2 -2
- package/dist/resolvers/UserFavoriteResolver.d.ts.map +1 -1
- package/dist/resolvers/UserFavoriteResolver.js +7 -4
- package/dist/resolvers/UserFavoriteResolver.js.map +1 -1
- package/dist/resolvers/UserResolver.d.ts +3 -3
- package/dist/resolvers/UserResolver.d.ts.map +1 -1
- package/dist/resolvers/UserResolver.js +10 -6
- package/dist/resolvers/UserResolver.js.map +1 -1
- package/dist/resolvers/UserViewResolver.d.ts +2 -2
- package/dist/resolvers/UserViewResolver.d.ts.map +1 -1
- package/dist/resolvers/UserViewResolver.js +11 -6
- package/dist/resolvers/UserViewResolver.js.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.d.ts.map +1 -1
- package/dist/scheduler/LearningCycleScheduler.js +7 -1
- package/dist/scheduler/LearningCycleScheduler.js.map +1 -1
- package/dist/types.d.ts +7 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/dist/util.d.ts +8 -1
- package/dist/util.d.ts.map +1 -1
- package/dist/util.js +28 -0
- package/dist/util.js.map +1 -1
- package/package.json +34 -34
- package/src/apolloServer/index.ts +3 -3
- package/src/auth/exampleNewUserSubClass.ts +3 -2
- package/src/auth/newUsers.ts +1 -1
- package/src/context.ts +49 -9
- package/src/entitySubclasses/entityPermissions.server.ts +3 -3
- package/src/generated/generated.ts +5709 -5049
- package/src/generic/ResolverBase.ts +103 -86
- package/src/generic/RunViewResolver.ts +55 -54
- package/src/index.ts +1 -1
- package/src/resolvers/AskSkipResolver.ts +44 -23
- package/src/resolvers/CreateQueryResolver.ts +19 -11
- package/src/resolvers/EntityResolver.ts +18 -9
- package/src/resolvers/FileCategoryResolver.ts +12 -9
- package/src/resolvers/FileResolver.ts +4 -2
- package/src/resolvers/MergeRecordsResolver.ts +2 -1
- package/src/resolvers/ReportResolver.ts +1 -1
- package/src/resolvers/SyncDataResolver.ts +21 -21
- package/src/resolvers/SyncRolesUsersResolver.ts +24 -21
- package/src/resolvers/TransactionGroupResolver.ts +1 -1
- package/src/resolvers/UserFavoriteResolver.ts +7 -5
- package/src/resolvers/UserResolver.ts +10 -6
- package/src/resolvers/UserViewResolver.ts +13 -7
- package/src/scheduler/LearningCycleScheduler.ts +10 -4
- package/src/types.ts +14 -4
- package/src/util.ts +45 -2
- package/dist/apolloServer/TransactionPlugin.d.ts +0 -4
- package/dist/apolloServer/TransactionPlugin.d.ts.map +0 -1
- package/dist/apolloServer/TransactionPlugin.js +0 -46
- package/dist/apolloServer/TransactionPlugin.js.map +0 -1
- package/src/apolloServer/TransactionPlugin.ts +0 -53
|
@@ -2,8 +2,11 @@ import {
|
|
|
2
2
|
BaseEntity,
|
|
3
3
|
BaseEntityEvent,
|
|
4
4
|
CompositeKey,
|
|
5
|
+
DatabaseProviderBase,
|
|
5
6
|
EntityFieldTSType,
|
|
6
7
|
EntityPermissionType,
|
|
8
|
+
EntitySaveOptions,
|
|
9
|
+
IRunViewProvider,
|
|
7
10
|
LogDebug,
|
|
8
11
|
LogError,
|
|
9
12
|
LogStatus,
|
|
@@ -80,65 +83,82 @@ export class ResolverBase {
|
|
|
80
83
|
return dataObjectArray;
|
|
81
84
|
}
|
|
82
85
|
|
|
83
|
-
protected async findBy(
|
|
86
|
+
protected async findBy<T = any>(provider: DatabaseProviderBase, entity: string, params: any, contextUser: UserInfo): Promise<Array<T>> {
|
|
84
87
|
// build the SQL query based on the params passed in
|
|
85
|
-
const
|
|
86
|
-
const e =
|
|
88
|
+
const rv = provider as any as IRunViewProvider;
|
|
89
|
+
const e = provider.Entities.find((e) => e.Name === entity);
|
|
87
90
|
if (!e) throw new Error(`Entity ${entity} not found in metadata`);
|
|
88
91
|
// now build a SQL string using the entityInfo and using the properties in the params object
|
|
89
|
-
let
|
|
92
|
+
let extraFilter = "";
|
|
90
93
|
const keys = Object.keys(params);
|
|
91
94
|
keys.forEach((k, i) => {
|
|
92
|
-
if (i > 0)
|
|
95
|
+
if (i > 0) extraFilter += ' AND ';
|
|
93
96
|
// look up the field in the entityInfo to see if it needs quotes
|
|
94
97
|
const field = e.Fields.find((f) => f.Name === k);
|
|
95
98
|
if (!field) throw new Error(`Field ${k} not found in entity ${entity}`);
|
|
96
99
|
const quotes = field.NeedsQuotes ? "'" : '';
|
|
97
|
-
|
|
100
|
+
extraFilter += `${k} = ${quotes}${params[k]}${quotes}`;
|
|
98
101
|
});
|
|
99
102
|
|
|
100
103
|
// ok, now we have a SQL string, run it and return the results
|
|
101
104
|
// use the SQLServerDataProvider
|
|
102
|
-
const result = await
|
|
103
|
-
|
|
105
|
+
const result = await rv.RunView({
|
|
106
|
+
EntityName: entity,
|
|
107
|
+
ExtraFilter: extraFilter,
|
|
108
|
+
}, contextUser)
|
|
109
|
+
if (result && result.Success && result.Results.length > 0) {
|
|
110
|
+
return result.Results;
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
104
115
|
}
|
|
105
116
|
|
|
106
|
-
async RunViewByNameGeneric(viewInput: RunViewByNameInput,
|
|
117
|
+
async RunViewByNameGeneric(viewInput: RunViewByNameInput, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
|
|
107
118
|
try {
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
119
|
+
const rv = provider as any as IRunViewProvider;
|
|
120
|
+
const result = await rv.RunView<UserViewEntity>({
|
|
121
|
+
EntityName: 'User Views',
|
|
122
|
+
ExtraFilter: "Name='" + viewInput.ViewName + "'",
|
|
123
|
+
}, userPayload.userRecord);
|
|
124
|
+
if (result && result.Success && result.Results.length > 0) {
|
|
125
|
+
const viewInfo = result.Results[0];
|
|
126
|
+
return this.RunViewGenericInternal(
|
|
127
|
+
provider,
|
|
128
|
+
viewInfo,
|
|
129
|
+
viewInput.ExtraFilter,
|
|
130
|
+
viewInput.OrderBy,
|
|
131
|
+
viewInput.UserSearchString,
|
|
132
|
+
viewInput.ExcludeUserViewRunID,
|
|
133
|
+
viewInput.OverrideExcludeFilter,
|
|
134
|
+
viewInput.SaveViewResults,
|
|
135
|
+
viewInput.Fields,
|
|
136
|
+
viewInput.IgnoreMaxRows,
|
|
137
|
+
viewInput.ExcludeDataFromAllPriorViewRuns,
|
|
138
|
+
viewInput.ForceAuditLog,
|
|
139
|
+
viewInput.AuditLogDescription,
|
|
140
|
+
viewInput.ResultType,
|
|
141
|
+
userPayload,
|
|
142
|
+
viewInput.MaxRows
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
LogError(`RunViewByNameGeneric: View ${viewInput.ViewName} not found or no results returned`);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
130
149
|
} catch (err) {
|
|
131
150
|
console.log(err);
|
|
132
151
|
return null;
|
|
133
152
|
}
|
|
134
153
|
}
|
|
135
154
|
|
|
136
|
-
async RunViewByIDGeneric(viewInput: RunViewByIDInput,
|
|
155
|
+
async RunViewByIDGeneric(viewInput: RunViewByIDInput, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
|
|
137
156
|
try {
|
|
138
|
-
const viewInfo
|
|
157
|
+
const viewInfo = await provider.GetEntityObject<UserViewEntity>('User Views');
|
|
158
|
+
await viewInfo.Load(viewInput.ViewID);
|
|
139
159
|
return this.RunViewGenericInternal(
|
|
160
|
+
provider,
|
|
140
161
|
viewInfo,
|
|
141
|
-
dataSource,
|
|
142
162
|
viewInput.ExtraFilter,
|
|
143
163
|
viewInput.OrderBy,
|
|
144
164
|
viewInput.UserSearchString,
|
|
@@ -152,7 +172,6 @@ export class ResolverBase {
|
|
|
152
172
|
viewInput.AuditLogDescription,
|
|
153
173
|
viewInput.ResultType,
|
|
154
174
|
userPayload,
|
|
155
|
-
pubSub,
|
|
156
175
|
viewInput.MaxRows
|
|
157
176
|
);
|
|
158
177
|
} catch (err) {
|
|
@@ -161,9 +180,9 @@ export class ResolverBase {
|
|
|
161
180
|
}
|
|
162
181
|
}
|
|
163
182
|
|
|
164
|
-
async RunDynamicViewGeneric(viewInput: RunDynamicViewInput,
|
|
183
|
+
async RunDynamicViewGeneric(viewInput: RunDynamicViewInput, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
|
|
165
184
|
try {
|
|
166
|
-
const md =
|
|
185
|
+
const md = provider;
|
|
167
186
|
const entity = md.Entities.find((e) => e.Name === viewInput.EntityName);
|
|
168
187
|
if (!entity) throw new Error(`Entity ${viewInput.EntityName} not found in metadata`);
|
|
169
188
|
|
|
@@ -175,8 +194,8 @@ export class ResolverBase {
|
|
|
175
194
|
} as UserViewEntity; // only providing a few bits of data here, but it's enough to get the view to run
|
|
176
195
|
|
|
177
196
|
return this.RunViewGenericInternal(
|
|
197
|
+
provider,
|
|
178
198
|
viewInfo,
|
|
179
|
-
dataSource,
|
|
180
199
|
viewInput.ExtraFilter,
|
|
181
200
|
viewInput.OrderBy,
|
|
182
201
|
viewInput.UserSearchString,
|
|
@@ -190,7 +209,6 @@ export class ResolverBase {
|
|
|
190
209
|
viewInput.AuditLogDescription,
|
|
191
210
|
viewInput.ResultType,
|
|
192
211
|
userPayload,
|
|
193
|
-
pubSub,
|
|
194
212
|
viewInput.MaxRows
|
|
195
213
|
);
|
|
196
214
|
} catch (err) {
|
|
@@ -201,22 +219,21 @@ export class ResolverBase {
|
|
|
201
219
|
|
|
202
220
|
async RunViewsGeneric(
|
|
203
221
|
viewInputs: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
|
|
204
|
-
|
|
205
|
-
userPayload: UserPayload
|
|
206
|
-
pubSub: PubSubEngine
|
|
222
|
+
provider: DatabaseProviderBase,
|
|
223
|
+
userPayload: UserPayload
|
|
207
224
|
) {
|
|
208
|
-
|
|
225
|
+
const md = provider;
|
|
209
226
|
let params: RunViewGenericParams[] = [];
|
|
210
227
|
for (const viewInput of viewInputs) {
|
|
211
228
|
try {
|
|
212
229
|
let viewInfo: UserViewEntity | null = null;
|
|
213
230
|
|
|
214
231
|
if (viewInput.ViewName) {
|
|
215
|
-
viewInfo = this.safeFirstArrayElement(await this.findBy(
|
|
232
|
+
viewInfo = this.safeFirstArrayElement(await this.findBy(provider, 'User Views', { Name: viewInput.ViewName }, userPayload.userRecord));
|
|
216
233
|
} else if (viewInput.ViewID) {
|
|
217
|
-
viewInfo =
|
|
234
|
+
viewInfo = await provider.GetEntityObject<UserViewEntity>('User Views');
|
|
235
|
+
await viewInfo.Load(viewInput.ViewID);
|
|
218
236
|
} else if (viewInput.EntityName) {
|
|
219
|
-
md = md || new Metadata();
|
|
220
237
|
const entity = md.Entities.find((e) => e.Name === viewInput.EntityName);
|
|
221
238
|
if (!entity) {
|
|
222
239
|
throw new Error(`Entity ${viewInput.EntityName} not found in metadata`);
|
|
@@ -234,8 +251,8 @@ export class ResolverBase {
|
|
|
234
251
|
}
|
|
235
252
|
|
|
236
253
|
params.push({
|
|
237
|
-
viewInfo
|
|
238
|
-
|
|
254
|
+
viewInfo,
|
|
255
|
+
provider,
|
|
239
256
|
extraFilter: viewInput.ExtraFilter,
|
|
240
257
|
orderBy: viewInput.OrderBy,
|
|
241
258
|
userSearchString: viewInput.UserSearchString,
|
|
@@ -248,8 +265,7 @@ export class ResolverBase {
|
|
|
248
265
|
forceAuditLog: viewInput.ForceAuditLog,
|
|
249
266
|
auditLogDescription: viewInput.AuditLogDescription,
|
|
250
267
|
resultType: viewInput.ResultType,
|
|
251
|
-
userPayload,
|
|
252
|
-
pubSub,
|
|
268
|
+
userPayload,
|
|
253
269
|
});
|
|
254
270
|
} catch (err) {
|
|
255
271
|
LogError(err);
|
|
@@ -335,8 +351,8 @@ export class ResolverBase {
|
|
|
335
351
|
* - Improved error handling (Fix #9)
|
|
336
352
|
*/
|
|
337
353
|
protected async RunViewGenericInternal(
|
|
354
|
+
provider: DatabaseProviderBase,
|
|
338
355
|
viewInfo: UserViewEntity,
|
|
339
|
-
dataSource: sql.ConnectionPool,
|
|
340
356
|
extraFilter: string,
|
|
341
357
|
orderBy: string,
|
|
342
358
|
userSearchString: string,
|
|
@@ -350,20 +366,19 @@ export class ResolverBase {
|
|
|
350
366
|
auditLogDescription: string | undefined,
|
|
351
367
|
resultType: string | undefined,
|
|
352
368
|
userPayload: UserPayload | null,
|
|
353
|
-
pubSub: PubSubEngine,
|
|
354
369
|
maxRows: number | undefined
|
|
355
370
|
) {
|
|
356
371
|
try {
|
|
357
372
|
if (!viewInfo || !userPayload) return null;
|
|
358
373
|
|
|
359
|
-
const md =
|
|
374
|
+
const md = provider
|
|
360
375
|
const user = UserCache.Users.find((u) => u.Email.toLowerCase().trim() === userPayload?.email.toLowerCase().trim());
|
|
361
376
|
if (!user) throw new Error(`User ${userPayload?.email} not found in metadata`);
|
|
362
377
|
|
|
363
378
|
const entityInfo = md.Entities.find((e) => e.Name === viewInfo.Entity);
|
|
364
379
|
if (!entityInfo) throw new Error(`Entity ${viewInfo.Entity} not found in metadata`);
|
|
365
380
|
|
|
366
|
-
const rv =
|
|
381
|
+
const rv = md as any as IRunViewProvider;
|
|
367
382
|
|
|
368
383
|
// Determine result type
|
|
369
384
|
let rt: 'simple' | 'entity_object' | 'count_only' = 'simple';
|
|
@@ -445,7 +460,7 @@ export class ResolverBase {
|
|
|
445
460
|
if (!params.length) return [];
|
|
446
461
|
|
|
447
462
|
let md: Metadata | null = null;
|
|
448
|
-
const rv =
|
|
463
|
+
const rv = params[0].provider as any as IRunViewProvider;
|
|
449
464
|
let runViewParams: RunViewParams[] = [];
|
|
450
465
|
|
|
451
466
|
// Fix #1: Get user info only once for all queries
|
|
@@ -524,9 +539,9 @@ export class ResolverBase {
|
|
|
524
539
|
}
|
|
525
540
|
}
|
|
526
541
|
|
|
527
|
-
protected async createRecordAccessAuditLogRecord(userPayload: UserPayload, entityName: string, recordId: any): Promise<any> {
|
|
542
|
+
protected async createRecordAccessAuditLogRecord(provider: DatabaseProviderBase, userPayload: UserPayload, entityName: string, recordId: any): Promise<any> {
|
|
528
543
|
try {
|
|
529
|
-
const md =
|
|
544
|
+
const md = provider;
|
|
530
545
|
const entityInfo = md.Entities.find((e) => e.Name.trim().toLowerCase() === entityName.trim().toLowerCase());
|
|
531
546
|
if (!entityInfo) throw new Error(`Entity ${entityName} not found in metadata`);
|
|
532
547
|
|
|
@@ -538,15 +553,15 @@ export class ResolverBase {
|
|
|
538
553
|
if (!userInfo) throw new Error(`User ${userPayload?.email} not found in metadata`);
|
|
539
554
|
if (!auditLogType) throw new Error(`Audit Log Type ${auditLogTypeName} not found in metadata`);
|
|
540
555
|
|
|
541
|
-
return await this.createAuditLogRecord(userPayload, null, auditLogTypeName, 'Success', null, entityInfo.ID, recordId);
|
|
556
|
+
return await this.createAuditLogRecord(provider, userPayload, null, auditLogTypeName, 'Success', null, entityInfo.ID, recordId);
|
|
542
557
|
}
|
|
543
558
|
} catch (e) {
|
|
544
559
|
console.log(e);
|
|
545
560
|
}
|
|
546
561
|
}
|
|
547
562
|
|
|
548
|
-
protected getRowLevelSecurityWhereClause(entityName: string, userPayload: UserPayload, type: EntityPermissionType, returnPrefix: string) {
|
|
549
|
-
const md =
|
|
563
|
+
protected getRowLevelSecurityWhereClause(provider: DatabaseProviderBase, entityName: string, userPayload: UserPayload, type: EntityPermissionType, returnPrefix: string) {
|
|
564
|
+
const md = provider;
|
|
550
565
|
const entityInfo = md.Entities.find((e) => e.Name.trim().toLowerCase() === entityName.trim().toLowerCase());
|
|
551
566
|
if (!entityInfo) throw new Error(`Entity ${entityName} not found in metadata`);
|
|
552
567
|
const user = UserCache.Users.find((u) => u.Email.toLowerCase().trim() === userPayload?.email.toLowerCase().trim());
|
|
@@ -556,6 +571,7 @@ export class ResolverBase {
|
|
|
556
571
|
}
|
|
557
572
|
|
|
558
573
|
protected async createAuditLogRecord(
|
|
574
|
+
provider: DatabaseProviderBase,
|
|
559
575
|
userPayload: UserPayload,
|
|
560
576
|
authorizationName: string | null,
|
|
561
577
|
auditLogTypeName: string,
|
|
@@ -565,7 +581,7 @@ export class ResolverBase {
|
|
|
565
581
|
recordId: any | null
|
|
566
582
|
): Promise<any> {
|
|
567
583
|
try {
|
|
568
|
-
const md =
|
|
584
|
+
const md = provider;
|
|
569
585
|
const userInfo = UserCache.Users.find((u) => u.Email.toLowerCase().trim() === userPayload?.email.toLowerCase().trim());
|
|
570
586
|
const authorization = authorizationName
|
|
571
587
|
? md.Authorizations.find((a) => a.Name.trim().toLowerCase() === authorizationName.trim().toLowerCase())
|
|
@@ -593,15 +609,17 @@ export class ResolverBase {
|
|
|
593
609
|
|
|
594
610
|
if (recordId) auditLog.RecordID = recordId;
|
|
595
611
|
|
|
596
|
-
if (await auditLog.Save())
|
|
597
|
-
|
|
612
|
+
if (await auditLog.Save())
|
|
613
|
+
return auditLog;
|
|
614
|
+
else
|
|
615
|
+
throw new Error(`Error saving audit log record`);
|
|
598
616
|
} catch (err) {
|
|
599
617
|
console.log(err);
|
|
600
618
|
return null;
|
|
601
619
|
}
|
|
602
620
|
}
|
|
603
621
|
|
|
604
|
-
protected safeFirstArrayElement(arr:
|
|
622
|
+
protected safeFirstArrayElement<T = any>(arr: T[]) {
|
|
605
623
|
if (arr && arr.length > 0) {
|
|
606
624
|
return arr[0];
|
|
607
625
|
}
|
|
@@ -613,7 +631,6 @@ export class ResolverBase {
|
|
|
613
631
|
}
|
|
614
632
|
|
|
615
633
|
protected GetUserFromEmail(email: string): UserInfo | undefined {
|
|
616
|
-
const md = new Metadata();
|
|
617
634
|
return UserCache.Users.find((u) => u.Email.toLowerCase().trim() === email.toLowerCase().trim());
|
|
618
635
|
}
|
|
619
636
|
protected GetUserFromPayload(userPayload: UserPayload): UserInfo | undefined {
|
|
@@ -626,7 +643,6 @@ export class ResolverBase {
|
|
|
626
643
|
if (!userPayload.email)
|
|
627
644
|
return undefined;
|
|
628
645
|
|
|
629
|
-
const md = new Metadata();
|
|
630
646
|
return UserCache.Users.find((u) => u.Email.toLowerCase().trim() === userPayload.email.toLowerCase().trim());
|
|
631
647
|
}
|
|
632
648
|
|
|
@@ -673,18 +689,19 @@ export class ResolverBase {
|
|
|
673
689
|
}
|
|
674
690
|
}
|
|
675
691
|
|
|
676
|
-
protected async CreateRecord(entityName: string, input: any,
|
|
677
|
-
if (await this.BeforeCreate(
|
|
692
|
+
protected async CreateRecord(entityName: string, input: any, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
|
|
693
|
+
if (await this.BeforeCreate(provider, input)) {
|
|
678
694
|
// fire event and proceed if it wasn't cancelled
|
|
679
|
-
const entityObject = await
|
|
695
|
+
const entityObject = await provider.GetEntityObject(entityName, this.GetUserFromPayload(userPayload));
|
|
680
696
|
entityObject.NewRecord();
|
|
681
697
|
entityObject.SetMany(input);
|
|
682
698
|
|
|
683
699
|
this.ListenForEntityMessages(entityObject, pubSub, userPayload);
|
|
684
700
|
|
|
701
|
+
// Pass the transactionScopeId from the user payload to the save operation
|
|
685
702
|
if (await entityObject.Save()) {
|
|
686
703
|
// save worked, fire the AfterCreate event and then return all the data
|
|
687
|
-
await this.AfterCreate(
|
|
704
|
+
await this.AfterCreate(provider, input); // fire event
|
|
688
705
|
return this.MapFieldNamesToCodeNames(entityName, entityObject.GetAll());
|
|
689
706
|
}
|
|
690
707
|
// save failed, return null
|
|
@@ -693,17 +710,16 @@ export class ResolverBase {
|
|
|
693
710
|
}
|
|
694
711
|
|
|
695
712
|
// Before/After CREATE Event Hooks for Sub-Classes to Override
|
|
696
|
-
protected async BeforeCreate(
|
|
713
|
+
protected async BeforeCreate(provider: DatabaseProviderBase, input: any): Promise<boolean> {
|
|
697
714
|
return true;
|
|
698
715
|
}
|
|
699
|
-
protected async AfterCreate(
|
|
716
|
+
protected async AfterCreate(provider: DatabaseProviderBase, input: any) {}
|
|
700
717
|
|
|
701
|
-
protected async UpdateRecord(entityName: string, input: any,
|
|
702
|
-
if (await this.BeforeUpdate(
|
|
718
|
+
protected async UpdateRecord(entityName: string, input: any, provider: DatabaseProviderBase, userPayload: UserPayload, pubSub: PubSubEngine) {
|
|
719
|
+
if (await this.BeforeUpdate(provider, input)) {
|
|
703
720
|
// fire event and proceed if it wasn't cancelled
|
|
704
|
-
const md = new Metadata();
|
|
705
721
|
const userInfo = this.GetUserFromPayload(userPayload);
|
|
706
|
-
const entityObject = await
|
|
722
|
+
const entityObject = await provider.GetEntityObject(entityName, userInfo);
|
|
707
723
|
const entityInfo = entityObject.EntityInfo;
|
|
708
724
|
const clientNewValues = {};
|
|
709
725
|
Object.keys(input).forEach((key) => {
|
|
@@ -752,9 +768,10 @@ export class ResolverBase {
|
|
|
752
768
|
}
|
|
753
769
|
|
|
754
770
|
this.ListenForEntityMessages(entityObject, pubSub, userPayload);
|
|
771
|
+
|
|
755
772
|
if (await entityObject.Save()) {
|
|
756
773
|
// save worked, fire afterevent and return all the data
|
|
757
|
-
await this.AfterUpdate(
|
|
774
|
+
await this.AfterUpdate(provider, input); // fire event
|
|
758
775
|
|
|
759
776
|
return this.MapFieldNamesToCodeNames(entityName, entityObject.GetAll());
|
|
760
777
|
} else {
|
|
@@ -937,20 +954,20 @@ export class ResolverBase {
|
|
|
937
954
|
entityName: string,
|
|
938
955
|
key: CompositeKey,
|
|
939
956
|
options: DeleteOptionsInput,
|
|
940
|
-
|
|
957
|
+
provider: DatabaseProviderBase,
|
|
941
958
|
userPayload: UserPayload,
|
|
942
959
|
pubSub: PubSubEngine
|
|
943
960
|
) {
|
|
944
|
-
if (await this.BeforeDelete(
|
|
961
|
+
if (await this.BeforeDelete(provider, key)) {
|
|
945
962
|
// fire event and proceed if it wasn't cancelled
|
|
946
|
-
const entityObject = await
|
|
963
|
+
const entityObject = await provider.GetEntityObject(entityName, this.GetUserFromPayload(userPayload));
|
|
947
964
|
await entityObject.InnerLoad(key);
|
|
948
965
|
const returnValue = entityObject.GetAll(); // grab the values before we delete so we can return last state before delete if we are successful.
|
|
949
966
|
|
|
950
967
|
this.ListenForEntityMessages(entityObject, pubSub, userPayload);
|
|
951
|
-
|
|
968
|
+
|
|
952
969
|
if (await entityObject.Delete(options)) {
|
|
953
|
-
await this.AfterDelete(
|
|
970
|
+
await this.AfterDelete(provider, key); // fire event
|
|
954
971
|
return returnValue;
|
|
955
972
|
} else {
|
|
956
973
|
throw new GraphQLError(entityObject.LatestResult?.Message ?? 'Unknown error', {
|
|
@@ -965,14 +982,14 @@ export class ResolverBase {
|
|
|
965
982
|
}
|
|
966
983
|
|
|
967
984
|
// Before/After DELETE Event Hooks for Sub-Classes to Override
|
|
968
|
-
protected async BeforeDelete(
|
|
985
|
+
protected async BeforeDelete(provider: DatabaseProviderBase, key: CompositeKey): Promise<boolean> {
|
|
969
986
|
return true;
|
|
970
987
|
}
|
|
971
|
-
protected async AfterDelete(
|
|
988
|
+
protected async AfterDelete(provider: DatabaseProviderBase, key: CompositeKey) {}
|
|
972
989
|
|
|
973
990
|
// Before/After UPDATE Event Hooks for Sub-Classes to Override
|
|
974
|
-
protected async BeforeUpdate(
|
|
991
|
+
protected async BeforeUpdate(provider: DatabaseProviderBase, input: any): Promise<boolean> {
|
|
975
992
|
return true;
|
|
976
993
|
}
|
|
977
|
-
protected async AfterUpdate(
|
|
994
|
+
protected async AfterUpdate(provider: DatabaseProviderBase, input: any) {}
|
|
978
995
|
}
|
|
@@ -3,6 +3,8 @@ import { AppContext } from '../types.js';
|
|
|
3
3
|
import { ResolverBase } from './ResolverBase.js';
|
|
4
4
|
import { LogError, LogStatus } from '@memberjunction/core';
|
|
5
5
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
6
|
+
import { GetReadOnlyProvider } from '../util.js';
|
|
7
|
+
import { UserViewEntity } from '@memberjunction/core-entities';
|
|
6
8
|
|
|
7
9
|
/********************************************************************************
|
|
8
10
|
* The PURPOSE of this resolver is to provide a generic way to run a view and return the results.
|
|
@@ -457,17 +459,17 @@ export class RunViewResolver extends ResolverBase {
|
|
|
457
459
|
@Query(() => RunViewResult)
|
|
458
460
|
async RunViewByName(
|
|
459
461
|
@Arg('input', () => RunViewByNameInput) input: RunViewByNameInput,
|
|
460
|
-
@Ctx() {
|
|
462
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
461
463
|
pubSub: PubSubEngine
|
|
462
464
|
) {
|
|
463
465
|
try {
|
|
464
|
-
const
|
|
465
|
-
|
|
466
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
467
|
+
const rawData = await super.RunViewByNameGeneric(input, provider, userPayload, pubSub);
|
|
468
|
+
if (rawData === null)
|
|
469
|
+
return null;
|
|
466
470
|
|
|
467
|
-
const
|
|
468
|
-
const
|
|
469
|
-
const entityId = entityIdResult.recordset;
|
|
470
|
-
const returnData = this.processRawData(rawData.Results, entityId[0].EntityID);
|
|
471
|
+
const viewInfo = super.safeFirstArrayElement<UserViewEntity>(await super.findBy<UserViewEntity>(provider, "User Views", { Name: input.ViewName }, userPayload.userRecord));
|
|
472
|
+
const returnData = this.processRawData(rawData.Results, viewInfo.EntityID);
|
|
471
473
|
return {
|
|
472
474
|
Results: returnData,
|
|
473
475
|
UserViewRunID: rawData?.UserViewRunID,
|
|
@@ -484,17 +486,17 @@ export class RunViewResolver extends ResolverBase {
|
|
|
484
486
|
@Query(() => RunViewResult)
|
|
485
487
|
async RunViewByID(
|
|
486
488
|
@Arg('input', () => RunViewByIDInput) input: RunViewByIDInput,
|
|
487
|
-
@Ctx() {
|
|
489
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
488
490
|
pubSub: PubSubEngine
|
|
489
491
|
) {
|
|
490
492
|
try {
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
494
|
+
const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
|
|
495
|
+
if (rawData === null)
|
|
496
|
+
return null;
|
|
493
497
|
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
const entityId = entityIdResult.recordset;
|
|
497
|
-
const returnData = this.processRawData(rawData.Results, entityId[0].EntityID);
|
|
498
|
+
const viewInfo = super.safeFirstArrayElement<UserViewEntity>(await super.findBy<UserViewEntity>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
|
|
499
|
+
const returnData = this.processRawData(rawData.Results, viewInfo.EntityID);
|
|
498
500
|
return {
|
|
499
501
|
Results: returnData,
|
|
500
502
|
UserViewRunID: rawData?.UserViewRunID,
|
|
@@ -511,17 +513,16 @@ export class RunViewResolver extends ResolverBase {
|
|
|
511
513
|
@Query(() => RunViewResult)
|
|
512
514
|
async RunDynamicView(
|
|
513
515
|
@Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput,
|
|
514
|
-
@Ctx() {
|
|
516
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
515
517
|
pubSub: PubSubEngine
|
|
516
518
|
) {
|
|
517
519
|
try {
|
|
518
|
-
const
|
|
520
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
521
|
+
const rawData = await super.RunDynamicViewGeneric(input, provider, userPayload, pubSub);
|
|
519
522
|
if (rawData === null) return null;
|
|
520
523
|
|
|
521
|
-
const
|
|
522
|
-
const
|
|
523
|
-
const entityId = entityIdResult.recordset;
|
|
524
|
-
const returnData = this.processRawData(rawData.Results, entityId[0].EntityID);
|
|
524
|
+
const entity = provider.Entities.find((e) => e.Name === input.EntityName);
|
|
525
|
+
const returnData = this.processRawData(rawData.Results, entity.ID);
|
|
525
526
|
return {
|
|
526
527
|
Results: returnData,
|
|
527
528
|
UserViewRunID: rawData?.UserViewRunID,
|
|
@@ -538,23 +539,20 @@ export class RunViewResolver extends ResolverBase {
|
|
|
538
539
|
@Query(() => [RunViewGenericResult])
|
|
539
540
|
async RunViews(
|
|
540
541
|
@Arg('input', () => [RunViewGenericInput]) input: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
|
|
541
|
-
@Ctx() {
|
|
542
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
542
543
|
pubSub: PubSubEngine
|
|
543
544
|
) {
|
|
544
545
|
try {
|
|
545
|
-
const
|
|
546
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
547
|
+
const rawData: RunViewGenericResult[] = await super.RunViewsGeneric(input, provider, userPayload);
|
|
546
548
|
if (!rawData) {
|
|
547
549
|
return null;
|
|
548
550
|
}
|
|
549
551
|
|
|
550
552
|
let results: RunViewGenericResult[] = [];
|
|
551
553
|
for (const [index, data] of rawData.entries()) {
|
|
552
|
-
const
|
|
553
|
-
const
|
|
554
|
-
`SELECT TOP 1 ID from [${this.MJCoreSchema}].vwEntities WHERE Name='${input[index].EntityName}'`
|
|
555
|
-
);
|
|
556
|
-
const entityId = entityIdResult.recordset;
|
|
557
|
-
const returnData: any[] = this.processRawData(data.Results, entityId[0].ID);
|
|
554
|
+
const entity = provider.Entities.find((e) => e.Name === input[index].EntityName);
|
|
555
|
+
const returnData: any[] = this.processRawData(data.Results, entity.ID);
|
|
558
556
|
|
|
559
557
|
results.push({
|
|
560
558
|
Results: returnData,
|
|
@@ -577,17 +575,17 @@ export class RunViewResolver extends ResolverBase {
|
|
|
577
575
|
@Query(() => RunViewResult)
|
|
578
576
|
async RunViewByNameSystemUser(
|
|
579
577
|
@Arg('input', () => RunViewByNameInput) input: RunViewByNameInput,
|
|
580
|
-
@Ctx() {
|
|
578
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
581
579
|
pubSub: PubSubEngine
|
|
582
580
|
) {
|
|
583
581
|
try {
|
|
584
|
-
const
|
|
582
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
583
|
+
const rawData = await super.RunViewByNameGeneric(input, provider, userPayload, pubSub);
|
|
585
584
|
if (rawData === null) return null;
|
|
586
585
|
|
|
587
|
-
const
|
|
588
|
-
const
|
|
589
|
-
const
|
|
590
|
-
const returnData = this.processRawData(rawData.Results, entityId[0].EntityID);
|
|
586
|
+
const entity = provider.Entities.find((e) => e.Name === input.ViewName);
|
|
587
|
+
const entityId = entity ? entity.ID : null;
|
|
588
|
+
const returnData = this.processRawData(rawData.Results, entityId);
|
|
591
589
|
return {
|
|
592
590
|
Results: returnData,
|
|
593
591
|
UserViewRunID: rawData?.UserViewRunID,
|
|
@@ -607,17 +605,16 @@ export class RunViewResolver extends ResolverBase {
|
|
|
607
605
|
@Query(() => RunViewResult)
|
|
608
606
|
async RunViewByIDSystemUser(
|
|
609
607
|
@Arg('input', () => RunViewByIDInput) input: RunViewByIDInput,
|
|
610
|
-
@Ctx() {
|
|
608
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
611
609
|
pubSub: PubSubEngine
|
|
612
610
|
) {
|
|
613
611
|
try {
|
|
614
|
-
const
|
|
612
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
613
|
+
const rawData = await super.RunViewByIDGeneric(input, provider, userPayload, pubSub);
|
|
615
614
|
if (rawData === null) return null;
|
|
616
615
|
|
|
617
|
-
const
|
|
618
|
-
const
|
|
619
|
-
const entityId = entityIdResult.recordset;
|
|
620
|
-
const returnData = this.processRawData(rawData.Results, entityId[0].EntityID);
|
|
616
|
+
const viewInfo = super.safeFirstArrayElement<UserViewEntity>(await super.findBy<UserViewEntity>(provider, "User Views", { ID: input.ViewID }, userPayload.userRecord));
|
|
617
|
+
const returnData = this.processRawData(rawData.Results, viewInfo.EntityID);
|
|
621
618
|
return {
|
|
622
619
|
Results: returnData,
|
|
623
620
|
UserViewRunID: rawData?.UserViewRunID,
|
|
@@ -637,17 +634,20 @@ export class RunViewResolver extends ResolverBase {
|
|
|
637
634
|
@Query(() => RunViewResult)
|
|
638
635
|
async RunDynamicViewSystemUser(
|
|
639
636
|
@Arg('input', () => RunDynamicViewInput) input: RunDynamicViewInput,
|
|
640
|
-
@Ctx() {
|
|
637
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
641
638
|
pubSub: PubSubEngine
|
|
642
639
|
) {
|
|
643
640
|
try {
|
|
644
|
-
const
|
|
641
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
642
|
+
const rawData = await super.RunDynamicViewGeneric(input, provider, userPayload, pubSub);
|
|
645
643
|
if (rawData === null) return null;
|
|
646
644
|
|
|
647
|
-
const
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
645
|
+
const entity = provider.Entities.find((e) => e.Name === input.EntityName);
|
|
646
|
+
if (!entity) {
|
|
647
|
+
LogError(new Error(`Entity with name ${input.EntityName} not found`));
|
|
648
|
+
return null;
|
|
649
|
+
}
|
|
650
|
+
const returnData = this.processRawData(rawData.Results, entity.ID);
|
|
651
651
|
return {
|
|
652
652
|
Results: returnData,
|
|
653
653
|
UserViewRunID: rawData?.UserViewRunID,
|
|
@@ -667,23 +667,24 @@ export class RunViewResolver extends ResolverBase {
|
|
|
667
667
|
@Query(() => [RunViewGenericResult])
|
|
668
668
|
async RunViewsSystemUser(
|
|
669
669
|
@Arg('input', () => [RunViewGenericInput]) input: (RunViewByNameInput & RunViewByIDInput & RunDynamicViewInput)[],
|
|
670
|
-
@Ctx() {
|
|
670
|
+
@Ctx() { providers, userPayload }: AppContext,
|
|
671
671
|
pubSub: PubSubEngine
|
|
672
672
|
) {
|
|
673
673
|
try {
|
|
674
|
-
const
|
|
674
|
+
const provider = GetReadOnlyProvider(providers, { allowFallbackToReadWrite: true });
|
|
675
|
+
const rawData: RunViewGenericResult[] = await super.RunViewsGeneric(input, provider, userPayload);
|
|
675
676
|
if (!rawData) {
|
|
676
677
|
return null;
|
|
677
678
|
}
|
|
678
679
|
|
|
679
680
|
let results: RunViewGenericResult[] = [];
|
|
680
681
|
for (const [index, data] of rawData.entries()) {
|
|
681
|
-
const
|
|
682
|
-
|
|
683
|
-
`
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
const returnData: any[] = this.processRawData(data.Results,
|
|
682
|
+
const entity = provider.Entities.find((e) => e.Name === input[index].EntityName);
|
|
683
|
+
if (!entity) {
|
|
684
|
+
LogError(new Error(`Entity with name ${input[index].EntityName} not found`));
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
const returnData: any[] = this.processRawData(data.Results, entity.ID);
|
|
687
688
|
|
|
688
689
|
results.push({
|
|
689
690
|
Results: returnData,
|