mirror of https://github.com/tucnak/telebot
telebot: restructure and refactor
parent
bd66ef87a9
commit
d90e8974cc
@ -0,0 +1,39 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestEmbedRights(t *testing.T) {
|
||||
rights := NoRestrictions()
|
||||
params := map[string]interface{}{
|
||||
"chat_id": "1",
|
||||
"user_id": "2",
|
||||
}
|
||||
embedRights(params, rights)
|
||||
|
||||
expected := map[string]interface{}{
|
||||
"is_anonymous": false,
|
||||
"chat_id": "1",
|
||||
"user_id": "2",
|
||||
"can_be_edited": true,
|
||||
"can_send_messages": true,
|
||||
"can_send_media_messages": true,
|
||||
"can_send_polls": true,
|
||||
"can_send_other_messages": true,
|
||||
"can_add_web_page_previews": true,
|
||||
"can_change_info": false,
|
||||
"can_post_messages": false,
|
||||
"can_edit_messages": false,
|
||||
"can_delete_messages": false,
|
||||
"can_invite_users": false,
|
||||
"can_restrict_members": false,
|
||||
"can_pin_messages": false,
|
||||
"can_promote_members": false,
|
||||
"can_manage_video_chats": false,
|
||||
"can_manage_chat": false,
|
||||
}
|
||||
assert.Equal(t, expected, params)
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
package telebot
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
// Command represents a bot command.
|
||||
type Command struct {
|
||||
// Text is a text of the command, 1-32 characters.
|
||||
// Can contain only lowercase English letters, digits and underscores.
|
||||
Text string `json:"command"`
|
||||
|
||||
// Description of the command, 3-256 characters.
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// CommandParams controls parameters for commands-related methods (setMyCommands, deleteMyCommands and getMyCommands).
|
||||
type CommandParams struct {
|
||||
Commands []Command `json:"commands,omitempty"`
|
||||
Scope *CommandScope `json:"scope,omitempty"`
|
||||
LanguageCode string `json:"language_code,omitempty"`
|
||||
}
|
||||
|
||||
type CommandScopeType = string
|
||||
|
||||
const (
|
||||
CommandScopeDefault CommandScopeType = "default"
|
||||
CommandScopeAllPrivateChats CommandScopeType = "all_private_chats"
|
||||
CommandScopeAllGroupChats CommandScopeType = "all_group_chats"
|
||||
CommandScopeAllChatAdmin CommandScopeType = "all_chat_administrators"
|
||||
CommandScopeChat CommandScopeType = "chat"
|
||||
CommandScopeChatAdmin CommandScopeType = "chat_administrators"
|
||||
CommandScopeChatMember CommandScopeType = "chat_member"
|
||||
)
|
||||
|
||||
// CommandScope object represents a scope to which bot commands are applied.
|
||||
type CommandScope struct {
|
||||
Type CommandScopeType `json:"type"`
|
||||
ChatID int64 `json:"chat_id,omitempty"`
|
||||
UserID int64 `json:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
// Commands returns the current list of the bot's commands for the given scope and user language.
|
||||
func (b *Bot) Commands(opts ...interface{}) ([]Command, error) {
|
||||
params := extractCommandsParams(opts...)
|
||||
data, err := b.Raw("getMyCommands", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
Result []Command
|
||||
}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, wrapError(err)
|
||||
}
|
||||
return resp.Result, nil
|
||||
}
|
||||
|
||||
// SetCommands changes the list of the bot's commands.
|
||||
func (b *Bot) SetCommands(opts ...interface{}) error {
|
||||
params := extractCommandsParams(opts...)
|
||||
_, err := b.Raw("setMyCommands", params)
|
||||
return err
|
||||
}
|
||||
|
||||
// DeleteCommands deletes the list of the bot's commands for the given scope and user language.
|
||||
func (b *Bot) DeleteCommands(opts ...interface{}) error {
|
||||
params := extractCommandsParams(opts...)
|
||||
_, err := b.Raw("deleteMyCommands", params)
|
||||
return err
|
||||
}
|
||||
|
||||
// extractCommandsParams extracts parameters for commands-related methods from the given options.
|
||||
func extractCommandsParams(opts ...interface{}) (params CommandParams) {
|
||||
for _, opt := range opts {
|
||||
switch value := opt.(type) {
|
||||
case []Command:
|
||||
params.Commands = value
|
||||
case string:
|
||||
params.LanguageCode = value
|
||||
case CommandScope:
|
||||
params.Scope = &value
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,346 @@
|
||||
package telebot
|
||||
|
||||
import "strings"
|
||||
|
||||
// Update object represents an incoming update.
|
||||
type Update struct {
|
||||
ID int `json:"update_id"`
|
||||
|
||||
Message *Message `json:"message,omitempty"`
|
||||
EditedMessage *Message `json:"edited_message,omitempty"`
|
||||
ChannelPost *Message `json:"channel_post,omitempty"`
|
||||
EditedChannelPost *Message `json:"edited_channel_post,omitempty"`
|
||||
Callback *Callback `json:"callback_query,omitempty"`
|
||||
Query *Query `json:"inline_query,omitempty"`
|
||||
InlineResult *InlineResult `json:"chosen_inline_result,omitempty"`
|
||||
ShippingQuery *ShippingQuery `json:"shipping_query,omitempty"`
|
||||
PreCheckoutQuery *PreCheckoutQuery `json:"pre_checkout_query,omitempty"`
|
||||
Poll *Poll `json:"poll,omitempty"`
|
||||
PollAnswer *PollAnswer `json:"poll_answer,omitempty"`
|
||||
MyChatMember *ChatMemberUpdate `json:"my_chat_member,omitempty"`
|
||||
ChatMember *ChatMemberUpdate `json:"chat_member,omitempty"`
|
||||
ChatJoinRequest *ChatJoinRequest `json:"chat_join_request,omitempty"`
|
||||
}
|
||||
|
||||
// ProcessUpdate processes a single incoming update.
|
||||
// A started bot calls this function automatically.
|
||||
func (b *Bot) ProcessUpdate(u Update) {
|
||||
c := b.NewContext(u)
|
||||
|
||||
if u.Message != nil {
|
||||
m := u.Message
|
||||
|
||||
if m.PinnedMessage != nil {
|
||||
b.handle(OnPinned, c)
|
||||
return
|
||||
}
|
||||
|
||||
// Commands
|
||||
if m.Text != "" {
|
||||
// Filtering malicious messages
|
||||
if m.Text[0] == '\a' {
|
||||
return
|
||||
}
|
||||
|
||||
match := cmdRx.FindAllStringSubmatch(m.Text, -1)
|
||||
if match != nil {
|
||||
// Syntax: "</command>@<bot> <payload>"
|
||||
command, botName := match[0][1], match[0][3]
|
||||
|
||||
if botName != "" && !strings.EqualFold(b.Me.Username, botName) {
|
||||
return
|
||||
}
|
||||
|
||||
m.Payload = match[0][5]
|
||||
if b.handle(command, c) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 1:1 satisfaction
|
||||
if b.handle(m.Text, c) {
|
||||
return
|
||||
}
|
||||
|
||||
b.handle(OnText, c)
|
||||
return
|
||||
}
|
||||
|
||||
if b.handleMedia(c) {
|
||||
return
|
||||
}
|
||||
|
||||
if m.Contact != nil {
|
||||
b.handle(OnContact, c)
|
||||
return
|
||||
}
|
||||
if m.Location != nil {
|
||||
b.handle(OnLocation, c)
|
||||
return
|
||||
}
|
||||
if m.Venue != nil {
|
||||
b.handle(OnVenue, c)
|
||||
return
|
||||
}
|
||||
if m.Game != nil {
|
||||
b.handle(OnGame, c)
|
||||
return
|
||||
}
|
||||
if m.Dice != nil {
|
||||
b.handle(OnDice, c)
|
||||
return
|
||||
}
|
||||
if m.Invoice != nil {
|
||||
b.handle(OnInvoice, c)
|
||||
return
|
||||
}
|
||||
if m.Payment != nil {
|
||||
b.handle(OnPayment, c)
|
||||
return
|
||||
}
|
||||
|
||||
wasAdded := (m.UserJoined != nil && m.UserJoined.ID == b.Me.ID) ||
|
||||
(m.UsersJoined != nil && isUserInList(b.Me, m.UsersJoined))
|
||||
if m.GroupCreated || m.SuperGroupCreated || wasAdded {
|
||||
b.handle(OnAddedToGroup, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.UserJoined != nil {
|
||||
b.handle(OnUserJoined, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.UsersJoined != nil {
|
||||
for _, user := range m.UsersJoined {
|
||||
m.UserJoined = &user
|
||||
b.handle(OnUserJoined, c)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if m.UserLeft != nil {
|
||||
b.handle(OnUserLeft, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.NewGroupTitle != "" {
|
||||
b.handle(OnNewGroupTitle, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.NewGroupPhoto != nil {
|
||||
b.handle(OnNewGroupPhoto, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.GroupPhotoDeleted {
|
||||
b.handle(OnGroupPhotoDeleted, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.GroupCreated {
|
||||
b.handle(OnGroupCreated, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.SuperGroupCreated {
|
||||
b.handle(OnSuperGroupCreated, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.ChannelCreated {
|
||||
b.handle(OnChannelCreated, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.MigrateTo != 0 {
|
||||
m.MigrateFrom = m.Chat.ID
|
||||
b.handle(OnMigration, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.VideoChatStarted != nil {
|
||||
b.handle(OnVideoChatStarted, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.VideoChatEnded != nil {
|
||||
b.handle(OnVideoChatEnded, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.VideoChatParticipants != nil {
|
||||
b.handle(OnVideoChatParticipants, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.VideoChatScheduled != nil {
|
||||
b.handle(OnVideoChatScheduled, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.WebAppData != nil {
|
||||
b.handle(OnWebApp, c)
|
||||
}
|
||||
|
||||
if m.ProximityAlert != nil {
|
||||
b.handle(OnProximityAlert, c)
|
||||
return
|
||||
}
|
||||
|
||||
if m.AutoDeleteTimer != nil {
|
||||
b.handle(OnAutoDeleteTimer, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if u.EditedMessage != nil {
|
||||
b.handle(OnEdited, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.ChannelPost != nil {
|
||||
m := u.ChannelPost
|
||||
|
||||
if m.PinnedMessage != nil {
|
||||
b.handle(OnPinned, c)
|
||||
return
|
||||
}
|
||||
|
||||
b.handle(OnChannelPost, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.EditedChannelPost != nil {
|
||||
b.handle(OnEditedChannelPost, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.Callback != nil {
|
||||
if data := u.Callback.Data; data != "" && data[0] == '\f' {
|
||||
match := cbackRx.FindAllStringSubmatch(data, -1)
|
||||
if match != nil {
|
||||
unique, payload := match[0][1], match[0][3]
|
||||
if handler, ok := b.handlers["\f"+unique]; ok {
|
||||
u.Callback.Unique = unique
|
||||
u.Callback.Data = payload
|
||||
b.runHandler(handler, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
b.handle(OnCallback, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.Query != nil {
|
||||
b.handle(OnQuery, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.InlineResult != nil {
|
||||
b.handle(OnInlineResult, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.ShippingQuery != nil {
|
||||
b.handle(OnShipping, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.PreCheckoutQuery != nil {
|
||||
b.handle(OnCheckout, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.Poll != nil {
|
||||
b.handle(OnPoll, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.PollAnswer != nil {
|
||||
b.handle(OnPollAnswer, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.MyChatMember != nil {
|
||||
b.handle(OnMyChatMember, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.ChatMember != nil {
|
||||
b.handle(OnChatMember, c)
|
||||
return
|
||||
}
|
||||
|
||||
if u.ChatJoinRequest != nil {
|
||||
b.handle(OnChatJoinRequest, c)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) handle(end string, c Context) bool {
|
||||
if handler, ok := b.handlers[end]; ok {
|
||||
b.runHandler(handler, c)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (b *Bot) handleMedia(c Context) bool {
|
||||
var (
|
||||
m = c.Message()
|
||||
fired = true
|
||||
)
|
||||
|
||||
switch {
|
||||
case m.Photo != nil:
|
||||
fired = b.handle(OnPhoto, c)
|
||||
case m.Voice != nil:
|
||||
fired = b.handle(OnVoice, c)
|
||||
case m.Audio != nil:
|
||||
fired = b.handle(OnAudio, c)
|
||||
case m.Animation != nil:
|
||||
fired = b.handle(OnAnimation, c)
|
||||
case m.Document != nil:
|
||||
fired = b.handle(OnDocument, c)
|
||||
case m.Sticker != nil:
|
||||
fired = b.handle(OnSticker, c)
|
||||
case m.Video != nil:
|
||||
fired = b.handle(OnVideo, c)
|
||||
case m.VideoNote != nil:
|
||||
fired = b.handle(OnVideoNote, c)
|
||||
default:
|
||||
return false
|
||||
}
|
||||
|
||||
if !fired {
|
||||
return b.handle(OnMedia, c)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func (b *Bot) runHandler(h HandlerFunc, c Context) {
|
||||
f := func() {
|
||||
if err := h(c); err != nil {
|
||||
b.OnError(err, c)
|
||||
}
|
||||
}
|
||||
if b.synchronous {
|
||||
f()
|
||||
} else {
|
||||
go f()
|
||||
}
|
||||
}
|
||||
|
||||
func isUserInList(user *User, list []User) bool {
|
||||
for _, user2 := range list {
|
||||
if user.ID == user2.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
@ -1,306 +0,0 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
var defaultOnError = func(err error, c Context) {
|
||||
if c != nil {
|
||||
log.Println(c.Update().ID, err)
|
||||
} else {
|
||||
log.Println(err)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) debug(err error) {
|
||||
if b.verbose {
|
||||
b.OnError(err, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func verbose(method string, payload interface{}, data []byte) {
|
||||
body, _ := json.Marshal(payload)
|
||||
body = bytes.ReplaceAll(body, []byte(`\"`), []byte(`"`))
|
||||
body = bytes.ReplaceAll(body, []byte(`"{`), []byte(`{`))
|
||||
body = bytes.ReplaceAll(body, []byte(`}"`), []byte(`}`))
|
||||
|
||||
indent := func(b []byte) string {
|
||||
var buf bytes.Buffer
|
||||
json.Indent(&buf, b, "", " ")
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"[verbose] telebot: sent request\nMethod: %v\nParams: %v\nResponse: %v",
|
||||
method, indent(body), indent(data),
|
||||
)
|
||||
}
|
||||
|
||||
func (b *Bot) runHandler(h HandlerFunc, c Context) {
|
||||
f := func() {
|
||||
if err := h(c); err != nil {
|
||||
b.OnError(err, c)
|
||||
}
|
||||
}
|
||||
if b.synchronous {
|
||||
f()
|
||||
} else {
|
||||
go f()
|
||||
}
|
||||
}
|
||||
|
||||
func applyMiddleware(h HandlerFunc, m ...MiddlewareFunc) HandlerFunc {
|
||||
for i := len(m) - 1; i >= 0; i-- {
|
||||
h = m[i](h)
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
// wrapError returns new wrapped telebot-related error.
|
||||
func wrapError(err error) error {
|
||||
return fmt.Errorf("telebot: %w", err)
|
||||
}
|
||||
|
||||
// extractOk checks given result for error. If result is ok returns nil.
|
||||
// In other cases it extracts API error. If error is not presented
|
||||
// in errors.go, it will be prefixed with `unknown` keyword.
|
||||
func extractOk(data []byte) error {
|
||||
var e struct {
|
||||
Ok bool `json:"ok"`
|
||||
Code int `json:"error_code"`
|
||||
Description string `json:"description"`
|
||||
Parameters map[string]interface{} `json:"parameters"`
|
||||
}
|
||||
if json.NewDecoder(bytes.NewReader(data)).Decode(&e) != nil {
|
||||
return nil // FIXME
|
||||
}
|
||||
if e.Ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
err := Err(e.Description)
|
||||
switch err {
|
||||
case nil:
|
||||
case ErrGroupMigrated:
|
||||
migratedTo, ok := e.Parameters["migrate_to_chat_id"]
|
||||
if !ok {
|
||||
return NewError(e.Code, e.Description)
|
||||
}
|
||||
|
||||
return GroupError{
|
||||
err: err.(*Error),
|
||||
MigratedTo: int64(migratedTo.(float64)),
|
||||
}
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
switch e.Code {
|
||||
case http.StatusTooManyRequests:
|
||||
retryAfter, ok := e.Parameters["retry_after"]
|
||||
if !ok {
|
||||
return NewError(e.Code, e.Description)
|
||||
}
|
||||
|
||||
err = FloodError{
|
||||
err: NewError(e.Code, e.Description),
|
||||
RetryAfter: int(retryAfter.(float64)),
|
||||
}
|
||||
default:
|
||||
err = fmt.Errorf("telegram: %s (%d)", e.Description, e.Code)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// extractMessage extracts common Message result from given data.
|
||||
// Should be called after extractOk or b.Raw() to handle possible errors.
|
||||
func extractMessage(data []byte) (*Message, error) {
|
||||
var resp struct {
|
||||
Result *Message
|
||||
}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
var resp struct {
|
||||
Result bool
|
||||
}
|
||||
if err := json.Unmarshal(data, &resp); err != nil {
|
||||
return nil, wrapError(err)
|
||||
}
|
||||
if resp.Result {
|
||||
return nil, ErrTrueResult
|
||||
}
|
||||
return nil, wrapError(err)
|
||||
}
|
||||
return resp.Result, nil
|
||||
}
|
||||
|
||||
func extractOptions(how []interface{}) *SendOptions {
|
||||
opts := &SendOptions{}
|
||||
|
||||
for _, prop := range how {
|
||||
switch opt := prop.(type) {
|
||||
case *SendOptions:
|
||||
opts = opt.copy()
|
||||
case *ReplyMarkup:
|
||||
if opt != nil {
|
||||
opts.ReplyMarkup = opt.copy()
|
||||
}
|
||||
case Option:
|
||||
switch opt {
|
||||
case NoPreview:
|
||||
opts.DisableWebPagePreview = true
|
||||
case Silent:
|
||||
opts.DisableNotification = true
|
||||
case AllowWithoutReply:
|
||||
opts.AllowWithoutReply = true
|
||||
case ForceReply:
|
||||
if opts.ReplyMarkup == nil {
|
||||
opts.ReplyMarkup = &ReplyMarkup{}
|
||||
}
|
||||
opts.ReplyMarkup.ForceReply = true
|
||||
case OneTimeKeyboard:
|
||||
if opts.ReplyMarkup == nil {
|
||||
opts.ReplyMarkup = &ReplyMarkup{}
|
||||
}
|
||||
opts.ReplyMarkup.OneTimeKeyboard = true
|
||||
case RemoveKeyboard:
|
||||
if opts.ReplyMarkup == nil {
|
||||
opts.ReplyMarkup = &ReplyMarkup{}
|
||||
}
|
||||
opts.ReplyMarkup.RemoveKeyboard = true
|
||||
case Protected:
|
||||
opts.Protected = true
|
||||
default:
|
||||
panic("telebot: unsupported flag-option")
|
||||
}
|
||||
case ParseMode:
|
||||
opts.ParseMode = opt
|
||||
case Entities:
|
||||
opts.Entities = opt
|
||||
default:
|
||||
panic("telebot: unsupported send-option")
|
||||
}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
// extractCommandsParams extracts parameters for commands-related methods from the given options.
|
||||
func extractCommandsParams(opts ...interface{}) (params CommandParams) {
|
||||
for _, opt := range opts {
|
||||
switch value := opt.(type) {
|
||||
case []Command:
|
||||
params.Commands = value
|
||||
case string:
|
||||
params.LanguageCode = value
|
||||
case CommandScope:
|
||||
params.Scope = &value
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *Bot) embedSendOptions(params map[string]string, opt *SendOptions) {
|
||||
if b.parseMode != ModeDefault {
|
||||
params["parse_mode"] = b.parseMode
|
||||
}
|
||||
|
||||
if opt == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if opt.ReplyTo != nil && opt.ReplyTo.ID != 0 {
|
||||
params["reply_to_message_id"] = strconv.Itoa(opt.ReplyTo.ID)
|
||||
}
|
||||
|
||||
if opt.DisableWebPagePreview {
|
||||
params["disable_web_page_preview"] = "true"
|
||||
}
|
||||
|
||||
if opt.DisableNotification {
|
||||
params["disable_notification"] = "true"
|
||||
}
|
||||
|
||||
if opt.ParseMode != ModeDefault {
|
||||
params["parse_mode"] = opt.ParseMode
|
||||
}
|
||||
|
||||
if len(opt.Entities) > 0 {
|
||||
delete(params, "parse_mode")
|
||||
entities, _ := json.Marshal(opt.Entities)
|
||||
|
||||
if params["caption"] != "" {
|
||||
params["caption_entities"] = string(entities)
|
||||
} else {
|
||||
params["entities"] = string(entities)
|
||||
}
|
||||
}
|
||||
|
||||
if opt.AllowWithoutReply {
|
||||
params["allow_sending_without_reply"] = "true"
|
||||
}
|
||||
|
||||
if opt.ReplyMarkup != nil {
|
||||
processButtons(opt.ReplyMarkup.InlineKeyboard)
|
||||
replyMarkup, _ := json.Marshal(opt.ReplyMarkup)
|
||||
params["reply_markup"] = string(replyMarkup)
|
||||
}
|
||||
|
||||
if opt.Protected {
|
||||
params["protect_content"] = "true"
|
||||
}
|
||||
}
|
||||
|
||||
func processButtons(keys [][]InlineButton) {
|
||||
if keys == nil || len(keys) < 1 || len(keys[0]) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for i := range keys {
|
||||
for j := range keys[i] {
|
||||
key := &keys[i][j]
|
||||
if key.Unique != "" {
|
||||
// Format: "\f<callback_name>|<data>"
|
||||
data := key.Data
|
||||
if data == "" {
|
||||
key.Data = "\f" + key.Unique
|
||||
} else {
|
||||
key.Data = "\f" + key.Unique + "|" + data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func embedRights(p map[string]interface{}, rights Rights) {
|
||||
data, _ := json.Marshal(rights)
|
||||
_ = json.Unmarshal(data, &p)
|
||||
}
|
||||
|
||||
func thumbnailToFilemap(thumb *Photo) map[string]File {
|
||||
if thumb != nil {
|
||||
return map[string]File{"thumb": thumb.File}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isUserInList(user *User, list []User) bool {
|
||||
for _, user2 := range list {
|
||||
if user.ID == user2.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func intsToStrs(ns []int) (s []string) {
|
||||
for _, n := range ns {
|
||||
s = append(s, strconv.Itoa(n))
|
||||
}
|
||||
return
|
||||
}
|
@ -1,84 +0,0 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestExtractOk(t *testing.T) {
|
||||
data := []byte(`{"ok": true, "result": {}}`)
|
||||
require.NoError(t, extractOk(data))
|
||||
|
||||
data = []byte(`{
|
||||
"ok": false,
|
||||
"error_code": 400,
|
||||
"description": "Bad Request: reply message not found"
|
||||
}`)
|
||||
assert.EqualError(t, extractOk(data), ErrNotFoundToReply.Error())
|
||||
|
||||
data = []byte(`{
|
||||
"ok": false,
|
||||
"error_code": 429,
|
||||
"description": "Too Many Requests: retry after 8",
|
||||
"parameters": {"retry_after": 8}
|
||||
}`)
|
||||
assert.Equal(t, FloodError{
|
||||
err: NewError(429, "Too Many Requests: retry after 8"),
|
||||
RetryAfter: 8,
|
||||
}, extractOk(data))
|
||||
|
||||
data = []byte(`{
|
||||
"ok": false,
|
||||
"error_code": 400,
|
||||
"description": "Bad Request: group chat was upgraded to a supergroup chat",
|
||||
"parameters": {"migrate_to_chat_id": -100123456789}
|
||||
}`)
|
||||
assert.Equal(t, GroupError{
|
||||
err: ErrGroupMigrated,
|
||||
MigratedTo: -100123456789,
|
||||
}, extractOk(data))
|
||||
}
|
||||
|
||||
func TestExtractMessage(t *testing.T) {
|
||||
data := []byte(`{"ok":true,"result":true}`)
|
||||
_, err := extractMessage(data)
|
||||
assert.Equal(t, ErrTrueResult, err)
|
||||
|
||||
data = []byte(`{"ok":true,"result":{"foo":"bar"}}`)
|
||||
_, err = extractMessage(data)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestEmbedRights(t *testing.T) {
|
||||
rights := NoRestrictions()
|
||||
params := map[string]interface{}{
|
||||
"chat_id": "1",
|
||||
"user_id": "2",
|
||||
}
|
||||
embedRights(params, rights)
|
||||
|
||||
expected := map[string]interface{}{
|
||||
"is_anonymous": false,
|
||||
"chat_id": "1",
|
||||
"user_id": "2",
|
||||
"can_be_edited": true,
|
||||
"can_send_messages": true,
|
||||
"can_send_media_messages": true,
|
||||
"can_send_polls": true,
|
||||
"can_send_other_messages": true,
|
||||
"can_add_web_page_previews": true,
|
||||
"can_change_info": false,
|
||||
"can_post_messages": false,
|
||||
"can_edit_messages": false,
|
||||
"can_delete_messages": false,
|
||||
"can_invite_users": false,
|
||||
"can_restrict_members": false,
|
||||
"can_pin_messages": false,
|
||||
"can_promote_members": false,
|
||||
"can_manage_video_chats": false,
|
||||
"can_manage_chat": false,
|
||||
}
|
||||
assert.Equal(t, expected, params)
|
||||
}
|
Loading…
Reference in New Issue