mirror of
https://github.com/prosolis/gogobee.git
synced 2026-07-15 08:32:41 +00:00
Fix scheduled posts only broadcasting to first room
All scheduled post dedup keys (wotd, holidays, gaming, anime, movies, concerts, birthdays) were global — after posting to the first room, the job was marked complete and the second room was skipped. Fixed by including the room ID in each dedup key so posts go to all broadcast rooms. Birthday XP grants and DMs remain once-per-user-per-year. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -445,7 +445,7 @@ func (p *AnimePlugin) handleUpcoming(ctx MessageContext) error {
|
|||||||
// PostDailyReleases checks broadcast days and DMs watchers about anime airing today.
|
// PostDailyReleases checks broadcast days and DMs watchers about anime airing today.
|
||||||
// Intended to be called by the scheduler daily.
|
// Intended to be called by the scheduler daily.
|
||||||
func (p *AnimePlugin) PostDailyReleases(roomID id.RoomID) {
|
func (p *AnimePlugin) PostDailyReleases(roomID id.RoomID) {
|
||||||
todayKey := time.Now().UTC().Format("2006-01-02")
|
todayKey := fmt.Sprintf("%s:%s", time.Now().UTC().Format("2006-01-02"), roomID)
|
||||||
if db.JobCompleted("anime_releases", todayKey) {
|
if db.JobCompleted("anime_releases", todayKey) {
|
||||||
slog.Info("anime: already sent daily releases", "date", todayKey)
|
slog.Info("anime: already sent daily releases", "date", todayKey)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -260,13 +260,10 @@ func (p *BirthdayPlugin) CheckAndPost(roomID id.RoomID) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, m := range matches {
|
for _, m := range matches {
|
||||||
// Check if already fired this year
|
// Check if already announced in THIS room this year
|
||||||
var fired int
|
roomKey := fmt.Sprintf("%s:%d:%s", m.userID, year, roomID)
|
||||||
err := d.QueryRow(
|
if db.JobCompleted("birthday", roomKey) {
|
||||||
`SELECT 1 FROM birthday_fired WHERE user_id = ? AND year = ?`, m.userID, year,
|
continue
|
||||||
).Scan(&fired)
|
|
||||||
if err == nil {
|
|
||||||
continue // Already fired this year
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build announcement
|
// Build announcement
|
||||||
@@ -282,6 +279,17 @@ func (p *BirthdayPlugin) CheckAndPost(roomID id.RoomID) error {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
db.MarkJobCompleted("birthday", roomKey)
|
||||||
|
|
||||||
|
// XP grant and DM only once per user per year (not per room)
|
||||||
|
var fired int
|
||||||
|
err := d.QueryRow(
|
||||||
|
`SELECT 1 FROM birthday_fired WHERE user_id = ? AND year = ?`, m.userID, year,
|
||||||
|
).Scan(&fired)
|
||||||
|
if err == nil {
|
||||||
|
continue // Already granted XP and sent DM
|
||||||
|
}
|
||||||
|
|
||||||
// Send DM to the birthday person
|
// Send DM to the birthday person
|
||||||
dmMsg := fmt.Sprintf("Happy Birthday! The community wishes you a wonderful day!%s You've been granted 100 bonus XP as a birthday gift!", ageStr)
|
dmMsg := fmt.Sprintf("Happy Birthday! The community wishes you a wonderful day!%s You've been granted 100 bonus XP as a birthday gift!", ageStr)
|
||||||
if err := p.SendDM(id.UserID(m.userID), dmMsg); err != nil {
|
if err := p.SendDM(id.UserID(m.userID), dmMsg); err != nil {
|
||||||
@@ -295,7 +303,7 @@ func (p *BirthdayPlugin) CheckAndPost(roomID id.RoomID) error {
|
|||||||
p.grantBirthdayXP(id.UserID(m.userID), 100)
|
p.grantBirthdayXP(id.UserID(m.userID), 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as fired
|
// Mark as fired (for XP/DM dedup)
|
||||||
_, err = d.Exec(
|
_, err = d.Exec(
|
||||||
`INSERT INTO birthday_fired (user_id, year) VALUES (?, ?)
|
`INSERT INTO birthday_fired (user_id, year) VALUES (?, ?)
|
||||||
ON CONFLICT(user_id, year) DO NOTHING`,
|
ON CONFLICT(user_id, year) DO NOTHING`,
|
||||||
|
|||||||
@@ -337,7 +337,7 @@ func (p *ConcertsPlugin) PostWeeklyDigest(roomID id.RoomID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
year, week := time.Now().UTC().ISOWeek()
|
year, week := time.Now().UTC().ISOWeek()
|
||||||
weekKey := fmt.Sprintf("%d-W%02d", year, week)
|
weekKey := fmt.Sprintf("%d-W%02d:%s", year, week, roomID)
|
||||||
if db.JobCompleted("concert_digest", weekKey) {
|
if db.JobCompleted("concert_digest", weekKey) {
|
||||||
slog.Info("concerts: already sent digest this week", "week", weekKey)
|
slog.Info("concerts: already sent digest this week", "week", weekKey)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func (p *GamingPlugin) PostReleases(roomID id.RoomID) error {
|
|||||||
// Check if already posted this week
|
// Check if already posted this week
|
||||||
now := time.Now().UTC()
|
now := time.Now().UTC()
|
||||||
year, week := now.ISOWeek()
|
year, week := now.ISOWeek()
|
||||||
weekKey := fmt.Sprintf("%d-W%02d", year, week)
|
weekKey := fmt.Sprintf("%d-W%02d:%s", year, week, roomID)
|
||||||
if db.JobCompleted("releases", weekKey) {
|
if db.JobCompleted("releases", weekKey) {
|
||||||
slog.Info("gaming: already posted releases this week", "week", weekKey)
|
slog.Info("gaming: already posted releases this week", "week", weekKey)
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
@@ -203,19 +203,25 @@ func (p *HolidaysPlugin) PostHolidays(roomID id.RoomID) error {
|
|||||||
today := time.Now().UTC().Format("2006-01-02")
|
today := time.Now().UTC().Format("2006-01-02")
|
||||||
d := db.Get()
|
d := db.Get()
|
||||||
|
|
||||||
|
// Per-room dedup
|
||||||
|
roomKey := fmt.Sprintf("%s:%s", today, roomID)
|
||||||
|
if db.JobCompleted("holidays", roomKey) {
|
||||||
|
slog.Info("holidays: already posted today", "date", today, "room", roomID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var dataStr string
|
var dataStr string
|
||||||
var posted int
|
|
||||||
err := d.QueryRow(
|
err := d.QueryRow(
|
||||||
`SELECT data, posted FROM holidays_log WHERE date = ?`, today,
|
`SELECT data FROM holidays_log WHERE date = ?`, today,
|
||||||
).Scan(&dataStr, &posted)
|
).Scan(&dataStr)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
slog.Warn("holidays: no entry for today, attempting prefetch", "date", today)
|
slog.Warn("holidays: no entry for today, attempting prefetch", "date", today)
|
||||||
if err := p.Prefetch(); err != nil {
|
if err := p.Prefetch(); err != nil {
|
||||||
return fmt.Errorf("holidays: prefetch failed: %w", err)
|
return fmt.Errorf("holidays: prefetch failed: %w", err)
|
||||||
}
|
}
|
||||||
err = d.QueryRow(
|
err = d.QueryRow(
|
||||||
`SELECT data, posted FROM holidays_log WHERE date = ?`, today,
|
`SELECT data FROM holidays_log WHERE date = ?`, today,
|
||||||
).Scan(&dataStr, &posted)
|
).Scan(&dataStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("holidays: still no entry after prefetch: %w", err)
|
return fmt.Errorf("holidays: still no entry after prefetch: %w", err)
|
||||||
}
|
}
|
||||||
@@ -223,11 +229,6 @@ func (p *HolidaysPlugin) PostHolidays(roomID id.RoomID) error {
|
|||||||
return fmt.Errorf("holidays: query: %w", err)
|
return fmt.Errorf("holidays: query: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if posted == 1 {
|
|
||||||
slog.Info("holidays: already posted today", "date", today)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var data holidaysDayData
|
var data holidaysDayData
|
||||||
if err := json.Unmarshal([]byte(dataStr), &data); err != nil {
|
if err := json.Unmarshal([]byte(dataStr), &data); err != nil {
|
||||||
return fmt.Errorf("holidays: unmarshal: %w", err)
|
return fmt.Errorf("holidays: unmarshal: %w", err)
|
||||||
@@ -243,10 +244,7 @@ func (p *HolidaysPlugin) PostHolidays(roomID id.RoomID) error {
|
|||||||
return fmt.Errorf("holidays: send: %w", err)
|
return fmt.Errorf("holidays: send: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = d.Exec(`UPDATE holidays_log SET posted = 1 WHERE date = ?`, today)
|
db.MarkJobCompleted("holidays", roomKey)
|
||||||
if err != nil {
|
|
||||||
slog.Error("holidays: mark posted", "err", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,14 +558,15 @@ func (p *MoviesPlugin) PostDailyReleases(roomID id.RoomID) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
today := time.Now().UTC().Format("2006-01-02")
|
today := time.Now().UTC().Format("2006-01-02")
|
||||||
if db.JobCompleted("movie_releases", today) {
|
todayKey := fmt.Sprintf("%s:%s", today, roomID)
|
||||||
slog.Info("movies: already sent daily releases", "date", today)
|
if db.JobCompleted("movie_releases", todayKey) {
|
||||||
|
slog.Info("movies: already sent daily releases", "date", todayKey)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
success := false
|
success := false
|
||||||
defer func() {
|
defer func() {
|
||||||
if success {
|
if success {
|
||||||
db.MarkJobCompleted("movie_releases", today)
|
db.MarkJobCompleted("movie_releases", todayKey)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -148,19 +148,25 @@ func (p *WOTDPlugin) PostWOTD(roomID id.RoomID) error {
|
|||||||
today := time.Now().UTC().Format("2006-01-02")
|
today := time.Now().UTC().Format("2006-01-02")
|
||||||
d := db.Get()
|
d := db.Get()
|
||||||
|
|
||||||
|
// Per-room dedup
|
||||||
|
roomKey := fmt.Sprintf("%s:%s", today, roomID)
|
||||||
|
if db.JobCompleted("wotd", roomKey) {
|
||||||
|
slog.Info("wotd: already posted today", "date", today, "room", roomID)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
var word, definition, partOfSpeech, example string
|
var word, definition, partOfSpeech, example string
|
||||||
var posted int
|
|
||||||
err := d.QueryRow(
|
err := d.QueryRow(
|
||||||
`SELECT word, definition, part_of_speech, example, posted FROM wotd_log WHERE date = ?`, today,
|
`SELECT word, definition, part_of_speech, example FROM wotd_log WHERE date = ?`, today,
|
||||||
).Scan(&word, &definition, &partOfSpeech, &example, &posted)
|
).Scan(&word, &definition, &partOfSpeech, &example)
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
slog.Warn("wotd: no entry for today, attempting prefetch", "date", today)
|
slog.Warn("wotd: no entry for today, attempting prefetch", "date", today)
|
||||||
if err := p.Prefetch(); err != nil {
|
if err := p.Prefetch(); err != nil {
|
||||||
return fmt.Errorf("wotd: prefetch failed: %w", err)
|
return fmt.Errorf("wotd: prefetch failed: %w", err)
|
||||||
}
|
}
|
||||||
err = d.QueryRow(
|
err = d.QueryRow(
|
||||||
`SELECT word, definition, part_of_speech, example, posted FROM wotd_log WHERE date = ?`, today,
|
`SELECT word, definition, part_of_speech, example FROM wotd_log WHERE date = ?`, today,
|
||||||
).Scan(&word, &definition, &partOfSpeech, &example, &posted)
|
).Scan(&word, &definition, &partOfSpeech, &example)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("wotd: still no entry after prefetch: %w", err)
|
return fmt.Errorf("wotd: still no entry after prefetch: %w", err)
|
||||||
}
|
}
|
||||||
@@ -168,20 +174,12 @@ func (p *WOTDPlugin) PostWOTD(roomID id.RoomID) error {
|
|||||||
return fmt.Errorf("wotd: query: %w", err)
|
return fmt.Errorf("wotd: query: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if posted == 1 {
|
|
||||||
slog.Info("wotd: already posted today", "date", today)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
msg := p.formatWOTD(word, definition, partOfSpeech, example)
|
msg := p.formatWOTD(word, definition, partOfSpeech, example)
|
||||||
if err := p.SendMessage(roomID, msg); err != nil {
|
if err := p.SendMessage(roomID, msg); err != nil {
|
||||||
return fmt.Errorf("wotd: send message: %w", err)
|
return fmt.Errorf("wotd: send message: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = d.Exec(`UPDATE wotd_log SET posted = 1 WHERE date = ?`, today)
|
db.MarkJobCompleted("wotd", roomKey)
|
||||||
if err != nil {
|
|
||||||
slog.Error("wotd: mark posted", "err", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user