add rspay logic

This commit is contained in:
Pavel 2024-02-05 15:24:56 +03:00
commit da7fe4c4d6
19 changed files with 514 additions and 125 deletions

@ -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:

@ -4,8 +4,6 @@ import (
"encoding/json"
"fmt"
"log"
"os"
"path/filepath"
"go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/app"
@ -17,15 +15,8 @@ func main() {
if err != nil {
log.Fatalf("failed to init zap logger: %v", err)
}
// todo убрать
currentDir, err := os.Getwd()
if err != nil {
logger.Fatal("failed to get current directory: %v", zap.Error(err))
}
envFilePath := filepath.Join(currentDir, "deployments", "local", ".env.test")
config, err := initialize.Configuration(envFilePath)
config, err := initialize.Configuration(".env.test")
if err != nil {
logger.Fatal("failed to init config: %v", zap.Error(err))
}

@ -4,7 +4,7 @@ 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=8000
HTTP_PORT=8003
GRPC_HOST=0.0.0.0
GRPC_PORT=9000
@ -20,10 +20,16 @@ MONGO_AUTH=admin
KAFKA_BROKERS=localhost:9092
KAFKA_TOPIC_TARIFF=tariffs
AUTH_MICROSERVICE_USER_URL=http://localhost:8002/user
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
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

18
go.mod

@ -6,6 +6,7 @@ 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
@ -24,6 +25,7 @@ require (
)
require (
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-openapi/jsonpointer v0.19.6 // indirect
@ -31,34 +33,38 @@ require (
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/uuid v1.4.0 // indirect
github.com/google/uuid v1.5.0 // indirect
github.com/gorilla/mux v1.8.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.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/pmezard/go-difflib v1.0.0 // 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.2 // indirect
github.com/xdg-go/stringprep v1.0.4 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // 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.14.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
)

36
go.sum

@ -1,6 +1,8 @@
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=
@ -33,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=
@ -55,8 +59,8 @@ 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.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/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=
@ -71,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=
@ -97,6 +101,8 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
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=
@ -113,6 +119,8 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
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/sethvargo/go-envconfig v0.9.0 h1:Q6FQ6hVEeTECULvkJZakq3dZMeBQ3JUpcKMfPQbKMDE=
@ -145,9 +153,13 @@ github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4d
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.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY=
@ -176,8 +188,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U
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=
@ -198,8 +210,8 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v
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.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
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.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=
@ -225,8 +237,8 @@ golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.14.0 h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=
golang.org/x/sys v0.14.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
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=
@ -235,8 +247,8 @@ 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.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
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.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=

@ -75,6 +75,7 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) {
PaymentServiceConfiguration: &config.Service.PaymentMicroservice,
VerificationURL: &config.Service.VerificationMicroservice.URL,
TemplategenURL: &config.Service.TemplategenMicroserviceURL.URL,
MailClient: &config.Service.Mail,
})
repositories := initialize.NewRepositories(initialize.RepositoriesDeps{

@ -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(),
}),
}
}

@ -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{

@ -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": "pashamullin202@gmail.com",
"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)
}

@ -46,6 +46,7 @@ type clients struct {
payment *client.PaymentClient
verify *client.VerificationClient
template *client.TemplateClient
mail *client.MailClient
}
var _ ServerInterface = (*API2)(nil)
@ -597,7 +598,6 @@ func (api *API2) ChangeCurrency(ctx echo.Context) error {
return ctx.JSON(http.StatusOK, updatedAccount)
}
// todo need tests
func (api *API2) CalculateLTV(ctx echo.Context) error {
var req CalculateLTVJSONBody
@ -749,3 +749,41 @@ func (api *API2) SendReport(ctx echo.Context) error {
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,87 +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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",
"WKMkDmpVAAA=",
"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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)
}

@ -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"`
}

@ -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
}

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
}
})
})
}

@ -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")
}