@friggframework/core 2.0.0--canary.398.53eac55.0 → 2.0.0--canary.397.878fefa.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 +931 -50
- package/core/create-handler.js +1 -0
- package/credential/credential-repository.js +42 -0
- package/credential/use-cases/get-credential-for-user.js +21 -0
- package/credential/use-cases/update-authentication-status.js +15 -0
- package/database/models/WebsocketConnection.js +0 -5
- package/handlers/app-definition-loader.js +38 -0
- package/handlers/app-handler-helpers.js +0 -3
- package/handlers/backend-utils.js +35 -34
- package/handlers/routers/auth.js +3 -14
- 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 +1 -16
- package/integrations/index.js +0 -5
- package/integrations/integration-base.js +42 -44
- package/integrations/integration-repository.js +67 -0
- package/integrations/integration-router.js +301 -178
- package/integrations/integration.js +233 -0
- package/integrations/options.js +1 -1
- package/integrations/tests/doubles/dummy-integration-class.js +90 -0
- package/integrations/tests/doubles/test-integration-repository.js +89 -0
- package/integrations/tests/use-cases/create-integration.test.js +124 -0
- package/integrations/tests/use-cases/delete-integration-for-user.test.js +143 -0
- package/integrations/tests/use-cases/get-integration-for-user.test.js +143 -0
- package/integrations/tests/use-cases/get-integration-instance.test.js +169 -0
- package/integrations/tests/use-cases/get-integrations-for-user.test.js +169 -0
- package/integrations/tests/use-cases/get-possible-integrations.test.js +188 -0
- package/integrations/tests/use-cases/update-integration-messages.test.js +142 -0
- package/integrations/tests/use-cases/update-integration-status.test.js +103 -0
- package/integrations/tests/use-cases/update-integration.test.js +134 -0
- package/integrations/use-cases/create-integration.js +72 -0
- package/integrations/use-cases/delete-integration-for-user.js +73 -0
- package/integrations/use-cases/get-integration-for-user.js +79 -0
- package/integrations/use-cases/get-integration-instance.js +84 -0
- package/integrations/use-cases/get-integrations-for-user.js +77 -0
- package/integrations/use-cases/get-possible-integrations.js +27 -0
- package/integrations/use-cases/index.js +11 -0
- package/integrations/use-cases/update-integration-messages.js +31 -0
- package/integrations/use-cases/update-integration-status.js +28 -0
- package/integrations/use-cases/update-integration.js +92 -0
- package/integrations/utils/map-integration-dto.js +36 -0
- package/{module-plugin → modules}/index.js +0 -8
- package/modules/module-factory.js +54 -0
- package/modules/module-repository.js +107 -0
- package/modules/module.js +221 -0
- package/{module-plugin → modules}/test/mock-api/api.js +8 -3
- package/{module-plugin → modules}/test/mock-api/definition.js +12 -8
- package/modules/tests/doubles/test-module-factory.js +16 -0
- package/modules/tests/doubles/test-module-repository.js +19 -0
- package/modules/use-cases/get-entities-for-user.js +32 -0
- package/modules/use-cases/get-entity-options-by-id.js +58 -0
- package/modules/use-cases/get-entity-options-by-type.js +34 -0
- package/modules/use-cases/get-module-instance-from-type.js +31 -0
- package/modules/use-cases/get-module.js +56 -0
- package/modules/use-cases/process-authorization-callback.js +114 -0
- package/modules/use-cases/refresh-entity-options.js +58 -0
- package/modules/use-cases/test-module-auth.js +54 -0
- package/modules/utils/map-module-dto.js +18 -0
- package/package.json +5 -5
- package/syncs/sync.js +0 -1
- package/types/integrations/index.d.ts +2 -6
- package/types/module-plugin/index.d.ts +4 -56
- package/types/syncs/index.d.ts +0 -2
- 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/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/integrations/test/integration-base.test.js +0 -144
- package/module-plugin/auther.js +0 -393
- package/module-plugin/entity-manager.js +0 -70
- package/module-plugin/manager.js +0 -169
- package/module-plugin/module-factory.js +0 -61
- /package/{module-plugin → modules}/ModuleConstants.js +0 -0
- /package/{module-plugin → modules}/credential.js +0 -0
- /package/{module-plugin → modules}/entity.js +0 -0
- /package/{module-plugin → modules}/requester/api-key.js +0 -0
- /package/{module-plugin → modules}/requester/basic.js +0 -0
- /package/{module-plugin → modules}/requester/oauth-2.js +0 -0
- /package/{module-plugin → modules}/requester/requester.js +0 -0
- /package/{module-plugin → modules}/requester/requester.test.js +0 -0
- /package/{module-plugin → modules}/test/auther.test.js +0 -0
- /package/{module-plugin → modules}/test/mock-api/mocks/hubspot.js +0 -0
package/core/create-handler.js
CHANGED
|
@@ -34,6 +34,7 @@ const createHandler = (optionByName = {}) => {
|
|
|
34
34
|
// Helps mongoose reuse the connection. Lowers response times.
|
|
35
35
|
context.callbackWaitsForEmptyEventLoop = false;
|
|
36
36
|
|
|
37
|
+
// todo: this should not be necessary anymore
|
|
37
38
|
if (shouldUseDatabase) {
|
|
38
39
|
await connectToDatabase();
|
|
39
40
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { Credential } = require('../modules');
|
|
2
|
+
|
|
3
|
+
class CredentialRepository {
|
|
4
|
+
async findCredentialById(id) {
|
|
5
|
+
return Credential.findById(id);
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
async updateAuthenticationStatus(credentialId, authIsValid) {
|
|
9
|
+
return Credential.updateOne({ _id: credentialId }, { $set: { auth_is_valid: authIsValid } });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Permanently remove a credential document.
|
|
14
|
+
* @param {string} credentialId
|
|
15
|
+
* @returns {Promise<import('mongoose').DeleteResult>}
|
|
16
|
+
*/
|
|
17
|
+
async deleteCredentialById(credentialId) {
|
|
18
|
+
return Credential.deleteOne({ _id: credentialId });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create a new credential or update an existing one matching the identifiers.
|
|
23
|
+
* `credentialDetails` format: { identifiers: { ... }, details: { ... } }
|
|
24
|
+
* Identifiers are used in the query filter; details are merged into the document.
|
|
25
|
+
* @param {{identifiers: Object, details: Object}} credentialDetails
|
|
26
|
+
* @returns {Promise<Object>} The persisted credential (lean object)
|
|
27
|
+
*/
|
|
28
|
+
async upsertCredential(credentialDetails) {
|
|
29
|
+
const { identifiers, details } = credentialDetails;
|
|
30
|
+
if (!identifiers) throw new Error('identifiers required to upsert credential');
|
|
31
|
+
|
|
32
|
+
const query = { ...identifiers };
|
|
33
|
+
|
|
34
|
+
const update = { $set: { ...details } };
|
|
35
|
+
|
|
36
|
+
const options = { upsert: true, new: true, setDefaultsOnInsert: true, lean: true };
|
|
37
|
+
|
|
38
|
+
return Credential.findOneAndUpdate(query, update, options);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
module.exports = { CredentialRepository };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class GetCredentialForUser {
|
|
2
|
+
constructor({ credentialRepository }) {
|
|
3
|
+
this.credentialRepository = credentialRepository;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
async execute(credentialId, userId) {
|
|
7
|
+
const credential = await this.credentialRepository.findCredentialById(credentialId);
|
|
8
|
+
|
|
9
|
+
if (!credential) {
|
|
10
|
+
throw new Error(`Credential with id ${credentialId} not found`);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
if (credential.user.toString() !== userId.toString()) {
|
|
14
|
+
throw new Error(`Credential ${credentialId} does not belong to user ${userId}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
return credential;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = { GetCredentialForUser };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
class UpdateAuthenticationStatus {
|
|
2
|
+
constructor({ credentialRepository }) {
|
|
3
|
+
this.credentialRepository = credentialRepository;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} credentialId
|
|
8
|
+
* @param {boolean} authIsValid
|
|
9
|
+
*/
|
|
10
|
+
async execute(credentialId, authIsValid) {
|
|
11
|
+
await this.credentialRepository.updateAuthenticationStatus(credentialId, authIsValid);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
module.exports = { UpdateAuthenticationStatus };
|
|
@@ -8,11 +8,6 @@ const schema = new mongoose.Schema({
|
|
|
8
8
|
// Add a static method to get active connections
|
|
9
9
|
schema.statics.getActiveConnections = async function () {
|
|
10
10
|
try {
|
|
11
|
-
// Return empty array if websockets are not configured
|
|
12
|
-
if (!process.env.WEBSOCKET_API_ENDPOINT) {
|
|
13
|
-
return [];
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
const connections = await this.find({}, 'connectionId');
|
|
17
12
|
return connections.map((conn) => ({
|
|
18
13
|
connectionId: conn.connectionId,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const { findNearestBackendPackageJson } = require('@friggframework/core/utils');
|
|
2
|
+
const path = require('node:path');
|
|
3
|
+
const fs = require('fs-extra');
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Loads the App definition from the nearest backend package
|
|
7
|
+
* @function loadAppDefinition
|
|
8
|
+
* @description Searches for the nearest backend package.json, loads the corresponding index.js file,
|
|
9
|
+
* and extracts the application definition containing integrations and user configuration.
|
|
10
|
+
* @returns {{integrations: Array<object>, userConfig: object | null}} An object containing the application definition.
|
|
11
|
+
* @throws {Error} Throws error if backend package.json cannot be found.
|
|
12
|
+
* @throws {Error} Throws error if index.js file cannot be found in the backend directory.
|
|
13
|
+
* @example
|
|
14
|
+
* const { integrations, userConfig } = loadAppDefinition();
|
|
15
|
+
* console.log(`Found ${integrations.length} integrations`);
|
|
16
|
+
*/
|
|
17
|
+
function loadAppDefinition() {
|
|
18
|
+
const backendPath = findNearestBackendPackageJson();
|
|
19
|
+
if (!backendPath) {
|
|
20
|
+
throw new Error('Could not find backend package.json');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const backendDir = path.dirname(backendPath);
|
|
24
|
+
const backendFilePath = path.join(backendDir, 'index.js');
|
|
25
|
+
if (!fs.existsSync(backendFilePath)) {
|
|
26
|
+
throw new Error('Could not find index.js');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const backendJsFile = require(backendFilePath);
|
|
30
|
+
const appDefinition = backendJsFile.Definition;
|
|
31
|
+
|
|
32
|
+
const { integrations = [], user: userConfig = null } = appDefinition;
|
|
33
|
+
return { integrations, userConfig };
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
loadAppDefinition,
|
|
38
|
+
};
|
|
@@ -3,7 +3,6 @@ const express = require('express');
|
|
|
3
3
|
const bodyParser = require('body-parser');
|
|
4
4
|
const cors = require('cors');
|
|
5
5
|
const Boom = require('@hapi/boom');
|
|
6
|
-
const loadUserManager = require('./routers/middleware/loadUser');
|
|
7
6
|
const serverlessHttp = require('serverless-http');
|
|
8
7
|
|
|
9
8
|
const createApp = (applyMiddleware) => {
|
|
@@ -20,8 +19,6 @@ const createApp = (applyMiddleware) => {
|
|
|
20
19
|
})
|
|
21
20
|
);
|
|
22
21
|
|
|
23
|
-
app.use(loadUserManager);
|
|
24
|
-
|
|
25
22
|
if (applyMiddleware) applyMiddleware(app);
|
|
26
23
|
|
|
27
24
|
// Handle sending error response and logging server errors to console
|
|
@@ -1,24 +1,12 @@
|
|
|
1
|
-
const { createFriggBackend, Worker } = require('@friggframework/core');
|
|
2
|
-
const { findNearestBackendPackageJson } = require('@friggframework/core/utils');
|
|
3
|
-
const path = require('node:path');
|
|
4
|
-
const fs = require('fs-extra');
|
|
5
|
-
|
|
6
|
-
const backendPath = findNearestBackendPackageJson();
|
|
7
|
-
if (!backendPath) {
|
|
8
|
-
throw new Error('Could not find backend package.json');
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const backendDir = path.dirname(backendPath);
|
|
12
|
-
const backendFilePath = path.join(backendDir, 'index.js');
|
|
13
|
-
if (!fs.existsSync(backendFilePath)) {
|
|
14
|
-
throw new Error('Could not find index.js');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
const backendJsFile = require(backendFilePath);
|
|
18
1
|
const { Router } = require('express');
|
|
19
|
-
const
|
|
2
|
+
const { Worker } = require('@friggframework/core');
|
|
3
|
+
const { loadAppDefinition } = require('./app-definition-loader');
|
|
4
|
+
const { IntegrationRepository } = require('../integrations/integration-repository');
|
|
5
|
+
const { ModuleFactory } = require('../modules/module-factory');
|
|
6
|
+
const { GetIntegrationInstance } = require('../integrations/use-cases/get-integration-instance');
|
|
7
|
+
const { getModulesDefinitionFromIntegrationClasses } = require('../integrations/utils/map-integration-dto');
|
|
8
|
+
const { ModuleRepository } = require('../modules/module-repository');
|
|
20
9
|
|
|
21
|
-
const backend = createFriggBackend(appDefinition);
|
|
22
10
|
const loadRouterFromObject = (IntegrationClass, routerObject) => {
|
|
23
11
|
const router = Router();
|
|
24
12
|
const { path, method, event } = routerObject;
|
|
@@ -27,10 +15,10 @@ const loadRouterFromObject = (IntegrationClass, routerObject) => {
|
|
|
27
15
|
);
|
|
28
16
|
router[method.toLowerCase()](path, async (req, res, next) => {
|
|
29
17
|
try {
|
|
30
|
-
const integration = new IntegrationClass(
|
|
18
|
+
const integration = new IntegrationClass();
|
|
31
19
|
await integration.loadModules();
|
|
32
20
|
await integration.registerEventHandlers();
|
|
33
|
-
const result = await integration.send(event, {req, res, next});
|
|
21
|
+
const result = await integration.send(event, { req, res, next });
|
|
34
22
|
res.json(result);
|
|
35
23
|
} catch (error) {
|
|
36
24
|
next(error);
|
|
@@ -39,29 +27,43 @@ const loadRouterFromObject = (IntegrationClass, routerObject) => {
|
|
|
39
27
|
|
|
40
28
|
return router;
|
|
41
29
|
};
|
|
42
|
-
|
|
30
|
+
|
|
31
|
+
//todo: this should be in a use case class
|
|
32
|
+
const createQueueWorker = (integrationClass) => {
|
|
43
33
|
class QueueWorker extends Worker {
|
|
44
34
|
async _run(params, context) {
|
|
45
35
|
try {
|
|
46
|
-
let
|
|
36
|
+
let integrationInstance;
|
|
47
37
|
if (!params.integrationId) {
|
|
48
|
-
|
|
49
|
-
await
|
|
50
|
-
|
|
51
|
-
await instance.registerEventHandlers();
|
|
38
|
+
integrationInstance = new integrationClass();
|
|
39
|
+
await integrationInstance.loadModules();
|
|
40
|
+
await integrationInstance.registerEventHandlers();
|
|
52
41
|
console.log(
|
|
53
42
|
`${params.event} for ${integrationClass.Definition.name} integration with no integrationId`
|
|
54
43
|
);
|
|
55
44
|
} else {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
45
|
+
const { integrations: integrationClasses } = loadAppDefinition();
|
|
46
|
+
const integrationRepository = new IntegrationRepository();
|
|
47
|
+
const moduleRepository = new ModuleRepository();
|
|
48
|
+
const moduleFactory = new ModuleFactory({
|
|
49
|
+
moduleRepository,
|
|
50
|
+
moduleDefinitions: getModulesDefinitionFromIntegrationClasses(integrationClasses),
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
const getIntegrationInstance = new GetIntegrationInstance({
|
|
54
|
+
integrationRepository,
|
|
55
|
+
integrationClasses,
|
|
56
|
+
moduleFactory,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// todo: are we going to have the userId available here?
|
|
60
|
+
integrationInstance = await getIntegrationInstance.execute(params.integrationId, params.userId);
|
|
60
61
|
console.log(
|
|
61
|
-
`${params.event} for ${
|
|
62
|
+
`${params.event} for ${integrationInstance.record.config.type} of integrationId: ${params.integrationId}`
|
|
62
63
|
);
|
|
63
64
|
}
|
|
64
|
-
|
|
65
|
+
|
|
66
|
+
const res = await integrationInstance.send(params.event, {
|
|
65
67
|
data: params.data,
|
|
66
68
|
context,
|
|
67
69
|
});
|
|
@@ -79,7 +81,6 @@ const createQueueWorker = (integrationClass, integrationFactory) => {
|
|
|
79
81
|
};
|
|
80
82
|
|
|
81
83
|
module.exports = {
|
|
82
|
-
...backend,
|
|
83
84
|
loadRouterFromObject,
|
|
84
85
|
createQueueWorker,
|
|
85
86
|
};
|
package/handlers/routers/auth.js
CHANGED
|
@@ -1,26 +1,15 @@
|
|
|
1
1
|
const { createIntegrationRouter } = require('@friggframework/core');
|
|
2
2
|
const { createAppHandler } = require('./../app-handler-helpers');
|
|
3
|
-
const { requireLoggedInUser } = require('./middleware/requireLoggedInUser');
|
|
4
|
-
const {
|
|
5
|
-
moduleFactory,
|
|
6
|
-
integrationFactory,
|
|
7
|
-
IntegrationHelper,
|
|
8
|
-
} = require('./../backend-utils');
|
|
9
3
|
|
|
10
|
-
const router = createIntegrationRouter(
|
|
11
|
-
factory: { moduleFactory, integrationFactory, IntegrationHelper },
|
|
12
|
-
requireLoggedInUser,
|
|
13
|
-
getUserId: (req) => req.user.getUserId(),
|
|
14
|
-
});
|
|
4
|
+
const router = createIntegrationRouter();
|
|
15
5
|
|
|
16
6
|
router.route('/redirect/:appId').get((req, res) => {
|
|
17
7
|
res.redirect(
|
|
18
|
-
`${process.env.FRONTEND_URI}/redirect/${
|
|
19
|
-
req.params.appId
|
|
8
|
+
`${process.env.FRONTEND_URI}/redirect/${req.params.appId
|
|
20
9
|
}?${new URLSearchParams(req.query)}`
|
|
21
10
|
);
|
|
22
11
|
});
|
|
23
12
|
|
|
24
13
|
const handler = createAppHandler('HTTP Event: Auth', router);
|
|
25
14
|
|
|
26
|
-
module.exports = { handler
|
|
15
|
+
module.exports = { handler };
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
const { createAppHandler } = require('./../app-handler-helpers');
|
|
2
2
|
const {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} = require('./../backend-utils');
|
|
3
|
+
loadAppDefinition,
|
|
4
|
+
} = require('../app-definition-loader');
|
|
6
5
|
const { Router } = require('express');
|
|
6
|
+
const { loadRouterFromObject } = require('../backend-utils');
|
|
7
7
|
|
|
8
8
|
const handlers = {};
|
|
9
|
-
|
|
9
|
+
const { integrations: integrationClasses } = loadAppDefinition();
|
|
10
|
+
|
|
11
|
+
//todo: this should be in a use case class
|
|
12
|
+
for (const IntegrationClass of integrationClasses) {
|
|
10
13
|
const router = Router();
|
|
11
14
|
const basePath = `/api/${IntegrationClass.Definition.name}-integration`;
|
|
12
|
-
|
|
15
|
+
|
|
13
16
|
console.log(`\n│ Configuring routes for ${IntegrationClass.Definition.name} Integration:`);
|
|
14
17
|
|
|
15
18
|
for (const routeDef of IntegrationClass.Definition.routes) {
|
package/handlers/routers/user.js
CHANGED
|
@@ -1,10 +1,29 @@
|
|
|
1
1
|
const express = require('express');
|
|
2
2
|
const { createAppHandler } = require('../app-handler-helpers');
|
|
3
3
|
const { checkRequiredParams } = require('@friggframework/core');
|
|
4
|
-
const {
|
|
4
|
+
const { UserRepository } = require('../../user/user-repository');
|
|
5
|
+
const {
|
|
6
|
+
CreateIndividualUser,
|
|
7
|
+
} = require('../../user/use-cases/create-individual-user');
|
|
8
|
+
const { LoginUser } = require('../../user/use-cases/login-user');
|
|
9
|
+
const {
|
|
10
|
+
CreateTokenForUserId,
|
|
11
|
+
} = require('../../user/use-cases/create-token-for-user-id');
|
|
5
12
|
const catchAsyncError = require('express-async-handler');
|
|
13
|
+
const { loadAppDefinition } = require('../app-definition-loader');
|
|
6
14
|
|
|
7
15
|
const router = express();
|
|
16
|
+
const { userConfig } = loadAppDefinition();
|
|
17
|
+
const userRepository = new UserRepository({ userConfig });
|
|
18
|
+
const createIndividualUser = new CreateIndividualUser({
|
|
19
|
+
userRepository,
|
|
20
|
+
userConfig,
|
|
21
|
+
});
|
|
22
|
+
const loginUser = new LoginUser({
|
|
23
|
+
userRepository,
|
|
24
|
+
userConfig,
|
|
25
|
+
});
|
|
26
|
+
const createTokenForUserId = new CreateTokenForUserId({ userRepository });
|
|
8
27
|
|
|
9
28
|
// define the login endpoint
|
|
10
29
|
router.route('/user/login').post(
|
|
@@ -13,8 +32,8 @@ router.route('/user/login').post(
|
|
|
13
32
|
'username',
|
|
14
33
|
'password',
|
|
15
34
|
]);
|
|
16
|
-
const user = await
|
|
17
|
-
const token = await user.
|
|
35
|
+
const user = await loginUser.execute({ username, password });
|
|
36
|
+
const token = await createTokenForUserId.execute(user.getId(), 120);
|
|
18
37
|
res.status(201);
|
|
19
38
|
res.json({ token });
|
|
20
39
|
})
|
|
@@ -26,11 +45,12 @@ router.route('/user/create').post(
|
|
|
26
45
|
'username',
|
|
27
46
|
'password',
|
|
28
47
|
]);
|
|
29
|
-
|
|
48
|
+
|
|
49
|
+
const user = await createIndividualUser.execute({
|
|
30
50
|
username,
|
|
31
51
|
password,
|
|
32
52
|
});
|
|
33
|
-
const token = await user.
|
|
53
|
+
const token = await createTokenForUserId.execute(user.getId(), 120);
|
|
34
54
|
res.status(201);
|
|
35
55
|
res.json({ token });
|
|
36
56
|
})
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
const { createHandler } = require('@friggframework/core');
|
|
2
|
-
const {
|
|
2
|
+
const { loadAppDefinition } = require('../app-definition-loader');
|
|
3
|
+
const { createQueueWorker } = require('../backend-utils');
|
|
3
4
|
|
|
4
5
|
const handlers = {};
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
const { integrations: integrationClasses } = loadAppDefinition();
|
|
7
|
+
|
|
8
|
+
integrationClasses.forEach((IntegrationClass) => {
|
|
9
|
+
const defaultQueueWorker = createQueueWorker(IntegrationClass);
|
|
7
10
|
|
|
8
11
|
handlers[`${IntegrationClass.Definition.name}`] = {
|
|
9
12
|
queueWorker: createHandler({
|
package/index.js
CHANGED
|
@@ -38,27 +38,20 @@ const {
|
|
|
38
38
|
IntegrationModel,
|
|
39
39
|
Options,
|
|
40
40
|
IntegrationMapping,
|
|
41
|
-
IntegrationFactory,
|
|
42
|
-
IntegrationHelper,
|
|
43
41
|
createIntegrationRouter,
|
|
44
42
|
checkRequiredParams,
|
|
45
|
-
createFriggBackend,
|
|
46
43
|
} = require('./integrations/index');
|
|
47
44
|
const { TimeoutCatcher } = require('./lambda/index');
|
|
48
45
|
const { debug, initDebugLog, flushDebugLog } = require('./logs/index');
|
|
49
46
|
const {
|
|
50
47
|
Credential,
|
|
51
|
-
EntityManager,
|
|
52
48
|
Entity,
|
|
53
|
-
ModuleManager,
|
|
54
49
|
ApiKeyRequester,
|
|
55
50
|
BasicAuthRequester,
|
|
56
51
|
OAuth2Requester,
|
|
57
52
|
Requester,
|
|
58
53
|
ModuleConstants,
|
|
59
|
-
|
|
60
|
-
Auther,
|
|
61
|
-
} = require('./module-plugin/index');
|
|
54
|
+
} = require('./modules/index');
|
|
62
55
|
const utils = require('./utils');
|
|
63
56
|
|
|
64
57
|
// const {Sync } = require('./syncs/model');
|
|
@@ -109,11 +102,8 @@ module.exports = {
|
|
|
109
102
|
IntegrationModel,
|
|
110
103
|
Options,
|
|
111
104
|
IntegrationMapping,
|
|
112
|
-
IntegrationFactory,
|
|
113
|
-
IntegrationHelper,
|
|
114
105
|
checkRequiredParams,
|
|
115
106
|
createIntegrationRouter,
|
|
116
|
-
createFriggBackend,
|
|
117
107
|
|
|
118
108
|
// lambda
|
|
119
109
|
TimeoutCatcher,
|
|
@@ -125,17 +115,12 @@ module.exports = {
|
|
|
125
115
|
|
|
126
116
|
// module plugin
|
|
127
117
|
Credential,
|
|
128
|
-
EntityManager,
|
|
129
118
|
Entity,
|
|
130
|
-
ModuleManager,
|
|
131
119
|
ApiKeyRequester,
|
|
132
120
|
BasicAuthRequester,
|
|
133
121
|
OAuth2Requester,
|
|
134
122
|
Requester,
|
|
135
123
|
ModuleConstants,
|
|
136
|
-
ModuleFactory,
|
|
137
|
-
Auther,
|
|
138
|
-
|
|
139
124
|
// queues
|
|
140
125
|
QueuerUtil,
|
|
141
126
|
|
package/integrations/index.js
CHANGED
|
@@ -2,18 +2,13 @@ const { IntegrationBase } = require('./integration-base');
|
|
|
2
2
|
const { IntegrationModel } = require('./integration-model');
|
|
3
3
|
const { Options } = require('./options');
|
|
4
4
|
const { IntegrationMapping } = require('./integration-mapping');
|
|
5
|
-
const { IntegrationFactory, IntegrationHelper } = require('./integration-factory');
|
|
6
5
|
const { createIntegrationRouter, checkRequiredParams } = require('./integration-router');
|
|
7
|
-
const { createFriggBackend } = require('./create-frigg-backend');
|
|
8
6
|
|
|
9
7
|
module.exports = {
|
|
10
8
|
IntegrationBase,
|
|
11
9
|
IntegrationModel,
|
|
12
10
|
Options,
|
|
13
11
|
IntegrationMapping,
|
|
14
|
-
IntegrationFactory,
|
|
15
|
-
IntegrationHelper,
|
|
16
12
|
createIntegrationRouter,
|
|
17
13
|
checkRequiredParams,
|
|
18
|
-
createFriggBackend
|
|
19
14
|
};
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
const { IntegrationMapping } = require('./integration-mapping');
|
|
2
2
|
const { Options } = require('./options');
|
|
3
|
+
const { UpdateIntegrationStatus } = require('./use-cases/update-integration-status');
|
|
4
|
+
const { IntegrationRepository } = require('./integration-repository');
|
|
5
|
+
const { UpdateIntegrationMessages } = require('./use-cases/update-integration-messages');
|
|
6
|
+
|
|
3
7
|
const constantsToBeMigrated = {
|
|
4
8
|
defaultEvents: {
|
|
5
9
|
ON_CREATE: 'ON_CREATE',
|
|
@@ -19,6 +23,12 @@ const constantsToBeMigrated = {
|
|
|
19
23
|
};
|
|
20
24
|
|
|
21
25
|
class IntegrationBase {
|
|
26
|
+
|
|
27
|
+
// todo: maybe we can pass this as Dependency Injection in the sub-class constructor
|
|
28
|
+
integrationRepository = new IntegrationRepository();
|
|
29
|
+
updateIntegrationStatus = new UpdateIntegrationStatus({ integrationRepository: this.integrationRepository });
|
|
30
|
+
updateIntegrationMessages = new UpdateIntegrationMessages({ integrationRepository: this.integrationRepository });
|
|
31
|
+
|
|
22
32
|
static getOptionDetails() {
|
|
23
33
|
const options = new Options({
|
|
24
34
|
module: Object.values(this.Definition.modules)[0], // This is a placeholder until we revamp the frontend
|
|
@@ -26,6 +36,7 @@ class IntegrationBase {
|
|
|
26
36
|
});
|
|
27
37
|
return options.get();
|
|
28
38
|
}
|
|
39
|
+
|
|
29
40
|
/**
|
|
30
41
|
* CHILDREN SHOULD SPECIFY A DEFINITION FOR THE INTEGRATION
|
|
31
42
|
*/
|
|
@@ -50,21 +61,7 @@ class IntegrationBase {
|
|
|
50
61
|
static getCurrentVersion() {
|
|
51
62
|
return this.Definition.version;
|
|
52
63
|
}
|
|
53
|
-
|
|
54
|
-
// Load all the modules defined in Definition.modules
|
|
55
|
-
const moduleNames = Object.keys(this.constructor.Definition.modules);
|
|
56
|
-
for (const moduleName of moduleNames) {
|
|
57
|
-
const { definition } =
|
|
58
|
-
this.constructor.Definition.modules[moduleName];
|
|
59
|
-
if (typeof definition.API === 'function') {
|
|
60
|
-
this[moduleName] = { api: new definition.API() };
|
|
61
|
-
} else {
|
|
62
|
-
throw new Error(
|
|
63
|
-
`Module ${moduleName} must be a function that extends IntegrationModule`
|
|
64
|
-
);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
64
|
+
|
|
68
65
|
registerEventHandlers() {
|
|
69
66
|
this.on = {
|
|
70
67
|
...this.defaultEvents,
|
|
@@ -73,6 +70,7 @@ class IntegrationBase {
|
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
constructor(params) {
|
|
73
|
+
|
|
76
74
|
this.defaultEvents = {
|
|
77
75
|
[constantsToBeMigrated.defaultEvents.ON_CREATE]: {
|
|
78
76
|
type: constantsToBeMigrated.types.LIFE_CYCLE_EVENT,
|
|
@@ -107,7 +105,6 @@ class IntegrationBase {
|
|
|
107
105
|
handler: this.refreshActionOptions,
|
|
108
106
|
},
|
|
109
107
|
};
|
|
110
|
-
this.loadModules();
|
|
111
108
|
}
|
|
112
109
|
|
|
113
110
|
async send(event, object) {
|
|
@@ -121,7 +118,7 @@ class IntegrationBase {
|
|
|
121
118
|
|
|
122
119
|
async validateConfig() {
|
|
123
120
|
const configOptions = await this.getConfigOptions();
|
|
124
|
-
const currentConfig = this.
|
|
121
|
+
const currentConfig = this.getConfig();
|
|
125
122
|
let needsConfig = false;
|
|
126
123
|
for (const option of configOptions) {
|
|
127
124
|
if (option.required) {
|
|
@@ -133,17 +130,18 @@ class IntegrationBase {
|
|
|
133
130
|
)
|
|
134
131
|
) {
|
|
135
132
|
needsConfig = true;
|
|
136
|
-
this.
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
133
|
+
await this.updateIntegrationMessages.execute(
|
|
134
|
+
this.id,
|
|
135
|
+
'warnings',
|
|
136
|
+
'Config Validation Error',
|
|
137
|
+
`Missing required field of ${option.label}`,
|
|
138
|
+
Date.now()
|
|
139
|
+
);
|
|
141
140
|
}
|
|
142
141
|
}
|
|
143
142
|
}
|
|
144
143
|
if (needsConfig) {
|
|
145
|
-
this.
|
|
146
|
-
await this.record.save();
|
|
144
|
+
await this.updateIntegrationStatus.execute(this.id, 'NEEDS_CONFIG');
|
|
147
145
|
}
|
|
148
146
|
}
|
|
149
147
|
|
|
@@ -155,34 +153,36 @@ class IntegrationBase {
|
|
|
155
153
|
await this[module].testAuth();
|
|
156
154
|
} catch {
|
|
157
155
|
didAuthPass = false;
|
|
158
|
-
this.
|
|
159
|
-
|
|
160
|
-
|
|
156
|
+
await this.updateIntegrationMessages.execute(
|
|
157
|
+
this.id,
|
|
158
|
+
'errors',
|
|
159
|
+
'Authentication Error',
|
|
160
|
+
`There was an error with your ${this[
|
|
161
161
|
module
|
|
162
162
|
].constructor.getName()} Entity.
|
|
163
163
|
Please reconnect/re-authenticate, or reach out to Support for assistance.`,
|
|
164
|
-
|
|
165
|
-
|
|
164
|
+
Date.now()
|
|
165
|
+
);
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
if (!didAuthPass) {
|
|
170
|
-
this.
|
|
171
|
-
this.record.markModified('messages.error');
|
|
172
|
-
await this.record.save();
|
|
170
|
+
await this.updateIntegrationStatus.execute(this.id, 'ERROR');
|
|
173
171
|
}
|
|
174
172
|
}
|
|
175
173
|
|
|
176
174
|
async getMapping(sourceId) {
|
|
177
|
-
|
|
175
|
+
// todo: this should be a use case
|
|
176
|
+
return IntegrationMapping.findBy(this.id, sourceId);
|
|
178
177
|
}
|
|
179
178
|
|
|
180
179
|
async upsertMapping(sourceId, mapping) {
|
|
181
180
|
if (!sourceId) {
|
|
182
181
|
throw new Error(`sourceId must be set`);
|
|
183
182
|
}
|
|
183
|
+
// todo: this should be a use case
|
|
184
184
|
return await IntegrationMapping.upsert(
|
|
185
|
-
this.
|
|
185
|
+
this.id,
|
|
186
186
|
sourceId,
|
|
187
187
|
mapping
|
|
188
188
|
);
|
|
@@ -191,15 +191,13 @@ class IntegrationBase {
|
|
|
191
191
|
/**
|
|
192
192
|
* CHILDREN CAN OVERRIDE THESE CONFIGURATION METHODS
|
|
193
193
|
*/
|
|
194
|
-
async onCreate(
|
|
195
|
-
this.
|
|
196
|
-
await this.record.save();
|
|
197
|
-
return this.record;
|
|
194
|
+
async onCreate({ integrationId }) {
|
|
195
|
+
await this.updateIntegrationStatus.execute(integrationId, 'ENABLED');
|
|
198
196
|
}
|
|
199
197
|
|
|
200
|
-
async onUpdate(params) {}
|
|
198
|
+
async onUpdate(params) { }
|
|
201
199
|
|
|
202
|
-
async onDelete(params) {}
|
|
200
|
+
async onDelete(params) { }
|
|
203
201
|
|
|
204
202
|
async getConfigOptions() {
|
|
205
203
|
const options = {
|
|
@@ -236,10 +234,10 @@ class IntegrationBase {
|
|
|
236
234
|
const dynamicUserActions = await this.loadDynamicUserActions();
|
|
237
235
|
const filteredDynamicActions = actionType
|
|
238
236
|
? Object.fromEntries(
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
237
|
+
Object.entries(dynamicUserActions).filter(
|
|
238
|
+
([_, event]) => event.userActionType === actionType
|
|
239
|
+
)
|
|
240
|
+
)
|
|
243
241
|
: dynamicUserActions;
|
|
244
242
|
return { ...userActions, ...filteredDynamicActions };
|
|
245
243
|
}
|