@friggframework/core 2.0.0--canary.395.af305ea.0 → 2.0.0--canary.396.d14a555.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/handlers/backend-utils.js +2 -2
- package/handlers/routers/auth.js +1 -2
- package/index.js +0 -5
- package/integrations/integration-base.js +9 -6
- package/integrations/integration-factory.js +9 -64
- package/integrations/integration-repository.js +26 -0
- package/integrations/integration-router.js +68 -31
- package/integrations/integration.js +156 -0
- package/integrations/options.js +1 -1
- package/integrations/use-cases/create-integration.js +49 -0
- package/integrations/use-cases/delete-integration-for-user.js +29 -0
- package/integrations/use-cases/get-integration-for-user.js +30 -0
- package/integrations/use-cases/get-integration-instance.js +77 -0
- package/integrations/use-cases/get-integrations-for-user.js +19 -0
- package/integrations/use-cases/index.js +15 -0
- package/module-plugin/index.js +0 -2
- package/module-plugin/module-factory.js +14 -20
- package/module-plugin/module-repository.js +14 -0
- package/module-plugin/module-service.js +50 -0
- package/module-plugin/{auther.js → module.js} +93 -159
- package/package.json +5 -5
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { Integration } = require('../integration');
|
|
2
|
+
|
|
3
|
+
class CreateIntegration {
|
|
4
|
+
/**
|
|
5
|
+
* @param {Object} params
|
|
6
|
+
* @param {import('../integration-repository').IntegrationRepository} params.integrationRepository
|
|
7
|
+
* @param {import('../integration-classes').IntegrationClasses} params.integrationClasses
|
|
8
|
+
* @param {import('../../module-plugin/module-service').ModuleService} params.moduleService
|
|
9
|
+
*/
|
|
10
|
+
constructor({ integrationRepository, integrationClasses, moduleService }) {
|
|
11
|
+
this.integrationRepository = integrationRepository;
|
|
12
|
+
this.integrationClasses = integrationClasses;
|
|
13
|
+
this.moduleService = moduleService;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
async execute(entities, userId, config) {
|
|
17
|
+
const integrationRecord = await this.integrationRepository.createIntegration(entities, userId, config);
|
|
18
|
+
|
|
19
|
+
const modules = {};
|
|
20
|
+
for (const [entityId, key] of Object.entries(integrationRecord.entityReference)) {
|
|
21
|
+
const moduleInstance = await this.moduleService.getModuleInstance(
|
|
22
|
+
entityId,
|
|
23
|
+
integrationRecord.user
|
|
24
|
+
);
|
|
25
|
+
modules[key] = moduleInstance;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const integration = new Integration({
|
|
29
|
+
id: integrationRecord.id,
|
|
30
|
+
userId: integrationRecord.user,
|
|
31
|
+
entities: integrationRecord.entities,
|
|
32
|
+
config: integrationRecord.config,
|
|
33
|
+
status: integrationRecord.status,
|
|
34
|
+
version: integrationRecord.version,
|
|
35
|
+
messages: integrationRecord.messages,
|
|
36
|
+
entityReference: integrationRecord.entityReference,
|
|
37
|
+
integrationClass: this.integrationClasses[integrationRecord.config.type], // todo: check if this is correct
|
|
38
|
+
modules
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
// load dynamic user actions and register event handlers
|
|
43
|
+
await integration.initialize();
|
|
44
|
+
|
|
45
|
+
return integration;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = { CreateIntegration };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const Boom = require('@hapi/boom');
|
|
2
|
+
|
|
3
|
+
class DeleteIntegrationForUser {
|
|
4
|
+
constructor({ integrationRepository }) {
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @type {import('../integration-repository').IntegrationRepository}
|
|
8
|
+
*/
|
|
9
|
+
this.integrationRepository = integrationRepository;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async execute(integrationId, userId) {
|
|
13
|
+
const integration = await this.integrationRepository.findIntegrationById(integrationId);
|
|
14
|
+
|
|
15
|
+
if (!integration) {
|
|
16
|
+
throw Boom.notFound(
|
|
17
|
+
`Integration with id of ${integrationId} does not exist`
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (integration.user.toString() !== userId.toString()) {
|
|
22
|
+
throw Boom.forbidden('User does not have access to this integration');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
await this.integrationRepository.deleteIntegrationById(integrationId);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = { DeleteIntegrationForUser };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
class GetIntegrationForUser {
|
|
2
|
+
constructor({ integrationRepository }) {
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @type {import('../integration-repository').IntegrationRepository}
|
|
6
|
+
*/
|
|
7
|
+
this.integrationRepository = integrationRepository;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} integrationId
|
|
12
|
+
* @param {string} userId
|
|
13
|
+
* @returns {Promise<Integration>}
|
|
14
|
+
*/
|
|
15
|
+
async execute(integrationId, userId) {
|
|
16
|
+
const integration = await this.integrationRepository.findIntegrationById(integrationId);
|
|
17
|
+
|
|
18
|
+
if (!integration) {
|
|
19
|
+
throw Boom.notFound(`Integration with id of ${integrationId} does not exist`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
if (integration.user.toString() !== userId.toString()) {
|
|
23
|
+
throw Boom.forbidden('User does not have access to this integration');
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return integration;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
module.exports = { GetIntegrationForUser };
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
const { Integration } = require('../integration');
|
|
2
|
+
const { ModuleService } = require('../../module-plugin/module-service');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
// todo: remove this use case
|
|
6
|
+
class GetIntegrationInstance {
|
|
7
|
+
constructor({
|
|
8
|
+
integrationRepository,
|
|
9
|
+
integrationClasses,
|
|
10
|
+
moduleService,
|
|
11
|
+
}) {
|
|
12
|
+
this.integrationRepository = integrationRepository;
|
|
13
|
+
this.integrationClasses = integrationClasses;
|
|
14
|
+
this.moduleService = moduleService;
|
|
15
|
+
|
|
16
|
+
// Build type mapping for quick lookup
|
|
17
|
+
this.integrationTypeMap = new Map();
|
|
18
|
+
this.integrationClasses.forEach((IntegrationClass) => {
|
|
19
|
+
this.integrationTypeMap.set(IntegrationClass.getName(), IntegrationClass);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// todo: check if this is really all we need to instantiate an integration instance
|
|
24
|
+
async execute(integrationId, userId) {
|
|
25
|
+
// 1. Get integration record from repository
|
|
26
|
+
const integrationRecord = await this.integrationRepository.findIntegrationById(integrationId);
|
|
27
|
+
|
|
28
|
+
if (!integrationRecord) {
|
|
29
|
+
throw new Error(`No integration found by the ID of ${integrationId}`);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// 2. Get the correct Integration class by type
|
|
33
|
+
const IntegrationClass = this.integrationTypeMap.get(integrationRecord.config.type);
|
|
34
|
+
|
|
35
|
+
if (!IntegrationClass) {
|
|
36
|
+
throw new Error(`No integration class found for type: ${integrationRecord.config.type}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (!integrationRecord.user.equals(userId)) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`Integration ${integrationId} does not belong to User ${userId}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 3. Load modules based on entity references
|
|
46
|
+
const modules = {};
|
|
47
|
+
for (const [entityId, key] of Object.entries(integrationRecord.entityReference)) {
|
|
48
|
+
const moduleInstance = await this.moduleService.getModuleInstance(
|
|
49
|
+
entityId,
|
|
50
|
+
integrationRecord.user
|
|
51
|
+
);
|
|
52
|
+
modules[key] = moduleInstance;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 4. Create the Integration domain entity with modules
|
|
56
|
+
const integration = new Integration({
|
|
57
|
+
id: integrationRecord.id,
|
|
58
|
+
userId: integrationRecord.user,
|
|
59
|
+
entities: integrationRecord.entities,
|
|
60
|
+
config: integrationRecord.config,
|
|
61
|
+
status: integrationRecord.status,
|
|
62
|
+
version: integrationRecord.version,
|
|
63
|
+
messages: integrationRecord.messages,
|
|
64
|
+
entityReference: integrationRecord.entityReference,
|
|
65
|
+
integrationClass: IntegrationClass,
|
|
66
|
+
modules
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
// 6. Complete async initialization (load dynamic actions, register handlers)
|
|
71
|
+
await integration.initialize();
|
|
72
|
+
|
|
73
|
+
return integration;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
module.exports = { GetIntegrationInstance };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
class GetIntegrationsForUser {
|
|
2
|
+
constructor({ integrationRepository }) {
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @type {import('../integration-repository').IntegrationRepository}
|
|
6
|
+
*/
|
|
7
|
+
this.integrationRepository = integrationRepository;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {string} userId
|
|
12
|
+
* @returns {Promise<Integration[]>}
|
|
13
|
+
*/
|
|
14
|
+
async execute(userId) {
|
|
15
|
+
return this.integrationRepository.findIntegrationsByUserId(userId);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = { GetIntegrationsForUser };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const { GetIntegrationsForUserId } = require('./get-integrations-for-user');
|
|
2
|
+
const { DeleteIntegrationForUserById } = require('./delete-integration-for-user-by-id');
|
|
3
|
+
const { GetIntegrationById } = require('./get-integration-by-id');
|
|
4
|
+
const { ListCredentials } = require('./list-credentials');
|
|
5
|
+
const { CreateIntegration } = require('./create-integration');
|
|
6
|
+
const { GetIntegrationInstance } = require('./get-integration-instance');
|
|
7
|
+
|
|
8
|
+
module.exports = {
|
|
9
|
+
GetIntegrationsForUserId,
|
|
10
|
+
DeleteIntegrationForUserById,
|
|
11
|
+
GetIntegrationById,
|
|
12
|
+
ListCredentials,
|
|
13
|
+
CreateIntegration,
|
|
14
|
+
GetIntegrationInstance,
|
|
15
|
+
};
|
package/module-plugin/index.js
CHANGED
|
@@ -8,7 +8,6 @@ const { OAuth2Requester } = require('./requester/oauth-2');
|
|
|
8
8
|
const { Requester } = require('./requester/requester');
|
|
9
9
|
const { ModuleConstants } = require('./ModuleConstants');
|
|
10
10
|
const { ModuleFactory } = require('./module-factory');
|
|
11
|
-
const { Auther } = require('./auther');
|
|
12
11
|
|
|
13
12
|
module.exports = {
|
|
14
13
|
Credential,
|
|
@@ -21,5 +20,4 @@ module.exports = {
|
|
|
21
20
|
Requester,
|
|
22
21
|
ModuleConstants,
|
|
23
22
|
ModuleFactory,
|
|
24
|
-
Auther
|
|
25
23
|
};
|
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const {
|
|
1
|
+
const { ModuleRepository } = require('./module-repository');
|
|
2
|
+
const { GetModuleInstance } = require('./use-cases/get-module-instance');
|
|
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);
|
|
9
|
+
this.moduleRepository = new ModuleRepository();
|
|
10
|
+
this.getModuleInstanceUseCase = new GetModuleInstance({
|
|
11
|
+
moduleRepository: this.moduleRepository,
|
|
12
|
+
moduleDefinitions: this.moduleDefinitions,
|
|
13
|
+
});
|
|
8
14
|
}
|
|
9
15
|
|
|
10
16
|
async getEntitiesForUser(userId) {
|
|
11
17
|
let results = [];
|
|
12
18
|
for (const moduleDefinition of this.moduleDefinitions) {
|
|
13
|
-
const moduleInstance =
|
|
19
|
+
const moduleInstance = new Module({
|
|
14
20
|
userId,
|
|
15
21
|
definition: moduleDefinition,
|
|
16
22
|
});
|
|
@@ -29,29 +35,17 @@ class ModuleFactory {
|
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
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
|
-
});
|
|
38
|
+
return this.getModuleInstanceUseCase.execute(entityId, userId);
|
|
48
39
|
}
|
|
49
40
|
|
|
50
41
|
async getInstanceFromTypeName(typeName, userId) {
|
|
51
42
|
const moduleDefinition = this.moduleDefinitions.find(
|
|
52
43
|
(def) => def.getName() === typeName
|
|
53
44
|
);
|
|
54
|
-
|
|
45
|
+
if (!moduleDefinition) {
|
|
46
|
+
throw new Error(`Module definition not found for type: ${typeName}`);
|
|
47
|
+
}
|
|
48
|
+
return new Module({
|
|
55
49
|
userId,
|
|
56
50
|
definition: moduleDefinition,
|
|
57
51
|
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
const { Entity } = require('./entity');
|
|
2
|
+
|
|
3
|
+
class ModuleRepository {
|
|
4
|
+
async findEntityById(entityId) {
|
|
5
|
+
const entity = await Entity.findById(entityId).populate('credential');
|
|
6
|
+
if (!entity) {
|
|
7
|
+
throw new Error(`Entity ${entityId} not found`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return entity;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
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.user.toString() !== userId.toString()) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`Entity ${entityId} does not belong to user ${userId}`
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const entityType = entity.toJSON().__t;
|
|
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.toObject();
|
|
26
|
+
this.credential = entityObj?.credential.toObject();
|
|
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) {
|
|
@@ -233,19 +131,10 @@ class Auther extends Delegate {
|
|
|
233
131
|
}
|
|
234
132
|
|
|
235
133
|
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
|
-
console.log(this.api);
|
|
245
134
|
return this.api.getAuthorizationRequirements();
|
|
246
135
|
}
|
|
247
136
|
|
|
248
|
-
async testAuth(
|
|
137
|
+
async testAuth() {
|
|
249
138
|
let validAuth = false;
|
|
250
139
|
try {
|
|
251
140
|
if (await this.testAuthRequest(this.api)) validAuth = true;
|
|
@@ -308,18 +197,6 @@ class Auther extends Delegate {
|
|
|
308
197
|
}
|
|
309
198
|
}
|
|
310
199
|
|
|
311
|
-
async getEntityOptions() {
|
|
312
|
-
throw new Error(
|
|
313
|
-
'Method getEntityOptions() is not defined in the class'
|
|
314
|
-
);
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
async refreshEntityOptions() {
|
|
318
|
-
throw new Error(
|
|
319
|
-
'Method refreshEntityOptions() is not defined in the class'
|
|
320
|
-
);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
200
|
async findOrCreateEntity(entityDetails) {
|
|
324
201
|
const identifiers = get(entityDetails, 'identifiers');
|
|
325
202
|
const details = get(entityDetails, 'details');
|
|
@@ -389,6 +266,63 @@ class Auther extends Delegate {
|
|
|
389
266
|
await this.entity.save();
|
|
390
267
|
}
|
|
391
268
|
}
|
|
269
|
+
|
|
270
|
+
// todo: check if all these props are still up to date
|
|
271
|
+
validateDefinition(definition) {
|
|
272
|
+
if (!definition) {
|
|
273
|
+
throw new Error('Module definition is required');
|
|
274
|
+
}
|
|
275
|
+
if (!definition.moduleName) {
|
|
276
|
+
throw new Error('Module definition requires moduleName');
|
|
277
|
+
}
|
|
278
|
+
if (!definition.API) {
|
|
279
|
+
throw new Error('Module definition requires API class');
|
|
280
|
+
}
|
|
281
|
+
if (!definition.requiredAuthMethods) {
|
|
282
|
+
throw new Error('Module definition requires requiredAuthMethods');
|
|
283
|
+
} else {
|
|
284
|
+
if (
|
|
285
|
+
definition.API.requesterType ===
|
|
286
|
+
ModuleConstants.authType.oauth2 &&
|
|
287
|
+
!definition.requiredAuthMethods.getToken
|
|
288
|
+
) {
|
|
289
|
+
throw new Error(
|
|
290
|
+
'Module definition requires requiredAuthMethods.getToken'
|
|
291
|
+
);
|
|
292
|
+
}
|
|
293
|
+
if (!definition.requiredAuthMethods.getEntityDetails) {
|
|
294
|
+
throw new Error(
|
|
295
|
+
'Module definition requires requiredAuthMethods.getEntityDetails'
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
if (!definition.requiredAuthMethods.getCredentialDetails) {
|
|
299
|
+
throw new Error(
|
|
300
|
+
'Module definition requires requiredAuthMethods.getCredentialDetails'
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
if (!definition.requiredAuthMethods.apiPropertiesToPersist) {
|
|
304
|
+
throw new Error(
|
|
305
|
+
'Module definition requires requiredAuthMethods.apiPropertiesToPersist'
|
|
306
|
+
);
|
|
307
|
+
} else if (definition.Credential) {
|
|
308
|
+
for (const prop of definition.requiredAuthMethods
|
|
309
|
+
.apiPropertiesToPersist?.credential) {
|
|
310
|
+
if (
|
|
311
|
+
!definition.Credential.schema.paths.hasOwnProperty(prop)
|
|
312
|
+
) {
|
|
313
|
+
throw new Error(
|
|
314
|
+
`Module definition requires Credential schema to have property ${prop}`
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (!definition.requiredAuthMethods.testAuthRequest) {
|
|
320
|
+
throw new Error(
|
|
321
|
+
'Module definition requires requiredAuthMethods.testAuth'
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
392
326
|
}
|
|
393
327
|
|
|
394
|
-
module.exports = {
|
|
328
|
+
module.exports = { Module };
|