Add obligation webhooks

Signed-off-by: Sacha Al Himdani <sacha@getprobo.com>
This commit is contained in:
Sacha Al Himdani
2026-02-27 17:03:44 +01:00
parent 6905472fba
commit 6a83b53b47
11 changed files with 138 additions and 25 deletions

View File

@@ -9,7 +9,7 @@
// @ts-nocheck // @ts-nocheck
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "USER_CREATED" | "USER_DELETED" | "USER_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED"; export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "OBLIGATION_CREATED" | "OBLIGATION_DELETED" | "OBLIGATION_UPDATED" | "USER_CREATED" | "USER_DELETED" | "USER_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED";
export type WebhooksSettingsPageQuery$variables = { export type WebhooksSettingsPageQuery$variables = {
organizationId: string; organizationId: string;
}; };

View File

@@ -9,7 +9,7 @@
// @ts-nocheck // @ts-nocheck
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "USER_CREATED" | "USER_DELETED" | "USER_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED"; export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "OBLIGATION_CREATED" | "OBLIGATION_DELETED" | "OBLIGATION_UPDATED" | "USER_CREATED" | "USER_DELETED" | "USER_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED";
export type CreateWebhookSubscriptionInput = { export type CreateWebhookSubscriptionInput = {
endpointUrl: string; endpointUrl: string;
organizationId: string; organizationId: string;

View File

@@ -9,7 +9,7 @@
// @ts-nocheck // @ts-nocheck
import { ConcreteRequest } from 'relay-runtime'; import { ConcreteRequest } from 'relay-runtime';
export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "USER_CREATED" | "USER_DELETED" | "USER_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED"; export type WebhookEventType = "MEETING_CREATED" | "MEETING_DELETED" | "MEETING_UPDATED" | "OBLIGATION_CREATED" | "OBLIGATION_DELETED" | "OBLIGATION_UPDATED" | "USER_CREATED" | "USER_DELETED" | "USER_UPDATED" | "VENDOR_CREATED" | "VENDOR_DELETED" | "VENDOR_UPDATED";
export type UpdateWebhookSubscriptionInput = { export type UpdateWebhookSubscriptionInput = {
endpointUrl?: string | null | undefined; endpointUrl?: string | null | undefined;
id: string; id: string;

View File

@@ -150,6 +150,9 @@ const EVENT_TYPES = [
{ value: "USER_CREATED", label: "user:created" }, { value: "USER_CREATED", label: "user:created" },
{ value: "USER_UPDATED", label: "user:updated" }, { value: "USER_UPDATED", label: "user:updated" },
{ value: "USER_DELETED", label: "user:deleted" }, { value: "USER_DELETED", label: "user:deleted" },
{ value: "OBLIGATION_CREATED", label: "obligation:created" },
{ value: "OBLIGATION_UPDATED", label: "obligation:updated" },
{ value: "OBLIGATION_DELETED", label: "obligation:deleted" },
] as const; ] as const;
type WebhookEventType = (typeof EVENT_TYPES)[number]["value"]; type WebhookEventType = (typeof EVENT_TYPES)[number]["value"];

1
package-lock.json generated
View File

@@ -14347,6 +14347,7 @@
"os": [ "os": [
"darwin" "darwin"
], ],
"peer": true,
"engines": { "engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0" "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
} }

View File

@@ -0,0 +1,3 @@
ALTER TYPE webhook_event_type ADD VALUE 'obligation:created';
ALTER TYPE webhook_event_type ADD VALUE 'obligation:updated';
ALTER TYPE webhook_event_type ADD VALUE 'obligation:deleted';

View File

@@ -32,6 +32,9 @@ const (
WebhookEventTypeUserCreated WebhookEventType = "user:created" WebhookEventTypeUserCreated WebhookEventType = "user:created"
WebhookEventTypeUserUpdated WebhookEventType = "user:updated" WebhookEventTypeUserUpdated WebhookEventType = "user:updated"
WebhookEventTypeUserDeleted WebhookEventType = "user:deleted" WebhookEventTypeUserDeleted WebhookEventType = "user:deleted"
WebhookEventTypeObligationCreated WebhookEventType = "obligation:created"
WebhookEventTypeObligationUpdated WebhookEventType = "obligation:updated"
WebhookEventTypeObligationDeleted WebhookEventType = "obligation:deleted"
) )
func (w WebhookEventType) String() string { func (w WebhookEventType) String() string {
@@ -42,7 +45,8 @@ func (w WebhookEventType) IsValid() bool {
switch w { switch w {
case WebhookEventTypeMeetingCreated, WebhookEventTypeMeetingUpdated, WebhookEventTypeMeetingDeleted, case WebhookEventTypeMeetingCreated, WebhookEventTypeMeetingUpdated, WebhookEventTypeMeetingDeleted,
WebhookEventTypeVendorCreated, WebhookEventTypeVendorUpdated, WebhookEventTypeVendorDeleted, WebhookEventTypeVendorCreated, WebhookEventTypeVendorUpdated, WebhookEventTypeVendorDeleted,
WebhookEventTypeUserCreated, WebhookEventTypeUserUpdated, WebhookEventTypeUserDeleted: WebhookEventTypeUserCreated, WebhookEventTypeUserUpdated, WebhookEventTypeUserDeleted,
WebhookEventTypeObligationCreated, WebhookEventTypeObligationUpdated, WebhookEventTypeObligationDeleted:
return true return true
} }
return false return false

View File

@@ -24,6 +24,8 @@ import (
"go.probo.inc/probo/pkg/gid" "go.probo.inc/probo/pkg/gid"
"go.probo.inc/probo/pkg/page" "go.probo.inc/probo/pkg/page"
"go.probo.inc/probo/pkg/validator" "go.probo.inc/probo/pkg/validator"
"go.probo.inc/probo/pkg/webhook"
webhooktypes "go.probo.inc/probo/pkg/webhook/types"
) )
type ObligationService struct { type ObligationService struct {
@@ -160,6 +162,10 @@ func (s *ObligationService) Create(
return fmt.Errorf("cannot insert obligation: %w", err) return fmt.Errorf("cannot insert obligation: %w", err)
} }
if err := webhook.InsertData(ctx, conn, s.svc.scope, req.OrganizationID, coredata.WebhookEventTypeObligationCreated, webhooktypes.NewObligation(obligation)); err != nil {
return fmt.Errorf("cannot insert webhook event: %w", err)
}
return nil return nil
}, },
) )
@@ -238,6 +244,10 @@ func (s *ObligationService) Update(
return fmt.Errorf("cannot update obligation: %w", err) return fmt.Errorf("cannot update obligation: %w", err)
} }
if err := webhook.InsertData(ctx, conn, s.svc.scope, obligation.OrganizationID, coredata.WebhookEventTypeObligationUpdated, webhooktypes.NewObligation(obligation)); err != nil {
return fmt.Errorf("cannot insert webhook event: %w", err)
}
return nil return nil
}, },
) )
@@ -261,6 +271,10 @@ func (s *ObligationService) Delete(
return fmt.Errorf("cannot load obligation: %w", err) return fmt.Errorf("cannot load obligation: %w", err)
} }
if err := webhook.InsertData(ctx, conn, s.svc.scope, obligation.OrganizationID, coredata.WebhookEventTypeObligationDeleted, webhooktypes.NewObligation(obligation)); err != nil {
return fmt.Errorf("cannot insert webhook event: %w", err)
}
if err := obligation.Delete(ctx, conn, s.svc.scope); err != nil { if err := obligation.Delete(ctx, conn, s.svc.scope); err != nil {
return fmt.Errorf("cannot delete obligation: %w", err) return fmt.Errorf("cannot delete obligation: %w", err)
} }

View File

@@ -2288,6 +2288,12 @@ enum WebhookEventType
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserUpdated") @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserUpdated")
USER_DELETED USER_DELETED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserDeleted") @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserDeleted")
OBLIGATION_CREATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationCreated")
OBLIGATION_UPDATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationUpdated")
OBLIGATION_DELETED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationDeleted")
} }
type WebhookSubscription implements Node { type WebhookSubscription implements Node {

View File

@@ -12988,6 +12988,18 @@ enum WebhookEventType
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorUpdated") @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorUpdated")
VENDOR_DELETED VENDOR_DELETED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorDeleted") @goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeVendorDeleted")
USER_CREATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserCreated")
USER_UPDATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserUpdated")
USER_DELETED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeUserDeleted")
OBLIGATION_CREATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationCreated")
OBLIGATION_UPDATED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationUpdated")
OBLIGATION_DELETED
@goEnum(value: "go.probo.inc/probo/pkg/coredata.WebhookEventTypeObligationDeleted")
} }
type WebhookSubscription implements Node { type WebhookSubscription implements Node {
@@ -101902,6 +101914,12 @@ var (
"VENDOR_CREATED": coredata.WebhookEventTypeVendorCreated, "VENDOR_CREATED": coredata.WebhookEventTypeVendorCreated,
"VENDOR_UPDATED": coredata.WebhookEventTypeVendorUpdated, "VENDOR_UPDATED": coredata.WebhookEventTypeVendorUpdated,
"VENDOR_DELETED": coredata.WebhookEventTypeVendorDeleted, "VENDOR_DELETED": coredata.WebhookEventTypeVendorDeleted,
"USER_CREATED": coredata.WebhookEventTypeUserCreated,
"USER_UPDATED": coredata.WebhookEventTypeUserUpdated,
"USER_DELETED": coredata.WebhookEventTypeUserDeleted,
"OBLIGATION_CREATED": coredata.WebhookEventTypeObligationCreated,
"OBLIGATION_UPDATED": coredata.WebhookEventTypeObligationUpdated,
"OBLIGATION_DELETED": coredata.WebhookEventTypeObligationDeleted,
} }
marshalNWebhookEventType2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐWebhookEventType = map[coredata.WebhookEventType]string{ marshalNWebhookEventType2goᚗproboᚗincᚋproboᚋpkgᚋcoredataᚐWebhookEventType = map[coredata.WebhookEventType]string{
coredata.WebhookEventTypeMeetingCreated: "MEETING_CREATED", coredata.WebhookEventTypeMeetingCreated: "MEETING_CREATED",
@@ -101910,6 +101928,12 @@ var (
coredata.WebhookEventTypeVendorCreated: "VENDOR_CREATED", coredata.WebhookEventTypeVendorCreated: "VENDOR_CREATED",
coredata.WebhookEventTypeVendorUpdated: "VENDOR_UPDATED", coredata.WebhookEventTypeVendorUpdated: "VENDOR_UPDATED",
coredata.WebhookEventTypeVendorDeleted: "VENDOR_DELETED", coredata.WebhookEventTypeVendorDeleted: "VENDOR_DELETED",
coredata.WebhookEventTypeUserCreated: "USER_CREATED",
coredata.WebhookEventTypeUserUpdated: "USER_UPDATED",
coredata.WebhookEventTypeUserDeleted: "USER_DELETED",
coredata.WebhookEventTypeObligationCreated: "OBLIGATION_CREATED",
coredata.WebhookEventTypeObligationUpdated: "OBLIGATION_UPDATED",
coredata.WebhookEventTypeObligationDeleted: "OBLIGATION_DELETED",
} }
) )

View File

@@ -0,0 +1,58 @@
// Copyright (c) 2025 Probo Inc <hello@getprobo.com>.
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
package types
import (
"time"
"go.probo.inc/probo/pkg/coredata"
"go.probo.inc/probo/pkg/gid"
)
type Obligation struct {
ID gid.GID `json:"id"`
OrganizationID gid.GID `json:"organizationId"`
Area *string `json:"area"`
Source *string `json:"source"`
Requirement *string `json:"requirement"`
ActionsToBeImplemented *string `json:"actionsToBeImplemented"`
Regulator *string `json:"regulator"`
OwnerID gid.GID `json:"ownerId"`
LastReviewDate *time.Time `json:"lastReviewDate"`
DueDate *time.Time `json:"dueDate"`
Status coredata.ObligationStatus `json:"status"`
Type coredata.ObligationType `json:"type"`
CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"`
}
func NewObligation(o *coredata.Obligation) *Obligation {
return &Obligation{
ID: o.ID,
OrganizationID: o.OrganizationID,
Area: o.Area,
Source: o.Source,
Requirement: o.Requirement,
ActionsToBeImplemented: o.ActionsToBeImplemented,
Regulator: o.Regulator,
OwnerID: o.OwnerID,
LastReviewDate: o.LastReviewDate,
DueDate: o.DueDate,
Status: o.Status,
Type: o.Type,
CreatedAt: o.CreatedAt,
UpdatedAt: o.UpdatedAt,
}
}