@memberjunction/server 2.12.0 → 2.13.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memberjunction/server",
3
- "version": "2.12.0",
3
+ "version": "2.13.0",
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.12.0",
26
- "@memberjunction/ai": "2.12.0",
27
- "@memberjunction/ai-mistral": "2.12.0",
28
- "@memberjunction/ai-openai": "2.12.0",
29
- "@memberjunction/ai-vectors-pinecone": "2.12.0",
30
- "@memberjunction/aiengine": "2.12.0",
31
- "@memberjunction/core": "2.12.0",
32
- "@memberjunction/core-actions": "2.12.0",
33
- "@memberjunction/core-entities": "2.12.0",
34
- "@memberjunction/data-context": "2.12.0",
35
- "@memberjunction/data-context-server": "2.12.0",
36
- "@memberjunction/doc-utils": "2.12.0",
37
- "@memberjunction/entity-communications-server": "2.12.0",
38
- "@memberjunction/external-change-detection": "2.12.0",
39
- "@memberjunction/global": "2.12.0",
40
- "@memberjunction/queue": "2.12.0",
41
- "@memberjunction/skip-types": "2.12.0",
42
- "@memberjunction/sqlserver-dataprovider": "2.12.0",
43
- "@memberjunction/graphql-dataprovider": "2.12.0",
44
- "@memberjunction/storage": "2.12.0",
45
- "@memberjunction/templates": "2.12.0",
25
+ "@memberjunction/actions": "2.13.0",
26
+ "@memberjunction/ai": "2.13.0",
27
+ "@memberjunction/ai-mistral": "2.13.0",
28
+ "@memberjunction/ai-openai": "2.13.0",
29
+ "@memberjunction/ai-vectors-pinecone": "2.13.0",
30
+ "@memberjunction/aiengine": "2.13.0",
31
+ "@memberjunction/core": "2.13.0",
32
+ "@memberjunction/core-actions": "2.13.0",
33
+ "@memberjunction/core-entities": "2.13.0",
34
+ "@memberjunction/data-context": "2.13.0",
35
+ "@memberjunction/data-context-server": "2.13.0",
36
+ "@memberjunction/doc-utils": "2.13.0",
37
+ "@memberjunction/entity-communications-server": "2.13.0",
38
+ "@memberjunction/external-change-detection": "2.13.0",
39
+ "@memberjunction/global": "2.13.0",
40
+ "@memberjunction/queue": "2.13.0",
41
+ "@memberjunction/skip-types": "2.13.0",
42
+ "@memberjunction/sqlserver-dataprovider": "2.13.0",
43
+ "@memberjunction/graphql-dataprovider": "2.13.0",
44
+ "@memberjunction/storage": "2.13.0",
45
+ "@memberjunction/templates": "2.13.0",
46
46
  "@types/cors": "^2.8.13",
47
47
  "@types/jsonwebtoken": "9.0.6",
48
48
  "@types/node": "20.14.2",
package/src/auth/index.ts CHANGED
@@ -3,9 +3,10 @@ import jwksClient from 'jwks-rsa';
3
3
  import { auth0Domain, auth0WebClientID, configInfo, tenantID, webClientID } from '../config.js';
4
4
  import { UserCache } from '@memberjunction/sqlserver-dataprovider';
5
5
  import { DataSource } from 'typeorm';
6
- import { Metadata, UserInfo } from '@memberjunction/core';
6
+ import { Metadata, RoleInfo, UserInfo } from '@memberjunction/core';
7
7
  import { NewUserBase } from './newUsers.js';
8
8
  import { MJGlobal } from '@memberjunction/global';
9
+ import { UserEntity, UserEntityType } from '@memberjunction/core-entities';
9
10
 
10
11
  export { TokenExpiredError } from './tokenExpiredError.js';
11
12
 
@@ -120,15 +121,22 @@ export const verifyUserRecord = async (
120
121
  if (passesDomainCheck) {
121
122
  // we have a domain from the request that matches one of the domains provided by the configuration, so we will create a new user
122
123
  console.warn(`User ${email} not found in cache. Attempting to create a new user...`);
123
- const newUserCreator: NewUserBase = <NewUserBase>MJGlobal.Instance.ClassFactory.CreateInstance(NewUserBase); // this will create the object that handles creating the new user for us
124
- const newUser = await newUserCreator.createNewUser(firstName, lastName, email);
124
+ const newUserCreator: NewUserBase = MJGlobal.Instance.ClassFactory.CreateInstance<NewUserBase>(NewUserBase); // this will create the object that handles creating the new user for us
125
+ const newUser: UserEntity | null = await newUserCreator.createNewUser(firstName, lastName, email);
125
126
  if (newUser) {
126
127
  // new user worked! we already have the stuff we need for the cache, so no need to go to the DB now, just create a new UserInfo object and use the return value from the createNewUser method
127
128
  // to init it, including passing in the role list for the user.
128
- const initData: any = newUser.GetAll();
129
+ const md: Metadata = new Metadata();
130
+
131
+ const initData: UserEntityType & {UserRoles: {UserID: string, RoleName: string, RoleID: string}[] } = newUser.GetAll();
132
+
129
133
  initData.UserRoles = configInfo.userHandling.newUserRoles.map((role) => {
130
- return { UserID: initData.ID, RoleName: role };
134
+ const roleInfo: RoleInfo | undefined = md.Roles.find((r) => r.Name === role);
135
+ const roleID: string = roleInfo ? roleInfo.ID : "";
136
+
137
+ return { UserID: initData.ID, RoleName: role, RoleID: roleID };
131
138
  });
139
+
132
140
  user = new UserInfo(Metadata.Provider, initData);
133
141
  UserCache.Instance.Users.push(user);
134
142
  console.warn(` >>> New user ${email} created successfully!`);
@@ -139,6 +147,7 @@ export const verifyUserRecord = async (
139
147
  );
140
148
  }
141
149
  }
150
+
142
151
  if (!user && configInfo.userHandling.updateCacheWhenNotFound && dataSource && attemptCacheUpdateIfNeeded) {
143
152
  // if we get here that means in the above, if we were attempting to create a new user, it did not work, or it wasn't attempted and we have a config that asks us to auto update the cache
144
153
  console.warn(`User ${email} not found in cache. Updating cache in attempt to find the user...`);
@@ -1,4 +1,4 @@
1
- import { LogError, Metadata } from "@memberjunction/core";
1
+ import { LogError, LogStatus, Metadata, UserInfo } from "@memberjunction/core";
2
2
  import { RegisterClass } from "@memberjunction/global";
3
3
  import { UserCache } from "@memberjunction/sqlserver-dataprovider";
4
4
  import { configInfo } from "../config.js";
@@ -6,49 +6,73 @@ import { UserEntity, UserRoleEntity } from "@memberjunction/core-entities";
6
6
 
7
7
  @RegisterClass(NewUserBase)
8
8
  export class NewUserBase {
9
- public async createNewUser(firstName: string, lastName: string, email: string, linkedRecordType: string = 'None', linkedEntityId?: string, linkedEntityRecordId?: string) {
9
+ public async createNewUser(firstName: string, lastName: string, email: string, linkedRecordType: string = 'None', linkedEntityId?: string, linkedEntityRecordId?: string): Promise<UserEntity | null> {
10
10
  try {
11
- const md = new Metadata();
12
- const contextUser = UserCache.Instance.Users.find(u => u.Email.trim().toLowerCase() === configInfo?.userHandling?.contextUserForNewUserCreation?.trim().toLowerCase())
11
+ let contextUser: UserInfo | null = null;
12
+
13
+ const contextUserForNewUserCreation: string = configInfo?.userHandling?.contextUserForNewUserCreation;
14
+ if(contextUserForNewUserCreation){
15
+ contextUser = UserCache.Instance.UserByName(contextUserForNewUserCreation);
16
+ }
17
+
13
18
  if (!contextUser) {
14
- LogError(`Failed to load context user ${configInfo?.userHandling?.contextUserForNewUserCreation}, if you've not specified this on your config.json you must do so. This is the user that is contextually used for creating a new user record dynamically.`);
15
- return undefined;
19
+ LogError(`Failed to load context user ${configInfo?.userHandling?.contextUserForNewUserCreation}, using an existing user with the Owner role instead`);
20
+
21
+ contextUser = UserCache.Users.find(user => user.Type.trim().toLowerCase() ==='owner')!;
22
+ if (!contextUser) {
23
+ LogError(`No existing users found in the database with the Owner role, cannot create a new user`);
24
+ return null;
25
+ }
26
+ }
27
+
28
+ const md: Metadata = new Metadata();
29
+ const user = await md.GetEntityObject<UserEntity>('Users', contextUser) // To-Do - change this to be a different defined user for the user creation process
30
+ user.NewRecord();
31
+ user.Name = email;
32
+ user.IsActive = true;
33
+ user.FirstName = firstName;
34
+ user.LastName = lastName;
35
+ user.Email = email;
36
+ user.Type = 'User';
37
+ user.LinkedRecordType = linkedRecordType;
38
+
39
+ if (linkedEntityId){
40
+ user.LinkedEntityID = linkedEntityId;
41
+ }
42
+
43
+ if (linkedEntityRecordId){
44
+ user.LinkedEntityRecordID = linkedEntityRecordId;
45
+ }
46
+
47
+ const saveResult: boolean = await user.Save();
48
+ if(!saveResult){
49
+ LogError(`Failed to create new user ${firstName} ${lastName} ${email}:`, undefined, user.LatestResult);
50
+ return null;
16
51
  }
17
- const u = <UserEntity>await md.GetEntityObject('Users', contextUser) // To-Do - change this to be a different defined user for the user creation process
18
- u.NewRecord();
19
- u.Name = email;
20
- u.IsActive = true;
21
- u.FirstName = firstName;
22
- u.LastName = lastName;
23
- u.Email = email;
24
- u.Type = 'User';
25
- u.LinkedRecordType = linkedRecordType;
26
- if (linkedEntityId)
27
- u.LinkedEntityID = linkedEntityId;
28
- if (linkedEntityRecordId)
29
- u.LinkedEntityRecordID = linkedEntityRecordId;
30
-
31
- if (await u.Save()) {
52
+
53
+ if(configInfo.userHandling && configInfo.userHandling.newUserRoles){
32
54
  // user created, now create however many roles we need to create for this user based on the config settings
33
- const ur = await md.GetEntityObject<UserRoleEntity>('User Roles', contextUser);
34
- let bSuccess: boolean = true;
55
+ LogStatus(`User ${user.Email} created, assigning roles`);
35
56
  for (const role of configInfo.userHandling.newUserRoles) {
36
- ur.NewRecord();
37
- ur.UserID = u.ID;
38
- const roleID = md.Roles.find(r => r.Name === role)?.ID;
39
- ur.RoleID = roleID;
40
- bSuccess = bSuccess && await ur.Save();
41
- }
42
- if (!bSuccess) {
43
- LogError(`Failed to create roles for newly created user ${firstName} ${lastName} ${email}`);
44
- return undefined;
57
+ const userRoleEntity: UserRoleEntity = await md.GetEntityObject<UserRoleEntity>('User Roles', contextUser);
58
+ userRoleEntity.NewRecord();
59
+ userRoleEntity.UserID = user.ID;
60
+ const userRole = md.Roles.find(r => r.Name === role);
61
+
62
+ if (!userRole) {
63
+ LogError(`Role ${role} not found in the database, cannot assign to new user ${user.Name}`);
64
+ continue;
65
+ }
66
+
67
+ userRoleEntity.RoleID = userRole.ID;
68
+ const roleSaveResult: boolean = await userRoleEntity.Save();
69
+ if(!roleSaveResult){
70
+ LogError(`Failed to assign role ${role} to new user ${user.Name}:`, undefined, userRoleEntity.LatestResult);
71
+ }
45
72
  }
46
73
  }
47
- else {
48
- LogError(`Failed to create new user ${firstName} ${lastName} ${email}`);
49
- return undefined;
50
- }
51
- return u;
74
+
75
+ return user;
52
76
  }
53
77
  catch (e) {
54
78
  LogError(e);