Skip to content

Commit

Permalink
Merge pull request #70 from eurofurence/issue-66-ef-2024
Browse files Browse the repository at this point in the history
Issue 66 ef 2024
  • Loading branch information
Jumpy-Squirrel authored Jan 13, 2024
2 parents 1f622e5 + e616089 commit 4cd3739
Show file tree
Hide file tree
Showing 10 changed files with 133 additions and 4 deletions.
21 changes: 20 additions & 1 deletion .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ on:
push:
branches:
- 'main'
tags:
- 'v[0-9]+.[0-9]+.[0-9]+'

jobs:
call_build-and-push-image:
call_build-and-push-image_latest:
if: startsWith(github.ref, 'refs/heads/')
permissions:
contents: read
packages: write
Expand All @@ -20,3 +23,19 @@ jobs:
registry-user: ${{ github.actor }}
secrets:
registry-pass: ${{ secrets.GITHUB_TOKEN }}

call_build-and-push-image_versioned:
if: startsWith(github.ref, 'refs/tags/v0.1.')
permissions:
contents: read
packages: write
uses: eurofurence/reg-workflows/.github/workflows/docker-build-push.yml@main
with:
image-name: ${{ github.repository }}
image-tags: ${{ github.ref_name }} v0.1
full-repo-url: https://github.com/${{ github.repository }}
branch-or-tag-name: ${{ github.ref_name }}
commit-hash: ${{ github.sha }}
registry-user: ${{ github.actor }}
secrets:
registry-pass: ${{ secrets.GITHUB_TOKEN }}
2 changes: 2 additions & 0 deletions docs/config-template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ service:
# if set, will add these redirects to the request for the paylink
success_redirect: 'http://localhost:10000/app/register'
failure_redirect: 'http://localhost:10000/app/register'
# the service will reject webhooks that reference another prefix (previous year expiry, etc.)
transaction_id_prefix: "EF2023"
server:
port: 9097
database:
Expand Down
21 changes: 21 additions & 0 deletions internal/repository/concardis/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,27 @@ func newMock() Mock {
},
},
}
simData[4242] = PaymentLinkQueryResponse{
ID: 4242,
Status: "confirmed",
ReferenceID: "230001-122218-000001",
Link: constructSimulatedPaylink("4242"),
Name: "Online-Shop payment #002",
Purpose: map[string]string{"1": "some payment purpose"},
Amount: 390,
Currency: "EUR",
CreatedAt: 1418392958,
Invoices: []PaymentLinkInvoice{
{
Transactions: []TransactionData{
{
Time: "2023-01-08 12:22:58",
UUID: "d3adb33f",
},
},
},
},
}
return &mockImpl{
recording: make([]string, 0),
simulatorData: simData,
Expand Down
4 changes: 4 additions & 0 deletions internal/repository/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,10 @@ func WebhookSecret() string {
return Configuration().Security.Fixed.Webhook
}

func TransactionIDPrefix() string {
return Configuration().Service.TransactionIDPrefix
}

func InvoiceTitle() string {
return Configuration().Invoice.Title
}
Expand Down
1 change: 1 addition & 0 deletions internal/repository/config/structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ type ServiceConfig struct {
ConcardisApiSecret string `yaml:"concardis_api_secret"` // your instance's api secret, required
SuccessRedirect string `yaml:"success_redirect"`
FailureRedirect string `yaml:"failure_redirect"`
TransactionIDPrefix string `yaml:"transaction_id_prefix"`
}

// DatabaseConfig configures which db to use (mysql, inmemory)
Expand Down
1 change: 1 addition & 0 deletions internal/repository/paymentservice/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type PaymentMethod string

const (
Credit PaymentMethod = "credit"
Cash PaymentMethod = "cash"
Paypal PaymentMethod = "paypal"
Transfer PaymentMethod = "transfer"
Internal PaymentMethod = "internal"
Expand Down
25 changes: 22 additions & 3 deletions internal/service/paymentlinksrv/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import (
"errors"
"fmt"
"github.com/eurofurence/reg-payment-cncrd-adapter/internal/entity"
"github.com/eurofurence/reg-payment-cncrd-adapter/internal/repository/config"
"github.com/eurofurence/reg-payment-cncrd-adapter/internal/repository/database"
"github.com/eurofurence/reg-payment-cncrd-adapter/internal/web/util/ctxvalues"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -47,7 +49,7 @@ func (i *Impl) HandleWebhook(ctx context.Context, webhook cncrdapi.WebhookEventD
Kind: "error",
Message: "webhook query-pay-link failed",
Details: err.Error(),
RequestId: "",
RequestId: ctxvalues.RequestId(ctx),
})
_ = i.SendErrorNotifyMail(ctx, "webhook", fmt.Sprintf("paylinkId: %d", paylinkId), "api-error")
return err
Expand All @@ -63,12 +65,29 @@ func (i *Impl) HandleWebhook(ctx context.Context, webhook cncrdapi.WebhookEventD
Kind: "error",
Message: "webhook ref-id-mismatch",
Details: fmt.Sprintf("response ref-id=%s vs webhook ref-id=%s", paylink.ReferenceID, webhook.Transaction.Invoice.ReferenceId),
RequestId: "",
RequestId: ctxvalues.RequestId(ctx),
})
_ = i.SendErrorNotifyMail(ctx, "webhook", fmt.Sprintf("paylinkId: %d", paylinkId), "ref-id-mismatch")
return WebhookRefIdMismatchErr
}

prefix := config.TransactionIDPrefix()
if prefix != "" && !strings.HasPrefix(paylink.ReferenceID, prefix) {
aulogging.Logger.Ctx(ctx).Warn().Printf("webhook with wrong ref id prefix, ref_id=%s", paylink.ReferenceID)
db := database.GetRepository()
_ = db.WriteProtocolEntry(ctx, &entity.ProtocolEntry{
ReferenceId: webhook.Transaction.Invoice.ReferenceId,
ApiId: paylinkId,
Kind: "error",
Message: "webhook ref-id-prefix",
Details: fmt.Sprintf("ref-id=%s", paylink.ReferenceID),
RequestId: ctxvalues.RequestId(ctx),
})
_ = i.SendErrorNotifyMail(ctx, "webhook", paylink.ReferenceID, "ref-id-prefix")
// report success so they don't retry, it's not a big problem after all
return nil
}

aulogging.Logger.Ctx(ctx).Info().Printf("webhook call for paylink id=%d ref=%s status=%s amount=%d", paylink.ID, paylink.ReferenceID, paylink.Status, paylink.Amount)
db := database.GetRepository()
_ = db.WriteProtocolEntry(ctx, &entity.ProtocolEntry{
Expand All @@ -77,7 +96,7 @@ func (i *Impl) HandleWebhook(ctx context.Context, webhook cncrdapi.WebhookEventD
Kind: "success",
Message: "webhook query-pay-link",
Details: fmt.Sprintf("status=%s amount=%d", paylink.Status, paylink.Amount),
RequestId: "",
RequestId: ctxvalues.RequestId(ctx),
})

if paylink.Status == "cancelled" || paylink.Status == "declined" {
Expand Down
1 change: 1 addition & 0 deletions internal/web/app/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ func setupLogging(applicationName string, useEcsLogging bool) {
aulogging.RequestIdRetriever = ctxvalues.RequestId
if useEcsLogging {
auzerolog.SetupJsonLogging(applicationName)
zerolog.TimeFieldFormat = "2006-01-02T15:04:05.000Z"
} else {
aulogging.DefaultRequestIdValue = "00000000"
auzerolog.SetupPlaintextLogging()
Expand Down
60 changes: 60 additions & 0 deletions test/acceptance/webhook_acc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,66 @@ func TestWebhook_DownstreamError(t *testing.T) {
tstRequireErrorResponse(t, response, http.StatusBadGateway, "webhook.downstream.error", nil)
}

func TestWebhook_Success_Status_WrongPrefix(t *testing.T) {
tstSetup(tstConfigFile)
defer tstShutdown()

docs.Given("given the payment provider has a transaction in status confirmed")

docs.Given("and an anonymous caller who knows the secret url")
url := "/api/rest/v1/webhook/demosecret"

docs.When("when they trigger our webhook endpoint with the wrong prefix")
request := `
{
"transaction": {
"id": 1892362736,
"invoice": {
"paymentRequestId": 4242,
"referenceId": "230001-122218-000001"
}
}
}
`
response := tstPerformPost(url, request, tstNoToken())

docs.Then("then the request is successful")
require.Equal(t, http.StatusOK, response.status)

docs.Then("and the expected downstream requests have been made to the concardis api")
tstRequireConcardisRecording(t,
"QueryPaymentLink 4242",
)

docs.Then("and no requests to the payment service have been made")
tstRequirePaymentServiceRecording(t, nil)

docs.Then("and the expected error notification emails have been sent")
tstRequireMailServiceRecording(t, []mailservice.MailSendDto{
{
CommonID: "payment-cncrd-adapter-error",
Lang: "en-US",
To: []string{
"[email protected]",
},
Variables: map[string]string{
"status": "ref-id-prefix",
"operation": "webhook",
"referenceId": "230001-122218-000001",
},
},
})

docs.Then("and the expected protocol entries have been written")
tstRequireProtocolEntries(t, entity.ProtocolEntry{
ReferenceId: "230001-122218-000001",
ApiId: 4242,
Kind: "error",
Message: "webhook ref-id-prefix",
Details: "ref-id=230001-122218-000001",
})
}

// --- helpers ---

func tstWebhookSuccessCase(t *testing.T, status string, expectedPaymentServiceRecording []paymentservice.Transaction, expectedMailRecording []mailservice.MailSendDto, expectedProtocol []entity.ProtocolEntry) {
Expand Down
1 change: 1 addition & 0 deletions test/resources/testconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ service:
name: 'Registration Concardis Adapter Unit Testing Configuration'
concardis_instance: 'myinstance'
concardis_api_secret: 'mydemosecret'
transaction_id_prefix: "221216"
database:
use: inmemory
security:
Expand Down

0 comments on commit 4cd3739

Please sign in to comment.