[draft] Move sms verificaiton to otp models

This commit is contained in:
Lakhan Samani 2023-07-12 11:24:13 +05:30
parent 07f71e883b
commit abe809ca68
9 changed files with 78 additions and 23 deletions

View File

@ -1,14 +1,22 @@
package models package models
const (
// FieldName email is the field name for email
FieldNameEmail = "email"
// FieldNamePhoneNumber is the field name for phone number
FieldNamePhoneNumber = "phone_number"
)
// OTP model for database // OTP model for database
type OTP struct { type OTP struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"` Email string `gorm:"unique" json:"email" bson:"email" cql:"email" dynamo:"email" index:"email,hash"`
Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"` PhoneNumber string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number" index:"phone_number,hash"`
ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"` Otp string `json:"otp" bson:"otp" cql:"otp" dynamo:"otp"`
CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"` ExpiresAt int64 `json:"expires_at" bson:"expires_at" cql:"expires_at" dynamo:"expires_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"` CreatedAt int64 `json:"created_at" bson:"created_at" cql:"created_at" dynamo:"created_at"`
UpdatedAt int64 `json:"updated_at" bson:"updated_at" cql:"updated_at" dynamo:"updated_at"`
} }
type Paging struct { type Paging struct {

View File

@ -1,7 +1,8 @@
package models package models
// SMS verification requests model for database // SMSVerificationRequest is SMS verification requests model for database
type SMSVerificationRequest struct { type SMSVerificationRequest struct {
Key string `json:"_key,omitempty" bson:"_key,omitempty" cql:"_key,omitempty" dynamo:"key,omitempty"` // for arangodb
ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"` ID string `gorm:"primaryKey;type:char(36)" json:"_id" bson:"_id" cql:"id" dynamo:"id,hash"`
PhoneNumber string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number" index:"phone_number,hash"` PhoneNumber string `gorm:"unique" json:"phone_number" bson:"phone_number" cql:"phone_number" dynamo:"phone_number" index:"phone_number,hash"`
Code string `json:"code" bson:"code" cql:"code" dynamo:"code"` Code string `json:"code" bson:"code" cql:"code" dynamo:"code"`

View File

@ -225,7 +225,6 @@ func NewProvider() (*provider, error) {
return nil, err return nil, err
} }
} }
otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP) otpCollection, err := arangodb.Collection(ctx, models.Collections.OTP)
if err != nil { if err != nil {
return nil, err return nil, err
@ -235,6 +234,24 @@ func NewProvider() (*provider, error) {
Sparse: true, Sparse: true,
}) })
smsVerificationCollectionExists, err := arangodb.CollectionExists(ctx, models.Collections.SMSVerificationRequest)
if err != nil {
return nil, err
}
if !smsVerificationCollectionExists {
_, err = arangodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, nil)
if err != nil {
return nil, err
}
}
smsVerificationCollection, err := arangodb.Collection(ctx, models.Collections.SMSVerificationRequest)
if err != nil {
return nil, err
}
smsVerificationCollection.EnsureHashIndex(ctx, []string{"phone_number"}, &arangoDriver.EnsureHashIndexOptions{
Unique: true,
Sparse: true,
})
return &provider{ return &provider{
db: arangodb, db: arangodb,
}, err }, err

View File

@ -11,24 +11,19 @@ import (
func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) { func GetSetFields(webhookMap map[string]interface{}) (string, map[string]interface{}) {
params := make(map[string]interface{}, 1) params := make(map[string]interface{}, 1)
updateFields := "" updateFields := ""
for key, value := range webhookMap { for key, value := range webhookMap {
if key == "_id" { if key == "_id" {
continue continue
} }
if key == "_key" { if key == "_key" {
continue continue
} }
if value == nil { if value == nil {
updateFields += fmt.Sprintf("%s=$%s,", key, key) updateFields += fmt.Sprintf("%s=$%s,", key, key)
params[key] = "null" params[key] = "null"
continue continue
} }
valueType := reflect.TypeOf(value) valueType := reflect.TypeOf(value)
if valueType.Name() == "string" { if valueType.Name() == "string" {
updateFields += fmt.Sprintf("%s = $%s, ", key, key) updateFields += fmt.Sprintf("%s = $%s, ", key, key)

View File

@ -2,6 +2,7 @@ package mongodb
import ( import (
"context" "context"
"errors"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -12,6 +13,18 @@ import (
// UpsertOTP to add or update otp // UpsertOTP to add or update otp
func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) { func (p *provider) UpsertOTP(ctx context.Context, otpParam *models.OTP) (*models.OTP, error) {
// check if email or phone number is present
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
return nil, errors.New("email or phone_number is required")
}
// check if email or phone number is present
if otpParam.Email == "" && otpParam.PhoneNumber == "" {
return nil, errors.New("email or phone_number is required")
}
uniqueField := models.FieldNameEmail
if otp.Email == "" && otp.PhoneNumber != "" {
uniqueField = models.FieldNamePhoneNumber
}
otp, _ := p.GetOTPByEmail(ctx, otpParam.Email) otp, _ := p.GetOTPByEmail(ctx, otpParam.Email)
shouldCreate := false shouldCreate := false
if otp == nil { if otp == nil {

View File

@ -118,6 +118,12 @@ func NewProvider() (*provider, error) {
Options: options.Index().SetUnique(true).SetSparse(true), Options: options.Index().SetUnique(true).SetSparse(true),
}, },
}, options.CreateIndexes()) }, options.CreateIndexes())
otpCollection.Indexes().CreateMany(ctx, []mongo.IndexModel{
{
Keys: bson.M{"phone_number": 1},
Options: options.Index().SetUnique(true).SetSparse(true),
},
}, options.CreateIndexes())
mongodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, options.CreateCollection()) mongodb.CreateCollection(ctx, models.Collections.SMSVerificationRequest, options.CreateCollection())
smsCollection := mongodb.Collection(models.Collections.SMSVerificationRequest, options.Collection()) smsCollection := mongodb.Collection(models.Collections.SMSVerificationRequest, options.Collection())

View File

@ -12,10 +12,7 @@ import (
// UpsertSMSRequest adds/updates SMS verification request // UpsertSMSRequest adds/updates SMS verification request
func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) { func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSVerificationRequest) (*models.SMSVerificationRequest, error) {
smsVerificationRequest, err := p.GetCodeByPhone(ctx, smsRequest.PhoneNumber) smsVerificationRequest, _ := p.GetCodeByPhone(ctx, smsRequest.PhoneNumber)
if err != nil {
return nil, err
}
// Boolean to check if we should create a new record or update the existing one // Boolean to check if we should create a new record or update the existing one
shouldCreate := false shouldCreate := false
if smsVerificationRequest == nil { if smsVerificationRequest == nil {
@ -29,7 +26,7 @@ func (p *provider) UpsertSMSRequest(ctx context.Context, smsRequest *models.SMSV
} }
shouldCreate = true shouldCreate = true
} }
var err error
smsVerificationRequest.UpdatedAt = time.Now().Unix() smsVerificationRequest.UpdatedAt = time.Now().Unix()
smsRequestCollection := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection()) smsRequestCollection := p.db.Collection(models.Collections.SMSVerificationRequest, options.Collection())
if shouldCreate { if shouldCreate {

View File

@ -82,6 +82,8 @@ type Provider interface {
UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP, error)
// GetOTPByEmail to get otp for a given email address // GetOTPByEmail to get otp for a given email address
GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error)
// GetOTPByPhoneNumber to get otp for a given phone number
GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error)
// DeleteOTP to delete otp // DeleteOTP to delete otp
DeleteOTP(ctx context.Context, otp *models.OTP) error DeleteOTP(ctx context.Context, otp *models.OTP) error

View File

@ -2,6 +2,7 @@ package sql
import ( import (
"context" "context"
"errors"
"time" "time"
"github.com/authorizerdev/authorizer/server/db/models" "github.com/authorizerdev/authorizer/server/db/models"
@ -14,13 +15,19 @@ func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP,
if otp.ID == "" { if otp.ID == "" {
otp.ID = uuid.New().String() otp.ID = uuid.New().String()
} }
// check if email or phone number is present
if otp.Email == "" && otp.PhoneNumber == "" {
return nil, errors.New("email or phone_number is required")
}
uniqueField := models.FieldNameEmail
if otp.Email == "" && otp.PhoneNumber != "" {
uniqueField = models.FieldNamePhoneNumber
}
otp.Key = otp.ID otp.Key = otp.ID
otp.CreatedAt = time.Now().Unix() otp.CreatedAt = time.Now().Unix()
otp.UpdatedAt = time.Now().Unix() otp.UpdatedAt = time.Now().Unix()
res := p.db.Clauses(clause.OnConflict{ res := p.db.Clauses(clause.OnConflict{
Columns: []clause.Column{{Name: "email"}}, Columns: []clause.Column{{Name: uniqueField}},
DoUpdates: clause.AssignmentColumns([]string{"otp", "expires_at", "updated_at"}), DoUpdates: clause.AssignmentColumns([]string{"otp", "expires_at", "updated_at"}),
}).Create(&otp) }).Create(&otp)
if res.Error != nil { if res.Error != nil {
@ -33,7 +40,6 @@ func (p *provider) UpsertOTP(ctx context.Context, otp *models.OTP) (*models.OTP,
// GetOTPByEmail to get otp for a given email address // GetOTPByEmail to get otp for a given email address
func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) { func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*models.OTP, error) {
var otp models.OTP var otp models.OTP
result := p.db.Where("email = ?", emailAddress).First(&otp) result := p.db.Where("email = ?", emailAddress).First(&otp)
if result.Error != nil { if result.Error != nil {
return nil, result.Error return nil, result.Error
@ -41,6 +47,16 @@ func (p *provider) GetOTPByEmail(ctx context.Context, emailAddress string) (*mod
return &otp, nil return &otp, nil
} }
// GetOTPByPhoneNumber to get otp for a given phone number
func (p *provider) GetOTPByPhoneNumber(ctx context.Context, phoneNumber string) (*models.OTP, error) {
var otp models.OTP
result := p.db.Where("phone_number = ?", phoneNumber).First(&otp)
if result.Error != nil {
return nil, result.Error
}
return &otp, nil
}
// DeleteOTP to delete otp // DeleteOTP to delete otp
func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error { func (p *provider) DeleteOTP(ctx context.Context, otp *models.OTP) error {
result := p.db.Delete(&models.OTP{ result := p.db.Delete(&models.OTP{