@contember/engine-actions 2.1.0-alpha.23 → 2.1.0-alpha.25
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/dist/development/src/ActionsExecutionContainerHookFactory.cjs +3 -3
- package/dist/development/src/ActionsExecutionContainerHookFactory.cjs.map +1 -1
- package/dist/development/src/ActionsExecutionContainerHookFactory.js +3 -3
- package/dist/development/src/ActionsExecutionContainerHookFactory.js.map +1 -1
- package/dist/development/src/dispatch/WebhookTargetHandler.cjs +3 -0
- package/dist/development/src/dispatch/WebhookTargetHandler.cjs.map +1 -1
- package/dist/development/src/dispatch/WebhookTargetHandler.js +3 -0
- package/dist/development/src/dispatch/WebhookTargetHandler.js.map +1 -1
- package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.cjs +4 -1
- package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.cjs.map +1 -1
- package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.js +4 -1
- package/dist/development/src/graphql/resolvers/query/EventsQueryResolver.js.map +1 -1
- package/dist/development/src/graphql/schema/actions.graphql.cjs +9 -6
- package/dist/development/src/graphql/schema/actions.graphql.cjs.map +1 -1
- package/dist/development/src/graphql/schema/actions.graphql.js +9 -6
- package/dist/development/src/graphql/schema/actions.graphql.js.map +1 -1
- package/dist/development/src/migrations/2025-05-28-160000-action-event-user.cjs +16 -0
- package/dist/development/src/migrations/2025-05-28-160000-action-event-user.cjs.map +1 -0
- package/dist/development/src/migrations/2025-05-28-160000-action-event-user.js +17 -0
- package/dist/development/src/migrations/2025-05-28-160000-action-event-user.js.map +1 -0
- package/dist/development/src/migrations/index.cjs +3 -1
- package/dist/development/src/migrations/index.cjs.map +1 -1
- package/dist/development/src/migrations/index.js +3 -1
- package/dist/development/src/migrations/index.js.map +1 -1
- package/dist/development/src/migrations/snapshot.cjs +5 -2
- package/dist/development/src/migrations/snapshot.cjs.map +1 -1
- package/dist/development/src/migrations/snapshot.js +5 -2
- package/dist/development/src/migrations/snapshot.js.map +1 -1
- package/dist/development/src/triggers/TriggerHandler.cjs +12 -11
- package/dist/development/src/triggers/TriggerHandler.cjs.map +1 -1
- package/dist/development/src/triggers/TriggerHandler.js +12 -11
- package/dist/development/src/triggers/TriggerHandler.js.map +1 -1
- package/dist/development/src/triggers/TriggerIndirectChangesFetcher.cjs +44 -2
- package/dist/development/src/triggers/TriggerIndirectChangesFetcher.cjs.map +1 -1
- package/dist/development/src/triggers/TriggerIndirectChangesFetcher.js +44 -2
- package/dist/development/src/triggers/TriggerIndirectChangesFetcher.js.map +1 -1
- package/dist/development/src/triggers/TriggerListenersStore.cjs.map +1 -1
- package/dist/development/src/triggers/TriggerListenersStore.js.map +1 -1
- package/dist/development/src/triggers/TriggerPayloadBuilder.cjs +20 -5
- package/dist/development/src/triggers/TriggerPayloadBuilder.cjs.map +1 -1
- package/dist/development/src/triggers/TriggerPayloadBuilder.js +20 -5
- package/dist/development/src/triggers/TriggerPayloadBuilder.js.map +1 -1
- package/dist/development/src/triggers/TriggerPayloadManager.cjs.map +1 -1
- package/dist/development/src/triggers/TriggerPayloadManager.js.map +1 -1
- package/dist/development/src/triggers/TriggerPayloadPersister.cjs +7 -2
- package/dist/development/src/triggers/TriggerPayloadPersister.cjs.map +1 -1
- package/dist/development/src/triggers/TriggerPayloadPersister.js +7 -2
- package/dist/development/src/triggers/TriggerPayloadPersister.js.map +1 -1
- package/dist/production/src/ActionsExecutionContainerHookFactory.cjs +3 -3
- package/dist/production/src/ActionsExecutionContainerHookFactory.cjs.map +1 -1
- package/dist/production/src/ActionsExecutionContainerHookFactory.js +3 -3
- package/dist/production/src/ActionsExecutionContainerHookFactory.js.map +1 -1
- package/dist/production/src/dispatch/WebhookTargetHandler.cjs +3 -0
- package/dist/production/src/dispatch/WebhookTargetHandler.cjs.map +1 -1
- package/dist/production/src/dispatch/WebhookTargetHandler.js +3 -0
- package/dist/production/src/dispatch/WebhookTargetHandler.js.map +1 -1
- package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.cjs +4 -1
- package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.cjs.map +1 -1
- package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.js +4 -1
- package/dist/production/src/graphql/resolvers/query/EventsQueryResolver.js.map +1 -1
- package/dist/production/src/graphql/schema/actions.graphql.cjs +9 -6
- package/dist/production/src/graphql/schema/actions.graphql.cjs.map +1 -1
- package/dist/production/src/graphql/schema/actions.graphql.js +9 -6
- package/dist/production/src/graphql/schema/actions.graphql.js.map +1 -1
- package/dist/production/src/migrations/2025-05-28-160000-action-event-user.cjs +16 -0
- package/dist/production/src/migrations/2025-05-28-160000-action-event-user.cjs.map +1 -0
- package/dist/production/src/migrations/2025-05-28-160000-action-event-user.js +17 -0
- package/dist/production/src/migrations/2025-05-28-160000-action-event-user.js.map +1 -0
- package/dist/production/src/migrations/index.cjs +3 -1
- package/dist/production/src/migrations/index.cjs.map +1 -1
- package/dist/production/src/migrations/index.js +3 -1
- package/dist/production/src/migrations/index.js.map +1 -1
- package/dist/production/src/migrations/snapshot.cjs +5 -2
- package/dist/production/src/migrations/snapshot.cjs.map +1 -1
- package/dist/production/src/migrations/snapshot.js +5 -2
- package/dist/production/src/migrations/snapshot.js.map +1 -1
- package/dist/production/src/triggers/TriggerHandler.cjs +12 -11
- package/dist/production/src/triggers/TriggerHandler.cjs.map +1 -1
- package/dist/production/src/triggers/TriggerHandler.js +12 -11
- package/dist/production/src/triggers/TriggerHandler.js.map +1 -1
- package/dist/production/src/triggers/TriggerIndirectChangesFetcher.cjs +44 -2
- package/dist/production/src/triggers/TriggerIndirectChangesFetcher.cjs.map +1 -1
- package/dist/production/src/triggers/TriggerIndirectChangesFetcher.js +44 -2
- package/dist/production/src/triggers/TriggerIndirectChangesFetcher.js.map +1 -1
- package/dist/production/src/triggers/TriggerListenersStore.cjs.map +1 -1
- package/dist/production/src/triggers/TriggerListenersStore.js.map +1 -1
- package/dist/production/src/triggers/TriggerPayloadBuilder.cjs +20 -5
- package/dist/production/src/triggers/TriggerPayloadBuilder.cjs.map +1 -1
- package/dist/production/src/triggers/TriggerPayloadBuilder.js +20 -5
- package/dist/production/src/triggers/TriggerPayloadBuilder.js.map +1 -1
- package/dist/production/src/triggers/TriggerPayloadManager.cjs.map +1 -1
- package/dist/production/src/triggers/TriggerPayloadManager.js.map +1 -1
- package/dist/production/src/triggers/TriggerPayloadPersister.cjs +7 -2
- package/dist/production/src/triggers/TriggerPayloadPersister.cjs.map +1 -1
- package/dist/production/src/triggers/TriggerPayloadPersister.js +7 -2
- package/dist/production/src/triggers/TriggerPayloadPersister.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/dispatch/WebhookTargetHandler.d.ts.map +1 -1
- package/dist/types/graphql/resolvers/query/EventsQueryResolver.d.ts.map +1 -1
- package/dist/types/graphql/schema/actions.graphql.d.ts.map +1 -1
- package/dist/types/graphql/schema/index.d.ts +6 -0
- package/dist/types/graphql/schema/index.d.ts.map +1 -1
- package/dist/types/migrations/2025-05-28-160000-action-event-user.d.ts +3 -0
- package/dist/types/migrations/2025-05-28-160000-action-event-user.d.ts.map +1 -0
- package/dist/types/migrations/index.d.ts.map +1 -1
- package/dist/types/migrations/snapshot.d.ts.map +1 -1
- package/dist/types/model/types.d.ts +3 -0
- package/dist/types/model/types.d.ts.map +1 -1
- package/dist/types/triggers/TriggerHandler.d.ts.map +1 -1
- package/dist/types/triggers/TriggerIndirectChangesFetcher.d.ts +11 -3
- package/dist/types/triggers/TriggerIndirectChangesFetcher.d.ts.map +1 -1
- package/dist/types/triggers/TriggerListenersStore.d.ts +2 -2
- package/dist/types/triggers/TriggerListenersStore.d.ts.map +1 -1
- package/dist/types/triggers/TriggerPayloadBuilder.d.ts.map +1 -1
- package/dist/types/triggers/TriggerPayloadManager.d.ts +2 -1
- package/dist/types/triggers/TriggerPayloadManager.d.ts.map +1 -1
- package/dist/types/triggers/TriggerPayloadPersister.d.ts +7 -2
- package/dist/types/triggers/TriggerPayloadPersister.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +15 -15
- package/src/ActionsExecutionContainerHookFactory.ts +3 -3
- package/src/dispatch/WebhookTargetHandler.ts +3 -0
- package/src/graphql/resolvers/query/EventsQueryResolver.ts +3 -0
- package/src/graphql/schema/actions.graphql.ts +9 -6
- package/src/graphql/schema/index.ts +6 -0
- package/src/migrations/2025-05-28-160000-action-event-user.ts +16 -0
- package/src/migrations/index.ts +2 -0
- package/src/migrations/snapshot.ts +5 -2
- package/src/model/types.ts +3 -0
- package/src/triggers/TriggerHandler.ts +12 -11
- package/src/triggers/TriggerIndirectChangesFetcher.ts +62 -3
- package/src/triggers/TriggerListenersStore.ts +2 -2
- package/src/triggers/TriggerPayloadBuilder.ts +18 -1
- package/src/triggers/TriggerPayloadManager.ts +2 -1
- package/src/triggers/TriggerPayloadPersister.ts +6 -1
- package/tests/cases/unit/generator.test.ts +1 -1
- package/tests/cases/unit/webhookHandler.test.ts +9 -0
package/package.json
CHANGED
|
@@ -22,20 +22,20 @@
|
|
|
22
22
|
}
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@contember/authorization": "2.1.0-alpha.
|
|
26
|
-
"@contember/database": "2.1.0-alpha.
|
|
27
|
-
"@contember/database-migrations": "2.1.0-alpha.
|
|
28
|
-
"@contember/engine-common": "2.1.0-alpha.
|
|
29
|
-
"@contember/engine-content-api": "2.1.0-alpha.
|
|
30
|
-
"@contember/engine-http": "2.1.0-alpha.
|
|
31
|
-
"@contember/engine-plugins": "2.1.0-alpha.
|
|
32
|
-
"@contember/engine-system-api": "2.1.0-alpha.
|
|
33
|
-
"@contember/engine-tenant-api": "2.1.0-alpha.
|
|
34
|
-
"@contember/graphql-utils": "2.1.0-alpha.
|
|
35
|
-
"@contember/logger": "2.1.0-alpha.
|
|
36
|
-
"@contember/schema": "2.1.0-alpha.
|
|
37
|
-
"@contember/schema-utils": "2.1.0-alpha.
|
|
38
|
-
"@contember/typesafe": "2.1.0-alpha.
|
|
25
|
+
"@contember/authorization": "2.1.0-alpha.25",
|
|
26
|
+
"@contember/database": "2.1.0-alpha.25",
|
|
27
|
+
"@contember/database-migrations": "2.1.0-alpha.25",
|
|
28
|
+
"@contember/engine-common": "2.1.0-alpha.25",
|
|
29
|
+
"@contember/engine-content-api": "2.1.0-alpha.25",
|
|
30
|
+
"@contember/engine-http": "2.1.0-alpha.25",
|
|
31
|
+
"@contember/engine-plugins": "2.1.0-alpha.25",
|
|
32
|
+
"@contember/engine-system-api": "2.1.0-alpha.25",
|
|
33
|
+
"@contember/engine-tenant-api": "2.1.0-alpha.25",
|
|
34
|
+
"@contember/graphql-utils": "2.1.0-alpha.25",
|
|
35
|
+
"@contember/logger": "2.1.0-alpha.25",
|
|
36
|
+
"@contember/schema": "2.1.0-alpha.25",
|
|
37
|
+
"@contember/schema-utils": "2.1.0-alpha.25",
|
|
38
|
+
"@contember/typesafe": "2.1.0-alpha.25",
|
|
39
39
|
"@graphql-tools/schema": "^10.0.7",
|
|
40
40
|
"graphql-tag": "^2.12.6"
|
|
41
41
|
},
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"pg": "^8.5.0"
|
|
50
50
|
},
|
|
51
51
|
"type": "module",
|
|
52
|
-
"version": "2.1.0-alpha.
|
|
52
|
+
"version": "2.1.0-alpha.25"
|
|
53
53
|
}
|
|
@@ -12,12 +12,12 @@ export class ActionsExecutionContainerHookFactory {
|
|
|
12
12
|
|
|
13
13
|
create(): ExecutionContainerHook {
|
|
14
14
|
return builder => {
|
|
15
|
-
return builder.setupService('mapperFactory', (mapperFactory, { whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta }) => {
|
|
15
|
+
return builder.setupService('mapperFactory', (mapperFactory, { whereBuilder, schema, pathFactory, systemSchema, providers, stage, project, schemaMeta, joinBuilder, userInfo }) => {
|
|
16
16
|
mapperFactory.hooks.push(mapper => {
|
|
17
|
-
const triggerPayloadPersister = new TriggerPayloadPersister(mapper, mapper.db.forSchema(systemSchema), providers, project.slug, stage.id, schemaMeta.id)
|
|
17
|
+
const triggerPayloadPersister = new TriggerPayloadPersister(mapper, mapper.db.forSchema(systemSchema), providers, project.slug, stage.id, schemaMeta.id, mapper.identityId, userInfo)
|
|
18
18
|
const triggerPayloadBuilder = new TriggerPayloadBuilder(mapper)
|
|
19
19
|
const payloadManager = new TriggerPayloadManager(triggerPayloadBuilder, triggerPayloadPersister)
|
|
20
|
-
const changesFetcher = new TriggerIndirectChangesFetcher(mapper, whereBuilder, pathFactory)
|
|
20
|
+
const changesFetcher = new TriggerIndirectChangesFetcher(schema.model, mapper, whereBuilder, joinBuilder, pathFactory)
|
|
21
21
|
const listenersStore = this.listenerStoreProvider.getListenerStore(schema)
|
|
22
22
|
const triggerHandler = new TriggerHandler(payloadManager, listenersStore, changesFetcher)
|
|
23
23
|
triggerHandler.attach(mapper.eventManager)
|
|
@@ -174,6 +174,9 @@ export class WebhookTargetHandler implements InvokeHandler<Actions.WebhookTarget
|
|
|
174
174
|
meta: {
|
|
175
175
|
eventId: it.id,
|
|
176
176
|
transactionId: it.transaction_id,
|
|
177
|
+
identityId: it.identity_id ?? null,
|
|
178
|
+
ipAddress: it.ip_address ?? null,
|
|
179
|
+
userAgent: it.user_agent ?? null,
|
|
177
180
|
createdAt: it.created_at.toISOString(),
|
|
178
181
|
lastStateChange: it.last_state_change.toISOString(),
|
|
179
182
|
numRetries: it.num_retries,
|
|
@@ -68,6 +68,9 @@ export class EventsQueryResolver implements QueryResolvers<ActionsContext> {
|
|
|
68
68
|
state: row.state,
|
|
69
69
|
target: row.target,
|
|
70
70
|
transactionId: row.transaction_id,
|
|
71
|
+
identityId: row.identity_id ?? undefined,
|
|
72
|
+
ipAddress: row.ip_address ?? undefined,
|
|
73
|
+
userAgent: row.user_agent ?? undefined,
|
|
71
74
|
}))
|
|
72
75
|
}
|
|
73
76
|
}
|
|
@@ -35,6 +35,9 @@ export const schema: DocumentNode = gql`
|
|
|
35
35
|
type Event {
|
|
36
36
|
id: Uuid!
|
|
37
37
|
transactionId: Uuid!
|
|
38
|
+
identityId: Uuid
|
|
39
|
+
ipAddress: String
|
|
40
|
+
userAgent: String
|
|
38
41
|
createdAt: DateTime!
|
|
39
42
|
lastStateChange: DateTime!
|
|
40
43
|
resolvedAt: DateTime
|
|
@@ -59,11 +62,11 @@ export const schema: DocumentNode = gql`
|
|
|
59
62
|
type ProcessBatchResponse {
|
|
60
63
|
ok: Boolean!
|
|
61
64
|
}
|
|
62
|
-
|
|
65
|
+
|
|
63
66
|
type RetryEventResponse {
|
|
64
67
|
ok: Boolean!
|
|
65
68
|
}
|
|
66
|
-
|
|
69
|
+
|
|
67
70
|
type StopEventResponse {
|
|
68
71
|
ok: Boolean!
|
|
69
72
|
}
|
|
@@ -72,12 +75,12 @@ export const schema: DocumentNode = gql`
|
|
|
72
75
|
variables: [VariableInput!]!
|
|
73
76
|
mode: SetVariablesMode
|
|
74
77
|
}
|
|
75
|
-
|
|
78
|
+
|
|
76
79
|
"""
|
|
77
|
-
Defines how it handles original variables.
|
|
80
|
+
Defines how it handles original variables.
|
|
78
81
|
- MERGE merges with new values (default behaviour)
|
|
79
82
|
- SET replaces all variables
|
|
80
|
-
- APPEND_ONLY_MISSING appends values if not already exist
|
|
83
|
+
- APPEND_ONLY_MISSING appends values if not already exist
|
|
81
84
|
"""
|
|
82
85
|
enum SetVariablesMode {
|
|
83
86
|
MERGE
|
|
@@ -89,7 +92,7 @@ export const schema: DocumentNode = gql`
|
|
|
89
92
|
name: String!
|
|
90
93
|
value: String!
|
|
91
94
|
}
|
|
92
|
-
|
|
95
|
+
|
|
93
96
|
type SetVariablesResponse {
|
|
94
97
|
ok: Boolean!
|
|
95
98
|
}
|
|
@@ -23,6 +23,8 @@ export type Event = {
|
|
|
23
23
|
readonly __typename?: 'Event'
|
|
24
24
|
readonly createdAt: Scalars['DateTime']['output']
|
|
25
25
|
readonly id: Scalars['Uuid']['output']
|
|
26
|
+
readonly identityId?: Maybe<Scalars['Uuid']['output']>
|
|
27
|
+
readonly ipAddress?: Maybe<Scalars['String']['output']>
|
|
26
28
|
readonly lastStateChange: Scalars['DateTime']['output']
|
|
27
29
|
readonly log: Scalars['Json']['output']
|
|
28
30
|
readonly numRetries: Scalars['Int']['output']
|
|
@@ -32,6 +34,7 @@ export type Event = {
|
|
|
32
34
|
readonly state: EventState
|
|
33
35
|
readonly target: Scalars['String']['output']
|
|
34
36
|
readonly transactionId: Scalars['Uuid']['output']
|
|
37
|
+
readonly userAgent?: Maybe<Scalars['String']['output']>
|
|
35
38
|
readonly visibleAt?: Maybe<Scalars['DateTime']['output']>
|
|
36
39
|
}
|
|
37
40
|
|
|
@@ -268,6 +271,8 @@ export interface DateTimeScalarConfig extends GraphQLScalarTypeConfig<ResolversT
|
|
|
268
271
|
export type EventResolvers<ContextType = any, ParentType extends ResolversParentTypes['Event'] = ResolversParentTypes['Event']> = {
|
|
269
272
|
createdAt?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>
|
|
270
273
|
id?: Resolver<ResolversTypes['Uuid'], ParentType, ContextType>
|
|
274
|
+
identityId?: Resolver<Maybe<ResolversTypes['Uuid']>, ParentType, ContextType>
|
|
275
|
+
ipAddress?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>
|
|
271
276
|
lastStateChange?: Resolver<ResolversTypes['DateTime'], ParentType, ContextType>
|
|
272
277
|
log?: Resolver<ResolversTypes['Json'], ParentType, ContextType>
|
|
273
278
|
numRetries?: Resolver<ResolversTypes['Int'], ParentType, ContextType>
|
|
@@ -277,6 +282,7 @@ export type EventResolvers<ContextType = any, ParentType extends ResolversParent
|
|
|
277
282
|
state?: Resolver<ResolversTypes['EventState'], ParentType, ContextType>
|
|
278
283
|
target?: Resolver<ResolversTypes['String'], ParentType, ContextType>
|
|
279
284
|
transactionId?: Resolver<ResolversTypes['Uuid'], ParentType, ContextType>
|
|
285
|
+
userAgent?: Resolver<Maybe<ResolversTypes['String']>, ParentType, ContextType>
|
|
280
286
|
visibleAt?: Resolver<Maybe<ResolversTypes['DateTime']>, ParentType, ContextType>
|
|
281
287
|
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>
|
|
282
288
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { MigrationBuilder } from '@contember/database-migrations'
|
|
2
|
+
|
|
3
|
+
const sql = `
|
|
4
|
+
ALTER TABLE actions_event
|
|
5
|
+
ADD COLUMN IF NOT EXISTS identity_id UUID DEFAULT NULL;
|
|
6
|
+
|
|
7
|
+
ALTER TABLE actions_event
|
|
8
|
+
ADD COLUMN IF NOT EXISTS ip_address INET DEFAULT NULL;
|
|
9
|
+
|
|
10
|
+
ALTER TABLE actions_event
|
|
11
|
+
ADD COLUMN IF NOT EXISTS user_agent TEXT DEFAULT NULL;
|
|
12
|
+
`
|
|
13
|
+
|
|
14
|
+
export default async function (builder: MigrationBuilder) {
|
|
15
|
+
builder.sql(sql)
|
|
16
|
+
}
|
package/src/migrations/index.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import snapshot from './snapshot'
|
|
2
2
|
import { MigrationGroup } from '@contember/database-migrations'
|
|
3
3
|
import _20230310145000actionsvariables from './2023-03-10-145000-actions-variables'
|
|
4
|
+
import _20250528160000actioneventuser from './2025-05-28-160000-action-event-user'
|
|
4
5
|
|
|
5
6
|
export const migrationsGroup = new MigrationGroup(snapshot, {
|
|
6
7
|
'2023-03-10-145000-actions-variables': _20230310145000actionsvariables,
|
|
8
|
+
'2025-05-28-160000-action-event-user': _20250528160000actioneventuser,
|
|
7
9
|
})
|
|
@@ -30,11 +30,14 @@ export default async function (builder: MigrationBuilder) {
|
|
|
30
30
|
trigger TEXT NOT NULL,
|
|
31
31
|
priority INT NOT NULL DEFAULT 0,
|
|
32
32
|
payload JSONB NOT NULL,
|
|
33
|
-
log JSONB NOT NULL DEFAULT '[]'
|
|
33
|
+
log JSONB NOT NULL DEFAULT '[]',
|
|
34
|
+
identity_id UUID DEFAULT NULL,
|
|
35
|
+
ip_address INET DEFAULT NULL,
|
|
36
|
+
user_agent TEXT DEFAULT NULL
|
|
34
37
|
);
|
|
35
38
|
|
|
36
39
|
CREATE INDEX ON actions_event (priority DESC, visible_at) WHERE state IN ('created', 'retrying', 'processing');
|
|
37
|
-
|
|
40
|
+
|
|
38
41
|
CREATE TABLE actions_variable
|
|
39
42
|
(
|
|
40
43
|
id UUID PRIMARY KEY NOT NULL,
|
package/src/model/types.ts
CHANGED
|
@@ -71,28 +71,28 @@ export class TriggerHandler {
|
|
|
71
71
|
|
|
72
72
|
private async directUpdateHandler(event: AfterUpdateEvent) {
|
|
73
73
|
const updateListeners = this.listenersStore.getUpdateListeners(event.entity.name)
|
|
74
|
-
updateListeners.map(listener => {
|
|
74
|
+
await Promise.all(updateListeners.map(listener => {
|
|
75
75
|
if (event.data.some(it => listener.fields.has(it.fieldName) && it.value !== it.old)) {
|
|
76
|
-
this.payloadManager.add({
|
|
76
|
+
return this.payloadManager.add({
|
|
77
77
|
listener,
|
|
78
78
|
entity: event.entity,
|
|
79
79
|
primary: event.id,
|
|
80
80
|
cause: event,
|
|
81
81
|
})
|
|
82
82
|
}
|
|
83
|
-
})
|
|
83
|
+
}))
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
private async directCreateHandler(event: AfterInsertEvent) {
|
|
87
87
|
const createListeners = this.listenersStore.getCreateListener(event.entity.name)
|
|
88
|
-
createListeners.map(listener => {
|
|
89
|
-
this.payloadManager.add({
|
|
88
|
+
await Promise.all(createListeners.map(listener => {
|
|
89
|
+
return this.payloadManager.add({
|
|
90
90
|
listener,
|
|
91
91
|
entity: event.entity,
|
|
92
92
|
primary: event.id,
|
|
93
93
|
cause: event,
|
|
94
94
|
})
|
|
95
|
-
})
|
|
95
|
+
}))
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
|
|
@@ -103,7 +103,7 @@ export class TriggerHandler {
|
|
|
103
103
|
private async indirectChangesEntityHandler(event: BeforeDeleteEvent | AfterInsertEvent) {
|
|
104
104
|
//
|
|
105
105
|
const indirectEntityListeners = this.listenersStore.getIndirectListeners(event.entity.name)
|
|
106
|
-
const promises =
|
|
106
|
+
const promises = indirectEntityListeners.map(listener => this.collectDeepChanges(event, listener, {
|
|
107
107
|
[event.entity.primary]: { eq: event.id },
|
|
108
108
|
}))
|
|
109
109
|
await Promise.all(promises)
|
|
@@ -149,13 +149,14 @@ export class TriggerHandler {
|
|
|
149
149
|
where: Input.Where,
|
|
150
150
|
) {
|
|
151
151
|
const result = await this.changesFetcher.fetch(listener, where)
|
|
152
|
-
|
|
153
|
-
this.payloadManager.add({
|
|
152
|
+
await Promise.all(result.map(row => {
|
|
153
|
+
return this.payloadManager.add({
|
|
154
154
|
listener,
|
|
155
155
|
entity: listener.rootEntity,
|
|
156
|
-
primary: row,
|
|
156
|
+
primary: row.id,
|
|
157
157
|
cause,
|
|
158
|
+
nodes: row.nodes,
|
|
158
159
|
})
|
|
159
|
-
}
|
|
160
|
+
}))
|
|
160
161
|
}
|
|
161
162
|
}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { Mapper, PathFactory, WhereBuilder } from '@contember/engine-content-api'
|
|
2
2
|
import { IndirectListener, JunctionListener } from './TriggerListenersStore'
|
|
3
3
|
import { SelectBuilder } from '@contember/database'
|
|
4
|
-
import { Input } from '@contember/schema'
|
|
4
|
+
import { ActionsPayload, Input, Model, Schema } from '@contember/schema'
|
|
5
|
+
import { JoinBuilder } from '@contember/engine-content-api'
|
|
6
|
+
import { getTargetEntity } from '@contember/schema-utils'
|
|
7
|
+
|
|
8
|
+
export type TriggerIndirectChangesFetcherResult = {
|
|
9
|
+
id: Input.PrimaryValue
|
|
10
|
+
nodes?: ActionsPayload.EntityEventPathNode[]
|
|
11
|
+
}[]
|
|
5
12
|
|
|
6
13
|
export class TriggerIndirectChangesFetcher {
|
|
7
14
|
constructor(
|
|
15
|
+
private readonly model: Model.Schema,
|
|
8
16
|
private readonly mapper: Mapper,
|
|
9
17
|
private readonly whereBuilder: WhereBuilder,
|
|
18
|
+
private readonly joinBuilder: JoinBuilder,
|
|
10
19
|
private readonly pathFactory: PathFactory,
|
|
11
20
|
) {
|
|
12
21
|
}
|
|
@@ -14,7 +23,11 @@ export class TriggerIndirectChangesFetcher {
|
|
|
14
23
|
public async fetch(
|
|
15
24
|
listener: IndirectListener | JunctionListener,
|
|
16
25
|
where: Input.Where,
|
|
17
|
-
): Promise<
|
|
26
|
+
): Promise<TriggerIndirectChangesFetcherResult> {
|
|
27
|
+
if (listener.trigger.withNodes) {
|
|
28
|
+
return this.fetchWithNodes(listener, where)
|
|
29
|
+
}
|
|
30
|
+
|
|
18
31
|
for (let i = listener.path.length - 1; i >= 0; i--) {
|
|
19
32
|
where = { [listener.path[i]]: where }
|
|
20
33
|
}
|
|
@@ -24,7 +37,53 @@ export class TriggerIndirectChangesFetcher {
|
|
|
24
37
|
const path = this.pathFactory.create([])
|
|
25
38
|
const qbWithWhere = this.whereBuilder.build(qb, listener.rootEntity, path, where)
|
|
26
39
|
|
|
27
|
-
return (await qbWithWhere.getResult(this.mapper.db))
|
|
40
|
+
return (await qbWithWhere.getResult(this.mapper.db))
|
|
28
41
|
}
|
|
29
42
|
|
|
43
|
+
private async fetchWithNodes(
|
|
44
|
+
listener: IndirectListener | JunctionListener,
|
|
45
|
+
where: Input.Where,
|
|
46
|
+
): Promise<TriggerIndirectChangesFetcherResult> {
|
|
47
|
+
const basePath = this.pathFactory.create([])
|
|
48
|
+
let path = basePath
|
|
49
|
+
let entity = listener.rootEntity
|
|
50
|
+
let qb = SelectBuilder.create()
|
|
51
|
+
.from(entity.tableName, path.alias)
|
|
52
|
+
.select([path.alias, entity.primaryColumn], path.for(entity.primary).alias)
|
|
53
|
+
|
|
54
|
+
for (let i = 0; i < listener.path.length; i++) {
|
|
55
|
+
const relationName = listener.path[i]
|
|
56
|
+
path = path.for(relationName)
|
|
57
|
+
const targetEntity = getTargetEntity(this.model, entity, relationName)
|
|
58
|
+
if (!targetEntity) {
|
|
59
|
+
throw new Error(`Target entity for relation ${entity.name}::${relationName} not found`)
|
|
60
|
+
}
|
|
61
|
+
qb = this.joinBuilder.join(qb, path, entity, relationName)
|
|
62
|
+
|
|
63
|
+
entity = targetEntity
|
|
64
|
+
qb = qb.select([path.alias, targetEntity.primaryColumn], path.for(targetEntity.primary).alias)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const qbWithWhere = this.whereBuilder.build(qb, entity, path, where)
|
|
68
|
+
|
|
69
|
+
const result = await qbWithWhere.getResult(this.mapper.db)
|
|
70
|
+
|
|
71
|
+
return result.map(row => {
|
|
72
|
+
const nodes: ActionsPayload.EntityEventPathNode[] = []
|
|
73
|
+
let entity = listener.rootEntity
|
|
74
|
+
let path = basePath
|
|
75
|
+
const id = row[path.for(entity.primary).alias]
|
|
76
|
+
for (let i = 0; i < listener.path.length; i++) {
|
|
77
|
+
const relationName = listener.path[i]
|
|
78
|
+
const targetEntity = getTargetEntity(this.model, entity, relationName)
|
|
79
|
+
if (!targetEntity) {
|
|
80
|
+
throw new Error(`Target entity for relation ${entity.name}::${relationName} not found`)
|
|
81
|
+
}
|
|
82
|
+
path = path.for(relationName)
|
|
83
|
+
nodes.push({ relation: relationName, entity: targetEntity.name, id: row[path.for(targetEntity.primary).alias] })
|
|
84
|
+
entity = targetEntity
|
|
85
|
+
}
|
|
86
|
+
return { id, nodes }
|
|
87
|
+
})
|
|
88
|
+
}
|
|
30
89
|
}
|
|
@@ -3,7 +3,7 @@ import { TriggerListeners } from './TriggerListeners'
|
|
|
3
3
|
|
|
4
4
|
export interface IndirectListener {
|
|
5
5
|
type: 'indirect'
|
|
6
|
-
trigger: Actions.
|
|
6
|
+
trigger: Actions.WatchTrigger
|
|
7
7
|
rootEntity: Model.Entity
|
|
8
8
|
fields: Set<string>
|
|
9
9
|
relations: Set<string>
|
|
@@ -12,7 +12,7 @@ export interface IndirectListener {
|
|
|
12
12
|
|
|
13
13
|
export interface JunctionListener {
|
|
14
14
|
type: 'junction'
|
|
15
|
-
trigger: Actions.
|
|
15
|
+
trigger: Actions.WatchTrigger
|
|
16
16
|
rootEntity: Model.Entity
|
|
17
17
|
path: string[]
|
|
18
18
|
context: {
|
|
@@ -51,6 +51,19 @@ export class TriggerPayloadBuilder {
|
|
|
51
51
|
}
|
|
52
52
|
const payloads: ActionsPayload.WatchEventPayload[] = []
|
|
53
53
|
for (const eventsByPrimary of Object.values(byPrimary)) {
|
|
54
|
+
const baseEvents: ActionsPayload.BaseEventPayload[] = []
|
|
55
|
+
|
|
56
|
+
const existingEvents = new Set<string>()
|
|
57
|
+
for (const event of eventsByPrimary.events) {
|
|
58
|
+
const baseEvent = this.buildBaseEventPayloads(event)
|
|
59
|
+
const stringRepresentation = JSON.stringify(baseEvent)
|
|
60
|
+
if (existingEvents.has(stringRepresentation)) {
|
|
61
|
+
continue
|
|
62
|
+
}
|
|
63
|
+
existingEvents.add(stringRepresentation)
|
|
64
|
+
baseEvents.push(baseEvent)
|
|
65
|
+
}
|
|
66
|
+
|
|
54
67
|
payloads.push({
|
|
55
68
|
operation: 'watch',
|
|
56
69
|
trigger: events[0].listener.trigger.name,
|
|
@@ -58,7 +71,7 @@ export class TriggerPayloadBuilder {
|
|
|
58
71
|
id: eventsByPrimary.primary,
|
|
59
72
|
selection: eventsByPrimary.events.find(it => it.selection)?.selection
|
|
60
73
|
?? selections[eventsByPrimary.primary],
|
|
61
|
-
events:
|
|
74
|
+
events: baseEvents,
|
|
62
75
|
})
|
|
63
76
|
}
|
|
64
77
|
return payloads
|
|
@@ -74,6 +87,7 @@ export class TriggerPayloadBuilder {
|
|
|
74
87
|
selection,
|
|
75
88
|
values: Object.fromEntries(event.cause.data.map(it => [it.fieldName, it.value])),
|
|
76
89
|
path: 'path' in event.listener ? event.listener.path : undefined,
|
|
90
|
+
nodes: event.nodes,
|
|
77
91
|
}
|
|
78
92
|
case 'AfterUpdateEvent':
|
|
79
93
|
case 'BeforeUpdateEvent':
|
|
@@ -89,6 +103,7 @@ export class TriggerPayloadBuilder {
|
|
|
89
103
|
values: Object.fromEntries(event.cause.data.map(it => [it.fieldName, it.value])),
|
|
90
104
|
path: 'path' in event.listener ? event.listener.path : undefined,
|
|
91
105
|
old: Object.fromEntries(afterEvent.data.map(it => [it.fieldName, it.old])),
|
|
106
|
+
nodes: event.nodes,
|
|
92
107
|
}
|
|
93
108
|
case 'BeforeDeleteEvent':
|
|
94
109
|
return {
|
|
@@ -97,6 +112,7 @@ export class TriggerPayloadBuilder {
|
|
|
97
112
|
id: event.cause.id,
|
|
98
113
|
selection,
|
|
99
114
|
path: 'path' in event.listener ? event.listener.path : undefined,
|
|
115
|
+
nodes: event.nodes,
|
|
100
116
|
}
|
|
101
117
|
case 'AfterJunctionUpdateEvent':
|
|
102
118
|
if (event.listener.type !== 'junction') {
|
|
@@ -112,6 +128,7 @@ export class TriggerPayloadBuilder {
|
|
|
112
128
|
id,
|
|
113
129
|
inverseId,
|
|
114
130
|
path: 'path' in event.listener ? event.listener.path : undefined,
|
|
131
|
+
nodes: event.nodes,
|
|
115
132
|
}
|
|
116
133
|
default:
|
|
117
134
|
assertNever(event.cause, it => it.type)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Actions, Input, Model } from '@contember/schema'
|
|
1
|
+
import { Actions, ActionsPayload, Input, Model } from '@contember/schema'
|
|
2
2
|
import { AnyListener } from './TriggerListenersStore'
|
|
3
3
|
import { EventCause } from './TriggerHandler'
|
|
4
4
|
import { TriggerPayloadBuilder } from './TriggerPayloadBuilder'
|
|
@@ -11,6 +11,7 @@ export interface FiredEvent {
|
|
|
11
11
|
entity: Model.Entity
|
|
12
12
|
primary: Input.PrimaryValue
|
|
13
13
|
selection?: any
|
|
14
|
+
nodes?: ActionsPayload.EntityEventPathNode[]
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
export class TriggerPayloadManager {
|
|
@@ -18,7 +18,9 @@ export class TriggerPayloadPersister {
|
|
|
18
18
|
private readonly providers: { uuid: () => string },
|
|
19
19
|
private readonly projectSlug: string,
|
|
20
20
|
private readonly stageId: string,
|
|
21
|
-
private readonly schemaId
|
|
21
|
+
private readonly schemaId: number | undefined,
|
|
22
|
+
private readonly identityId: string,
|
|
23
|
+
private readonly userInfo: { ipAddress: string | null; userAgent: string | null },
|
|
22
24
|
) {
|
|
23
25
|
}
|
|
24
26
|
|
|
@@ -46,6 +48,9 @@ export class TriggerPayloadPersister {
|
|
|
46
48
|
payload: it,
|
|
47
49
|
resolved_at: null,
|
|
48
50
|
last_state_change: 'now',
|
|
51
|
+
identity_id: this.identityId,
|
|
52
|
+
ip_address: this.userInfo.ipAddress,
|
|
53
|
+
user_agent: this.userInfo.userAgent,
|
|
49
54
|
})))
|
|
50
55
|
.execute(this.client)
|
|
51
56
|
}
|
|
@@ -8,7 +8,7 @@ const assert = {
|
|
|
8
8
|
equal: (a: any, b: any) => expect(a).toEqual(b),
|
|
9
9
|
deepStrictEqual: (a: any, b: any) => expect(a).toStrictEqual(b),
|
|
10
10
|
}
|
|
11
|
-
const createTrigger = (watchNode: Actions.SelectionNode): Actions.
|
|
11
|
+
const createTrigger = (watchNode: Actions.SelectionNode): Actions.WatchTrigger => ({
|
|
12
12
|
type: 'watch',
|
|
13
13
|
entity: 'Author',
|
|
14
14
|
name: 'author_trigger',
|
|
@@ -29,6 +29,9 @@ const createTestEvent = (i = 0, row: Partial<EventRow> = {}): EventRow => ({
|
|
|
29
29
|
priority: 1,
|
|
30
30
|
schema_id: 1,
|
|
31
31
|
state: 'created',
|
|
32
|
+
identity_id: testUuid(i * 10 + 4),
|
|
33
|
+
ip_address: '127.0.0.1',
|
|
34
|
+
user_agent: 'test-agent',
|
|
32
35
|
...row,
|
|
33
36
|
})
|
|
34
37
|
|
|
@@ -56,6 +59,9 @@ describe('webhook request', () => {
|
|
|
56
59
|
meta: {
|
|
57
60
|
eventId: testUuid(1),
|
|
58
61
|
transactionId: testUuid(2),
|
|
62
|
+
identityId: testUuid(4),
|
|
63
|
+
ipAddress: '127.0.0.1',
|
|
64
|
+
userAgent: 'test-agent',
|
|
59
65
|
createdAt: now.toISOString(),
|
|
60
66
|
lastStateChange: now.toISOString(),
|
|
61
67
|
numRetries: 0,
|
|
@@ -104,6 +110,9 @@ describe('webhook request', () => {
|
|
|
104
110
|
meta: {
|
|
105
111
|
eventId: testUuid(1),
|
|
106
112
|
transactionId: testUuid(2),
|
|
113
|
+
identityId: testUuid(4),
|
|
114
|
+
ipAddress: '127.0.0.1',
|
|
115
|
+
userAgent: 'test-agent',
|
|
107
116
|
createdAt: now.toISOString(),
|
|
108
117
|
lastStateChange: now.toISOString(),
|
|
109
118
|
numRetries: 0,
|