Updates for Bot API 4.4 and 4.5.

bot-api-6.1
Syfaro 2020-01-06 01:44:13 -06:00
parent ffe77fb717
commit 5ce2767dad
6 changed files with 266 additions and 91 deletions

View File

@ -34,8 +34,9 @@ const (
// Constant values for ParseMode in MessageConfig // Constant values for ParseMode in MessageConfig
const ( const (
ModeMarkdown = "Markdown" ModeMarkdown = "Markdown"
ModeHTML = "HTML" ModeMarkdownV2 = "MarkdownV2"
ModeHTML = "HTML"
) )
// Library errors // Library errors
@ -939,11 +940,8 @@ func (config KickChatMemberConfig) params() (Params, error) {
// RestrictChatMemberConfig contains fields to restrict members of chat // RestrictChatMemberConfig contains fields to restrict members of chat
type RestrictChatMemberConfig struct { type RestrictChatMemberConfig struct {
ChatMemberConfig ChatMemberConfig
UntilDate int64 UntilDate int64
CanSendMessages *bool Permissions *ChatPermissions
CanSendMediaMessages *bool
CanSendOtherMessages *bool
CanAddWebPagePreviews *bool
} }
func (config RestrictChatMemberConfig) method() string { func (config RestrictChatMemberConfig) method() string {
@ -956,10 +954,9 @@ func (config RestrictChatMemberConfig) params() (Params, error) {
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
params.AddNonZero("user_id", config.UserID) params.AddNonZero("user_id", config.UserID)
params.AddNonNilBool("can_send_messages", config.CanSendMessages) if err := params.AddInterface("permissions", config.Permissions); err != nil {
params.AddNonNilBool("can_send_media_messages", config.CanSendMediaMessages) return params, err
params.AddNonNilBool("can_send_other_messages", config.CanSendOtherMessages) }
params.AddNonNilBool("can_add_web_page_previews", config.CanAddWebPagePreviews)
params.AddNonZero64("until_date", config.UntilDate) params.AddNonZero64("until_date", config.UntilDate)
return params, nil return params, nil
@ -968,14 +965,14 @@ func (config RestrictChatMemberConfig) params() (Params, error) {
// PromoteChatMemberConfig contains fields to promote members of chat // PromoteChatMemberConfig contains fields to promote members of chat
type PromoteChatMemberConfig struct { type PromoteChatMemberConfig struct {
ChatMemberConfig ChatMemberConfig
CanChangeInfo *bool CanChangeInfo bool
CanPostMessages *bool CanPostMessages bool
CanEditMessages *bool CanEditMessages bool
CanDeleteMessages *bool CanDeleteMessages bool
CanInviteUsers *bool CanInviteUsers bool
CanRestrictMembers *bool CanRestrictMembers bool
CanPinMessages *bool CanPinMessages bool
CanPromoteMembers *bool CanPromoteMembers bool
} }
func (config PromoteChatMemberConfig) method() string { func (config PromoteChatMemberConfig) method() string {
@ -988,14 +985,35 @@ func (config PromoteChatMemberConfig) params() (Params, error) {
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
params.AddNonZero("user_id", config.UserID) params.AddNonZero("user_id", config.UserID)
params.AddNonNilBool("can_change_info", config.CanChangeInfo) params.AddBool("can_change_info", config.CanChangeInfo)
params.AddNonNilBool("can_post_messages", config.CanPostMessages) params.AddBool("can_post_messages", config.CanPostMessages)
params.AddNonNilBool("can_edit_messages", config.CanEditMessages) params.AddBool("can_edit_messages", config.CanEditMessages)
params.AddNonNilBool("can_delete_messages", config.CanDeleteMessages) params.AddBool("can_delete_messages", config.CanDeleteMessages)
params.AddNonNilBool("can_invite_users", config.CanInviteUsers) params.AddBool("can_invite_users", config.CanInviteUsers)
params.AddNonNilBool("can_restrict_members", config.CanRestrictMembers) params.AddBool("can_restrict_members", config.CanRestrictMembers)
params.AddNonNilBool("can_pin_messages", config.CanPinMessages) params.AddBool("can_pin_messages", config.CanPinMessages)
params.AddNonNilBool("can_promote_members", config.CanPromoteMembers) params.AddBool("can_promote_members", config.CanPromoteMembers)
return params, nil
}
// SetChatAdministratorCustomTitle sets the title of an administrative user
// promoted by the bot for a chat.
type SetChatAdministratorCustomTitle struct {
ChatMemberConfig
CustomTitle string
}
func (SetChatAdministratorCustomTitle) method() string {
return "setChatAdministratorCustomTitle"
}
func (config SetChatAdministratorCustomTitle) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername)
params.AddNonZero("user_id", config.UserID)
params.AddNonEmpty("custom_title", config.CustomTitle)
return params, nil return params, nil
} }
@ -1041,6 +1059,27 @@ func (ChatAdministratorsConfig) method() string {
return "getChatAdministrators" return "getChatAdministrators"
} }
// SetChatPermissionsConfig allows you to set default permissions for the
// members in a group. The bot must be an administrator and have rights to
// restrict members.
type SetChatPermissionsConfig struct {
ChatConfig
Permissions *ChatPermissions
}
func (SetChatPermissionsConfig) method() string {
return "setChatPermissions"
}
func (config SetChatPermissionsConfig) params() (Params, error) {
params := make(Params)
params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername)
params.AddInterface("permissions", config.Permissions)
return params, nil
}
// ChatInviteLinkConfig contains information about getting a chat link. // ChatInviteLinkConfig contains information about getting a chat link.
// //
// Note that generating a new link will revoke any previous links. // Note that generating a new link will revoke any previous links.

View File

@ -37,13 +37,6 @@ func (p Params) AddBool(key string, value bool) {
} }
} }
// AddNonNilBool adds the value of a bool pointer if not nil.
func (p Params) AddNonNilBool(key string, value *bool) {
if value != nil {
p[key] = strconv.FormatBool(*value)
}
}
// AddNonZeroFloat adds a floating point value that is not zero. // AddNonZeroFloat adds a floating point value that is not zero.
func (p Params) AddNonZeroFloat(key string, value float64) { func (p Params) AddNonZeroFloat(key string, value float64) {
if value != 0 { if value != 0 {
@ -76,14 +69,17 @@ func (p Params) AddFirstValid(key string, args ...interface{}) error {
case int: case int:
if v != 0 { if v != 0 {
p[key] = strconv.Itoa(v) p[key] = strconv.Itoa(v)
return nil
} }
case int64: case int64:
if v != 0 { if v != 0 {
p[key] = strconv.FormatInt(v, 10) p[key] = strconv.FormatInt(v, 10)
return nil
} }
case string: case string:
if v != "" { if v != "" {
p[key] = v p[key] = v
return nil
} }
case nil: case nil:
default: default:
@ -93,6 +89,7 @@ func (p Params) AddFirstValid(key string, args ...interface{}) error {
} }
p[key] = string(b) p[key] = string(b)
return nil
} }
} }

93
params_test.go 100644
View File

@ -0,0 +1,93 @@
package tgbotapi
import (
"testing"
)
func assertLen(t *testing.T, params Params, l int) {
actual := len(params)
if actual != l {
t.Fatalf("Incorrect number of params, expected %d but found %d\n", l, actual)
}
}
func assertEq(t *testing.T, a interface{}, b interface{}) {
if a != b {
t.Fatalf("Values did not match, a: %v, b: %v\n", a, b)
}
}
func TestAddNonEmpty(t *testing.T) {
params := make(Params)
params.AddNonEmpty("value", "value")
assertLen(t, params, 1)
assertEq(t, params["value"], "value")
params.AddNonEmpty("test", "")
assertLen(t, params, 1)
assertEq(t, params["test"], "")
}
func TestAddNonZero(t *testing.T) {
params := make(Params)
params.AddNonZero("value", 1)
assertLen(t, params, 1)
assertEq(t, params["value"], "1")
params.AddNonZero("test", 0)
assertLen(t, params, 1)
assertEq(t, params["test"], "")
}
func TestAddNonZero64(t *testing.T) {
params := make(Params)
params.AddNonZero64("value", 1)
assertLen(t, params, 1)
assertEq(t, params["value"], "1")
params.AddNonZero64("test", 0)
assertLen(t, params, 1)
assertEq(t, params["test"], "")
}
func TestAddBool(t *testing.T) {
params := make(Params)
params.AddBool("value", true)
assertLen(t, params, 1)
assertEq(t, params["value"], "true")
params.AddBool("test", false)
assertLen(t, params, 1)
assertEq(t, params["test"], "")
}
func TestAddNonZeroFloat(t *testing.T) {
params := make(Params)
params.AddNonZeroFloat("value", 1)
assertLen(t, params, 1)
assertEq(t, params["value"], "1.000000")
params.AddNonZeroFloat("test", 0)
assertLen(t, params, 1)
assertEq(t, params["test"], "")
}
func TestAddInterface(t *testing.T) {
params := make(Params)
data := struct {
Name string `json:"name"`
}{
Name: "test",
}
params.AddInterface("value", data)
assertLen(t, params, 1)
assertEq(t, params["value"], `{"name":"test"}`)
params.AddInterface("test", nil)
assertLen(t, params, 1)
assertEq(t, params["test"], "")
}
func TestAddFirstValid(t *testing.T) {
params := make(Params)
params.AddFirstValid("value", 0, "", "test")
assertLen(t, params, 1)
assertEq(t, params["value"], "test")
params.AddFirstValid("value2", 3, "test")
assertLen(t, params, 2)
assertEq(t, params["value2"], "3")
}

View File

@ -61,6 +61,8 @@ type (
// Unique identifier for this file // Unique identifier for this file
FileID string `json:"file_id"` FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
// File size // File size
FileSize int `json:"file_size"` FileSize int `json:"file_size"`

144
types.go
View File

@ -85,25 +85,42 @@ type GroupChat struct {
// ChatPhoto represents a chat photo. // ChatPhoto represents a chat photo.
type ChatPhoto struct { type ChatPhoto struct {
SmallFileID string `json:"small_file_id"` SmallFileID string `json:"small_file_id"`
BigFileID string `json:"big_file_id"` SmallFileUniqueID string `json:"small_file_unique_id"`
BigFileID string `json:"big_file_id"`
BigFileUniqueID string `json:"big_file_unique_id"`
}
// ChatPermissions describes actions that a non-administrator user is
// allowed to take in a chat. All fields are optional.
type ChatPermissions struct {
CanSendMessages bool `json:"can_send_messages"`
CanSendMediaMessages bool `json:"can_send_media_messages"`
CanSendPolls bool `json:"can_send_polls"`
CanSendOtherMessages bool `json:"can_send_other_messages"`
CanAddWebPagePreviews bool `json:"can_add_web_page_previews"`
CanChangeInfo bool `json:"can_change_info"`
CanInviteUsers bool `json:"can_invite_users"`
CanPinMessages bool `json:"can_pin_messages"`
} }
// Chat contains information about the place a message was sent. // Chat contains information about the place a message was sent.
type Chat struct { type Chat struct {
ID int64 `json:"id"` ID int64 `json:"id"`
Type string `json:"type"` Type string `json:"type"`
Title string `json:"title"` // optional Title string `json:"title"` // optional
UserName string `json:"username"` // optional UserName string `json:"username"` // optional
FirstName string `json:"first_name"` // optional FirstName string `json:"first_name"` // optional
LastName string `json:"last_name"` // optional LastName string `json:"last_name"` // optional
AllMembersAreAdmins bool `json:"all_members_are_administrators"` // optional AllMembersAreAdmins bool `json:"all_members_are_administrators"` // deprecated, optional
Photo *ChatPhoto `json:"photo"` // optional Photo *ChatPhoto `json:"photo"` // optional
Description string `json:"description,omitempty"` // optional Description string `json:"description,omitempty"` // optional
InviteLink string `json:"invite_link,omitempty"` // optional InviteLink string `json:"invite_link,omitempty"` // optional
PinnedMessage *Message `json:"pinned_message"` // optional PinnedMessage *Message `json:"pinned_message"` // optional
StickerSetName string `json:"sticker_set_name"` // optional Permissions *ChatPermissions `json:"permissions"` // optional
CanSetStickerSet bool `json:"can_set_sticker_set"` // optional SlowModeDelay int `json:"slow_mode_delay"` // optional
StickerSetName string `json:"sticker_set_name"` // optional
CanSetStickerSet bool `json:"can_set_sticker_set"` // optional
} }
// IsPrivate returns if the Chat is a private conversation. // IsPrivate returns if the Chat is a private conversation.
@ -272,36 +289,41 @@ func (entity MessageEntity) ParseURL() (*url.URL, error) {
// PhotoSize contains information about photos. // PhotoSize contains information about photos.
type PhotoSize struct { type PhotoSize struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Width int `json:"width"` FileUniqueID string `json:"file_unique_id"`
Height int `json:"height"` Width int `json:"width"`
FileSize int `json:"file_size"` // optional Height int `json:"height"`
FileSize int `json:"file_size"` // optional
} }
// Audio contains information about audio. // Audio contains information about audio.
type Audio struct { type Audio struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Duration int `json:"duration"` FileUniqueID string `json:"file_unique_id"`
Performer string `json:"performer"` // optional Duration int `json:"duration"`
Title string `json:"title"` // optional Performer string `json:"performer"` // optional
MimeType string `json:"mime_type"` // optional Title string `json:"title"` // optional
FileSize int `json:"file_size"` // optional MimeType string `json:"mime_type"` // optional
FileSize int `json:"file_size"` // optional
} }
// Document contains information about a document. // Document contains information about a document.
type Document struct { type Document struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Thumbnail *PhotoSize `json:"thumb"` // optional FileUniqueID string `json:"file_unique_id"`
FileName string `json:"file_name"` // optional Thumbnail *PhotoSize `json:"thumb"` // optional
MimeType string `json:"mime_type"` // optional FileName string `json:"file_name"` // optional
FileSize int `json:"file_size"` // optional MimeType string `json:"mime_type"` // optional
FileSize int `json:"file_size"` // optional
} }
// Sticker contains information about a sticker. // Sticker contains information about a sticker.
type Sticker struct { type Sticker struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
FileUniqueID string `json:"file_unique_id"`
Width int `json:"width"` Width int `json:"width"`
Height int `json:"height"` Height int `json:"height"`
IsAnimated bool `json:"is_animated"`
Thumbnail *PhotoSize `json:"thumb"` // optional Thumbnail *PhotoSize `json:"thumb"` // optional
Emoji string `json:"emoji"` // optional Emoji string `json:"emoji"` // optional
SetName string `json:"set_name"` // optional SetName string `json:"set_name"` // optional
@ -338,30 +360,33 @@ type ChatAnimation struct {
// Video contains information about a video. // Video contains information about a video.
type Video struct { type Video struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Width int `json:"width"` FileUniqueID string `json:"file_unique_id"`
Height int `json:"height"` Width int `json:"width"`
Duration int `json:"duration"` Height int `json:"height"`
Thumbnail *PhotoSize `json:"thumb"` // optional Duration int `json:"duration"`
MimeType string `json:"mime_type"` // optional Thumbnail *PhotoSize `json:"thumb"` // optional
FileSize int `json:"file_size"` // optional MimeType string `json:"mime_type"` // optional
FileSize int `json:"file_size"` // optional
} }
// VideoNote contains information about a video. // VideoNote contains information about a video.
type VideoNote struct { type VideoNote struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Length int `json:"length"` FileUniqueID string `json:"file_unique_id"`
Duration int `json:"duration"` Length int `json:"length"`
Thumbnail *PhotoSize `json:"thumb"` // optional Duration int `json:"duration"`
FileSize int `json:"file_size"` // optional Thumbnail *PhotoSize `json:"thumb"` // optional
FileSize int `json:"file_size"` // optional
} }
// Voice contains information about a voice. // Voice contains information about a voice.
type Voice struct { type Voice struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Duration int `json:"duration"` FileUniqueID string `json:"file_unique_id"`
MimeType string `json:"mime_type"` // optional Duration int `json:"duration"`
FileSize int `json:"file_size"` // optional MimeType string `json:"mime_type"` // optional
FileSize int `json:"file_size"` // optional
} }
// Contact contains information about a contact. // Contact contains information about a contact.
@ -411,9 +436,10 @@ type UserProfilePhotos struct {
// File contains information about a file to download from Telegram. // File contains information about a file to download from Telegram.
type File struct { type File struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
FileSize int `json:"file_size"` // optional FileUniqueID string `json:"file_unique_id"`
FilePath string `json:"file_path"` // optional FileSize int `json:"file_size"` // optional
FilePath string `json:"file_path"` // optional
} }
// Link returns a full path to the download URL for a File. // Link returns a full path to the download URL for a File.
@ -504,19 +530,21 @@ type ForceReply struct {
type ChatMember struct { type ChatMember struct {
User *User `json:"user"` User *User `json:"user"`
Status string `json:"status"` Status string `json:"status"`
CustomTitle string `json:"custom_title"` // optional
UntilDate int64 `json:"until_date,omitempty"` // optional UntilDate int64 `json:"until_date,omitempty"` // optional
CanBeEdited bool `json:"can_be_edited,omitempty"` // optional CanBeEdited bool `json:"can_be_edited,omitempty"` // optional
CanChangeInfo bool `json:"can_change_info,omitempty"` // optional
CanPostMessages bool `json:"can_post_messages,omitempty"` // optional CanPostMessages bool `json:"can_post_messages,omitempty"` // optional
CanEditMessages bool `json:"can_edit_messages,omitempty"` // optional CanEditMessages bool `json:"can_edit_messages,omitempty"` // optional
CanDeleteMessages bool `json:"can_delete_messages,omitempty"` // optional CanDeleteMessages bool `json:"can_delete_messages,omitempty"` // optional
CanInviteUsers bool `json:"can_invite_users,omitempty"` // optional
CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // optional CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // optional
CanPinMessages bool `json:"can_pin_messages,omitempty"` // optional
CanPromoteMembers bool `json:"can_promote_members,omitempty"` // optional CanPromoteMembers bool `json:"can_promote_members,omitempty"` // optional
CanChangeInfo bool `json:"can_change_info,omitempty"` // optional
CanInviteUsers bool `json:"can_invite_users,omitempty"` // optional
CanPinMessages bool `json:"can_pin_messages,omitempty"` // optional
IsChatMember bool `json:"is_member"` // optional IsChatMember bool `json:"is_member"` // optional
CanSendMessages bool `json:"can_send_messages,omitempty"` // optional CanSendMessages bool `json:"can_send_messages,omitempty"` // optional
CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` // optional CanSendMediaMessages bool `json:"can_send_media_messages,omitempty"` // optional
CanSendPolls bool `json:"can_send_polls,omitempty"` // optional
CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` // optional CanSendOtherMessages bool `json:"can_send_other_messages,omitempty"` // optional
CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` // optional CanAddWebPagePreviews bool `json:"can_add_web_page_previews,omitempty"` // optional
} }
@ -548,11 +576,12 @@ type Game struct {
// Animation is a GIF animation demonstrating the game. // Animation is a GIF animation demonstrating the game.
type Animation struct { type Animation struct {
FileID string `json:"file_id"` FileID string `json:"file_id"`
Thumb PhotoSize `json:"thumb"` FileUniqueID string `json:"file_unique_id"`
FileName string `json:"file_name"` Thumb PhotoSize `json:"thumb"`
MimeType string `json:"mime_type"` FileName string `json:"file_name"`
FileSize int `json:"file_size"` MimeType string `json:"mime_type"`
FileSize int `json:"file_size"`
} }
// GameHighScore is a user's score and position on the leaderboard. // GameHighScore is a user's score and position on the leaderboard.
@ -862,6 +891,7 @@ type PreCheckoutQuery struct {
type StickerSet struct { type StickerSet struct {
Name string `json:"name"` Name string `json:"name"`
Title string `json:"title"` Title string `json:"title"`
IsAnimated bool `json:"is_animated"`
ContainsMasks bool `json:"contains_masks"` ContainsMasks bool `json:"contains_masks"`
Stickers []Sticker `json:"stickers"` Stickers []Sticker `json:"stickers"`
} }

View File

@ -202,7 +202,10 @@ var (
_ Chattable = AnimationConfig{} _ Chattable = AnimationConfig{}
_ Chattable = AudioConfig{} _ Chattable = AudioConfig{}
_ Chattable = CallbackConfig{} _ Chattable = CallbackConfig{}
_ Chattable = ChatAdministratorsConfig{}
_ Chattable = ChatActionConfig{} _ Chattable = ChatActionConfig{}
_ Chattable = ChatInfoConfig{}
_ Chattable = ChatInviteLinkConfig{}
_ Chattable = ContactConfig{} _ Chattable = ContactConfig{}
_ Chattable = DeleteChatPhotoConfig{} _ Chattable = DeleteChatPhotoConfig{}
_ Chattable = DeleteChatStickerSetConfig{} _ Chattable = DeleteChatStickerSetConfig{}
@ -210,24 +213,35 @@ var (
_ Chattable = DocumentConfig{} _ Chattable = DocumentConfig{}
_ Chattable = EditMessageCaptionConfig{} _ Chattable = EditMessageCaptionConfig{}
_ Chattable = EditMessageLiveLocationConfig{} _ Chattable = EditMessageLiveLocationConfig{}
_ Chattable = EditMessageMediaConfig{}
_ Chattable = EditMessageReplyMarkupConfig{} _ Chattable = EditMessageReplyMarkupConfig{}
_ Chattable = EditMessageTextConfig{} _ Chattable = EditMessageTextConfig{}
_ Chattable = FileConfig{}
_ Chattable = ForwardConfig{} _ Chattable = ForwardConfig{}
_ Chattable = GameConfig{} _ Chattable = GameConfig{}
_ Chattable = GetChatMemberConfig{}
_ Chattable = GetGameHighScoresConfig{} _ Chattable = GetGameHighScoresConfig{}
_ Chattable = InlineConfig{} _ Chattable = InlineConfig{}
_ Chattable = InvoiceConfig{} _ Chattable = InvoiceConfig{}
_ Chattable = KickChatMemberConfig{} _ Chattable = KickChatMemberConfig{}
_ Chattable = LeaveChatConfig{}
_ Chattable = LocationConfig{} _ Chattable = LocationConfig{}
_ Chattable = MediaGroupConfig{} _ Chattable = MediaGroupConfig{}
_ Chattable = MessageConfig{} _ Chattable = MessageConfig{}
_ Chattable = PhotoConfig{} _ Chattable = PhotoConfig{}
_ Chattable = PinChatMessageConfig{} _ Chattable = PinChatMessageConfig{}
_ Chattable = PromoteChatMemberConfig{}
_ Chattable = RemoveWebhookConfig{}
_ Chattable = RestrictChatMemberConfig{}
_ Chattable = SendPollConfig{}
_ Chattable = SetChatDescriptionConfig{} _ Chattable = SetChatDescriptionConfig{}
_ Chattable = SetChatPhotoConfig{} _ Chattable = SetChatPhotoConfig{}
_ Chattable = SetChatTitleConfig{} _ Chattable = SetChatTitleConfig{}
_ Chattable = SetGameScoreConfig{} _ Chattable = SetGameScoreConfig{}
_ Chattable = StickerConfig{} _ Chattable = StickerConfig{}
_ Chattable = StopPollConfig{}
_ Chattable = StopMessageLiveLocationConfig{}
_ Chattable = UnbanChatMemberConfig{}
_ Chattable = UnpinChatMessageConfig{} _ Chattable = UnpinChatMessageConfig{}
_ Chattable = UpdateConfig{} _ Chattable = UpdateConfig{}
_ Chattable = UserProfilePhotosConfig{} _ Chattable = UserProfilePhotosConfig{}