package channelserver import ( "context" "time" dbutil "erupe-ce/common/db" ) // EventQuest represents a row from the event_quests table. type EventQuest struct { ID uint32 `db:"id"` MaxPlayers uint8 `db:"max_players"` QuestType uint8 `db:"quest_type"` QuestID int `db:"quest_id"` Mark uint32 `db:"mark"` Flags int `db:"flags"` StartTime time.Time `db:"start_time"` ActiveDays int `db:"active_days"` InactiveDays int `db:"inactive_days"` } // EventRepository centralizes all database access for event-related tables. type EventRepository struct { db *dbutil.DB } // NewEventRepository creates a new EventRepository. func NewEventRepository(db *dbutil.DB) *EventRepository { return &EventRepository{db: db} } // GetFeatureWeapon returns the featured weapon bitfield for a given start time. func (r *EventRepository) GetFeatureWeapon(startTime time.Time) (activeFeature, error) { var af activeFeature err := r.db.QueryRowx(`SELECT start_time, featured FROM feature_weapon WHERE start_time=$1`, startTime).StructScan(&af) return af, err } // InsertFeatureWeapon stores a new featured weapon entry. func (r *EventRepository) InsertFeatureWeapon(startTime time.Time, features uint32) error { _, err := r.db.Exec(`INSERT INTO feature_weapon VALUES ($1, $2)`, startTime, features) return err } // GetLoginBoosts returns all login boost rows for a character, ordered by week_req. func (r *EventRepository) GetLoginBoosts(charID uint32) ([]loginBoost, error) { var result []loginBoost err := r.db.Select(&result, "SELECT week_req, expiration, reset FROM login_boost WHERE char_id=$1 ORDER BY week_req", charID) return result, err } // InsertLoginBoost creates a new login boost entry. func (r *EventRepository) InsertLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error { _, err := r.db.Exec(`INSERT INTO login_boost VALUES ($1, $2, $3, $4)`, charID, weekReq, expiration, reset) return err } // UpdateLoginBoost updates expiration and reset for a login boost entry. func (r *EventRepository) UpdateLoginBoost(charID uint32, weekReq uint8, expiration, reset time.Time) error { _, err := r.db.Exec(`UPDATE login_boost SET expiration=$1, reset=$2 WHERE char_id=$3 AND week_req=$4`, expiration, reset, charID, weekReq) return err } // GetEventQuests returns all event quest rows ordered by quest_id. func (r *EventRepository) GetEventQuests() ([]EventQuest, error) { var result []EventQuest err := r.db.Select(&result, "SELECT id, COALESCE(max_players, 4) AS max_players, quest_type, quest_id, COALESCE(mark, 0) AS mark, COALESCE(flags, -1) AS flags, start_time, COALESCE(active_days, 0) AS active_days, COALESCE(inactive_days, 0) AS inactive_days FROM event_quests ORDER BY quest_id") return result, err } // EventQuestUpdate pairs a quest ID with its new start time. type EventQuestUpdate struct { ID uint32 StartTime time.Time } // UpdateEventQuestStartTimes batch-updates start times within a single transaction. func (r *EventRepository) UpdateEventQuestStartTimes(updates []EventQuestUpdate) error { if len(updates) == 0 { return nil } tx, err := r.db.BeginTxx(context.Background(), nil) if err != nil { return err } defer func() { _ = tx.Rollback() }() for _, u := range updates { if _, err := tx.Exec("UPDATE event_quests SET start_time = $1 WHERE id = $2", u.StartTime, u.ID); err != nil { return err } } return tx.Commit() }