You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
4.8 KiB

package message
import (
"context"
"strconv"
"time"
"github.com/go-faster/errors"
"github.com/gotd/td/internal/crypto"
"github.com/gotd/td/telegram/message/entity"
"github.com/gotd/td/telegram/message/styling"
"github.com/gotd/td/tg"
)
type pollAnswerBuilder struct {
input *tg.InputMediaPoll
}
// PollAnswerOption is an option to create poll answer.
type PollAnswerOption func(p *pollAnswerBuilder)
// RawPollAnswer creates new raw poll answer option.
func RawPollAnswer(poll tg.PollAnswer) PollAnswerOption {
return func(p *pollAnswerBuilder) {
p.input.Poll.Answers = append(p.input.Poll.Answers, poll)
}
}
// PollAnswer creates new plain poll answer option.
func PollAnswer(text string) PollAnswerOption {
return func(p *pollAnswerBuilder) {
i := len(p.input.Poll.Answers)
p.input.Poll.Answers = append(p.input.Poll.Answers, tg.PollAnswer{
Text: text,
Option: []byte(text + strconv.Itoa(i)),
})
}
}
// CorrectPollAnswer creates new correct poll answer option.
func CorrectPollAnswer(text string) PollAnswerOption {
return func(p *pollAnswerBuilder) {
p.input.Poll.Quiz = true
i := len(p.input.Poll.Answers)
option := []byte(text + strconv.Itoa(i))
p.input.Poll.Answers = append(p.input.Poll.Answers, tg.PollAnswer{
Text: text,
Option: option,
})
p.input.CorrectAnswers = append(p.input.CorrectAnswers, option)
}
}
// PollBuilder is a Poll media option.
type PollBuilder struct {
input tg.InputMediaPoll
answers []PollAnswerOption
opts []StyledTextOption
}
// PollID return poll ID. If poll was not sent, will be zero.
// It useful to close polls.
func (p *PollBuilder) PollID() int64 {
return p.input.Poll.ID
}
// Close sets flag that the poll is closed and doesn't accept any more answers.
func (p *PollBuilder) Close() *PollBuilder {
p.input.Poll.Closed = true
return p
}
// PublicVoters sets flag that votes are publicly visible to all users (non-anonymous poll).
func (p *PollBuilder) PublicVoters(publicVoters bool) *PollBuilder {
p.input.Poll.PublicVoters = publicVoters
return p
}
// MultipleChoice sets flag that multiple options can be chosen as answer.
func (p *PollBuilder) MultipleChoice(multipleChoice bool) *PollBuilder {
p.input.Poll.MultipleChoice = multipleChoice
return p
}
// CloseDate sets point in time (Unix timestamp) when the poll will be automatically closed.
// Must be at least 5 and no more than 600 seconds in the future.
func (p *PollBuilder) CloseDate(d time.Time) *PollBuilder {
return p.CloseDateTS(int(d.Unix()))
}
// CloseDateTS sets point in time (Unix timestamp) when the poll will be automatically closed.
// Must be at least 5 and no more than 600 seconds in the future.
func (p *PollBuilder) CloseDateTS(ts int) *PollBuilder {
p.input.Poll.ClosePeriod = 0
p.input.Poll.CloseDate = ts
return p
}
// ClosePeriod sets amount of time in seconds the poll will be active after creation, 5-600 seconds.
func (p *PollBuilder) ClosePeriod(d time.Duration) *PollBuilder {
return p.ClosePeriodSeconds(int(d.Seconds()))
}
// ClosePeriodSeconds sets amount of time in seconds the poll will be active after creation, 5-600.
func (p *PollBuilder) ClosePeriodSeconds(s int) *PollBuilder {
p.input.Poll.ClosePeriod = s
p.input.Poll.CloseDate = 0
return p
}
// Explanation sets explanation message.
func (p *PollBuilder) Explanation(msg string) *PollBuilder {
p.input.Solution = msg
p.input.SolutionEntities = nil
return p
}
// StyledExplanation sets styled explanation message.
func (p *PollBuilder) StyledExplanation(texts ...StyledTextOption) *PollBuilder {
p.opts = texts
return p
}
func (p *PollBuilder) apply(ctx context.Context, b *multiMediaBuilder) error {
if p.input.Poll.ID == 0 {
id, err := crypto.RandInt64(b.sender.rand)
if err != nil {
return errors.Wrap(err, "generate id")
}
p.input.Poll.ID = id
}
if len(p.opts) > 0 {
tb := entity.Builder{}
if err := styling.Perform(&tb, p.opts...); err != nil {
return err
}
p.input.Solution, p.input.SolutionEntities = tb.Complete()
}
pb := pollAnswerBuilder{input: &p.input}
for _, opt := range p.answers {
opt(&pb)
}
return Media(&p.input).apply(ctx, b)
}
// Poll adds poll attachment.
func Poll(question string, a, b PollAnswerOption, answers ...PollAnswerOption) *PollBuilder {
return &PollBuilder{
input: tg.InputMediaPoll{
Poll: tg.Poll{
Question: question,
},
},
answers: append([]PollAnswerOption{a, b}, answers...),
}
}
// PollVote votes in a poll.
func (b *RequestBuilder) PollVote(
ctx context.Context, msgID int,
answer []byte, answers ...[]byte,
) (tg.UpdatesClass, error) {
p, err := b.peer(ctx)
if err != nil {
return nil, errors.Wrap(err, "peer")
}
upd, err := b.sender.sendVote(ctx, &tg.MessagesSendVoteRequest{
Peer: p,
MsgID: msgID,
Options: append([][]byte{answer}, answers...),
})
if err != nil {
return nil, errors.Wrap(err, "start bot")
}
return upd, nil
}