fix: ensure poll unpins reliably and remove duplicate quiz

- Remove the extra Wednesday 16:19 send_quiz job; only the Friday 17:00
  quiz remains, matching the /start description. The duplicate send
  overwrote the poll mapping, orphaning the earlier pinned poll so it
  was never unpinned.
- Extract unpinPoll() and call it at the start of CreatePairs so the
  poll is always unpinned, even when no pairs can be formed (previously
  early returns skipped the unpin block entirely).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-01 22:02:55 +03:00
parent 913c945a32
commit 2ffd31885e
2 changed files with 29 additions and 20 deletions

View File

@@ -391,8 +391,37 @@ func appendUnpairedMessage(ctx context.Context, db *sql.DB, message string, grou
return message return message
} }
// unpinPoll unpins the active poll for the group and removes its mapping.
// Safe to call even if there is no active poll.
func unpinPoll(ctx context.Context, db *sql.DB, api echotron.API, groupID int64) {
pollMapping, err := database.GetPollMappingByGroupID(ctx, db, groupID)
if err != nil {
log.Warn().Err(err).Int64("group_id", groupID).Msg("GetPollMappingByGroupID failed (no active poll)")
return
}
if pollMapping == nil {
return
}
_, err = api.UnpinChatMessage(groupID, &echotron.UnpinMessageOptions{MessageID: int(pollMapping.MessageID)})
if err != nil {
log.Warn().Err(err).Int64("group_id", groupID).Int64("message_id", pollMapping.MessageID).Msg("UnpinChatMessage failed (check bot permissions)")
} else {
log.Info().Int64("group_id", groupID).Int64("message_id", pollMapping.MessageID).Msg("Poll message unpinned")
}
// Delete poll mapping after attempting to unpin (even if unpin failed)
if err := database.DeletePollMapping(ctx, db, groupID); err != nil {
log.Warn().Err(err).Int64("group_id", groupID).Msg("DeletePollMapping failed")
}
}
// CreatePairs generates random pairs // CreatePairs generates random pairs
func CreatePairs(ctx context.Context, db *sql.DB, api echotron.API, groupID int64) { func CreatePairs(ctx context.Context, db *sql.DB, api echotron.API, groupID int64) {
// Always unpin the active poll first, regardless of whether pairs get
// created below — otherwise an early return would leave the poll pinned.
unpinPoll(ctx, db, api, groupID)
availablePairs, err := database.GetAvailablePairs(ctx, db, groupID) availablePairs, err := database.GetAvailablePairs(ctx, db, groupID)
if err != nil { if err != nil {
log.Error().Err(err).Int64("group_id", groupID).Msg("GetAvailablePairs failed") log.Error().Err(err).Int64("group_id", groupID).Msg("GetAvailablePairs failed")
@@ -428,24 +457,6 @@ func CreatePairs(ctx context.Context, db *sql.DB, api echotron.API, groupID int6
sendMessage(api, message, groupID) sendMessage(api, message, groupID)
// Unpin the poll message
pollMapping, err := database.GetPollMappingByGroupID(ctx, db, groupID)
if err != nil {
log.Warn().Err(err).Int64("group_id", groupID).Msg("GetPollMappingByGroupID failed (no active poll)")
} else if pollMapping != nil {
_, err = api.UnpinChatMessage(groupID, &echotron.UnpinMessageOptions{MessageID: int(pollMapping.MessageID)})
if err != nil {
log.Warn().Err(err).Int64("group_id", groupID).Int64("message_id", pollMapping.MessageID).Msg("UnpinChatMessage failed (check bot permissions)")
} else {
log.Info().Int64("group_id", groupID).Int64("message_id", pollMapping.MessageID).Msg("Poll message unpinned")
}
// Delete poll mapping after attempting to unpin (even if unpin failed)
if err := database.DeletePollMapping(ctx, db, groupID); err != nil {
log.Warn().Err(err).Int64("group_id", groupID).Msg("DeletePollMapping failed")
}
}
if err = database.ClearAllParticipants(ctx, db, groupID); err != nil { if err = database.ClearAllParticipants(ctx, db, groupID); err != nil {
log.Error().Err(err).Int64("group_id", groupID).Msg("ClearAllParticipants failed") log.Error().Err(err).Int64("group_id", groupID).Msg("ClearAllParticipants failed")
} }

View File

@@ -206,8 +206,6 @@ func startScheduler(db *sql.DB, api echotron.API, stopChan chan struct{}) {
// Friday 17:00 - send quiz // Friday 17:00 - send quiz
scheduleJob("send_quiz", time.Friday, 17, 0, SendQuizToAllGroups, db, api, stopChan, moscowTZ) scheduleJob("send_quiz", time.Friday, 17, 0, SendQuizToAllGroups, db, api, stopChan, moscowTZ)
scheduleJob("send_quiz", time.Wednesday, 16, 19, SendQuizToAllGroups, db, api, stopChan, moscowTZ)
// Sunday 19:00 - create pairs // Sunday 19:00 - create pairs
scheduleJob("create_pairs", time.Sunday, 19, 0, CreatePairsForAllGroups, db, api, stopChan, moscowTZ) scheduleJob("create_pairs", time.Sunday, 19, 0, CreatePairsForAllGroups, db, api, stopChan, moscowTZ)