forked from ebhomengo/niki
Compare commits
1 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
cef2aa9247 |
|
|
@ -1,34 +0,0 @@
|
||||||
root = "."
|
|
||||||
tmp_dir = "cmd/productapp/temp"
|
|
||||||
|
|
||||||
[build]
|
|
||||||
bin = "/entrypoint.sh"
|
|
||||||
args_bin = []
|
|
||||||
cmd = "go build -mod=mod -buildvcs=false -o ./cmd/productapp/temp/main ./cmd/productapp/"
|
|
||||||
delay = 1000
|
|
||||||
exclude_dir = ["vendor", "cmd/productapp/temp"]
|
|
||||||
exclude_file = []
|
|
||||||
exclude_regex = []
|
|
||||||
exclude_unchanged = false
|
|
||||||
follow_symlink = false
|
|
||||||
include_dir = []
|
|
||||||
include_ext = ["go"]
|
|
||||||
kill_delay = "0s"
|
|
||||||
log = "build-errors.log"
|
|
||||||
send_interrupt = false
|
|
||||||
stop_on_error = true
|
|
||||||
poll = true
|
|
||||||
poll_interval = 1000
|
|
||||||
|
|
||||||
[color]
|
|
||||||
app = ""
|
|
||||||
build = "yellow"
|
|
||||||
main = "magenta"
|
|
||||||
runner = "green"
|
|
||||||
watcher = "cyan"
|
|
||||||
|
|
||||||
[log]
|
|
||||||
time = false
|
|
||||||
|
|
||||||
[misc]
|
|
||||||
clean_on_exit = false
|
|
||||||
|
|
@ -30,5 +30,3 @@ logs/
|
||||||
mise.log
|
mise.log
|
||||||
|
|
||||||
curl
|
curl
|
||||||
|
|
||||||
cmd/**/temp/main
|
|
||||||
|
|
@ -19,7 +19,7 @@ FROM alpine:3.20 AS runtime
|
||||||
# Copy the binary from the builder stage
|
# Copy the binary from the builder stage
|
||||||
COPY --from=builder /niki/niki .
|
COPY --from=builder /niki/niki .
|
||||||
|
|
||||||
# Copy migrations files
|
# Copy migration files
|
||||||
COPY --from=builder /niki/repository/mysql/migration ./repository/mysql/migration
|
COPY --from=builder /niki/repository/mysql/migration ./repository/mysql/migration
|
||||||
|
|
||||||
# Expose application port
|
# Expose application port
|
||||||
|
|
|
||||||
124
Makefile
124
Makefile
|
|
@ -1,64 +1,54 @@
|
||||||
# --- Variables ---
|
# TODO: add commands for build and run in dev/produciton mode
|
||||||
BINARY_NAME ?= niki
|
|
||||||
BUILD_DIR ?= bin
|
|
||||||
|
|
||||||
# ====================================================================================
|
ROOT=$(realpath $(dir $(lastword $(MAKEFILE_LIST))))
|
||||||
# General Go Commands
|
|
||||||
# ====================================================================================
|
|
||||||
.PHONY: start test build clean mod-tidy lint install-linter help format swagger watch
|
|
||||||
|
|
||||||
start: build
|
.PHONY: help confirm lint test format build run docker swagger watch migrate/status migrate/new migrate/up migrate/down
|
||||||
$(BUILD_DIR)/$(BINARY_NAME)
|
|
||||||
|
confirm:
|
||||||
|
@echo -n 'Are you sure? [y/N] ' && read ans && [ $${ans:-N} = y ]
|
||||||
|
|
||||||
|
lint:
|
||||||
|
which golangci-lint || (go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.0)
|
||||||
|
golangci-lint run --config=$(ROOT)/.golangci.yml $(ROOT)/...
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v ./...
|
go test -v ./...
|
||||||
|
|
||||||
build:
|
|
||||||
@mkdir -p $(BUILD_DIR)
|
|
||||||
go build -o $(BUILD_DIR)/$(BINARY_NAME) main.go
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf $(BUILD_DIR)/
|
|
||||||
|
|
||||||
mod-tidy:
|
|
||||||
go mod tidy
|
|
||||||
|
|
||||||
lint:
|
|
||||||
golangci-lint run
|
|
||||||
|
|
||||||
install-linter:
|
|
||||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
|
||||||
|
|
||||||
format:
|
format:
|
||||||
@which gofumpt || (go install mvdan.cc/gofumpt@latest)
|
@which gofumpt || (go install mvdan.cc/gofumpt@latest)
|
||||||
@gofumpt -l -w .
|
@gofumpt -l -w $(ROOT)
|
||||||
@which gci || (go install github.com/daixiang0/gci@latest)
|
@which gci || (go install github.com/daixiang0/gci@latest)
|
||||||
@gci write . --skip-generated --skip-vendor
|
@gci write $(ROOT) --skip-generated --skip-vendor
|
||||||
|
@which golangci-lint || (go install github.com/golangci/golangci-lint/cmd/golangci-lint@v1.54.0)
|
||||||
@golangci-lint run --fix
|
@golangci-lint run --fix
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -o niki main.go
|
||||||
|
|
||||||
|
run:
|
||||||
|
go run main.go --migrate
|
||||||
|
|
||||||
|
docker:
|
||||||
|
sudo docker compose up -d
|
||||||
|
|
||||||
swagger:
|
swagger:
|
||||||
swag init
|
swag init
|
||||||
|
|
||||||
# Live Reload
|
# Live Reload
|
||||||
watch:
|
watch:
|
||||||
@if command -v CompileDaemon > /dev/null; then \
|
@if command -v CompileDaemon > /dev/null; then \
|
||||||
CompileDaemon -exclude-dir=.git -exclude=".#*" -command="./$(BUILD_DIR)/$(BINARY_NAME)"; \
|
CompileDaemon -exclude-dir=.git -exclude=".#*" -command="./niki"; \
|
||||||
else \
|
else \
|
||||||
read -p "Go's 'CompileDaemon' is not installed. Do you want to install it? [Y/n] " choice; \
|
read -p "Go's 'CompileDaemon' is not installed on your machine. Do you want to install it? [Y/n] " choice; \
|
||||||
if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \
|
if [ "$$choice" != "n" ] && [ "$$choice" != "N" ]; then \
|
||||||
go install github.com/githubnemo/CompileDaemon@latest; \
|
go install github.com/githubnemo/CompileDaemon@latest; \
|
||||||
CompileDaemon -exclude-dir=.git -exclude=".#*" -command="./$(BUILD_DIR)/$(BINARY_NAME)"; \
|
CompileDaemon -exclude-dir=.git -exclude=".#*" -command="./niki"; \
|
||||||
else \
|
else \
|
||||||
echo "You chose not to install CompileDaemon. Exiting..."; \
|
echo "You chose not to install CompileDaemon. Exiting..."; \
|
||||||
exit 1; \
|
exit 1; \
|
||||||
fi; \
|
fi; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# ====================================================================================
|
|
||||||
# Database Migration Commands (legacy niki-core)
|
|
||||||
# ====================================================================================
|
|
||||||
.PHONY: migrate/status migrate/new migrate/up migrate/down
|
|
||||||
|
|
||||||
migrate/status:
|
migrate/status:
|
||||||
@sql-migrate status -env="production" -config=repository/mysql/dbconfig.yml
|
@sql-migrate status -env="production" -config=repository/mysql/dbconfig.yml
|
||||||
|
|
||||||
|
|
@ -74,67 +64,3 @@ migrate/up: confirm
|
||||||
migrate/down: confirm
|
migrate/down: confirm
|
||||||
@echo 'Tearing down last migration...'
|
@echo 'Tearing down last migration...'
|
||||||
@sql-migrate down -env="production" -config=repository/mysql/dbconfig.yml -limit=1
|
@sql-migrate down -env="production" -config=repository/mysql/dbconfig.yml -limit=1
|
||||||
|
|
||||||
confirm:
|
|
||||||
@echo -n 'Are you sure? [y/N] ' && read ans && [ $${ans:-N} = y ]
|
|
||||||
|
|
||||||
# ====================================================================================
|
|
||||||
# Productapp Service Commands
|
|
||||||
# ====================================================================================
|
|
||||||
.PHONY: productapp-up productapp-up-logs productapp-rebuild productapp-watch
|
|
||||||
|
|
||||||
PRODUCTAPP_ENV = deploy/productapp/development/.env
|
|
||||||
PRODUCTAPP_COMPOSE = deploy/productapp/development/docker-compose.yml
|
|
||||||
|
|
||||||
productapp-up:
|
|
||||||
@echo "Building and starting productapp full stack..."
|
|
||||||
docker compose --env-file $(PRODUCTAPP_ENV) -f $(PRODUCTAPP_COMPOSE) up --build -d
|
|
||||||
@echo "productapp stack is up."
|
|
||||||
|
|
||||||
productapp-down:
|
|
||||||
@echo "Building and starting productapp full stack..."
|
|
||||||
docker compose --env-file $(PRODUCTAPP_ENV) -f $(PRODUCTAPP_COMPOSE) down
|
|
||||||
@echo "productapp stack is up."
|
|
||||||
|
|
||||||
productapp-up-logs:
|
|
||||||
@echo "Building and starting productapp full stack..."
|
|
||||||
docker compose --env-file $(PRODUCTAPP_ENV) -f $(PRODUCTAPP_COMPOSE) up --build
|
|
||||||
|
|
||||||
# ====================================================================================
|
|
||||||
# Docker Commands (legacy)
|
|
||||||
# ====================================================================================
|
|
||||||
.PHONY: docker
|
|
||||||
|
|
||||||
docker:
|
|
||||||
docker compose up -d
|
|
||||||
|
|
||||||
# ====================================================================================
|
|
||||||
# Help Target
|
|
||||||
# ====================================================================================
|
|
||||||
help:
|
|
||||||
@echo "Available targets:"
|
|
||||||
@echo ""
|
|
||||||
@echo "General Go Commands:"
|
|
||||||
@echo " start - Build and run niki-core locally"
|
|
||||||
@echo " test - Run tests"
|
|
||||||
@echo " build - Compile binary"
|
|
||||||
@echo " clean - Remove build artifacts"
|
|
||||||
@echo " mod-tidy - Clean up dependencies"
|
|
||||||
@echo " format - Format code (gofumpt + gci + lint fix)"
|
|
||||||
@echo " lint - Run linters"
|
|
||||||
@echo " install-linter - Install golangci-lint"
|
|
||||||
@echo " swagger - Generate swagger docs"
|
|
||||||
@echo " watch - Live reload with CompileDaemon"
|
|
||||||
@echo ""
|
|
||||||
@echo "Database Migration (niki-core):"
|
|
||||||
@echo " migrate/status - Show migration status"
|
|
||||||
@echo " migrate/new - Create new migration (name=<name>)"
|
|
||||||
@echo " migrate/up - Run migrations up"
|
|
||||||
@echo " migrate/down - Rollback last migration"
|
|
||||||
@echo ""
|
|
||||||
@echo "Productapp Service:"
|
|
||||||
@echo " productapp-up - Build and start full stack in background"
|
|
||||||
@echo " productapp-up-logs - Build and start full stack with logs"
|
|
||||||
@echo ""
|
|
||||||
@echo "Docker (legacy):"
|
|
||||||
@echo " docker - Start docker-compose services"
|
|
||||||
|
|
|
||||||
|
|
@ -1,44 +0,0 @@
|
||||||
package accountapp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/accountapp/delivery/grpc"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/kavenegar"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/account/repository/mysql"
|
|
||||||
redisRepo "git.gocasts.ir/ebhomengo/niki/domain/account/repository/redis"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/account/service"
|
|
||||||
database "git.gocasts.ir/ebhomengo/niki/pkg/database/mysql"
|
|
||||||
rpcPkg "git.gocasts.ir/ebhomengo/niki/pkg/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Application struct {
|
|
||||||
GrpcServer grpc.Server
|
|
||||||
Config Config
|
|
||||||
accountSvc service.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func Setup(cfg Config, db *database.DB) Application {
|
|
||||||
redisConn := redis.New(cfg.Redis)
|
|
||||||
otpRepo := redisRepo.NewRepositoryOtp(redisConn)
|
|
||||||
mysqlRepo := mysql.New(db)
|
|
||||||
smsAdapter := kavenegar.New(cfg.Kavenegar)
|
|
||||||
accountSvc := service.NewService(cfg.accountSvc, otpRepo, mysqlRepo, smsAdapter)
|
|
||||||
|
|
||||||
rpcServer := rpcPkg.New(cfg.grpcServerCfg)
|
|
||||||
|
|
||||||
return Application{
|
|
||||||
accountSvc: accountSvc,
|
|
||||||
Config: cfg,
|
|
||||||
GrpcServer: grpc.New(rpcServer, accountSvc),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app *Application) Start() {
|
|
||||||
err := app.GrpcServer.Start()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("error in serving GRPC server: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package accountapp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/kavenegar"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/account/service"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/database/mysql"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
accountSvc service.Config `koanf:"service"`
|
|
||||||
Redis redis.Config `koanf:"redis_db"`
|
|
||||||
MysqlDB mysql.Config `koanf:"mysql_db"`
|
|
||||||
Kavenegar kavenegar.Config `koanf:"kavenegar"`
|
|
||||||
grpcServerCfg grpc.Config `koanf:"grpc_server"`
|
|
||||||
grpcClientCfg grpc.Client `koanf:"grpc_client"`
|
|
||||||
PathOfMigration string `koanf:"path_of_migration"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
package grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
pb "git.gocasts.ir/ebhomengo/niki/contract/goprotobuf/account"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/account/service"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
server *grpc.RPCServer
|
|
||||||
accountSvc service.Service
|
|
||||||
pb.UnimplementedAccountServiceServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(server *grpc.RPCServer, accountSvc service.Service) Server {
|
|
||||||
return Server{
|
|
||||||
server: server,
|
|
||||||
accountSvc: accountSvc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) SendOtp(ctx context.Context, req *pb.SendOtpRequest) (*pb.SendOtpResponse, error) {
|
|
||||||
err := s.accountSvc.SendOTP(ctx, req.PhoneNumber)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &pb.SendOtpResponse{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) LoginOrRegister(ctx context.Context, req *pb.LoginOrRegisterRequest) (*pb.LoginOrRegisterResponse, error) {
|
|
||||||
res := &pb.LoginOrRegisterResponse{}
|
|
||||||
driver, err := s.accountSvc.LoginOrRegisterDriver(ctx, req.PhoneNumber, req.VerifyCode)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
id := uint64(driver.ID)
|
|
||||||
|
|
||||||
res.Id = id
|
|
||||||
res.PhoneNumber = driver.PhoneNumber
|
|
||||||
|
|
||||||
return res, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) Start() error {
|
|
||||||
listener, err := net.Listen(s.server.Config.NetworkType, fmt.Sprintf(":%d", s.server.Config.Port))
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
accountSvcServer := Server{}
|
|
||||||
|
|
||||||
pb.RegisterAccountServiceServer(s.server.Server, &accountSvcServer)
|
|
||||||
|
|
||||||
if err := s.server.Server.Serve(listener); err != nil {
|
|
||||||
log.Fatalf("failed to serve: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
||||||
package account
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
pb "git.gocasts.ir/ebhomengo/niki/contract/goprotobuf/account"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/driverapp/service"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Client struct {
|
|
||||||
Conn *grpc.ClientConn
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(conn *grpc.ClientConn) *Client {
|
|
||||||
return &Client{
|
|
||||||
Conn: conn,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Client) SendOTP(ctx context.Context, phoneNumber string) error {
|
|
||||||
|
|
||||||
client := pb.NewAccountServiceClient(c.Conn)
|
|
||||||
|
|
||||||
_, err := client.SendOtp(ctx, &pb.SendOtpRequest{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c Client) LoginOrRegister(ctx context.Context, req service.LoginOrRegisterRequest) (service.LoginOrRegisterResponse, error) {
|
|
||||||
|
|
||||||
client := pb.NewAccountServiceClient(c.Conn)
|
|
||||||
|
|
||||||
res, err := client.LoginOrRegister(ctx, &pb.LoginOrRegisterRequest{
|
|
||||||
PhoneNumber: req.PhoneNumber,
|
|
||||||
VerifyCode: req.VerifyCode,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return service.LoginOrRegisterResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return service.LoginOrRegisterResponse{
|
|
||||||
ID: types.ID(res.Id),
|
|
||||||
PhoneNumber: res.PhoneNumber,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package agentapp
|
||||||
|
|
||||||
|
type Application struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func Setup() {}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
package agentapp
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
// database config
|
||||||
|
// httpserver config
|
||||||
|
//...
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package http
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package http
|
||||||
|
|
||||||
|
type Server struct {
|
||||||
|
// httpServer
|
||||||
|
// handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Server {
|
||||||
|
return Server{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Server) Serve() {}
|
||||||
|
|
||||||
|
func (s Server) RegisterRoutes() {}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package repository
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
type Agent struct {
|
||||||
|
ID uint
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package service
|
||||||
|
|
@ -0,0 +1,8 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Service {
|
||||||
|
return Service{}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package service
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package command
|
|
||||||
|
|
||||||
import "github.com/spf13/cobra"
|
|
||||||
|
|
||||||
var up bool
|
|
||||||
var down bool
|
|
||||||
|
|
||||||
var migrateCmd = &cobra.Command{
|
|
||||||
Use: "migrate",
|
|
||||||
Short: "Run database migrations",
|
|
||||||
Long: `This command runs the database migrations for the account service.`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
migrate()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func migrate() {}
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
migrateCmd.Flags().BoolVar(&up, "up", false, "Run migrations up")
|
|
||||||
migrateCmd.Flags().BoolVar(&down, "down", false, "Run migrations down")
|
|
||||||
RootCmd.AddCommand(migrateCmd)
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
package command
|
|
||||||
|
|
||||||
import "github.com/spf13/cobra"
|
|
||||||
|
|
||||||
var RootCmd = &cobra.Command{
|
|
||||||
Use: "account_service",
|
|
||||||
Short: "A CLI for account Service",
|
|
||||||
Long: `account Service CLI is a tool to manage and run
|
|
||||||
the account service, including migrations and server startup.`,
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package command
|
|
||||||
|
|
||||||
import "github.com/spf13/cobra"
|
|
||||||
|
|
||||||
var serveCmd = &cobra.Command{
|
|
||||||
Use: "serve",
|
|
||||||
Short: "start a account service.",
|
|
||||||
Long: `This command starts the main account service.`,
|
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
|
||||||
serve()
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func serve() {}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
package account
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/cmd/account/command"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
if err := command.RootCmd.Execute(); err != nil {
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
package driverapp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"flag"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/driverapp"
|
|
||||||
cfgloader "git.gocasts.ir/ebhomengo/niki/pkg/cfg_loader"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/migrator"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
var cfg driverapp.Config
|
|
||||||
|
|
||||||
workingDir, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("Error getting current working directory: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
options := cfgloader.Option{
|
|
||||||
Prefix: "DRIVER_",
|
|
||||||
Delimiter: ".",
|
|
||||||
Separator: "__",
|
|
||||||
YamlFilePath: filepath.Join(workingDir, "deploy", "driver", "development", "config.yaml"),
|
|
||||||
CallbackEnv: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
lErr := cfgloader.Load(options, &cfg)
|
|
||||||
if lErr != nil {
|
|
||||||
log.Fatalf("Failed to load driver config: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
conn := mysql.New(cfg.MysqlDB)
|
|
||||||
|
|
||||||
mgr := migrator.New(cfg.MysqlDB, cfg.PathOfMigration)
|
|
||||||
|
|
||||||
migrate := flag.Bool("migrate", false, "perform database migrations")
|
|
||||||
flag.Parse()
|
|
||||||
|
|
||||||
if *migrate {
|
|
||||||
fmt.Println("Running migrations")
|
|
||||||
mgr.Up()
|
|
||||||
}
|
|
||||||
|
|
||||||
//dapp := driverapp.Setup(cfg)
|
|
||||||
//dapp.Start()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +1,13 @@
|
||||||
package command
|
package command
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strconv"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/productapp"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -28,53 +25,27 @@ var serveCmd = &cobra.Command{
|
||||||
func serve() {
|
func serve() {
|
||||||
log.Println("Product Service Starting...")
|
log.Println("Product Service Starting...")
|
||||||
|
|
||||||
cfg := productapp.Config{
|
// TODO: Initialize database connection
|
||||||
HTTPServer: productapp.HTTPServerConfig{
|
// TODO: Initialize service dependencies
|
||||||
Port: getEnvInt("HTTP_PORT", 8080),
|
// TODO: Setup HTTP server with routes
|
||||||
},
|
|
||||||
Database: mysql.Config{
|
|
||||||
Username: getEnv("DB_USERNAME", "root"),
|
|
||||||
Password: getEnv("DB_PASSWORD", ""),
|
|
||||||
Port: getEnvInt("DB_PORT", 3306),
|
|
||||||
Host: getEnv("DB_HOST", "localhost"),
|
|
||||||
DBName: getEnv("DB_NAME", "niki_db"),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if p, err := strconv.Atoi(port); err == nil && p > 0 {
|
|
||||||
cfg.HTTPServer.Port = p
|
|
||||||
}
|
|
||||||
|
|
||||||
app := productapp.Setup(cfg)
|
|
||||||
|
|
||||||
|
// Setup graceful shutdown
|
||||||
go func() {
|
go func() {
|
||||||
app.Start()
|
sigCh := make(chan os.Signal, 1)
|
||||||
|
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
<-sigCh
|
||||||
|
log.Println("Shutting down Product Service gracefully...")
|
||||||
|
os.Exit(0)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
quit := make(chan os.Signal, 1)
|
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
fmt.Fprintf(w, "Product Service OK!")
|
||||||
<-quit
|
})
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
log.Printf("Product Service listening on port %s", port)
|
||||||
defer cancel()
|
if err := http.ListenAndServe(":"+port, nil); err != nil {
|
||||||
|
log.Fatalf("Failed to start server: %v", err)
|
||||||
if err := app.Stop(ctx); err != nil {
|
|
||||||
log.Fatalf("Server shutdown error: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Product Service stopped.")
|
|
||||||
}
|
|
||||||
|
|
||||||
func getEnvInt(key string, defaultValue int) int {
|
|
||||||
val := os.Getenv(key)
|
|
||||||
if val == "" {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
n, err := strconv.Atoi(val)
|
|
||||||
if err != nil {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,63 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
purchaseMysql "git.gocasts.ir/ebhomengo/niki/domain/purchase/repository/mysql"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/purchaseapp/delivery/http"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/purchaseapp/service/order"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/migrator"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
func MariaDB() *mysql.DB {
|
||||||
|
cfg := mysql.Config{
|
||||||
|
Username: "niki",
|
||||||
|
Password: "nikiappt0lk2o20",
|
||||||
|
Port: 3306,
|
||||||
|
Host: "localhost",
|
||||||
|
DBName: "niki_db",
|
||||||
|
}
|
||||||
|
migrate := flag.Bool("migrate", false, "perform database migration")
|
||||||
|
flag.Parse()
|
||||||
|
if *migrate {
|
||||||
|
migrator.New(migrator.Config{
|
||||||
|
MysqlConfig: cfg,
|
||||||
|
MigrationPath: "./purchaseapp/repository/mysql/migration",
|
||||||
|
MigrationDBName: "gorp_migrations",
|
||||||
|
}).Up()
|
||||||
|
}
|
||||||
|
|
||||||
|
return mysql.New(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
cfg := mysql.Config{
|
||||||
|
Username: "niki",
|
||||||
|
Password: "nikiappt0lk2o20",
|
||||||
|
Port: 3306,
|
||||||
|
Host: "localhost",
|
||||||
|
DBName: "niki_db",
|
||||||
|
}
|
||||||
|
db := mysql.New(cfg)
|
||||||
|
defer func() {
|
||||||
|
if err := db.CloseStatements(); err != nil {
|
||||||
|
fmt.Printf("Error closing statements: %v\n", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
orderRepo := purchaseMysql.New(db)
|
||||||
|
|
||||||
|
orderSvc := Service(orderRepo)
|
||||||
|
server := HTTPServer(orderSvc)
|
||||||
|
server.Serve()
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func HTTPServer(orderSvc order.Service) *http.Server {
|
||||||
|
return http.New(orderSvc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Service(orderRepo *purchaseMysql.DB) order.Service {
|
||||||
|
return order.New(orderRepo)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,281 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.36.11
|
|
||||||
// protoc v3.21.12
|
|
||||||
// source: contract/protobuf/account/account.proto
|
|
||||||
|
|
||||||
package account
|
|
||||||
|
|
||||||
import (
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
unsafe "unsafe"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type LoginOrRegisterRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
PhoneNumber string `protobuf:"bytes,1,opt,name=phoneNumber,proto3" json:"phoneNumber,omitempty"`
|
|
||||||
VerifyCode string `protobuf:"bytes,2,opt,name=verifyCode,proto3" json:"verifyCode,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterRequest) Reset() {
|
|
||||||
*x = LoginOrRegisterRequest{}
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*LoginOrRegisterRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use LoginOrRegisterRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*LoginOrRegisterRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_contract_protobuf_account_account_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterRequest) GetPhoneNumber() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.PhoneNumber
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterRequest) GetVerifyCode() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.VerifyCode
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginOrRegisterResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
Id uint64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
|
||||||
PhoneNumber string `protobuf:"bytes,2,opt,name=phoneNumber,proto3" json:"phoneNumber,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterResponse) Reset() {
|
|
||||||
*x = LoginOrRegisterResponse{}
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*LoginOrRegisterResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[1]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use LoginOrRegisterResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*LoginOrRegisterResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_contract_protobuf_account_account_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterResponse) GetId() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Id
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *LoginOrRegisterResponse) GetPhoneNumber() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.PhoneNumber
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type SendOtpRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
PhoneNumber string `protobuf:"bytes,1,opt,name=phoneNumber,proto3" json:"phoneNumber,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SendOtpRequest) Reset() {
|
|
||||||
*x = SendOtpRequest{}
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[2]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SendOtpRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SendOtpRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SendOtpRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[2]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SendOtpRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SendOtpRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_contract_protobuf_account_account_proto_rawDescGZIP(), []int{2}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SendOtpRequest) GetPhoneNumber() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.PhoneNumber
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
type SendOtpResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SendOtpResponse) Reset() {
|
|
||||||
*x = SendOtpResponse{}
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[3]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *SendOtpResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*SendOtpResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *SendOtpResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_contract_protobuf_account_account_proto_msgTypes[3]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use SendOtpResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*SendOtpResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_contract_protobuf_account_account_proto_rawDescGZIP(), []int{3}
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_contract_protobuf_account_account_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
const file_contract_protobuf_account_account_proto_rawDesc = "" +
|
|
||||||
"\n" +
|
|
||||||
"'contract/protobuf/account/account.proto\x12\asendOtp\"Z\n" +
|
|
||||||
"\x16LoginOrRegisterRequest\x12 \n" +
|
|
||||||
"\vphoneNumber\x18\x01 \x01(\tR\vphoneNumber\x12\x1e\n" +
|
|
||||||
"\n" +
|
|
||||||
"verifyCode\x18\x02 \x01(\tR\n" +
|
|
||||||
"verifyCode\"K\n" +
|
|
||||||
"\x17LoginOrRegisterResponse\x12\x0e\n" +
|
|
||||||
"\x02id\x18\x01 \x01(\x04R\x02id\x12 \n" +
|
|
||||||
"\vphoneNumber\x18\x02 \x01(\tR\vphoneNumber\"2\n" +
|
|
||||||
"\x0eSendOtpRequest\x12 \n" +
|
|
||||||
"\vphoneNumber\x18\x01 \x01(\tR\vphoneNumber\"\x11\n" +
|
|
||||||
"\x0fSendOtpResponse2\xa4\x01\n" +
|
|
||||||
"\x0eAccountService\x12<\n" +
|
|
||||||
"\aSendOtp\x12\x17.sendOtp.SendOtpRequest\x1a\x18.sendOtp.SendOtpResponse\x12T\n" +
|
|
||||||
"\x0fLoginOrRegister\x12\x1f.sendOtp.LoginOrRegisterRequest\x1a .sendOtp.LoginOrRegisterResponseB\x1dZ\x1bcontract/goprotobuf/accountb\x06proto3"
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_contract_protobuf_account_account_proto_rawDescOnce sync.Once
|
|
||||||
file_contract_protobuf_account_account_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_contract_protobuf_account_account_proto_rawDescGZIP() []byte {
|
|
||||||
file_contract_protobuf_account_account_proto_rawDescOnce.Do(func() {
|
|
||||||
file_contract_protobuf_account_account_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_contract_protobuf_account_account_proto_rawDesc), len(file_contract_protobuf_account_account_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_contract_protobuf_account_account_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_contract_protobuf_account_account_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
|
||||||
var file_contract_protobuf_account_account_proto_goTypes = []any{
|
|
||||||
(*LoginOrRegisterRequest)(nil), // 0: sendOtp.LoginOrRegisterRequest
|
|
||||||
(*LoginOrRegisterResponse)(nil), // 1: sendOtp.LoginOrRegisterResponse
|
|
||||||
(*SendOtpRequest)(nil), // 2: sendOtp.SendOtpRequest
|
|
||||||
(*SendOtpResponse)(nil), // 3: sendOtp.SendOtpResponse
|
|
||||||
}
|
|
||||||
var file_contract_protobuf_account_account_proto_depIdxs = []int32{
|
|
||||||
2, // 0: sendOtp.AccountService.SendOtp:input_type -> sendOtp.SendOtpRequest
|
|
||||||
0, // 1: sendOtp.AccountService.LoginOrRegister:input_type -> sendOtp.LoginOrRegisterRequest
|
|
||||||
3, // 2: sendOtp.AccountService.SendOtp:output_type -> sendOtp.SendOtpResponse
|
|
||||||
1, // 3: sendOtp.AccountService.LoginOrRegister:output_type -> sendOtp.LoginOrRegisterResponse
|
|
||||||
2, // [2:4] is the sub-list for method output_type
|
|
||||||
0, // [0:2] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_contract_protobuf_account_account_proto_init() }
|
|
||||||
func file_contract_protobuf_account_account_proto_init() {
|
|
||||||
if File_contract_protobuf_account_account_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_contract_protobuf_account_account_proto_rawDesc), len(file_contract_protobuf_account_account_proto_rawDesc)),
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 4,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_contract_protobuf_account_account_proto_goTypes,
|
|
||||||
DependencyIndexes: file_contract_protobuf_account_account_proto_depIdxs,
|
|
||||||
MessageInfos: file_contract_protobuf_account_account_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_contract_protobuf_account_account_proto = out.File
|
|
||||||
file_contract_protobuf_account_account_proto_goTypes = nil
|
|
||||||
file_contract_protobuf_account_account_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,159 +0,0 @@
|
||||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// - protoc-gen-go-grpc v1.6.1
|
|
||||||
// - protoc v3.21.12
|
|
||||||
// source: contract/protobuf/account/account.proto
|
|
||||||
|
|
||||||
package account
|
|
||||||
|
|
||||||
import (
|
|
||||||
context "context"
|
|
||||||
grpc "google.golang.org/grpc"
|
|
||||||
codes "google.golang.org/grpc/codes"
|
|
||||||
status "google.golang.org/grpc/status"
|
|
||||||
)
|
|
||||||
|
|
||||||
// This is a compile-time assertion to ensure that this generated file
|
|
||||||
// is compatible with the grpc package it is being compiled against.
|
|
||||||
// Requires gRPC-Go v1.64.0 or later.
|
|
||||||
const _ = grpc.SupportPackageIsVersion9
|
|
||||||
|
|
||||||
const (
|
|
||||||
AccountService_SendOtp_FullMethodName = "/sendOtp.AccountService/SendOtp"
|
|
||||||
AccountService_LoginOrRegister_FullMethodName = "/sendOtp.AccountService/LoginOrRegister"
|
|
||||||
)
|
|
||||||
|
|
||||||
// AccountServiceClient is the client API for AccountService service.
|
|
||||||
//
|
|
||||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
|
||||||
type AccountServiceClient interface {
|
|
||||||
SendOtp(ctx context.Context, in *SendOtpRequest, opts ...grpc.CallOption) (*SendOtpResponse, error)
|
|
||||||
LoginOrRegister(ctx context.Context, in *LoginOrRegisterRequest, opts ...grpc.CallOption) (*LoginOrRegisterResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type accountServiceClient struct {
|
|
||||||
cc grpc.ClientConnInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewAccountServiceClient(cc grpc.ClientConnInterface) AccountServiceClient {
|
|
||||||
return &accountServiceClient{cc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *accountServiceClient) SendOtp(ctx context.Context, in *SendOtpRequest, opts ...grpc.CallOption) (*SendOtpResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(SendOtpResponse)
|
|
||||||
err := c.cc.Invoke(ctx, AccountService_SendOtp_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *accountServiceClient) LoginOrRegister(ctx context.Context, in *LoginOrRegisterRequest, opts ...grpc.CallOption) (*LoginOrRegisterResponse, error) {
|
|
||||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
|
||||||
out := new(LoginOrRegisterResponse)
|
|
||||||
err := c.cc.Invoke(ctx, AccountService_LoginOrRegister_FullMethodName, in, out, cOpts...)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return out, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountServiceServer is the server API for AccountService service.
|
|
||||||
// All implementations must embed UnimplementedAccountServiceServer
|
|
||||||
// for forward compatibility.
|
|
||||||
type AccountServiceServer interface {
|
|
||||||
SendOtp(context.Context, *SendOtpRequest) (*SendOtpResponse, error)
|
|
||||||
LoginOrRegister(context.Context, *LoginOrRegisterRequest) (*LoginOrRegisterResponse, error)
|
|
||||||
mustEmbedUnimplementedAccountServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
// UnimplementedAccountServiceServer must be embedded to have
|
|
||||||
// forward compatible implementations.
|
|
||||||
//
|
|
||||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
|
||||||
// pointer dereference when methods are called.
|
|
||||||
type UnimplementedAccountServiceServer struct{}
|
|
||||||
|
|
||||||
func (UnimplementedAccountServiceServer) SendOtp(context.Context, *SendOtpRequest) (*SendOtpResponse, error) {
|
|
||||||
return nil, status.Error(codes.Unimplemented, "method SendOtp not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedAccountServiceServer) LoginOrRegister(context.Context, *LoginOrRegisterRequest) (*LoginOrRegisterResponse, error) {
|
|
||||||
return nil, status.Error(codes.Unimplemented, "method LoginOrRegister not implemented")
|
|
||||||
}
|
|
||||||
func (UnimplementedAccountServiceServer) mustEmbedUnimplementedAccountServiceServer() {}
|
|
||||||
func (UnimplementedAccountServiceServer) testEmbeddedByValue() {}
|
|
||||||
|
|
||||||
// UnsafeAccountServiceServer may be embedded to opt out of forward compatibility for this service.
|
|
||||||
// Use of this interface is not recommended, as added methods to AccountServiceServer will
|
|
||||||
// result in compilation errors.
|
|
||||||
type UnsafeAccountServiceServer interface {
|
|
||||||
mustEmbedUnimplementedAccountServiceServer()
|
|
||||||
}
|
|
||||||
|
|
||||||
func RegisterAccountServiceServer(s grpc.ServiceRegistrar, srv AccountServiceServer) {
|
|
||||||
// If the following call panics, it indicates UnimplementedAccountServiceServer was
|
|
||||||
// embedded by pointer and is nil. This will cause panics if an
|
|
||||||
// unimplemented method is ever invoked, so we test this at initialization
|
|
||||||
// time to prevent it from happening at runtime later due to I/O.
|
|
||||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
|
||||||
t.testEmbeddedByValue()
|
|
||||||
}
|
|
||||||
s.RegisterService(&AccountService_ServiceDesc, srv)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _AccountService_SendOtp_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(SendOtpRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(AccountServiceServer).SendOtp(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: AccountService_SendOtp_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(AccountServiceServer).SendOtp(ctx, req.(*SendOtpRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
func _AccountService_LoginOrRegister_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
|
||||||
in := new(LoginOrRegisterRequest)
|
|
||||||
if err := dec(in); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if interceptor == nil {
|
|
||||||
return srv.(AccountServiceServer).LoginOrRegister(ctx, in)
|
|
||||||
}
|
|
||||||
info := &grpc.UnaryServerInfo{
|
|
||||||
Server: srv,
|
|
||||||
FullMethod: AccountService_LoginOrRegister_FullMethodName,
|
|
||||||
}
|
|
||||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
|
||||||
return srv.(AccountServiceServer).LoginOrRegister(ctx, req.(*LoginOrRegisterRequest))
|
|
||||||
}
|
|
||||||
return interceptor(ctx, in, info, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AccountService_ServiceDesc is the grpc.ServiceDesc for AccountService service.
|
|
||||||
// It's only intended for direct use with grpc.RegisterService,
|
|
||||||
// and not to be introspected or modified (even as a copy)
|
|
||||||
var AccountService_ServiceDesc = grpc.ServiceDesc{
|
|
||||||
ServiceName: "sendOtp.AccountService",
|
|
||||||
HandlerType: (*AccountServiceServer)(nil),
|
|
||||||
Methods: []grpc.MethodDesc{
|
|
||||||
{
|
|
||||||
MethodName: "SendOtp",
|
|
||||||
Handler: _AccountService_SendOtp_Handler,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
MethodName: "LoginOrRegister",
|
|
||||||
Handler: _AccountService_LoginOrRegister_Handler,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Streams: []grpc.StreamDesc{},
|
|
||||||
Metadata: "contract/protobuf/account/account.proto",
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
|
|
||||||
package sendOtp;
|
|
||||||
option go_package = "contract/goprotobuf/account";
|
|
||||||
|
|
||||||
message LoginOrRegisterRequest{
|
|
||||||
string phoneNumber = 1;
|
|
||||||
string verifyCode = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message LoginOrRegisterResponse {
|
|
||||||
uint64 id = 1;
|
|
||||||
string phoneNumber = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
message SendOtpRequest {
|
|
||||||
string phoneNumber = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SendOtpResponse {}
|
|
||||||
|
|
||||||
service AccountService {
|
|
||||||
rpc SendOtp(SendOtpRequest) returns (SendOtpResponse);
|
|
||||||
rpc LoginOrRegister(LoginOrRegisterRequest) returns(LoginOrRegisterResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -8,7 +8,7 @@ import (
|
||||||
func MigrateMariaDB(cfg mysql.Config) func() {
|
func MigrateMariaDB(cfg mysql.Config) func() {
|
||||||
migrations := migrator.New(migrator.Config{
|
migrations := migrator.New(migrator.Config{
|
||||||
MysqlConfig: cfg,
|
MysqlConfig: cfg,
|
||||||
MigrationPath: "../../../repository/mysql/migrations",
|
MigrationPath: "../../../repository/mysql/migration",
|
||||||
MigrationDBName: "gorp_migrations",
|
MigrationDBName: "gorp_migrations",
|
||||||
})
|
})
|
||||||
migrations.Up()
|
migrations.Up()
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
service:
|
|
||||||
length_of_otp_code: 6
|
|
||||||
otp_chars: "0123456789"
|
|
||||||
otp_expire_time: 2
|
|
||||||
redis_db:
|
|
||||||
host:
|
|
||||||
port:
|
|
||||||
password:
|
|
||||||
db:
|
|
||||||
mysql_db:
|
|
||||||
username:
|
|
||||||
password:
|
|
||||||
port:
|
|
||||||
host:
|
|
||||||
db_name:
|
|
||||||
kavenegar:
|
|
||||||
api_key:
|
|
||||||
sender:
|
|
||||||
grpc_server:
|
|
||||||
port:
|
|
||||||
network:
|
|
||||||
grpc_client:
|
|
||||||
host:
|
|
||||||
port:
|
|
||||||
|
|
||||||
|
|
||||||
path_of_migration: ./account/repository/mysql/migration
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
service:
|
|
||||||
length_of_otp_code: 6
|
|
||||||
otp_chars: "0123456789"
|
|
||||||
otp_expire_time: 2
|
|
||||||
redis_db:
|
|
||||||
host:
|
|
||||||
port:
|
|
||||||
password:
|
|
||||||
db:
|
|
||||||
mysql_db:
|
|
||||||
username:
|
|
||||||
password:
|
|
||||||
port:
|
|
||||||
host:
|
|
||||||
db_name:
|
|
||||||
kavenegar:
|
|
||||||
api_key:
|
|
||||||
sender:
|
|
||||||
|
|
||||||
path_of_migration: ./driverapp/repository/mysql/migration
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
services:
|
|
||||||
driver_mariadb:
|
|
||||||
image: bitnami/mariadb:11.1
|
|
||||||
container_name: driver_mariadb
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "3305:3306"
|
|
||||||
volumes:
|
|
||||||
- 'driver-mariadb-data:/bitnami/mariadb'
|
|
||||||
environment:
|
|
||||||
MARIADB_USER: driver_admin
|
|
||||||
MARIADB_PASSWORD: password123
|
|
||||||
MARIADB_DATABASE: driver_db
|
|
||||||
MARIADB_ROOT_PASSWORD: password123
|
|
||||||
driver_redis:
|
|
||||||
image: bitnami/redis:6.2
|
|
||||||
container_name: driver-redis
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- '6380:6379'
|
|
||||||
command: redis-server --loglevel warning --protected-mode no --save "" --appendonly no
|
|
||||||
environment:
|
|
||||||
- ALLOW_EMPTY_PASSWORD=yes
|
|
||||||
volumes:
|
|
||||||
- driver-redis-data:/data
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
driver-mariadb-data:
|
|
||||||
driver-redis-data:
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
ARG GO_IMAGE_NAME
|
|
||||||
ARG GO_IMAGE_VERSION
|
|
||||||
|
|
||||||
FROM ${GO_IMAGE_NAME}:${GO_IMAGE_VERSION}
|
|
||||||
ENV GOPROXY=https://package-mirror.liara.ir/repository/go/
|
|
||||||
ENV GOSUMDB=off
|
|
||||||
|
|
||||||
WORKDIR /home/app
|
|
||||||
|
|
||||||
COPY go.mod go.sum ./
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
RUN go install github.com/air-verse/air@latest
|
|
||||||
|
|
||||||
RUN printf '#!/bin/sh\n./cmd/productapp/temp/main migrate --up\nexec ./cmd/productapp/temp/main serve\n' > /entrypoint.sh && chmod +x /entrypoint.sh
|
|
||||||
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
CMD ["air", "-c", "/home/app/.air/.air.productapp.toml"]
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
services:
|
|
||||||
productapp-mysql:
|
|
||||||
image: mirror2.chabokan.net/mysql:8.0
|
|
||||||
container_name: productapp-mysql
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "3307:3306"
|
|
||||||
volumes:
|
|
||||||
- productapp-mysql-data:/var/lib/mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_DATABASE: niki_db
|
|
||||||
MYSQL_ROOT_PASSWORD: secret
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
productapp-mysql-data:
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
services:
|
|
||||||
productapp-app:
|
|
||||||
build:
|
|
||||||
context: ../../..
|
|
||||||
dockerfile: deploy/productapp/development/Dockerfile
|
|
||||||
args:
|
|
||||||
GO_IMAGE_NAME: ${GO_IMAGE_NAME}
|
|
||||||
GO_IMAGE_VERSION: ${GO_IMAGE_VERSION}
|
|
||||||
container_name: productapp-app
|
|
||||||
ports:
|
|
||||||
- "8080:8080"
|
|
||||||
volumes:
|
|
||||||
- ../../..:/home/app
|
|
||||||
environment:
|
|
||||||
DB_HOST: productapp-mysql
|
|
||||||
DB_USERNAME: root
|
|
||||||
DB_PASSWORD: secret
|
|
||||||
DB_NAME: niki_db
|
|
||||||
MIGRATION_PATH: /home/app/productapp/repository/migrations
|
|
||||||
depends_on:
|
|
||||||
productapp-mysql:
|
|
||||||
condition: service_healthy
|
|
||||||
restart: unless-stopped
|
|
||||||
|
|
||||||
productapp-mysql:
|
|
||||||
image: mirror2.chabokan.net/mysql:8.0
|
|
||||||
container_name: productapp-mysql
|
|
||||||
restart: always
|
|
||||||
ports:
|
|
||||||
- "3307:3306"
|
|
||||||
volumes:
|
|
||||||
- productapp-mysql-data:/var/lib/mysql
|
|
||||||
environment:
|
|
||||||
MYSQL_DATABASE: niki_db
|
|
||||||
MYSQL_ROOT_PASSWORD: secret
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
|
||||||
interval: 10s
|
|
||||||
timeout: 5s
|
|
||||||
retries: 5
|
|
||||||
|
|
||||||
volumes:
|
|
||||||
productapp-mysql-data:
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
|
|
||||||
type Driver struct {
|
|
||||||
ID types.ID
|
|
||||||
PhoneNumber string
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
"errors"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/account/entity"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/database/mysql"
|
|
||||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
types "git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
StatementKeyIsExistDriverByPhoneNumber = iota + 1
|
|
||||||
StatementKeyCreateDriver = iota + 1
|
|
||||||
)
|
|
||||||
|
|
||||||
type AccountRepo struct {
|
|
||||||
db *mysql.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(db *mysql.DB) AccountRepo {
|
|
||||||
return AccountRepo{
|
|
||||||
db: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r AccountRepo) IsExistDriverByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Driver, error) {
|
|
||||||
const op = "Repository.IsExistDriverByPhoneNumber"
|
|
||||||
query := `select * from drivers where phone_number = ?`
|
|
||||||
stmt, err := r.db.PrepareStatement(ctx, StatementKeyIsExistDriverByPhoneNumber, query)
|
|
||||||
if err != nil {
|
|
||||||
return false, entity.Driver{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantPrepareStatement)
|
|
||||||
}
|
|
||||||
|
|
||||||
defer stmt.Close()
|
|
||||||
|
|
||||||
row := stmt.QueryRowContext(ctx, phoneNumber)
|
|
||||||
d, sErr := DriverScan(row)
|
|
||||||
if sErr != nil {
|
|
||||||
if errors.Is(sErr, sql.ErrNoRows) {
|
|
||||||
return false, entity.Driver{}, richerror.New(op).WithKind(richerror.KindNotFound).
|
|
||||||
WithMessage(errmsg.ErrorMsgNotFound)
|
|
||||||
}
|
|
||||||
return false, entity.Driver{}, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, d, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r AccountRepo) CreateDriver(ctx context.Context, driver entity.Driver) (entity.Driver, error) {
|
|
||||||
const op = "Repository.CreateDriver"
|
|
||||||
query := `insert into drivers(phone_number) values(?)`
|
|
||||||
|
|
||||||
stmt, err := r.db.PrepareStatement(ctx, StatementKeyCreateDriver, query)
|
|
||||||
if err != nil {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantPrepareStatement)
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := stmt.ExecContext(ctx, driver.PhoneNumber)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected).
|
|
||||||
WithMessage(errmsg.ErrorMsgNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
id, _ := res.LastInsertId()
|
|
||||||
driver.ID = types.ID(id)
|
|
||||||
|
|
||||||
return driver, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DriverScan(scanner mysql.Scanner) (entity.Driver, error) {
|
|
||||||
var createdAt, updatedAt time.Time
|
|
||||||
var driver entity.Driver
|
|
||||||
|
|
||||||
err := scanner.Scan(&driver.ID, &driver.PhoneNumber, &createdAt, &updatedAt)
|
|
||||||
|
|
||||||
return driver, err
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
-- +migrate Up
|
|
||||||
CREATE TABLE `drivers`(
|
|
||||||
`iD` INT PRIMARY KEY AUTO_INCREMENT,
|
|
||||||
`phone_number` VARCHAR(191) NOT NULL UNIQUE ,
|
|
||||||
|
|
||||||
`created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
||||||
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
-- +migrate Down
|
|
||||||
DROP TABLE `drivers`;
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
package redis
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RepositoryOtp struct {
|
|
||||||
conn *redis.Adapter
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewRepositoryOtp(conn *redis.Adapter) RepositoryOtp {
|
|
||||||
return RepositoryOtp{conn: conn}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r RepositoryOtp) IsExistPhoneNumber(ctx context.Context, phoneNumber string) (bool, error) {
|
|
||||||
const op = "RepositoryOtp.IsExistPhoneNumber"
|
|
||||||
|
|
||||||
result, err := r.conn.Client().Exists(ctx, phoneNumber).Result()
|
|
||||||
if err != nil {
|
|
||||||
return false, richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if result == 0 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r RepositoryOtp) SaveCodeWithPhoneNumber(ctx context.Context, phoneNumber string, code string, expireTime time.Duration) error {
|
|
||||||
const op = "RepositoryOtp.SaveCodeWithPhoneNumber"
|
|
||||||
|
|
||||||
_, err := r.conn.Client().Set(ctx, phoneNumber, code, expireTime).Result()
|
|
||||||
if err != nil {
|
|
||||||
return richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r RepositoryOtp) GetCodeByPhoneNumber(ctx context.Context, phoneNumber string) (string, error) {
|
|
||||||
const op = "RepositoryOtp.GetCodeByPhoneNumber"
|
|
||||||
|
|
||||||
result, err := r.conn.Client().Get(ctx, phoneNumber).Result()
|
|
||||||
if err != nil {
|
|
||||||
return "", richerror.New(op).WithKind(richerror.KindUnexpected).WithErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r RepositoryOtp) DeleteCodeByPhoneNumber(ctx context.Context, PhoneNumber string) (bool, error) {
|
|
||||||
const op = "RepositoryOtp.DeleteCodeByPhoneNumber"
|
|
||||||
success, err := r.conn.Client().Del(ctx, PhoneNumber).Result()
|
|
||||||
if err != nil {
|
|
||||||
return false, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
if success != 1 {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,115 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"math/rand"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
smscontract "git.gocasts.ir/ebhomengo/niki/contract/sms"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/account/entity"
|
|
||||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
LengthOfOtpCode int `koanf:"length_of_otp_code"`
|
|
||||||
OtpChars string `koanf:"otp_chars"`
|
|
||||||
OtpExpireTime time.Duration `koanf:"otp_expire_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type RepositoryOtp interface {
|
|
||||||
IsExistPhoneNumber(ctx context.Context, phoneNumber string) (bool, error)
|
|
||||||
SaveCodeWithPhoneNumber(ctx context.Context, phoneNumber string, code string, expireTime time.Duration) error
|
|
||||||
GetCodeByPhoneNumber(ctx context.Context, phoneNumber string) (string, error)
|
|
||||||
DeleteCodeByPhoneNumber(ctx context.Context, PhoneNumber string) (bool, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Repository interface {
|
|
||||||
IsExistDriverByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Driver, error)
|
|
||||||
CreateDriver(ctx context.Context, driver entity.Driver) (entity.Driver, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
config Config
|
|
||||||
repositoryOtp RepositoryOtp
|
|
||||||
repository Repository
|
|
||||||
smsContract smscontract.SmsAdapter
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(cfg Config, repositoryOtp RepositoryOtp, repository Repository, smsContract smscontract.SmsAdapter) Service {
|
|
||||||
return Service{
|
|
||||||
config: cfg,
|
|
||||||
repositoryOtp: repositoryOtp,
|
|
||||||
repository: repository,
|
|
||||||
smsContract: smsContract,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) SendOTP(ctx context.Context, phoneNumber string) error {
|
|
||||||
const op = "accountService.SendOTP"
|
|
||||||
|
|
||||||
isExist, iErr := s.repositoryOtp.IsExistPhoneNumber(ctx, phoneNumber)
|
|
||||||
if iErr != nil {
|
|
||||||
return richerror.New(op).WithErr(iErr).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
if isExist {
|
|
||||||
return richerror.New(op).WithMessage(errmsg.ErrorMsgOtpCodeExist).WithKind(richerror.KindForbidden)
|
|
||||||
}
|
|
||||||
|
|
||||||
newCode := s.generateVerificationCode()
|
|
||||||
sErr := s.repositoryOtp.SaveCodeWithPhoneNumber(ctx, phoneNumber, newCode, s.config.OtpExpireTime)
|
|
||||||
if sErr != nil {
|
|
||||||
return richerror.New(op).WithErr(sErr).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
go s.smsContract.Send(phoneNumber, newCode)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) LoginOrRegisterDriver(ctx context.Context, phoneNumber string, verifyCode string) (entity.Driver, error) {
|
|
||||||
const op = "accountService.LoginOrRegisterDriver"
|
|
||||||
|
|
||||||
code, gErr := s.repositoryOtp.GetCodeByPhoneNumber(ctx, phoneNumber)
|
|
||||||
if gErr != nil {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithErr(gErr).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
if code == "" || code != verifyCode {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithMessage(errmsg.ErrorMsgOtpCodeIsNotValid).WithKind(richerror.KindForbidden)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, dErr := s.repositoryOtp.DeleteCodeByPhoneNumber(ctx, phoneNumber)
|
|
||||||
if dErr != nil {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithErr(dErr).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
isExist, driver, eErr := s.repository.IsExistDriverByPhoneNumber(ctx, phoneNumber)
|
|
||||||
if eErr != nil {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithErr(eErr).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !isExist {
|
|
||||||
newDriver, cErr := s.repository.CreateDriver(ctx, entity.Driver{
|
|
||||||
PhoneNumber: phoneNumber,
|
|
||||||
})
|
|
||||||
if cErr != nil {
|
|
||||||
return entity.Driver{}, richerror.New(op).WithErr(cErr).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
driver = newDriver
|
|
||||||
}
|
|
||||||
|
|
||||||
return driver, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) generateVerificationCode() string {
|
|
||||||
result := make([]byte, s.config.LengthOfOtpCode)
|
|
||||||
for i := 0; i < s.config.LengthOfOtpCode; i++ {
|
|
||||||
result[i] = s.config.OtpChars[rand.Intn(len(s.config.OtpChars))]
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(result)
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Benefactor struct {
|
|
||||||
ID types.ID
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
PhoneNumber string
|
|
||||||
Description string
|
|
||||||
Email string
|
|
||||||
Gender Gender
|
|
||||||
BirthDate time.Time
|
|
||||||
Status BenefactorStatus
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
type BenefactorStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
BenefactorActiveStatus = BenefactorStatus("active")
|
|
||||||
BenefactorInactiveStatus = BenefactorStatus("inactive")
|
|
||||||
)
|
|
||||||
|
|
||||||
var BenefactorStatusStrings = map[BenefactorStatus]string{
|
|
||||||
BenefactorActiveStatus: "active",
|
|
||||||
BenefactorInactiveStatus: "inactive",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (b BenefactorStatus) IsValid() bool {
|
|
||||||
_, ok := BenefactorStatusStrings[b]
|
|
||||||
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
type Gender string
|
|
||||||
|
|
||||||
const (
|
|
||||||
MaleGender = Gender("male")
|
|
||||||
FemaleGender = Gender("female")
|
|
||||||
)
|
|
||||||
|
|
||||||
var GenderStrings = map[Gender]string{
|
|
||||||
MaleGender: "male",
|
|
||||||
FemaleGender: "female",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g Gender) IsValid() bool {
|
|
||||||
_, ok := GenderStrings[g]
|
|
||||||
|
|
||||||
return ok
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
package mysql
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/benefactor/entity"
|
|
||||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (d *DB) Create(ctx context.Context, b entity.Benefactor) (entity.Benefactor, error) {
|
|
||||||
const op = "repository.mysql.benefactor.create"
|
|
||||||
|
|
||||||
query := `INSERT INTO benefactors
|
|
||||||
(first_name, last_name, phone_number, description, email, gender, birthdate)
|
|
||||||
VALUES(?, ?, ?, ?, ?, ?, ?)`
|
|
||||||
|
|
||||||
res, err := d.conn.Conn().ExecContext(ctx, query,
|
|
||||||
b.FirstName, b.LastName, b.PhoneNumber,b.Description, b.Email, b.Gender, b.BirthDate)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
id, _ := res.LastInsertId()
|
|
||||||
b.ID = types.ID(id)
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DB) GetBenefactorByID(ctx context.Context, benefactorID types.ID) (entity.Benefactor, error) {
|
|
||||||
const op = "repository.mysql.benefactor.getBenefactorById"
|
|
||||||
var b entity.Benefactor
|
|
||||||
|
|
||||||
query := `SELECT * FROM benefactors WHERE id = ?`
|
|
||||||
|
|
||||||
row := d.conn.Conn().QueryRowContext(ctx, query, benefactorID)
|
|
||||||
err := row.Scan(&b.ID, &b.FirstName, &b.LastName, &b.PhoneNumber,
|
|
||||||
&b.Description, &b.Email, b.Gender, b.BirthDate, b.Status)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindNotFound)
|
|
||||||
}
|
|
||||||
|
|
||||||
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return b, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DB) Activate(ctx context.Context, benefactorID types.ID) error {
|
|
||||||
const op = "repository.mysql.benefactor.Activate"
|
|
||||||
|
|
||||||
query := `UPDATE benefactors SET status ='active' WHERE id = ?`
|
|
||||||
|
|
||||||
_, err := d.conn.Conn().ExecContext(ctx, query, benefactorID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *DB) Deactivate(ctx context.Context, benefactorID types.ID) error {
|
|
||||||
const op = "repository.mysql.benefactor.Deativate"
|
|
||||||
|
|
||||||
query := `UPDATE benefactors SET status ='inactive' WHERE id = ?`
|
|
||||||
|
|
||||||
_, err := d.conn.Conn().ExecContext(ctx, query, benefactorID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return richerror.New(op).WithErr(err).
|
|
||||||
WithMessage(errmsg.ErrorMsgSomethingWentWrong).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package mysql
|
|
||||||
|
|
||||||
import(
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DB struct {
|
|
||||||
conn *mysql.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(conn *mysql.DB) *DB {
|
|
||||||
return &DB{conn: conn}
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
-- +migrate Up
|
|
||||||
CREATE TABLE `benefactors` (
|
|
||||||
`id` INT NOT NULL PRIMARY KEY,
|
|
||||||
`first_name` VARCHAR(100) NOT NULL,
|
|
||||||
`last_name` VARCHAR(100) NOT NULL,
|
|
||||||
`phone_number` VARCHAR(20) NOT NULL,
|
|
||||||
`description` TEXT,
|
|
||||||
`email` VARCHAR(255),
|
|
||||||
`gender` ENUM('male', 'female') NOT NULL,
|
|
||||||
`birth_date` DATE,
|
|
||||||
`status` ENUM('active', 'inactive') NOT NULL DEFAULT `active`,
|
|
||||||
|
|
||||||
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
`updated_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
||||||
);
|
|
||||||
|
|
||||||
-- +migrate Down
|
|
||||||
DROP TABLE `benefactors`;
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/benefactor/entity"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CreateBenefactorRequest struct {
|
|
||||||
ID types.ID `json:"id"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
Description string `json:"description"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Gender entity.Gender `json:"gender"`
|
|
||||||
BirthDate time.Time `json:"birth_date"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreateBenefactorResponse struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProfileRequest struct {
|
|
||||||
BenefactorID types.ID
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProfileResponse struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ActivenessRequest struct {
|
|
||||||
BenefactorID types.ID
|
|
||||||
}
|
|
||||||
|
|
@ -1,87 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/benefactor/entity"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Repository interface {
|
|
||||||
Create(ctx context.Context, b entity.Benefactor) (entity.Benefactor, error)
|
|
||||||
GetBenefactorByID(ctx context.Context, benefactorID types.ID) (entity.Benefactor, error)
|
|
||||||
Activate(ctx context.Context, benefactorID types.ID) error
|
|
||||||
Deactivate(ctx context.Context, benefactorID types.ID) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
repo Repository
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(repo Repository) Service {
|
|
||||||
return Service{repo: repo}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) CreateBenefactor(ctx context.Context, req CreateBenefactorRequest) (CreateBenefactorResponse, error) {
|
|
||||||
const op = "beneafactorservice.CreateBenefactor"
|
|
||||||
|
|
||||||
benefactor := entity.Benefactor{
|
|
||||||
ID: 0,
|
|
||||||
FirstName: req.FirstName,
|
|
||||||
LastName: req.LastName,
|
|
||||||
PhoneNumber: req.PhoneNumber,
|
|
||||||
Description: req.Description,
|
|
||||||
Email: req.Email,
|
|
||||||
Gender: req.Gender,
|
|
||||||
BirthDate: req.BirthDate,
|
|
||||||
Status: entity.BenefactorActiveStatus,
|
|
||||||
}
|
|
||||||
|
|
||||||
createdBenefactor, err := s.repo.Create(ctx, benefactor)
|
|
||||||
if err != nil {
|
|
||||||
return CreateBenefactorResponse{}, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return CreateBenefactorResponse{
|
|
||||||
Name: createdBenefactor.FirstName + " " + createdBenefactor.LastName,
|
|
||||||
Email: createdBenefactor.Email,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func(s Service) Profile(ctx context.Context, req ProfileRequest) (ProfileResponse, error) {
|
|
||||||
const op = "benefactorservice.Profile"
|
|
||||||
|
|
||||||
benefactor, err := s.repo.GetBenefactorByID(ctx, types.ID(req.BenefactorID))
|
|
||||||
if err != nil {
|
|
||||||
return ProfileResponse{}, richerror.New(op).WithErr(err).
|
|
||||||
WithMeta(map[string]interface{}{"req": req})
|
|
||||||
}
|
|
||||||
|
|
||||||
return ProfileResponse{Name: benefactor.FirstName + " " + benefactor.LastName}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) Activate(ctx context.Context, req ActivenessRequest) error {
|
|
||||||
const op = "benefactorservice.Activate"
|
|
||||||
|
|
||||||
err := s.repo.Activate(ctx, types.ID(req.BenefactorID))
|
|
||||||
if err != nil {
|
|
||||||
return richerror.New(op).WithErr(err).
|
|
||||||
WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) Dectivate(ctx context.Context, req ActivenessRequest) error {
|
|
||||||
const op = "benefactorservice.Deactivate"
|
|
||||||
|
|
||||||
err := s.repo.Deactivate(ctx, types.ID(req.BenefactorID))
|
|
||||||
if err != nil {
|
|
||||||
return richerror.New(op).WithErr(err).
|
|
||||||
WithKind(richerror.KindUnexpected)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
@ -5,31 +5,41 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type CampaignStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CampaignDraft CampaignStatus = "draft"
|
||||||
|
CampaignActive CampaignStatus = "active"
|
||||||
|
CampaignFinished CampaignStatus = "completed"
|
||||||
|
CampaignPaused CampaignStatus = "paused"
|
||||||
|
CampaignCanceled CampaignStatus = "cancelled"
|
||||||
|
)
|
||||||
|
|
||||||
type Campaign struct {
|
type Campaign struct {
|
||||||
ID types.ID `json:"id"`
|
ID types.ID `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Link string `json:"link"`
|
Link string `json:"link"`
|
||||||
Slogan string `json:"slogan"` //
|
Slogan string `json:"slogan"` //
|
||||||
GoalAmount float64 `json:"goal_amount"`
|
GoalAmount float64 `json:"goal_amount"`
|
||||||
RaisedAmount float64 `json:"raised_amount"`
|
RaisedAmount float64 `json:"raised_amount"`
|
||||||
Status types.CampaignStatus `json:"status"`
|
Status CampaignStatus `json:"status"`
|
||||||
CreatedAt time.Time `json:"created_at"`
|
CreatedAt time.Time `json:"created_at"`
|
||||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||||
AdminID types.ID `json:"creator_id"`
|
AdminID types.ID `json:"creator_id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Behavior
|
// Behavior
|
||||||
func (c *Campaign) Activate() {
|
func (c *Campaign) Activate() {
|
||||||
if c.Status == types.CampaignDraft {
|
if c.Status == CampaignDraft {
|
||||||
c.Status = types.CampaignActive
|
c.Status = CampaignActive
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Campaign) AddFunds(amount float64) {
|
func (c *Campaign) AddFunds(amount float64) {
|
||||||
c.RaisedAmount += amount
|
c.RaisedAmount += amount
|
||||||
if c.RaisedAmount >= c.GoalAmount {
|
if c.RaisedAmount >= c.GoalAmount {
|
||||||
c.Status = types.CampaignFinished
|
c.Status = CampaignFinished
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,27 +3,11 @@ package service
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
|
"git.gocasts.ir/ebhomengo/niki/domain/campaign/service/mapper"
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
"git.gocasts.ir/ebhomengo/niki/types"
|
"git.gocasts.ir/ebhomengo/niki/types"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func ToCampaignEntity(req CreateCampaignRequest) entity.Campaign {
|
|
||||||
return entity.Campaign{
|
|
||||||
Title: req.Title,
|
|
||||||
Description: req.Description,
|
|
||||||
Link: req.Link,
|
|
||||||
Slogan: req.Slogan,
|
|
||||||
GoalAmount: req.GoalAmount,
|
|
||||||
RaisedAmount: 0,
|
|
||||||
Status: types.CampaignStatus(req.Status),
|
|
||||||
DeadlineAt: req.DeadlineAt,
|
|
||||||
AdminID: req.AdminID,
|
|
||||||
CreatedAt: time.Now(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateCampaign handles creation of a new campaign.
|
// CreateCampaign handles creation of a new campaign.
|
||||||
func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (types.ID, error) {
|
func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaignRequest) (types.ID, error) {
|
||||||
const op = "service.campaign.create_campaign"
|
const op = "service.campaign.create_campaign"
|
||||||
|
|
@ -32,7 +16,7 @@ func (s *CampaignService) CreateCampaign(ctx context.Context, req CreateCampaign
|
||||||
return 0, richerror.New(op).WithErr(err)
|
return 0, richerror.New(op).WithErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
campaign := ToCampaignEntity(req)
|
campaign := mapper.ToCampaignEntity(req)
|
||||||
|
|
||||||
id, err := s.repo.Create(ctx, campaign)
|
id, err := s.repo.Create(ctx, campaign)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
package mapper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/domain/campaign/entity"
|
||||||
|
param "git.gocasts.ir/ebhomengo/niki/domain/campaign/service"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ToCampaignEntity(req param.CreateCampaignRequest) entity.Campaign {
|
||||||
|
return entity.Campaign{
|
||||||
|
Title: req.Title,
|
||||||
|
Description: req.Description,
|
||||||
|
Link: req.Link,
|
||||||
|
Slogan: req.Slogan,
|
||||||
|
GoalAmount: req.GoalAmount,
|
||||||
|
RaisedAmount: 0,
|
||||||
|
Status: entity.CampaignStatus(req.Status),
|
||||||
|
DeadlineAt: req.DeadlineAt,
|
||||||
|
AdminID: req.AdminID,
|
||||||
|
CreatedAt: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,12 +19,3 @@ type CreateCampaignRequest struct {
|
||||||
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
DeadlineAt *time.Time `json:"deadline_at,omitempty"`
|
||||||
AdminID types.ID `json:"admin_id" validate:"required"`
|
AdminID types.ID `json:"admin_id" validate:"required"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CompletedCampaignResponse struct {
|
|
||||||
TotalChecked uint64 `json:"total_checked"`
|
|
||||||
TotalFinished uint64 `json:"total_finished"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type FilterRequest struct {
|
|
||||||
Limit uint32 `json:"total_checked"`
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,6 @@ type CampaignFilterParam struct {
|
||||||
IsArchived *bool
|
IsArchived *bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type CampaignStatus interface {
|
|
||||||
FindActiveCampaigns(ctx context.Context) ([]entity.Campaign, error)
|
|
||||||
UpdateStatus(ctx context.Context, id types.ID, status types.CampaignStatus) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type CampaignStorage interface {
|
type CampaignStorage interface {
|
||||||
Create(ctx context.Context, c entity.Campaign) (types.ID, error)
|
Create(ctx context.Context, c entity.Campaign) (types.ID, error)
|
||||||
Update(ctx context.Context, c entity.Campaign) error
|
Update(ctx context.Context, c entity.Campaign) error
|
||||||
|
|
@ -29,10 +24,10 @@ type CampaignStorage interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CampaignService struct {
|
type CampaignService struct {
|
||||||
repo CampaignStorage
|
repo CampaignStorage
|
||||||
repoStatus CampaignStatus
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewCampaignService constructs a new CampaignService.
|
||||||
func NewCampaignService(storage CampaignStorage) *CampaignService {
|
func NewCampaignService(storage CampaignStorage) *CampaignService {
|
||||||
return &CampaignService{
|
return &CampaignService{
|
||||||
repo: storage,
|
repo: storage,
|
||||||
|
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/types"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s *CampaignService) MonitorCampaignProgress(ctx context.Context, req FilterRequest) {
|
|
||||||
|
|
||||||
ticker := time.NewTicker(1 * time.Hour)
|
|
||||||
defer ticker.Stop()
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case <-ticker.C:
|
|
||||||
s.CheckAndCompleteCampaigns(ctx, req)
|
|
||||||
case <-ctx.Done():
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *CampaignService) CheckAndCompleteCampaigns(ctx context.Context, req FilterRequest) (CompletedCampaignResponse, error) {
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
|
|
||||||
//TODO:with filter request later complete
|
|
||||||
activeCampaigns, err := s.repoStatus.FindActiveCampaigns(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return CompletedCampaignResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var totalChecked uint64
|
|
||||||
var totalFinished uint64
|
|
||||||
|
|
||||||
for _, campaign := range activeCampaigns {
|
|
||||||
|
|
||||||
totalChecked++
|
|
||||||
|
|
||||||
shouldFinish := false
|
|
||||||
|
|
||||||
if campaign.DeadlineAt != nil && campaign.DeadlineAt.Before(now) {
|
|
||||||
shouldFinish = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if campaign.RaisedAmount >= campaign.GoalAmount {
|
|
||||||
shouldFinish = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if shouldFinish && campaign.Status != types.CampaignFinished {
|
|
||||||
if err := s.repoStatus.UpdateStatus(ctx, campaign.ID, types.CampaignFinished); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
totalFinished++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CompletedCampaignResponse{
|
|
||||||
TotalChecked: totalChecked,
|
|
||||||
TotalFinished: totalFinished,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Gateway struct {
|
|
||||||
ID uint
|
|
||||||
Name string
|
|
||||||
Code string
|
|
||||||
IsActive bool
|
|
||||||
Config json.RawMessage
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Currency string
|
|
||||||
|
|
||||||
const (
|
|
||||||
CurrencyIRR Currency = "IRR"
|
|
||||||
CurrencyUSD Currency = "USD"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PaymentStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
PaymentStatusPending PaymentStatus = "Pending"
|
|
||||||
PaymentStatusSuccess PaymentStatus = "Success"
|
|
||||||
PaymentStatusFailed PaymentStatus = "Failed"
|
|
||||||
PaymentStatusCancelled PaymentStatus = "Cancelled"
|
|
||||||
//...
|
|
||||||
)
|
|
||||||
|
|
||||||
type PayableType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
PayableTypeDonate PayableType = "Donate"
|
|
||||||
PayableTypeOrder PayableType = "Order"
|
|
||||||
PayableTypeWalet PayableType = "WaletCharge"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Payment struct {
|
|
||||||
ID uint
|
|
||||||
UserID uint
|
|
||||||
MethodID uint
|
|
||||||
GatewayID uint
|
|
||||||
PayableType PayableType
|
|
||||||
PayableID uint
|
|
||||||
TotalAmount int64
|
|
||||||
PaidAmount int64
|
|
||||||
Currency Currency
|
|
||||||
Status PaymentStatus
|
|
||||||
Description string
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
PaidAt *time.Time
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type PaymentMethod struct {
|
|
||||||
ID uint
|
|
||||||
Name string
|
|
||||||
IsActive bool
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
@ -1,35 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TransactionType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TransactionTypeRequest TransactionType = "request"
|
|
||||||
TransactionTypeVerify TransactionType = "verify"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TransactionStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TransactionStatusPending = "Pending"
|
|
||||||
TransactionStatusSuccess = "Success"
|
|
||||||
TransactionStatusFailed = "Failed"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PaymentTransaction struct {
|
|
||||||
ID uint
|
|
||||||
PaymentID uint
|
|
||||||
Type TransactionType
|
|
||||||
RequestData json.RawMessage
|
|
||||||
ResponseData json.RawMessage
|
|
||||||
RefID string
|
|
||||||
Status TransactionStatus
|
|
||||||
GatewayToken string
|
|
||||||
ErrorMessage string
|
|
||||||
CreatedAt time.Time
|
|
||||||
UpdatedAt time.Time
|
|
||||||
}
|
|
||||||
|
|
@ -12,7 +12,7 @@ func NewGatewayFactory() service.GatewayFactory {
|
||||||
return &gatewayFactoryImpl{}
|
return &gatewayFactoryImpl{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f gatewayFactoryImpl) GetGatewayAdapter(code string) (service.GatewayPort, error) {
|
func (f *gatewayFactoryImpl) GetGatewayAdapter(code string) (service.GatewayPort, error) {
|
||||||
switch code {
|
switch code {
|
||||||
case "melat":
|
case "melat":
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,13 @@
|
||||||
package repository
|
package repository
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/entity"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PaymentRepository struct {
|
type PaymentRepository struct {
|
||||||
DB *sql.DB
|
DB *sql.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreatePayment implements [service.PaymentRepo].
|
|
||||||
func (*PaymentRepository) CreatePayment(ctx context.Context, p *entity.Payment) error {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateTransaction implements [service.PaymentRepo].
|
|
||||||
func (p *PaymentRepository) CreateTransaction(ctx context.Context, t *entity.PaymentTransaction) error {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
// UpdateTransaction implements [service.PaymentRepo].
|
|
||||||
func (p *PaymentRepository) UpdateTransaction(ctx context.Context, t *entity.PaymentTransaction) error {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPaymentRepository(db *sql.DB) *PaymentRepository {
|
func NewPaymentRepository(db *sql.DB) *PaymentRepository {
|
||||||
return &PaymentRepository{
|
return &PaymentRepository{
|
||||||
DB: db,
|
DB: db,
|
||||||
|
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package repository
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"database/sql"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PaymentMethodRepository struct {
|
|
||||||
DB *sql.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetGatewayByCode implements [service.PaymentMethodRepo].
|
|
||||||
func (p *PaymentMethodRepository) GetGatewayByCode(ctx context.Context, code string) (entity.Gateway, error) {
|
|
||||||
panic("unimplemented")
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPaymentMethodRepository(db *sql.DB) *PaymentMethodRepository {
|
|
||||||
return &PaymentMethodRepository{
|
|
||||||
DB: db,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,94 @@
|
||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PaymentStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PaymentStatusPending PaymentStatus = "Pending"
|
||||||
|
PaymentStatusSuccess PaymentStatus = "Success"
|
||||||
|
PaymentStatusFailed PaymentStatus = "Failed"
|
||||||
|
PaymentStatusCancelled PaymentStatus = "Cancelled"
|
||||||
|
//...
|
||||||
|
)
|
||||||
|
|
||||||
|
type Currency string
|
||||||
|
|
||||||
|
const (
|
||||||
|
CurrencyIRR Currency = "IRR"
|
||||||
|
CurrencyUSD Currency = "USD"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransactionType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TransactionTypeRequest TransactionType = "request"
|
||||||
|
TransactionTypeVerify TransactionType = "verify"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TransactionStatus string
|
||||||
|
|
||||||
|
const (
|
||||||
|
TransactionStatusPending = "Pending"
|
||||||
|
TransactionStatusSuccess = "Success"
|
||||||
|
TransactionStatusFailed = "Failed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PayableType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
PayableTypeDonate PayableType = "Donate"
|
||||||
|
PayableTypeOrder PayableType = "Order"
|
||||||
|
PayableTypeWalet PayableType = "WaletCharge"
|
||||||
|
)
|
||||||
|
|
||||||
|
type PaymentMethod struct {
|
||||||
|
ID uint
|
||||||
|
Name string
|
||||||
|
IsActive bool
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
type Gateway struct {
|
||||||
|
ID uint
|
||||||
|
Name string
|
||||||
|
Code string
|
||||||
|
IsActive bool
|
||||||
|
Config json.RawMessage
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type Payment struct {
|
||||||
|
ID uint
|
||||||
|
UserID uint
|
||||||
|
MethodID uint
|
||||||
|
GatewayID uint
|
||||||
|
PayableType PayableType
|
||||||
|
PayableID uint
|
||||||
|
TotalAmount int64
|
||||||
|
PaidAmount int64
|
||||||
|
Currency Currency
|
||||||
|
Status PaymentStatus
|
||||||
|
Description string
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
PaidAt *time.Time
|
||||||
|
}
|
||||||
|
|
||||||
|
type PaymentTransaction struct {
|
||||||
|
ID uint
|
||||||
|
PaymentID uint
|
||||||
|
Type TransactionType
|
||||||
|
RequestData json.RawMessage
|
||||||
|
ResponseData json.RawMessage
|
||||||
|
RefID string
|
||||||
|
Status TransactionStatus
|
||||||
|
GatewayToken string
|
||||||
|
ErrorMessage string
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
|
|
@ -1,10 +1,8 @@
|
||||||
package service
|
package service
|
||||||
|
|
||||||
import "git.gocasts.ir/ebhomengo/niki/domain/payment/entity"
|
|
||||||
|
|
||||||
type InitiatePaymentRequest struct {
|
type InitiatePaymentRequest struct {
|
||||||
UserID uint
|
UserID uint
|
||||||
PayableType entity.PayableType
|
PayableType PayableType
|
||||||
PayableID uint
|
PayableID uint
|
||||||
GatewayCode string
|
GatewayCode string
|
||||||
CallbackURL string
|
CallbackURL string
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
type PaymentMethodService struct {
|
|
||||||
}
|
|
||||||
|
|
@ -5,23 +5,18 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/entity"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type PaymentService struct {
|
type PaymentService struct {
|
||||||
paymentRepo PaymentRepo
|
repo PaymentRepository
|
||||||
paymentMethodRepo PaymentMethodRepo
|
gwFactory GatewayFactory
|
||||||
gwFactory GatewayFactory
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type PaymentRepo interface {
|
type PaymentRepository interface {
|
||||||
CreatePayment(ctx context.Context, p *entity.Payment) error
|
CreatePayment(ctx context.Context, p *Payment) error
|
||||||
CreateTransaction(ctx context.Context, t *entity.PaymentTransaction) error
|
CreateTransaction(ctx context.Context, t *PaymentTransaction) error
|
||||||
UpdateTransaction(ctx context.Context, t *entity.PaymentTransaction) error
|
UpdateTransaction(ctx context.Context, t *PaymentTransaction) error
|
||||||
}
|
GetGatewayByCode(ctx context.Context, code string) (*Gateway, error)
|
||||||
type PaymentMethodRepo interface {
|
|
||||||
GetGatewayByCode(ctx context.Context, code string) (entity.Gateway, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type GatewayFactory interface {
|
type GatewayFactory interface {
|
||||||
|
|
@ -32,44 +27,43 @@ type GatewayPort interface {
|
||||||
Request(amount int64, callbackURL string, description string) (token string, redirectURL string, rawReq []byte, rawRes []byte, err error)
|
Request(amount int64, callbackURL string, description string) (token string, redirectURL string, rawReq []byte, rawRes []byte, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPaymentService(pr PaymentRepo, pmr PaymentMethodRepo, gwf GatewayFactory) *PaymentService {
|
func NewPaymentService(r PaymentRepository, gwf GatewayFactory) *PaymentService {
|
||||||
return &PaymentService{
|
return &PaymentService{
|
||||||
paymentRepo: pr,
|
repo: r,
|
||||||
paymentMethodRepo: pmr,
|
gwFactory: gwf,
|
||||||
gwFactory: gwf,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *PaymentService) InitiatePayment(ctx context.Context, req InitiatePaymentRequest) (*InitiatePaymentResponse, error) {
|
func (s *PaymentService) InitiatePayment(ctx context.Context, req InitiatePaymentRequest) (*InitiatePaymentResponse, error) {
|
||||||
|
|
||||||
gateway, err := s.paymentMethodRepo.GetGatewayByCode(ctx, req.GatewayCode)
|
gateway, err := s.repo.GetGatewayByCode(ctx, req.GatewayCode)
|
||||||
if err != nil || !gateway.IsActive {
|
if err != nil || !gateway.IsActive {
|
||||||
return nil, errors.New("gateway is not available")
|
return nil, errors.New("gateway is not available")
|
||||||
}
|
}
|
||||||
|
|
||||||
payment := &entity.Payment{
|
payment := &Payment{
|
||||||
UserID: req.UserID,
|
UserID: req.UserID,
|
||||||
PayableType: req.PayableType,
|
PayableType: req.PayableType,
|
||||||
PayableID: req.PayableID,
|
PayableID: req.PayableID,
|
||||||
GatewayID: gateway.ID,
|
GatewayID: gateway.ID,
|
||||||
TotalAmount: req.Amount,
|
TotalAmount: req.Amount,
|
||||||
Currency: entity.CurrencyIRR,
|
Currency: CurrencyIRR,
|
||||||
Status: entity.PaymentStatusPending,
|
Status: PaymentStatusPending,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
UpdatedAt: time.Now(),
|
UpdatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
if err := s.paymentRepo.CreatePayment(ctx, payment); err != nil {
|
if err := s.repo.CreatePayment(ctx, payment); err != nil {
|
||||||
return nil, fmt.Errorf("failed to create payment: %w", err)
|
return nil, fmt.Errorf("failed to create payment: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction := &entity.PaymentTransaction{
|
transaction := &PaymentTransaction{
|
||||||
PaymentID: payment.ID,
|
PaymentID: payment.ID,
|
||||||
Type: entity.TransactionTypeRequest,
|
Type: TransactionTypeRequest,
|
||||||
Status: entity.TransactionStatusPending,
|
Status: TransactionStatusPending,
|
||||||
CreatedAt: time.Now(),
|
CreatedAt: time.Now(),
|
||||||
UpdatedAt: time.Now(),
|
UpdatedAt: time.Now(),
|
||||||
}
|
}
|
||||||
if err := s.paymentRepo.CreateTransaction(ctx, transaction); err != nil {
|
if err := s.repo.CreateTransaction(ctx, transaction); err != nil {
|
||||||
return nil, fmt.Errorf("failed to create initial transaction: %w", err)
|
return nil, fmt.Errorf("failed to create initial transaction: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,15 +80,15 @@ func (s *PaymentService) InitiatePayment(ctx context.Context, req InitiatePaymen
|
||||||
transaction.UpdatedAt = time.Now()
|
transaction.UpdatedAt = time.Now()
|
||||||
|
|
||||||
if gwErr != nil {
|
if gwErr != nil {
|
||||||
transaction.Status = entity.TransactionStatusFailed
|
transaction.Status = TransactionStatusFailed
|
||||||
transaction.ErrorMessage = gwErr.Error()
|
transaction.ErrorMessage = gwErr.Error()
|
||||||
_ = s.paymentRepo.UpdateTransaction(ctx, transaction)
|
_ = s.repo.UpdateTransaction(ctx, transaction)
|
||||||
return nil, fmt.Errorf("gateway request failed: %w", gwErr)
|
return nil, fmt.Errorf("gateway request failed: %w", gwErr)
|
||||||
}
|
}
|
||||||
|
|
||||||
transaction.Status = entity.TransactionStatusSuccess
|
transaction.Status = TransactionStatusSuccess
|
||||||
transaction.GatewayToken = token
|
transaction.GatewayToken = token
|
||||||
if err := s.paymentRepo.UpdateTransaction(ctx, transaction); err != nil {
|
if err := s.repo.UpdateTransaction(ctx, transaction); err != nil {
|
||||||
return nil, fmt.Errorf("failed to update transaction with token: %w", err)
|
return nil, fmt.Errorf("failed to update transaction with token: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Transaction struct {
|
|
||||||
ID uint64
|
|
||||||
UserID uint64
|
|
||||||
Amount float64
|
|
||||||
Currency Currency
|
|
||||||
ActionType TransactionType
|
|
||||||
Timestamp time.Time
|
|
||||||
}
|
|
||||||
|
|
||||||
type TransactionType string
|
|
||||||
|
|
||||||
const (
|
|
||||||
TransactionTypeDeposit TransactionType = "deposit"
|
|
||||||
TransactionTypeWithdraw TransactionType = "withdraw"
|
|
||||||
TransactionTypeRefund TransactionType = "refund"
|
|
||||||
TransactionTypeDonate TransactionType = "donate"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Currency string
|
|
||||||
|
|
||||||
const (
|
|
||||||
IRR Currency = "IRR"
|
|
||||||
USD Currency = "USD"
|
|
||||||
)
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type Wallet struct {
|
|
||||||
ID uint64
|
|
||||||
UserID uint64 // user unique ID
|
|
||||||
Balance float64
|
|
||||||
Currency Currency
|
|
||||||
UpdatedAt time.Time
|
|
||||||
Status WalletStatus // "active", "frozen", "closed"
|
|
||||||
}
|
|
||||||
|
|
||||||
type WalletStatus string
|
|
||||||
|
|
||||||
const (
|
|
||||||
Frozen WalletStatus = "frozen" // when need to check , approve ,validate , solve sth (but deposit is possible)
|
|
||||||
Active WalletStatus = "active" // when everything is ok
|
|
||||||
|
|
||||||
// ??
|
|
||||||
// Closed WalletStatus = "closed" // when need to check , approve ,validate , solve sth (exp : security problem)
|
|
||||||
|
|
||||||
)
|
|
||||||
|
|
@ -1,15 +0,0 @@
|
||||||
package param
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
type CreateTransactionRequest struct {
|
|
||||||
UserID uint64 `json:"user_id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Currency entity.Currency `json:"currency"`
|
|
||||||
ActionType entity.TransactionType `json:"action_type"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type InsertTransactionResponse struct {
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package param
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
type TransactionRequest struct {
|
|
||||||
UserID uint64 `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TransactionResponse struct {
|
|
||||||
Transaction []TransactionInfo `json:"transaction"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type TransactionInfo struct {
|
|
||||||
ID uint64 `json:"id"`
|
|
||||||
UserID uint64 `json:"user_id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Currency entity.Currency `json:"currency"`
|
|
||||||
ActionType entity.TransactionType `json:"action_type"`
|
|
||||||
Timestamp time.Time `json:"timestamp"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
package param
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
type WalletRequest struct {
|
|
||||||
UserID uint64 `json:"user_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WalletResponse struct {
|
|
||||||
Wallet WalletInfo `json:"wallet"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type WalletInfo struct {
|
|
||||||
Balance float64 `json:"balance"`
|
|
||||||
UpdatedAt time.Time `json:"updated_at"`
|
|
||||||
Status entity.WalletStatus `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
package postgres
|
|
||||||
|
|
||||||
import "git.gocasts.ir/ebhomengo/niki/pkg/database/postgres"
|
|
||||||
|
|
||||||
type DB struct {
|
|
||||||
conn *postgres.DB
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(conn *postgres.DB) *DB {
|
|
||||||
return &DB{conn: conn}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
production:
|
|
||||||
dialect: postgres
|
|
||||||
datasource: "host=127.0.0.1 port=5432 user=wallet password=wallet2123 dbname=wallet_db sslmode=disable"
|
|
||||||
dir: domain/wallet/repository/postgres/migrations
|
|
||||||
table: wallet_migrationsns
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/entity"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/param"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s Service) CreateTransaction(ctx context.Context, request param.CreateTransactionRequest) (param.InsertTransactionResponse, error) {
|
|
||||||
|
|
||||||
const op = richerror.Op("wallet.service.CreateTransaction")
|
|
||||||
|
|
||||||
transaction := entity.Transaction{
|
|
||||||
ID: 0,
|
|
||||||
UserID: request.UserID,
|
|
||||||
Amount: request.Amount,
|
|
||||||
Currency: request.Currency,
|
|
||||||
ActionType: request.ActionType,
|
|
||||||
Timestamp: time.Now(),
|
|
||||||
}
|
|
||||||
err := s.repo.InsertTransaction(ctx, transaction)
|
|
||||||
if err != nil {
|
|
||||||
return param.InsertTransactionResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return param.InsertTransactionResponse{}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/entity"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Repository interface {
|
|
||||||
GetTransactionListByUserID(ctx context.Context, UserID uint64) ([]entity.Transaction, error)
|
|
||||||
GetWalletByUserID(ctx context.Context, UserID uint64) (entity.Wallet, error)
|
|
||||||
InsertTransaction(ctx context.Context, transaction entity.Transaction) error
|
|
||||||
}
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
repo Repository
|
|
||||||
cfg Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(repo Repository, cfg Config) Service {
|
|
||||||
|
|
||||||
return Service{repo: repo, cfg: cfg}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/entity"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/param"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s Service) GetUserTransactionHistory(ctx context.Context, request param.TransactionRequest) (param.TransactionResponse, error) {
|
|
||||||
const op = richerror.Op("wallet.service.GetUserTransactionHistory")
|
|
||||||
|
|
||||||
transactionList, err := s.repo.GetTransactionListByUserID(ctx, request.UserID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return param.TransactionResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return param.TransactionResponse{Transaction: transactionEntityToTransactionInfo(transactionList)}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func transactionEntityToTransactionInfo(TransactionList []entity.Transaction) []param.TransactionInfo {
|
|
||||||
transactionInfoList := make([]param.TransactionInfo, len(TransactionList))
|
|
||||||
for i, transaction := range TransactionList {
|
|
||||||
transactionInfoList[i] = param.TransactionInfo{
|
|
||||||
ID: transaction.ID,
|
|
||||||
UserID: transaction.UserID,
|
|
||||||
Amount: transaction.Amount,
|
|
||||||
Currency: transaction.Currency,
|
|
||||||
ActionType: transaction.ActionType,
|
|
||||||
Timestamp: transaction.Timestamp,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return transactionInfoList
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/wallet/param"
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s Service) GetUserWallet(ctx context.Context, request param.WalletRequest) (param.WalletResponse, error) {
|
|
||||||
const op = richerror.Op("wallet.service.GetUserWallet")
|
|
||||||
|
|
||||||
wallet, err := s.repo.GetWalletByUserID(ctx, request.UserID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return param.WalletResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return param.WalletResponse{
|
|
||||||
Wallet: param.WalletInfo{
|
|
||||||
Balance: wallet.Balance,
|
|
||||||
UpdatedAt: wallet.UpdatedAt,
|
|
||||||
Status: wallet.Status,
|
|
||||||
},
|
|
||||||
}, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package campaign;
|
|
||||||
|
|
||||||
option go_package = "git.gocasts.ir/ebhomengo/niki/donate_app/protobuf;campaignpb";
|
|
||||||
|
|
||||||
service CampaignService {
|
|
||||||
rpc CheckAndCompleteCampaigns (CheckAndCompleteCampaignsRequest) returns (CheckAndCompleteCampaignsResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
message CheckAndCompleteCampaignsRequest {
|
|
||||||
FilterRequest filter = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
message CheckAndCompleteCampaignsResponse {
|
|
||||||
uint64 total_checked = 1;
|
|
||||||
uint64 total_finished = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message FilterRequest {
|
|
||||||
uint32 limit = 1;
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
package service
|
||||||
|
|
@ -1,38 +0,0 @@
|
||||||
package driverapp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/account"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/driverapp/delivery/http"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/driverapp/service"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/http_server"
|
|
||||||
"google.golang.org/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Application struct {
|
|
||||||
svc service.Service
|
|
||||||
accountClient account.Client
|
|
||||||
handler http.Handler
|
|
||||||
httpServer http.Server
|
|
||||||
config Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func Setup(config Config, conn *grpc.ClientConn) Application {
|
|
||||||
driverValidator := service.NewValidator()
|
|
||||||
accountClient := account.New(conn)
|
|
||||||
driverSvc := service.NewService(config.DriverSvc, accountClient, driverValidator)
|
|
||||||
driverHandler := http.NewHandler(driverSvc)
|
|
||||||
|
|
||||||
httpServer := httpserver.New(config.HttpServer)
|
|
||||||
|
|
||||||
return Application{
|
|
||||||
svc: driverSvc,
|
|
||||||
handler: driverHandler,
|
|
||||||
httpServer: http.New(httpServer, driverHandler),
|
|
||||||
config: config,
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (app Application) Start() {
|
|
||||||
app.httpServer.Serve()
|
|
||||||
}
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
package driverapp
|
|
||||||
|
|
||||||
import (
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/kavenegar"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/driverapp/service"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/http_server"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
DriverSvc service.Config `koanf:"service"`
|
|
||||||
HttpServer http_server.Config `koanf:"http_server"`
|
|
||||||
Redis redis.Config `koanf:"redis_db"`
|
|
||||||
MysqlDB mysql.Config `koanf:"mysql_db"`
|
|
||||||
Kavenegar kavenegar.Config `koanf:"kavenegar"`
|
|
||||||
PathOfMigration string `koanf:"path_of_migration"`
|
|
||||||
}
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/driverapp/service"
|
|
||||||
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
DriverSvc service.Service
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(driverSvc service.Service) Handler {
|
|
||||||
return Handler{
|
|
||||||
DriverSvc: driverSvc,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Handler) SendOtp(c echo.Context) error {
|
|
||||||
var req service.SendOtpRequest
|
|
||||||
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.DriverSvc.SendOtp(c.Request().Context(), req)
|
|
||||||
if err != nil {
|
|
||||||
msg, code := httpmsg.Error(err)
|
|
||||||
return echo.NewHTTPError(code, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, res)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h Handler) loginOrRegister(c echo.Context) error {
|
|
||||||
var req service.LoginOrRegisterRequest
|
|
||||||
|
|
||||||
if err := c.Bind(&req); err != nil {
|
|
||||||
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := h.DriverSvc.LoginOrRegister(c.Request().Context(), req)
|
|
||||||
if err != nil {
|
|
||||||
msg, code := httpmsg.Error(err)
|
|
||||||
return echo.NewHTTPError(code, msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
return c.JSON(http.StatusOK, res)
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (s Server) HealthCheck(c echo.Context) error {
|
|
||||||
return c.JSON(http.StatusOK, echo.Map{
|
|
||||||
"message": "everything is good!",
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
package http
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/http_server"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Server struct {
|
|
||||||
HTTPServer http_server.Server
|
|
||||||
Handler Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(server http_server.Server, handler Handler) Server {
|
|
||||||
return Server{
|
|
||||||
HTTPServer: server,
|
|
||||||
Handler: handler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) Serve() {
|
|
||||||
s.RegisterRoutes()
|
|
||||||
|
|
||||||
if err := s.HTTPServer.Start(); err != nil {
|
|
||||||
fmt.Println("router start error", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Server) RegisterRoutes() {
|
|
||||||
v1 := s.HTTPServer.Router.Group("/v1")
|
|
||||||
|
|
||||||
v1.GET("/health_check", s.HealthCheck)
|
|
||||||
v1.POST("/send_otp", s.Handler.SendOtp)
|
|
||||||
v1.POST("/login_or_register", s.Handler.loginOrRegister)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
package entity
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Driver struct {
|
|
||||||
ID types.ID
|
|
||||||
FirstName string
|
|
||||||
LastName string
|
|
||||||
PhoneNumber string
|
|
||||||
NationalCode string
|
|
||||||
LicenseNumber string
|
|
||||||
BirthDate time.Time
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import "git.gocasts.ir/ebhomengo/niki/pkg/types"
|
|
||||||
|
|
||||||
type LoginOrRegisterRequest struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
VerifyCode string `json:"verify_code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type LoginOrRegisterResponse struct {
|
|
||||||
ID types.ID `json:"id"`
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Token struct {
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
RefreshToken string `json:"refresh_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SendOtpRequest struct {
|
|
||||||
PhoneNumber string `json:"phone_number"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type SendOtpResponse struct {
|
|
||||||
}
|
|
||||||
|
|
@ -1,76 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
LengthOfOtpCode int `koanf:"length_of_otp_code"`
|
|
||||||
OtpChars string `koanf:"otp_chars"`
|
|
||||||
OtpExpireTime time.Duration `koanf:"otp_expire_time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccountClient interface {
|
|
||||||
SendOTP(ctx context.Context, phoneNumber string) error
|
|
||||||
LoginOrRegister(ctx context.Context, req LoginOrRegisterRequest) (LoginOrRegisterResponse, error)
|
|
||||||
}
|
|
||||||
|
|
||||||
type AuthClient interface {
|
|
||||||
CreateAccessToken()
|
|
||||||
CreateRefreshToken()
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
config Config
|
|
||||||
accountClient AccountClient
|
|
||||||
validator Validator
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewService(cfg Config,
|
|
||||||
accountClient AccountClient,
|
|
||||||
validator Validator) Service {
|
|
||||||
return Service{
|
|
||||||
config: cfg,
|
|
||||||
accountClient: accountClient,
|
|
||||||
validator: validator,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) SendOtp(ctx context.Context, req SendOtpRequest) (SendOtpResponse, error) {
|
|
||||||
const op = "driverService.SendOtp"
|
|
||||||
err := s.validator.ValidateSendOtpRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
return SendOtpResponse{}, richerror.New(op).WithErr(err).WithMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
sErr := s.accountClient.SendOTP(ctx, req.PhoneNumber)
|
|
||||||
if sErr != nil {
|
|
||||||
return SendOtpResponse{}, richerror.New(op).WithErr(sErr).WithMessage(sErr.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
return SendOtpResponse{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Service) LoginOrRegister(ctx context.Context, req LoginOrRegisterRequest) (LoginOrRegisterResponse, error) {
|
|
||||||
const op = "driverService.LoginOrRegister"
|
|
||||||
|
|
||||||
err := s.validator.ValidateLoginOrRegisterRequest(req)
|
|
||||||
if err != nil {
|
|
||||||
return LoginOrRegisterResponse{}, richerror.New(op).WithErr(err).WithMessage(err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, lErr := s.accountClient.LoginOrRegister(ctx, req)
|
|
||||||
if lErr != nil {
|
|
||||||
return LoginOrRegisterResponse{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Println("res:", resp)
|
|
||||||
|
|
||||||
// TODO : CreateAccessToken and create CreateRefreshToken
|
|
||||||
|
|
||||||
return LoginOrRegisterResponse{}, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
package service
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
|
|
||||||
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
|
||||||
validation "github.com/go-ozzo/ozzo-validation"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
PhoneNumberRegex = "^(0|0098|\\+98)9(0[1-5]|[1 3]\\d|2[0-2]|98)\\d{7}$"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Validator struct{}
|
|
||||||
|
|
||||||
func NewValidator() Validator {
|
|
||||||
return Validator{}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Validator) ValidateSendOtpRequest(req SendOtpRequest) error {
|
|
||||||
err := validation.ValidateStruct(&req,
|
|
||||||
validation.Field(req.PhoneNumber,
|
|
||||||
validation.Required,
|
|
||||||
validation.Match(regexp.MustCompile(PhoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid),
|
|
||||||
))
|
|
||||||
|
|
||||||
return err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (v Validator) ValidateLoginOrRegisterRequest(req LoginOrRegisterRequest) error {
|
|
||||||
err := validation.ValidateStruct(&req,
|
|
||||||
validation.Field(req.PhoneNumber,
|
|
||||||
validation.Required,
|
|
||||||
validation.Match(regexp.MustCompile(PhoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid)),
|
|
||||||
validation.Field(req.VerifyCode,
|
|
||||||
validation.Required))
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
18
go.mod
18
go.mod
|
|
@ -9,13 +9,11 @@ require (
|
||||||
github.com/go-sql-driver/mysql v1.9.3
|
github.com/go-sql-driver/mysql v1.9.3
|
||||||
github.com/gocasters/rankr v0.0.0-20260222055437-aadc1fdc6a1d
|
github.com/gocasters/rankr v0.0.0-20260222055437-aadc1fdc6a1d
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.2
|
github.com/golang-jwt/jwt/v4 v4.5.2
|
||||||
github.com/jackc/pgx/v5 v5.7.6
|
|
||||||
github.com/jalaali/go-jalaali v0.0.0-20250521085720-bf793ab67800
|
|
||||||
github.com/kavenegar/kavenegar-go v0.0.0-20240205151018-77039f51467d
|
github.com/kavenegar/kavenegar-go v0.0.0-20240205151018-77039f51467d
|
||||||
github.com/knadh/koanf v1.5.0
|
github.com/knadh/koanf v1.5.0
|
||||||
|
github.com/knadh/koanf/v2 v2.3.0
|
||||||
github.com/labstack/echo-jwt/v4 v4.4.0
|
github.com/labstack/echo-jwt/v4 v4.4.0
|
||||||
github.com/labstack/echo/v4 v4.15.1
|
github.com/labstack/echo/v4 v4.15.1
|
||||||
github.com/labstack/gommon v0.4.2
|
|
||||||
github.com/lib/pq v1.10.9
|
github.com/lib/pq v1.10.9
|
||||||
github.com/mattn/go-sqlite3 v1.14.19
|
github.com/mattn/go-sqlite3 v1.14.19
|
||||||
github.com/ory/dockertest/v3 v3.12.0
|
github.com/ory/dockertest/v3 v3.12.0
|
||||||
|
|
@ -25,9 +23,7 @@ require (
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/swaggo/echo-swagger v1.5.2
|
github.com/swaggo/echo-swagger v1.5.2
|
||||||
github.com/swaggo/swag v1.16.6
|
github.com/swaggo/swag v1.16.6
|
||||||
golang.org/x/crypto v0.49.0
|
golang.org/x/crypto v0.48.0
|
||||||
google.golang.org/grpc v1.80.0
|
|
||||||
google.golang.org/protobuf v1.36.11
|
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
)
|
)
|
||||||
|
|
@ -61,10 +57,9 @@ require (
|
||||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
github.com/jalaali/go-jalaali v0.0.0-20250521085720-bf793ab67800 // indirect
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.14 // indirect
|
github.com/mattn/go-colorable v0.1.14 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
|
|
@ -92,13 +87,12 @@ require (
|
||||||
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
|
||||||
go.uber.org/atomic v1.11.0 // indirect
|
go.uber.org/atomic v1.11.0 // indirect
|
||||||
golang.org/x/mod v0.33.0 // indirect
|
golang.org/x/mod v0.33.0 // indirect
|
||||||
golang.org/x/net v0.52.0 // indirect
|
golang.org/x/net v0.50.0 // indirect
|
||||||
golang.org/x/sync v0.20.0 // indirect
|
golang.org/x/sync v0.20.0 // indirect
|
||||||
golang.org/x/sys v0.42.0 // indirect
|
golang.org/x/sys v0.41.0 // indirect
|
||||||
golang.org/x/text v0.35.0 // indirect
|
golang.org/x/text v0.35.0 // indirect
|
||||||
golang.org/x/time v0.14.0 // indirect
|
golang.org/x/time v0.14.0 // indirect
|
||||||
golang.org/x/tools v0.42.0 // indirect
|
golang.org/x/tools v0.42.0 // indirect
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 // indirect
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
|
||||||
54
go.sum
54
go.sum
|
|
@ -98,10 +98,6 @@ github.com/go-ldap/ldap v3.0.2+incompatible/go.mod h1:qfd9rJvER9Q0/D/Sqn1DfHRoBp
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
|
||||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
|
||||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
|
||||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
||||||
|
|
@ -151,8 +147,6 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
|
||||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
|
||||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||||
|
|
@ -164,14 +158,12 @@ github.com/google/go-cmp v0.5.4/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.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
|
||||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
|
github.com/hashicorp/consul/api v1.13.0/go.mod h1:ZlVrynguJKcYr54zGaDbaL3fOvKC9m72FhPvA8T35KQ=
|
||||||
|
|
@ -212,14 +204,6 @@ github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2
|
||||||
github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
|
||||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
|
||||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
|
||||||
github.com/jackc/pgx/v5 v5.7.6 h1:rWQc5FwZSPX58r1OQmkuaNicxdmExaEz5A2DO2hUuTk=
|
|
||||||
github.com/jackc/pgx/v5 v5.7.6/go.mod h1:aruU7o91Tc2q2cFp5h4uP3f6ztExVpyVv88Xl/8Vl8M=
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
|
||||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
|
||||||
github.com/jalaali/go-jalaali v0.0.0-20250521085720-bf793ab67800 h1:lvIuaX7hO0eO3Rlev+cVnlsoExR3i/JXxu88zt4JHPg=
|
github.com/jalaali/go-jalaali v0.0.0-20250521085720-bf793ab67800 h1:lvIuaX7hO0eO3Rlev+cVnlsoExR3i/JXxu88zt4JHPg=
|
||||||
github.com/jalaali/go-jalaali v0.0.0-20250521085720-bf793ab67800/go.mod h1:Wqfu7mjUHj9WDzSSPI5KfBclTTEnLveRUFr/ujWnTgE=
|
github.com/jalaali/go-jalaali v0.0.0-20250521085720-bf793ab67800/go.mod h1:Wqfu7mjUHj9WDzSSPI5KfBclTTEnLveRUFr/ujWnTgE=
|
||||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||||
|
|
@ -242,6 +226,8 @@ github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBF
|
||||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=
|
github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=
|
||||||
github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
|
github.com/knadh/koanf v1.5.0/go.mod h1:Hgyjp4y8v44hpZtPzs7JZfRAW5AhN7KfZcwv1RYggDs=
|
||||||
|
github.com/knadh/koanf/v2 v2.3.0 h1:Qg076dDRFHvqnKG97ZEsi9TAg2/nFTa9hCdcSa1lvlM=
|
||||||
|
github.com/knadh/koanf/v2 v2.3.0/go.mod h1:gRb40VRAbd4iJMYYD5IxZ6hfuopFcXBpc9bbQpZwo28=
|
||||||
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/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
|
|
@ -423,18 +409,6 @@ github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaD
|
||||||
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||||
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
|
go.etcd.io/etcd/client/v3 v3.5.4/go.mod h1:ZaRkVgBZC+L+dLCjTcF1hRXpgZXQPOvnA/Ak/gq3kiY=
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
|
||||||
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
|
||||||
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
|
||||||
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
|
||||||
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
|
||||||
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
|
||||||
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
|
||||||
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
|
||||||
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
|
||||||
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
|
||||||
|
|
@ -446,8 +420,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
|
||||||
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
golang.org/x/crypto v0.0.0-20190923035154-9ee001bba392/go.mod h1:/lpIB1dKB+9EgE3H3cr1v9wB50oz8l4C4h62xy7jSTY=
|
||||||
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.49.0 h1:+Ng2ULVvLHnJ/ZFEq4KdcDd/cfjrrjjNSXNzxg0Y4U4=
|
golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts=
|
||||||
golang.org/x/crypto v0.49.0/go.mod h1:ErX4dUh2UM+CFYiXZRTcMpEcN8b/1gxEuv3nODoYtCA=
|
golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos=
|
||||||
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=
|
||||||
|
|
@ -476,8 +450,8 @@ golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwY
|
||||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||||
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60=
|
||||||
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM=
|
||||||
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/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
|
@ -525,8 +499,8 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/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.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=
|
golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k=
|
||||||
golang.org/x/sys v0.42.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
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.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
|
|
@ -556,8 +530,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
|
|
||||||
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||||
|
|
@ -566,8 +538,6 @@ google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529 h1:XF8+t6QQiS0o9ArVan/HW8Q7cycNPGsJf6GA2nXxYAg=
|
|
||||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20260420184626-e10c466a9529/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8=
|
|
||||||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
|
|
@ -576,8 +546,6 @@ google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQ
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM=
|
|
||||||
google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||||
|
|
@ -589,8 +557,6 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||||
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.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
|
||||||
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
|
||||||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
|
||||||
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
gopkg.in/asn1-ber.v1 v1.0.0-20181015200546-f715ec2f112d/go.mod h1:cuepJuh7vyXfUyUwEgHQXw849cJrilpS5NeIjOWESAw=
|
||||||
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=
|
||||||
|
|
|
||||||
2
main.go
2
main.go
|
|
@ -48,7 +48,7 @@ func MariaDB(cfg config.Config) *mysql.DB {
|
||||||
if *migrate {
|
if *migrate {
|
||||||
migrator.New(migrator.Config{
|
migrator.New(migrator.Config{
|
||||||
MysqlConfig: cfg.Mysql,
|
MysqlConfig: cfg.Mysql,
|
||||||
MigrationPath: "./repository/mysql/migrations",
|
MigrationPath: "./repository/mysql/migration",
|
||||||
MigrationDBName: "gorp_migrations",
|
MigrationDBName: "gorp_migrations",
|
||||||
}).Up()
|
}).Up()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,53 +3,23 @@ package paymentapp
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/gateway"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/repository"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/service"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/paymentapp/delivery/grpc"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/database"
|
"git.gocasts.ir/ebhomengo/niki/pkg/database"
|
||||||
sgrpc "git.gocasts.ir/ebhomengo/niki/pkg/grpc"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
paymentrepo service.PaymentRepo
|
|
||||||
paymentMethodRepo service.PaymentMethodRepo
|
|
||||||
gwFactory service.GatewayFactory
|
|
||||||
paymentService *service.PaymentService
|
|
||||||
paymenthandler *grpc.Handler
|
|
||||||
rpcServer *sgrpc.RPCServer
|
|
||||||
server grpc.PaymentGrpcServer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Setup(ctx context.Context, cfg Config, conn *database.Database) (*App, error) {
|
func Setup(ctx context.Context, cfg Config, conn *database.Database) (*App, error) {
|
||||||
paymentrepo := repository.NewPaymentRepository(conn.DB)
|
|
||||||
paymentMethodRepo := repository.NewPaymentMethodRepository(conn.DB)
|
|
||||||
gwFactory := gateway.NewGatewayFactory()
|
|
||||||
paymentService := service.NewPaymentService(paymentrepo, paymentMethodRepo, gwFactory)
|
|
||||||
|
|
||||||
paymenthandler := grpc.NewHandler(paymentService)
|
//TODO Setup
|
||||||
|
|
||||||
rpcServer := sgrpc.New(sgrpc.Config(cfg.Grpc))
|
return &App{}, nil
|
||||||
|
|
||||||
server := grpc.NewPaymentGrpcServer(rpcServer, paymenthandler)
|
|
||||||
|
|
||||||
return &App{
|
|
||||||
paymentrepo: paymentrepo,
|
|
||||||
paymentMethodRepo: paymentMethodRepo,
|
|
||||||
gwFactory: gwFactory,
|
|
||||||
paymentService: paymentService,
|
|
||||||
paymenthandler: paymenthandler,
|
|
||||||
rpcServer: rpcServer,
|
|
||||||
server: server,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Start() error {
|
func (a *App) Start() error {
|
||||||
a.server.Serve()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Stop(ctx context.Context) error {
|
func (a *App) Stop(ctx context.Context) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,5 @@
|
||||||
package paymentapp
|
package paymentapp
|
||||||
|
|
||||||
import "time"
|
|
||||||
|
|
||||||
type GrpcConfig struct {
|
|
||||||
Port int `yaml:"port"`
|
|
||||||
NetworkType string `yaml:"type"`
|
|
||||||
ShutDownCtxTimeout time.Duration `yaml:"shutdown_context_timeout"`
|
|
||||||
}
|
|
||||||
type PostgresConfig struct {
|
type PostgresConfig struct {
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port int `yaml:"port"`
|
Port int `yaml:"port"`
|
||||||
|
|
@ -26,7 +19,6 @@ type LoggerConfig struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Grpc GrpcConfig `yaml:"grpc" json:"grpc"`
|
|
||||||
Postgres PostgresConfig `yaml:"postgres" json:"postgres"`
|
Postgres PostgresConfig `yaml:"postgres" json:"postgres"`
|
||||||
Logger LoggerConfig `yaml:"logger" json:"logger"`
|
Logger LoggerConfig `yaml:"logger" json:"logger"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
package grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/entity"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/domain/payment/service"
|
|
||||||
paymentpb "git.gocasts.ir/ebhomengo/niki/paymentapp/protobuf"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Handler struct {
|
|
||||||
paymentpb.UnimplementedPaymentServiceServer
|
|
||||||
scvPayment *service.PaymentService
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewHandler(s *service.PaymentService) *Handler {
|
|
||||||
return &Handler{
|
|
||||||
scvPayment: s,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *Handler) InitiatePayment(ctx context.Context, req *paymentpb.InitiatePaymentRequest) (*paymentpb.InitiatePaymentResponse, error) {
|
|
||||||
|
|
||||||
paymentResponse, err := h.scvPayment.InitiatePayment(ctx, service.InitiatePaymentRequest{
|
|
||||||
UserID: uint(req.GetUserId()),
|
|
||||||
PayableType: entity.PayableType(req.GetPayableType()),
|
|
||||||
PayableID: uint(req.GetPayableId()),
|
|
||||||
GatewayCode: req.GetGatewayCode(),
|
|
||||||
CallbackURL: req.GetCallbackUrl(),
|
|
||||||
Amount: req.GetAmount(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
response := &paymentpb.InitiatePaymentResponse{
|
|
||||||
PaymentId: uint64(paymentResponse.PaymentID),
|
|
||||||
RedirectUrl: paymentResponse.RedirectURL,
|
|
||||||
}
|
|
||||||
|
|
||||||
return response, nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
package grpc
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
|
|
||||||
paymentpb "git.gocasts.ir/ebhomengo/niki/paymentapp/protobuf"
|
|
||||||
"git.gocasts.ir/ebhomengo/niki/pkg/grpc"
|
|
||||||
)
|
|
||||||
|
|
||||||
type PaymentGrpcServer struct {
|
|
||||||
server *grpc.RPCServer
|
|
||||||
handler *Handler
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewPaymentGrpcServer(server *grpc.RPCServer, handler *Handler) PaymentGrpcServer {
|
|
||||||
return PaymentGrpcServer{
|
|
||||||
server: server,
|
|
||||||
handler: handler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s PaymentGrpcServer) Serve() error {
|
|
||||||
listener, err := net.Listen(s.server.Config.NetworkType, fmt.Sprintf(":%d", s.server.Config.Port))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
paymentpb.RegisterPaymentServiceServer(s.server.Server, s.handler)
|
|
||||||
if err := s.server.Server.Serve(listener); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s PaymentGrpcServer) Stop() {
|
|
||||||
s.server.Stop()
|
|
||||||
}
|
|
||||||
|
|
@ -1,230 +0,0 @@
|
||||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
|
||||||
// versions:
|
|
||||||
// protoc-gen-go v1.36.11
|
|
||||||
// protoc v4.25.1
|
|
||||||
// source: paymentapp/protobuf/payment.proto
|
|
||||||
|
|
||||||
package paymentpb
|
|
||||||
|
|
||||||
import (
|
|
||||||
reflect "reflect"
|
|
||||||
sync "sync"
|
|
||||||
unsafe "unsafe"
|
|
||||||
|
|
||||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
|
||||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
// Verify that this generated code is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
|
||||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
|
||||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
|
||||||
)
|
|
||||||
|
|
||||||
type InitiatePaymentRequest struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
UserId uint64 `protobuf:"varint,1,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
|
||||||
PayableType string `protobuf:"bytes,2,opt,name=payable_type,json=payableType,proto3" json:"payable_type,omitempty"`
|
|
||||||
PayableId uint64 `protobuf:"varint,3,opt,name=payable_id,json=payableId,proto3" json:"payable_id,omitempty"`
|
|
||||||
GatewayCode string `protobuf:"bytes,4,opt,name=gateway_code,json=gatewayCode,proto3" json:"gateway_code,omitempty"`
|
|
||||||
CallbackUrl string `protobuf:"bytes,5,opt,name=callback_url,json=callbackUrl,proto3" json:"callback_url,omitempty"`
|
|
||||||
Amount int64 `protobuf:"varint,6,opt,name=amount,proto3" json:"amount,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) Reset() {
|
|
||||||
*x = InitiatePaymentRequest{}
|
|
||||||
mi := &file_paymentapp_protobuf_payment_proto_msgTypes[0]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*InitiatePaymentRequest) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_paymentapp_protobuf_payment_proto_msgTypes[0]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use InitiatePaymentRequest.ProtoReflect.Descriptor instead.
|
|
||||||
func (*InitiatePaymentRequest) Descriptor() ([]byte, []int) {
|
|
||||||
return file_paymentapp_protobuf_payment_proto_rawDescGZIP(), []int{0}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) GetUserId() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.UserId
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) GetPayableType() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.PayableType
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) GetPayableId() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.PayableId
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) GetGatewayCode() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.GatewayCode
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) GetCallbackUrl() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.CallbackUrl
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentRequest) GetAmount() int64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.Amount
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
type InitiatePaymentResponse struct {
|
|
||||||
state protoimpl.MessageState `protogen:"open.v1"`
|
|
||||||
PaymentId uint64 `protobuf:"varint,1,opt,name=payment_id,json=paymentId,proto3" json:"payment_id,omitempty"`
|
|
||||||
RedirectUrl string `protobuf:"bytes,2,opt,name=redirect_url,json=redirectUrl,proto3" json:"redirect_url,omitempty"`
|
|
||||||
unknownFields protoimpl.UnknownFields
|
|
||||||
sizeCache protoimpl.SizeCache
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentResponse) Reset() {
|
|
||||||
*x = InitiatePaymentResponse{}
|
|
||||||
mi := &file_paymentapp_protobuf_payment_proto_msgTypes[1]
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentResponse) String() string {
|
|
||||||
return protoimpl.X.MessageStringOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*InitiatePaymentResponse) ProtoMessage() {}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentResponse) ProtoReflect() protoreflect.Message {
|
|
||||||
mi := &file_paymentapp_protobuf_payment_proto_msgTypes[1]
|
|
||||||
if x != nil {
|
|
||||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
|
||||||
if ms.LoadMessageInfo() == nil {
|
|
||||||
ms.StoreMessageInfo(mi)
|
|
||||||
}
|
|
||||||
return ms
|
|
||||||
}
|
|
||||||
return mi.MessageOf(x)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Deprecated: Use InitiatePaymentResponse.ProtoReflect.Descriptor instead.
|
|
||||||
func (*InitiatePaymentResponse) Descriptor() ([]byte, []int) {
|
|
||||||
return file_paymentapp_protobuf_payment_proto_rawDescGZIP(), []int{1}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentResponse) GetPaymentId() uint64 {
|
|
||||||
if x != nil {
|
|
||||||
return x.PaymentId
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (x *InitiatePaymentResponse) GetRedirectUrl() string {
|
|
||||||
if x != nil {
|
|
||||||
return x.RedirectUrl
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
var File_paymentapp_protobuf_payment_proto protoreflect.FileDescriptor
|
|
||||||
|
|
||||||
const file_paymentapp_protobuf_payment_proto_rawDesc = "" +
|
|
||||||
"\n" +
|
|
||||||
"!paymentapp/protobuf/payment.proto\x12\apayment\"\xd1\x01\n" +
|
|
||||||
"\x16InitiatePaymentRequest\x12\x17\n" +
|
|
||||||
"\auser_id\x18\x01 \x01(\x04R\x06userId\x12!\n" +
|
|
||||||
"\fpayable_type\x18\x02 \x01(\tR\vpayableType\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"payable_id\x18\x03 \x01(\x04R\tpayableId\x12!\n" +
|
|
||||||
"\fgateway_code\x18\x04 \x01(\tR\vgatewayCode\x12!\n" +
|
|
||||||
"\fcallback_url\x18\x05 \x01(\tR\vcallbackUrl\x12\x16\n" +
|
|
||||||
"\x06amount\x18\x06 \x01(\x03R\x06amount\"[\n" +
|
|
||||||
"\x17InitiatePaymentResponse\x12\x1d\n" +
|
|
||||||
"\n" +
|
|
||||||
"payment_id\x18\x01 \x01(\x04R\tpaymentId\x12!\n" +
|
|
||||||
"\fredirect_url\x18\x02 \x01(\tR\vredirectUrl2f\n" +
|
|
||||||
"\x0ePaymentService\x12T\n" +
|
|
||||||
"\x0fInitiatePayment\x12\x1f.payment.InitiatePaymentRequest\x1a .payment.InitiatePaymentResponseB=Z;git.gocasts.ir/ebhomengo/niki/paymentapp/protobuf;paymentpbb\x06proto3"
|
|
||||||
|
|
||||||
var (
|
|
||||||
file_paymentapp_protobuf_payment_proto_rawDescOnce sync.Once
|
|
||||||
file_paymentapp_protobuf_payment_proto_rawDescData []byte
|
|
||||||
)
|
|
||||||
|
|
||||||
func file_paymentapp_protobuf_payment_proto_rawDescGZIP() []byte {
|
|
||||||
file_paymentapp_protobuf_payment_proto_rawDescOnce.Do(func() {
|
|
||||||
file_paymentapp_protobuf_payment_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_paymentapp_protobuf_payment_proto_rawDesc), len(file_paymentapp_protobuf_payment_proto_rawDesc)))
|
|
||||||
})
|
|
||||||
return file_paymentapp_protobuf_payment_proto_rawDescData
|
|
||||||
}
|
|
||||||
|
|
||||||
var file_paymentapp_protobuf_payment_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
|
||||||
var file_paymentapp_protobuf_payment_proto_goTypes = []any{
|
|
||||||
(*InitiatePaymentRequest)(nil), // 0: payment.InitiatePaymentRequest
|
|
||||||
(*InitiatePaymentResponse)(nil), // 1: payment.InitiatePaymentResponse
|
|
||||||
}
|
|
||||||
var file_paymentapp_protobuf_payment_proto_depIdxs = []int32{
|
|
||||||
0, // 0: payment.PaymentService.InitiatePayment:input_type -> payment.InitiatePaymentRequest
|
|
||||||
1, // 1: payment.PaymentService.InitiatePayment:output_type -> payment.InitiatePaymentResponse
|
|
||||||
1, // [1:2] is the sub-list for method output_type
|
|
||||||
0, // [0:1] is the sub-list for method input_type
|
|
||||||
0, // [0:0] is the sub-list for extension type_name
|
|
||||||
0, // [0:0] is the sub-list for extension extendee
|
|
||||||
0, // [0:0] is the sub-list for field type_name
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() { file_paymentapp_protobuf_payment_proto_init() }
|
|
||||||
func file_paymentapp_protobuf_payment_proto_init() {
|
|
||||||
if File_paymentapp_protobuf_payment_proto != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
type x struct{}
|
|
||||||
out := protoimpl.TypeBuilder{
|
|
||||||
File: protoimpl.DescBuilder{
|
|
||||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
|
||||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_paymentapp_protobuf_payment_proto_rawDesc), len(file_paymentapp_protobuf_payment_proto_rawDesc)),
|
|
||||||
NumEnums: 0,
|
|
||||||
NumMessages: 2,
|
|
||||||
NumExtensions: 0,
|
|
||||||
NumServices: 1,
|
|
||||||
},
|
|
||||||
GoTypes: file_paymentapp_protobuf_payment_proto_goTypes,
|
|
||||||
DependencyIndexes: file_paymentapp_protobuf_payment_proto_depIdxs,
|
|
||||||
MessageInfos: file_paymentapp_protobuf_payment_proto_msgTypes,
|
|
||||||
}.Build()
|
|
||||||
File_paymentapp_protobuf_payment_proto = out.File
|
|
||||||
file_paymentapp_protobuf_payment_proto_goTypes = nil
|
|
||||||
file_paymentapp_protobuf_payment_proto_depIdxs = nil
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package payment;
|
|
||||||
option go_package = "git.gocasts.ir/ebhomengo/niki/paymentapp/protobuf;paymentpb";
|
|
||||||
|
|
||||||
service PaymentService {
|
|
||||||
rpc InitiatePayment (InitiatePaymentRequest) returns (InitiatePaymentResponse);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
message InitiatePaymentRequest {
|
|
||||||
uint64 user_id = 1;
|
|
||||||
string payable_type = 2;
|
|
||||||
uint64 payable_id = 3;
|
|
||||||
string gateway_code = 4;
|
|
||||||
string callback_url = 5;
|
|
||||||
int64 amount = 6;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
message InitiatePaymentResponse {
|
|
||||||
uint64 payment_id = 1;
|
|
||||||
string redirect_url = 2;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue