@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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Arg, Ctx, Field, InputType, Mutation, ObjectType, registerEnumType } from 'type-graphql';
|
|
2
|
-
import { AppContext } from '../types.js';
|
|
3
|
-
import { LogError, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
2
|
+
import { AppContext, UserPayload } from '../types.js';
|
|
3
|
+
import { EntityDeleteOptions, EntitySaveOptions, LogError, Metadata, RunView, UserInfo } from '@memberjunction/core';
|
|
4
4
|
import { RequireSystemUser } from '../directives/RequireSystemUser.js';
|
|
5
5
|
import { RoleEntity, UserEntity, UserRoleEntity } from '@memberjunction/core-entities';
|
|
6
6
|
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
@@ -131,9 +131,9 @@ export class SyncRolesAndUsersResolver {
|
|
|
131
131
|
|
|
132
132
|
if (result && result.Success) {
|
|
133
133
|
const currentRoles = result.Results;
|
|
134
|
-
if (await this.DeleteRemovedRoles(currentRoles, roles, context.userPayload.userRecord)) {
|
|
135
|
-
if ( await this.AddNewRoles(currentRoles, roles, context.userPayload.userRecord)) {
|
|
136
|
-
return await this.UpdateExistingRoles(currentRoles, roles, context.userPayload
|
|
134
|
+
if (await this.DeleteRemovedRoles(currentRoles, roles, context.userPayload.userRecord, context.userPayload)) {
|
|
135
|
+
if ( await this.AddNewRoles(currentRoles, roles, context.userPayload.userRecord, context.userPayload)) {
|
|
136
|
+
return await this.UpdateExistingRoles(currentRoles, roles, context.userPayload);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
}
|
|
@@ -145,7 +145,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
145
145
|
}
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
protected async UpdateExistingRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[],
|
|
148
|
+
protected async UpdateExistingRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], userPayload: UserPayload): Promise<SyncRolesAndUsersResultType> {
|
|
149
149
|
// go through the future roles and update any that are in the current roles
|
|
150
150
|
const md = new Metadata();
|
|
151
151
|
let ok: boolean = true;
|
|
@@ -160,7 +160,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
160
160
|
return { Success: ok };
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
protected async AddNewRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<boolean> {
|
|
163
|
+
protected async AddNewRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo, userPayload: UserPayload): Promise<boolean> {
|
|
164
164
|
// go through the future roles and add any that are not in the current roles
|
|
165
165
|
const md = new Metadata();
|
|
166
166
|
let ok: boolean = true;
|
|
@@ -177,7 +177,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
|
|
180
|
-
protected async DeleteRemovedRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo): Promise<boolean> {
|
|
180
|
+
protected async DeleteRemovedRoles(currentRoles: RoleEntity[], futureRoles: RoleInputType[], user: UserInfo, userPayload: UserPayload): Promise<boolean> {
|
|
181
181
|
const rv = new RunView();
|
|
182
182
|
let ok: boolean = true;
|
|
183
183
|
|
|
@@ -185,7 +185,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
185
185
|
for (const remove of currentRoles) {
|
|
186
186
|
if (!this.IsStandardRole(remove.Name)) {
|
|
187
187
|
if (!futureRoles.find(r => r.Name.trim().toLowerCase() === remove.Name.trim().toLowerCase())) {
|
|
188
|
-
ok = ok && await this.DeleteSingleRole(remove, rv, user);
|
|
188
|
+
ok = ok && await this.DeleteSingleRole(remove, rv, user, userPayload);
|
|
189
189
|
}
|
|
190
190
|
}
|
|
191
191
|
}
|
|
@@ -199,9 +199,10 @@ export class SyncRolesAndUsersResolver {
|
|
|
199
199
|
return this.StandardRoles.find(r => r.toLowerCase() === roleName.toLowerCase()) !== undefined;
|
|
200
200
|
}
|
|
201
201
|
|
|
202
|
-
protected async DeleteSingleRole(role: RoleEntity, rv: RunView, user: UserInfo): Promise<boolean> {
|
|
202
|
+
protected async DeleteSingleRole(role: RoleEntity, rv: RunView, user: UserInfo, userPayload: UserPayload): Promise<boolean> {
|
|
203
203
|
// first, remove all the UserRole records that match this role
|
|
204
204
|
let ok: boolean = true;
|
|
205
|
+
|
|
205
206
|
const r2 = await rv.RunView<UserRoleEntity>({
|
|
206
207
|
EntityName: "User Roles",
|
|
207
208
|
ExtraFilter: "RoleID = '" + role.ID + "'",
|
|
@@ -238,10 +239,10 @@ export class SyncRolesAndUsersResolver {
|
|
|
238
239
|
if (result && result.Success) {
|
|
239
240
|
// go through current users and remove those that are not in the input
|
|
240
241
|
const currentUsers = result.Results;
|
|
241
|
-
if (await this.DeleteRemovedUsers(currentUsers, users, context.userPayload.userRecord)) {
|
|
242
|
-
if (await this.AddNewUsers(currentUsers, users, context.userPayload
|
|
243
|
-
if (await this.UpdateExistingUsers(currentUsers, users, context.userPayload
|
|
244
|
-
if (await this.SyncUserRoles(users, context.userPayload.userRecord)) {
|
|
242
|
+
if (await this.DeleteRemovedUsers(currentUsers, users, context.userPayload.userRecord, context.userPayload)) {
|
|
243
|
+
if (await this.AddNewUsers(currentUsers, users, context.userPayload)) {
|
|
244
|
+
if (await this.UpdateExistingUsers(currentUsers, users, context.userPayload)) {
|
|
245
|
+
if (await this.SyncUserRoles(users, context.userPayload.userRecord, context.userPayload)) {
|
|
245
246
|
return { Success: true };
|
|
246
247
|
}
|
|
247
248
|
}
|
|
@@ -256,9 +257,10 @@ export class SyncRolesAndUsersResolver {
|
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
|
|
259
|
-
protected async UpdateExistingUsers(currentUsers: UserEntity[], futureUsers: UserInputType[],
|
|
260
|
+
protected async UpdateExistingUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], userPayload: UserPayload): Promise<boolean> {
|
|
260
261
|
// go through the future users and update any that are in the current users
|
|
261
262
|
let ok: boolean = true;
|
|
263
|
+
|
|
262
264
|
for (const update of futureUsers) {
|
|
263
265
|
const current = currentUsers.find(c => c.Email?.trim().toLowerCase() === update.Email?.trim().toLowerCase());
|
|
264
266
|
if (current) {
|
|
@@ -272,7 +274,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
272
274
|
}
|
|
273
275
|
return ok;
|
|
274
276
|
}
|
|
275
|
-
protected async AddNewUsers(currentUsers: UserEntity[], futureUsers: UserInputType[],
|
|
277
|
+
protected async AddNewUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], userPayload: UserPayload): Promise<boolean> {
|
|
276
278
|
// add users that are not in the current users
|
|
277
279
|
const md = new Metadata();
|
|
278
280
|
let ok: boolean = true;
|
|
@@ -285,7 +287,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
285
287
|
ok = ok && await match.Save();
|
|
286
288
|
}
|
|
287
289
|
else {
|
|
288
|
-
const user = await md.GetEntityObject<UserEntity>("Users",
|
|
290
|
+
const user = await md.GetEntityObject<UserEntity>("Users", userPayload.userRecord);
|
|
289
291
|
user.Name = add.Name;
|
|
290
292
|
user.Type = add.Type;
|
|
291
293
|
user.Email = add.Email;
|
|
@@ -300,7 +302,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
300
302
|
return ok;
|
|
301
303
|
}
|
|
302
304
|
|
|
303
|
-
protected async DeleteRemovedUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo): Promise<boolean> {
|
|
305
|
+
protected async DeleteRemovedUsers(currentUsers: UserEntity[], futureUsers: UserInputType[], u: UserInfo, userPayload: UserPayload): Promise<boolean> {
|
|
304
306
|
// remove users that are not in the future users
|
|
305
307
|
const rv = new RunView();
|
|
306
308
|
const md = new Metadata();
|
|
@@ -310,16 +312,17 @@ export class SyncRolesAndUsersResolver {
|
|
|
310
312
|
for (const remove of currentUsers) {
|
|
311
313
|
if (remove.Type.trim().toLowerCase() !== 'owner') {
|
|
312
314
|
if (!futureUsers.find(r => r.Email.trim().toLowerCase() === remove.Email.trim().toLowerCase())) {
|
|
313
|
-
ok = ok && await this.DeleteSingleUser(remove, rv, u);
|
|
315
|
+
ok = ok && await this.DeleteSingleUser(remove, rv, u, userPayload);
|
|
314
316
|
}
|
|
315
317
|
}
|
|
316
318
|
}
|
|
317
319
|
return ok;
|
|
318
320
|
}
|
|
319
321
|
|
|
320
|
-
protected async DeleteSingleUser(user: UserEntity, rv: RunView, u: UserInfo): Promise<boolean> {
|
|
322
|
+
protected async DeleteSingleUser(user: UserEntity, rv: RunView, u: UserInfo, userPayload: UserPayload): Promise<boolean> {
|
|
321
323
|
// first, remove all the UserRole records that match this user
|
|
322
324
|
let ok: boolean = true;
|
|
325
|
+
|
|
323
326
|
const r2 = await rv.RunView<UserRoleEntity>({
|
|
324
327
|
EntityName: "User Roles",
|
|
325
328
|
ExtraFilter: "UserID = '" + user.ID + "'",
|
|
@@ -341,7 +344,7 @@ export class SyncRolesAndUsersResolver {
|
|
|
341
344
|
}
|
|
342
345
|
}
|
|
343
346
|
|
|
344
|
-
protected async SyncUserRoles(users: UserInputType[], u: UserInfo): Promise<boolean> {
|
|
347
|
+
protected async SyncUserRoles(users: UserInputType[], u: UserInfo, userPayload: UserPayload): Promise<boolean> {
|
|
345
348
|
// 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
|
|
346
349
|
const rv = new RunView();
|
|
347
350
|
const md = new Metadata();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Arg, Ctx, Field, InputType, Int, Mutation, ObjectType, registerEnumType } from 'type-graphql';
|
|
2
2
|
import { AppContext } from '../types.js';
|
|
3
|
-
import { CompositeKey, KeyValuePair, LogError, Metadata, TransactionVariable, BaseEntity } from '@memberjunction/core';
|
|
3
|
+
import { CompositeKey, KeyValuePair, LogError, Metadata, TransactionVariable, BaseEntity, EntityDeleteOptions, EntitySaveOptions } from '@memberjunction/core';
|
|
4
4
|
import { SafeJSONParse } from '@memberjunction/global';
|
|
5
5
|
|
|
6
6
|
export enum TransactionVariableType {
|
|
@@ -14,9 +14,9 @@ import {
|
|
|
14
14
|
Resolver,
|
|
15
15
|
} from '@memberjunction/server';
|
|
16
16
|
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
17
|
-
import { UserFavoriteEntity } from '@memberjunction/core-entities';
|
|
18
17
|
|
|
19
18
|
import { UserFavorite_, UserFavoriteResolverBase } from '../generated/generated.js';
|
|
19
|
+
import { GetReadOnlyProvider } from '../util.js';
|
|
20
20
|
|
|
21
21
|
//****************************************************************************
|
|
22
22
|
// INPUT TYPE for User Favorite Queries
|
|
@@ -69,13 +69,15 @@ export class UserFavoriteResult {
|
|
|
69
69
|
@Resolver(UserFavorite_)
|
|
70
70
|
export class UserFavoriteResolver extends UserFavoriteResolverBase {
|
|
71
71
|
@Query(() => [UserFavorite_])
|
|
72
|
-
async UserFavoritesByUserID(@Arg('UserID', () => Int) UserID: number, @Ctx() {
|
|
73
|
-
|
|
72
|
+
async UserFavoritesByUserID(@Arg('UserID', () => Int) UserID: number, @Ctx() { providers, userPayload }: AppContext) {
|
|
73
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
74
|
+
return await this.findBy(provider, 'User Favorites', { UserID }, userPayload.userRecord);
|
|
74
75
|
}
|
|
75
76
|
|
|
76
77
|
@Query(() => [UserFavorite_])
|
|
77
|
-
async UserFavoriteSearchByParams(@Arg('params', () => Int) params: UserFavoriteSearchParams, @Ctx() {
|
|
78
|
-
|
|
78
|
+
async UserFavoriteSearchByParams(@Arg('params', () => Int) params: UserFavoriteSearchParams, @Ctx() { providers, userPayload }: AppContext) {
|
|
79
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
80
|
+
return await this.findBy(provider, 'User Favorites', params, userPayload.userRecord);
|
|
79
81
|
}
|
|
80
82
|
|
|
81
83
|
@Query(() => UserFavoriteResult)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AppContext, Arg, Ctx, Int, Query, Resolver } from '@memberjunction/server';
|
|
2
2
|
import { User_, UserResolverBase } from '../generated/generated.js';
|
|
3
|
+
import { GetReadOnlyProvider } from '../util.js';
|
|
3
4
|
|
|
4
5
|
@Resolver(User_)
|
|
5
6
|
export class UserResolver extends UserResolverBase {
|
|
@@ -11,22 +12,25 @@ export class UserResolver extends UserResolverBase {
|
|
|
11
12
|
}
|
|
12
13
|
|
|
13
14
|
@Query(() => User_)
|
|
14
|
-
async UserByID(@Arg('ID', () => Int) ID: number, @Ctx() {
|
|
15
|
-
const
|
|
15
|
+
async UserByID(@Arg('ID', () => Int) ID: number, @Ctx() { providers, userPayload }: AppContext) {
|
|
16
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
17
|
+
const retVal = super.safeFirstArrayElement(await this.findBy(provider, 'Users', { ID }, userPayload.userRecord));
|
|
16
18
|
return this.MapFieldNamesToCodeNames('Users', retVal);
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
@Query(() => User_)
|
|
20
|
-
async UserByEmployeeID(@Arg('EmployeeID', () => Int) EmployeeID: number, @Ctx() {
|
|
21
|
-
const
|
|
22
|
+
async UserByEmployeeID(@Arg('EmployeeID', () => Int) EmployeeID: number, @Ctx() { providers, userPayload }: AppContext) {
|
|
23
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
24
|
+
const retVal = super.safeFirstArrayElement(await this.findBy(provider, 'Users', { EmployeeID }, userPayload.userRecord));
|
|
22
25
|
return this.MapFieldNamesToCodeNames('Users', retVal);
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
@Query(() => User_)
|
|
26
|
-
async UserByEmail(@Arg('Email', () => String) Email: string, @Ctx() {
|
|
29
|
+
async UserByEmail(@Arg('Email', () => String) Email: string, @Ctx() { providers, userPayload }: AppContext) {
|
|
27
30
|
// const searchEmail = userEmailMap[Email] ?? Email;
|
|
28
31
|
const searchEmail = Email;
|
|
29
|
-
const
|
|
32
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
33
|
+
const returnVal = super.safeFirstArrayElement(await this.findBy(provider, 'Users', { Email: searchEmail }, userPayload.userRecord));
|
|
30
34
|
return this.MapFieldNamesToCodeNames('Users', returnVal);
|
|
31
35
|
}
|
|
32
36
|
}
|
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
import { Metadata } from '@memberjunction/core';
|
|
2
|
+
import { EntitySaveOptions, Metadata } from '@memberjunction/core';
|
|
3
3
|
import { AppContext, Arg, Ctx, Int, Query, Resolver, UserPayload } from '@memberjunction/server';
|
|
4
4
|
import { UserView_, UserViewResolverBase } from '../generated/generated.js';
|
|
5
5
|
import { UserResolver } from './UserResolver.js';
|
|
6
6
|
import { UserViewEntity, UserViewEntityExtended } from '@memberjunction/core-entities';
|
|
7
|
+
import { GetReadOnlyProvider } from '../util.js';
|
|
7
8
|
|
|
8
9
|
@Resolver(UserView_)
|
|
9
10
|
export class UserViewResolver extends UserViewResolverBase {
|
|
10
11
|
@Query(() => [UserView_])
|
|
11
|
-
async UserViewsByUserID(@Arg('UserID', () => Int) UserID: number, @Ctx() {
|
|
12
|
-
|
|
12
|
+
async UserViewsByUserID(@Arg('UserID', () => Int) UserID: number, @Ctx() { providers, userPayload }: AppContext) {
|
|
13
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
14
|
+
return await this.findBy(provider, 'User Views', { UserID }, userPayload.userRecord);
|
|
13
15
|
}
|
|
14
16
|
|
|
15
17
|
@Query(() => [UserView_])
|
|
16
18
|
async DefaultViewByUserAndEntity(
|
|
17
19
|
@Arg('UserID', () => Int) UserID: number,
|
|
18
20
|
@Arg('EntityID', () => Int) EntityID: number,
|
|
19
|
-
@Ctx() {
|
|
21
|
+
@Ctx() { providers, userPayload }: AppContext
|
|
20
22
|
) {
|
|
21
|
-
|
|
23
|
+
const provider = GetReadOnlyProvider(providers, {allowFallbackToReadWrite: true})
|
|
24
|
+
return await this.findBy(provider, 'User Views', { UserID, EntityID, IsDefault: true }, userPayload.userRecord);
|
|
22
25
|
}
|
|
23
26
|
|
|
24
27
|
@Query(() => [UserView_])
|
|
25
28
|
async CurrentUserDefaultViewByEntityID(@Arg('EntityID', () => Int) EntityID: number, @Ctx() context: AppContext) {
|
|
26
|
-
|
|
29
|
+
const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true})
|
|
30
|
+
return await this.findBy(provider, 'User Views', {
|
|
27
31
|
UserID: await this.getCurrentUserID(context),
|
|
28
32
|
EntityID,
|
|
29
33
|
IsDefault: true,
|
|
@@ -38,7 +42,8 @@ export class UserViewResolver extends UserViewResolverBase {
|
|
|
38
42
|
|
|
39
43
|
@Query(() => [UserView_])
|
|
40
44
|
async CurrentUserUserViewsByEntityID(@Arg('EntityID', () => Int) EntityID: number, @Ctx() context: AppContext) {
|
|
41
|
-
|
|
45
|
+
const provider = GetReadOnlyProvider(context.providers, {allowFallbackToReadWrite: true})
|
|
46
|
+
return this.findBy(provider, 'User Views', { UserID: await this.getCurrentUserID(context), EntityID}, context.userPayload.userRecord);
|
|
42
47
|
}
|
|
43
48
|
|
|
44
49
|
@Query(() => [UserView_])
|
|
@@ -52,6 +57,7 @@ export class UserViewResolver extends UserViewResolverBase {
|
|
|
52
57
|
const viewEntity = <UserViewEntityExtended>await md.GetEntityObject('User Views', u);
|
|
53
58
|
await viewEntity.Load(ID);
|
|
54
59
|
viewEntity.UpdateWhereClause();
|
|
60
|
+
|
|
55
61
|
if (await viewEntity.Save()) {
|
|
56
62
|
return viewEntity.GetAll();
|
|
57
63
|
} else {
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { LogStatus, LogError } from '@memberjunction/core';
|
|
2
|
-
import { UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
2
|
+
import { SQLServerDataProvider, SQLServerProviderConfigData, UserCache } from '@memberjunction/sqlserver-dataprovider';
|
|
3
3
|
import { GetReadWriteDataSource } from '../util.js';
|
|
4
4
|
import { AskSkipResolver } from '../resolvers/AskSkipResolver.js';
|
|
5
|
-
import { DataSourceInfo } from '../types.js';
|
|
5
|
+
import { AppContext, DataSourceInfo } from '../types.js';
|
|
6
6
|
import { getSystemUser } from '../auth/index.js';
|
|
7
7
|
import { BaseSingleton } from '@memberjunction/global';
|
|
8
|
+
import { mj_core_schema } from '../config.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* A simple scheduler for the Skip AI learning cycle
|
|
@@ -89,7 +90,11 @@ export class LearningCycleScheduler extends BaseSingleton<LearningCycleScheduler
|
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
// Create context for the resolver
|
|
92
|
-
const
|
|
93
|
+
const config = new SQLServerProviderConfigData(dataSource, mj_core_schema, 0, undefined, undefined, false);
|
|
94
|
+
const p = new SQLServerDataProvider();
|
|
95
|
+
await p.Config(config);
|
|
96
|
+
|
|
97
|
+
const context: AppContext = {
|
|
93
98
|
dataSource: dataSource,
|
|
94
99
|
dataSources: this.dataSources,
|
|
95
100
|
userPayload: {
|
|
@@ -97,7 +102,8 @@ export class LearningCycleScheduler extends BaseSingleton<LearningCycleScheduler
|
|
|
97
102
|
sessionId: `scheduler_${Date.now()}`,
|
|
98
103
|
userRecord: systemUser,
|
|
99
104
|
isSystemUser: true
|
|
100
|
-
}
|
|
105
|
+
},
|
|
106
|
+
providers: [{provider: p, type: 'Read-Write'}]
|
|
101
107
|
};
|
|
102
108
|
|
|
103
109
|
// Execute the learning cycle
|
package/src/types.ts
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { UserInfo } from '@memberjunction/core';
|
|
1
|
+
import { DatabaseProviderBase, UserInfo } from '@memberjunction/core';
|
|
2
2
|
import { UserViewEntity } from '@memberjunction/core-entities';
|
|
3
3
|
import { GraphQLSchema } from 'graphql';
|
|
4
4
|
import { PubSubEngine } from 'type-graphql';
|
|
5
5
|
import sql from 'mssql';
|
|
6
6
|
import { getSystemUser } from './auth/index.js';
|
|
7
7
|
import { MJEvent, MJEventType, MJGlobal } from '@memberjunction/global';
|
|
8
|
+
import { SQLServerDataProvider } from '@memberjunction/sqlserver-dataprovider';
|
|
8
9
|
|
|
9
10
|
export type UserPayload = {
|
|
10
11
|
email: string;
|
|
@@ -28,8 +29,18 @@ export type AppContext = {
|
|
|
28
29
|
* Array of connection pools that have additional information about their intended use e.g. Admin, Read-Write, Read-Only.
|
|
29
30
|
*/
|
|
30
31
|
dataSources: DataSourceInfo[];
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Per-request DatabaseProviderBase instances
|
|
35
|
+
*/
|
|
36
|
+
providers: Array<ProviderInfo>;
|
|
31
37
|
};
|
|
32
38
|
|
|
39
|
+
export class ProviderInfo {
|
|
40
|
+
provider: DatabaseProviderBase;
|
|
41
|
+
type: 'Admin' | 'Read-Write' | 'Read-Only' | 'Other';
|
|
42
|
+
}
|
|
43
|
+
|
|
33
44
|
export class DataSourceInfo {
|
|
34
45
|
dataSource: sql.ConnectionPool;
|
|
35
46
|
host: string;
|
|
@@ -56,7 +67,7 @@ export type DirectiveBuilder = {
|
|
|
56
67
|
|
|
57
68
|
export type RunViewGenericParams = {
|
|
58
69
|
viewInfo: UserViewEntity;
|
|
59
|
-
|
|
70
|
+
provider: DatabaseProviderBase;
|
|
60
71
|
extraFilter: string;
|
|
61
72
|
orderBy: string;
|
|
62
73
|
userSearchString: string;
|
|
@@ -69,8 +80,7 @@ export type RunViewGenericParams = {
|
|
|
69
80
|
forceAuditLog?: boolean;
|
|
70
81
|
auditLogDescription?: string;
|
|
71
82
|
resultType?: string;
|
|
72
|
-
userPayload?: UserPayload;
|
|
73
|
-
pubSub: PubSubEngine;
|
|
83
|
+
userPayload?: UserPayload;
|
|
74
84
|
};
|
|
75
85
|
|
|
76
86
|
|
package/src/util.ts
CHANGED
|
@@ -4,8 +4,9 @@ import { gzip as gzipCallback, createGunzip } from 'zlib';
|
|
|
4
4
|
import { promisify } from 'util';
|
|
5
5
|
import { URL } from 'url';
|
|
6
6
|
import { z } from 'zod';
|
|
7
|
-
import { DataSourceInfo } from './types';
|
|
7
|
+
import { DataSourceInfo, ProviderInfo } from './types';
|
|
8
8
|
import sql from 'mssql';
|
|
9
|
+
import { DatabaseProviderBase } from '@memberjunction/core';
|
|
9
10
|
|
|
10
11
|
const gzip = promisify(gzipCallback);
|
|
11
12
|
|
|
@@ -29,7 +30,7 @@ export async function sendPostRequest(url: string, payload: any, useCompression:
|
|
|
29
30
|
let data;
|
|
30
31
|
if (useCompression) {
|
|
31
32
|
try {
|
|
32
|
-
data = await gzip(Buffer.from(JSON.stringify(payload)));
|
|
33
|
+
data = await gzip(Buffer.from(JSON.stringify(payload)) as any);
|
|
33
34
|
headers = headers || {}; // Ensure headers is an object
|
|
34
35
|
headers['Content-Encoding'] = 'gzip';
|
|
35
36
|
} catch (error) {
|
|
@@ -136,6 +137,48 @@ export async function sendPostRequest(url: string, payload: any, useCompression:
|
|
|
136
137
|
throw new Error('No suitable data source found');
|
|
137
138
|
}
|
|
138
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Returns the read-only provider if it exists, otherwise returns the original provider if options is not provided or if options.allowFallbackToReadWrite is true.
|
|
142
|
+
* @param options
|
|
143
|
+
* @returns
|
|
144
|
+
*/
|
|
145
|
+
export function GetReadOnlyProvider(providers: Array<ProviderInfo>, options?: {allowFallbackToReadWrite: boolean}): DatabaseProviderBase {
|
|
146
|
+
if (!providers || providers.length === 0)
|
|
147
|
+
return null; // no providers available
|
|
148
|
+
|
|
149
|
+
const readOnlyProvider = providers.find((p) => p.type === 'Read-Only');
|
|
150
|
+
if (readOnlyProvider) {
|
|
151
|
+
return readOnlyProvider.provider;
|
|
152
|
+
}
|
|
153
|
+
else if (options?.allowFallbackToReadWrite) {
|
|
154
|
+
return providers[0].provider; // if no read-only provider is provided, use the original provider since we are allowed to fallback to read-write
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
return null; // no read only provider available and we are not allowed to fallback to read-write
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Returns the read-write provider if it exists, otherwise returns the original provider if options is not provided or if options.allowFallbackToReadOnly is true.
|
|
163
|
+
* @param options
|
|
164
|
+
* @returns
|
|
165
|
+
*/
|
|
166
|
+
export function GetReadWriteProvider(providers: Array<ProviderInfo>, options?: {allowFallbackToReadOnly: boolean}): DatabaseProviderBase {
|
|
167
|
+
if (!providers || providers.length === 0)
|
|
168
|
+
return null; // no providers available
|
|
169
|
+
|
|
170
|
+
const readWriteProvider = providers.find((p) => p.type === 'Read-Write');
|
|
171
|
+
if (readWriteProvider) {
|
|
172
|
+
return readWriteProvider.provider;
|
|
173
|
+
}
|
|
174
|
+
else if (options?.allowFallbackToReadOnly) {
|
|
175
|
+
return GetReadOnlyProvider(providers, { allowFallbackToReadWrite: false }); // if no read-write provider is provided, use the read-only provider since we are allowed to fallback to read-only
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
return null; // no read-write provider available and we are not allowed to fallback to read-only
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
139
182
|
/**
|
|
140
183
|
* Returns the read-write data source if it exists, otherwise throws an error.
|
|
141
184
|
* @param dataSources
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionPlugin.d.ts","sourceRoot":"","sources":["../../src/apolloServer/TransactionPlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAgF,MAAM,gBAAgB,CAAC;AAElI,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,eAAO,MAAM,iBAAiB,EAAE,kBAAkB,CAAC,UAAU,CAgD5D,CAAC"}
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import sql from 'mssql';
|
|
2
|
-
export const TransactionPlugin = {
|
|
3
|
-
async requestDidStart(requestContext) {
|
|
4
|
-
const start = Date.now();
|
|
5
|
-
const query = requestContext.request.query || '';
|
|
6
|
-
const isMutation = /^\s*mutation\b/i.test(query);
|
|
7
|
-
if (!isMutation) {
|
|
8
|
-
return null;
|
|
9
|
-
}
|
|
10
|
-
const pool = requestContext.contextValue.dataSource;
|
|
11
|
-
const transaction = new sql.Transaction(pool);
|
|
12
|
-
requestContext.contextValue.transaction = transaction;
|
|
13
|
-
console.log('Starting transaction wrapper, time spent: ', Date.now() - start, 'ms ');
|
|
14
|
-
await transaction.begin();
|
|
15
|
-
return {
|
|
16
|
-
didEncounterErrors: async (requestContext) => {
|
|
17
|
-
console.log('Error in transaction wrapper: ' + requestContext.errors, 'time spent: ', Date.now() - start, 'ms');
|
|
18
|
-
},
|
|
19
|
-
executionDidStart: async () => {
|
|
20
|
-
return {
|
|
21
|
-
executionDidEnd: async (err) => {
|
|
22
|
-
try {
|
|
23
|
-
if (err) {
|
|
24
|
-
console.log('Error in transaction, rolling back, time spent: ', Date.now() - start, 'ms ');
|
|
25
|
-
console.error('Rolling back transaction', err);
|
|
26
|
-
await transaction.rollback();
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
console.log('Committing transaction, time spent: ', Date.now() - start, 'ms ');
|
|
30
|
-
await transaction.commit();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
catch (execErr) {
|
|
34
|
-
console.log('Execution Error, time spent: ', Date.now() - start, 'ms ');
|
|
35
|
-
console.error(execErr);
|
|
36
|
-
}
|
|
37
|
-
finally {
|
|
38
|
-
console.log('Transaction complete, time spent: ', Date.now() - start, 'ms ');
|
|
39
|
-
}
|
|
40
|
-
},
|
|
41
|
-
};
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
},
|
|
45
|
-
};
|
|
46
|
-
//# sourceMappingURL=TransactionPlugin.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TransactionPlugin.js","sourceRoot":"","sources":["../../src/apolloServer/TransactionPlugin.ts"],"names":[],"mappings":"AACA,OAAO,GAAG,MAAM,OAAO,CAAC;AAGxB,MAAM,CAAC,MAAM,iBAAiB,GAAmC;IAC/D,KAAK,CAAC,eAAe,CAAC,cAAc;QAClC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QAKD,MAAM,IAAI,GAAuB,cAAc,CAAC,YAAY,CAAC,UAAU,CAAC;QACxE,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;QAG7C,cAAc,CAAC,YAAoB,CAAC,WAAW,GAAG,WAAW,CAAC;QAC/D,OAAO,CAAC,GAAG,CAAC,4CAA4C,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;QACrF,MAAM,WAAW,CAAC,KAAK,EAAE,CAAC;QAE1B,OAAO;YACL,kBAAkB,EAAE,KAAK,EAAE,cAAc,EAAE,EAAE;gBAC3C,OAAO,CAAC,GAAG,CAAC,gCAAgC,GAAG,cAAc,CAAC,MAAM,EAAE,cAAc,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,IAAI,CAAC,CAAC;YAClH,CAAC;YACD,iBAAiB,EAAE,KAAK,IAAI,EAAE;gBAC5B,OAAO;oBACL,eAAe,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;wBAC7B,IAAI,CAAC;4BACH,IAAI,GAAG,EAAE,CAAC;gCACR,OAAO,CAAC,GAAG,CAAC,kDAAkD,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;gCAC3F,OAAO,CAAC,KAAK,CAAC,0BAA0B,EAAE,GAAG,CAAC,CAAC;gCAC/C,MAAM,WAAW,CAAC,QAAQ,EAAE,CAAC;4BAC/B,CAAC;iCAAM,CAAC;gCACN,OAAO,CAAC,GAAG,CAAC,sCAAsC,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;gCAC/E,MAAM,WAAW,CAAC,MAAM,EAAE,CAAC;4BAC7B,CAAC;wBACH,CAAC;wBAAC,OAAO,OAAO,EAAE,CAAC;4BACjB,OAAO,CAAC,GAAG,CAAC,+BAA+B,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;4BACxE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;wBACzB,CAAC;gCAAS,CAAC;4BACT,OAAO,CAAC,GAAG,CAAC,oCAAoC,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC;wBAC/E,CAAC;oBACH,CAAC;iBACF,CAAC;YACJ,CAAC;SACF,CAAC;IACJ,CAAC;CACF,CAAC"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import { ApolloServerPlugin, GraphQLRequestContextDidEncounterErrors, GraphQLRequestListenerParsingDidEnd } from '@apollo/server';
|
|
2
|
-
import sql from 'mssql';
|
|
3
|
-
import { AppContext } from '../types.js';
|
|
4
|
-
|
|
5
|
-
export const TransactionPlugin: ApolloServerPlugin<AppContext> = {
|
|
6
|
-
async requestDidStart(requestContext) {
|
|
7
|
-
const start = Date.now();
|
|
8
|
-
const query = requestContext.request.query || '';
|
|
9
|
-
const isMutation = /^\s*mutation\b/i.test(query);
|
|
10
|
-
|
|
11
|
-
if (!isMutation) {
|
|
12
|
-
return null;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
// Start transaction, one or more mutations. If it is just one mutation, this trans wrapper isn't really needed
|
|
16
|
-
// but there's no good way to know if it's one or more mutations, so we just start a transaction anyway and it isn't terribly expensive
|
|
17
|
-
// to do so with SQL Server anyway.
|
|
18
|
-
const pool: sql.ConnectionPool = requestContext.contextValue.dataSource;
|
|
19
|
-
const transaction = new sql.Transaction(pool);
|
|
20
|
-
|
|
21
|
-
// Store transaction in context for resolvers to use
|
|
22
|
-
(requestContext.contextValue as any).transaction = transaction;
|
|
23
|
-
console.log('Starting transaction wrapper, time spent: ', Date.now() - start, 'ms ');
|
|
24
|
-
await transaction.begin();
|
|
25
|
-
|
|
26
|
-
return {
|
|
27
|
-
didEncounterErrors: async (requestContext) => {
|
|
28
|
-
console.log('Error in transaction wrapper: ' + requestContext.errors, 'time spent: ', Date.now() - start, 'ms');
|
|
29
|
-
},
|
|
30
|
-
executionDidStart: async () => {
|
|
31
|
-
return {
|
|
32
|
-
executionDidEnd: async (err) => {
|
|
33
|
-
try {
|
|
34
|
-
if (err) {
|
|
35
|
-
console.log('Error in transaction, rolling back, time spent: ', Date.now() - start, 'ms ');
|
|
36
|
-
console.error('Rolling back transaction', err);
|
|
37
|
-
await transaction.rollback();
|
|
38
|
-
} else {
|
|
39
|
-
console.log('Committing transaction, time spent: ', Date.now() - start, 'ms ');
|
|
40
|
-
await transaction.commit();
|
|
41
|
-
}
|
|
42
|
-
} catch (execErr) {
|
|
43
|
-
console.log('Execution Error, time spent: ', Date.now() - start, 'ms ');
|
|
44
|
-
console.error(execErr);
|
|
45
|
-
} finally {
|
|
46
|
-
console.log('Transaction complete, time spent: ', Date.now() - start, 'ms ');
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
|
-
};
|
|
50
|
-
},
|
|
51
|
-
};
|
|
52
|
-
},
|
|
53
|
-
};
|