feat: filter history by type

This commit is contained in:
Kirill 2023-09-14 10:07:28 +00:00
parent c7ad0d8795
commit d8bba38774
47 changed files with 607 additions and 426 deletions

@ -1,27 +0,0 @@
HTTP_HOST=0.0.0.0
HTTP_PORT=8082
GRPC_HOST=0.0.0.0
GRPC_PORT=9082
GRPC_DOMEN=customer-app:9082
MONGO_HOST=mongo
MONGO_PORT=27017
MONGO_USER=test
MONGO_PASSWORD=test
MONGO_DB_NAME=admin
MONGO_AUTH=admin
AUTH_MICROSERVICE_USER_URL=http://pena-auth-service:8000/user
HUBADMIN_MICROSERVICE_TARIFF_URL=http://hub-admin-service:8010/tariff
CURRENCY_MICROSERVICE_TRANSLATE_URL=http://cbrf-service:8020/translate
DISCOUNT_MICROSERVICE_GRPC_HOST=discount-service:9040
PAYMENT_MICROSERVICE_GRPC_HOST=treasurer-service:9085
KAFKA_BROKERS=localhost:8080,localhost:1111
KAFKA_TOPIC_TARIFF=tariff
# JWT settings
JWT_ISSUER="pena-auth-service"
JWT_AUDIENCE="pena"
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm6980fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6BdA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y+3GyaOY536H47qyXAgMBAAE=\n-----END PUBLIC KEY-----"

@ -1,72 +1,54 @@
# BUILD # BUILD
FROM golang:1.20.3-alpine AS build FROM golang:1.20.3-alpine AS build
# Update depences # Update packages and clear cache
RUN apk update && apk add --no-cache curl RUN apk update && apk add --no-cache curl && rm -rf /var/cache/apk/*
# Create build directory # Set work directory
RUN mkdir /app/bin -p
RUN mkdir /bin/golang-migrate -p
# Download migrate app
RUN GOLANG_MIGRATE_VERSION=v4.15.1 && \
curl -L https://github.com/golang-migrate/migrate/releases/download/${GOLANG_MIGRATE_VERSION}/migrate.linux-amd64.tar.gz |\
tar xvz migrate -C /bin/golang-migrate
# Download health check utility
RUN GRPC_HEALTH_PROBE_VERSION=v0.4.6 && \
wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \
chmod +x /bin/grpc_health_probe
# Download debugger
# Set home directory
WORKDIR /app WORKDIR /app
# Copy go.mod # Create binary directory
ADD go.mod go.sum /app/ RUN mkdir /app/bin -p
# Create golang migrate util directory
RUN mkdir /bin/golang-migrate -p
# Add migrate tool
ADD ./tools/migrate /bin/golang-migrate/
# Add main files to app
ADD . .
# Download go depences # Download go depences
RUN go mod download RUN go mod download
# Copy all local files
ADD . /app
# Build app # Build app
RUN GOOS=linux go build -o bin ./... RUN GOOS=linux go build -o bin ./...
# TEST # TEST
FROM alpine:latest AS test FROM alpine:3.18.3 AS test
# Install packages # Install packages
RUN apk --no-cache add ca-certificates RUN apk --no-cache add ca-certificates && rm -rf /var/cache/apk/*
# Set GO111MODULE env
ENV GO111MODULE=off ENV GO111MODULE=off
# Create home directory # Create home directory
WORKDIR /app WORKDIR /app
# Copy build file # Copy build file
COPY --from=build /app/bin/app ./app COPY --from=build /app/bin/app ./app
# CMD
CMD [ "./app" ]
# MIGRATION
FROM alpine:latest AS migration
# Install packages
RUN apk --no-cache add ca-certificates
# Create home directory
WORKDIR /app
# Copy migration dir # Copy migration dir
COPY --from=build /app/migrations/test ./migrations COPY --from=build /app/migrations/test ./migrations
# Install migrate tool # Install migrate tool
COPY --from=build /bin/golang-migrate /usr/local/bin COPY --from=build /bin/golang-migrate /usr/local/bin
# CMD
CMD [ "./app" ]
# PRODUCTION # PRODUCTION
FROM alpine:latest AS production FROM alpine:3.18.3 AS production
# Install packages # Install packages
RUN apk --no-cache add ca-certificates RUN apk --no-cache add ca-certificates && rm -rf /var/cache/apk/*
# Create home directory # Create home directory
WORKDIR /app WORKDIR /app
# Copy build file # Copy build file
COPY --from=build /app/bin/app ./app COPY --from=build /app/bin/app ./app
# Copy grpc health probe dir
COPY --from=build /bin/grpc_health_probe /bin/grpc_health_probe
# Install migrate tool # Install migrate tool
COPY --from=build /bin/golang-migrate /usr/local/bin COPY --from=build /bin/golang-migrate /usr/local/bin
# CMD # CMD

@ -14,7 +14,8 @@ install: ## install all go dependencies
generate: ## generate grpc proto for golang generate: ## generate grpc proto for golang
buf generate buf generate
go generate ./internal/interface/swagger oapi-codegen --config ./api/openapi/v1/api.yaml ./api/openapi/v1/openapi.yaml
oapi-codegen --config ./api/openapi/v1/models.yaml ./api/openapi/v1/openapi.yaml
test: ## run all layers tests test: ## run all layers tests
@make test.unit @make test.unit
@ -29,13 +30,16 @@ test.integration: ## run integration tests
@make test.integration.down @make test.integration.down
test.integration.up: ## build integration test environment test.integration.up: ## build integration test environment
docker-compose -f deployments/test/docker-compose.yaml --env-file ./.env.test up -d docker-compose -f deployments/test/docker-compose.yaml up -d
test.integration.start: ## run integration test
go test -tags integration ./tests/integration/...
test.integration.down: ## shutting down integration environment test.integration.down: ## shutting down integration environment
docker-compose -f deployments/test/docker-compose.yaml --env-file ./.env.test down --volumes --rmi local docker-compose -f deployments/test/docker-compose.yaml down --volumes --rmi local
test.integration.start: ## run integration test
go test ./tests/integration/...
test.e2e.start: ## run integration test
go test ./tests/e2e/...
run: ## run app run: ## run app
go run ./cmd/app/main.go go run ./cmd/app/main.go

@ -1,4 +1,4 @@
output: api.gen.go output: ./internal/interface/swagger/api.gen.go
package: swagger package: swagger
generate: generate:
echo-server: true echo-server: true

@ -0,0 +1,4 @@
output: ./internal/interface/swagger/models.gen.go
package: swagger
generate:
models: true

@ -544,6 +544,13 @@ paths:
schema: schema:
type: integer type: integer
default: 100 default: 100
- name: type
in: query
description: Тип события
required: false
explode: false
schema:
type: string
responses: responses:
'200': '200':
description: Успешное получение событий description: Успешное получение событий

@ -1,3 +1,3 @@
version: v1 version: v1
directories: directories:
- proto - api/proto

@ -1,27 +1,4 @@
# HTTP settings
HTTP_HOST=0.0.0.0
HTTP_PORT=8080
# MONGO settings
MONGO_HOST=localhost
MONGO_PORT=27017
MONGO_USER=test
MONGO_PASSWORD=test
MONGO_AUTH=admin
MONGO_DB_NAME=admin
# Auth Microservice settings
AUTH_MICROSERVICE_USER_URL=http://localhost:8000/user
# Hub Admin Microservice settings
HUBADMIN_MICROSERVICE_TARIFF_URL=http://localhost:8001/tariff
# Currency Microservice settings
CURRENCY_MICROSERVICE_TRANSLATE_URL=http://localhost:8002/change
# Admin
# JWT settings # JWT settings
JWT_ISSUER="pena-auth-service" JWT_ISSUER="pena-auth-service"
JWT_AUDIENCE="pena" JWT_AUDIENCE="pena"
JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyt4XuLovUY7i12K2PIMbQZOKn+wFFKUvxvKQDel049/+VMpHMx1FLolUKuyGp9zi6gOwjHsBPgc9oqr/eaXGQSh7Ult7i9f+Ht563Y0er5UU9Zc5ZPSxf9O75KYD48ruGkqiFoncDqPENK4dtUa7w0OqlN4bwVBbmIsP8B3EDC5Dof+vtiNTSHSXPx+zifKeZGyknp+nyOHVrRDhPjOhzQzCom0MSZA/sJYmps8QZgiPA0k4Z6jTupDymPOIwYeD2C57zSxnAv0AfC3/pZYJbZYH/0TszRzmy052DME3zMnhMK0ikdN4nzYqU0dkkA5kb5GtKDymspHIJ9eWbUuwgtg8Rq/LrVBj1I3UFgs0ibio40k6gqinLKslc5Y1I5mro7J3OSEP5eO/XeDLOLlOJjEqkrx4fviI1cL3m5L6QV905xmcoNZG1+RmOg7D7cZQUf27TXqM381jkbNdktm1JLTcMScxuo3vaRftnIVw70V8P8sIkaKY8S8HU1sQgE2LB9t04oog5u59htx2FHv4B13NEm8tt8Tv1PexpB4UVh7PIualF6SxdFBrKbraYej72wgjXVPQ0eGXtGGD57j8DUEzk7DK2OvIWhehlVqtiRnFdAvdBj2ynHT2/5FJ/Zpd4n5dKGJcQvy1U1qWMs+8M7AHfWyt2+nZ04s48+bK3yMCAwEAAQ==\n-----END PUBLIC KEY-----" JWT_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69\n80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B\ndA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y\n+3GyaOY536H47qyXAgMBAAE=\n-----END PUBLIC KEY-----"

@ -1,7 +1,11 @@
version: "3" version: "3"
volumes:
redpanda: null
services: services:
app: customer-service:
container_name: customer-service
build: build:
context: ../../. context: ../../.
dockerfile: Dockerfile dockerfile: Dockerfile
@ -10,59 +14,162 @@ services:
- .env.test - .env.test
environment: environment:
- HTTP_HOST=0.0.0.0 - HTTP_HOST=0.0.0.0
- HTTP_PORT=8082 - HTTP_PORT=8000
- GRPC_HOST=0.0.0.0 - GRPC_HOST=0.0.0.0
- GRPC_PORT=9082 - GRPC_PORT=9000
- GRPC_DOMEN=customer-app:9082 - GRPC_DOMEN=customer-service:9000
- MONGO_HOST=mongo - MONGO_HOST=customer-db
- MONGO_PORT=27017 - MONGO_PORT=27017
- MONGO_USER=test - MONGO_USER=test
- MONGO_PASSWORD=test - MONGO_PASSWORD=test
- MONGO_DB_NAME=admin - MONGO_DB_NAME=admin
- MONGO_AUTH=admin - MONGO_AUTH=admin
- JWT_ISSUER=issuer - KAFKA_BROKERS=customer-redpanda:9092
- JWT_AUDIENCE=audience - KAFKA_TOPIC_TARIFF=tariffs
- AUTH_MICROSERVICE_USER_URL=http://pena-auth-service:8000/user - AUTH_MICROSERVICE_USER_URL=http://pena-auth-service:8000/user
- HUBADMIN_MICROSERVICE_TARIFF_URL=http://hub-admin-service:8010/tariff - HUBADMIN_MICROSERVICE_TARIFF_URL=http://hub-admin-backend-service:8000/tariff
- CURRENCY_MICROSERVICE_TRANSLATE_URL=http://cbrf-service:8020/translate - CURRENCY_MICROSERVICE_TRANSLATE_URL=http://cbrfworker-service:8000/change
- DISCOUNT_MICROSERVICE_GRPC_HOST=discount-service:9040 - DISCOUNT_MICROSERVICE_GRPC_HOST=discount-service:9000
- PAYMENT_MICROSERVICE_GRPC_HOST=treasurer-service:9085 - PAYMENT_MICROSERVICE_GRPC_HOST=treasurer-service:9085
ports: ports:
- 8082:8082 - 8082:8000
- 9092:9000
depends_on: depends_on:
- migration - customer-db
- customer-migration
- redpanda
networks: networks:
- integration_test - test
migration: customer-migration:
container_name: customer-migration
build: build:
context: ../../. context: ../../.
dockerfile: Dockerfile dockerfile: Dockerfile
target: migration target: test
command: command:
[ [
"sh", "sh",
"-c", "-c",
'migrate -source file://migrations -database "mongodb://test:test@mongo:27017/admin?authSource=admin" up', 'migrate -source file://migrations -database "mongodb://test:test@customer-db:27017/admin?authSource=admin" up',
] ]
depends_on: depends_on:
- mongo - customer-db
networks: networks:
- integration_test - test
mongo: customer-db:
image: 'mongo:6.0.3' container_name: customer-db
image: "mongo:6.0.3"
environment: environment:
MONGO_INITDB_ROOT_USERNAME: test MONGO_INITDB_ROOT_USERNAME: test
MONGO_INITDB_ROOT_PASSWORD: test MONGO_INITDB_ROOT_PASSWORD: test
ports: ports:
- '27017:27017' - "27024:27017"
networks: networks:
- integration_test - test
redpanda:
container_name: customer-redpanda
tty: true
image: docker.redpanda.com/redpandadata/redpanda:v23.1.13
command:
- redpanda start
- --smp 1
- --overprovisioned
- --kafka-addr internal://0.0.0.0:9092,external://0.0.0.0:19092
# Address the broker advertises to clients that connect to the Kafka API.
# Use the internal addresses to connect to the Redpanda brokers
# from inside the same Docker network.
# Use the external addresses to connect to the Redpanda brokers
# from outside the Docker network.
- --advertise-kafka-addr internal://redpanda:9092,external://localhost:19092
- --pandaproxy-addr internal://0.0.0.0:8082,external://0.0.0.0:18082
# Address the broker advertises to clients that connect to the HTTP Proxy.
- --advertise-pandaproxy-addr internal://redpanda:8082,external://localhost:18082
- --schema-registry-addr internal://0.0.0.0:8081,external://0.0.0.0:18081
# Redpanda brokers use the RPC API to communicate with each other internally.
- --rpc-addr redpanda:33145
- --advertise-rpc-addr redpanda:33145
ports:
- 18081:18081
- 18082:18082
- 19092:19092
- 19644:9644
volumes:
- redpanda:/var/lib/redpanda/data
networks:
- test
healthcheck:
test: ["CMD-SHELL", "rpk cluster health | grep -E 'Healthy:.+true' || exit 1"]
interval: 15s
timeout: 3s
retries: 5
start_period: 5s
console:
tty: true
image: docker.redpanda.com/redpandadata/console:v2.2.4
entrypoint: /bin/sh
command: -c "echo \"$$CONSOLE_CONFIG_FILE\" > /tmp/config.yml; /app/console"
environment:
CONFIG_FILEPATH: /tmp/config.yml
CONSOLE_CONFIG_FILE: |
kafka:
brokers: ["redpanda:9092"]
schemaRegistry:
enabled: true
urls: ["http://redpanda:8081"]
redpanda:
adminApi:
enabled: true
urls: ["http://redpanda:9644"]
connect:
enabled: true
clusters:
- name: local-connect-cluster
url: http://connect:8083
ports:
- 8080:8080
networks:
- test
depends_on:
- redpanda
connect:
tty: true
image: docker.redpanda.com/redpandadata/connectors:latest
hostname: connect
container_name: connect
networks:
- test
# platform: 'linux/amd64'
depends_on:
- redpanda
ports:
- "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
CONNECT_BOOTSTRAP_SERVERS: redpanda:9092
CONNECT_GC_LOG_ENABLED: "false"
CONNECT_HEAP_OPTS: -Xms512M -Xmx512M
CONNECT_LOG_LEVEL: info
networks: networks:
integration_test: test:

21
go.mod

@ -9,16 +9,17 @@ require (
github.com/golang-jwt/jwt/v5 v5.0.0 github.com/golang-jwt/jwt/v5 v5.0.0
github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 github.com/grpc-ecosystem/go-grpc-middleware v1.4.0
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/labstack/echo/v4 v4.10.2 github.com/labstack/echo/v4 v4.11.1
github.com/oapi-codegen/runtime v1.0.0
github.com/sethvargo/go-envconfig v0.9.0 github.com/sethvargo/go-envconfig v0.9.0
github.com/stretchr/testify v1.8.2 github.com/stretchr/testify v1.8.4
github.com/twmb/franz-go v1.13.6 github.com/twmb/franz-go v1.13.6
github.com/twmb/franz-go/pkg/kadm v1.8.1 github.com/twmb/franz-go/pkg/kadm v1.8.1
go.mongodb.org/mongo-driver v1.11.4 go.mongodb.org/mongo-driver v1.11.4
go.uber.org/zap v1.24.0 go.uber.org/zap v1.24.0
google.golang.org/genproto v0.0.0-20230223222841-637eb2293923 google.golang.org/genproto v0.0.0-20230223222841-637eb2293923
google.golang.org/grpc v1.53.0 google.golang.org/grpc v1.53.0
google.golang.org/protobuf v1.30.0 google.golang.org/protobuf v1.31.0
) )
require ( require (
@ -31,16 +32,16 @@ require (
github.com/golang/protobuf v1.5.3 // indirect github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect github.com/golang/snappy v0.0.5-0.20220116011046-fa5810519dcb // indirect
github.com/google/go-cmp v0.5.9 // indirect github.com/google/go-cmp v0.5.9 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.1 // indirect
github.com/gorilla/mux v1.8.0 // indirect github.com/gorilla/mux v1.8.0 // indirect
github.com/invopop/yaml v0.1.0 // indirect github.com/invopop/yaml v0.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.16.5 // indirect github.com/klauspost/compress v1.16.7 // indirect
github.com/kr/pretty v0.3.1 // indirect github.com/kr/pretty v0.3.1 // indirect
github.com/labstack/gommon v0.4.0 // indirect github.com/labstack/gommon v0.4.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.18 // indirect github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/perimeterx/marshmallow v1.1.4 // indirect github.com/perimeterx/marshmallow v1.1.4 // indirect
@ -56,11 +57,11 @@ require (
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
go.uber.org/atomic v1.11.0 // indirect go.uber.org/atomic v1.11.0 // indirect
go.uber.org/multierr v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect
golang.org/x/crypto v0.9.0 // indirect golang.org/x/crypto v0.12.0 // indirect
golang.org/x/net v0.10.0 // indirect golang.org/x/net v0.14.0 // indirect
golang.org/x/sync v0.2.0 // indirect golang.org/x/sync v0.2.0 // indirect
golang.org/x/sys v0.8.0 // indirect golang.org/x/sys v0.11.0 // indirect
golang.org/x/text v0.9.0 // indirect golang.org/x/text v0.12.0 // indirect
golang.org/x/time v0.3.0 // indirect golang.org/x/time v0.3.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

44
go.sum

@ -57,8 +57,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.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 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI= github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= 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 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI=
@ -73,8 +73,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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= 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.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/compress v1.16.7/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/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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
@ -84,8 +84,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.10.2 h1:n1jAhnq/elIFTHr1EYpiYtyKgx4RW9ccVgkqByZaN2M= github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
github.com/labstack/echo/v4 v4.10.2/go.mod h1:OEyqf2//K1DFdE57vw2DRgWY0M7s65IVQO2FzvI4J5k= github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8= github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM= github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
@ -97,12 +97,14 @@ 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-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.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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.18 h1:DOKFKCQ7FNG2L1rbrmstDN4QVRdS89Nkh85u68Uwp98= github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.18/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= 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/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw= github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw= github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
@ -133,8 +135,8 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.7.1/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.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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 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 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= 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 h1:DRh06Hy3GthZuA+fQhDo+IMV+QUZHQfS2TIiWf/rCw8=
@ -145,8 +147,8 @@ github.com/twmb/franz-go/pkg/kmsg v1.4.0 h1:tbp9hxU6m8qZhQTlpGiaIJOm4BXix5lsuEZ7
github.com/twmb/franz-go/pkg/kmsg v1.4.0/go.mod h1:SxG/xJKhgPu25SamAq0rrucfp7lbzCpEXOC+vH/ELrY= github.com/twmb/franz-go/pkg/kmsg v1.4.0/go.mod h1:SxG/xJKhgPu25SamAq0rrucfp7lbzCpEXOC+vH/ELrY=
github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo= 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 v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY= 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/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= 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/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ= github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
@ -179,8 +181,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= golang.org/x/crypto v0.12.0 h1:tFM/ta59kqch6LlvYnPa0yx5a83cL2nHflFhYKvv9Yk=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= golang.org/x/crypto v0.12.0/go.mod h1:NF0Gs7EO5K4qLn+Ylc+fih8BSTeIjAP05siRnAh98yw=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -198,8 +200,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 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-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= golang.org/x/net v0.14.0 h1:BONx9s002vGdD9umnlX1Po8vOZmrgH34qlHcD1MfK14=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 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-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-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -223,15 +225,15 @@ golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/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-20220811171246-fbc7d0a398ab/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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= golang.org/x/sys v0.11.0 h1:eG7RXZHdqOJ1i+0lgLgCpSXAp6M3LYlAo6osgSi0xOM=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/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.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= 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/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -263,8 +265,8 @@ google.golang.org/grpc v1.53.0 h1:LAv2ds7cmFV/XTS3XG1NneeENYrXGmorPxsBbptIjNc=
google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw= google.golang.org/grpc v1.53.0/go.mod h1:OnIrk0ipVdj4N5d9IUoFUx72/VlD7+jUsHwZgwSMQpw=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=

@ -40,7 +40,7 @@ func Run(config *models.Config, logger *zap.Logger) (appErr error) {
if err := kafka.Initialize(ctx, config.Service.Kafka.Brokers, []string{ if err := kafka.Initialize(ctx, config.Service.Kafka.Brokers, []string{
config.Service.Kafka.Tariff.Topic, config.Service.Kafka.Tariff.Topic,
}); err != nil { }); err != nil {
return err return fmt.Errorf("failed initialize kafka: %w", err)
} }
mongoDB, err := mongo.Connect(ctx, &mongo.ConnectDeps{ mongoDB, err := mongo.Connect(ctx, &mongo.ConnectDeps{

@ -0,0 +1,25 @@
package dto
import (
"go.mongodb.org/mongo-driver/bson"
"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/pkg/bsontools"
)
type GetHistories struct {
Pagination *models.Pagination
Type *string
}
func (receiver *GetHistories) BSON() bson.M {
query := bson.M{
fields.History.IsDeleted: false,
}
if receiver.Type != nil {
query[fields.History.Type] = bsontools.BuildCaseInsensitiveRegex(*receiver.Type)
}
return query
}

@ -15,9 +15,9 @@ import (
) )
type cartService interface { type cartService interface {
Remove(ctx context.Context, userID, itemID string) ([]string, errors.Error) Remove(ctx context.Context, userID, itemID string) (*models.Account, errors.Error)
Add(context.Context, *models.AddItemToCart) ([]string, errors.Error) Add(context.Context, *models.AddItemToCart) (*models.Account, errors.Error)
Pay(ctx context.Context, token, userID string) errors.Error Pay(ctx context.Context, token, userID string) (*models.Account, errors.Error)
} }
type Deps struct { type Deps struct {
@ -114,10 +114,11 @@ func (receiver *Controller) Pay(ctx echo.Context) error {
return errors.HTTP(ctx, errors.NewWithMessage("failed to convert access token payload to string", errors.ErrInvalidArgs)) return errors.HTTP(ctx, errors.NewWithMessage("failed to convert access token payload to string", errors.ErrInvalidArgs))
} }
if err := receiver.cartService.Pay(ctx.Request().Context(), token, userID); err != nil { account, err := receiver.cartService.Pay(ctx.Request().Context(), token, userID)
if err != nil {
receiver.logger.Error("failed to pay cart on <Pay> of <CartController>", zap.Error(err)) receiver.logger.Error("failed to pay cart on <Pay> of <CartController>", zap.Error(err))
return errors.HTTP(ctx, err) return errors.HTTP(ctx, err)
} }
return ctx.JSON(http.StatusOK, true) return ctx.JSON(http.StatusOK, account)
} }

@ -7,13 +7,14 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"go.uber.org/zap" "go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/dto"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/interface/swagger" "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/internal/models"
) )
type historyService interface { type historyService interface {
GetHistoryList(context.Context, *models.Pagination) (*models.PaginationResponse[models.History], errors.Error) GetHistoryList(context.Context, *dto.GetHistories) (*models.PaginationResponse[models.History], errors.Error)
} }
type Deps struct { type Deps struct {
@ -42,9 +43,12 @@ func New(deps Deps) *Controller {
} }
func (receiver *Controller) GetHistoryList(ctx echo.Context, params swagger.GetHistoryParams) error { func (receiver *Controller) GetHistoryList(ctx echo.Context, params swagger.GetHistoryParams) error {
histories, err := receiver.historyService.GetHistoryList(ctx.Request().Context(), &models.Pagination{ histories, err := receiver.historyService.GetHistoryList(ctx.Request().Context(), &dto.GetHistories{
Page: int64(*params.Page), Type: params.Type,
Limit: int64(*params.Limit), Pagination: &models.Pagination{
Page: int64(*params.Page),
Limit: int64(*params.Limit),
},
}) })
if err != nil { if err != nil {
receiver.logger.Error("failed to get histories on <GetHistoryList> of <HistoryController>", zap.Error(err)) receiver.logger.Error("failed to get histories on <GetHistoryList> of <HistoryController>", zap.Error(err))

@ -10,6 +10,7 @@ import (
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
"go.uber.org/zap" "go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/dto"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "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/fields"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
@ -61,24 +62,22 @@ func (receiver *HistoryRepository) Insert(ctx context.Context, history *models.H
return history, nil return history, nil
} }
func (receiver *HistoryRepository) FindMany(ctx context.Context, page, limit int64) ([]models.History, errors.Error) { func (receiver *HistoryRepository) FindMany(ctx context.Context, dto *dto.GetHistories) ([]models.History, errors.Error) {
filter := bson.M{fields.Account.IsDeleted: false}
findOptions := options.Find() findOptions := options.Find()
skip := (page - 1) * limit
findOptions.SetSkip(skip) findOptions.SetSkip((dto.Pagination.Page - 1) * dto.Pagination.Limit)
findOptions.SetLimit(limit) findOptions.SetLimit(dto.Pagination.Limit)
histories, err := mongoWrapper.Find[models.History](ctx, &mongoWrapper.RequestSettings{ histories, err := mongoWrapper.Find[models.History](ctx, &mongoWrapper.RequestSettings{
Driver: receiver.mongoDB, Driver: receiver.mongoDB,
Options: findOptions, Options: findOptions,
Filter: filter, Filter: dto.BSON(),
}) })
if err != nil { if err != nil {
receiver.logger.Error("failed to find many histories on <FindMany> of <HistoryRepository>", receiver.logger.Error("failed to find many histories on <FindMany> of <HistoryRepository>",
zap.Int64("page", page), zap.Int64("page", dto.Pagination.Page),
zap.Int64("limit", limit), zap.Int64("limit", dto.Pagination.Limit),
zap.Int64("skip", skip), zap.Int64("skip", (dto.Pagination.Page-1)*dto.Pagination.Limit),
zap.Error(err), zap.Error(err),
) )

@ -1,6 +1,6 @@
// Package swagger provides primitives to interact with the openapi HTTP API. // Package swagger provides primitives to interact with the openapi HTTP API.
// //
// Code generated by github.com/deepmap/oapi-codegen version v1.13.0 DO NOT EDIT. // Code generated by github.com/deepmap/oapi-codegen version v1.15.0 DO NOT EDIT.
package swagger package swagger
import ( import (
@ -13,9 +13,9 @@ import (
"path" "path"
"strings" "strings"
"github.com/deepmap/oapi-codegen/pkg/runtime"
"github.com/getkin/kin-openapi/openapi3" "github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
"github.com/oapi-codegen/runtime"
) )
// ServerInterface represents all server handlers. // ServerInterface represents all server handlers.
@ -81,7 +81,7 @@ func (w *ServerInterfaceWrapper) DeleteAccount(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.DeleteAccount(ctx) err = w.Handler.DeleteAccount(ctx)
return err return err
} }
@ -92,7 +92,7 @@ func (w *ServerInterfaceWrapper) GetAccount(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetAccount(ctx) err = w.Handler.GetAccount(ctx)
return err return err
} }
@ -103,7 +103,7 @@ func (w *ServerInterfaceWrapper) ChangeAccount(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.ChangeAccount(ctx) err = w.Handler.ChangeAccount(ctx)
return err return err
} }
@ -114,7 +114,7 @@ func (w *ServerInterfaceWrapper) AddAccount(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.AddAccount(ctx) err = w.Handler.AddAccount(ctx)
return err return err
} }
@ -132,7 +132,7 @@ func (w *ServerInterfaceWrapper) DeleteDirectAccount(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.DeleteDirectAccount(ctx, userId) err = w.Handler.DeleteDirectAccount(ctx, userId)
return err return err
} }
@ -150,7 +150,7 @@ func (w *ServerInterfaceWrapper) GetDirectAccount(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetDirectAccount(ctx, userId) err = w.Handler.GetDirectAccount(ctx, userId)
return err return err
} }
@ -168,7 +168,7 @@ func (w *ServerInterfaceWrapper) SetAccountVerificationStatus(ctx echo.Context)
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.SetAccountVerificationStatus(ctx, userId) err = w.Handler.SetAccountVerificationStatus(ctx, userId)
return err return err
} }
@ -193,7 +193,7 @@ func (w *ServerInterfaceWrapper) PaginationAccounts(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
} }
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.PaginationAccounts(ctx, params) err = w.Handler.PaginationAccounts(ctx, params)
return err return err
} }
@ -213,7 +213,7 @@ func (w *ServerInterfaceWrapper) RemoveFromCart(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
} }
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.RemoveFromCart(ctx, params) err = w.Handler.RemoveFromCart(ctx, params)
return err return err
} }
@ -233,7 +233,7 @@ func (w *ServerInterfaceWrapper) Add2cart(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err)) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
} }
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.Add2cart(ctx, params) err = w.Handler.Add2cart(ctx, params)
return err return err
} }
@ -244,7 +244,7 @@ func (w *ServerInterfaceWrapper) PayCart(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.PayCart(ctx) err = w.Handler.PayCart(ctx)
return err return err
} }
@ -253,7 +253,7 @@ func (w *ServerInterfaceWrapper) PayCart(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) GetCurrencies(ctx echo.Context) error { func (w *ServerInterfaceWrapper) GetCurrencies(ctx echo.Context) error {
var err error var err error
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetCurrencies(ctx) err = w.Handler.GetCurrencies(ctx)
return err return err
} }
@ -264,7 +264,7 @@ func (w *ServerInterfaceWrapper) UpdateCurrencies(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.UpdateCurrencies(ctx) err = w.Handler.UpdateCurrencies(ctx)
return err return err
} }
@ -291,7 +291,14 @@ func (w *ServerInterfaceWrapper) GetHistory(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err)) return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
} }
// Invoke the callback with all the unmarshalled arguments // ------------- Optional query parameter "type" -------------
err = runtime.BindQueryParameter("form", false, false, "type", ctx.QueryParams(), &params.Type)
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err))
}
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetHistory(ctx, params) err = w.Handler.GetHistory(ctx, params)
return err return err
} }
@ -302,7 +309,7 @@ func (w *ServerInterfaceWrapper) ChangeCurrency(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.ChangeCurrency(ctx) err = w.Handler.ChangeCurrency(ctx)
return err return err
} }
@ -313,7 +320,7 @@ func (w *ServerInterfaceWrapper) RequestMoney(ctx echo.Context) error {
ctx.Set(BearerScopes, []string{}) ctx.Set(BearerScopes, []string{})
// Invoke the callback with all the unmarshalled arguments // Invoke the callback with all the unmarshaled arguments
err = w.Handler.RequestMoney(ctx) err = w.Handler.RequestMoney(ctx)
return err return err
} }
@ -368,71 +375,71 @@ func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL
// Base64 encoded, gzipped, json marshaled Swagger object // Base64 encoded, gzipped, json marshaled Swagger object
var swaggerSpec = []string{ var swaggerSpec = []string{
"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",
"Fhp/DwAA//8+Bz17tEYAAA==", "4xEhjR9XC9QMSFxRp5RVDQjzicZC458BAAD//9qBCRoiRwAA",
} }
// GetSwagger returns the content of the embedded swagger specification file // GetSwagger returns the content of the embedded swagger specification file
@ -440,16 +447,16 @@ var swaggerSpec = []string{
func decodeSpec() ([]byte, error) { func decodeSpec() ([]byte, error) {
zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, "")) zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
if err != nil { if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %s", err) return nil, fmt.Errorf("error base64 decoding spec: %w", err)
} }
zr, err := gzip.NewReader(bytes.NewReader(zipped)) zr, err := gzip.NewReader(bytes.NewReader(zipped))
if err != nil { if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err) return nil, fmt.Errorf("error decompressing spec: %w", err)
} }
var buf bytes.Buffer var buf bytes.Buffer
_, err = buf.ReadFrom(zr) _, err = buf.ReadFrom(zr)
if err != nil { if err != nil {
return nil, fmt.Errorf("error decompressing spec: %s", err) return nil, fmt.Errorf("error decompressing spec: %w", err)
} }
return buf.Bytes(), nil return buf.Bytes(), nil
@ -467,7 +474,7 @@ func decodeSpecCached() func() ([]byte, error) {
// Constructs a synthetic filesystem for resolving external references when loading openapi specifications. // Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) { func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
var res = make(map[string]func() ([]byte, error)) res := make(map[string]func() ([]byte, error))
if len(pathToFile) > 0 { if len(pathToFile) > 0 {
res[pathToFile] = rawSpec res[pathToFile] = rawSpec
} }
@ -481,12 +488,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
// Externally referenced files must be embedded in the corresponding golang packages. // Externally referenced files must be embedded in the corresponding golang packages.
// Urls can be supported but this task was out of the scope. // Urls can be supported but this task was out of the scope.
func GetSwagger() (swagger *openapi3.T, err error) { func GetSwagger() (swagger *openapi3.T, err error) {
var resolvePath = PathToRawSpec("") resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader() loader := openapi3.NewLoader()
loader.IsExternalRefsAllowed = true loader.IsExternalRefsAllowed = true
loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) { loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
var pathToFile = url.String() pathToFile := url.String()
pathToFile = path.Clean(pathToFile) pathToFile = path.Clean(pathToFile)
getSpec, ok := resolvePath[pathToFile] getSpec, ok := resolvePath[pathToFile]
if !ok { if !ok {

@ -6,9 +6,6 @@ import (
"github.com/labstack/echo/v4" "github.com/labstack/echo/v4"
) )
//go:generate oapi-codegen --config api.yaml ../../../openapi.yaml
//go:generate oapi-codegen --config models.yaml ../../../openapi.yaml
type accountController interface { type accountController interface {
RemoveAccount(ctx echo.Context) error RemoveAccount(ctx echo.Context) error
GetAccount(ctx echo.Context) error GetAccount(ctx echo.Context) error

@ -1,6 +1,6 @@
// Package swagger provides primitives to interact with the openapi HTTP API. // Package swagger provides primitives to interact with the openapi HTTP API.
// //
// Code generated by github.com/deepmap/oapi-codegen version v1.13.0 DO NOT EDIT. // Code generated by github.com/deepmap/oapi-codegen version v1.15.0 DO NOT EDIT.
package swagger package swagger
import ( import (
@ -152,6 +152,9 @@ type GetHistoryParams struct {
// Limit Размер страницы // Limit Размер страницы
Limit *int `form:"limit,omitempty" json:"limit,omitempty"` Limit *int `form:"limit,omitempty" json:"limit,omitempty"`
// Type Тип события
Type *string `form:"type,omitempty" json:"type,omitempty"`
} }
// ChangeCurrencyJSONBody defines parameters for ChangeCurrency. // ChangeCurrencyJSONBody defines parameters for ChangeCurrency.

@ -1,4 +0,0 @@
output: models.gen.go
package: swagger
generate:
models: true

@ -7,7 +7,7 @@ type History struct {
UserID string `json:"userId" bson:"userId"` UserID string `json:"userId" bson:"userId"`
Comment string `json:"comment" bson:"comment"` Comment string `json:"comment" bson:"comment"`
Key string `json:"key" bson:"key"` Key string `json:"key" bson:"key"`
RawDetails string `json:"rawDetails" bson:"rawDetails"` RawDetails any `json:"rawDetails" bson:"rawDetails"`
Deleted bool `json:"isDeleted" bson:"isDeleted"` Deleted bool `json:"isDeleted" bson:"isDeleted"`
CreatedAt time.Time `json:"createdAt" bson:"createdAt"` CreatedAt time.Time `json:"createdAt" bson:"createdAt"`
UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"` UpdatedAt time.Time `json:"updatedAt" bson:"updatedAt"`

@ -9,9 +9,9 @@ import (
type Tariff struct { type Tariff struct {
ID string `json:"_id"` ID string `json:"_id"`
Name string `json:"name"` Name string `json:"name"`
Price int64 `json:"price,omitempty"` Price uint64 `json:"price,omitempty"`
IsCustom bool `json:"isCustom"` IsCustom bool `json:"isCustom"`
Privileges []Privilege `json:"privilegies"` //nolint Privileges []Privilege `json:"privileges"`
Deleted bool `json:"isDeleted"` Deleted bool `json:"isDeleted"`
CreatedAt time.Time `json:"createdAt"` CreatedAt time.Time `json:"createdAt"`
UpdatedAt time.Time `json:"updatedAt"` UpdatedAt time.Time `json:"updatedAt"`

@ -2,6 +2,7 @@ package callback
import ( import (
"context" "context"
"fmt"
"log" "log"
"go.uber.org/zap" "go.uber.org/zap"
@ -82,22 +83,26 @@ func (receiver *PaymentCallbackService) SuccessEvent(ctx context.Context, event
return err return err
} }
if _, err := receiver.historyService.CreateHistory(ctx, &models.History{ go func() {
UserID: account.UserID, if _, err := receiver.historyService.CreateHistory(ctx, &models.History{
Comment: event.Message, UserID: account.UserID,
Key: event.Key, Comment: event.Message,
}); err != nil { Key: event.Key,
receiver.logger.Error("failed to create history on <SuccessEvent> of <PaymentCallbackService>", zap.Error(err)) RawDetails: fmt.Sprintf("%d%s", event.Amount, event.Currency),
} }); err != nil {
receiver.logger.Error("failed to create history on <SuccessEvent> of <PaymentCallbackService>", zap.Error(err))
}
}()
return nil return nil
} }
func (receiver *PaymentCallbackService) FailureEvent(ctx context.Context, event *models.PaymentEvent) errors.Error { func (receiver *PaymentCallbackService) FailureEvent(ctx context.Context, event *models.PaymentEvent) errors.Error {
if _, err := receiver.historyService.CreateHistory(ctx, &models.History{ if _, err := receiver.historyService.CreateHistory(ctx, &models.History{
UserID: event.UserID, UserID: event.UserID,
Comment: event.Message, Comment: event.Message,
Key: event.Key, Key: event.Key,
RawDetails: fmt.Sprintf("%d%s", event.Amount, event.Currency),
}); err != nil { }); err != nil {
receiver.logger.Error("failed to create history on <FailureEvent> of <PaymentCallbackService>", zap.Error(err)) receiver.logger.Error("failed to create history on <FailureEvent> of <PaymentCallbackService>", zap.Error(err))
return err return err

@ -104,17 +104,17 @@ func New(deps Deps) *Service {
} }
} }
func (receiver *Service) Remove(ctx context.Context, userID, itemID string) ([]string, errors.Error) { func (receiver *Service) Remove(ctx context.Context, userID, itemID string) (*models.Account, errors.Error) {
account, err := receiver.repository.RemoveItemFromCart(ctx, userID, itemID) account, err := receiver.repository.RemoveItemFromCart(ctx, userID, itemID)
if err != nil { if err != nil {
receiver.logger.Error("failed to remove item from cart on <Remove> of <CartService>", zap.Error(err)) receiver.logger.Error("failed to remove item from cart on <Remove> of <CartService>", zap.Error(err))
return []string{}, err return nil, err
} }
return account.Cart, nil return account, nil
} }
func (receiver *Service) Add(ctx context.Context, request *models.AddItemToCart) ([]string, errors.Error) { func (receiver *Service) Add(ctx context.Context, request *models.AddItemToCart) (*models.Account, errors.Error) {
tariff, err := receiver.hubadminClient.GetTariff(ctx, request.AccessToken, request.TariffID) tariff, err := receiver.hubadminClient.GetTariff(ctx, request.AccessToken, request.TariffID)
if err != nil { if err != nil {
receiver.logger.Error("failed to get tariff on <Add> of <CartService>", receiver.logger.Error("failed to get tariff on <Add> of <CartService>",
@ -123,11 +123,11 @@ func (receiver *Service) Add(ctx context.Context, request *models.AddItemToCart)
zap.String("accessToken", request.AccessToken), zap.String("accessToken", request.AccessToken),
) )
return []string{}, err return nil, err
} }
if tariff == nil { if tariff == nil {
return []string{}, errors.New( return nil, errors.New(
fmt.Errorf("failed to get tariff <%s> on <Add> of <CartService>: tariff not found", request.TariffID), fmt.Errorf("failed to get tariff <%s> on <Add> of <CartService>: tariff not found", request.TariffID),
errors.ErrNotFound, errors.ErrNotFound,
) )
@ -136,69 +136,66 @@ func (receiver *Service) Add(ctx context.Context, request *models.AddItemToCart)
account, err := receiver.repository.AddItemToCart(ctx, request.UserID, request.TariffID) account, err := receiver.repository.AddItemToCart(ctx, request.UserID, request.TariffID)
if err != nil { if err != nil {
receiver.logger.Error("failed to add item to cart on <Add> of <CartService>", zap.Error(err)) receiver.logger.Error("failed to add item to cart on <Add> of <CartService>", zap.Error(err))
return []string{}, err return nil, err
} }
return account.Cart, nil return account, nil
} }
func (receiver *Service) Pay(ctx context.Context, accessToken string, userID string) errors.Error { func (receiver *Service) Pay(ctx context.Context, accessToken string, userID string) (*models.Account, errors.Error) {
account, err := receiver.repository.FindByUserID(ctx, userID) account, err := receiver.repository.FindByUserID(ctx, userID)
if err != nil { if err != nil {
receiver.logger.Error("failed to find account on <Pay> of <CartService>", zap.String("userID", userID), zap.Error(err)) receiver.logger.Error("failed to find account on <Pay> of <CartService>", zap.String("userID", userID), zap.Error(err))
return err return nil, err
} }
receiver.logger.Info("account for buy cart", zap.Any("trtr", account))
tariffs, err := receiver.hubadminClient.GetTariffs(ctx, accessToken, account.Cart) tariffs, err := receiver.hubadminClient.GetTariffs(ctx, accessToken, account.Cart)
if err != nil { if err != nil {
receiver.logger.Error("failed to get tarrifs on <Pay> of <CartService>", zap.Strings("cart", account.Cart), zap.Error(err)) receiver.logger.Error("failed to get tarrifs on <Pay> of <CartService>", zap.Strings("cart", account.Cart), zap.Error(err))
return err return nil, err
} }
receiver.logger.Info("tariffs for buy cart", zap.Any("trtr", tariffs))
tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs) tariffsAmount := utils.CalculateCartPurchasesAmount(tariffs)
receiver.logger.Info("tariffsAmount for buy cart", zap.Any("trtr", tariffsAmount))
response, err := receiver.discountClient.Apply(ctx, &discount.ApplyDiscountRequest{ discountResponse, err := receiver.discountClient.Apply(ctx, &discount.ApplyDiscountRequest{
UserInformation: &discount.UserInformation{ UserInformation: &discount.UserInformation{
ID: account.UserID, ID: account.UserID,
Type: string(account.Status), Type: string(account.Status),
PurchasesAmount: uint64(account.Wallet.PurchasesAmount), PurchasesAmount: uint64(account.Wallet.PurchasesAmount),
CartPurchasesAmount: uint64(tariffsAmount), CartPurchasesAmount: tariffsAmount,
}, },
Products: transfer.TariffsToProductInformations(tariffs), Products: transfer.TariffsToProductInformations(tariffs),
Date: timestamppb.New(time.Now()), Date: timestamppb.New(time.Now()),
}) })
if err != nil { if err != nil {
receiver.logger.Error("failed to discount on <Pay> of <CartService>", zap.Error(err)) receiver.logger.Error("failed to discount on <Pay> of <CartService>", zap.Error(err))
return err return nil, err
} }
receiver.logger.Info("applyed discounts for buy cart", zap.Any("trtr", response)) if account.Wallet.Money < int64(discountResponse.Price) {
if account.Wallet.Money < int64(response.Price) {
receiver.logger.Error("insufficient funds on <Pay> of <CartService>") receiver.logger.Error("insufficient funds on <Pay> of <CartService>")
return errors.New(fmt.Errorf("insufficient funds: %d", int64(response.Price)-account.Wallet.Money), errors.ErrInsufficientFunds) return nil, errors.New(fmt.Errorf("insufficient funds: %d", int64(discountResponse.Price)-account.Wallet.Money), errors.ErrInsufficientFunds)
} }
if _, err := receiver.walletService.WithdrawAccountWalletMoney(ctx, &models.WithdrawAccountWallet{ updatedAccount, err := receiver.walletService.WithdrawAccountWalletMoney(ctx, &models.WithdrawAccountWallet{
Money: int64(response.Price), Money: int64(discountResponse.Price),
Account: account, Account: account,
}); err != nil { })
if err != nil {
receiver.logger.Error("failed to withdraw money on <Pay> of <CartService>", zap.Error(err)) receiver.logger.Error("failed to withdraw money on <Pay> of <CartService>", zap.Error(err))
return err return nil, err
} }
if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{ go func(tariffs []models.Tariff) {
Key: models.CustomerHistoryKeyPayCart, if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
UserID: account.UserID, Key: models.CustomerHistoryKeyPayCart,
Comment: "Успешная оплата корзины", UserID: account.UserID,
}); historyErr != nil { Comment: "Успешная оплата корзины",
receiver.logger.Error("failed to insert history on <Pay> of <CartService>", zap.Error(historyErr)) RawDetails: utils.TranslateTariffsArrayToMapPair(tariffs),
} }); historyErr != nil {
receiver.logger.Error("failed to insert history on <Pay> of <CartService>", zap.Error(historyErr))
}
}(tariffs)
// TODO: обработать ошибки при отправке сообщений // TODO: обработать ошибки при отправке сообщений
@ -207,13 +204,15 @@ func (receiver *Service) Pay(ctx context.Context, accessToken string, userID str
receiver.logger.Error("failed to send tariffs to broker on <Pay> of <CartService>", zap.Error(err)) receiver.logger.Error("failed to send tariffs to broker on <Pay> of <CartService>", zap.Error(err))
} }
return errors.NewWithMessage("failed to send tariffs to broker", errors.ErrInternalError) return nil, errors.NewWithMessage("failed to send tariffs to broker", errors.ErrInternalError)
} }
if _, err := receiver.repository.ClearCart(ctx, account.UserID); err != nil { if _, err := receiver.repository.ClearCart(ctx, account.UserID); err != nil {
receiver.logger.Error("failed to clear cart on <Pay> of <CartService>", zap.Error(err)) receiver.logger.Error("failed to clear cart on <Pay> of <CartService>", zap.Error(err))
return err return nil, err
} }
return nil updatedAccount.Cart = []string{}
return updatedAccount, nil
} }

@ -7,13 +7,14 @@ import (
"math" "math"
"go.uber.org/zap" "go.uber.org/zap"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/dto"
"penahub.gitlab.yandexcloud.net/pena-services/customer/internal/errors" "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/models"
) )
type historyRepository interface { type historyRepository interface {
CountAll(context.Context) (int64, errors.Error) CountAll(context.Context) (int64, errors.Error)
FindMany(ctx context.Context, page, limit int64) ([]models.History, errors.Error) FindMany(context.Context, *dto.GetHistories) ([]models.History, errors.Error)
Insert(context.Context, *models.History) (*models.History, errors.Error) Insert(context.Context, *models.History) (*models.History, errors.Error)
} }
@ -42,8 +43,8 @@ func New(deps Deps) *Service {
} }
} }
func (receiver *Service) GetHistoryList(ctx context.Context, pagination *models.Pagination) (*models.PaginationResponse[models.History], errors.Error) { func (receiver *Service) GetHistoryList(ctx context.Context, dto *dto.GetHistories) (*models.PaginationResponse[models.History], errors.Error) {
if pagination == nil { if dto == nil {
return nil, errors.New( return nil, errors.New(
fmt.Errorf("pagination is nil on <GetHistoryList> of <HistoryService>: %w", errors.ErrInternalError), fmt.Errorf("pagination is nil on <GetHistoryList> of <HistoryService>: %w", errors.ErrInternalError),
errors.ErrInternalError, errors.ErrInternalError,
@ -63,14 +64,12 @@ func (receiver *Service) GetHistoryList(ctx context.Context, pagination *models.
return &models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}}, nil return &models.PaginationResponse[models.History]{TotalPages: 0, Records: []models.History{}}, nil
} }
totalPages := int64(math.Ceil(float64(count) / float64(pagination.Limit))) totalPages := int64(math.Ceil(float64(count) / float64(dto.Pagination.Limit)))
histories, err := receiver.repository.FindMany(ctx, pagination.Page, pagination.Limit) histories, err := receiver.repository.FindMany(ctx, dto)
if err != nil { if err != nil {
receiver.logger.Error("failed to get historiy list on <GetHistoryList> of <HistoryService>", receiver.logger.Error("failed to get historiy list on <GetHistoryList> of <HistoryService>",
zap.Error(err), zap.Error(err),
zap.Int64("page", pagination.Page),
zap.Int64("limit", pagination.Limit),
) )
return nil, err return nil, err

@ -2,6 +2,7 @@ package wallet
import ( import (
"context" "context"
"fmt"
"log" "log"
"go.uber.org/zap" "go.uber.org/zap"
@ -10,8 +11,6 @@ import (
"penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate" "penahub.gitlab.yandexcloud.net/pena-services/customer/pkg/validate"
) )
const defaultCurrency = "RUB"
type accountRepository interface { type accountRepository interface {
ChangeWallet(ctx context.Context, userID string, wallet *models.Wallet) (*models.Account, errors.Error) ChangeWallet(ctx context.Context, userID string, wallet *models.Wallet) (*models.Account, errors.Error)
FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error) FindByUserID(ctx context.Context, id string) (*models.Account, errors.Error)
@ -66,7 +65,7 @@ func New(deps Deps) *Service {
func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *models.ReplenishAccountWallet) (*models.Account, errors.Error) { func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *models.ReplenishAccountWallet) (*models.Account, errors.Error) {
if validate.IsStringEmpty(request.Account.Wallet.Currency) { if validate.IsStringEmpty(request.Account.Wallet.Currency) {
request.Account.Wallet.Currency = defaultCurrency request.Account.Wallet.Currency = models.InternalCurrencyKey
} }
cash := request.Cash cash := request.Cash
@ -99,19 +98,21 @@ func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *mo
zap.String("Currency", request.Account.Wallet.Currency), zap.String("Currency", request.Account.Wallet.Currency),
zap.Int64("Money", request.Account.Wallet.Money+request.Cash), zap.Int64("Money", request.Account.Wallet.Money+request.Cash),
zap.Int64("Cash", request.Account.Wallet.Cash+cash), zap.Int64("Cash", request.Account.Wallet.Cash+cash),
zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey),
) )
return nil, changeErr return nil, changeErr
} }
if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{ go func() {
Key: models.CustomerHistoryKeyReplenish, if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
UserID: request.Account.UserID, Key: models.CustomerHistoryKeyReplenish,
Comment: "Успешное пополнение средств (Без конвертации валюты)", UserID: request.Account.UserID,
}); historyErr != nil { Comment: "Успешное пополнение средств (Без конвертации валюты)",
receiver.logger.Error("failed to insert history on <ReplenishAccountWallet> of <WalletService>", zap.Error(historyErr)) RawDetails: fmt.Sprintf("%d%s", cash, models.InternalCurrencyKey),
} }); historyErr != nil {
receiver.logger.Error("failed to insert history on <ReplenishAccountWallet> of <WalletService>", zap.Error(historyErr))
}
}()
return updatedAccount, nil return updatedAccount, nil
} }
@ -138,7 +139,7 @@ func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *mo
receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>", receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
zap.Error(err), zap.Error(err),
zap.String("Currency", request.Account.Wallet.Currency), zap.String("Currency", request.Account.Wallet.Currency),
zap.Int64("Money", request.Account.Wallet.Money+request.Cash), zap.Int64("Money", request.Account.Wallet.Money+money),
zap.Int64("Cash", request.Account.Wallet.Cash+cash), zap.Int64("Cash", request.Account.Wallet.Cash+cash),
zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey), zap.Bool("Is currensy equal internal", request.Currency == models.InternalCurrencyKey),
) )
@ -146,20 +147,45 @@ func (receiver *Service) ReplenishAccountWallet(ctx context.Context, request *mo
return nil, err return nil, err
} }
if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{ go func() {
Key: models.CustomerHistoryKeyReplenish, if _, historyErr := receiver.historyService.CreateHistory(ctx, &models.History{
UserID: request.Account.UserID, Key: models.CustomerHistoryKeyReplenish,
Comment: "Успешное пополнение средств (C конвертацией валюты)", UserID: request.Account.UserID,
}); historyErr != nil { Comment: "Успешное пополнение средств (C конвертацией валюты)",
receiver.logger.Error("failed to insert history on <ReplenishAccountWallet> of <WalletService>", zap.Error(historyErr)) RawDetails: fmt.Sprintf("%d%s", cash, request.Currency),
} }); historyErr != nil {
receiver.logger.Error("failed to insert history on <ReplenishAccountWallet> of <WalletService>", zap.Error(historyErr))
}
}()
return updatedAccount, nil return updatedAccount, nil
} }
func (receiver *Service) WithdrawAccountWalletMoney(ctx context.Context, request *models.WithdrawAccountWallet) (*models.Account, errors.Error) { func (receiver *Service) WithdrawAccountWalletMoney(ctx context.Context, request *models.WithdrawAccountWallet) (*models.Account, errors.Error) {
if validate.IsStringEmpty(request.Account.Wallet.Currency) { if validate.IsStringEmpty(request.Account.Wallet.Currency) {
request.Account.Wallet.Currency = defaultCurrency request.Account.Wallet.Currency = models.InternalCurrencyKey
}
if request.Account.Wallet.Currency == models.InternalCurrencyKey {
updatedAccount, err := receiver.repository.ChangeWallet(ctx, 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 {
receiver.logger.Error("failed to replenish wallet on <ReplenishAccountWallet> of <WalletService>",
zap.Error(err),
zap.String("Currency", request.Account.Wallet.Currency),
zap.Int64("Money", request.Account.Wallet.Money-request.Money),
zap.Int64("Cash", request.Account.Wallet.Cash+request.Money),
)
return nil, err
}
return updatedAccount, nil
} }
cash, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{ cash, err := receiver.currencyClient.Translate(ctx, &models.TranslateCurrency{

@ -2,12 +2,34 @@ package utils
import "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models" import "penahub.gitlab.yandexcloud.net/pena-services/customer/internal/models"
func CalculateCartPurchasesAmount(tariffs []models.Tariff) int64 { func CalculateCartPurchasesAmount(tariffs []models.Tariff) uint64 {
sum := int64(0) sum := uint64(0)
for _, tariff := range tariffs { for _, tariff := range tariffs {
if tariff.Price == 0 {
privilegesSum := uint64(0)
for _, privilege := range tariff.Privileges {
privilegesSum += privilege.Price
}
sum += privilegesSum
continue
}
sum += tariff.Price sum += tariff.Price
} }
return sum return sum
} }
func TranslateTariffsArrayToMapPair(tariffs []models.Tariff) map[string]string {
pair := make(map[string]string, len(tariffs))
for _, tariff := range tariffs {
pair[tariff.Name] = tariff.ID
}
return pair
}

@ -10,7 +10,7 @@ import (
func TestCalculateCartPurchasesAmount(t *testing.T) { func TestCalculateCartPurchasesAmount(t *testing.T) {
t.Run("Успешное вычиление суммы корзины", func(t *testing.T) { t.Run("Успешное вычиление суммы корзины", func(t *testing.T) {
assert.Equal(t, int64(200000), utils.CalculateCartPurchasesAmount([]models.Tariff{ assert.Equal(t, uint64(200000), utils.CalculateCartPurchasesAmount([]models.Tariff{
{Price: 90000}, {Price: 90000},
{Price: 110000}, {Price: 110000},
})) }))

@ -19,7 +19,7 @@ func TariffsToProductInformations(tarrifs []models.Tariff) []*discount.ProductIn
func TariffToProductInformation(tarrif models.Tariff) *discount.ProductInformation { func TariffToProductInformation(tarrif models.Tariff) *discount.ProductInformation {
return &discount.ProductInformation{ return &discount.ProductInformation{
ID: tarrif.ID, ID: tarrif.ID,
Price: uint64(tarrif.Price), Price: tarrif.Price,
} }
} }

@ -22,6 +22,26 @@
"createdAt": "2023-06-16T08:15:30.336Z", "createdAt": "2023-06-16T08:15:30.336Z",
"updatedAt": "2023-06-16T08:15:30.336Z", "updatedAt": "2023-06-16T08:15:30.336Z",
"deletedAt": "2023-06-16T08:15:30.336Z" "deletedAt": "2023-06-16T08:15:30.336Z"
},
{
"_id": {
"$oid": "64e4869f9fa60b9222bf4d84"
},
"userId": "64e5d9830fcca0596d82c0c7",
"name": {},
"cart": [],
"wallet": {
"currency": "RUB",
"cash": 10000,
"purchasesAmount": 0,
"spent": 0,
"money": 10000
},
"status": "no",
"isDeleted": false,
"createdAt": "2023-06-16T08:15:30.336Z",
"updatedAt": "2023-06-16T08:15:30.336Z",
"deletedAt": "2023-06-16T08:15:30.336Z"
} }
] ]
} }

17
pkg/bsontools/regex.go Normal file

@ -0,0 +1,17 @@
package bsontools
import (
"fmt"
"regexp"
"strings"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
func BuildCaseInsensitiveRegex(value string) bson.M {
return bson.M{"$regex": primitive.Regex{
Pattern: regexp.QuoteMeta(fmt.Sprintf(".*%s.*", regexp.QuoteMeta(strings.ToLower(value)))),
Options: "i",
}}
}

@ -8,7 +8,6 @@ import (
"net/url" "net/url"
"time" "time"
"go.mongodb.org/mongo-driver/event"
"go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options" "go.mongodb.org/mongo-driver/mongo/options"
) )
@ -28,18 +27,6 @@ func Connect(ctx context.Context, deps *ConnectDeps) (*mongo.Database, error) {
Host: net.JoinHostPort(deps.Configuration.Host, deps.Configuration.Port), Host: net.JoinHostPort(deps.Configuration.Host, deps.Configuration.Port),
} }
cmdMonitor := &event.CommandMonitor{
Started: func(_ context.Context, evt *event.CommandStartedEvent) {
log.Println(evt.Command)
},
Succeeded: func(_ context.Context, evt *event.CommandSucceededEvent) {
log.Println(evt.Reply)
},
Failed: func(_ context.Context, evt *event.CommandFailedEvent) {
log.Println(evt.Failure)
},
}
connectionOptions := options.Client(). connectionOptions := options.Client().
ApplyURI(mongoURI.String()). ApplyURI(mongoURI.String()).
SetAuth(options.Credential{ SetAuth(options.Credential{
@ -47,10 +34,7 @@ func Connect(ctx context.Context, deps *ConnectDeps) (*mongo.Database, error) {
AuthSource: deps.Configuration.Auth, AuthSource: deps.Configuration.Auth,
Username: deps.Configuration.User, Username: deps.Configuration.User,
Password: deps.Configuration.Password, Password: deps.Configuration.Password,
}). })
SetMonitor(cmdMonitor)
fmt.Println(connectionOptions.GetURI())
ticker := time.NewTicker(1 * time.Second) ticker := time.NewTicker(1 * time.Second)
timeoutExceeded := time.After(deps.Timeout) timeoutExceeded := time.After(deps.Timeout)

@ -0,0 +1,65 @@
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 TestBuyTariff(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
}
responseAddCart, errAddCart := client.Patch[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
URL: "http://localhost:8082/cart",
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
QueryParams: map[string]string{"id": "64e6105384368b75221a5c3e"},
})
if isNoError := assert.NoError(t, errAddCart); !isNoError {
return
}
if isNoRequestError := assert.Nil(t, responseAddCart.Error); !isNoRequestError {
return
}
isUserIDValid := assert.Equal(t, "64e5d9830fcca0596d82c0c7", responseAddCart.Body.UserID)
isCartLengthValid := assert.Equal(t, 1, len(responseAddCart.Body.Cart))
isCartItemValid := assert.Equal(t, "64e6105384368b75221a5c3e", responseAddCart.Body.Cart[0])
if isUserIDValid && isCartItemValid && isCartLengthValid {
responsePay, errPay := client.Post[models.Account, models.ResponseErrorHTTP](ctx, &client.RequestSettings{
URL: "http://localhost:8082/cart/pay",
Headers: map[string]string{"Authorization": fmt.Sprintf("Bearer %s", token)},
})
if isNoError := assert.NoError(t, errPay); !isNoError {
return
}
if isNoRequestError := assert.Nil(t, responsePay.Error); !isNoRequestError {
return
}
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.PurchasesAmount, responsePay.Body.Wallet.PurchasesAmount)
assert.Equal(t, "RUB", responsePay.Body.Wallet.Currency)
}
})
})
}

@ -11,77 +11,32 @@ import (
func InitializeJWT() *utils.JWT { func InitializeJWT() *utils.JWT {
publicKey := strings.Replace(`-----BEGIN PUBLIC KEY----- publicKey := strings.Replace(`-----BEGIN PUBLIC KEY-----
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAyt4XuLovUY7i12K2PIMb MIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHgnvr7O2tiApjJfid1orFnIGm69
QZOKn+wFFKUvxvKQDel049/+VMpHMx1FLolUKuyGp9zi6gOwjHsBPgc9oqr/eaXG 80fZp+Lpbjo+NC/0whMFga2Biw5b1G2Q/B2u0tpO1Fs/E8z7Lv1nYfr5jx2S8x6B
QSh7Ult7i9f+Ht563Y0er5UU9Zc5ZPSxf9O75KYD48ruGkqiFoncDqPENK4dtUa7 dA4TS2kB9Kf0wn0+7wSlyikHoKhbtzwXHZl17GsyEi6wHnsqNBSauyIWhpha8i+Y
w0OqlN4bwVBbmIsP8B3EDC5Dof+vtiNTSHSXPx+zifKeZGyknp+nyOHVrRDhPjOh +3GyaOY536H47qyXAgMBAAE=
zQzCom0MSZA/sJYmps8QZgiPA0k4Z6jTupDymPOIwYeD2C57zSxnAv0AfC3/pZYJ
bZYH/0TszRzmy052DME3zMnhMK0ikdN4nzYqU0dkkA5kb5GtKDymspHIJ9eWbUuw
gtg8Rq/LrVBj1I3UFgs0ibio40k6gqinLKslc5Y1I5mro7J3OSEP5eO/XeDLOLlO
JjEqkrx4fviI1cL3m5L6QV905xmcoNZG1+RmOg7D7cZQUf27TXqM381jkbNdktm1
JLTcMScxuo3vaRftnIVw70V8P8sIkaKY8S8HU1sQgE2LB9t04oog5u59htx2FHv4
B13NEm8tt8Tv1PexpB4UVh7PIualF6SxdFBrKbraYej72wgjXVPQ0eGXtGGD57j8
DUEzk7DK2OvIWhehlVqtiRnFdAvdBj2ynHT2/5FJ/Zpd4n5dKGJcQvy1U1qWMs+8
M7AHfWyt2+nZ04s48+bK3yMCAwEAAQ==
-----END PUBLIC KEY-----`, "\t", "", -1) -----END PUBLIC KEY-----`, "\t", "", -1)
privateKey := strings.Replace(`-----BEGIN RSA PRIVATE KEY----- privateKey := strings.Replace(`-----BEGIN RSA PRIVATE KEY-----
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
-----END RSA PRIVATE KEY-----`, "\t", "", -1) -----END RSA PRIVATE KEY-----`, "\t", "", -1)
return utils.NewJWT(&models.JWTConfiguration{ return utils.NewJWT(&models.JWTConfiguration{
PrivateKey: privateKey, PrivateKey: privateKey,
PublicKey: publicKey, PublicKey: publicKey,
Audience: "audience", Audience: "pena",
Issuer: "issuer", Issuer: "pena-auth-service",
Algorithm: *jwt.SigningMethodRS256, Algorithm: *jwt.SigningMethodRS256,
ExpiresIn: 15 * time.Minute, ExpiresIn: 15 * time.Minute,
}) })

BIN
tools/migrate Normal file

Binary file not shown.