@friggframework/core 2.0.0--canary.684.0da024b.0 → 2.0.0--canary.679.a2bcc2f.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/CLAUDE.md +0 -2
- package/README.md +0 -105
- package/application/commands/integration-commands.js +2 -2
- package/application/commands/user-commands.js +5 -17
- package/credential/use-cases/credential-operations-for-user.js +25 -110
- package/credential/use-cases/reauthorize-credential-for-user.js +8 -15
- package/database/documentdb-utils.js +1 -6
- package/generated/prisma-mongodb/edge.js +4 -15
- package/generated/prisma-mongodb/index-browser.js +1 -12
- package/generated/prisma-mongodb/index.d.ts +86 -2027
- package/generated/prisma-mongodb/index.js +4 -15
- package/generated/prisma-mongodb/package.json +1 -1
- package/generated/prisma-mongodb/schema.prisma +0 -47
- package/generated/prisma-mongodb/wasm.js +4 -15
- package/generated/prisma-postgresql/edge.js +4 -15
- package/generated/prisma-postgresql/index-browser.js +1 -12
- package/generated/prisma-postgresql/index.d.ts +63 -2162
- package/generated/prisma-postgresql/index.js +4 -15
- package/generated/prisma-postgresql/package.json +1 -1
- package/generated/prisma-postgresql/schema.prisma +0 -44
- package/generated/prisma-postgresql/wasm.js +4 -15
- package/handlers/app-definition-loader.js +1 -15
- package/index.js +0 -18
- package/integrations/integration-router.js +73 -115
- package/integrations/repositories/integration-repository-documentdb.js +3 -35
- package/integrations/repositories/integration-repository-interface.js +1 -17
- package/integrations/repositories/integration-repository-mongo.js +76 -59
- package/integrations/repositories/integration-repository-postgres.js +76 -62
- package/integrations/tests/doubles/test-integration-repository.js +1 -12
- package/integrations/use-cases/create-integration.js +20 -55
- package/integrations/use-cases/get-integrations-for-user.js +40 -80
- package/integrations/use-cases/index.js +1 -5
- package/integrations/use-cases/integration-operations-for-user.js +24 -55
- package/management-api/management-api-config.js +0 -3
- package/management-api/openapi/components.js +0 -40
- package/management-api/openapi/v2-operations.js +1 -13
- package/management-api/v2/dependencies.js +15 -40
- package/management-api/v2/dto.js +0 -20
- package/management-api/v2/handlers/authorization.js +0 -1
- package/management-api/v2/handlers/credentials.js +2 -6
- package/management-api/v2/handlers/entities.js +7 -10
- package/management-api/v2/handlers/integrations.js +3 -6
- package/management-api/v2/request.js +1 -32
- package/modules/index.js +0 -8
- package/modules/repositories/module-repository-documentdb.js +4 -48
- package/modules/repositories/module-repository-interface.js +2 -19
- package/modules/repositories/module-repository-mongo.js +73 -65
- package/modules/repositories/module-repository-postgres.js +73 -64
- package/modules/use-cases/entity-operations-for-user.js +13 -50
- package/modules/use-cases/entity-types.js +7 -31
- package/modules/use-cases/execute-entity-proxy-request.js +0 -15
- package/modules/use-cases/get-entities-for-user.js +5 -16
- package/modules/use-cases/get-entity-module-for-user.js +3 -23
- package/modules/use-cases/get-entity-options-by-id.js +3 -9
- package/modules/use-cases/get-module.js +3 -9
- package/modules/use-cases/multi-step-authorization.js +12 -39
- package/modules/use-cases/process-authorization-callback.js +18 -52
- package/modules/use-cases/refresh-entity-options.js +3 -9
- package/modules/use-cases/test-module-auth.js +3 -9
- package/package.json +5 -6
- package/prisma-mongodb/schema.prisma +0 -47
- package/prisma-postgresql/schema.prisma +0 -44
- package/types/index.d.ts +0 -1
- package/types/modules/index.d.ts +0 -87
- package/user/repositories/user-repository-documentdb.js +2 -27
- package/user/repositories/user-repository-interface.js +0 -18
- package/user/repositories/user-repository-mongo.js +0 -24
- package/user/repositories/user-repository-postgres.js +0 -18
- package/user/use-cases/authenticate-user.js +1 -7
- package/user/use-cases/get-user-from-adopter-jwt.js +124 -95
- package/user/use-cases/get-user-from-x-frigg-headers.js +80 -83
- package/user/user.js +1 -64
- package/database/organization-where.js +0 -18
- package/database/unique-violation.js +0 -25
- package/integrations/repositories/integration-not-found.js +0 -14
- package/integrations/use-cases/resolve-integration-ownership.js +0 -177
- package/modules/entity-scope.js +0 -15
- package/modules/scope-config.js +0 -192
- package/modules/scope-policy.js +0 -112
- package/modules/scope-resolution.js +0 -288
- package/modules/scope-visibility.js +0 -239
- package/modules/tests/doubles/ownership-matching.js +0 -18
- package/modules/use-cases/authorize-entity-for-user.js +0 -61
- package/modules/use-cases/create-entity-from-credential.js +0 -113
- package/modules/use-cases/manage-access.js +0 -21
- package/prisma-postgresql/migrations/20261015000000_add_organization_membership/migration.sql +0 -26
- package/prisma-postgresql/migrations/20261016000000_add_entity_integration_organization/migration.sql +0 -25
- package/types/user/index.d.ts +0 -134
- package/user/adopter-jwt-config.js +0 -177
- package/user/adopter-jwt-errors.js +0 -59
- package/user/adopter-token-verifier.js +0 -122
- package/user/app-user-helpers.js +0 -97
- package/user/create-user-authentication.js +0 -64
- package/user/membership.js +0 -51
- package/user/repositories/organization-membership-record.js +0 -19
- package/user/repositories/organization-membership-repository-documentdb.js +0 -106
- package/user/repositories/organization-membership-repository-factory.js +0 -42
- package/user/repositories/organization-membership-repository-interface.js +0 -57
- package/user/repositories/organization-membership-repository-mongo.js +0 -13
- package/user/repositories/organization-membership-repository-postgres.js +0 -29
- package/user/repositories/organization-membership-repository-prisma.js +0 -81
- package/user/tests/doubles/adopter-jwt-fixtures.js +0 -220
- package/user/use-cases/ensure-organization-membership.js +0 -92
- package/user/use-cases/find-individual-users-by-organization.js +0 -54
|
@@ -51,27 +51,22 @@ const {
|
|
|
51
51
|
const {
|
|
52
52
|
createUserRepository,
|
|
53
53
|
} = require('../user/repositories/user-repository-factory');
|
|
54
|
+
const {
|
|
55
|
+
GetUserFromBearerToken,
|
|
56
|
+
} = require('../user/use-cases/get-user-from-bearer-token');
|
|
57
|
+
const {
|
|
58
|
+
GetUserFromXFriggHeaders,
|
|
59
|
+
} = require('../user/use-cases/get-user-from-x-frigg-headers');
|
|
60
|
+
const {
|
|
61
|
+
GetUserFromAdopterJwt,
|
|
62
|
+
} = require('../user/use-cases/get-user-from-adopter-jwt');
|
|
54
63
|
const {
|
|
55
64
|
AuthenticateWithSharedSecret,
|
|
56
65
|
} = require('../user/use-cases/authenticate-with-shared-secret');
|
|
57
66
|
const { AuthenticateUser } = require('../user/use-cases/authenticate-user');
|
|
58
|
-
const {
|
|
59
|
-
buildUserAuthentication,
|
|
60
|
-
} = require('../user/create-user-authentication');
|
|
61
67
|
const {
|
|
62
68
|
ProcessAuthorizationCallback,
|
|
63
69
|
} = require('../modules/use-cases/process-authorization-callback');
|
|
64
|
-
const { createScopePolicy } = require('../modules/scope-policy');
|
|
65
|
-
const {
|
|
66
|
-
AuthorizeEntityForUser,
|
|
67
|
-
} = require('../modules/use-cases/authorize-entity-for-user');
|
|
68
|
-
const {
|
|
69
|
-
CreateEntityFromCredential,
|
|
70
|
-
} = require('../modules/use-cases/create-entity-from-credential');
|
|
71
|
-
const {
|
|
72
|
-
ResolveIntegrationOwnership,
|
|
73
|
-
} = require('./use-cases/resolve-integration-ownership');
|
|
74
|
-
const { GetOwnedIntegrationRecord } = require('./use-cases/integration-operations-for-user');
|
|
75
70
|
|
|
76
71
|
const log = getLogger('frigg.integrations');
|
|
77
72
|
|
|
@@ -82,20 +77,26 @@ function createIntegrationRouter() {
|
|
|
82
77
|
integrations: integrationClasses,
|
|
83
78
|
userConfig,
|
|
84
79
|
moduleDefinitions,
|
|
85
|
-
ownership,
|
|
86
|
-
entityTypeRegistry,
|
|
87
80
|
} = loadAppDefinition();
|
|
88
|
-
// Ownership by scope (ADR-056 §3): one object every use case asks.
|
|
89
|
-
const scopePolicy = createScopePolicy({ ownership, entityTypeRegistry });
|
|
90
81
|
const moduleRepository = createModuleRepository();
|
|
91
82
|
const integrationRepository = createIntegrationRepository();
|
|
92
83
|
const credentialRepository = createCredentialRepository();
|
|
93
84
|
const userRepository = createUserRepository();
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
85
|
+
|
|
86
|
+
const getUserFromBearerToken = new GetUserFromBearerToken({
|
|
87
|
+
userRepository,
|
|
88
|
+
userConfig,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const getUserFromXFriggHeaders = new GetUserFromXFriggHeaders({
|
|
92
|
+
userRepository,
|
|
93
|
+
userConfig,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const getUserFromAdopterJwt = new GetUserFromAdopterJwt({
|
|
97
|
+
userRepository,
|
|
98
|
+
userConfig,
|
|
99
|
+
});
|
|
99
100
|
|
|
100
101
|
const authenticateWithSharedSecret = new AuthenticateWithSharedSecret();
|
|
101
102
|
|
|
@@ -122,19 +123,6 @@ function createIntegrationRouter() {
|
|
|
122
123
|
integrationClasses,
|
|
123
124
|
moduleFactory,
|
|
124
125
|
moduleRepository,
|
|
125
|
-
scopePolicy,
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
// Decides who owns a new integration and which entities the caller may bind
|
|
129
|
-
// (the v1 create used to check neither), and who may reach an existing one.
|
|
130
|
-
const resolveIntegrationOwnership = new ResolveIntegrationOwnership({
|
|
131
|
-
moduleRepository,
|
|
132
|
-
integrationClasses,
|
|
133
|
-
scopePolicy,
|
|
134
|
-
});
|
|
135
|
-
const getOwnedIntegrationRecord = new GetOwnedIntegrationRecord({
|
|
136
|
-
integrationRepository,
|
|
137
|
-
scopePolicy,
|
|
138
126
|
});
|
|
139
127
|
|
|
140
128
|
const getCredentialForUser = new GetCredentialForUser({
|
|
@@ -150,7 +138,6 @@ function createIntegrationRouter() {
|
|
|
150
138
|
const getEntitiesForUser = new GetEntitiesForUser({
|
|
151
139
|
moduleRepository,
|
|
152
140
|
moduleDefinitions,
|
|
153
|
-
scopePolicy,
|
|
154
141
|
});
|
|
155
142
|
|
|
156
143
|
const getIntegrationInstance = new GetIntegrationInstance({
|
|
@@ -176,55 +163,37 @@ function createIntegrationRouter() {
|
|
|
176
163
|
const testModuleAuth = new TestModuleAuth({
|
|
177
164
|
moduleRepository,
|
|
178
165
|
moduleDefinitions,
|
|
179
|
-
scopePolicy,
|
|
180
166
|
});
|
|
181
167
|
|
|
182
168
|
const getModule = new GetModule({
|
|
183
169
|
moduleRepository,
|
|
184
170
|
moduleDefinitions,
|
|
185
|
-
scopePolicy,
|
|
186
171
|
});
|
|
187
172
|
|
|
188
173
|
const getEntityOptionsById = new GetEntityOptionsById({
|
|
189
174
|
moduleRepository,
|
|
190
175
|
moduleDefinitions,
|
|
191
|
-
scopePolicy,
|
|
192
176
|
});
|
|
193
177
|
|
|
194
178
|
const refreshEntityOptions = new RefreshEntityOptions({
|
|
195
179
|
moduleRepository,
|
|
196
180
|
moduleDefinitions,
|
|
197
|
-
scopePolicy,
|
|
198
181
|
});
|
|
199
182
|
|
|
200
183
|
const getPossibleIntegrations = new GetPossibleIntegrations({
|
|
201
184
|
integrationClasses,
|
|
202
185
|
});
|
|
203
186
|
|
|
204
|
-
// The owner of what an authorization creates follows its scope (ADR-056 §3.2).
|
|
205
187
|
const processAuthorizationCallback = new ProcessAuthorizationCallback({
|
|
206
188
|
moduleRepository,
|
|
207
189
|
credentialRepository,
|
|
208
190
|
integrationRepository,
|
|
209
191
|
moduleDefinitions,
|
|
210
192
|
});
|
|
211
|
-
const authorizeEntityForUser = new AuthorizeEntityForUser({
|
|
212
|
-
scopePolicy,
|
|
213
|
-
processAuthorizationCallback,
|
|
214
|
-
});
|
|
215
|
-
// v1 POST /api/entity: same owner resolution as /api/authorize.
|
|
216
|
-
const createEntityFromCredential = new CreateEntityFromCredential({
|
|
217
|
-
authorizeEntityForUser,
|
|
218
|
-
processAuthorizationCallback,
|
|
219
|
-
credentialRepository,
|
|
220
|
-
moduleDefinitions,
|
|
221
|
-
});
|
|
222
193
|
|
|
223
194
|
const router = express();
|
|
224
195
|
|
|
225
196
|
setIntegrationRoutes(router, authenticateUser, {
|
|
226
|
-
resolveIntegrationOwnership,
|
|
227
|
-
getOwnedIntegrationRecord,
|
|
228
197
|
createIntegration,
|
|
229
198
|
deleteIntegrationForUser,
|
|
230
199
|
getIntegrationsForUser,
|
|
@@ -241,8 +210,7 @@ function createIntegrationRouter() {
|
|
|
241
210
|
getModule,
|
|
242
211
|
getEntityOptionsById,
|
|
243
212
|
refreshEntityOptions,
|
|
244
|
-
|
|
245
|
-
createEntityFromCredential,
|
|
213
|
+
processAuthorizationCallback,
|
|
246
214
|
});
|
|
247
215
|
return router;
|
|
248
216
|
}
|
|
@@ -279,8 +247,6 @@ function checkRequiredParams(params, requiredKeys) {
|
|
|
279
247
|
*/
|
|
280
248
|
function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
281
249
|
const {
|
|
282
|
-
resolveIntegrationOwnership,
|
|
283
|
-
getOwnedIntegrationRecord,
|
|
284
250
|
createIntegration,
|
|
285
251
|
deleteIntegrationForUser,
|
|
286
252
|
getIntegrationsForUser,
|
|
@@ -289,22 +255,15 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
289
255
|
updateIntegration,
|
|
290
256
|
getPossibleIntegrations,
|
|
291
257
|
} = useCases;
|
|
292
|
-
|
|
293
|
-
// The owner of an integration the caller may reach (404 otherwise), which is
|
|
294
|
-
// what the id-and-owner use cases below expect. `manage: true` is for
|
|
295
|
-
// changing or deleting: an organization's integration needs an admin (403).
|
|
296
|
-
const ownerOf = async (integrationId, user, options) =>
|
|
297
|
-
(await getOwnedIntegrationRecord.execute(integrationId, user, options))
|
|
298
|
-
.userId;
|
|
299
|
-
|
|
300
258
|
router.route('/api/integrations').get(
|
|
301
259
|
catchAsyncError(async (req, res) => {
|
|
302
260
|
const user = await authenticateUser.execute(req);
|
|
303
|
-
const
|
|
261
|
+
const userId = user.getId();
|
|
262
|
+
const integrations = await getIntegrationsForUser.execute(userId);
|
|
304
263
|
const results = {
|
|
305
264
|
entities: {
|
|
306
265
|
options: await getPossibleIntegrations.execute(),
|
|
307
|
-
authorized: await getEntitiesForUser.execute(
|
|
266
|
+
authorized: await getEntitiesForUser.execute(userId),
|
|
308
267
|
},
|
|
309
268
|
integrations: integrations,
|
|
310
269
|
};
|
|
@@ -316,6 +275,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
316
275
|
router.route('/api/integrations').post(
|
|
317
276
|
catchAsyncError(async (req, res) => {
|
|
318
277
|
const user = await authenticateUser.execute(req);
|
|
278
|
+
const userId = user.getId();
|
|
319
279
|
const params = checkRequiredParams(req.body, [
|
|
320
280
|
'entities',
|
|
321
281
|
'config',
|
|
@@ -323,17 +283,10 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
323
283
|
|
|
324
284
|
get(params.config, 'type');
|
|
325
285
|
|
|
326
|
-
const { ownerId, organizationId, adoptUnscoped } =
|
|
327
|
-
await resolveIntegrationOwnership.execute({
|
|
328
|
-
entityIds: params.entities,
|
|
329
|
-
config: params.config,
|
|
330
|
-
user,
|
|
331
|
-
});
|
|
332
286
|
const integration = await createIntegration.execute(
|
|
333
287
|
params.entities,
|
|
334
|
-
|
|
335
|
-
params.config
|
|
336
|
-
{ organizationId, adoptUnscoped }
|
|
288
|
+
userId,
|
|
289
|
+
params.config
|
|
337
290
|
);
|
|
338
291
|
|
|
339
292
|
res.status(201).json(integration);
|
|
@@ -343,11 +296,12 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
343
296
|
router.route('/api/integrations/:integrationId').patch(
|
|
344
297
|
catchAsyncError(async (req, res) => {
|
|
345
298
|
const user = await authenticateUser.execute(req);
|
|
299
|
+
const userId = user.getId();
|
|
346
300
|
const params = checkRequiredParams(req.body, ['config']);
|
|
347
301
|
|
|
348
302
|
const integration = await updateIntegration.execute(
|
|
349
303
|
req.params.integrationId,
|
|
350
|
-
|
|
304
|
+
userId,
|
|
351
305
|
params.config
|
|
352
306
|
);
|
|
353
307
|
res.json(integration);
|
|
@@ -360,7 +314,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
360
314
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
361
315
|
await deleteIntegrationForUser.execute(
|
|
362
316
|
params.integrationId,
|
|
363
|
-
|
|
317
|
+
user.getId()
|
|
364
318
|
);
|
|
365
319
|
res.status(204).json({});
|
|
366
320
|
})
|
|
@@ -372,7 +326,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
372
326
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
373
327
|
const integration = await getIntegrationInstance.execute(
|
|
374
328
|
params.integrationId,
|
|
375
|
-
|
|
329
|
+
user.getId()
|
|
376
330
|
);
|
|
377
331
|
res.json(await integration.send('GET_CONFIG_OPTIONS'));
|
|
378
332
|
})
|
|
@@ -388,7 +342,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
388
342
|
]);
|
|
389
343
|
const integration = await getIntegrationInstance.execute(
|
|
390
344
|
params.integrationId,
|
|
391
|
-
|
|
345
|
+
user.getId()
|
|
392
346
|
);
|
|
393
347
|
|
|
394
348
|
res.json(
|
|
@@ -402,7 +356,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
402
356
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
403
357
|
const integration = await getIntegrationInstance.execute(
|
|
404
358
|
params.integrationId,
|
|
405
|
-
|
|
359
|
+
user.getId()
|
|
406
360
|
);
|
|
407
361
|
res.json(await integration.send('GET_USER_ACTIONS', req.body));
|
|
408
362
|
})
|
|
@@ -419,7 +373,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
419
373
|
]);
|
|
420
374
|
const integration = await getIntegrationInstance.execute(
|
|
421
375
|
params.integrationId,
|
|
422
|
-
|
|
376
|
+
user.getId()
|
|
423
377
|
);
|
|
424
378
|
|
|
425
379
|
res.json(
|
|
@@ -444,7 +398,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
444
398
|
]);
|
|
445
399
|
const integration = await getIntegrationInstance.execute(
|
|
446
400
|
params.integrationId,
|
|
447
|
-
|
|
401
|
+
user.getId()
|
|
448
402
|
);
|
|
449
403
|
|
|
450
404
|
res.json(
|
|
@@ -465,7 +419,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
465
419
|
]);
|
|
466
420
|
const integration = await getIntegrationInstance.execute(
|
|
467
421
|
params.integrationId,
|
|
468
|
-
|
|
422
|
+
user.getId()
|
|
469
423
|
);
|
|
470
424
|
res.json(await integration.send(params.actionId, req.body));
|
|
471
425
|
})
|
|
@@ -482,7 +436,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
482
436
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
483
437
|
const integration = await getIntegrationInstance.execute(
|
|
484
438
|
params.integrationId,
|
|
485
|
-
|
|
439
|
+
user.getId()
|
|
486
440
|
);
|
|
487
441
|
|
|
488
442
|
// We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
|
|
@@ -502,7 +456,7 @@ function setIntegrationRoutes(router, authenticateUser, useCases) {
|
|
|
502
456
|
const params = checkRequiredParams(req.params, ['integrationId']);
|
|
503
457
|
const instance = await getIntegrationInstance.execute(
|
|
504
458
|
params.integrationId,
|
|
505
|
-
|
|
459
|
+
user.getId()
|
|
506
460
|
);
|
|
507
461
|
|
|
508
462
|
if (!instance) {
|
|
@@ -540,21 +494,16 @@ function setEntityRoutes(router, authenticateUser, useCases) {
|
|
|
540
494
|
getModule,
|
|
541
495
|
getEntityOptionsById,
|
|
542
496
|
refreshEntityOptions,
|
|
543
|
-
|
|
544
|
-
createEntityFromCredential,
|
|
497
|
+
processAuthorizationCallback,
|
|
545
498
|
} = useCases;
|
|
546
499
|
|
|
547
500
|
router.route('/api/authorize').get(
|
|
548
501
|
catchAsyncError(async (req, res) => {
|
|
549
502
|
const user = await authenticateUser.execute(req);
|
|
503
|
+
const userId = user.getId();
|
|
550
504
|
const params = checkRequiredParams(req.query, ['entityType']);
|
|
551
|
-
// The owner POST stores under, so GET and POST describe one connection.
|
|
552
|
-
const { ownerId } = authorizeEntityForUser.resolveOwnership({
|
|
553
|
-
user,
|
|
554
|
-
entityType: params.entityType,
|
|
555
|
-
});
|
|
556
505
|
const module = await getModuleInstanceFromType.execute(
|
|
557
|
-
|
|
506
|
+
userId,
|
|
558
507
|
params.entityType,
|
|
559
508
|
{ state: req.query.state }
|
|
560
509
|
);
|
|
@@ -573,15 +522,11 @@ function setEntityRoutes(router, authenticateUser, useCases) {
|
|
|
573
522
|
router.route('/api/authorize').post(
|
|
574
523
|
catchAsyncError(async (req, res) => {
|
|
575
524
|
const user = await authenticateUser.execute(req);
|
|
525
|
+
const userId = user.getId();
|
|
576
526
|
const params = checkRequiredParams(req.body, [
|
|
577
527
|
'entityType',
|
|
578
528
|
'data',
|
|
579
529
|
]);
|
|
580
|
-
const ownership = authorizeEntityForUser.resolveOwnership({
|
|
581
|
-
user,
|
|
582
|
-
entityType: params.entityType,
|
|
583
|
-
});
|
|
584
|
-
const userId = ownership.ownerId;
|
|
585
530
|
|
|
586
531
|
const dataKeys =
|
|
587
532
|
params.data && typeof params.data === 'object'
|
|
@@ -593,13 +538,11 @@ function setEntityRoutes(router, authenticateUser, useCases) {
|
|
|
593
538
|
dataKeys,
|
|
594
539
|
});
|
|
595
540
|
|
|
596
|
-
const
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
ownership,
|
|
602
|
-
});
|
|
541
|
+
const entityDetails = await processAuthorizationCallback.execute(
|
|
542
|
+
userId,
|
|
543
|
+
params.entityType,
|
|
544
|
+
params.data
|
|
545
|
+
);
|
|
603
546
|
|
|
604
547
|
log.info('Entity authorized', {
|
|
605
548
|
eventName: 'frigg.integrations.authorized',
|
|
@@ -616,20 +559,35 @@ function setEntityRoutes(router, authenticateUser, useCases) {
|
|
|
616
559
|
router.route('/api/entity').post(
|
|
617
560
|
catchAsyncError(async (req, res) => {
|
|
618
561
|
const user = await authenticateUser.execute(req);
|
|
562
|
+
const userId = user.getId();
|
|
619
563
|
const params = checkRequiredParams(req.body, [
|
|
620
564
|
'entityType',
|
|
621
565
|
'data',
|
|
622
566
|
]);
|
|
623
567
|
checkRequiredParams(req.body.data, ['credential_id']);
|
|
624
568
|
|
|
625
|
-
//
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
569
|
+
// May want to pass along the user ID as well so credential ID's can't be fished???
|
|
570
|
+
const credential = await getCredentialForUser.execute(
|
|
571
|
+
params.data.credential_id,
|
|
572
|
+
userId
|
|
573
|
+
);
|
|
574
|
+
|
|
575
|
+
if (!credential) {
|
|
576
|
+
throw Boom.badRequest('Invalid credential ID');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
const module = await getModuleInstanceFromType.execute(
|
|
580
|
+
userId,
|
|
581
|
+
params.entityType
|
|
582
|
+
);
|
|
583
|
+
const entityDetails = await module.getEntityDetails(
|
|
584
|
+
module.api,
|
|
585
|
+
null,
|
|
586
|
+
null,
|
|
587
|
+
userId
|
|
632
588
|
);
|
|
589
|
+
|
|
590
|
+
res.json(await module.findOrCreateEntity(entityDetails));
|
|
633
591
|
})
|
|
634
592
|
);
|
|
635
593
|
|
|
@@ -14,7 +14,6 @@ const {
|
|
|
14
14
|
IntegrationRepositoryInterface,
|
|
15
15
|
} = require('./integration-repository-interface');
|
|
16
16
|
const { validateConfigPatch } = require('./config-patch-shared');
|
|
17
|
-
const { integrationNotFoundError } = require('./integration-not-found');
|
|
18
17
|
|
|
19
18
|
class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
20
19
|
constructor() {
|
|
@@ -29,28 +28,6 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
29
28
|
return records.map((doc) => this._mapIntegration(doc));
|
|
30
29
|
}
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* Find integrations matching any of the owner/organization pairs, in one
|
|
34
|
-
* query. `organizationId: null` matches rows with no organization (a raw
|
|
35
|
-
* MongoDB `null` also matches a missing field). The caller (a use case)
|
|
36
|
-
* decides which pairs; this only runs them.
|
|
37
|
-
*
|
|
38
|
-
* @param {Array<{userId: string, organizationId: (string|null)}>} clauses
|
|
39
|
-
* @returns {Promise<Array>}
|
|
40
|
-
*/
|
|
41
|
-
async findIntegrationsByOwnership(clauses) {
|
|
42
|
-
if (!Array.isArray(clauses) || clauses.length === 0) return [];
|
|
43
|
-
// Drained: a list can hold more than the first cursor batch (~101).
|
|
44
|
-
const records = await findManyDrained(this.prisma, 'Integration', {
|
|
45
|
-
$or: clauses.map(({ userId, organizationId }) => ({
|
|
46
|
-
userId: toObjectId(userId),
|
|
47
|
-
organizationId:
|
|
48
|
-
organizationId === null ? null : toObjectId(organizationId),
|
|
49
|
-
})),
|
|
50
|
-
});
|
|
51
|
-
return records.map((doc) => this._mapIntegration(doc));
|
|
52
|
-
}
|
|
53
|
-
|
|
54
31
|
async findIntegrations({ type, status } = {}) {
|
|
55
32
|
const filter = {};
|
|
56
33
|
if (type) {
|
|
@@ -91,11 +68,11 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
91
68
|
async findIntegrationById(id) {
|
|
92
69
|
const objectId = toObjectId(id);
|
|
93
70
|
if (!objectId) {
|
|
94
|
-
throw
|
|
71
|
+
throw new Error(`Integration with id ${id} not found`);
|
|
95
72
|
}
|
|
96
73
|
const doc = await findOne(this.prisma, 'Integration', { _id: objectId });
|
|
97
74
|
if (!doc) {
|
|
98
|
-
throw
|
|
75
|
+
throw new Error(`Integration with id ${id} not found`);
|
|
99
76
|
}
|
|
100
77
|
return this._mapIntegration(doc);
|
|
101
78
|
}
|
|
@@ -155,18 +132,10 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
155
132
|
return true;
|
|
156
133
|
}
|
|
157
134
|
|
|
158
|
-
|
|
159
|
-
* @param {Array<string>} entities - entity ids
|
|
160
|
-
* @param {string} userId - owner (the person, or the organization's user)
|
|
161
|
-
* @param {Object} config - Integration configuration
|
|
162
|
-
* @param {{organizationId?: (string|null)}} [tenancy] - the organization the
|
|
163
|
-
* integration is created in (ADR-056 §3.6)
|
|
164
|
-
*/
|
|
165
|
-
async createIntegration(entities, userId, config, tenancy = {}) {
|
|
135
|
+
async createIntegration(entities, userId, config) {
|
|
166
136
|
const now = new Date();
|
|
167
137
|
const document = {
|
|
168
138
|
userId: toObjectId(userId) || null,
|
|
169
|
-
organizationId: toObjectId(tenancy.organizationId) || null,
|
|
170
139
|
config,
|
|
171
140
|
version: '0.0.0',
|
|
172
141
|
status: 'IN_CREATION',
|
|
@@ -329,7 +298,6 @@ class IntegrationRepositoryDocumentDB extends IntegrationRepositoryInterface {
|
|
|
329
298
|
id: fromObjectId(doc?._id),
|
|
330
299
|
entitiesIds: (doc?.entityIds || []).map((value) => fromObjectId(value)),
|
|
331
300
|
userId: fromObjectId(doc?.userId),
|
|
332
|
-
organizationId: fromObjectId(doc?.organizationId) ?? null,
|
|
333
301
|
config: doc?.config ?? null,
|
|
334
302
|
version: doc?.version ?? null,
|
|
335
303
|
status: doc?.status ?? null,
|
|
@@ -10,20 +10,6 @@
|
|
|
10
10
|
* @abstract
|
|
11
11
|
*/
|
|
12
12
|
class IntegrationRepositoryInterface {
|
|
13
|
-
/**
|
|
14
|
-
* Find integrations matching any of the owner/organization pairs, in one
|
|
15
|
-
* query (ADR-056 §3.6). `organizationId: null` matches rows with no
|
|
16
|
-
* organization. Which pairs is decided by the caller
|
|
17
|
-
* (modules/entity-scope.js), not here.
|
|
18
|
-
*
|
|
19
|
-
* @param {Array<{userId: string|number, organizationId: (string|number|null)}>} clauses
|
|
20
|
-
* @returns {Promise<Array>} Array of integration objects
|
|
21
|
-
* @abstract
|
|
22
|
-
*/
|
|
23
|
-
async findIntegrationsByOwnership(clauses) {
|
|
24
|
-
throw new Error('Method findIntegrationsByOwnership must be implemented by subclass');
|
|
25
|
-
}
|
|
26
|
-
|
|
27
13
|
/**
|
|
28
14
|
* Find all integrations for a user
|
|
29
15
|
*
|
|
@@ -137,12 +123,10 @@ class IntegrationRepositoryInterface {
|
|
|
137
123
|
* @param {Array<string|number>} entities - Array of entity IDs
|
|
138
124
|
* @param {string|number} userId - User ID
|
|
139
125
|
* @param {Object} config - Integration configuration
|
|
140
|
-
* @param {{organizationId?: (string|number|null)}} [tenancy] - the organization the
|
|
141
|
-
* integration is created in (ADR-056 §3.6)
|
|
142
126
|
* @returns {Promise<Object>} Created integration object
|
|
143
127
|
* @abstract
|
|
144
128
|
*/
|
|
145
|
-
async createIntegration(entities, userId, config
|
|
129
|
+
async createIntegration(entities, userId, config) {
|
|
146
130
|
throw new Error('Method createIntegration must be implemented by subclass');
|
|
147
131
|
}
|
|
148
132
|
|