bot: complete Polls 2.0 API

pull/269/head
Demian 4 years ago
parent 299838450e
commit 9b11223d56

@ -76,6 +76,7 @@ var (
ErrWrongFileIDPadding = NewAPIError(400, "Bad Request: wrong remote file id specified: Wrong padding in the string")
ErrFailedImageProcess = NewAPIError(400, "Bad Request: IMAGE_PROCESS_FAILED", "Image process failed")
ErrInvaliadStickerset = NewAPIError(400, "Bad Request: STICKERSET_INVALID", "Stickerset is invalid")
ErrBadPollOptions = NewAPIError(400, "Bad Request: expected Array of String as options")
// No rights errors
ErrNoRightsToRestrict = NewAPIError(400, "Bad Request: not enough rights to restrict/unrestrict chat member")
@ -122,6 +123,8 @@ func ErrByDescription(s string) error {
return ErrMessageNotModified
case ErrButtonDataInvalid.ʔ():
return ErrButtonDataInvalid
case ErrBadPollOptions.ʔ():
return ErrBadPollOptions
case ErrNoRightsToRestrict.ʔ():
return ErrNoRightsToRestrict
case ErrNoRightsToSend.ʔ():

@ -99,6 +99,9 @@ type Message struct {
// For a venue, information about it.
Venue *Venue `json:"venue"`
// For a poll, information the native poll.
Poll *Poll `json:"poll"`
// For a service message, represents a user,
// that just got added to chat, this message came from.
//

@ -1,5 +1,7 @@
package telebot
import "encoding/json"
// Option is a shorcut flag type for certain message features
// (so-called options). It means that instead of passing
// fully-fledged SendOptions* to Send(), you can use these
@ -127,8 +129,9 @@ func (og *ReplyMarkup) copy() *ReplyMarkup {
type ReplyButton struct {
Text string `json:"text"`
Contact bool `json:"request_contact,omitempty"`
Location bool `json:"request_location,omitempty"`
Contact bool `json:"request_contact,omitempty"`
Location bool `json:"request_location,omitempty"`
Poll PollType `json:"request_poll,omitempty"`
// Not used anywhere.
// Will be removed in future releases.
@ -143,9 +146,11 @@ type InlineKeyboardMarkup struct {
InlineKeyboard [][]InlineButton `json:"inline_keyboard,omitempty"`
}
// PollOptions represents arguments for sendPoll method.
type PollOptions struct {
DisableNotification bool `json:"disable_notification"`
ReplyToMessageID *int `json:"reply_to_message_id"`
ReplyMarkup *ReplyMarkup `json:"reply_markup"`
func (pt PollType) MarshalJSON() ([]byte, error) {
var aux = struct {
Type string `json:"type"`
}{
Type: string(pt),
}
return json.Marshal(&aux)
}

@ -1,47 +0,0 @@
package telebot
// Poll object represents a poll, it contains information about a poll.
type Poll struct {
ID string `json:"id"`
Question string `json:"question"`
Options []PollOption `json:"options"`
TotalVoterCount int `json:"total_voter_count"`
IsClosed bool `json:"is_closed"`
IsAnonymous bool `json:"is_anonymous"`
Type PollType `json:"type"`
AllowsMultipleAnswers bool `json:"allows_multiple_answers"`
// Optional. 0-based identifier of the correct answer option.
// Available only for polls in the quiz mode, which are closed,
// or was sent (not forwarded) by the bot or to the private chat with the bot.
CorrectOptionID int `json:"correct_option_id"`
}
// PollOption object represents a option of a poll
type PollOption struct {
Text string `json:"text"`
VoterCount int `json:"voter_count"`
}
// PollAnswer object represents an answer of a user in a non-anonymous poll.
type PollAnswer struct {
PollID string `json:"poll_id"`
User User `json:"user"`
// 0-based identifiers of answer options, chosen by the user. May be empty if the user retracted their vote.
OptionIDs []int `json:"option_ids"`
}
func (p *Poll) IsRegular() bool {
return p.Type == "regular"
}
func (p *Poll) IsQuiz() bool {
return p.Type == "quiz"
}
func (p *Poll) AddOptions(text ...string) {
for _, t := range text {
p.Options = append(p.Options, PollOption{Text: t})
}
}

@ -0,0 +1,58 @@
package telebot
import "time"
// Poll contains information about a poll.
type Poll struct {
ID string `json:"id"`
Type PollType `json:"type"`
Question string `json:"question"`
Options []PollOption `json:"options"`
VoterCount int `json:"total_voter_count"`
// (Optional)
Closed bool `json:"is_closed,omitempty"`
CorrectOption int `json:"correct_option_id,omitempty"`
MultipleAnswers bool `json:"allows_multiple_answers,omitempty"`
Explanation string `json:"explanation,omitempty"`
ParseMode ParseMode `json:"explanation_parse_mode,omitempty"`
Entities []MessageEntity `json:"explanation_entities"`
// True by default, shouldn't be omitted.
Anonymous bool `json:"is_anonymous"`
// (Mutually exclusive)
OpenPeriod int `json:"open_period,omitempty"`
CloseUnixdate int64 `json:"close_date,omitempty"`
}
// PollOption contains information about one answer option in a poll.
type PollOption struct {
Text string `json:"text"`
VoterCount int `json:"voter_count"`
}
// PollAnswer represents an answer of a user in a non-anonymous poll.
type PollAnswer struct {
PollID string `json:"poll_id"`
User User `json:"user"`
Options []int `json:"option_ids"`
}
func (p *Poll) IsRegular() bool {
return p.Type == PollRegular
}
func (p *Poll) IsQuiz() bool {
return p.Type == PollQuiz
}
func (p *Poll) CloseDate() time.Time {
return time.Unix(p.CloseUnixdate, 0)
}
func (p *Poll) AddOptions(opts ...string) {
for _, t := range opts {
p.Options = append(p.Options, PollOption{Text: t})
}
}

@ -0,0 +1,45 @@
package telebot
import (
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func TestPoll(t *testing.T) {
assert.True(t, (&Poll{Type: PollRegular}).IsRegular())
assert.True(t, (&Poll{Type: PollQuiz}).IsQuiz())
p := &Poll{}
opts := []PollOption{{Text: "Option 1"}, {Text: "Option 2"}}
p.AddOptions(opts[0].Text, opts[1].Text)
assert.Equal(t, opts, p.Options)
}
func TestPollSend(t *testing.T) {
p := &Poll{
Type: PollQuiz,
Question: "Test Poll",
CloseUnixdate: time.Now().Unix() + 60,
Explanation: "Explanation",
}
p.AddOptions("1", "2")
markup := &ReplyMarkup{
ReplyKeyboard: [][]ReplyButton{{{
Text: "Poll",
Poll: PollAny,
}}},
}
msg, err := b.Send(to, p, markup)
assert.NoError(t, err)
assert.Equal(t, p.Question, msg.Poll.Question)
assert.Equal(t, p.Options, msg.Poll.Options)
assert.Equal(t, p.CloseUnixdate, msg.Poll.CloseUnixdate)
assert.Equal(t, p.CloseDate(), msg.Poll.CloseDate())
_, err = b.Send(to, &Poll{}) // empty poll
assert.Equal(t, ErrBadPollOptions, err)
}

@ -317,15 +317,25 @@ func (i *Invoice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error)
return extractMessage(data)
}
// Send delivers poll through bot b to recipient.
func (p *Poll) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
params := map[string]string{
"chat_id": to.Recipient(),
"question": p.Question,
"type": p.Type,
"allows_multiple_answers": strconv.FormatBool(p.AllowsMultipleAnswers),
"correct_option_id": strconv.Itoa(p.CorrectOptionID),
"is_anonymous": strconv.FormatBool(p.IsAnonymous),
"is_closed": strconv.FormatBool(p.IsClosed),
"type": string(p.Type),
"is_closed": strconv.FormatBool(p.Closed),
"is_anonymous": strconv.FormatBool(p.Anonymous),
"allows_multiple_answers": strconv.FormatBool(p.MultipleAnswers),
"correct_option_id": strconv.Itoa(p.CorrectOption),
}
if p.Explanation != "" {
params["explanation"] = p.Explanation
params["explanation_parse_mode"] = p.ParseMode
}
if p.OpenPeriod != 0 {
params["open_period"] = strconv.Itoa(p.OpenPeriod)
} else if p.CloseUnixdate != 0 {
params["close_date"] = strconv.FormatInt(p.CloseUnixdate, 10)
}
embedSendOptions(params, opt)

@ -188,10 +188,13 @@ const (
)
// PollType defines poll types.
type PollType = string
type PollType string
const (
PollAny PollType = ""
// Despite "any" type isn't described in documentation,
// it needed for proper KeyboardButtonPollType marshaling.
PollAny PollType = "any"
PollQuiz PollType = "quiz"
PollRegular PollType = "regular"
)

Loading…
Cancel
Save