diff --git a/apps/console/src/pages/organizations/settings/WebhooksSettingsPage.tsx b/apps/console/src/pages/organizations/settings/WebhooksSettingsPage.tsx index 623f1b1f1..5f79f9119 100644 --- a/apps/console/src/pages/organizations/settings/WebhooksSettingsPage.tsx +++ b/apps/console/src/pages/organizations/settings/WebhooksSettingsPage.tsx @@ -170,6 +170,9 @@ const EVENT_TYPES = [ { value: "OBLIGATION_CREATED", label: "obligation:created" }, { value: "OBLIGATION_UPDATED", label: "obligation:updated" }, { value: "OBLIGATION_DELETED", label: "obligation:deleted" }, + { value: "RIGHT_REQUEST_CREATED", label: "right-request:created" }, + { value: "RIGHT_REQUEST_UPDATED", label: "right-request:updated" }, + { value: "RIGHT_REQUEST_DELETED", label: "right-request:deleted" }, { value: "DOCUMENT_CREATED", label: "document:created" }, { value: "DOCUMENT_UPDATED", label: "document:updated" }, { value: "DOCUMENT_ARCHIVED", label: "document:archived" }, diff --git a/packages/n8n-node/nodes/Probo/actions/webhook/events.ts b/packages/n8n-node/nodes/Probo/actions/webhook/events.ts index 27cfccc41..412a7aa35 100644 --- a/packages/n8n-node/nodes/Probo/actions/webhook/events.ts +++ b/packages/n8n-node/nodes/Probo/actions/webhook/events.ts @@ -42,6 +42,9 @@ export const WEBHOOK_EVENT_OPTIONS: INodePropertyOptions[] = [ { name: 'Obligation Created', value: 'OBLIGATION_CREATED' }, { name: 'Obligation Deleted', value: 'OBLIGATION_DELETED' }, { name: 'Obligation Updated', value: 'OBLIGATION_UPDATED' }, + { name: 'Right Request Created', value: 'RIGHT_REQUEST_CREATED' }, + { name: 'Right Request Deleted', value: 'RIGHT_REQUEST_DELETED' }, + { name: 'Right Request Updated', value: 'RIGHT_REQUEST_UPDATED' }, { name: 'Third Party Created', value: 'THIRD_PARTY_CREATED' }, { name: 'Third Party Deleted', value: 'THIRD_PARTY_DELETED' }, { name: 'Third Party Updated', value: 'THIRD_PARTY_UPDATED' }, diff --git a/pkg/cmd/webhook/shared/events.go b/pkg/cmd/webhook/shared/events.go index 814c2c4ac..ab1b46742 100644 --- a/pkg/cmd/webhook/shared/events.go +++ b/pkg/cmd/webhook/shared/events.go @@ -33,6 +33,9 @@ var ValidEvents = []string{ "OBLIGATION_CREATED", "OBLIGATION_UPDATED", "OBLIGATION_DELETED", + "RIGHT_REQUEST_CREATED", + "RIGHT_REQUEST_UPDATED", + "RIGHT_REQUEST_DELETED", "DOCUMENT_CREATED", "DOCUMENT_UPDATED", "DOCUMENT_ARCHIVED", diff --git a/pkg/coredata/migrations/20260721T075032Z.sql b/pkg/coredata/migrations/20260721T075032Z.sql new file mode 100644 index 000000000..a4a95f27e --- /dev/null +++ b/pkg/coredata/migrations/20260721T075032Z.sql @@ -0,0 +1,23 @@ +-- Copyright (c) 2026 Probo Inc . +-- +-- Permission is hereby granted, free of charge, to any person obtaining a copy +-- of this software and associated documentation files (the "Software"), to deal +-- in the Software without restriction, including without limitation the rights +-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +-- copies of the Software, and to permit persons to whom the Software is +-- furnished to do so, subject to the following conditions: +-- +-- The above copyright notice and this permission notice shall be included in +-- all copies or substantial portions of the Software. +-- +-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +-- SOFTWARE. + +ALTER TYPE webhook_event_type ADD VALUE 'right-request:created'; +ALTER TYPE webhook_event_type ADD VALUE 'right-request:updated'; +ALTER TYPE webhook_event_type ADD VALUE 'right-request:deleted'; diff --git a/pkg/coredata/webhook_event_type.go b/pkg/coredata/webhook_event_type.go index c99ed7132..79ac026db 100644 --- a/pkg/coredata/webhook_event_type.go +++ b/pkg/coredata/webhook_event_type.go @@ -30,15 +30,18 @@ import ( type WebhookEventType string const ( - WebhookEventTypeThirdPartyCreated WebhookEventType = "third-party:created" - WebhookEventTypeThirdPartyUpdated WebhookEventType = "third-party:updated" - WebhookEventTypeThirdPartyDeleted WebhookEventType = "third-party:deleted" - WebhookEventTypeUserCreated WebhookEventType = "user:created" - WebhookEventTypeUserUpdated WebhookEventType = "user:updated" - WebhookEventTypeUserDeleted WebhookEventType = "user:deleted" - WebhookEventTypeObligationCreated WebhookEventType = "obligation:created" - WebhookEventTypeObligationUpdated WebhookEventType = "obligation:updated" - WebhookEventTypeObligationDeleted WebhookEventType = "obligation:deleted" + WebhookEventTypeThirdPartyCreated WebhookEventType = "third-party:created" + WebhookEventTypeThirdPartyUpdated WebhookEventType = "third-party:updated" + WebhookEventTypeThirdPartyDeleted WebhookEventType = "third-party:deleted" + WebhookEventTypeUserCreated WebhookEventType = "user:created" + WebhookEventTypeUserUpdated WebhookEventType = "user:updated" + WebhookEventTypeUserDeleted WebhookEventType = "user:deleted" + WebhookEventTypeObligationCreated WebhookEventType = "obligation:created" + WebhookEventTypeObligationUpdated WebhookEventType = "obligation:updated" + WebhookEventTypeObligationDeleted WebhookEventType = "obligation:deleted" + WebhookEventTypeRightRequestCreated WebhookEventType = "right-request:created" + WebhookEventTypeRightRequestUpdated WebhookEventType = "right-request:updated" + WebhookEventTypeRightRequestDeleted WebhookEventType = "right-request:deleted" WebhookEventTypeDocumentCreated WebhookEventType = "document:created" WebhookEventTypeDocumentUpdated WebhookEventType = "document:updated" @@ -81,6 +84,9 @@ func (v WebhookEventType) IsValid() bool { WebhookEventTypeObligationCreated, WebhookEventTypeObligationUpdated, WebhookEventTypeObligationDeleted, + WebhookEventTypeRightRequestCreated, + WebhookEventTypeRightRequestUpdated, + WebhookEventTypeRightRequestDeleted, WebhookEventTypeDocumentCreated, WebhookEventTypeDocumentUpdated, WebhookEventTypeDocumentArchived, diff --git a/pkg/probo/rights_request_service.go b/pkg/probo/rights_request_service.go index 3b42f8a67..2439fc28a 100644 --- a/pkg/probo/rights_request_service.go +++ b/pkg/probo/rights_request_service.go @@ -30,6 +30,8 @@ import ( "go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/validator" + "go.probo.inc/probo/pkg/webhook" + webhooktypes "go.probo.inc/probo/pkg/webhook/types" ) type RightsRequestService struct { @@ -147,6 +149,17 @@ func (s *RightsRequestService) Create( return fmt.Errorf("cannot insert rights request: %w", err) } + if err := webhook.InsertData( + ctx, + conn, + scope, + request.OrganizationID, + coredata.WebhookEventTypeRightRequestCreated, + webhooktypes.NewRightsRequest(request), + ); err != nil { + return fmt.Errorf("cannot insert webhook event: %w", err) + } + return nil }, ) @@ -174,6 +187,8 @@ func (s *RightsRequestService) Update( return fmt.Errorf("cannot load rights request: %w", err) } + previousRequest := webhooktypes.NewRightsRequest(request) + if req.RequestType != nil { request.RequestType = *req.RequestType } @@ -208,6 +223,18 @@ func (s *RightsRequestService) Update( return fmt.Errorf("cannot update rights request: %w", err) } + if err := webhook.InsertUpdateData( + ctx, + conn, + scope, + request.OrganizationID, + coredata.WebhookEventTypeRightRequestUpdated, + webhooktypes.NewRightsRequest(request), + previousRequest, + ); err != nil { + return fmt.Errorf("cannot insert webhook event: %w", err) + } + return nil }, ) @@ -230,6 +257,17 @@ func (s *RightsRequestService) Delete( return fmt.Errorf("cannot load rights request: %w", err) } + if err := webhook.InsertData( + ctx, + conn, + scope, + request.OrganizationID, + coredata.WebhookEventTypeRightRequestDeleted, + webhooktypes.NewRightsRequest(request), + ); err != nil { + return fmt.Errorf("cannot insert webhook event: %w", err) + } + if err := request.Delete(ctx, conn, scope); err != nil { return fmt.Errorf("cannot delete rights request: %w", err) } diff --git a/pkg/probo/rights_request_service_test.go b/pkg/probo/rights_request_service_test.go new file mode 100644 index 000000000..aa6fdd5a2 --- /dev/null +++ b/pkg/probo/rights_request_service_test.go @@ -0,0 +1,224 @@ +// Copyright (c) 2026 Probo Inc . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package probo + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.gearno.de/kit/pg" + "go.probo.inc/probo/internal/test" + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/gid" + webhooktypes "go.probo.inc/probo/pkg/webhook/types" +) + +func TestRightsRequestService_WebhookLifecycle(t *testing.T) { + t.Parallel() + + client := test.PGClient(t) + organizationID := insertRightsRequestWebhookOrganization(t, client) + scope := coredata.NewScope(organizationID.TenantID()) + insertRightsRequestWebhookSubscription(t, client, scope, organizationID) + + service := RightsRequestService{svc: &Service{pg: client}} + requestType := coredata.RightsRequestTypeAccess + requestState := coredata.RightsRequestStateTodo + dataSubject := "Jane Doe" + contact := "jane@example.com" + + rightsRequest, err := service.Create( + t.Context(), + scope, + &CreateRightsRequestRequest{ + OrganizationID: organizationID, + RequestType: &requestType, + RequestState: &requestState, + DataSubject: &dataSubject, + Contact: &contact, + }, + ) + require.NoError(t, err) + + created, createdFrom := loadRightsRequestWebhookData( + t, + client, + organizationID, + coredata.WebhookEventTypeRightRequestCreated, + ) + assert.Equal(t, rightsRequest.ID, created.ID) + assert.Equal(t, dataSubject, *created.DataSubject) + assert.Nil(t, createdFrom) + + updatedState := coredata.RightsRequestStateInProgress + updatedSubject := "Jane Smith" + rightsRequest, err = service.Update( + t.Context(), + scope, + &UpdateRightsRequestRequest{ + ID: rightsRequest.ID, + RequestState: &updatedState, + DataSubject: new(&updatedSubject), + }, + ) + require.NoError(t, err) + + updated, updatedFrom := loadRightsRequestWebhookData( + t, + client, + organizationID, + coredata.WebhookEventTypeRightRequestUpdated, + ) + require.NotNil(t, updatedFrom) + assert.Equal(t, updatedState, updated.RequestState) + assert.Equal(t, updatedSubject, *updated.DataSubject) + assert.Equal(t, requestState, updatedFrom.RequestState) + assert.Equal(t, dataSubject, *updatedFrom.DataSubject) + + err = service.Delete(t.Context(), scope, rightsRequest.ID) + require.NoError(t, err) + + deleted, deletedFrom := loadRightsRequestWebhookData( + t, + client, + organizationID, + coredata.WebhookEventTypeRightRequestDeleted, + ) + assert.Equal(t, rightsRequest.ID, deleted.ID) + assert.Equal(t, updatedState, deleted.RequestState) + assert.Nil(t, deletedFrom) +} + +func insertRightsRequestWebhookOrganization(t *testing.T, client *pg.Client) gid.GID { + t.Helper() + + tenantID := gid.NewTenantID() + organizationID := gid.New(tenantID, coredata.OrganizationEntityType) + now := time.Now() + + err := client.WithConn( + t.Context(), + func(ctx context.Context, conn pg.Querier) error { + _, err := conn.Exec( + ctx, + `INSERT INTO organizations (id, tenant_id, name, created_at, updated_at) VALUES ($1, $2, $3, $4, $5)`, + organizationID.String(), + tenantID.String(), + "right-request-webhook-"+organizationID.String(), + now, + now, + ) + + return err + }, + ) + require.NoError(t, err) + + t.Cleanup(func() { + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + + _ = client.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + _, err := conn.Exec(ctx, "DELETE FROM organizations WHERE id = $1", organizationID.String()) + return err + }, + ) + }) + + return organizationID +} + +func insertRightsRequestWebhookSubscription( + t *testing.T, + client *pg.Client, + scope coredata.Scoper, + organizationID gid.GID, +) { + t.Helper() + + now := time.Now() + subscription := coredata.WebhookSubscription{ + ID: gid.New(organizationID.TenantID(), coredata.WebhookSubscriptionEntityType), + OrganizationID: organizationID, + EndpointURL: "https://example.test/webhook", + SelectedEvents: coredata.WebhookEventTypes{ + coredata.WebhookEventTypeRightRequestCreated, + coredata.WebhookEventTypeRightRequestUpdated, + coredata.WebhookEventTypeRightRequestDeleted, + }, + EncryptedSigningSecret: []byte("test-signing-secret"), + CreatedAt: now, + UpdatedAt: now, + } + + err := client.WithTx( + t.Context(), + func(ctx context.Context, tx pg.Tx) error { + return subscription.Insert(ctx, tx, scope) + }, + ) + require.NoError(t, err) +} + +func loadRightsRequestWebhookData( + t *testing.T, + client *pg.Client, + organizationID gid.GID, + eventType coredata.WebhookEventType, +) (*webhooktypes.RightsRequest, *webhooktypes.RightsRequest) { + t.Helper() + + var ( + data []byte + updatedFrom []byte + ) + + err := client.WithConn( + t.Context(), + func(ctx context.Context, conn pg.Querier) error { + return conn.QueryRow( + ctx, + `SELECT data, updated_from FROM webhook_data WHERE organization_id = $1 AND event_type = $2`, + organizationID.String(), + eventType.String(), + ).Scan(&data, &updatedFrom) + }, + ) + require.NoError(t, err) + + current := &webhooktypes.RightsRequest{} + require.NoError(t, json.Unmarshal(data, current)) + + if updatedFrom == nil { + return current, nil + } + + previous := &webhooktypes.RightsRequest{} + require.NoError(t, json.Unmarshal(updatedFrom, previous)) + + return current, previous +} diff --git a/pkg/server/api/console/v1/graphql/webhook.graphql b/pkg/server/api/console/v1/graphql/webhook.graphql index 00a09c06b..1152577d1 100644 --- a/pkg/server/api/console/v1/graphql/webhook.graphql +++ b/pkg/server/api/console/v1/graphql/webhook.graphql @@ -18,6 +18,12 @@ enum WebhookEventType @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationUpdated") OBLIGATION_DELETED @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationDeleted") + RIGHT_REQUEST_CREATED + @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeRightRequestCreated") + RIGHT_REQUEST_UPDATED + @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeRightRequestUpdated") + RIGHT_REQUEST_DELETED + @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeRightRequestDeleted") DOCUMENT_CREATED @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeDocumentCreated") DOCUMENT_UPDATED diff --git a/pkg/server/api/mcp/v1/specification.yaml b/pkg/server/api/mcp/v1/specification.yaml index e5b66b509..48f008a06 100644 --- a/pkg/server/api/mcp/v1/specification.yaml +++ b/pkg/server/api/mcp/v1/specification.yaml @@ -6577,6 +6577,9 @@ components: - "obligation:created" - "obligation:updated" - "obligation:deleted" + - "right-request:created" + - "right-request:updated" + - "right-request:deleted" go.probo.inc/mcpgen/type: go.probo.inc/probo/pkg/coredata.WebhookEventType WebhookEventStatus: diff --git a/pkg/trust/rights_request_service.go b/pkg/trust/rights_request_service.go index d9acd66d7..9c2b5741f 100644 --- a/pkg/trust/rights_request_service.go +++ b/pkg/trust/rights_request_service.go @@ -31,6 +31,8 @@ import ( "go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/probo" "go.probo.inc/probo/pkg/validator" + "go.probo.inc/probo/pkg/webhook" + webhooktypes "go.probo.inc/probo/pkg/webhook/types" ) // RightsRequestDeadlineDays is the number of days a portal-submitted data @@ -104,6 +106,17 @@ func (s *RightsRequestService) Create( return fmt.Errorf("cannot insert rights request: %w", err) } + if err := webhook.InsertData( + ctx, + tx, + scope, + request.OrganizationID, + coredata.WebhookEventTypeRightRequestCreated, + webhooktypes.NewRightsRequest(request), + ); err != nil { + return fmt.Errorf("cannot insert webhook event: %w", err) + } + return nil }, ) diff --git a/pkg/trust/rights_request_service_test.go b/pkg/trust/rights_request_service_test.go new file mode 100644 index 000000000..34e5d45c8 --- /dev/null +++ b/pkg/trust/rights_request_service_test.go @@ -0,0 +1,152 @@ +// Copyright (c) 2026 Probo Inc . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package trust + +import ( + "context" + "encoding/json" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "go.gearno.de/kit/pg" + "go.probo.inc/probo/internal/test" + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/gid" + webhooktypes "go.probo.inc/probo/pkg/webhook/types" +) + +func TestRightsRequestService_CreateEnqueuesWebhook(t *testing.T) { + t.Parallel() + + client := test.PGClient(t) + organizationID := insertPortalRequestWebhookOrganization(t, client) + scope := coredata.NewScope(organizationID.TenantID()) + insertPortalRequestWebhookSubscription(t, client, scope, organizationID) + + service := RightsRequestService{svc: &Service{pg: client}} + dataSubject := "Jane Doe" + contact := "jane@example.com" + rightsRequest, err := service.Create( + t.Context(), + scope, + &CreateRightsRequest{ + OrganizationID: organizationID, + RequestType: coredata.RightsRequestTypeAccess, + DataSubject: &dataSubject, + Contact: contact, + }, + ) + require.NoError(t, err) + + var data []byte + + err = client.WithConn( + t.Context(), + func(ctx context.Context, conn pg.Querier) error { + return conn.QueryRow( + ctx, + `SELECT data FROM webhook_data WHERE organization_id = $1 AND event_type = $2`, + organizationID.String(), + coredata.WebhookEventTypeRightRequestCreated.String(), + ).Scan(&data) + }, + ) + require.NoError(t, err) + + payload := &webhooktypes.RightsRequest{} + require.NoError(t, json.Unmarshal(data, payload)) + assert.Equal(t, rightsRequest.ID, payload.ID) + assert.Equal(t, coredata.RightsRequestStateTodo, payload.RequestState) + assert.Equal(t, dataSubject, *payload.DataSubject) + assert.Equal(t, contact, *payload.Contact) + assert.NotNil(t, payload.Deadline) +} + +func insertPortalRequestWebhookOrganization(t *testing.T, client *pg.Client) gid.GID { + t.Helper() + + tenantID := gid.NewTenantID() + organizationID := gid.New(tenantID, coredata.OrganizationEntityType) + now := time.Now() + + err := client.WithConn( + t.Context(), + func(ctx context.Context, conn pg.Querier) error { + _, err := conn.Exec( + ctx, + `INSERT INTO organizations (id, tenant_id, name, created_at, updated_at) VALUES ($1, $2, $3, $4, $5)`, + organizationID.String(), + tenantID.String(), + "portal-request-webhook-"+organizationID.String(), + now, + now, + ) + + return err + }, + ) + require.NoError(t, err) + + t.Cleanup(func() { + ctx, cancel := context.WithTimeout(t.Context(), 5*time.Second) + defer cancel() + + _ = client.WithConn( + ctx, + func(ctx context.Context, conn pg.Querier) error { + _, err := conn.Exec(ctx, "DELETE FROM organizations WHERE id = $1", organizationID.String()) + return err + }, + ) + }) + + return organizationID +} + +func insertPortalRequestWebhookSubscription( + t *testing.T, + client *pg.Client, + scope coredata.Scoper, + organizationID gid.GID, +) { + t.Helper() + + now := time.Now() + subscription := coredata.WebhookSubscription{ + ID: gid.New(organizationID.TenantID(), coredata.WebhookSubscriptionEntityType), + OrganizationID: organizationID, + EndpointURL: "https://example.test/webhook", + SelectedEvents: coredata.WebhookEventTypes{coredata.WebhookEventTypeRightRequestCreated}, + EncryptedSigningSecret: []byte("test-signing-secret"), + CreatedAt: now, + UpdatedAt: now, + } + + err := client.WithTx( + t.Context(), + func(ctx context.Context, tx pg.Tx) error { + return subscription.Insert(ctx, tx, scope) + }, + ) + require.NoError(t, err) +} diff --git a/pkg/webhook/types/rights_request.go b/pkg/webhook/types/rights_request.go new file mode 100644 index 000000000..ad4e67fe2 --- /dev/null +++ b/pkg/webhook/types/rights_request.go @@ -0,0 +1,58 @@ +// Copyright (c) 2026 Probo Inc . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +package types + +import ( + "time" + + "go.probo.inc/probo/pkg/coredata" + "go.probo.inc/probo/pkg/gid" +) + +type RightsRequest struct { + ID gid.GID `json:"id"` + OrganizationID gid.GID `json:"organizationId"` + RequestType coredata.RightsRequestType `json:"requestType"` + RequestState coredata.RightsRequestState `json:"requestState"` + DataSubject *string `json:"dataSubject"` + Contact *string `json:"contact"` + Details *string `json:"details"` + Deadline *time.Time `json:"deadline"` + ActionTaken *string `json:"actionTaken"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` +} + +func NewRightsRequest(r *coredata.RightsRequest) *RightsRequest { + return &RightsRequest{ + ID: r.ID, + OrganizationID: r.OrganizationID, + RequestType: r.RequestType, + RequestState: r.RequestState, + DataSubject: r.DataSubject, + Contact: r.Contact, + Details: r.Details, + Deadline: r.Deadline, + ActionTaken: r.ActionTaken, + CreatedAt: r.CreatedAt, + UpdatedAt: r.UpdatedAt, + } +}