546 lines
16 KiB
Go
546 lines
16 KiB
Go
package domain
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
var (
|
|
ErrSettingNotFound = errors.New("cannot find setting in list")
|
|
)
|
|
|
|
type SettingList struct {
|
|
SMSProvider SMSProvider `json:"sms_provider"`
|
|
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
|
|
BetAmountLimit Currency `json:"bet_amount_limit"`
|
|
DailyTicketPerIP int64 `json:"daily_ticket_limit"`
|
|
TotalWinningLimit Currency `json:"total_winning_limit"`
|
|
AmountForBetReferral Currency `json:"amount_for_bet_referral"`
|
|
CashbackAmountCap Currency `json:"cashback_amount_cap"`
|
|
DefaultWinningLimit int64 `json:"default_winning_limit"`
|
|
ReferralRewardAmount Currency `json:"referral_reward_amount"`
|
|
CashbackPercentage float32 `json:"cashback_percentage"`
|
|
DefaultMaxReferrals int64 `json:"default_max_referrals"`
|
|
}
|
|
|
|
type SettingListRes struct {
|
|
SMSProvider SMSProvider `json:"sms_provider"`
|
|
MaxNumberOfOutcomes int64 `json:"max_number_of_outcomes"`
|
|
BetAmountLimit float32 `json:"bet_amount_limit"`
|
|
DailyTicketPerIP int64 `json:"daily_ticket_limit"`
|
|
TotalWinningLimit float32 `json:"total_winning_limit"`
|
|
AmountForBetReferral float32 `json:"amount_for_bet_referral"`
|
|
CashbackAmountCap float32 `json:"cashback_amount_cap"`
|
|
DefaultWinningLimit int64 `json:"default_winning_limit"`
|
|
ReferralRewardAmount float32 `json:"referral_reward_amount"`
|
|
CashbackPercentage float32 `json:"cashback_percentage"`
|
|
DefaultMaxReferrals int64 `json:"default_max_referrals"`
|
|
}
|
|
|
|
func ConvertSettingListRes(settings SettingList) SettingListRes {
|
|
return SettingListRes{
|
|
SMSProvider: settings.SMSProvider,
|
|
MaxNumberOfOutcomes: settings.MaxNumberOfOutcomes,
|
|
BetAmountLimit: settings.BetAmountLimit.Float32(),
|
|
DailyTicketPerIP: settings.DailyTicketPerIP,
|
|
TotalWinningLimit: settings.TotalWinningLimit.Float32(),
|
|
AmountForBetReferral: settings.AmountForBetReferral.Float32(),
|
|
CashbackAmountCap: settings.CashbackAmountCap.Float32(),
|
|
DefaultWinningLimit: settings.DefaultWinningLimit,
|
|
ReferralRewardAmount: settings.ReferralRewardAmount.Float32(),
|
|
CashbackPercentage: settings.CashbackPercentage,
|
|
DefaultMaxReferrals: settings.DefaultMaxReferrals,
|
|
}
|
|
}
|
|
|
|
type SaveSettingListReq struct {
|
|
SMSProvider *string `json:"sms_provider,omitempty"`
|
|
MaxNumberOfOutcomes *int64 `json:"max_number_of_outcomes,omitempty"`
|
|
BetAmountLimit *float32 `json:"bet_amount_limit,omitempty"`
|
|
DailyTicketPerIP *int64 `json:"daily_ticket_limit,omitempty"`
|
|
TotalWinningLimit *float32 `json:"total_winning_limit,omitempty"`
|
|
AmountForBetReferral *float32 `json:"amount_for_bet_referral,omitempty"`
|
|
CashbackAmountCap *float32 `json:"cashback_amount_cap,omitempty"`
|
|
DefaultWinningLimit *int64 `json:"default_winning_limit,omitempty"`
|
|
ReferralRewardAmount *float32 `json:"referral_reward_amount"`
|
|
CashbackPercentage *float32 `json:"cashback_percentage"`
|
|
DefaultMaxReferrals *int64 `json:"default_max_referrals"`
|
|
}
|
|
|
|
type ValidSettingList struct {
|
|
SMSProvider ValidString
|
|
MaxNumberOfOutcomes ValidInt64
|
|
BetAmountLimit ValidCurrency
|
|
DailyTicketPerIP ValidInt64
|
|
TotalWinningLimit ValidCurrency
|
|
AmountForBetReferral ValidCurrency
|
|
CashbackAmountCap ValidCurrency
|
|
DefaultWinningLimit ValidInt64
|
|
ReferralRewardAmount ValidCurrency
|
|
CashbackPercentage ValidFloat32
|
|
DefaultMaxReferrals ValidInt64
|
|
}
|
|
|
|
func ConvertSaveSettingListReq(settings SaveSettingListReq) ValidSettingList {
|
|
return ValidSettingList{
|
|
SMSProvider: ConvertStringPtr(settings.SMSProvider),
|
|
MaxNumberOfOutcomes: ConvertInt64Ptr(settings.MaxNumberOfOutcomes),
|
|
BetAmountLimit: ConvertFloat32PtrToCurrency(settings.BetAmountLimit),
|
|
DailyTicketPerIP: ConvertInt64Ptr(settings.DailyTicketPerIP),
|
|
TotalWinningLimit: ConvertFloat32PtrToCurrency(settings.TotalWinningLimit),
|
|
AmountForBetReferral: ConvertFloat32PtrToCurrency(settings.AmountForBetReferral),
|
|
CashbackAmountCap: ConvertFloat32PtrToCurrency(settings.CashbackAmountCap),
|
|
DefaultWinningLimit: ConvertInt64Ptr(settings.DefaultWinningLimit),
|
|
ReferralRewardAmount: ConvertFloat32PtrToCurrency(settings.ReferralRewardAmount),
|
|
CashbackPercentage: ConvertFloat32Ptr(settings.CashbackPercentage),
|
|
DefaultMaxReferrals: ConvertInt64Ptr(settings.DefaultMaxReferrals),
|
|
}
|
|
}
|
|
|
|
// Always make sure to run the validation before converting this
|
|
func (vsl *ValidSettingList) ToSettingList() SettingList {
|
|
return SettingList{
|
|
SMSProvider: SMSProvider(vsl.SMSProvider.Value),
|
|
MaxNumberOfOutcomes: vsl.MaxNumberOfOutcomes.Value,
|
|
BetAmountLimit: vsl.BetAmountLimit.Value,
|
|
DailyTicketPerIP: vsl.DailyTicketPerIP.Value,
|
|
TotalWinningLimit: vsl.TotalWinningLimit.Value,
|
|
AmountForBetReferral: vsl.AmountForBetReferral.Value,
|
|
CashbackAmountCap: vsl.CashbackAmountCap.Value,
|
|
DefaultWinningLimit: vsl.DefaultWinningLimit.Value,
|
|
ReferralRewardAmount: vsl.ReferralRewardAmount.Value,
|
|
CashbackPercentage: vsl.CashbackPercentage.Value,
|
|
DefaultMaxReferrals: vsl.DefaultMaxReferrals.Value,
|
|
}
|
|
}
|
|
|
|
// Custom Validations for non-generic types
|
|
func (vsl *ValidSettingList) CustomValidationSettings() error {
|
|
if !SMSProvider(vsl.SMSProvider.Value).IsValid() {
|
|
return fmt.Errorf("sms provider invalid")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetInt64SettingsMap() map[string]*ValidInt64 {
|
|
return map[string]*ValidInt64{
|
|
"max_number_of_outcomes": &vsl.MaxNumberOfOutcomes,
|
|
"daily_ticket_limit": &vsl.DailyTicketPerIP,
|
|
"default_winning_limit": &vsl.DefaultWinningLimit,
|
|
"default_max_referrals": &vsl.DefaultMaxReferrals,
|
|
}
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetCurrencySettingsMap() map[string]*ValidCurrency {
|
|
return map[string]*ValidCurrency{
|
|
"bet_amount_limit": &vsl.BetAmountLimit,
|
|
"total_winnings_limit": &vsl.TotalWinningLimit,
|
|
"amount_for_bet_referral": &vsl.AmountForBetReferral,
|
|
"cashback_amount_cap": &vsl.CashbackAmountCap,
|
|
"referral_reward_amount": &vsl.ReferralRewardAmount,
|
|
}
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetStringSettingsMap() map[string]*ValidString {
|
|
return map[string]*ValidString{
|
|
"sms_provider": &vsl.SMSProvider,
|
|
}
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetBoolSettingsMap() map[string]*ValidBool {
|
|
return map[string]*ValidBool{}
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetFloat32SettingsMap() map[string]*ValidFloat32 {
|
|
return map[string]*ValidFloat32{
|
|
"cashback_percentage": &vsl.CashbackPercentage,
|
|
}
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetTimeSettingsMap() map[string]*ValidTime {
|
|
return map[string]*ValidTime{}
|
|
}
|
|
|
|
|
|
// Setting Functions
|
|
|
|
func (vsl *ValidSettingList) GetTotalSettings() int {
|
|
return len(vsl.GetInt64SettingsMap()) +
|
|
len(vsl.GetCurrencySettingsMap()) +
|
|
len(vsl.GetStringSettingsMap()) +
|
|
len(vsl.GetBoolSettingsMap()) +
|
|
len(vsl.GetFloat32SettingsMap()) +
|
|
len(vsl.GetTimeSettingsMap())
|
|
}
|
|
|
|
func (vsl *ValidSettingList) GetAllValid() map[string]*bool {
|
|
|
|
settingValid := make(map[string]*bool)
|
|
|
|
for key, setting := range vsl.GetInt64SettingsMap() {
|
|
settingValid[key] = &(*setting).Valid
|
|
}
|
|
for key, setting := range vsl.GetCurrencySettingsMap() {
|
|
settingValid[key] = &(*setting).Valid
|
|
}
|
|
for key, setting := range vsl.GetStringSettingsMap() {
|
|
settingValid[key] = &(*setting).Valid
|
|
}
|
|
for key, setting := range vsl.GetBoolSettingsMap() {
|
|
settingValid[key] = &(*setting).Valid
|
|
}
|
|
for key, setting := range vsl.GetFloat32SettingsMap() {
|
|
settingValid[key] = &(*setting).Valid
|
|
}
|
|
for key, setting := range vsl.GetTimeSettingsMap() {
|
|
settingValid[key] = &(*setting).Valid
|
|
}
|
|
|
|
return settingValid
|
|
}
|
|
|
|
// func setValidSetting[T any](settings map[string]*T, searchKey string, searchVal string, setVal func(string) (T, error)) error {
|
|
// for key, setting := range settings {
|
|
|
|
// if key == searchKey {
|
|
// s, err := setVal(searchVal)
|
|
// if err != nil {
|
|
// return err
|
|
// }
|
|
// *setting = s
|
|
// }
|
|
// return nil
|
|
// }
|
|
// return ErrSettingNotFound
|
|
// }
|
|
func (vsl *ValidSettingList) SetInt64Setting(searchKey string, searchVal string) error {
|
|
for key, setting := range vsl.GetInt64SettingsMap() {
|
|
if key == searchKey {
|
|
value, err := strconv.ParseInt(searchVal, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*setting = ValidInt64{Value: value, Valid: true}
|
|
return nil
|
|
}
|
|
}
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func (vsl *ValidSettingList) SetCurrencySetting(searchKey string, searchVal string) error {
|
|
for key, setting := range vsl.GetCurrencySettingsMap() {
|
|
if key == searchKey {
|
|
value, err := strconv.ParseInt(searchVal, 10, 64)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*setting = ValidCurrency{Value: Currency(value), Valid: true}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func (vsl *ValidSettingList) SetStringSetting(searchKey string, searchVal string) error {
|
|
for key, setting := range vsl.GetStringSettingsMap() {
|
|
if key == searchKey {
|
|
*setting = ValidString{Value: searchVal, Valid: true}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func (vsl *ValidSettingList) SetBoolSetting(searchKey string, searchVal string) error {
|
|
for key, setting := range vsl.GetBoolSettingsMap() {
|
|
|
|
if key == searchKey {
|
|
value, err := strconv.ParseBool(searchVal)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
*setting = ValidBool{Value: value, Valid: true}
|
|
return nil
|
|
}
|
|
|
|
}
|
|
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func (vsl *ValidSettingList) SetFloat32Setting(searchKey string, searchVal string) error {
|
|
for key, setting := range vsl.GetFloat32SettingsMap() {
|
|
if key == searchKey {
|
|
value, err := strconv.ParseFloat(searchVal, 32)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*setting = ValidFloat32{Value: float32(value), Valid: true}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func (vsl *ValidSettingList) SetTimeSetting(searchKey string, searchVal string) error {
|
|
for key, setting := range vsl.GetTimeSettingsMap() {
|
|
if key == searchKey {
|
|
value, err := time.Parse(time.RFC3339, searchVal)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
*setting = ValidTime{Value: value, Valid: true}
|
|
return nil
|
|
}
|
|
}
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func (vsl *ValidSettingList) SetSetting(searchKey string, searchVal string) error {
|
|
setters := []func(string, string) error{
|
|
vsl.SetInt64Setting,
|
|
vsl.SetCurrencySetting,
|
|
vsl.SetStringSetting,
|
|
vsl.SetBoolSetting,
|
|
vsl.SetFloat32Setting,
|
|
vsl.SetTimeSetting,
|
|
}
|
|
|
|
for _, setter := range setters {
|
|
if err := setter(searchKey, searchVal); err != nil {
|
|
if err == ErrSettingNotFound {
|
|
// fmt.Printf("setting is not found %v \n", searchKey)
|
|
continue // not this setter, try the next
|
|
}
|
|
return fmt.Errorf("error while processing setting %q: %w \n", searchKey, err)
|
|
}
|
|
return nil // successfully set
|
|
}
|
|
|
|
// If we get here, none of the setters matched
|
|
return ErrSettingNotFound
|
|
}
|
|
|
|
func convertValidSettings[T any](
|
|
settings map[string]*T,
|
|
isValid func(*T) bool,
|
|
toString func(*T) string,
|
|
) []Setting {
|
|
result := make([]Setting, 0, len(settings))
|
|
for key, s := range settings {
|
|
if isValid(s) {
|
|
result = append(result, Setting{
|
|
Key: key,
|
|
Value: toString(s),
|
|
})
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertInt64Settings() []Setting {
|
|
return convertValidSettings(
|
|
vsl.GetInt64SettingsMap(),
|
|
func(s *ValidInt64) bool { return s.Valid },
|
|
func(s *ValidInt64) string { return strconv.FormatInt(s.Value, 10) },
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertCurrencySettings() []Setting {
|
|
return convertValidSettings(
|
|
vsl.GetCurrencySettingsMap(),
|
|
func(s *ValidCurrency) bool { return s.Valid },
|
|
func(s *ValidCurrency) string { return strconv.FormatInt(int64(s.Value), 10) },
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertStringSettings() []Setting {
|
|
return convertValidSettings(
|
|
vsl.GetStringSettingsMap(),
|
|
func(s *ValidString) bool { return s.Valid },
|
|
func(s *ValidString) string { return s.Value },
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertBoolSettings() []Setting {
|
|
return convertValidSettings(
|
|
vsl.GetBoolSettingsMap(),
|
|
func(s *ValidBool) bool { return s.Valid },
|
|
func(s *ValidBool) string { return strconv.FormatBool(s.Value) },
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertFloat32Settings() []Setting {
|
|
return convertValidSettings(
|
|
vsl.GetFloat32SettingsMap(),
|
|
func(s *ValidFloat32) bool { return s.Valid },
|
|
func(s *ValidFloat32) string { return strconv.FormatFloat(float64(s.Value), 'f', -1, 32) },
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertTimeSettings() []Setting {
|
|
return convertValidSettings(
|
|
vsl.GetTimeSettingsMap(),
|
|
func(s *ValidTime) bool { return s.Valid },
|
|
func(s *ValidTime) string { return s.Value.Format(time.RFC3339) },
|
|
)
|
|
}
|
|
|
|
func validateSettings[T any](
|
|
settings map[string]*T,
|
|
customValidator func(*T) bool,
|
|
) error {
|
|
var errs []string
|
|
for key, s := range settings {
|
|
if !customValidator(s) {
|
|
|
|
errs = append(errs, fmt.Sprintf("%v is invalid", key))
|
|
}
|
|
}
|
|
if len(errs) > 0 {
|
|
return errors.New(strings.Join(errs, "; "))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateInt64Settings() error {
|
|
return validateSettings(vsl.GetInt64SettingsMap(),
|
|
func(s *ValidInt64) bool {
|
|
return s.Valid
|
|
},
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateCurrencySettings() error {
|
|
return validateSettings(vsl.GetCurrencySettingsMap(),
|
|
func(s *ValidCurrency) bool {
|
|
return s.Valid
|
|
},
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateStringSettings() error {
|
|
return validateSettings(vsl.GetStringSettingsMap(),
|
|
func(s *ValidString) bool {
|
|
return s.Valid
|
|
},
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateBoolSettings() error {
|
|
return validateSettings(vsl.GetBoolSettingsMap(),
|
|
func(s *ValidBool) bool {
|
|
return s.Valid
|
|
},
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateFloat32Settings() error {
|
|
return validateSettings(vsl.GetFloat32SettingsMap(),
|
|
func(s *ValidFloat32) bool {
|
|
return s.Valid
|
|
},
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateTimeSettings() error {
|
|
return validateSettings(vsl.GetTimeSettingsMap(),
|
|
func(s *ValidTime) bool {
|
|
return s.Valid
|
|
},
|
|
)
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ValidateAllSettings() error {
|
|
var errs []string
|
|
validators := []func() error{
|
|
vsl.ValidateInt64Settings,
|
|
vsl.ValidateCurrencySettings,
|
|
vsl.ValidateStringSettings,
|
|
vsl.ValidateBoolSettings,
|
|
vsl.ValidateFloat32Settings,
|
|
vsl.ValidateTimeSettings,
|
|
vsl.CustomValidationSettings,
|
|
}
|
|
|
|
for _, validator := range validators {
|
|
if err := validator(); err != nil {
|
|
|
|
errs = append(errs, err.Error())
|
|
}
|
|
}
|
|
if len(errs) > 0 {
|
|
return errors.New(strings.Join(errs, "; "))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (vsl *ValidSettingList) ConvertAllSettings() []Setting {
|
|
totalCap := vsl.GetTotalSettings()
|
|
all := make([]Setting, 0, totalCap)
|
|
|
|
all = append(all, vsl.ConvertInt64Settings()...)
|
|
all = append(all, vsl.ConvertCurrencySettings()...)
|
|
all = append(all, vsl.ConvertStringSettings()...)
|
|
all = append(all, vsl.ConvertBoolSettings()...)
|
|
all = append(all, vsl.ConvertFloat32Settings()...)
|
|
all = append(all, vsl.ConvertTimeSettings()...)
|
|
|
|
return all
|
|
}
|
|
|
|
func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, error) {
|
|
var dbSettingList ValidSettingList
|
|
|
|
for _, setting := range settings {
|
|
if err := dbSettingList.SetSetting(setting.Key, setting.Value); err != nil {
|
|
if err == ErrSettingNotFound {
|
|
MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key))
|
|
}
|
|
MongoDBLogger.Error("unknown error while fetching settings", zap.Error(err))
|
|
}
|
|
}
|
|
|
|
if err := dbSettingList.ValidateAllSettings(); err != nil {
|
|
MongoDBLogger.Warn("setting validation error", zap.Error(err), zap.Any("db_setting_list", dbSettingList))
|
|
return SettingList{}, err
|
|
}
|
|
|
|
settingList := dbSettingList.ToSettingList()
|
|
|
|
return settingList, nil
|
|
}
|
|
|
|
func ConvertDBOverrideSettingList(settings []dbgen.GetOverrideSettingsRow) (SettingList, error) {
|
|
var dbSettingList ValidSettingList
|
|
|
|
for _, setting := range settings {
|
|
if err := dbSettingList.SetSetting(setting.Key, setting.Value); err != nil {
|
|
if err == ErrSettingNotFound {
|
|
MongoDBLogger.Warn("unknown setting found on database", zap.String("setting", setting.Key))
|
|
}
|
|
}
|
|
}
|
|
|
|
if err := dbSettingList.ValidateAllSettings(); err != nil {
|
|
MongoDBLogger.Warn("setting validation error", zap.Error(err))
|
|
return SettingList{}, err
|
|
}
|
|
|
|
settingList := dbSettingList.ToSettingList()
|
|
|
|
return settingList, nil
|
|
}
|