main
parent
89f3bdeeec
commit
ffc70d4648
14 changed files with 7948 additions and 0 deletions
@ -0,0 +1,4 @@ |
|||||||
|
.idea/ |
||||||
|
coverage.out |
||||||
|
tmp/ |
||||||
|
book/ |
@ -0,0 +1,21 @@ |
|||||||
|
The MIT License (MIT) |
||||||
|
|
||||||
|
Copyright (c) 2015 Syfaro |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||||
|
of this software and associated documentation files (the "Software"), to deal |
||||||
|
in the Software without restriction, including without limitation the rights |
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||||
|
copies of the Software, and to permit persons to whom the Software is |
||||||
|
furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all |
||||||
|
copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||||
|
SOFTWARE. |
@ -0,0 +1,121 @@ |
|||||||
|
# Golang bindings for the Telegram Bot API |
||||||
|
|
||||||
|
[](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) |
||||||
|
[](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml) |
||||||
|
|
||||||
|
All methods are fairly self-explanatory, and reading the [godoc](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) page should |
||||||
|
explain everything. If something isn't clear, open an issue or submit |
||||||
|
a pull request. |
||||||
|
|
||||||
|
There are more tutorials and high-level information on the website, [go-telegram-bot-api.dev](https://go-telegram-bot-api.dev). |
||||||
|
|
||||||
|
The scope of this project is just to provide a wrapper around the API |
||||||
|
without any additional features. There are other projects for creating |
||||||
|
something with plugins and command handlers without having to design |
||||||
|
all that yourself. |
||||||
|
|
||||||
|
Join [the development group](https://telegram.me/go_telegram_bot_api) if |
||||||
|
you want to ask questions or discuss development. |
||||||
|
|
||||||
|
## Example |
||||||
|
|
||||||
|
First, ensure the library is installed and up to date by running |
||||||
|
`go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5`. |
||||||
|
|
||||||
|
This is a very simple bot that just displays any gotten updates, |
||||||
|
then replies it to that chat. |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
|
||||||
|
tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") |
||||||
|
if err != nil { |
||||||
|
log.Panic(err) |
||||||
|
} |
||||||
|
|
||||||
|
bot.Debug = true |
||||||
|
|
||||||
|
log.Printf("Authorized on account %s", bot.Self.UserName) |
||||||
|
|
||||||
|
u := tgbotapi.NewUpdate(0) |
||||||
|
u.Timeout = 60 |
||||||
|
|
||||||
|
updates := bot.GetUpdatesChan(u) |
||||||
|
|
||||||
|
for update := range updates { |
||||||
|
if update.Message != nil { // If we got a message |
||||||
|
log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) |
||||||
|
|
||||||
|
msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) |
||||||
|
msg.ReplyToMessageID = update.Message.MessageID |
||||||
|
|
||||||
|
bot.Send(msg) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
If you need to use webhooks (if you wish to run on Google App Engine), |
||||||
|
you may use a slightly different method. |
||||||
|
|
||||||
|
```go |
||||||
|
package main |
||||||
|
|
||||||
|
import ( |
||||||
|
"log" |
||||||
|
"net/http" |
||||||
|
|
||||||
|
"github.com/go-telegram-bot-api/telegram-bot-api/v5" |
||||||
|
) |
||||||
|
|
||||||
|
func main() { |
||||||
|
bot, err := tgbotapi.NewBotAPI("MyAwesomeBotToken") |
||||||
|
if err != nil { |
||||||
|
log.Fatal(err) |
||||||
|
} |
||||||
|
|
||||||
|
bot.Debug = true |
||||||
|
|
||||||
|
log.Printf("Authorized on account %s", bot.Self.UserName) |
||||||
|
|
||||||
|
wh, _ := tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem") |
||||||
|
|
||||||
|
_, err = bot.SetWebhook(wh) |
||||||
|
if err != nil { |
||||||
|
log.Fatal(err) |
||||||
|
} |
||||||
|
|
||||||
|
info, err := bot.GetWebhookInfo() |
||||||
|
if err != nil { |
||||||
|
log.Fatal(err) |
||||||
|
} |
||||||
|
|
||||||
|
if info.LastErrorDate != 0 { |
||||||
|
log.Printf("Telegram callback failed: %s", info.LastErrorMessage) |
||||||
|
} |
||||||
|
|
||||||
|
updates := bot.ListenForWebhook("/" + bot.Token) |
||||||
|
go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil) |
||||||
|
|
||||||
|
for update := range updates { |
||||||
|
log.Printf("%+v\n", update) |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
If you need, you may generate a self-signed certificate, as this requires |
||||||
|
HTTPS / TLS. The above example tells Telegram that this is your |
||||||
|
certificate and that it should be trusted, even though it is not |
||||||
|
properly signed. |
||||||
|
|
||||||
|
openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3560 -subj "//O=Org\CN=Test" -nodes |
||||||
|
|
||||||
|
Now that [Let's Encrypt](https://letsencrypt.org) is available, |
||||||
|
you may wish to generate your free TLS certificate there. |
@ -0,0 +1,9 @@ |
|||||||
|
[book] |
||||||
|
authors = ["Syfaro"] |
||||||
|
language = "en" |
||||||
|
multilingual = false |
||||||
|
src = "docs" |
||||||
|
title = "Go Telegram Bot API" |
||||||
|
|
||||||
|
[output.html] |
||||||
|
git-repository-url = "https://github.com/go-telegram-bot-api/telegram-bot-api" |
@ -0,0 +1,726 @@ |
|||||||
|
// Package tgbotapi has functions and types used for interacting with
|
||||||
|
// the Telegram Bot API.
|
||||||
|
package tgbotapi |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"errors" |
||||||
|
"fmt" |
||||||
|
"io" |
||||||
|
"io/ioutil" |
||||||
|
"mime/multipart" |
||||||
|
"net/http" |
||||||
|
"net/url" |
||||||
|
"strings" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
|
// HTTPClient is the type needed for the bot to perform HTTP requests.
|
||||||
|
type HTTPClient interface { |
||||||
|
Do(req *http.Request) (*http.Response, error) |
||||||
|
} |
||||||
|
|
||||||
|
// BotAPI allows you to interact with the Telegram Bot API.
|
||||||
|
type BotAPI struct { |
||||||
|
Token string `json:"token"` |
||||||
|
Debug bool `json:"debug"` |
||||||
|
Buffer int `json:"buffer"` |
||||||
|
|
||||||
|
Self User `json:"-"` |
||||||
|
Client HTTPClient `json:"-"` |
||||||
|
shutdownChannel chan interface{} |
||||||
|
|
||||||
|
apiEndpoint string |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotAPI creates a new BotAPI instance.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram.
|
||||||
|
func NewBotAPI(token string) (*BotAPI, error) { |
||||||
|
return NewBotAPIWithClient(token, APIEndpoint, &http.Client{}) |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotAPIWithAPIEndpoint creates a new BotAPI instance
|
||||||
|
// and allows you to pass API endpoint.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
|
func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) { |
||||||
|
return NewBotAPIWithClient(token, apiEndpoint, &http.Client{}) |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotAPIWithClient creates a new BotAPI instance
|
||||||
|
// and allows you to pass a http.Client.
|
||||||
|
//
|
||||||
|
// It requires a token, provided by @BotFather on Telegram and API endpoint.
|
||||||
|
func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) { |
||||||
|
bot := &BotAPI{ |
||||||
|
Token: token, |
||||||
|
Client: client, |
||||||
|
Buffer: 100, |
||||||
|
shutdownChannel: make(chan interface{}), |
||||||
|
|
||||||
|
apiEndpoint: apiEndpoint, |
||||||
|
} |
||||||
|
|
||||||
|
self, err := bot.GetMe() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
bot.Self = self |
||||||
|
|
||||||
|
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) url.Values { |
||||||
|
if in == nil { |
||||||
|
return url.Values{} |
||||||
|
} |
||||||
|
|
||||||
|
out := url.Values{} |
||||||
|
|
||||||
|
for key, value := range in { |
||||||
|
out.Set(key, value) |
||||||
|
} |
||||||
|
|
||||||
|
return out |
||||||
|
} |
||||||
|
|
||||||
|
// MakeRequest makes a request to a specific endpoint with our token.
|
||||||
|
func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) { |
||||||
|
if bot.Debug { |
||||||
|
log.Printf("Endpoint: %s, params: %v\n", endpoint, params) |
||||||
|
} |
||||||
|
|
||||||
|
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) |
||||||
|
|
||||||
|
values := buildParams(params) |
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", method, strings.NewReader(values.Encode())) |
||||||
|
if err != nil { |
||||||
|
return &APIResponse{}, err |
||||||
|
} |
||||||
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") |
||||||
|
|
||||||
|
resp, err := bot.Client.Do(req) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
|
||||||
|
var apiResp APIResponse |
||||||
|
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) |
||||||
|
if err != nil { |
||||||
|
return &apiResp, err |
||||||
|
} |
||||||
|
|
||||||
|
if bot.Debug { |
||||||
|
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) |
||||||
|
} |
||||||
|
|
||||||
|
if !apiResp.Ok { |
||||||
|
var parameters ResponseParameters |
||||||
|
|
||||||
|
if apiResp.Parameters != nil { |
||||||
|
parameters = *apiResp.Parameters |
||||||
|
} |
||||||
|
|
||||||
|
return &apiResp, &Error{ |
||||||
|
Code: apiResp.ErrorCode, |
||||||
|
Message: apiResp.Description, |
||||||
|
ResponseParameters: parameters, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return &apiResp, nil |
||||||
|
} |
||||||
|
|
||||||
|
// decodeAPIResponse decode response and return slice of bytes if debug enabled.
|
||||||
|
// If debug disabled, just decode http.Response.Body stream to APIResponse struct
|
||||||
|
// for efficient memory usage
|
||||||
|
func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) ([]byte, error) { |
||||||
|
if !bot.Debug { |
||||||
|
dec := json.NewDecoder(responseBody) |
||||||
|
err := dec.Decode(resp) |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
// if debug, read response body
|
||||||
|
data, err := ioutil.ReadAll(responseBody) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
err = json.Unmarshal(data, resp) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return data, nil |
||||||
|
} |
||||||
|
|
||||||
|
// UploadFiles makes a request to the API with files.
|
||||||
|
func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) { |
||||||
|
r, w := io.Pipe() |
||||||
|
m := multipart.NewWriter(w) |
||||||
|
|
||||||
|
// 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 { |
||||||
|
if file.Data.NeedsUpload() { |
||||||
|
name, reader, err := file.Data.UploadData() |
||||||
|
if err != nil { |
||||||
|
w.CloseWithError(err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
part, err := m.CreateFormFile(file.Name, name) |
||||||
|
if err != nil { |
||||||
|
w.CloseWithError(err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if _, err := io.Copy(part, reader); err != nil { |
||||||
|
w.CloseWithError(err) |
||||||
|
return |
||||||
|
} |
||||||
|
|
||||||
|
if closer, ok := reader.(io.ReadCloser); ok { |
||||||
|
if err = closer.Close(); err != nil { |
||||||
|
w.CloseWithError(err) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
value := file.Data.SendData() |
||||||
|
|
||||||
|
if err := m.WriteField(file.Name, value); err != nil { |
||||||
|
w.CloseWithError(err) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
if bot.Debug { |
||||||
|
log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files)) |
||||||
|
} |
||||||
|
|
||||||
|
method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) |
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", method, r) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
req.Header.Set("Content-Type", m.FormDataContentType()) |
||||||
|
|
||||||
|
resp, err := bot.Client.Do(req) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
defer resp.Body.Close() |
||||||
|
|
||||||
|
var apiResp APIResponse |
||||||
|
bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) |
||||||
|
if err != nil { |
||||||
|
return &apiResp, err |
||||||
|
} |
||||||
|
|
||||||
|
if bot.Debug { |
||||||
|
log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) |
||||||
|
} |
||||||
|
|
||||||
|
if !apiResp.Ok { |
||||||
|
var parameters ResponseParameters |
||||||
|
|
||||||
|
if apiResp.Parameters != nil { |
||||||
|
parameters = *apiResp.Parameters |
||||||
|
} |
||||||
|
|
||||||
|
return &apiResp, &Error{ |
||||||
|
Message: apiResp.Description, |
||||||
|
ResponseParameters: parameters, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return &apiResp, nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetFileDirectURL returns direct URL to file
|
||||||
|
//
|
||||||
|
// It requires the FileID.
|
||||||
|
func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) { |
||||||
|
file, err := bot.GetFile(FileConfig{fileID}) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
|
||||||
|
return file.Link(bot.Token), nil |
||||||
|
} |
||||||
|
|
||||||
|
// GetMe fetches the currently authenticated bot.
|
||||||
|
//
|
||||||
|
// This method is called upon creation to validate the token,
|
||||||
|
// and so you may get this data from BotAPI.Self without the need for
|
||||||
|
// another request.
|
||||||
|
func (bot *BotAPI) GetMe() (User, error) { |
||||||
|
resp, err := bot.MakeRequest("getMe", nil) |
||||||
|
if err != nil { |
||||||
|
return User{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var user User |
||||||
|
err = json.Unmarshal(resp.Result, &user) |
||||||
|
|
||||||
|
return user, err |
||||||
|
} |
||||||
|
|
||||||
|
// IsMessageToMe returns true if message directed to this bot.
|
||||||
|
//
|
||||||
|
// It requires the Message.
|
||||||
|
func (bot *BotAPI) IsMessageToMe(message Message) bool { |
||||||
|
return strings.Contains(message.Text, "@"+bot.Self.UserName) |
||||||
|
} |
||||||
|
|
||||||
|
func hasFilesNeedingUpload(files []RequestFile) bool { |
||||||
|
for _, file := range files { |
||||||
|
if file.Data.NeedsUpload() { |
||||||
|
return true |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false |
||||||
|
} |
||||||
|
|
||||||
|
// Request sends a Chattable to Telegram, and returns the APIResponse.
|
||||||
|
func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) { |
||||||
|
params, err := c.params() |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
if t, ok := c.(Fileable); ok { |
||||||
|
files := t.files() |
||||||
|
|
||||||
|
// If we have files that need to be uploaded, we should delegate the
|
||||||
|
// request to UploadFile.
|
||||||
|
if hasFilesNeedingUpload(files) { |
||||||
|
return bot.UploadFiles(t.method(), params, files) |
||||||
|
} |
||||||
|
|
||||||
|
// 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 { |
||||||
|
params[file.Name] = file.Data.SendData() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return bot.MakeRequest(c.method(), params) |
||||||
|
} |
||||||
|
|
||||||
|
// Send will send a Chattable item to Telegram and provides the
|
||||||
|
// returned Message.
|
||||||
|
func (bot *BotAPI) Send(c Chattable) (Message, error) { |
||||||
|
resp, err := bot.Request(c) |
||||||
|
if err != nil { |
||||||
|
return Message{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var message Message |
||||||
|
err = json.Unmarshal(resp.Result, &message) |
||||||
|
|
||||||
|
return message, err |
||||||
|
} |
||||||
|
|
||||||
|
// SendMediaGroup sends a media group and returns the resulting messages.
|
||||||
|
func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
var messages []Message |
||||||
|
err = json.Unmarshal(resp.Result, &messages) |
||||||
|
|
||||||
|
return messages, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetUserProfilePhotos gets a user's profile photos.
|
||||||
|
//
|
||||||
|
// It requires UserID.
|
||||||
|
// Offset and Limit are optional.
|
||||||
|
func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return UserProfilePhotos{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var profilePhotos UserProfilePhotos |
||||||
|
err = json.Unmarshal(resp.Result, &profilePhotos) |
||||||
|
|
||||||
|
return profilePhotos, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetFile returns a File which can download a file from Telegram.
|
||||||
|
//
|
||||||
|
// Requires FileID.
|
||||||
|
func (bot *BotAPI) GetFile(config FileConfig) (File, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return File{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var file File |
||||||
|
err = json.Unmarshal(resp.Result, &file) |
||||||
|
|
||||||
|
return file, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetUpdates fetches updates.
|
||||||
|
// If a WebHook is set, this will not return any data!
|
||||||
|
//
|
||||||
|
// Offset, Limit, Timeout, and AllowedUpdates are optional.
|
||||||
|
// To avoid stale items, set Offset to one higher than the previous item.
|
||||||
|
// Set Timeout to a large number to reduce requests, so you can get updates
|
||||||
|
// instantly instead of having to wait between requests.
|
||||||
|
func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return []Update{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var updates []Update |
||||||
|
err = json.Unmarshal(resp.Result, &updates) |
||||||
|
|
||||||
|
return updates, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetWebhookInfo allows you to fetch information about a webhook and if
|
||||||
|
// one currently is set, along with pending update count and error messages.
|
||||||
|
func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) { |
||||||
|
resp, err := bot.MakeRequest("getWebhookInfo", nil) |
||||||
|
if err != nil { |
||||||
|
return WebhookInfo{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var info WebhookInfo |
||||||
|
err = json.Unmarshal(resp.Result, &info) |
||||||
|
|
||||||
|
return info, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetUpdatesChan starts and returns a channel for getting updates.
|
||||||
|
func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel { |
||||||
|
ch := make(chan Update, bot.Buffer) |
||||||
|
|
||||||
|
go func() { |
||||||
|
for { |
||||||
|
select { |
||||||
|
case <-bot.shutdownChannel: |
||||||
|
close(ch) |
||||||
|
return |
||||||
|
default: |
||||||
|
} |
||||||
|
|
||||||
|
updates, err := bot.GetUpdates(config) |
||||||
|
if err != nil { |
||||||
|
log.Println(err) |
||||||
|
log.Println("Failed to get updates, retrying in 3 seconds...") |
||||||
|
time.Sleep(time.Second * 3) |
||||||
|
|
||||||
|
continue |
||||||
|
} |
||||||
|
|
||||||
|
for _, update := range updates { |
||||||
|
if update.UpdateID >= config.Offset { |
||||||
|
config.Offset = update.UpdateID + 1 |
||||||
|
ch <- update |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
}() |
||||||
|
|
||||||
|
return ch |
||||||
|
} |
||||||
|
|
||||||
|
// StopReceivingUpdates stops the go routine which receives updates
|
||||||
|
func (bot *BotAPI) StopReceivingUpdates() { |
||||||
|
if bot.Debug { |
||||||
|
log.Println("Stopping the update receiver routine...") |
||||||
|
} |
||||||
|
close(bot.shutdownChannel) |
||||||
|
} |
||||||
|
|
||||||
|
// ListenForWebhook registers a http handler for a webhook.
|
||||||
|
func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel { |
||||||
|
ch := make(chan Update, bot.Buffer) |
||||||
|
|
||||||
|
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { |
||||||
|
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 |
||||||
|
} |
||||||
|
|
||||||
|
ch <- *update |
||||||
|
}) |
||||||
|
|
||||||
|
return ch |
||||||
|
} |
||||||
|
|
||||||
|
// ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook.
|
||||||
|
func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel { |
||||||
|
ch := make(chan Update, bot.Buffer) |
||||||
|
|
||||||
|
func(w http.ResponseWriter, r *http.Request) { |
||||||
|
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 |
||||||
|
} |
||||||
|
|
||||||
|
ch <- *update |
||||||
|
close(ch) |
||||||
|
}(w, r) |
||||||
|
|
||||||
|
return ch |
||||||
|
} |
||||||
|
|
||||||
|
// HandleUpdate parses and returns update received via webhook
|
||||||
|
func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) { |
||||||
|
if r.Method != http.MethodPost { |
||||||
|
err := errors.New("wrong HTTP method required POST") |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
var update Update |
||||||
|
err := json.NewDecoder(r.Body).Decode(&update) |
||||||
|
if err != nil { |
||||||
|
return nil, err |
||||||
|
} |
||||||
|
|
||||||
|
return &update, nil |
||||||
|
} |
||||||
|
|
||||||
|
// WriteToHTTPResponse writes the request to the HTTP ResponseWriter.
|
||||||
|
//
|
||||||
|
// It doesn't support uploading files.
|
||||||
|
//
|
||||||
|
// See https://core.telegram.org/bots/api#making-requests-when-getting-updates
|
||||||
|
// for details.
|
||||||
|
func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error { |
||||||
|
params, err := c.params() |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
if t, ok := c.(Fileable); ok { |
||||||
|
if hasFilesNeedingUpload(t.files()) { |
||||||
|
return errors.New("unable to use http response to upload files") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
values := buildParams(params) |
||||||
|
values.Set("method", c.method()) |
||||||
|
|
||||||
|
w.Header().Set("Content-Type", "application/x-www-form-urlencoded") |
||||||
|
_, err = w.Write([]byte(values.Encode())) |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
// GetChat gets information about a chat.
|
||||||
|
func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return Chat{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var chat Chat |
||||||
|
err = json.Unmarshal(resp.Result, &chat) |
||||||
|
|
||||||
|
return chat, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetChatAdministrators gets a list of administrators in the chat.
|
||||||
|
//
|
||||||
|
// If none have been appointed, only the creator will be returned.
|
||||||
|
// Bots are not shown, even if they are an administrator.
|
||||||
|
func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return []ChatMember{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var members []ChatMember |
||||||
|
err = json.Unmarshal(resp.Result, &members) |
||||||
|
|
||||||
|
return members, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetChatMembersCount gets the number of users in a chat.
|
||||||
|
func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return -1, err |
||||||
|
} |
||||||
|
|
||||||
|
var count int |
||||||
|
err = json.Unmarshal(resp.Result, &count) |
||||||
|
|
||||||
|
return count, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetChatMember gets a specific chat member.
|
||||||
|
func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return ChatMember{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var member ChatMember |
||||||
|
err = json.Unmarshal(resp.Result, &member) |
||||||
|
|
||||||
|
return member, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetGameHighScores allows you to get the high scores for a game.
|
||||||
|
func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return []GameHighScore{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var highScores []GameHighScore |
||||||
|
err = json.Unmarshal(resp.Result, &highScores) |
||||||
|
|
||||||
|
return highScores, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetInviteLink get InviteLink for a chat
|
||||||
|
func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return "", err |
||||||
|
} |
||||||
|
|
||||||
|
var inviteLink string |
||||||
|
err = json.Unmarshal(resp.Result, &inviteLink) |
||||||
|
|
||||||
|
return inviteLink, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetStickerSet returns a StickerSet.
|
||||||
|
func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return StickerSet{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var stickers StickerSet |
||||||
|
err = json.Unmarshal(resp.Result, &stickers) |
||||||
|
|
||||||
|
return stickers, err |
||||||
|
} |
||||||
|
|
||||||
|
// StopPoll stops a poll and returns the result.
|
||||||
|
func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) { |
||||||
|
resp, err := bot.Request(config) |
||||||
|
if err != nil { |
||||||
|
return Poll{}, err |
||||||
|
} |
||||||
|
|
||||||
|
var poll Poll |
||||||
|
err = json.Unmarshal(resp.Result, &poll) |
||||||
|
|
||||||
|
return poll, err |
||||||
|
} |
||||||
|
|
||||||
|
// GetMyCommands gets the currently registered commands.
|
||||||
|
func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) { |
||||||
|
return bot.GetMyCommandsWithConfig(GetMyCommandsConfig{}) |
||||||
|
} |
||||||
|
|
||||||
|
// GetMyCommandsWithConfig gets the currently registered commands with a config.
|
||||||
|
func (bot *BotAPI) GetMyCommandsWithConfig(config GetMyCommandsConfig) ([]BotCommand, error) { |
||||||
|
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 |
||||||
|
} |
||||||
|
|
||||||
|
// EscapeText takes an input text and escape Telegram markup symbols.
|
||||||
|
// In this way we can send a text without being afraid of having to escape the characters manually.
|
||||||
|
// Note that you don't have to include the formatting style in the input text, or it will be escaped too.
|
||||||
|
// If there is an error, an empty string will be returned.
|
||||||
|
//
|
||||||
|
// parseMode is the text formatting mode (ModeMarkdown, ModeMarkdownV2 or ModeHTML)
|
||||||
|
// text is the input string that will be escaped
|
||||||
|
func EscapeText(parseMode string, text string) string { |
||||||
|
var replacer *strings.Replacer |
||||||
|
|
||||||
|
if parseMode == ModeHTML { |
||||||
|
replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&") |
||||||
|
} else if parseMode == ModeMarkdown { |
||||||
|
replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[") |
||||||
|
} else if parseMode == ModeMarkdownV2 { |
||||||
|
replacer = strings.NewReplacer( |
||||||
|
"_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(", |
||||||
|
"\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>", |
||||||
|
"#", "\\#", "+", "\\+", "-", "\\-", "=", "\\=", "|", |
||||||
|
"\\|", "{", "\\{", "}", "\\}", ".", "\\.", "!", "\\!", |
||||||
|
) |
||||||
|
} else { |
||||||
|
return "" |
||||||
|
} |
||||||
|
|
||||||
|
return replacer.Replace(text) |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,927 @@ |
|||||||
|
package tgbotapi |
||||||
|
|
||||||
|
import ( |
||||||
|
"net/url" |
||||||
|
) |
||||||
|
|
||||||
|
// NewMessage creates a new Message.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, text is the message text.
|
||||||
|
func NewMessage(chatID int64, text string) MessageConfig { |
||||||
|
return MessageConfig{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChatID: chatID, |
||||||
|
ReplyToMessageID: 0, |
||||||
|
}, |
||||||
|
Text: text, |
||||||
|
DisableWebPagePreview: false, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewDeleteMessage creates a request to delete a message.
|
||||||
|
func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { |
||||||
|
return DeleteMessageConfig{ |
||||||
|
ChatID: chatID, |
||||||
|
MessageID: messageID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewMessageToChannel creates a new Message that is sent to a channel
|
||||||
|
// by username.
|
||||||
|
//
|
||||||
|
// username is the username of the channel, text is the message text,
|
||||||
|
// and the username should be in the form of `@username`.
|
||||||
|
func NewMessageToChannel(username string, text string) MessageConfig { |
||||||
|
return MessageConfig{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChannelUsername: username, |
||||||
|
}, |
||||||
|
Text: text, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewForward creates a new forward.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, fromChatID is the source chat,
|
||||||
|
// and messageID is the ID of the original message.
|
||||||
|
func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { |
||||||
|
return ForwardConfig{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
FromChatID: fromChatID, |
||||||
|
MessageID: messageID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewCopyMessage creates a new copy message.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, fromChatID is the source chat,
|
||||||
|
// and messageID is the ID of the original message.
|
||||||
|
func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig { |
||||||
|
return CopyMessageConfig{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
FromChatID: fromChatID, |
||||||
|
MessageID: messageID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewPhoto creates a new sendPhoto request.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, file is a string path to the file,
|
||||||
|
// FileReader, or FileBytes.
|
||||||
|
//
|
||||||
|
// Note that you must send animated GIFs as a document.
|
||||||
|
func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { |
||||||
|
return PhotoConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewPhotoToChannel creates a new photo uploader to send a photo to a channel.
|
||||||
|
//
|
||||||
|
// Note that you must send animated GIFs as a document.
|
||||||
|
func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { |
||||||
|
return PhotoConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChannelUsername: username, |
||||||
|
}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewAudio creates a new sendAudio request.
|
||||||
|
func NewAudio(chatID int64, file RequestFileData) AudioConfig { |
||||||
|
return AudioConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewDocument creates a new sendDocument request.
|
||||||
|
func NewDocument(chatID int64, file RequestFileData) DocumentConfig { |
||||||
|
return DocumentConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewSticker creates a new sendSticker request.
|
||||||
|
func NewSticker(chatID int64, file RequestFileData) StickerConfig { |
||||||
|
return StickerConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewVideo creates a new sendVideo request.
|
||||||
|
func NewVideo(chatID int64, file RequestFileData) VideoConfig { |
||||||
|
return VideoConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewAnimation creates a new sendAnimation request.
|
||||||
|
func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { |
||||||
|
return AnimationConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewVideoNote creates a new sendVideoNote request.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, file is a string path to the file,
|
||||||
|
// FileReader, or FileBytes.
|
||||||
|
func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig { |
||||||
|
return VideoNoteConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
Length: length, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewVoice creates a new sendVoice request.
|
||||||
|
func NewVoice(chatID int64, file RequestFileData) VoiceConfig { |
||||||
|
return VoiceConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
File: file, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewMediaGroup creates a new media group. Files should be an array of
|
||||||
|
// two to ten InputMediaPhoto or InputMediaVideo.
|
||||||
|
func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig { |
||||||
|
return MediaGroupConfig{ |
||||||
|
ChatID: chatID, |
||||||
|
Media: files, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInputMediaPhoto creates a new InputMediaPhoto.
|
||||||
|
func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto { |
||||||
|
return InputMediaPhoto{ |
||||||
|
BaseInputMedia{ |
||||||
|
Type: "photo", |
||||||
|
Media: media, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInputMediaVideo creates a new InputMediaVideo.
|
||||||
|
func NewInputMediaVideo(media RequestFileData) InputMediaVideo { |
||||||
|
return InputMediaVideo{ |
||||||
|
BaseInputMedia: BaseInputMedia{ |
||||||
|
Type: "video", |
||||||
|
Media: media, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInputMediaAnimation creates a new InputMediaAnimation.
|
||||||
|
func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation { |
||||||
|
return InputMediaAnimation{ |
||||||
|
BaseInputMedia: BaseInputMedia{ |
||||||
|
Type: "animation", |
||||||
|
Media: media, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInputMediaAudio creates a new InputMediaAudio.
|
||||||
|
func NewInputMediaAudio(media RequestFileData) InputMediaAudio { |
||||||
|
return InputMediaAudio{ |
||||||
|
BaseInputMedia: BaseInputMedia{ |
||||||
|
Type: "audio", |
||||||
|
Media: media, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInputMediaDocument creates a new InputMediaDocument.
|
||||||
|
func NewInputMediaDocument(media RequestFileData) InputMediaDocument { |
||||||
|
return InputMediaDocument{ |
||||||
|
BaseInputMedia: BaseInputMedia{ |
||||||
|
Type: "document", |
||||||
|
Media: media, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewContact allows you to send a shared contact.
|
||||||
|
func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig { |
||||||
|
return ContactConfig{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChatID: chatID, |
||||||
|
}, |
||||||
|
PhoneNumber: phoneNumber, |
||||||
|
FirstName: firstName, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewLocation shares your location.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, latitude and longitude are coordinates.
|
||||||
|
func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig { |
||||||
|
return LocationConfig{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChatID: chatID, |
||||||
|
}, |
||||||
|
Latitude: latitude, |
||||||
|
Longitude: longitude, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewVenue allows you to send a venue and its location.
|
||||||
|
func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig { |
||||||
|
return VenueConfig{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChatID: chatID, |
||||||
|
}, |
||||||
|
Title: title, |
||||||
|
Address: address, |
||||||
|
Latitude: latitude, |
||||||
|
Longitude: longitude, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewChatAction sets a chat action.
|
||||||
|
// Actions last for 5 seconds, or until your next action.
|
||||||
|
//
|
||||||
|
// chatID is where to send it, action should be set via Chat constants.
|
||||||
|
func NewChatAction(chatID int64, action string) ChatActionConfig { |
||||||
|
return ChatActionConfig{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
Action: action, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewUserProfilePhotos gets user profile photos.
|
||||||
|
//
|
||||||
|
// userID is the ID of the user you wish to get profile photos from.
|
||||||
|
func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig { |
||||||
|
return UserProfilePhotosConfig{ |
||||||
|
UserID: userID, |
||||||
|
Offset: 0, |
||||||
|
Limit: 0, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewUpdate gets updates since the last Offset.
|
||||||
|
//
|
||||||
|
// offset is the last Update ID to include.
|
||||||
|
// You likely want to set this to the last Update ID plus 1.
|
||||||
|
func NewUpdate(offset int) UpdateConfig { |
||||||
|
return UpdateConfig{ |
||||||
|
Offset: offset, |
||||||
|
Limit: 0, |
||||||
|
Timeout: 0, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewWebhook creates a new webhook.
|
||||||
|
//
|
||||||
|
// link is the url parsable link you wish to get the updates.
|
||||||
|
func NewWebhook(link string) (WebhookConfig, error) { |
||||||
|
u, err := url.Parse(link) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return WebhookConfig{}, err |
||||||
|
} |
||||||
|
|
||||||
|
return WebhookConfig{ |
||||||
|
URL: u, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// NewWebhookWithCert creates a new webhook with a certificate.
|
||||||
|
//
|
||||||
|
// link is the url you wish to get webhooks,
|
||||||
|
// file contains a string to a file, FileReader, or FileBytes.
|
||||||
|
func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) { |
||||||
|
u, err := url.Parse(link) |
||||||
|
|
||||||
|
if err != nil { |
||||||
|
return WebhookConfig{}, err |
||||||
|
} |
||||||
|
|
||||||
|
return WebhookConfig{ |
||||||
|
URL: u, |
||||||
|
Certificate: file, |
||||||
|
}, nil |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultArticle creates a new inline query article.
|
||||||
|
func NewInlineQueryResultArticle(id, title, messageText string) InlineQueryResultArticle { |
||||||
|
return InlineQueryResultArticle{ |
||||||
|
Type: "article", |
||||||
|
ID: id, |
||||||
|
Title: title, |
||||||
|
InputMessageContent: InputTextMessageContent{ |
||||||
|
Text: messageText, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultArticleMarkdown creates a new inline query article with Markdown parsing.
|
||||||
|
func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQueryResultArticle { |
||||||
|
return InlineQueryResultArticle{ |
||||||
|
Type: "article", |
||||||
|
ID: id, |
||||||
|
Title: title, |
||||||
|
InputMessageContent: InputTextMessageContent{ |
||||||
|
Text: messageText, |
||||||
|
ParseMode: "Markdown", |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing.
|
||||||
|
func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle { |
||||||
|
return InlineQueryResultArticle{ |
||||||
|
Type: "article", |
||||||
|
ID: id, |
||||||
|
Title: title, |
||||||
|
InputMessageContent: InputTextMessageContent{ |
||||||
|
Text: messageText, |
||||||
|
ParseMode: "MarkdownV2", |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing.
|
||||||
|
func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle { |
||||||
|
return InlineQueryResultArticle{ |
||||||
|
Type: "article", |
||||||
|
ID: id, |
||||||
|
Title: title, |
||||||
|
InputMessageContent: InputTextMessageContent{ |
||||||
|
Text: messageText, |
||||||
|
ParseMode: "HTML", |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultGIF creates a new inline query GIF.
|
||||||
|
func NewInlineQueryResultGIF(id, url string) InlineQueryResultGIF { |
||||||
|
return InlineQueryResultGIF{ |
||||||
|
Type: "gif", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedGIF create a new inline query with cached photo.
|
||||||
|
func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF { |
||||||
|
return InlineQueryResultCachedGIF{ |
||||||
|
Type: "gif", |
||||||
|
ID: id, |
||||||
|
GIFID: gifID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultMPEG4GIF creates a new inline query MPEG4 GIF.
|
||||||
|
func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF { |
||||||
|
return InlineQueryResultMPEG4GIF{ |
||||||
|
Type: "mpeg4_gif", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF.
|
||||||
|
func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF { |
||||||
|
return InlineQueryResultCachedMPEG4GIF{ |
||||||
|
Type: "mpeg4_gif", |
||||||
|
ID: id, |
||||||
|
MPEG4FileID: MPEG4GIFID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultPhoto creates a new inline query photo.
|
||||||
|
func NewInlineQueryResultPhoto(id, url string) InlineQueryResultPhoto { |
||||||
|
return InlineQueryResultPhoto{ |
||||||
|
Type: "photo", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultPhotoWithThumb creates a new inline query photo.
|
||||||
|
func NewInlineQueryResultPhotoWithThumb(id, url, thumb string) InlineQueryResultPhoto { |
||||||
|
return InlineQueryResultPhoto{ |
||||||
|
Type: "photo", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
ThumbURL: thumb, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedPhoto create a new inline query with cached photo.
|
||||||
|
func NewInlineQueryResultCachedPhoto(id, photoID string) InlineQueryResultCachedPhoto { |
||||||
|
return InlineQueryResultCachedPhoto{ |
||||||
|
Type: "photo", |
||||||
|
ID: id, |
||||||
|
PhotoID: photoID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultVideo creates a new inline query video.
|
||||||
|
func NewInlineQueryResultVideo(id, url string) InlineQueryResultVideo { |
||||||
|
return InlineQueryResultVideo{ |
||||||
|
Type: "video", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedVideo create a new inline query with cached video.
|
||||||
|
func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResultCachedVideo { |
||||||
|
return InlineQueryResultCachedVideo{ |
||||||
|
Type: "video", |
||||||
|
ID: id, |
||||||
|
VideoID: videoID, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedSticker create a new inline query with cached sticker.
|
||||||
|
func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker { |
||||||
|
return InlineQueryResultCachedSticker{ |
||||||
|
Type: "sticker", |
||||||
|
ID: id, |
||||||
|
StickerID: stickerID, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultAudio creates a new inline query audio.
|
||||||
|
func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio { |
||||||
|
return InlineQueryResultAudio{ |
||||||
|
Type: "audio", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedAudio create a new inline query with cached photo.
|
||||||
|
func NewInlineQueryResultCachedAudio(id, audioID string) InlineQueryResultCachedAudio { |
||||||
|
return InlineQueryResultCachedAudio{ |
||||||
|
Type: "audio", |
||||||
|
ID: id, |
||||||
|
AudioID: audioID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultVoice creates a new inline query voice.
|
||||||
|
func NewInlineQueryResultVoice(id, url, title string) InlineQueryResultVoice { |
||||||
|
return InlineQueryResultVoice{ |
||||||
|
Type: "voice", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedVoice create a new inline query with cached photo.
|
||||||
|
func NewInlineQueryResultCachedVoice(id, voiceID, title string) InlineQueryResultCachedVoice { |
||||||
|
return InlineQueryResultCachedVoice{ |
||||||
|
Type: "voice", |
||||||
|
ID: id, |
||||||
|
VoiceID: voiceID, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultDocument creates a new inline query document.
|
||||||
|
func NewInlineQueryResultDocument(id, url, title, mimeType string) InlineQueryResultDocument { |
||||||
|
return InlineQueryResultDocument{ |
||||||
|
Type: "document", |
||||||
|
ID: id, |
||||||
|
URL: url, |
||||||
|
Title: title, |
||||||
|
MimeType: mimeType, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultCachedDocument create a new inline query with cached photo.
|
||||||
|
func NewInlineQueryResultCachedDocument(id, documentID, title string) InlineQueryResultCachedDocument { |
||||||
|
return InlineQueryResultCachedDocument{ |
||||||
|
Type: "document", |
||||||
|
ID: id, |
||||||
|
DocumentID: documentID, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultLocation creates a new inline query location.
|
||||||
|
func NewInlineQueryResultLocation(id, title string, latitude, longitude float64) InlineQueryResultLocation { |
||||||
|
return InlineQueryResultLocation{ |
||||||
|
Type: "location", |
||||||
|
ID: id, |
||||||
|
Title: title, |
||||||
|
Latitude: latitude, |
||||||
|
Longitude: longitude, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineQueryResultVenue creates a new inline query venue.
|
||||||
|
func NewInlineQueryResultVenue(id, title, address string, latitude, longitude float64) InlineQueryResultVenue { |
||||||
|
return InlineQueryResultVenue{ |
||||||
|
Type: "venue", |
||||||
|
ID: id, |
||||||
|
Title: title, |
||||||
|
Address: address, |
||||||
|
Latitude: latitude, |
||||||
|
Longitude: longitude, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewEditMessageText allows you to edit the text of a message.
|
||||||
|
func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig { |
||||||
|
return EditMessageTextConfig{ |
||||||
|
BaseEdit: BaseEdit{ |
||||||
|
ChatID: chatID, |
||||||
|
MessageID: messageID, |
||||||
|
}, |
||||||
|
Text: text, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message.
|
||||||
|
func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig { |
||||||
|
return EditMessageTextConfig{ |
||||||
|
BaseEdit: BaseEdit{ |
||||||
|
ChatID: chatID, |
||||||
|
MessageID: messageID, |
||||||
|
ReplyMarkup: &replyMarkup, |
||||||
|
}, |
||||||
|
Text: text, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewEditMessageCaption allows you to edit the caption of a message.
|
||||||
|
func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig { |
||||||
|
return EditMessageCaptionConfig{ |
||||||
|
BaseEdit: BaseEdit{ |
||||||
|
ChatID: chatID, |
||||||
|
MessageID: messageID, |
||||||
|
}, |
||||||
|
Caption: caption, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewEditMessageReplyMarkup allows you to edit the inline
|
||||||
|
// keyboard markup.
|
||||||
|
func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig { |
||||||
|
return EditMessageReplyMarkupConfig{ |
||||||
|
BaseEdit: BaseEdit{ |
||||||
|
ChatID: chatID, |
||||||
|
MessageID: messageID, |
||||||
|
ReplyMarkup: &replyMarkup, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewRemoveKeyboard hides the keyboard, with the option for being selective
|
||||||
|
// or hiding for everyone.
|
||||||
|
func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove { |
||||||
|
return ReplyKeyboardRemove{ |
||||||
|
RemoveKeyboard: true, |
||||||
|
Selective: selective, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewKeyboardButton creates a regular keyboard button.
|
||||||
|
func NewKeyboardButton(text string) KeyboardButton { |
||||||
|
return KeyboardButton{ |
||||||
|
Text: text, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewKeyboardButtonContact creates a keyboard button that requests
|
||||||
|
// user contact information upon click.
|
||||||
|
func NewKeyboardButtonContact(text string) KeyboardButton { |
||||||
|
return KeyboardButton{ |
||||||
|
Text: text, |
||||||
|
RequestContact: true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewKeyboardButtonLocation creates a keyboard button that requests
|
||||||
|
// user location information upon click.
|
||||||
|
func NewKeyboardButtonLocation(text string) KeyboardButton { |
||||||
|
return KeyboardButton{ |
||||||
|
Text: text, |
||||||
|
RequestLocation: true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewKeyboardButtonRow creates a row of keyboard buttons.
|
||||||
|
func NewKeyboardButtonRow(buttons ...KeyboardButton) []KeyboardButton { |
||||||
|
var row []KeyboardButton |
||||||
|
|
||||||
|
row = append(row, buttons...) |
||||||
|
|
||||||
|
return row |
||||||
|
} |
||||||
|
|
||||||
|
// NewReplyKeyboard creates a new regular keyboard with sane defaults.
|
||||||
|
func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { |
||||||
|
var keyboard [][]KeyboardButton |
||||||
|
|
||||||
|
keyboard = append(keyboard, rows...) |
||||||
|
|
||||||
|
return ReplyKeyboardMarkup{ |
||||||
|
ResizeKeyboard: true, |
||||||
|
Keyboard: keyboard, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewOneTimeReplyKeyboard creates a new one time keyboard.
|
||||||
|
func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { |
||||||
|
markup := NewReplyKeyboard(rows...) |
||||||
|
markup.OneTimeKeyboard = true |
||||||
|
return markup |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineKeyboardButtonData creates an inline keyboard button with text
|
||||||
|
// and data for a callback.
|
||||||
|
func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton { |
||||||
|
return InlineKeyboardButton{ |
||||||
|
Text: text, |
||||||
|
CallbackData: &data, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text
|
||||||
|
// which goes to a LoginURL.
|
||||||
|
func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton { |
||||||
|
return InlineKeyboardButton{ |
||||||
|
Text: text, |
||||||
|
LoginURL: &loginURL, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineKeyboardButtonURL creates an inline keyboard button with text
|
||||||
|
// which goes to a URL.
|
||||||
|
func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { |
||||||
|
return InlineKeyboardButton{ |
||||||
|
Text: text, |
||||||
|
URL: &url, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineKeyboardButtonSwitch creates an inline keyboard button with
|
||||||
|
// text which allows the user to switch to a chat or return to a chat.
|
||||||
|
func NewInlineKeyboardButtonSwitch(text, sw string) InlineKeyboardButton { |
||||||
|
return InlineKeyboardButton{ |
||||||
|
Text: text, |
||||||
|
SwitchInlineQuery: &sw, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineKeyboardRow creates an inline keyboard row with buttons.
|
||||||
|
func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { |
||||||
|
var row []InlineKeyboardButton |
||||||
|
|
||||||
|
row = append(row, buttons...) |
||||||
|
|
||||||
|
return row |
||||||
|
} |
||||||
|
|
||||||
|
// NewInlineKeyboardMarkup creates a new inline keyboard.
|
||||||
|
func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) InlineKeyboardMarkup { |
||||||
|
var keyboard [][]InlineKeyboardButton |
||||||
|
|
||||||
|
keyboard = append(keyboard, rows...) |
||||||
|
|
||||||
|
return InlineKeyboardMarkup{ |
||||||
|
InlineKeyboard: keyboard, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewCallback creates a new callback message.
|
||||||
|
func NewCallback(id, text string) CallbackConfig { |
||||||
|
return CallbackConfig{ |
||||||
|
CallbackQueryID: id, |
||||||
|
Text: text, |
||||||
|
ShowAlert: false, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewCallbackWithAlert creates a new callback message that alerts
|
||||||
|
// the user.
|
||||||
|
func NewCallbackWithAlert(id, text string) CallbackConfig { |
||||||
|
return CallbackConfig{ |
||||||
|
CallbackQueryID: id, |
||||||
|
Text: text, |
||||||
|
ShowAlert: true, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewInvoice creates a new Invoice request to the user.
|
||||||
|
func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig { |
||||||
|
return InvoiceConfig{ |
||||||
|
BaseChat: BaseChat{ChatID: chatID}, |
||||||
|
Title: title, |
||||||
|
Description: description, |
||||||
|
Payload: payload, |
||||||
|
ProviderToken: providerToken, |
||||||
|
StartParameter: startParameter, |
||||||
|
Currency: currency, |
||||||
|
Prices: prices} |
||||||
|
} |
||||||
|
|
||||||
|
// NewChatTitle allows you to update the title of a chat.
|
||||||
|
func NewChatTitle(chatID int64, title string) SetChatTitleConfig { |
||||||
|
return SetChatTitleConfig{ |
||||||
|
ChatID: chatID, |
||||||
|
Title: title, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewChatDescription allows you to update the description of a chat.
|
||||||
|
func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig { |
||||||
|
return SetChatDescriptionConfig{ |
||||||
|
ChatID: chatID, |
||||||
|
Description: description, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewChatPhoto allows you to update the photo for a chat.
|
||||||
|
func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { |
||||||
|
return SetChatPhotoConfig{ |
||||||
|
BaseFile: BaseFile{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChatID: chatID, |
||||||
|
}, |
||||||
|
File: photo, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewDeleteChatPhoto allows you to delete the photo for a chat.
|
||||||
|
func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { |
||||||
|
return DeleteChatPhotoConfig{ |
||||||
|
ChatID: chatID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewPoll allows you to create a new poll.
|
||||||
|
func NewPoll(chatID int64, question string, options ...string) SendPollConfig { |
||||||
|
return SendPollConfig{ |
||||||
|
BaseChat: BaseChat{ |
||||||
|
ChatID: chatID, |
||||||
|
}, |
||||||
|
Question: question, |
||||||
|
Options: options, |
||||||
|
IsAnonymous: true, // This is Telegram's default.
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewStopPoll allows you to stop a poll.
|
||||||
|
func NewStopPoll(chatID int64, messageID int) StopPollConfig { |
||||||
|
return StopPollConfig{ |
||||||
|
BaseEdit{ |
||||||
|
ChatID: chatID, |
||||||
|
MessageID: messageID, |
||||||
|
}, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 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, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeDefault represents the default scope of bot commands.
|
||||||
|
func NewBotCommandScopeDefault() BotCommandScope { |
||||||
|
return BotCommandScope{Type: "default"} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeAllPrivateChats represents the scope of bot commands,
|
||||||
|
// covering all private chats.
|
||||||
|
func NewBotCommandScopeAllPrivateChats() BotCommandScope { |
||||||
|
return BotCommandScope{Type: "all_private_chats"} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeAllGroupChats represents the scope of bot commands,
|
||||||
|
// covering all group and supergroup chats.
|
||||||
|
func NewBotCommandScopeAllGroupChats() BotCommandScope { |
||||||
|
return BotCommandScope{Type: "all_group_chats"} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeAllChatAdministrators represents the scope of bot commands,
|
||||||
|
// covering all group and supergroup chat administrators.
|
||||||
|
func NewBotCommandScopeAllChatAdministrators() BotCommandScope { |
||||||
|
return BotCommandScope{Type: "all_chat_administrators"} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeChat represents the scope of bot commands, covering a
|
||||||
|
// specific chat.
|
||||||
|
func NewBotCommandScopeChat(chatID int64) BotCommandScope { |
||||||
|
return BotCommandScope{ |
||||||
|
Type: "chat", |
||||||
|
ChatID: chatID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeChatAdministrators represents the scope of bot commands,
|
||||||
|
// covering all administrators of a specific group or supergroup chat.
|
||||||
|
func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope { |
||||||
|
return BotCommandScope{ |
||||||
|
Type: "chat_administrators", |
||||||
|
ChatID: chatID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewBotCommandScopeChatMember represents the scope of bot commands, covering a
|
||||||
|
// specific member of a group or supergroup chat.
|
||||||
|
func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope { |
||||||
|
return BotCommandScope{ |
||||||
|
Type: "chat_member", |
||||||
|
ChatID: chatID, |
||||||
|
UserID: userID, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// NewGetMyCommandsWithScope allows you to set the registered commands for a
|
||||||
|
// given scope.
|
||||||
|
func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig { |
||||||
|
return GetMyCommandsConfig{Scope: &scope} |
||||||
|
} |
||||||
|
|
||||||
|
// NewGetMyCommandsWithScopeAndLanguage allows you to set the registered
|
||||||
|
// commands for a given scope and language code.
|
||||||
|
func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig { |
||||||
|
return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} |
||||||
|
} |
||||||
|
|
||||||
|
// NewSetMyCommands allows you to set the registered commands.
|
||||||
|
func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig { |
||||||
|
return SetMyCommandsConfig{Commands: commands} |
||||||
|
} |
||||||
|
|
||||||
|
// NewSetMyCommandsWithScope allows you to set the registered commands for a given scope.
|
||||||
|
func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig { |
||||||
|
return SetMyCommandsConfig{Commands: commands, Scope: &scope} |
||||||
|
} |
||||||
|
|
||||||
|
// NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope
|
||||||
|
// and language code.
|
||||||
|
func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig { |
||||||
|
return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode} |
||||||
|
} |
||||||
|
|
||||||
|
// NewDeleteMyCommands allows you to delete the registered commands.
|
||||||
|
func NewDeleteMyCommands() DeleteMyCommandsConfig { |
||||||
|
return DeleteMyCommandsConfig{} |
||||||
|
} |
||||||
|
|
||||||
|
// NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given
|
||||||
|
// scope.
|
||||||
|
func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig { |
||||||
|
return DeleteMyCommandsConfig{Scope: &scope} |
||||||
|
} |
||||||
|
|
||||||
|
// NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given
|
||||||
|
// scope and language code.
|
||||||
|
func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig { |
||||||
|
return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package tgbotapi |
||||||
|
|
||||||
|
import ( |
||||||
|
"errors" |
||||||
|
stdlog "log" |
||||||
|
"os" |
||||||
|
) |
||||||
|
|
||||||
|
// BotLogger is an interface that represents the required methods to log data.
|
||||||
|
//
|
||||||
|
// Instead of requiring the standard logger, we can just specify the methods we
|
||||||
|
// use and allow users to pass anything that implements these.
|
||||||
|
type BotLogger interface { |
||||||
|
Println(v ...interface{}) |
||||||
|
Printf(format string, v ...interface{}) |
||||||
|
} |
||||||
|
|
||||||
|
var log BotLogger = stdlog.New(os.Stderr, "", stdlog.LstdFlags) |
||||||
|
|
||||||
|
// SetLogger specifies the logger that the package should use.
|
||||||
|
func SetLogger(logger BotLogger) error { |
||||||
|
if logger == nil { |
||||||
|
return errors.New("logger is nil") |
||||||
|
} |
||||||
|
log = logger |
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
package tgbotapi |
||||||
|
|
||||||
|
import ( |
||||||
|
"encoding/json" |
||||||
|
"reflect" |
||||||
|
"strconv" |
||||||
|
) |
||||||
|
|
||||||
|
// Params represents a set of parameters that gets passed to a request.
|
||||||
|
type Params map[string]string |
||||||
|
|
||||||
|
// AddNonEmpty adds a value if it not an empty string.
|
||||||
|
func (p Params) AddNonEmpty(key, value string) { |
||||||
|
if value != "" { |
||||||
|
p[key] = value |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddNonZero adds a value if it is not zero.
|
||||||
|
func (p Params) AddNonZero(key string, value int) { |
||||||
|
if value != 0 { |
||||||
|
p[key] = strconv.Itoa(value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddNonZero64 is the same as AddNonZero except uses an int64.
|
||||||
|
func (p Params) AddNonZero64(key string, value int64) { |
||||||
|
if value != 0 { |
||||||
|
p[key] = strconv.FormatInt(value, 10) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddBool adds a value of a bool if it is true.
|
||||||
|
func (p Params) AddBool(key string, value bool) { |
||||||
|
if value { |
||||||
|
p[key] = strconv.FormatBool(value) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddNonZeroFloat adds a floating point value that is not zero.
|
||||||
|
func (p Params) AddNonZeroFloat(key string, value float64) { |
||||||
|
if value != 0 { |
||||||
|
p[key] = strconv.FormatFloat(value, 'f', 6, 64) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// AddInterface adds an interface if it is not nil and can be JSON marshalled.
|
||||||
|
func (p Params) AddInterface(key string, value interface{}) error { |
||||||
|
if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { |
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
b, err := json.Marshal(value) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
p[key] = string(b) |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
||||||
|
|
||||||
|
// AddFirstValid attempts to add the first item that is not a default value.
|
||||||
|
//
|
||||||
|
// For example, AddFirstValid(0, "", "test") would add "test".
|
||||||
|
func (p Params) AddFirstValid(key string, args ...interface{}) error { |
||||||
|
for _, arg := range args { |
||||||
|
switch v := arg.(type) { |
||||||
|
case int: |
||||||
|
if v != 0 { |
||||||
|
p[key] = strconv.Itoa(v) |
||||||
|
return nil |
||||||
|
} |
||||||
|
case int64: |
||||||
|
if v != 0 { |
||||||
|
p[key] = strconv.FormatInt(v, 10) |
||||||
|
return nil |
||||||
|
} |
||||||
|
case string: |
||||||
|
if v != "" { |
||||||
|
p[key] = v |
||||||
|
return nil |
||||||
|
} |
||||||
|
case nil: |
||||||
|
default: |
||||||
|
b, err := json.Marshal(arg) |
||||||
|
if err != nil { |
||||||
|
return err |
||||||
|
} |
||||||
|
|
||||||
|
p[key] = string(b) |
||||||
|
return nil |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return nil |
||||||
|
} |
@ -0,0 +1,317 @@ |
|||||||
|
package tgbotapi |
||||||
|
|
||||||
|
// PassportRequestInfoConfig allows you to request passport info
|
||||||
|
type PassportRequestInfoConfig struct { |
||||||
|
BotID int `json:"bot_id"` |
||||||
|
Scope *PassportScope `json:"scope"` |
||||||
|
Nonce string `json:"nonce"` |
||||||
|
PublicKey string `json:"public_key"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportScopeElement supports using one or one of several elements.
|
||||||
|
type PassportScopeElement interface { |
||||||
|
ScopeType() string |
||||||
|
} |
||||||
|
|
||||||
|
// PassportScope is the requested scopes of data.
|
||||||
|
type PassportScope struct { |
||||||
|
V int `json:"v"` |
||||||
|
Data []PassportScopeElement `json:"data"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportScopeElementOneOfSeveral allows you to request any one of the
|
||||||
|
// requested documents.
|
||||||
|
type PassportScopeElementOneOfSeveral struct { |
||||||
|
} |
||||||
|
|
||||||
|
// ScopeType is the scope type.
|
||||||
|
func (eo *PassportScopeElementOneOfSeveral) ScopeType() string { |
||||||
|
return "one_of" |
||||||
|
} |
||||||
|
|
||||||
|
// PassportScopeElementOne requires the specified element be provided.
|
||||||
|
type PassportScopeElementOne struct { |
||||||
|
Type string `json:"type"` // One of “personal_details”, “passport”, “driver_license”, “identity_card”, “internal_passport”, “address”, “utility_bill”, “bank_statement”, “rental_agreement”, “passport_registration”, “temporary_registration”, “phone_number”, “email”
|
||||||
|
Selfie bool `json:"selfie"` |
||||||
|
Translation bool `json:"translation"` |
||||||
|
NativeNames bool `json:"native_name"` |
||||||
|
} |
||||||
|
|
||||||
|
// ScopeType is the scope type.
|
||||||
|
func (eo *PassportScopeElementOne) ScopeType() string { |
||||||
|
return "one" |
||||||
|
} |
||||||
|
|
||||||
|
type ( |
||||||
|
// PassportData contains information about Telegram Passport data shared with
|
||||||
|
// the bot by the user.
|
||||||
|
PassportData struct { |
||||||
|
// Array with information about documents and other Telegram Passport
|
||||||
|
// elements that was shared with the bot
|
||||||
|
Data []EncryptedPassportElement `json:"data"` |
||||||
|
|
||||||
|
// Encrypted credentials required to decrypt the data
|
||||||
|
Credentials *EncryptedCredentials `json:"credentials"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportFile represents a file uploaded to Telegram Passport. Currently, all
|
||||||
|
// Telegram Passport files are in JPEG format when decrypted and don't exceed
|
||||||
|
// 10MB.
|
||||||
|
PassportFile struct { |
||||||
|
// Unique identifier for this file
|
||||||
|
FileID string `json:"file_id"` |
||||||
|
|
||||||
|
FileUniqueID string `json:"file_unique_id"` |
||||||
|
|
||||||
|
// File size
|
||||||
|
FileSize int `json:"file_size"` |
||||||
|
|
||||||
|
// Unix time when the file was uploaded
|
||||||
|
FileDate int64 `json:"file_date"` |
||||||
|
} |
||||||
|
|
||||||
|
// EncryptedPassportElement contains information about documents or other
|
||||||
|
// Telegram Passport elements shared with the bot by the user.
|
||||||
|
EncryptedPassportElement struct { |
||||||
|
// Element type.
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// Base64-encoded encrypted Telegram Passport element data provided by
|
||||||
|
// the user, available for "personal_details", "passport",
|
||||||
|
// "driver_license", "identity_card", "identity_passport" and "address"
|
||||||
|
// types. Can be decrypted and verified using the accompanying
|
||||||
|
// EncryptedCredentials.
|
||||||
|
Data string `json:"data,omitempty"` |
||||||
|
|
||||||
|
// User's verified phone number, available only for "phone_number" type
|
||||||
|
PhoneNumber string `json:"phone_number,omitempty"` |
||||||
|
|
||||||
|
// User's verified email address, available only for "email" type
|
||||||
|
Email string `json:"email,omitempty"` |
||||||
|
|
||||||
|
// Array of encrypted files with documents provided by the user,
|
||||||
|
// available for "utility_bill", "bank_statement", "rental_agreement",
|
||||||
|
// "passport_registration" and "temporary_registration" types. Files can
|
||||||
|
// be decrypted and verified using the accompanying EncryptedCredentials.
|
||||||
|
Files []PassportFile `json:"files,omitempty"` |
||||||
|
|
||||||
|
// Encrypted file with the front side of the document, provided by the
|
||||||
|
// user. Available for "passport", "driver_license", "identity_card" and
|
||||||
|
// "internal_passport". The file can be decrypted and verified using the
|
||||||
|
// accompanying EncryptedCredentials.
|
||||||
|
FrontSide *PassportFile `json:"front_side,omitempty"` |
||||||
|
|
||||||
|
// Encrypted file with the reverse side of the document, provided by the
|
||||||
|
// user. Available for "driver_license" and "identity_card". The file can
|
||||||
|
// be decrypted and verified using the accompanying EncryptedCredentials.
|
||||||
|
ReverseSide *PassportFile `json:"reverse_side,omitempty"` |
||||||
|
|
||||||
|
// Encrypted file with the selfie of the user holding a document,
|
||||||
|
// provided by the user; available for "passport", "driver_license",
|
||||||
|
// "identity_card" and "internal_passport". The file can be decrypted
|
||||||
|
// and verified using the accompanying EncryptedCredentials.
|
||||||
|
Selfie *PassportFile `json:"selfie,omitempty"` |
||||||
|
} |
||||||
|
|
||||||
|
// EncryptedCredentials contains data required for decrypting and
|
||||||
|
// authenticating EncryptedPassportElement. See the Telegram Passport
|
||||||
|
// Documentation for a complete description of the data decryption and
|
||||||
|
// authentication processes.
|
||||||
|
EncryptedCredentials struct { |
||||||
|
// Base64-encoded encrypted JSON-serialized data with unique user's
|
||||||
|
// payload, data hashes and secrets required for EncryptedPassportElement
|
||||||
|
// decryption and authentication
|
||||||
|
Data string `json:"data"` |
||||||
|
|
||||||
|
// Base64-encoded data hash for data authentication
|
||||||
|
Hash string `json:"hash"` |
||||||
|
|
||||||
|
// Base64-encoded secret, encrypted with the bot's public RSA key,
|
||||||
|
// required for data decryption
|
||||||
|
Secret string `json:"secret"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportElementError represents an error in the Telegram Passport element
|
||||||
|
// which was submitted that should be resolved by the user.
|
||||||
|
PassportElementError interface{} |
||||||
|
|
||||||
|
// PassportElementErrorDataField represents an issue in one of the data
|
||||||
|
// fields that was provided by the user. The error is considered resolved
|
||||||
|
// when the field's value changes.
|
||||||
|
PassportElementErrorDataField struct { |
||||||
|
// Error source, must be data
|
||||||
|
Source string `json:"source"` |
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the error, one
|
||||||
|
// of "personal_details", "passport", "driver_license", "identity_card",
|
||||||
|
// "internal_passport", "address"
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// Name of the data field which has the error
|
||||||
|
FieldName string `json:"field_name"` |
||||||
|
|
||||||
|
// Base64-encoded data hash
|
||||||
|
DataHash string `json:"data_hash"` |
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportElementErrorFrontSide represents an issue with the front side of
|
||||||
|
// a document. The error is considered resolved when the file with the front
|
||||||
|
// side of the document changes.
|
||||||
|
PassportElementErrorFrontSide struct { |
||||||
|
// Error source, must be front_side
|
||||||
|
Source string `json:"source"` |
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "passport", "driver_license", "identity_card", "internal_passport"
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// Base64-encoded hash of the file with the front side of the document
|
||||||
|
FileHash string `json:"file_hash"` |
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportElementErrorReverseSide represents an issue with the reverse side
|
||||||
|
// of a document. The error is considered resolved when the file with reverse
|
||||||
|
// side of the document changes.
|
||||||
|
PassportElementErrorReverseSide struct { |
||||||
|
// Error source, must be reverse_side
|
||||||
|
Source string `json:"source"` |
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "driver_license", "identity_card"
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// Base64-encoded hash of the file with the reverse side of the document
|
||||||
|
FileHash string `json:"file_hash"` |
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportElementErrorSelfie represents an issue with the selfie with a
|
||||||
|
// document. The error is considered resolved when the file with the selfie
|
||||||
|
// changes.
|
||||||
|
PassportElementErrorSelfie struct { |
||||||
|
// Error source, must be selfie
|
||||||
|
Source string `json:"source"` |
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "passport", "driver_license", "identity_card", "internal_passport"
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// Base64-encoded hash of the file with the selfie
|
||||||
|
FileHash string `json:"file_hash"` |
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportElementErrorFile represents an issue with a document scan. The
|
||||||
|
// error is considered resolved when the file with the document scan changes.
|
||||||
|
PassportElementErrorFile struct { |
||||||
|
// Error source, must be a file
|
||||||
|
Source string `json:"source"` |
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "utility_bill", "bank_statement", "rental_agreement",
|
||||||
|
// "passport_registration", "temporary_registration"
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// Base64-encoded file hash
|
||||||
|
FileHash string `json:"file_hash"` |
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
// PassportElementErrorFiles represents an issue with a list of scans. The
|
||||||
|
// error is considered resolved when the list of files containing the scans
|
||||||
|
// changes.
|
||||||
|
PassportElementErrorFiles struct { |
||||||
|
// Error source, must be files
|
||||||
|
Source string `json:"source"` |
||||||
|
|
||||||
|
// The section of the user's Telegram Passport which has the issue, one
|
||||||
|
// of "utility_bill", "bank_statement", "rental_agreement",
|
||||||
|
// "passport_registration", "temporary_registration"
|
||||||
|
Type string `json:"type"` |
||||||
|
|
||||||
|
// List of base64-encoded file hashes
|
||||||
|
FileHashes []string `json:"file_hashes"` |
||||||
|
|
||||||
|
// Error message
|
||||||
|
Message string `json:"message"` |
||||||
|
} |
||||||
|
|
||||||
|
// Credentials contains encrypted data.
|
||||||
|
Credentials struct { |
||||||
|
Data SecureData `json:"secure_data"` |
||||||
|
// Nonce the same nonce given in the request
|
||||||
|
Nonce string `json:"nonce"` |
||||||
|
} |
||||||
|
|
||||||
|
// SecureData is a map of the fields and their encrypted values.
|
||||||
|
SecureData map[string]*SecureValue |
||||||
|
// PersonalDetails *SecureValue `json:"personal_details"`
|
||||||
|
// Passport *SecureValue `json:"passport"`
|
||||||
|
// InternalPassport *SecureValue `json:"internal_passport"`
|
||||||
|
// DriverLicense *SecureValue `json:"driver_license"`
|
||||||
|
// IdentityCard *SecureValue `json:"identity_card"`
|
||||||
|
// Address *SecureValue `json:"address"`
|
||||||
|
// UtilityBill *SecureValue `json:"utility_bill"`
|
||||||
|
// BankStatement *SecureValue `json:"bank_statement"`
|
||||||
|
// RentalAgreement *SecureValue `json:"rental_agreement"`
|
||||||
|
// PassportRegistration *SecureValue `json:"passport_registration"`
|
||||||
|
// TemporaryRegistration *SecureValue `json:"temporary_registration"`
|
||||||
|
|
||||||
|
// SecureValue contains encrypted values for a SecureData item.
|
||||||
|
SecureValue struct { |
||||||
|
Data *DataCredentials `json:"data"` |
||||||
|
FrontSide *FileCredentials `json:"front_side"` |
||||||
|
ReverseSide *FileCredentials `json:"reverse_side"` |
||||||
|
Selfie *FileCredentials `json:"selfie"` |
||||||
|
Translation []*FileCredentials `json:"translation"` |
||||||
|
Files []*FileCredentials `json:"files"` |
||||||
|
} |
||||||
|
|
||||||
|
// DataCredentials contains information required to decrypt data.
|
||||||
|
DataCredentials struct { |
||||||
|
// DataHash checksum of encrypted data
|
||||||
|
DataHash string `json:"data_hash"` |
||||||
|
// Secret of encrypted data
|
||||||
|
Secret string `json:"secret"` |
||||||
|
} |
||||||
|
|
||||||
|
// FileCredentials contains information required to decrypt files.
|
||||||
|
FileCredentials struct { |
||||||
|
// FileHash checksum of encrypted data
|
||||||
|
FileHash string `json:"file_hash"` |
||||||
|
// Secret of encrypted data
|
||||||
|
Secret string `json:"secret"` |
||||||
|
} |
||||||
|
|
||||||
|
// PersonalDetails https://core.telegram.org/passport#personaldetails
|
||||||
|
PersonalDetails struct { |
||||||
|
FirstName string `json:"first_name"` |
||||||
|
LastName string `json:"last_name"` |
||||||
|
MiddleName string `json:"middle_name"` |
||||||
|
BirthDate string `json:"birth_date"` |
||||||
|
Gender string `json:"gender"` |
||||||
|
CountryCode string `json:"country_code"` |
||||||
|
ResidenceCountryCode string `json:"residence_country_code"` |
||||||
|
FirstNameNative string `json:"first_name_native"` |
||||||
|
LastNameNative string `json:"last_name_native"` |
||||||
|
MiddleNameNative string `json:"middle_name_native"` |
||||||
|
} |
||||||
|
|
||||||
|
// IDDocumentData https://core.telegram.org/passport#iddocumentdata
|
||||||
|
IDDocumentData struct { |
||||||
|
DocumentNumber string `json:"document_no"` |
||||||
|
ExpiryDate string `json:"expiry_date"` |
||||||
|
} |
||||||
|
) |
File diff suppressed because it is too large
Load Diff
Loading…
Reference in new issue