Yimaru-BackEnd/internal/web_server/handlers/event_handler.go

655 lines
19 KiB
Go

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"
)
// @Summary Retrieve all upcoming events
// @Description Retrieve all upcoming events from the database
// @Tags prematch
// @Accept json
// @Produce json
// @Param page query int false "Page number"
// @Param page_size query int false "Page size"
// @Param league_id query string false "League ID Filter"
// @Param sport_id query string false "Sport ID Filter"
// @Param cc query string false "Country Code Filter"
// @Param first_start_time query string false "Start Time"
// @Param last_start_time query string false "End Time"
// @Success 200 {array} domain.BaseEvent
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/events [get]
func (h *Handler) GetAllEvents(c *fiber.Ctx) error {
page := c.QueryInt("page", 1)
pageSize := c.QueryInt("page_size", 10)
limit := domain.ValidInt32{
Value: int32(pageSize),
Valid: true,
}
offset := domain.ValidInt32{
Value: int32(page - 1),
Valid: true,
}
leagueIDQuery := c.Query("league_id")
var leagueID domain.ValidInt64
if leagueIDQuery != "" {
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
if err != nil {
h.BadRequestLogger().Error("invalid league id",
zap.String("league_id", leagueIDQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
}
leagueID = domain.ValidInt64{
Value: leagueIDInt,
Valid: true,
}
}
sportIDQuery := c.Query("sport_id")
var sportID domain.ValidInt32
if sportIDQuery != "" {
sportIDint, err := strconv.Atoi(sportIDQuery)
if err != nil {
h.BadRequestLogger().Info("invalid sport id",
zap.String("sportID", sportIDQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid sport id")
}
sportID = domain.ValidInt32{
Value: int32(sportIDint),
Valid: true,
}
}
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
firstStartTimeQuery := c.Query("first_start_time")
var firstStartTime domain.ValidTime
if firstStartTimeQuery != "" {
firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
if err != nil {
h.BadRequestLogger().Info("invalid start_time format",
zap.String("first_start_time", firstStartTimeQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
}
firstStartTime = domain.ValidTime{
Value: firstStartTimeParsed,
Valid: true,
}
}
lastStartTimeQuery := c.Query("last_start_time")
var lastStartTime domain.ValidTime
if lastStartTimeQuery != "" {
lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
if err != nil {
h.BadRequestLogger().Info("invalid last_start_time format",
zap.String("last_start_time", lastStartTimeQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
}
lastStartTime = domain.ValidTime{
Value: lastStartTimeParsed,
Valid: true,
}
}
countryCodeQuery := c.Query("cc")
countryCode := domain.ValidString{
Value: countryCodeQuery,
Valid: countryCodeQuery != "",
}
isFeaturedQuery := c.Query("is_featured")
var isFeatured domain.ValidBool
if isFeaturedQuery != "" {
isFeaturedParsed, err := strconv.ParseBool(isFeaturedQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse isFeatured",
zap.String("is_featured", isFeaturedQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_shop_bet")
}
isFeatured = domain.ValidBool{
Value: isFeaturedParsed,
Valid: true,
}
}
events, total, err := h.eventSvc.GetAllEvents(
c.Context(), domain.EventFilter{
SportID: sportID,
LeagueID: leagueID,
Query: searchString,
FirstStartTime: firstStartTime,
LastStartTime: lastStartTime,
Limit: limit,
Offset: offset,
CountryCode: countryCode,
Featured: isFeatured,
})
// fmt.Printf("League ID: %v", leagueID)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to retrieve all upcoming events",
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
res := domain.ConvertEventResList(events)
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", res, nil, page, int(total))
}
// @Summary Retrieve all upcoming events with settings
// @Description Retrieve all upcoming events settings from the database
// @Tags prematch
// @Accept json
// @Produce json
// @Param page query int false "Page number"
// @Param page_size query int false "Page size"
// @Param league_id query string false "League ID Filter"
// @Param sport_id query string false "Sport ID Filter"
// @Param cc query string false "Country Code Filter"
// @Param first_start_time query string false "Start Time"
// @Param last_start_time query string false "End Time"
// @Success 200 {array} domain.BaseEvent
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/{tenant_slug}/events [get]
func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
}
page := c.QueryInt("page", 1)
pageSize := c.QueryInt("page_size", 10)
limit := domain.ValidInt32{
Value: int32(pageSize),
Valid: true,
}
offset := domain.ValidInt32{
Value: int32(page - 1),
Valid: true,
}
leagueIDQuery := c.Query("league_id")
var leagueID domain.ValidInt64
if leagueIDQuery != "" {
leagueIDInt, err := strconv.ParseInt(leagueIDQuery, 10, 64)
if err != nil {
h.BadRequestLogger().Error("invalid league id",
zap.String("league_id", leagueIDQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid league id")
}
leagueID = domain.ValidInt64{
Value: leagueIDInt,
Valid: true,
}
}
sportIDQuery := c.Query("sport_id")
var sportID domain.ValidInt32
if sportIDQuery != "" {
sportIDint, err := strconv.Atoi(sportIDQuery)
if err != nil {
h.BadRequestLogger().Info("invalid sport id",
zap.String("sportID", sportIDQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "invalid sport id")
}
sportID = domain.ValidInt32{
Value: int32(sportIDint),
Valid: true,
}
}
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
firstStartTimeQuery := c.Query("first_start_time")
var firstStartTime domain.ValidTime
if firstStartTimeQuery != "" {
firstStartTimeParsed, err := time.Parse(time.RFC3339, firstStartTimeQuery)
if err != nil {
h.BadRequestLogger().Info("invalid start_time format",
zap.String("first_start_time", firstStartTimeQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
}
firstStartTime = domain.ValidTime{
Value: firstStartTimeParsed,
Valid: true,
}
}
lastStartTimeQuery := c.Query("last_start_time")
var lastStartTime domain.ValidTime
if lastStartTimeQuery != "" {
lastStartTimeParsed, err := time.Parse(time.RFC3339, lastStartTimeQuery)
if err != nil {
h.BadRequestLogger().Info("invalid last_start_time format",
zap.String("last_start_time", lastStartTimeQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Invalid start_time format")
}
lastStartTime = domain.ValidTime{
Value: lastStartTimeParsed,
Valid: true,
}
}
countryCodeQuery := c.Query("cc")
countryCode := domain.ValidString{
Value: countryCodeQuery,
Valid: countryCodeQuery != "",
}
isFeaturedQuery := c.Query("is_featured")
var isFeatured domain.ValidBool
if isFeaturedQuery != "" {
isFeaturedParsed, err := strconv.ParseBool(isFeaturedQuery)
if err != nil {
h.BadRequestLogger().Error("Failed to parse isFeatured",
zap.String("is_featured", isFeaturedQuery),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse is_shop_bet")
}
isFeatured = domain.ValidBool{
Value: isFeaturedParsed,
Valid: true,
}
}
events, total, err := h.eventSvc.GetEventsWithSettings(
c.Context(), companyID.Value, domain.EventFilter{
SportID: sportID,
LeagueID: leagueID,
Query: searchString,
FirstStartTime: firstStartTime,
LastStartTime: lastStartTime,
Limit: limit,
Offset: offset,
CountryCode: countryCode,
Featured: isFeatured,
Status: domain.ValidEventStatus{
Value: domain.STATUS_PENDING,
Valid: true,
},
IsLive: domain.ValidBool{
Value: false,
Valid: true,
},
Active: domain.ValidBool{
Value: true,
Valid: true,
},
})
// fmt.Printf("League ID: %v", leagueID)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to retrieve all upcoming events",
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
res := domain.ConvertEventWithSettingResList(events)
return response.WritePaginatedJSON(c, fiber.StatusOK, "All upcoming events retrieved successfully", res, nil, page, int(total))
}
type TopLeaguesRes struct {
Leagues []TopLeague `json:"leagues"`
}
type TopLeague struct {
LeagueID int64 `json:"league_id"`
LeagueName string `json:"league_name"`
LeagueCC string `json:"league_cc"`
LeagueSportID int32 `json:"league_sport_id"`
Events []domain.EventWithSettingsRes `json:"events"`
// Total int64 `json:"total"`
}
// @Summary Retrieve all top leagues
// @Description Retrieve all top leagues
// @Tags prematch
// @Accept json
// @Produce json
// @Success 200 {array} TopLeague
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/{tenant_slug}/top-leagues [get]
func (h *Handler) GetTopLeagues(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
}
leagues, _, err := h.leagueSvc.GetAllLeaguesByCompany(c.Context(), companyID.Value, domain.LeagueFilter{
IsFeatured: domain.ValidBool{
Value: true,
Valid: true,
},
})
if err != nil {
h.InternalServerErrorLogger().Error("Error while fetching top leagues",
zap.Int64("company_id", companyID.Value),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
var topLeague []TopLeague = make([]TopLeague, 0, len(leagues))
for _, league := range leagues {
events, _, err := h.eventSvc.GetEventsWithSettings(
c.Context(), companyID.Value, domain.EventFilter{
LeagueID: domain.ValidInt64{
Value: league.ID,
Valid: true,
},
Active: domain.ValidBool{Value: true, Valid: true},
})
if err != nil {
h.InternalServerErrorLogger().Warn("Error while fetching events for top league",
zap.Int64("LeagueID", league.ID),
zap.Int64("company_id", companyID.Value),
zap.Error(err),
)
}
topLeague = append(topLeague, TopLeague{
LeagueID: league.ID,
LeagueName: league.Name,
LeagueCC: league.CountryCode.Value,
LeagueSportID: league.SportID,
Events: domain.ConvertEventWithSettingResList(events),
})
}
res := TopLeaguesRes{
Leagues: topLeague,
}
return response.WriteJSON(c, fiber.StatusOK, "All top leagues events retrieved successfully", res, nil)
}
// @Summary Retrieve an upcoming by ID
// @Description Retrieve an upcoming event by ID
// @Tags prematch
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} domain.BaseEvent
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/events/{id} [get]
func (h *Handler) GetEventByID(c *fiber.Ctx) error {
idStr := c.Params("id")
eventID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
event, err := h.eventSvc.GetEventByID(c.Context(), eventID)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to get event by id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
res := domain.ConvertEventRes(event)
return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", res, nil)
}
// @Summary Retrieve an upcoming by ID
// @Description Retrieve an upcoming event by ID
// @Tags prematch
// @Accept json
// @Produce json
// @Param id path string true "ID"
// @Success 200 {object} domain.BaseEvent
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/{tenant_slug}events/{id} [get]
func (h *Handler) GetTenantEventByID(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
}
idStr := c.Params("id")
eventID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
event, err := h.eventSvc.GetEventWithSettingByID(c.Context(), eventID, companyID.Value)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to get upcoming event by id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
res := domain.ConvertEventWitSettingRes(event)
return response.WriteJSON(c, fiber.StatusOK, "Upcoming event retrieved successfully", res, nil)
}
type UpdateEventStatusReq struct {
}
// SetEventStatusToRemoved godoc
// @Summary Set the event status to removed
// @Description Set the event status to removed
// @Tags event
// @Accept json
// @Produce json
// @Param id path int true "Event ID"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/events/{id} [delete]
func (h *Handler) SetEventStatusToRemoved(c *fiber.Ctx) error {
idStr := c.Params("id")
eventID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
err = h.eventSvc.UpdateEventStatus(c.Context(), eventID, domain.STATUS_REMOVED)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to update event status",
zap.Int64("EventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update event status")
}
return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil)
}
type UpdateEventSettingsReq struct {
Featured *bool `json:"is_featured" example:"true"`
IsActive *bool `json:"is_active" example:"true"`
WinningUpperLimit *int `json:"winning_upper_limit" example:"10000"`
}
// UpdateEventSettings godoc
// @Summary update the event settings
// @Description Update the event settings
// @Tags event
// @Accept json
// @Produce json
// @Param id path int true "Event ID"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/tenant/{tenant_slug}/events/{id}/settings [put]
func (h *Handler) UpdateEventSettings(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid {
h.BadRequestLogger().Error("invalid company id")
return fiber.NewError(fiber.StatusBadRequest, "invalid company id")
}
eventIDStr := c.Params("id")
eventID, err := strconv.ParseInt(eventIDStr, 10, 64)
if err != nil {
h.BadRequestLogger().Error("invalid event id")
return fiber.NewError(fiber.StatusBadRequest, "invalid event id")
}
var req UpdateEventSettingsReq
if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("Failed to parse event id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
logFields := []zap.Field{
zap.Int64("eventID", eventID),
zap.Int64("companyID", companyID.Value),
zap.Any("is_featured", req.Featured),
zap.Any("is_active", req.IsActive),
zap.Any("winning_upper_limit", req.WinningUpperLimit),
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.BadRequestLogger().Error("Failed to update event settings",
append(logFields, zap.String("errMsg", errMsg))...,
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
err = h.eventSvc.UpdateEventSettings(c.Context(), domain.CreateEventSettings{
CompanyID: companyID.Value,
EventID: eventID,
IsFeatured: domain.ConvertBoolPtr(req.Featured),
IsActive: domain.ConvertBoolPtr(req.IsActive),
WinningUpperLimit: domain.ConvertIntPtr(req.WinningUpperLimit),
})
if err != nil {
h.InternalServerErrorLogger().Error("Failed to update event settings", append(logFields, zap.Error(err))...)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil)
}
type SetEventIsMonitoredReq struct {
IsMonitored bool `json:"is_monitored"`
}
// SetEventIsMonitored godoc
// @Summary update the event is_monitored
// @Description Update the event is_monitored
// @Tags event
// @Accept json
// @Produce json
// @Param id path int true "Event ID"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /api/v1/events/{id}/is_monitored [patch]
func (h *Handler) SetEventIsMonitored(c *fiber.Ctx) error {
idStr := c.Params("id")
eventID, err := strconv.ParseInt(idStr, 10, 64)
if err != nil {
h.BadRequestLogger().Info("Failed to parse event id", zap.String("id", idStr))
return fiber.NewError(fiber.StatusBadRequest, "Missing id")
}
var req SetEventIsMonitoredReq
if err := c.BodyParser(&req); err != nil {
h.BadRequestLogger().Info("Failed to parse bet id",
zap.Int64("eventID", eventID),
zap.Error(err),
)
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
logFields := []zap.Field{
zap.Int64("eventID", eventID),
zap.Any("is_featured", req.IsMonitored),
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
h.BadRequestLogger().Error("Failed to update event featured",
append(logFields, zap.String("errMsg", errMsg))...,
)
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
err = h.eventSvc.UpdateEventMonitored(c.Context(), eventID, req.IsMonitored)
if err != nil {
h.InternalServerErrorLogger().Error("Failed to update event is_monitored", append(logFields, zap.Error(err))...)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
return response.WriteJSON(c, fiber.StatusOK, "Event updated successfully", nil, nil)
}