feat(niki): add benefactor logn or register - run server

This commit is contained in:
Masood Keshvari 2024-01-15 14:03:24 +03:30
parent 0760ab8fe2
commit f622b6edd0
30 changed files with 184 additions and 78 deletions

View File

@ -2,6 +2,7 @@ package redis
import (
"fmt"
"github.com/redis/go-redis/v9"
)

View File

@ -5,11 +5,11 @@ type Config struct {
Port int `koanf:"port"`
}
type Adapter struct {
}
type Adapter struct{}
//nolint
func New(config Config) Adapter {
//rdb := redis.NewClient(&redis.Options{
// rdb := redis.NewClient(&redis.Options{
// Addr: fmt.Sprintf("%s:%d", config.Host, config.Port),
//})

View File

@ -1,5 +1,6 @@
package smsprovider
//nolint
func (a Adapter) SendSms(phoneNumber string, code string) error {
return nil
}

View File

@ -3,8 +3,8 @@ package config
import "time"
const (
OptChars = "0123456789"
OtpExpireTime time.Duration = 120000 // 2 minutes
OtpChars = "0123456789"
OtpExpireTime time.Duration = 2 * 60 * 1000 * 1000000 // 2 minutes
JwtSignKey = "jwt_secret"
AccessTokenSubject = "ac"

View File

@ -1,5 +1,24 @@
package config
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
)
func Default() Config {
return Config{}
cfx := Config{
Auth: authservice.Config{
AccessExpirationTime: AccessTokenExpireDuration,
RefreshExpirationTime: RefreshTokenExpireDuration,
AccessSubject: AccessTokenSubject,
RefreshSubject: RefreshTokenSubject,
},
BenefactorSvc: benefactorservice.Config{
OtpChars: OtpChars,
OtpExpireTime: OtpExpireTime,
},
}
return cfx
}

View File

@ -2,7 +2,7 @@ package adminkindboxhandler
import (
adminkindboxservice "git.gocasts.ir/ebhomengo/niki/service/admin/kind_box"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/user"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
adminkindboxvalidator "git.gocasts.ir/ebhomengo/niki/validator/admin/kind_box"
)

View File

@ -2,7 +2,7 @@ package adminkindboxreqhandler
import (
adminkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/admin/kind_box_req"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/user"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
adminkindboxreqvalidator "git.gocasts.ir/ebhomengo/niki/validator/admin/kind_box_req"
)

View File

@ -1,10 +1,11 @@
package benefactorhandler
import (
"net/http"
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 {

View File

@ -1,10 +1,11 @@
package benefactorhandler
import (
"net/http"
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 {

View File

@ -1,7 +1,7 @@
package benefactorkindboxreqhandler
import (
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/user"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
benefactorkindboxreqservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/kind_box_req"
benefactorkindboxreqvalidator "git.gocasts.ir/ebhomengo/niki/validator/benefactor/kind_box_req"
)

View File

@ -2,11 +2,11 @@ package httpserver
import (
"fmt"
config "git.gocasts.ir/ebhomengo/niki/config"
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"
echo "github.com/labstack/echo/v4"
middleware "github.com/labstack/echo/v4/middleware"
)

View File

@ -7,7 +7,7 @@ services:
- "3306:3306"
container_name: niki-database
volumes:
- niki-db-data:/data
- dbdata:/var/lib/mysql
restart: always
command: [ 'mysqld', '--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci' ]
environment:
@ -33,5 +33,4 @@ services:
volumes:
dbdata:
niki-redis-data:
niki-db-data:
niki-redis-data:

3
go.mod
View File

@ -5,10 +5,12 @@ go 1.21.3
require (
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/knadh/koanf v1.5.0
github.com/labstack/echo/v4 v4.11.4
github.com/redis/go-redis/v9 v9.4.0
github.com/rubenv/sql-migrate v1.6.0
gopkg.in/natefinch/lumberjack.v2 v2.2.1
)
@ -26,7 +28,6 @@ require (
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // 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/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.17.0 // indirect

19
go.sum
View File

@ -71,6 +71,8 @@ github.com/go-ozzo/ozzo-validation v3.6.0+incompatible h1:msy24VGS42fKO9K1vLz82/
github.com/go-ozzo/ozzo-validation v3.6.0+incompatible/go.mod h1:gsEKFIVnabGBt6mXmxK0MoFy+cZoTJY6mu5Ll3LVLBU=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
@ -165,15 +167,19 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
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/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/labstack/echo/v4 v4.11.4 h1:vDZmA+qNeh1pd/cCkEicDMrjtrnMGQ1QFI9gWN1zGq8=
github.com/labstack/echo/v4 v4.11.4/go.mod h1:noh7EvLwqDsmh/X/HWKPUl1AjzJrhyptRyEbQJfxen8=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/lib/pq v1.10.7 h1:p7ZhMD+KsSRozJr34udlUrhboJwWAgCg34+/ZZNvZZw=
github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
@ -187,6 +193,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.1.26/go.mod h1:bPDLeHnStXmXAq1m/Ch/hvfNHr14JKNPMBo3VZKjuso=
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
@ -226,6 +234,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s=
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
@ -245,6 +255,8 @@ github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwy
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/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/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=
@ -416,8 +428,9 @@ google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQ
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/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=

15
main.go
View File

@ -5,21 +5,21 @@ import (
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"
_ "github.com/go-sql-driver/mysql"
)
func main() {
cfg := config.C()
// TODO - add command for migrations
mgr := migrator.New(cfg.Mysql)
mgr.Up()
// mgr := migrator.New(cfg.Mysql)
// mgr.Up()
_, benefactorSvc, benefactorVld := setupServices(cfg)
server := httpserver.New(cfg, benefactorSvc, benefactorVld)
@ -27,10 +27,9 @@ func main() {
}
func setupServices(cfg config.Config) (
authservice.Service, benefactorservice.Service, benefactorvalidator.Validator,
authSvc authservice.Service, benefactorSvc benefactorservice.Service, benefactorVld benefactorvalidator.Validator,
) {
authSvc := authservice.New(cfg.Auth)
authSvc = authservice.New(cfg.Auth)
MysqlRepo := mysql.New(cfg.Mysql)
@ -40,9 +39,9 @@ func setupServices(cfg config.Config) (
smsProvider := smsprovider.New(cfg.SmsProvider)
authGenerator := authservice.New(cfg.Auth)
benefactorSvc := benefactorservice.New(cfg.BenefactorSvc, RedisOtp, smsProvider, authGenerator, benefactorMysql)
benefactorSvc = benefactorservice.New(cfg.BenefactorSvc, RedisOtp, smsProvider, authGenerator, benefactorMysql)
benefactorVld := benefactorvalidator.New()
benefactorVld = benefactorvalidator.New()
return authSvc, benefactorSvc, benefactorVld
}

View File

@ -2,6 +2,7 @@ package httpmsg
import (
"errors"
"fmt"
"net/http"
errmsg "git.gocasts.ir/ebhomengo/niki/pkg/err_msg"
@ -22,6 +23,8 @@ func Error(err error) (message string, code int) {
code = mapKindToHTTPStatusCode(re.Kind())
// we should not expose unexpected error messages
if code >= internalStatus {
// TODO - we have to use log instead of print
fmt.Println("internal error: ", msg)
msg = errmsg.ErrorMsgSomethingWentWrong
}

View File

@ -3,6 +3,7 @@ package migrator
import (
"database/sql"
"fmt"
"git.gocasts.ir/ebhomengo/niki/repository/mysql"
migrate "github.com/rubenv/sql-migrate"
)
@ -19,7 +20,7 @@ type Migrator struct {
func New(dbConfig mysql.Config) Migrator {
// OR: Read migrations from a folder:
migrations := &migrate.FileMigrationSource{
Dir: "./repository/mysql/migrations",
Dir: "./repository/mysql/migration",
}
return Migrator{dbConfig: dbConfig, dialect: "mysql", migrations: migrations}
@ -31,12 +32,12 @@ func (m Migrator) Up() {
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))
panic(fmt.Errorf("can't open mysql db: %w", err))
}
n, err := migrate.Exec(db, m.dialect, m.migrations, migrate.Up)
if err != nil {
panic(fmt.Errorf("can't apply migrations: %v", err))
panic(fmt.Errorf("can't apply migrations: %w", err))
}
fmt.Printf("Applied %d migrations!\n", n)
}
@ -45,12 +46,12 @@ 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))
panic(fmt.Errorf("can't open mysql db: %w", err))
}
n, err := migrate.Exec(db, m.dialect, m.migrations, migrate.Down)
if err != nil {
panic(fmt.Errorf("can't rollback migrations: %v", err))
panic(fmt.Errorf("can't rollback migrations: %w", err))
}
fmt.Printf("Rollbacked %d migrations!\n", n)
}

View File

@ -2,6 +2,7 @@ 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"
@ -10,13 +11,14 @@ import (
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(?, ?, ?)`,
res, err := d.conn.Conn().ExecContext(ctx, `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)
}
//nolint
// error is always nil
id, _ := res.LastInsertId()
benefactor.ID = uint(id)

View File

@ -3,11 +3,13 @@ package mysqlbenefactor
import (
"context"
"database/sql"
"errors"
"time"
"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) {
@ -17,9 +19,11 @@ func (d DB) IsExistBenefactorByPhoneNumber(ctx context.Context, phoneNumber stri
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)
sErr := sql.ErrNoRows
//TODO-errorsas: second argument to errors.As should not be *error
//nolint
if errors.As(err, &sErr) {
return false, entity.Benefactor{}, nil
}
// TODO - log unexpected error for better observability
@ -33,18 +37,60 @@ func (d DB) IsExistBenefactorByPhoneNumber(ctx context.Context, phoneNumber stri
func scanBenefactor(scanner mysql.Scanner) (entity.Benefactor, error) {
var createdAt time.Time
var benefactor entity.Benefactor
var roleStr, genderStr, statusStr string
var roleStr, statusStr string
// TODO - use db model and mapper between entity and db model OR use this approach
err := scanner.Scan(&benefactor.ID, &benefactor.FirstName,
&benefactor.LastName, &benefactor.PhoneNumber,
&benefactor.Address, &benefactor.Description,
&benefactor.Email, &benefactor.City, &genderStr,
&statusStr, &benefactor.Birthdate, &roleStr,
var benefactorNullableFields nullableFields
err := scanner.Scan(&benefactor.ID, &benefactorNullableFields.firstName,
&benefactorNullableFields.lastName, &benefactor.PhoneNumber,
&benefactorNullableFields.address, &benefactorNullableFields.description,
&benefactorNullableFields.email, &benefactorNullableFields.city, &benefactorNullableFields.genderStr,
&statusStr, &benefactorNullableFields.birthdate, &roleStr,
&createdAt)
benefactor.Role = entity.MapToUserRole(roleStr)
benefactor.Gender = entity.MapToGender(genderStr)
benefactor.Status = entity.MapToBenefactorStatus(statusStr)
mapNotNullToBenefactor(benefactorNullableFields, &benefactor)
return benefactor, err
}
type nullableFields struct {
firstName sql.NullString
lastName sql.NullString
address sql.NullString
description sql.NullString
email sql.NullString
city sql.NullString
genderStr sql.NullString
birthdate sql.NullTime
}
// TODO - find the other solution.
func mapNotNullToBenefactor(data nullableFields, benefactor *entity.Benefactor) {
if data.firstName.Valid {
benefactor.FirstName = data.firstName.String
}
if data.lastName.Valid {
benefactor.LastName = data.lastName.String
}
if data.address.Valid {
benefactor.Address = data.address.String
}
if data.description.Valid {
benefactor.Description = data.description.String
}
if data.email.Valid {
benefactor.Email = data.email.String
}
if data.city.Valid {
benefactor.City = data.city.String
}
if data.genderStr.Valid {
benefactor.Gender = entity.MapToGender(data.genderStr.String)
}
if data.birthdate.Valid {
benefactor.Birthdate = data.birthdate.Time
}
}

View File

@ -2,6 +2,7 @@ package redisotp
import (
"context"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
)
@ -15,5 +16,6 @@ func (d DB) DeleteCodeByPhoneNumber(ctx context.Context, phoneNumber string) (bo
if success != 1 {
return false, nil
}
return true, nil
}

View File

@ -2,6 +2,7 @@ package redisotp
import (
"context"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
)

View File

@ -2,7 +2,10 @@ package redisotp
import (
"context"
"errors"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"github.com/redis/go-redis/v9"
)
func (d DB) GetCodeByPhoneNumber(ctx context.Context, phoneNumber string) (string, error) {
@ -10,6 +13,11 @@ func (d DB) GetCodeByPhoneNumber(ctx context.Context, phoneNumber string) (strin
value, err := d.adapter.Client().Get(ctx, phoneNumber).Result()
if err != nil {
rErr := redis.Nil
if errors.As(err, &rErr) {
return "", nil
}
return "", richerror.New(op).WithErr(err).WithKind(richerror.KindUnexpected)
}

View File

@ -2,12 +2,14 @@ package redisotp
import (
"context"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"time"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
)
func (d DB) SaveCodeWithPhoneNumber(ctx context.Context, phoneNumber string, code string, expireTime time.Duration) error {
func (d DB) SaveCodeWithPhoneNumber(ctx context.Context, phoneNumber, 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)

View File

@ -1,10 +1,11 @@
package benefactorauthservice
import (
"git.gocasts.ir/ebhomengo/niki/entity"
"github.com/golang-jwt/jwt/v4"
"strings"
"time"
"git.gocasts.ir/ebhomengo/niki/entity"
"github.com/golang-jwt/jwt/v4"
)
type Config struct {
@ -34,7 +35,7 @@ func (s Service) CreateRefreshToken(benefactor entity.Benefactor) (string, error
}
func (s Service) ParseToken(bearerToken string) (*Claims, error) {
//https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-ParseWithClaims-CustomClaimsType
// https://pkg.go.dev/github.com/golang-jwt/jwt/v5#example-ParseWithClaims-CustomClaimsType
tokenStr := strings.Replace(bearerToken, "Bearer ", "", 1)
@ -47,9 +48,9 @@ func (s Service) ParseToken(bearerToken string) (*Claims, error) {
if claims, ok := token.Claims.(*Claims); ok && token.Valid {
return claims, nil
} else {
return nil, err
}
return nil, err
}
func (s Service) createToken(userID uint, role entity.UserRole, subject string, expireDuration time.Duration) (string, error) {

View File

@ -2,6 +2,7 @@ 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"
@ -19,13 +20,10 @@ func (s Service) LoginOrRegister(ctx context.Context, req benefactoreparam.Login
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithMessage(errmsg.ErrorMsgOtpCodeIsNotValid).WithKind(richerror.KindForbidden)
}
deleted, dErr := s.redisOtp.DeleteCodeByPhoneNumber(ctx, req.PhoneNumber)
_, dErr := s.redisOtp.DeleteCodeByPhoneNumber(ctx, req.PhoneNumber)
if dErr != nil {
return benefactoreparam.LoginOrRegisterResponse{}, richerror.New(op).WithErr(gErr).WithKind(richerror.KindUnexpected)
}
if !deleted {
//TODO - add to log
}
isExist, benefactor, rErr := s.repo.IsExistBenefactorByPhoneNumber(ctx, req.PhoneNumber)
if rErr != nil {
@ -33,7 +31,7 @@ func (s Service) LoginOrRegister(ctx context.Context, req benefactoreparam.Login
}
if !isExist {
newBenefactor, err := s.repo.CreateBenefactor(ctx, entity.Benefactor{
PhoneNumber: "",
PhoneNumber: req.PhoneNumber,
Status: entity.BenefactorActiveStatus,
Role: entity.UserBenefactorRole,
})

View File

@ -2,11 +2,12 @@ package benefactorservice
import (
"context"
"math/rand"
"time"
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) {
@ -26,7 +27,7 @@ func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpReques
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(spErr).WithKind(richerror.KindUnexpected)
}
//TODO- use goroutine
// TODO- use goroutine
sErr := s.smsProviderClient.SendSms(req.PhoneNumber, newCode)
if sErr != nil {
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(sErr).WithKind(richerror.KindUnexpected)
@ -35,7 +36,7 @@ func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpReques
// 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
Code: newCode, // TODO - have to remove it in production
}, nil
}
@ -43,7 +44,9 @@ func (s Service) generateVerificationCode() string {
rand.NewSource(time.Now().UnixNano())
result := make([]byte, s.config.LengthOfOtpCode)
for i := 0; i < s.config.LengthOfOtpCode; i++ {
//nolint
result[i] = s.config.OtpChars[rand.Intn(len(s.config.OtpChars))]
}
return string(result)
}

View File

@ -2,8 +2,9 @@ package benefactorservice
import (
"context"
"git.gocasts.ir/ebhomengo/niki/entity"
"time"
"git.gocasts.ir/ebhomengo/niki/entity"
)
type Config struct {
@ -42,8 +43,8 @@ type Service struct {
}
func New(cfg Config, redisOtp RedisOtp, smsProviderClient SmsProviderClient,
auth AuthGenerator, repo Repository) Service {
auth AuthGenerator, repo Repository,
) Service {
return Service{
config: cfg,
redisOtp: redisOtp,

View File

@ -1,12 +1,13 @@
package benefactorvalidator
import (
"errors"
"regexp"
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) {
@ -14,7 +15,7 @@ func (v Validator) ValidateLoginRegisterRequest(req benefactoreparam.LoginOrRegi
if err := validation.ValidateStruct(&req,
// TODO - add length of code config from benefactor config
//validation.Field(&req.VerificationCode,
// validation.Field(&req.VerificationCode,
// validation.Required,
// validation.Length(3, 50)),
@ -23,9 +24,9 @@ func (v Validator) ValidateLoginRegisterRequest(req benefactoreparam.LoginOrRegi
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 {
vErr := validation.Errors{}
if errors.As(err, &vErr) {
for key, value := range vErr {
if value != nil {
fieldErrors[key] = value.Error()
}
@ -37,5 +38,6 @@ func (v Validator) ValidateLoginRegisterRequest(req benefactoreparam.LoginOrRegi
WithMeta(map[string]interface{}{"req": req}).WithErr(err)
}
//nolint
return nil, nil
}

View File

@ -1,12 +1,13 @@
package benefactorvalidator
import (
"errors"
"regexp"
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) {
@ -18,9 +19,9 @@ func (v Validator) ValidateSendOtpRequest(req benefactoreparam.SendOtpRequest) (
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 {
vErr := validation.Errors{}
if errors.As(err, &vErr) {
for key, value := range vErr {
if value != nil {
fieldErrors[key] = value.Error()
}
@ -32,5 +33,6 @@ func (v Validator) ValidateSendOtpRequest(req benefactoreparam.SendOtpRequest) (
WithMeta(map[string]interface{}{"req": req}).WithErr(err)
}
//nolint
return nil, nil
}

View File

@ -1,11 +1,10 @@
package benefactorvalidator
const (
phoneNumberRegex = "^09[0-9]{9}$"
phoneNumberRegex = "^09\\d{9}$"
)
type Validator struct {
}
type Validator struct{}
func New() Validator {
return Validator{}