- Added EditMessageMedia + Upload

pull/216/head
AliMVP 7 years ago
parent 789767cb14
commit 3db3ff77bb
  1. 181
      bot.go
  2. 368
      configs.go
  3. 129
      helpers.go
  4. 315
      passport.go
  5. 82
      types.go

181
bot.go

@ -26,8 +26,9 @@ type BotAPI struct {
Debug bool `json:"debug"`
Buffer int `json:"buffer"`
Self User `json:"-"`
Client *http.Client `json:"-"`
Self User `json:"-"`
Client *http.Client `json:"-"`
shutdownChannel chan interface{}
}
// NewBotAPI creates a new BotAPI instance.
@ -43,9 +44,10 @@ func NewBotAPI(token string) (*BotAPI, error) {
// It requires a token, provided by @BotFather on Telegram.
func NewBotAPIWithClient(token string, client *http.Client) (*BotAPI, error) {
bot := &BotAPI{
Token: token,
Client: client,
Buffer: 100,
Token: token,
Client: client,
Buffer: 100,
shutdownChannel: make(chan interface{}),
}
self, err := bot.GetMe()
@ -193,7 +195,6 @@ func (bot *BotAPI) UploadFile(endpoint string, params map[string]string, fieldna
}
ms.SetupRequest(req)
res, err := bot.Client.Do(req)
if err != nil {
return APIResponse{}, err
@ -308,7 +309,6 @@ func (bot *BotAPI) uploadAndSend(method string, config Fileable) (Message, error
}
file := config.getFile()
resp, err := bot.UploadFile(method, params, config.name(), file)
if err != nil {
return Message{}, err
@ -484,6 +484,12 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
go func() {
for {
select {
case <-bot.shutdownChannel:
return
default:
}
updates, err := bot.GetUpdates(config)
if err != nil {
log.Println(err)
@ -505,12 +511,22 @@ func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) (UpdatesChannel, error) {
return ch, nil
}
// 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) {
bytes, _ := ioutil.ReadAll(r.Body)
r.Body.Close()
var update Update
json.Unmarshal(bytes, &update)
@ -949,154 +965,3 @@ func (bot *BotAPI) DeleteChatPhoto(config DeleteChatPhotoConfig) (APIResponse, e
return bot.MakeRequest(config.method(), v)
}
// GetStickerSet is used to get a sticker set.
func (bot *BotAPI) GetStickerSet(name string) (StickerSet, error) {
v := url.Values{}
v.Add("name", name)
resp, err := bot.MakeRequest("getStickerSet", v)
if err != nil {
return StickerSet{}, err
}
var stickerSet StickerSet
err = json.Unmarshal(resp.Result, &stickerSet)
return stickerSet, err
}
// UploadStickerFile uploads a .png file with a sticker for later use in
// createNewStickerSet and addStickerToSet methods (can be used multiple times).
//
// File should be a string to a file path, a FileBytes struct, or a FileReader
// struct.
func (bot *BotAPI) UploadStickerFile(userID int, file interface{}) (APIResponse, File, error) {
switch file.(type) {
case url.URL:
return APIResponse{}, File{}, errors.New(ErrBadFileType)
}
params := make(map[string]string)
params["user_id"] = strconv.Itoa(userID)
resp, err := bot.UploadFile("uploadStickerFile", params, "png_sticker", file)
if err != nil {
return resp, File{}, err
}
returnFile := File{}
err = json.Unmarshal(resp.Result, &returnFile)
if err != nil {
return resp, File{}, err
}
return resp, returnFile, nil
}
// CreateNewStickerSet creates a new sticker set owned by a user. The bot will
// be able to edit the created sticker set.
func (bot *BotAPI) CreateNewStickerSet(config CreateNewStickerSetConfig) (APIResponse, error) {
params := make(map[string]string)
params["user_id"] = strconv.Itoa(config.UserID)
params["name"] = config.Name
params["title"] = config.Title
params["emojis"] = config.Emojis
if config.ContainsMasks {
params["contains_masks"] = strconv.FormatBool(config.ContainsMasks)
}
if config.MaskPosition != nil {
maskPosition, err := json.Marshal(&config.MaskPosition)
if err != nil {
return APIResponse{}, err
}
params["mask_position"] = string(maskPosition)
}
return bot.UploadFile("createNewStickerSet", params, "png_sticker", config.PNGSticker)
}
// CreateNewStickerSet creates a new sticker set owned by a user. The bot will
// be able to edit the created sticker set.
func (bot *BotAPI) CreateNewStickerSetFileId(config CreateNewStickerSetConfig) (APIResponse, error) {
v := url.Values{}
v.Add("png_sticker", config.PNGSticker.(string))
v.Add("user_id", strconv.Itoa(config.UserID))
v.Add("name", config.Name)
v.Add("title", config.Title)
v.Add("emojis", config.Emojis)
if config.MaskPosition != nil {
maskPosition, err := json.Marshal(&config.MaskPosition)
if err != nil {
return APIResponse{}, err
}
v.Add("mask_position", string(maskPosition))
}
if config.ContainsMasks {
v.Add("contains_masks", strconv.FormatBool(config.ContainsMasks))
}
return bot.MakeRequest("createNewStickerSet", v)
}
// AddStickerToSet adds a new sticker to a set created by the bot.
func (bot *BotAPI) AddStickerToSet(config AddStickerToSetConfig) (APIResponse, error) {
params := make(map[string]string)
params["user_id"] = strconv.Itoa(config.UserID)
params["name"] = config.Name
params["emojis"] = config.Emojis
if config.MaskPosition != nil {
maskPosition, err := json.Marshal(&config.MaskPosition)
if err != nil {
return APIResponse{}, err
}
params["mask_position"] = string(maskPosition)
}
return bot.UploadFile("addStickerToSet", params, "png_sticker", config.PNGSticker)
}
// AddStickerToSet adds a new sticker to a set created by the bot.
func (bot *BotAPI) AddStickerToSetFileId(config AddStickerToSetConfig) (APIResponse, error) {
v := url.Values{}
v.Add("png_sticker", config.PNGSticker.(string))
v.Add("user_id", strconv.Itoa(config.UserID))
v.Add("name", config.Name)
v.Add("emojis", config.Emojis)
if config.MaskPosition != nil {
maskPosition, err := json.Marshal(&config.MaskPosition)
if err != nil {
return APIResponse{}, err
}
v.Add("mask_position", string(maskPosition))
}
return bot.MakeRequest("addStickerToSet", v)
}
// SetStickerPositionInSet moves a sticker in a set created by the bot to a specific position.
func (bot *BotAPI) SetStickerPositionInSet(config SetStickerPositionInSetConfig) (APIResponse, error) {
v, _ := config.values()
bot.debugLog(config.method(), v, nil)
return bot.MakeRequest(config.method(), v)
}
// DeleteStickerFromSet deletes a sticker from a set created by the bot.
func (bot *BotAPI) DeleteStickerFromSet(sticker string) (APIResponse, error) {
v := url.Values{}
v.Add("sticker", sticker)
return bot.MakeRequest("deleteStickerFromSet", v)
}

@ -240,47 +240,6 @@ func (config ForwardConfig) method() string {
return "forwardMessage"
}
// AnimationConfig contains information about a SendAnimation request.
type AnimationConfig struct {
BaseFile
Caption string
}
// Params returns a map[string]string representation of AnimationConfig.
func (config AnimationConfig) params() (map[string]string, error) {
params, _ := config.BaseFile.params()
if config.Caption != "" {
params["caption"] = config.Caption
}
return params, nil
}
// Values returns a url.Values representation of AnimationConfig.
func (config AnimationConfig) values() (url.Values, error) {
v, err := config.BaseChat.values()
if err != nil {
return v, err
}
v.Add(config.name(), config.FileID)
if config.Caption != "" {
v.Add("caption", config.Caption)
}
return v, nil
}
// name returns the field name for the Animation.
func (config AnimationConfig) name() string {
return "animation"
}
// method returns Telegram API method name for sending Animation.
func (config AnimationConfig) method() string {
return "sendAnimation"
}
// PhotoConfig contains information about a SendPhoto request.
type PhotoConfig struct {
BaseFile
@ -294,10 +253,9 @@ func (config PhotoConfig) params() (map[string]string, error) {
if config.Caption != "" {
params["caption"] = config.Caption
}
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
}
}
return params, nil
@ -313,10 +271,11 @@ func (config PhotoConfig) values() (url.Values, error) {
v.Add(config.name(), config.FileID)
if config.Caption != "" {
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
}
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
return v, nil
}
@ -334,6 +293,7 @@ func (config PhotoConfig) method() string {
type AudioConfig struct {
BaseFile
Caption string
ParseMode string
Duration int
Performer string
Title string
@ -359,6 +319,9 @@ func (config AudioConfig) values() (url.Values, error) {
}
if config.Caption != "" {
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
}
return v, nil
@ -380,6 +343,9 @@ func (config AudioConfig) params() (map[string]string, error) {
}
if config.Caption != "" {
params["caption"] = config.Caption
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
}
}
return params, nil
@ -398,7 +364,8 @@ func (config AudioConfig) method() string {
// DocumentConfig contains information about a SendDocument request.
type DocumentConfig struct {
BaseFile
Caption string
Caption string
ParseMode string
}
// values returns a url.Values representation of DocumentConfig.
@ -411,6 +378,9 @@ func (config DocumentConfig) values() (url.Values, error) {
v.Add(config.name(), config.FileID)
if config.Caption != "" {
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
}
return v, nil
@ -422,6 +392,9 @@ func (config DocumentConfig) params() (map[string]string, error) {
if config.Caption != "" {
params["caption"] = config.Caption
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
}
}
return params, nil
@ -474,8 +447,9 @@ func (config StickerConfig) method() string {
// VideoConfig contains information about a SendVideo request.
type VideoConfig struct {
BaseFile
Duration int
Caption string
Duration int
Caption string
ParseMode string
}
// values returns a url.Values representation of VideoConfig.
@ -491,6 +465,9 @@ func (config VideoConfig) values() (url.Values, error) {
}
if config.Caption != "" {
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
}
return v, nil
@ -502,6 +479,9 @@ func (config VideoConfig) params() (map[string]string, error) {
if config.Caption != "" {
params["caption"] = config.Caption
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
}
}
return params, nil
@ -517,6 +497,59 @@ func (config VideoConfig) method() string {
return "sendVideo"
}
// AnimationConfig contains information about a SendAnimation request.
type AnimationConfig struct {
BaseFile
Duration int
Caption string
ParseMode string
}
// values returns a url.Values representation of AnimationConfig.
func (config AnimationConfig) values() (url.Values, error) {
v, err := config.BaseChat.values()
if err != nil {
return v, err
}
v.Add(config.name(), config.FileID)
if config.Duration != 0 {
v.Add("duration", strconv.Itoa(config.Duration))
}
if config.Caption != "" {
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
}
return v, nil
}
// params returns a map[string]string representation of AnimationConfig.
func (config AnimationConfig) params() (map[string]string, error) {
params, _ := config.BaseFile.params()
if config.Caption != "" {
params["caption"] = config.Caption
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
}
}
return params, nil
}
// name returns the field name for the Animation.
func (config AnimationConfig) name() string {
return "animation"
}
// method returns Telegram API method name for sending Animation.
func (config AnimationConfig) method() string {
return "sendAnimation"
}
// VideoNoteConfig contains information about a SendVideoNote request.
type VideoNoteConfig struct {
BaseFile
@ -571,8 +604,9 @@ func (config VideoNoteConfig) method() string {
// VoiceConfig contains information about a SendVoice request.
type VoiceConfig struct {
BaseFile
Caption string
Duration int
Caption string
ParseMode string
Duration int
}
// values returns a url.Values representation of VoiceConfig.
@ -588,6 +622,9 @@ func (config VoiceConfig) values() (url.Values, error) {
}
if config.Caption != "" {
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
}
return v, nil
@ -602,6 +639,9 @@ func (config VoiceConfig) params() (map[string]string, error) {
}
if config.Caption != "" {
params["caption"] = config.Caption
if config.ParseMode != "" {
params["parse_mode"] = config.ParseMode
}
}
return params, nil
@ -617,6 +657,32 @@ func (config VoiceConfig) method() string {
return "sendVoice"
}
// MediaGroupConfig contains information about a sendMediaGroup request.
type MediaGroupConfig struct {
BaseChat
InputMedia []interface{}
}
func (config MediaGroupConfig) values() (url.Values, error) {
v, err := config.BaseChat.values()
if err != nil {
return v, err
}
data, err := json.Marshal(config.InputMedia)
if err != nil {
return v, err
}
v.Add("media", string(data))
return v, nil
}
func (config MediaGroupConfig) method() string {
return "sendMediaGroup"
}
// LocationConfig contains information about a SendLocation request.
type LocationConfig struct {
BaseChat
@ -832,44 +898,20 @@ func (config EditMessageTextConfig) method() string {
return "editMessageText"
}
// EditMessageMediaConfig allows you to modify the text in a message.
type EditMessageMediaConfig struct {
BaseEdit
Media interface{} `json:"media"`
ParseMode string
DisableWebPagePreview bool
}
func (config EditMessageMediaConfig) values() (url.Values, error) {
v, err := config.BaseEdit.values()
if err != nil {
return v, err
}
bytes, err := json.Marshal(config.Media)
if err != nil {
return v, err
}
v.Add("media", string(bytes))
v.Add("parse_mode", config.ParseMode)
v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
return v, nil
}
func (config EditMessageMediaConfig) method() string {
return "editMessageMedia"
}
// EditMessageCaptionConfig allows you to modify the caption of a message.
type EditMessageCaptionConfig struct {
BaseEdit
Caption string
Caption string
ParseMode string
}
func (config EditMessageCaptionConfig) values() (url.Values, error) {
v, _ := config.BaseEdit.values()
v.Add("caption", config.Caption)
if config.ParseMode != "" {
v.Add("parse_mode", config.ParseMode)
}
return v, nil
}
@ -892,6 +934,59 @@ func (config EditMessageReplyMarkupConfig) method() string {
return "editMessageReplyMarkup"
}
// EditMessageMediaConfig allows you to modify the media
// of a message.
type EditMessageMediaConfig struct {
BaseFile
BaseEdit
Media interface{} `json:"media"`
ParseMode string
DisableWebPagePreview bool
}
func (config EditMessageMediaConfig) values() (url.Values, error) {
v, err := config.BaseChat.values()
if err != nil {
return v, err
}
v, err = config.BaseEdit.values()
if err != nil {
return v, err
}
if !config.UseExisting {
fileName := ""
switch mType := config.Media.(type) {
case InputMediaPhoto:
fileName = mType.Media
mType.Media = "attach://" + config.name()
config.Media = mType
case InputMediaVideo:
fileName = mType.Media
mType.Media = "attach://" + config.name()
config.Media = mType
}
config.File = fileName
}
bytes, err := json.Marshal(config.Media)
if err != nil {
return v, err
}
v.Add("media", string(bytes))
v.Add("parse_mode", config.ParseMode)
v.Add("disable_web_page_preview", strconv.FormatBool(config.DisableWebPagePreview))
return v, nil
}
func (config EditMessageMediaConfig) name() string {
return "fileName"
}
func (config EditMessageMediaConfig) method() string {
return "editMessageMedia"
}
// UserProfilePhotosConfig contains information about a
// GetUserProfilePhotos request.
type UserProfilePhotosConfig struct {
@ -1220,112 +1315,3 @@ func (config DeleteChatPhotoConfig) values() (url.Values, error) {
return v, nil
}
// MediaGroupConfig allows you to send a group of media.
//
// Media consist of InputMedia items (InputMediaPhoto, InputMediaVideo).
type MediaGroupConfig struct {
ChatID int64
ChannelUsername string
Media []interface{} `json:"media"`
DisableNotification bool
ReplyToMessageID int
}
func (config MediaGroupConfig) method() string {
return "sendMediaGroup"
}
func (config MediaGroupConfig) values() (url.Values, error) {
v := url.Values{}
if config.ChannelUsername == "" {
v.Add("chat_id", strconv.FormatInt(config.ChatID, 10))
} else {
v.Add("chat_id", config.ChannelUsername)
}
bytes, err := json.Marshal(config.Media)
if err != nil {
return v, err
}
v.Add("media", string(bytes))
if config.DisableNotification {
v.Add("disable_notification", strconv.FormatBool(config.DisableNotification))
}
if config.ReplyToMessageID != 0 {
v.Add("reply_to_message_id", strconv.Itoa(config.ReplyToMessageID))
}
return v, nil
}
type InputMediaPhoto struct {
Type string `json:"type"`
Media string `json:"media"`
Caption string `json:"caption"`
ParseMode string `json:"parse_mode"`
}
type InputMediaAudio struct {
Type string `json:"type"`
Media string `json:"media"`
Thumb string `json:"thumb,-"`
Caption string `json:"caption,-"`
ParseMode string `json:"parse_mode,-"`
Duration int `json:"duration,-"`
Performer string `json:"duration,-"`
Title string `json:"title,-"`
}
type InputMediaVideo struct {
Type string `json:"type"`
Media string `json:"media"`
Caption string `json:"caption"`
ParseMode string `json:"parse_mode"`
Width int `json:"width"`
Height int `json:"height"`
Duration int `json:"duration"`
SupportsStreaming bool `json:"supports_streaming"`
}
// CreateNewStickerSetConfig contains information about a CreateNewStickerSet
// request.
type CreateNewStickerSetConfig struct {
UserID int // required
Name string // required
Title string // required
PNGSticker interface{} // required
Emojis string // required
ContainsMasks bool
MaskPosition *MaskPosition
}
// AddStickerToSetConfig contains information about a AddToStickerSet request.
type AddStickerToSetConfig struct {
UserID int // required
Name string // required
PNGSticker interface{} // required
Emojis string // required
MaskPosition *MaskPosition
}
// SetStickerPositionInSetConfig contains information about a
// SetStickerPositionInSet request.
type SetStickerPositionInSetConfig struct {
Sticker string // required
Position int64 // required
}
func (config SetStickerPositionInSetConfig) values() (url.Values, error) {
v := url.Values{}
v.Add("sticker", config.Sticker)
v.Add("position", strconv.FormatInt(config.Position, 10))
return v, nil
}
func (config SetStickerPositionInSetConfig) method() string {
return "setStickerPositionInSet"
}

@ -19,6 +19,7 @@ func NewMessage(chatID int64, text string) MessageConfig {
}
}
// NewDeleteMessage creates a request to delete a message.
func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig {
return DeleteMessageConfig{
ChatID: chatID,
@ -51,22 +52,6 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig {
}
}
// NewAnimationUpload creates a new animation 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 NewAnimationUpload(chatID int64, file interface{}) AnimationConfig {
return AnimationConfig{
BaseFile: BaseFile{
BaseChat: BaseChat{ChatID: chatID},
File: file,
UseExisting: false,
},
}
}
// NewPhotoUpload creates a new photo uploader.
//
// chatID is where to send it, file is a string path to the file,
@ -98,17 +83,6 @@ func NewPhotoShare(chatID int64, fileID string) PhotoConfig {
}
}
// NewMediaGroupShare shares media group.
//
// chatID is where to send it, medias is the media interface
// already uploaded.
func NewMediaGroupShare(chatID int64, medias []interface{}) MediaGroupConfig {
return MediaGroupConfig{
ChatID: chatID,
Media: medias,
}
}
// NewAudioUpload creates a new audio uploader.
//
// chatID is where to send it, file is a string path to the file,
@ -228,6 +202,35 @@ func NewVideoShare(chatID int64, fileID string) VideoConfig {
}
}
// 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{
BaseFile: BaseFile{
BaseChat: BaseChat{ChatID: chatID},
File: file,
UseExisting: false,
},
}
}
// NewAnimationShare shares an existing animation.
// You may use this to reshare an existing animation without reuploading it.
//
// chatID is where to send it, fileID is the ID of the animation
// already uploaded.
func NewAnimationShare(chatID int64, fileID string) AnimationConfig {
return AnimationConfig{
BaseFile: BaseFile{
BaseChat: BaseChat{ChatID: chatID},
FileID: fileID,
UseExisting: true,
},
}
}
// NewVideoNoteUpload creates a new video note uploader.
//
// chatID is where to send it, file is a string path to the file,
@ -288,6 +291,33 @@ func NewVoiceShare(chatID int64, fileID string) VoiceConfig {
}
}
// 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{
BaseChat: BaseChat{
ChatID: chatID,
},
InputMedia: files,
}
}
// NewInputMediaPhoto creates a new InputMediaPhoto.
func NewInputMediaPhoto(media string) InputMediaPhoto {
return InputMediaPhoto{
Type: "photo",
Media: media,
}
}
// NewInputMediaVideo creates a new InputMediaVideo.
func NewInputMediaVideo(media string) InputMediaVideo {
return InputMediaVideo{
Type: "video",
Media: media,
}
}
// NewContact allows you to send a shared contact.
func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig {
return ContactConfig{
@ -531,25 +561,56 @@ func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMess
}
}
// NewEditMessageMedia allows you to edit the media of a message.
// 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,
},
}
}
// NewEditMessageReplyMedia allows you to edit audio, document, photo, or video messages
// keyboard markup.
func NewEditMessageMedia(chatID int64, messageID int, media interface{}) EditMessageMediaConfig {
fileName := ""
switch media.(type) {
case InputMediaPhoto:
photo := media.(InputMediaPhoto)
fileName = photo.Media
case InputMediaVideo:
video := media.(InputMediaVideo)
fileName = video.Media
}
return EditMessageMediaConfig{
BaseEdit: BaseEdit{
ChatID: chatID,
MessageID: messageID,
},
Media: media,
BaseFile: BaseFile{
FileID: fileName,
UseExisting: true,
},
}
}
// NewEditMessageReplyMarkup allows you to edit the inline
// NewEditMessageReplyMedia allows you to edit audio, document, photo, or video messages
// keyboard markup.
func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig {
return EditMessageReplyMarkupConfig{
func NewEditMessageMediaUpload(chatID int64, messageID int, media interface{}) EditMessageMediaConfig {
return EditMessageMediaConfig{
BaseEdit: BaseEdit{
ChatID: chatID,
MessageID: messageID,
ReplyMarkup: &replyMarkup,
ChatID: chatID,
MessageID: messageID,
},
Media: media,
BaseFile: BaseFile{
BaseChat: BaseChat{ChatID: chatID},
File: media,
UseExisting: false,
},
}
}

@ -0,0 +1,315 @@
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"`
// 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 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"`
}
)

@ -142,10 +142,9 @@ type Message struct {
EditDate int `json:"edit_date"` // optional
Text string `json:"text"` // optional
Entities *[]MessageEntity `json:"entities"` // optional
CaptionEntities *[]MessageEntity `json:"caption_entities"` // optional
Animation *Animation `json:"animation"` // optional
Audio *Audio `json:"audio"` // optional
Document *Document `json:"document"` // optional
Animation *ChatAnimation `json:"animation"` // optional
Game *Game `json:"game"` // optional
Photo *[]PhotoSize `json:"photo"` // optional
Sticker *Sticker `json:"sticker"` // optional
@ -169,6 +168,7 @@ type Message struct {
PinnedMessage *Message `json:"pinned_message"` // optional
Invoice *Invoice `json:"invoice"` // optional
SuccessfulPayment *SuccessfulPayment `json:"successful_payment"` // optional
PassportData *PassportData `json:"passport_data,omitempty"` // optional
}
// Time converts the message timestamp into a Time.
@ -178,11 +178,7 @@ func (m *Message) Time() time.Time {
// IsCommand returns true if message starts with a "bot_command" entity.
func (m *Message) IsCommand() bool {
lenEntities := 0
if m.Entities != nil {
lenEntities = len(*m.Entities)
}
if m.Entities == nil || lenEntities == 0 {
if m.Entities == nil || len(*m.Entities) == 0 {
return false
}
@ -288,6 +284,29 @@ type Document struct {
FileSize int `json:"file_size"` // optional
}
// Sticker contains information about a sticker.
type Sticker struct {
FileID string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Thumbnail *PhotoSize `json:"thumb"` // optional
Emoji string `json:"emoji"` // optional
FileSize int `json:"file_size"` // optional
SetName string `json:"set_name"` // optional
}
// ChatAnimation contains information about an animation.
type ChatAnimation struct {
FileID string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Duration int `json:"duration"`
Thumbnail *PhotoSize `json:"thumb"` // optional
FileName string `json:"file_name"` // optional
MimeType string `json:"mime_type"` // optional
FileSize int `json:"file_size"` // optional
}
// Video contains information about a video.
type Video struct {
FileID string `json:"file_id"`
@ -506,6 +525,27 @@ func (info WebhookInfo) IsSet() bool {
return info.URL != ""
}
// InputMediaPhoto contains a photo for displaying as part of a media group.
type InputMediaPhoto struct {
Type string `json:"type"`
Media string `json:"media"`
Caption string `json:"caption"`
ParseMode string `json:"parse_mode"`
}
// InputMediaVideo contains a video for displaying as part of a media group.
type InputMediaVideo struct {
Type string `json:"type"`
Media string `json:"media"`
// thumb intentionally missing as it is not currently compatible
Caption string `json:"caption"`
ParseMode string `json:"parse_mode"`
Width int `json:"width"`
Height int `json:"height"`
Duration int `json:"duration"`
SupportsStreaming bool `json:"supports_streaming"`
}
// InlineQuery is a Query from Telegram for an inline request.
type InlineQuery struct {
ID string `json:"id"`
@ -768,34 +808,6 @@ type PreCheckoutQuery struct {
OrderInfo *OrderInfo `json:"order_info,omitempty"`
}
// Sticker contains information about a sticker.
type Sticker struct {
FileID string `json:"file_id"`
Width int `json:"width"`
Height int `json:"height"`
Thumbnail *PhotoSize `json:"thumb"` // optional
Emoji string `json:"emoji"` // optional
SetName string `json:"set_name"` // optional
MaskPosition *MaskPosition `json:"mask_position"` // optional
FileSize int `json:"file_size"` // optional
}
// StickerSet represents a sticker set.
type StickerSet struct {
Name string `json:"name"`
Title string `json:"title"`
ContainsMasks bool `json:"contains_masks"`
Stickers *[]Sticker `json:"stickers"`
}
// MaskPosition describes the position on faces where a mask should be placed by default.
type MaskPosition struct {
Point string `json:"point"`
XShift float64 `json:"x_shift"`
YShift float64 `json:"y_shift"`
scale float64 `json:"scale"`
}
// Error is an error containing extra information returned by the Telegram API.
type Error struct {
Message string