fix: polling
This commit is contained in:
@@ -3,7 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -60,6 +63,54 @@ func getWeekStart(t time.Time) string {
|
|||||||
return t.AddDate(0, 0, -offset).Format("2006-01-02")
|
return t.AddDate(0, 0, -offset).Format("2006-01-02")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sendPollNonAnonymous sends a non-anonymous poll by manually constructing the request
|
||||||
|
// Workaround for echotron bug where IsAnonymous=false is ignored (bool false is zero value)
|
||||||
|
func sendPollNonAnonymous(chatID int64, question string, options []echotron.InputPollOption, opts *echotron.PollOptions) (*echotron.APIResponseMessage, error) {
|
||||||
|
token := os.Getenv("TELEGRAM__TOKEN")
|
||||||
|
if token == "" {
|
||||||
|
return nil, fmt.Errorf("TELEGRAM__TOKEN not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
baseURL := "https://api.telegram.org/bot" + token + "/sendPoll"
|
||||||
|
|
||||||
|
vals := make(url.Values)
|
||||||
|
vals.Set("chat_id", strconv.FormatInt(chatID, 10))
|
||||||
|
vals.Set("question", question)
|
||||||
|
|
||||||
|
optionsJSON, err := json.Marshal(options)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
vals.Set("options", string(optionsJSON))
|
||||||
|
|
||||||
|
// IMPORTANT: Explicitly set is_anonymous=false to get poll_answer updates
|
||||||
|
// echotron ignores IsAnonymous=false because bool false is zero value in scan()
|
||||||
|
vals.Set("is_anonymous", "false")
|
||||||
|
|
||||||
|
if opts != nil && opts.AllowsMultipleAnswers {
|
||||||
|
vals.Set("allows_multiple_answers", "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make the HTTP request
|
||||||
|
resp, err := http.PostForm(baseURL, vals)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Parse response
|
||||||
|
var result echotron.APIResponseMessage
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !result.Ok {
|
||||||
|
return nil, fmt.Errorf("telegram API error: %s", result.Description)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func parseCommaSeparatedIDs(envKey, fieldName string) []int64 {
|
func parseCommaSeparatedIDs(envKey, fieldName string) []int64 {
|
||||||
value := os.Getenv(envKey)
|
value := os.Getenv(envKey)
|
||||||
if value == "" {
|
if value == "" {
|
||||||
@@ -221,12 +272,14 @@ func SendQuiz(ctx context.Context, db *sql.DB, api echotron.API, groupID int64)
|
|||||||
{Text: "Да!"},
|
{Text: "Да!"},
|
||||||
{Text: "Нет"},
|
{Text: "Нет"},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Workaround for echotron bug: IsAnonymous=false is ignored because bool false is zero value
|
||||||
|
// We need to explicitly set is_anonymous=false in the request
|
||||||
opts := &echotron.PollOptions{
|
opts := &echotron.PollOptions{
|
||||||
IsAnonymous: false,
|
|
||||||
AllowsMultipleAnswers: false,
|
AllowsMultipleAnswers: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := api.SendPoll(groupID, question, options, opts)
|
result, err := sendPollNonAnonymous(groupID, question, options, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Int64("group_id", groupID).Msg("SendPoll failed")
|
log.Error().Err(err).Int64("group_id", groupID).Msg("SendPoll failed")
|
||||||
return
|
return
|
||||||
|
|||||||
10
cmd/main.go
10
cmd/main.go
@@ -117,11 +117,11 @@ func main() {
|
|||||||
dsp := echotron.NewDispatcher(botToken, newBot)
|
dsp := echotron.NewDispatcher(botToken, newBot)
|
||||||
|
|
||||||
updateOpts := echotron.UpdateOptions{
|
updateOpts := echotron.UpdateOptions{
|
||||||
AllowedUpdates: []echotron.UpdateType{
|
// AllowedUpdates: []echotron.UpdateType{
|
||||||
echotron.MessageUpdate,
|
// echotron.MessageUpdate,
|
||||||
echotron.CallbackQueryUpdate,
|
// echotron.CallbackQueryUpdate,
|
||||||
echotron.PollAnswerUpdate,
|
// echotron.PollAnswerUpdate,
|
||||||
},
|
// },
|
||||||
}
|
}
|
||||||
|
|
||||||
errChan := make(chan error, 1)
|
errChan := make(chan error, 1)
|
||||||
|
|||||||
@@ -58,10 +58,17 @@ func GetAllParticipants(ctx context.Context, db *sql.DB, groupID int64) ([]Parti
|
|||||||
participants := make([]Participant, 0)
|
participants := make([]Participant, 0)
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var p Participant
|
var p Participant
|
||||||
var idStr string
|
var idStr, createdAtStr string
|
||||||
if err := rows.Scan(&idStr, &p.GroupID, &p.UserID, &p.Username, &p.FullName, &p.CreatedAt); err != nil {
|
if err := rows.Scan(&idStr, &p.GroupID, &p.UserID, &p.Username, &p.FullName, &createdAtStr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse time string - SQLite returns timestamps as strings
|
||||||
|
p.CreatedAt, _ = time.Parse(time.RFC3339, createdAtStr)
|
||||||
|
if p.CreatedAt.IsZero() {
|
||||||
|
p.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", createdAtStr)
|
||||||
|
}
|
||||||
|
|
||||||
p.ID, _ = uuid.Parse(idStr)
|
p.ID, _ = uuid.Parse(idStr)
|
||||||
participants = append(participants, p)
|
participants = append(participants, p)
|
||||||
}
|
}
|
||||||
@@ -131,13 +138,25 @@ func GetAvailablePairs(ctx context.Context, db *sql.DB, groupID int64) ([][2]Par
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var p1, p2 Participant
|
var p1, p2 Participant
|
||||||
var p1IDStr, p2IDStr string
|
var p1IDStr, p2IDStr string
|
||||||
|
var p1CreatedAtStr, p2CreatedAtStr string
|
||||||
p1.GroupID = groupID
|
p1.GroupID = groupID
|
||||||
p2.GroupID = groupID
|
p2.GroupID = groupID
|
||||||
|
|
||||||
if err := rows.Scan(&p1IDStr, &p1.UserID, &p1.Username, &p1.FullName, &p1.CreatedAt,
|
if err := rows.Scan(&p1IDStr, &p1.UserID, &p1.Username, &p1.FullName, &p1CreatedAtStr,
|
||||||
&p2IDStr, &p2.UserID, &p2.Username, &p2.FullName, &p2.CreatedAt); err != nil {
|
&p2IDStr, &p2.UserID, &p2.Username, &p2.FullName, &p2CreatedAtStr); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse time strings - SQLite returns timestamps as strings
|
||||||
|
p1.CreatedAt, _ = time.Parse(time.RFC3339, p1CreatedAtStr)
|
||||||
|
if p1.CreatedAt.IsZero() {
|
||||||
|
p1.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", p1CreatedAtStr)
|
||||||
|
}
|
||||||
|
p2.CreatedAt, _ = time.Parse(time.RFC3339, p2CreatedAtStr)
|
||||||
|
if p2.CreatedAt.IsZero() {
|
||||||
|
p2.CreatedAt, _ = time.Parse("2006-01-02 15:04:05", p2CreatedAtStr)
|
||||||
|
}
|
||||||
|
|
||||||
p1.ID, _ = uuid.Parse(p1IDStr)
|
p1.ID, _ = uuid.Parse(p1IDStr)
|
||||||
p2.ID, _ = uuid.Parse(p2IDStr)
|
p2.ID, _ = uuid.Parse(p2IDStr)
|
||||||
pairs = append(pairs, [2]Participant{p1, p2})
|
pairs = append(pairs, [2]Participant{p1, p2})
|
||||||
|
|||||||
Reference in New Issue
Block a user