forked from ebhomengo/niki
feat(benefactor): add login and register
This commit is contained in:
parent
052f062cca
commit
866c5b42e1
|
@ -0,0 +1,31 @@
|
||||||
|
package redis
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/redis/go-redis/v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Host string `koanf:"host"`
|
||||||
|
Port int `koanf:"port"`
|
||||||
|
Password string `koanf:"password"`
|
||||||
|
DB int `koanf:"db"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Adapter struct {
|
||||||
|
client *redis.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config Config) Adapter {
|
||||||
|
rdb := redis.NewClient(&redis.Options{
|
||||||
|
Addr: fmt.Sprintf("%s:%d", config.Host, config.Port),
|
||||||
|
Password: config.Password,
|
||||||
|
DB: config.DB,
|
||||||
|
})
|
||||||
|
|
||||||
|
return Adapter{client: rdb}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Adapter) Client() *redis.Client {
|
||||||
|
return a.client
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package smsprovider
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
Host string `koanf:"host"`
|
||||||
|
Port int `koanf:"port"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Adapter struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(config Config) Adapter {
|
||||||
|
//rdb := redis.NewClient(&redis.Options{
|
||||||
|
// Addr: fmt.Sprintf("%s:%d", config.Host, config.Port),
|
||||||
|
//})
|
||||||
|
|
||||||
|
return Adapter{}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
package smsprovider
|
||||||
|
|
||||||
|
func (a Adapter) SendSms(phoneNumber string, code string) error {
|
||||||
|
return nil
|
||||||
|
}
|
25
config.yml
25
config.yml
|
@ -1,14 +1,33 @@
|
||||||
---
|
---
|
||||||
type: yml
|
type: yml
|
||||||
|
|
||||||
auth:
|
auth:
|
||||||
sign_key: jwt_secret
|
sign_key: jwt_secret_test_nik
|
||||||
|
|
||||||
http_server:
|
http_server:
|
||||||
port: 8080
|
port: 1313
|
||||||
|
|
||||||
mysql:
|
mysql:
|
||||||
port: 3308
|
port: 3308
|
||||||
host: localhost
|
host: localhost
|
||||||
db_name: niki_db
|
db_name: niki_db
|
||||||
username: niki
|
username: niki
|
||||||
password: nikit0lk2o20
|
password: nikiappt0lk2o20
|
||||||
|
|
||||||
|
redis:
|
||||||
|
port: 6380
|
||||||
|
host: localhost
|
||||||
|
password: ""
|
||||||
|
db: 0
|
||||||
|
|
||||||
|
sms_provider:
|
||||||
|
host: localhost
|
||||||
|
port: 443
|
||||||
|
|
||||||
|
benefactor_service:
|
||||||
|
length_of_otp_code: 5
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
||||||
|
smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider"
|
||||||
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
|
||||||
|
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HTTPServer struct {
|
type HTTPServer struct {
|
||||||
|
@ -9,6 +13,10 @@ type HTTPServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
HTTPServer HTTPServer `koanf:"http_server"`
|
HTTPServer HTTPServer `koanf:"http_server"`
|
||||||
Mysql mysql.Config `koanf:"mysql"`
|
Mysql mysql.Config `koanf:"mysql"`
|
||||||
|
Auth authservice.Config `koanf:"auth"`
|
||||||
|
Redis redis.Config `koanf:"redis"`
|
||||||
|
SmsProvider smsprovider.Config `koanf:"sms_provider"`
|
||||||
|
BenefactorSvc benefactorservice.Config `koanf:"benefactor_service"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
package config
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
const (
|
||||||
|
OptChars = "0123456789"
|
||||||
|
OtpExpireTime time.Duration = 120000 // 2 minutes
|
||||||
|
|
||||||
|
JwtSignKey = "jwt_secret"
|
||||||
|
AccessTokenSubject = "ac"
|
||||||
|
RefreshTokenSubject = "rt"
|
||||||
|
AccessTokenExpireDuration = time.Hour * 24
|
||||||
|
RefreshTokenExpireDuration = time.Hour * 24 * 7
|
||||||
|
AuthMiddlewareContextKey = "claims"
|
||||||
|
)
|
|
@ -0,0 +1,24 @@
|
||||||
|
package benefactorhandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
benefactorauthservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
|
||||||
|
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
|
||||||
|
benefactorvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/benefactor"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Handler struct {
|
||||||
|
authConfig benefactorauthservice.Config
|
||||||
|
benefactorSvc benefactorservice.Service
|
||||||
|
benefactorVld benefactorvalidator.Validator
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(authConfig benefactorauthservice.Config,
|
||||||
|
benefactorSvc benefactorservice.Service,
|
||||||
|
benefactorVld benefactorvalidator.Validator,
|
||||||
|
) Handler {
|
||||||
|
return Handler{
|
||||||
|
authConfig: authConfig,
|
||||||
|
benefactorSvc: benefactorSvc,
|
||||||
|
benefactorVld: benefactorVld,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package benefactorhandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
|
||||||
|
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h Handler) loginOrRegister(c echo.Context) error {
|
||||||
|
var req benefactoreparam.LoginOrRegisterRequest
|
||||||
|
|
||||||
|
if bErr := c.Bind(&req); bErr != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
if fieldErrors, err := h.benefactorVld.ValidateLoginRegisterRequest(req); err != nil {
|
||||||
|
msg, code := httpmsg.Error(err)
|
||||||
|
|
||||||
|
return c.JSON(code, echo.Map{
|
||||||
|
"message": msg,
|
||||||
|
"errors": fieldErrors,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resp, sErr := h.benefactorSvc.LoginOrRegister(c.Request().Context(), req)
|
||||||
|
if sErr != nil {
|
||||||
|
msg, code := httpmsg.Error(sErr)
|
||||||
|
|
||||||
|
return echo.NewHTTPError(code, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
package benefactorhandler
|
||||||
|
|
||||||
|
import "github.com/labstack/echo/v4"
|
||||||
|
|
||||||
|
func (h Handler) SetRoutes(e *echo.Echo) {
|
||||||
|
r := e.Group("/benefactor")
|
||||||
|
|
||||||
|
r.POST("/send-otp", h.SendOtp)
|
||||||
|
r.POST("/login-register", h.loginOrRegister)
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package benefactorhandler
|
||||||
|
|
||||||
|
import (
|
||||||
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
|
||||||
|
httpmsg "git.gocasts.ir/ebhomengo/niki/pkg/http_msg"
|
||||||
|
"github.com/labstack/echo/v4"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h Handler) SendOtp(c echo.Context) error {
|
||||||
|
var req benefactoreparam.SendOtpRequest
|
||||||
|
|
||||||
|
if bErr := c.Bind(&req); bErr != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusBadRequest)
|
||||||
|
}
|
||||||
|
if fieldErrors, err := h.benefactorVld.ValidateSendOtpRequest(req); err != nil {
|
||||||
|
msg, code := httpmsg.Error(err)
|
||||||
|
|
||||||
|
return c.JSON(code, echo.Map{
|
||||||
|
"message": msg,
|
||||||
|
"errors": fieldErrors,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resp, sErr := h.benefactorSvc.SendOtp(c.Request().Context(), req)
|
||||||
|
if sErr != nil {
|
||||||
|
msg, code := httpmsg.Error(sErr)
|
||||||
|
|
||||||
|
return echo.NewHTTPError(code, msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(http.StatusOK, resp)
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
package benefactorkindboxhandler
|
package benefactorkindboxhandler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/user"
|
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
|
||||||
benefactorkindboxservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box"
|
benefactorkindboxservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box"
|
||||||
benefactorkindboxvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box"
|
benefactorkindboxvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box"
|
||||||
)
|
)
|
||||||
|
|
|
@ -2,6 +2,9 @@ package httpserver
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
benefactorhandler "git.gocasts.ir/ebhomengo/niki/delivery/http_server/benefactor/benefactor"
|
||||||
|
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
|
||||||
|
benefactorvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/benefactor"
|
||||||
|
|
||||||
config "git.gocasts.ir/ebhomengo/niki/config"
|
config "git.gocasts.ir/ebhomengo/niki/config"
|
||||||
echo "github.com/labstack/echo/v4"
|
echo "github.com/labstack/echo/v4"
|
||||||
|
@ -9,14 +12,16 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Server struct {
|
type Server struct {
|
||||||
config config.Config
|
config config.Config
|
||||||
Router *echo.Echo
|
Router *echo.Echo
|
||||||
|
benefactorHandler benefactorhandler.Handler
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(cfg config.Config) Server {
|
func New(cfg config.Config, benefactorSvc benefactorservice.Service, benefactorVld benefactorvalidator.Validator) Server {
|
||||||
return Server{
|
return Server{
|
||||||
Router: echo.New(),
|
Router: echo.New(),
|
||||||
config: cfg,
|
config: cfg,
|
||||||
|
benefactorHandler: benefactorhandler.New(cfg.Auth, benefactorSvc, benefactorVld),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,6 +32,7 @@ func (s Server) Serve() {
|
||||||
|
|
||||||
// Routes
|
// Routes
|
||||||
s.Router.GET("/health-check", s.healthCheck)
|
s.Router.GET("/health-check", s.healthCheck)
|
||||||
|
s.benefactorHandler.SetRoutes(s.Router)
|
||||||
|
|
||||||
// Start server
|
// Start server
|
||||||
address := fmt.Sprintf(":%d", s.config.HTTPServer.Port)
|
address := fmt.Sprintf(":%d", s.config.HTTPServer.Port)
|
||||||
|
|
|
@ -2,19 +2,35 @@ version: '3.9'
|
||||||
|
|
||||||
services:
|
services:
|
||||||
mysql:
|
mysql:
|
||||||
platform: linux/amd64
|
|
||||||
image: mysql:8.0
|
image: mysql:8.0
|
||||||
ports:
|
ports:
|
||||||
- 3305:3305
|
- "3308:3306"
|
||||||
|
container_name: niki-database
|
||||||
volumes:
|
volumes:
|
||||||
- ~/apps/mysql:/var/lib/mysql
|
- dbdata:/var/lib/mysql
|
||||||
restart: always
|
restart: always
|
||||||
hostname: mysql
|
command: [ 'mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ]
|
||||||
container_name: niki_mysql
|
|
||||||
environment:
|
environment:
|
||||||
- MYSQL_ROOT_PASSWORD=niki_user
|
MYSQL_ROOT_PASSWORD: nikiRoo7t0lk2o20
|
||||||
- MYSQL_PASSWORD=NIKI_user@123
|
MYSQL_DATABASE: niki_db
|
||||||
- MYSQL_USER=user
|
MYSQL_USER: niki
|
||||||
- MYSQL_DATABASE=niki
|
MYSQL_PASSWORD: nikiappt0lk2o20
|
||||||
|
|
||||||
|
niki-redis:
|
||||||
|
image: bitnami/redis:6.2
|
||||||
|
container_name: niki-redis
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- '6380:6379'
|
||||||
|
# TODO - remove `--save "" --appendonly no` from command to persist data
|
||||||
|
command: redis-server --loglevel warning --protected-mode no --save "" --appendonly no
|
||||||
|
environment:
|
||||||
|
- ALLOW_EMPTY_PASSWORD=yes
|
||||||
|
volumes:
|
||||||
|
- niki-redis-data:/data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dbdata:
|
||||||
|
niki-redis-data:
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
version: '3.9'
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
platform: linux/amd64
|
||||||
|
image: mysql:8.0
|
||||||
|
ports:
|
||||||
|
- 3305:3305
|
||||||
|
volumes:
|
||||||
|
- ~/apps/mysql:/var/lib/mysql
|
||||||
|
restart: always
|
||||||
|
hostname: mysql
|
||||||
|
container_name: niki_mysql
|
||||||
|
environment:
|
||||||
|
- MYSQL_ROOT_PASSWORD=root
|
||||||
|
- MYSQL_USER=niki_user
|
||||||
|
- MYSQL_PASSWORD=NIKI_user@123
|
||||||
|
- MYSQL_DATABASE=niki_db
|
||||||
|
|
||||||
|
niki-redis:
|
||||||
|
image: bitnami/redis:6.2
|
||||||
|
container_name: niki-redis
|
||||||
|
restart: always
|
||||||
|
ports:
|
||||||
|
- '6380:6379'
|
||||||
|
# TODO - remove `--save "" --appendonly no` from command to persist data
|
||||||
|
command: redis-server --loglevel warning --protected-mode no --save "" --appendonly no
|
||||||
|
environment:
|
||||||
|
- ALLOW_EMPTY_PASSWORD=yes
|
||||||
|
volumes:
|
||||||
|
- niki-redis-data:/data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dbdata:
|
||||||
|
niki-redis-data:
|
|
@ -3,16 +3,16 @@ package entity
|
||||||
import "time"
|
import "time"
|
||||||
|
|
||||||
type Benefactor struct {
|
type Benefactor struct {
|
||||||
ID uint
|
ID uint
|
||||||
FirstName string
|
FirstName string
|
||||||
LastName string
|
LastName string
|
||||||
PhoneNumber string
|
PhoneNumber string
|
||||||
Address string
|
Address string
|
||||||
Description string
|
Description string
|
||||||
Email string
|
Email string
|
||||||
City string
|
City string
|
||||||
Gender Gender
|
Gender Gender
|
||||||
Status BenefactorStatus
|
Status BenefactorStatus
|
||||||
Birthday time.Time
|
Birthdate time.Time
|
||||||
StatusChangedAt time.Time
|
Role UserRole
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
package entity
|
||||||
|
|
||||||
|
type UserRole uint
|
||||||
|
|
||||||
|
const (
|
||||||
|
UserBenefactorRole UserRole = iota + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var UserRoleStrings = map[UserRole]string{
|
||||||
|
UserBenefactorRole: "benefactor",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s UserRole) String() string {
|
||||||
|
return UserRoleStrings[s]
|
||||||
|
}
|
||||||
|
|
||||||
|
// AllUserRole returns a slice containing all string values of UserRole.
|
||||||
|
func AllUserRole() []string {
|
||||||
|
roleStrings := make([]string, len(UserRoleStrings))
|
||||||
|
for role, str := range UserRoleStrings {
|
||||||
|
roleStrings[int(role)-1] = str
|
||||||
|
}
|
||||||
|
|
||||||
|
return roleStrings
|
||||||
|
}
|
||||||
|
|
||||||
|
// MapToUserRole converts a string to the corresponding UserRole value.
|
||||||
|
func MapToUserRole(roleStr string) UserRole {
|
||||||
|
for role, str := range UserRoleStrings {
|
||||||
|
if str == roleStr {
|
||||||
|
return role
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return UserRole(0)
|
||||||
|
}
|
6
go.mod
6
go.mod
|
@ -5,15 +5,20 @@ go 1.21.3
|
||||||
require (
|
require (
|
||||||
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
|
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
|
||||||
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0
|
||||||
github.com/knadh/koanf v1.5.0
|
github.com/knadh/koanf v1.5.0
|
||||||
github.com/labstack/echo/v4 v4.11.4
|
github.com/labstack/echo/v4 v4.11.4
|
||||||
|
github.com/redis/go-redis/v9 v9.4.0
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect
|
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
github.com/fatih/structs v1.1.0 // indirect
|
github.com/fatih/structs v1.1.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
github.com/fsnotify/fsnotify v1.4.9 // indirect
|
||||||
|
github.com/go-gorp/gorp/v3 v3.1.0 // indirect
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
|
||||||
github.com/labstack/gommon v0.4.2 // indirect
|
github.com/labstack/gommon v0.4.2 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
|
@ -21,6 +26,7 @@ require (
|
||||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||||
|
github.com/rubenv/sql-migrate v1.6.0 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.2 // indirect
|
github.com/valyala/fasttemplate v1.2.2 // indirect
|
||||||
golang.org/x/crypto v0.17.0 // indirect
|
golang.org/x/crypto v0.17.0 // indirect
|
||||||
|
|
16
go.sum
16
go.sum
|
@ -27,8 +27,14 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
|
||||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0 h1:Ny8MWAHyOepLGlLKYmXG4IEkioBysk6GpaRTLC8zwWs=
|
||||||
|
github.com/bsm/ginkgo/v2 v2.12.0/go.mod h1:SwYbGRRDovPVboqFv0tPTcG1sN61LM1Z4ARdbAV9g4c=
|
||||||
|
github.com/bsm/gomega v1.27.10 h1:yeMWxP2pV2fG3FgAODIY8EiRE3dy0aeFYt4l7wh6yKA=
|
||||||
|
github.com/bsm/gomega v1.27.10/go.mod h1:JyEr/xRbxbtgWNi8tIEVPUYZ5Dzef52k01W3YH0H+O0=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
|
@ -37,6 +43,8 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||||
|
@ -50,6 +58,8 @@ github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga
|
||||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/go-gorp/gorp/v3 v3.1.0 h1:ItKF/Vbuj31dmV4jxA1qblpSwkl9g1typ24xoe70IGs=
|
||||||
|
github.com/go-gorp/gorp/v3 v3.1.0/go.mod h1:dLEjIyyRNiXvNZ8PSmzpt1GsWAUK8kjVhEpjH8TixEw=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
|
||||||
|
@ -68,6 +78,8 @@ github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7a
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||||
|
@ -229,8 +241,12 @@ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R
|
||||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||||
|
github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
|
||||||
|
github.com/redis/go-redis/v9 v9.4.0/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||||
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
github.com/rhnvrm/simples3 v0.6.1/go.mod h1:Y+3vYm2V7Y4VijFoJHHTrja6OgPrJ2cBti8dPGkC3sA=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
|
github.com/rubenv/sql-migrate v1.6.0 h1:IZpcTlAx/VKXphWEpwWJ7BaMq05tYtE80zYz+8a5Il8=
|
||||||
|
github.com/rubenv/sql-migrate v1.6.0/go.mod h1:m3ilnKP7sNb4eYkLsp6cGdPOl4OBcXM6rcbzU+Oqc5k=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc=
|
||||||
|
|
44
main.go
44
main.go
|
@ -1,4 +1,48 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
||||||
|
smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/config"
|
||||||
|
httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/migrator"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
mysqlbenefactor "git.gocasts.ir/ebhomengo/niki/repository/mysql/benefactor"
|
||||||
|
redisotp "git.gocasts.ir/ebhomengo/niki/repository/redis/redis_otp"
|
||||||
|
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
|
||||||
|
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
|
||||||
|
benefactorvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/benefactor"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
cfg := config.C()
|
||||||
|
|
||||||
|
// TODO - add command for migrations
|
||||||
|
mgr := migrator.New(cfg.Mysql)
|
||||||
|
mgr.Up()
|
||||||
|
|
||||||
|
_, benefactorSvc, benefactorVld := setupServices(cfg)
|
||||||
|
server := httpserver.New(cfg, benefactorSvc, benefactorVld)
|
||||||
|
server.Serve()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupServices(cfg config.Config) (
|
||||||
|
authservice.Service, benefactorservice.Service, benefactorvalidator.Validator,
|
||||||
|
) {
|
||||||
|
|
||||||
|
authSvc := authservice.New(cfg.Auth)
|
||||||
|
|
||||||
|
MysqlRepo := mysql.New(cfg.Mysql)
|
||||||
|
|
||||||
|
redisAdapter := redis.New(cfg.Redis)
|
||||||
|
RedisOtp := redisotp.New(redisAdapter)
|
||||||
|
benefactorMysql := mysqlbenefactor.New(MysqlRepo)
|
||||||
|
smsProvider := smsprovider.New(cfg.SmsProvider)
|
||||||
|
authGenerator := authservice.New(cfg.Auth)
|
||||||
|
|
||||||
|
benefactorSvc := benefactorservice.New(cfg.BenefactorSvc, RedisOtp, smsProvider, authGenerator, benefactorMysql)
|
||||||
|
|
||||||
|
benefactorVld := benefactorvalidator.New()
|
||||||
|
|
||||||
|
return authSvc, benefactorSvc, benefactorVld
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package benefactoreparam
|
||||||
|
|
||||||
|
type BenefactroInfo struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package benefactoreparam
|
||||||
|
|
||||||
|
type LoginOrRegisterRequest struct {
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
VerificationCode string `json:"verification_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LoginOrRegisterResponse struct {
|
||||||
|
BenefactorInfo BenefactroInfo `json:"benefactore_info"`
|
||||||
|
Tokens Tokens `json:"tokens"`
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package benefactoreparam
|
||||||
|
|
||||||
|
type SendOtpRequest struct {
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
}
|
||||||
|
type SendOtpResponse struct {
|
||||||
|
PhoneNumber string `json:"phone_number"`
|
||||||
|
/*
|
||||||
|
this just use in test env
|
||||||
|
TODO - remove it after test
|
||||||
|
*/
|
||||||
|
Code string `json:"code"`
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
package benefactoreparam
|
||||||
|
|
||||||
|
type Tokens struct {
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
RefreshToken string `json:"refresh_token"`
|
||||||
|
}
|
|
@ -9,8 +9,7 @@ const (
|
||||||
ErrorMsgPhoneNumberIsNotValid = "phone number is not valid"
|
ErrorMsgPhoneNumberIsNotValid = "phone number is not valid"
|
||||||
ErrorMsgUserNotAllowed = "user not allowed"
|
ErrorMsgUserNotAllowed = "user not allowed"
|
||||||
ErrorMsgUserNotFound = "benefactor not found"
|
ErrorMsgUserNotFound = "benefactor not found"
|
||||||
|
ErrorMsgOtpCodeExist = "please wait a little bit"
|
||||||
|
ErrorMsgOtpCodeIsNotValid = "verification code is not valid"
|
||||||
|
ErrorMsgCantScanQueryResult = "can't scan query result"
|
||||||
)
|
)
|
||||||
|
|
||||||
// const (
|
|
||||||
// ErrorMsgCantScanQueryResult = "can't scan query result"
|
|
||||||
// )
|
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
package migrator
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"fmt"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
migrate "github.com/rubenv/sql-migrate"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Migrator struct {
|
||||||
|
dialect string
|
||||||
|
dbConfig mysql.Config
|
||||||
|
migrations *migrate.FileMigrationSource
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - set migration table name
|
||||||
|
// TODO - add limit to Up and Down method
|
||||||
|
|
||||||
|
func New(dbConfig mysql.Config) Migrator {
|
||||||
|
// OR: Read migrations from a folder:
|
||||||
|
migrations := &migrate.FileMigrationSource{
|
||||||
|
Dir: "./repository/mysql/migrations",
|
||||||
|
}
|
||||||
|
|
||||||
|
return Migrator{dbConfig: dbConfig, dialect: "mysql", migrations: migrations}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Migrator) Up() {
|
||||||
|
fmt.Println("mysql add= ", fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true",
|
||||||
|
m.dbConfig.Username, m.dbConfig.Password, m.dbConfig.Host, m.dbConfig.Port, m.dbConfig.DBName))
|
||||||
|
db, err := sql.Open(m.dialect, fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true",
|
||||||
|
m.dbConfig.Username, m.dbConfig.Password, m.dbConfig.Host, m.dbConfig.Port, m.dbConfig.DBName))
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("can't open mysql db: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := migrate.Exec(db, m.dialect, m.migrations, migrate.Up)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("can't apply migrations: %v", err))
|
||||||
|
}
|
||||||
|
fmt.Printf("Applied %d migrations!\n", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Migrator) Down() {
|
||||||
|
db, err := sql.Open(m.dialect, fmt.Sprintf("%s:%s@(%s:%d)/%s?parseTime=true",
|
||||||
|
m.dbConfig.Username, m.dbConfig.Password, m.dbConfig.Host, m.dbConfig.Port, m.dbConfig.DBName))
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("can't open mysql db: %v", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
n, err := migrate.Exec(db, m.dialect, m.migrations, migrate.Down)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Errorf("can't rollback migrations: %v", err))
|
||||||
|
}
|
||||||
|
fmt.Printf("Rollbacked %d migrations!\n", n)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m Migrator) Status() {
|
||||||
|
// TODO - add status
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
package mysqlbenefactor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DB) CreateBenefactor(ctx context.Context, benefactor entity.Benefactor) (entity.Benefactor, error) {
|
||||||
|
const op = "mysqlbenefactor.CreateBenefactor"
|
||||||
|
|
||||||
|
res, err := d.conn.Conn().Exec(`insert into benefactors(phone_number, status, role) values(?, ?, ?)`,
|
||||||
|
benefactor.PhoneNumber, benefactor.Status.String(), benefactor.Role.String())
|
||||||
|
if err != nil {
|
||||||
|
return entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// error is always nil
|
||||||
|
id, _ := res.LastInsertId()
|
||||||
|
benefactor.ID = uint(id)
|
||||||
|
|
||||||
|
return benefactor, nil
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package mysqlbenefactor
|
||||||
|
|
||||||
|
import "git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
|
||||||
|
type DB struct {
|
||||||
|
conn *mysql.DB
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(conn *mysql.DB) *DB {
|
||||||
|
return &DB{
|
||||||
|
conn: conn,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,50 @@
|
||||||
|
package mysqlbenefactor
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DB) IsExistBenefactorByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Benefactor, error) {
|
||||||
|
const op = "mysqlbenefactor.IsExistBenefactorByPhoneNumber"
|
||||||
|
|
||||||
|
row := d.conn.Conn().QueryRowContext(ctx, `select * from benefactors where phone_number = ?`, phoneNumber)
|
||||||
|
|
||||||
|
Benefactor, err := scanBenefactor(row)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
return false, entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgNotFound).WithKind(richerror.KindNotFound)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - log unexpected error for better observability
|
||||||
|
return false, entity.Benefactor{}, richerror.New(op).WithErr(err).
|
||||||
|
WithMessage(errmsg.ErrorMsgCantScanQueryResult).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, Benefactor, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func scanBenefactor(scanner mysql.Scanner) (entity.Benefactor, error) {
|
||||||
|
var createdAt time.Time
|
||||||
|
var benefactor entity.Benefactor
|
||||||
|
var roleStr, genderStr, statusStr string
|
||||||
|
|
||||||
|
err := scanner.Scan(&benefactor.ID, &benefactor.FirstName,
|
||||||
|
&benefactor.LastName, &benefactor.PhoneNumber,
|
||||||
|
&benefactor.Address, &benefactor.Description,
|
||||||
|
&benefactor.Email, &benefactor.City, &genderStr,
|
||||||
|
&statusStr, &benefactor.Birthdate, &roleStr,
|
||||||
|
&createdAt)
|
||||||
|
|
||||||
|
benefactor.Role = entity.MapToUserRole(roleStr)
|
||||||
|
benefactor.Gender = entity.MapToGender(genderStr)
|
||||||
|
benefactor.Status = entity.MapToBenefactorStatus(statusStr)
|
||||||
|
|
||||||
|
return benefactor, err
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
production:
|
||||||
|
dialect: mysql
|
||||||
|
datasource: niki:nikiappt0lk2o20(localhost:3308)/niki_db?parseTime=true
|
||||||
|
dir: repository/mysql/migration
|
||||||
|
table: gorp_migrations
|
|
@ -0,0 +1,21 @@
|
||||||
|
-- +migrate Up
|
||||||
|
-- please read this article to understand why we use VARCHAR(191)
|
||||||
|
-- https://www.grouparoo.com/blog/varchar-191#why-varchar-and-not-text
|
||||||
|
CREATE TABLE `benefactors` (
|
||||||
|
`id` INT PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
`first_name` VARCHAR(191) ,
|
||||||
|
`last_name` VARCHAR(191) ,
|
||||||
|
`phone_number` VARCHAR(191) NOT NULL UNIQUE,
|
||||||
|
`address` TEXT,
|
||||||
|
`description` TEXT,
|
||||||
|
`email` VARCHAR(191),
|
||||||
|
`city` VARCHAR(191),
|
||||||
|
`gender` VARCHAR(191),
|
||||||
|
`status` VARCHAR(191),
|
||||||
|
`birthdate` TIMESTAMP,
|
||||||
|
`role` ENUM('benefactor') NOT NULL,
|
||||||
|
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
|
);
|
||||||
|
|
||||||
|
-- +migrate Down
|
||||||
|
DROP TABLE `benefactors`;
|
|
@ -0,0 +1,5 @@
|
||||||
|
package mysql
|
||||||
|
|
||||||
|
type Scanner interface {
|
||||||
|
Scan(dest ...any) error
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package redisotp
|
||||||
|
|
||||||
|
import "git.gocasts.ir/ebhomengo/niki/adapter/redis"
|
||||||
|
|
||||||
|
type DB struct {
|
||||||
|
adapter redis.Adapter
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(adapter redis.Adapter) DB {
|
||||||
|
return DB{adapter: adapter}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package redisotp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DB) IsExistPhoneNumber(ctx context.Context, phoneNumber string) (bool, error) {
|
||||||
|
const op = "redisotp.IsExistPhoneNumber"
|
||||||
|
|
||||||
|
isExist, err := d.adapter.Client().Exists(ctx, phoneNumber).Result()
|
||||||
|
if err != nil {
|
||||||
|
return false, richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
if isExist == 0 {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, nil
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package redisotp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DB) GetCodeByPhoneNumber(ctx context.Context, phoneNumber string) (string, error) {
|
||||||
|
const op = "redisotp.GetCodeByPhoneNumber"
|
||||||
|
|
||||||
|
value, err := d.adapter.Client().Get(ctx, phoneNumber).Result()
|
||||||
|
if err != nil {
|
||||||
|
return "", richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return value, nil
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package redisotp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (d DB) SaveCodeWithPhoneNumber(ctx context.Context, phoneNumber string, code string, expireTime time.Duration) error {
|
||||||
|
const op = "redisotp.SaveCodeWithPhoneNumber"
|
||||||
|
err := d.adapter.Client().Set(ctx, phoneNumber, code, expireTime).Err()
|
||||||
|
if err != nil {
|
||||||
|
return richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package benefactorauthservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Claims struct {
|
||||||
|
jwt.RegisteredClaims
|
||||||
|
UserID uint `json:"user_id"`
|
||||||
|
Role entity.UserRole `json:"role"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c Claims) Valid() error {
|
||||||
|
return c.RegisteredClaims.Valid()
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
package benefactorauthservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
SignKey string `koanf:"sign_key"`
|
||||||
|
AccessExpirationTime time.Duration `koanf:"access_expiration_time"`
|
||||||
|
RefreshExpirationTime time.Duration `koanf:"refresh_expiration_time"`
|
||||||
|
AccessSubject string `koanf:"access_subject"`
|
||||||
|
RefreshSubject string `koanf:"refresh_subject"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
config Config
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg Config) Service {
|
||||||
|
return Service{
|
||||||
|
config: cfg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) CreateAccessToken(benefactor entity.Benefactor) (string, error) {
|
||||||
|
return s.createToken(benefactor.ID, benefactor.Role, s.config.AccessSubject, s.config.AccessExpirationTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) CreateRefreshToken(benefactor entity.Benefactor) (string, error) {
|
||||||
|
return s.createToken(benefactor.ID, benefactor.Role, s.config.RefreshSubject, s.config.RefreshExpirationTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) ParseToken(bearerToken string) (*Claims, error) {
|
||||||
|
//https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-ParseWithClaims-CustomClaimsType
|
||||||
|
|
||||||
|
tokenStr := strings.Replace(bearerToken, "Bearer ", "", 1)
|
||||||
|
|
||||||
|
token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
|
return []byte(s.config.SignKey), nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
|
||||||
|
return claims, nil
|
||||||
|
} else {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) createToken(userID uint, role entity.UserRole, subject string, expireDuration time.Duration) (string, error) {
|
||||||
|
// create a signer for rsa 256
|
||||||
|
// TODO - replace with rsa 256 RS256 - https://github.com/golang-jwt/jwt/blob/main/http_example_test.go
|
||||||
|
|
||||||
|
// set our claims
|
||||||
|
claims := Claims{
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
|
Subject: subject,
|
||||||
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)),
|
||||||
|
},
|
||||||
|
UserID: userID,
|
||||||
|
Role: role,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO - add sign method to config
|
||||||
|
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||||
|
tokenString, err := accessToken.SignedString([]byte(s.config.SignKey))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenString, nil
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
package user
|
|
|
@ -1 +0,0 @@
|
||||||
package user
|
|
|
@ -1,23 +0,0 @@
|
||||||
package user
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Config struct {
|
|
||||||
SignKey string `koanf:"sign_key"`
|
|
||||||
AccessExpirationTime time.Duration `koanf:"access_expiration_time"`
|
|
||||||
RefreshExpirationTime time.Duration `koanf:"refresh_expiration_time"`
|
|
||||||
AccessSubject string `koanf:"access_subject"`
|
|
||||||
RefreshSubject string `koanf:"refresh_subject"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Service struct {
|
|
||||||
config Config
|
|
||||||
}
|
|
||||||
|
|
||||||
func New(cfg Config) Service {
|
|
||||||
return Service{
|
|
||||||
config: cfg,
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,61 @@
|
||||||
|
package benefactorservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) LoginOrRegister(ctx context.Context, req benefactoreparam.LoginOrRegisterRequest) (benefactoreparam.LoginOrRegisterResponse, error) {
|
||||||
|
const op = "benefactorservice.LoginOrRegister"
|
||||||
|
|
||||||
|
code, gErr := s.redisOtp.GetCodeByPhoneNumber(ctx, req.PhoneNumber)
|
||||||
|
if gErr != nil {
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(gErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
if code == "" || code != req.VerificationCode {
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithMessage(errmsg.ErrorMsgOtpCodeIsNotValid).WithKind(richerror.KindForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
isExist, benefactor, rErr := s.repo.IsExistBenefactorByPhoneNumber(ctx, req.PhoneNumber)
|
||||||
|
if rErr != nil {
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(rErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
if !isExist {
|
||||||
|
newBenefactor, err := s.repo.CreateBenefactor(ctx, entity.Benefactor{
|
||||||
|
PhoneNumber: "",
|
||||||
|
Status: entity.BenefactorActiveStatus,
|
||||||
|
Role: entity.UserBenefactorRole,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(rErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
benefactor = newBenefactor
|
||||||
|
}
|
||||||
|
|
||||||
|
accessToken, err := s.auth.CreateAccessToken(benefactor)
|
||||||
|
if err != nil {
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(rErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshToken, err := s.auth.CreateRefreshToken(benefactor)
|
||||||
|
if err != nil {
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(rErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
return benefactoreparam.LoginOrRegisterResponse{
|
||||||
|
BenefactorInfo: benefactoreparam.BenefactroInfo{
|
||||||
|
ID: benefactor.ID,
|
||||||
|
FirstName: benefactor.FirstName,
|
||||||
|
LastName: benefactor.LastName,
|
||||||
|
Role: benefactor.Role.String(),
|
||||||
|
},
|
||||||
|
Tokens: benefactoreparam.Tokens{
|
||||||
|
AccessToken: accessToken,
|
||||||
|
RefreshToken: refreshToken,
|
||||||
|
},
|
||||||
|
}, nil
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
package benefactorservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpRequest) (benefactoreparam.SendOtpResponse, error) {
|
||||||
|
const op = "benefactorservice.SendOtp"
|
||||||
|
|
||||||
|
isExist, iErr := s.redisOtp.IsExistPhoneNumber(ctx, req.PhoneNumber)
|
||||||
|
if iErr != nil {
|
||||||
|
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(iErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
if isExist {
|
||||||
|
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithMessage(errmsg.ErrorMsgOtpCodeExist).WithKind(richerror.KindForbidden)
|
||||||
|
}
|
||||||
|
|
||||||
|
newCode := s.generateVerificationCode()
|
||||||
|
spErr := s.redisOtp.SaveCodeWithPhoneNumber(ctx, req.PhoneNumber, newCode, s.config.OtpExpireTime)
|
||||||
|
if spErr != nil {
|
||||||
|
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(spErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO- use goroutine
|
||||||
|
sErr := s.smsProviderClient.SendSms(req.PhoneNumber, newCode)
|
||||||
|
if sErr != nil {
|
||||||
|
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(sErr).WithKind(richerror.KindUnexpected)
|
||||||
|
}
|
||||||
|
|
||||||
|
// we use code in sendOtpResponse until sms provider will implement
|
||||||
|
return benefactoreparam.SendOtpResponse{
|
||||||
|
PhoneNumber: req.PhoneNumber,
|
||||||
|
Code: newCode, //TODO - have to remove it in production
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Service) generateVerificationCode() string {
|
||||||
|
rand.NewSource(time.Now().UnixNano())
|
||||||
|
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)
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
package benefactorservice
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"git.gocasts.ir/ebhomengo/niki/entity"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
LengthOfOtpCode int `koanf:"length_of_otp_code"`
|
||||||
|
OtpChars string `koanf:"otp_chars"`
|
||||||
|
OtpExpireTime time.Duration `koanf:"otp_expire_time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Repository interface {
|
||||||
|
IsExistBenefactorByPhoneNumber(ctx context.Context, phoneNumber string) (bool, entity.Benefactor, error)
|
||||||
|
CreateBenefactor(ctx context.Context, benefactor entity.Benefactor) (entity.Benefactor, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthGenerator interface {
|
||||||
|
CreateAccessToken(benefactor entity.Benefactor) (string, error)
|
||||||
|
CreateRefreshToken(benefactor entity.Benefactor) (string, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RedisOtp 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
type SmsProviderClient interface {
|
||||||
|
SendSms(phoneNumber string, code string) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type Service struct {
|
||||||
|
config Config
|
||||||
|
redisOtp RedisOtp
|
||||||
|
smsProviderClient SmsProviderClient
|
||||||
|
auth AuthGenerator
|
||||||
|
repo Repository
|
||||||
|
}
|
||||||
|
|
||||||
|
func New(cfg Config, redisOtp RedisOtp, smsProviderClient SmsProviderClient,
|
||||||
|
auth AuthGenerator, repo Repository) Service {
|
||||||
|
|
||||||
|
return Service{
|
||||||
|
config: cfg,
|
||||||
|
redisOtp: redisOtp,
|
||||||
|
smsProviderClient: smsProviderClient,
|
||||||
|
auth: auth,
|
||||||
|
repo: repo,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,41 @@
|
||||||
|
package benefactorvalidator
|
||||||
|
|
||||||
|
import (
|
||||||
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
|
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v Validator) ValidateLoginRegisterRequest(req benefactoreparam.LoginOrRegisterRequest) (map[string]string, error) {
|
||||||
|
const op = "benefactorvalidator.ValidateRegisterRequest"
|
||||||
|
|
||||||
|
if err := validation.ValidateStruct(&req,
|
||||||
|
// TODO - add length of code config from benefactor config
|
||||||
|
//validation.Field(&req.VerificationCode,
|
||||||
|
// validation.Required,
|
||||||
|
// validation.Length(3, 50)),
|
||||||
|
|
||||||
|
validation.Field(&req.PhoneNumber,
|
||||||
|
validation.Required,
|
||||||
|
validation.Match(regexp.MustCompile(phoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid))); err != nil {
|
||||||
|
fieldErrors := make(map[string]string)
|
||||||
|
|
||||||
|
errV, ok := err.(validation.Errors)
|
||||||
|
if ok {
|
||||||
|
for key, value := range errV {
|
||||||
|
if value != nil {
|
||||||
|
fieldErrors[key] = value.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fieldErrors, richerror.New(op).WithMessage(errmsg.ErrorMsgInvalidInput).
|
||||||
|
WithKind(richerror.KindInvalid).
|
||||||
|
WithMeta(map[string]interface{}{"req": req}).WithErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package benefactorvalidator
|
||||||
|
|
||||||
|
import (
|
||||||
|
benefactoreparam "git.gocasts.ir/ebhomengo/niki/param/benefactor/benefactore"
|
||||||
|
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
|
||||||
|
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
|
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v Validator) ValidateSendOtpRequest(req benefactoreparam.SendOtpRequest) (map[string]string, error) {
|
||||||
|
const op = "benefactorvalidator.ValidateSendOtpRequest"
|
||||||
|
|
||||||
|
if err := validation.ValidateStruct(&req,
|
||||||
|
validation.Field(&req.PhoneNumber,
|
||||||
|
validation.Required,
|
||||||
|
validation.Match(regexp.MustCompile(phoneNumberRegex)).Error(errmsg.ErrorMsgPhoneNumberIsNotValid))); err != nil {
|
||||||
|
fieldErrors := make(map[string]string)
|
||||||
|
|
||||||
|
errV, ok := err.(validation.Errors)
|
||||||
|
if ok {
|
||||||
|
for key, value := range errV {
|
||||||
|
if value != nil {
|
||||||
|
fieldErrors[key] = value.Error()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fieldErrors, richerror.New(op).WithMessage(errmsg.ErrorMsgInvalidInput).
|
||||||
|
WithKind(richerror.KindInvalid).
|
||||||
|
WithMeta(map[string]interface{}{"req": req}).WithErr(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, nil
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package benefactorvalidator
|
||||||
|
|
||||||
|
const (
|
||||||
|
phoneNumberRegex = "^09[0-9]{9}$"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Validator struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() Validator {
|
||||||
|
return Validator{}
|
||||||
|
}
|
Loading…
Reference in New Issue