resolve conflict

This commit is contained in:
Asher Samuel 2025-09-09 15:24:20 +03:00
commit e3a24d6bb1
50 changed files with 771 additions and 39 deletions

View File

@ -45,6 +45,7 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/messenger" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/messenger"
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification" notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
@ -147,6 +148,7 @@ func main() {
recommendationRepo := repository.NewRecommendationRepository(store) recommendationRepo := repository.NewRecommendationRepository(store)
referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger) referalSvc := referralservice.New(referalRepo, *walletSvc, store, cfg, logger)
raffleSvc := raffle.NewService(store)
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger) virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger) aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
veliCLient := veli.NewClient(cfg, walletSvc) veliCLient := veli.NewClient(cfg, walletSvc)
@ -271,6 +273,7 @@ func main() {
eventSvc, eventSvc,
leagueSvc, leagueSvc,
referalSvc, referalSvc,
raffleSvc,
bonusSvc, bonusSvc,
virtualGameSvc, virtualGameSvc,
aleaService, aleaService,

View File

@ -518,6 +518,22 @@ CREATE TABLE IF NOT EXISTS supported_operations (
name VARCHAR(255) NOT NULL, name VARCHAR(255) NOT NULL,
description VARCHAR(255) NOT NULL description VARCHAR(255) NOT NULL
); );
CREATE TABLE IF NOT EXISTS raffles (
id SERIAL PRIMARY KEY,
company_id INT NOT NULL,
name VARCHAR(255) NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT NOW(),
expires_at TIMESTAMP NOT NULL,
type VARCHAR(50) NOT NULL CHECK (type IN ('virtual', 'sport')),
status VARCHAR(50) NOT NULL DEFAULT 'pending' CHECK (status IN ('pending', 'completed'))
);
CREATE TABLE IF NOT EXISTS raffle_tickets (
id SERIAL PRIMARY KEY,
raffle_id INT NOT NULL REFERENCES raffles(id) ON DELETE CASCADE,
user_id INT NOT NULL,
is_active BOOL DEFAULT true,
UNIQUE (raffle_id, user_id)
);
CREATE VIEW bet_with_outcomes AS CREATE VIEW bet_with_outcomes AS
SELECT bets.*, SELECT bets.*,
CONCAT (users.first_name, ' ', users.last_name) AS full_name, CONCAT (users.first_name, ' ', users.last_name) AS full_name,

34
db/query/raffle.sql Normal file
View File

@ -0,0 +1,34 @@
-- name: CreateRaffle :one
INSERT INTO raffles (company_id, name, expires_at, type)
VALUES ($1, $2, $3, $4)
RETURNING *;
-- name: GetRafflesOfCompany :many
SELECT * FROM raffles WHERE company_id = $1;
-- name: DeleteRaffle :one
DELETE FROM raffles
WHERE id = $1
RETURNING *;
-- name: UpdateRaffleTicketStatus :exec
UPDATE raffle_tickets
SET is_active = $1
WHERE id = $2;
-- name: CreateRaffleTicket :one
INSERT INTO raffle_tickets (raffle_id, user_id)
VALUES ($1, $2)
RETURNING *;
-- name: GetUserRaffleTickets :many
SELECT
rt.id AS ticket_id,
rt.user_id,
r.name,
r.type,
r.expires_at,
r.status
FROM raffle_tickets rt
JOIN raffles r ON rt.raffle_id = r.id
WHERE rt.user_id = $1;

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: auth.sql // source: auth.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: bet.sql // source: bet.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: bet_stat.sql // source: bet_stat.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: bonus.sql // source: bonus.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: branch.sql // source: branch.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: cashier.sql // source: cashier.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: company.sql // source: company.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: copyfrom.go // source: copyfrom.go
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: direct_deposit.sql // source: direct_deposit.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: disabled_odds.sql // source: disabled_odds.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: event_history.sql // source: event_history.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: events.sql // source: events.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: events_stat.sql // source: events_stat.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: flags.sql // source: flags.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: institutions.sql // source: institutions.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: issue_reporting.sql // source: issue_reporting.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: leagues.sql // source: leagues.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: location.sql // source: location.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
package dbgen package dbgen
@ -538,6 +538,23 @@ type Otp struct {
ExpiresAt pgtype.Timestamptz `json:"expires_at"` ExpiresAt pgtype.Timestamptz `json:"expires_at"`
} }
type Raffle struct {
ID int32 `json:"id"`
CompanyID int32 `json:"company_id"`
Name string `json:"name"`
CreatedAt pgtype.Timestamp `json:"created_at"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
Type string `json:"type"`
Status string `json:"status"`
}
type RaffleTicket struct {
ID int32 `json:"id"`
RaffleID int32 `json:"raffle_id"`
UserID int32 `json:"user_id"`
IsActive pgtype.Bool `json:"is_active"`
}
type Referral struct { type Referral struct {
ID int64 `json:"id"` ID int64 `json:"id"`
CompanyID int64 `json:"company_id"` CompanyID int64 `json:"company_id"`

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: monitor.sql // source: monitor.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: notification.sql // source: notification.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: odd_history.sql // source: odd_history.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: odds.sql // source: odds.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: otp.sql // source: otp.sql
package dbgen package dbgen

186
gen/db/raffle.sql.go Normal file
View File

@ -0,0 +1,186 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.30.0
// source: raffle.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const CreateRaffle = `-- name: CreateRaffle :one
INSERT INTO raffles (company_id, name, expires_at, type)
VALUES ($1, $2, $3, $4)
RETURNING id, company_id, name, created_at, expires_at, type, status
`
type CreateRaffleParams struct {
CompanyID int32 `json:"company_id"`
Name string `json:"name"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
Type string `json:"type"`
}
func (q *Queries) CreateRaffle(ctx context.Context, arg CreateRaffleParams) (Raffle, error) {
row := q.db.QueryRow(ctx, CreateRaffle,
arg.CompanyID,
arg.Name,
arg.ExpiresAt,
arg.Type,
)
var i Raffle
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Name,
&i.CreatedAt,
&i.ExpiresAt,
&i.Type,
&i.Status,
)
return i, err
}
const CreateRaffleTicket = `-- name: CreateRaffleTicket :one
INSERT INTO raffle_tickets (raffle_id, user_id)
VALUES ($1, $2)
RETURNING id, raffle_id, user_id, is_active
`
type CreateRaffleTicketParams struct {
RaffleID int32 `json:"raffle_id"`
UserID int32 `json:"user_id"`
}
func (q *Queries) CreateRaffleTicket(ctx context.Context, arg CreateRaffleTicketParams) (RaffleTicket, error) {
row := q.db.QueryRow(ctx, CreateRaffleTicket, arg.RaffleID, arg.UserID)
var i RaffleTicket
err := row.Scan(
&i.ID,
&i.RaffleID,
&i.UserID,
&i.IsActive,
)
return i, err
}
const DeleteRaffle = `-- name: DeleteRaffle :one
DELETE FROM raffles
WHERE id = $1
RETURNING id, company_id, name, created_at, expires_at, type, status
`
func (q *Queries) DeleteRaffle(ctx context.Context, id int32) (Raffle, error) {
row := q.db.QueryRow(ctx, DeleteRaffle, id)
var i Raffle
err := row.Scan(
&i.ID,
&i.CompanyID,
&i.Name,
&i.CreatedAt,
&i.ExpiresAt,
&i.Type,
&i.Status,
)
return i, err
}
const GetRafflesOfCompany = `-- name: GetRafflesOfCompany :many
SELECT id, company_id, name, created_at, expires_at, type, status FROM raffles WHERE company_id = $1
`
func (q *Queries) GetRafflesOfCompany(ctx context.Context, companyID int32) ([]Raffle, error) {
rows, err := q.db.Query(ctx, GetRafflesOfCompany, companyID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []Raffle
for rows.Next() {
var i Raffle
if err := rows.Scan(
&i.ID,
&i.CompanyID,
&i.Name,
&i.CreatedAt,
&i.ExpiresAt,
&i.Type,
&i.Status,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetUserRaffleTickets = `-- name: GetUserRaffleTickets :many
SELECT
rt.id AS ticket_id,
rt.user_id,
r.name,
r.type,
r.expires_at,
r.status
FROM raffle_tickets rt
JOIN raffles r ON rt.raffle_id = r.id
WHERE rt.user_id = $1
`
type GetUserRaffleTicketsRow struct {
TicketID int32 `json:"ticket_id"`
UserID int32 `json:"user_id"`
Name string `json:"name"`
Type string `json:"type"`
ExpiresAt pgtype.Timestamp `json:"expires_at"`
Status string `json:"status"`
}
func (q *Queries) GetUserRaffleTickets(ctx context.Context, userID int32) ([]GetUserRaffleTicketsRow, error) {
rows, err := q.db.Query(ctx, GetUserRaffleTickets, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []GetUserRaffleTicketsRow
for rows.Next() {
var i GetUserRaffleTicketsRow
if err := rows.Scan(
&i.TicketID,
&i.UserID,
&i.Name,
&i.Type,
&i.ExpiresAt,
&i.Status,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const UpdateRaffleTicketStatus = `-- name: UpdateRaffleTicketStatus :exec
UPDATE raffle_tickets
SET is_active = $1
WHERE id = $2
`
type UpdateRaffleTicketStatusParams struct {
IsActive pgtype.Bool `json:"is_active"`
ID int32 `json:"id"`
}
func (q *Queries) UpdateRaffleTicketStatus(ctx context.Context, arg UpdateRaffleTicketStatusParams) error {
_, err := q.db.Exec(ctx, UpdateRaffleTicketStatus, arg.IsActive, arg.ID)
return err
}

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: referal.sql // source: referal.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: report.sql // source: report.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: result.sql // source: result.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: result_log.sql // source: result_log.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: settings.sql // source: settings.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: shop_transactions.sql // source: shop_transactions.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: ticket.sql // source: ticket.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: transfer.sql // source: transfer.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: user.sql // source: user.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: virtual_games.sql // source: virtual_games.sql
package dbgen package dbgen

View File

@ -1,6 +1,6 @@
// Code generated by sqlc. DO NOT EDIT. // Code generated by sqlc. DO NOT EDIT.
// versions: // versions:
// sqlc v1.29.0 // sqlc v1.30.0
// source: wallet.sql // source: wallet.sql
package dbgen package dbgen

48
internal/domain/raffle.go Normal file
View File

@ -0,0 +1,48 @@
package domain
import "time"
type Raffle struct {
ID int32
CompanyID int32
Name string
CreatedAt time.Time
ExpiresAt time.Time
Type string
Status string
}
type RaffleTicket struct {
ID int32
RaffleID int32
UserID int32
IsActive bool
}
type RaffleTicketRes struct {
TicketID int32
UserID int32
Name string
Type string
ExpiresAt time.Time
Status string
}
type CreateRaffle struct {
CompanyID int32 `json:"company_id" validate:"required"`
Name string `json:"name" validate:"required"`
ExpiresAt *time.Time `json:"expires_at" validate:"required"`
Type string `json:"type" validate:"required"`
}
type CreateRaffleTicket struct {
RaffleID int32 `json:"raffle_id" validate:"required"`
UserID int32 `json:"user_id" validate:"required"`
}
// aside from ID, atleast one of the fields should be required
type UpdateRaffleParams struct {
ID int32 `json:"id" validate:"required"`
Name string `json:"name" validate:"required_without_all=ExpiresAt"`
ExpiresAt *time.Time `json:"expires_at" validate:"required_without_all=Name"`
}

View File

@ -0,0 +1,128 @@
package repository
import (
"context"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5/pgtype"
)
func convertRaffleOutcome(raffle dbgen.Raffle) domain.Raffle {
return domain.Raffle{
ID: raffle.ID,
CompanyID: raffle.CompanyID,
Name: raffle.Name,
CreatedAt: raffle.CreatedAt.Time,
ExpiresAt: raffle.ExpiresAt.Time,
Type: raffle.Type,
Status: raffle.Status,
}
}
func convertRaffleTicketOutcome(raffle dbgen.RaffleTicket) domain.RaffleTicket {
return domain.RaffleTicket{
ID: raffle.ID,
RaffleID: raffle.RaffleID,
UserID: raffle.UserID,
IsActive: raffle.IsActive.Bool,
}
}
func convertJoinedRaffleTicketOutcome(raffle dbgen.GetUserRaffleTicketsRow) domain.RaffleTicketRes {
return domain.RaffleTicketRes{
TicketID: raffle.TicketID,
UserID: raffle.UserID,
Name: raffle.Name,
Type: raffle.Type,
ExpiresAt: raffle.ExpiresAt.Time,
Status: raffle.Status,
}
}
func convertCreateRaffle(raffle domain.CreateRaffle) dbgen.CreateRaffleParams {
return dbgen.CreateRaffleParams{
CompanyID: raffle.CompanyID,
Name: raffle.Name,
ExpiresAt: pgtype.Timestamp{
Time: *raffle.ExpiresAt,
Valid: true,
},
Type: raffle.Type,
}
}
func (s *Store) CreateRaffle(ctx context.Context, raffle domain.CreateRaffle) (domain.Raffle, error) {
raffleRes, err := s.queries.CreateRaffle(ctx, convertCreateRaffle(raffle))
if err != nil {
return domain.Raffle{}, err
}
return convertRaffleOutcome(raffleRes), nil
}
func (s *Store) DeleteRaffle(ctx context.Context, raffleID int32) (domain.Raffle, error) {
raffleRes, err := s.queries.DeleteRaffle(ctx, raffleID)
if err != nil {
return domain.Raffle{}, err
}
return convertRaffleOutcome(raffleRes), nil
}
func (s *Store) GetRafflesOfCompany(ctx context.Context, companyID int32) ([]dbgen.Raffle, error) {
raffles, err := s.queries.GetRafflesOfCompany(ctx, companyID)
if err != nil {
return nil, err
}
return raffles, nil
}
func (s *Store) CreateRaffleTicket(ctx context.Context, raffleTicketParams domain.CreateRaffleTicket) (domain.RaffleTicket, error) {
raffleTicket, err := s.queries.CreateRaffleTicket(ctx, dbgen.CreateRaffleTicketParams{
RaffleID: raffleTicketParams.RaffleID,
UserID: raffleTicketParams.UserID,
})
if err != nil {
return domain.RaffleTicket{}, err
}
return convertRaffleTicketOutcome(raffleTicket), nil
}
func (s *Store) GetUserRaffleTickets(ctx context.Context, userID int32) ([]domain.RaffleTicketRes, error) {
raffleTickets, err := s.queries.GetUserRaffleTickets(ctx, userID)
if err != nil {
return nil, err
}
res := []domain.RaffleTicketRes{}
for _, raffle := range raffleTickets {
res = append(res, convertJoinedRaffleTicketOutcome(raffle))
}
return res, nil
}
func (s *Store) SuspendRaffleTicket(ctx context.Context, raffleTicketID int32) error {
return s.queries.UpdateRaffleTicketStatus(ctx, dbgen.UpdateRaffleTicketStatusParams{
ID: raffleTicketID,
IsActive: pgtype.Bool{
Bool: false,
Valid: true,
},
})
}
func (s *Store) UnSuspendRaffleTicket(ctx context.Context, raffleID int32) error {
return s.queries.UpdateRaffleTicketStatus(ctx, dbgen.UpdateRaffleTicketStatusParams{
ID: raffleID,
IsActive: pgtype.Bool{
Bool: true,
Valid: true,
},
})
}
// TODO: could also add -> suspend a specific user's raffle tickets

View File

@ -165,9 +165,9 @@ func (s *Store) GetOverrideSettingsList(ctx context.Context, companyID int64) (d
func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error { func (s *Store) DeleteCompanySetting(ctx context.Context, companyID int64, key string) error {
return s.queries.DeleteCompanySetting(ctx, dbgen.DeleteCompanySettingParams{ return s.queries.DeleteCompanySetting(ctx, dbgen.DeleteCompanySettingParams{
CompanyID: companyID, CompanyID: companyID,
Key: key, Key: key,
}) })
} }
func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64,) error { func (s *Store) DeleteAllCompanySetting(ctx context.Context, companyID int64) error {
return s.queries.DeleteAllCompanySetting(ctx, companyID) return s.queries.DeleteAllCompanySetting(ctx, companyID)
} }

View File

@ -0,0 +1,18 @@
package raffle
import (
"context"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
type RaffleStore interface {
CreateRaffle(ctx context.Context, raffle domain.CreateRaffle) (domain.Raffle, error)
DeleteRaffle(ctx context.Context, raffleID int32) (domain.Raffle, error)
GetRafflesOfCompany(ctx context.Context, companyID int32) ([]dbgen.Raffle, error)
CreateRaffleTicket(ctx context.Context, raffleTicketParams domain.CreateRaffleTicket) (domain.RaffleTicket, error)
GetUserRaffleTickets(ctx context.Context, userID int32) ([]domain.RaffleTicketRes, error)
SuspendRaffleTicket(ctx context.Context, raffleTicketID int32) error
UnSuspendRaffleTicket(ctx context.Context, raffleID int32) error
}

View File

@ -0,0 +1,46 @@
package raffle
import (
"context"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
)
type Service struct {
raffleStore RaffleStore
}
func NewService(raffleStore RaffleStore) *Service {
return &Service{
raffleStore: raffleStore,
}
}
func (s *Service) CreateRaffle(ctx context.Context, raffle domain.CreateRaffle) (domain.Raffle, error) {
return s.raffleStore.CreateRaffle(ctx, raffle)
}
func (s *Service) DeleteRaffle(ctx context.Context, raffleID int32) (domain.Raffle, error) {
return s.raffleStore.DeleteRaffle(ctx, raffleID)
}
func (s *Service) GetRafflesOfCompany(ctx context.Context, companyID int32) ([]dbgen.Raffle, error) {
return s.raffleStore.GetRafflesOfCompany(ctx, companyID)
}
func (s *Service) CreateRaffleTicket(ctx context.Context, raffleTicketParams domain.CreateRaffleTicket) (domain.RaffleTicket, error) {
return s.raffleStore.CreateRaffleTicket(ctx, raffleTicketParams)
}
func (s *Service) GetUserRaffleTickets(ctx context.Context, userID int32) ([]domain.RaffleTicketRes, error) {
return s.raffleStore.GetUserRaffleTickets(ctx, userID)
}
func (s *Service) SuspendRaffleTicket(ctx context.Context, raffleTicketID int32) error {
return s.raffleStore.SuspendRaffleTicket(ctx, raffleTicketID)
}
func (s *Service) UnSuspendRaffleTicket(ctx context.Context, raffleID int32) error {
return s.raffleStore.UnSuspendRaffleTicket(ctx, raffleID)
}

View File

@ -18,6 +18,7 @@ import (
issuereporting "github.com/SamuelTariku/FortuneBet-Backend/internal/services/issue_reporting" issuereporting "github.com/SamuelTariku/FortuneBet-Backend/internal/services/issue_reporting"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
@ -57,6 +58,7 @@ type App struct {
logger *slog.Logger logger *slog.Logger
NotidicationStore *notificationservice.Service NotidicationStore *notificationservice.Service
referralSvc referralservice.ReferralStore referralSvc referralservice.ReferralStore
raffleSvc raffle.RaffleStore
bonusSvc *bonus.Service bonusSvc *bonus.Service
port int port int
settingSvc *settings.Service settingSvc *settings.Service
@ -108,6 +110,7 @@ func NewApp(
eventSvc event.Service, eventSvc event.Service,
leagueSvc league.Service, leagueSvc league.Service,
referralSvc referralservice.ReferralStore, referralSvc referralservice.ReferralStore,
raffleSvc raffle.RaffleStore,
bonusSvc *bonus.Service, bonusSvc *bonus.Service,
virtualGameSvc virtualgameservice.VirtualGameService, virtualGameSvc virtualgameservice.VirtualGameService,
aleaVirtualGameService alea.AleaVirtualGameService, aleaVirtualGameService alea.AleaVirtualGameService,
@ -158,6 +161,7 @@ func NewApp(
companySvc: companySvc, companySvc: companySvc,
NotidicationStore: notidicationStore, NotidicationStore: notidicationStore,
referralSvc: referralSvc, referralSvc: referralSvc,
raffleSvc: raffleSvc,
bonusSvc: bonusSvc, bonusSvc: bonusSvc,
Logger: logger, Logger: logger,
prematchSvc: prematchSvc, prematchSvc: prematchSvc,

View File

@ -236,6 +236,8 @@ func (h *Handler) CreateBetInternal(c *fiber.Ctx, req domain.CreateBetReq, userI
return domain.CreateBetRes{}, err return domain.CreateBetRes{}, err
} }
// create raffle ticket here
return res, nil return res, nil
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/league" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/league"
notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification" notificationservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/notification"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/odds"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation"
referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report"
@ -49,6 +50,7 @@ type Handler struct {
notificationSvc *notificationservice.Service notificationSvc *notificationservice.Service
userSvc *user.Service userSvc *user.Service
referralSvc referralservice.ReferralStore referralSvc referralservice.ReferralStore
raffleSvc raffle.RaffleStore
bonusSvc *bonus.Service bonusSvc *bonus.Service
reportSvc report.ReportStore reportSvc report.ReportStore
chapaSvc *chapa.Service chapaSvc *chapa.Service
@ -88,6 +90,7 @@ func New(
chapaSvc *chapa.Service, chapaSvc *chapa.Service,
walletSvc *wallet.Service, walletSvc *wallet.Service,
referralSvc referralservice.ReferralStore, referralSvc referralservice.ReferralStore,
raffleSvc raffle.RaffleStore,
bonusSvc *bonus.Service, bonusSvc *bonus.Service,
virtualGameSvc virtualgameservice.VirtualGameService, virtualGameSvc virtualgameservice.VirtualGameService,
aleaVirtualGameSvc alea.AleaVirtualGameService, aleaVirtualGameSvc alea.AleaVirtualGameService,
@ -122,6 +125,7 @@ func New(
chapaSvc: chapaSvc, chapaSvc: chapaSvc,
walletSvc: walletSvc, walletSvc: walletSvc,
referralSvc: referralSvc, referralSvc: referralSvc,
raffleSvc: raffleSvc,
bonusSvc: bonusSvc, bonusSvc: bonusSvc,
validator: validator, validator: validator,
userSvc: userSvc, userSvc: userSvc,

View File

@ -0,0 +1,216 @@
package handlers
import (
"fmt"
"strconv"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
"github.com/gofiber/fiber/v2"
"go.uber.org/zap"
)
func (h *Handler) CreateRaffle(c *fiber.Ctx) error {
var req domain.CreateRaffle
if err := c.BodyParser(&req); err != nil {
h.mongoLoggerSvc.Info("Failed to parse raffle request",
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
}
if valErrs, ok := h.validator.Validate(c, req); !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.mongoLoggerSvc.Info("Failed to validate settings",
zap.String("errMsg", errMsg),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
raffle, err := h.raffleSvc.CreateRaffle(c.Context(), req)
if err != nil {
h.mongoLoggerSvc.Error("Failed to create raffle",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create raffle")
}
return response.WriteJSON(c, fiber.StatusOK, "Raffle created successfully", raffle, nil)
}
func (h *Handler) DeleteRaffle(c *fiber.Ctx) error {
stringRaffleID := c.Params("id")
raffleID, err := strconv.Atoi(stringRaffleID)
if err != nil {
h.mongoLoggerSvc.Info("failed to parse raffle id",
zap.String("stringRaffleID", stringRaffleID),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid raffle id")
}
raffle, err := h.raffleSvc.DeleteRaffle(c.Context(), int32(raffleID))
if err != nil {
fmt.Println("raffle delete error: ", err)
h.mongoLoggerSvc.Error("Failed to delete raffle",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to delete raffle")
}
return response.WriteJSON(c, fiber.StatusOK, "Raffle deleted successfully", raffle, nil)
}
func (h *Handler) GetRafflesOfCompany(c *fiber.Ctx) error {
stringCompanyID := c.Params("id")
companyID, err := strconv.Atoi(stringCompanyID)
if err != nil || companyID == 0 {
h.mongoLoggerSvc.Info("failed to parse company id",
zap.String("stringCompanyID", stringCompanyID),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid company ID")
}
companyRaffles, err := h.raffleSvc.GetRafflesOfCompany(c.Context(), int32(companyID))
if err != nil {
h.mongoLoggerSvc.Error("Failed to fetch company raffle",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch company raffle")
}
return response.WriteJSON(c, fiber.StatusOK, "Company Raffles fetched successfully", companyRaffles, nil)
}
func (h *Handler) CreateRaffleTicket(c *fiber.Ctx) error {
var req domain.CreateRaffleTicket
if err := c.BodyParser(&req); err != nil {
h.mongoLoggerSvc.Info("Failed to parse raffle ticket request",
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
}
if valErrs, ok := h.validator.Validate(c, req); !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.mongoLoggerSvc.Info("Failed to validate settings",
zap.String("errMsg", errMsg),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
raffleTicket, err := h.raffleSvc.CreateRaffleTicket(c.Context(), req)
if err != nil {
h.mongoLoggerSvc.Error("Failed to create raffle ticket",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create raffle ticket")
}
return response.WriteJSON(c, fiber.StatusOK, "Raffle created successfully", raffleTicket, nil)
}
func (h *Handler) GetUserRaffleTickets(c *fiber.Ctx) error {
stringUserID := c.Params("id")
userID, err := strconv.Atoi(stringUserID)
if err != nil {
h.mongoLoggerSvc.Info("failed to parse company id",
zap.String("stringUserID", stringUserID),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
}
raffleTickets, err := h.raffleSvc.GetUserRaffleTickets(c.Context(), int32(userID))
if err != nil {
h.mongoLoggerSvc.Error("Failed to fetch user raffle tickets",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch user raffle tickets")
}
return response.WriteJSON(c, fiber.StatusOK, "User raffle tickets fetched successfully", raffleTickets, nil)
}
func (h *Handler) SuspendRaffleTicket(c *fiber.Ctx) error {
stringRaffleTicketID := c.Params("id")
raffleTicketID, err := strconv.Atoi(stringRaffleTicketID)
if err != nil {
h.mongoLoggerSvc.Info("failed to parse raffle ticket id",
zap.String("stringUserID", stringRaffleTicketID),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid raffel ticket id")
}
if err := h.raffleSvc.SuspendRaffleTicket(c.Context(), int32(raffleTicketID)); err != nil {
h.mongoLoggerSvc.Error("Failed to suspend raffle ticket",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to suspend raffle ticket")
}
return response.WriteJSON(c, fiber.StatusOK, "User raffle tickets suspended successfully", nil, nil)
}
func (h *Handler) UnSuspendRaffleTicket(c *fiber.Ctx) error {
stringRaffleTicketID := c.Params("id")
raffleTicketID, err := strconv.Atoi(stringRaffleTicketID)
if err != nil {
h.mongoLoggerSvc.Info("failed to parse raffle ticket id",
zap.String("stringUserID", stringRaffleTicketID),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid raffel ticket id")
}
if err := h.raffleSvc.UnSuspendRaffleTicket(c.Context(), int32(raffleTicketID)); err != nil {
h.mongoLoggerSvc.Error("Failed to unsuspend raffle ticket",
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to unsuspend raffle ticket")
}
return response.WriteJSON(c, fiber.StatusOK, "User raffle tickets unsuspended successfully", nil, nil)
}

View File

@ -34,6 +34,7 @@ func (a *App) initAppRoutes() {
a.chapaSvc, a.chapaSvc,
a.walletSvc, a.walletSvc,
a.referralSvc, a.referralSvc,
a.raffleSvc,
a.bonusSvc, a.bonusSvc,
a.virtualGameSvc, a.virtualGameSvc,
a.aleaVirtualGameService, a.aleaVirtualGameService,
@ -193,6 +194,15 @@ func (a *App) initAppRoutes() {
groupV1.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings) groupV1.Get("/referral/settings", a.authMiddleware, h.GetReferralSettings)
groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings) groupV1.Patch("/referral/settings", a.authMiddleware, h.UpdateReferralSettings)
// Raffle Routes
a.fiber.Post("/raffle/create", a.authMiddleware, h.CreateRaffle)
a.fiber.Get("/raffle/delete/:id", a.authMiddleware, h.DeleteRaffle)
a.fiber.Get("/raffle/company/:id", a.authMiddleware, h.GetRafflesOfCompany)
a.fiber.Post("/raffle-ticket/create", a.authMiddleware, h.CreateRaffleTicket)
a.fiber.Get("/raffle-ticket/:id", a.authMiddleware, h.GetUserRaffleTickets)
a.fiber.Get("/raffle-ticket/suspend/:id", a.authMiddleware, h.SuspendRaffleTicket)
a.fiber.Get("/raffle-ticket/unsuspend/:id", a.authMiddleware, h.UnSuspendRaffleTicket)
// Bonus Routes // Bonus Routes
groupV1.Get("/bonus", a.authMiddleware, h.GetBonusMultiplier) groupV1.Get("/bonus", a.authMiddleware, h.GetBonusMultiplier)
groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier) groupV1.Post("/bonus/create", a.authMiddleware, h.CreateBonusMultiplier)