Compare commits
49 Commits
b481de9ffc
...
SEND066
| Author | SHA1 | Date | |
|---|---|---|---|
| fdd8dd8845 | |||
|
|
3b23eada33 | ||
| b4b9507e7e | |||
|
|
6911757e1d | ||
| fba992f898 | |||
|
|
5a8392a6d0 | ||
| 6b82825494 | |||
|
|
54e9821886 | ||
| c74444ab0b | |||
| aba63ecd37 | |||
|
|
9ad2104d7d | ||
| e446486b77 | |||
|
|
65b04fba39 | ||
|
|
bbdbd9a197 | ||
|
|
049b23516a | ||
| 3862fa4e52 | |||
|
|
7ae4518926 | ||
|
|
e5b4de5d48 | ||
|
|
0e64ab5558 | ||
|
|
840a7f85c8 | ||
| 9c2b3bf8bd | |||
|
|
41720a6817 | ||
|
|
918dbe8bb5 | ||
|
|
6cc0340ba3 | ||
|
|
e77d1ab793 | ||
| d87e709f43 | |||
|
|
185f8f2ed6 | ||
| 2160b6bf4d | |||
|
|
54bbe41f7a | ||
|
|
f7f0612af9 | ||
|
|
0aceb2f441 | ||
|
|
281b3834d3 | ||
| 6633a1d807 | |||
|
|
88b279dd78 | ||
| 0f42a0e77f | |||
|
|
10bcdb4fe2 | ||
|
|
2b0ada1541 | ||
| ea5ec79a6e | |||
|
|
3295b9d9f0 | ||
| 031b8931ca | |||
|
|
4295456f63 | ||
| 2b1b4135f4 | |||
|
|
c60e7d2329 | ||
| be49254769 | |||
|
|
34e507b664 | ||
|
|
b67d199427 | ||
|
|
97b16542c2 | ||
|
|
39c04beb21 | ||
|
|
d6a3a0cc5b |
@@ -1,2 +1,18 @@
|
|||||||
ci/dev/mongo.key*
|
ci/dev/mongo.key*
|
||||||
|
|
||||||
|
# VCS / editor files
|
||||||
|
.git
|
||||||
|
.vscode
|
||||||
|
.DS_Store
|
||||||
|
**/.DS_Store
|
||||||
|
|
||||||
|
# Local caches and temporary artifacts
|
||||||
|
.cache
|
||||||
|
.gocache
|
||||||
|
**/.gocache
|
||||||
|
**/tmp/
|
||||||
|
**/tmp/**
|
||||||
|
|
||||||
|
# Frontend local build artifacts (rebuilt in Docker)
|
||||||
|
frontend/**/.dart_tool
|
||||||
|
frontend/**/build
|
||||||
|
|||||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -10,7 +10,9 @@ generate_protos.sh
|
|||||||
update_dep.sh
|
update_dep.sh
|
||||||
test.sh
|
test.sh
|
||||||
.vscode/
|
.vscode/
|
||||||
|
|
||||||
.gocache/
|
.gocache/
|
||||||
|
.golangci-cache/
|
||||||
.cache/
|
.cache/
|
||||||
.claude/
|
.claude/
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ matrix:
|
|||||||
BFF_VAULT_SECRET_PATH: sendico/edge/bff/vault
|
BFF_VAULT_SECRET_PATH: sendico/edge/bff/vault
|
||||||
BFF_ENV: prod
|
BFF_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -47,6 +50,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh bff
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -75,8 +88,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/bff/build-image.sh
|
- sh ci/scripts/bff/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
DOCUMENTS_MONGO_SECRET_PATH: sendico/db
|
DOCUMENTS_MONGO_SECRET_PATH: sendico/db
|
||||||
DOCUMENTS_ENV: prod
|
DOCUMENTS_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -42,6 +45,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh billing_documents
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -70,8 +83,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/billing_documents/build-image.sh
|
- sh ci/scripts/billing_documents/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
FEES_MONGO_SECRET_PATH: sendico/db
|
FEES_MONGO_SECRET_PATH: sendico/db
|
||||||
FEES_ENV: prod
|
FEES_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -42,6 +45,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh billing_fees
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -70,8 +83,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/billing_fees/build-image.sh
|
- sh ci/scripts/billing_fees/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ matrix:
|
|||||||
CALLBACKS_VAULT_SECRET_PATH: sendico/edge/callbacks/vault
|
CALLBACKS_VAULT_SECRET_PATH: sendico/edge/callbacks/vault
|
||||||
CALLBACKS_ENV: prod
|
CALLBACKS_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -43,6 +46,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh callbacks
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -71,8 +84,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/callbacks/build-image.sh
|
- sh ci/scripts/callbacks/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ matrix:
|
|||||||
DISCOVERY_DOCKERFILE: ci/prod/compose/discovery.dockerfile
|
DISCOVERY_DOCKERFILE: ci/prod/compose/discovery.dockerfile
|
||||||
DISCOVERY_ENV: prod
|
DISCOVERY_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -41,6 +44,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh discovery
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -69,8 +82,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/discovery/build-image.sh
|
- sh ci/scripts/discovery/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ matrix:
|
|||||||
FRONTEND_DOCKERFILE: ci/prod/compose/frontend.dockerfile
|
FRONTEND_DOCKERFILE: ci/prod/compose/frontend.dockerfile
|
||||||
FRONTEND_ENV: prod
|
FRONTEND_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -22,7 +25,8 @@ steps:
|
|||||||
- name: version
|
- name: version
|
||||||
image: alpine:latest
|
image: alpine:latest
|
||||||
commands:
|
commands:
|
||||||
- set -euo pipefail 2>/dev/null || set -eu
|
- set -eu
|
||||||
|
- if set -o | grep -q pipefail 2>/dev/null; then set -o pipefail; fi
|
||||||
- apk add --no-cache git
|
- apk add --no-cache git
|
||||||
- GIT_REV="$(git rev-parse --short HEAD)"
|
- GIT_REV="$(git rev-parse --short HEAD)"
|
||||||
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
- BUILD_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
||||||
@@ -50,10 +54,21 @@ steps:
|
|||||||
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
|
- ./ci/vlt kv_get kv registry user > secrets/REGISTRY_USER
|
||||||
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
|
- ./ci/vlt kv_get kv registry password > secrets/REGISTRY_PASSWORD
|
||||||
|
|
||||||
|
- name: frontend-tests
|
||||||
|
image: ghcr.io/cirruslabs/flutter:stable
|
||||||
|
depends_on: [ version ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- if set -o | grep -q pipefail 2>/dev/null; then set -o pipefail; fi
|
||||||
|
- flutter --version
|
||||||
|
- (cd frontend/pshared && flutter pub get && dart run build_runner build --delete-conflicting-outputs && flutter test)
|
||||||
|
- (cd frontend/pweb && flutter pub get && dart run build_runner build --delete-conflicting-outputs && flutter test)
|
||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ version, secrets ]
|
depends_on: [ frontend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/frontend/build-image.sh
|
- sh ci/scripts/frontend/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ matrix:
|
|||||||
FX_NEEDS_NATS: "true"
|
FX_NEEDS_NATS: "true"
|
||||||
FX_ENV: prod
|
FX_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -47,6 +50,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh fx_ingestor
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -75,8 +88,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/fx/build-image.sh
|
- sh ci/scripts/fx/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ matrix:
|
|||||||
FX_NEEDS_NATS: "true"
|
FX_NEEDS_NATS: "true"
|
||||||
FX_ENV: prod
|
FX_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -48,6 +51,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh fx_oracle
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -76,8 +89,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/fx/build-image.sh
|
- sh ci/scripts/fx/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ matrix:
|
|||||||
CHAIN_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/chain/vault
|
CHAIN_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/chain/vault
|
||||||
CHAIN_GATEWAY_ENV: prod
|
CHAIN_GATEWAY_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -46,6 +49,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh gateway_chain
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -74,8 +87,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "chain gateway image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/chain_gateway/build-image.sh
|
- sh ci/scripts/chain_gateway/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ matrix:
|
|||||||
MNTX_GATEWAY_NATS_SECRET_PATH: sendico/nats
|
MNTX_GATEWAY_NATS_SECRET_PATH: sendico/nats
|
||||||
MNTX_GATEWAY_MONGO_SECRET_PATH: sendico/db
|
MNTX_GATEWAY_MONGO_SECRET_PATH: sendico/db
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -45,6 +48,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh gateway_mntx
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -73,8 +86,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/mntx/build-image.sh
|
- sh ci/scripts/mntx/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
TGSETTLE_GATEWAY_MONGO_SECRET_PATH: sendico/db
|
TGSETTLE_GATEWAY_MONGO_SECRET_PATH: sendico/db
|
||||||
TGSETTLE_GATEWAY_ENV: prod
|
TGSETTLE_GATEWAY_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -43,6 +46,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh gateway_tgsettle
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -71,8 +84,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/tgsettle/build-image.sh
|
- sh ci/scripts/tgsettle/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ matrix:
|
|||||||
TRON_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/tron/vault
|
TRON_GATEWAY_VAULT_SECRET_PATH: sendico/gateway/tron/vault
|
||||||
TRON_GATEWAY_ENV: prod
|
TRON_GATEWAY_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -46,6 +49,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh gateway_tron
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -74,8 +87,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/tron_gateway/build-image.sh
|
- sh ci/scripts/tron_gateway/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
LEDGER_MONGO_SECRET_PATH: sendico/db
|
LEDGER_MONGO_SECRET_PATH: sendico/db
|
||||||
LEDGER_ENV: prod
|
LEDGER_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -42,6 +45,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh ledger
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -70,8 +83,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/ledger/build-image.sh
|
- sh ci/scripts/ledger/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -8,6 +8,9 @@ matrix:
|
|||||||
NOTIFICATION_TELEGRAM_SECRET_PATH: sendico/notification/telegram
|
NOTIFICATION_TELEGRAM_SECRET_PATH: sendico/notification/telegram
|
||||||
NOTIFICATION_ENV: prod
|
NOTIFICATION_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -45,6 +48,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh notification
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -73,8 +86,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/notification/build-image.sh
|
- sh ci/scripts/notification/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
PAYMENTS_METHODS_MONGO_SECRET_PATH: sendico/db
|
PAYMENTS_METHODS_MONGO_SECRET_PATH: sendico/db
|
||||||
PAYMENTS_METHODS_ENV: prod
|
PAYMENTS_METHODS_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -43,6 +46,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh payments_methods
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -71,8 +84,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/payments_methods/build-image.sh
|
- sh ci/scripts/payments_methods/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
PAYMENTS_MONGO_SECRET_PATH: sendico/db
|
PAYMENTS_MONGO_SECRET_PATH: sendico/db
|
||||||
PAYMENTS_ENV: prod
|
PAYMENTS_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -43,6 +46,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh payments_orchestrator
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -71,8 +84,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/payments_orchestrator/build-image.sh
|
- sh ci/scripts/payments_orchestrator/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ matrix:
|
|||||||
PAYMENTS_QUOTATION_MONGO_SECRET_PATH: sendico/db
|
PAYMENTS_QUOTATION_MONGO_SECRET_PATH: sendico/db
|
||||||
PAYMENTS_QUOTATION_ENV: prod
|
PAYMENTS_QUOTATION_ENV: prod
|
||||||
|
|
||||||
|
labels:
|
||||||
|
platform: linux/amd64
|
||||||
|
|
||||||
when:
|
when:
|
||||||
- event: push
|
- event: push
|
||||||
branch: main
|
branch: main
|
||||||
@@ -43,6 +46,16 @@ steps:
|
|||||||
- export PATH="$(go env GOPATH)/bin:$PATH"
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
- bash ci/scripts/proto/generate.sh
|
- bash ci/scripts/proto/generate.sh
|
||||||
|
|
||||||
|
- name: backend-lint
|
||||||
|
image: golang:alpine
|
||||||
|
depends_on: [ proto ]
|
||||||
|
commands:
|
||||||
|
- set -eu
|
||||||
|
- apk add --no-cache bash git build-base
|
||||||
|
- CGO_ENABLED=0 go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@latest
|
||||||
|
- export PATH="$(go env GOPATH)/bin:$PATH"
|
||||||
|
- sh ci/scripts/common/run_backend_lint.sh payments_quotation
|
||||||
|
|
||||||
- name: backend-tests
|
- name: backend-tests
|
||||||
image: golang:alpine
|
image: golang:alpine
|
||||||
depends_on: [ proto ]
|
depends_on: [ proto ]
|
||||||
@@ -71,8 +84,9 @@ steps:
|
|||||||
|
|
||||||
- name: build-image
|
- name: build-image
|
||||||
image: gcr.io/kaniko-project/executor:debug
|
image: gcr.io/kaniko-project/executor:debug
|
||||||
depends_on: [ backend-tests, secrets ]
|
depends_on: [ backend-lint, backend-tests, secrets ]
|
||||||
commands:
|
commands:
|
||||||
|
- '[ "$(uname -m)" = "x86_64" ] || { echo "image build requires an amd64 runner"; exit 1; }'
|
||||||
- sh ci/scripts/payments_quotation/build-image.sh
|
- sh ci/scripts/payments_quotation/build-image.sh
|
||||||
|
|
||||||
- name: deploy
|
- name: deploy
|
||||||
|
|||||||
114
Makefile
114
Makefile
@@ -1,10 +1,48 @@
|
|||||||
# Sendico Development Environment - Makefile
|
# Sendico Development Environment - Makefile
|
||||||
# Docker Compose + Makefile build system
|
# Docker Compose + Makefile build system
|
||||||
|
|
||||||
.PHONY: help init build up down restart logs rebuild clean vault-init proto generate generate-api generate-frontend update update-api update-frontend test test-api test-frontend backend-up backend-down backend-rebuild
|
.PHONY: \
|
||||||
|
help \
|
||||||
|
init \
|
||||||
|
build \
|
||||||
|
build-infra \
|
||||||
|
build-core \
|
||||||
|
build-fx \
|
||||||
|
build-payments \
|
||||||
|
build-gateways \
|
||||||
|
build-backend \
|
||||||
|
build-frontend \
|
||||||
|
up \
|
||||||
|
down \
|
||||||
|
restart \
|
||||||
|
infra-up \
|
||||||
|
services-up \
|
||||||
|
backend-up \
|
||||||
|
backend-down \
|
||||||
|
backend-rebuild \
|
||||||
|
status \
|
||||||
|
list-services \
|
||||||
|
logs \
|
||||||
|
rebuild \
|
||||||
|
clean \
|
||||||
|
health \
|
||||||
|
vault-init \
|
||||||
|
proto \
|
||||||
|
generate \
|
||||||
|
generate-backend \
|
||||||
|
generate-frontend \
|
||||||
|
update \
|
||||||
|
update-backend \
|
||||||
|
update-frontend \
|
||||||
|
test \
|
||||||
|
test-backend \
|
||||||
|
test-frontend \
|
||||||
|
lint-backend
|
||||||
|
|
||||||
COMPOSE := docker compose -f docker-compose.dev.yml --env-file .env.dev
|
COMPOSE := docker compose -f docker-compose.dev.yml --env-file .env.dev
|
||||||
SERVICE ?=
|
SERVICE ?=
|
||||||
|
BACKEND_GOCACHE ?= $(CURDIR)/.gocache
|
||||||
|
BACKEND_GOLANGCI_LINT_CACHE ?= $(CURDIR)/.golangci-cache
|
||||||
BACKEND_SERVICES := \
|
BACKEND_SERVICES := \
|
||||||
dev-discovery \
|
dev-discovery \
|
||||||
dev-fx-oracle \
|
dev-fx-oracle \
|
||||||
@@ -20,7 +58,7 @@ BACKEND_SERVICES := \
|
|||||||
dev-tron-gateway-vault-agent \
|
dev-tron-gateway-vault-agent \
|
||||||
dev-tron-gateway \
|
dev-tron-gateway \
|
||||||
dev-aurora-gateway \
|
dev-aurora-gateway \
|
||||||
dev-tgsettle-gateway \
|
dev-chsettle-gateway \
|
||||||
dev-notification \
|
dev-notification \
|
||||||
dev-callbacks-vault-agent \
|
dev-callbacks-vault-agent \
|
||||||
dev-callbacks \
|
dev-callbacks \
|
||||||
@@ -45,8 +83,8 @@ help:
|
|||||||
@echo " make down Stop all services"
|
@echo " make down Stop all services"
|
||||||
@echo " make restart Restart all services"
|
@echo " make restart Restart all services"
|
||||||
@echo " make status Show service status"
|
@echo " make status Show service status"
|
||||||
@echo " make logs [SERVICE=x] View logs (all or specific service)"
|
@echo " make logs [SERVICE=dev-ledger] View logs (all or specific service)"
|
||||||
@echo " make rebuild SERVICE=x Rebuild specific service"
|
@echo " make rebuild SERVICE=dev-ledger Rebuild specific service"
|
||||||
@echo " make clean Remove all containers and volumes"
|
@echo " make clean Remove all containers and volumes"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "$(YELLOW)Selective Operations:$(NC)"
|
@echo "$(YELLOW)Selective Operations:$(NC)"
|
||||||
@@ -60,22 +98,23 @@ help:
|
|||||||
@echo "$(YELLOW)Build Groups:$(NC)"
|
@echo "$(YELLOW)Build Groups:$(NC)"
|
||||||
@echo " make build-core Build core services (discovery, ledger, fees, documents)"
|
@echo " make build-core Build core services (discovery, ledger, fees, documents)"
|
||||||
@echo " make build-fx Build FX services (oracle, ingestor)"
|
@echo " make build-fx Build FX services (oracle, ingestor)"
|
||||||
@echo " make build-payments Build payment orchestrator"
|
@echo " make build-payments Build payment services (orchestrator, quotation, methods)"
|
||||||
@echo " make build-gateways Build gateway services (chain, tron, aurora, tgsettle)"
|
@echo " make build-gateways Build gateway services (chain, tron, aurora, chsettle)"
|
||||||
@echo " make build-api Build API services (notification, callbacks, bff)"
|
@echo " make build-backend Build backend edge services (notification, callbacks, bff)"
|
||||||
@echo " make build-frontend Build Flutter web frontend"
|
@echo " make build-frontend Build Flutter web frontend"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "$(YELLOW)Development:$(NC)"
|
@echo "$(YELLOW)Development:$(NC)"
|
||||||
@echo " make proto Generate protobuf code"
|
@echo " make proto Generate protobuf code"
|
||||||
@echo " make generate Generate all code (protobuf + Flutter)"
|
@echo " make generate Generate all code (protobuf + Flutter)"
|
||||||
@echo " make generate-api Generate protobuf code only"
|
@echo " make generate-backend Generate protobuf code only"
|
||||||
@echo " make generate-frontend Generate Flutter code only"
|
@echo " make generate-frontend Generate Flutter code only"
|
||||||
@echo " make update Update all dependencies (Go + Flutter)"
|
@echo " make update Update all dependencies (Go + Flutter)"
|
||||||
@echo " make update-api Update Go dependencies only"
|
@echo " make update-backend Update Go dependencies only"
|
||||||
@echo " make update-frontend Update Flutter dependencies only"
|
@echo " make update-frontend Update Flutter dependencies only"
|
||||||
@echo " make test Run all tests (API + frontend)"
|
@echo " make test Run all tests (backend + frontend)"
|
||||||
@echo " make test-api Run Go API tests only"
|
@echo " make test-backend Run Go backend tests only"
|
||||||
@echo " make test-frontend Run Flutter tests only"
|
@echo " make test-frontend Run Flutter tests only"
|
||||||
|
@echo " make lint-backend Run golangci-lint across all backend Go modules"
|
||||||
@echo " make health Check service health"
|
@echo " make health Check service health"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "Examples:"
|
@echo "Examples:"
|
||||||
@@ -137,7 +176,7 @@ up:
|
|||||||
@echo " NATS UI: http://localhost:8222"
|
@echo " NATS UI: http://localhost:8222"
|
||||||
@echo " Vault: http://localhost:8200 (run 'make vault-init' first)"
|
@echo " Vault: http://localhost:8200 (run 'make vault-init' first)"
|
||||||
@echo ""
|
@echo ""
|
||||||
@echo "View logs: make logs [SERVICE=name]"
|
@echo "View logs: make logs [SERVICE=dev-ledger]"
|
||||||
@echo "Stop: make down"
|
@echo "Stop: make down"
|
||||||
|
|
||||||
# Stop all services
|
# Stop all services
|
||||||
@@ -161,7 +200,7 @@ endif
|
|||||||
# Rebuild specific service
|
# Rebuild specific service
|
||||||
rebuild:
|
rebuild:
|
||||||
ifndef SERVICE
|
ifndef SERVICE
|
||||||
$(error SERVICE is required: make rebuild SERVICE=ledger)
|
$(error SERVICE is required: make rebuild SERVICE=dev-ledger)
|
||||||
endif
|
endif
|
||||||
@echo "$(GREEN)Rebuilding $(SERVICE)...$(NC)"
|
@echo "$(GREEN)Rebuilding $(SERVICE)...$(NC)"
|
||||||
@$(COMPOSE) build $(SERVICE)
|
@$(COMPOSE) build $(SERVICE)
|
||||||
@@ -170,13 +209,13 @@ endif
|
|||||||
@echo "View logs: make logs SERVICE=$(SERVICE)"
|
@echo "View logs: make logs SERVICE=$(SERVICE)"
|
||||||
|
|
||||||
# Generate protobuf code (alias)
|
# Generate protobuf code (alias)
|
||||||
proto: generate-api
|
proto: generate-backend
|
||||||
|
|
||||||
# Generate all code
|
# Generate all code
|
||||||
generate: generate-api generate-frontend
|
generate: generate-backend generate-frontend
|
||||||
|
|
||||||
# Generate protobuf code
|
# Generate backend protobuf code
|
||||||
generate-api:
|
generate-backend:
|
||||||
@echo "$(GREEN)Generating protobuf code...$(NC)"
|
@echo "$(GREEN)Generating protobuf code...$(NC)"
|
||||||
@./ci/scripts/proto/generate.sh
|
@./ci/scripts/proto/generate.sh
|
||||||
@echo "$(GREEN)✅ Protobuf generation complete$(NC)"
|
@echo "$(GREEN)✅ Protobuf generation complete$(NC)"
|
||||||
@@ -247,7 +286,7 @@ services-up:
|
|||||||
dev-chain-gateway \
|
dev-chain-gateway \
|
||||||
dev-tron-gateway \
|
dev-tron-gateway \
|
||||||
dev-aurora-gateway \
|
dev-aurora-gateway \
|
||||||
dev-tgsettle-gateway \
|
dev-chsettle-gateway \
|
||||||
dev-notification \
|
dev-notification \
|
||||||
dev-callbacks \
|
dev-callbacks \
|
||||||
dev-bff \
|
dev-bff \
|
||||||
@@ -292,7 +331,7 @@ list-services:
|
|||||||
@echo " - dev-chain-gateway :50070, :9404 (EVM Blockchain Gateway)"
|
@echo " - dev-chain-gateway :50070, :9404 (EVM Blockchain Gateway)"
|
||||||
@echo " - dev-tron-gateway :50071, :9408 (TRON Blockchain Gateway)"
|
@echo " - dev-tron-gateway :50071, :9408 (TRON Blockchain Gateway)"
|
||||||
@echo " - dev-aurora-gateway :50075, :9405, :8084 (Card Payouts Simulator)"
|
@echo " - dev-aurora-gateway :50075, :9405, :8084 (Card Payouts Simulator)"
|
||||||
@echo " - dev-tgsettle-gateway :50080, :9406 (Telegram Settlements)"
|
@echo " - dev-chsettle-gateway :50080, :9406 (Chimera Settlements Simulator)"
|
||||||
@echo " - dev-notification :8081 (Notifications)"
|
@echo " - dev-notification :8081 (Notifications)"
|
||||||
@echo " - dev-callbacks :9420 (Webhook Callbacks)"
|
@echo " - dev-callbacks :9420 (Webhook Callbacks)"
|
||||||
@echo " - dev-bff :8080 (Backend for Frontend)"
|
@echo " - dev-bff :8080 (Backend for Frontend)"
|
||||||
@@ -322,10 +361,10 @@ build-payments:
|
|||||||
|
|
||||||
build-gateways:
|
build-gateways:
|
||||||
@echo "$(GREEN)Building gateway services...$(NC)"
|
@echo "$(GREEN)Building gateway services...$(NC)"
|
||||||
@$(COMPOSE) build dev-chain-gateway dev-tron-gateway dev-aurora-gateway dev-tgsettle-gateway
|
@$(COMPOSE) build dev-chain-gateway dev-tron-gateway dev-aurora-gateway dev-chsettle-gateway
|
||||||
|
|
||||||
build-api:
|
build-backend:
|
||||||
@echo "$(GREEN)Building API services...$(NC)"
|
@echo "$(GREEN)Building backend edge services...$(NC)"
|
||||||
@$(COMPOSE) build dev-notification dev-callbacks dev-bff
|
@$(COMPOSE) build dev-notification dev-callbacks dev-bff
|
||||||
|
|
||||||
build-frontend:
|
build-frontend:
|
||||||
@@ -333,10 +372,10 @@ build-frontend:
|
|||||||
@$(COMPOSE) build dev-frontend
|
@$(COMPOSE) build dev-frontend
|
||||||
|
|
||||||
# Update all dependencies
|
# Update all dependencies
|
||||||
update: update-api update-frontend
|
update: update-backend update-frontend
|
||||||
|
|
||||||
# Update Go API dependencies
|
# Update Go backend dependencies
|
||||||
update-api:
|
update-backend:
|
||||||
@echo "$(GREEN)Updating Go dependencies...$(NC)"
|
@echo "$(GREEN)Updating Go dependencies...$(NC)"
|
||||||
@for dir in $$(find api -name go.mod -exec dirname {} \;); do \
|
@for dir in $$(find api -name go.mod -exec dirname {} \;); do \
|
||||||
echo "Updating $$dir..."; \
|
echo "Updating $$dir..."; \
|
||||||
@@ -352,11 +391,11 @@ update-frontend:
|
|||||||
@echo "$(GREEN)✅ Flutter dependencies updated$(NC)"
|
@echo "$(GREEN)✅ Flutter dependencies updated$(NC)"
|
||||||
|
|
||||||
# Run all tests
|
# Run all tests
|
||||||
test: test-api test-frontend
|
test: test-backend test-frontend
|
||||||
|
|
||||||
# Run Go API tests
|
# Run Go backend tests
|
||||||
test-api:
|
test-backend:
|
||||||
@echo "$(GREEN)Running API tests...$(NC)"
|
@echo "$(GREEN)Running backend tests...$(NC)"
|
||||||
@failed=""; \
|
@failed=""; \
|
||||||
for dir in $$(find api -name go.mod -exec dirname {} \;); do \
|
for dir in $$(find api -name go.mod -exec dirname {} \;); do \
|
||||||
echo "Testing $$dir..."; \
|
echo "Testing $$dir..."; \
|
||||||
@@ -366,7 +405,7 @@ test-api:
|
|||||||
echo "$(YELLOW)Failed:$$failed$(NC)"; \
|
echo "$(YELLOW)Failed:$$failed$(NC)"; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi
|
fi
|
||||||
@echo "$(GREEN)✅ All API tests passed$(NC)"
|
@echo "$(GREEN)✅ All backend tests passed$(NC)"
|
||||||
|
|
||||||
# Run Flutter tests
|
# Run Flutter tests
|
||||||
test-frontend:
|
test-frontend:
|
||||||
@@ -374,3 +413,18 @@ test-frontend:
|
|||||||
@cd frontend/pshared && flutter test
|
@cd frontend/pshared && flutter test
|
||||||
@cd frontend/pweb && flutter test
|
@cd frontend/pweb && flutter test
|
||||||
@echo "$(GREEN)✅ All frontend tests passed$(NC)"
|
@echo "$(GREEN)✅ All frontend tests passed$(NC)"
|
||||||
|
|
||||||
|
# Run Go backend linting
|
||||||
|
lint-backend:
|
||||||
|
@echo "$(GREEN)Running backend linting...$(NC)"
|
||||||
|
@mkdir -p "$(BACKEND_GOCACHE)" "$(BACKEND_GOLANGCI_LINT_CACHE)"
|
||||||
|
@failed=""; \
|
||||||
|
for dir in $$(find api -name go.mod -exec dirname {} \;); do \
|
||||||
|
echo "Linting $$dir..."; \
|
||||||
|
(cd "$$dir" && GOCACHE="$(BACKEND_GOCACHE)" GOLANGCI_LINT_CACHE="$(BACKEND_GOLANGCI_LINT_CACHE)" golangci-lint run --allow-serial-runners --allow-parallel-runners ./...) || failed="$$failed $$dir"; \
|
||||||
|
done; \
|
||||||
|
if [ -n "$$failed" ]; then \
|
||||||
|
echo "$(YELLOW)Lint failed:$$failed$(NC)"; \
|
||||||
|
exit 1; \
|
||||||
|
fi
|
||||||
|
@echo "$(GREEN)✅ All backend lint checks passed$(NC)"
|
||||||
|
|||||||
38
README.md
38
README.md
@@ -25,14 +25,15 @@ Financial services platform providing payment orchestration, ledger accounting,
|
|||||||
| Gateway Chain | `api/gateway/chain/` | EVM blockchain gateway |
|
| Gateway Chain | `api/gateway/chain/` | EVM blockchain gateway |
|
||||||
| Gateway TRON | `api/gateway/tron/` | TRON blockchain gateway |
|
| Gateway TRON | `api/gateway/tron/` | TRON blockchain gateway |
|
||||||
| Gateway Aurora | `api/gateway/aurora/` | Card payouts simulator |
|
| Gateway Aurora | `api/gateway/aurora/` | Card payouts simulator |
|
||||||
|
| Gateway ChimeraSettle | `api/gateway/chsettle/` | Dummy settlement simulator (fast/slow/success/fail/stuck) |
|
||||||
| Gateway MNTX | `api/gateway/mntx/` | Card payouts |
|
| Gateway MNTX | `api/gateway/mntx/` | Card payouts |
|
||||||
| Gateway TGSettle | `api/gateway/tgsettle/` | Telegram settlements with MNTX |
|
| Gateway TGSettle (legacy) | `api/gateway/tgsettle/` | Legacy Telegram settlement gateway (not used in dev compose) |
|
||||||
| Notification | `api/notification/` | Notifications |
|
| Notification | `api/notification/` | Notifications |
|
||||||
| BFF | `api/edge/bff/` | Backend for frontend |
|
| BFF | `api/edge/bff/` | Backend for frontend |
|
||||||
| Callbacks | `api/edge/callbacks/` | Webhook callbacks delivery |
|
| Callbacks | `api/edge/callbacks/` | Webhook callbacks delivery |
|
||||||
| Frontend | `frontend/pweb/` | Flutter web UI |
|
| Frontend | `frontend/pweb/` | Flutter web UI |
|
||||||
|
|
||||||
Gateway note: current dev compose workflows (`make services-up`, `make build-gateways`) use Aurora for card-payout flows (`chain`, `tron`, `aurora`, `tgsettle`). The MNTX gateway codebase is retained separately for Monetix-specific integration.
|
Gateway note: current dev compose workflows (`make services-up`, `make build-gateways`) use (`chain`, `tron`, `aurora`, `chsettle`). ChimeraSettle is the settlement simulator for test flows; it supports deterministic behavior routing via explicit scenario override and amount buckets. TGSettle remains in-repo as legacy code and is not started by default in dev compose.
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
@@ -87,8 +88,8 @@ make list-services # Show service names, ports, and descriptions
|
|||||||
make build-core # discovery, ledger, fees, documents
|
make build-core # discovery, ledger, fees, documents
|
||||||
make build-fx # oracle, ingestor
|
make build-fx # oracle, ingestor
|
||||||
make build-payments # orchestrator, quotation, methods
|
make build-payments # orchestrator, quotation, methods
|
||||||
make build-gateways # chain, tron, aurora, tgsettle
|
make build-gateways # chain, tron, aurora, chsettle
|
||||||
make build-api # notification, callbacks, bff
|
make build-backend # notification, callbacks, bff
|
||||||
make build-frontend # Flutter web UI
|
make build-frontend # Flutter web UI
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -96,24 +97,43 @@ make build-frontend # Flutter web UI
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
make generate # Generate all code (protobuf + Flutter)
|
make generate # Generate all code (protobuf + Flutter)
|
||||||
make generate-api # Generate protobuf code only
|
make generate-backend # Generate protobuf code only
|
||||||
make generate-frontend # Generate Flutter code only (build_runner)
|
make generate-frontend # Generate Flutter code only (build_runner)
|
||||||
make proto # Alias for generate-api
|
make proto # Alias for generate-backend
|
||||||
```
|
```
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make test # Run all tests (API + frontend)
|
make test # Run all tests (backend + frontend)
|
||||||
make test-api # Run Go API tests only
|
make test-backend # Run Go backend tests only
|
||||||
make test-frontend # Run Flutter tests only
|
make test-frontend # Run Flutter tests only
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Backend CI Bypass Tags
|
||||||
|
|
||||||
|
Backend Woodpecker module pipelines now run both lint and tests before image build/deploy.
|
||||||
|
If you intentionally need to bypass checks for a specific commit, include one of these tags in the commit message:
|
||||||
|
|
||||||
|
```text
|
||||||
|
[skip-lint:<service>] # Skip lint for one backend service pipeline
|
||||||
|
[skip-lint] # Skip lint for all backend service pipelines
|
||||||
|
[skip-tests:<service>] # Skip tests for one backend service pipeline
|
||||||
|
[skip-tests] # Skip tests for all backend service pipelines
|
||||||
|
[skip-autotests:<service>] # Alias for skip-tests:<service>
|
||||||
|
[skip-autotests] # Alias for skip-tests
|
||||||
|
[skip-checks:<service>] # Skip both lint and tests for one backend service pipeline
|
||||||
|
[skip-checks] # Skip both lint and tests for all backend service pipelines
|
||||||
|
```
|
||||||
|
|
||||||
|
`<service>` must match the backend pipeline key used by CI:
|
||||||
|
`bff`, `callbacks`, `billing_documents`, `billing_fees`, `discovery`, `fx_ingestor`, `fx_oracle`, `gateway_chain`, `gateway_mntx`, `gateway_tgsettle`, `gateway_tron`, `ledger`, `notification`, `payments_methods`, `payments_orchestrator`, `payments_quotation`.
|
||||||
|
|
||||||
### Update Dependencies
|
### Update Dependencies
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
make update # Update all Go and Flutter dependencies
|
make update # Update all Go and Flutter dependencies
|
||||||
make update-api # Update Go dependencies only
|
make update-backend # Update Go dependencies only
|
||||||
make update-frontend # Update Flutter dependencies only
|
make update-frontend # Update Flutter dependencies only
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
7
SETUP.md
7
SETUP.md
@@ -137,10 +137,11 @@ make infra-up
|
|||||||
make services-up
|
make services-up
|
||||||
|
|
||||||
# Or start specific service groups
|
# Or start specific service groups
|
||||||
make build-core # discovery, ledger, billing-fees
|
make build-core # discovery, ledger, billing-fees, billing-documents
|
||||||
make build-fx # fx-oracle, fx-ingestor
|
make build-fx # fx-oracle, fx-ingestor
|
||||||
make build-payments # payments-orchestrator
|
make build-payments # payments-orchestrator, payments-quotation, payments-methods
|
||||||
make build-gateways # chain, mntx, tgsettle
|
make build-gateways # chain, tron, aurora, chsettle
|
||||||
|
make build-backend # notification, callbacks, bff
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|||||||
@@ -1,196 +1,47 @@
|
|||||||
# See the dedicated "version" documentation section.
|
|
||||||
version: "2"
|
version: "2"
|
||||||
linters:
|
linters:
|
||||||
# Default set of linters.
|
default: none
|
||||||
# The value can be:
|
|
||||||
# - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
|
|
||||||
# - `all`: enables all linters by default.
|
|
||||||
# - `none`: disables all linters by default.
|
|
||||||
# - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
|
|
||||||
# Default: standard
|
|
||||||
default: all
|
|
||||||
# Enable specific linter.
|
|
||||||
enable:
|
enable:
|
||||||
- arangolint
|
|
||||||
- asasalint
|
|
||||||
- asciicheck
|
|
||||||
- bidichk
|
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- canonicalheader
|
- canonicalheader
|
||||||
- containedctx
|
|
||||||
- contextcheck
|
|
||||||
- copyloopvar
|
- copyloopvar
|
||||||
- cyclop
|
|
||||||
- decorder
|
|
||||||
- dogsled
|
|
||||||
- dupl
|
|
||||||
- dupword
|
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- embeddedstructfieldcheck
|
|
||||||
- err113
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- errchkjson
|
- errchkjson
|
||||||
- errname
|
- errname
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
|
||||||
- exptostd
|
|
||||||
- fatcontext
|
|
||||||
- forbidigo
|
|
||||||
- forcetypeassert
|
|
||||||
- funcorder
|
|
||||||
- funlen
|
|
||||||
- ginkgolinter
|
|
||||||
- gocheckcompilerdirectives
|
|
||||||
- gochecknoglobals
|
|
||||||
- gochecknoinits
|
|
||||||
- gochecksumtype
|
|
||||||
- gocognit
|
|
||||||
- goconst
|
|
||||||
- gocritic
|
|
||||||
- gocyclo
|
|
||||||
- godoclint
|
|
||||||
- godot
|
|
||||||
- godox
|
|
||||||
- goheader
|
|
||||||
- gomodguard
|
|
||||||
- goprintffuncname
|
|
||||||
- gosec
|
- gosec
|
||||||
- gosmopolitan
|
|
||||||
- govet
|
- govet
|
||||||
- grouper
|
|
||||||
- iface
|
|
||||||
- importas
|
|
||||||
- inamedparam
|
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- interfacebloat
|
|
||||||
- intrange
|
|
||||||
- iotamixing
|
|
||||||
- ireturn
|
|
||||||
- lll
|
|
||||||
- loggercheck
|
|
||||||
- maintidx
|
|
||||||
- makezero
|
|
||||||
- mirror
|
|
||||||
- misspell
|
|
||||||
- mnd
|
|
||||||
- modernize
|
|
||||||
- musttag
|
|
||||||
- nakedret
|
|
||||||
- nestif
|
|
||||||
- nilerr
|
- nilerr
|
||||||
- nilnesserr
|
- nilnesserr
|
||||||
- nilnil
|
- nilnil
|
||||||
- nlreturn
|
|
||||||
- noctx
|
- noctx
|
||||||
- noinlineerr
|
|
||||||
- nolintlint
|
|
||||||
- nonamedreturns
|
|
||||||
- nosprintfhostport
|
|
||||||
- paralleltest
|
|
||||||
- perfsprint
|
|
||||||
- prealloc
|
|
||||||
- predeclared
|
|
||||||
- promlinter
|
|
||||||
- protogetter
|
|
||||||
- reassign
|
|
||||||
- recvcheck
|
|
||||||
- revive
|
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- sloglint
|
|
||||||
- spancheck
|
|
||||||
- sqlclosecheck
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- tagalign
|
|
||||||
- tagliatelle
|
|
||||||
- testableexamples
|
|
||||||
- testifylint
|
|
||||||
- testpackage
|
|
||||||
- thelper
|
|
||||||
- tparallel
|
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
|
||||||
- unqueryvet
|
|
||||||
- unused
|
|
||||||
- usestdlibvars
|
|
||||||
- usetesting
|
|
||||||
- varnamelen
|
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
|
||||||
- wsl_v5
|
|
||||||
- zerologlint
|
|
||||||
# Disable specific linters.
|
|
||||||
disable:
|
disable:
|
||||||
- depguard
|
- depguard
|
||||||
- exhaustruct
|
- exhaustruct
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- wsl
|
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
# All available settings of specific linters.
|
- cyclop
|
||||||
# See the dedicated "linters.settings" documentation section.
|
- dupl
|
||||||
settings:
|
- funlen
|
||||||
wsl_v5:
|
- gocognit
|
||||||
allow-first-in-block: true
|
- gocyclo
|
||||||
allow-whole-block: false
|
- ireturn
|
||||||
branch-max-lines: 2
|
- lll
|
||||||
|
- mnd
|
||||||
# Defines a set of rules to ignore issues.
|
- nestif
|
||||||
# It does not skip the analysis, and so does not ignore "typecheck" errors.
|
- nlreturn
|
||||||
exclusions:
|
- noinlineerr
|
||||||
# Mode of the generated files analysis.
|
- paralleltest
|
||||||
#
|
- tagliatelle
|
||||||
# - `strict`: sources are excluded by strictly following the Go generated file convention.
|
- testpackage
|
||||||
# Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$`
|
- varnamelen
|
||||||
# This line must appear before the first non-comment, non-blank text in the file.
|
- wsl_v5
|
||||||
# https://go.dev/s/generatedcode
|
|
||||||
# - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc.
|
|
||||||
# - `disable`: disable the generated files exclusion.
|
|
||||||
#
|
|
||||||
# Default: strict
|
|
||||||
generated: lax
|
|
||||||
# Log a warning if an exclusion rule is unused.
|
|
||||||
# Default: false
|
|
||||||
warn-unused: true
|
|
||||||
# Predefined exclusion rules.
|
|
||||||
# Default: []
|
|
||||||
presets:
|
|
||||||
- comments
|
|
||||||
- std-error-handling
|
|
||||||
- common-false-positives
|
|
||||||
- legacy
|
|
||||||
# Excluding configuration per-path, per-linter, per-text and per-source.
|
|
||||||
rules:
|
|
||||||
# Exclude some linters from running on tests files.
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- funlen
|
|
||||||
- gocyclo
|
|
||||||
- errcheck
|
|
||||||
- dupl
|
|
||||||
- gosec
|
|
||||||
# Run some linter only for test files by excluding its issues for everything else.
|
|
||||||
- path-except: _test\.go
|
|
||||||
linters:
|
|
||||||
- forbidigo
|
|
||||||
# Exclude known linters from partially hard-vendored code,
|
|
||||||
# which is impossible to exclude via `nolint` comments.
|
|
||||||
# `/` will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
- path: internal/hmac/
|
|
||||||
text: "weak cryptographic primitive"
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
||||||
# Exclude some `staticcheck` messages.
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "SA9003:"
|
|
||||||
# Exclude `lll` issues for long lines with `go:generate`.
|
|
||||||
- linters:
|
|
||||||
- lll
|
|
||||||
source: "^//go:generate "
|
|
||||||
# Which file paths to exclude: they will be analyzed, but issues from them won't be reported.
|
|
||||||
# "/" will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
# Default: []
|
|
||||||
paths: []
|
|
||||||
# Which file paths to not exclude.
|
|
||||||
# Default: []
|
|
||||||
paths-except: []
|
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ database:
|
|||||||
|
|
||||||
documents:
|
documents:
|
||||||
issuer:
|
issuer:
|
||||||
legal_name: "Sendico Ltd"
|
|
||||||
legal_address: "12 Market Street, London, UK"
|
|
||||||
logo_path: "assets/logo.png"
|
logo_path: "assets/logo.png"
|
||||||
templates:
|
templates:
|
||||||
acceptance_path: "templates/acceptance.tpl"
|
acceptance_path: "templates/acceptance.tpl"
|
||||||
|
|||||||
@@ -24,8 +24,6 @@ database:
|
|||||||
|
|
||||||
documents:
|
documents:
|
||||||
issuer:
|
issuer:
|
||||||
legal_name: "Sendico Ltd"
|
|
||||||
legal_address: "12 Market Street, London, UK"
|
|
||||||
logo_path: "/app/assets/logo.png"
|
logo_path: "/app/assets/logo.png"
|
||||||
templates:
|
templates:
|
||||||
acceptance_path: "/app/templates/acceptance.tpl"
|
acceptance_path: "/app/templates/acceptance.tpl"
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2 v1.41.3
|
github.com/aws/aws-sdk-go-v2 v1.41.3
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4
|
||||||
github.com/jung-kurt/gofpdf v1.16.2
|
github.com/jung-kurt/gofpdf v1.16.2
|
||||||
github.com/prometheus/client_golang v1.23.2
|
github.com/prometheus/client_golang v1.23.2
|
||||||
github.com/shopspring/decimal v1.4.0
|
github.com/shopspring/decimal v1.4.0
|
||||||
github.com/tech/sendico/pkg v0.1.0
|
github.com/tech/sendico/pkg v0.1.0
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
||||||
@@ -59,11 +59,11 @@ require (
|
|||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/net v0.51.0 // indirect
|
golang.org/x/net v0.51.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJ
|
|||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 h1:3Y4oma5TiV7tT9wa8zRcdoXwZkGz9Q/wxbEUK7cMuAM=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 h1:qi3e/dmpdONhj1RyIZdi6DKKpDXS5Lb8ftr3p7cyHJc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw=
|
||||||
@@ -30,8 +30,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7su
|
|||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3 h1:+d0SsTvxtIJt4tSJ6wr+jrxEMDa6XeupjRv8H7Qitkk=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3/go.mod h1:ROUNFvFWPwBlOu687WJNQ9cPvd2ccpFrnCiA1YGz50o=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
||||||
@@ -217,8 +217,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
@@ -233,16 +233,16 @@ golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
|||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -260,8 +260,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
116
api/billing/documents/internal/content/content.go
Normal file
116
api/billing/documents/internal/content/content.go
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
package content
|
||||||
|
|
||||||
|
// Issuer details are intentionally centralized to avoid document text drift.
|
||||||
|
const (
|
||||||
|
IssuerLegalName = "SMX Operations Limited"
|
||||||
|
IssuerLegalAddress = "Room 607, 12/F., Block C, Hong Kong Industrial Centre, 489-491 Castle Peak Road, Lai Chi Kok, Hong Kong"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
PDFTitleActOfAcceptance = "Act of Acceptance"
|
||||||
|
DocumentIntegrityHashPrefix = "Document integrity hash: "
|
||||||
|
)
|
||||||
|
|
||||||
|
// AcceptanceTemplateContent contains all static copy used by the acceptance act template.
|
||||||
|
type AcceptanceTemplateContent struct {
|
||||||
|
Title string
|
||||||
|
Subtitle string
|
||||||
|
MetaDateLabel string
|
||||||
|
MetaActNumberLabel string
|
||||||
|
SectionParties string
|
||||||
|
PartiesIntro string
|
||||||
|
PartyExecutorLabel string
|
||||||
|
PartyStatusLabel string
|
||||||
|
PartyStatusValue string
|
||||||
|
SectionBasis string
|
||||||
|
BasisLine1 string
|
||||||
|
BasisLine2 string
|
||||||
|
SectionServicesRendered string
|
||||||
|
ServicesRenderedLine1 string
|
||||||
|
ServicesRenderedLine2 string
|
||||||
|
SectionRemuneration string
|
||||||
|
RemunerationHeaderDesc string
|
||||||
|
RemunerationHeaderAmount string
|
||||||
|
RemunerationServicesDesc string
|
||||||
|
SectionConfirmation string
|
||||||
|
ConfirmationLine1 string
|
||||||
|
ConfirmationLine2 string
|
||||||
|
ConfirmationPaymentLine1 string
|
||||||
|
ConfirmationPaymentLine2 string
|
||||||
|
SectionSignatures string
|
||||||
|
SignatureCustomerLine string
|
||||||
|
SignatureExecutorLine string
|
||||||
|
}
|
||||||
|
|
||||||
|
var AcceptanceTemplate = AcceptanceTemplateContent{
|
||||||
|
Title: "ACT OF ACCEPTANCE OF SERVICES",
|
||||||
|
Subtitle: "under the Public Offer Agreement",
|
||||||
|
MetaDateLabel: "Date",
|
||||||
|
MetaActNumberLabel: "Act No",
|
||||||
|
SectionParties: "PARTIES",
|
||||||
|
PartiesIntro: "This Act is made between the following Parties.",
|
||||||
|
PartyExecutorLabel: "Executor",
|
||||||
|
PartyStatusLabel: "Status",
|
||||||
|
PartyStatusValue: "Individual",
|
||||||
|
SectionBasis: "BASIS",
|
||||||
|
BasisLine1: "This Act is issued pursuant to the Public Offer Agreement",
|
||||||
|
BasisLine2: "accepted by the Executor by joining the offer.",
|
||||||
|
SectionServicesRendered: "SERVICES RENDERED",
|
||||||
|
ServicesRenderedLine1: "The Executor has rendered services to the Customer",
|
||||||
|
ServicesRenderedLine2: "in accordance with the terms of the Public Offer Agreement.",
|
||||||
|
SectionRemuneration: "REMUNERATION",
|
||||||
|
RemunerationHeaderDesc: "Description",
|
||||||
|
RemunerationHeaderAmount: "Amount",
|
||||||
|
RemunerationServicesDesc: "Services rendered under the Public Offer Agreement",
|
||||||
|
SectionConfirmation: "CONFIRMATION",
|
||||||
|
ConfirmationLine1: "The Customer confirms that the services were rendered properly",
|
||||||
|
ConfirmationLine2: "and accepted without any claims.",
|
||||||
|
ConfirmationPaymentLine1: "The remuneration for the services was paid to the Executor",
|
||||||
|
ConfirmationPaymentLine2: "using the bank card details provided by the Executor.",
|
||||||
|
SectionSignatures: "SIGNATURES",
|
||||||
|
SignatureCustomerLine: "Customer ___________________________",
|
||||||
|
SignatureExecutorLine: "Executor ___________________________",
|
||||||
|
}
|
||||||
|
|
||||||
|
// OperationDocumentContent contains all static copy for operation documents.
|
||||||
|
type OperationDocumentContent struct {
|
||||||
|
Title string
|
||||||
|
Subtitle string
|
||||||
|
MetaDocumentType string
|
||||||
|
SectionOperation string
|
||||||
|
SectionFailure string
|
||||||
|
RowOrganization string
|
||||||
|
RowGatewayService string
|
||||||
|
RowOperationRef string
|
||||||
|
RowPaymentRef string
|
||||||
|
RowCode string
|
||||||
|
RowState string
|
||||||
|
RowLabel string
|
||||||
|
RowStartedAtUTC string
|
||||||
|
RowCompletedAtUTC string
|
||||||
|
RowAmount string
|
||||||
|
RowFailureCode string
|
||||||
|
RowFailureReason string
|
||||||
|
MissingValuePlaceholder string
|
||||||
|
}
|
||||||
|
|
||||||
|
var OperationDocument = OperationDocumentContent{
|
||||||
|
Title: "OPERATION BILLING DOCUMENT",
|
||||||
|
Subtitle: "Gateway operation statement",
|
||||||
|
MetaDocumentType: "Document Type: Operation",
|
||||||
|
SectionOperation: "OPERATION DETAILS",
|
||||||
|
SectionFailure: "FAILURE DETAILS",
|
||||||
|
RowOrganization: "Organization",
|
||||||
|
RowGatewayService: "Gateway Service",
|
||||||
|
RowOperationRef: "Operation Ref",
|
||||||
|
RowPaymentRef: "Payment Ref",
|
||||||
|
RowCode: "Code",
|
||||||
|
RowState: "State",
|
||||||
|
RowLabel: "Label",
|
||||||
|
RowStartedAtUTC: "Started At (UTC)",
|
||||||
|
RowCompletedAtUTC: "Completed At (UTC)",
|
||||||
|
RowAmount: "Amount",
|
||||||
|
RowFailureCode: "Failure Code",
|
||||||
|
RowFailureReason: "Failure Reason",
|
||||||
|
MissingValuePlaceholder: "n/a",
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package docstore
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -36,8 +37,12 @@ func (s *LocalStore) Save(ctx context.Context, key string, data []byte) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
path := filepath.Join(s.rootPath, filepath.Clean(key))
|
path, err := resolveStoragePath(s.rootPath, key)
|
||||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.MkdirAll(filepath.Dir(path), 0o750); err != nil {
|
||||||
s.logger.Warn("Failed to create document directory", zap.Error(err), zap.String("path", path))
|
s.logger.Warn("Failed to create document directory", zap.Error(err), zap.String("path", path))
|
||||||
|
|
||||||
return err
|
return err
|
||||||
@@ -56,8 +61,12 @@ func (s *LocalStore) Load(ctx context.Context, key string) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
path := filepath.Join(s.rootPath, filepath.Clean(key))
|
path, err := resolveStoragePath(s.rootPath, key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
//nolint:gosec // path is constrained by resolveStoragePath to stay within configured root.
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Warn("Failed to read document file", zap.Error(err), zap.String("path", path))
|
s.logger.Warn("Failed to read document file", zap.Error(err), zap.String("path", path))
|
||||||
@@ -69,3 +78,32 @@ func (s *LocalStore) Load(ctx context.Context, key string) ([]byte, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var _ Store = (*LocalStore)(nil)
|
var _ Store = (*LocalStore)(nil)
|
||||||
|
|
||||||
|
func resolveStoragePath(rootPath string, key string) (string, error) {
|
||||||
|
cleanKey := filepath.Clean(strings.TrimSpace(key))
|
||||||
|
if cleanKey == "" || cleanKey == "." {
|
||||||
|
return "", merrors.InvalidArgument("docstore: key is required")
|
||||||
|
}
|
||||||
|
|
||||||
|
if filepath.IsAbs(cleanKey) {
|
||||||
|
return "", merrors.InvalidArgument("docstore: absolute keys are not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
|
rootAbs, err := filepath.Abs(rootPath)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("resolve local store root: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
path := filepath.Join(rootAbs, cleanKey)
|
||||||
|
pathAbs, err := filepath.Abs(path)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("resolve local store path: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prefix := rootAbs + string(filepath.Separator)
|
||||||
|
if pathAbs != rootAbs && !strings.HasPrefix(pathAbs, prefix) {
|
||||||
|
return "", merrors.InvalidArgument("docstore: key escapes root path")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathAbs, nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -124,7 +124,11 @@ func (s *S3Store) Load(ctx context.Context, key string) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer obj.Body.Close()
|
defer func() {
|
||||||
|
if closeErr := obj.Body.Close(); closeErr != nil {
|
||||||
|
s.logger.Warn("Failed to close document body", zap.Error(closeErr), zap.String("key", key))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
return io.ReadAll(obj.Body)
|
return io.ReadAll(obj.Body)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,24 @@ package documents
|
|||||||
import (
|
import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
"github.com/tech/sendico/billing/documents/internal/docstore"
|
"github.com/tech/sendico/billing/documents/internal/docstore"
|
||||||
"github.com/tech/sendico/billing/documents/renderer"
|
"github.com/tech/sendico/billing/documents/renderer"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config holds document service settings loaded from YAML.
|
// Config holds document service settings loaded from YAML.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Issuer renderer.Issuer `yaml:"issuer"`
|
Issuer IssuerConfig `yaml:"issuer"`
|
||||||
Templates TemplateConfig `yaml:"templates"`
|
Templates TemplateConfig `yaml:"templates"`
|
||||||
Protection ProtectionConfig `yaml:"protection"`
|
Protection ProtectionConfig `yaml:"protection"`
|
||||||
Storage docstore.Config `yaml:"storage"`
|
Storage docstore.Config `yaml:"storage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IssuerConfig defines issuer settings that are environment-specific.
|
||||||
|
type IssuerConfig struct {
|
||||||
|
LogoPath string `yaml:"logo_path"`
|
||||||
|
}
|
||||||
|
|
||||||
// TemplateConfig defines document template locations.
|
// TemplateConfig defines document template locations.
|
||||||
type TemplateConfig struct {
|
type TemplateConfig struct {
|
||||||
AcceptancePath string `yaml:"acceptance_path"`
|
AcceptancePath string `yaml:"acceptance_path"`
|
||||||
@@ -25,6 +31,14 @@ type ProtectionConfig struct {
|
|||||||
OwnerPassword string `yaml:"owner_password"`
|
OwnerPassword string `yaml:"owner_password"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c Config) IssuerDetails() renderer.Issuer {
|
||||||
|
return renderer.Issuer{
|
||||||
|
LegalName: content.IssuerLegalName,
|
||||||
|
LegalAddress: content.IssuerLegalAddress,
|
||||||
|
LogoPath: c.Issuer.LogoPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c Config) AcceptanceTemplatePath() string {
|
func (c Config) AcceptanceTemplatePath() string {
|
||||||
if strings.TrimSpace(c.Templates.AcceptancePath) == "" {
|
if strings.TrimSpace(c.Templates.AcceptancePath) == "" {
|
||||||
return "templates/acceptance.tpl"
|
return "templates/acceptance.tpl"
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import (
|
|||||||
|
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||||
documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
|
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
)
|
)
|
||||||
@@ -17,7 +16,6 @@ var (
|
|||||||
|
|
||||||
requestsTotal *prometheus.CounterVec
|
requestsTotal *prometheus.CounterVec
|
||||||
requestLatency *prometheus.HistogramVec
|
requestLatency *prometheus.HistogramVec
|
||||||
batchSize prometheus.Histogram
|
|
||||||
documentBytes *prometheus.HistogramVec
|
documentBytes *prometheus.HistogramVec
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,16 +42,6 @@ func initMetrics() {
|
|||||||
[]string{"call", "status", "doc_type"},
|
[]string{"call", "status", "doc_type"},
|
||||||
)
|
)
|
||||||
|
|
||||||
batchSize = promauto.NewHistogram(
|
|
||||||
prometheus.HistogramOpts{
|
|
||||||
Namespace: "billing",
|
|
||||||
Subsystem: "documents",
|
|
||||||
Name: "batch_size",
|
|
||||||
Help: "Number of payment references in batch resolution requests.",
|
|
||||||
Buckets: []float64{0, 1, 2, 5, 10, 20, 50, 100, 250, 500},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
|
|
||||||
documentBytes = promauto.NewHistogramVec(
|
documentBytes = promauto.NewHistogramVec(
|
||||||
prometheus.HistogramOpts{
|
prometheus.HistogramOpts{
|
||||||
Namespace: "billing",
|
Namespace: "billing",
|
||||||
@@ -67,18 +55,14 @@ func initMetrics() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func observeRequest(call string, docType documentsv1.DocumentType, statusLabel string, took time.Duration) {
|
func observeRequest(call string, documentKind, statusLabel string, took time.Duration) {
|
||||||
typeLabel := docTypeLabel(docType)
|
kind := docKindLabel(documentKind)
|
||||||
requestsTotal.WithLabelValues(call, statusLabel, typeLabel).Inc()
|
requestsTotal.WithLabelValues(call, statusLabel, kind).Inc()
|
||||||
requestLatency.WithLabelValues(call, statusLabel, typeLabel).Observe(took.Seconds())
|
requestLatency.WithLabelValues(call, statusLabel, kind).Observe(took.Seconds())
|
||||||
}
|
}
|
||||||
|
|
||||||
func observeBatchSize(size int) {
|
func observeDocumentBytes(documentKind string, size int) {
|
||||||
batchSize.Observe(float64(size))
|
documentBytes.WithLabelValues(docKindLabel(documentKind)).Observe(float64(size))
|
||||||
}
|
|
||||||
|
|
||||||
func observeDocumentBytes(docType documentsv1.DocumentType, size int) {
|
|
||||||
documentBytes.WithLabelValues(docTypeLabel(docType)).Observe(float64(size))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func statusFromError(err error) string {
|
func statusFromError(err error) string {
|
||||||
@@ -100,10 +84,10 @@ func statusFromError(err error) string {
|
|||||||
return strings.ToLower(code.String())
|
return strings.ToLower(code.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func docTypeLabel(docType documentsv1.DocumentType) string {
|
func docKindLabel(documentKind string) string {
|
||||||
label := docType.String()
|
label := strings.TrimSpace(documentKind)
|
||||||
if label == "" {
|
if label == "" {
|
||||||
return "DOCUMENT_TYPE_UNSPECIFIED"
|
return "operation"
|
||||||
}
|
}
|
||||||
|
|
||||||
return label
|
return label
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import (
|
|||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/tech/sendico/billing/documents/internal/appversion"
|
"github.com/tech/sendico/billing/documents/internal/appversion"
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
"github.com/tech/sendico/billing/documents/internal/docstore"
|
"github.com/tech/sendico/billing/documents/internal/docstore"
|
||||||
"github.com/tech/sendico/billing/documents/renderer"
|
"github.com/tech/sendico/billing/documents/renderer"
|
||||||
"github.com/tech/sendico/billing/documents/storage"
|
"github.com/tech/sendico/billing/documents/storage"
|
||||||
@@ -145,94 +145,6 @@ func (s *Service) Shutdown() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) BatchResolveDocuments(ctx context.Context, req *documentsv1.BatchResolveDocumentsRequest) (resp *documentsv1.BatchResolveDocumentsResponse, err error) {
|
|
||||||
start := time.Now()
|
|
||||||
paymentRefs := 0
|
|
||||||
if req != nil {
|
|
||||||
paymentRefs = len(req.GetPaymentRefs())
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := s.logger.With(zap.Int("payment_refs", paymentRefs))
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
statusLabel := statusFromError(err)
|
|
||||||
observeRequest("batch_resolve", documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED, statusLabel, time.Since(start))
|
|
||||||
observeBatchSize(paymentRefs)
|
|
||||||
|
|
||||||
itemsCount := 0
|
|
||||||
if resp != nil {
|
|
||||||
itemsCount = len(resp.GetItems())
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := []zap.Field{
|
|
||||||
zap.String("status", statusLabel),
|
|
||||||
zap.Duration("duration", time.Since(start)),
|
|
||||||
zap.Int("items", itemsCount),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Warn("BatchResolveDocuments failed", append(fields, zap.Error(err))...)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("BatchResolveDocuments finished", fields...)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_ = ctx
|
|
||||||
err = status.Error(codes.Unimplemented, "payment-level document flow removed; use GetOperationDocument")
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetDocument(ctx context.Context, req *documentsv1.GetDocumentRequest) (resp *documentsv1.GetDocumentResponse, err error) {
|
|
||||||
start := time.Now()
|
|
||||||
docType := documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED
|
|
||||||
paymentRef := ""
|
|
||||||
if req != nil {
|
|
||||||
docType = req.GetType()
|
|
||||||
paymentRef = strings.TrimSpace(req.GetPaymentRef())
|
|
||||||
}
|
|
||||||
|
|
||||||
logger := s.logger.With(
|
|
||||||
zap.String("payment_ref", paymentRef),
|
|
||||||
zap.String("document_type", docTypeLabel(docType)),
|
|
||||||
)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
statusLabel := statusFromError(err)
|
|
||||||
observeRequest("get_document", docType, statusLabel, time.Since(start))
|
|
||||||
|
|
||||||
if resp != nil {
|
|
||||||
observeDocumentBytes(docType, len(resp.GetContent()))
|
|
||||||
}
|
|
||||||
|
|
||||||
contentBytes := 0
|
|
||||||
if resp != nil {
|
|
||||||
contentBytes = len(resp.GetContent())
|
|
||||||
}
|
|
||||||
|
|
||||||
fields := []zap.Field{
|
|
||||||
zap.String("status", statusLabel),
|
|
||||||
zap.Duration("duration", time.Since(start)),
|
|
||||||
zap.Int("content_bytes", contentBytes),
|
|
||||||
}
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
logger.Warn("GetDocument failed", append(fields, zap.Error(err))...)
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Info("GetDocument finished", fields...)
|
|
||||||
}()
|
|
||||||
|
|
||||||
_ = ctx
|
|
||||||
err = status.Error(codes.Unimplemented, "payment-level document flow removed; use GetOperationDocument")
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) GetOperationDocument(_ context.Context, req *documentsv1.GetOperationDocumentRequest) (resp *documentsv1.GetDocumentResponse, err error) {
|
func (s *Service) GetOperationDocument(_ context.Context, req *documentsv1.GetOperationDocumentRequest) (resp *documentsv1.GetDocumentResponse, err error) {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
organizationRef := ""
|
organizationRef := ""
|
||||||
@@ -253,11 +165,10 @@ func (s *Service) GetOperationDocument(_ context.Context, req *documentsv1.GetOp
|
|||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
statusLabel := statusFromError(err)
|
statusLabel := statusFromError(err)
|
||||||
docType := documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED
|
observeRequest("get_operation_document", "operation", statusLabel, time.Since(start))
|
||||||
observeRequest("get_operation_document", docType, statusLabel, time.Since(start))
|
|
||||||
|
|
||||||
if resp != nil {
|
if resp != nil {
|
||||||
observeDocumentBytes(docType, len(resp.GetContent()))
|
observeDocumentBytes("operation", len(resp.GetContent()))
|
||||||
}
|
}
|
||||||
|
|
||||||
contentBytes := 0
|
contentBytes := 0
|
||||||
@@ -336,18 +247,6 @@ func (s *Service) startDiscoveryAnnouncer() {
|
|||||||
s.announcer.Start()
|
s.announcer.Start()
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceError string
|
|
||||||
|
|
||||||
func (e serviceError) Error() string {
|
|
||||||
return string(e)
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errStorageUnavailable = serviceError("documents: storage not initialised")
|
|
||||||
errDocStoreUnavailable = serviceError("documents: document store not initialised")
|
|
||||||
errTemplateUnavailable = serviceError("documents: template renderer not initialised")
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *Service) generateActPDF(snapshot model.ActSnapshot) ([]byte, string, error) {
|
func (s *Service) generateActPDF(snapshot model.ActSnapshot) ([]byte, string, error) {
|
||||||
blocks, err := s.template.Render(snapshot)
|
blocks, err := s.template.Render(snapshot)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -363,7 +262,7 @@ func (s *Service) generateOperationPDF(snapshot operationSnapshot) ([]byte, stri
|
|||||||
|
|
||||||
func (s *Service) renderPDFWithIntegrity(blocks []renderer.Block) ([]byte, string, error) {
|
func (s *Service) renderPDFWithIntegrity(blocks []renderer.Block) ([]byte, string, error) {
|
||||||
generated := renderer.Renderer{
|
generated := renderer.Renderer{
|
||||||
Issuer: s.config.Issuer,
|
Issuer: s.config.IssuerDetails(),
|
||||||
OwnerPassword: s.config.Protection.OwnerPassword,
|
OwnerPassword: s.config.Protection.OwnerPassword,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -427,39 +326,41 @@ func operationSnapshotFromRequest(req *documentsv1.GetOperationDocumentRequest)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
||||||
|
documentCopy := content.OperationDocument
|
||||||
|
|
||||||
rows := [][]string{
|
rows := [][]string{
|
||||||
{"Organization", snapshot.OrganizationRef},
|
{documentCopy.RowOrganization, snapshot.OrganizationRef},
|
||||||
{"Gateway Service", snapshot.GatewayService},
|
{documentCopy.RowGatewayService, snapshot.GatewayService},
|
||||||
{"Operation Ref", snapshot.OperationRef},
|
{documentCopy.RowOperationRef, snapshot.OperationRef},
|
||||||
{"Payment Ref", safeValue(snapshot.PaymentRef)},
|
{documentCopy.RowPaymentRef, safeValue(snapshot.PaymentRef)},
|
||||||
{"Code", safeValue(snapshot.OperationCode)},
|
{documentCopy.RowCode, safeValue(snapshot.OperationCode)},
|
||||||
{"State", safeValue(snapshot.OperationState)},
|
{documentCopy.RowState, safeValue(snapshot.OperationState)},
|
||||||
{"Label", safeValue(snapshot.OperationLabel)},
|
{documentCopy.RowLabel, safeValue(snapshot.OperationLabel)},
|
||||||
{"Started At (UTC)", formatSnapshotTime(snapshot.StartedAt)},
|
{documentCopy.RowStartedAtUTC, formatSnapshotTime(snapshot.StartedAt)},
|
||||||
{"Completed At (UTC)", formatSnapshotTime(snapshot.CompletedAt)},
|
{documentCopy.RowCompletedAtUTC, formatSnapshotTime(snapshot.CompletedAt)},
|
||||||
}
|
}
|
||||||
if snapshot.Amount != "" || snapshot.Currency != "" {
|
if snapshot.Amount != "" || snapshot.Currency != "" {
|
||||||
rows = append(rows, []string{"Amount", strings.TrimSpace(strings.TrimSpace(snapshot.Amount) + " " + strings.TrimSpace(snapshot.Currency))})
|
rows = append(rows, []string{documentCopy.RowAmount, strings.TrimSpace(strings.TrimSpace(snapshot.Amount) + " " + strings.TrimSpace(snapshot.Currency))})
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks := []renderer.Block{
|
blocks := []renderer.Block{
|
||||||
{
|
{
|
||||||
Tag: renderer.TagTitle,
|
Tag: renderer.TagTitle,
|
||||||
Lines: []string{"OPERATION BILLING DOCUMENT"},
|
Lines: []string{documentCopy.Title},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: renderer.TagSubtitle,
|
Tag: renderer.TagSubtitle,
|
||||||
Lines: []string{"Gateway operation statement"},
|
Lines: []string{documentCopy.Subtitle},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: renderer.TagMeta,
|
Tag: renderer.TagMeta,
|
||||||
Lines: []string{
|
Lines: []string{
|
||||||
"Document Type: Operation",
|
documentCopy.MetaDocumentType,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: renderer.TagSection,
|
Tag: renderer.TagSection,
|
||||||
Lines: []string{"OPERATION DETAILS"},
|
Lines: []string{documentCopy.SectionOperation},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Tag: renderer.TagKV,
|
Tag: renderer.TagKV,
|
||||||
@@ -469,12 +370,12 @@ func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
|||||||
|
|
||||||
if snapshot.FailureCode != "" || snapshot.FailureReason != "" {
|
if snapshot.FailureCode != "" || snapshot.FailureReason != "" {
|
||||||
blocks = append(blocks,
|
blocks = append(blocks,
|
||||||
renderer.Block{Tag: renderer.TagSection, Lines: []string{"FAILURE DETAILS"}},
|
renderer.Block{Tag: renderer.TagSection, Lines: []string{documentCopy.SectionFailure}},
|
||||||
renderer.Block{
|
renderer.Block{
|
||||||
Tag: renderer.TagKV,
|
Tag: renderer.TagKV,
|
||||||
Rows: [][]string{
|
Rows: [][]string{
|
||||||
{"Failure Code", safeValue(snapshot.FailureCode)},
|
{documentCopy.RowFailureCode, safeValue(snapshot.FailureCode)},
|
||||||
{"Failure Reason", safeValue(snapshot.FailureReason)},
|
{documentCopy.RowFailureReason, safeValue(snapshot.FailureReason)},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -485,7 +386,7 @@ func buildOperationBlocks(snapshot operationSnapshot) []renderer.Block {
|
|||||||
|
|
||||||
func formatSnapshotTime(value time.Time) string {
|
func formatSnapshotTime(value time.Time) string {
|
||||||
if value.IsZero() {
|
if value.IsZero() {
|
||||||
return "n/a"
|
return content.OperationDocument.MissingValuePlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
return value.UTC().Format(time.RFC3339)
|
return value.UTC().Format(time.RFC3339)
|
||||||
@@ -494,7 +395,7 @@ func formatSnapshotTime(value time.Time) string {
|
|||||||
func safeValue(value string) string {
|
func safeValue(value string) string {
|
||||||
trimmed := strings.TrimSpace(value)
|
trimmed := strings.TrimSpace(value)
|
||||||
if trimmed == "" {
|
if trimmed == "" {
|
||||||
return "n/a"
|
return content.OperationDocument.MissingValuePlaceholder
|
||||||
}
|
}
|
||||||
|
|
||||||
return trimmed
|
return trimmed
|
||||||
@@ -535,50 +436,3 @@ func sanitizeFilenameComponent(value string) string {
|
|||||||
|
|
||||||
return strings.Trim(b.String(), "_")
|
return strings.Trim(b.String(), "_")
|
||||||
}
|
}
|
||||||
|
|
||||||
func toProtoTypes(types []model.DocumentType) []documentsv1.DocumentType {
|
|
||||||
if len(types) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
result := make([]documentsv1.DocumentType, 0, len(types))
|
|
||||||
for _, t := range types {
|
|
||||||
result = append(result, t.Proto())
|
|
||||||
}
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
func documentStoragePath(paymentRef string, docType documentsv1.DocumentType) string {
|
|
||||||
suffix := "document.pdf"
|
|
||||||
|
|
||||||
switch docType {
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_ACT:
|
|
||||||
suffix = "act.pdf"
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_INVOICE:
|
|
||||||
suffix = "invoice.pdf"
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_RECEIPT:
|
|
||||||
suffix = "receipt.pdf"
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED:
|
|
||||||
// default suffix used
|
|
||||||
}
|
|
||||||
|
|
||||||
return filepath.ToSlash(filepath.Join("documents", paymentRef, suffix))
|
|
||||||
}
|
|
||||||
|
|
||||||
func documentFilename(docType documentsv1.DocumentType, paymentRef string) string {
|
|
||||||
name := "document"
|
|
||||||
|
|
||||||
switch docType {
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_ACT:
|
|
||||||
name = "act"
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_INVOICE:
|
|
||||||
name = "invoice"
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_RECEIPT:
|
|
||||||
name = "receipt"
|
|
||||||
case documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED:
|
|
||||||
// default name used
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("%s_%s.pdf", name, paymentRef)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
"github.com/tech/sendico/billing/documents/renderer"
|
"github.com/tech/sendico/billing/documents/renderer"
|
||||||
"github.com/tech/sendico/billing/documents/storage"
|
"github.com/tech/sendico/billing/documents/storage"
|
||||||
"github.com/tech/sendico/billing/documents/storage/model"
|
"github.com/tech/sendico/billing/documents/storage/model"
|
||||||
@@ -53,38 +54,6 @@ func (s *stubDocumentsStore) ListByPaymentRefs(_ context.Context, _ []string) ([
|
|||||||
|
|
||||||
var _ storage.DocumentsStore = (*stubDocumentsStore)(nil)
|
var _ storage.DocumentsStore = (*stubDocumentsStore)(nil)
|
||||||
|
|
||||||
type memDocStore struct {
|
|
||||||
data map[string][]byte
|
|
||||||
saveCount int
|
|
||||||
loadCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
func newMemDocStore() *memDocStore {
|
|
||||||
return &memDocStore{data: map[string][]byte{}}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memDocStore) Save(_ context.Context, key string, data []byte) error {
|
|
||||||
m.saveCount++
|
|
||||||
copyData := make([]byte, len(data))
|
|
||||||
copy(copyData, data)
|
|
||||||
m.data[key] = copyData
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memDocStore) Load(_ context.Context, key string) ([]byte, error) {
|
|
||||||
m.loadCount++
|
|
||||||
data := m.data[key]
|
|
||||||
copyData := make([]byte, len(data))
|
|
||||||
copy(copyData, data)
|
|
||||||
|
|
||||||
return copyData, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *memDocStore) Counts() (int, int) {
|
|
||||||
return m.saveCount, m.loadCount
|
|
||||||
}
|
|
||||||
|
|
||||||
type stubTemplate struct {
|
type stubTemplate struct {
|
||||||
blocks []renderer.Block
|
blocks []renderer.Block
|
||||||
calls int
|
calls int
|
||||||
@@ -112,15 +81,7 @@ func TestGenerateActPDF_IdempotentAndHashed(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg := Config{
|
|
||||||
Issuer: renderer.Issuer{
|
|
||||||
LegalName: "Sendico Ltd",
|
|
||||||
LegalAddress: "12 Market Street, London, UK",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
svc := NewService(zap.NewNop(), nil, nil,
|
svc := NewService(zap.NewNop(), nil, nil,
|
||||||
WithConfig(cfg),
|
|
||||||
WithTemplateRenderer(tmpl),
|
WithTemplateRenderer(tmpl),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -164,7 +125,7 @@ func TestGenerateActPDF_IdempotentAndHashed(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func extractFooterHash(pdf []byte) string {
|
func extractFooterHash(pdf []byte) string {
|
||||||
prefix := []byte("Document integrity hash: ")
|
prefix := []byte(content.DocumentIntegrityHashPrefix)
|
||||||
idx := bytes.Index(pdf, prefix)
|
idx := bytes.Index(pdf, prefix)
|
||||||
|
|
||||||
if idx == -1 {
|
if idx == -1 {
|
||||||
@@ -191,11 +152,7 @@ func isHexDigit(b byte) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOperationDocument_GeneratesPDF(t *testing.T) {
|
func TestGetOperationDocument_GeneratesPDF(t *testing.T) {
|
||||||
svc := NewService(zap.NewNop(), nil, nil, WithConfig(Config{
|
svc := NewService(zap.NewNop(), nil, nil)
|
||||||
Issuer: renderer.Issuer{
|
|
||||||
LegalName: "Sendico Ltd",
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
|
|
||||||
resp, err := svc.GetOperationDocument(context.Background(), &documentsv1.GetOperationDocumentRequest{
|
resp, err := svc.GetOperationDocument(context.Background(), &documentsv1.GetOperationDocumentRequest{
|
||||||
OrganizationRef: "org-1",
|
OrganizationRef: "org-1",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
"github.com/tech/sendico/billing/documents/renderer"
|
"github.com/tech/sendico/billing/documents/renderer"
|
||||||
"github.com/tech/sendico/billing/documents/storage/model"
|
"github.com/tech/sendico/billing/documents/storage/model"
|
||||||
)
|
)
|
||||||
@@ -17,7 +18,13 @@ type templateRenderer struct {
|
|||||||
tpl *template.Template
|
tpl *template.Template
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type acceptanceTemplateData struct {
|
||||||
|
model.ActSnapshot
|
||||||
|
Content content.AcceptanceTemplateContent
|
||||||
|
}
|
||||||
|
|
||||||
func newTemplateRenderer(path string) (*templateRenderer, error) {
|
func newTemplateRenderer(path string) (*templateRenderer, error) {
|
||||||
|
//nolint:gosec // template file path is provided by trusted service configuration.
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read template: %w", err)
|
return nil, fmt.Errorf("read template: %w", err)
|
||||||
@@ -38,7 +45,12 @@ func newTemplateRenderer(path string) (*templateRenderer, error) {
|
|||||||
|
|
||||||
func (r *templateRenderer) Render(snapshot model.ActSnapshot) ([]renderer.Block, error) {
|
func (r *templateRenderer) Render(snapshot model.ActSnapshot) ([]renderer.Block, error) {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
if err := r.tpl.Execute(&buf, snapshot); err != nil {
|
data := acceptanceTemplateData{
|
||||||
|
ActSnapshot: snapshot,
|
||||||
|
Content: content.AcceptanceTemplate,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := r.tpl.Execute(&buf, data); err != nil {
|
||||||
return nil, fmt.Errorf("execute template: %w", err)
|
return nil, fmt.Errorf("execute template: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
"github.com/tech/sendico/billing/documents/renderer"
|
"github.com/tech/sendico/billing/documents/renderer"
|
||||||
"github.com/tech/sendico/billing/documents/storage/model"
|
"github.com/tech/sendico/billing/documents/storage/model"
|
||||||
)
|
)
|
||||||
@@ -42,7 +43,7 @@ func TestTemplateRenderer_Render(t *testing.T) {
|
|||||||
t.Fatalf("expected title block")
|
t.Fatalf("expected title block")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !slices.Contains(title.Lines, "ACT OF ACCEPTANCE OF SERVICES") {
|
if !slices.Contains(title.Lines, content.AcceptanceTemplate.Title) {
|
||||||
t.Fatalf("expected title content not found")
|
t.Fatalf("expected title content not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +55,7 @@ func TestTemplateRenderer_Render(t *testing.T) {
|
|||||||
foundExecutor := false
|
foundExecutor := false
|
||||||
|
|
||||||
for _, row := range kv.Rows {
|
for _, row := range kv.Rows {
|
||||||
if len(row) >= 2 && row[0] == "Executor" && row[1] == snapshot.ExecutorFullName {
|
if len(row) >= 2 && row[0] == content.AcceptanceTemplate.PartyExecutorLabel && row[1] == snapshot.ExecutorFullName {
|
||||||
foundExecutor = true
|
foundExecutor = true
|
||||||
|
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jung-kurt/gofpdf"
|
"github.com/jung-kurt/gofpdf"
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -28,7 +29,7 @@ func (r Renderer) Render(blocks []Block, footerHash string) ([]byte, error) {
|
|||||||
pdf.SetAutoPageBreak(true, pageMarginBottom)
|
pdf.SetAutoPageBreak(true, pageMarginBottom)
|
||||||
pdf.SetCompression(false)
|
pdf.SetCompression(false)
|
||||||
pdf.SetAuthor(r.Issuer.LegalName, false)
|
pdf.SetAuthor(r.Issuer.LegalName, false)
|
||||||
pdf.SetTitle("Act of Acceptance", false)
|
pdf.SetTitle(content.PDFTitleActOfAcceptance, false)
|
||||||
|
|
||||||
owner := strings.TrimSpace(r.OwnerPassword)
|
owner := strings.TrimSpace(r.OwnerPassword)
|
||||||
if owner != "" {
|
if owner != "" {
|
||||||
@@ -39,7 +40,7 @@ func (r Renderer) Render(blocks []Block, footerHash string) ([]byte, error) {
|
|||||||
pdf.SetY(-15)
|
pdf.SetY(-15)
|
||||||
pdf.SetFont("Helvetica", "", 8)
|
pdf.SetFont("Helvetica", "", 8)
|
||||||
|
|
||||||
footer := "Document integrity hash: " + footerHash
|
footer := content.DocumentIntegrityHashPrefix + footerHash
|
||||||
pdf.CellFormat(0, 5, footer, "", 0, "L", false, 0, "")
|
pdf.CellFormat(0, 5, footer, "", 0, "L", false, 0, "")
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"unicode/utf16"
|
"unicode/utf16"
|
||||||
|
|
||||||
|
"github.com/tech/sendico/billing/documents/internal/content"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRenderer_RenderContainsText(t *testing.T) {
|
func TestRenderer_RenderContainsText(t *testing.T) {
|
||||||
@@ -31,7 +33,7 @@ func TestRenderer_RenderContainsText(t *testing.T) {
|
|||||||
t.Fatalf("expected PDF bytes")
|
t.Fatalf("expected PDF bytes")
|
||||||
}
|
}
|
||||||
|
|
||||||
checks := []string{"Sendico Ltd", "Jane Doe", "100 USD", "Document integrity hash"}
|
checks := []string{"Sendico Ltd", "Jane Doe", "100 USD", strings.TrimSpace(strings.TrimSuffix(content.DocumentIntegrityHashPrefix, ": "))}
|
||||||
|
|
||||||
for _, token := range checks {
|
for _, token := range checks {
|
||||||
if !containsPDFText(pdfBytes, token) {
|
if !containsPDFText(pdfBytes, token) {
|
||||||
@@ -100,7 +102,7 @@ func encodeUTF16BE(text string, withBOM bool) []byte {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, v := range encoded {
|
for _, v := range encoded {
|
||||||
out = append(out, byte(v>>8), byte(v))
|
out = append(out, byte(v>>8), byte(v&0x00FF))
|
||||||
}
|
}
|
||||||
|
|
||||||
return out
|
return out
|
||||||
|
|||||||
@@ -6,14 +6,13 @@ import (
|
|||||||
|
|
||||||
"github.com/shopspring/decimal"
|
"github.com/shopspring/decimal"
|
||||||
"github.com/tech/sendico/pkg/db/storable"
|
"github.com/tech/sendico/pkg/db/storable"
|
||||||
documentsv1 "github.com/tech/sendico/pkg/proto/billing/documents/v1"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
DocumentRecordsCollection = "document_records"
|
DocumentRecordsCollection = "document_records"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DocumentType mirrors the protobuf enum but stores string names for Mongo compatibility.
|
// DocumentType represents document kinds cached in storage.
|
||||||
type DocumentType string
|
type DocumentType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -23,24 +22,6 @@ const (
|
|||||||
DocumentTypeReceipt DocumentType = "DOCUMENT_TYPE_RECEIPT"
|
DocumentTypeReceipt DocumentType = "DOCUMENT_TYPE_RECEIPT"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DocumentTypeFromProto converts a protobuf enum to the storage representation.
|
|
||||||
func DocumentTypeFromProto(t documentsv1.DocumentType) DocumentType {
|
|
||||||
if name, ok := documentsv1.DocumentType_name[int32(t)]; ok {
|
|
||||||
return DocumentType(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return DocumentTypeUnspecified
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proto converts the storage representation to a protobuf enum.
|
|
||||||
func (t DocumentType) Proto() documentsv1.DocumentType {
|
|
||||||
if value, ok := documentsv1.DocumentType_value[string(t)]; ok {
|
|
||||||
return documentsv1.DocumentType(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
return documentsv1.DocumentType_DOCUMENT_TYPE_UNSPECIFIED
|
|
||||||
}
|
|
||||||
|
|
||||||
// ActSnapshot captures the immutable data needed to generate an acceptance act.
|
// ActSnapshot captures the immutable data needed to generate an acceptance act.
|
||||||
type ActSnapshot struct {
|
type ActSnapshot struct {
|
||||||
PaymentID string `bson:"paymentId" json:"paymentId"`
|
PaymentID string `bson:"paymentId" json:"paymentId"`
|
||||||
|
|||||||
@@ -2,66 +2,66 @@
|
|||||||
|
|
||||||
|
|
||||||
#title
|
#title
|
||||||
ACT OF ACCEPTANCE OF SERVICES
|
{{ .Content.Title }}
|
||||||
|
|
||||||
#subtitle
|
#subtitle
|
||||||
under the Public Offer Agreement
|
{{ .Content.Subtitle }}
|
||||||
|
|
||||||
#meta
|
#meta
|
||||||
Date: {{ date .Date }}
|
{{ .Content.MetaDateLabel }}: {{ date .Date }}
|
||||||
Act No: {{ .PaymentID }}
|
{{ .Content.MetaActNumberLabel }}: {{ .PaymentID }}
|
||||||
|
|
||||||
|
|
||||||
#section
|
#section
|
||||||
PARTIES
|
{{ .Content.SectionParties }}
|
||||||
|
|
||||||
#text
|
#text
|
||||||
This Act is made between the following Parties.
|
{{ .Content.PartiesIntro }}
|
||||||
|
|
||||||
#kv
|
#kv
|
||||||
Executor | {{ .ExecutorFullName }}
|
{{ .Content.PartyExecutorLabel }} | {{ .ExecutorFullName }}
|
||||||
Status | Individual
|
{{ .Content.PartyStatusLabel }} | {{ .Content.PartyStatusValue }}
|
||||||
|
|
||||||
|
|
||||||
#section
|
#section
|
||||||
BASIS
|
{{ .Content.SectionBasis }}
|
||||||
|
|
||||||
#text
|
#text
|
||||||
This Act is issued pursuant to the Public Offer Agreement
|
{{ .Content.BasisLine1 }}
|
||||||
accepted by the Executor by joining the offer.
|
{{ .Content.BasisLine2 }}
|
||||||
|
|
||||||
|
|
||||||
#section
|
#section
|
||||||
SERVICES RENDERED
|
{{ .Content.SectionServicesRendered }}
|
||||||
|
|
||||||
#text
|
#text
|
||||||
The Executor has rendered services to the Customer
|
{{ .Content.ServicesRenderedLine1 }}
|
||||||
in accordance with the terms of the Public Offer Agreement.
|
{{ .Content.ServicesRenderedLine2 }}
|
||||||
|
|
||||||
|
|
||||||
#section
|
#section
|
||||||
REMUNERATION
|
{{ .Content.SectionRemuneration }}
|
||||||
|
|
||||||
#table
|
#table
|
||||||
Description | Amount
|
{{ .Content.RemunerationHeaderDesc }} | {{ .Content.RemunerationHeaderAmount }}
|
||||||
Services rendered under the Public Offer Agreement | {{ money .Amount .Currency }}
|
{{ .Content.RemunerationServicesDesc }} | {{ money .Amount .Currency }}
|
||||||
|
|
||||||
|
|
||||||
#section
|
#section
|
||||||
CONFIRMATION
|
{{ .Content.SectionConfirmation }}
|
||||||
|
|
||||||
#text
|
#text
|
||||||
The Customer confirms that the services were rendered properly
|
{{ .Content.ConfirmationLine1 }}
|
||||||
and accepted without any claims.
|
{{ .Content.ConfirmationLine2 }}
|
||||||
|
|
||||||
The remuneration for the services was paid to the Executor
|
{{ .Content.ConfirmationPaymentLine1 }}
|
||||||
using the bank card details provided by the Executor.
|
{{ .Content.ConfirmationPaymentLine2 }}
|
||||||
|
|
||||||
|
|
||||||
#section
|
#section
|
||||||
SIGNATURES
|
{{ .Content.SectionSignatures }}
|
||||||
|
|
||||||
#sign
|
#sign
|
||||||
Customer ___________________________
|
{{ .Content.SignatureCustomerLine }}
|
||||||
|
|
||||||
Executor ___________________________
|
{{ .Content.SignatureExecutorLine }}
|
||||||
|
|||||||
@@ -1,198 +1,47 @@
|
|||||||
# See the dedicated "version" documentation section.
|
|
||||||
version: "2"
|
version: "2"
|
||||||
linters:
|
linters:
|
||||||
# Default set of linters.
|
default: none
|
||||||
# The value can be:
|
|
||||||
# - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
|
|
||||||
# - `all`: enables all linters by default.
|
|
||||||
# - `none`: disables all linters by default.
|
|
||||||
# - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
|
|
||||||
# Default: standard
|
|
||||||
default: all
|
|
||||||
# Enable specific linter.
|
|
||||||
enable:
|
enable:
|
||||||
- arangolint
|
|
||||||
- asasalint
|
|
||||||
- asciicheck
|
|
||||||
- bidichk
|
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- canonicalheader
|
- canonicalheader
|
||||||
- containedctx
|
|
||||||
- contextcheck
|
|
||||||
- copyloopvar
|
- copyloopvar
|
||||||
- cyclop
|
|
||||||
- decorder
|
|
||||||
- dogsled
|
|
||||||
- dupl
|
|
||||||
- dupword
|
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- embeddedstructfieldcheck
|
|
||||||
- err113
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- errchkjson
|
- errchkjson
|
||||||
- errname
|
- errname
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
|
||||||
- exptostd
|
|
||||||
- fatcontext
|
|
||||||
- forbidigo
|
|
||||||
- forcetypeassert
|
|
||||||
- funcorder
|
|
||||||
- funlen
|
|
||||||
- ginkgolinter
|
|
||||||
- gocheckcompilerdirectives
|
|
||||||
- gochecknoglobals
|
|
||||||
- gochecknoinits
|
|
||||||
- gochecksumtype
|
|
||||||
- gocognit
|
|
||||||
- goconst
|
|
||||||
- gocritic
|
|
||||||
- gocyclo
|
|
||||||
- godoclint
|
|
||||||
- godot
|
|
||||||
- godox
|
|
||||||
- goheader
|
|
||||||
- gomodguard
|
|
||||||
- goprintffuncname
|
|
||||||
- gosec
|
- gosec
|
||||||
- gosmopolitan
|
|
||||||
- govet
|
- govet
|
||||||
- grouper
|
|
||||||
- iface
|
|
||||||
- importas
|
|
||||||
- inamedparam
|
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- interfacebloat
|
|
||||||
- intrange
|
|
||||||
- iotamixing
|
|
||||||
- ireturn
|
|
||||||
- lll
|
|
||||||
- loggercheck
|
|
||||||
- maintidx
|
|
||||||
- makezero
|
|
||||||
- mirror
|
|
||||||
- misspell
|
|
||||||
- mnd
|
|
||||||
- modernize
|
|
||||||
- musttag
|
|
||||||
- nakedret
|
|
||||||
- nestif
|
|
||||||
- nilerr
|
- nilerr
|
||||||
- nilnesserr
|
- nilnesserr
|
||||||
- nilnil
|
- nilnil
|
||||||
- nlreturn
|
|
||||||
- noctx
|
- noctx
|
||||||
- noinlineerr
|
|
||||||
- nolintlint
|
|
||||||
- nonamedreturns
|
|
||||||
- nosprintfhostport
|
|
||||||
- paralleltest
|
|
||||||
- perfsprint
|
|
||||||
- prealloc
|
|
||||||
- predeclared
|
|
||||||
- promlinter
|
|
||||||
- protogetter
|
|
||||||
- reassign
|
|
||||||
- recvcheck
|
|
||||||
- revive
|
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- sloglint
|
|
||||||
- spancheck
|
|
||||||
- sqlclosecheck
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- tagalign
|
|
||||||
- tagliatelle
|
|
||||||
- testableexamples
|
|
||||||
- testifylint
|
|
||||||
- testpackage
|
|
||||||
- thelper
|
|
||||||
- tparallel
|
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
|
||||||
- unqueryvet
|
|
||||||
- unused
|
|
||||||
- usestdlibvars
|
|
||||||
- usetesting
|
|
||||||
- varnamelen
|
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
|
||||||
- wsl_v5
|
|
||||||
- zerologlint
|
|
||||||
# Disable specific linters.
|
|
||||||
disable:
|
disable:
|
||||||
- depguard
|
- depguard
|
||||||
- exhaustruct
|
- exhaustruct
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- noinlineerr
|
|
||||||
- wsl
|
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
# All available settings of specific linters.
|
- cyclop
|
||||||
# See the dedicated "linters.settings" documentation section.
|
- dupl
|
||||||
settings:
|
- funlen
|
||||||
wsl_v5:
|
- gocognit
|
||||||
allow-first-in-block: true
|
- gocyclo
|
||||||
allow-whole-block: false
|
- ireturn
|
||||||
branch-max-lines: 2
|
- lll
|
||||||
|
- mnd
|
||||||
# Defines a set of rules to ignore issues.
|
- nestif
|
||||||
# It does not skip the analysis, and so does not ignore "typecheck" errors.
|
- nlreturn
|
||||||
exclusions:
|
- noinlineerr
|
||||||
# Mode of the generated files analysis.
|
- paralleltest
|
||||||
#
|
- tagliatelle
|
||||||
# - `strict`: sources are excluded by strictly following the Go generated file convention.
|
- testpackage
|
||||||
# Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$`
|
- varnamelen
|
||||||
# This line must appear before the first non-comment, non-blank text in the file.
|
- wsl_v5
|
||||||
# https://go.dev/s/generatedcode
|
|
||||||
# - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc.
|
|
||||||
# - `disable`: disable the generated files exclusion.
|
|
||||||
#
|
|
||||||
# Default: strict
|
|
||||||
generated: lax
|
|
||||||
# Log a warning if an exclusion rule is unused.
|
|
||||||
# Default: false
|
|
||||||
warn-unused: true
|
|
||||||
# Predefined exclusion rules.
|
|
||||||
# Default: []
|
|
||||||
presets:
|
|
||||||
- comments
|
|
||||||
- std-error-handling
|
|
||||||
- common-false-positives
|
|
||||||
- legacy
|
|
||||||
# Excluding configuration per-path, per-linter, per-text and per-source.
|
|
||||||
rules:
|
|
||||||
# Exclude some linters from running on tests files.
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- cyclop
|
|
||||||
- funlen
|
|
||||||
- gocyclo
|
|
||||||
- errcheck
|
|
||||||
- dupl
|
|
||||||
- gosec
|
|
||||||
# Run some linter only for test files by excluding its issues for everything else.
|
|
||||||
- path-except: _test\.go
|
|
||||||
linters:
|
|
||||||
- forbidigo
|
|
||||||
# Exclude known linters from partially hard-vendored code,
|
|
||||||
# which is impossible to exclude via `nolint` comments.
|
|
||||||
# `/` will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
- path: internal/hmac/
|
|
||||||
text: "weak cryptographic primitive"
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
||||||
# Exclude some `staticcheck` messages.
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "SA9003:"
|
|
||||||
# Exclude `lll` issues for long lines with `go:generate`.
|
|
||||||
- linters:
|
|
||||||
- lll
|
|
||||||
source: "^//go:generate "
|
|
||||||
# Which file paths to exclude: they will be analyzed, but issues from them won't be reported.
|
|
||||||
# "/" will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
# Default: []
|
|
||||||
paths: []
|
|
||||||
# Which file paths to not exclude.
|
|
||||||
# Default: []
|
|
||||||
paths-except: []
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ require (
|
|||||||
github.com/tech/sendico/fx/oracle v0.0.0
|
github.com/tech/sendico/fx/oracle v0.0.0
|
||||||
github.com/tech/sendico/pkg v0.1.0
|
github.com/tech/sendico/pkg v0.1.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -44,11 +44,11 @@ require (
|
|||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/net v0.51.0 // indirect
|
golang.org/x/net v0.51.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
@@ -183,16 +183,16 @@ golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
|||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -1,196 +1,47 @@
|
|||||||
# See the dedicated "version" documentation section.
|
|
||||||
version: "2"
|
version: "2"
|
||||||
linters:
|
linters:
|
||||||
# Default set of linters.
|
default: none
|
||||||
# The value can be:
|
|
||||||
# - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
|
|
||||||
# - `all`: enables all linters by default.
|
|
||||||
# - `none`: disables all linters by default.
|
|
||||||
# - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
|
|
||||||
# Default: standard
|
|
||||||
default: all
|
|
||||||
# Enable specific linter.
|
|
||||||
enable:
|
enable:
|
||||||
- arangolint
|
|
||||||
- asasalint
|
|
||||||
- asciicheck
|
|
||||||
- bidichk
|
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- canonicalheader
|
- canonicalheader
|
||||||
- containedctx
|
|
||||||
- contextcheck
|
|
||||||
- copyloopvar
|
- copyloopvar
|
||||||
- cyclop
|
|
||||||
- decorder
|
|
||||||
- dogsled
|
|
||||||
- dupl
|
|
||||||
- dupword
|
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- embeddedstructfieldcheck
|
|
||||||
- err113
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- errchkjson
|
- errchkjson
|
||||||
- errname
|
- errname
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
|
||||||
- exptostd
|
|
||||||
- fatcontext
|
|
||||||
- forbidigo
|
|
||||||
- forcetypeassert
|
|
||||||
- funcorder
|
|
||||||
- funlen
|
|
||||||
- ginkgolinter
|
|
||||||
- gocheckcompilerdirectives
|
|
||||||
- gochecknoglobals
|
|
||||||
- gochecknoinits
|
|
||||||
- gochecksumtype
|
|
||||||
- gocognit
|
|
||||||
- goconst
|
|
||||||
- gocritic
|
|
||||||
- gocyclo
|
|
||||||
- godoclint
|
|
||||||
- godot
|
|
||||||
- godox
|
|
||||||
- goheader
|
|
||||||
- gomodguard
|
|
||||||
- goprintffuncname
|
|
||||||
- gosec
|
- gosec
|
||||||
- gosmopolitan
|
|
||||||
- govet
|
- govet
|
||||||
- grouper
|
|
||||||
- iface
|
|
||||||
- importas
|
|
||||||
- inamedparam
|
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- interfacebloat
|
|
||||||
- intrange
|
|
||||||
- iotamixing
|
|
||||||
- ireturn
|
|
||||||
- lll
|
|
||||||
- loggercheck
|
|
||||||
- maintidx
|
|
||||||
- makezero
|
|
||||||
- mirror
|
|
||||||
- misspell
|
|
||||||
- mnd
|
|
||||||
- modernize
|
|
||||||
- musttag
|
|
||||||
- nakedret
|
|
||||||
- nestif
|
|
||||||
- nilerr
|
- nilerr
|
||||||
- nilnesserr
|
- nilnesserr
|
||||||
- nilnil
|
- nilnil
|
||||||
- nlreturn
|
|
||||||
- noctx
|
- noctx
|
||||||
- noinlineerr
|
|
||||||
- nolintlint
|
|
||||||
- nonamedreturns
|
|
||||||
- nosprintfhostport
|
|
||||||
- paralleltest
|
|
||||||
- perfsprint
|
|
||||||
- prealloc
|
|
||||||
- predeclared
|
|
||||||
- promlinter
|
|
||||||
- protogetter
|
|
||||||
- reassign
|
|
||||||
- recvcheck
|
|
||||||
- revive
|
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- sloglint
|
|
||||||
- spancheck
|
|
||||||
- sqlclosecheck
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- tagalign
|
|
||||||
- tagliatelle
|
|
||||||
- testableexamples
|
|
||||||
- testifylint
|
|
||||||
- testpackage
|
|
||||||
- thelper
|
|
||||||
- tparallel
|
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
|
||||||
- unqueryvet
|
|
||||||
- unused
|
|
||||||
- usestdlibvars
|
|
||||||
- usetesting
|
|
||||||
- varnamelen
|
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
|
||||||
- wsl_v5
|
|
||||||
- zerologlint
|
|
||||||
# Disable specific linters.
|
|
||||||
disable:
|
disable:
|
||||||
- depguard
|
- depguard
|
||||||
- exhaustruct
|
- exhaustruct
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- wsl
|
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
# All available settings of specific linters.
|
- cyclop
|
||||||
# See the dedicated "linters.settings" documentation section.
|
- dupl
|
||||||
settings:
|
- funlen
|
||||||
wsl_v5:
|
- gocognit
|
||||||
allow-first-in-block: true
|
- gocyclo
|
||||||
allow-whole-block: false
|
- ireturn
|
||||||
branch-max-lines: 2
|
- lll
|
||||||
|
- mnd
|
||||||
# Defines a set of rules to ignore issues.
|
- nestif
|
||||||
# It does not skip the analysis, and so does not ignore "typecheck" errors.
|
- nlreturn
|
||||||
exclusions:
|
- noinlineerr
|
||||||
# Mode of the generated files analysis.
|
- paralleltest
|
||||||
#
|
- tagliatelle
|
||||||
# - `strict`: sources are excluded by strictly following the Go generated file convention.
|
- testpackage
|
||||||
# Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$`
|
- varnamelen
|
||||||
# This line must appear before the first non-comment, non-blank text in the file.
|
- wsl_v5
|
||||||
# https://go.dev/s/generatedcode
|
|
||||||
# - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc.
|
|
||||||
# - `disable`: disable the generated files exclusion.
|
|
||||||
#
|
|
||||||
# Default: strict
|
|
||||||
generated: lax
|
|
||||||
# Log a warning if an exclusion rule is unused.
|
|
||||||
# Default: false
|
|
||||||
warn-unused: true
|
|
||||||
# Predefined exclusion rules.
|
|
||||||
# Default: []
|
|
||||||
presets:
|
|
||||||
- comments
|
|
||||||
- std-error-handling
|
|
||||||
- common-false-positives
|
|
||||||
- legacy
|
|
||||||
# Excluding configuration per-path, per-linter, per-text and per-source.
|
|
||||||
rules:
|
|
||||||
# Exclude some linters from running on tests files.
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- funlen
|
|
||||||
- gocyclo
|
|
||||||
- errcheck
|
|
||||||
- dupl
|
|
||||||
- gosec
|
|
||||||
# Run some linter only for test files by excluding its issues for everything else.
|
|
||||||
- path-except: _test\.go
|
|
||||||
linters:
|
|
||||||
- forbidigo
|
|
||||||
# Exclude known linters from partially hard-vendored code,
|
|
||||||
# which is impossible to exclude via `nolint` comments.
|
|
||||||
# `/` will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
- path: internal/hmac/
|
|
||||||
text: "weak cryptographic primitive"
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
||||||
# Exclude some `staticcheck` messages.
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "SA9003:"
|
|
||||||
# Exclude `lll` issues for long lines with `go:generate`.
|
|
||||||
- linters:
|
|
||||||
- lll
|
|
||||||
source: "^//go:generate "
|
|
||||||
# Which file paths to exclude: they will be analyzed, but issues from them won't be reported.
|
|
||||||
# "/" will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
# Default: []
|
|
||||||
paths: []
|
|
||||||
# Which file paths to not exclude.
|
|
||||||
# Default: []
|
|
||||||
paths-except: []
|
|
||||||
|
|||||||
@@ -37,13 +37,13 @@ require (
|
|||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/net v0.51.0 // indirect
|
golang.org/x/net v0.51.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
google.golang.org/grpc v1.79.1 // indirect
|
google.golang.org/grpc v1.79.2 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
@@ -183,16 +183,16 @@ golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
|||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
47
api/edge/bff/.golangci.yml
Normal file
47
api/edge/bff/.golangci.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
version: "2"
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- canonicalheader
|
||||||
|
- copyloopvar
|
||||||
|
- durationcheck
|
||||||
|
- errcheck
|
||||||
|
- errchkjson
|
||||||
|
- errname
|
||||||
|
- errorlint
|
||||||
|
- gosec
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- nilerr
|
||||||
|
- nilnesserr
|
||||||
|
- nilnil
|
||||||
|
- noctx
|
||||||
|
- rowserrcheck
|
||||||
|
- sqlclosecheck
|
||||||
|
- staticcheck
|
||||||
|
- unconvert
|
||||||
|
- wastedassign
|
||||||
|
disable:
|
||||||
|
- depguard
|
||||||
|
- exhaustruct
|
||||||
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
|
- gomoddirectives
|
||||||
|
- wrapcheck
|
||||||
|
- cyclop
|
||||||
|
- dupl
|
||||||
|
- funlen
|
||||||
|
- gocognit
|
||||||
|
- gocyclo
|
||||||
|
- ireturn
|
||||||
|
- lll
|
||||||
|
- mnd
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- noinlineerr
|
||||||
|
- paralleltest
|
||||||
|
- tagliatelle
|
||||||
|
- testpackage
|
||||||
|
- varnamelen
|
||||||
|
- wsl_v5
|
||||||
@@ -18,7 +18,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2 v1.41.3
|
github.com/aws/aws-sdk-go-v2 v1.41.3
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
github.com/aws/aws-sdk-go-v2/config v1.32.11
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
github.com/aws/aws-sdk-go-v2/credentials v1.19.11
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4
|
||||||
github.com/go-chi/chi/v5 v5.2.5
|
github.com/go-chi/chi/v5 v5.2.5
|
||||||
github.com/go-chi/cors v1.2.2
|
github.com/go-chi/cors v1.2.2
|
||||||
github.com/go-chi/jwtauth/v5 v5.4.0
|
github.com/go-chi/jwtauth/v5 v5.4.0
|
||||||
@@ -38,7 +38,7 @@ require (
|
|||||||
go.mongodb.org/mongo-driver/v2 v2.5.0
|
go.mongodb.org/mongo-driver/v2 v2.5.0
|
||||||
go.uber.org/zap v1.27.1
|
go.uber.org/zap v1.27.1
|
||||||
golang.org/x/net v0.51.0
|
golang.org/x/net v0.51.0
|
||||||
google.golang.org/grpc v1.79.1
|
google.golang.org/grpc v1.79.2
|
||||||
google.golang.org/protobuf v1.36.11
|
google.golang.org/protobuf v1.36.11
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
moul.io/chizap v1.0.3
|
moul.io/chizap v1.0.3
|
||||||
@@ -59,7 +59,7 @@ require (
|
|||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 // indirect
|
||||||
@@ -147,17 +147,17 @@ require (
|
|||||||
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
github.com/yusufpapurcu/wmi v1.2.4 // indirect
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 // indirect
|
||||||
go.opentelemetry.io/otel v1.41.0 // indirect
|
go.opentelemetry.io/otel v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.41.0 // indirect
|
go.opentelemetry.io/otel/metric v1.42.0 // indirect
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
|
go.opentelemetry.io/otel/sdk/metric v1.40.0 // indirect
|
||||||
go.opentelemetry.io/otel/trace v1.41.0 // indirect
|
go.opentelemetry.io/otel/trace v1.42.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.15.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19 h1:AWeJMk33GTBf6J20XJ
|
|||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.19/go.mod h1:+GWrYoaAsV7/4pNHpwh1kiNLXkKaSoppxQq9lbH8Ejw=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5 h1:clHU5fm//kWS1C2HgtgWxfQbFbx4b6rx+5jzhgX9HrI=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.5/go.mod h1:O3h0IK87yXci+kg6flUKzJnWeziQUKciKrLjcatSNcY=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19 h1:3Y4oma5TiV7tT9wa8zRcdoXwZkGz9Q/wxbEUK7cMuAM=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20 h1:qi3e/dmpdONhj1RyIZdi6DKKpDXS5Lb8ftr3p7cyHJc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.19/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.20/go.mod h1:V1K+TeJVD5JOk3D9e5tsX2KUdL7BlB+FV6cBhdobN8c=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6 h1:XAq62tBTJP/85lFD5oqOOe7YYgWxY9LvWq8plyDvDVg=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.6/go.mod h1:x0nZssQ3qZSnIcePWLvcoFisRXJzcTVvYpAAdYX8+GI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.11 h1:BYf7XNsJMzl4mObARUBUib+j2tf0U//JAAtTnYqvqCw=
|
||||||
@@ -32,8 +32,8 @@ github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19 h1:X1Tow7su
|
|||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.19/go.mod h1:/rARO8psX+4sfjUQXp5LLifjUt8DuATZ31WptNJTyQA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19 h1:JnQeStZvPHFHeyky/7LbMlyQjUa+jIBj36OlWm0pzIk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.19/go.mod h1:HGyasyHvYdFQeJhvDHfH7HXkHh57htcJGKDZ+7z+I24=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3 h1:+d0SsTvxtIJt4tSJ6wr+jrxEMDa6XeupjRv8H7Qitkk=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4 h1:4ExZyubQ6LQQVuF2Qp9OsfEvsTdAWh5Gfwf6PgIdLdk=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.3/go.mod h1:ROUNFvFWPwBlOu687WJNQ9cPvd2ccpFrnCiA1YGz50o=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.96.4/go.mod h1:NF3JcMGOiARAss1ld3WGORCw71+4ExDD2cbbdKS5PpA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7 h1:Y2cAXlClHsXkkOvWZFXATr34b0hxxloeQu/pAZz2row=
|
||||||
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
github.com/aws/aws-sdk-go-v2/service/signin v1.0.7/go.mod h1:idzZ7gmDeqeNrSPkdbtMp9qWMgcBwykA7P7Rzh5DXVU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.30.12 h1:iSsvB9EtQ09YrsmIc44Heqlx5ByGErqhPK1ZQLppias=
|
||||||
@@ -296,20 +296,20 @@ go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ
|
|||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0 h1:UP6IpuHFkUgOQL9FFQFrZ+5LiwhhYRbi7VZSIx6Nj5s=
|
||||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.56.0/go.mod h1:qxuZLtbq5QDtdeSHsS7bcf6EH6uO6jUAgk764zd3rhM=
|
||||||
go.opentelemetry.io/otel v1.41.0 h1:YlEwVsGAlCvczDILpUXpIpPSL/VPugt7zHThEMLce1c=
|
go.opentelemetry.io/otel v1.42.0 h1:lSQGzTgVR3+sgJDAU/7/ZMjN9Z+vUip7leaqBKy4sho=
|
||||||
go.opentelemetry.io/otel v1.41.0/go.mod h1:Yt4UwgEKeT05QbLwbyHXEwhnjxNO6D8L5PQP51/46dE=
|
go.opentelemetry.io/otel v1.42.0/go.mod h1:lJNsdRMxCUIWuMlVJWzecSMuNjE7dOYyWlqOXWkdqCc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0 h1:QKdN8ly8zEMrByybbQgv8cWBcdAarwmIPZ6FThrWXJs=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.40.0/go.mod h1:bTdK1nhqF76qiPoCCdyFIV+N/sRHYXYCTQc+3VCi3MI=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0 h1:wVZXIWjQSeSmMoxF74LzAnpVQOAFDo3pPji9Y4SOFKc=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.40.0/go.mod h1:khvBS2IggMFNwZK/6lEeHg/W57h/IX6J4URh57fuI40=
|
||||||
go.opentelemetry.io/otel/metric v1.41.0 h1:rFnDcs4gRzBcsO9tS8LCpgR0dxg4aaxWlJxCno7JlTQ=
|
go.opentelemetry.io/otel/metric v1.42.0 h1:2jXG+3oZLNXEPfNmnpxKDeZsFI5o4J+nz6xUlaFdF/4=
|
||||||
go.opentelemetry.io/otel/metric v1.41.0/go.mod h1:xPvCwd9pU0VN8tPZYzDZV/BMj9CM9vs00GuBjeKhJps=
|
go.opentelemetry.io/otel/metric v1.42.0/go.mod h1:RlUN/7vTU7Ao/diDkEpQpnz3/92J9ko05BIwxYa2SSI=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
go.opentelemetry.io/otel/sdk v1.40.0 h1:KHW/jUzgo6wsPh9At46+h4upjtccTmuZCFAc9OJ71f8=
|
||||||
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
go.opentelemetry.io/otel/sdk v1.40.0/go.mod h1:Ph7EFdYvxq72Y8Li9q8KebuYUr2KoeyHx0DRMKrYBUE=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
go.opentelemetry.io/otel/sdk/metric v1.40.0 h1:mtmdVqgQkeRxHgRv4qhyJduP3fYJRMX4AtAlbuWdCYw=
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
go.opentelemetry.io/otel/sdk/metric v1.40.0/go.mod h1:4Z2bGMf0KSK3uRjlczMOeMhKU2rhUqdWNoKcYrtcBPg=
|
||||||
go.opentelemetry.io/otel/trace v1.41.0 h1:Vbk2co6bhj8L59ZJ6/xFTskY+tGAbOnCtQGVVa9TIN0=
|
go.opentelemetry.io/otel/trace v1.42.0 h1:OUCgIPt+mzOnaUTpOQcBiM/PLQ/Op7oq6g4LenLmOYY=
|
||||||
go.opentelemetry.io/otel/trace v1.41.0/go.mod h1:U1NU4ULCoxeDKc09yCWdWe+3QoyweJcISEVa1RBzOis=
|
go.opentelemetry.io/otel/trace v1.42.0/go.mod h1:f3K9S+IFqnumBkKhRJMeaZeNk9epyhnCmQh/EysQCdc=
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
go.opentelemetry.io/proto/otlp v1.9.0 h1:l706jCMITVouPOqEnii2fIAuO3IVGBRPV5ICjceRb/A=
|
||||||
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
go.opentelemetry.io/proto/otlp v1.9.0/go.mod h1:xE+Cx5E/eEHw+ISFkwPLwCZefwVjY+pqKg1qcK03+/4=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
@@ -324,8 +324,8 @@ go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN8
|
|||||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
@@ -353,8 +353,8 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -370,8 +370,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg=
|
||||||
@@ -382,8 +382,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
@@ -403,8 +403,8 @@ google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 h1:
|
|||||||
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171/go.mod h1:M5krXqk4GhBKvB596udGL3UyjL4I1+cTbK0orROM9ng=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -159,7 +159,7 @@ func (s *service) VerifyAccount(
|
|||||||
token, err := s.vdb.Create(
|
token, err := s.vdb.Create(
|
||||||
ctx,
|
ctx,
|
||||||
verification.NewLinkRequest(*acct.GetID(), model.PurposeAccountActivation, "").
|
verification.NewLinkRequest(*acct.GetID(), model.PurposeAccountActivation, "").
|
||||||
WithTTL(time.Duration(time.Hour*24)),
|
WithTTL(time.Hour * 24),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Warn("Failed to create verification token for new account", zap.Error(err), mzap.StorableRef(acct))
|
s.logger.Warn("Failed to create verification token for new account", zap.Error(err), mzap.StorableRef(acct))
|
||||||
@@ -238,7 +238,7 @@ func (s *service) ResetPassword(
|
|||||||
return s.vdb.Create(
|
return s.vdb.Create(
|
||||||
ctx,
|
ctx,
|
||||||
verification.NewOTPRequest(*acct.GetID(), model.PurposePasswordReset, "").
|
verification.NewOTPRequest(*acct.GetID(), model.PurposePasswordReset, "").
|
||||||
WithTTL(time.Duration(time.Hour*1)),
|
WithTTL(time.Hour),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ func (s *service) UpdateLogin(
|
|||||||
return s.vdb.Create(
|
return s.vdb.Create(
|
||||||
ctx,
|
ctx,
|
||||||
verification.NewOTPRequest(*acct.GetID(), model.PurposeEmailChange, newLogin).
|
verification.NewOTPRequest(*acct.GetID(), model.PurposeEmailChange, newLogin).
|
||||||
WithTTL(time.Duration(time.Hour*1)),
|
WithTTL(time.Hour),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -164,6 +164,7 @@ func (e Endpoint) DecodeIBAN() (IBANEndpoint, error) {
|
|||||||
|
|
||||||
func LegacyPaymentEndpointToEndpointDTO(old *LegacyPaymentEndpoint) (*Endpoint, error) {
|
func LegacyPaymentEndpointToEndpointDTO(old *LegacyPaymentEndpoint) (*Endpoint, error) {
|
||||||
if old == nil {
|
if old == nil {
|
||||||
|
//nolint:nilnil // Nil legacy endpoint means no endpoint provided.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +203,7 @@ func LegacyPaymentEndpointToEndpointDTO(old *LegacyPaymentEndpoint) (*Endpoint,
|
|||||||
|
|
||||||
func EndpointDTOToLegacyPaymentEndpoint(new *Endpoint) (*LegacyPaymentEndpoint, error) {
|
func EndpointDTOToLegacyPaymentEndpoint(new *Endpoint) (*LegacyPaymentEndpoint, error) {
|
||||||
if new == nil {
|
if new == nil {
|
||||||
|
//nolint:nilnil // Nil endpoint DTO means no endpoint provided.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,11 @@ import (
|
|||||||
gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1"
|
gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1"
|
||||||
paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
|
paginationv1 "github.com/tech/sendico/pkg/proto/common/pagination/v1"
|
||||||
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
oraclev1 "github.com/tech/sendico/pkg/proto/oracle/v1"
|
||||||
|
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
|
||||||
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
||||||
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
|
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
|
||||||
|
"github.com/tech/sendico/server/interface/api/srequest"
|
||||||
|
"go.mongodb.org/mongo-driver/v2/bson"
|
||||||
"google.golang.org/protobuf/types/known/timestamppb"
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -67,16 +70,24 @@ type PaymentQuotes struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Payment struct {
|
type Payment struct {
|
||||||
PaymentRef string `json:"paymentRef,omitempty"`
|
PaymentRef string `json:"paymentRef,omitempty"`
|
||||||
IdempotencyKey string `json:"idempotencyKey,omitempty"`
|
State string `json:"state,omitempty"`
|
||||||
State string `json:"state,omitempty"`
|
Comment string `json:"comment,omitempty"`
|
||||||
Comment string `json:"comment,omitempty"`
|
Source *PaymentEndpoint `json:"source"`
|
||||||
FailureCode string `json:"failureCode,omitempty"`
|
Destination *PaymentEndpoint `json:"destination"`
|
||||||
FailureReason string `json:"failureReason,omitempty"`
|
FailureCode string `json:"failureCode,omitempty"`
|
||||||
Operations []PaymentOperation `json:"operations,omitempty"`
|
FailureReason string `json:"failureReason,omitempty"`
|
||||||
LastQuote *PaymentQuote `json:"lastQuote,omitempty"`
|
Operations []PaymentOperation `json:"operations,omitempty"`
|
||||||
CreatedAt time.Time `json:"createdAt,omitempty"`
|
LastQuote *PaymentQuote `json:"lastQuote,omitempty"`
|
||||||
Meta map[string]string `json:"meta,omitempty"`
|
CreatedAt time.Time `json:"createdAt,omitempty"`
|
||||||
|
Meta map[string]string `json:"meta,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentEndpoint struct {
|
||||||
|
Type string `json:"type,omitempty"`
|
||||||
|
Data any `json:"data,omitempty"`
|
||||||
|
PaymentMethodRef string `json:"paymentMethodRef,omitempty"`
|
||||||
|
PayeeRef string `json:"payeeRef,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaymentOperation struct {
|
type PaymentOperation struct {
|
||||||
@@ -290,22 +301,257 @@ func toPayment(p *orchestrationv2.Payment) *Payment {
|
|||||||
if p == nil {
|
if p == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
operations := toUserVisibleOperations(p.GetStepExecutions(), p.GetQuoteSnapshot())
|
intent := p.GetIntentSnapshot()
|
||||||
|
operations := toUserVisibleOperations(p.GetStepExecutions())
|
||||||
failureCode, failureReason := firstFailure(operations)
|
failureCode, failureReason := firstFailure(operations)
|
||||||
return &Payment{
|
return &Payment{
|
||||||
PaymentRef: p.GetPaymentRef(),
|
PaymentRef: p.GetPaymentRef(),
|
||||||
State: enumJSONName(p.GetState().String()),
|
State: enumJSONName(p.GetState().String()),
|
||||||
Comment: strings.TrimSpace(p.GetIntentSnapshot().GetComment()),
|
Comment: strings.TrimSpace(intent.GetComment()),
|
||||||
FailureCode: failureCode,
|
Source: toPaymentEndpoint(intent.GetSource()),
|
||||||
FailureReason: failureReason,
|
Destination: toPaymentEndpoint(intent.GetDestination()),
|
||||||
Operations: operations,
|
FailureCode: failureCode,
|
||||||
LastQuote: toPaymentQuote(p.GetQuoteSnapshot()),
|
FailureReason: failureReason,
|
||||||
CreatedAt: timestampAsTime(p.GetCreatedAt()),
|
Operations: operations,
|
||||||
Meta: paymentMeta(p),
|
LastQuote: toPaymentQuote(p.GetQuoteSnapshot()),
|
||||||
IdempotencyKey: "",
|
CreatedAt: timestampAsTime(p.GetCreatedAt()),
|
||||||
|
Meta: paymentMeta(p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func toPaymentEndpoint(endpoint *endpointv1.PaymentEndpoint) *PaymentEndpoint {
|
||||||
|
if endpoint == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if paymentMethodRef := strings.TrimSpace(endpoint.GetPaymentMethodRef()); paymentMethodRef != "" {
|
||||||
|
return &PaymentEndpoint{PaymentMethodRef: paymentMethodRef}
|
||||||
|
}
|
||||||
|
if payeeRef := strings.TrimSpace(endpoint.GetPayeeRef()); payeeRef != "" {
|
||||||
|
return &PaymentEndpoint{PayeeRef: payeeRef}
|
||||||
|
}
|
||||||
|
method := endpoint.GetPaymentMethod()
|
||||||
|
if method == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return &PaymentEndpoint{
|
||||||
|
Type: paymentEndpointType(method.GetType()),
|
||||||
|
Data: paymentEndpointData(method),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func paymentEndpointType(methodType endpointv1.PaymentMethodType) string {
|
||||||
|
switch methodType {
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_IBAN:
|
||||||
|
return string(srequest.EndpointTypeIBAN)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD:
|
||||||
|
return string(srequest.EndpointTypeCard)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN:
|
||||||
|
return string(srequest.EndpointTypeCardToken)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_BANK_ACCOUNT:
|
||||||
|
return string(srequest.EndpointTypeBankAccount)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET:
|
||||||
|
return string(srequest.EndpointTypeWallet)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS:
|
||||||
|
return string(srequest.EndpointTypeExternalChain)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER:
|
||||||
|
return string(srequest.EndpointTypeLedger)
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_ACCOUNT:
|
||||||
|
return "account"
|
||||||
|
default:
|
||||||
|
return "unspecified"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func paymentEndpointData(method *endpointv1.PaymentMethod) any {
|
||||||
|
if method == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch method.GetType() {
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_LEDGER:
|
||||||
|
type ledgerMethodData struct {
|
||||||
|
LedgerAccountRef string `bson:"ledgerAccountRef"`
|
||||||
|
ContraLedgerAccountRef string `bson:"contraLedgerAccountRef,omitempty"`
|
||||||
|
}
|
||||||
|
var payload ledgerMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
return srequest.LedgerEndpoint{
|
||||||
|
LedgerAccountRef: strings.TrimSpace(payload.LedgerAccountRef),
|
||||||
|
ContraLedgerAccountRef: strings.TrimSpace(payload.ContraLedgerAccountRef),
|
||||||
|
}
|
||||||
|
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET:
|
||||||
|
type walletMethodData struct {
|
||||||
|
WalletID string `bson:"walletId"`
|
||||||
|
}
|
||||||
|
var payload walletMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
return srequest.WalletEndpoint{
|
||||||
|
WalletID: strings.TrimSpace(payload.WalletID),
|
||||||
|
}
|
||||||
|
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS:
|
||||||
|
type cryptoMethodData struct {
|
||||||
|
Currency string `bson:"currency"`
|
||||||
|
Address string `bson:"address"`
|
||||||
|
Network string `bson:"network"`
|
||||||
|
DestinationTag *string `bson:"destinationTag,omitempty"`
|
||||||
|
}
|
||||||
|
var payload cryptoMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
endpoint := srequest.ExternalChainEndpoint{
|
||||||
|
Asset: &srequest.Asset{
|
||||||
|
Chain: parseChainNetwork(payload.Network),
|
||||||
|
TokenSymbol: strings.ToUpper(strings.TrimSpace(payload.Currency)),
|
||||||
|
},
|
||||||
|
Address: strings.TrimSpace(payload.Address),
|
||||||
|
}
|
||||||
|
if memo := strings.TrimSpace(strPtr(payload.DestinationTag)); memo != "" {
|
||||||
|
endpoint.Memo = memo
|
||||||
|
}
|
||||||
|
if endpoint.Asset.Chain == srequest.ChainNetworkUnspecified && endpoint.Asset.TokenSymbol == "" {
|
||||||
|
endpoint.Asset = nil
|
||||||
|
}
|
||||||
|
return endpoint
|
||||||
|
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD:
|
||||||
|
type cardMethodData struct {
|
||||||
|
Pan string `bson:"pan"`
|
||||||
|
FirstName string `bson:"firstName"`
|
||||||
|
LastName string `bson:"lastName"`
|
||||||
|
ExpMonth string `bson:"expMonth"`
|
||||||
|
ExpYear string `bson:"expYear"`
|
||||||
|
Country string `bson:"country,omitempty"`
|
||||||
|
}
|
||||||
|
var payload cardMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
return srequest.CardEndpoint{
|
||||||
|
Pan: strings.TrimSpace(payload.Pan),
|
||||||
|
FirstName: strings.TrimSpace(payload.FirstName),
|
||||||
|
LastName: strings.TrimSpace(payload.LastName),
|
||||||
|
ExpMonth: parseUint32(payload.ExpMonth),
|
||||||
|
ExpYear: parseUint32(payload.ExpYear),
|
||||||
|
Country: strings.TrimSpace(payload.Country),
|
||||||
|
}
|
||||||
|
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CARD_TOKEN:
|
||||||
|
type cardTokenMethodData struct {
|
||||||
|
Token string `bson:"token"`
|
||||||
|
Last4 string `bson:"last4,omitempty"`
|
||||||
|
}
|
||||||
|
var payload cardTokenMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
return srequest.CardTokenEndpoint{
|
||||||
|
Token: strings.TrimSpace(payload.Token),
|
||||||
|
MaskedPan: strings.TrimSpace(payload.Last4),
|
||||||
|
}
|
||||||
|
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_BANK_ACCOUNT:
|
||||||
|
type bankAccountMethodData struct {
|
||||||
|
RecipientName string `bson:"recipientName"`
|
||||||
|
Inn string `bson:"inn"`
|
||||||
|
Kpp string `bson:"kpp"`
|
||||||
|
BankName string `bson:"bankName"`
|
||||||
|
Bik string `bson:"bik"`
|
||||||
|
AccountNumber string `bson:"accountNumber"`
|
||||||
|
CorrespondentAccount string `bson:"correspondentAccount"`
|
||||||
|
}
|
||||||
|
var payload bankAccountMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
return srequest.BankAccountEndpoint{
|
||||||
|
RecipientName: strings.TrimSpace(payload.RecipientName),
|
||||||
|
Inn: strings.TrimSpace(payload.Inn),
|
||||||
|
Kpp: strings.TrimSpace(payload.Kpp),
|
||||||
|
BankName: strings.TrimSpace(payload.BankName),
|
||||||
|
Bik: strings.TrimSpace(payload.Bik),
|
||||||
|
AccountNumber: strings.TrimSpace(payload.AccountNumber),
|
||||||
|
CorrespondentAccount: strings.TrimSpace(payload.CorrespondentAccount),
|
||||||
|
}
|
||||||
|
|
||||||
|
case endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_IBAN:
|
||||||
|
type ibanMethodData struct {
|
||||||
|
IBAN string `bson:"iban"`
|
||||||
|
AccountHolder string `bson:"accountHolder"`
|
||||||
|
BIC *string `bson:"bic,omitempty"`
|
||||||
|
BankName *string `bson:"bankName,omitempty"`
|
||||||
|
}
|
||||||
|
var payload ibanMethodData
|
||||||
|
if err := bson.Unmarshal(method.GetData(), &payload); err != nil {
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
return srequest.IBANEndpoint{
|
||||||
|
IBAN: strings.TrimSpace(payload.IBAN),
|
||||||
|
AccountHolder: strings.TrimSpace(payload.AccountHolder),
|
||||||
|
BIC: strings.TrimSpace(strPtr(payload.BIC)),
|
||||||
|
BankName: strings.TrimSpace(strPtr(payload.BankName)),
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return toRawBSON(method.GetData())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func toRawBSON(raw []byte) map[string]any {
|
||||||
|
if len(raw) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var data map[string]any
|
||||||
|
if err := bson.Unmarshal(raw, &data); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseChainNetwork(value string) srequest.ChainNetwork {
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(value)) {
|
||||||
|
case "ETHEREUM_MAINNET":
|
||||||
|
return srequest.ChainNetworkEthereumMainnet
|
||||||
|
case "ARBITRUM_ONE":
|
||||||
|
return srequest.ChainNetworkArbitrumOne
|
||||||
|
case "TRON_MAINNET":
|
||||||
|
return srequest.ChainNetworkTronMainnet
|
||||||
|
case "TRON_NILE":
|
||||||
|
return srequest.ChainNetworkTronNile
|
||||||
|
case "", "UNSPECIFIED":
|
||||||
|
return srequest.ChainNetworkUnspecified
|
||||||
|
default:
|
||||||
|
return srequest.ChainNetwork(strings.ToLower(strings.TrimSpace(value)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseUint32(value string) uint32 {
|
||||||
|
clean := strings.TrimSpace(value)
|
||||||
|
if clean == "" {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
parsed, err := strconv.ParseUint(clean, 10, 32)
|
||||||
|
if err != nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return uint32(parsed)
|
||||||
|
}
|
||||||
|
|
||||||
|
func strPtr(v *string) string {
|
||||||
|
if v == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return *v
|
||||||
|
}
|
||||||
|
|
||||||
func firstFailure(operations []PaymentOperation) (string, string) {
|
func firstFailure(operations []PaymentOperation) (string, string) {
|
||||||
for _, op := range operations {
|
for _, op := range operations {
|
||||||
if strings.TrimSpace(op.FailureCode) == "" && strings.TrimSpace(op.FailureReason) == "" {
|
if strings.TrimSpace(op.FailureCode) == "" && strings.TrimSpace(op.FailureReason) == "" {
|
||||||
@@ -316,7 +562,7 @@ func firstFailure(operations []PaymentOperation) (string, string) {
|
|||||||
return "", ""
|
return "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func toUserVisibleOperations(steps []*orchestrationv2.StepExecution, quote *quotationv2.PaymentQuote) []PaymentOperation {
|
func toUserVisibleOperations(steps []*orchestrationv2.StepExecution) []PaymentOperation {
|
||||||
if len(steps) == 0 {
|
if len(steps) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -325,7 +571,7 @@ func toUserVisibleOperations(steps []*orchestrationv2.StepExecution, quote *quot
|
|||||||
if step == nil || !isUserVisibleStep(step.GetReportVisibility()) {
|
if step == nil || !isUserVisibleStep(step.GetReportVisibility()) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ops = append(ops, toPaymentOperation(step, quote))
|
ops = append(ops, toPaymentOperation(step))
|
||||||
}
|
}
|
||||||
if len(ops) == 0 {
|
if len(ops) == 0 {
|
||||||
return nil
|
return nil
|
||||||
@@ -333,9 +579,10 @@ func toUserVisibleOperations(steps []*orchestrationv2.StepExecution, quote *quot
|
|||||||
return ops
|
return ops
|
||||||
}
|
}
|
||||||
|
|
||||||
func toPaymentOperation(step *orchestrationv2.StepExecution, quote *quotationv2.PaymentQuote) PaymentOperation {
|
func toPaymentOperation(step *orchestrationv2.StepExecution) PaymentOperation {
|
||||||
operationRef, gateway := operationRefAndGateway(step.GetStepCode(), step.GetRefs())
|
operationRef, gateway := operationRefAndGateway(step.GetStepCode(), step.GetRefs())
|
||||||
amount, convertedAmount := operationAmounts(step.GetStepCode(), quote)
|
amount := normalizeOperationMoney(toMoney(step.GetExecutedMoney()))
|
||||||
|
convertedAmount := normalizeOperationMoney(toMoney(step.GetConvertedMoney()))
|
||||||
op := PaymentOperation{
|
op := PaymentOperation{
|
||||||
StepRef: step.GetStepRef(),
|
StepRef: step.GetStepRef(),
|
||||||
Code: step.GetStepCode(),
|
Code: step.GetStepCode(),
|
||||||
@@ -344,7 +591,7 @@ func toPaymentOperation(step *orchestrationv2.StepExecution, quote *quotationv2.
|
|||||||
Amount: amount,
|
Amount: amount,
|
||||||
ConvertedAmount: convertedAmount,
|
ConvertedAmount: convertedAmount,
|
||||||
OperationRef: operationRef,
|
OperationRef: operationRef,
|
||||||
Gateway: string(gateway),
|
Gateway: gateway,
|
||||||
StartedAt: timestampAsTime(step.GetStartedAt()),
|
StartedAt: timestampAsTime(step.GetStartedAt()),
|
||||||
CompletedAt: timestampAsTime(step.GetCompletedAt()),
|
CompletedAt: timestampAsTime(step.GetCompletedAt()),
|
||||||
}
|
}
|
||||||
@@ -360,52 +607,19 @@ func toPaymentOperation(step *orchestrationv2.StepExecution, quote *quotationv2.
|
|||||||
return op
|
return op
|
||||||
}
|
}
|
||||||
|
|
||||||
func operationAmounts(stepCode string, quote *quotationv2.PaymentQuote) (*paymenttypes.Money, *paymenttypes.Money) {
|
func normalizeOperationMoney(value *paymenttypes.Money) *paymenttypes.Money {
|
||||||
if quote == nil {
|
if value == nil {
|
||||||
return nil, nil
|
return nil
|
||||||
}
|
}
|
||||||
operation := stepOperationToken(stepCode)
|
amount := strings.TrimSpace(value.GetAmount())
|
||||||
|
currency := strings.TrimSpace(value.GetCurrency())
|
||||||
primary := firstValidMoney(
|
if amount == "" || currency == "" {
|
||||||
toMoney(quote.GetDestinationAmount()),
|
return nil
|
||||||
toMoney(quote.GetTransferPrincipalAmount()),
|
|
||||||
toMoney(quote.GetPayerTotalDebitAmount()),
|
|
||||||
)
|
|
||||||
if operation != "fx_convert" {
|
|
||||||
return primary, nil
|
|
||||||
}
|
}
|
||||||
|
return &paymenttypes.Money{
|
||||||
base := firstValidMoney(
|
Amount: amount,
|
||||||
toMoney(quote.GetTransferPrincipalAmount()),
|
Currency: currency,
|
||||||
toMoney(quote.GetPayerTotalDebitAmount()),
|
|
||||||
toMoney(quote.GetFxQuote().GetBaseAmount()),
|
|
||||||
)
|
|
||||||
quoteAmount := firstValidMoney(
|
|
||||||
toMoney(quote.GetDestinationAmount()),
|
|
||||||
toMoney(quote.GetFxQuote().GetQuoteAmount()),
|
|
||||||
)
|
|
||||||
return base, quoteAmount
|
|
||||||
}
|
|
||||||
|
|
||||||
func stepOperationToken(stepCode string) string {
|
|
||||||
parts := strings.Split(strings.ToLower(strings.TrimSpace(stepCode)), ".")
|
|
||||||
if len(parts) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
}
|
||||||
return strings.TrimSpace(parts[len(parts)-1])
|
|
||||||
}
|
|
||||||
|
|
||||||
func firstValidMoney(values ...*paymenttypes.Money) *paymenttypes.Money {
|
|
||||||
for _, value := range values {
|
|
||||||
if value == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.TrimSpace(value.GetAmount()) == "" || strings.TrimSpace(value.GetCurrency()) == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -456,9 +670,9 @@ func gatewayTypeFromInstanceID(raw string) mservice.Type {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
switch mservice.Type(value) {
|
switch value {
|
||||||
case mservice.ChainGateway, mservice.TronGateway, mservice.MntxGateway, mservice.PaymentGateway, mservice.TgSettle, mservice.Ledger:
|
case mservice.ChainGateway, mservice.TronGateway, mservice.MntxGateway, mservice.PaymentGateway, mservice.TgSettle, mservice.Ledger:
|
||||||
return mservice.Type(value)
|
return value
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
@@ -5,9 +5,12 @@ import (
|
|||||||
|
|
||||||
gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1"
|
gatewayv1 "github.com/tech/sendico/pkg/proto/common/gateway/v1"
|
||||||
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
|
||||||
|
endpointv1 "github.com/tech/sendico/pkg/proto/payments/endpoint/v1"
|
||||||
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
||||||
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
|
quotationv2 "github.com/tech/sendico/pkg/proto/payments/quotation/v2"
|
||||||
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
sharedv1 "github.com/tech/sendico/pkg/proto/payments/shared/v1"
|
||||||
|
"github.com/tech/sendico/server/interface/api/srequest"
|
||||||
|
"go.mongodb.org/mongo-driver/v2/bson"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestToUserVisibleOperationsFiltersByVisibility(t *testing.T) {
|
func TestToUserVisibleOperationsFiltersByVisibility(t *testing.T) {
|
||||||
@@ -34,7 +37,7 @@ func TestToUserVisibleOperationsFiltersByVisibility(t *testing.T) {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
ops := toUserVisibleOperations(steps, nil)
|
ops := toUserVisibleOperations(steps)
|
||||||
if len(ops) != 2 {
|
if len(ops) != 2 {
|
||||||
t.Fatalf("operations count mismatch: got=%d want=2", len(ops))
|
t.Fatalf("operations count mismatch: got=%d want=2", len(ops))
|
||||||
}
|
}
|
||||||
@@ -137,6 +140,125 @@ func TestToPaymentMapsIntentComment(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToPaymentMapsSourceAndDestination(t *testing.T) {
|
||||||
|
sourceRaw, err := bson.Marshal(struct {
|
||||||
|
WalletID string `bson:"walletId"`
|
||||||
|
}{
|
||||||
|
WalletID: "wallet-src-1",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal source method data: %v", err)
|
||||||
|
}
|
||||||
|
destinationRaw, err := bson.Marshal(struct {
|
||||||
|
Currency string `bson:"currency"`
|
||||||
|
Address string `bson:"address"`
|
||||||
|
Network string `bson:"network"`
|
||||||
|
DestinationTag *string `bson:"destinationTag,omitempty"`
|
||||||
|
}{
|
||||||
|
Currency: "USDT",
|
||||||
|
Address: "TXabc",
|
||||||
|
Network: "TRON_MAINNET",
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("marshal destination method data: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := toPayment(&orchestrationv2.Payment{
|
||||||
|
PaymentRef: "pay-src-dst",
|
||||||
|
State: orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_CREATED,
|
||||||
|
IntentSnapshot: "ationv2.QuoteIntent{
|
||||||
|
Source: &endpointv1.PaymentEndpoint{
|
||||||
|
Source: &endpointv1.PaymentEndpoint_PaymentMethod{
|
||||||
|
PaymentMethod: &endpointv1.PaymentMethod{
|
||||||
|
Type: endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_WALLET,
|
||||||
|
Data: sourceRaw,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Destination: &endpointv1.PaymentEndpoint{
|
||||||
|
Source: &endpointv1.PaymentEndpoint_PaymentMethod{
|
||||||
|
PaymentMethod: &endpointv1.PaymentMethod{
|
||||||
|
Type: endpointv1.PaymentMethodType_PAYMENT_METHOD_TYPE_CRYPTO_ADDRESS,
|
||||||
|
Data: destinationRaw,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if dto == nil {
|
||||||
|
t.Fatal("expected non-nil payment dto")
|
||||||
|
}
|
||||||
|
if dto.Source == nil {
|
||||||
|
t.Fatal("expected source endpoint")
|
||||||
|
}
|
||||||
|
if got, want := dto.Source.Type, string(srequest.EndpointTypeWallet); got != want {
|
||||||
|
t.Fatalf("source type mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
sourceEndpoint, ok := dto.Source.Data.(srequest.WalletEndpoint)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("source endpoint payload type mismatch: got=%T", dto.Source.Data)
|
||||||
|
}
|
||||||
|
if got, want := sourceEndpoint.WalletID, "wallet-src-1"; got != want {
|
||||||
|
t.Fatalf("source wallet id mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if dto.Destination == nil {
|
||||||
|
t.Fatal("expected destination endpoint")
|
||||||
|
}
|
||||||
|
if got, want := dto.Destination.Type, string(srequest.EndpointTypeExternalChain); got != want {
|
||||||
|
t.Fatalf("destination type mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
destinationEndpoint, ok := dto.Destination.Data.(srequest.ExternalChainEndpoint)
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("destination endpoint payload type mismatch: got=%T", dto.Destination.Data)
|
||||||
|
}
|
||||||
|
if got, want := destinationEndpoint.Address, "TXabc"; got != want {
|
||||||
|
t.Fatalf("destination address mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if destinationEndpoint.Asset == nil {
|
||||||
|
t.Fatal("expected destination asset")
|
||||||
|
}
|
||||||
|
if got, want := destinationEndpoint.Asset.TokenSymbol, "USDT"; got != want {
|
||||||
|
t.Fatalf("destination token mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := destinationEndpoint.Asset.Chain, srequest.ChainNetworkTronMainnet; got != want {
|
||||||
|
t.Fatalf("destination chain mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPaymentMapsEndpointRefs(t *testing.T) {
|
||||||
|
dto := toPayment(&orchestrationv2.Payment{
|
||||||
|
PaymentRef: "pay-refs",
|
||||||
|
State: orchestrationv2.OrchestrationState_ORCHESTRATION_STATE_CREATED,
|
||||||
|
IntentSnapshot: "ationv2.QuoteIntent{
|
||||||
|
Source: &endpointv1.PaymentEndpoint{
|
||||||
|
Source: &endpointv1.PaymentEndpoint_PaymentMethodRef{
|
||||||
|
PaymentMethodRef: "pm-123",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Destination: &endpointv1.PaymentEndpoint{
|
||||||
|
Source: &endpointv1.PaymentEndpoint_PayeeRef{
|
||||||
|
PayeeRef: "payee-777",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if dto == nil {
|
||||||
|
t.Fatal("expected non-nil payment dto")
|
||||||
|
}
|
||||||
|
if dto.Source == nil {
|
||||||
|
t.Fatal("expected source endpoint")
|
||||||
|
}
|
||||||
|
if got, want := dto.Source.PaymentMethodRef, "pm-123"; got != want {
|
||||||
|
t.Fatalf("source payment_method_ref mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if dto.Destination == nil {
|
||||||
|
t.Fatal("expected destination endpoint")
|
||||||
|
}
|
||||||
|
if got, want := dto.Destination.PayeeRef, "payee-777"; got != want {
|
||||||
|
t.Fatalf("destination payee_ref mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestToPaymentQuote_MapsIntentRef(t *testing.T) {
|
func TestToPaymentQuote_MapsIntentRef(t *testing.T) {
|
||||||
dto := toPaymentQuote("ationv2.PaymentQuote{
|
dto := toPaymentQuote("ationv2.PaymentQuote{
|
||||||
QuoteRef: "quote-1",
|
QuoteRef: "quote-1",
|
||||||
@@ -166,7 +288,7 @@ func TestToPaymentOperation_MapsOperationRefAndGateway(t *testing.T) {
|
|||||||
Ref: "op-123",
|
Ref: "op-123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
})
|
||||||
|
|
||||||
if got, want := op.OperationRef, "op-123"; got != want {
|
if got, want := op.OperationRef, "op-123"; got != want {
|
||||||
t.Fatalf("operation_ref mismatch: got=%q want=%q", got, want)
|
t.Fatalf("operation_ref mismatch: got=%q want=%q", got, want)
|
||||||
@@ -181,7 +303,7 @@ func TestToPaymentOperation_InfersGatewayFromStepCode(t *testing.T) {
|
|||||||
StepRef: "step-2",
|
StepRef: "step-2",
|
||||||
StepCode: "edge.1_2.ledger.debit",
|
StepCode: "edge.1_2.ledger.debit",
|
||||||
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
||||||
}, nil)
|
})
|
||||||
|
|
||||||
if got := op.OperationRef; got != "" {
|
if got := op.OperationRef; got != "" {
|
||||||
t.Fatalf("expected empty operation_ref, got=%q", got)
|
t.Fatalf("expected empty operation_ref, got=%q", got)
|
||||||
@@ -204,7 +326,7 @@ func TestToPaymentOperation_DoesNotFallbackToCardPayoutRef(t *testing.T) {
|
|||||||
Ref: "payout-123",
|
Ref: "payout-123",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, nil)
|
})
|
||||||
|
|
||||||
if got := op.OperationRef; got != "" {
|
if got := op.OperationRef; got != "" {
|
||||||
t.Fatalf("expected empty operation_ref, got=%q", got)
|
t.Fatalf("expected empty operation_ref, got=%q", got)
|
||||||
@@ -219,15 +341,28 @@ func TestToPaymentOperation_MapsAmount(t *testing.T) {
|
|||||||
StepRef: "step-4",
|
StepRef: "step-4",
|
||||||
StepCode: "hop.4.card_payout.send",
|
StepCode: "hop.4.card_payout.send",
|
||||||
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
||||||
}, "ationv2.PaymentQuote{
|
})
|
||||||
TransferPrincipalAmount: &moneyv1.Money{Amount: "110.00", Currency: "USDT"},
|
|
||||||
DestinationAmount: &moneyv1.Money{Amount: "100.00", Currency: "EUR"},
|
if got := op.Amount; got != nil {
|
||||||
|
t.Fatalf("expected nil amount without executed_money, got=%+v", got)
|
||||||
|
}
|
||||||
|
if got := op.ConvertedAmount; got != nil {
|
||||||
|
t.Fatalf("expected no converted_amount for non-fx operation, got=%+v", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestToPaymentOperation_PrefersExecutedMoney(t *testing.T) {
|
||||||
|
op := toPaymentOperation(&orchestrationv2.StepExecution{
|
||||||
|
StepRef: "step-4b",
|
||||||
|
StepCode: "hop.4.card_payout.send",
|
||||||
|
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
||||||
|
ExecutedMoney: &moneyv1.Money{Amount: "99.95", Currency: "EUR"},
|
||||||
})
|
})
|
||||||
|
|
||||||
if op.Amount == nil {
|
if op.Amount == nil {
|
||||||
t.Fatal("expected amount to be mapped")
|
t.Fatal("expected amount to be mapped")
|
||||||
}
|
}
|
||||||
if got, want := op.Amount.Amount, "100.00"; got != want {
|
if got, want := op.Amount.Amount, "99.95"; got != want {
|
||||||
t.Fatalf("amount.value mismatch: got=%q want=%q", got, want)
|
t.Fatalf("amount.value mismatch: got=%q want=%q", got, want)
|
||||||
}
|
}
|
||||||
if got, want := op.Amount.Currency, "EUR"; got != want {
|
if got, want := op.Amount.Currency, "EUR"; got != want {
|
||||||
@@ -240,22 +375,14 @@ func TestToPaymentOperation_MapsAmount(t *testing.T) {
|
|||||||
|
|
||||||
func TestToPaymentOperation_MapsFxTwoAmounts(t *testing.T) {
|
func TestToPaymentOperation_MapsFxTwoAmounts(t *testing.T) {
|
||||||
op := toPaymentOperation(&orchestrationv2.StepExecution{
|
op := toPaymentOperation(&orchestrationv2.StepExecution{
|
||||||
StepRef: "step-5",
|
StepRef: "step-5",
|
||||||
StepCode: "hop.2.settlement.fx_convert",
|
StepCode: "hop.2.settlement.fx_convert",
|
||||||
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
||||||
}, "ationv2.PaymentQuote{
|
ConvertedMoney: &moneyv1.Money{Amount: "100.00", Currency: "EUR"},
|
||||||
TransferPrincipalAmount: &moneyv1.Money{Amount: "110.00", Currency: "USDT"},
|
|
||||||
DestinationAmount: &moneyv1.Money{Amount: "100.00", Currency: "EUR"},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if op.Amount == nil {
|
if got := op.Amount; got != nil {
|
||||||
t.Fatal("expected fx base amount to be mapped")
|
t.Fatalf("expected nil base amount without executed_money, got=%+v", got)
|
||||||
}
|
|
||||||
if got, want := op.Amount.Amount, "110.00"; got != want {
|
|
||||||
t.Fatalf("base amount.value mismatch: got=%q want=%q", got, want)
|
|
||||||
}
|
|
||||||
if got, want := op.Amount.Currency, "USDT"; got != want {
|
|
||||||
t.Fatalf("base amount.currency mismatch: got=%q want=%q", got, want)
|
|
||||||
}
|
}
|
||||||
if op.ConvertedAmount == nil {
|
if op.ConvertedAmount == nil {
|
||||||
t.Fatal("expected fx converted amount to be mapped")
|
t.Fatal("expected fx converted amount to be mapped")
|
||||||
@@ -267,3 +394,32 @@ func TestToPaymentOperation_MapsFxTwoAmounts(t *testing.T) {
|
|||||||
t.Fatalf("converted amount.currency mismatch: got=%q want=%q", got, want)
|
t.Fatalf("converted amount.currency mismatch: got=%q want=%q", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestToPaymentOperation_FxWithExecutedMoney_StillProvidesTwoAmounts(t *testing.T) {
|
||||||
|
op := toPaymentOperation(&orchestrationv2.StepExecution{
|
||||||
|
StepRef: "step-6",
|
||||||
|
StepCode: "hop.2.settlement.fx_convert",
|
||||||
|
State: orchestrationv2.StepExecutionState_STEP_EXECUTION_STATE_COMPLETED,
|
||||||
|
ExecutedMoney: &moneyv1.Money{Amount: "109.50", Currency: "USDT"},
|
||||||
|
ConvertedMoney: &moneyv1.Money{Amount: "100.00", Currency: "EUR"},
|
||||||
|
})
|
||||||
|
|
||||||
|
if op.Amount == nil {
|
||||||
|
t.Fatal("expected fx base amount to be mapped")
|
||||||
|
}
|
||||||
|
if got, want := op.Amount.Amount, "109.50"; got != want {
|
||||||
|
t.Fatalf("base amount.value mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := op.Amount.Currency, "USDT"; got != want {
|
||||||
|
t.Fatalf("base amount.currency mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if op.ConvertedAmount == nil {
|
||||||
|
t.Fatal("expected fx quote amount to be mapped")
|
||||||
|
}
|
||||||
|
if got, want := op.ConvertedAmount.Amount, "100.00"; got != want {
|
||||||
|
t.Fatalf("converted amount.value mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
if got, want := op.ConvertedAmount.Currency, "EUR"; got != want {
|
||||||
|
t.Fatalf("converted amount.currency mismatch: got=%q want=%q", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ func Account2ClaimsForClient(a *model.Account, expiration int, clientID string)
|
|||||||
paramNameName: t.Name,
|
paramNameName: t.Name,
|
||||||
paramNameLocale: t.Locale,
|
paramNameLocale: t.Locale,
|
||||||
paramNameClientID: t.ClientID,
|
paramNameClientID: t.ClientID,
|
||||||
paramNameExpiration: int64(t.Expiration.Unix()),
|
paramNameExpiration: t.Expiration.Unix(),
|
||||||
paramNamePending: t.Pending,
|
paramNamePending: t.Pending,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,11 +26,11 @@ const (
|
|||||||
var (
|
var (
|
||||||
ledgerDiscoveryServiceNames = []string{
|
ledgerDiscoveryServiceNames = []string{
|
||||||
"LEDGER",
|
"LEDGER",
|
||||||
string(mservice.Ledger),
|
mservice.Ledger,
|
||||||
}
|
}
|
||||||
paymentOrchestratorDiscoveryServiceNames = []string{
|
paymentOrchestratorDiscoveryServiceNames = []string{
|
||||||
"PAYMENTS_ORCHESTRATOR",
|
"PAYMENTS_ORCHESTRATOR",
|
||||||
string(mservice.PaymentOrchestrator),
|
mservice.PaymentOrchestrator,
|
||||||
}
|
}
|
||||||
paymentQuotationDiscoveryServiceNames = []string{
|
paymentQuotationDiscoveryServiceNames = []string{
|
||||||
"PAYMENTS_QUOTATION",
|
"PAYMENTS_QUOTATION",
|
||||||
@@ -41,7 +41,7 @@ var (
|
|||||||
paymentMethodsDiscoveryServiceNames = []string{
|
paymentMethodsDiscoveryServiceNames = []string{
|
||||||
"PAYMENTS_METHODS",
|
"PAYMENTS_METHODS",
|
||||||
"PAYMENT_METHODS",
|
"PAYMENT_METHODS",
|
||||||
string(mservice.PaymentMethods),
|
mservice.PaymentMethods,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -339,13 +339,13 @@ func selectGatewayEndpoint(gateways []discovery.GatewaySummary, preferredNetwork
|
|||||||
func parseDiscoveryInvokeURI(raw string) (discoveryEndpoint, error) {
|
func parseDiscoveryInvokeURI(raw string) (discoveryEndpoint, error) {
|
||||||
raw = strings.TrimSpace(raw)
|
raw = strings.TrimSpace(raw)
|
||||||
if raw == "" {
|
if raw == "" {
|
||||||
return discoveryEndpoint{}, fmt.Errorf("Invoke uri is empty")
|
return discoveryEndpoint{}, fmt.Errorf("invoke uri is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Without a scheme we expect a plain host:port target.
|
// Without a scheme we expect a plain host:port target.
|
||||||
if !strings.Contains(raw, "://") {
|
if !strings.Contains(raw, "://") {
|
||||||
if _, _, err := net.SplitHostPort(raw); err != nil {
|
if _, _, err := net.SplitHostPort(raw); err != nil {
|
||||||
return discoveryEndpoint{}, fmt.Errorf("Invoke uri must include host:port: %w", err)
|
return discoveryEndpoint{}, fmt.Errorf("invoke uri must include host:port: %w", err)
|
||||||
}
|
}
|
||||||
return discoveryEndpoint{
|
return discoveryEndpoint{
|
||||||
address: raw,
|
address: raw,
|
||||||
@@ -363,7 +363,7 @@ func parseDiscoveryInvokeURI(raw string) (discoveryEndpoint, error) {
|
|||||||
case "grpc":
|
case "grpc":
|
||||||
address := strings.TrimSpace(parsed.Host)
|
address := strings.TrimSpace(parsed.Host)
|
||||||
if _, _, splitErr := net.SplitHostPort(address); splitErr != nil {
|
if _, _, splitErr := net.SplitHostPort(address); splitErr != nil {
|
||||||
return discoveryEndpoint{}, fmt.Errorf("Grpc invoke uri must include host:port: %w", splitErr)
|
return discoveryEndpoint{}, fmt.Errorf("grpc invoke uri must include host:port: %w", splitErr)
|
||||||
}
|
}
|
||||||
return discoveryEndpoint{
|
return discoveryEndpoint{
|
||||||
address: address,
|
address: address,
|
||||||
@@ -373,7 +373,7 @@ func parseDiscoveryInvokeURI(raw string) (discoveryEndpoint, error) {
|
|||||||
case "grpcs":
|
case "grpcs":
|
||||||
address := strings.TrimSpace(parsed.Host)
|
address := strings.TrimSpace(parsed.Host)
|
||||||
if _, _, splitErr := net.SplitHostPort(address); splitErr != nil {
|
if _, _, splitErr := net.SplitHostPort(address); splitErr != nil {
|
||||||
return discoveryEndpoint{}, fmt.Errorf("Grpcs invoke uri must include host:port: %w", splitErr)
|
return discoveryEndpoint{}, fmt.Errorf("grpcs invoke uri must include host:port: %w", splitErr)
|
||||||
}
|
}
|
||||||
return discoveryEndpoint{
|
return discoveryEndpoint{
|
||||||
address: address,
|
address: address,
|
||||||
@@ -388,7 +388,7 @@ func parseDiscoveryInvokeURI(raw string) (discoveryEndpoint, error) {
|
|||||||
raw: raw,
|
raw: raw,
|
||||||
}, nil
|
}, nil
|
||||||
default:
|
default:
|
||||||
return discoveryEndpoint{}, fmt.Errorf("Unsupported invoke uri scheme: %s", parsed.Scheme)
|
return discoveryEndpoint{}, fmt.Errorf("unsupported invoke uri scheme: %s", parsed.Scheme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ func (d *DispatcherImpl) dispatchMessage(ctx context.Context, conn *websocket.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *DispatcherImpl) handle(w http.ResponseWriter, r *http.Request) {
|
func (d *DispatcherImpl) handle(w http.ResponseWriter, r *http.Request) {
|
||||||
|
//nolint:contextcheck // websocket.Handler callback signature does not carry request context.
|
||||||
websocket.Handler(func(conn *websocket.Conn) {
|
websocket.Handler(func(conn *websocket.Conn) {
|
||||||
ctx, cancel := context.WithTimeout(r.Context(), time.Duration(d.timeout)*time.Second)
|
ctx, cancel := context.WithTimeout(r.Context(), time.Duration(d.timeout)*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ func GetOptionalParam[T any](logger mlogger.Logger, r *http.Request, key string,
|
|||||||
vals := r.URL.Query()
|
vals := r.URL.Query()
|
||||||
s := vals.Get(key)
|
s := vals.Get(key)
|
||||||
if s == "" {
|
if s == "" {
|
||||||
|
//nolint:nilnil // Missing optional query parameter is represented as (nil, nil).
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
package mutil
|
package mutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"net/http"
|
"net/http"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/tech/sendico/pkg/mlogger"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetOptionalBoolParam(t *testing.T) {
|
func TestGetOptionalBoolParam(t *testing.T) {
|
||||||
logger := mlogger.Logger(zap.NewNop())
|
logger := zap.NewNop()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -47,7 +47,7 @@ func TestGetOptionalBoolParam(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
req, err := http.NewRequest("GET", "http://example.com"+tt.query, nil)
|
req, err := http.NewRequestWithContext(context.Background(), "GET", "http://example.com"+tt.query, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err := GetOptionalBoolParam(logger, req, "param")
|
result, err := GetOptionalBoolParam(logger, req, "param")
|
||||||
@@ -69,7 +69,7 @@ func TestGetOptionalBoolParam(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOptionalInt64Param(t *testing.T) {
|
func TestGetOptionalInt64Param(t *testing.T) {
|
||||||
logger := mlogger.Logger(zap.NewNop())
|
logger := zap.NewNop()
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@@ -111,7 +111,7 @@ func TestGetOptionalInt64Param(t *testing.T) {
|
|||||||
|
|
||||||
for _, tt := range tests {
|
for _, tt := range tests {
|
||||||
t.Run(tt.name, func(t *testing.T) {
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
req, err := http.NewRequest("GET", "http://example.com"+tt.query, nil)
|
req, err := http.NewRequestWithContext(context.Background(), "GET", "http://example.com"+tt.query, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
result, err := GetOptionalInt64Param(logger, req, "param")
|
result, err := GetOptionalInt64Param(logger, req, "param")
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ func (a *AccountAPI) deleteAll(r *http.Request, account *model.Account, token *s
|
|||||||
a.logger.Warn("Failed to delete all data", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account))
|
a.logger.Warn("Failed to delete all data", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, nil
|
return struct{}{}, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
a.logger.Warn("Failed to execute delete transaction", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account))
|
a.logger.Warn("Failed to execute delete transaction", zap.Error(err), mzap.StorableRef(&org), mzap.StorableRef(account))
|
||||||
return response.Auto(a.logger, a.Name(), err)
|
return response.Auto(a.logger, a.Name(), err)
|
||||||
|
|||||||
@@ -192,5 +192,5 @@ func (a *AccountAPI) resetPasswordTransactionBody(ctx context.Context, user *mod
|
|||||||
// Don't fail the transaction if token revocation fails, but log it
|
// Don't fail the transaction if token revocation fails, but log it
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return struct{}{}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -133,12 +133,7 @@ func TestPasswordValidationLogic(t *testing.T) {
|
|||||||
for _, password := range invalidPasswords {
|
for _, password := range invalidPasswords {
|
||||||
t.Run(password, func(t *testing.T) {
|
t.Run(password, func(t *testing.T) {
|
||||||
// Test that invalid passwords fail at least one requirement
|
// Test that invalid passwords fail at least one requirement
|
||||||
isValid := true
|
isValid := len(password) >= 8
|
||||||
|
|
||||||
// Check length
|
|
||||||
if len(password) < 8 {
|
|
||||||
isValid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for digit
|
// Check for digit
|
||||||
hasDigit := false
|
hasDigit := false
|
||||||
|
|||||||
@@ -276,7 +276,7 @@ func (a *AccountAPI) grantAllPermissions(ctx context.Context, organizationRef bs
|
|||||||
|
|
||||||
for resource, granted := range required {
|
for resource, granted := range required {
|
||||||
if !granted {
|
if !granted {
|
||||||
a.logger.Warn("Required policy description not found for signup permissions", zap.String("resource", string(resource)))
|
a.logger.Warn("Required policy description not found for signup permissions", zap.String("resource", resource))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,9 +338,6 @@ func (a *AccountAPI) openOrgLedgerAccount(ctx context.Context, org *model.Organi
|
|||||||
return merrors.Internal("chain gateway default asset is not configured")
|
return merrors.Internal("chain gateway default asset is not configured")
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove hardcode
|
|
||||||
currency := "RUB"
|
|
||||||
|
|
||||||
var describable *describablev1.Describable
|
var describable *describablev1.Describable
|
||||||
name := strings.TrimSpace(sr.LedgerWallet.Name)
|
name := strings.TrimSpace(sr.LedgerWallet.Name)
|
||||||
var description *string
|
var description *string
|
||||||
@@ -357,26 +354,47 @@ func (a *AccountAPI) openOrgLedgerAccount(ctx context.Context, org *model.Organi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := a.ledgerClient.CreateAccount(ctx, &ledgerv1.CreateAccountRequest{
|
currencies := []string{"RUB", "USDT"}
|
||||||
OrganizationRef: org.ID.Hex(),
|
if chainTokenCurrency := strings.ToUpper(strings.TrimSpace(a.chainAsset.GetTokenSymbol())); chainTokenCurrency != "" {
|
||||||
AccountType: ledgerv1.AccountType_ACCOUNT_TYPE_ASSET,
|
currencies = append(currencies, chainTokenCurrency)
|
||||||
Currency: currency,
|
}
|
||||||
Status: ledgerv1.AccountStatus_ACCOUNT_STATUS_ACTIVE,
|
|
||||||
Role: ledgerv1.AccountRole_ACCOUNT_ROLE_OPERATING,
|
seen := make(map[string]struct{}, len(currencies))
|
||||||
Metadata: map[string]string{
|
for _, currency := range currencies {
|
||||||
"source": "signup",
|
currency = strings.ToUpper(strings.TrimSpace(currency))
|
||||||
"login": sr.Account.Login,
|
if currency == "" {
|
||||||
},
|
continue
|
||||||
Describable: describable,
|
}
|
||||||
})
|
if _, exists := seen[currency]; exists {
|
||||||
if err != nil {
|
continue
|
||||||
a.logger.Warn("Failed to create ledger account for organization", zap.Error(err), mzap.StorableRef(org))
|
}
|
||||||
return err
|
seen[currency] = struct{}{}
|
||||||
}
|
|
||||||
if resp == nil || resp.GetAccount() == nil || strings.TrimSpace(resp.GetAccount().GetLedgerAccountRef()) == "" {
|
resp, err := a.ledgerClient.CreateAccount(ctx, &ledgerv1.CreateAccountRequest{
|
||||||
return merrors.Internal("ledger returned empty account reference")
|
OrganizationRef: org.ID.Hex(),
|
||||||
|
AccountType: ledgerv1.AccountType_ACCOUNT_TYPE_ASSET,
|
||||||
|
Currency: currency,
|
||||||
|
Status: ledgerv1.AccountStatus_ACCOUNT_STATUS_ACTIVE,
|
||||||
|
Role: ledgerv1.AccountRole_ACCOUNT_ROLE_OPERATING,
|
||||||
|
Metadata: map[string]string{
|
||||||
|
"source": "signup",
|
||||||
|
"login": sr.Account.Login,
|
||||||
|
},
|
||||||
|
Describable: describable,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
a.logger.Warn("Failed to create ledger account for organization", zap.Error(err), mzap.StorableRef(org), zap.String("currency", currency))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp == nil || resp.GetAccount() == nil || strings.TrimSpace(resp.GetAccount().GetLedgerAccountRef()) == "" {
|
||||||
|
return merrors.Internal("ledger returned empty account reference")
|
||||||
|
}
|
||||||
|
|
||||||
|
a.logger.Info("Ledger account created for organization",
|
||||||
|
mzap.StorableRef(org),
|
||||||
|
zap.String("currency", currency),
|
||||||
|
zap.String("ledger_account_ref", resp.GetAccount().GetLedgerAccountRef()))
|
||||||
}
|
}
|
||||||
|
|
||||||
a.logger.Info("Ledger account created for organization", mzap.StorableRef(org), zap.String("ledger_account_ref", resp.GetAccount().GetLedgerAccountRef()))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ func TestSignupHTTPSerialization(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create HTTP request
|
// Create HTTP request
|
||||||
req := httptest.NewRequest(http.MethodPost, "/signup", bytes.NewBuffer(reqBody))
|
req := httptest.NewRequestWithContext(context.Background(), http.MethodPost, "/signup", bytes.NewBuffer(reqBody))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
// Parse the request body
|
// Parse the request body
|
||||||
@@ -162,7 +162,7 @@ func TestSignupHTTPSerialization(t *testing.T) {
|
|||||||
t.Run("InvalidJSONRequest", func(t *testing.T) {
|
t.Run("InvalidJSONRequest", func(t *testing.T) {
|
||||||
invalidJSON := `{"account": {"login": "test@example.com", "password": "invalid json structure`
|
invalidJSON := `{"account": {"login": "test@example.com", "password": "invalid json structure`
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/signup", bytes.NewBufferString(invalidJSON))
|
req := httptest.NewRequestWithContext(context.Background(), http.MethodPost, "/signup", bytes.NewBufferString(invalidJSON))
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
var parsedRequest srequest.Signup
|
var parsedRequest srequest.Signup
|
||||||
|
|||||||
@@ -16,13 +16,13 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type stubLedgerAccountClient struct {
|
type stubLedgerAccountClient struct {
|
||||||
createReq *ledgerv1.CreateAccountRequest
|
createReqs []*ledgerv1.CreateAccountRequest
|
||||||
createResp *ledgerv1.CreateAccountResponse
|
createResp *ledgerv1.CreateAccountResponse
|
||||||
createErr error
|
createErr error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *stubLedgerAccountClient) CreateAccount(_ context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error) {
|
func (s *stubLedgerAccountClient) CreateAccount(_ context.Context, req *ledgerv1.CreateAccountRequest) (*ledgerv1.CreateAccountResponse, error) {
|
||||||
s.createReq = req
|
s.createReqs = append(s.createReqs, req)
|
||||||
return s.createResp, s.createErr
|
return s.createResp, s.createErr
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -31,7 +31,7 @@ func (s *stubLedgerAccountClient) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestOpenOrgLedgerAccount(t *testing.T) {
|
func TestOpenOrgLedgerAccount(t *testing.T) {
|
||||||
t.Run("creates operating ledger account", func(t *testing.T) {
|
t.Run("creates operating ledger accounts for RUB and USDT", func(t *testing.T) {
|
||||||
desc := " Main org ledger account "
|
desc := " Main org ledger account "
|
||||||
sr := &srequest.Signup{
|
sr := &srequest.Signup{
|
||||||
Account: model.AccountData{
|
Account: model.AccountData{
|
||||||
@@ -65,22 +65,26 @@ func TestOpenOrgLedgerAccount(t *testing.T) {
|
|||||||
|
|
||||||
err := api.openOrgLedgerAccount(context.Background(), org, sr)
|
err := api.openOrgLedgerAccount(context.Background(), org, sr)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
if assert.NotNil(t, ledgerStub.createReq) {
|
if assert.Len(t, ledgerStub.createReqs, 2) {
|
||||||
assert.Equal(t, org.ID.Hex(), ledgerStub.createReq.GetOrganizationRef())
|
currencies := make([]string, 0, len(ledgerStub.createReqs))
|
||||||
assert.Equal(t, "RUB", ledgerStub.createReq.GetCurrency())
|
for _, req := range ledgerStub.createReqs {
|
||||||
assert.Equal(t, ledgerv1.AccountType_ACCOUNT_TYPE_ASSET, ledgerStub.createReq.GetAccountType())
|
currencies = append(currencies, req.GetCurrency())
|
||||||
assert.Equal(t, ledgerv1.AccountStatus_ACCOUNT_STATUS_ACTIVE, ledgerStub.createReq.GetStatus())
|
assert.Equal(t, org.ID.Hex(), req.GetOrganizationRef())
|
||||||
assert.Equal(t, ledgerv1.AccountRole_ACCOUNT_ROLE_OPERATING, ledgerStub.createReq.GetRole())
|
assert.Equal(t, ledgerv1.AccountType_ACCOUNT_TYPE_ASSET, req.GetAccountType())
|
||||||
assert.Equal(t, map[string]string{
|
assert.Equal(t, ledgerv1.AccountStatus_ACCOUNT_STATUS_ACTIVE, req.GetStatus())
|
||||||
"source": "signup",
|
assert.Equal(t, ledgerv1.AccountRole_ACCOUNT_ROLE_OPERATING, req.GetRole())
|
||||||
"login": "owner@example.com",
|
assert.Equal(t, map[string]string{
|
||||||
}, ledgerStub.createReq.GetMetadata())
|
"source": "signup",
|
||||||
if assert.NotNil(t, ledgerStub.createReq.GetDescribable()) {
|
"login": "owner@example.com",
|
||||||
assert.Equal(t, "Primary Ledger", ledgerStub.createReq.GetDescribable().GetName())
|
}, req.GetMetadata())
|
||||||
if assert.NotNil(t, ledgerStub.createReq.GetDescribable().Description) {
|
if assert.NotNil(t, req.GetDescribable()) {
|
||||||
assert.Equal(t, "Main org ledger account", ledgerStub.createReq.GetDescribable().GetDescription())
|
assert.Equal(t, "Primary Ledger", req.GetDescribable().GetName())
|
||||||
|
if assert.NotNil(t, req.GetDescribable().Description) {
|
||||||
|
assert.Equal(t, "Main org ledger account", req.GetDescribable().GetDescription())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert.ElementsMatch(t, []string{"RUB", "USDT"}, currencies)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ func (a *CallbacksAPI) create(r *http.Request, account *model.Account, accessTok
|
|||||||
if err := a.applySigningSecretMutation(ctx, *account.GetID(), *callback.GetID(), mutation); err != nil {
|
if err := a.applySigningSecretMutation(ctx, *account.GetID(), *callback.GetID(), mutation); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, nil
|
return struct{}{}, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
a.Logger.Warn("Failed to create callback transaction", zap.Error(err))
|
a.Logger.Warn("Failed to create callback transaction", zap.Error(err))
|
||||||
return response.Auto(a.Logger, a.Name(), err)
|
return response.Auto(a.Logger, a.Name(), err)
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ func (a *CallbacksAPI) update(r *http.Request, account *model.Account, accessTok
|
|||||||
if err := a.applySigningSecretMutation(ctx, *account.GetID(), callbackRef, mutation); err != nil {
|
if err := a.applySigningSecretMutation(ctx, *account.GetID(), callbackRef, mutation); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return nil, nil
|
return struct{}{}, nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
a.Logger.Warn("Failed to update callback transaction", zap.Error(err))
|
a.Logger.Warn("Failed to update callback transaction", zap.Error(err))
|
||||||
return response.Auto(a.Logger, a.Name(), err)
|
return response.Auto(a.Logger, a.Name(), err)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/tech/sendico/pkg/api/http/response"
|
"github.com/tech/sendico/pkg/api/http/response"
|
||||||
"github.com/tech/sendico/pkg/domainprovider"
|
"github.com/tech/sendico/pkg/domainprovider"
|
||||||
@@ -34,7 +35,10 @@ func (storage *LocalStorage) Delete(ctx context.Context, objID string) error {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := filepath.Join(storage.storageDir, objID)
|
filePath, err := storage.resolvePath(objID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if err := os.Remove(filePath); err != nil {
|
if err := os.Remove(filePath); err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
storage.logger.Debug("File not found", zap.String("obj_ref", objID))
|
storage.logger.Debug("File not found", zap.String("obj_ref", objID))
|
||||||
@@ -54,7 +58,11 @@ func (storage *LocalStorage) Save(ctx context.Context, file io.Reader, objID str
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := filepath.Join(storage.storageDir, objID)
|
filePath, err := storage.resolvePath(objID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
//nolint:gosec // File path is resolved and constrained to storage root.
|
||||||
dst, err := os.Create(filePath)
|
dst, err := os.Create(filePath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
storage.logger.Warn("Error occurred while creating file", zap.Error(err), zap.String("storage", storage.storageDir), zap.String("obj_ref", objID))
|
storage.logger.Warn("Error occurred while creating file", zap.Error(err), zap.String("storage", storage.storageDir), zap.String("obj_ref", objID))
|
||||||
@@ -78,7 +86,9 @@ func (storage *LocalStorage) Save(ctx context.Context, file io.Reader, objID str
|
|||||||
}
|
}
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
// Context was cancelled, clean up the partial file
|
// Context was cancelled, clean up the partial file
|
||||||
os.Remove(filePath)
|
if removeErr := os.Remove(filePath); removeErr != nil && !os.IsNotExist(removeErr) {
|
||||||
|
storage.logger.Warn("Failed to remove partially written file", zap.Error(removeErr), zap.String("obj_ref", objID))
|
||||||
|
}
|
||||||
return "", ctx.Err()
|
return "", ctx.Err()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +103,10 @@ func (storage *LocalStorage) Get(ctx context.Context, objRef string) http.Handle
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
|
||||||
filePath := filepath.Join(storage.storageDir, objRef)
|
filePath, err := storage.resolvePath(objRef)
|
||||||
|
if err != nil {
|
||||||
|
return response.Internal(storage.logger, storage.service, err)
|
||||||
|
}
|
||||||
if _, err := os.Stat(filePath); err != nil {
|
if _, err := os.Stat(filePath); err != nil {
|
||||||
storage.logger.Warn("Failed to access file", zap.Error(err), zap.String("storage", storage.storageDir), zap.String("obj_ref", objRef))
|
storage.logger.Warn("Failed to access file", zap.Error(err), zap.String("storage", storage.storageDir), zap.String("obj_ref", objRef))
|
||||||
return response.Internal(storage.logger, storage.service, err)
|
return response.Internal(storage.logger, storage.service, err)
|
||||||
@@ -117,7 +130,7 @@ func (storage *LocalStorage) Get(ctx context.Context, objRef string) http.Handle
|
|||||||
func ensureDir(dirName string) error {
|
func ensureDir(dirName string) error {
|
||||||
info, err := os.Stat(dirName)
|
info, err := os.Stat(dirName)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
return os.MkdirAll(dirName, 0o755)
|
return os.MkdirAll(dirName, 0o750)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -128,6 +141,24 @@ func ensureDir(dirName string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (storage *LocalStorage) resolvePath(objID string) (string, error) {
|
||||||
|
objID = strings.TrimSpace(objID)
|
||||||
|
if objID == "" {
|
||||||
|
return "", merrors.InvalidArgument("obj_ref is required", "obj_ref")
|
||||||
|
}
|
||||||
|
|
||||||
|
filePath := filepath.Join(storage.storageDir, objID)
|
||||||
|
relPath, err := filepath.Rel(storage.storageDir, filePath)
|
||||||
|
if err != nil {
|
||||||
|
return "", merrors.InternalWrap(err, "failed to resolve local file path")
|
||||||
|
}
|
||||||
|
if relPath == "." || strings.HasPrefix(relPath, "..") {
|
||||||
|
return "", merrors.InvalidArgument("obj_ref is invalid", "obj_ref")
|
||||||
|
}
|
||||||
|
|
||||||
|
return filePath, nil
|
||||||
|
}
|
||||||
|
|
||||||
func CreateLocalFileStorage(logger mlogger.Logger, service mservice.Type, directory, subDir string, dp domainprovider.DomainProvider, cfg config.LocalFSSConfig) (*LocalStorage, error) {
|
func CreateLocalFileStorage(logger mlogger.Logger, service mservice.Type, directory, subDir string, dp domainprovider.DomainProvider, cfg config.LocalFSSConfig) (*LocalStorage, error) {
|
||||||
dir := filepath.Join(cfg.RootPath, directory)
|
dir := filepath.Join(cfg.RootPath, directory)
|
||||||
if err := ensureDir(dir); err != nil {
|
if err := ensureDir(dir); err != nil {
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ func setupTestStorage(t *testing.T) (*LocalStorage, string, func()) {
|
|||||||
|
|
||||||
// Return cleanup function
|
// Return cleanup function
|
||||||
cleanup := func() {
|
cleanup := func() {
|
||||||
os.RemoveAll(tempDir)
|
require.NoError(t, os.RemoveAll(tempDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
return storage, tempDir, cleanup
|
return storage, tempDir, cleanup
|
||||||
@@ -81,7 +81,7 @@ func setupBenchmarkStorage(b *testing.B) (*LocalStorage, string, func()) {
|
|||||||
|
|
||||||
// Return cleanup function
|
// Return cleanup function
|
||||||
cleanup := func() {
|
cleanup := func() {
|
||||||
os.RemoveAll(tempDir)
|
require.NoError(b, os.RemoveAll(tempDir))
|
||||||
}
|
}
|
||||||
|
|
||||||
return storage, tempDir, cleanup
|
return storage, tempDir, cleanup
|
||||||
@@ -138,6 +138,7 @@ func TestLocalStorage_Save(t *testing.T) {
|
|||||||
|
|
||||||
// Verify file was actually saved
|
// Verify file was actually saved
|
||||||
filePath := filepath.Join(tempDir, tt.objID)
|
filePath := filepath.Join(tempDir, tt.objID)
|
||||||
|
//nolint:gosec // Test-controlled path inside temporary directory.
|
||||||
content, err := os.ReadFile(filePath)
|
content, err := os.ReadFile(filePath)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.Equal(t, tt.content, string(content))
|
assert.Equal(t, tt.content, string(content))
|
||||||
@@ -186,7 +187,7 @@ func TestLocalStorage_Delete(t *testing.T) {
|
|||||||
|
|
||||||
// Create a test file
|
// Create a test file
|
||||||
testFile := filepath.Join(tempDir, "test.txt")
|
testFile := filepath.Join(tempDir, "test.txt")
|
||||||
err := os.WriteFile(testFile, []byte("test content"), 0o644)
|
err := os.WriteFile(testFile, []byte("test content"), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -232,7 +233,7 @@ func TestLocalStorage_Delete_ContextCancellation(t *testing.T) {
|
|||||||
|
|
||||||
// Create a test file
|
// Create a test file
|
||||||
testFile := filepath.Join(tempDir, "test.txt")
|
testFile := filepath.Join(tempDir, "test.txt")
|
||||||
err := os.WriteFile(testFile, []byte("test content"), 0o644)
|
err := os.WriteFile(testFile, []byte("test content"), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a context that's already cancelled
|
// Create a context that's already cancelled
|
||||||
@@ -256,7 +257,7 @@ func TestLocalStorage_Get(t *testing.T) {
|
|||||||
// Create a test file
|
// Create a test file
|
||||||
testContent := "test file content"
|
testContent := "test file content"
|
||||||
testFile := filepath.Join(tempDir, "test.txt")
|
testFile := filepath.Join(tempDir, "test.txt")
|
||||||
err := os.WriteFile(testFile, []byte(testContent), 0o644)
|
err := os.WriteFile(testFile, []byte(testContent), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
@@ -285,7 +286,7 @@ func TestLocalStorage_Get(t *testing.T) {
|
|||||||
handler := storage.Get(ctx, tt.objID)
|
handler := storage.Get(ctx, tt.objID)
|
||||||
|
|
||||||
// Create test request
|
// Create test request
|
||||||
req := httptest.NewRequest("GET", "/files/"+tt.objID, nil)
|
req := httptest.NewRequestWithContext(context.Background(), "GET", "/files/"+tt.objID, nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
@@ -304,7 +305,7 @@ func TestLocalStorage_Get_ContextCancellation(t *testing.T) {
|
|||||||
|
|
||||||
// Create a test file
|
// Create a test file
|
||||||
testFile := filepath.Join(tempDir, "test.txt")
|
testFile := filepath.Join(tempDir, "test.txt")
|
||||||
err := os.WriteFile(testFile, []byte("test content"), 0o644)
|
err := os.WriteFile(testFile, []byte("test content"), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Create a context that's already cancelled
|
// Create a context that's already cancelled
|
||||||
@@ -314,7 +315,7 @@ func TestLocalStorage_Get_ContextCancellation(t *testing.T) {
|
|||||||
handler := storage.Get(ctx, "test.txt")
|
handler := storage.Get(ctx, "test.txt")
|
||||||
|
|
||||||
// Create test request
|
// Create test request
|
||||||
req := httptest.NewRequest("GET", "/files/test.txt", nil)
|
req := httptest.NewRequestWithContext(context.Background(), "GET", "/files/test.txt", nil)
|
||||||
w := httptest.NewRecorder()
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
@@ -328,14 +329,14 @@ func TestLocalStorage_Get_RequestContextCancellation(t *testing.T) {
|
|||||||
|
|
||||||
// Create a test file
|
// Create a test file
|
||||||
testFile := filepath.Join(tempDir, "test.txt")
|
testFile := filepath.Join(tempDir, "test.txt")
|
||||||
err := os.WriteFile(testFile, []byte("test content"), 0o644)
|
err := os.WriteFile(testFile, []byte("test content"), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
handler := storage.Get(ctx, "test.txt")
|
handler := storage.Get(ctx, "test.txt")
|
||||||
|
|
||||||
// Create test request with cancelled context
|
// Create test request with cancelled context
|
||||||
req := httptest.NewRequest("GET", "/files/test.txt", nil)
|
req := httptest.NewRequestWithContext(context.Background(), "GET", "/files/test.txt", nil)
|
||||||
reqCtx, cancel := context.WithCancel(req.Context())
|
reqCtx, cancel := context.WithCancel(req.Context())
|
||||||
req = req.WithContext(reqCtx)
|
req = req.WithContext(reqCtx)
|
||||||
cancel() // Cancel the request context
|
cancel() // Cancel the request context
|
||||||
@@ -352,7 +353,9 @@ func TestCreateLocalFileStorage(t *testing.T) {
|
|||||||
// Create temporary directory for testing
|
// Create temporary directory for testing
|
||||||
tempDir, err := os.MkdirTemp("", "storage_test")
|
tempDir, err := os.MkdirTemp("", "storage_test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.RemoveAll(tempDir)
|
defer func() {
|
||||||
|
require.NoError(t, os.RemoveAll(tempDir))
|
||||||
|
}()
|
||||||
|
|
||||||
logger := zap.NewNop()
|
logger := zap.NewNop()
|
||||||
cfg := config.LocalFSSConfig{
|
cfg := config.LocalFSSConfig{
|
||||||
@@ -372,10 +375,12 @@ func TestCreateLocalFileStorage_InvalidPath(t *testing.T) {
|
|||||||
// Build a deterministic failure case: the target path already exists as a file.
|
// Build a deterministic failure case: the target path already exists as a file.
|
||||||
tempDir, err := os.MkdirTemp("", "storage_invalid_path_test")
|
tempDir, err := os.MkdirTemp("", "storage_invalid_path_test")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer os.RemoveAll(tempDir)
|
defer func() {
|
||||||
|
require.NoError(t, os.RemoveAll(tempDir))
|
||||||
|
}()
|
||||||
|
|
||||||
fileAtTargetPath := filepath.Join(tempDir, "test")
|
fileAtTargetPath := filepath.Join(tempDir, "test")
|
||||||
err = os.WriteFile(fileAtTargetPath, []byte("not a directory"), 0o644)
|
err = os.WriteFile(fileAtTargetPath, []byte("not a directory"), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
logger := zap.NewNop()
|
logger := zap.NewNop()
|
||||||
@@ -426,7 +431,7 @@ func TestLocalStorage_ConcurrentOperations(t *testing.T) {
|
|||||||
// Create files to delete
|
// Create files to delete
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < 5; i++ {
|
||||||
filePath := filepath.Join(tempDir, fmt.Sprintf("delete_%d.txt", i))
|
filePath := filepath.Join(tempDir, fmt.Sprintf("delete_%d.txt", i))
|
||||||
err := os.WriteFile(filePath, []byte("content"), 0o644)
|
err := os.WriteFile(filePath, []byte("content"), 0o600)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -536,7 +541,7 @@ func BenchmarkLocalStorage_Delete(b *testing.B) {
|
|||||||
// Pre-create files for deletion
|
// Pre-create files for deletion
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
filePath := filepath.Join(tempDir, fmt.Sprintf("bench_delete_%d.txt", i))
|
filePath := filepath.Join(tempDir, fmt.Sprintf("bench_delete_%d.txt", i))
|
||||||
err := os.WriteFile(filePath, []byte("content"), 0o644)
|
err := os.WriteFile(filePath, []byte("content"), 0o600)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -97,7 +97,9 @@ func (a *LedgerAPI) createAccount(r *http.Request, account *model.Account, token
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeLedgerAccountCreatePayload(r *http.Request) (*srequest.CreateLedgerAccount, error) {
|
func decodeLedgerAccountCreatePayload(r *http.Request) (*srequest.CreateLedgerAccount, error) {
|
||||||
defer r.Body.Close()
|
defer func() {
|
||||||
|
_ = r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
payload := srequest.CreateLedgerAccount{}
|
payload := srequest.CreateLedgerAccount{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func (a *ProtectedAPI[T]) archive(r *http.Request, account *model.Account, acces
|
|||||||
|
|
||||||
ctx := r.Context()
|
ctx := r.Context()
|
||||||
_, err = a.a.DBFactory().TransactionFactory().CreateTransaction().Execute(ctx, func(ctx context.Context) (any, error) {
|
_, err = a.a.DBFactory().TransactionFactory().CreateTransaction().Execute(ctx, func(ctx context.Context) (any, error) {
|
||||||
return nil, a.DB.SetArchived(r.Context(), *account.GetID(), organizationRef, objectRef, *archived, *cascade)
|
return nil, a.DB.SetArchived(ctx, *account.GetID(), organizationRef, objectRef, *archived, *cascade)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.Logger.Warn("Failed to change archive property", zap.Error(err), mzap.StorableRef(account), mutil.PLog(a.Cph, r),
|
a.Logger.Warn("Failed to change archive property", zap.Error(err), mzap.StorableRef(account), mutil.PLog(a.Cph, r),
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (a *PaymentAPI) getOperationDocument(r *http.Request, account *model.Accoun
|
|||||||
|
|
||||||
op, err := a.fetchGatewayOperation(r.Context(), gateway.InvokeURI, operationRef)
|
op, err := a.fetchGatewayOperation(r.Context(), gateway.InvokeURI, operationRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Warn("Failed to fetch gateway operation for document generation", zap.Error(err), mzap.ObjRef("organization_ref", orgRef), zap.String("gateway_service", string(gatewayService)), zap.String("operation_ref", operationRef))
|
a.logger.Warn("Failed to fetch gateway operation for document generation", zap.Error(err), mzap.ObjRef("organization_ref", orgRef), zap.String("gateway_service", gatewayService), zap.String("operation_ref", operationRef))
|
||||||
return documentErrorResponse(a.logger, a.Name(), err)
|
return documentErrorResponse(a.logger, a.Name(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ func (a *PaymentAPI) getOperationDocument(r *http.Request, account *model.Accoun
|
|||||||
|
|
||||||
docResp, err := a.fetchOperationDocument(r.Context(), service.InvokeURI, req)
|
docResp, err := a.fetchOperationDocument(r.Context(), service.InvokeURI, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
a.logger.Warn("Failed to fetch operation document", zap.Error(err), mzap.ObjRef("organization_ref", orgRef), zap.String("gateway_service", string(gatewayService)), zap.String("operation_ref", operationRef))
|
a.logger.Warn("Failed to fetch operation document", zap.Error(err), mzap.ObjRef("organization_ref", orgRef), zap.String("gateway_service", gatewayService), zap.String("operation_ref", operationRef))
|
||||||
return documentErrorResponse(a.logger, a.Name(), err)
|
return documentErrorResponse(a.logger, a.Name(), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,6 +154,7 @@ func operationDocumentResponse(logger mlogger.Logger, source mservice.Type, docR
|
|||||||
w.Header().Set("Content-Type", mimeType)
|
w.Header().Set("Content-Type", mimeType)
|
||||||
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filename))
|
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%q", filename))
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
|
//nolint:gosec // Binary payload is served as attachment with explicit content type.
|
||||||
if _, err := w.Write(docResp.GetContent()); err != nil {
|
if _, err := w.Write(docResp.GetContent()); err != nil {
|
||||||
logger.Warn("Failed to write document response", zap.Error(err))
|
logger.Warn("Failed to write document response", zap.Error(err))
|
||||||
}
|
}
|
||||||
@@ -167,15 +168,15 @@ func normalizeGatewayService(raw string) mservice.Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch value {
|
switch value {
|
||||||
case string(mservice.ChainGateway):
|
case mservice.ChainGateway:
|
||||||
return mservice.ChainGateway
|
return mservice.ChainGateway
|
||||||
case string(mservice.TronGateway):
|
case mservice.TronGateway:
|
||||||
return mservice.TronGateway
|
return mservice.TronGateway
|
||||||
case string(mservice.MntxGateway):
|
case mservice.MntxGateway:
|
||||||
return mservice.MntxGateway
|
return mservice.MntxGateway
|
||||||
case string(mservice.PaymentGateway):
|
case mservice.PaymentGateway:
|
||||||
return mservice.PaymentGateway
|
return mservice.PaymentGateway
|
||||||
case string(mservice.TgSettle):
|
case mservice.TgSettle:
|
||||||
return mservice.TgSettle
|
return mservice.TgSettle
|
||||||
default:
|
default:
|
||||||
return ""
|
return ""
|
||||||
@@ -219,7 +220,11 @@ func (a *PaymentAPI) fetchOperationDocument(ctx context.Context, invokeURI strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, merrors.InternalWrap(err, "dial billing documents")
|
return nil, merrors.InternalWrap(err, "dial billing documents")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer func() {
|
||||||
|
if closeErr := conn.Close(); closeErr != nil {
|
||||||
|
a.logger.Warn("Failed to close billing documents connection", zap.Error(closeErr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
client := documentsv1.NewDocumentServiceClient(conn)
|
client := documentsv1.NewDocumentServiceClient(conn)
|
||||||
|
|
||||||
@@ -234,7 +239,11 @@ func (a *PaymentAPI) fetchGatewayOperation(ctx context.Context, invokeURI, opera
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, merrors.InternalWrap(err, "dial gateway connector")
|
return nil, merrors.InternalWrap(err, "dial gateway connector")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer func() {
|
||||||
|
if closeErr := conn.Close(); closeErr != nil {
|
||||||
|
a.logger.Warn("Failed to close gateway connector connection", zap.Error(closeErr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
client := connectorv1.NewConnectorServiceClient(conn)
|
client := connectorv1.NewConnectorServiceClient(conn)
|
||||||
|
|
||||||
@@ -307,7 +316,7 @@ func findGatewayForService(gateways []discovery.GatewaySummary, gatewayService m
|
|||||||
func operationDocumentRequest(organizationRef string, gatewayService mservice.Type, requestedOperationRef string, op *connectorv1.Operation) *documentsv1.GetOperationDocumentRequest {
|
func operationDocumentRequest(organizationRef string, gatewayService mservice.Type, requestedOperationRef string, op *connectorv1.Operation) *documentsv1.GetOperationDocumentRequest {
|
||||||
req := &documentsv1.GetOperationDocumentRequest{
|
req := &documentsv1.GetOperationDocumentRequest{
|
||||||
OrganizationRef: strings.TrimSpace(organizationRef),
|
OrganizationRef: strings.TrimSpace(organizationRef),
|
||||||
GatewayService: string(gatewayService),
|
GatewayService: gatewayService,
|
||||||
OperationRef: firstNonEmpty(strings.TrimSpace(op.GetOperationRef()), strings.TrimSpace(requestedOperationRef)),
|
OperationRef: firstNonEmpty(strings.TrimSpace(op.GetOperationRef()), strings.TrimSpace(requestedOperationRef)),
|
||||||
OperationCode: strings.TrimSpace(op.GetType().String()),
|
OperationCode: strings.TrimSpace(op.GetType().String()),
|
||||||
OperationLabel: operationLabel(op.GetType()),
|
OperationLabel: operationLabel(op.GetType()),
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ func listPaymentsPage(r *http.Request) (*paginationv1.CursorPageRequest, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if cursor == "" && !hasLimit {
|
if cursor == "" && !hasLimit {
|
||||||
|
//nolint:nilnil // Absent pagination params mean no page request should be sent downstream.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,6 +190,7 @@ func firstNonEmpty(values ...string) string {
|
|||||||
func parseRFC3339Timestamp(raw string, field string) (*timestamppb.Timestamp, error) {
|
func parseRFC3339Timestamp(raw string, field string) (*timestamppb.Timestamp, error) {
|
||||||
trimmed := strings.TrimSpace(raw)
|
trimmed := strings.TrimSpace(raw)
|
||||||
if trimmed == "" {
|
if trimmed == "" {
|
||||||
|
//nolint:nilnil // Empty timestamp filter is represented as (nil, nil).
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
parsed, err := time.Parse(time.RFC3339, trimmed)
|
parsed, err := time.Parse(time.RFC3339, trimmed)
|
||||||
|
|||||||
@@ -102,7 +102,9 @@ func (a *PaymentAPI) initiatePayment(r *http.Request, account *model.Account, to
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeInitiatePayload(r *http.Request) (*srequest.InitiatePayment, error) {
|
func decodeInitiatePayload(r *http.Request) (*srequest.InitiatePayment, error) {
|
||||||
defer r.Body.Close()
|
defer func() {
|
||||||
|
_ = r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
payload := &srequest.InitiatePayment{}
|
payload := &srequest.InitiatePayment{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(payload); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(payload); err != nil {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ func TestInitiateByQuote_RejectsMetadataIntentRef(t *testing.T) {
|
|||||||
func invokeInitiateByQuote(t *testing.T, api *PaymentAPI, orgRef bson.ObjectID, body string) *httptest.ResponseRecorder {
|
func invokeInitiateByQuote(t *testing.T, api *PaymentAPI, orgRef bson.ObjectID, body string) *httptest.ResponseRecorder {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/by-quote", bytes.NewBufferString(body))
|
req := httptest.NewRequestWithContext(context.Background(), http.MethodPost, "/by-quote", bytes.NewBufferString(body))
|
||||||
routeCtx := chi.NewRouteContext()
|
routeCtx := chi.NewRouteContext()
|
||||||
routeCtx.URLParams.Add("organizations_ref", orgRef.Hex())
|
routeCtx.URLParams.Add("organizations_ref", orgRef.Hex())
|
||||||
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, routeCtx))
|
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, routeCtx))
|
||||||
|
|||||||
@@ -63,7 +63,9 @@ func (a *PaymentAPI) initiatePaymentsByQuote(r *http.Request, account *model.Acc
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeInitiatePaymentsPayload(r *http.Request) (*srequest.InitiatePayments, error) {
|
func decodeInitiatePaymentsPayload(r *http.Request) (*srequest.InitiatePayments, error) {
|
||||||
defer r.Body.Close()
|
defer func() {
|
||||||
|
_ = r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
payload := &srequest.InitiatePayments{}
|
payload := &srequest.InitiatePayments{}
|
||||||
decoder := json.NewDecoder(r.Body)
|
decoder := json.NewDecoder(r.Body)
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
|
|
||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/tech/sendico/pkg/auth"
|
"github.com/tech/sendico/pkg/auth"
|
||||||
"github.com/tech/sendico/pkg/mlogger"
|
|
||||||
"github.com/tech/sendico/pkg/model"
|
"github.com/tech/sendico/pkg/model"
|
||||||
"github.com/tech/sendico/pkg/mservice"
|
"github.com/tech/sendico/pkg/mservice"
|
||||||
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
orchestrationv2 "github.com/tech/sendico/pkg/proto/payments/orchestration/v2"
|
||||||
@@ -118,7 +117,7 @@ func TestInitiatePaymentsByQuote_RejectsDeprecatedIntentRefsField(t *testing.T)
|
|||||||
|
|
||||||
func newBatchAPI(exec executionClient) *PaymentAPI {
|
func newBatchAPI(exec executionClient) *PaymentAPI {
|
||||||
return &PaymentAPI{
|
return &PaymentAPI{
|
||||||
logger: mlogger.Logger(zap.NewNop()),
|
logger: zap.NewNop(),
|
||||||
execution: exec,
|
execution: exec,
|
||||||
enf: fakeEnforcerForBatch{allowed: true},
|
enf: fakeEnforcerForBatch{allowed: true},
|
||||||
oph: mutil.CreatePH(mservice.Organizations),
|
oph: mutil.CreatePH(mservice.Organizations),
|
||||||
@@ -129,7 +128,7 @@ func newBatchAPI(exec executionClient) *PaymentAPI {
|
|||||||
func invokeInitiatePaymentsByQuote(t *testing.T, api *PaymentAPI, orgRef bson.ObjectID, body string) *httptest.ResponseRecorder {
|
func invokeInitiatePaymentsByQuote(t *testing.T, api *PaymentAPI, orgRef bson.ObjectID, body string) *httptest.ResponseRecorder {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
req := httptest.NewRequest(http.MethodPost, "/by-multiquote", bytes.NewBufferString(body))
|
req := httptest.NewRequestWithContext(context.Background(), http.MethodPost, "/by-multiquote", bytes.NewBufferString(body))
|
||||||
routeCtx := chi.NewRouteContext()
|
routeCtx := chi.NewRouteContext()
|
||||||
routeCtx.URLParams.Add("organizations_ref", orgRef.Hex())
|
routeCtx.URLParams.Add("organizations_ref", orgRef.Hex())
|
||||||
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, routeCtx))
|
req = req.WithContext(context.WithValue(req.Context(), chi.RouteCtxKey, routeCtx))
|
||||||
@@ -177,6 +176,7 @@ func (f fakeEnforcerForBatch) Enforce(context.Context, bson.ObjectID, bson.Objec
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (fakeEnforcerForBatch) EnforceBatch(context.Context, []model.PermissionBoundStorable, bson.ObjectID, model.Action) (map[bson.ObjectID]bool, error) {
|
func (fakeEnforcerForBatch) EnforceBatch(context.Context, []model.PermissionBoundStorable, bson.ObjectID, model.Action) (map[bson.ObjectID]bool, error) {
|
||||||
|
//nolint:nilnil // Test stub does not provide batch permissions map.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,7 +126,9 @@ func (a *PaymentAPI) quotePayments(r *http.Request, account *model.Account, toke
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeQuotePayload(r *http.Request) (*srequest.QuotePayment, error) {
|
func decodeQuotePayload(r *http.Request) (*srequest.QuotePayment, error) {
|
||||||
defer r.Body.Close()
|
defer func() {
|
||||||
|
_ = r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
payload := &srequest.QuotePayment{}
|
payload := &srequest.QuotePayment{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(payload); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(payload); err != nil {
|
||||||
@@ -140,7 +142,9 @@ func decodeQuotePayload(r *http.Request) (*srequest.QuotePayment, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func decodeQuotePaymentsPayload(r *http.Request) (*srequest.QuotePayments, error) {
|
func decodeQuotePaymentsPayload(r *http.Request) (*srequest.QuotePayments, error) {
|
||||||
defer r.Body.Close()
|
defer func() {
|
||||||
|
_ = r.Body.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
payload := &srequest.QuotePayments{}
|
payload := &srequest.QuotePayments{}
|
||||||
if err := json.NewDecoder(r.Body).Decode(payload); err != nil {
|
if err := json.NewDecoder(r.Body).Decode(payload); err != nil {
|
||||||
|
|||||||
@@ -256,6 +256,7 @@ func (c *grpcQuotationClient) callContext(ctx context.Context) (context.Context,
|
|||||||
if timeout <= 0 {
|
if timeout <= 0 {
|
||||||
timeout = 3 * time.Second
|
timeout = 3 * time.Second
|
||||||
}
|
}
|
||||||
|
//nolint:gosec // Caller receives cancel func and defers it in every call path.
|
||||||
return context.WithTimeout(ctx, timeout)
|
return context.WithTimeout(ctx, timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +272,7 @@ func (a *PaymentAPI) initDiscoveryClient(cfg *eapi.Config) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
client, err := discovery.NewClient(a.logger, broker, nil, string(a.Name()))
|
client, err := discovery.NewClient(a.logger, broker, nil, a.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,5 +90,5 @@ func (a *PermissionsAPI) changePoliciesImp(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return struct{}{}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,7 @@ func (a *WalletAPI) queryBalanceFromGateways(ctx context.Context, gateways []dis
|
|||||||
a.logger.Debug("Wallet balance fan-out completed without result",
|
a.logger.Debug("Wallet balance fan-out completed without result",
|
||||||
zap.String("organization_ref", organizationRef),
|
zap.String("organization_ref", organizationRef),
|
||||||
zap.String("wallet_ref", walletRef))
|
zap.String("wallet_ref", walletRef))
|
||||||
|
//nolint:nilnil // No gateway returned a balance and no hard error occurred.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +239,11 @@ func (a *WalletAPI) queryGatewayBalance(ctx context.Context, gateway discovery.G
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, merrors.InternalWrap(err, "dial gateway")
|
return nil, merrors.InternalWrap(err, "dial gateway")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer func() {
|
||||||
|
if closeErr := conn.Close(); closeErr != nil {
|
||||||
|
a.logger.Warn("Failed to close gateway connection", zap.Error(closeErr), zap.String("gateway", gateway.ID))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
client := connectorv1.NewConnectorServiceClient(conn)
|
client := connectorv1.NewConnectorServiceClient(conn)
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,11 @@ func (a *WalletAPI) createWalletOnGateway(ctx context.Context, gateway discovery
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", merrors.InternalWrap(err, "dial gateway")
|
return "", merrors.InternalWrap(err, "dial gateway")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer func() {
|
||||||
|
if closeErr := conn.Close(); closeErr != nil {
|
||||||
|
a.logger.Warn("Failed to close gateway connection", zap.Error(closeErr), zap.String("gateway", gateway.ID))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
client := connectorv1.NewConnectorServiceClient(conn)
|
client := connectorv1.NewConnectorServiceClient(conn)
|
||||||
|
|
||||||
|
|||||||
@@ -226,7 +226,11 @@ func (a *WalletAPI) queryGateway(ctx context.Context, gateway discovery.GatewayS
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, merrors.InternalWrap(err, "dial gateway")
|
return nil, merrors.InternalWrap(err, "dial gateway")
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer func() {
|
||||||
|
if closeErr := conn.Close(); closeErr != nil {
|
||||||
|
a.logger.Warn("Failed to close gateway connection", zap.Error(closeErr), zap.String("gateway", gateway.ID))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
client := connectorv1.NewConnectorServiceClient(conn)
|
client := connectorv1.NewConnectorServiceClient(conn)
|
||||||
|
|
||||||
|
|||||||
@@ -64,18 +64,21 @@ func (a *WalletAPI) rememberWalletRoute(ctx context.Context, organizationRef str
|
|||||||
|
|
||||||
func (a *WalletAPI) walletRoute(ctx context.Context, organizationRef string, walletRef string) (*model.ChainWalletRoute, error) {
|
func (a *WalletAPI) walletRoute(ctx context.Context, organizationRef string, walletRef string) (*model.ChainWalletRoute, error) {
|
||||||
if a.routes == nil {
|
if a.routes == nil {
|
||||||
|
//nolint:nilnil // Routing cache is optional and may be disabled.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
walletRef = strings.TrimSpace(walletRef)
|
walletRef = strings.TrimSpace(walletRef)
|
||||||
organizationRef = strings.TrimSpace(organizationRef)
|
organizationRef = strings.TrimSpace(organizationRef)
|
||||||
if walletRef == "" || organizationRef == "" {
|
if walletRef == "" || organizationRef == "" {
|
||||||
|
//nolint:nilnil // Missing route keys mean no cached route.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
route, err := a.routes.Get(ctx, organizationRef, walletRef)
|
route, err := a.routes.Get(ctx, organizationRef, walletRef)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, merrors.ErrNoData) {
|
if errors.Is(err, merrors.ErrNoData) {
|
||||||
|
//nolint:nilnil // Route not found in cache.
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ func (a *WalletAPI) initDiscoveryClient(cfg *eapi.Config) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
client, err := discovery.NewClient(a.logger, broker, nil, string(a.Name()))
|
client, err := discovery.NewClient(a.logger, broker, nil, a.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// generate translations
|
// generate translations
|
||||||
// go:generate Users/stephandeshevikh/go/bin/go18n extract
|
//go:generate Users/stephandeshevikh/go/bin/go18n extract
|
||||||
// go:generate Users/stephandeshevikh/go/bin/go18n merge
|
//go:generate Users/stephandeshevikh/go/bin/go18n merge
|
||||||
|
|
||||||
// lint go code
|
// lint go code
|
||||||
// docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:latest golangci-lint run -v --timeout 10m0s --enable-all -D ireturn -D wrapcheck -D varnamelen -D tagliatelle -D nosnakecase -D gochecknoglobals -D nlreturn -D stylecheck -D lll -D wsl -D scopelint -D varcheck -D exhaustivestruct -D golint -D maligned -D interfacer -D ifshort -D structcheck -D deadcode -D godot -D depguard -D tagalign
|
// docker run -t --rm -v $(pwd):/app -w /app golangci/golangci-lint:latest golangci-lint run -v --timeout 10m0s --enable-all -D ireturn -D wrapcheck -D varnamelen -D tagliatelle -D nosnakecase -D gochecknoglobals -D nlreturn -D stylecheck -D lll -D wsl -D scopelint -D varcheck -D exhaustivestruct -D golint -D maligned -D interfacer -D ifshort -D structcheck -D deadcode -D godot -D depguard -D tagalign
|
||||||
|
|||||||
47
api/edge/callbacks/.golangci.yml
Normal file
47
api/edge/callbacks/.golangci.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
version: "2"
|
||||||
|
linters:
|
||||||
|
default: none
|
||||||
|
enable:
|
||||||
|
- bodyclose
|
||||||
|
- canonicalheader
|
||||||
|
- copyloopvar
|
||||||
|
- durationcheck
|
||||||
|
- errcheck
|
||||||
|
- errchkjson
|
||||||
|
- errname
|
||||||
|
- errorlint
|
||||||
|
- gosec
|
||||||
|
- govet
|
||||||
|
- ineffassign
|
||||||
|
- nilerr
|
||||||
|
- nilnesserr
|
||||||
|
- nilnil
|
||||||
|
- noctx
|
||||||
|
- rowserrcheck
|
||||||
|
- sqlclosecheck
|
||||||
|
- staticcheck
|
||||||
|
- unconvert
|
||||||
|
- wastedassign
|
||||||
|
disable:
|
||||||
|
- depguard
|
||||||
|
- exhaustruct
|
||||||
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
|
- gomoddirectives
|
||||||
|
- wrapcheck
|
||||||
|
- cyclop
|
||||||
|
- dupl
|
||||||
|
- funlen
|
||||||
|
- gocognit
|
||||||
|
- gocyclo
|
||||||
|
- ireturn
|
||||||
|
- lll
|
||||||
|
- mnd
|
||||||
|
- nestif
|
||||||
|
- nlreturn
|
||||||
|
- noinlineerr
|
||||||
|
- paralleltest
|
||||||
|
- tagliatelle
|
||||||
|
- testpackage
|
||||||
|
- varnamelen
|
||||||
|
- wsl_v5
|
||||||
@@ -51,14 +51,14 @@ require (
|
|||||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/net v0.51.0 // indirect
|
golang.org/x/net v0.51.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.15.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
google.golang.org/grpc v1.79.1 // indirect
|
google.golang.org/grpc v1.79.2 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -201,8 +201,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
@@ -216,16 +216,16 @@ golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
|||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -234,8 +234,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
|||||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||||
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk=
|
||||||
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA=
|
||||||
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
|
golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
|
||||||
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
|
golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
@@ -245,8 +245,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ func (s *service) Load(path string) (*Config, error) {
|
|||||||
return nil, merrors.InvalidArgument("config path is required", "path")
|
return nil, merrors.InvalidArgument("config path is required", "path")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:gosec // Configuration file path is provided by service startup configuration.
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
s.logger.Error("Failed to read config file", zap.String("path", path), zap.Error(err))
|
s.logger.Error("Failed to read config file", zap.String("path", path), zap.Error(err))
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ func (s *service) Start(ctx context.Context) {
|
|||||||
if runCtx == nil {
|
if runCtx == nil {
|
||||||
runCtx = context.Background()
|
runCtx = context.Background()
|
||||||
}
|
}
|
||||||
runCtx, s.cancel = context.WithCancel(runCtx)
|
runCtx, s.cancel = context.WithCancel(runCtx) //nolint:gosec // canceled by Stop; service lifecycle outlives Start scope
|
||||||
|
|
||||||
for i := 0; i < s.cfg.WorkerConcurrency; i++ {
|
for i := 0; i < s.cfg.WorkerConcurrency; i++ {
|
||||||
workerID := "worker-" + strconv.Itoa(i+1)
|
workerID := "worker-" + strconv.Itoa(i+1)
|
||||||
@@ -143,6 +143,10 @@ func (s *service) runWorker(ctx context.Context, workerID string) {
|
|||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
task, err := s.tasks.LockNextTask(ctx, now, workerID, s.cfg.LockTTL)
|
task, err := s.tasks.LockNextTask(ctx, now, workerID, s.cfg.LockTTL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if errors.Is(err, merrors.ErrNoData) {
|
||||||
|
time.Sleep(s.cfg.WorkerPoll)
|
||||||
|
continue
|
||||||
|
}
|
||||||
s.logger.Warn("Failed to lock next task", zap.String("worker_id", workerID), zap.Error(err))
|
s.logger.Warn("Failed to lock next task", zap.String("worker_id", workerID), zap.Error(err))
|
||||||
time.Sleep(s.cfg.WorkerPoll)
|
time.Sleep(s.cfg.WorkerPoll)
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ func (s *service) Start(ctx context.Context) {
|
|||||||
if runCtx == nil {
|
if runCtx == nil {
|
||||||
runCtx = context.Background()
|
runCtx = context.Background()
|
||||||
}
|
}
|
||||||
runCtx, s.cancel = context.WithCancel(runCtx)
|
runCtx, s.cancel = context.WithCancel(runCtx) //nolint:gosec // canceled by Stop; service lifecycle outlives Start scope
|
||||||
|
|
||||||
s.wg.Add(1)
|
s.wg.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ type service struct {
|
|||||||
|
|
||||||
// New creates retry policy service.
|
// New creates retry policy service.
|
||||||
func New() Policy {
|
func New() Policy {
|
||||||
|
//nolint:gosec // Backoff jitter is non-cryptographic and only needs pseudo-random distribution.
|
||||||
return &service{rnd: rand.New(rand.NewSource(time.Now().UnixNano()))}
|
return &service{rnd: rand.New(rand.NewSource(time.Now().UnixNano()))}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ func (i *Imp) Start() error {
|
|||||||
|
|
||||||
runCtx, cancel := context.WithCancel(context.Background())
|
runCtx, cancel := context.WithCancel(context.Background())
|
||||||
i.runCancel = cancel
|
i.runCancel = cancel
|
||||||
|
defer cancel()
|
||||||
i.ingest.Start(runCtx)
|
i.ingest.Start(runCtx)
|
||||||
i.delivery.Start(runCtx)
|
i.delivery.Start(runCtx)
|
||||||
i.opServer.SetStatus(health.SSRunning)
|
i.opServer.SetStatus(health.SSRunning)
|
||||||
|
|||||||
@@ -379,7 +379,7 @@ func (r *taskStore) LockNextTask(ctx context.Context, now time.Time, workerID st
|
|||||||
candidates, err := mutil.GetObjects[taskDoc](ctx, r.logger, query, nil, r.repo)
|
candidates, err := mutil.GetObjects[taskDoc](ctx, r.logger, query, nil, r.repo)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, merrors.ErrNoData) {
|
if errors.Is(err, merrors.ErrNoData) {
|
||||||
return nil, nil
|
return nil, merrors.ErrNoData
|
||||||
}
|
}
|
||||||
return nil, merrors.InternalWrap(err, "callbacks task query failed")
|
return nil, merrors.InternalWrap(err, "callbacks task query failed")
|
||||||
}
|
}
|
||||||
@@ -418,7 +418,7 @@ func (r *taskStore) LockNextTask(ctx context.Context, now time.Time, workerID st
|
|||||||
return mapTaskDoc(locked), nil
|
return mapTaskDoc(locked), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, merrors.ErrNoData
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *taskStore) MarkDelivered(ctx context.Context, taskID bson.ObjectID, httpCode int, latency time.Duration, at time.Time) error {
|
func (r *taskStore) MarkDelivered(ctx context.Context, taskID bson.ObjectID, httpCode int, latency time.Duration, at time.Time) error {
|
||||||
|
|||||||
@@ -1,196 +1,47 @@
|
|||||||
# See the dedicated "version" documentation section.
|
|
||||||
version: "2"
|
version: "2"
|
||||||
linters:
|
linters:
|
||||||
# Default set of linters.
|
default: none
|
||||||
# The value can be:
|
|
||||||
# - `standard`: https://golangci-lint.run/docs/linters/#enabled-by-default
|
|
||||||
# - `all`: enables all linters by default.
|
|
||||||
# - `none`: disables all linters by default.
|
|
||||||
# - `fast`: enables only linters considered as "fast" (`golangci-lint help linters --json | jq '[ .[] | select(.fast==true) ] | map(.name)'`).
|
|
||||||
# Default: standard
|
|
||||||
default: all
|
|
||||||
# Enable specific linter.
|
|
||||||
enable:
|
enable:
|
||||||
- arangolint
|
|
||||||
- asasalint
|
|
||||||
- asciicheck
|
|
||||||
- bidichk
|
|
||||||
- bodyclose
|
- bodyclose
|
||||||
- canonicalheader
|
- canonicalheader
|
||||||
- containedctx
|
|
||||||
- contextcheck
|
|
||||||
- copyloopvar
|
- copyloopvar
|
||||||
- cyclop
|
|
||||||
- decorder
|
|
||||||
- dogsled
|
|
||||||
- dupl
|
|
||||||
- dupword
|
|
||||||
- durationcheck
|
- durationcheck
|
||||||
- embeddedstructfieldcheck
|
|
||||||
- err113
|
|
||||||
- errcheck
|
- errcheck
|
||||||
- errchkjson
|
- errchkjson
|
||||||
- errname
|
- errname
|
||||||
- errorlint
|
- errorlint
|
||||||
- exhaustive
|
|
||||||
- exptostd
|
|
||||||
- fatcontext
|
|
||||||
- forbidigo
|
|
||||||
- forcetypeassert
|
|
||||||
- funcorder
|
|
||||||
- funlen
|
|
||||||
- ginkgolinter
|
|
||||||
- gocheckcompilerdirectives
|
|
||||||
- gochecknoglobals
|
|
||||||
- gochecknoinits
|
|
||||||
- gochecksumtype
|
|
||||||
- gocognit
|
|
||||||
- goconst
|
|
||||||
- gocritic
|
|
||||||
- gocyclo
|
|
||||||
- godoclint
|
|
||||||
- godot
|
|
||||||
- godox
|
|
||||||
- goheader
|
|
||||||
- gomodguard
|
|
||||||
- goprintffuncname
|
|
||||||
- gosec
|
- gosec
|
||||||
- gosmopolitan
|
|
||||||
- govet
|
- govet
|
||||||
- grouper
|
|
||||||
- iface
|
|
||||||
- importas
|
|
||||||
- inamedparam
|
|
||||||
- ineffassign
|
- ineffassign
|
||||||
- interfacebloat
|
|
||||||
- intrange
|
|
||||||
- iotamixing
|
|
||||||
- ireturn
|
|
||||||
- lll
|
|
||||||
- loggercheck
|
|
||||||
- maintidx
|
|
||||||
- makezero
|
|
||||||
- mirror
|
|
||||||
- misspell
|
|
||||||
- mnd
|
|
||||||
- modernize
|
|
||||||
- musttag
|
|
||||||
- nakedret
|
|
||||||
- nestif
|
|
||||||
- nilerr
|
- nilerr
|
||||||
- nilnesserr
|
- nilnesserr
|
||||||
- nilnil
|
- nilnil
|
||||||
- nlreturn
|
|
||||||
- noctx
|
- noctx
|
||||||
- noinlineerr
|
|
||||||
- nolintlint
|
|
||||||
- nonamedreturns
|
|
||||||
- nosprintfhostport
|
|
||||||
- paralleltest
|
|
||||||
- perfsprint
|
|
||||||
- prealloc
|
|
||||||
- predeclared
|
|
||||||
- promlinter
|
|
||||||
- protogetter
|
|
||||||
- reassign
|
|
||||||
- recvcheck
|
|
||||||
- revive
|
|
||||||
- rowserrcheck
|
- rowserrcheck
|
||||||
- sloglint
|
|
||||||
- spancheck
|
|
||||||
- sqlclosecheck
|
- sqlclosecheck
|
||||||
- staticcheck
|
- staticcheck
|
||||||
- tagalign
|
|
||||||
- tagliatelle
|
|
||||||
- testableexamples
|
|
||||||
- testifylint
|
|
||||||
- testpackage
|
|
||||||
- thelper
|
|
||||||
- tparallel
|
|
||||||
- unconvert
|
- unconvert
|
||||||
- unparam
|
|
||||||
- unqueryvet
|
|
||||||
- unused
|
|
||||||
- usestdlibvars
|
|
||||||
- usetesting
|
|
||||||
- varnamelen
|
|
||||||
- wastedassign
|
- wastedassign
|
||||||
- whitespace
|
|
||||||
- wsl_v5
|
|
||||||
- zerologlint
|
|
||||||
# Disable specific linters.
|
|
||||||
disable:
|
disable:
|
||||||
- depguard
|
- depguard
|
||||||
- exhaustruct
|
- exhaustruct
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
|
- gochecknoinits
|
||||||
- gomoddirectives
|
- gomoddirectives
|
||||||
- wrapcheck
|
- wrapcheck
|
||||||
- wsl
|
- cyclop
|
||||||
# All available settings of specific linters.
|
- dupl
|
||||||
# See the dedicated "linters.settings" documentation section.
|
- funlen
|
||||||
settings:
|
- gocognit
|
||||||
wsl_v5:
|
- gocyclo
|
||||||
allow-first-in-block: true
|
- ireturn
|
||||||
allow-whole-block: false
|
- lll
|
||||||
branch-max-lines: 2
|
- mnd
|
||||||
|
- nestif
|
||||||
# Defines a set of rules to ignore issues.
|
- nlreturn
|
||||||
# It does not skip the analysis, and so does not ignore "typecheck" errors.
|
- noinlineerr
|
||||||
exclusions:
|
- paralleltest
|
||||||
# Mode of the generated files analysis.
|
- tagliatelle
|
||||||
#
|
- testpackage
|
||||||
# - `strict`: sources are excluded by strictly following the Go generated file convention.
|
- varnamelen
|
||||||
# Source files that have lines matching only the following regular expression will be excluded: `^// Code generated .* DO NOT EDIT\.$`
|
- wsl_v5
|
||||||
# This line must appear before the first non-comment, non-blank text in the file.
|
|
||||||
# https://go.dev/s/generatedcode
|
|
||||||
# - `lax`: sources are excluded if they contain lines like `autogenerated file`, `code generated`, `do not edit`, etc.
|
|
||||||
# - `disable`: disable the generated files exclusion.
|
|
||||||
#
|
|
||||||
# Default: strict
|
|
||||||
generated: lax
|
|
||||||
# Log a warning if an exclusion rule is unused.
|
|
||||||
# Default: false
|
|
||||||
warn-unused: true
|
|
||||||
# Predefined exclusion rules.
|
|
||||||
# Default: []
|
|
||||||
presets:
|
|
||||||
- comments
|
|
||||||
- std-error-handling
|
|
||||||
- common-false-positives
|
|
||||||
- legacy
|
|
||||||
# Excluding configuration per-path, per-linter, per-text and per-source.
|
|
||||||
rules:
|
|
||||||
# Exclude some linters from running on tests files.
|
|
||||||
- path: _test\.go
|
|
||||||
linters:
|
|
||||||
- funlen
|
|
||||||
- gocyclo
|
|
||||||
- errcheck
|
|
||||||
- dupl
|
|
||||||
- gosec
|
|
||||||
# Run some linter only for test files by excluding its issues for everything else.
|
|
||||||
- path-except: _test\.go
|
|
||||||
linters:
|
|
||||||
- forbidigo
|
|
||||||
# Exclude known linters from partially hard-vendored code,
|
|
||||||
# which is impossible to exclude via `nolint` comments.
|
|
||||||
# `/` will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
- path: internal/hmac/
|
|
||||||
text: "weak cryptographic primitive"
|
|
||||||
linters:
|
|
||||||
- gosec
|
|
||||||
# Exclude some `staticcheck` messages.
|
|
||||||
- linters:
|
|
||||||
- staticcheck
|
|
||||||
text: "SA9003:"
|
|
||||||
# Exclude `lll` issues for long lines with `go:generate`.
|
|
||||||
- linters:
|
|
||||||
- lll
|
|
||||||
source: "^//go:generate "
|
|
||||||
# Which file paths to exclude: they will be analyzed, but issues from them won't be reported.
|
|
||||||
# "/" will be replaced by the current OS file path separator to properly work on Windows.
|
|
||||||
# Default: []
|
|
||||||
paths: []
|
|
||||||
# Which file paths to not exclude.
|
|
||||||
# Default: []
|
|
||||||
paths-except: []
|
|
||||||
|
|||||||
@@ -42,12 +42,12 @@ require (
|
|||||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||||
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
go.mongodb.org/mongo-driver/v2 v2.5.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
go.yaml.in/yaml/v2 v2.4.4 // indirect
|
||||||
golang.org/x/crypto v0.48.0 // indirect
|
golang.org/x/crypto v0.48.0 // indirect
|
||||||
golang.org/x/sync v0.19.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.41.0 // indirect
|
golang.org/x/sys v0.42.0 // indirect
|
||||||
golang.org/x/text v0.34.0 // indirect
|
golang.org/x/text v0.34.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect
|
||||||
google.golang.org/grpc v1.79.1 // indirect
|
google.golang.org/grpc v1.79.2 // indirect
|
||||||
google.golang.org/protobuf v1.36.11 // indirect
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -168,8 +168,8 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
|||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
|
||||||
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||||
go.yaml.in/yaml/v2 v2.4.3 h1:6gvOSjQoTB3vt1l+CU+tSyi/HOjfOjRLJ4YwYZGwRO0=
|
go.yaml.in/yaml/v2 v2.4.4 h1:tuyd0P+2Ont/d6e2rl3be67goVK4R6deVxCUX5vyPaQ=
|
||||||
go.yaml.in/yaml/v2 v2.4.3/go.mod h1:zSxWcmIDjOzPXpjlTTbAsKokqkDNAVtZO0WOMiT90s8=
|
go.yaml.in/yaml/v2 v2.4.4/go.mod h1:gMZqIpDtDqOfM0uNfy0SkpRhvUryYH0Z6wdMYcacYXQ=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
@@ -183,16 +183,16 @@ golang.org/x/net v0.51.0 h1:94R/GTO7mt3/4wIKpcR5gkGmRLOuE/2hNGeWq/GBIFo=
|
|||||||
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
golang.org/x/net v0.51.0/go.mod h1:aamm+2QF5ogm02fjy5Bb7CQ0WMt1/WVM7FtyaTLlA9Y=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
|
||||||
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
||||||
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
@@ -210,8 +210,8 @@ gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
|||||||
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 h1:ggcbiqK8WWh6l1dnltU4BgWGIGo+EVYxCaAPih/zQXQ=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
||||||
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
|
google.golang.org/grpc v1.79.2 h1:fRMD94s2tITpyJGtBBn7MkMseNpOZU8ZxgC3MMBaXRU=
|
||||||
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
google.golang.org/grpc v1.79.2/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ func Load(path string) (*Config, error) {
|
|||||||
return nil, merrors.InvalidArgument("config: path is empty")
|
return nil, merrors.InvalidArgument("config: path is empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//nolint:gosec // config path is provided by process startup arguments/config.
|
||||||
data, err := os.ReadFile(path)
|
data, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, merrors.InternalWrap(err, "config: failed to read file")
|
return nil, merrors.InternalWrap(err, "config: failed to read file")
|
||||||
@@ -73,8 +74,10 @@ func Load(path string) (*Config, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if _, ok := sourceSet[driver]; !ok {
|
if _, ok := sourceSet[driver]; !ok {
|
||||||
return nil, merrors.InvalidArgument( //nolint:lll
|
return nil, merrors.InvalidArgument(
|
||||||
"config: pair references unknown source: "+driver.String(), "pairs."+driver.String())
|
"config: pair references unknown source: "+driver.String(),
|
||||||
|
"pairs."+driver.String(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
processed := make([]PairConfig, len(pairList))
|
processed := make([]PairConfig, len(pairList))
|
||||||
@@ -86,8 +89,10 @@ func Load(path string) (*Config, error) {
|
|||||||
pair.Symbol = strings.TrimSpace(pair.Symbol)
|
pair.Symbol = strings.TrimSpace(pair.Symbol)
|
||||||
|
|
||||||
if pair.Base == "" || pair.Quote == "" || pair.Symbol == "" {
|
if pair.Base == "" || pair.Quote == "" || pair.Symbol == "" {
|
||||||
return nil, merrors.InvalidArgument( //nolint:lll
|
return nil, merrors.InvalidArgument(
|
||||||
"config: pair entries must define base, quote, and symbol", "pairs."+driver.String())
|
"config: pair entries must define base, quote, and symbol",
|
||||||
|
"pairs."+driver.String(),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.TrimSpace(pair.Provider) == "" {
|
if strings.TrimSpace(pair.Provider) == "" {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errNoSnapshot = errors.New("snapshot not found")
|
||||||
|
|
||||||
func TestParseDecimal(t *testing.T) {
|
func TestParseDecimal(t *testing.T) {
|
||||||
got, err := parseDecimal("123.456")
|
got, err := parseDecimal("123.456")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -191,19 +193,9 @@ func (r *ratesStoreStub) UpsertSnapshot(_ context.Context, snapshot *model.RateS
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *ratesStoreStub) LatestSnapshot(context.Context, model.CurrencyPair, string) (*model.RateSnapshot, error) {
|
func (r *ratesStoreStub) LatestSnapshot(context.Context, model.CurrencyPair, string) (*model.RateSnapshot, error) {
|
||||||
return nil, nil
|
return nil, errNoSnapshot
|
||||||
}
|
}
|
||||||
|
|
||||||
type repositoryStub struct {
|
|
||||||
rates storage.RatesStore
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *repositoryStub) Ping(context.Context) error { return nil }
|
|
||||||
func (r *repositoryStub) Rates() storage.RatesStore { return r.rates }
|
|
||||||
func (r *repositoryStub) Quotes() storage.QuotesStore { return nil }
|
|
||||||
func (r *repositoryStub) Pairs() storage.PairStore { return nil }
|
|
||||||
func (r *repositoryStub) Currencies() storage.CurrencyStore { return nil }
|
|
||||||
|
|
||||||
type connectorStub struct {
|
type connectorStub struct {
|
||||||
id mmarket.Driver
|
id mmarket.Driver
|
||||||
ticker *mmarket.Ticker
|
ticker *mmarket.Ticker
|
||||||
|
|||||||
@@ -116,7 +116,11 @@ func (c *binanceConnector) FetchTicker(ctx context.Context, symbol string) (*mmo
|
|||||||
|
|
||||||
return nil, merrors.InternalWrap(err, "binance: request failed")
|
return nil, merrors.InternalWrap(err, "binance: request failed")
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer func() {
|
||||||
|
if closeErr := resp.Body.Close(); closeErr != nil {
|
||||||
|
c.logger.Warn("Failed to close Binance response body", zap.Error(closeErr))
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
c.logger.Warn("Binance returned non-OK status", zap.String("symbol", symbol), zap.Int("status", resp.StatusCode))
|
c.logger.Warn("Binance returned non-OK status", zap.String("symbol", symbol), zap.Int("status", resp.StatusCode))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user