@friggframework/core 2.0.0--canary.405.1f6792c.0 → 2.0.0--canary.396.6862738.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/credential/credential-repository.js +9 -0
- package/credential/use-cases/get-credential-for-user.js +21 -0
- package/encrypt/encrypt.js +27 -4
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +0 -3
- package/handlers/backend-utils.js +29 -34
- package/handlers/routers/auth.js +14 -11
- package/handlers/routers/integration-defined-routers.js +8 -5
- package/handlers/routers/user.js +25 -5
- package/handlers/workers/integration-defined-workers.js +6 -3
- package/index.js +0 -11
- package/integrations/index.js +0 -5
- package/integrations/integration-base.js +10 -7
- package/integrations/integration-repository.js +44 -0
- package/integrations/integration-router.js +230 -132
- package/integrations/integration.js +233 -0
- package/integrations/options.js +1 -1
- package/integrations/use-cases/create-integration.js +58 -0
- package/integrations/use-cases/delete-integration-for-user.js +53 -0
- package/integrations/use-cases/get-integration-for-user.js +63 -0
- package/integrations/use-cases/get-integration-instance.js +73 -0
- package/integrations/use-cases/get-integrations-for-user.js +64 -0
- package/integrations/use-cases/index.js +11 -0
- package/integrations/use-cases/update-integration.js +81 -0
- package/integrations/utils/map-integration-dto.js +37 -0
- package/module-plugin/index.js +0 -4
- package/module-plugin/module-factory.js +13 -32
- package/module-plugin/module-repository.js +70 -0
- package/module-plugin/module-service.js +50 -0
- package/module-plugin/{auther.js → module.js} +109 -173
- package/module-plugin/test/mock-api/api.js +8 -3
- package/module-plugin/test/mock-api/definition.js +12 -8
- package/module-plugin/use-cases/get-entities-for-user.js +32 -0
- package/module-plugin/utils/map-module-dto.js +18 -0
- package/package.json +5 -5
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +4 -21
- package/user/tests/doubles/test-user-repository.js +72 -0
- package/user/tests/use-cases/create-individual-user.test.js +24 -0
- package/user/tests/use-cases/create-organization-user.test.js +28 -0
- package/user/tests/use-cases/create-token-for-user-id.test.js +19 -0
- package/user/tests/use-cases/get-user-from-bearer-token.test.js +64 -0
- package/user/tests/use-cases/login-user.test.js +140 -0
- package/user/use-cases/create-individual-user.js +61 -0
- package/user/use-cases/create-organization-user.js +47 -0
- package/user/use-cases/create-token-for-user-id.js +30 -0
- package/user/use-cases/get-user-from-bearer-token.js +77 -0
- package/user/use-cases/login-user.js +122 -0
- package/user/user-repository.js +62 -0
- package/user/user.js +77 -0
- package/handlers/routers/HEALTHCHECK.md +0 -240
- package/handlers/routers/health.js +0 -459
- package/handlers/routers/health.test.js +0 -203
- package/handlers/routers/middleware/loadUser.js +0 -15
- package/handlers/routers/middleware/requireLoggedInUser.js +0 -12
- package/integrations/create-frigg-backend.js +0 -31
- package/integrations/integration-factory.js +0 -251
- package/integrations/integration-user.js +0 -144
- package/module-plugin/entity-manager.js +0 -70
package/module-plugin/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
const { Credential } = require('./credential');
|
|
2
|
-
const { EntityManager } = require('./entity-manager');
|
|
3
2
|
const { Entity } = require('./entity');
|
|
4
3
|
const { ModuleManager } = require('./manager');
|
|
5
4
|
const { ApiKeyRequester } = require('./requester/api-key');
|
|
@@ -8,11 +7,9 @@ const { OAuth2Requester } = require('./requester/oauth-2');
|
|
|
8
7
|
const { Requester } = require('./requester/requester');
|
|
9
8
|
const { ModuleConstants } = require('./ModuleConstants');
|
|
10
9
|
const { ModuleFactory } = require('./module-factory');
|
|
11
|
-
const { Auther } = require('./auther');
|
|
12
10
|
|
|
13
11
|
module.exports = {
|
|
14
12
|
Credential,
|
|
15
|
-
EntityManager,
|
|
16
13
|
Entity,
|
|
17
14
|
ModuleManager,
|
|
18
15
|
ApiKeyRequester,
|
|
@@ -21,5 +18,4 @@ module.exports = {
|
|
|
21
18
|
Requester,
|
|
22
19
|
ModuleConstants,
|
|
23
20
|
ModuleFactory,
|
|
24
|
-
Auther
|
|
25
21
|
};
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const {
|
|
1
|
+
const { ModuleRepository } = require('./module-repository');
|
|
2
|
+
const { ModuleService } = require('./module-service');
|
|
3
|
+
const { Module } = require('./module');
|
|
3
4
|
|
|
4
5
|
class ModuleFactory {
|
|
5
6
|
constructor(...params) {
|
|
6
7
|
this.moduleDefinitions = params;
|
|
7
8
|
this.moduleTypes = this.moduleDefinitions.map((def) => def.moduleName);
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const moduleInstance = await Auther.getInstance({
|
|
14
|
-
userId,
|
|
15
|
-
definition: moduleDefinition,
|
|
16
|
-
});
|
|
17
|
-
const list = await moduleInstance.getEntitiesForUserId(userId);
|
|
18
|
-
results.push(...list);
|
|
19
|
-
}
|
|
20
|
-
return results;
|
|
9
|
+
this.moduleRepository = new ModuleRepository();
|
|
10
|
+
this.moduleService = new ModuleService({
|
|
11
|
+
moduleRepository: this.moduleRepository,
|
|
12
|
+
moduleDefinitions: this.moduleDefinitions,
|
|
13
|
+
});
|
|
21
14
|
}
|
|
22
15
|
|
|
23
16
|
checkIsValidType(entityType) {
|
|
@@ -29,29 +22,17 @@ class ModuleFactory {
|
|
|
29
22
|
}
|
|
30
23
|
|
|
31
24
|
async getModuleInstanceFromEntityId(entityId, userId) {
|
|
32
|
-
|
|
33
|
-
const moduleDefinition = this.moduleDefinitions.find(
|
|
34
|
-
(def) =>
|
|
35
|
-
entity.toJSON()['__t'] ===
|
|
36
|
-
Auther.getEntityModelFromDefinition(def).modelName
|
|
37
|
-
);
|
|
38
|
-
if (!moduleDefinition) {
|
|
39
|
-
throw new Error(
|
|
40
|
-
'Module definition not found for entity type: ' + entity['__t']
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
return await Auther.getInstance({
|
|
44
|
-
userId,
|
|
45
|
-
entityId,
|
|
46
|
-
definition: moduleDefinition,
|
|
47
|
-
});
|
|
25
|
+
return this.moduleService.getModuleInstance(entityId, userId);
|
|
48
26
|
}
|
|
49
27
|
|
|
50
28
|
async getInstanceFromTypeName(typeName, userId) {
|
|
51
29
|
const moduleDefinition = this.moduleDefinitions.find(
|
|
52
30
|
(def) => def.getName() === typeName
|
|
53
31
|
);
|
|
54
|
-
|
|
32
|
+
if (!moduleDefinition) {
|
|
33
|
+
throw new Error(`Module definition not found for type: ${typeName}`);
|
|
34
|
+
}
|
|
35
|
+
return new Module({
|
|
55
36
|
userId,
|
|
56
37
|
definition: moduleDefinition,
|
|
57
38
|
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
const { Entity } = require('./entity');
|
|
2
|
+
|
|
3
|
+
class ModuleRepository {
|
|
4
|
+
async findEntityById(entityId) {
|
|
5
|
+
const entity = await Entity.findById(entityId, undefined, { lean: true }).populate('credential');
|
|
6
|
+
if (!entity) {
|
|
7
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
id: entity._id,
|
|
12
|
+
accountId: entity.accountId,
|
|
13
|
+
credential: entity.credential,
|
|
14
|
+
userId: entity.user.toString(),
|
|
15
|
+
name: entity.name,
|
|
16
|
+
externalId: entity.externalId,
|
|
17
|
+
type: entity.__t,
|
|
18
|
+
moduleName: entity.moduleName,
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async findEntitiesByIds(entitiesIds) {
|
|
23
|
+
const entitiesRecords = await Entity.find({ _id: { $in: entitiesIds } }, '', { lean: true }).populate('credential');
|
|
24
|
+
|
|
25
|
+
// todo: this is a workaround needed while we create an integration with the same entity twice
|
|
26
|
+
if (entitiesRecords.length !== entitiesIds.length && entitiesIds[0] !== entitiesIds[1]) {
|
|
27
|
+
throw new Error(`Some entities not found`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return entitiesRecords.map(e => ({
|
|
31
|
+
id: e._id,
|
|
32
|
+
accountId: e.accountId,
|
|
33
|
+
credential: e.credential,
|
|
34
|
+
userId: e.user.toString(),
|
|
35
|
+
name: e.name,
|
|
36
|
+
externalId: e.externalId,
|
|
37
|
+
type: e.__t,
|
|
38
|
+
moduleName: e.moduleName,
|
|
39
|
+
}));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
async findEntitiesByUserId(userId) {
|
|
43
|
+
return Entity.find(
|
|
44
|
+
{ user: userId },
|
|
45
|
+
'-dateCreated -dateUpdated -user -credentials -credential -__t -__v',
|
|
46
|
+
{ lean: true }
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
async findEntitiesByIds(entityIds) {
|
|
51
|
+
const entities = await Entity.find(
|
|
52
|
+
{ _id: { $in: entityIds } },
|
|
53
|
+
'',
|
|
54
|
+
{ lean: true }
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
return entities.map(e => ({
|
|
58
|
+
id: e._id.toString(),
|
|
59
|
+
accountId: e.accountId,
|
|
60
|
+
credentialId: e.credential.toString(),
|
|
61
|
+
userId: e.user.toString(),
|
|
62
|
+
name: e.name,
|
|
63
|
+
externalId: e.externalId,
|
|
64
|
+
type: e.__t,
|
|
65
|
+
moduleName: e.moduleName,
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = { ModuleRepository };
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
const { Module } = require('./module');
|
|
2
|
+
|
|
3
|
+
class ModuleService {
|
|
4
|
+
/**
|
|
5
|
+
* @param {Object} params - Configuration parameters.
|
|
6
|
+
* @param {import('./module-repository').ModuleRepository} params.moduleRepository - Repository for module data operations.
|
|
7
|
+
* @param {Array<Object>} params.moduleDefinitions - Array of module definitions.
|
|
8
|
+
*/
|
|
9
|
+
constructor({ moduleRepository, moduleDefinitions }) {
|
|
10
|
+
this.moduleRepository = moduleRepository;
|
|
11
|
+
this.moduleDefinitions = moduleDefinitions;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async getModuleInstance(entityId, userId) {
|
|
15
|
+
const entity = await this.moduleRepository.findEntityById(
|
|
16
|
+
entityId,
|
|
17
|
+
userId
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
if (!entity) {
|
|
21
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (entity.userId !== userId) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Entity ${entityId} does not belong to user ${userId}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const entityType = entity.type;
|
|
31
|
+
const moduleDefinition = this.moduleDefinitions.find((def) => {
|
|
32
|
+
const modelName = Module.getEntityModelFromDefinition(def).modelName;
|
|
33
|
+
return entityType === modelName;
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (!moduleDefinition) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`Module definition not found for entity type: ${entityType}`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return new Module({
|
|
43
|
+
userId,
|
|
44
|
+
entity,
|
|
45
|
+
definition: moduleDefinition,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = { ModuleService };
|
|
@@ -1,30 +1,3 @@
|
|
|
1
|
-
// Manages authorization and credential persistence
|
|
2
|
-
// Instantiation of an API Class
|
|
3
|
-
// Expects input object like this:
|
|
4
|
-
// const authDef = {
|
|
5
|
-
// API: class anAPI{},
|
|
6
|
-
// moduleName: 'anAPI', //maybe not required
|
|
7
|
-
// requiredAuthMethods: {
|
|
8
|
-
// // oauth methods, how to handle these being required/not?
|
|
9
|
-
// getToken: async function(params, callbackParams, tokenResponse) {},
|
|
10
|
-
// // required for all Auth methods
|
|
11
|
-
// getEntityDetails: async function(params) {}, //probably calls api method
|
|
12
|
-
// getCredentialDetails: async function(params) {}, // might be same as above
|
|
13
|
-
// apiParamsFromCredential: function(params) {},
|
|
14
|
-
// testAuth: async function() {}, // basic request to testAuth
|
|
15
|
-
// },
|
|
16
|
-
// env: {
|
|
17
|
-
// client_id: process.env.HUBSPOT_CLIENT_ID,
|
|
18
|
-
// client_secret: process.env.HUBSPOT_CLIENT_SECRET,
|
|
19
|
-
// scope: process.env.HUBSPOT_SCOPE,
|
|
20
|
-
// redirect_uri: `${process.env.REDIRECT_URI}/an-api`,
|
|
21
|
-
// }
|
|
22
|
-
// };
|
|
23
|
-
|
|
24
|
-
//TODO:
|
|
25
|
-
// 1. Add definition of expected params to API Class (or could just be credential?)
|
|
26
|
-
// 2.
|
|
27
|
-
|
|
28
1
|
const { Delegate } = require('../core');
|
|
29
2
|
const { get } = require('../assertions');
|
|
30
3
|
const _ = require('lodash');
|
|
@@ -34,119 +7,44 @@ const { Entity } = require('./entity');
|
|
|
34
7
|
const { mongoose } = require('../database/mongoose');
|
|
35
8
|
const { ModuleConstants } = require('./ModuleConstants');
|
|
36
9
|
|
|
37
|
-
class
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
if (!definition.requiredAuthMethods.getEntityDetails) {
|
|
67
|
-
throw new Error(
|
|
68
|
-
'Auther definition requires requiredAuthMethods.getEntityDetails'
|
|
69
|
-
);
|
|
70
|
-
}
|
|
71
|
-
if (!definition.requiredAuthMethods.getCredentialDetails) {
|
|
72
|
-
throw new Error(
|
|
73
|
-
'Auther definition requires requiredAuthMethods.getCredentialDetails'
|
|
74
|
-
);
|
|
75
|
-
}
|
|
76
|
-
if (!definition.requiredAuthMethods.apiPropertiesToPersist) {
|
|
77
|
-
throw new Error(
|
|
78
|
-
'Auther definition requires requiredAuthMethods.apiPropertiesToPersist'
|
|
79
|
-
);
|
|
80
|
-
} else if (definition.Credential) {
|
|
81
|
-
for (const prop of definition.requiredAuthMethods
|
|
82
|
-
.apiPropertiesToPersist?.credential) {
|
|
83
|
-
if (
|
|
84
|
-
!definition.Credential.schema.paths.hasOwnProperty(prop)
|
|
85
|
-
) {
|
|
86
|
-
throw new Error(
|
|
87
|
-
`Auther definition requires Credential schema to have property ${prop}`
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (!definition.requiredAuthMethods.testAuthRequest) {
|
|
93
|
-
throw new Error(
|
|
94
|
-
'Auther definition requires requiredAuthMethods.testAuth'
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
}
|
|
10
|
+
class Module extends Delegate {
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param {Object} params
|
|
15
|
+
* @param {Object} params.definition The definition of the Api Module
|
|
16
|
+
* @param {string} params.userId The user id
|
|
17
|
+
* @param {Object} params.entity The entity record from the database
|
|
18
|
+
*/
|
|
19
|
+
constructor({ definition, userId = null, entity: entityObj = null }) {
|
|
20
|
+
super({ definition, userId, entity: entityObj });
|
|
21
|
+
|
|
22
|
+
this.validateDefinition(definition);
|
|
23
|
+
|
|
24
|
+
this.userId = userId;
|
|
25
|
+
this.entity = entityObj;
|
|
26
|
+
this.credential = entityObj?.credential;
|
|
27
|
+
this.definition = definition;
|
|
28
|
+
this.getEntityOptions = this.definition.getEntityOptions;
|
|
29
|
+
this.refreshEntityOptions = this.definition.refreshEntityOptions;
|
|
30
|
+
this.name = this.definition.moduleName;
|
|
31
|
+
this.modelName = this.definition.modelName;
|
|
32
|
+
this.apiClass = this.definition.API;
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
Object.assign(this, this.definition.requiredAuthMethods);
|
|
36
|
+
|
|
37
|
+
this.CredentialModel = this.getCredentialModel();
|
|
38
|
+
this.EntityModel = this.getEntityModel();
|
|
99
39
|
|
|
100
|
-
constructor(params) {
|
|
101
|
-
super(params);
|
|
102
|
-
this.userId = get(params, 'userId', null); // Making this non-required
|
|
103
|
-
const definition = get(params, 'definition');
|
|
104
|
-
Auther.validateDefinition(definition);
|
|
105
|
-
Object.assign(this, definition.requiredAuthMethods);
|
|
106
|
-
if (definition.getEntityOptions) {
|
|
107
|
-
this.getEntityOptions = definition.getEntityOptions;
|
|
108
|
-
}
|
|
109
|
-
if (definition.refreshEntityOptions) {
|
|
110
|
-
this.refreshEntityOptions = definition.refreshEntityOptions;
|
|
111
|
-
}
|
|
112
|
-
this.name = definition.moduleName;
|
|
113
|
-
this.modelName = definition.modelName;
|
|
114
|
-
this.apiClass = definition.API;
|
|
115
|
-
this.CredentialModel =
|
|
116
|
-
definition.Credential || this.getCredentialModel();
|
|
117
|
-
this.EntityModel = definition.Entity || this.getEntityModel();
|
|
118
|
-
}
|
|
119
40
|
|
|
120
|
-
static async getInstance(params) {
|
|
121
|
-
const instance = new this(params);
|
|
122
|
-
if (params.entityId) {
|
|
123
|
-
instance.entity = await instance.EntityModel.findById(
|
|
124
|
-
params.entityId
|
|
125
|
-
);
|
|
126
|
-
instance.credential = await instance.CredentialModel.findById(
|
|
127
|
-
instance.entity.credential
|
|
128
|
-
);
|
|
129
|
-
} else if (params.credentialId) {
|
|
130
|
-
instance.credential = await instance.CredentialModel.findById(
|
|
131
|
-
params.credentialId
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
let credential = {};
|
|
135
|
-
let entity = {};
|
|
136
|
-
if (instance.credential) {
|
|
137
|
-
credential = instance.credential.toObject();
|
|
138
|
-
}
|
|
139
|
-
if (instance.entity) {
|
|
140
|
-
entity = instance.entity.toObject();
|
|
141
|
-
}
|
|
142
41
|
const apiParams = {
|
|
143
|
-
...
|
|
144
|
-
delegate:
|
|
145
|
-
...
|
|
146
|
-
...
|
|
42
|
+
...this.definition.env,
|
|
43
|
+
delegate: this,
|
|
44
|
+
...this.apiParamsFromCredential(this.credential),
|
|
45
|
+
...this.apiParamsFromEntity(this.entity),
|
|
147
46
|
};
|
|
148
|
-
|
|
149
|
-
return instance;
|
|
47
|
+
this.api = new this.apiClass(apiParams);
|
|
150
48
|
}
|
|
151
49
|
|
|
152
50
|
static getEntityModelFromDefinition(definition) {
|
|
@@ -205,20 +103,21 @@ class Auther extends Delegate {
|
|
|
205
103
|
return this.CredentialModel;
|
|
206
104
|
}
|
|
207
105
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
}
|
|
106
|
+
// todo: remove this method from all places
|
|
107
|
+
// async getEntitiesForUserId(userId) {
|
|
108
|
+
// // Only return non-internal fields. Leverages "select" and "options" to non-excepted fields and a pure object.
|
|
109
|
+
// const list = await this.EntityModel.find(
|
|
110
|
+
// { user: userId },
|
|
111
|
+
// '-dateCreated -dateUpdated -user -credentials -credential -__t -__v',
|
|
112
|
+
// { lean: true }
|
|
113
|
+
// );
|
|
114
|
+
// console.log('getEntitiesForUserId list', list, userId);
|
|
115
|
+
// return list.map((entity) => ({
|
|
116
|
+
// id: entity._id,
|
|
117
|
+
// type: this.getName(),
|
|
118
|
+
// ...entity,
|
|
119
|
+
// }));
|
|
120
|
+
// }
|
|
222
121
|
|
|
223
122
|
async validateAuthorizationRequirements() {
|
|
224
123
|
const requirements = await this.getAuthorizationRequirements();
|
|
@@ -233,18 +132,10 @@ class Auther extends Delegate {
|
|
|
233
132
|
}
|
|
234
133
|
|
|
235
134
|
async getAuthorizationRequirements(params) {
|
|
236
|
-
// TODO: How can this be more helpful both to implement and consume
|
|
237
|
-
// this function must return a dictionary with the following format
|
|
238
|
-
// node only url key is required. Data would be used for Base Authentication
|
|
239
|
-
// let returnData = {
|
|
240
|
-
// url: "callback url for the data or teh redirect url for login",
|
|
241
|
-
// type: one of the types defined in modules/Constants.js
|
|
242
|
-
// data: ["required", "fields", "we", "may", "need"]
|
|
243
|
-
// }
|
|
244
135
|
return this.api.getAuthorizationRequirements();
|
|
245
136
|
}
|
|
246
137
|
|
|
247
|
-
async testAuth(
|
|
138
|
+
async testAuth() {
|
|
248
139
|
let validAuth = false;
|
|
249
140
|
try {
|
|
250
141
|
if (await this.testAuthRequest(this.api)) validAuth = true;
|
|
@@ -307,18 +198,6 @@ class Auther extends Delegate {
|
|
|
307
198
|
}
|
|
308
199
|
}
|
|
309
200
|
|
|
310
|
-
async getEntityOptions() {
|
|
311
|
-
throw new Error(
|
|
312
|
-
'Method getEntityOptions() is not defined in the class'
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
async refreshEntityOptions() {
|
|
317
|
-
throw new Error(
|
|
318
|
-
'Method refreshEntityOptions() is not defined in the class'
|
|
319
|
-
);
|
|
320
|
-
}
|
|
321
|
-
|
|
322
201
|
async findOrCreateEntity(entityDetails) {
|
|
323
202
|
const identifiers = get(entityDetails, 'identifiers');
|
|
324
203
|
const details = get(entityDetails, 'details');
|
|
@@ -326,7 +205,7 @@ class Auther extends Delegate {
|
|
|
326
205
|
if (search.length > 1) {
|
|
327
206
|
throw new Error(
|
|
328
207
|
'Multiple entities found with the same identifiers: ' +
|
|
329
|
-
|
|
208
|
+
JSON.stringify(identifiers)
|
|
330
209
|
);
|
|
331
210
|
} else if (search.length === 0) {
|
|
332
211
|
this.entity = await this.EntityModel.create({
|
|
@@ -388,6 +267,63 @@ class Auther extends Delegate {
|
|
|
388
267
|
await this.entity.save();
|
|
389
268
|
}
|
|
390
269
|
}
|
|
270
|
+
|
|
271
|
+
// todo: check if all these props are still up to date
|
|
272
|
+
validateDefinition(definition) {
|
|
273
|
+
if (!definition) {
|
|
274
|
+
throw new Error('Module definition is required');
|
|
275
|
+
}
|
|
276
|
+
if (!definition.moduleName) {
|
|
277
|
+
throw new Error('Module definition requires moduleName');
|
|
278
|
+
}
|
|
279
|
+
if (!definition.API) {
|
|
280
|
+
throw new Error('Module definition requires API class');
|
|
281
|
+
}
|
|
282
|
+
if (!definition.requiredAuthMethods) {
|
|
283
|
+
throw new Error('Module definition requires requiredAuthMethods');
|
|
284
|
+
} else {
|
|
285
|
+
if (
|
|
286
|
+
definition.API.requesterType ===
|
|
287
|
+
ModuleConstants.authType.oauth2 &&
|
|
288
|
+
!definition.requiredAuthMethods.getToken
|
|
289
|
+
) {
|
|
290
|
+
throw new Error(
|
|
291
|
+
'Module definition requires requiredAuthMethods.getToken'
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
if (!definition.requiredAuthMethods.getEntityDetails) {
|
|
295
|
+
throw new Error(
|
|
296
|
+
'Module definition requires requiredAuthMethods.getEntityDetails'
|
|
297
|
+
);
|
|
298
|
+
}
|
|
299
|
+
if (!definition.requiredAuthMethods.getCredentialDetails) {
|
|
300
|
+
throw new Error(
|
|
301
|
+
'Module definition requires requiredAuthMethods.getCredentialDetails'
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
if (!definition.requiredAuthMethods.apiPropertiesToPersist) {
|
|
305
|
+
throw new Error(
|
|
306
|
+
'Module definition requires requiredAuthMethods.apiPropertiesToPersist'
|
|
307
|
+
);
|
|
308
|
+
} else if (definition.Credential) {
|
|
309
|
+
for (const prop of definition.requiredAuthMethods
|
|
310
|
+
.apiPropertiesToPersist?.credential) {
|
|
311
|
+
if (
|
|
312
|
+
!definition.Credential.schema.paths.hasOwnProperty(prop)
|
|
313
|
+
) {
|
|
314
|
+
throw new Error(
|
|
315
|
+
`Module definition requires Credential schema to have property ${prop}`
|
|
316
|
+
);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
if (!definition.requiredAuthMethods.testAuthRequest) {
|
|
321
|
+
throw new Error(
|
|
322
|
+
'Module definition requires requiredAuthMethods.testAuth'
|
|
323
|
+
);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
391
327
|
}
|
|
392
328
|
|
|
393
|
-
module.exports = {
|
|
329
|
+
module.exports = { Module };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
const { get } = require('
|
|
2
|
-
const { OAuth2Requester } = require('
|
|
1
|
+
const { get } = require('../../../assertions');
|
|
2
|
+
const { OAuth2Requester } = require('../..');
|
|
3
3
|
|
|
4
4
|
class Api extends OAuth2Requester {
|
|
5
5
|
constructor(params) {
|
|
@@ -23,7 +23,12 @@ class Api extends OAuth2Requester {
|
|
|
23
23
|
return this.authorizationUri;
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
getAuthorizationRequirements() {
|
|
27
|
+
return {
|
|
28
|
+
url: this.getAuthUri(),
|
|
29
|
+
type: 'oauth2',
|
|
30
|
+
};
|
|
31
|
+
}
|
|
27
32
|
}
|
|
28
33
|
|
|
29
34
|
module.exports = { Api };
|
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
require('dotenv').config();
|
|
2
|
-
const {Api} = require('./api');
|
|
3
|
-
const {get} = require('
|
|
4
|
-
const config = {name: 'anapi'}
|
|
2
|
+
const { Api } = require('./api');
|
|
3
|
+
const { get } = require('../../../assertions');
|
|
4
|
+
const config = { name: 'anapi' }
|
|
5
5
|
|
|
6
6
|
const Definition = {
|
|
7
7
|
API: Api,
|
|
8
|
-
|
|
8
|
+
getAuthorizationRequirements: () => ({
|
|
9
|
+
url: 'http://localhost:3000/redirect/anapi',
|
|
10
|
+
type: 'oauth2',
|
|
11
|
+
}),
|
|
12
|
+
getName: function () { return config.name },
|
|
9
13
|
moduleName: config.name,
|
|
10
14
|
modelName: 'AnApi',
|
|
11
15
|
requiredAuthMethods: {
|
|
12
|
-
getToken: async function(api, params){
|
|
16
|
+
getToken: async function (api, params) {
|
|
13
17
|
const code = get(params.data, 'code');
|
|
14
18
|
return api.getTokenFromCode(code);
|
|
15
19
|
},
|
|
16
|
-
getEntityDetails: async function(api, callbackParams, tokenResponse, userId) {
|
|
20
|
+
getEntityDetails: async function (api, callbackParams, tokenResponse, userId) {
|
|
17
21
|
const userDetails = await api.getUserDetails();
|
|
18
22
|
return {
|
|
19
23
|
identifiers: { externalId: userDetails.portalId, user: userId },
|
|
@@ -26,14 +30,14 @@ const Definition = {
|
|
|
26
30
|
],
|
|
27
31
|
entity: [],
|
|
28
32
|
},
|
|
29
|
-
getCredentialDetails: async function(api, userId) {
|
|
33
|
+
getCredentialDetails: async function (api, userId) {
|
|
30
34
|
const userDetails = await api.getUserDetails();
|
|
31
35
|
return {
|
|
32
36
|
identifiers: { externalId: userDetails.portalId, user: userId },
|
|
33
37
|
details: {}
|
|
34
38
|
};
|
|
35
39
|
},
|
|
36
|
-
testAuthRequest: async function(api){
|
|
40
|
+
testAuthRequest: async function (api) {
|
|
37
41
|
return api.getUserDetails()
|
|
38
42
|
},
|
|
39
43
|
},
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const { Module } = require('../module');
|
|
2
|
+
const { mapModuleClassToModuleDTO } = require('../utils/map-module-dto');
|
|
3
|
+
|
|
4
|
+
class GetEntitiesForUser {
|
|
5
|
+
constructor({ moduleRepository, moduleDefinitions }) {
|
|
6
|
+
this.moduleRepository = moduleRepository;
|
|
7
|
+
|
|
8
|
+
this.definitionMap = new Map();
|
|
9
|
+
for (const definition of moduleDefinitions) {
|
|
10
|
+
this.definitionMap.set(definition.modelName, definition);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async execute(userId) {
|
|
15
|
+
const entities = await this.moduleRepository.findEntitiesByUserId(
|
|
16
|
+
userId
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
return entities.map((entity) => {
|
|
20
|
+
const definition = this.definitionMap.get(entity.moduleName);
|
|
21
|
+
|
|
22
|
+
const moduleInstance = new Module({
|
|
23
|
+
userId,
|
|
24
|
+
definition: definition,
|
|
25
|
+
entity: entity,
|
|
26
|
+
});
|
|
27
|
+
return mapModuleClassToModuleDTO(moduleInstance);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
module.exports = { GetEntitiesForUser };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {import('../module').Module} moduleInstance
|
|
3
|
+
* Convert a Module domain instance to a plain DTO suitable for JSON responses.
|
|
4
|
+
*/
|
|
5
|
+
function mapModuleClassToModuleDTO(moduleInstance) {
|
|
6
|
+
if (!moduleInstance) return null;
|
|
7
|
+
|
|
8
|
+
return {
|
|
9
|
+
id: moduleInstance.entity._id.toString(),
|
|
10
|
+
name: moduleInstance.name,
|
|
11
|
+
userId: moduleInstance.userId,
|
|
12
|
+
entity: moduleInstance.entity,
|
|
13
|
+
credentialId: moduleInstance.credential?._id?.toString(),
|
|
14
|
+
type: moduleInstance.getName()
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
module.exports = { mapModuleClassToModuleDTO };
|