feat(adapter): add kavenegar sms provider adapter

This commit is contained in:
Masood Keshvari 2024-01-17 13:34:50 +03:30
parent 1a4db87c73
commit 5c41903221
12 changed files with 120 additions and 42 deletions

View File

@ -1,17 +0,0 @@
package smsprovider
type Config struct {
Host string `koanf:"host"`
Port int `koanf:"port"`
}
type Adapter struct{}
//nolint
func New(config Config) Adapter {
// rdb := redis.NewClient(&redis.Options{
// Addr: fmt.Sprintf("%s:%d", config.Host, config.Port),
//})
return Adapter{}
}

View File

@ -0,0 +1,25 @@
package kavenegar
import "github.com/kavenegar/kavenegar-go"
type Config struct {
APIKey string `koanf:"api_key"`
OtpTemplateNewUser string `koanf:"otp_template_new_user"`
OtpTemplateRegisteredUser string `koanf:"otp_template_registered_user"`
}
type Adapter struct {
config Config
api *kavenegar.Kavenegar
}
func New(config Config) *Adapter {
return &Adapter{config: config, api: kavenegar.New(config.APIKey)}
}
func (a Adapter) Client() *kavenegar.Kavenegar {
return a.api
}
func (a Adapter) Config() Config {
return a.config
}

View File

@ -0,0 +1,13 @@
package kavenegarotp
import (
smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider/kavenegar"
)
type Adapter struct {
adapter *smsprovider.Adapter
}
func New(conn *smsprovider.Adapter) *Adapter {
return &Adapter{adapter: conn}
}

View File

@ -0,0 +1,50 @@
package kavenegarotp
import (
"fmt"
richerror "git.gocasts.ir/ebhomengo/niki/pkg/rich_error"
"github.com/kavenegar/kavenegar-go"
)
func (a Adapter) SendForNewUser(phoneNumber, code string) {
const op = richerror.Op("kavenegarotp.Send")
params := &kavenegar.VerifyLookupParam{}
if _, err := a.adapter.Client().Verify.Lookup(phoneNumber, a.adapter.Config().OtpTemplateNewUser, code, params); err != nil {
//nolint
switch err := err.(type) {
case *kavenegar.APIError:
// log error
fmt.Println(fmt.Errorf("error(%s):%w", op, err))
case *kavenegar.HTTPError:
// log error
fmt.Println(fmt.Errorf("error(%s):%w", op, err))
default:
// log error
fmt.Println(fmt.Errorf("error(%s):%w", op, err))
}
}
// TODO - log res res.Status
}
func (a Adapter) SendForRegisteredUser(phoneNumber, code string) {
const op = richerror.Op("kavenegarotp.Send")
params := &kavenegar.VerifyLookupParam{}
if _, err := a.adapter.Client().Verify.Lookup(phoneNumber, a.adapter.Config().OtpTemplateRegisteredUser, code, params); err != nil {
//nolint
switch err := err.(type) {
case *kavenegar.APIError:
// log error
fmt.Println(fmt.Errorf("error(%s):%w", op, err))
case *kavenegar.HTTPError:
// log error
fmt.Println(fmt.Errorf("error(%s):%w", op, err))
default:
// log error
fmt.Println(fmt.Errorf("error(%s):%w", op, err))
}
}
// TODO - log res res.Status
}

View File

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

View File

@ -27,6 +27,12 @@ sms_provider:
benefactor_service: benefactor_service:
length_of_otp_code: 5 length_of_otp_code: 5
kavenegar_sms_provider:
api_key: insert_your_api_key
otp_template_new_user: ebhomeverify
otp_template_registered_user: ebhomeverify

View File

@ -2,7 +2,7 @@ package config
import ( import (
"git.gocasts.ir/ebhomengo/niki/adapter/redis" "git.gocasts.ir/ebhomengo/niki/adapter/redis"
smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider" smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider/kavenegar"
"git.gocasts.ir/ebhomengo/niki/repository/mysql" "git.gocasts.ir/ebhomengo/niki/repository/mysql"
authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor" authservice "git.gocasts.ir/ebhomengo/niki/service/auth/benefactor"
benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor" benefactorservice "git.gocasts.ir/ebhomengo/niki/service/benefactor/benefactor"
@ -17,6 +17,6 @@ type Config struct {
Mysql mysql.Config `koanf:"mysql"` Mysql mysql.Config `koanf:"mysql"`
Auth authservice.Config `koanf:"auth"` Auth authservice.Config `koanf:"auth"`
Redis redis.Config `koanf:"redis"` Redis redis.Config `koanf:"redis"`
SmsProvider smsprovider.Config `koanf:"sms_provider"` KavenegarSmsProvider smsprovider.Config `koanf:"kavenegar_sms_provider"`
BenefactorSvc benefactorservice.Config `koanf:"benefactor_service"` BenefactorSvc benefactorservice.Config `koanf:"benefactor_service"`
} }

1
go.mod
View File

@ -7,6 +7,7 @@ require (
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/go-sql-driver/mysql v1.6.0 github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.5.0 github.com/golang-jwt/jwt/v4 v4.5.0
github.com/kavenegar/kavenegar-go v0.0.0-20221124112814-40341057b5ca
github.com/knadh/koanf v1.5.0 github.com/knadh/koanf v1.5.0
github.com/labstack/echo-jwt/v4 v4.2.0 github.com/labstack/echo-jwt/v4 v4.2.0
github.com/labstack/echo/v4 v4.11.4 github.com/labstack/echo/v4 v4.11.4

2
go.sum
View File

@ -161,6 +161,8 @@ github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kavenegar/kavenegar-go v0.0.0-20221124112814-40341057b5ca h1:aEyiDaExheG7fNpEYcILCVGgM7jlLzTVgxEQAGaepeM=
github.com/kavenegar/kavenegar-go v0.0.0-20221124112814-40341057b5ca/go.mod h1:CRhvvr4KNAyrg+ewrutOf+/QoHs7lztSoLjp+GqhYlA=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs= github.com/knadh/koanf v1.5.0 h1:q2TSd/3Pyc/5yP9ldIrSdIz26MCcyNQzW0pEAugLPNs=

View File

@ -2,7 +2,8 @@ package main
import ( import (
"git.gocasts.ir/ebhomengo/niki/adapter/redis" "git.gocasts.ir/ebhomengo/niki/adapter/redis"
smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider" smsprovider "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider/kavenegar"
kavenegarotp "git.gocasts.ir/ebhomengo/niki/adapter/sms_provider/kavenegar/otp"
"git.gocasts.ir/ebhomengo/niki/config" "git.gocasts.ir/ebhomengo/niki/config"
httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server" httpserver "git.gocasts.ir/ebhomengo/niki/delivery/http_server"
"git.gocasts.ir/ebhomengo/niki/repository/migrator" "git.gocasts.ir/ebhomengo/niki/repository/migrator"
@ -22,7 +23,6 @@ import (
func main() { func main() {
cfg := config.C() cfg := config.C()
// TODO - add command for migrations // TODO - add command for migrations
mgr := migrator.New(cfg.Mysql) mgr := migrator.New(cfg.Mysql)
mgr.Up() mgr.Up()
@ -44,10 +44,11 @@ func setupServices(cfg config.Config) (
redisAdapter := redis.New(cfg.Redis) redisAdapter := redis.New(cfg.Redis)
RedisOtp := redisotp.New(redisAdapter) RedisOtp := redisotp.New(redisAdapter)
benefactorMysql := mysqlbenefactor.New(MysqlRepo) benefactorMysql := mysqlbenefactor.New(MysqlRepo)
smsProvider := smsprovider.New(cfg.SmsProvider) kavenegarSmsProvider := smsprovider.New(cfg.KavenegarSmsProvider)
otpSmsProvider := kavenegarotp.New(kavenegarSmsProvider)
authGenerator := authservice.New(cfg.Auth) authGenerator := authservice.New(cfg.Auth)
benefactorSvc = benefactorservice.New(cfg.BenefactorSvc, RedisOtp, smsProvider, authGenerator, benefactorMysql) benefactorSvc = benefactorservice.New(cfg.BenefactorSvc, RedisOtp, otpSmsProvider, authGenerator, benefactorMysql)
benefactorVld = benefactorvalidator.New() benefactorVld = benefactorvalidator.New()

View File

@ -27,10 +27,12 @@ func (s Service) SendOtp(ctx context.Context, req benefactoreparam.SendOtpReques
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(spErr).WithKind(richerror.KindUnexpected) return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(spErr).WithKind(richerror.KindUnexpected)
} }
// TODO- use goroutine if isExist {
sErr := s.smsProviderClient.SendSms(req.PhoneNumber, newCode) // Log error in sms provider
if sErr != nil { go s.smsProviderClient.SendForRegisteredUser(req.PhoneNumber, newCode)
return benefactoreparam.SendOtpResponse{}, richerror.New(op).WithErr(sErr).WithKind(richerror.KindUnexpected) } else {
// Log error in sms provider
go s.smsProviderClient.SendForNewUser(req.PhoneNumber, newCode)
} }
// we use code in sendOtpResponse until sms provider will implement // we use code in sendOtpResponse until sms provider will implement

View File

@ -31,19 +31,20 @@ type RedisOtp interface {
DeleteCodeByPhoneNumber(ctx context.Context, phoneNumber string) (bool, error) DeleteCodeByPhoneNumber(ctx context.Context, phoneNumber string) (bool, error)
} }
type SmsProviderClient interface { type OtpSmsProviderClient interface {
SendSms(phoneNumber string, code string) error SendForNewUser(phoneNumber string, code string)
SendForRegisteredUser(phoneNumber string, code string)
} }
type Service struct { type Service struct {
config Config config Config
redisOtp RedisOtp redisOtp RedisOtp
smsProviderClient SmsProviderClient smsProviderClient OtpSmsProviderClient
auth AuthGenerator auth AuthGenerator
repo Repository repo Repository
} }
func New(cfg Config, redisOtp RedisOtp, smsProviderClient SmsProviderClient, func New(cfg Config, redisOtp RedisOtp, smsProviderClient OtpSmsProviderClient,
auth AuthGenerator, repo Repository, auth AuthGenerator, repo Repository,
) Service { ) Service {
return Service{ return Service{