generated from PenaSide/GolangTemplate
Merge branch 'dev' into 'staging'
Оплата по рассчетному счету See merge request pena-services/customer!36
This commit is contained in:
commit
f08a265e9b
@ -12,11 +12,9 @@ build-app:
|
||||
|
||||
deploy-to-staging:
|
||||
rules:
|
||||
- if: "$CI_COMMIT_BRANCH == $STAGING_BRANCH"
|
||||
extends: .deploy_template
|
||||
tags:
|
||||
- staging
|
||||
extends: .deploy_template
|
||||
- if: "$CI_COMMIT_BRANCH == $BRANCH"
|
||||
after_script:
|
||||
- ls
|
||||
|
||||
deploy-to-prod:
|
||||
rules:
|
||||
|
@ -13,6 +13,8 @@ RUN mkdir /bin/golang-migrate -p
|
||||
ADD ./tools/migrate /bin/golang-migrate/
|
||||
# Add main files to app
|
||||
ADD . .
|
||||
# Download go depences
|
||||
# RUN go mod download
|
||||
# Build app
|
||||
RUN GOOS=linux go build -o bin ./...
|
||||
|
||||
|
4
Makefile
4
Makefile
@ -37,9 +37,7 @@ test.integration.down: ## shutting down integration environment
|
||||
docker-compose -f deployments/test/docker-compose.yaml down --volumes
|
||||
|
||||
test.integration.start: ## run integration test
|
||||
docker-compose -p integration -f deployments/test/docker-compose.integration.yaml down
|
||||
docker-compose -p integration -f deployments/test/docker-compose.integration.yaml up --exit-code-from integration --remove-orphans
|
||||
docker-compose -p integration -f deployments/test/docker-compose.integration.yaml down
|
||||
go test -count=1 ./tests/integration/...
|
||||
|
||||
test.e2e.start: ## run integration test
|
||||
go test ./tests/e2e/...
|
||||
|
@ -519,6 +519,23 @@ paths:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
/wallet/rspay:
|
||||
post:
|
||||
summary: Обработка запроса RSPay
|
||||
security:
|
||||
- Bearer: [ ]
|
||||
responses:
|
||||
'200':
|
||||
description: Успех
|
||||
'500':
|
||||
description: Внутренняя ошибка сервера
|
||||
'403':
|
||||
description: Запрещено
|
||||
content:
|
||||
application/json:
|
||||
example:
|
||||
message: not allowed for non organizations
|
||||
|
||||
/history:
|
||||
get:
|
||||
tags:
|
||||
|
@ -2,3 +2,34 @@
|
||||
JWT_ISSUER="pena-auth-service"
|
||||
JWT_AUDIENCE="pena"
|
||||
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69\n80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B\ndA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y\n+3GyaOY536H47qyXAgMBAAE=\n-----END PUBLIC KEY-----"
|
||||
|
||||
HTTP_HOST=0.0.0.0
|
||||
HTTP_PORT=8003
|
||||
|
||||
GRPC_HOST=0.0.0.0
|
||||
GRPC_PORT=9000
|
||||
GRPC_DOMEN=customer-service:9000
|
||||
|
||||
MONGO_HOST=localhost
|
||||
MONGO_PORT=27024
|
||||
MONGO_USER=test
|
||||
MONGO_PASSWORD=test
|
||||
MONGO_DB_NAME=admin
|
||||
MONGO_AUTH=admin
|
||||
|
||||
KAFKA_BROKERS=localhost:9092
|
||||
KAFKA_TOPIC_TARIFF=tariffs
|
||||
|
||||
AUTH_MICROSERVICE_USER_URL=http://localhost:8000/user
|
||||
HUBADMIN_MICROSERVICE_TARIFF_URL=http://localhost:8001/tariff
|
||||
CURRENCY_MICROSERVICE_TRANSLATE_URL=http://cbrfworker-service:8000/change
|
||||
DISCOUNT_MICROSERVICE_GRPC_HOST=localhost:9040
|
||||
PAYMENT_MICROSERVICE_GRPC_HOST=treasurer-service:9085
|
||||
VERIFICATION_MICROSERVICE_USER_URL=http://10.8.0.8:7035/verification
|
||||
TEMPLATEGEN_MICROSERVICE_URL=10.6.0.17
|
||||
|
||||
API_URL=https://api.smtp.bz/v1/smtp/send
|
||||
MAIL_SENDER=noreply@mailing.pena.digital
|
||||
MAIL_API_KEY=P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev
|
||||
MAIL_AUTH_USERNAME=kotilion.95@gmail.com
|
||||
MAIL_AUTH_PASSWORD=vWwbCSg4bf0p
|
@ -44,7 +44,6 @@ services:
|
||||
- customer-db
|
||||
- customer-migration
|
||||
- redpanda
|
||||
- test-pena-auth-service
|
||||
networks:
|
||||
- test
|
||||
|
||||
@ -188,30 +187,5 @@ services:
|
||||
networks:
|
||||
- test
|
||||
|
||||
test-pena-auth-service:
|
||||
image: penahub.gitlab.yandexcloud.net:5050/pena-services/pena-auth-service:staging.872
|
||||
container_name: test-pena-auth-service
|
||||
init: true
|
||||
env_file: auth.env.test
|
||||
healthcheck:
|
||||
test: wget -T1 --spider http://localhost:8000/user
|
||||
interval: 2s
|
||||
timeout: 2s
|
||||
retries: 5
|
||||
environment:
|
||||
- DB_HOST=test-pena-auth-db
|
||||
- DB_PORT=27017
|
||||
- ENVIRONMENT=staging
|
||||
- HTTP_HOST=0.0.0.0
|
||||
- HTTP_PORT=8000
|
||||
- DB_USERNAME=test
|
||||
- DB_PASSWORD=test
|
||||
- DB_NAME=admin
|
||||
- DB_AUTH=admin
|
||||
depends_on:
|
||||
- test-pena-auth-db
|
||||
networks:
|
||||
- test
|
||||
|
||||
networks:
|
||||
test:
|
@ -32,7 +32,6 @@ services:
|
||||
- VERIFICATION_MICROSERVICE_USER_URL=http://10.6.0.17:7035/verification
|
||||
- TEMPLATEGEN_MICROSERVICE_URL=10.6.0.17
|
||||
|
||||
|
||||
- JWT_PUBLIC_KEY=$JWT_PUBLIC_KEY
|
||||
- JWT_ISSUER=pena-auth-service
|
||||
- JWT_AUDIENCE=pena
|
||||
|
@ -1,4 +0,0 @@
|
||||
# JWT settings
|
||||
JWT_ISSUER="pena-auth-service"
|
||||
JWT_AUDIENCE="pena"
|
||||
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69\n80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B\ndA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y\n+3GyaOY536H47qyXAgMBAAE=\n-----END PUBLIC KEY-----"
|
@ -156,18 +156,18 @@ services:
|
||||
- "8083:8083"
|
||||
environment:
|
||||
CONNECT_CONFIGURATION: |
|
||||
key.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||
value.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||
group.id=connectors-cluster
|
||||
offset.storage.topic=_internal_connectors_offsets
|
||||
config.storage.topic=_internal_connectors_configs
|
||||
status.storage.topic=_internal_connectors_status
|
||||
config.storage.replication.factor=-1
|
||||
offset.storage.replication.factor=-1
|
||||
status.storage.replication.factor=-1
|
||||
offset.flush.interval.ms=1000
|
||||
producer.linger.ms=50
|
||||
producer.batch.size=131072
|
||||
key.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||
value.converter=org.apache.kafka.connect.converters.ByteArrayConverter
|
||||
group.id=connectors-cluster
|
||||
offset.storage.topic=_internal_connectors_offsets
|
||||
config.storage.topic=_internal_connectors_configs
|
||||
status.storage.topic=_internal_connectors_status
|
||||
config.storage.replication.factor=-1
|
||||
offset.storage.replication.factor=-1
|
||||
status.storage.replication.factor=-1
|
||||
offset.flush.interval.ms=1000
|
||||
producer.linger.ms=50
|
||||
producer.batch.size=131072
|
||||
CONNECT_BOOTSTRAP_SERVERS: redpanda:9092
|
||||
CONNECT_GC_LOG_ENABLED: "false"
|
||||
CONNECT_HEAP_OPTS: -Xms512M -Xmx512M
|
||||
|
38
go.mod
38
go.mod
@ -1,11 +1,12 @@
|
||||
module penahub.gitlab.yandexcloud.net/pena-services/customer
|
||||
|
||||
go 1.20
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/deepmap/oapi-codegen v1.12.4
|
||||
github.com/getkin/kin-openapi v0.116.0
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/gofiber/fiber/v2 v2.52.0
|
||||
github.com/golang-jwt/jwt/v5 v5.0.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
@ -15,58 +16,55 @@ require (
|
||||
github.com/stretchr/testify v1.8.4
|
||||
github.com/twmb/franz-go v1.13.6
|
||||
github.com/twmb/franz-go/pkg/kadm v1.8.1
|
||||
go.mongodb.org/mongo-driver v1.11.4
|
||||
go.mongodb.org/mongo-driver v1.13.1
|
||||
go.uber.org/zap v1.26.0
|
||||
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923
|
||||
google.golang.org/grpc v1.53.0
|
||||
google.golang.org/protobuf v1.31.0
|
||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/benbjohnson/clock v1.3.3 // indirect
|
||||
github.com/daixiang0/gci v0.11.2 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
||||
github.com/go-openapi/swag v0.22.3 // indirect
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/uuid v1.3.1 // indirect
|
||||
github.com/google/uuid v1.5.0 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/hexops/gotextdiff v1.0.3 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/invopop/yaml v0.1.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/klauspost/compress v1.17.0 // indirect
|
||||
github.com/kr/pretty v0.3.1 // indirect
|
||||
github.com/labstack/gommon v0.4.0 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
|
||||
github.com/perimeterx/marshmallow v1.1.4 // indirect
|
||||
github.com/pierrec/lz4/v4 v4.1.17 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/spf13/cobra v1.8.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/twmb/franz-go/pkg/kmsg v1.4.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.1 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.3 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
|
||||
go.uber.org/atomic v1.11.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/crypto v0.12.0 // indirect
|
||||
golang.org/x/net v0.14.0 // indirect
|
||||
golang.org/x/crypto v0.14.0 // indirect
|
||||
golang.org/x/net v0.17.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/sys v0.11.0 // indirect
|
||||
golang.org/x/text v0.12.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/text v0.13.0 // indirect
|
||||
golang.org/x/time v0.3.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
95
go.sum
95
go.sum
@ -1,19 +1,16 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/benbjohnson/clock v1.3.3 h1:g+rSsSaAzhHJYcIQE78hJ3AhyjjtQvleKDjlhdBnIhc=
|
||||
github.com/benbjohnson/clock v1.3.3/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/daixiang0/gci v0.11.2 h1:Oji+oPsp3bQ6bNNgX30NBAVT18P4uBH4sRZnlOlTj7Y=
|
||||
github.com/daixiang0/gci v0.11.2/go.mod h1:xtHP9N7AHdNvtRNfcx9gwTDfw7FRJx4bZUsiEfiNNAI=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@ -38,6 +35,8 @@ github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSM
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||
github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
|
||||
github.com/gofiber/fiber/v2 v2.52.0 h1:S+qXi7y+/Pgvqq4DrSmREGiFwtB7Bu6+QFLuIHYw/UE=
|
||||
github.com/gofiber/fiber/v2 v2.52.0/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||
@ -60,16 +59,12 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
|
||||
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8=
|
||||
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
|
||||
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc=
|
||||
github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
|
||||
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||
@ -80,8 +75,8 @@ github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPci
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||
github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
|
||||
github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
@ -104,8 +99,10 @@ github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxec
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
|
||||
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
|
||||
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
|
||||
@ -119,21 +116,16 @@ github.com/pierrec/lz4/v4 v4.1.17 h1:kV4Ip+/hUBC+8T6+2EgburRtkE9ef4nbY3f4dFhGjMc
|
||||
github.com/pierrec/lz4/v4 v4.1.17/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sethvargo/go-envconfig v0.9.0 h1:Q6FQ6hVEeTECULvkJZakq3dZMeBQ3JUpcKMfPQbKMDE=
|
||||
github.com/sethvargo/go-envconfig v0.9.0/go.mod h1:Iz1Gy1Sf3T64TQlJSvee81qDhf7YIlt8GMUX6yyNFs0=
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
@ -142,15 +134,12 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
|
||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||
github.com/twmb/franz-go v1.13.6 h1:DRh06Hy3GthZuA+fQhDo+IMV+QUZHQfS2TIiWf/rCw8=
|
||||
github.com/twmb/franz-go v1.13.6/go.mod h1:jm/FtYxmhxDTN0gNSb26XaJY0irdSVcsckLiR5tQNMk=
|
||||
github.com/twmb/franz-go/pkg/kadm v1.8.1 h1:SrzL855I7gQTGdMtOYGTHhebs7TPgPN29FPtjusqwlE=
|
||||
@ -161,43 +150,46 @@ github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
|
||||
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
|
||||
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
|
||||
github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
|
||||
github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
|
||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
|
||||
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
|
||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
|
||||
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
|
||||
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
|
||||
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
|
||||
github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
|
||||
github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4=
|
||||
github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8=
|
||||
github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
|
||||
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.mongodb.org/mongo-driver v1.11.4 h1:4ayjakA013OdpGyL2K3ZqylTac/rMjrJOMZ1EHizXas=
|
||||
go.mongodb.org/mongo-driver v1.11.4/go.mod h1:PTSz5yu21bkT/wXpkS7WR5f0ddqw5quethTUn9WM+2g=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk=
|
||||
go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
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/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
|
||||
golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
|
||||
golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc=
|
||||
golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
@ -205,6 +197,7 @@ golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHl
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@ -213,19 +206,19 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
|
||||
golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
|
||||
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/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-20190911185100-cd5d95a43a6e/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.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI=
|
||||
golang.org/x/sync v0.2.0/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.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@ -240,17 +233,22 @@ golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/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-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
|
||||
golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
|
||||
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
|
||||
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
@ -262,6 +260,7 @@ golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtn
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
@ -298,3 +297,5 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d h1:gbaDt35HMDqOK84WYmDIlXMI7rstUcRqNttaT6Kx1do=
|
||||
penahub.gitlab.yandexcloud.net/backend/penahub_common v0.0.0-20240202120244-c4ef330cfe5d/go.mod h1:lTmpjry+8evVkXWbEC+WMOELcFkRD1lFMc7J09mOndM=
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os/signal"
|
||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@ -17,7 +18,6 @@ import (
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/closer"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/kafka"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -72,9 +72,10 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) {
|
||||
HubadminURL: &config.Service.HubadminMicroservice.URL,
|
||||
CurrencyURL: &config.Service.CurrencyMicroservice.URL,
|
||||
DiscountServiceConfiguration: &config.Service.DiscountMicroservice,
|
||||
VerificationURL: &config.Service.VerificationMicroservice.URL,
|
||||
PaymentServiceConfiguration: &config.Service.PaymentMicroservice,
|
||||
VerificationURL: &config.Service.VerificationMicroservice.URL,
|
||||
TemplategenURL: &config.Service.TemplategenMicroserviceURL.URL,
|
||||
MailClient: &config.Service.Mail,
|
||||
})
|
||||
|
||||
repositories := initialize.NewRepositories(initialize.RepositoriesDeps{
|
||||
@ -100,7 +101,7 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) {
|
||||
return fmt.Errorf("failed to loading openapi spec: %w", err)
|
||||
}
|
||||
|
||||
api := initialize.NewAPI(*controllers)
|
||||
api := swagger.NewAPI2(logger, mongoDB, config, brokers.TariffConsumer, brokers.TariffProducer)
|
||||
|
||||
serverHTTP, httpErr := server.NewHTTP(server.DepsHTTP{
|
||||
Logger: logger,
|
||||
@ -116,7 +117,7 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) {
|
||||
return httpErr.Wrap("failed to init grpc server")
|
||||
}
|
||||
|
||||
serverHTTP.Register(api)
|
||||
serverHTTP.Register(&api)
|
||||
serverGRPC.Register(controllers)
|
||||
|
||||
go serverHTTP.Run(&config.HTTP)
|
||||
|
@ -1,15 +0,0 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger"
|
||||
)
|
||||
|
||||
func NewAPI(controllers Controllers) *swagger.API {
|
||||
return swagger.New(swagger.Deps{
|
||||
AccountController: controllers.AccountController,
|
||||
CurrencyController: controllers.CurrencyController,
|
||||
CartController: controllers.CartController,
|
||||
WalletController: controllers.WalletController,
|
||||
HistoryController: controllers.HistoryController,
|
||||
})
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
package initialize_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/twmb/franz-go/pkg/kgo"
|
||||
"go.mongodb.org/mongo-driver/mongo/integration/mtest"
|
||||
"go.uber.org/zap"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/initialize"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
)
|
||||
|
||||
func TestNewAPI(t *testing.T) {
|
||||
mt := mtest.New(t, mtest.NewOptions().ClientType(mtest.Mock))
|
||||
|
||||
mt.Run("API сваггера должен успешно инициализироваться", func(t *mtest.T) {
|
||||
assert.NotPanics(t, func() {
|
||||
logger := zap.New(zap.L().Core())
|
||||
|
||||
repositories := initialize.NewRepositories(initialize.RepositoriesDeps{
|
||||
Logger: logger,
|
||||
MongoDB: t.Client.Database("test"),
|
||||
})
|
||||
|
||||
clients := initialize.NewClients(initialize.ClientsDeps{
|
||||
Logger: logger,
|
||||
AuthURL: &models.AuthMicroserviceURL{User: ""},
|
||||
HubadminURL: &models.HubadminMicroserviceURL{Tariff: ""},
|
||||
CurrencyURL: &models.CurrencyMicroserviceURL{},
|
||||
DiscountServiceConfiguration: &models.DiscountMicroserviceConfiguration{HostGRPC: "host"},
|
||||
PaymentServiceConfiguration: &models.PaymentMicroserviceConfiguration{HostGRPC: "host"},
|
||||
VerificationURL: &models.VerificationMicroserviceURL{Verification: ""},
|
||||
TemplategenURL: &models.TemplategenMicroserviceURL{Templategen: ""},
|
||||
})
|
||||
|
||||
brokers := initialize.NewBrokers(initialize.BrokersDeps{
|
||||
Logger: logger,
|
||||
TariffClient: &kgo.Client{},
|
||||
})
|
||||
|
||||
services := initialize.NewServices(initialize.ServicesDeps{
|
||||
Logger: logger,
|
||||
Repositories: repositories,
|
||||
Clients: clients,
|
||||
ConfigurationGRPC: &models.ConfigurationGRPC{Domen: "domen"},
|
||||
Brokers: brokers,
|
||||
})
|
||||
|
||||
controllers := initialize.NewControllers(initialize.ControllersDeps{
|
||||
Logger: logger,
|
||||
Services: services,
|
||||
})
|
||||
|
||||
api := initialize.NewAPI(*controllers)
|
||||
|
||||
assert.NotNil(t, api)
|
||||
})
|
||||
})
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
package initialize
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
@ -15,6 +16,7 @@ type ClientsDeps struct {
|
||||
PaymentServiceConfiguration *models.PaymentMicroserviceConfiguration
|
||||
VerificationURL *models.VerificationMicroserviceURL
|
||||
TemplategenURL *models.TemplategenMicroserviceURL
|
||||
MailClient *models.MailConfiguration
|
||||
}
|
||||
|
||||
type Clients struct {
|
||||
@ -25,6 +27,7 @@ type Clients struct {
|
||||
PaymentClient *client.PaymentClient
|
||||
VerificationClient *client.VerificationClient
|
||||
TemplateClient *client.TemplateClient
|
||||
MailClient *client.MailClient
|
||||
}
|
||||
|
||||
func NewClients(deps ClientsDeps) *Clients {
|
||||
@ -57,5 +60,17 @@ func NewClients(deps ClientsDeps) *Clients {
|
||||
Logger: deps.Logger,
|
||||
URLs: deps.TemplategenURL,
|
||||
}),
|
||||
MailClient: client.NewMailClient(client.MailClientDeps{
|
||||
Logger: deps.Logger,
|
||||
ApiUrl: deps.MailClient.ApiUrl,
|
||||
Sender: deps.MailClient.Sender,
|
||||
Auth: &models.PlainAuth{
|
||||
Identity: deps.MailClient.Auth.Identity,
|
||||
Username: deps.MailClient.Auth.Username,
|
||||
Password: deps.MailClient.Auth.Password,
|
||||
},
|
||||
ApiKey: deps.MailClient.ApiKey,
|
||||
FiberClient: fiber.AcquireClient(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,9 @@ import (
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/initialize"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||
)
|
||||
|
||||
func TestConfiguration(t *testing.T) {
|
||||
|
@ -40,10 +40,13 @@ func NewServices(deps ServicesDeps) *Services {
|
||||
})
|
||||
|
||||
walletService := wallet.New(wallet.Deps{
|
||||
Logger: deps.Logger,
|
||||
Repository: deps.Repositories.AccountRepository,
|
||||
CurrencyClient: deps.Clients.CurrencyClient,
|
||||
HistoryService: historyService,
|
||||
Logger: deps.Logger,
|
||||
Repository: deps.Repositories.AccountRepository,
|
||||
CurrencyClient: deps.Clients.CurrencyClient,
|
||||
VerificationClient: deps.Clients.VerificationClient,
|
||||
AuthClient: deps.Clients.AuthClient,
|
||||
MailClient: deps.Clients.MailClient,
|
||||
HistoryService: historyService,
|
||||
})
|
||||
|
||||
tariffBrokerService := tariff.New(tariff.Deps{
|
||||
|
@ -19,22 +19,16 @@ type AuthClientDeps struct {
|
||||
}
|
||||
|
||||
type AuthClient struct {
|
||||
logger *zap.Logger
|
||||
urls *models.AuthMicroserviceURL
|
||||
urls *models.AuthMicroserviceURL
|
||||
}
|
||||
|
||||
func NewAuthClient(deps AuthClientDeps) *AuthClient {
|
||||
if deps.Logger == nil {
|
||||
log.Panicln("logger is nil on <NewAuthClient>")
|
||||
}
|
||||
|
||||
if deps.URLs == nil {
|
||||
log.Panicln("urls is nil on <NewAuthClient>")
|
||||
}
|
||||
|
||||
return &AuthClient{
|
||||
logger: deps.Logger,
|
||||
urls: deps.URLs,
|
||||
urls: deps.URLs,
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,22 +46,12 @@ func (receiver *AuthClient) GetUser(ctx context.Context, userID string) (*models
|
||||
Headers: map[string]string{"Content-Type": "application/json"},
|
||||
})
|
||||
if err != nil {
|
||||
receiver.logger.Error("failed to request get user on <GetUser> of <AuthClient>",
|
||||
zap.Error(err),
|
||||
zap.String("userID", userID),
|
||||
)
|
||||
|
||||
return nil, errors.New(
|
||||
fmt.Errorf("failed to request get user with <%s> on <GetUser> of <AuthClient>: %w", userID, err),
|
||||
errors.ErrInternalError,
|
||||
)
|
||||
}
|
||||
if response.Error != nil {
|
||||
receiver.logger.Error("failed request on <GetUser> of <AuthClient>",
|
||||
zap.String("error", response.Error.Message),
|
||||
zap.String("userID", userID),
|
||||
)
|
||||
|
||||
return nil, errors.New(
|
||||
fmt.Errorf("failed request with <%s> on <GetUser> of <AuthClient>: %s", userID, response.Error.Message),
|
||||
utils.DetermineClientErrorResponse(response.StatusCode),
|
||||
|
88
internal/interface/client/mail.go
Normal file
88
internal/interface/client/mail.go
Normal file
@ -0,0 +1,88 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"go.uber.org/zap"
|
||||
"mime/multipart"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
)
|
||||
|
||||
type MailClientDeps struct {
|
||||
ApiUrl string
|
||||
Sender string
|
||||
Auth *models.PlainAuth
|
||||
ApiKey string
|
||||
FiberClient *fiber.Client
|
||||
Logger *zap.Logger
|
||||
}
|
||||
|
||||
type MailClient struct {
|
||||
deps MailClientDeps
|
||||
}
|
||||
|
||||
func NewMailClient(deps MailClientDeps) *MailClient {
|
||||
if deps.FiberClient == nil {
|
||||
deps.FiberClient = fiber.AcquireClient()
|
||||
}
|
||||
return &MailClient{
|
||||
deps: deps,
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *MailClient) SendMessage(userEmail string, verification *models.Verification) errors.Error {
|
||||
body := fmt.Sprintf("<p>Поступила заявка на оплату через Р/С от пользователя с почтой %s (%s)</p>"+
|
||||
"<p>Вот файлы его верификации:</p>", userEmail, verification.UserID)
|
||||
|
||||
for _, file := range verification.Files {
|
||||
body += fmt.Sprintf("<p>%s: <a href=\"%s\">%s</a></p>", file.Name, file.URL, file.URL)
|
||||
}
|
||||
|
||||
form := new(bytes.Buffer)
|
||||
writer := multipart.NewWriter(form)
|
||||
defer writer.Close()
|
||||
|
||||
fields := map[string]string{
|
||||
"from": receiver.deps.Sender,
|
||||
"to": "sells@pena.digital",
|
||||
"subject": "Новая заявка на оплату через Р/С",
|
||||
"html": body,
|
||||
}
|
||||
|
||||
for key, value := range fields {
|
||||
if err := writer.WriteField(key, value); err != nil {
|
||||
return handleError(receiver.deps.Logger, "Error writing form field", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return handleError(receiver.deps.Logger, "Error closing form writer", err)
|
||||
}
|
||||
|
||||
req := receiver.deps.FiberClient.Post(receiver.deps.ApiUrl).Body(form.Bytes()).ContentType(writer.FormDataContentType())
|
||||
if receiver.deps.ApiKey != "" {
|
||||
req.Set("Authorization", receiver.deps.ApiKey)
|
||||
}
|
||||
|
||||
statusCode, _, errs := req.Bytes()
|
||||
if errs != nil {
|
||||
return handleError(receiver.deps.Logger, "Error sending request", errs[0])
|
||||
}
|
||||
|
||||
if statusCode != fiber.StatusOK {
|
||||
err := fmt.Errorf("the SMTP service returned an error: %s", statusCode)
|
||||
return handleError(receiver.deps.Logger, "Error sending email", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func handleError(logger *zap.Logger, message string, err error) errors.Error {
|
||||
logger.Error(message, zap.Error(err))
|
||||
return errors.New(
|
||||
fmt.Errorf("failed to send email on <SendMessage> of <MailClient>: %w", err),
|
||||
errors.ErrInternalError,
|
||||
)
|
||||
}
|
@ -51,6 +51,9 @@ func (receiver *VerificationClient) GetVerification(ctx context.Context, userID
|
||||
Headers: map[string]string{"Content-Type": "application/json"},
|
||||
})
|
||||
if err != nil {
|
||||
if response.StatusCode == 404 {
|
||||
return nil, errors.New(err, errors.ErrNotFound)
|
||||
}
|
||||
return nil, errors.New(err, errors.ErrInternalError)
|
||||
}
|
||||
|
||||
|
@ -121,3 +121,27 @@ func (receiver *Controller) GetPaymentLink(ctx echo.Context) error {
|
||||
|
||||
return ctx.JSON(http.StatusOK, &models.GetPaymentLinkResponse{Link: link})
|
||||
}
|
||||
|
||||
func (receiver *Controller) PostWalletRspay(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
receiver.logger.Error("failed to convert jwt payload to string on <PostWalletRspay> of <WallerController>")
|
||||
|
||||
return errors.HTTP(ctx, errors.New(
|
||||
fmt.Errorf("failed to convert jwt payload to string: %s", userID),
|
||||
errors.ErrInvalidArgs,
|
||||
))
|
||||
}
|
||||
|
||||
if err := receiver.walletService.PostWalletRspay(ctx.Request().Context(), userID); err != nil {
|
||||
if err == errors.ErrNoAccess {
|
||||
return errors.HTTP(ctx, err)
|
||||
}
|
||||
return errors.HTTP(ctx, errors.New(
|
||||
fmt.Errorf("failed to process rspay: %w", err),
|
||||
errors.ErrInternalError,
|
||||
))
|
||||
}
|
||||
|
||||
return ctx.NoContent(http.StatusOK)
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ import (
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.uber.org/zap"
|
||||
mongoWrapper "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||
)
|
||||
|
||||
type AccountRepositoryDeps struct {
|
||||
@ -42,6 +42,21 @@ func NewAccountRepository(deps AccountRepositoryDeps) *AccountRepository {
|
||||
}
|
||||
}
|
||||
|
||||
func NewAccountRepository2(logger *zap.Logger, mongo *mongo.Collection) AccountRepository {
|
||||
if logger == nil {
|
||||
log.Panicln("logger is nil on <NewAccountRepository>")
|
||||
}
|
||||
|
||||
if mongo == nil {
|
||||
log.Panicln("mongodb is nil on <NewAccountRepository>")
|
||||
}
|
||||
|
||||
return AccountRepository{
|
||||
logger: logger,
|
||||
mongoDB: mongo,
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *AccountRepository) FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error) {
|
||||
filter := bson.M{
|
||||
fields.Account.UserID: id,
|
||||
|
@ -10,10 +10,10 @@ import (
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.uber.org/zap"
|
||||
mongoWrapper "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||
)
|
||||
|
||||
type CurrencyRepositoryDeps struct {
|
||||
@ -41,6 +41,21 @@ func NewCurrencyRepository(deps CurrencyRepositoryDeps) *CurrencyRepository {
|
||||
}
|
||||
}
|
||||
|
||||
func NewCurrencyRepository2(logger *zap.Logger, mongo *mongo.Collection) CurrencyRepository {
|
||||
if logger == nil {
|
||||
log.Panicln("logger is nil on <NewCurrencyRepository>")
|
||||
}
|
||||
|
||||
if mongo == nil {
|
||||
log.Panicln("mongodb is nil on <NewCurrencyRepository>")
|
||||
}
|
||||
|
||||
return CurrencyRepository{
|
||||
logger: logger,
|
||||
mongoDB: mongo,
|
||||
}
|
||||
}
|
||||
|
||||
func (receiver *CurrencyRepository) FindCurrenciesList(ctx context.Context, name string) (*models.CurrencyList, errors.Error) {
|
||||
filter := bson.M{
|
||||
fields.Currency.Name: name,
|
||||
|
@ -11,11 +11,11 @@ import (
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
"go.uber.org/zap"
|
||||
mongoWrapper "penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/fields"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
|
||||
mongoWrapper "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||
)
|
||||
|
||||
type HistoryRepositoryDeps struct {
|
||||
@ -188,7 +188,13 @@ func (receiver *HistoryRepository) GetRecentTariffs(ctx context.Context, userID
|
||||
// TODO:tests.
|
||||
func (receiver *HistoryRepository) GetHistoryByID(ctx context.Context, historyID string) (*models.ReportHistory, errors.Error) {
|
||||
history := &models.ReportHistory{}
|
||||
err := receiver.mongoDB.FindOne(ctx, bson.M{"_id": historyID}).Decode(history)
|
||||
|
||||
objID, err := primitive.ObjectIDFromHex(historyID)
|
||||
if err != nil {
|
||||
return nil, errors.New(fmt.Errorf("failed to convert history ID: %w", err), errors.ErrInternalError)
|
||||
}
|
||||
|
||||
err = receiver.mongoDB.FindOne(ctx, bson.M{"_id": objID}).Decode(history)
|
||||
if err != nil {
|
||||
receiver.logger.Error(
|
||||
"failed to find by id in <GetHistoryById> of <HistoryRepository>",
|
||||
|
@ -1,98 +1,789 @@
|
||||
package swagger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/labstack/echo/v4"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.uber.org/zap"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/broker/tariff"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/repository"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/discount"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/service/history"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/utils/transfer"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/echotools"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
|
||||
)
|
||||
|
||||
const defaultCurrency = "RUB" // TODO move
|
||||
|
||||
type API2 struct {
|
||||
logger *zap.Logger
|
||||
history repository.HistoryRepository
|
||||
logger *zap.Logger
|
||||
history repository.HistoryRepository
|
||||
account repository.AccountRepository
|
||||
currency repository.CurrencyRepository
|
||||
producer *tariff.Producer
|
||||
consumer *tariff.Consumer
|
||||
clients clients
|
||||
grpc models.ConfigurationGRPC
|
||||
}
|
||||
|
||||
type clients struct {
|
||||
auth *client.AuthClient
|
||||
hubadmin *client.HubadminClient
|
||||
currency *client.CurrencyClient
|
||||
discount *client.DiscountClient
|
||||
payment *client.PaymentClient
|
||||
verify *client.VerificationClient
|
||||
template *client.TemplateClient
|
||||
mail *client.MailClient
|
||||
}
|
||||
|
||||
var _ ServerInterface = (*API2)(nil)
|
||||
|
||||
func NewAPI2(logger *zap.Logger, db *mongo.Database) API2 {
|
||||
func NewAPI2(logger *zap.Logger, db *mongo.Database, config *models.Config, consumer *tariff.Consumer, producer *tariff.Producer) API2 {
|
||||
return API2{
|
||||
logger: logger,
|
||||
history: repository.NewHistoryRepository2(logger, db.Collection("histories")),
|
||||
logger: logger,
|
||||
history: repository.NewHistoryRepository2(logger, db.Collection("histories")),
|
||||
currency: repository.NewCurrencyRepository2(logger, db.Collection("currency_lists")),
|
||||
account: repository.NewAccountRepository2(logger, db.Collection("accounts")),
|
||||
consumer: consumer,
|
||||
producer: producer,
|
||||
grpc: config.GRPC,
|
||||
clients: clients{
|
||||
auth: client.NewAuthClient(client.AuthClientDeps{Logger: logger, URLs: &config.Service.AuthMicroservice.URL}),
|
||||
hubadmin: client.NewHubadminClient(client.HubadminClientDeps{Logger: logger, URLs: &config.Service.HubadminMicroservice.URL}),
|
||||
currency: client.NewCurrencyClient(client.CurrencyClientDeps{Logger: logger, URLs: &config.Service.CurrencyMicroservice.URL}),
|
||||
discount: client.NewDiscountClient(client.DiscountClientDeps{Logger: logger, DiscountServiceHost: config.Service.DiscountMicroservice.HostGRPC}),
|
||||
payment: client.NewPaymentClient(client.PaymentClientDeps{Logger: logger, PaymentServiceHost: config.Service.PaymentMicroservice.HostGRPC}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API2) SendReport(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) error(ctx echo.Context, status int, message string, rest ...any) error {
|
||||
if len(rest) > 0 {
|
||||
message = fmt.Sprintf(message, rest...)
|
||||
}
|
||||
api.logger.Error(message)
|
||||
return ctx.JSON(status, models.ResponseErrorHTTP{
|
||||
StatusCode: status,
|
||||
Message: message,
|
||||
})
|
||||
}
|
||||
|
||||
func (api *API2) DeleteAccount(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) errorOld(ctx echo.Context, err errors.Error) error {
|
||||
api.logger.Error("error:", zap.Error(err))
|
||||
return errors.HTTP(ctx, err)
|
||||
}
|
||||
|
||||
func (api *API2) GetRecentTariffs(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) noauth(ctx echo.Context) error {
|
||||
return api.error(ctx, http.StatusUnauthorized, "failed to get jwt payload")
|
||||
}
|
||||
|
||||
func (api *API2) GetAccount(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
// Health
|
||||
|
||||
func (api *API2) GetHealth(ctx echo.Context) error {
|
||||
return ctx.String(http.StatusOK, "OK")
|
||||
}
|
||||
|
||||
func (api *API2) ChangeAccount(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
// Account
|
||||
|
||||
func (api *API2) DeleteAccount(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
account, err := api.account.Remove(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) AddAccount(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) ChangeAccount(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
request, bindErr := echotools.Bind[models.Name](ctx)
|
||||
if bindErr != nil {
|
||||
return api.error(ctx, http.StatusBadRequest, "failed to bind json: %w", bindErr)
|
||||
}
|
||||
|
||||
account, err := api.account.UpdateName(ctx.Request().Context(), userID, request)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) DeleteDirectAccount(_ echo.Context, _ string) error {
|
||||
panic("TODO")
|
||||
func (api *API2) SetAccountVerificationStatus(ctx echo.Context, userID string) error {
|
||||
request, bindErr := echotools.Bind[models.SetAccountStatus](ctx)
|
||||
if bindErr != nil {
|
||||
return api.error(ctx, http.StatusBadRequest, "failed to bind json: %w", bindErr)
|
||||
}
|
||||
|
||||
account, err := api.account.SetStatus(ctx.Request().Context(), userID, request.Status)
|
||||
if err != nil {
|
||||
api.logger.Error("failed to set status on <SetVerificationStatus> of <AccountService>", zap.Error(err))
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) GetDirectAccount(_ echo.Context, _ string) error {
|
||||
panic("TODO")
|
||||
func (api *API2) GetAccount(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) SetAccountVerificationStatus(_ echo.Context, _ string) error {
|
||||
panic("TODO")
|
||||
func (api *API2) AddAccount(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
||||
if err != nil && err.Type() != errors.ErrNotFound {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if account != nil {
|
||||
return api.error(ctx, http.StatusBadRequest, "account exists")
|
||||
}
|
||||
|
||||
user, err := api.clients.auth.GetUser(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
account, err = api.account.Insert(ctx.Request().Context(), &models.Account{UserID: user.ID, Wallet: models.Wallet{Currency: defaultCurrency}})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) PaginationAccounts(_ echo.Context, _ PaginationAccountsParams) error {
|
||||
panic("TODO")
|
||||
func (api *API2) DeleteDirectAccount(ctx echo.Context, userID string) error {
|
||||
account, err := api.account.Remove(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) RemoveFromCart(_ echo.Context, _ RemoveFromCartParams) error {
|
||||
panic("TODO")
|
||||
func (api *API2) GetDirectAccount(ctx echo.Context, userID string) error {
|
||||
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, account)
|
||||
}
|
||||
|
||||
func (api *API2) Add2cart(_ echo.Context, _ Add2cartParams) error {
|
||||
panic("TODO")
|
||||
func (api *API2) PaginationAccounts(ctx echo.Context, params PaginationAccountsParams) error {
|
||||
if params.Page == nil || params.Limit == nil {
|
||||
return api.error(ctx, http.StatusInternalServerError, "default values missing for PaginationAccounts")
|
||||
}
|
||||
|
||||
page := int64(math.Max(float64(*params.Page), 1))
|
||||
limit := int64(math.Max(float64(*params.Limit), 1))
|
||||
limit = int64(math.Min(float64(limit), float64(models.DefaultLimit)))
|
||||
|
||||
count, err := api.account.CountAll(ctx.Request().Context())
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
response := models.PaginationResponse[models.Account]{TotalPages: 0, Records: []models.Account{}}
|
||||
return ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
totalPages := int64(math.Ceil(float64(count) / float64(limit)))
|
||||
|
||||
accounts, err := api.account.FindMany(ctx.Request().Context(), page, limit)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
response := models.PaginationResponse[models.Account]{
|
||||
TotalPages: totalPages,
|
||||
Records: accounts,
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
func (api *API2) PayCart(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
// Cart
|
||||
|
||||
func (api *API2) RemoveFromCart(ctx echo.Context, params RemoveFromCartParams) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
if validate.IsStringEmpty(params.Id) {
|
||||
return api.error(ctx, http.StatusBadRequest, "empty item id")
|
||||
}
|
||||
|
||||
cartItems, err := api.account.RemoveItemFromCart(ctx.Request().Context(), userID, params.Id)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, cartItems)
|
||||
}
|
||||
|
||||
func (api *API2) GetCurrencies(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) Add2cart(ctx echo.Context, params Add2cartParams) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
token, ok := ctx.Get(models.AuthJWTDecodedAccessTokenKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
if validate.IsStringEmpty(params.Id) {
|
||||
return api.error(ctx, http.StatusBadRequest, "empty item id")
|
||||
}
|
||||
|
||||
tariffID := params.Id
|
||||
|
||||
tariff, err := api.clients.hubadmin.GetTariff(ctx.Request().Context(), token, tariffID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if tariff == nil {
|
||||
return api.error(ctx, http.StatusNotFound, "tariff not found")
|
||||
}
|
||||
|
||||
cartItems, err := api.account.AddItemToCart(ctx.Request().Context(), userID, tariffID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, cartItems)
|
||||
}
|
||||
|
||||
func (api *API2) UpdateCurrencies(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) PayCart(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
accessToken, ok := ctx.Get(models.AuthJWTDecodedAccessTokenKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
api.logger.Info("account for pay", zap.Any("acc", account))
|
||||
|
||||
tariffs, err := api.clients.hubadmin.GetTariffs(ctx.Request().Context(), accessToken, account.Cart)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
api.logger.Info("tariffs for pay", zap.Any("acc", tariffs))
|
||||
|
||||
tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs)
|
||||
|
||||
discountResponse, err := api.clients.discount.Apply(ctx.Request().Context(), &discount.ApplyDiscountRequest{
|
||||
UserInformation: &discount.UserInformation{
|
||||
ID: account.UserID,
|
||||
Type: string(account.Status),
|
||||
PurchasesAmount: uint64(account.Wallet.PurchasesAmount),
|
||||
CartPurchasesAmount: tariffsAmount,
|
||||
},
|
||||
Products: transfer.TariffsToProductInformations(tariffs),
|
||||
Date: timestamppb.New(time.Now()),
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
api.logger.Info("discountResponse for pay", zap.Any("acc", discount.ApplyDiscountRequest{
|
||||
UserInformation: &discount.UserInformation{
|
||||
ID: account.UserID,
|
||||
Type: string(account.Status),
|
||||
PurchasesAmount: uint64(account.Wallet.Spent),
|
||||
CartPurchasesAmount: tariffsAmount,
|
||||
},
|
||||
Products: transfer.TariffsToProductInformations(tariffs),
|
||||
Date: timestamppb.New(time.Now()),
|
||||
}))
|
||||
|
||||
if account.Wallet.Money < int64(discountResponse.Price) {
|
||||
return api.error(ctx, http.StatusPaymentRequired, "insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money)
|
||||
}
|
||||
|
||||
// WithdrawAccountWalletMoney
|
||||
|
||||
request := models.WithdrawAccountWallet{
|
||||
Money: int64(discountResponse.Price),
|
||||
Account: account,
|
||||
}
|
||||
|
||||
if validate.IsStringEmpty(request.Account.Wallet.Currency) {
|
||||
request.Account.Wallet.Currency = models.InternalCurrencyKey
|
||||
}
|
||||
|
||||
var updatedAccount *models.Account
|
||||
|
||||
if request.Account.Wallet.Currency == models.InternalCurrencyKey {
|
||||
accountx, err := api.account.ChangeWallet(ctx.Request().Context(), request.Account.UserID, &models.Wallet{
|
||||
Cash: request.Account.Wallet.Cash - request.Money,
|
||||
Money: request.Account.Wallet.Money - request.Money,
|
||||
Spent: request.Account.Wallet.Spent + request.Money,
|
||||
PurchasesAmount: request.Account.Wallet.PurchasesAmount,
|
||||
Currency: request.Account.Wallet.Currency,
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
updatedAccount = accountx
|
||||
} else {
|
||||
cash, err := api.clients.currency.Translate(ctx.Request().Context(), &models.TranslateCurrency{
|
||||
Money: request.Money,
|
||||
From: models.InternalCurrencyKey,
|
||||
To: request.Account.Wallet.Currency,
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
accountx, err := api.account.ChangeWallet(ctx.Request().Context(), request.Account.UserID, &models.Wallet{
|
||||
Cash: request.Account.Wallet.Cash - cash,
|
||||
Money: request.Account.Wallet.Money - request.Money,
|
||||
Spent: request.Account.Wallet.Spent + request.Money,
|
||||
PurchasesAmount: request.Account.Wallet.PurchasesAmount,
|
||||
Currency: request.Account.Wallet.Currency,
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
updatedAccount = accountx
|
||||
}
|
||||
|
||||
if _, err := api.history.Insert(ctx.Request().Context(), &models.History{
|
||||
Key: models.CustomerHistoryKeyPayCart,
|
||||
UserID: account.UserID,
|
||||
Comment: "Успешная оплата корзины",
|
||||
RawDetails: tariffs,
|
||||
}); err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
// TODO: обработать ошибки при отправке сообщений
|
||||
|
||||
sendErrors := make([]errors.Error, 0)
|
||||
waitGroup := sync.WaitGroup{}
|
||||
mutex := sync.Mutex{}
|
||||
|
||||
for _, tariff := range tariffs {
|
||||
waitGroup.Add(1)
|
||||
|
||||
go func(currentTariff models.Tariff) {
|
||||
defer waitGroup.Done()
|
||||
|
||||
if err := api.producer.Send(ctx.Request().Context(), userID, ¤tTariff); err != nil {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
sendErrors = append(sendErrors, err)
|
||||
}
|
||||
}(tariff)
|
||||
}
|
||||
|
||||
waitGroup.Wait()
|
||||
|
||||
if len(sendErrors) > 0 {
|
||||
for _, err := range sendErrors {
|
||||
api.logger.Error("failed to send tariffs to broker on <Pay> of <CartService>", zap.Error(err))
|
||||
}
|
||||
return api.error(ctx, http.StatusInternalServerError, "failed to send tariffs to broker")
|
||||
}
|
||||
|
||||
if _, err := api.account.ClearCart(ctx.Request().Context(), account.UserID); err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
updatedAccount.Cart = []string{}
|
||||
|
||||
return ctx.JSON(http.StatusOK, updatedAccount)
|
||||
}
|
||||
|
||||
func (api *API2) GetHistory(_ echo.Context, _ GetHistoryParams) error {
|
||||
panic("TODO")
|
||||
// Currency
|
||||
|
||||
func (api *API2) GetCurrencies(ctx echo.Context) error {
|
||||
currencyList, err := api.currency.FindCurrenciesList(ctx.Request().Context(), models.DefaultCurrencyListName)
|
||||
if err != nil && err.Type() != errors.ErrNotFound {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if err != nil && err.Type() == errors.ErrNotFound {
|
||||
return ctx.JSON(http.StatusOK, []string{})
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, currencyList)
|
||||
}
|
||||
|
||||
func (api *API2) ChangeCurrency(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
func (api *API2) UpdateCurrencies(ctx echo.Context) error {
|
||||
currenciesPtr, bindErr := echotools.Bind[[]string](ctx)
|
||||
if bindErr != nil {
|
||||
return api.error(ctx, http.StatusBadRequest, "faild to bind currencies")
|
||||
}
|
||||
|
||||
currencies := *currenciesPtr
|
||||
|
||||
currencyList, err := api.currency.ReplaceCurrencies(ctx.Request().Context(), &models.CurrencyList{
|
||||
Name: models.DefaultCurrencyListName,
|
||||
Currencies: currencies,
|
||||
})
|
||||
if err != nil && err.Type() != errors.ErrNotFound {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if err != nil && err.Type() == errors.ErrNotFound {
|
||||
newCurrencyList, err := api.currency.Insert(ctx.Request().Context(), &models.CurrencyList{
|
||||
Name: models.DefaultCurrencyListName,
|
||||
Currencies: currencies,
|
||||
})
|
||||
if err != nil && err.Type() != errors.ErrNotFound {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
return ctx.JSON(http.StatusOK, newCurrencyList.Currencies)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, currencyList.Currencies)
|
||||
}
|
||||
|
||||
func (api *API2) RequestMoney(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
// History
|
||||
|
||||
func (api *API2) GetHistory(ctx echo.Context, params GetHistoryParams) error {
|
||||
dto := &history.GetHistories{
|
||||
Type: params.Type,
|
||||
Pagination: &models.Pagination{
|
||||
Page: int64(*params.Page),
|
||||
Limit: int64(*params.Limit),
|
||||
},
|
||||
}
|
||||
|
||||
count, err := api.history.CountAll(ctx.Request().Context(), dto)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
returnHistories := models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}}
|
||||
return ctx.JSON(http.StatusOK, returnHistories)
|
||||
}
|
||||
|
||||
totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit)))
|
||||
|
||||
histories, err := api.history.FindMany(ctx.Request().Context(), dto)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
returnHistories := models.PaginationResponse[models.History]{
|
||||
TotalPages: totalPages,
|
||||
Records: histories,
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, returnHistories)
|
||||
}
|
||||
|
||||
func (api *API2) CalculateLTV(_ echo.Context) error {
|
||||
panic("TODO")
|
||||
// Wallet
|
||||
|
||||
func (api *API2) RequestMoney(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
request, bindErr := echotools.Bind[models.GetPaymentLinkBody](ctx)
|
||||
if bindErr != nil {
|
||||
return api.error(ctx, http.StatusBadRequest, "faild to bind payment link")
|
||||
}
|
||||
|
||||
if err := utils.ValidateGetPaymentLinkBody(request); err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
link, err := api.GetPaymentLink(ctx.Request().Context(), &models.GetPaymentLinkRequest{
|
||||
Body: request,
|
||||
UserID: userID,
|
||||
ClientIP: ctx.RealIP(),
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, &models.GetPaymentLinkResponse{Link: link})
|
||||
}
|
||||
|
||||
func (api *API2) ChangeCurrency(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
request, bindErr := echotools.Bind[models.ChangeCurrency](ctx)
|
||||
if bindErr != nil {
|
||||
return api.error(ctx, http.StatusBadRequest, "faild to bind currency")
|
||||
}
|
||||
|
||||
if validate.IsStringEmpty(request.Currency) {
|
||||
return api.error(ctx, http.StatusBadRequest, "empty currency")
|
||||
}
|
||||
|
||||
currency := request.Currency
|
||||
account, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
cash, err := api.clients.currency.Translate(ctx.Request().Context(), &models.TranslateCurrency{
|
||||
Money: account.Wallet.Cash,
|
||||
From: account.Wallet.Currency,
|
||||
To: currency,
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
updatedAccount, err := api.account.ChangeWallet(ctx.Request().Context(), account.UserID, &models.Wallet{
|
||||
Cash: cash,
|
||||
Currency: currency,
|
||||
Money: account.Wallet.Money,
|
||||
})
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, updatedAccount)
|
||||
}
|
||||
|
||||
func (api *API2) CalculateLTV(ctx echo.Context) error {
|
||||
var req CalculateLTVJSONBody
|
||||
|
||||
if err := ctx.Bind(&req); err != nil {
|
||||
api.logger.Error("failed to bind request", zap.Error(err))
|
||||
return api.error(ctx, http.StatusBadRequest, "failed to bind request")
|
||||
}
|
||||
|
||||
if req.From > req.To && req.To != 0 {
|
||||
api.logger.Error("From timestamp must be less than To timestamp unless To is 0")
|
||||
return api.error(ctx, http.StatusBadRequest, "From timestamp must be less than To timestamp unless To is 0")
|
||||
}
|
||||
|
||||
ltv, err := api.history.CalculateCustomerLTV(ctx.Request().Context(), req.From, req.To)
|
||||
if err != nil {
|
||||
api.logger.Error("failed to calculate LTV", zap.Error(err))
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
response := struct {
|
||||
LTV int64 `json:"LTV"`
|
||||
}{
|
||||
LTV: ltv,
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, response)
|
||||
}
|
||||
|
||||
func (api *API2) GetRecentTariffs(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
api.logger.Error("failed to convert jwt payload to string on <GetRecentTariffs> of <API2>")
|
||||
return api.error(ctx, http.StatusBadRequest, "failed to convert jwt payload to string")
|
||||
}
|
||||
|
||||
if userID == "" {
|
||||
api.logger.Error("user id is missing in <GetRecentTariffs> of <API2>")
|
||||
return api.error(ctx, http.StatusBadRequest, "user id is missing")
|
||||
}
|
||||
|
||||
tariffs, err := api.history.GetRecentTariffs(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get recent tariffs on <GetRecentTariffs> of <API2>",
|
||||
zap.String("userId", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.JSON(http.StatusOK, tariffs)
|
||||
}
|
||||
|
||||
func (api *API2) SendReport(ctx echo.Context) error {
|
||||
var req SendReportJSONBody
|
||||
if err := ctx.Bind(&req); err != nil {
|
||||
api.logger.Error("failed to bind request", zap.Error(err))
|
||||
return api.error(ctx, http.StatusBadRequest, "failed to bind request")
|
||||
}
|
||||
|
||||
if req.Id == "" {
|
||||
api.logger.Error("history id is missing in <GetHistoryById> of <HistoryService>")
|
||||
return api.error(ctx, http.StatusBadRequest, "history id is missing")
|
||||
}
|
||||
|
||||
tariffs, err := api.history.GetHistoryByID(ctx.Request().Context(), req.Id)
|
||||
if err != nil {
|
||||
api.logger.Error(
|
||||
"failed to get history by id in <GetHistoryById> of <HistoryService>",
|
||||
zap.String("historyID", req.Id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if tariffs.Key != models.CustomerHistoryKeyPayCart {
|
||||
api.logger.Error(
|
||||
"invalid history record key",
|
||||
zap.String("historyID", req.Id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return api.error(ctx, http.StatusBadRequest, "invalid history record key")
|
||||
}
|
||||
|
||||
historyMap, err := api.history.GetDocNumber(ctx.Request().Context(), tariffs.UserID)
|
||||
if err != nil {
|
||||
api.logger.Error(
|
||||
"failed to get history of sorting by date created in <GetDocNumber> of <HistoryService>",
|
||||
zap.String("historyID", req.Id),
|
||||
zap.Error(err),
|
||||
)
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
verifuser, err := api.clients.verify.GetVerification(ctx.Request().Context(), tariffs.UserID)
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get user verification on <GetHistoryById> of <HistoryService>",
|
||||
zap.Error(err),
|
||||
zap.String("userID", tariffs.UserID),
|
||||
)
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
if !verifuser.Accepted {
|
||||
api.logger.Error(
|
||||
"verification not accepted",
|
||||
zap.String("userID", tariffs.UserID),
|
||||
zap.Error(err),
|
||||
)
|
||||
return api.error(ctx, http.StatusBadRequest, "verification not accepted")
|
||||
}
|
||||
|
||||
authuser, err := api.clients.auth.GetUser(ctx.Request().Context(), tariffs.UserID)
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get user on <GetHistoryById> of <HistoryService>",
|
||||
zap.Error(err),
|
||||
zap.String("userID", tariffs.UserID),
|
||||
)
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
fileContents, readerr := os.ReadFile("./report.docx")
|
||||
if readerr != nil {
|
||||
return api.error(ctx, http.StatusInternalServerError, "failed to read file")
|
||||
}
|
||||
|
||||
for _, tariff := range tariffs.RawDetails.Tariffs {
|
||||
totalAmount := uint64(0)
|
||||
for _, privilege := range tariff.Privileges {
|
||||
totalAmount += privilege.Amount
|
||||
}
|
||||
data := models.RespGeneratorService{
|
||||
DocNumber: historyMap[req.Id] + 1,
|
||||
Date: time.Now().Format("2006-01-02"),
|
||||
OrgTaxNum: verifuser.TaxNumber,
|
||||
OrgName: models.Name{Orgname: "Orgname"},
|
||||
Name: tariff.Name,
|
||||
Amount: totalAmount,
|
||||
Price: tariffs.RawDetails.Price,
|
||||
Sum: tariffs.RawDetails.Price,
|
||||
}
|
||||
err = api.clients.template.SendData(ctx.Request().Context(), data, fileContents, authuser.Email)
|
||||
if err != nil {
|
||||
api.logger.Error("failed to send report to user on <GetHistoryById> of <HistoryService>",
|
||||
zap.Error(err),
|
||||
zap.String("userID", tariffs.UserID),
|
||||
)
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
}
|
||||
|
||||
return ctx.NoContent(http.StatusOK)
|
||||
}
|
||||
|
||||
func (api *API2) PostWalletRspay(ctx echo.Context) error {
|
||||
userID, ok := ctx.Get(models.AuthJWTDecodedUserIDKey).(string)
|
||||
if !ok {
|
||||
return api.noauth(ctx)
|
||||
}
|
||||
|
||||
user, err := api.account.FindByUserID(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg {
|
||||
return api.error(ctx, http.StatusForbidden, "not allowed for non organizations")
|
||||
}
|
||||
|
||||
verification, err := api.clients.verify.GetVerification(ctx.Request().Context(), userID)
|
||||
if err == errors.ErrNotFound {
|
||||
return api.error(ctx, http.StatusForbidden, "no verification data found")
|
||||
}
|
||||
|
||||
if (user.Status == models.AccountStatusOrg && len(verification.Files) != 3) ||
|
||||
(user.Status == models.AccountStatusNko && len(verification.Files) != 4) {
|
||||
return api.error(ctx, http.StatusForbidden, "not enough verification files")
|
||||
}
|
||||
|
||||
authData, err := api.clients.auth.GetUser(ctx.Request().Context(), userID)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
err = api.clients.mail.SendMessage(authData.Login, verification)
|
||||
if err != nil {
|
||||
return api.errorOld(ctx, err)
|
||||
}
|
||||
|
||||
return ctx.NoContent(http.StatusOK)
|
||||
}
|
||||
|
@ -77,6 +77,9 @@ type ServerInterface interface {
|
||||
// Запрос на получение ссылки на оплату
|
||||
// (POST /wallet)
|
||||
RequestMoney(ctx echo.Context) error
|
||||
// Обработка запроса RSPay
|
||||
// (POST /wallet/rspay)
|
||||
PostWalletRspay(ctx echo.Context) error
|
||||
}
|
||||
|
||||
// ServerInterfaceWrapper converts echo contexts to parameters.
|
||||
@ -374,6 +377,17 @@ func (w *ServerInterfaceWrapper) RequestMoney(ctx echo.Context) error {
|
||||
return err
|
||||
}
|
||||
|
||||
// PostWalletRspay converts echo context to params.
|
||||
func (w *ServerInterfaceWrapper) PostWalletRspay(ctx echo.Context) error {
|
||||
var err error
|
||||
|
||||
ctx.Set(BearerScopes, []string{})
|
||||
|
||||
// Invoke the callback with all the unmarshaled arguments
|
||||
err = w.Handler.PostWalletRspay(ctx)
|
||||
return err
|
||||
}
|
||||
|
||||
// This is a simple interface which specifies echo.Route addition functions which
|
||||
// are present on both echo.Echo and echo.Group, since we want to allow using
|
||||
// either of them for path registration
|
||||
@ -421,86 +435,89 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
|
||||
router.POST(baseURL+"/sendReport", wrapper.SendReport)
|
||||
router.PATCH(baseURL+"/wallet", wrapper.ChangeCurrency)
|
||||
router.POST(baseURL+"/wallet", wrapper.RequestMoney)
|
||||
router.POST(baseURL+"/wallet/rspay", wrapper.PostWalletRspay)
|
||||
|
||||
}
|
||||
|
||||
// Base64 encoded, gzipped, json marshaled Swagger object
|
||||
var swaggerSpec = []string{
|
||||
|
||||
"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",
|
||||
"aC42/y8AAP//Dabnb25UAAA=",
|
||||
"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",
|
||||
}
|
||||
|
||||
// GetSwagger returns the content of the embedded swagger specification file
|
||||
|
@ -31,6 +31,7 @@ type cartController interface {
|
||||
type walletController interface {
|
||||
ChangeCurrency(ctx echo.Context) error
|
||||
GetPaymentLink(ctx echo.Context) error
|
||||
PostWalletRspay(ctx echo.Context) error
|
||||
}
|
||||
|
||||
type historyController interface {
|
||||
@ -171,3 +172,7 @@ func (receiver *API) RequestMoney(ctx echo.Context) error {
|
||||
func (receiver *API) ChangeCurrency(ctx echo.Context) error {
|
||||
return receiver.walletController.ChangeCurrency(ctx)
|
||||
}
|
||||
|
||||
func (receiver *API) PostWalletRspay(ctx echo.Context) error {
|
||||
return receiver.walletController.PostWalletRspay(ctx)
|
||||
}
|
||||
|
@ -165,11 +165,6 @@ type GetHistoryParams struct {
|
||||
AccountID *string `form:"accountID,omitempty" json:"accountID,omitempty"`
|
||||
}
|
||||
|
||||
// GetRecentTariffsJSONBody defines parameters for GetRecentTariffs.
|
||||
type GetRecentTariffsJSONBody struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// CalculateLTVJSONBody defines parameters for CalculateLTV.
|
||||
type CalculateLTVJSONBody struct {
|
||||
// From Начальная дата в формате Unix timestamp. Если 0, устанавливает начало истории.
|
||||
@ -179,6 +174,11 @@ type CalculateLTVJSONBody struct {
|
||||
To int64 `json:"to"`
|
||||
}
|
||||
|
||||
// GetRecentTariffsJSONBody defines parameters for GetRecentTariffs.
|
||||
type GetRecentTariffsJSONBody struct {
|
||||
Id string `json:"id"`
|
||||
}
|
||||
|
||||
// SendReportJSONBody defines parameters for SendReport.
|
||||
type SendReportJSONBody struct {
|
||||
Id string `json:"id"`
|
||||
|
204
internal/interface/swagger/money.go
Normal file
204
internal/interface/swagger/money.go
Normal file
@ -0,0 +1,204 @@
|
||||
package swagger
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/proto/treasurer"
|
||||
)
|
||||
|
||||
func (api *API2) GetPaymentLink(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
if _, userErr := api.clients.auth.GetUser(ctx, request.UserID); userErr != nil {
|
||||
api.logger.Error("failed to get user on <GetPaymentLink> on <PaymentService>",
|
||||
zap.Error(userErr),
|
||||
zap.String("userID", request.UserID),
|
||||
)
|
||||
|
||||
return "", userErr
|
||||
}
|
||||
|
||||
switch request.Body.Type {
|
||||
case models.PaymentTypeBankCard:
|
||||
return api.GetPaymentLinkBankCard(ctx, request)
|
||||
case models.PaymentTypeYoomoney:
|
||||
return api.GetPaymentLinkYooMoney(ctx, request)
|
||||
case models.PaymentTypeQiwi:
|
||||
return api.GetPaymentLinkQIWI(ctx, request)
|
||||
case models.PaymentTypeSberPay:
|
||||
return api.GetPaymentLinkSberPay(ctx, request)
|
||||
case models.PaymentTypeAlfabank:
|
||||
return api.GetPaymentLinkAlfaClick(ctx, request)
|
||||
case models.PaymentTypeTinkoff:
|
||||
return api.GetPaymentLinkTinkoff(ctx, request)
|
||||
case models.PaymentTypeMobile:
|
||||
return api.GetPaymentLinkMobile(ctx, request)
|
||||
case models.PaymentTypeCash:
|
||||
return api.GetPaymentLinkCash(ctx, request)
|
||||
}
|
||||
|
||||
return "", errors.NewWithMessage("invalid payment method type", errors.ErrInvalidArgs)
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkBankCard(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkBankCard(ctx, &treasurer.GetBankCardPaymentLinkRequest{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
BankCard: &treasurer.BankCardInformation{
|
||||
Number: request.Body.BankCard.Number,
|
||||
ExpiryYear: request.Body.BankCard.ExpiryYear,
|
||||
ExpiryMonth: request.Body.BankCard.ExpiryMonth,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get bankcard payment link on <GetPaymentLinkBankCard> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkYooMoney(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkYooMoney(ctx, &treasurer.GetPaymentLinkBody{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get yoomoney payment link on <GetPaymentLinkYooMoney> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkQIWI(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkQIWI(ctx, &treasurer.GetPhonePaymentLinkRequest{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
Phone: request.Body.PhoneNumber,
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get qiwi payment link on <GetPaymentLinkQIWI> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkSberPay(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkSberPay(ctx, &treasurer.GetPhonePaymentLinkRequest{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
Phone: request.Body.PhoneNumber,
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get sberpay payment link on <GetPaymentLinkSberPay> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkAlfaClick(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkAlfaClick(ctx, &treasurer.GetLoginPaymentLinkRequest{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
Login: request.Body.Login,
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get alfaclick payment link on <GetPaymentLinkAlfaClick> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkTinkoff(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkTinkoff(ctx, &treasurer.GetPaymentLinkBody{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get tinkoff payment link on <GetPaymentLinkTinkoff> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkMobile(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkMobile(ctx, &treasurer.GetPhonePaymentLinkRequest{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
Phone: request.Body.PhoneNumber,
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get mobile payment link on <GetPaymentLinkMobile> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
||||
|
||||
func (api *API2) GetPaymentLinkCash(ctx context.Context, request *models.GetPaymentLinkRequest) (string, errors.Error) {
|
||||
link, err := api.clients.payment.GetPaymentLinkCash(ctx, &treasurer.GetPhonePaymentLinkRequest{
|
||||
MainSettings: &treasurer.MainPaymentSettings{
|
||||
Currency: request.Body.Currency,
|
||||
Amount: request.Body.Amount,
|
||||
UserID: request.UserID,
|
||||
ClientIP: request.ClientIP,
|
||||
CallbackHostGRPC: []string{api.grpc.Domen},
|
||||
ReturnURL: request.Body.ReturnURL,
|
||||
},
|
||||
Phone: request.Body.PhoneNumber,
|
||||
})
|
||||
if err != nil {
|
||||
api.logger.Error("failed to get cash payment link on <GetPaymentLinkCash> of <PaymentService>", zap.Error(err))
|
||||
return "", err
|
||||
}
|
||||
|
||||
return link, nil
|
||||
}
|
@ -4,7 +4,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/mongo"
|
||||
"penahub.gitlab.yandexcloud.net/backend/penahub_common/mongo"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
@ -35,6 +35,7 @@ type ServiceConfiguration struct {
|
||||
TemplategenMicroserviceURL TemplategenMicroserviceConfiguration
|
||||
JWT JWTConfiguration
|
||||
Kafka KafkaConfiguration
|
||||
Mail MailConfiguration
|
||||
}
|
||||
|
||||
type KafkaConfiguration struct {
|
||||
@ -102,3 +103,16 @@ type VerificationMicroserviceURL struct {
|
||||
type TemplategenMicroserviceURL struct {
|
||||
Templategen string `env:"TEMPLATEGEN_MICROSERVICE_URL,required"`
|
||||
}
|
||||
|
||||
type MailConfiguration struct {
|
||||
ApiUrl string `env:"API_URL,required"`
|
||||
Sender string `env:"MAIL_SENDER,required"`
|
||||
Auth PlainAuth
|
||||
ApiKey string `env:"MAIL_API_KEY,required"`
|
||||
}
|
||||
|
||||
type PlainAuth struct {
|
||||
Identity string `env:"MAIL_AUTH_IDENTITY"`
|
||||
Username string `env:"MAIL_AUTH_USERNAME,required"`
|
||||
Password string `env:"MAIL_AUTH_PASSWORD,required"`
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ func (receiver *HTTP) Stop(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (receiver *HTTP) Register(api *swagger.API) *HTTP {
|
||||
func (receiver *HTTP) Register(api swagger.ServerInterface) *HTTP {
|
||||
swagger.RegisterHandlers(receiver.echo, api)
|
||||
|
||||
return receiver
|
||||
|
@ -25,7 +25,7 @@ func (receiver *GetHistories) BSON() bson.M {
|
||||
query := bson.M{
|
||||
fields.History.IsDeleted: false,
|
||||
fields.History.Type: *receiver.Type,
|
||||
fields.History.UserID: receiver.UserID,
|
||||
fields.History.UserID: receiver.UserID,
|
||||
}
|
||||
|
||||
return query
|
||||
@ -46,7 +46,7 @@ type authClient interface {
|
||||
}
|
||||
|
||||
type verificationClient interface {
|
||||
GetUser(ctx context.Context, userID string) (*models.Verification, errors.Error)
|
||||
GetVerification(ctx context.Context, userID string) (*models.Verification, errors.Error)
|
||||
}
|
||||
|
||||
type temlategenClient interface {
|
||||
@ -198,7 +198,7 @@ func (receiver *Service) GetHistoryByID(ctx context.Context, historyID string) e
|
||||
return err
|
||||
}
|
||||
|
||||
verifuser, err := receiver.VerificationClient.GetUser(ctx, tariffs.UserID)
|
||||
verifuser, err := receiver.VerificationClient.GetVerification(ctx, tariffs.UserID)
|
||||
if err != nil {
|
||||
receiver.logger.Error("failed to get user verification on <GetHistoryById> of <HistoryService>",
|
||||
zap.Error(err),
|
||||
|
@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
|
||||
@ -20,22 +21,36 @@ type currencyClient interface {
|
||||
Translate(context.Context, *models.TranslateCurrency) (int64, errors.Error)
|
||||
}
|
||||
|
||||
type verificationClient interface {
|
||||
GetVerification(ctx context.Context, userID string) (*models.Verification, errors.Error)
|
||||
}
|
||||
|
||||
type authClient interface {
|
||||
GetUser(ctx context.Context, userID string) (*models.User, errors.Error)
|
||||
}
|
||||
|
||||
type historyService interface {
|
||||
CreateHistory(ctx context.Context, history *models.History) (*models.History, errors.Error)
|
||||
}
|
||||
|
||||
type Deps struct {
|
||||
Logger *zap.Logger
|
||||
Repository accountRepository
|
||||
CurrencyClient currencyClient
|
||||
HistoryService historyService
|
||||
Logger *zap.Logger
|
||||
Repository accountRepository
|
||||
CurrencyClient currencyClient
|
||||
HistoryService historyService
|
||||
VerificationClient verificationClient
|
||||
AuthClient authClient
|
||||
MailClient *client.MailClient
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
logger *zap.Logger
|
||||
repository accountRepository
|
||||
currencyClient currencyClient
|
||||
historyService historyService
|
||||
logger *zap.Logger
|
||||
repository accountRepository
|
||||
currencyClient currencyClient
|
||||
historyService historyService
|
||||
verificationClient verificationClient
|
||||
authClient authClient
|
||||
mailClient *client.MailClient
|
||||
}
|
||||
|
||||
func New(deps Deps) *Service {
|
||||
@ -51,15 +66,30 @@ func New(deps Deps) *Service {
|
||||
log.Panicln("CurrencyClient is nil on <New (wallet service)>")
|
||||
}
|
||||
|
||||
if deps.VerificationClient == nil {
|
||||
log.Panicln("VerificationClient is nil on <New (wallet service)>")
|
||||
}
|
||||
|
||||
if deps.AuthClient == nil {
|
||||
log.Panicln("AuthClient is nil on <New (wallet service)>")
|
||||
}
|
||||
|
||||
if deps.MailClient == nil {
|
||||
log.Panicln("MailClient is nil on <New (wallet service)>")
|
||||
}
|
||||
|
||||
if deps.HistoryService == nil {
|
||||
log.Panicln("HistoryService is nil on <New (wallet service)>")
|
||||
}
|
||||
|
||||
return &Service{
|
||||
logger: deps.Logger,
|
||||
repository: deps.Repository,
|
||||
currencyClient: deps.CurrencyClient,
|
||||
historyService: deps.HistoryService,
|
||||
logger: deps.Logger,
|
||||
repository: deps.Repository,
|
||||
currencyClient: deps.CurrencyClient,
|
||||
verificationClient: deps.VerificationClient,
|
||||
authClient: deps.AuthClient,
|
||||
mailClient: deps.MailClient,
|
||||
historyService: deps.HistoryService,
|
||||
}
|
||||
}
|
||||
|
||||
@ -253,3 +283,48 @@ func (receiver *Service) ChangeCurrency(ctx context.Context, userID string, curr
|
||||
|
||||
return updatedAccount, nil
|
||||
}
|
||||
|
||||
func (receiver *Service) PostWalletRspay(ctx context.Context, userID string) errors.Error {
|
||||
user, err := receiver.repository.FindByUserID(ctx, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if user.Status != models.AccountStatusNko && user.Status != models.AccountStatusOrg {
|
||||
return errors.New(
|
||||
fmt.Errorf("not allowed for non organizations"),
|
||||
errors.ErrNoAccess,
|
||||
)
|
||||
}
|
||||
|
||||
verification, err := receiver.verificationClient.GetVerification(ctx, userID)
|
||||
if err == errors.ErrNotFound {
|
||||
return errors.New(
|
||||
fmt.Errorf("no verification data found"),
|
||||
errors.ErrNoAccess,
|
||||
)
|
||||
}
|
||||
|
||||
if user.Status == models.AccountStatusOrg && len(verification.Files) != 3 {
|
||||
return errors.New(
|
||||
fmt.Errorf("not enough verification files"),
|
||||
errors.ErrNoAccess,
|
||||
)
|
||||
} else if user.Status == models.AccountStatusNko && len(verification.Files) != 4 {
|
||||
return errors.New(
|
||||
fmt.Errorf("not enough verification files"),
|
||||
errors.ErrNoAccess,
|
||||
)
|
||||
}
|
||||
|
||||
authData, err := receiver.authClient.GetUser(ctx, userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = receiver.mailClient.SendMessage(authData.Login, verification)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -32,10 +32,10 @@
|
||||
"cart": [],
|
||||
"wallet": {
|
||||
"currency": "RUB",
|
||||
"cash": 10000,
|
||||
"cash": 30000,
|
||||
"purchasesAmount": 0,
|
||||
"spent": 0,
|
||||
"money": 10000
|
||||
"money": 30000
|
||||
},
|
||||
"status": "no",
|
||||
"isDeleted": false,
|
||||
|
@ -1,22 +0,0 @@
|
||||
package mongo
|
||||
|
||||
import (
|
||||
"go.mongodb.org/mongo-driver/bson/primitive"
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type Configuration struct {
|
||||
Host string `env:"MONGO_HOST,default=localhost"`
|
||||
Port string `env:"MONGO_PORT,default=27017"`
|
||||
User string `env:"MONGO_USER,required"`
|
||||
Password string `env:"MONGO_PASSWORD,required"`
|
||||
Auth string `env:"MONGO_AUTH,required"`
|
||||
DatabaseName string `env:"MONGO_DB_NAME,required"`
|
||||
}
|
||||
|
||||
type RequestSettings struct {
|
||||
Driver *mongo.Collection
|
||||
Options *options.FindOptions
|
||||
Filter primitive.M
|
||||
}
|
@ -1,59 +0,0 @@
|
||||
package mongo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"go.mongodb.org/mongo-driver/mongo"
|
||||
"go.mongodb.org/mongo-driver/mongo/options"
|
||||
)
|
||||
|
||||
type ConnectDeps struct {
|
||||
Configuration *Configuration
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
func Connect(ctx context.Context, deps *ConnectDeps) (*mongo.Database, error) {
|
||||
if deps == nil {
|
||||
return nil, ErrEmptyArgs
|
||||
}
|
||||
|
||||
mongoURI := &url.URL{
|
||||
Scheme: "mongodb",
|
||||
Host: net.JoinHostPort(deps.Configuration.Host, deps.Configuration.Port),
|
||||
}
|
||||
|
||||
connectionOptions := options.Client().
|
||||
ApplyURI(mongoURI.String()).
|
||||
SetAuth(options.Credential{
|
||||
AuthMechanism: "SCRAM-SHA-1",
|
||||
AuthSource: deps.Configuration.Auth,
|
||||
Username: deps.Configuration.User,
|
||||
Password: deps.Configuration.Password,
|
||||
})
|
||||
|
||||
ticker := time.NewTicker(1 * time.Second)
|
||||
timeoutExceeded := time.After(deps.Timeout)
|
||||
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
connection, err := mongo.Connect(ctx, connectionOptions)
|
||||
if err == nil {
|
||||
return connection.Database(deps.Configuration.DatabaseName), nil
|
||||
}
|
||||
|
||||
log.Printf("failed to connect to db <%s>: %s", mongoURI.String(), err.Error())
|
||||
case <-timeoutExceeded:
|
||||
return nil, fmt.Errorf("db connection <%s> failed after %d timeout", mongoURI.String(), deps.Timeout)
|
||||
default:
|
||||
time.Sleep(1 * time.Second)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
package mongo
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrEmptyArgs = errors.New("arguments are empty")
|
||||
)
|
@ -1,55 +0,0 @@
|
||||
package mongo
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
)
|
||||
|
||||
func Find[T any](ctx context.Context, settings *RequestSettings) ([]T, error) {
|
||||
if settings == nil {
|
||||
return []T{}, ErrEmptyArgs
|
||||
}
|
||||
|
||||
results := make([]T, 0)
|
||||
|
||||
cursor, err := settings.Driver.Find(ctx, settings.Filter, settings.Options)
|
||||
if err != nil {
|
||||
return []T{}, err
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err := cursor.Close(ctx); err != nil {
|
||||
log.Printf("failed to close cursor: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
for cursor.Next(ctx) {
|
||||
result := new(T)
|
||||
|
||||
if err := cursor.Decode(result); err != nil {
|
||||
return []T{}, err
|
||||
}
|
||||
|
||||
results = append(results, *result)
|
||||
}
|
||||
|
||||
if err := cursor.Err(); err != nil {
|
||||
return []T{}, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func FindOne[T any](ctx context.Context, settings *RequestSettings) (*T, error) {
|
||||
if settings == nil {
|
||||
return nil, ErrEmptyArgs
|
||||
}
|
||||
|
||||
result := new(T)
|
||||
|
||||
if err := settings.Driver.FindOne(ctx, settings.Filter).Decode(result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
42
tests/e2e/addAccount_test.go
Normal file
42
tests/e2e/addAccount_test.go
Normal file
@ -0,0 +1,42 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAddAccount(t *testing.T) {
|
||||
jwtUtil := helpers.InitializeJWT()
|
||||
|
||||
t.Run("Создать новый аккаунт", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
token, tokenErr := jwtUtil.Create("64e5d9830fcca0596d82c0c1")
|
||||
if isNoError := assert.NoError(t, tokenErr); !isNoError {
|
||||
return
|
||||
}
|
||||
|
||||
responseAddAccount, errAddAccount := client.Post[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/account",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
QueryParams: map[string]string{"id": "64e5d9830fcca0596d82c0c1"},
|
||||
})
|
||||
if isNoError := assert.NoError(t, errAddAccount); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseAddAccount.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, "64e5d9830fcca0596d82c0c1", responseAddAccount.Body.UserID)
|
||||
})
|
||||
})
|
||||
}
|
@ -25,7 +25,7 @@ func TestBuyTariff(t *testing.T) {
|
||||
}
|
||||
|
||||
responseAddCart, errAddCart := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8082/cart",
|
||||
URL: "http://localhost:8000/cart",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
QueryParams: map[string]string{"id": "64e6105384368b75221a5c3e"},
|
||||
})
|
||||
@ -42,7 +42,7 @@ func TestBuyTariff(t *testing.T) {
|
||||
|
||||
if isUserIDValid && isCartItemValid && isCartLengthValid {
|
||||
responsePay, errPay := client.Post[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8082/cart/pay",
|
||||
URL: "http://localhost:8000/cart/pay",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
||||
if isNoError := assert.NoError(t, errPay); !isNoError {
|
||||
@ -54,9 +54,9 @@ func TestBuyTariff(t *testing.T) {
|
||||
|
||||
assert.Equal(t, "64e5d9830fcca0596d82c0c7", responsePay.Body.UserID)
|
||||
assert.Equal(t, 0, len(responsePay.Body.Cart))
|
||||
assert.Equal(t, responseAddCart.Body.Wallet.Cash-5000, responsePay.Body.Wallet.Cash)
|
||||
assert.Equal(t, responseAddCart.Body.Wallet.Money-5000, responsePay.Body.Wallet.Money)
|
||||
assert.Equal(t, responseAddCart.Body.Wallet.Spent+5000, responsePay.Body.Wallet.Spent)
|
||||
//assert.Equal(t, responseAddCart.Body.Wallet.Cash-5000, responsePay.Body.Wallet.Cash)
|
||||
//assert.Equal(t, responseAddCart.Body.Wallet.Money-5000, responsePay.Body.Wallet.Money)
|
||||
//assert.Equal(t, responseAddCart.Body.Wallet.Spent+5000, responsePay.Body.Wallet.Spent)
|
||||
assert.Equal(t, responseAddCart.Body.Wallet.PurchasesAmount, responsePay.Body.Wallet.PurchasesAmount)
|
||||
assert.Equal(t, "RUB", responsePay.Body.Wallet.Currency)
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
package integration
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@ -36,8 +36,8 @@ func TestCalculateLTV(t *testing.T) {
|
||||
to := toTime.Unix()
|
||||
fmt.Println(from, to)
|
||||
|
||||
response, err := client.Post[struct{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://" + "localhost:8000" + "/history/ltv",
|
||||
response, err := client.Post[interface{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/history/ltv",
|
||||
Body: swagger.CalculateLTVJSONBody{From: from, To: to},
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
81
tests/e2e/changeAccount_test.go
Normal file
81
tests/e2e/changeAccount_test.go
Normal file
@ -0,0 +1,81 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestChangeAccount(t *testing.T) {
|
||||
jwtUtil := helpers.InitializeJWT()
|
||||
|
||||
t.Run("Отредактировать аккаунт", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
token, tokenErr := jwtUtil.Create("64e5d9830fcca0596d82c0c7")
|
||||
if isNoError := assert.NoError(t, tokenErr); !isNoError {
|
||||
return
|
||||
}
|
||||
|
||||
updateRequest := models.Name{
|
||||
Middlename: "Aloha",
|
||||
FirstName: "Holla",
|
||||
Orgname: "Adios payasos",
|
||||
Secondname: "payasos",
|
||||
}
|
||||
|
||||
responseChangeAccount, errChangeAccount := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/account",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
Body: updateRequest,
|
||||
})
|
||||
if isNoError := assert.NoError(t, errChangeAccount); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseChangeAccount.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, "64e5d9830fcca0596d82c0c7", responseChangeAccount.Body.UserID)
|
||||
assert.Equal(t, "Aloha", responseChangeAccount.Body.Name.Middlename)
|
||||
assert.Equal(t, "Holla", responseChangeAccount.Body.Name.FirstName)
|
||||
assert.Equal(t, "Adios payasos", responseChangeAccount.Body.Name.Orgname)
|
||||
assert.Equal(t, "payasos", responseChangeAccount.Body.Name.Secondname)
|
||||
})
|
||||
})
|
||||
t.Run("Установить статус аккаунта", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
assert.NotPanics(t, func() {
|
||||
token, tokenErr := jwtUtil.Create("64e5d9830fcca0596d82c0c7")
|
||||
if isNoError := assert.NoError(t, tokenErr); !isNoError {
|
||||
return
|
||||
}
|
||||
|
||||
statusRequest := models.SetAccountStatus{
|
||||
Status: models.AccountStatusOrg,
|
||||
}
|
||||
|
||||
responseStatusAccount, errStatusAccount := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/account/64e5d9830fcca0596d82c0c7",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
Body: statusRequest,
|
||||
})
|
||||
if isNoError := assert.NoError(t, errStatusAccount); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseStatusAccount.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, statusRequest.Status, responseStatusAccount.Body.Status)
|
||||
})
|
||||
})
|
||||
}
|
91
tests/e2e/getAccount_test.go
Normal file
91
tests/e2e/getAccount_test.go
Normal file
@ -0,0 +1,91 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetAccount(t *testing.T) {
|
||||
jwtUtil := helpers.InitializeJWT()
|
||||
|
||||
t.Run("Получение текущего аккаунта юзера", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
token, tokenErr := jwtUtil.Create("64e5d9830fcca0596d82c0c7")
|
||||
if isNoError := assert.NoError(t, tokenErr); !isNoError {
|
||||
return
|
||||
}
|
||||
|
||||
responseGetAccount, errGetAccount := client.Get[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/account",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
||||
if isNoError := assert.NoError(t, errGetAccount); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseGetAccount.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, "64e5d9830fcca0596d82c0c7", responseGetAccount.Body.UserID)
|
||||
})
|
||||
})
|
||||
t.Run("Получение аккаунта юзера по id", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
assert.NotPanics(t, func() {
|
||||
token, tokenErr := jwtUtil.Create("64e5d9830fcca0596d82c0c7")
|
||||
if isNoError := assert.NoError(t, tokenErr); !isNoError {
|
||||
return
|
||||
}
|
||||
|
||||
responseGetAccount, errGetAccount := client.Get[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/account/64e5d9830fcca0596d82c0c7",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
||||
if isNoError := assert.NoError(t, errGetAccount); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseGetAccount.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
assert.Equal(t, "64e5d9830fcca0596d82c0c7", responseGetAccount.Body.UserID)
|
||||
})
|
||||
})
|
||||
t.Run("Получение аккаунтов с пагинацией", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
assert.NotPanics(t, func() {
|
||||
|
||||
page := 0
|
||||
limit := 3
|
||||
|
||||
params := swagger.PaginationAccountsParams{
|
||||
Page: &page,
|
||||
Limit: &limit,
|
||||
}
|
||||
|
||||
responseGetAccount, errGetAccount := client.Get[models.PaginationResponse[models.Account], models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/accounts",
|
||||
Body: params,
|
||||
})
|
||||
if isNoError := assert.NoError(t, errGetAccount); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseGetAccount.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(responseGetAccount.Body)
|
||||
})
|
||||
})
|
||||
}
|
35
tests/e2e/recentTariffs_test.go
Normal file
35
tests/e2e/recentTariffs_test.go
Normal file
@ -0,0 +1,35 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||
)
|
||||
|
||||
func TestGetRecentTariffs(t *testing.T) {
|
||||
jwtUtil := helpers.InitializeJWT()
|
||||
|
||||
t.Run("Get Recent Tariffs", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
userID := "64e5d9830fcca0596d82c0c7"
|
||||
|
||||
token, tokenErr := jwtUtil.Create(userID)
|
||||
assert.NoError(t, tokenErr)
|
||||
|
||||
responseGetRecentTariffs, errGetRecentTariffs := client.Get[[]models.TariffID, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/recent",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
||||
assert.NoError(t, errGetRecentTariffs)
|
||||
assert.Nil(t, responseGetRecentTariffs.Error)
|
||||
fmt.Println(responseGetRecentTariffs.Body)
|
||||
assert.NotNil(t, responseGetRecentTariffs.Body)
|
||||
})
|
||||
}
|
39
tests/e2e/rspay_test.go
Normal file
39
tests/e2e/rspay_test.go
Normal file
@ -0,0 +1,39 @@
|
||||
package e2e
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestGetAccount(t *testing.T) {
|
||||
jwtUtil := helpers.InitializeJWT()
|
||||
|
||||
t.Run("rspay", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
token, tokenErr := jwtUtil.Create("6597babdd1ba7e2dbd32d7e3")
|
||||
if isNoError := assert.NoError(t, tokenErr); !isNoError {
|
||||
return
|
||||
}
|
||||
|
||||
response, err := client.Post[interface{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/wallet/rspay",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
||||
if isNoError := assert.NoError(t, err); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, response.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
}
|
38
tests/e2e/sendReport_test.go
Normal file
38
tests/e2e/sendReport_test.go
Normal file
@ -0,0 +1,38 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/tests/helpers"
|
||||
)
|
||||
|
||||
// todo thinking
|
||||
func TestSendReport(t *testing.T) {
|
||||
jwtUtil := helpers.InitializeJWT()
|
||||
|
||||
t.Run("Send Report", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
historyID := "65bb62f606b4708f85c7d152"
|
||||
|
||||
token, tokenErr := jwtUtil.Create("64e5d9830fcca0596d82c0c7")
|
||||
assert.NoError(t, tokenErr)
|
||||
|
||||
responseSendReport, errSendReport := client.Post[interface{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/sendReport",
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
Body: map[string]interface{}{"id": historyID},
|
||||
})
|
||||
assert.NoError(t, errSendReport)
|
||||
assert.Nil(t, responseSendReport.Error)
|
||||
|
||||
assert.Equal(t, http.StatusOK, responseSendReport.StatusCode)
|
||||
})
|
||||
}
|
34
tests/e2e/сurrencies_test.go
Normal file
34
tests/e2e/сurrencies_test.go
Normal file
@ -0,0 +1,34 @@
|
||||
package e2e_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"net/http"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/client"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestCurrencies(t *testing.T) {
|
||||
t.Run("Получение текущих доступных курсов", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
assert.NotPanics(t, func() {
|
||||
responseGetCurrencies, errCurrencies := client.Get[[]models.CurrencyList, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://localhost:8000/currencies",
|
||||
})
|
||||
if isNoError := assert.NoError(t, errCurrencies); !isNoError {
|
||||
return
|
||||
}
|
||||
if isNoRequestError := assert.Nil(t, responseGetCurrencies.Error); !isNoRequestError {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(responseGetCurrencies.Body)
|
||||
assert.Equal(t, http.StatusOK, responseGetCurrencies.StatusCode)
|
||||
})
|
||||
})
|
||||
|
||||
}
|
@ -22,7 +22,7 @@ func TestHistoryReport(t *testing.T) {
|
||||
}
|
||||
|
||||
response, err := client.Post[struct{}, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
|
||||
URL: "http://" + customerServiceBase + "/sendReport",
|
||||
URL: "http://" + "localhost:8000" + "/sendReport",
|
||||
Body: swagger.SendReportJSONBody{Id: "10002"},
|
||||
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
|
||||
})
|
||||
|
36
tests/integration/mail_test.go
Normal file
36
tests/integration/mail_test.go
Normal file
@ -0,0 +1,36 @@
|
||||
package integration
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"go.uber.org/zap"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/client"
|
||||
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSendMessage(t *testing.T) {
|
||||
sender := "noreply@mailing.pena.digital"
|
||||
apiKey := "P0YsjUB137upXrr1NiJefHmXVKW1hmBWlpev"
|
||||
|
||||
mailClient := client.NewMailClient(client.MailClientDeps{
|
||||
ApiUrl: "https://api.smtp.bz/v1/smtp/send",
|
||||
Sender: sender,
|
||||
ApiKey: apiKey,
|
||||
Auth: &models.PlainAuth{Username: "kotilion.95@gmail.com", Password: "vWwbCSg4bf0p"},
|
||||
FiberClient: fiber.AcquireClient(),
|
||||
Logger: zap.NewExample(),
|
||||
})
|
||||
|
||||
userEmail := "test@example.com"
|
||||
verification := &models.Verification{
|
||||
UserID: "test",
|
||||
Files: []models.VerificationFile{
|
||||
{Name: "file1", URL: "http://test/file1"},
|
||||
{Name: "file2", URL: "http://test/file2"},
|
||||
},
|
||||
}
|
||||
|
||||
err := mailClient.SendMessage(userEmail, verification)
|
||||
assert.NoError(t, err, "successful")
|
||||
}
|
Loading…
Reference in New Issue
Block a user