From d8a22b4b3d25447472276dc2c73010a8c3d4f5b6 Mon Sep 17 00:00:00 2001 From: Paul Nicolas Date: Fri, 13 Sep 2024 14:31:46 +0200 Subject: [PATCH] fix(payments): fix connectors installation --- .../api/v3/handler_connectors_install.go | 29 ++-------------- components/payments/internal/api/v3/router.go | 6 +++- .../storage_webhooks_configs_store.go | 2 +- .../engine/workflow/install_connector.go | 26 +++++++------- .../storage/migrations/0-init-schema.sql | 34 +++++++++++++++++++ .../payments/internal/storage/payments.go | 3 -- .../payments/internal/storage/webhooks.go | 4 +-- 7 files changed, 58 insertions(+), 46 deletions(-) diff --git a/components/payments/internal/api/v3/handler_connectors_install.go b/components/payments/internal/api/v3/handler_connectors_install.go index 93b9decf59..cd259398e1 100644 --- a/components/payments/internal/api/v3/handler_connectors_install.go +++ b/components/payments/internal/api/v3/handler_connectors_install.go @@ -1,8 +1,6 @@ package v3 import ( - "encoding/json" - "errors" "io" "net/http" @@ -11,18 +9,6 @@ import ( "github.com/formancehq/stack/libs/go-libs/api" ) -type connectorsInstallRequest struct { - Provider string `json:"provider"` -} - -func (request connectorsInstallRequest) validate() error { - if request.Provider == "" { - return errors.New("provider is required") - } - - return nil -} - func connectorsInstall(backend backend.Backend) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { ctx, span := otel.Tracer().Start(r.Context(), "v3_connectorsInstall") @@ -35,20 +21,9 @@ func connectorsInstall(backend backend.Backend) http.HandlerFunc { return } - var request connectorsInstallRequest - if err := json.Unmarshal(config, &request); err != nil { - otel.RecordError(span, err) - api.BadRequest(w, ErrMissingOrInvalidBody, err) - return - } - - if err := request.validate(); err != nil { - otel.RecordError(span, err) - api.BadRequest(w, ErrMissingOrInvalidBody, err) - return - } + provider := connector(r) - connectorID, err := backend.ConnectorsInstall(ctx, request.Provider, config) + connectorID, err := backend.ConnectorsInstall(ctx, provider, config) if err != nil { otel.RecordError(span, err) handleServiceErrors(w, r, err) diff --git a/components/payments/internal/api/v3/router.go b/components/payments/internal/api/v3/router.go index c9eb78c03a..ee2240b5f8 100644 --- a/components/payments/internal/api/v3/router.go +++ b/components/payments/internal/api/v3/router.go @@ -78,7 +78,7 @@ func newRouter(backend backend.Backend, a auth.Auth) *chi.Mux { // Connectors r.Route("/connectors", func(r chi.Router) { r.Get("/", connectorsList(backend)) - r.Post("/", connectorsInstall(backend)) + r.Post("/install/{connector}", connectorsInstall(backend)) r.Get("/configs", connectorsConfigs(backend)) @@ -100,6 +100,10 @@ func newRouter(backend backend.Backend, a auth.Auth) *chi.Mux { return r } +func connector(r *http.Request) string { + return chi.URLParam(r, "connector") +} + func connectorID(r *http.Request) string { return chi.URLParam(r, "connectorID") } diff --git a/components/payments/internal/connectors/engine/activities/storage_webhooks_configs_store.go b/components/payments/internal/connectors/engine/activities/storage_webhooks_configs_store.go index 7280512612..2b06f465ea 100644 --- a/components/payments/internal/connectors/engine/activities/storage_webhooks_configs_store.go +++ b/components/payments/internal/connectors/engine/activities/storage_webhooks_configs_store.go @@ -8,7 +8,7 @@ import ( ) func (a Activities) StorageWebhooksConfigsStore(ctx context.Context, configs []models.WebhookConfig) error { - return a.StorageWebhooksConfigsStore(ctx, configs) + return a.storage.WebhooksConfigsUpsert(ctx, configs) } var StorageWebhooksConfigsStoreActivity = Activities{}.StorageWebhooksConfigsStore diff --git a/components/payments/internal/connectors/engine/workflow/install_connector.go b/components/payments/internal/connectors/engine/workflow/install_connector.go index 084664875c..e2b93bd31b 100644 --- a/components/payments/internal/connectors/engine/workflow/install_connector.go +++ b/components/payments/internal/connectors/engine/workflow/install_connector.go @@ -51,18 +51,20 @@ func (w Workflow) runInstallConnector( return errors.Wrap(err, "failed to store tasks tree") } - configs := make([]models.WebhookConfig, 0, len(installResponse.WebhooksConfigs)) - for _, webhookConfig := range installResponse.WebhooksConfigs { - configs = append(configs, models.WebhookConfig{ - Name: webhookConfig.Name, - ConnectorID: installConnector.ConnectorID, - URLPath: webhookConfig.URLPath, - }) - } - // TODO(polo): store the capabilities - err = activities.StorageWebhooksConfigsStore(infiniteRetryContext(ctx), configs) - if err != nil { - return errors.Wrap(err, "failed to store webhooks configs") + if len(installResponse.WebhooksConfigs) > 0 { + configs := make([]models.WebhookConfig, 0, len(installResponse.WebhooksConfigs)) + for _, webhookConfig := range installResponse.WebhooksConfigs { + configs = append(configs, models.WebhookConfig{ + Name: webhookConfig.Name, + ConnectorID: installConnector.ConnectorID, + URLPath: webhookConfig.URLPath, + }) + } + // TODO(polo): store the capabilities + err = activities.StorageWebhooksConfigsStore(infiniteRetryContext(ctx), configs) + if err != nil { + return errors.Wrap(err, "failed to store webhooks configs") + } } var config models.Config diff --git a/components/payments/internal/storage/migrations/0-init-schema.sql b/components/payments/internal/storage/migrations/0-init-schema.sql index 52ea16254d..20c87f2628 100644 --- a/components/payments/internal/storage/migrations/0-init-schema.sql +++ b/components/payments/internal/storage/migrations/0-init-schema.sql @@ -251,4 +251,38 @@ create table if not exists workflows_instances ( alter table workflows_instances add constraint workflows_instances_connector_id_fk foreign key (connector_id) references connectors (id) + on delete cascade; + +-- Webhook configs +create table if not exists webhooks_configs ( + -- Mandatory fields + name text not null, + connector_id varchar not null, + url_path text not null, + + -- Primary key + primary key (name, connector_id) +); +alter table webhooks_configs + add constraint webhooks_configs_connector_id_fk foreign key (connector_id) + references connectors (id) + on delete cascade; + +-- Webhooks +create table if not exists webhooks ( + -- Mandatory fields + id text not null, + connector_id varchar not null, + + -- Optional fields + headers json, + query_values json, + body bytea, + + -- Primary key + primary key (id) +); +alter table webhooks + add constraint webhooks_connector_id_fk foreign key (connector_id) + references connectors (id) on delete cascade; \ No newline at end of file diff --git a/components/payments/internal/storage/payments.go b/components/payments/internal/storage/payments.go index 26b2c916ff..f715d2ddea 100644 --- a/components/payments/internal/storage/payments.go +++ b/components/payments/internal/storage/payments.go @@ -28,7 +28,6 @@ type payment struct { Amount *big.Int `bun:"amount,type:numeric,notnull"` Asset string `bun:"asset,type:text,notnull"` Scheme models.PaymentScheme `bun:"scheme,type:text,notnull"` - Status models.PaymentStatus `bun:"status,type:text,notnull"` // Optional fields // c.f.: https://bun.uptrace.dev/guide/models.html#nulls @@ -276,7 +275,6 @@ func fromPaymentModels(from models.Payment) payment { Amount: from.Amount, Asset: from.Asset, Scheme: from.Scheme, - Status: from.Status, SourceAccountID: from.SourceAccountID, DestinationAccountID: from.DestinationAccountID, Metadata: from.Metadata, @@ -294,7 +292,6 @@ func toPaymentModels(payment payment) models.Payment { Amount: payment.Amount, Asset: payment.Asset, Scheme: payment.Scheme, - Status: payment.Status, SourceAccountID: payment.SourceAccountID, DestinationAccountID: payment.DestinationAccountID, Metadata: payment.Metadata, diff --git a/components/payments/internal/storage/webhooks.go b/components/payments/internal/storage/webhooks.go index e15c314f45..0a2a73a656 100644 --- a/components/payments/internal/storage/webhooks.go +++ b/components/payments/internal/storage/webhooks.go @@ -15,8 +15,8 @@ type webhook struct { ConnectorID models.ConnectorID `bun:"connector_id,type:character varying,notnull"` // Optional fields - Headers map[string][]string `bun:"headers,type:jsonb"` - QueryValues map[string][]string `bun:"query_values,type:jsonb"` + Headers map[string][]string `bun:"headers,type:json"` + QueryValues map[string][]string `bun:"query_values,type:json"` Body []byte `bun:"payload,type:bytea,nullzero"` }