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)
|
[![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)
|
[![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
|
explain everything. If something isn't clear, open an issue or submit
|
||||||
a pull request.
|
a pull request.
|
||||||
|
|
||||||
|
|
368
bot.go
368
bot.go
|
@ -9,15 +9,20 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"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.
|
// BotAPI allows you to interact with the Telegram Bot API.
|
||||||
type BotAPI struct {
|
type BotAPI struct {
|
||||||
Token string `json:"token"`
|
Token string `json:"token"`
|
||||||
|
@ -25,27 +30,39 @@ type BotAPI struct {
|
||||||
Buffer int `json:"buffer"`
|
Buffer int `json:"buffer"`
|
||||||
|
|
||||||
Self User `json:"-"`
|
Self User `json:"-"`
|
||||||
Client *http.Client `json:"-"`
|
Client HTTPClient `json:"-"`
|
||||||
shutdownChannel chan interface{}
|
shutdownChannel chan interface{}
|
||||||
|
|
||||||
|
apiEndpoint string
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBotAPI creates a new BotAPI instance.
|
// NewBotAPI creates a new BotAPI instance.
|
||||||
//
|
//
|
||||||
// It requires a token, provided by @BotFather on Telegram.
|
// It requires a token, provided by @BotFather on Telegram.
|
||||||
func NewBotAPI(token string) (*BotAPI, error) {
|
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
|
// NewBotAPIWithClient creates a new BotAPI instance
|
||||||
// and allows you to pass a http.Client.
|
// and allows you to pass a http.Client.
|
||||||
//
|
//
|
||||||
// It requires a token, provided by @BotFather on Telegram.
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) {
|
||||||
bot := &BotAPI{
|
bot := &BotAPI{
|
||||||
Token: token,
|
Token: token,
|
||||||
Client: client,
|
Client: client,
|
||||||
Buffer: 100,
|
Buffer: 100,
|
||||||
shutdownChannel: make(chan interface{}),
|
shutdownChannel: make(chan interface{}),
|
||||||
|
|
||||||
|
apiEndpoint: apiEndpoint,
|
||||||
}
|
}
|
||||||
|
|
||||||
self, err := bot.GetMe()
|
self, err := bot.GetMe()
|
||||||
|
@ -58,6 +75,11 @@ func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
|
||||||
return bot, nil
|
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) {
|
func buildParams(in Params) (out url.Values) {
|
||||||
if in == nil {
|
if in == nil {
|
||||||
return url.Values{}
|
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.
|
// 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 {
|
if bot.Debug {
|
||||||
log.Printf("Endpoint: %s, params: %v\n", endpoint, params)
|
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)
|
values := buildParams(params)
|
||||||
|
|
||||||
resp, err := bot.Client.PostForm(method, values)
|
resp, err := bot.Client.PostForm(method, values)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
var apiResp APIResponse
|
var apiResp APIResponse
|
||||||
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return apiResp, err
|
return &apiResp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if bot.Debug {
|
if bot.Debug {
|
||||||
|
@ -105,13 +127,14 @@ func (bot *BotAPI) MakeRequest(endpoint string, params Params) (APIResponse, err
|
||||||
parameters = *apiResp.Parameters
|
parameters = *apiResp.Parameters
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiResp, Error{
|
return &apiResp, &Error{
|
||||||
|
Code: apiResp.ErrorCode,
|
||||||
Message: apiResp.Description,
|
Message: apiResp.Description,
|
||||||
ResponseParameters: parameters,
|
ResponseParameters: parameters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return apiResp, nil
|
return &apiResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
// 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
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UploadFile makes a request to the API with a file.
|
// UploadFiles makes a request to the API with files.
|
||||||
//
|
func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) {
|
||||||
// Requires the parameter to hold the file not be in the params.
|
r, w := io.Pipe()
|
||||||
// File should be a string to a file path, a FileBytes struct,
|
m := multipart.NewWriter(w)
|
||||||
// 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()
|
|
||||||
|
|
||||||
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:
|
case string:
|
||||||
ms.WriteFields(params)
|
|
||||||
|
|
||||||
fileHandle, err := os.Open(f)
|
fileHandle, err := os.Open(f)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
defer fileHandle.Close()
|
defer fileHandle.Close()
|
||||||
|
|
||||||
fi, err := os.Stat(f)
|
part, err := m.CreateFormFile(file.Name, fileHandle.Name())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.WriteReader(fieldname, fileHandle.Name(), fi.Size(), fileHandle)
|
io.Copy(part, fileHandle)
|
||||||
case FileBytes:
|
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)
|
buf := bytes.NewBuffer(f.Bytes)
|
||||||
ms.WriteReader(fieldname, f.Name, int64(len(f.Bytes)), buf)
|
io.Copy(part, buf)
|
||||||
case FileReader:
|
case FileReader:
|
||||||
ms.WriteFields(params)
|
part, err := m.CreateFormFile(file.Name, f.Name)
|
||||||
|
|
||||||
if f.Size != -1 {
|
|
||||||
ms.WriteReader(fieldname, f.Name, f.Size, f.Reader)
|
|
||||||
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := ioutil.ReadAll(f.Reader)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := bytes.NewBuffer(data)
|
io.Copy(part, f.Reader)
|
||||||
|
case FileURL:
|
||||||
ms.WriteReader(fieldname, f.Name, int64(len(data)), buf)
|
val := string(f)
|
||||||
case url.URL:
|
if err := m.WriteField(file.Name, val); err != nil {
|
||||||
params[fieldname] = f.String()
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
ms.WriteFields(params)
|
}
|
||||||
|
case FileID:
|
||||||
|
val := string(f)
|
||||||
|
if err := m.WriteField(file.Name, val); err != nil {
|
||||||
|
w.CloseWithError(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return APIResponse{}, errors.New(ErrBadFileType)
|
w.CloseWithError(errors.New(ErrBadFileType))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
if bot.Debug {
|
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 {
|
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 {
|
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 {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return &apiResp, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if bot.Debug {
|
if bot.Debug {
|
||||||
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes))
|
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 {
|
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
|
// 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)
|
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.
|
// 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()
|
params, err := c.params()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return APIResponse{}, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
switch t := c.(type) {
|
if t, ok := c.(Fileable); ok {
|
||||||
case Fileable:
|
files := t.files()
|
||||||
if t.useExistingFile() {
|
|
||||||
return bot.MakeRequest(t.method(), params)
|
// 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:
|
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
|
// 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.
|
// SendMediaGroup sends a media group and returns the resulting messages.
|
||||||
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -327,9 +396,7 @@ func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) {
|
||||||
// It requires UserID.
|
// It requires UserID.
|
||||||
// Offset and Limit are optional.
|
// Offset and Limit are optional.
|
||||||
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return UserProfilePhotos{}, err
|
return UserProfilePhotos{}, err
|
||||||
}
|
}
|
||||||
|
@ -344,9 +411,7 @@ func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserPro
|
||||||
//
|
//
|
||||||
// Requires FileID.
|
// Requires FileID.
|
||||||
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return File{}, err
|
return File{}, err
|
||||||
}
|
}
|
||||||
|
@ -360,14 +425,12 @@ func (bot *BotAPI) GetFile(config FileConfig) (File, error) {
|
||||||
// GetUpdates fetches updates.
|
// GetUpdates fetches updates.
|
||||||
// If a WebHook is set, this will not return any data!
|
// 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.
|
// 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
|
// Set Timeout to a large number to reduce requests so you can get updates
|
||||||
// instantly instead of having to wait between requests.
|
// instantly instead of having to wait between requests.
|
||||||
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []Update{}, err
|
return []Update{}, err
|
||||||
}
|
}
|
||||||
|
@ -400,6 +463,7 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel {
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-bot.shutdownChannel:
|
case <-bot.shutdownChannel:
|
||||||
|
close(ch)
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
|
@ -438,22 +502,66 @@ func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel {
|
||||||
ch := make(chan Update, bot.Buffer)
|
ch := make(chan Update, bot.Buffer)
|
||||||
|
|
||||||
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
|
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
|
ch <- *update
|
||||||
json.Unmarshal(bytes, &update)
|
|
||||||
|
|
||||||
ch <- update
|
|
||||||
})
|
})
|
||||||
|
|
||||||
return ch
|
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.
|
// GetChat gets information about a chat.
|
||||||
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Chat{}, err
|
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.
|
// If none have been appointed, only the creator will be returned.
|
||||||
// Bots are not shown, even if they are an administrator.
|
// Bots are not shown, even if they are an administrator.
|
||||||
func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) {
|
func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []ChatMember{}, err
|
return []ChatMember{}, err
|
||||||
}
|
}
|
||||||
|
@ -484,9 +590,7 @@ func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]Cha
|
||||||
|
|
||||||
// GetChatMembersCount gets the number of users in a chat.
|
// GetChatMembersCount gets the number of users in a chat.
|
||||||
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
|
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return -1, err
|
return -1, err
|
||||||
}
|
}
|
||||||
|
@ -499,9 +603,7 @@ func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error
|
||||||
|
|
||||||
// GetChatMember gets a specific chat member.
|
// GetChatMember gets a specific chat member.
|
||||||
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
|
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ChatMember{}, err
|
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.
|
// GetGameHighScores allows you to get the high scores for a game.
|
||||||
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return []GameHighScore{}, err
|
return []GameHighScore{}, err
|
||||||
}
|
}
|
||||||
|
@ -529,9 +629,7 @@ func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHigh
|
||||||
|
|
||||||
// GetInviteLink get InviteLink for a chat
|
// GetInviteLink get InviteLink for a chat
|
||||||
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -544,9 +642,7 @@ func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) {
|
||||||
|
|
||||||
// GetStickerSet returns a StickerSet.
|
// GetStickerSet returns a StickerSet.
|
||||||
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) {
|
||||||
params, _ := config.params()
|
resp, err := bot.Request(config)
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return StickerSet{}, err
|
return StickerSet{}, err
|
||||||
}
|
}
|
||||||
|
@ -559,12 +655,7 @@ func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error)
|
||||||
|
|
||||||
// StopPoll stops a poll and returns the result.
|
// StopPoll stops a poll and returns the result.
|
||||||
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
||||||
params, err := config.params()
|
resp, err := bot.Request(config)
|
||||||
if err != nil {
|
|
||||||
return Poll{}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
resp, err := bot.MakeRequest(config.method(), params)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return Poll{}, err
|
return Poll{}, err
|
||||||
}
|
}
|
||||||
|
@ -574,3 +665,38 @@ func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) {
|
||||||
|
|
||||||
return poll, err
|
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 (
|
const (
|
||||||
TestToken = "153667468:AAHlSHlMqSt1f_uFmVRJbm5gntu2HI4WW8I"
|
TestToken = "153667468:AAHlSHlMqSt1f_uFmVRJbm5gntu2HI4WW8I"
|
||||||
ChatID = 76918703
|
ChatID = 76918703
|
||||||
|
Channel = "@tgbotapitest"
|
||||||
SupergroupChatID = -1001120141283
|
SupergroupChatID = -1001120141283
|
||||||
ReplyToMessageID = 35
|
ReplyToMessageID = 35
|
||||||
ExistingPhotoFileID = "AgADAgADw6cxG4zHKAkr42N7RwEN3IFShCoABHQwXEtVks4EH2wBAAEC"
|
ExistingPhotoFileID = "AgADAgADw6cxG4zHKAkr42N7RwEN3IFShCoABHQwXEtVks4EH2wBAAEC"
|
||||||
|
@ -22,13 +23,27 @@ const (
|
||||||
ExistingStickerFileID = "BQADAgADcwADjMcoCbdl-6eB--YPAg"
|
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) {
|
func getBot(t *testing.T) (*BotAPI, error) {
|
||||||
bot, err := NewBotAPI(TestToken)
|
bot, err := NewBotAPI(TestToken)
|
||||||
bot.Debug = true
|
bot.Debug = true
|
||||||
|
|
||||||
|
logger := testLogger{t}
|
||||||
|
SetLogger(logger)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return bot, err
|
return bot, err
|
||||||
|
@ -39,7 +54,6 @@ func TestNewBotAPI_notoken(t *testing.T) {
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,7 +66,6 @@ func TestGetUpdates(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,12 +73,11 @@ func TestSendWithMessage(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
||||||
msg.ParseMode = "markdown"
|
msg.ParseMode = ModeMarkdown
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +90,6 @@ func TestSendWithMessageReply(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,20 +101,38 @@ func TestSendWithMessageForward(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
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) {
|
func TestSendWithNewPhoto(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewPhotoUpload(ChatID, "tests/image.jpg")
|
msg := NewPhoto(ChatID, "tests/image.jpg")
|
||||||
msg.Caption = "Test"
|
msg.Caption = "Test"
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,13 +142,12 @@ func TestSendWithNewPhotoWithFileBytes(t *testing.T) {
|
||||||
data, _ := ioutil.ReadFile("tests/image.jpg")
|
data, _ := ioutil.ReadFile("tests/image.jpg")
|
||||||
b := FileBytes{Name: "image.jpg", Bytes: data}
|
b := FileBytes{Name: "image.jpg", Bytes: data}
|
||||||
|
|
||||||
msg := NewPhotoUpload(ChatID, b)
|
msg := NewPhoto(ChatID, b)
|
||||||
msg.Caption = "Test"
|
msg.Caption = "Test"
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,9 +155,34 @@ func TestSendWithNewPhotoWithFileReader(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
f, _ := os.Open("tests/image.jpg")
|
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"
|
msg.Caption = "Test"
|
||||||
_, err := bot.Send(msg)
|
_, 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)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewPhotoUpload(ChatID, "tests/image.jpg")
|
data, _ := ioutil.ReadFile("tests/image.jpg")
|
||||||
msg.ReplyToMessageID = ReplyToMessageID
|
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)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -156,61 +227,67 @@ func TestSendWithNewPhotoReply(t *testing.T) {
|
||||||
func TestSendWithExistingPhoto(t *testing.T) {
|
func TestSendWithExistingPhoto(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewPhotoShare(ChatID, ExistingPhotoFileID)
|
msg := NewPhoto(ChatID, FileID(ExistingPhotoFileID))
|
||||||
msg.Caption = "Test"
|
msg.Caption = "Test"
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewDocument(t *testing.T) {
|
func TestSendWithNewDocument(t *testing.T) {
|
||||||
bot, _ := getBot(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)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingDocument(t *testing.T) {
|
func TestSendWithExistingDocument(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewDocumentShare(ChatID, ExistingDocumentFileID)
|
msg := NewDocument(ChatID, FileID(ExistingDocumentFileID))
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewAudio(t *testing.T) {
|
func TestSendWithNewAudio(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewAudioUpload(ChatID, "tests/audio.mp3")
|
msg := NewAudio(ChatID, "tests/audio.mp3")
|
||||||
msg.Title = "TEST"
|
msg.Title = "TEST"
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
msg.Performer = "TEST"
|
msg.Performer = "TEST"
|
||||||
msg.MimeType = "audio/mpeg"
|
|
||||||
msg.FileSize = 688
|
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingAudio(t *testing.T) {
|
func TestSendWithExistingAudio(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewAudioShare(ChatID, ExistingAudioFileID)
|
msg := NewAudio(ChatID, FileID(ExistingAudioFileID))
|
||||||
msg.Title = "TEST"
|
msg.Title = "TEST"
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
msg.Performer = "TEST"
|
msg.Performer = "TEST"
|
||||||
|
@ -219,33 +296,30 @@ func TestSendWithExistingAudio(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewVoice(t *testing.T) {
|
func TestSendWithNewVoice(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewVoiceUpload(ChatID, "tests/voice.ogg")
|
msg := NewVoice(ChatID, "tests/voice.ogg")
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingVoice(t *testing.T) {
|
func TestSendWithExistingVoice(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewVoiceShare(ChatID, ExistingVoiceFileID)
|
msg := NewVoice(ChatID, FileID(ExistingVoiceFileID))
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -256,7 +330,6 @@ func TestSendWithContact(t *testing.T) {
|
||||||
|
|
||||||
if _, err := bot.Send(contact); err != nil {
|
if _, err := bot.Send(contact); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -267,7 +340,6 @@ func TestSendWithLocation(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -278,14 +350,13 @@ func TestSendWithVenue(t *testing.T) {
|
||||||
|
|
||||||
if _, err := bot.Send(venue); err != nil {
|
if _, err := bot.Send(venue); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewVideo(t *testing.T) {
|
func TestSendWithNewVideo(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewVideoUpload(ChatID, "tests/video.mp4")
|
msg := NewVideo(ChatID, "tests/video.mp4")
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
msg.Caption = "TEST"
|
msg.Caption = "TEST"
|
||||||
|
|
||||||
|
@ -293,14 +364,13 @@ func TestSendWithNewVideo(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingVideo(t *testing.T) {
|
func TestSendWithExistingVideo(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewVideoShare(ChatID, ExistingVideoFileID)
|
msg := NewVideo(ChatID, FileID(ExistingVideoFileID))
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
msg.Caption = "TEST"
|
msg.Caption = "TEST"
|
||||||
|
|
||||||
|
@ -308,68 +378,63 @@ func TestSendWithExistingVideo(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewVideoNote(t *testing.T) {
|
func TestSendWithNewVideoNote(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewVideoNoteUpload(ChatID, 240, "tests/videonote.mp4")
|
msg := NewVideoNote(ChatID, 240, "tests/videonote.mp4")
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
|
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingVideoNote(t *testing.T) {
|
func TestSendWithExistingVideoNote(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewVideoNoteShare(ChatID, 240, ExistingVideoNoteFileID)
|
msg := NewVideoNote(ChatID, 240, FileID(ExistingVideoNoteFileID))
|
||||||
msg.Duration = 10
|
msg.Duration = 10
|
||||||
|
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewSticker(t *testing.T) {
|
func TestSendWithNewSticker(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewStickerUpload(ChatID, "tests/image.jpg")
|
msg := NewSticker(ChatID, "tests/image.jpg")
|
||||||
|
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingSticker(t *testing.T) {
|
func TestSendWithExistingSticker(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewStickerShare(ChatID, ExistingStickerFileID)
|
msg := NewSticker(ChatID, FileID(ExistingStickerFileID))
|
||||||
|
|
||||||
_, err := bot.Send(msg)
|
_, err := bot.Send(msg)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewStickerUpload(ChatID, "tests/image.jpg")
|
msg := NewSticker(ChatID, "tests/image.jpg")
|
||||||
msg.ReplyMarkup = ReplyKeyboardRemove{
|
msg.ReplyMarkup = ReplyKeyboardRemove{
|
||||||
RemoveKeyboard: true,
|
RemoveKeyboard: true,
|
||||||
Selective: false,
|
Selective: false,
|
||||||
|
@ -378,14 +443,13 @@ func TestSendWithNewStickerAndKeyboardHide(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewStickerShare(ChatID, ExistingStickerFileID)
|
msg := NewSticker(ChatID, FileID(ExistingStickerFileID))
|
||||||
msg.ReplyMarkup = ReplyKeyboardRemove{
|
msg.ReplyMarkup = ReplyKeyboardRemove{
|
||||||
RemoveKeyboard: true,
|
RemoveKeyboard: true,
|
||||||
Selective: false,
|
Selective: false,
|
||||||
|
@ -393,10 +457,35 @@ func TestSendWithExistingStickerAndKeyboardHide(t *testing.T) {
|
||||||
|
|
||||||
_, err := bot.Send(msg)
|
_, 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 {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
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) {
|
func TestGetFile(t *testing.T) {
|
||||||
|
@ -410,7 +499,6 @@ func TestGetFile(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -421,7 +509,6 @@ func TestSendChatConfig(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +518,6 @@ func TestSendEditMessage(t *testing.T) {
|
||||||
msg, err := bot.Send(NewMessage(ChatID, "Testing editing."))
|
msg, err := bot.Send(NewMessage(ChatID, "Testing editing."))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
edit := EditMessageTextConfig{
|
edit := EditMessageTextConfig{
|
||||||
|
@ -445,7 +531,6 @@ func TestSendEditMessage(t *testing.T) {
|
||||||
_, err = bot.Send(edit)
|
_, err = bot.Send(edit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -455,7 +540,6 @@ func TestGetUserProfilePhotos(t *testing.T) {
|
||||||
_, err := bot.GetUserProfilePhotos(NewUserProfilePhotos(ChatID))
|
_, err := bot.GetUserProfilePhotos(NewUserProfilePhotos(ChatID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,13 +548,17 @@ func TestSetWebhookWithCert(t *testing.T) {
|
||||||
|
|
||||||
time.Sleep(time.Second * 2)
|
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 {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = bot.GetWebhookInfo()
|
_, err = bot.GetWebhookInfo()
|
||||||
|
@ -479,7 +567,7 @@ func TestSetWebhookWithCert(t *testing.T) {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.Request(RemoveWebhookConfig{})
|
bot.Request(DeleteWebhookConfig{})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSetWebhookWithoutCert(t *testing.T) {
|
func TestSetWebhookWithoutCert(t *testing.T) {
|
||||||
|
@ -487,13 +575,18 @@ func TestSetWebhookWithoutCert(t *testing.T) {
|
||||||
|
|
||||||
time.Sleep(time.Second * 2)
|
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 {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info, err := bot.GetWebhookInfo()
|
info, err := bot.GetWebhookInfo()
|
||||||
|
@ -501,21 +594,23 @@ func TestSetWebhookWithoutCert(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
|
if info.MaxConnections == 0 {
|
||||||
|
t.Errorf("Expected maximum connections to be greater than 0")
|
||||||
|
}
|
||||||
if info.LastErrorDate != 0 {
|
if info.LastErrorDate != 0 {
|
||||||
t.Errorf("failed to set webhook: %s", info.LastErrorMessage)
|
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)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
cfg := NewMediaGroup(ChatID, []interface{}{
|
cfg := NewMediaGroup(ChatID, []interface{}{
|
||||||
NewInputMediaPhoto("https://i.imgur.com/unQLJIb.jpg"),
|
NewInputMediaPhoto(FileURL("https://github.com/go-telegram-bot-api/telegram-bot-api/raw/0a3a1c8716c4cd8d26a262af9f12dcbab7f3f28c/tests/image.jpg")),
|
||||||
NewInputMediaPhoto("https://i.imgur.com/J5qweNZ.jpg"),
|
NewInputMediaPhoto("tests/image.jpg"),
|
||||||
NewInputMediaVideo("https://i.imgur.com/F6RmI24.mp4"),
|
NewInputMediaVideo("tests/video.mp4"),
|
||||||
})
|
})
|
||||||
|
|
||||||
messages, err := bot.SendMediaGroup(cfg)
|
messages, err := bot.SendMediaGroup(cfg)
|
||||||
|
@ -524,11 +619,55 @@ func TestSendWithMediaGroup(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if messages == nil {
|
if messages == nil {
|
||||||
t.Error()
|
t.Error("No received messages")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(messages) != 3 {
|
if len(messages) != len(cfg.Media) {
|
||||||
t.Error()
|
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)
|
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 {
|
if err != nil {
|
||||||
panic(err)
|
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() {
|
func ExampleInlineConfig() {
|
||||||
bot, err := NewBotAPI("MyAwesomeBotToken") // create new bot
|
bot, err := NewBotAPI("MyAwesomeBotToken") // create new bot
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -637,7 +823,7 @@ func TestDeleteMessage(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api")
|
||||||
msg.ParseMode = "markdown"
|
msg.ParseMode = ModeMarkdown
|
||||||
message, _ := bot.Send(msg)
|
message, _ := bot.Send(msg)
|
||||||
|
|
||||||
deleteMessageConfig := DeleteMessageConfig{
|
deleteMessageConfig := DeleteMessageConfig{
|
||||||
|
@ -648,7 +834,6 @@ func TestDeleteMessage(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -656,7 +841,7 @@ func TestPinChatMessage(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
||||||
msg.ParseMode = "markdown"
|
msg.ParseMode = ModeMarkdown
|
||||||
message, _ := bot.Send(msg)
|
message, _ := bot.Send(msg)
|
||||||
|
|
||||||
pinChatMessageConfig := PinChatMessageConfig{
|
pinChatMessageConfig := PinChatMessageConfig{
|
||||||
|
@ -668,7 +853,6 @@ func TestPinChatMessage(t *testing.T) {
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -676,7 +860,7 @@ func TestUnpinChatMessage(t *testing.T) {
|
||||||
bot, _ := getBot(t)
|
bot, _ := getBot(t)
|
||||||
|
|
||||||
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
msg := NewMessage(SupergroupChatID, "A test message from the test library in telegram-bot-api")
|
||||||
msg.ParseMode = "markdown"
|
msg.ParseMode = ModeMarkdown
|
||||||
message, _ := bot.Send(msg)
|
message, _ := bot.Send(msg)
|
||||||
|
|
||||||
// We need pin message to unpin something
|
// We need pin message to unpin something
|
||||||
|
@ -688,16 +872,41 @@ func TestUnpinChatMessage(t *testing.T) {
|
||||||
|
|
||||||
if _, err := bot.Request(pinChatMessageConfig); err != nil {
|
if _, err := bot.Request(pinChatMessageConfig); err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unpinChatMessageConfig := UnpinChatMessageConfig{
|
unpinChatMessageConfig := UnpinChatMessageConfig{
|
||||||
ChatID: message.Chat.ID,
|
ChatID: message.Chat.ID,
|
||||||
|
MessageID: message.MessageID,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := bot.Request(unpinChatMessageConfig); err != nil {
|
if _, err := bot.Request(unpinChatMessageConfig); err != nil {
|
||||||
t.Error(err)
|
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)
|
msg, err := bot.Send(poll)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := bot.StopPoll(NewStopPoll(SupergroupChatID, msg.MessageID))
|
result, err := bot.StopPoll(NewStopPoll(SupergroupChatID, msg.MessageID))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error(err)
|
t.Error(err)
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if result.Question != "Are polls working?" {
|
if result.Question != "Are polls working?" {
|
||||||
t.Error("Poll question did not match")
|
t.Error("Poll question did not match")
|
||||||
t.Fail()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if !result.IsClosed {
|
if !result.IsClosed {
|
||||||
t.Error("Poll did not end")
|
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 {
|
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.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")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
1093
configs.go
1093
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
|
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
|
// NewMessageToChannel creates a new Message that is sent to a channel
|
||||||
// by username.
|
// 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 {
|
func NewMessageToChannel(username string, text string) MessageConfig {
|
||||||
return MessageConfig{
|
return MessageConfig{
|
||||||
BaseChat: BaseChat{
|
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,
|
// chatID is where to send it, file is a string path to the file,
|
||||||
// FileReader, or FileBytes.
|
// FileReader, or FileBytes.
|
||||||
//
|
//
|
||||||
// Note that you must send animated GIFs as a document.
|
// 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{
|
return PhotoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPhotoShare shares an existing photo.
|
// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
|
||||||
// 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
|
// Note that you must send animated GIFs as a document.
|
||||||
// already uploaded.
|
func NewPhotoToChannel(username string, file interface{}) PhotoConfig {
|
||||||
func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
|
|
||||||
return PhotoConfig{
|
return PhotoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{
|
||||||
FileID: fileID,
|
ChannelUsername: username,
|
||||||
UseExisting: true,
|
},
|
||||||
|
File: file,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAudioUpload creates a new audio uploader.
|
// NewAudio creates a new sendAudio request.
|
||||||
//
|
func NewAudio(chatID int64, file interface{}) AudioConfig {
|
||||||
// chatID is where to send it, file is a string path to the file,
|
|
||||||
// FileReader, or FileBytes.
|
|
||||||
func NewAudioUpload(chatID int64, file interface{}) AudioConfig {
|
|
||||||
return AudioConfig{
|
return AudioConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAudioShare shares an existing audio file.
|
// NewDocument creates a new sendDocument request.
|
||||||
// You may use this to reshare an existing audio file without
|
func NewDocument(chatID int64, file interface{}) DocumentConfig {
|
||||||
// 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 {
|
|
||||||
return DocumentConfig{
|
return DocumentConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDocumentShare shares an existing document.
|
// NewSticker creates a new sendSticker request.
|
||||||
// You may use this to reshare an existing document without
|
func NewSticker(chatID int64, file interface{}) StickerConfig {
|
||||||
// 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 {
|
|
||||||
return StickerConfig{
|
return StickerConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStickerShare shares an existing sticker.
|
// NewVideo creates a new sendVideo request.
|
||||||
// You may use this to reshare an existing sticker without
|
func NewVideo(chatID int64, file interface{}) VideoConfig {
|
||||||
// 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 {
|
|
||||||
return VideoConfig{
|
return VideoConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVideoShare shares an existing video.
|
// NewAnimation creates a new sendAnimation request.
|
||||||
// You may use this to reshare an existing video without reuploading it.
|
func NewAnimation(chatID int64, file interface{}) AnimationConfig {
|
||||||
//
|
|
||||||
// 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 {
|
|
||||||
return AnimationConfig{
|
return AnimationConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewAnimationShare shares an existing animation.
|
// NewVideoNote creates a new sendVideoNote request.
|
||||||
// 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.
|
|
||||||
//
|
//
|
||||||
// chatID is where to send it, file is a string path to the file,
|
// chatID is where to send it, file is a string path to the file,
|
||||||
// FileReader, or FileBytes.
|
// FileReader, or FileBytes.
|
||||||
func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig {
|
func NewVideoNote(chatID int64, length int, file interface{}) VideoNoteConfig {
|
||||||
return VideoNoteConfig{
|
return VideoNoteConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
File: file,
|
||||||
UseExisting: false,
|
|
||||||
},
|
},
|
||||||
Length: length,
|
Length: length,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewVideoNoteShare shares an existing video.
|
// NewVoice creates a new sendVoice request.
|
||||||
// You may use this to reshare an existing video without reuploading it.
|
func NewVoice(chatID int64, file interface{}) VoiceConfig {
|
||||||
//
|
|
||||||
// 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 {
|
|
||||||
return VoiceConfig{
|
return VoiceConfig{
|
||||||
BaseFile: BaseFile{
|
BaseFile: BaseFile{
|
||||||
BaseChat: BaseChat{ChatID: chatID},
|
BaseChat: BaseChat{ChatID: chatID},
|
||||||
File: file,
|
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.
|
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||||
func NewInputMediaPhoto(media string) InputMediaPhoto {
|
func NewInputMediaPhoto(media interface{}) InputMediaPhoto {
|
||||||
return InputMediaPhoto{
|
return InputMediaPhoto{
|
||||||
BaseInputMedia{
|
BaseInputMedia{
|
||||||
Type: "photo",
|
Type: "photo",
|
||||||
|
@ -310,7 +187,7 @@ func NewInputMediaPhoto(media string) InputMediaPhoto {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputMediaVideo creates a new InputMediaVideo.
|
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||||
func NewInputMediaVideo(media string) InputMediaVideo {
|
func NewInputMediaVideo(media interface{}) InputMediaVideo {
|
||||||
return InputMediaVideo{
|
return InputMediaVideo{
|
||||||
BaseInputMedia: BaseInputMedia{
|
BaseInputMedia: BaseInputMedia{
|
||||||
Type: "video",
|
Type: "video",
|
||||||
|
@ -320,7 +197,7 @@ func NewInputMediaVideo(media string) InputMediaVideo {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
||||||
func NewInputMediaAnimation(media string) InputMediaAnimation {
|
func NewInputMediaAnimation(media interface{}) InputMediaAnimation {
|
||||||
return InputMediaAnimation{
|
return InputMediaAnimation{
|
||||||
BaseInputMedia: BaseInputMedia{
|
BaseInputMedia: BaseInputMedia{
|
||||||
Type: "animation",
|
Type: "animation",
|
||||||
|
@ -330,7 +207,7 @@ func NewInputMediaAnimation(media string) InputMediaAnimation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputMediaAudio creates a new InputMediaAudio.
|
// NewInputMediaAudio creates a new InputMediaAudio.
|
||||||
func NewInputMediaAudio(media string) InputMediaAudio {
|
func NewInputMediaAudio(media interface{}) InputMediaAudio {
|
||||||
return InputMediaAudio{
|
return InputMediaAudio{
|
||||||
BaseInputMedia: BaseInputMedia{
|
BaseInputMedia: BaseInputMedia{
|
||||||
Type: "audio",
|
Type: "audio",
|
||||||
|
@ -340,7 +217,7 @@ func NewInputMediaAudio(media string) InputMediaAudio {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInputMediaDocument creates a new InputMediaDocument.
|
// NewInputMediaDocument creates a new InputMediaDocument.
|
||||||
func NewInputMediaDocument(media string) InputMediaDocument {
|
func NewInputMediaDocument(media interface{}) InputMediaDocument {
|
||||||
return InputMediaDocument{
|
return InputMediaDocument{
|
||||||
BaseInputMedia: BaseInputMedia{
|
BaseInputMedia: BaseInputMedia{
|
||||||
Type: "document",
|
Type: "document",
|
||||||
|
@ -400,7 +277,7 @@ func NewChatAction(chatID int64, action string) ChatActionConfig {
|
||||||
// NewUserProfilePhotos gets user profile photos.
|
// NewUserProfilePhotos gets user profile photos.
|
||||||
//
|
//
|
||||||
// userID is the ID of the user you wish to get profile photos from.
|
// 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{
|
return UserProfilePhotosConfig{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Offset: 0,
|
Offset: 0,
|
||||||
|
@ -423,25 +300,33 @@ func NewUpdate(offset int) UpdateConfig {
|
||||||
// NewWebhook creates a new webhook.
|
// NewWebhook creates a new webhook.
|
||||||
//
|
//
|
||||||
// link is the url parsable link you wish to get the updates.
|
// link is the url parsable link you wish to get the updates.
|
||||||
func NewWebhook(link string) WebhookConfig {
|
func NewWebhook(link string) (WebhookConfig, error) {
|
||||||
u, _ := url.Parse(link)
|
u, err := url.Parse(link)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return WebhookConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return WebhookConfig{
|
return WebhookConfig{
|
||||||
URL: u,
|
URL: u,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWebhookWithCert creates a new webhook with a certificate.
|
// NewWebhookWithCert creates a new webhook with a certificate.
|
||||||
//
|
//
|
||||||
// link is the url you wish to get webhooks,
|
// link is the url you wish to get webhooks,
|
||||||
// file contains a string to a file, FileReader, or FileBytes.
|
// file contains a string to a file, FileReader, or FileBytes.
|
||||||
func NewWebhookWithCert(link string, file interface{}) WebhookConfig {
|
func NewWebhookWithCert(link string, file interface{}) (WebhookConfig, error) {
|
||||||
u, _ := url.Parse(link)
|
u, err := url.Parse(link)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return WebhookConfig{}, err
|
||||||
|
}
|
||||||
|
|
||||||
return WebhookConfig{
|
return WebhookConfig{
|
||||||
URL: u,
|
URL: u,
|
||||||
Certificate: file,
|
Certificate: file,
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewInlineQueryResultArticle creates a new inline query article.
|
// 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.
|
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
||||||
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle {
|
||||||
return 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.
|
// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF.
|
||||||
func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF {
|
||||||
return 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.
|
// NewInlineQueryResultPhoto creates a new inline query photo.
|
||||||
func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto {
|
func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto {
|
||||||
return 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.
|
// NewInlineQueryResultVideo creates a new inline query video.
|
||||||
func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo {
|
func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo {
|
||||||
return 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.
|
// NewInlineQueryResultAudio creates a new inline query audio.
|
||||||
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio {
|
||||||
return 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.
|
// NewInlineQueryResultVoice creates a new inline query voice.
|
||||||
func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice {
|
func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice {
|
||||||
return 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.
|
// NewInlineQueryResultDocument creates a new inline query document.
|
||||||
func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument {
|
func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument {
|
||||||
return 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.
|
// NewInlineQueryResultLocation creates a new inline query location.
|
||||||
func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation {
|
func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation {
|
||||||
return 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.
|
// NewEditMessageText allows you to edit the text of a message.
|
||||||
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
|
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig {
|
||||||
return 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.
|
// NewEditMessageCaption allows you to edit the caption of a message.
|
||||||
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig {
|
||||||
return 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
|
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
||||||
// or hiding for everyone.
|
// or hiding for everyone.
|
||||||
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove {
|
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
|
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
||||||
// and data for a callback.
|
// and data for a callback.
|
||||||
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton {
|
||||||
|
@ -758,37 +752,6 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP
|
||||||
Prices: prices}
|
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.
|
// NewChatTitle allows you to update the title of a chat.
|
||||||
func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
|
func NewChatTitle(chatID int64, title string) SetChatTitleConfig {
|
||||||
return SetChatTitleConfig{
|
return SetChatTitleConfig{
|
||||||
|
@ -832,6 +795,7 @@ func NewPoll(chatID int64, question string, options ...string) SendPollConfig {
|
||||||
},
|
},
|
||||||
Question: question,
|
Question: question,
|
||||||
Options: options,
|
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"
|
"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) {
|
func TestNewInlineQueryResultArticle(t *testing.T) {
|
||||||
result := NewInlineQueryResultArticle("id", "title", "message")
|
result := NewInlineQueryResultArticle("id", "title", "message")
|
||||||
|
|
||||||
|
@ -176,8 +201,8 @@ func TestNewEditMessageCaption(t *testing.T) {
|
||||||
func TestNewEditMessageReplyMarkup(t *testing.T) {
|
func TestNewEditMessageReplyMarkup(t *testing.T) {
|
||||||
markup := InlineKeyboardMarkup{
|
markup := InlineKeyboardMarkup{
|
||||||
InlineKeyboard: [][]InlineKeyboardButton{
|
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.
|
// AddNonZeroFloat adds a floating point value that is not zero.
|
||||||
func (p Params) AddNonZeroFloat(key string, value float64) {
|
func (p Params) AddNonZeroFloat(key string, value float64) {
|
||||||
if value != 0 {
|
if value != 0 {
|
||||||
|
@ -76,14 +69,17 @@ func (p Params) AddFirstValid(key string, args ...interface{}) error {
|
||||||
case int:
|
case int:
|
||||||
if v != 0 {
|
if v != 0 {
|
||||||
p[key] = strconv.Itoa(v)
|
p[key] = strconv.Itoa(v)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
case int64:
|
case int64:
|
||||||
if v != 0 {
|
if v != 0 {
|
||||||
p[key] = strconv.FormatInt(v, 10)
|
p[key] = strconv.FormatInt(v, 10)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
case string:
|
case string:
|
||||||
if v != "" {
|
if v != "" {
|
||||||
p[key] = v
|
p[key] = v
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
case nil:
|
case nil:
|
||||||
default:
|
default:
|
||||||
|
@ -93,6 +89,7 @@ func (p Params) AddFirstValid(key string, args ...interface{}) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
p[key] = string(b)
|
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
|
// Unique identifier for this file
|
||||||
FileID string `json:"file_id"`
|
FileID string `json:"file_id"`
|
||||||
|
|
||||||
|
FileUniqueID string `json:"file_unique_id"`
|
||||||
|
|
||||||
// File size
|
// File size
|
||||||
FileSize int `json:"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) {
|
func TestFileLink(t *testing.T) {
|
||||||
file := File{FilePath: "test/test.txt"}
|
file := File{FilePath: "test/test.txt"}
|
||||||
|
|
||||||
|
@ -203,31 +283,53 @@ var (
|
||||||
_ Chattable = AudioConfig{}
|
_ Chattable = AudioConfig{}
|
||||||
_ Chattable = CallbackConfig{}
|
_ Chattable = CallbackConfig{}
|
||||||
_ Chattable = ChatActionConfig{}
|
_ Chattable = ChatActionConfig{}
|
||||||
|
_ Chattable = ChatAdministratorsConfig{}
|
||||||
|
_ Chattable = ChatInfoConfig{}
|
||||||
|
_ Chattable = ChatInviteLinkConfig{}
|
||||||
|
_ Chattable = CloseConfig{}
|
||||||
_ Chattable = ContactConfig{}
|
_ Chattable = ContactConfig{}
|
||||||
|
_ Chattable = CopyMessageConfig{}
|
||||||
|
_ Chattable = CreateChatInviteLinkConfig{}
|
||||||
_ Chattable = DeleteChatPhotoConfig{}
|
_ Chattable = DeleteChatPhotoConfig{}
|
||||||
_ Chattable = DeleteChatStickerSetConfig{}
|
_ Chattable = DeleteChatStickerSetConfig{}
|
||||||
_ Chattable = DeleteMessageConfig{}
|
_ Chattable = DeleteMessageConfig{}
|
||||||
|
_ Chattable = DeleteWebhookConfig{}
|
||||||
_ Chattable = DocumentConfig{}
|
_ Chattable = DocumentConfig{}
|
||||||
|
_ Chattable = EditChatInviteLinkConfig{}
|
||||||
_ Chattable = EditMessageCaptionConfig{}
|
_ Chattable = EditMessageCaptionConfig{}
|
||||||
_ Chattable = EditMessageLiveLocationConfig{}
|
_ Chattable = EditMessageLiveLocationConfig{}
|
||||||
|
_ Chattable = EditMessageMediaConfig{}
|
||||||
_ Chattable = EditMessageReplyMarkupConfig{}
|
_ Chattable = EditMessageReplyMarkupConfig{}
|
||||||
_ Chattable = EditMessageTextConfig{}
|
_ Chattable = EditMessageTextConfig{}
|
||||||
|
_ Chattable = FileConfig{}
|
||||||
_ Chattable = ForwardConfig{}
|
_ Chattable = ForwardConfig{}
|
||||||
_ Chattable = GameConfig{}
|
_ Chattable = GameConfig{}
|
||||||
|
_ Chattable = GetChatMemberConfig{}
|
||||||
_ Chattable = GetGameHighScoresConfig{}
|
_ Chattable = GetGameHighScoresConfig{}
|
||||||
_ Chattable = InlineConfig{}
|
_ Chattable = InlineConfig{}
|
||||||
_ Chattable = InvoiceConfig{}
|
_ Chattable = InvoiceConfig{}
|
||||||
_ Chattable = KickChatMemberConfig{}
|
_ Chattable = KickChatMemberConfig{}
|
||||||
|
_ Chattable = LeaveChatConfig{}
|
||||||
_ Chattable = LocationConfig{}
|
_ Chattable = LocationConfig{}
|
||||||
|
_ Chattable = LogOutConfig{}
|
||||||
_ Chattable = MediaGroupConfig{}
|
_ Chattable = MediaGroupConfig{}
|
||||||
_ Chattable = MessageConfig{}
|
_ Chattable = MessageConfig{}
|
||||||
_ Chattable = PhotoConfig{}
|
_ Chattable = PhotoConfig{}
|
||||||
_ Chattable = PinChatMessageConfig{}
|
_ Chattable = PinChatMessageConfig{}
|
||||||
|
_ Chattable = PreCheckoutConfig{}
|
||||||
|
_ Chattable = PromoteChatMemberConfig{}
|
||||||
|
_ Chattable = RestrictChatMemberConfig{}
|
||||||
|
_ Chattable = RevokeChatInviteLinkConfig{}
|
||||||
|
_ Chattable = SendPollConfig{}
|
||||||
_ Chattable = SetChatDescriptionConfig{}
|
_ Chattable = SetChatDescriptionConfig{}
|
||||||
_ Chattable = SetChatPhotoConfig{}
|
_ Chattable = SetChatPhotoConfig{}
|
||||||
_ Chattable = SetChatTitleConfig{}
|
_ Chattable = SetChatTitleConfig{}
|
||||||
_ Chattable = SetGameScoreConfig{}
|
_ Chattable = SetGameScoreConfig{}
|
||||||
|
_ Chattable = ShippingConfig{}
|
||||||
_ Chattable = StickerConfig{}
|
_ Chattable = StickerConfig{}
|
||||||
|
_ Chattable = StopMessageLiveLocationConfig{}
|
||||||
|
_ Chattable = StopPollConfig{}
|
||||||
|
_ Chattable = UnbanChatMemberConfig{}
|
||||||
_ Chattable = UnpinChatMessageConfig{}
|
_ Chattable = UnpinChatMessageConfig{}
|
||||||
_ Chattable = UpdateConfig{}
|
_ Chattable = UpdateConfig{}
|
||||||
_ Chattable = UserProfilePhotosConfig{}
|
_ Chattable = UserProfilePhotosConfig{}
|
||||||
|
@ -237,3 +339,24 @@ var (
|
||||||
_ Chattable = VoiceConfig{}
|
_ Chattable = VoiceConfig{}
|
||||||
_ Chattable = WebhookConfig{}
|
_ 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