Merge branch 'develop' into develop
commit
284b093107
|
@ -0,0 +1,33 @@
|
|||
name: Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: ^1.15
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build
|
||||
run: go build -v .
|
||||
|
||||
- name: Test
|
||||
run: go test -coverprofile=coverage.out -covermode=atomic -v .
|
||||
|
||||
- name: Upload coverage report
|
||||
uses: codecov/codecov-action@v1
|
||||
with:
|
||||
file: ./coverage.out
|
|
@ -1,6 +0,0 @@
|
|||
language: go
|
||||
|
||||
go:
|
||||
- '1.10'
|
||||
- '1.11'
|
||||
- tip
|
|
@ -3,7 +3,7 @@
|
|||
[![GoDoc](https://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api?status.svg)](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api)
|
||||
[![Travis](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api.svg)](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api)
|
||||
|
||||
All methods are fairly self explanatory, and reading the godoc page should
|
||||
All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should
|
||||
explain everything. If something isn't clear, open an issue or submit
|
||||
a pull request.
|
||||
|
||||
|
|
368
bot.go
368
bot.go
|
@ -9,15 +9,20 @@ import (
|
|||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/technoweenie/multipartstreamer"
|
||||
)
|
||||
|
||||
// HTTPClient is the type needed for the bot to perform HTTP requests.
|
||||
type HTTPClient interface {
|
||||
Do(req *http.Request) (*http.Response, error)
|
||||
PostForm(url string, data url.Values) (*http.Response, error)
|
||||
}
|
||||
|
||||
// BotAPI allows you to interact with the Telegram Bot API.
|
||||
type BotAPI struct {
|
||||
Token string `json:"token"`
|
||||
|
@ -25,27 +30,39 @@ type BotAPI struct {
|
|||
Buffer int `json:"buffer"`
|
||||
|
||||
Self User `json:"-"`
|
||||
Client *http.Client `json:"-"`
|
||||
Client HTTPClient `json:"-"`
|
||||
shutdownChannel chan interface{}
|
||||
|
||||
apiEndpoint string
|
||||
}
|
||||
|
||||
// NewBotAPI creates a new BotAPI instance.
|
||||
//
|
||||
// It requires a token, provided by @BotFather on Telegram.
|
||||
func NewBotAPI(token string) (*BotAPI, error) {
|
||||
return NewBotAPIWithClient(token, &http.Client{})
|
||||
return NewBotAPIWithClient(token, APIEndpoint, &http.Client{})
|
||||
}
|
||||
|
||||
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
|
||||
// and allows you to pass API endpoint.
|
||||
//
|
||||
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) {
|
||||
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{})
|
||||
}
|
||||
|
||||
// NewBotAPIWithClient creates a new BotAPI instance
|
||||
// and allows you to pass a http.Client.
|
||||
//
|
||||
// It requires a token, provided by @BotFather on Telegram.
|
||||
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
||||
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) {
|
||||
bot := &BotAPI{
|
||||
Token: token,
|
||||
Client: client,
|
||||
Buffer: 100,
|
||||
shutdownChannel: make(chan interface{}),
|
||||
|
||||
apiEndpoint: apiEndpoint,
|
||||
}
|
||||
|
||||
self, err := bot.GetMe()
|
||||
|
@ -58,6 +75,11 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
|||
return bot, nil
|
||||
}
|
||||
|
||||
// SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance.
|
||||
func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) {
|
||||
bot.apiEndpoint = apiEndpoint
|
||||
}
|
||||
|
||||
func buildParams(in Params) (out url.Values) {
|
||||
if in == nil {
|
||||
return url.Values{}
|
||||
|
@ -73,25 +95,25 @@ func buildParams(in Params) (out url.Values) {
|
|||
}
|
||||
|
||||
// MakeRequest makes a request to a specific endpoint with our token.
|
||||
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (APIResponse, error) {
|
||||
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) {
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, params: %v\n", endpoint, params)
|
||||
}
|
||||
|
||||
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint)
|
||||
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||
|
||||
values := buildParams(params)
|
||||
|
||||
resp, err := bot.Client.PostForm(method, values)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
var apiResp APIResponse
|
||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||
if err != nil {
|
||||
return apiResp, err
|
||||
return &apiResp, err
|
||||
}
|
||||
|
||||
if bot.Debug {
|
||||
|
@ -105,13 +127,14 @@ func (bot *BotAPI) MakeRequest(endpoint string, params Params) (APIResponse, err
|
|||
parameters = *apiResp.Parameters
|
||||
}
|
||||
|
||||
return apiResp, Error{
|
||||
return &apiResp, &Error{
|
||||
Code: apiResp.ErrorCode,
|
||||
Message: apiResp.Description,
|
||||
ResponseParameters: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
return apiResp, nil
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
||||
|
@ -138,103 +161,120 @@ func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse)
|
|||
return data, nil
|
||||
}
|
||||
|
||||
// UploadFile makes a request to the API with a file.
|
||||
//
|
||||
// Requires the parameter to hold the file not be in the params.
|
||||
// File should be a string to a file path, a FileBytes struct,
|
||||
// a FileReader struct, or a url.URL.
|
||||
//
|
||||
// Note that if your FileReader has a size set to -1, it will read
|
||||
// the file into memory to calculate a size.
|
||||
func (bot *BotAPI) UploadFile(endpoint string, params Params, fieldname string, file interface{}) (APIResponse, error) {
|
||||
ms := multipartstreamer.New()
|
||||
// UploadFiles makes a request to the API with files.
|
||||
func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) {
|
||||
r, w := io.Pipe()
|
||||
m := multipart.NewWriter(w)
|
||||
|
||||
switch f := file.(type) {
|
||||
// This code modified from the very helpful @HirbodBehnam
|
||||
// https://github.com/go-telegram-bot-api/telegram-bot-api/issues/354#issuecomment-663856473
|
||||
go func() {
|
||||
defer w.Close()
|
||||
defer m.Close()
|
||||
|
||||
for field, value := range params {
|
||||
if err := m.WriteField(field, value); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range files {
|
||||
switch f := file.File.(type) {
|
||||
case string:
|
||||
ms.WriteFields(params)
|
||||
|
||||
fileHandle, err := os.Open(f)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
defer fileHandle.Close()
|
||||
|
||||
fi, err := os.Stat(f)
|
||||
part, err := m.CreateFormFile(file.Name, fileHandle.Name())
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle)
|
||||
io.Copy(part, fileHandle)
|
||||
case FileBytes:
|
||||
ms.WriteFields(params)
|
||||
part, err := m.CreateFormFile(file.Name, f.Name)
|
||||
if err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(f.Bytes)
|
||||
ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf)
|
||||
io.Copy(part, buf)
|
||||
case FileReader:
|
||||
ms.WriteFields(params)
|
||||
|
||||
if f.Size != -1 {
|
||||
ms.WriteReader(fieldname, f.Name, f.Size, f.Reader)
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(f.Reader)
|
||||
part, err := m.CreateFormFile(file.Name, f.Name)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
|
||||
buf := bytes.NewBuffer(data)
|
||||
|
||||
ms.WriteReader(fieldname, f.Name, int64(len(data)), buf)
|
||||
case url.URL:
|
||||
params[fieldname] = f.String()
|
||||
|
||||
ms.WriteFields(params)
|
||||
io.Copy(part, f.Reader)
|
||||
case FileURL:
|
||||
val := string(f)
|
||||
if err := m.WriteField(file.Name, val); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
case FileID:
|
||||
val := string(f)
|
||||
if err := m.WriteField(file.Name, val); err != nil {
|
||||
w.CloseWithError(err)
|
||||
return
|
||||
}
|
||||
default:
|
||||
return APIResponse{}, errors.New(ErrBadFileType)
|
||||
w.CloseWithError(errors.New(ErrBadFileType))
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, fieldname: %s, params: %v, file: %T\n", endpoint, fieldname, params, file)
|
||||
log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files))
|
||||
}
|
||||
|
||||
method := fmt.Sprintf(APIEndpoint, bot.Token, endpoint)
|
||||
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint)
|
||||
|
||||
req, err := http.NewRequest("POST", method, nil)
|
||||
req, err := http.NewRequest("POST", method, r)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ms.SetupRequest(req)
|
||||
req.Header.Set("Content-Type", m.FormDataContentType())
|
||||
|
||||
res, err := bot.Client.Do(req)
|
||||
resp, err := bot.Client.Do(req)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
defer res.Body.Close()
|
||||
defer resp.Body.Close()
|
||||
|
||||
bytes, err := ioutil.ReadAll(res.Body)
|
||||
var apiResp APIResponse
|
||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return &apiResp, err
|
||||
}
|
||||
|
||||
if bot.Debug {
|
||||
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
|
||||
}
|
||||
|
||||
var apiResp APIResponse
|
||||
|
||||
err = json.Unmarshal(bytes, &apiResp)
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
}
|
||||
|
||||
if !apiResp.Ok {
|
||||
return APIResponse{}, errors.New(apiResp.Description)
|
||||
var parameters ResponseParameters
|
||||
|
||||
if apiResp.Parameters != nil {
|
||||
parameters = *apiResp.Parameters
|
||||
}
|
||||
|
||||
return apiResp, nil
|
||||
return &apiResp, &Error{
|
||||
Message: apiResp.Description,
|
||||
ResponseParameters: parameters,
|
||||
}
|
||||
}
|
||||
|
||||
return &apiResp, nil
|
||||
}
|
||||
|
||||
// GetFileDirectURL returns direct URL to file
|
||||
|
@ -274,23 +314,54 @@ func (bot *BotAPI) IsMessageToMe(message Message) bool {
|
|||
return strings.Contains(message.Text, "@"+bot.Self.UserName)
|
||||
}
|
||||
|
||||
func hasFilesNeedingUpload(files []RequestFile) bool {
|
||||
for _, file := range files {
|
||||
switch file.File.(type) {
|
||||
case string, FileBytes, FileReader:
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
// Request sends a Chattable to Telegram, and returns the APIResponse.
|
||||
func (bot *BotAPI) Request(c Chattable) (APIResponse, error) {
|
||||
func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) {
|
||||
params, err := c.params()
|
||||
if err != nil {
|
||||
return APIResponse{}, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch t := c.(type) {
|
||||
case Fileable:
|
||||
if t.useExistingFile() {
|
||||
return bot.MakeRequest(t.method(), params)
|
||||
if t, ok := c.(Fileable); ok {
|
||||
files := t.files()
|
||||
|
||||
// If we have files that need to be uploaded, we should delegate the
|
||||
// request to UploadFile.
|
||||
if hasFilesNeedingUpload(files) {
|
||||
return bot.UploadFiles(t.method(), params, files)
|
||||
}
|
||||
|
||||
return bot.UploadFile(t.method(), params, t.name(), t.getFile())
|
||||
// However, if there are no files to be uploaded, there's likely things
|
||||
// that need to be turned into params instead.
|
||||
for _, file := range files {
|
||||
var s string
|
||||
|
||||
switch f := file.File.(type) {
|
||||
case string:
|
||||
s = f
|
||||
case FileID:
|
||||
s = string(f)
|
||||
case FileURL:
|
||||
s = string(f)
|
||||
default:
|
||||
return bot.MakeRequest(c.method(), params)
|
||||
return nil, errors.New(ErrBadFileType)
|
||||
}
|
||||
|
||||
params[file.Name] = s
|
||||
}
|
||||
}
|
||||
|
||||
return bot.MakeRequest(c.method(), params)
|
||||
}
|
||||
|
||||
// Send will send a Chattable item to Telegram and provides the
|
||||
|
@ -309,9 +380,7 @@ func (bot *BotAPI) Send(c Chattable) (Message, error) {
|
|||
|
||||
// SendMediaGroup sends a media group and returns the resulting messages.
|
||||
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -327,9 +396,7 @@ func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
|||
// It requires UserID.
|
||||
// Offset and Limit are optional.
|
||||
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return UserProfilePhotos{}, err
|
||||
}
|
||||
|
@ -344,9 +411,7 @@ func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
|
|||
//
|
||||
// Requires FileID.
|
||||
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return File{}, err
|
||||
}
|
||||
|
@ -360,14 +425,12 @@ func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
|||
// GetUpdates fetches updates.
|
||||
// If a WebHook is set, this will not return any data!
|
||||
//
|
||||
// Offset, Limit, and Timeout are optional.
|
||||
// Offset, Limit, Timeout, and AllowedUpdates are optional.
|
||||
// To avoid stale items, set Offset to one higher than the previous item.
|
||||
// Set Timeout to a large number to reduce requests so you can get updates
|
||||
// instantly instead of having to wait between requests.
|
||||
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []Update{}, err
|
||||
}
|
||||
|
@ -400,6 +463,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
|
|||
for {
|
||||
select {
|
||||
case <-bot.shutdownChannel:
|
||||
close(ch)
|
||||
return
|
||||
default:
|
||||
}
|
||||
|
@ -438,22 +502,66 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
|||
ch := make(chan Update, bot.Buffer)
|
||||
|
||||
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
||||
bytes, _ := ioutil.ReadAll(r.Body)
|
||||
update, err := bot.HandleUpdate(r)
|
||||
if err != nil {
|
||||
errMsg, _ := json.Marshal(map[string]string{"error": err.Error()})
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write(errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
var update Update
|
||||
json.Unmarshal(bytes, &update)
|
||||
|
||||
ch <- update
|
||||
ch <- *update
|
||||
})
|
||||
|
||||
return ch
|
||||
}
|
||||
|
||||
// HandleUpdate parses and returns update received via webhook
|
||||
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) {
|
||||
if r.Method != http.MethodPost {
|
||||
err := errors.New("wrong HTTP method required POST")
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var update Update
|
||||
err := json.NewDecoder(r.Body).Decode(&update)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &update, nil
|
||||
}
|
||||
|
||||
// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
|
||||
//
|
||||
// It doesn't support uploading files.
|
||||
//
|
||||
// See https://core.telegram.org/bots/api#making-requests-when-getting-updates
|
||||
// for details.
|
||||
func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error {
|
||||
params, err := c.params()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t, ok := c.(Fileable); ok {
|
||||
if hasFilesNeedingUpload(t.files()) {
|
||||
return errors.New("unable to use http response to upload files")
|
||||
}
|
||||
}
|
||||
|
||||
values := buildParams(params)
|
||||
values.Set("method", c.method())
|
||||
|
||||
w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
|
||||
_, err = w.Write([]byte(values.Encode()))
|
||||
return err
|
||||
}
|
||||
|
||||
// GetChat gets information about a chat.
|
||||
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return Chat{}, err
|
||||
}
|
||||
|
@ -469,9 +577,7 @@ func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
|||
// If none have been appointed, only the creator will be returned.
|
||||
// Bots are not shown, even if they are an administrator.
|
||||
func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []ChatMember{}, err
|
||||
}
|
||||
|
@ -484,9 +590,7 @@ func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]Cha
|
|||
|
||||
// GetChatMembersCount gets the number of users in a chat.
|
||||
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
@ -499,9 +603,7 @@ func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error
|
|||
|
||||
// GetChatMember gets a specific chat member.
|
||||
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return ChatMember{}, err
|
||||
}
|
||||
|
@ -514,9 +616,7 @@ func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error)
|
|||
|
||||
// GetGameHighScores allows you to get the high scores for a game.
|
||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return []GameHighScore{}, err
|
||||
}
|
||||
|
@ -529,9 +629,7 @@ func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHigh
|
|||
|
||||
// GetInviteLink get InviteLink for a chat
|
||||
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -544,9 +642,7 @@ func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
|||
|
||||
// GetStickerSet returns a StickerSet.
|
||||
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
||||
params, _ := config.params()
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return StickerSet{}, err
|
||||
}
|
||||
|
@ -559,12 +655,7 @@ func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error)
|
|||
|
||||
// StopPoll stops a poll and returns the result.
|
||||
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
||||
params, err := config.params()
|
||||
if err != nil {
|
||||
return Poll{}, err
|
||||
}
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return Poll{}, err
|
||||
}
|
||||
|
@ -574,3 +665,38 @@ func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
|||
|
||||
return poll, err
|
||||
}
|
||||
|
||||
// GetMyCommands gets the currently registered commands.
|
||||
func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) {
|
||||
config := GetMyCommandsConfig{}
|
||||
|
||||
resp, err := bot.Request(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var commands []BotCommand
|
||||
err = json.Unmarshal(resp.Result, &commands)
|
||||
|
||||
return commands, err
|
||||
}
|
||||
|
||||
// CopyMessage copy messages of any kind. The method is analogous to the method
|
||||
// forwardMessage, but the copied message doesn't have a link to the original
|
||||
// message. Returns the MessageID of the sent message on success.
|
||||
func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) {
|
||||
params, err := config.params()
|
||||
if err != nil {
|
||||
return MessageID{}, err
|
||||
}
|
||||
|
||||
resp, err := bot.MakeRequest(config.method(), params)
|
||||
if err != nil {
|
||||
return MessageID{}, err
|
||||
}
|
||||
|
||||
var messageID MessageID
|
||||
err = json.Unmarshal(resp.Result, &messageID)
|
||||
|
||||
return messageID, err
|
||||
}
|
||||
|
|
463
bot_test.go
463
bot_test.go
|
@ -11,6 +11,7 @@ import (
|
|||
const (
|
||||
TestToken = "153667468:AAHlSHlMqSt1f_uFmVRJbm5gntu2HI4WW8I"
|
||||
ChatID = 76918703
|
||||
Channel = "@tgbotapitest"
|
||||
SupergroupChatID = -1001120141283
|
||||
ReplyToMessageID = 35
|
||||
ExistingPhotoFileID = "AgADAgADw6cxG4zHKAkr42N7RwEN3IFShCoABHQwXEtVks4EH2wBAAEC"
|
||||
|
@ -22,13 +23,27 @@ const (
|
|||
ExistingStickerFileID = "BQADAgADcwADjMcoCbdl-6eB--YPAg"
|
||||
)
|
||||
|
||||
type testLogger struct {
|
||||
t *testing.T
|
||||
}
|
||||
|
||||
func (t testLogger) Println(v ...interface{}) {
|
||||
t.t.Log(v...)
|
||||
}
|
||||
|
||||
func (t testLogger) Printf(format string, v ...interface{}) {
|
||||
t.t.Logf(format, v...)
|
||||
}
|
||||
|
||||
func getBot(t *testing.T) (*BotAPI, error) {
|
||||
bot, err := NewBotAPI(TestToken)
|
||||
bot.Debug = true
|
||||
|
||||
logger := testLogger{t}
|
||||
SetLogger(logger)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
return bot, err
|
||||
|
@ -39,7 +54,6 @@ func TestNewBotAPI_notoken(t *testing.T) {
|
|||
|
||||
if err == nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,7 +66,6 @@ func TestGetUpdates(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,12 +73,11 @@ func TestSendWithMessage(t *testing.T) {
|
|||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
||||
msg.ParseMode = "markdown"
|
||||
msg.ParseMode = ModeMarkdown
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,7 +90,6 @@ func TestSendWithMessageReply(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -90,20 +101,38 @@ func TestSendWithMessageForward(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyMessage(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
||||
message, err := bot.Send(msg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
copyMessageConfig := NewCopyMessage(SupergroupChatID, message.Chat.ID, message.MessageID)
|
||||
messageID, err := bot.CopyMessage(copyMessageConfig)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if messageID.MessageID == message.MessageID {
|
||||
t.Error("copied message ID was the same as original message")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewPhoto(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewPhoto(ChatID, "tests/image.jpg")
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,13 +142,12 @@ func TestSendWithNewPhotoWithFileBytes(t *testing.T) {
|
|||
data, _ := ioutil.ReadFile("tests/image.jpg")
|
||||
b := FileBytes{Name: "image.jpg", Bytes: data}
|
||||
|
||||
msg := NewPhotoUpload(ChatID, b)
|
||||
msg := NewPhoto(ChatID, b)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -127,9 +155,34 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
|
|||
bot, _ := getBot(t)
|
||||
|
||||
f, _ := os.Open("tests/image.jpg")
|
||||
reader := FileReader{Name: "image.jpg", Reader: f, Size: -1}
|
||||
reader := FileReader{Name: "image.jpg", Reader: f}
|
||||
|
||||
msg := NewPhotoUpload(ChatID, reader)
|
||||
msg := NewPhoto(ChatID, reader)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewPhotoReply(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhoto(ChatID, "tests/image.jpg")
|
||||
msg.ReplyToMessageID = ReplyToMessageID
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendNewPhotoToChannel(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoToChannel(Channel, "tests/image.jpg")
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
|
@ -139,12 +192,30 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewPhotoReply(t *testing.T) {
|
||||
func TestSendNewPhotoToChannelFileBytes(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoUpload(ChatID, "tests/image.jpg")
|
||||
msg.ReplyToMessageID = ReplyToMessageID
|
||||
data, _ := ioutil.ReadFile("tests/image.jpg")
|
||||
b := FileBytes{Name: "image.jpg", Bytes: data}
|
||||
|
||||
msg := NewPhotoToChannel(Channel, b)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendNewPhotoToChannelFileReader(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
f, _ := os.Open("tests/image.jpg")
|
||||
reader := FileReader{Name: "image.jpg", Reader: f}
|
||||
|
||||
msg := NewPhotoToChannel(Channel, reader)
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
|
@ -156,61 +227,67 @@ func TestSendWithNewPhotoReply(t *testing.T) {
|
|||
func TestSendWithExistingPhoto(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhotoShare(ChatID, ExistingPhotoFileID)
|
||||
msg := NewPhoto(ChatID, FileID(ExistingPhotoFileID))
|
||||
msg.Caption = "Test"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewDocument(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDocumentUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewDocument(ChatID, "tests/image.jpg")
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewDocumentAndThumb(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDocument(ChatID, "tests/voice.ogg")
|
||||
msg.Thumb = "tests/image.jpg"
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingDocument(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDocumentShare(ChatID, ExistingDocumentFileID)
|
||||
msg := NewDocument(ChatID, FileID(ExistingDocumentFileID))
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewAudio(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewAudioUpload(ChatID, "tests/audio.mp3")
|
||||
msg := NewAudio(ChatID, "tests/audio.mp3")
|
||||
msg.Title = "TEST"
|
||||
msg.Duration = 10
|
||||
msg.Performer = "TEST"
|
||||
msg.MimeType = "audio/mpeg"
|
||||
msg.FileSize = 688
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingAudio(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewAudioShare(ChatID, ExistingAudioFileID)
|
||||
msg := NewAudio(ChatID, FileID(ExistingAudioFileID))
|
||||
msg.Title = "TEST"
|
||||
msg.Duration = 10
|
||||
msg.Performer = "TEST"
|
||||
|
@ -219,33 +296,30 @@ func TestSendWithExistingAudio(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewVoice(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVoiceUpload(ChatID, "tests/voice.ogg")
|
||||
msg := NewVoice(ChatID, "tests/voice.ogg")
|
||||
msg.Duration = 10
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingVoice(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVoiceShare(ChatID, ExistingVoiceFileID)
|
||||
msg := NewVoice(ChatID, FileID(ExistingVoiceFileID))
|
||||
msg.Duration = 10
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -256,7 +330,6 @@ func TestSendWithContact(t *testing.T) {
|
|||
|
||||
if _, err := bot.Send(contact); err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -267,7 +340,6 @@ func TestSendWithLocation(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -278,14 +350,13 @@ func TestSendWithVenue(t *testing.T) {
|
|||
|
||||
if _, err := bot.Send(venue); err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewVideo(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoUpload(ChatID, "tests/video.mp4")
|
||||
msg := NewVideo(ChatID, "tests/video.mp4")
|
||||
msg.Duration = 10
|
||||
msg.Caption = "TEST"
|
||||
|
||||
|
@ -293,14 +364,13 @@ func TestSendWithNewVideo(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingVideo(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoShare(ChatID, ExistingVideoFileID)
|
||||
msg := NewVideo(ChatID, FileID(ExistingVideoFileID))
|
||||
msg.Duration = 10
|
||||
msg.Caption = "TEST"
|
||||
|
||||
|
@ -308,68 +378,63 @@ func TestSendWithExistingVideo(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewVideoNote(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoNoteUpload(ChatID, 240, "tests/videonote.mp4")
|
||||
msg := NewVideoNote(ChatID, 240, "tests/videonote.mp4")
|
||||
msg.Duration = 10
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingVideoNote(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewVideoNoteShare(ChatID, 240, ExistingVideoNoteFileID)
|
||||
msg := NewVideoNote(ChatID, 240, FileID(ExistingVideoNoteFileID))
|
||||
msg.Duration = 10
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewSticker(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewSticker(ChatID, "tests/image.jpg")
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingSticker(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerShare(ChatID, ExistingStickerFileID)
|
||||
msg := NewSticker(ChatID, FileID(ExistingStickerFileID))
|
||||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerUpload(ChatID, "tests/image.jpg")
|
||||
msg := NewSticker(ChatID, "tests/image.jpg")
|
||||
msg.ReplyMarkup = ReplyKeyboardRemove{
|
||||
RemoveKeyboard: true,
|
||||
Selective: false,
|
||||
|
@ -378,14 +443,13 @@ func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewStickerShare(ChatID, ExistingStickerFileID)
|
||||
msg := NewSticker(ChatID, FileID(ExistingStickerFileID))
|
||||
msg.ReplyMarkup = ReplyKeyboardRemove{
|
||||
RemoveKeyboard: true,
|
||||
Selective: false,
|
||||
|
@ -393,10 +457,35 @@ func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
|||
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithDice(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDice(ChatID)
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSendWithDiceWithEmoji(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewDiceWithEmoji(ChatID, "🏀")
|
||||
_, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestGetFile(t *testing.T) {
|
||||
|
@ -410,7 +499,6 @@ func TestGetFile(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -421,7 +509,6 @@ func TestSendChatConfig(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -431,7 +518,6 @@ func TestSendEditMessage(t *testing.T) {
|
|||
msg, err := bot.Send(NewMessage(ChatID, "Testing editing."))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
edit := EditMessageTextConfig{
|
||||
|
@ -445,7 +531,6 @@ func TestSendEditMessage(t *testing.T) {
|
|||
_, err = bot.Send(edit)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,7 +540,6 @@ func TestGetUserProfilePhotos(t *testing.T) {
|
|||
_, err := bot.GetUserProfilePhotos(NewUserProfilePhotos(ChatID))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,13 +548,17 @@ func TestSetWebhookWithCert(t *testing.T) {
|
|||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
bot.Request(RemoveWebhookConfig{})
|
||||
bot.Request(DeleteWebhookConfig{})
|
||||
|
||||
wh, err := NewWebhookWithCert("https://example.com/tgbotapi-test/"+bot.Token, "tests/cert.pem")
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
_, err = bot.Request(wh)
|
||||
|
||||
wh := NewWebhookWithCert("https://example.com/tgbotapi-test/"+bot.Token, "tests/cert.pem")
|
||||
_, err := bot.Request(wh)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
_, err = bot.GetWebhookInfo()
|
||||
|
@ -479,7 +567,7 @@ func TestSetWebhookWithCert(t *testing.T) {
|
|||
t.Error(err)
|
||||
}
|
||||
|
||||
bot.Request(RemoveWebhookConfig{})
|
||||
bot.Request(DeleteWebhookConfig{})
|
||||
}
|
||||
|
||||
func TestSetWebhookWithoutCert(t *testing.T) {
|
||||
|
@ -487,13 +575,18 @@ func TestSetWebhookWithoutCert(t *testing.T) {
|
|||
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
bot.Request(RemoveWebhookConfig{})
|
||||
bot.Request(DeleteWebhookConfig{})
|
||||
|
||||
wh, err := NewWebhook("https://example.com/tgbotapi-test/" + bot.Token)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
_, err = bot.Request(wh)
|
||||
|
||||
wh := NewWebhook("https://example.com/tgbotapi-test/" + bot.Token)
|
||||
_, err := bot.Request(wh)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
info, err := bot.GetWebhookInfo()
|
||||
|
@ -501,21 +594,23 @@ func TestSetWebhookWithoutCert(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if info.MaxConnections == 0 {
|
||||
t.Errorf("Expected maximum connections to be greater than 0")
|
||||
}
|
||||
if info.LastErrorDate != 0 {
|
||||
t.Errorf("failed to set webhook: %s", info.LastErrorMessage)
|
||||
}
|
||||
|
||||
bot.Request(RemoveWebhookConfig{})
|
||||
bot.Request(DeleteWebhookConfig{})
|
||||
}
|
||||
|
||||
func TestSendWithMediaGroup(t *testing.T) {
|
||||
func TestSendWithMediaGroupPhotoVideo(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
cfg := NewMediaGroup(ChatID, []interface{}{
|
||||
NewInputMediaPhoto("https://i.imgur.com/unQLJIb.jpg"),
|
||||
NewInputMediaPhoto("https://i.imgur.com/J5qweNZ.jpg"),
|
||||
NewInputMediaVideo("https://i.imgur.com/F6RmI24.mp4"),
|
||||
NewInputMediaPhoto(FileURL("https://github.com/go-telegram-bot-api/telegram-bot-api/raw/0a3a1c8716c4cd8d26a262af9f12dcbab7f3f28c/tests/image.jpg")),
|
||||
NewInputMediaPhoto("tests/image.jpg"),
|
||||
NewInputMediaVideo("tests/video.mp4"),
|
||||
})
|
||||
|
||||
messages, err := bot.SendMediaGroup(cfg)
|
||||
|
@ -524,11 +619,55 @@ func TestSendWithMediaGroup(t *testing.T) {
|
|||
}
|
||||
|
||||
if messages == nil {
|
||||
t.Error()
|
||||
t.Error("No received messages")
|
||||
}
|
||||
|
||||
if len(messages) != 3 {
|
||||
t.Error()
|
||||
if len(messages) != len(cfg.Media) {
|
||||
t.Errorf("Different number of messages: %d", len(messages))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithMediaGroupDocument(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
cfg := NewMediaGroup(ChatID, []interface{}{
|
||||
NewInputMediaDocument(FileURL("https://i.imgur.com/unQLJIb.jpg")),
|
||||
NewInputMediaDocument("tests/image.jpg"),
|
||||
})
|
||||
|
||||
messages, err := bot.SendMediaGroup(cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if messages == nil {
|
||||
t.Error("No received messages")
|
||||
}
|
||||
|
||||
if len(messages) != len(cfg.Media) {
|
||||
t.Errorf("Different number of messages: %d", len(messages))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendWithMediaGroupAudio(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
cfg := NewMediaGroup(ChatID, []interface{}{
|
||||
NewInputMediaAudio("tests/audio.mp3"),
|
||||
NewInputMediaAudio("tests/audio.mp3"),
|
||||
})
|
||||
|
||||
messages, err := bot.SendMediaGroup(cfg)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
if messages == nil {
|
||||
t.Error("No received messages")
|
||||
}
|
||||
|
||||
if len(messages) != len(cfg.Media) {
|
||||
t.Errorf("Different number of messages: %d", len(messages))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,7 +715,14 @@ func ExampleNewWebhook() {
|
|||
|
||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
||||
|
||||
_, err = bot.Request(NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem"))
|
||||
wh, err := NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = bot.Request(wh)
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -599,6 +745,46 @@ func ExampleNewWebhook() {
|
|||
}
|
||||
}
|
||||
|
||||
func ExampleWebhookHandler() {
|
||||
bot, err := NewBotAPI("MyAwesomeBotToken")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
bot.Debug = true
|
||||
|
||||
log.Printf("Authorized on account %s", bot.Self.UserName)
|
||||
|
||||
wh, err := NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")
|
||||
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
_, err = bot.Request(wh)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
info, err := bot.GetWebhookInfo()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if info.LastErrorDate != 0 {
|
||||
log.Printf("[Telegram callback failed]%s", info.LastErrorMessage)
|
||||
}
|
||||
|
||||
http.HandleFunc("/"+bot.Token, func(w http.ResponseWriter, r *http.Request) {
|
||||
update, err := bot.HandleUpdate(r)
|
||||
if err != nil {
|
||||
log.Printf("%+v\n", err.Error())
|
||||
} else {
|
||||
log.Printf("%+v\n", *update)
|
||||
}
|
||||
})
|
||||
|
||||
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil)
|
||||
}
|
||||
|
||||
func ExampleInlineConfig() {
|
||||
bot, err := NewBotAPI("MyAwesomeBotToken") // create new bot
|
||||
if err != nil {
|
||||
|
@ -637,7 +823,7 @@ func TestDeleteMessage(t *testing.T) {
|
|||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
||||
msg.ParseMode = "markdown"
|
||||
msg.ParseMode = ModeMarkdown
|
||||
message, _ := bot.Send(msg)
|
||||
|
||||
deleteMessageConfig := DeleteMessageConfig{
|
||||
|
@ -648,7 +834,6 @@ func TestDeleteMessage(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -656,7 +841,7 @@ func TestPinChatMessage(t *testing.T) {
|
|||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
||||
msg.ParseMode = "markdown"
|
||||
msg.ParseMode = ModeMarkdown
|
||||
message, _ := bot.Send(msg)
|
||||
|
||||
pinChatMessageConfig := PinChatMessageConfig{
|
||||
|
@ -668,7 +853,6 @@ func TestPinChatMessage(t *testing.T) {
|
|||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -676,7 +860,7 @@ func TestUnpinChatMessage(t *testing.T) {
|
|||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
||||
msg.ParseMode = "markdown"
|
||||
msg.ParseMode = ModeMarkdown
|
||||
message, _ := bot.Send(msg)
|
||||
|
||||
// We need pin message to unpin something
|
||||
|
@ -688,16 +872,41 @@ func TestUnpinChatMessage(t *testing.T) {
|
|||
|
||||
if _, err := bot.Request(pinChatMessageConfig); err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
unpinChatMessageConfig := UnpinChatMessageConfig{
|
||||
ChatID: message.Chat.ID,
|
||||
MessageID: message.MessageID,
|
||||
}
|
||||
|
||||
if _, err := bot.Request(unpinChatMessageConfig); err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnpinAllChatMessages(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
||||
msg.ParseMode = ModeMarkdown
|
||||
message, _ := bot.Send(msg)
|
||||
|
||||
pinChatMessageConfig := PinChatMessageConfig{
|
||||
ChatID: message.Chat.ID,
|
||||
MessageID: message.MessageID,
|
||||
DisableNotification: true,
|
||||
}
|
||||
|
||||
if _, err := bot.Request(pinChatMessageConfig); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
unpinAllChatMessagesConfig := UnpinAllChatMessagesConfig{
|
||||
ChatID: message.Chat.ID,
|
||||
}
|
||||
|
||||
if _, err := bot.Request(unpinAllChatMessagesConfig); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -709,27 +918,109 @@ func TestPolls(t *testing.T) {
|
|||
msg, err := bot.Send(poll)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
result, err := bot.StopPoll(NewStopPoll(SupergroupChatID, msg.MessageID))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if result.Question != "Are polls working?" {
|
||||
t.Error("Poll question did not match")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if !result.IsClosed {
|
||||
t.Error("Poll did not end")
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
if result.Options[0].Text != "Yes" || result.Options[0].VoterCount != 0 || result.Options[1].Text != "No" || result.Options[1].VoterCount != 0 {
|
||||
t.Error("Poll options were incorrect")
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendDice(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
dice := NewSendDice(ChatID)
|
||||
|
||||
msg, err := bot.Send(dice)
|
||||
if err != nil {
|
||||
t.Error("Unable to send dice roll")
|
||||
}
|
||||
|
||||
if msg.Dice == nil {
|
||||
t.Error("Dice roll was not received")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCommands(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
setCommands := NewSetMyCommands(BotCommand{
|
||||
Command: "test",
|
||||
Description: "a test command",
|
||||
})
|
||||
|
||||
if _, err := bot.Request(setCommands); err != nil {
|
||||
t.Error("Unable to set commands")
|
||||
}
|
||||
|
||||
commands, err := bot.GetMyCommands()
|
||||
if err != nil {
|
||||
t.Error("Unable to get commands")
|
||||
}
|
||||
|
||||
if len(commands) != 1 {
|
||||
t.Error("Incorrect number of commands returned")
|
||||
}
|
||||
|
||||
if commands[0].Command != "test" || commands[0].Description != "a test command" {
|
||||
t.Error("Commands were incorrectly set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEditMessageMedia(t *testing.T) {
|
||||
bot, _ := getBot(t)
|
||||
|
||||
msg := NewPhoto(ChatID, "tests/image.jpg")
|
||||
msg.Caption = "Test"
|
||||
m, err := bot.Send(msg)
|
||||
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
edit := EditMessageMediaConfig{
|
||||
BaseEdit: BaseEdit{
|
||||
ChatID: ChatID,
|
||||
MessageID: m.MessageID,
|
||||
},
|
||||
Media: NewInputMediaVideo("tests/video.mp4"),
|
||||
}
|
||||
|
||||
_, err = bot.Request(edit)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrepareInputMediaForParams(t *testing.T) {
|
||||
media := []interface{}{
|
||||
NewInputMediaPhoto("tests/image.jpg"),
|
||||
NewInputMediaVideo(FileID("test")),
|
||||
}
|
||||
|
||||
prepared := prepareInputMediaForParams(media)
|
||||
|
||||
if media[0].(InputMediaPhoto).Media != "tests/image.jpg" {
|
||||
t.Error("Original media was changed")
|
||||
}
|
||||
|
||||
if prepared[0].(InputMediaPhoto).Media != "attach://file-0" {
|
||||
t.Error("New media was not replaced")
|
||||
}
|
||||
|
||||
if prepared[1].(InputMediaVideo).Media != FileID("test") {
|
||||
t.Error("Passthrough value was not the same")
|
||||
}
|
||||
}
|
||||
|
|
1091
configs.go
1091
configs.go
File diff suppressed because it is too large
Load Diff
2
go.mod
2
go.mod
|
@ -1,3 +1,3 @@
|
|||
module github.com/go-telegram-bot-api/telegram-bot-api/v5
|
||||
|
||||
require github.com/technoweenie/multipartstreamer v1.0.1
|
||||
go 1.13
|
||||
|
|
2
go.sum
2
go.sum
|
@ -1,2 +0,0 @@
|
|||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
425
helpers.go
425
helpers.go
|
@ -29,7 +29,8 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
|
|||
// NewMessageToChannel creates a new Message that is sent to a channel
|
||||
// by username.
|
||||
//
|
||||
// username is the username of the channel, text is the message text.
|
||||
// username is the username of the channel, text is the message text,
|
||||
// and the username should be in the form of `@username`.
|
||||
func NewMessageToChannel(username string, text string) MessageConfig {
|
||||
return MessageConfig{
|
||||
BaseChat: BaseChat{
|
||||
|
@ -51,241 +52,117 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
|
|||
}
|
||||
}
|
||||
|
||||
// NewPhotoUpload creates a new photo uploader.
|
||||
// NewCopyMessage creates a new copy message.
|
||||
//
|
||||
// chatID is where to send it, fromChatID is the source chat,
|
||||
// and messageID is the ID of the original message.
|
||||
func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig {
|
||||
return CopyMessageConfig{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FromChatID: fromChatID,
|
||||
MessageID: messageID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPhoto creates a new sendPhoto request.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewPhotoUpload(chatID int64, file interface{}) PhotoConfig {
|
||||
func NewPhoto(chatID int64, file interface{}) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewPhotoShare shares an existing photo.
|
||||
// You may use this to reshare an existing photo without reuploading it.
|
||||
// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the file
|
||||
// already uploaded.
|
||||
func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewPhotoToChannel(username string, file interface{}) PhotoConfig {
|
||||
return PhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
BaseChat: BaseChat{
|
||||
ChannelUsername: username,
|
||||
},
|
||||
File: file,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAudioUpload creates a new audio uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewAudioUpload(chatID int64, file interface{}) AudioConfig {
|
||||
// NewAudio creates a new sendAudio request.
|
||||
func NewAudio(chatID int64, file interface{}) AudioConfig {
|
||||
return AudioConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAudioShare shares an existing audio file.
|
||||
// You may use this to reshare an existing audio file without
|
||||
// reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the audio
|
||||
// already uploaded.
|
||||
func NewAudioShare(chatID int64, fileID string) AudioConfig {
|
||||
return AudioConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDocumentUpload creates a new document uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewDocumentUpload(chatID int64, file interface{}) DocumentConfig {
|
||||
// NewDocument creates a new sendDocument request.
|
||||
func NewDocument(chatID int64, file interface{}) DocumentConfig {
|
||||
return DocumentConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDocumentShare shares an existing document.
|
||||
// You may use this to reshare an existing document without
|
||||
// reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the document
|
||||
// already uploaded.
|
||||
func NewDocumentShare(chatID int64, fileID string) DocumentConfig {
|
||||
return DocumentConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStickerUpload creates a new sticker uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewStickerUpload(chatID int64, file interface{}) StickerConfig {
|
||||
// NewSticker creates a new sendSticker request.
|
||||
func NewSticker(chatID int64, file interface{}) StickerConfig {
|
||||
return StickerConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewStickerShare shares an existing sticker.
|
||||
// You may use this to reshare an existing sticker without
|
||||
// reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the sticker
|
||||
// already uploaded.
|
||||
func NewStickerShare(chatID int64, fileID string) StickerConfig {
|
||||
return StickerConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoUpload creates a new video uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVideoUpload(chatID int64, file interface{}) VideoConfig {
|
||||
// NewVideo creates a new sendVideo request.
|
||||
func NewVideo(chatID int64, file interface{}) VideoConfig {
|
||||
return VideoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoShare shares an existing video.
|
||||
// You may use this to reshare an existing video without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the video
|
||||
// already uploaded.
|
||||
func NewVideoShare(chatID int64, fileID string) VideoConfig {
|
||||
return VideoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAnimationUpload creates a new animation uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewAnimationUpload(chatID int64, file interface{}) AnimationConfig {
|
||||
// NewAnimation creates a new sendAnimation request.
|
||||
func NewAnimation(chatID int64, file interface{}) AnimationConfig {
|
||||
return AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewAnimationShare shares an existing animation.
|
||||
// You may use this to reshare an existing animation without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the animation
|
||||
// already uploaded.
|
||||
func NewAnimationShare(chatID int64, fileID string) AnimationConfig {
|
||||
return AnimationConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoNoteUpload creates a new video note uploader.
|
||||
// NewVideoNote creates a new sendVideoNote request.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig {
|
||||
func NewVideoNote(chatID int64, length int, file interface{}) VideoNoteConfig {
|
||||
return VideoNoteConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
Length: length,
|
||||
}
|
||||
}
|
||||
|
||||
// NewVideoNoteShare shares an existing video.
|
||||
// You may use this to reshare an existing video without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the video
|
||||
// already uploaded.
|
||||
func NewVideoNoteShare(chatID int64, length int, fileID string) VideoNoteConfig {
|
||||
return VideoNoteConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
Length: length,
|
||||
}
|
||||
}
|
||||
|
||||
// NewVoiceUpload creates a new voice uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
func NewVoiceUpload(chatID int64, file interface{}) VoiceConfig {
|
||||
// NewVoice creates a new sendVoice request.
|
||||
func NewVoice(chatID int64, file interface{}) VoiceConfig {
|
||||
return VoiceConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewVoiceShare shares an existing voice.
|
||||
// You may use this to reshare an existing voice without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the video
|
||||
// already uploaded.
|
||||
func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
|
||||
return VoiceConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -300,7 +177,7 @@ func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig {
|
|||
}
|
||||
|
||||
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||
func NewInputMediaPhoto(media string) InputMediaPhoto {
|
||||
func NewInputMediaPhoto(media interface{}) InputMediaPhoto {
|
||||
return InputMediaPhoto{
|
||||
BaseInputMedia{
|
||||
Type: "photo",
|
||||
|
@ -310,7 +187,7 @@ func NewInputMediaPhoto(media string) InputMediaPhoto {
|
|||
}
|
||||
|
||||
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||
func NewInputMediaVideo(media string) InputMediaVideo {
|
||||
func NewInputMediaVideo(media interface{}) InputMediaVideo {
|
||||
return InputMediaVideo{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "video",
|
||||
|
@ -320,7 +197,7 @@ func NewInputMediaVideo(media string) InputMediaVideo {
|
|||
}
|
||||
|
||||
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
||||
func NewInputMediaAnimation(media string) InputMediaAnimation {
|
||||
func NewInputMediaAnimation(media interface{}) InputMediaAnimation {
|
||||
return InputMediaAnimation{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "animation",
|
||||
|
@ -330,7 +207,7 @@ func NewInputMediaAnimation(media string) InputMediaAnimation {
|
|||
}
|
||||
|
||||
// NewInputMediaAudio creates a new InputMediaAudio.
|
||||
func NewInputMediaAudio(media string) InputMediaAudio {
|
||||
func NewInputMediaAudio(media interface{}) InputMediaAudio {
|
||||
return InputMediaAudio{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "audio",
|
||||
|
@ -340,7 +217,7 @@ func NewInputMediaAudio(media string) InputMediaAudio {
|
|||
}
|
||||
|
||||
// NewInputMediaDocument creates a new InputMediaDocument.
|
||||
func NewInputMediaDocument(media string) InputMediaDocument {
|
||||
func NewInputMediaDocument(media interface{}) InputMediaDocument {
|
||||
return InputMediaDocument{
|
||||
BaseInputMedia: BaseInputMedia{
|
||||
Type: "document",
|
||||
|
@ -400,7 +277,7 @@ func NewChatAction(chatID int64, action string) ChatActionConfig {
|
|||
// NewUserProfilePhotos gets user profile photos.
|
||||
//
|
||||
// userID is the ID of the user you wish to get profile photos from.
|
||||
func NewUserProfilePhotos(userID int) UserProfilePhotosConfig {
|
||||
func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig {
|
||||
return UserProfilePhotosConfig{
|
||||
UserID: userID,
|
||||
Offset: 0,
|
||||
|
@ -423,25 +300,33 @@ func NewUpdate(offset int) UpdateConfig {
|
|||
// NewWebhook creates a new webhook.
|
||||
//
|
||||
// link is the url parsable link you wish to get the updates.
|
||||
func NewWebhook(link string) WebhookConfig {
|
||||
u, _ := url.Parse(link)
|
||||
func NewWebhook(link string) (WebhookConfig, error) {
|
||||
u, err := url.Parse(link)
|
||||
|
||||
if err != nil {
|
||||
return WebhookConfig{}, err
|
||||
}
|
||||
|
||||
return WebhookConfig{
|
||||
URL: u,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewWebhookWithCert creates a new webhook with a certificate.
|
||||
//
|
||||
// link is the url you wish to get webhooks,
|
||||
// file contains a string to a file, FileReader, or FileBytes.
|
||||
func NewWebhookWithCert(link string, file interface{}) WebhookConfig {
|
||||
u, _ := url.Parse(link)
|
||||
func NewWebhookWithCert(link string, file interface{}) (WebhookConfig, error) {
|
||||
u, err := url.Parse(link)
|
||||
|
||||
if err != nil {
|
||||
return WebhookConfig{}, err
|
||||
}
|
||||
|
||||
return WebhookConfig{
|
||||
URL: u,
|
||||
Certificate: file,
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// NewInlineQueryResultArticle creates a new inline query article.
|
||||
|
@ -469,6 +354,19 @@ func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQu
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing.
|
||||
func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle {
|
||||
return InlineQueryResultArticle{
|
||||
Type: "article",
|
||||
ID: id,
|
||||
Title: title,
|
||||
InputMessageContent: InputTextMessageContent{
|
||||
Text: messageText,
|
||||
ParseMode: "MarkdownV2",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
||||
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
||||
return InlineQueryResultArticle{
|
||||
|
@ -491,6 +389,15 @@ func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF {
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedGIF create a new inline query with cached photo.
|
||||
func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF {
|
||||
return InlineQueryResultCachedGIF{
|
||||
Type: "gif",
|
||||
ID: id,
|
||||
GIFID: gifID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF.
|
||||
func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
||||
return InlineQueryResultMPEG4GIF{
|
||||
|
@ -500,6 +407,15 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
|
||||
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF {
|
||||
return InlineQueryResultCachedMPEG4GIF{
|
||||
Type: "mpeg4_gif",
|
||||
ID: id,
|
||||
MPEG4FileID: MPEG4GIFID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultPhoto creates a new inline query photo.
|
||||
func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto {
|
||||
return InlineQueryResultPhoto{
|
||||
|
@ -519,6 +435,15 @@ func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResult
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedPhoto create a new inline query with cached photo.
|
||||
func NewInlineQueryResultCachedPhoto(id, photoID string) InlineQueryResultCachedPhoto {
|
||||
return InlineQueryResultCachedPhoto{
|
||||
Type: "photo",
|
||||
ID: id,
|
||||
PhotoID: photoID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultVideo creates a new inline query video.
|
||||
func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo {
|
||||
return InlineQueryResultVideo{
|
||||
|
@ -528,6 +453,26 @@ func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo {
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedVideo create a new inline query with cached video.
|
||||
func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResultCachedVideo {
|
||||
return InlineQueryResultCachedVideo{
|
||||
Type: "video",
|
||||
ID: id,
|
||||
VideoID: videoID,
|
||||
Title: title,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedSticker create a new inline query with cached sticker.
|
||||
func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker {
|
||||
return InlineQueryResultCachedSticker{
|
||||
Type: "sticker",
|
||||
ID: id,
|
||||
StickerID: stickerID,
|
||||
Title: title,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultAudio creates a new inline query audio.
|
||||
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
||||
return InlineQueryResultAudio{
|
||||
|
@ -538,6 +483,15 @@ func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedAudio create a new inline query with cached photo.
|
||||
func NewInlineQueryResultCachedAudio(id, audioID string) InlineQueryResultCachedAudio {
|
||||
return InlineQueryResultCachedAudio{
|
||||
Type: "audio",
|
||||
ID: id,
|
||||
AudioID: audioID,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultVoice creates a new inline query voice.
|
||||
func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice {
|
||||
return InlineQueryResultVoice{
|
||||
|
@ -548,6 +502,16 @@ func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice {
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedVoice create a new inline query with cached photo.
|
||||
func NewInlineQueryResultCachedVoice(id, voiceID, title string) InlineQueryResultCachedVoice {
|
||||
return InlineQueryResultCachedVoice{
|
||||
Type: "voice",
|
||||
ID: id,
|
||||
VoiceID: voiceID,
|
||||
Title: title,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultDocument creates a new inline query document.
|
||||
func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument {
|
||||
return InlineQueryResultDocument{
|
||||
|
@ -559,6 +523,16 @@ func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryRe
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultCachedDocument create a new inline query with cached photo.
|
||||
func NewInlineQueryResultCachedDocument(id, documentID, title string) InlineQueryResultCachedDocument {
|
||||
return InlineQueryResultCachedDocument{
|
||||
Type: "document",
|
||||
ID: id,
|
||||
DocumentID: documentID,
|
||||
Title: title,
|
||||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultLocation creates a new inline query location.
|
||||
func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation {
|
||||
return InlineQueryResultLocation{
|
||||
|
@ -570,6 +544,18 @@ func NewInlineQueryResultLocation(id, title string, latitude, longitude float64)
|
|||
}
|
||||
}
|
||||
|
||||
// NewInlineQueryResultVenue creates a new inline query venue.
|
||||
func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue {
|
||||
return InlineQueryResultVenue{
|
||||
Type: "venue",
|
||||
ID: id,
|
||||
Title: title,
|
||||
Address: address,
|
||||
Latitude: latitude,
|
||||
Longitude: longitude,
|
||||
}
|
||||
}
|
||||
|
||||
// NewEditMessageText allows you to edit the text of a message.
|
||||
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
|
||||
return EditMessageTextConfig{
|
||||
|
@ -581,6 +567,18 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex
|
|||
}
|
||||
}
|
||||
|
||||
// NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message.
|
||||
func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig {
|
||||
return EditMessageTextConfig{
|
||||
BaseEdit: BaseEdit{
|
||||
ChatID: chatID,
|
||||
MessageID: messageID,
|
||||
ReplyMarkup: &replyMarkup,
|
||||
},
|
||||
Text: text,
|
||||
}
|
||||
}
|
||||
|
||||
// NewEditMessageCaption allows you to edit the caption of a message.
|
||||
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
||||
return EditMessageCaptionConfig{
|
||||
|
@ -604,17 +602,6 @@ func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKe
|
|||
}
|
||||
}
|
||||
|
||||
// NewHideKeyboard hides the keyboard, with the option for being selective
|
||||
// or hiding for everyone.
|
||||
func NewHideKeyboard(selective bool) ReplyKeyboardHide {
|
||||
log.Println("NewHideKeyboard is deprecated, please use NewRemoveKeyboard")
|
||||
|
||||
return ReplyKeyboardHide{
|
||||
HideKeyboard: true,
|
||||
Selective: selective,
|
||||
}
|
||||
}
|
||||
|
||||
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
||||
// or hiding for everyone.
|
||||
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
|
||||
|
@ -670,6 +657,13 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
|||
}
|
||||
}
|
||||
|
||||
// NewOneTimeReplyKeyboard creates a new one time keyboard.
|
||||
func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup {
|
||||
markup := NewReplyKeyboard(rows...)
|
||||
markup.OneTimeKeyboard = true
|
||||
return markup
|
||||
}
|
||||
|
||||
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
||||
// and data for a callback.
|
||||
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
||||
|
@ -758,37 +752,6 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP
|
|||
Prices: prices}
|
||||
}
|
||||
|
||||
// NewSetChatPhotoUpload creates a new chat photo uploader.
|
||||
//
|
||||
// chatID is where to send it, file is a string path to the file,
|
||||
// FileReader, or FileBytes.
|
||||
//
|
||||
// Note that you must send animated GIFs as a document.
|
||||
func NewSetChatPhotoUpload(chatID int64, file interface{}) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
File: file,
|
||||
UseExisting: false,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewSetChatPhotoShare shares an existing photo.
|
||||
// You may use this to reshare an existing photo without reuploading it.
|
||||
//
|
||||
// chatID is where to send it, fileID is the ID of the file
|
||||
// already uploaded.
|
||||
func NewSetChatPhotoShare(chatID int64, fileID string) SetChatPhotoConfig {
|
||||
return SetChatPhotoConfig{
|
||||
BaseFile: BaseFile{
|
||||
BaseChat: BaseChat{ChatID: chatID},
|
||||
FileID: fileID,
|
||||
UseExisting: true,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewChatTitle allows you to update the title of a chat.
|
||||
func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
|
||||
return SetChatTitleConfig{
|
||||
|
@ -832,6 +795,7 @@ func NewPoll(chatID int64, question string, options ...string) SendPollConfig {
|
|||
},
|
||||
Question: question,
|
||||
Options: options,
|
||||
IsAnonymous: true, // This is Telegram's default.
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -844,3 +808,36 @@ func NewStopPoll(chatID int64, messageID int) StopPollConfig {
|
|||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewSendDice allows you to send a random dice roll.
|
||||
//
|
||||
// Deprecated: Use NewDice instead.
|
||||
func NewSendDice(chatID int64) DiceConfig {
|
||||
return NewDice(chatID)
|
||||
}
|
||||
|
||||
// NewDice allows you to send a random dice roll.
|
||||
func NewDice(chatID int64) DiceConfig {
|
||||
return DiceConfig{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// NewDiceWithEmoji allows you to send a random roll of one of many types.
|
||||
//
|
||||
// Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5).
|
||||
func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig {
|
||||
return DiceConfig{
|
||||
BaseChat: BaseChat{
|
||||
ChatID: chatID,
|
||||
},
|
||||
Emoji: emoji,
|
||||
}
|
||||
}
|
||||
|
||||
// NewSetMyCommands allows you to set the registered commands.
|
||||
func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig {
|
||||
return SetMyCommandsConfig{commands: commands}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,31 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestNewWebhook(t *testing.T) {
|
||||
result, err := NewWebhook("https://example.com/token")
|
||||
|
||||
if err != nil ||
|
||||
result.URL.String() != "https://example.com/token" ||
|
||||
result.Certificate != interface{}(nil) ||
|
||||
result.MaxConnections != 0 ||
|
||||
len(result.AllowedUpdates) != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewWebhookWithCert(t *testing.T) {
|
||||
exampleFile := File{FileID: "123"}
|
||||
result, err := NewWebhookWithCert("https://example.com/token", exampleFile)
|
||||
|
||||
if err != nil ||
|
||||
result.URL.String() != "https://example.com/token" ||
|
||||
result.Certificate != exampleFile ||
|
||||
result.MaxConnections != 0 ||
|
||||
len(result.AllowedUpdates) != 0 {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewInlineQueryResultArticle(t *testing.T) {
|
||||
result := NewInlineQueryResultArticle("id", "title", "message")
|
||||
|
||||
|
@ -176,8 +201,8 @@ func TestNewEditMessageCaption(t *testing.T) {
|
|||
func TestNewEditMessageReplyMarkup(t *testing.T) {
|
||||
markup := InlineKeyboardMarkup{
|
||||
InlineKeyboard: [][]InlineKeyboardButton{
|
||||
[]InlineKeyboardButton{
|
||||
InlineKeyboardButton{Text: "test"},
|
||||
{
|
||||
{Text: "test"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
@ -191,3 +216,21 @@ func TestNewEditMessageReplyMarkup(t *testing.T) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
func TestNewDice(t *testing.T) {
|
||||
dice := NewDice(42)
|
||||
|
||||
if dice.ChatID != 42 ||
|
||||
dice.Emoji != "" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewDiceWithEmoji(t *testing.T) {
|
||||
dice := NewDiceWithEmoji(42, "🏀")
|
||||
|
||||
if dice.ChatID != 42 ||
|
||||
dice.Emoji != "🏀" {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
|
11
params.go
11
params.go
|
@ -37,13 +37,6 @@ func (p Params) AddBool(key string, value bool) {
|
|||
}
|
||||
}
|
||||
|
||||
// AddNonNilBool adds the value of a bool pointer if not nil.
|
||||
func (p Params) AddNonNilBool(key string, value *bool) {
|
||||
if value != nil {
|
||||
p[key] = strconv.FormatBool(*value)
|
||||
}
|
||||
}
|
||||
|
||||
// AddNonZeroFloat adds a floating point value that is not zero.
|
||||
func (p Params) AddNonZeroFloat(key string, value float64) {
|
||||
if value != 0 {
|
||||
|
@ -76,14 +69,17 @@ func (p Params) AddFirstValid(key string, args ...interface{}) error {
|
|||
case int:
|
||||
if v != 0 {
|
||||
p[key] = strconv.Itoa(v)
|
||||
return nil
|
||||
}
|
||||
case int64:
|
||||
if v != 0 {
|
||||
p[key] = strconv.FormatInt(v, 10)
|
||||
return nil
|
||||
}
|
||||
case string:
|
||||
if v != "" {
|
||||
p[key] = v
|
||||
return nil
|
||||
}
|
||||
case nil:
|
||||
default:
|
||||
|
@ -93,6 +89,7 @@ func (p Params) AddFirstValid(key string, args ...interface{}) error {
|
|||
}
|
||||
|
||||
p[key] = string(b)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,93 @@
|
|||
package tgbotapi
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func assertLen(t *testing.T, params Params, l int) {
|
||||
actual := len(params)
|
||||
if actual != l {
|
||||
t.Fatalf("Incorrect number of params, expected %d but found %d\n", l, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func assertEq(t *testing.T, a interface{}, b interface{}) {
|
||||
if a != b {
|
||||
t.Fatalf("Values did not match, a: %v, b: %v\n", a, b)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddNonEmpty(t *testing.T) {
|
||||
params := make(Params)
|
||||
params.AddNonEmpty("value", "value")
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], "value")
|
||||
params.AddNonEmpty("test", "")
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["test"], "")
|
||||
}
|
||||
|
||||
func TestAddNonZero(t *testing.T) {
|
||||
params := make(Params)
|
||||
params.AddNonZero("value", 1)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], "1")
|
||||
params.AddNonZero("test", 0)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["test"], "")
|
||||
}
|
||||
|
||||
func TestAddNonZero64(t *testing.T) {
|
||||
params := make(Params)
|
||||
params.AddNonZero64("value", 1)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], "1")
|
||||
params.AddNonZero64("test", 0)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["test"], "")
|
||||
}
|
||||
|
||||
func TestAddBool(t *testing.T) {
|
||||
params := make(Params)
|
||||
params.AddBool("value", true)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], "true")
|
||||
params.AddBool("test", false)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["test"], "")
|
||||
}
|
||||
|
||||
func TestAddNonZeroFloat(t *testing.T) {
|
||||
params := make(Params)
|
||||
params.AddNonZeroFloat("value", 1)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], "1.000000")
|
||||
params.AddNonZeroFloat("test", 0)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["test"], "")
|
||||
}
|
||||
|
||||
func TestAddInterface(t *testing.T) {
|
||||
params := make(Params)
|
||||
data := struct {
|
||||
Name string `json:"name"`
|
||||
}{
|
||||
Name: "test",
|
||||
}
|
||||
params.AddInterface("value", data)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], `{"name":"test"}`)
|
||||
params.AddInterface("test", nil)
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["test"], "")
|
||||
}
|
||||
|
||||
func TestAddFirstValid(t *testing.T) {
|
||||
params := make(Params)
|
||||
params.AddFirstValid("value", 0, "", "test")
|
||||
assertLen(t, params, 1)
|
||||
assertEq(t, params["value"], "test")
|
||||
params.AddFirstValid("value2", 3, "test")
|
||||
assertLen(t, params, 2)
|
||||
assertEq(t, params["value2"], "3")
|
||||
}
|
|
@ -61,6 +61,8 @@ type (
|
|||
// Unique identifier for this file
|
||||
FileID string `json:"file_id"`
|
||||
|
||||
FileUniqueID string `json:"file_unique_id"`
|
||||
|
||||
// File size
|
||||
FileSize int `json:"file_size"`
|
||||
|
||||
|
|
123
types_test.go
123
types_test.go
|
@ -189,6 +189,86 @@ func TestChatIsSuperGroup(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsMention(t *testing.T) {
|
||||
entity := MessageEntity{Type: "mention"}
|
||||
|
||||
if !entity.IsMention() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsHashtag(t *testing.T) {
|
||||
entity := MessageEntity{Type: "hashtag"}
|
||||
|
||||
if !entity.IsHashtag() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsBotCommand(t *testing.T) {
|
||||
entity := MessageEntity{Type: "bot_command"}
|
||||
|
||||
if !entity.IsCommand() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsUrl(t *testing.T) {
|
||||
entity := MessageEntity{Type: "url"}
|
||||
|
||||
if !entity.IsURL() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsEmail(t *testing.T) {
|
||||
entity := MessageEntity{Type: "email"}
|
||||
|
||||
if !entity.IsEmail() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsBold(t *testing.T) {
|
||||
entity := MessageEntity{Type: "bold"}
|
||||
|
||||
if !entity.IsBold() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsItalic(t *testing.T) {
|
||||
entity := MessageEntity{Type: "italic"}
|
||||
|
||||
if !entity.IsItalic() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsCode(t *testing.T) {
|
||||
entity := MessageEntity{Type: "code"}
|
||||
|
||||
if !entity.IsCode() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsPre(t *testing.T) {
|
||||
entity := MessageEntity{Type: "pre"}
|
||||
|
||||
if !entity.IsPre() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestMessageEntityIsTextLink(t *testing.T) {
|
||||
entity := MessageEntity{Type: "text_link"}
|
||||
|
||||
if !entity.IsTextLink() {
|
||||
t.Fail()
|
||||
}
|
||||
}
|
||||
|
||||
func TestFileLink(t *testing.T) {
|
||||
file := File{FilePath: "test/test.txt"}
|
||||
|
||||
|
@ -203,31 +283,53 @@ var (
|
|||
_ Chattable = AudioConfig{}
|
||||
_ Chattable = CallbackConfig{}
|
||||
_ Chattable = ChatActionConfig{}
|
||||
_ Chattable = ChatAdministratorsConfig{}
|
||||
_ Chattable = ChatInfoConfig{}
|
||||
_ Chattable = ChatInviteLinkConfig{}
|
||||
_ Chattable = CloseConfig{}
|
||||
_ Chattable = ContactConfig{}
|
||||
_ Chattable = CopyMessageConfig{}
|
||||
_ Chattable = CreateChatInviteLinkConfig{}
|
||||
_ Chattable = DeleteChatPhotoConfig{}
|
||||
_ Chattable = DeleteChatStickerSetConfig{}
|
||||
_ Chattable = DeleteMessageConfig{}
|
||||
_ Chattable = DeleteWebhookConfig{}
|
||||
_ Chattable = DocumentConfig{}
|
||||
_ Chattable = EditChatInviteLinkConfig{}
|
||||
_ Chattable = EditMessageCaptionConfig{}
|
||||
_ Chattable = EditMessageLiveLocationConfig{}
|
||||
_ Chattable = EditMessageMediaConfig{}
|
||||
_ Chattable = EditMessageReplyMarkupConfig{}
|
||||
_ Chattable = EditMessageTextConfig{}
|
||||
_ Chattable = FileConfig{}
|
||||
_ Chattable = ForwardConfig{}
|
||||
_ Chattable = GameConfig{}
|
||||
_ Chattable = GetChatMemberConfig{}
|
||||
_ Chattable = GetGameHighScoresConfig{}
|
||||
_ Chattable = InlineConfig{}
|
||||
_ Chattable = InvoiceConfig{}
|
||||
_ Chattable = KickChatMemberConfig{}
|
||||
_ Chattable = LeaveChatConfig{}
|
||||
_ Chattable = LocationConfig{}
|
||||
_ Chattable = LogOutConfig{}
|
||||
_ Chattable = MediaGroupConfig{}
|
||||
_ Chattable = MessageConfig{}
|
||||
_ Chattable = PhotoConfig{}
|
||||
_ Chattable = PinChatMessageConfig{}
|
||||
_ Chattable = PreCheckoutConfig{}
|
||||
_ Chattable = PromoteChatMemberConfig{}
|
||||
_ Chattable = RestrictChatMemberConfig{}
|
||||
_ Chattable = RevokeChatInviteLinkConfig{}
|
||||
_ Chattable = SendPollConfig{}
|
||||
_ Chattable = SetChatDescriptionConfig{}
|
||||
_ Chattable = SetChatPhotoConfig{}
|
||||
_ Chattable = SetChatTitleConfig{}
|
||||
_ Chattable = SetGameScoreConfig{}
|
||||
_ Chattable = ShippingConfig{}
|
||||
_ Chattable = StickerConfig{}
|
||||
_ Chattable = StopMessageLiveLocationConfig{}
|
||||
_ Chattable = StopPollConfig{}
|
||||
_ Chattable = UnbanChatMemberConfig{}
|
||||
_ Chattable = UnpinChatMessageConfig{}
|
||||
_ Chattable = UpdateConfig{}
|
||||
_ Chattable = UserProfilePhotosConfig{}
|
||||
|
@ -237,3 +339,24 @@ var (
|
|||
_ Chattable = VoiceConfig{}
|
||||
_ Chattable = WebhookConfig{}
|
||||
)
|
||||
|
||||
// Ensure all Fileable types are correct.
|
||||
var (
|
||||
_ Fileable = (*PhotoConfig)(nil)
|
||||
_ Fileable = (*AudioConfig)(nil)
|
||||
_ Fileable = (*DocumentConfig)(nil)
|
||||
_ Fileable = (*StickerConfig)(nil)
|
||||
_ Fileable = (*VideoConfig)(nil)
|
||||
_ Fileable = (*AnimationConfig)(nil)
|
||||
_ Fileable = (*VideoNoteConfig)(nil)
|
||||
_ Fileable = (*VoiceConfig)(nil)
|
||||
_ Fileable = (*SetChatPhotoConfig)(nil)
|
||||
_ Fileable = (*EditMessageMediaConfig)(nil)
|
||||
_ Fileable = (*SetChatPhotoConfig)(nil)
|
||||
_ Fileable = (*UploadStickerConfig)(nil)
|
||||
_ Fileable = (*NewStickerSetConfig)(nil)
|
||||
_ Fileable = (*AddStickerConfig)(nil)
|
||||
_ Fileable = (*MediaGroupConfig)(nil)
|
||||
_ Fileable = (*WebhookConfig)(nil)
|
||||
_ Fileable = (*SetStickerSetThumbConfig)(nil)
|
||||
)
|
||||
|
|
Loading…
Reference in New Issue