forked from ebhomengo/niki
				
			feat(adapter): add kavenegar sms provider adapter
This commit is contained in:
		
							parent
							
								
									1a4db87c73
								
							
						
					
					
						commit
						5c41903221
					
				| 
						 | 
					@ -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{}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -1,6 +0,0 @@
 | 
				
			||||||
package smsprovider
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
//nolint
 | 
					 | 
				
			||||||
func (a Adapter) SendSms(phoneNumber string, code string) error {
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
								
								
								
								
							
							
						
						
									
										1
									
								
								go.mod
								
								
								
								
							| 
						 | 
					@ -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
								
								
								
								
							
							
						
						
									
										2
									
								
								go.sum
								
								
								
								
							| 
						 | 
					@ -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=
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										9
									
								
								main.go
								
								
								
								
							
							
						
						
									
										9
									
								
								main.go
								
								
								
								
							| 
						 | 
					@ -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()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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{
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue