feat: finished the setting service
This commit is contained in:
parent
050fe16f54
commit
9ec7d0cfc1
|
|
@ -43,6 +43,7 @@ import (
|
|||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||
|
|
@ -98,6 +99,7 @@ func main() {
|
|||
v := customvalidator.NewCustomValidator(validator.New())
|
||||
|
||||
// Initialize services
|
||||
settingSvc := settings.NewService(store)
|
||||
authSvc := authentication.NewService(store, store, cfg.RefreshExpiry)
|
||||
userSvc := user.NewService(store, store, cfg)
|
||||
eventSvc := event.New(cfg.Bet365Token, store)
|
||||
|
|
@ -119,7 +121,7 @@ func main() {
|
|||
branchSvc := branch.NewService(store)
|
||||
companySvc := company.NewService(store)
|
||||
leagueSvc := league.New(store)
|
||||
ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger)
|
||||
ticketSvc := ticket.NewService(store, eventSvc, *oddsSvc, domain.MongoDBLogger, *settingSvc)
|
||||
betSvc := bet.NewService(store, eventSvc, *oddsSvc, *walletSvc, *branchSvc, logger, domain.MongoDBLogger)
|
||||
resultSvc := result.NewService(store, cfg, logger, *betSvc, *oddsSvc, eventSvc, leagueSvc, notificationSvc)
|
||||
referalRepo := repository.NewReferralRepository(store)
|
||||
|
|
@ -202,6 +204,7 @@ func main() {
|
|||
currSvc,
|
||||
cfg.Port,
|
||||
v,
|
||||
settingSvc,
|
||||
authSvc,
|
||||
logger,
|
||||
jwtutil.JwtConfig{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,17 @@
|
|||
-- Settings Initial Data
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('max_number_of_outcomes', '30') ON CONFLICT (key) DO
|
||||
UPDATE
|
||||
SET value = EXCLUDED.value;
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('bet_amount_limit', '100000') ON CONFLICT (key) DO
|
||||
UPDATE
|
||||
SET value = EXCLUDED.value;
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('daily_ticket_limit', '50') ON CONFLICT (key) DO
|
||||
UPDATE
|
||||
SET value = EXCLUDED.value;
|
||||
INSERT INTO settings (key, value)
|
||||
VALUES ('total_winnings_limit', '1000000') ON CONFLICT (key) DO
|
||||
UPDATE
|
||||
SET value = EXCLUDED.value;
|
||||
|
|
@ -1,6 +1,10 @@
|
|||
-- name: GetSettings :many
|
||||
SELECT *
|
||||
from settings;
|
||||
FROM settings;
|
||||
-- name: GetSetting :one
|
||||
SELECT *
|
||||
FROM settings
|
||||
WHERE key = $1;
|
||||
-- name: SaveSetting :one
|
||||
INSERT INTO settings (key, value, updated_at)
|
||||
VALUES ($1, $2, CURRENT_TIMESTAMP) ON CONFLICT (key) DO
|
||||
|
|
|
|||
|
|
@ -9,9 +9,27 @@ import (
|
|||
"context"
|
||||
)
|
||||
|
||||
const GetSetting = `-- name: GetSetting :one
|
||||
SELECT key, value, created_at, updated_at
|
||||
FROM settings
|
||||
WHERE key = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetSetting(ctx context.Context, key string) (Setting, error) {
|
||||
row := q.db.QueryRow(ctx, GetSetting, key)
|
||||
var i Setting
|
||||
err := row.Scan(
|
||||
&i.Key,
|
||||
&i.Value,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const GetSettings = `-- name: GetSettings :many
|
||||
SELECT key, value, created_at, updated_at
|
||||
from settings
|
||||
FROM settings
|
||||
`
|
||||
|
||||
func (q *Queries) GetSettings(ctx context.Context) ([]Setting, error) {
|
||||
|
|
|
|||
|
|
@ -13,3 +13,10 @@ type SettingRes struct {
|
|||
Value string `json:"value"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
}
|
||||
|
||||
type SettingList struct {
|
||||
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"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,68 @@ package repository
|
|||
|
||||
import (
|
||||
"context"
|
||||
"strconv"
|
||||
|
||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
type DBSettingList struct {
|
||||
MaxNumberOfOutcomes domain.ValidInt64
|
||||
BetAmountLimit domain.ValidInt64
|
||||
DailyTicketPerIP domain.ValidInt64
|
||||
TotalWinningLimit domain.ValidInt64
|
||||
}
|
||||
|
||||
func GetDBSettingList(settings []dbgen.Setting) (domain.SettingList, error) {
|
||||
var dbSettingList DBSettingList
|
||||
var int64SettingsMap = map[string]*domain.ValidInt64{
|
||||
"max_number_of_outcomes": &dbSettingList.MaxNumberOfOutcomes,
|
||||
"bet_amount_limit": &dbSettingList.BetAmountLimit,
|
||||
"daily_ticket_limit": &dbSettingList.DailyTicketPerIP,
|
||||
"total_winnings_limit": &dbSettingList.DailyTicketPerIP,
|
||||
}
|
||||
|
||||
for _, setting := range settings {
|
||||
for key, dbSetting := range int64SettingsMap {
|
||||
if setting.Key == key {
|
||||
value, err := strconv.ParseInt(setting.Value, 10, 64)
|
||||
if err != nil {
|
||||
return domain.SettingList{}, err
|
||||
}
|
||||
*dbSetting = domain.ValidInt64{
|
||||
Value: value,
|
||||
Valid: true,
|
||||
}
|
||||
} else {
|
||||
domain.MongoDBLogger.Error("unknown setting found on database", zap.String("setting", setting.Key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for key, dbSetting := range int64SettingsMap {
|
||||
if !dbSetting.Valid {
|
||||
domain.MongoDBLogger.Warn("setting value not found on database", zap.String("setting", key))
|
||||
}
|
||||
}
|
||||
|
||||
return domain.SettingList{
|
||||
MaxNumberOfOutcomes: dbSettingList.MaxNumberOfOutcomes.Value,
|
||||
BetAmountLimit: domain.Currency(dbSettingList.BetAmountLimit.Value),
|
||||
DailyTicketPerIP: dbSettingList.DailyTicketPerIP.Value,
|
||||
TotalWinningLimit: domain.Currency(dbSettingList.TotalWinningLimit.Value),
|
||||
}, nil
|
||||
}
|
||||
func (s *Store) GetSettingList(ctx context.Context) (domain.SettingList, error) {
|
||||
settings, err := s.queries.GetSettings(ctx)
|
||||
if err != nil {
|
||||
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
|
||||
}
|
||||
|
||||
return GetDBSettingList(settings)
|
||||
}
|
||||
|
||||
func (s *Store) GetSettings(ctx context.Context) ([]domain.Setting, error) {
|
||||
settings, err := s.queries.GetSettings(ctx)
|
||||
|
||||
|
|
@ -27,9 +83,25 @@ func (s *Store) GetSettings(ctx context.Context) ([]domain.Setting, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetSetting(ctx context.Context, key string) (domain.Setting, error) {
|
||||
dbSetting, err := s.queries.GetSetting(ctx, key)
|
||||
|
||||
if err != nil {
|
||||
domain.MongoDBLogger.Error("failed to get all settings", zap.Error(err))
|
||||
}
|
||||
|
||||
result := domain.Setting{
|
||||
Key: dbSetting.Key,
|
||||
Value: dbSetting.Value,
|
||||
UpdatedAt: dbSetting.UpdatedAt.Time,
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (s *Store) SaveSetting(ctx context.Context, key, value string) (domain.Setting, error) {
|
||||
dbSetting, err := s.queries.SaveSetting(ctx, dbgen.SaveSettingParams{
|
||||
Key: key,
|
||||
Key: key,
|
||||
Value: value,
|
||||
})
|
||||
|
||||
|
|
@ -40,7 +112,7 @@ func (s *Store) SaveSetting(ctx context.Context, key, value string) (domain.Sett
|
|||
}
|
||||
|
||||
setting := domain.Setting{
|
||||
Key: dbSetting.Key,
|
||||
Key: dbSetting.Key,
|
||||
Value: dbSetting.Value,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import (
|
|||
)
|
||||
|
||||
type SettingStore interface {
|
||||
GetSettingList(ctx context.Context) (domain.SettingList, error)
|
||||
GetSettings(ctx context.Context) ([]domain.Setting, error)
|
||||
GetSetting(ctx context.Context, key string) (domain.Setting, error)
|
||||
SaveSetting(ctx context.Context, key, value string) (domain.Setting, error)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,10 +16,17 @@ func NewService(settingStore SettingStore) *Service {
|
|||
}
|
||||
}
|
||||
|
||||
func (s *Service) GetSettingList(ctx context.Context) (domain.SettingList, error) {
|
||||
return s.settingStore.GetSettingList(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) GetSettings(ctx context.Context) ([]domain.Setting, error) {
|
||||
return s.settingStore.GetSettings(ctx)
|
||||
}
|
||||
|
||||
func (s *Service) GetSetting(ctx context.Context, key string) (domain.Setting, error) {
|
||||
return s.settingStore.GetSetting(ctx, key)
|
||||
}
|
||||
func (s *Service) SaveSetting(ctx context.Context, key, value string) (domain.Setting, error) {
|
||||
return s.settingStore.SaveSetting(ctx, key, value)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,13 +10,14 @@ import (
|
|||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrGenerateRandomOutcome = errors.New("Failed to generate any random outcome for events")
|
||||
// ErrOutcomesNotCompleted = errors.New("Some bet outcomes are still pending")
|
||||
ErrEventHasNotEnded = errors.New("Event has not ended yet")
|
||||
ErrTicketHasExpired = errors.New("Ticket has expired")
|
||||
ErrNoEventsAvailable = errors.New("Not enough events available with the given filters")
|
||||
ErrEventHasBeenRemoved = errors.New("Event has been removed")
|
||||
ErrTooManyOutcomesForTicket = errors.New("Too many odds/outcomes for a single ticket")
|
||||
|
|
@ -32,6 +33,7 @@ type Service struct {
|
|||
eventSvc event.Service
|
||||
prematchSvc odds.ServiceImpl
|
||||
mongoLogger *zap.Logger
|
||||
settingSvc settings.Service
|
||||
}
|
||||
|
||||
func NewService(
|
||||
|
|
@ -39,16 +41,18 @@ func NewService(
|
|||
eventSvc event.Service,
|
||||
prematchSvc odds.ServiceImpl,
|
||||
mongoLogger *zap.Logger,
|
||||
settingSvc settings.Service,
|
||||
) *Service {
|
||||
return &Service{
|
||||
ticketStore: ticketStore,
|
||||
eventSvc: eventSvc,
|
||||
prematchSvc: prematchSvc,
|
||||
mongoLogger: mongoLogger,
|
||||
settingSvc: settingSvc,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Service) GenerateTicketOutcome(ctx context.Context, eventID int64, marketID int64, oddID int64) (domain.CreateTicketOutcome, error) {
|
||||
func (s *Service) GenerateTicketOutcome(ctx context.Context, settings domain.SettingList, eventID int64, marketID int64, oddID int64) (domain.CreateTicketOutcome, error) {
|
||||
eventIDStr := strconv.FormatInt(eventID, 10)
|
||||
marketIDStr := strconv.FormatInt(marketID, 10)
|
||||
oddIDStr := strconv.FormatInt(oddID, 10)
|
||||
|
|
@ -69,7 +73,7 @@ func (s *Service) GenerateTicketOutcome(ctx context.Context, eventID int64, mark
|
|||
zap.Time("event_start_time", event.StartTime),
|
||||
zap.Time("current_time", currentTime),
|
||||
)
|
||||
return domain.CreateTicketOutcome{}, ErrEventHasNotEnded
|
||||
return domain.CreateTicketOutcome{}, ErrTicketHasExpired
|
||||
}
|
||||
|
||||
odds, err := s.prematchSvc.GetRawOddsByMarketID(ctx, marketIDStr, eventIDStr)
|
||||
|
|
@ -151,17 +155,18 @@ func (s *Service) GenerateTicketOutcome(ctx context.Context, eventID int64, mark
|
|||
}
|
||||
|
||||
func (s *Service) CreateTicket(ctx context.Context, req domain.CreateTicketReq, clientIP string) (domain.Ticket, int64, error) {
|
||||
settingsList, err := s.settingSvc.GetSettingList(ctx)
|
||||
|
||||
// s.mongoLogger.Info("Creating ticket")
|
||||
// TODO Validate Outcomes Here and make sure they didn't expire
|
||||
// Validation for creating tickets
|
||||
if len(req.Outcomes) > 30 {
|
||||
if len(req.Outcomes) > int(settingsList.MaxNumberOfOutcomes) {
|
||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "Too many odds/outcomes selected", nil, nil)
|
||||
return domain.Ticket{}, 0, ErrTooManyOutcomesForTicket
|
||||
|
||||
}
|
||||
|
||||
if req.Amount > 100000 {
|
||||
if req.Amount > settingsList.BetAmountLimit.Float32() {
|
||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "Cannot create a ticket with an amount above 100,000 birr", nil, nil)
|
||||
return domain.Ticket{}, 0, ErrTicketAmountTooHigh
|
||||
}
|
||||
|
|
@ -170,17 +175,20 @@ func (s *Service) CreateTicket(ctx context.Context, req domain.CreateTicketReq,
|
|||
|
||||
if err != nil {
|
||||
// return response.WriteJSON(c, fiber.StatusInternalServerError, "Error fetching user info", nil, nil)
|
||||
s.mongoLogger.Error("failed to count number of ticket using ip",
|
||||
zap.Error(err),
|
||||
)
|
||||
return domain.Ticket{}, 0, err
|
||||
}
|
||||
|
||||
if count > 50 {
|
||||
if count > settingsList.DailyTicketPerIP {
|
||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "Ticket Limit reached", nil, nil)
|
||||
return domain.Ticket{}, 0, ErrTicketLimitForSingleUser
|
||||
}
|
||||
}
|
||||
var outcomes []domain.CreateTicketOutcome = make([]domain.CreateTicketOutcome, 0, len(req.Outcomes))
|
||||
var totalOdds float32 = 1
|
||||
for _, outcomeReq := range req.Outcomes {
|
||||
newOutcome, err := s.GenerateTicketOutcome(ctx, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID)
|
||||
newOutcome, err := s.GenerateTicketOutcome(ctx, settingsList, outcomeReq.EventID, outcomeReq.MarketID, outcomeReq.OddID)
|
||||
if err != nil {
|
||||
s.mongoLogger.Error("failed to generate outcome",
|
||||
zap.Int64("event_id", outcomeReq.EventID),
|
||||
|
|
@ -194,7 +202,7 @@ func (s *Service) CreateTicket(ctx context.Context, req domain.CreateTicketReq,
|
|||
outcomes = append(outcomes, newOutcome)
|
||||
}
|
||||
totalWinnings := req.Amount * totalOdds
|
||||
if totalWinnings > 1000000 {
|
||||
if totalWinnings > settingsList.TotalWinningLimit.Float32() {
|
||||
s.mongoLogger.Error("Total Winnings over limit", zap.Float32("Total Odds", totalOdds), zap.Float32("amount", req.Amount))
|
||||
// return response.WriteJSON(c, fiber.StatusBadRequest, "Cannot create a ticket with 1,000,000 winnings", nil, nil)
|
||||
return domain.Ticket{}, 0, ErrTicketWinningTooHigh
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||
|
|
@ -45,6 +46,7 @@ type App struct {
|
|||
NotidicationStore *notificationservice.Service
|
||||
referralSvc referralservice.ReferralStore
|
||||
port int
|
||||
settingSvc *settings.Service
|
||||
authSvc *authentication.Service
|
||||
userSvc *user.Service
|
||||
betSvc *bet.Service
|
||||
|
|
@ -68,6 +70,7 @@ type App struct {
|
|||
func NewApp(
|
||||
currSvc *currency.Service,
|
||||
port int, validator *customvalidator.CustomValidator,
|
||||
settingSvc *settings.Service,
|
||||
authSvc *authentication.Service,
|
||||
logger *slog.Logger,
|
||||
JwtConfig jwtutil.JwtConfig,
|
||||
|
|
@ -107,9 +110,11 @@ func NewApp(
|
|||
}))
|
||||
|
||||
s := &App{
|
||||
currSvc: currSvc,
|
||||
fiber: app,
|
||||
port: port,
|
||||
currSvc: currSvc,
|
||||
fiber: app,
|
||||
port: port,
|
||||
|
||||
settingSvc: settingSvc,
|
||||
authSvc: authSvc,
|
||||
validator: validator,
|
||||
logger: logger,
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import (
|
|||
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/result"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/ticket"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/transaction"
|
||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
|
||||
|
|
@ -31,6 +32,7 @@ import (
|
|||
type Handler struct {
|
||||
currSvc *currency.Service
|
||||
logger *slog.Logger
|
||||
settingSvc *settings.Service
|
||||
notificationSvc *notificationservice.Service
|
||||
userSvc *user.Service
|
||||
referralSvc referralservice.ReferralStore
|
||||
|
|
@ -59,6 +61,7 @@ type Handler struct {
|
|||
func New(
|
||||
currSvc *currency.Service,
|
||||
logger *slog.Logger,
|
||||
settingSvc *settings.Service,
|
||||
notificationSvc *notificationservice.Service,
|
||||
validator *customvalidator.CustomValidator,
|
||||
reportSvc report.ReportStore,
|
||||
|
|
@ -86,6 +89,7 @@ func New(
|
|||
return &Handler{
|
||||
currSvc: currSvc,
|
||||
logger: logger,
|
||||
settingSvc: settingSvc,
|
||||
notificationSvc: notificationSvc,
|
||||
reportSvc: reportSvc,
|
||||
chapaSvc: chapaSvc,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,10 @@ func (h *Handler) CreateTicket(c *fiber.Ctx) error {
|
|||
|
||||
if err != nil {
|
||||
switch err {
|
||||
case ticket.ErrEventHasBeenRemoved, ticket.ErrEventHasNotEnded, ticket.ErrRawOddInvalid:
|
||||
case ticket.ErrEventHasBeenRemoved, ticket.ErrTicketHasExpired,
|
||||
ticket.ErrRawOddInvalid, ticket.ErrTooManyOutcomesForTicket,
|
||||
ticket.ErrTicketAmountTooHigh, ticket.ErrTicketLimitForSingleUser,
|
||||
ticket.ErrTicketWinningTooHigh:
|
||||
return fiber.NewError(fiber.StatusBadRequest, err.Error())
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ func (a *App) initAppRoutes() {
|
|||
h := handlers.New(
|
||||
a.currSvc,
|
||||
a.logger,
|
||||
a.settingSvc,
|
||||
a.NotidicationStore,
|
||||
a.validator,
|
||||
a.reportSvc,
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user