diff --git a/answer_callback_query.go b/answer_callback_query.go index 3a65e4a..287b2a2 100644 --- a/answer_callback_query.go +++ b/answer_callback_query.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// AnswerCallbackQueryParameters represents data for AnswerCallbackQuery method. type AnswerCallbackQueryParameters struct { // Unique identifier for the query to be answered CallbackQueryID string `json:"callback_query_id"` @@ -29,6 +30,8 @@ type AnswerCallbackQueryParameters struct { CacheTime int `json:"cache_time,omitempty"` } +// NewAnswerCallbackQuery creates AnswerCallbackQueryParameters only with +// required parameters. func NewAnswerCallbackQuery(callbackQueryID string) *AnswerCallbackQueryParameters { return &AnswerCallbackQueryParameters{CallbackQueryID: callbackQueryID} } diff --git a/answer_inline_query.go b/answer_inline_query.go index fb9996f..968a507 100644 --- a/answer_inline_query.go +++ b/answer_inline_query.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// AnswerInlineQueryParameters represents data for AnswerInlineQuery method. type AnswerInlineQueryParameters struct { // Unique identifier for the answered query InlineQueryID string `json:"inline_query_id"` @@ -35,6 +36,8 @@ type AnswerInlineQueryParameters struct { IsPersonal bool `json:"is_personal,omitempty"` } +// NewAnswerInlineQuery creates AnswerInlineQueryParameters only with required +// parameters. func NewAnswerInlineQuery(inlineQueryID string, results ...interface{}) *AnswerInlineQueryParameters { return &AnswerInlineQueryParameters{ InlineQueryID: inlineQueryID, diff --git a/answer_pre_checkout_query.go b/answer_pre_checkout_query.go index 58a5f6a..630a526 100644 --- a/answer_pre_checkout_query.go +++ b/answer_pre_checkout_query.go @@ -2,6 +2,8 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// AnswerPreCheckoutQueryParameters represents data for AnswerPreCheckoutQuery +// method. type AnswerPreCheckoutQueryParameters struct { // Unique identifier for the query to be answered PreCheckoutQueryID string `json:"pre_checkout_query_id"` @@ -19,6 +21,8 @@ type AnswerPreCheckoutQueryParameters struct { Ok bool `json:"ok"` } +// NewAnswerPreCheckoutQuery creates AnswerPreCheckoutQueryParameters only with +// required parameters. func NewAnswerPreCheckoutQuery(preCheckoutQueryID string, ok bool) *AnswerPreCheckoutQueryParameters { return &AnswerPreCheckoutQueryParameters{ PreCheckoutQueryID: preCheckoutQueryID, diff --git a/answer_shipping_query.go b/answer_shipping_query.go index a2a00cf..a67d786 100644 --- a/answer_shipping_query.go +++ b/answer_shipping_query.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// AnswerShippingQueryParameters represents data for AnswerShippingQuery method. type AnswerShippingQueryParameters struct { // Unique identifier for the query to be answered ShippingQueryID string `json:"shipping_query_id"` @@ -22,6 +23,8 @@ type AnswerShippingQueryParameters struct { ShippingOptions []ShippingOption `json:"shipping_options,omitempty"` } +// NewAnswerShippingQuery creates AnswerShippingQueryParameters only with +// required parameters. func NewAnswerShippingQuery(shippingQueryID string, ok bool) *AnswerShippingQueryParameters { return &AnswerShippingQueryParameters{ ShippingQueryID: shippingQueryID, diff --git a/constants.go b/constants.go index 25108b4..2eca8cb 100644 --- a/constants.go +++ b/constants.go @@ -1,5 +1,9 @@ package telegram +// Version represents current version of Telegram API supported by this package +const Version = 3.6 + +// Action... represents available and supported status actions of bot const ( ActionFindLocation = "find_location" ActionRecordAudio = "record_audio" @@ -13,6 +17,7 @@ const ( ActionUploadVideoNote = "upload_video_note" ) +// Chat... represents available and supported chat types const ( ChatChannel = "channel" ChatGroup = "group" @@ -20,6 +25,7 @@ const ( ChatSuperGroup = "supergroup" ) +// Entity... represents available and supported entity types const ( EntityBold = "bold" EntityBotCommand = "bot_command" @@ -34,6 +40,7 @@ const ( EntityURL = "url" ) +// Method... represents available and supported Telegram API methods const ( MethodAddStickerToSet = "addStickerToSet" MethodAnswerCallbackQuery = "answerCallbackQuery" @@ -96,11 +103,13 @@ const ( MethodUploadStickerFile = "uploadStickerFile" ) +// Mode... represents available and supported parsing modes of messages const ( ModeHTML = "html" ModeMarkdown = "markdown" ) +// Mime... represents available and supported MIME types of data const ( MimeHTML = "text/html" MimeMP4 = "video/mp4" @@ -108,11 +117,13 @@ const ( MimeZIP = "application/zip" ) +// Scheme... represents optional schemes for URLs const ( SchemeAttach = "attach" SchemeTelegram = "tg" ) +// Status... represents available and supported statuses of ID const ( StatusAdministrator = "administrator" StatusCreator = "creator" @@ -122,6 +133,7 @@ const ( StatusRestricted = "restricted" ) +// Type... represents available and supported types of data const ( TypeArticle = "article" TypeAudio = "audio" @@ -138,6 +150,7 @@ const ( TypeVoice = "voice" ) +// Update... represents available and supported types of updates const ( UpdateCallbackQuery = "callback_query" UpdateChannelPost = "channel_post" diff --git a/delete_chat_photo.go b/delete_chat_photo.go index cbfb3c3..d61763d 100644 --- a/delete_chat_photo.go +++ b/delete_chat_photo.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// DeleteChatPhotoParameters represents data for DeleteChatPhoto method. type DeleteChatPhotoParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/delete_chat_sticker_set.go b/delete_chat_sticker_set.go index 5759681..0aab3dc 100644 --- a/delete_chat_sticker_set.go +++ b/delete_chat_sticker_set.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// DeleteChatStickerSetParameters represents data for DeleteChatStickerSet method. type DeleteChatStickerSetParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/delete_message.go b/delete_message.go index 3e9bbda..c4e57b0 100644 --- a/delete_message.go +++ b/delete_message.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// DeleteMessageParameters represents data for DeleteMessage method. type DeleteMessageParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/delete_sticker_from_set.go b/delete_sticker_from_set.go index d9e4ecc..20445f0 100644 --- a/delete_sticker_from_set.go +++ b/delete_sticker_from_set.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// DeleteStickerFromSetParameters represents data for DeleteStickerFromSet method. type DeleteStickerFromSetParameters struct { Sticker string `json:"sticker"` } diff --git a/doc.go b/doc.go index 323e289..a8a896a 100644 --- a/doc.go +++ b/doc.go @@ -1,2 +1,2 @@ -// Version of the bot API: 3.6 (February 13, 2018) +// Package telegram contains bindings for the Telegram API package telegram diff --git a/edit_message_caption.go b/edit_message_caption.go index 9db0809..522215c 100644 --- a/edit_message_caption.go +++ b/edit_message_caption.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// EditMessageCaptionParameters represents data for EditMessageCaption method. type EditMessageCaptionParameters struct { // Required if inline_message_id is not specified. Unique identifier for the // target chat or username of the target channel (in the format diff --git a/edit_message_live_location.go b/edit_message_live_location.go index f38d8dc..7a96b67 100644 --- a/edit_message_live_location.go +++ b/edit_message_live_location.go @@ -2,6 +2,8 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// EditMessageLiveLocationParameters represents data for EditMessageLiveLocation +// method. type EditMessageLiveLocationParameters struct { // Required if inline_message_id is not specified. Unique identifier for the // target chat or username of the target channel (in the format @@ -26,6 +28,8 @@ type EditMessageLiveLocationParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewLiveLocation creates EditMessageLiveLocationParameters only with required +// parameters. func NewLiveLocation(latitude, longitude float32) *EditMessageLiveLocationParameters { return &EditMessageLiveLocationParameters{ Latitude: latitude, diff --git a/edit_message_reply_markup.go b/edit_message_reply_markup.go index 9039fae..c63467c 100644 --- a/edit_message_reply_markup.go +++ b/edit_message_reply_markup.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// EditMessageReplyMarkupParameters represents data for EditMessageReplyMarkup method. type EditMessageReplyMarkupParameters struct { // Required if inline_message_id is not specified. Unique identifier for the // target chat or username of the target channel (in the format diff --git a/edit_message_text.go b/edit_message_text.go index 32753b6..e25f0b3 100644 --- a/edit_message_text.go +++ b/edit_message_text.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// EditMessageTextParameters represents data for EditMessageText method. type EditMessageTextParameters struct { // Required if inline_message_id is not specified. Unique identifier for the // target chat or username of the target channel (in the format @@ -30,6 +31,7 @@ type EditMessageTextParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewMessageText creates EditMessageTextParameters only with required parameters. func NewMessageText(text string) *EditMessageTextParameters { return &EditMessageTextParameters{ Text: text, diff --git a/export_chat_invite_link.go b/export_chat_invite_link.go index abd5f95..291be82 100644 --- a/export_chat_invite_link.go +++ b/export_chat_invite_link.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// ExportChatInviteLinkParameters represents data for ExportChatInviteLink method. type ExportChatInviteLinkParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/forward_message.go b/forward_message.go index 9c756aa..752c495 100644 --- a/forward_message.go +++ b/forward_message.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// ForwardMessageParameters represents data for ForwardMessage method. type ForwardMessageParameters struct { // Unique identifier for the target chat or username of the target channel (in the format @channelusername) ChatID int64 `json:"chat_id"` @@ -16,6 +17,7 @@ type ForwardMessageParameters struct { MessageID int `json:"message_id"` } +// NewForwardMessage creates ForwardMessageParameters only with reqired parameters. func NewForwardMessage(from, to int64, messageID int) *ForwardMessageParameters { return &ForwardMessageParameters{ FromChatID: from, diff --git a/get_chat.go b/get_chat.go index 4c81d24..9142a1c 100644 --- a/get_chat.go +++ b/get_chat.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetChatParameters represents data for GetChat method. type GetChatParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/get_chat_administrators.go b/get_chat_administrators.go index 30b64a3..9434dc8 100644 --- a/get_chat_administrators.go +++ b/get_chat_administrators.go @@ -2,6 +2,8 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetChatAdministratorsParameters represents data for GetChatAdministrators +// method. type GetChatAdministratorsParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/get_chat_member.go b/get_chat_member.go index 8703178..b81cc2a 100644 --- a/get_chat_member.go +++ b/get_chat_member.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetChatMemberParameters represents data for GetChatMember method. type GetChatMemberParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/get_chat_members_count.go b/get_chat_members_count.go index 2355966..140193c 100644 --- a/get_chat_members_count.go +++ b/get_chat_members_count.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetChatMembersCountParameters represents data for GetChatMembersCount method. type GetChatMembersCountParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/get_file.go b/get_file.go index ba66408..202101b 100644 --- a/get_file.go +++ b/get_file.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetFileParameters represents data for GetFile method. type GetFileParameters struct { FileID string `json:"file_id"` } diff --git a/get_game_high_scores.go b/get_game_high_scores.go index b5ce0a0..44e2b35 100644 --- a/get_game_high_scores.go +++ b/get_game_high_scores.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetGameHighScoresParameters represents data for GetGameHighScores method. type GetGameHighScoresParameters struct { // Target user id UserID int `json:"user_id"` @@ -19,6 +20,7 @@ type GetGameHighScoresParameters struct { InlineMessageID string `json:"inline_message_id,omitempty"` } +// NewGameHighScores creates GetGameHighScoresParameters only with required parameters. func NewGameHighScores(userID int) *GetGameHighScoresParameters { return &GetGameHighScoresParameters{ UserID: userID, diff --git a/get_sticker_set.go b/get_sticker_set.go index 349c78e..654b0da 100644 --- a/get_sticker_set.go +++ b/get_sticker_set.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetStickerSetParameters represents data for GetStickerSet method. type GetStickerSetParameters struct { Name string `json:"name"` } diff --git a/get_updates.go b/get_updates.go index 3d96062..0086381 100644 --- a/get_updates.go +++ b/get_updates.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetUpdatesParameters represents data for GetUpdates method. type GetUpdatesParameters struct { // Identifier of the first update to be returned. Must be greater by one than // the highest among the identifiers of previously received updates. By diff --git a/get_user_profile_photos.go b/get_user_profile_photos.go index 7fe1a8d..61d25d7 100644 --- a/get_user_profile_photos.go +++ b/get_user_profile_photos.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// GetUserProfilePhotosParameters represents data for GetUserProfilePhotos method. type GetUserProfilePhotosParameters struct { UserID int `json:"user_id"` Offset int `json:"offset"` diff --git a/kick_chat_member.go b/kick_chat_member.go index 8ace526..5052ec6 100644 --- a/kick_chat_member.go +++ b/kick_chat_member.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// KickChatMemberParameters represents data for KickChatMember method. type KickChatMemberParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/leave_chat.go b/leave_chat.go index 4eaba35..81d55e2 100644 --- a/leave_chat.go +++ b/leave_chat.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// LeaveChatParameters represents data for LeaveChat method. type LeaveChatParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/login/check_authorization.go b/login/check_authorization.go index 6efc220..1e492de 100644 --- a/login/check_authorization.go +++ b/login/check_authorization.go @@ -9,6 +9,7 @@ import ( "strconv" ) +// ErrUserNotDefined describes error of an unassigned structure of user var ErrUserNotDefined = errors.New("user is not defined") // CheckAuthorization verify the authentication and the integrity of the data diff --git a/login/constants.go b/login/constants.go index 9e8d796..bed2879 100644 --- a/login/constants.go +++ b/login/constants.go @@ -1,5 +1,6 @@ package login +// Key... represents available and supported data keys const ( KeyAuthDate = "auth_date" KeyFirstName = "first_name" diff --git a/pin_chat_message.go b/pin_chat_message.go index 2283584..928e60f 100644 --- a/pin_chat_message.go +++ b/pin_chat_message.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// PinChatMessageParameters represents data for PinChatMessage method. type PinChatMessageParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/request.go b/request.go index 5db5d90..ba8cc1e 100644 --- a/request.go +++ b/request.go @@ -3,7 +3,6 @@ package telegram import ( "errors" "fmt" - "net/url" log "github.com/kirillDanshin/dlog" json "github.com/pquerna/ffjson/ffjson" @@ -11,18 +10,18 @@ import ( ) func (bot *Bot) request(dst []byte, method string) (*Response, error) { - requestURI := &url.URL{ - Scheme: "https", - Host: "api.telegram.org", - Path: fmt.Sprint("/bot", bot.AccessToken, "/", method), - } + requestURI := defaultURI + requestURI.Path = fmt.Sprint("/bot", bot.AccessToken, "/", method) req := http.AcquireRequest() defer http.ReleaseRequest(req) req.Header.SetContentType("application/json; charset=utf-8") req.Header.SetMethod("POST") + if dst == nil { + req.Header.SetMethod("GET") + } req.Header.SetRequestURI(requestURI.String()) - req.Header.SetUserAgent("go-telegram/3.5") + req.Header.SetUserAgent(fmt.Sprint("telegram/", Version)) req.Header.SetHost(requestURI.Hostname()) req.SetBody(dst) diff --git a/send_chat_action.go b/send_chat_action.go index 985615a..d332d84 100644 --- a/send_chat_action.go +++ b/send_chat_action.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendChatActionParameters represents data for SendChatAction method. type SendChatActionParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/send_contact.go b/send_contact.go index b917f7b..979740e 100644 --- a/send_contact.go +++ b/send_contact.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendContactParameters represents data for SendContact method. type SendContactParameters struct { // Unique identifier for the target private chat ChatID int64 `json:"chat_id"` @@ -28,6 +29,7 @@ type SendContactParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewContact creates SendContactParameters only with required parameters. func NewContact(chatID int64, phoneNumber, firstName string) *SendContactParameters { return &SendContactParameters{ ChatID: chatID, diff --git a/send_document.go b/send_document.go index 0ff2d60..9772ce1 100644 --- a/send_document.go +++ b/send_document.go @@ -7,6 +7,7 @@ import ( http "github.com/valyala/fasthttp" ) +// SendDocumentParameters represents data for SendDocument method. type SendDocumentParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` @@ -34,6 +35,7 @@ type SendDocumentParameters struct { ReplyMarkup interface{} `json:"reply_markup,omitempty"` } +// NewDocument creates SendDocumentParameters only with required parameters. func NewDocument(chatID int64, document interface{}) *SendDocumentParameters { return &SendDocumentParameters{ ChatID: chatID, diff --git a/send_game.go b/send_game.go index beaedb0..efe11a8 100644 --- a/send_game.go +++ b/send_game.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendGameParameters represents data for SendGame method. type SendGameParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` @@ -23,6 +24,7 @@ type SendGameParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewGame creates SendGameParameters only with required parameters. func NewGame(chatID int64, gameShortName string) *SendGameParameters { return &SendGameParameters{ ChatID: chatID, diff --git a/send_invoice.go b/send_invoice.go index 6b930e7..39d5f85 100644 --- a/send_invoice.go +++ b/send_invoice.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendInvoiceParameters represents data for SendInvoice method. type SendInvoiceParameters struct { // Unique identifier for the target private chat ChatID int64 `json:"chat_id"` @@ -78,6 +79,7 @@ type SendInvoiceParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewInvoice creates SendInvoiceParameters only with required parameters. func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices ...LabeledPrice) *SendInvoiceParameters { return &SendInvoiceParameters{ ChatID: chatID, diff --git a/send_location.go b/send_location.go index 3638f96..ca5c36b 100644 --- a/send_location.go +++ b/send_location.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendLocationParameters represents data for SendLocation method. type SendLocationParameters struct { // Unique identifier for the target private chat ChatID int64 `json:"chat_id"` @@ -29,6 +30,7 @@ type SendLocationParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewLocation creates SendLocationParameters only with required parameters. func NewLocation(chatID int64, latitude, longitude float32) *SendLocationParameters { return &SendLocationParameters{ ChatID: chatID, diff --git a/send_media_group.go b/send_media_group.go index 846b6ea..b026064 100644 --- a/send_media_group.go +++ b/send_media_group.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendMediaGroupParameters represents data for SendMediaGroup method. type SendMediaGroupParameters struct { // Unique identifier for the target chat. ChatID int64 `json:"chat_id"` @@ -18,6 +19,7 @@ type SendMediaGroupParameters struct { ReplyToMessageID int `json:"reply_to_message_id,omitempty"` } +// NewMediaGroup creates SendMediaGroupParameters only with required parameters. func NewMediaGroup(chatID int64, media ...interface{}) *SendMediaGroupParameters { return &SendMediaGroupParameters{ ChatID: chatID, diff --git a/send_message.go b/send_message.go index 58677f7..8347c27 100644 --- a/send_message.go +++ b/send_message.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendMessageParameters represents data for SendMessage method. type SendMessageParameters struct { // Unique identifier for the target chat or username of the target channel // (in the format @channelusername) @@ -30,6 +31,7 @@ type SendMessageParameters struct { ReplyMarkup interface{} `json:"reply_markup,omitempty"` } +// NewMessage creates SendMessageParameters only with required parameters. func NewMessage(chatID int64, text string) *SendMessageParameters { return &SendMessageParameters{ ChatID: chatID, diff --git a/send_photo.go b/send_photo.go index 9992131..6d0de3c 100644 --- a/send_photo.go +++ b/send_photo.go @@ -7,6 +7,7 @@ import ( http "github.com/valyala/fasthttp" ) +// SendPhotoParameters represents data for SendPhoto method. type SendPhotoParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` @@ -41,6 +42,7 @@ type SendPhotoParameters struct { ReplyMarkup interface{} `json:"reply_markup,omitempty"` } +// NewPhoto creates SendPhotoParameters only with required parameters. func NewPhoto(chatID int64, photo interface{}) *SendPhotoParameters { return &SendPhotoParameters{ ChatID: chatID, diff --git a/send_venue.go b/send_venue.go index 8273736..6508f29 100644 --- a/send_venue.go +++ b/send_venue.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SendVenueParameters represents data for SendVenue method. type SendVenueParameters struct { // Unique identifier for the target private chat ChatID int64 `json:"chat_id"` @@ -34,6 +35,7 @@ type SendVenueParameters struct { ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } +// NewVenue creates SendVenueParameters only with required parameters. func NewVenue(chatID int64, latitude, longitude float32, title, address string) *SendVenueParameters { return &SendVenueParameters{ ChatID: chatID, diff --git a/set_chat_description.go b/set_chat_description.go index 5e938d4..6968a96 100644 --- a/set_chat_description.go +++ b/set_chat_description.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SetChatDescriptionParameters represents data for SetChatDescription method. type SetChatDescriptionParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/set_chat_photo.go b/set_chat_photo.go index c98e341..cc7d3aa 100644 --- a/set_chat_photo.go +++ b/set_chat_photo.go @@ -7,6 +7,7 @@ import ( http "github.com/valyala/fasthttp" ) +// SetChatPhotoParameters represents data for SetChatPhoto method. type SetChatPhotoParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/set_chat_sticker_set.go b/set_chat_sticker_set.go index cb08b7a..61e3d26 100644 --- a/set_chat_sticker_set.go +++ b/set_chat_sticker_set.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SetChatStickerSetParameters represents data for SetChatStickerSet method. type SetChatStickerSetParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/set_chat_title.go b/set_chat_title.go index 7b75d34..e6a25a8 100644 --- a/set_chat_title.go +++ b/set_chat_title.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SetChatTitleParameters represents data for SetChatTitle method. type SetChatTitleParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/set_game_score.go b/set_game_score.go index 25ae59e..9dd30a5 100644 --- a/set_game_score.go +++ b/set_game_score.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SetGameScoreParameters represents data for SetGameScore method. type SetGameScoreParameters struct { // User identifier UserID int `json:"user_id"` @@ -30,6 +31,7 @@ type SetGameScoreParameters struct { InlineMessageID string `json:"inline_message_id,omitempty"` } +// NewGameScore creates SetGameScoreParameters only with required parameters. func NewGameScore(userID, score int) *SetGameScoreParameters { return &SetGameScoreParameters{ UserID: userID, diff --git a/set_sticker_position_in_set.go b/set_sticker_position_in_set.go index f466004..37f0f48 100644 --- a/set_sticker_position_in_set.go +++ b/set_sticker_position_in_set.go @@ -2,6 +2,8 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// SetStickerPositionInSetParameters represents data for SetStickerPositionInSet +// method. type SetStickerPositionInSetParameters struct { Sticker string `json:"sticker"` Position int `json:"position"` diff --git a/set_webhook.go b/set_webhook.go index d912613..e090266 100644 --- a/set_webhook.go +++ b/set_webhook.go @@ -8,6 +8,7 @@ import ( http "github.com/valyala/fasthttp" ) +// SetWebhookParameters represents data for SetWebhook method. type SetWebhookParameters struct { // HTTPS url to send updates to. Use an empty string to remove webhook // integration @@ -36,6 +37,7 @@ type SetWebhookParameters struct { AllowedUpdates []string `json:"allowed_updates,omitempty"` } +// NewWebhook creates new SetWebhookParameters only with required parameters. func NewWebhook(url string, file interface{}) *SetWebhookParameters { return &SetWebhookParameters{ URL: url, diff --git a/unban_chat_member.go b/unban_chat_member.go index 52d6a85..61553b7 100644 --- a/unban_chat_member.go +++ b/unban_chat_member.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// UnbanChatMemberParameters represents data for UnbanChatMember method. type UnbanChatMemberParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/unpin_chat_message.go b/unpin_chat_message.go index a59398f..15e6fa1 100644 --- a/unpin_chat_message.go +++ b/unpin_chat_message.go @@ -2,6 +2,7 @@ package telegram import json "github.com/pquerna/ffjson/ffjson" +// UnpinChatMessageParameters represents data for UnpinChatMessage method. type UnpinChatMessageParameters struct { // Unique identifier for the target chat ChatID int64 `json:"chat_id"` diff --git a/upload.go b/upload.go index 2dd54c8..388d608 100644 --- a/upload.go +++ b/upload.go @@ -14,6 +14,7 @@ import ( http "github.com/valyala/fasthttp" ) +// ErrBadFileType describes error of the unsupported file data type for uploading var ErrBadFileType = errors.New("bad file type") /* @@ -23,8 +24,10 @@ media, etc.): 1. If the file is already stored somewhere on the Telegram servers, you don't need to reupload it: each file object has a file_id field, simply pass this file_id as a parameter instead of uploading. There are no limits for files sent this way. + 2. Provide Telegram with an *url.URL for the file to be sent. Telegram will download and send the file. 5 MB max size for photos and 20 MB max for other types of content. + 3. Post the file using multipart/form-data in the usual way that files are uploaded via the browser. Use []byte or io.Reader for this. 10 MB max size for photos, 50 MB for other files. @@ -49,11 +52,8 @@ func (bot *Bot) Upload(method, key, name string, file InputFile, args fmt.String buffer := bytes.NewBuffer(nil) multi := multipart.NewWriter(buffer) - requestURI := &url.URL{ - Scheme: "https", - Host: "api.telegram.org", - Path: fmt.Sprint("/bot", bot.AccessToken, "/", method), - } + requestURI := defaultURI + requestURI.Path = fmt.Sprint("/bot", bot.AccessToken, "/", method) query, err := url.ParseQuery(args.String()) if err != nil { @@ -66,19 +66,7 @@ func (bot *Bot) Upload(method, key, name string, file InputFile, args fmt.String } } - switch src := file.(type) { - case string: - err = uploadByString(multi, key, src) - case *url.URL: // Send by URL - err = uploadFromURL(multi, key, src) - case []byte: // Upload new - err = uploadFromMemory(multi, key, name, bytes.NewReader(src)) - case io.Reader: // Upload new - err = uploadFromMemory(multi, key, name, src) - default: - return nil, ErrBadFileType - } - if err != nil { + if err = createFileField(multi, file, key, name); err != nil { return nil, err } @@ -92,23 +80,21 @@ func (bot *Bot) Upload(method, key, name string, file InputFile, args fmt.String req.Header.SetContentType(multi.FormDataContentType()) req.Header.SetMethod("POST") req.Header.SetRequestURI(requestURI.String()) - req.Header.SetUserAgent("go-telegram/3.5") - req.Header.SetHost("api.telegram.org") + req.Header.SetUserAgent(fmt.Sprint("telegram/", Version)) + req.Header.SetHost(requestURI.Hostname()) log.Ln("Request:") log.D(req) resp := http.AcquireResponse() defer http.ReleaseResponse(resp) - if err = http.Do(req, resp); err != nil { - log.Ln("Resp:") - log.D(resp) - - return nil, err - } + err = http.Do(req, resp) log.Ln("Resp:") log.D(resp) + if err != nil { + return nil, err + } var data Response if err = json.Unmarshal(resp.Body(), &data); err != nil { @@ -122,19 +108,34 @@ func (bot *Bot) Upload(method, key, name string, file InputFile, args fmt.String return &data, nil } -func uploadByString(w *multipart.Writer, key, src string) error { - _, err := os.Stat(src) - switch { - case os.IsNotExist(err): - err = uploadFromFileID(w, key, src) - case os.IsExist(err): - err = uploadFromDisk(w, key, src) +func createFileField(w *multipart.Writer, file interface{}, key, val string) error { + var err error + switch src := file.(type) { + case string: // Send FileID of file on disk path + err = createFileFieldString(w, key, src) + case *url.URL: // Send by URL + err = w.WriteField(key, src.String()) + case []byte: // Upload new + err = createFileFieldRaw(w, key, val, bytes.NewReader(src)) + case io.Reader: // Upload new + err = createFileFieldRaw(w, key, val, src) + default: + return ErrBadFileType } return err } -func uploadFromFileID(w *multipart.Writer, key, src string) error { - return w.WriteField(key, src) +func createFileFieldString(w *multipart.Writer, key, src string) error { + _, err := os.Stat(src) + + switch { + case os.IsNotExist(err): + err = w.WriteField(key, src) + case os.IsExist(err): + err = uploadFromDisk(w, key, src) + } + + return err } func uploadFromDisk(w *multipart.Writer, key, src string) error { @@ -156,11 +157,7 @@ func uploadFromDisk(w *multipart.Writer, key, src string) error { return err } -func uploadFromURL(w *multipart.Writer, key string, src *url.URL) error { - return w.WriteField(key, src.String()) -} - -func uploadFromMemory(w *multipart.Writer, key, value string, src io.Reader) error { +func createFileFieldRaw(w *multipart.Writer, key, value string, src io.Reader) error { field, err := w.CreateFormFile(key, value) if err != nil { return err diff --git a/utils.go b/utils.go index 6b27183..e57839b 100644 --- a/utils.go +++ b/utils.go @@ -5,10 +5,12 @@ import ( "strconv" ) +// NewForceReply calls the response interface to the message. func NewForceReply() *ForceReply { return &ForceReply{ForceReply: true} } +// NewInlineMentionURL creates a url.URL for the mention user without username. func NewInlineMentionURL(userID int) *url.URL { link := &url.URL{ Scheme: SchemeTelegram, diff --git a/utils_bot.go b/utils_bot.go index e2de5c2..f9d633e 100644 --- a/utils_bot.go +++ b/utils_bot.go @@ -6,61 +6,42 @@ import ( "strings" ) +// Bot represents a bot user with access token getted from @BotFather. type Bot struct { AccessToken string *User } +// New creates a new Bot structure based on the input access token. func New(accessToken string) (*Bot, error) { var err error - bot := &Bot{AccessToken: accessToken} + bot := new(Bot) + bot.AccessToken = accessToken bot.User, err = bot.GetMe() return bot, err } +// IsMessageFromMe checks that the input message is a message from the current +// bot. func (bot *Bot) IsMessageFromMe(msg *Message) bool { - if msg == nil || bot == nil { - return false - } - - if msg.From == nil || bot.User == nil { - return false - } - - return msg.From.ID == bot.ID + return msg != nil && bot != nil && msg.From != nil && bot.User != nil && msg.From.ID == bot.ID } +// IsForwardFromMe checks that the input message is a forwarded message from the +// current bot. func (bot *Bot) IsForwardFromMe(msg *Message) bool { - if !msg.IsForward() { - return false - } - - if bot == nil { - return false - } - - if bot.User == nil { - return false - } - - return msg.ForwardFrom.ID == bot.ID + return msg.IsForward() && bot != nil && bot.User != nil && msg.ForwardFrom.ID == bot.ID } +// IsReplyToMe checks that the input message is a reply to the current bot. func (bot *Bot) IsReplyToMe(msg *Message) bool { - if msg.Chat.IsPrivate() { - return true - } - - if !msg.IsReply() { - return false - } - - return bot.IsMessageFromMe(msg.ReplyToMessage) + return msg.Chat.IsPrivate() || (msg.IsReply() && bot.IsMessageFromMe(msg.ReplyToMessage)) } +// IsCommandToMe checks that the input message is a command for the current bot. func (bot *Bot) IsCommandToMe(msg *Message) bool { - if !msg.IsCommand("") { + if !msg.IsCommand() { return false } @@ -76,12 +57,9 @@ func (bot *Bot) IsCommandToMe(msg *Message) bool { return strings.ToLower(parts[1]) == strings.ToLower(bot.User.Username) } +// IsMessageMentionsMe checks that the input message mentions the current bot. func (bot *Bot) IsMessageMentionsMe(msg *Message) bool { - if msg == nil || bot == nil { - return false - } - - if bot.User == nil { + if msg == nil || bot == nil || bot.User == nil { return false } @@ -108,59 +86,45 @@ func (bot *Bot) IsMessageMentionsMe(msg *Message) bool { return false } +// IsForwardMentionsMe checks that the input forwarded message mentions the +// current bot. func (bot *Bot) IsForwardMentionsMe(msg *Message) bool { return msg.IsForward() && bot.IsMessageMentionsMe(msg) } +// IsReplyMentionsMe checks that the input message mentions the current bot. func (bot *Bot) IsReplyMentionsMe(msg *Message) bool { return msg.IsReply() && bot.IsMessageMentionsMe(msg.ReplyToMessage) } +// IsMessageToMe checks that the input message is addressed to the current bot. func (bot *Bot) IsMessageToMe(msg *Message) bool { - if msg == nil { + if msg == nil || msg.Chat == nil { return false } - if msg.Chat == nil { - return false - } - - if msg.Chat.IsPrivate() || - bot.IsCommandToMe(msg) || - bot.IsReplyToMe(msg) || - bot.IsMessageMentionsMe(msg) { + if msg.Chat.IsPrivate() || bot.IsCommandToMe(msg) || bot.IsReplyToMe(msg) || bot.IsMessageMentionsMe(msg) { return true } return false } +// NewFileURL creates a url.URL to file with path getted from GetFile method. func (bot *Bot) NewFileURL(filePath string) *url.URL { - if bot == nil { + if bot == nil || bot.AccessToken == "" || filePath == "" { return nil } - if bot.AccessToken == "" || filePath == "" { - return nil - } + result := defaultURI + result.Path = fmt.Sprint("/file/bot", bot.AccessToken, "/", filePath) - return &url.URL{ - Scheme: "https", - Host: "api.telegram.org", - Path: fmt.Sprint("/file/bot", bot.AccessToken, "/", filePath), - } + return result } -func (bot *Bot) NewRedirectURL(group bool, param string) *url.URL { - if bot == nil { - return nil - } - - if bot.User == nil { - return nil - } - - if bot.User.Username == "" { +// NewRedirectURL creates new url.URL for redirecting from one chat to another. +func (bot *Bot) NewRedirectURL(param string, group bool) *url.URL { + if bot == nil || bot.User == nil || bot.User.Username == "" { return nil } @@ -171,11 +135,11 @@ func (bot *Bot) NewRedirectURL(group bool, param string) *url.URL { } q := link.Query() + key := "start" if group { - q.Add("startgroup", param) - } else { - q.Add("start", param) + key += "group" } + q.Add(key, param) link.RawQuery = q.Encode() diff --git a/utils_chat.go b/utils_chat.go index 331137e..d4839fd 100644 --- a/utils_chat.go +++ b/utils_chat.go @@ -2,60 +2,39 @@ package telegram import "fmt" +// IsPrivate checks that the current chat is a private chat with single user. func (chat *Chat) IsPrivate() bool { - if chat == nil { - return false - } - - return chat.Type == ChatPrivate + return chat != nil && chat.Type == ChatPrivate } +// IsGroup checks that the current chat is a group. func (chat *Chat) IsGroup() bool { - if chat == nil { - return false - } - - return chat.Type == ChatGroup + return chat != nil && chat.Type == ChatGroup } +// IsSuperGroup checks that the current chat is a supergroup. func (chat *Chat) IsSuperGroup() bool { - if chat == nil { - return false - } - - return chat.Type == ChatSuperGroup + return chat != nil && chat.Type == ChatSuperGroup } +// IsChannel checks that the current chat is a channel. func (chat *Chat) IsChannel() bool { - if chat == nil { - return false - } - - return chat.Type == ChatChannel + return chat != nil && chat.Type == ChatChannel } +// HasPinnedMessage checks that the current chat has a pinned message. func (chat *Chat) HasPinnedMessage() bool { - if chat == nil { - return false - } - - return chat.PinnedMessage != nil + return chat != nil && chat.PinnedMessage != nil } +// HasStickerSet checks that the current chat has a sticker set. func (chat *Chat) HasStickerSet() bool { - if chat == nil { - return false - } - - return chat.StickerSetName != "" + return chat != nil && chat.StickerSetName != "" } +// StickerSet return StickerSet structure if StickerSetName is available. func (chat *Chat) StickerSet(bot *Bot) *StickerSet { - if !chat.HasStickerSet() { - return nil - } - - if bot == nil { + if !chat.HasStickerSet() || bot == nil { return nil } @@ -67,6 +46,7 @@ func (chat *Chat) StickerSet(bot *Bot) *StickerSet { return set } +// FullName returns the full name of chat or FirstName if LastName is not available. func (chat *Chat) FullName() string { if chat == nil { return "" diff --git a/utils_entity.go b/utils_entity.go index d13516f..5e027d0 100644 --- a/utils_entity.go +++ b/utils_entity.go @@ -5,16 +5,9 @@ import ( "net/url" ) +// ParseURL selects URL from entered text of message and parse it as url.URL. func (entity *MessageEntity) ParseURL(messageText string) *url.URL { - if entity == nil { - return nil - } - - if !entity.IsURL() { - return nil - } - - if messageText == "" { + if entity == nil || !entity.IsURL() || messageText == "" { return nil } @@ -36,94 +29,62 @@ func (entity *MessageEntity) ParseURL(messageText string) *url.URL { return link } +// IsBold checks that the current entity is a bold tag. func (entity *MessageEntity) IsBold() bool { - if entity == nil { - return false - } - - return entity.Type == EntityBold + return entity != nil && entity.Type == EntityBold } +// IsBotCommand checks that the current entity is a bot command. func (entity *MessageEntity) IsBotCommand() bool { - if entity == nil { - return false - } - - return entity.Type == EntityBotCommand + return entity != nil && entity.Type == EntityBotCommand } +// IsCode checks that the current entity is a code tag. func (entity *MessageEntity) IsCode() bool { - if entity == nil { - return false - } - - return entity.Type == EntityCode + return entity != nil && entity.Type == EntityCode } +// IsEmail checks that the current entity is a email. func (entity *MessageEntity) IsEmail() bool { - if entity == nil { - return false - } - - return entity.Type == EntityEmail + return entity != nil && entity.Type == EntityEmail } +// IsHashtag checks that the current entity is a hashtag. func (entity *MessageEntity) IsHashtag() bool { - if entity == nil { - return false - } - - return entity.Type == EntityHashtag + return entity != nil && entity.Type == EntityHashtag } +// IsItalic checks that the current entity is a italic tag. func (entity *MessageEntity) IsItalic() bool { - if entity == nil { - return false - } - - return entity.Type == EntityItalic + return entity != nil && entity.Type == EntityItalic } +// IsMention checks that the current entity is a username mention. func (entity *MessageEntity) IsMention() bool { - if entity == nil { - return false - } - - return entity.Type == EntityMention + return entity != nil && entity.Type == EntityMention } +// IsPre checks that the current entity is a pre tag. func (entity *MessageEntity) IsPre() bool { - if entity == nil { - return false - } - - return entity.Type == EntityPre + return entity != nil && entity.Type == EntityPre } +// IsTextLink checks that the current entity is a text link. func (entity *MessageEntity) IsTextLink() bool { - if entity == nil { - return false - } - - return entity.Type == EntityTextLink + return entity != nil && entity.Type == EntityTextLink } +// IsTextMention checks that the current entity is a mention without username. func (entity *MessageEntity) IsTextMention() bool { - if entity == nil { - return false - } - - return entity.Type == EntityTextMention + return entity != nil && entity.Type == EntityTextMention } +// IsURL checks that the current entity is a URL func (entity *MessageEntity) IsURL() bool { - if entity == nil { - return false - } - - return entity.Type == EntityURL + return entity != nil && entity.Type == EntityURL } +// TextLink parse current text link entity as url.URL. func (entity *MessageEntity) TextLink() *url.URL { if entity == nil { return nil diff --git a/utils_inline_keyboard.go b/utils_inline_keyboard.go index 62301f9..345a3ff 100644 --- a/utils_inline_keyboard.go +++ b/utils_inline_keyboard.go @@ -1,5 +1,6 @@ package telegram +// NewInlineKeyboardMarkup creates a new inline keyboard markup for message. func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) *InlineKeyboardMarkup { var keyboard [][]InlineKeyboardButton keyboard = append(keyboard, rows...) @@ -8,12 +9,14 @@ func NewInlineKeyboardMarkup(rows ...[]InlineKeyboardButton) *InlineKeyboardMark } } +// NewInlineKeyboardRow creates a new inline keyboard row for buttons. func NewInlineKeyboardRow(buttons ...InlineKeyboardButton) []InlineKeyboardButton { var row []InlineKeyboardButton row = append(row, buttons...) return row } +// NewInlineKeyboardButton creates a new inline keyboard callback button. func NewInlineKeyboardButton(text, data string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, @@ -21,6 +24,7 @@ func NewInlineKeyboardButton(text, data string) InlineKeyboardButton { } } +// NewInlineKeyboardButtonURL creates a new inline keyboard button with URL. func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, @@ -28,6 +32,8 @@ func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { } } +// NewInlineKeyboardButtonSwitch creates a new inline keyboard button to make +// specific inline query in other chat. func NewInlineKeyboardButtonSwitch(text, query string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, @@ -35,6 +41,8 @@ func NewInlineKeyboardButtonSwitch(text, query string) InlineKeyboardButton { } } +// NewInlineKeyboardButtonSwitchSelf creates a new inline keyboard button to make +// specific inline query in same chat. func NewInlineKeyboardButtonSwitchSelf(text, query string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, @@ -42,6 +50,8 @@ func NewInlineKeyboardButtonSwitchSelf(text, query string) InlineKeyboardButton } } +// NewInlineKeyboardButtonGame creates a new inline keyboard button with game +// callback. func NewInlineKeyboardButtonGame(text string) InlineKeyboardButton { var game CallbackGame return InlineKeyboardButton{ @@ -50,6 +60,8 @@ func NewInlineKeyboardButtonGame(text string) InlineKeyboardButton { } } +// NewInlineKeyboardButtonPay creates a new inline keyboard button with pay +// callback. func NewInlineKeyboardButtonPay(text string) InlineKeyboardButton { return InlineKeyboardButton{ Text: text, diff --git a/utils_inline_query_result.go b/utils_inline_query_result.go index 067e710..b6af143 100644 --- a/utils_inline_query_result.go +++ b/utils_inline_query_result.go @@ -1,5 +1,7 @@ package telegram +// NewInlineQueryResultCachedAudio creates a new inline query result with cached +// audio. func NewInlineQueryResultCachedAudio(resultID, fileID string) *InlineQueryResultCachedAudio { return &InlineQueryResultCachedAudio{ Type: TypeAudio, @@ -8,6 +10,8 @@ func NewInlineQueryResultCachedAudio(resultID, fileID string) *InlineQueryResult } } +// NewInlineQueryResultCachedDocument creates a new inline query result with +// cached document. func NewInlineQueryResultCachedDocument(resultID, fileID, title string) *InlineQueryResultCachedDocument { return &InlineQueryResultCachedDocument{ Type: TypeDocument, @@ -17,6 +21,8 @@ func NewInlineQueryResultCachedDocument(resultID, fileID, title string) *InlineQ } } +// NewInlineQueryResultCachedGif creates a new inline query result with cached +// GIF. func NewInlineQueryResultCachedGif(resultID, fileID string) *InlineQueryResultCachedGif { return &InlineQueryResultCachedGif{ Type: TypeGIF, @@ -25,6 +31,8 @@ func NewInlineQueryResultCachedGif(resultID, fileID string) *InlineQueryResultCa } } +// NewInlineQueryResultCachedMpeg4Gif creates a new inline query result with +// cached MPEG GIF. func NewInlineQueryResultCachedMpeg4Gif(resultID, fileID string) *InlineQueryResultCachedMpeg4Gif { return &InlineQueryResultCachedMpeg4Gif{ Type: TypeMpeg4Gif, @@ -33,6 +41,8 @@ func NewInlineQueryResultCachedMpeg4Gif(resultID, fileID string) *InlineQueryRes } } +// NewInlineQueryResultCachedPhoto creates a new inline query result with cached +// photo. func NewInlineQueryResultCachedPhoto(resultID, fileID string) *InlineQueryResultCachedPhoto { return &InlineQueryResultCachedPhoto{ Type: TypePhoto, @@ -41,6 +51,8 @@ func NewInlineQueryResultCachedPhoto(resultID, fileID string) *InlineQueryResult } } +// NewInlineQueryResultCachedSticker creates a new inline query result with +// cached sticker. func NewInlineQueryResultCachedSticker(resultID, fileID string) *InlineQueryResultCachedSticker { return &InlineQueryResultCachedSticker{ Type: TypeSticker, @@ -49,6 +61,8 @@ func NewInlineQueryResultCachedSticker(resultID, fileID string) *InlineQueryResu } } +// NewInlineQueryResultCachedVideo creates a new inline query result with cached +// video. func NewInlineQueryResultCachedVideo(resultID, fileID, title string) *InlineQueryResultCachedVideo { return &InlineQueryResultCachedVideo{ Type: TypeVideo, @@ -58,6 +72,8 @@ func NewInlineQueryResultCachedVideo(resultID, fileID, title string) *InlineQuer } } +// NewInlineQueryResultCachedVoice creates a new inline query result with cached +// voice. func NewInlineQueryResultCachedVoice(resultID, fileID, title string) *InlineQueryResultCachedVoice { return &InlineQueryResultCachedVoice{ Type: TypeVoice, @@ -67,6 +83,7 @@ func NewInlineQueryResultCachedVoice(resultID, fileID, title string) *InlineQuer } } +// NewInlineQueryResultArticle creates a new inline query result with article. func NewInlineQueryResultArticle(resultID, title string, content *InputMessageContent) *InlineQueryResultArticle { return &InlineQueryResultArticle{ Type: TypeArticle, @@ -76,6 +93,7 @@ func NewInlineQueryResultArticle(resultID, title string, content *InputMessageCo } } +// NewInlineQueryResultAudio creates a new inline query result with audio. func NewInlineQueryResultAudio(resultID, audioURL, title string) *InlineQueryResultAudio { return &InlineQueryResultAudio{ Type: TypeAudio, @@ -85,6 +103,7 @@ func NewInlineQueryResultAudio(resultID, audioURL, title string) *InlineQueryRes } } +// NewInlineQueryResultContact creates a new inline query result with contact. func NewInlineQueryResultContact(resultID, phoneNumber, firstName string) *InlineQueryResultContact { return &InlineQueryResultContact{ Type: TypeContact, @@ -94,6 +113,7 @@ func NewInlineQueryResultContact(resultID, phoneNumber, firstName string) *Inlin } } +// NewInlineQueryResultGame creates a new inline query result with game. func NewInlineQueryResultGame(resultID, gameShortName string) *InlineQueryResultGame { return &InlineQueryResultGame{ Type: TypeGame, @@ -102,6 +122,7 @@ func NewInlineQueryResultGame(resultID, gameShortName string) *InlineQueryResult } } +// NewInlineQueryResultDocument creates a new inline query result with document. func NewInlineQueryResultDocument(resultID, title, documentURL, mimeType string) *InlineQueryResultDocument { return &InlineQueryResultDocument{ Type: TypeDocument, @@ -112,6 +133,7 @@ func NewInlineQueryResultDocument(resultID, title, documentURL, mimeType string) } } +// NewInlineQueryResultGif creates a new inline query result with GIF. func NewInlineQueryResultGif(resultID, gifURL, thumbURL string) *InlineQueryResultGif { return &InlineQueryResultGif{ Type: TypeGIF, @@ -121,6 +143,7 @@ func NewInlineQueryResultGif(resultID, gifURL, thumbURL string) *InlineQueryResu } } +// NewInlineQueryResultLocation creates a new inline query result with location. func NewInlineQueryResultLocation(resultID, title string, latitude, longitude float32) *InlineQueryResultLocation { return &InlineQueryResultLocation{ Type: TypeLocation, @@ -131,6 +154,7 @@ func NewInlineQueryResultLocation(resultID, title string, latitude, longitude fl } } +// NewInlineQueryResultMpeg4Gif creates a new inline query result with MPEG GIF. func NewInlineQueryResultMpeg4Gif(resultID, mpeg4URL, thumbURL string) *InlineQueryResultMpeg4Gif { return &InlineQueryResultMpeg4Gif{ Type: TypeMpeg4Gif, @@ -140,6 +164,7 @@ func NewInlineQueryResultMpeg4Gif(resultID, mpeg4URL, thumbURL string) *InlineQu } } +// NewInlineQueryResultPhoto creates a new inline query result with photo. func NewInlineQueryResultPhoto(resultID, photoURL, thumbURL string) *InlineQueryResultPhoto { return &InlineQueryResultPhoto{ Type: TypePhoto, @@ -149,6 +174,7 @@ func NewInlineQueryResultPhoto(resultID, photoURL, thumbURL string) *InlineQuery } } +// NewInlineQueryResultVenue creates a new inline query result with venue. func NewInlineQueryResultVenue(resultID, title, address string, latitude, longitude float32) *InlineQueryResultVenue { return &InlineQueryResultVenue{ Type: TypeVenue, @@ -160,6 +186,7 @@ func NewInlineQueryResultVenue(resultID, title, address string, latitude, longit } } +// NewInlineQueryResultVideo creates a new inline query result with video. func NewInlineQueryResultVideo(resultID, videoURL, mimeType, thumbURL, title string) *InlineQueryResultVideo { return &InlineQueryResultVideo{ Type: TypeVideo, @@ -171,6 +198,7 @@ func NewInlineQueryResultVideo(resultID, videoURL, mimeType, thumbURL, title str } } +// NewInlineQueryResultVoice creates a new inline query result with voice. func NewInlineQueryResultVoice(resultID, voiceURL, title string) *InlineQueryResultVoice { return &InlineQueryResultVoice{ Type: TypeVoice, diff --git a/utils_input.go b/utils_input.go index 63bf430..d516c0d 100644 --- a/utils_input.go +++ b/utils_input.go @@ -1,11 +1,13 @@ package telegram +// NewInputTextMessageContent creates a new text of message. func NewInputTextMessageContent(messageText string) *InputTextMessageContent { return &InputTextMessageContent{ MessageText: messageText, } } +// NewInputLocationMessageContent creates a new location. func NewInputLocationMessageContent(latitude, longitude float32) *InputLocationMessageContent { return &InputLocationMessageContent{ Latitude: latitude, @@ -13,6 +15,7 @@ func NewInputLocationMessageContent(latitude, longitude float32) *InputLocationM } } +// NewInputVenueMessageContent creates a new venue. func NewInputVenueMessageContent(latitude, longitude float32, title, address string) *InputVenueMessageContent { return &InputVenueMessageContent{ Latitude: latitude, @@ -22,6 +25,7 @@ func NewInputVenueMessageContent(latitude, longitude float32, title, address str } } +// NewInputContactMessageContent creates a new contact. func NewInputContactMessageContent(phoneNumber, firstName string) *InputContactMessageContent { return &InputContactMessageContent{ PhoneNumber: phoneNumber, @@ -29,6 +33,7 @@ func NewInputContactMessageContent(phoneNumber, firstName string) *InputContactM } } +// NewInputMediaPhoto creates a new photo in media album. func NewInputMediaPhoto(media string) *InputMediaPhoto { return &InputMediaPhoto{ Type: TypePhoto, @@ -36,6 +41,7 @@ func NewInputMediaPhoto(media string) *InputMediaPhoto { } } +// NewInputMediaVideo creates a new video in media album. func NewInputMediaVideo(media string) *InputMediaVideo { return &InputMediaVideo{ Type: TypeVideo, diff --git a/utils_keyboard.go b/utils_keyboard.go index 7ce5a9d..ed4146c 100644 --- a/utils_keyboard.go +++ b/utils_keyboard.go @@ -1,5 +1,6 @@ package telegram +// NewReplyKeyboardRemove just hides keyboard. func NewReplyKeyboardRemove(selective bool) *ReplyKeyboardRemove { return &ReplyKeyboardRemove{ RemoveKeyboard: true, @@ -7,27 +8,29 @@ func NewReplyKeyboardRemove(selective bool) *ReplyKeyboardRemove { } } +// NewReplyKeyboardMarkup creates new keyboard markup of simple buttons. func NewReplyKeyboardMarkup(rows ...[]KeyboardButton) *ReplyKeyboardMarkup { var keyboard [][]KeyboardButton keyboard = append(keyboard, rows...) - return &ReplyKeyboardMarkup{ - Keyboard: keyboard, - ResizeKeyboard: true, - } + return &ReplyKeyboardMarkup{Keyboard: keyboard} } +// NewReplyKeyboardRow creates new keyboard row for buttons. func NewReplyKeyboardRow(buttons ...KeyboardButton) []KeyboardButton { var row []KeyboardButton row = append(row, buttons...) return row } +// NewReplyKeyboardButton creates new button with custom text for sending it. func NewReplyKeyboardButton(text string) KeyboardButton { return KeyboardButton{ Text: text, } } +// NewReplyKeyboardButtonContact creates new button with custom text for sending +// user contact. func NewReplyKeyboardButtonContact(text string) KeyboardButton { return KeyboardButton{ Text: text, @@ -35,6 +38,8 @@ func NewReplyKeyboardButtonContact(text string) KeyboardButton { } } +// NewReplyKeyboardButtonLocation creates new button with custom text for sending +// user location. func NewReplyKeyboardButtonLocation(text string) KeyboardButton { return KeyboardButton{ Text: text, diff --git a/utils_member.go b/utils_member.go index dae9dd8..78c1bbc 100644 --- a/utils_member.go +++ b/utils_member.go @@ -2,54 +2,37 @@ package telegram import "time" +// IsCreator checks that current member is creator. func (member *ChatMember) IsCreator() bool { - if member == nil { - return false - } - - return member.Status == StatusCreator + return member != nil && member.Status == StatusCreator } +// IsAdministrator checks that current member is administrator. func (member *ChatMember) IsAdministrator() bool { - if member == nil { - return false - } - - return member.Status == StatusAdministrator + return member != nil && member.Status == StatusAdministrator } +// IsMember checks that current member is a member. func (member *ChatMember) IsMember() bool { - if member == nil { - return false - } - - return member.Status == StatusMember + return member != nil && member.Status == StatusMember } +// IsRestricted checks that current member has been restricted. func (member *ChatMember) IsRestricted() bool { - if member == nil { - return false - } - - return member.Status == StatusRestricted + return member != nil && member.Status == StatusRestricted } +// IsLeft checks that current member has left the chat. func (member *ChatMember) IsLeft() bool { - if member == nil { - return false - } - - return member.Status == StatusLeft + return member != nil && member.Status == StatusLeft } +// IsKicked checks that current member has been kicked. func (member *ChatMember) IsKicked() bool { - if member == nil { - return false - } - - return member.Status == StatusKicked + return member != nil && member.Status == StatusKicked } +// UntilTime parse UntilDate of restrictions and returns time.Time. func (member *ChatMember) UntilTime() time.Time { if member == nil { return time.Time{} diff --git a/utils_message.go b/utils_message.go index db3143a..039b0b8 100644 --- a/utils_message.go +++ b/utils_message.go @@ -5,42 +5,44 @@ import ( "time" ) -func (msg *Message) IsCommand(command string) bool { - if !msg.IsText() { - return false - } - - if !msg.HasEntities() { +// IsCommand checks that the current message is a bot command. +func (msg *Message) IsCommand() bool { + if !msg.IsText() || !msg.HasEntities() { return false } entity := msg.Entities[0] - isBotCommand := entity.IsBotCommand() && entity.Offset == 0 - if command != "" { - return isBotCommand && strings.EqualFold(msg.Command(), command) - } - - return isBotCommand + return entity.IsBotCommand() && entity.Offset == 0 } +// IsCommandEqual checks that the current message is a specific bot command. +func (msg *Message) IsCommandEqual(command string) bool { + return msg.IsCommand() && strings.EqualFold(msg.Command(), command) +} + +// Command returns identifier of the bot command without bot username, if it was +// available func (msg *Message) Command() string { - if !msg.IsCommand("") { + if !msg.IsCommand() { return "" } return strings.Split(msg.RawCommand(), "@")[0] } +// RawCommand returns identifier of the bot command with bot username, if it was +// available func (msg *Message) RawCommand() string { - if !msg.IsCommand("") { + if !msg.IsCommand() { return "" } return string([]rune(msg.Text)[1:msg.Entities[0].Length]) } +// HasCommandArgument checks that the current command message contains argument. func (msg *Message) HasCommandArgument() bool { - if !msg.IsCommand("") { + if !msg.IsCommand() { return false } @@ -52,6 +54,7 @@ func (msg *Message) HasCommandArgument() bool { return len([]rune(msg.Text)) != entity.Length } +// CommandArgument returns raw command argument. func (msg *Message) CommandArgument() string { if !msg.HasCommandArgument() { return "" @@ -60,22 +63,17 @@ func (msg *Message) CommandArgument() string { return string([]rune(msg.Text)[msg.Entities[0].Length+1:]) } +// IsReply checks that the current message is a reply on other message. func (msg *Message) IsReply() bool { - if msg == nil { - return false - } - - return msg.ReplyToMessage != nil + return msg != nil && msg.ReplyToMessage != nil } +// IsForward checks that the current message is a forward of other message. func (msg *Message) IsForward() bool { - if msg == nil { - return false - } - - return msg.ForwardFrom != nil + return msg != nil && msg.ForwardFrom != nil } +// Time parse current message Date and returns time.Time. func (msg *Message) Time() time.Time { if msg == nil { return time.Time{} @@ -84,6 +82,7 @@ func (msg *Message) Time() time.Time { return time.Unix(msg.Date, 0) } +// ForwardTime parse current message ForwardDate and returns time.Time. func (msg *Message) ForwardTime() time.Time { if msg == nil { return time.Time{} @@ -92,131 +91,157 @@ func (msg *Message) ForwardTime() time.Time { return time.Unix(msg.ForwardDate, 0) } +// EditTime parse current message EditDate and returns time.Time. func (msg *Message) EditTime() time.Time { var t time.Time - if msg == nil { - return t - } - - if !msg.HasBeenEdited() { + if msg == nil || !msg.HasBeenEdited() { return t } return time.Unix(msg.EditDate, 0) } +// HasBeenEdited checks that the current message has been edited. func (msg *Message) HasBeenEdited() bool { - if msg == nil { - return false - } - - return msg.EditDate > 0 + return msg != nil && msg.EditDate > 0 } +// IsText checks that the current message is just a text message. func (msg *Message) IsText() bool { - if msg == nil { - return false - } - - return msg.Text != "" + return msg != nil && msg.Text != "" } +// IsAudio checks that the current message is a audio. func (msg *Message) IsAudio() bool { return !msg.IsText() && msg.Audio != nil } +// IsDocument checks that the current message is a document. func (msg *Message) IsDocument() bool { return !msg.IsText() && msg.Document != nil } +// IsGame checks that the current message is a game. func (msg *Message) IsGame() bool { return !msg.IsText() && msg.Game != nil } +// IsPhoto checks that the current message is a photo. func (msg *Message) IsPhoto() bool { return !msg.IsText() && len(msg.Photo) > 0 } +// IsSticker checks that the current message is a sticker. func (msg *Message) IsSticker() bool { return !msg.IsText() && msg.Sticker != nil } +// IsVideo checks that the current message is a video. func (msg *Message) IsVideo() bool { return !msg.IsText() && msg.Video != nil } +// IsVoice checks that the current message is a voice. func (msg *Message) IsVoice() bool { return !msg.IsText() && msg.Voice != nil } +// IsVideoNote checks that the current message is a video note. func (msg *Message) IsVideoNote() bool { return !msg.IsText() && msg.VideoNote != nil } +// IsContact checks that the current message is a contact. func (msg *Message) IsContact() bool { return !msg.IsText() && msg.Contact != nil } +// IsLocation checks that the current message is a location. func (msg *Message) IsLocation() bool { return !msg.IsText() && msg.Location != nil } +// IsVenue checks that the current message is a venue. func (msg *Message) IsVenue() bool { return !msg.IsText() && msg.Venue != nil } +// IsNewChatMembersEvent checks that the current message is a event of entry of +// new members. func (msg *Message) IsNewChatMembersEvent() bool { return !msg.IsText() && len(msg.NewChatMembers) > 0 } +// IsLeftChatMemberEvent checks that the current message is a event of members +// exit. func (msg *Message) IsLeftChatMemberEvent() bool { return !msg.IsText() && msg.LeftChatMember != nil } +// IsNewChatTitleEvent checks that the current message is a event of setting a +// new chat title. func (msg *Message) IsNewChatTitleEvent() bool { return !msg.IsText() && msg.NewChatTitle != "" } +// IsNewChatPhotoEvent checks that the current message is a event of setting a +// new chat avatar. func (msg *Message) IsNewChatPhotoEvent() bool { return !msg.IsText() && len(msg.NewChatPhoto) > 0 } +// IsDeleteChatPhotoEvent checks that the current message is a event of deleting +// a chat avatar. func (msg *Message) IsDeleteChatPhotoEvent() bool { return !msg.IsText() && msg.DeleteChatPhoto } +// IsGroupChatCreatedEvent checks that the current message is a event of creating +// a new group. func (msg *Message) IsGroupChatCreatedEvent() bool { return !msg.IsText() && msg.GroupChatCreated } +// IsSupergroupChatCreatedEvent checks that the current message is a event of +// creating a new supergroup. func (msg *Message) IsSupergroupChatCreatedEvent() bool { return !msg.IsText() && msg.SupergroupChatCreated } +// IsChannelChatCreatedEvent checks that the current message is a event of +// creating a new channel. func (msg *Message) IsChannelChatCreatedEvent() bool { return !msg.IsText() && msg.ChannelChatCreated } +// IsPinnedMessage checks that the current message is a event of pinning another +// message. func (msg *Message) IsPinnedMessage() bool { return !msg.IsText() && msg.PinnedMessage != nil } +// IsInvoice checks that the current message is a invoice. func (msg *Message) IsInvoice() bool { return !msg.IsText() && msg.Invoice != nil } +// IsSuccessfulPayment checks that the current message is a event of successful +// payment. func (msg *Message) IsSuccessfulPayment() bool { return !msg.IsText() && msg.SuccessfulPayment != nil } +// HasEntities checks that the current message contains entities. func (msg *Message) HasEntities() bool { return msg.IsText() && len(msg.Entities) > 0 } +// HasCaptionEntities checks that the current media contains entities in caption. func (msg *Message) HasCaptionEntities() bool { return !msg.IsText() && len(msg.CaptionEntities) > 0 } +// HasMentions checks that the current message contains mentions. func (msg *Message) HasMentions() bool { if !msg.HasEntities() { return false @@ -231,6 +256,7 @@ func (msg *Message) HasMentions() bool { return false } +// HasCaptionMentions checks that the current media contains mentions in caption. func (msg *Message) HasCaptionMentions() bool { if !msg.HasCaptionEntities() { return false @@ -245,14 +271,12 @@ func (msg *Message) HasCaptionMentions() bool { return false } +// HasCaption checks that the current media has caption. func (msg *Message) HasCaption() bool { return !msg.IsText() && msg.Caption != "" } +// HasAuthorSignature checks that the current channel post has author signature. func (msg *Message) HasAuthorSignature() bool { - if msg == nil { - return false - } - - return msg.AuthorSignature != "" + return msg != nil && msg.AuthorSignature != "" } diff --git a/utils_update.go b/utils_update.go index 43e3ce7..bdf80d4 100644 --- a/utils_update.go +++ b/utils_update.go @@ -10,8 +10,11 @@ import ( http "github.com/valyala/fasthttp" ) +// UpdatesChannel is a channel for reading updates of bot. type UpdatesChannel <-chan Update +// NewLongPollingChannel creates channel for receive incoming updates using long +// polling. func (bot *Bot) NewLongPollingChannel(params *GetUpdatesParameters) UpdatesChannel { if params == nil { params = &GetUpdatesParameters{ @@ -44,6 +47,8 @@ func (bot *Bot) NewLongPollingChannel(params *GetUpdatesParameters) UpdatesChann return channel } +// NewWebhookChannel creates channel for receive incoming updates via an outgoing +// webhook. func (bot *Bot) NewWebhookChannel(params *SetWebhookParameters, certFile, keyFile, set, listen, serve string) (updates UpdatesChannel) { if params == nil { params = &SetWebhookParameters{ @@ -92,74 +97,50 @@ func (bot *Bot) NewWebhookChannel(params *SetWebhookParameters, certFile, keyFil return channel } +// IsMessage checks that the current update is a message creation event. func (upd *Update) IsMessage() bool { - if upd == nil { - return false - } - - return upd.Message != nil + return upd != nil && upd.Message != nil } +// IsEditedMessage checks that the current update is a editing message event. func (upd *Update) IsEditedMessage() bool { - if upd == nil { - return false - } - - return upd.EditedMessage != nil + return upd != nil && upd.EditedMessage != nil } +// IsChannelPost checks that the current update is a post channel creation event. func (upd *Update) IsChannelPost() bool { - if upd == nil { - return false - } - - return upd.ChannelPost != nil + return upd != nil && upd.ChannelPost != nil } +// IsEditedChannelPost checks that the current update is a editing post channel +// event. func (upd *Update) IsEditedChannelPost() bool { - if upd == nil { - return false - } - - return upd.EditedChannelPost != nil + return upd != nil && upd.EditedChannelPost != nil } +// IsInlineQuery checks that the current update is a inline query update. func (upd *Update) IsInlineQuery() bool { - if upd == nil { - return false - } - - return upd.InlineQuery != nil + return upd != nil && upd.InlineQuery != nil } +// IsChosenInlineResult checks that the current update is a chosen inline result +// update. func (upd *Update) IsChosenInlineResult() bool { - if upd == nil { - return false - } - - return upd.ChosenInlineResult != nil + return upd != nil && upd.ChosenInlineResult != nil } +// IsCallbackQuery checks that the current update is a callback query update. func (upd *Update) IsCallbackQuery() bool { - if upd == nil { - return false - } - - return upd.CallbackQuery != nil + return upd != nil && upd.CallbackQuery != nil } +// IsShippingQuery checks that the current update is a shipping query update. func (upd *Update) IsShippingQuery() bool { - if upd == nil { - return false - } - - return upd.ShippingQuery != nil + return upd != nil && upd.ShippingQuery != nil } +// IsPreCheckoutQuery checks that the current update is a pre checkout query +// update. func (upd *Update) IsPreCheckoutQuery() bool { - if upd == nil { - return false - } - - return upd.PreCheckoutQuery != nil + return upd != nil && upd.PreCheckoutQuery != nil } diff --git a/utils_user.go b/utils_user.go index 5ebf53d..ec3ad28 100644 --- a/utils_user.go +++ b/utils_user.go @@ -6,6 +6,7 @@ import ( "golang.org/x/text/language" ) +// Language parse LanguageCode of current user and returns language.Tag. func (user *User) Language() *language.Tag { if user == nil { return nil @@ -19,6 +20,8 @@ func (user *User) Language() *language.Tag { return &tag } +// FullName returns the full name of user or FirstName if LastName is not +// available. func (user *User) FullName() string { if user == nil { return "" diff --git a/variables.go b/variables.go new file mode 100644 index 0000000..0e4dd9a --- /dev/null +++ b/variables.go @@ -0,0 +1,8 @@ +package telegram + +import "net/url" + +var defaultURI = &url.URL{ + Scheme: "https", + Host: "api.telegram.org", +}