Error handling. Vendoring
Signed-off-by: Ettore Dreucci <ettore.dreucci@gmail.com>
This commit is contained in:
22
vendor/gopkg.in/tucnak/telebot.v2/LICENSE
generated
vendored
Normal file
22
vendor/gopkg.in/tucnak/telebot.v2/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 llya Kowalewski
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
442
vendor/gopkg.in/tucnak/telebot.v2/README.md
generated
vendored
Normal file
442
vendor/gopkg.in/tucnak/telebot.v2/README.md
generated
vendored
Normal file
@@ -0,0 +1,442 @@
|
||||
# Telebot
|
||||
>"I never knew creating Telegram bots could be so _sexy_!"
|
||||
|
||||
[](https://godoc.org/gopkg.in/tucnak/telebot.v2)
|
||||
[](https://travis-ci.org/tucnak/telebot)
|
||||
|
||||
```bash
|
||||
go get -u gopkg.in/tucnak/telebot.v2
|
||||
```
|
||||
|
||||
* [Overview](#overview)
|
||||
* [Getting Started](#getting-started)
|
||||
- [Poller](#poller)
|
||||
- [Commands](#commands)
|
||||
- [Files](#files)
|
||||
- [Sendable](#sendable)
|
||||
- [Editable](#editable)
|
||||
- [Keyboards](#keyboards)
|
||||
- [Inline mode](#inline-mode)
|
||||
* [Contributing](#contributing)
|
||||
* [Donate](#donate)
|
||||
* [License](#license)
|
||||
|
||||
# Overview
|
||||
Telebot is a bot framework for [Telegram Bot API](https://core.telegram.org/bots/api).
|
||||
This package provides the best of its kind API for command routing, inline query requests and keyboards, as well
|
||||
as callbacks. Actually, I went a couple steps further, so instead of making a 1:1 API wrapper I chose to focus on
|
||||
the beauty of API and performance. Some of the strong sides of telebot are:
|
||||
|
||||
* Real concise API
|
||||
* Command routing
|
||||
* Middleware
|
||||
* Transparent File API
|
||||
* Effortless bot callbacks
|
||||
|
||||
All the methods of telebot API are _extremely_ easy to memorize and get used to. Also, consider Telebot a
|
||||
highload-ready solution. I'll test and benchmark the most popular actions and if necessary, optimize
|
||||
against them without sacrificing API quality.
|
||||
|
||||
# Getting Started
|
||||
Let's take a look at the minimal telebot setup:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"time"
|
||||
"log"
|
||||
|
||||
tb "gopkg.in/tucnak/telebot.v2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
b, err := tb.NewBot(tb.Settings{
|
||||
Token: "TOKEN_HERE",
|
||||
Poller: &tb.LongPoller{Timeout: 10 * time.Second},
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
return
|
||||
}
|
||||
|
||||
b.Handle("/hello", func(m *tb.Message) {
|
||||
b.Send(m.Sender, "hello world")
|
||||
})
|
||||
|
||||
b.Start()
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Simple, innit? Telebot's routing system takes care of deliviering updates
|
||||
to their endpoints, so in order to get to handle any meaningful event,
|
||||
all you got to do is just plug your function to one of the Telebot-provided
|
||||
endpoints. You can find the full list
|
||||
[here](https://godoc.org/gopkg.in/tucnak/telebot.v2#pkg-constants).
|
||||
|
||||
```go
|
||||
b, _ := tb.NewBot(settings)
|
||||
|
||||
b.Handle(tb.OnText, func(m *tb.Message) {
|
||||
// all the text messages that weren't
|
||||
// captured by existing handlers
|
||||
})
|
||||
|
||||
b.Handle(tb.OnPhoto, func(m *tb.Message) {
|
||||
// photos only
|
||||
})
|
||||
|
||||
b.Handle(tb.OnChannelPost, func (m *tb.Message) {
|
||||
// channel posts only
|
||||
})
|
||||
|
||||
b.Handle(tb.Query, func (q *tb.Query) {
|
||||
// incoming inline queries
|
||||
})
|
||||
```
|
||||
|
||||
Now there's a dozen of supported endpoints (see package consts). Let me know
|
||||
if you'd like to see some endpoint or endpoint idea implemented. This system
|
||||
is completely extensible, so I can introduce them without breaking
|
||||
backwards-compatibity.
|
||||
|
||||
## Poller
|
||||
Telebot doesn't really care how you provide it with incoming updates, as long
|
||||
as you set it up with a Poller:
|
||||
```go
|
||||
// Poller is a provider of Updates.
|
||||
//
|
||||
// All pollers must implement Poll(), which accepts bot
|
||||
// pointer and subscription channel and start polling
|
||||
// synchronously straight away.
|
||||
type Poller interface {
|
||||
// Poll is supposed to take the bot object
|
||||
// subscription channel and start polling
|
||||
// for Updates immediately.
|
||||
//
|
||||
// Poller must listen for stop constantly and close
|
||||
// it as soon as it's done polling.
|
||||
Poll(b *Bot, updates chan Update, stop chan struct{})
|
||||
}
|
||||
```
|
||||
|
||||
Telegram Bot API supports long polling and webhook integration. I don't really
|
||||
care about webhooks, so the only concrete Poller you'll find in the library
|
||||
is the `LongPoller`. Poller means you can plug telebot into whatever existing
|
||||
bot infrastructure (load balancers?) you need, if you need to. Another great thing
|
||||
about pollers is that you can chain them, making some sort of middleware:
|
||||
```go
|
||||
poller := &tb.LongPoller{Timeout: 15 * time.Second}
|
||||
spamProtected := tb.NewMiddlewarePoller(poller, func(upd *tb.Update) bool {
|
||||
if upd.Message == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if strings.Contains(upd.Message.Text, "spam") {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
bot, _ := tb.NewBot(tb.Settings{
|
||||
// ...
|
||||
Poller: spamProtected,
|
||||
})
|
||||
|
||||
// graceful shutdown
|
||||
go func() {
|
||||
<-time.After(N * time.Second)
|
||||
bot.Stop()
|
||||
})()
|
||||
|
||||
bot.Start() // blocks until shutdown
|
||||
|
||||
fmt.Println(poller.LastUpdateID) // 134237
|
||||
```
|
||||
|
||||
## Commands
|
||||
When handling commands, Telebot supports both direct (`/command`) and group-like
|
||||
syntax (`/command@botname`) and will never deliver messages addressed to some
|
||||
other bot, even if [privacy mode](https://core.telegram.org/bots#privacy-mode) is off.
|
||||
For simplified deep-linking, telebot also extracts payload:
|
||||
```go
|
||||
// Command: /start <PAYLOAD>
|
||||
b.Handle("/start", func(m *tb.Message) {
|
||||
if !m.Private() {
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(m.Payload) // <PAYLOAD>
|
||||
})
|
||||
```
|
||||
|
||||
## Files
|
||||
>Telegram allows files up to 20 MB in size.
|
||||
|
||||
Telebot allows to both upload (from disk / by URL) and download (from Telegram)
|
||||
and files in bot's scope. Also, sending any kind of media with a File created
|
||||
from disk will upload the file to Telegram automatically:
|
||||
```go
|
||||
a := &tb.Audio{File: tb.FromDisk("file.ogg")}
|
||||
|
||||
fmt.Println(a.OnDisk()) // true
|
||||
fmt.Println(a.InCloud()) // false
|
||||
|
||||
// Will upload the file from disk and send it to recipient
|
||||
bot.Send(recipient, a)
|
||||
|
||||
// Next time you'll be sending this very *Audio, Telebot won't
|
||||
// re-upload the same file but rather utilize its Telegram FileID
|
||||
bot.Send(otherRecipient, a)
|
||||
|
||||
fmt.Println(a.OnDisk()) // true
|
||||
fmt.Println(a.InCloud()) // true
|
||||
fmt.Println(a.FileID) // <telegram file id: ABC-DEF1234ghIkl-zyx57W2v1u123ew11>
|
||||
```
|
||||
|
||||
You might want to save certain `File`s in order to avoid re-uploading. Feel free
|
||||
to marshal them into whatever format, `File` only contain public fields, so no
|
||||
data will ever be lost.
|
||||
|
||||
## Sendable
|
||||
Send is undoubteldy the most important method in Telebot. `Send()` accepts a
|
||||
`Recipient` (could be user, group or a channel) and a `Sendable`. FYI, not only
|
||||
all telebot-provided media types (`Photo`, `Audio`, `Video`, etc.) are `Sendable`,
|
||||
but you can create composite types of your own. As long as they satisfy `Sendable`,
|
||||
Telebot will be able to send them out.
|
||||
|
||||
```go
|
||||
// Sendable is any object that can send itself.
|
||||
//
|
||||
// This is pretty cool, since it lets bots implement
|
||||
// custom Sendables for complex kind of media or
|
||||
// chat objects spanning across multiple messages.
|
||||
type Sendable interface {
|
||||
Send(*Bot, Recipient, *SendOptions) (*Message, error)
|
||||
}
|
||||
```
|
||||
|
||||
The only type at the time that doesn't fit `Send()` is `Album` and there is a reason
|
||||
for that. Albums were added not so long ago, so they are slightly quirky for backwards
|
||||
compatibilities sake. In fact, an `Album` can be sent, but never received. Instead,
|
||||
Telegram returns a `[]Message`, one for each media object in the album:
|
||||
```go
|
||||
p := &tb.Photo{File: tb.FromDisk("chicken.jpg")}
|
||||
v := &tb.Video{File: tb.FromURL("http://video.mp4")}
|
||||
|
||||
msgs, err := b.SendAlbum(user, tb.Album{p, v})
|
||||
```
|
||||
|
||||
### Send options
|
||||
Send options are objects and flags you can pass to `Send()`, `Edit()` and friends
|
||||
as optional arguments (following the recipient and the text/media). The most
|
||||
important one is called `SendOptions`, it lets you control _all_ the properties of
|
||||
the message supported by Telegram. The only drawback is that it's rather
|
||||
inconvenient to use at times, so `Send()` supports multiple shorthands:
|
||||
```go
|
||||
// regular send options
|
||||
b.Send(user, "text", &tb.SendOptions{
|
||||
// ...
|
||||
})
|
||||
|
||||
// ReplyMarkup is a part of SendOptions,
|
||||
// but often it's the only option you need
|
||||
b.Send(user, "text", &tb.ReplyMarkup{
|
||||
// ...
|
||||
})
|
||||
|
||||
// flags: no notification && no web link preview
|
||||
b.Send(user, "text", tb.Silent, tb.NoPreview)
|
||||
```
|
||||
|
||||
Full list of supported option-flags you can find
|
||||
[here](https://github.com/tucnak/telebot/blob/v2/options.go#L9).
|
||||
|
||||
## Editable
|
||||
If you want to edit some existing message, you don't really need to store the
|
||||
original `*Message` object. In fact, upon edit, Telegram only requires `chat_id`
|
||||
and `message_id`. So you don't really need the Message as the whole. Also you
|
||||
might want to store references to certain messages in the database, so I thought
|
||||
it made sense for *any* Go struct to be editable as a Telegram message, to implement
|
||||
`Editable`:
|
||||
```go
|
||||
// Editable is an interface for all objects that
|
||||
// provide "message signature", a pair of 32-bit
|
||||
// message ID and 64-bit chat ID, both required
|
||||
// for edit operations.
|
||||
//
|
||||
// Use case: DB model struct for messages to-be
|
||||
// edited with, say two collums: msg_id,chat_id
|
||||
// could easily implement MessageSig() making
|
||||
// instances of stored messages editable.
|
||||
type Editable interface {
|
||||
// MessageSig is a "message signature".
|
||||
//
|
||||
// For inline messages, return chatID = 0.
|
||||
MessageSig() (messageID int, chatID int64)
|
||||
}
|
||||
```
|
||||
|
||||
For example, `Message` type is Editable. Here is the implementation of `StoredMessage`
|
||||
type, provided by telebot:
|
||||
```go
|
||||
// StoredMessage is an example struct suitable for being
|
||||
// stored in the database as-is or being embedded into
|
||||
// a larger struct, which is often the case (you might
|
||||
// want to store some metadata alongside, or might not.)
|
||||
type StoredMessage struct {
|
||||
MessageID int `sql:"message_id" json:"message_id"`
|
||||
ChatID int64 `sql:"chat_id" json:"chat_id"`
|
||||
}
|
||||
|
||||
func (x StoredMessage) MessageSig() (int, int64) {
|
||||
return x.MessageID, x.ChatID
|
||||
}
|
||||
```
|
||||
|
||||
Why bother at all? Well, it allows you to do things like this:
|
||||
```go
|
||||
// just two integer columns in the database
|
||||
var msgs []tb.StoredMessage
|
||||
db.Find(&msgs) // gorm syntax
|
||||
|
||||
for _, msg := range msgs {
|
||||
bot.Edit(&msg, "Updated text.")
|
||||
// or
|
||||
bot.Delete(&msg)
|
||||
}
|
||||
```
|
||||
|
||||
I find it incredibly neat. Worth noting, at this point of time there exists
|
||||
another method in the Edit family, `EditCaption()` which is of a pretty
|
||||
rare use, so I didn't bother including it to `Edit()`, just like I did with
|
||||
`SendAlbum()` as it would inevitably lead to unnecessary complications.
|
||||
```go
|
||||
var m *Message
|
||||
|
||||
// change caption of a photo, audio, etc.
|
||||
bot.EditCaption(m, "new caption")
|
||||
```
|
||||
|
||||
## Keyboards
|
||||
Telebot supports both kinds of keyboards Telegram provides: reply and inline
|
||||
keyboards. Any button can also act as an endpoints for `Handle()`:
|
||||
|
||||
```go
|
||||
func main() {
|
||||
b, _ := tb.NewBot(tb.Settings{...})
|
||||
|
||||
// This button will be displayed in user's
|
||||
// reply keyboard.
|
||||
replyBtn := tb.ReplyButton{Text: "🌕 Button #1"}
|
||||
replyKeys := [][]tb.ReplyButton{
|
||||
[]tb.ReplyButton{replyBtn},
|
||||
// ...
|
||||
}
|
||||
|
||||
// And this one — just under the message itself.
|
||||
// Pressing it will cause the client to send
|
||||
// the bot a callback.
|
||||
//
|
||||
// Make sure Unique stays unique as it has to be
|
||||
// for callback routing to work.
|
||||
inlineBtn := tb.InlineButton{
|
||||
Unique: "sad_moon",
|
||||
Text: "🌚 Button #2",
|
||||
}
|
||||
inlineKeys := [][]tb.InlineButton{
|
||||
[]tb.InlineButton{inlineBtn},
|
||||
// ...
|
||||
}
|
||||
|
||||
b.Handle(&replyBtn, func(m *tb.Message) {
|
||||
// on reply button pressed
|
||||
})
|
||||
|
||||
b.Handle(&inlineBtn, func(c *tb.Callback) {
|
||||
// on inline button pressed (callback!)
|
||||
|
||||
// always respond!
|
||||
b.Respond(c, &tb.CallbackResponse{...})
|
||||
})
|
||||
|
||||
// Command: /start <PAYLOAD>
|
||||
b.Handle("/start", func(m *tb.Message) {
|
||||
if !m.Private() {
|
||||
return
|
||||
}
|
||||
|
||||
b.Send(m.Sender, "Hello!", &tb.ReplyMarkup{
|
||||
ReplyKeyboard: replyKeys,
|
||||
InlineKeyboard: inlineKeys,
|
||||
})
|
||||
})
|
||||
|
||||
b.Start()
|
||||
}
|
||||
```
|
||||
|
||||
## Inline mode
|
||||
So if you want to handle incoming inline queries you better plug the `tb.OnQuery`
|
||||
endpoint and then use the `Answer()` method to send a list of inline queries
|
||||
back. I think at the time of writing, telebot supports all of the provided result
|
||||
types (but not the cached ones). This is how it looks like:
|
||||
|
||||
```go
|
||||
b.Handle(tb.OnQuery, func(q *tb.Query) {
|
||||
urls := []string{
|
||||
"http://photo.jpg",
|
||||
"http://photo2.jpg",
|
||||
}
|
||||
|
||||
results := make(tb.Results, len(urls)) // []tb.Result
|
||||
for i, url := range urls {
|
||||
result := &tb.PhotoResult{
|
||||
URL: url,
|
||||
|
||||
// required for photos
|
||||
ThumbURL: url,
|
||||
}
|
||||
|
||||
results[i] = result
|
||||
results[i].SetResultID(strconv.Itoa(i)) // It's needed to set a unique string ID for each result
|
||||
}
|
||||
|
||||
err := b.Answer(q, &tb.QueryResponse{
|
||||
Results: results,
|
||||
CacheTime: 60, // a minute
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
There's not much to talk about really. It also support some form of authentication
|
||||
through deep-linking. For that, use fields `SwitchPMText` and `SwitchPMParameter`
|
||||
of `QueryResponse`.
|
||||
|
||||
# Contributing
|
||||
|
||||
1. Fork it
|
||||
2. Clone it: `git clone https://github.com/tucnak/telebot`
|
||||
3. Create your feature branch: `git checkout -b my-new-feature`
|
||||
4. Make changes and add them: `git add .`
|
||||
5. Commit: `git commit -m 'Add some feature'`
|
||||
6. Push: `git push origin my-new-feature`
|
||||
7. Pull request
|
||||
|
||||
# Donate
|
||||
|
||||
I do coding for fun but I also try to search for interesting solutions and
|
||||
optimize them as much as possible.
|
||||
If you feel like it's a good piece of software, I wouldn't mind a tip!
|
||||
|
||||
Bitcoin: `1DkfrFvSRqgBnBuxv9BzAz83dqur5zrdTH`
|
||||
|
||||
# License
|
||||
|
||||
Telebot is distributed under MIT.
|
205
vendor/gopkg.in/tucnak/telebot.v2/admin.go
generated
vendored
Normal file
205
vendor/gopkg.in/tucnak/telebot.v2/admin.go
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Rights is a list of privileges available to chat members.
|
||||
type Rights struct {
|
||||
CanBeEdited bool `json:"can_be_edited,omitempty"` // 1
|
||||
CanChangeInfo bool `json:"can_change_info,omitempty"` // 2
|
||||
CanPostMessages bool `json:"can_post_messages,omitempty"` // 3
|
||||
CanEditMessages bool `json:"can_edit_messages,omitempty"` // 4
|
||||
CanDeleteMessages bool `json:"can_delete_messages,omitempty"` // 5
|
||||
CanInviteUsers bool `json:"can_invite_users,omitempty"` // 6
|
||||
CanRestrictMembers bool `json:"can_restrict_members,omitempty"` // 7
|
||||
CanPinMessages bool `json:"can_pin_messages,omitempty"` // 8
|
||||
CanPromoteMembers bool `json:"can_promote_members,omitempty"` // 9
|
||||
CanSendMessages bool `json:"can_send_messages,omitempty"` // 10
|
||||
CanSendMedia bool `json:"can_send_media_messages,omitempty"` // 11
|
||||
CanSendOther bool `json:"can_send_other_messages,omitempty"` // 12
|
||||
CanAddPreviews bool `json:"can_add_web_page_previews,omitempty"` // 13
|
||||
}
|
||||
|
||||
// NoRights is the default Rights{}
|
||||
func NoRights() Rights { return Rights{} }
|
||||
|
||||
// NoRestrictions should be used when un-restricting or
|
||||
// un-promoting user.
|
||||
//
|
||||
// member.Rights = NoRestrictions()
|
||||
// bot.Restrict(chat, member)
|
||||
//
|
||||
func NoRestrictions() Rights {
|
||||
return Rights{
|
||||
true, false, false, false, false, // 1-5
|
||||
false, false, false, false, true, // 6-10
|
||||
true, true, true}
|
||||
}
|
||||
|
||||
// AdminRights could be used to promote user to admin.
|
||||
func AdminRights() Rights {
|
||||
return Rights{
|
||||
true, true, true, true, true, // 1-5
|
||||
true, true, true, true, true, // 6-10
|
||||
true, true, true} // 11-13
|
||||
}
|
||||
|
||||
// Forever is a Unixtime of "forever" banning.
|
||||
func Forever() int64 {
|
||||
return time.Now().Add(367 * 24 * time.Hour).Unix()
|
||||
}
|
||||
|
||||
// Ban will ban user from chat until `member.RestrictedUntil`.
|
||||
func (b *Bot) Ban(chat *Chat, member *ChatMember) error {
|
||||
params := map[string]string{
|
||||
"chat_id": chat.Recipient(),
|
||||
"user_id": member.User.Recipient(),
|
||||
"until_date": strconv.FormatInt(member.RestrictedUntil, 10),
|
||||
}
|
||||
|
||||
respJSON, err := b.Raw("kickChatMember", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return extractOkResponse(respJSON)
|
||||
}
|
||||
|
||||
// Unban will unban user from chat, who would have thought eh?
|
||||
func (b *Bot) Unban(chat *Chat, user *User) error {
|
||||
params := map[string]string{
|
||||
"chat_id": chat.Recipient(),
|
||||
"user_id": user.Recipient(),
|
||||
}
|
||||
|
||||
respJSON, err := b.Raw("unbanChatMember", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return extractOkResponse(respJSON)
|
||||
}
|
||||
|
||||
// Restrict let's you restrict a subset of member's rights until
|
||||
// member.RestrictedUntil, such as:
|
||||
//
|
||||
// * can send messages
|
||||
// * can send media
|
||||
// * can send other
|
||||
// * can add web page previews
|
||||
//
|
||||
func (b *Bot) Restrict(chat *Chat, member *ChatMember) error {
|
||||
prv, until := member.Rights, member.RestrictedUntil
|
||||
|
||||
params := map[string]string{
|
||||
"chat_id": chat.Recipient(),
|
||||
"user_id": member.User.Recipient(),
|
||||
"until_date": strconv.FormatInt(until, 10),
|
||||
}
|
||||
|
||||
embedRights(params, prv)
|
||||
|
||||
respJSON, err := b.Raw("restrictChatMember", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return extractOkResponse(respJSON)
|
||||
}
|
||||
|
||||
// Promote lets you update member's admin rights, such as:
|
||||
//
|
||||
// * can change info
|
||||
// * can post messages
|
||||
// * can edit messages
|
||||
// * can delete messages
|
||||
// * can invite users
|
||||
// * can restrict members
|
||||
// * can pin messages
|
||||
// * can promote members
|
||||
//
|
||||
func (b *Bot) Promote(chat *Chat, member *ChatMember) error {
|
||||
prv := member.Rights
|
||||
|
||||
params := map[string]string{
|
||||
"chat_id": chat.Recipient(),
|
||||
"user_id": member.User.Recipient(),
|
||||
}
|
||||
|
||||
embedRights(params, prv)
|
||||
|
||||
respJSON, err := b.Raw("promoteChatMember", params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return extractOkResponse(respJSON)
|
||||
}
|
||||
|
||||
// AdminsOf return a member list of chat admins.
|
||||
//
|
||||
// On success, returns an Array of ChatMember objects that
|
||||
// contains information about all chat administrators except other bots.
|
||||
// If the chat is a group or a supergroup and
|
||||
// no administrators were appointed, only the creator will be returned.
|
||||
func (b *Bot) AdminsOf(chat *Chat) ([]ChatMember, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": chat.Recipient(),
|
||||
}
|
||||
|
||||
respJSON, err := b.Raw("getChatAdministrators", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
Ok bool
|
||||
Result []ChatMember
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
err = json.Unmarshal(respJSON, &resp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bad response json")
|
||||
}
|
||||
|
||||
if !resp.Ok {
|
||||
return nil, errors.Errorf("api error: %s", resp.Description)
|
||||
}
|
||||
|
||||
return resp.Result, nil
|
||||
}
|
||||
|
||||
// Len return the number of members in a chat.
|
||||
func (b *Bot) Len(chat *Chat) (int, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": chat.Recipient(),
|
||||
}
|
||||
|
||||
respJSON, err := b.Raw("getChatMembersCount", params)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
var resp struct {
|
||||
Ok bool
|
||||
Result int
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
err = json.Unmarshal(respJSON, &resp)
|
||||
if err != nil {
|
||||
return 0, errors.Wrap(err, "bad response json")
|
||||
}
|
||||
|
||||
if !resp.Ok {
|
||||
return 0, errors.Errorf("api error: %s", resp.Description)
|
||||
}
|
||||
|
||||
return resp.Result, nil
|
||||
}
|
187
vendor/gopkg.in/tucnak/telebot.v2/api.go
generated
vendored
Normal file
187
vendor/gopkg.in/tucnak/telebot.v2/api.go
generated
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Raw lets you call any method of Bot API manually.
|
||||
func (b *Bot) Raw(method string, payload interface{}) ([]byte, error) {
|
||||
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", b.Token, method)
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := json.NewEncoder(&buf).Encode(payload); err != nil {
|
||||
return []byte{}, wrapSystem(err)
|
||||
}
|
||||
|
||||
resp, err := b.client.Post(url, "application/json", &buf)
|
||||
if err != nil {
|
||||
return []byte{}, errors.Wrap(err, "http.Post failed")
|
||||
}
|
||||
resp.Close = true
|
||||
defer resp.Body.Close()
|
||||
json, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return []byte{}, wrapSystem(err)
|
||||
}
|
||||
|
||||
return json, nil
|
||||
}
|
||||
|
||||
func (b *Bot) sendFiles(
|
||||
method string,
|
||||
files map[string]string,
|
||||
params map[string]string) ([]byte, error) {
|
||||
// ---
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
|
||||
for name, path := range files {
|
||||
if err := func() error {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
part, err := writer.CreateFormFile(name, filepath.Base(path))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(part, file)
|
||||
return err
|
||||
} (); err != nil {
|
||||
return nil, wrapSystem(err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for field, value := range params {
|
||||
writer.WriteField(field, value)
|
||||
}
|
||||
|
||||
if err := writer.Close(); err != nil {
|
||||
return nil, wrapSystem(err)
|
||||
}
|
||||
|
||||
url := fmt.Sprintf("https://api.telegram.org/bot%s/%s", b.Token, method)
|
||||
req, err := http.NewRequest("POST", url, body)
|
||||
if err != nil {
|
||||
return nil, wrapSystem(err)
|
||||
}
|
||||
|
||||
req.Header.Add("Content-Type", writer.FormDataContentType())
|
||||
|
||||
resp, err := b.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "http.Post failed")
|
||||
}
|
||||
|
||||
if resp.StatusCode == http.StatusInternalServerError {
|
||||
return nil, errors.New("api error: internal server error")
|
||||
}
|
||||
|
||||
json, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, wrapSystem(err)
|
||||
}
|
||||
|
||||
return json, nil
|
||||
}
|
||||
|
||||
func (b *Bot) sendObject(f *File, what string, params map[string]string) (*Message, error) {
|
||||
sendWhat := "send" + strings.Title(what)
|
||||
|
||||
if what == "videoNote" {
|
||||
what = "video_note"
|
||||
}
|
||||
|
||||
var respJSON []byte
|
||||
var err error
|
||||
|
||||
if f.InCloud() {
|
||||
params[what] = f.FileID
|
||||
respJSON, err = b.Raw(sendWhat, params)
|
||||
} else if f.FileURL != "" {
|
||||
params[what] = f.FileURL
|
||||
respJSON, err = b.Raw(sendWhat, params)
|
||||
} else {
|
||||
respJSON, err = b.sendFiles(sendWhat,
|
||||
map[string]string{what: f.FileLocal}, params)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return extractMsgResponse(respJSON)
|
||||
}
|
||||
|
||||
func (b *Bot) getMe() (*User, error) {
|
||||
meJSON, err := b.Raw("getMe", nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var botInfo struct {
|
||||
Ok bool
|
||||
Result *User
|
||||
Description string
|
||||
}
|
||||
|
||||
err = json.Unmarshal(meJSON, &botInfo)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bad response json")
|
||||
}
|
||||
|
||||
if !botInfo.Ok {
|
||||
return nil, errors.Errorf("api error: %s", botInfo.Description)
|
||||
}
|
||||
|
||||
return botInfo.Result, nil
|
||||
|
||||
}
|
||||
|
||||
func (b *Bot) getUpdates(offset int, timeout time.Duration) (upd []Update, err error) {
|
||||
params := map[string]string{
|
||||
"offset": strconv.Itoa(offset),
|
||||
"timeout": strconv.Itoa(int(timeout / time.Second)),
|
||||
}
|
||||
updatesJSON, errCommand := b.Raw("getUpdates", params)
|
||||
if errCommand != nil {
|
||||
err = errCommand
|
||||
return
|
||||
|
||||
}
|
||||
var updatesReceived struct {
|
||||
Ok bool
|
||||
Result []Update
|
||||
Description string
|
||||
}
|
||||
|
||||
err = json.Unmarshal(updatesJSON, &updatesReceived)
|
||||
if err != nil {
|
||||
err = errors.Wrap(err, "bad response json")
|
||||
return
|
||||
}
|
||||
|
||||
if !updatesReceived.Ok {
|
||||
err = errors.Errorf("api error: %s", updatesReceived.Description)
|
||||
return
|
||||
}
|
||||
|
||||
return updatesReceived.Result, nil
|
||||
}
|
1144
vendor/gopkg.in/tucnak/telebot.v2/bot.go
generated
vendored
Normal file
1144
vendor/gopkg.in/tucnak/telebot.v2/bot.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
81
vendor/gopkg.in/tucnak/telebot.v2/callbacks.go
generated
vendored
Normal file
81
vendor/gopkg.in/tucnak/telebot.v2/callbacks.go
generated
vendored
Normal file
@@ -0,0 +1,81 @@
|
||||
package telebot
|
||||
|
||||
// CallbackEndpoint is an interface any element capable
|
||||
// of responding to a callback `\f<unique>`.
|
||||
type CallbackEndpoint interface {
|
||||
CallbackUnique() string
|
||||
}
|
||||
|
||||
// Callback object represents a query from a callback button in an
|
||||
// inline keyboard.
|
||||
type Callback struct {
|
||||
ID string `json:"id"`
|
||||
|
||||
// For message sent to channels, Sender may be empty
|
||||
Sender *User `json:"from"`
|
||||
|
||||
// Message will be set if the button that originated the query
|
||||
// was attached to a message sent by a bot.
|
||||
Message *Message `json:"message"`
|
||||
|
||||
// MessageID will be set if the button was attached to a message
|
||||
// sent via the bot in inline mode.
|
||||
MessageID string `json:"inline_message_id"`
|
||||
|
||||
// Data associated with the callback button. Be aware that
|
||||
// a bad client can send arbitrary data in this field.
|
||||
Data string `json:"data"`
|
||||
}
|
||||
|
||||
// CallbackResponse builds a response to a Callback query.
|
||||
//
|
||||
// See also: https://core.telegram.org/bots/api#answerCallbackQuery
|
||||
type CallbackResponse struct {
|
||||
// The ID of the callback to which this is a response.
|
||||
//
|
||||
// Note: Telebot sets this field automatically!
|
||||
CallbackID string `json:"callback_query_id"`
|
||||
|
||||
// Text of the notification. If not specified, nothing will be
|
||||
// shown to the user.
|
||||
Text string `json:"text,omitempty"`
|
||||
|
||||
// (Optional) If true, an alert will be shown by the client instead
|
||||
// of a notification at the top of the chat screen. Defaults to false.
|
||||
ShowAlert bool `json:"show_alert,omitempty"`
|
||||
|
||||
// (Optional) URL that will be opened by the user's client.
|
||||
// If you have created a Game and accepted the conditions via
|
||||
// @BotFather, specify the URL that opens your game.
|
||||
//
|
||||
// Note: this will only work if the query comes from a game
|
||||
// callback button. Otherwise, you may use deep-linking:
|
||||
// https://telegram.me/your_bot?start=XXXX
|
||||
URL string `json:"url,omitempty"`
|
||||
}
|
||||
|
||||
// InlineButton represents a button displayed in the message.
|
||||
type InlineButton struct {
|
||||
// Unique slagish name for this kind of button,
|
||||
// try to be as specific as possible.
|
||||
//
|
||||
// It will be used as a callback endpoint.
|
||||
Unique string `json:"unique,omitempty"`
|
||||
|
||||
Text string `json:"text"`
|
||||
URL string `json:"url,omitempty"`
|
||||
Data string `json:"callback_data,omitempty"`
|
||||
InlineQuery string `json:"switch_inline_query,omitempty"`
|
||||
|
||||
Action func(*Callback) `json:"-"`
|
||||
}
|
||||
|
||||
// CallbackUnique returns InlineButto.Unique.
|
||||
func (t *InlineButton) CallbackUnique() string {
|
||||
return "\f" + t.Unique
|
||||
}
|
||||
|
||||
// CallbackUnique returns KeyboardButton.Text.
|
||||
func (t *ReplyButton) CallbackUnique() string {
|
||||
return t.Text
|
||||
}
|
58
vendor/gopkg.in/tucnak/telebot.v2/chat.go
generated
vendored
Normal file
58
vendor/gopkg.in/tucnak/telebot.v2/chat.go
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
package telebot
|
||||
|
||||
import "strconv"
|
||||
|
||||
// User object represents a Telegram user, bot
|
||||
type User struct {
|
||||
ID int `json:"id"`
|
||||
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// Recipient returns user ID (see Recipient interface).
|
||||
func (u *User) Recipient() string {
|
||||
return strconv.Itoa(u.ID)
|
||||
}
|
||||
|
||||
// Chat object represents a Telegram user, bot, group or a channel.
|
||||
type Chat struct {
|
||||
ID int64 `json:"id"`
|
||||
|
||||
// See telebot.ChatType and consts.
|
||||
Type ChatType `json:"type"`
|
||||
|
||||
// Won't be there for ChatPrivate.
|
||||
Title string `json:"title"`
|
||||
|
||||
FirstName string `json:"first_name"`
|
||||
LastName string `json:"last_name"`
|
||||
Username string `json:"username"`
|
||||
}
|
||||
|
||||
// Recipient returns chat ID (see Recipient interface).
|
||||
func (c *Chat) Recipient() string {
|
||||
if c.Type == ChatChannel {
|
||||
return "@" + c.Username
|
||||
}
|
||||
return strconv.FormatInt(c.ID, 10)
|
||||
}
|
||||
|
||||
// ChatMember object represents information about a single chat member.
|
||||
type ChatMember struct {
|
||||
Rights
|
||||
|
||||
User *User `json:"user"`
|
||||
Role MemberStatus `json:"status"`
|
||||
|
||||
// Date when restrictions will be lifted for the user, unix time.
|
||||
//
|
||||
// If user is restricted for more than 366 days or less than
|
||||
// 30 seconds from the current time, they are considered to be
|
||||
// restricted forever.
|
||||
//
|
||||
// Use tb.Forever().
|
||||
//
|
||||
RestrictedUntil int64 `json:"until_date,omitempty"`
|
||||
}
|
30
vendor/gopkg.in/tucnak/telebot.v2/editable.go
generated
vendored
Normal file
30
vendor/gopkg.in/tucnak/telebot.v2/editable.go
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
package telebot
|
||||
|
||||
// Editable is an interface for all objects that
|
||||
// provide "message signature", a pair of 32-bit
|
||||
// message ID and 64-bit chat ID, both required
|
||||
// for edit operations.
|
||||
//
|
||||
// Use case: DB model struct for messages to-be
|
||||
// edited with, say two collums: msg_id,chat_id
|
||||
// could easily implement MessageSig() making
|
||||
// instances of stored messages editable.
|
||||
type Editable interface {
|
||||
// MessageSig is a "message signature".
|
||||
//
|
||||
// For inline messages, return chatID = 0.
|
||||
MessageSig() (messageID string, chatID int64)
|
||||
}
|
||||
|
||||
// StoredMessage is an example struct suitable for being
|
||||
// stored in the database as-is or being embedded into
|
||||
// a larger struct, which is often the case (you might
|
||||
// want to store some metadata alongside, or might not.)
|
||||
type StoredMessage struct {
|
||||
MessageID string `sql:"message_id" json:"message_id"`
|
||||
ChatID int64 `sql:"chat_id" json:"chat_id"`
|
||||
}
|
||||
|
||||
func (x StoredMessage) MessageSig() (string, int64) {
|
||||
return x.MessageID, x.ChatID
|
||||
}
|
70
vendor/gopkg.in/tucnak/telebot.v2/file.go
generated
vendored
Normal file
70
vendor/gopkg.in/tucnak/telebot.v2/file.go
generated
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// File object represents any sort of file.
|
||||
type File struct {
|
||||
FileID string `json:"file_id"`
|
||||
FileSize int `json:"file_size"`
|
||||
|
||||
// file on telegram server https://core.telegram.org/bots/api#file
|
||||
FilePath string `json:"file_path"`
|
||||
|
||||
// file on local file system.
|
||||
FileLocal string `json:"file_local"`
|
||||
|
||||
// file on the internet
|
||||
FileURL string `json:"file_url"`
|
||||
}
|
||||
|
||||
// FromDisk constructs a new local (on-disk) file object.
|
||||
//
|
||||
// Note, it returns File, not *File for a very good reason:
|
||||
// in telebot, File is pretty much an embeddable struct,
|
||||
// so upon uploading media you'll need to set embedded File
|
||||
// with something. NewFile() returning File makes it a one-liner.
|
||||
//
|
||||
// photo := &tb.Photo{File: tb.FromDisk("chicken.jpg")}
|
||||
//
|
||||
func FromDisk(filename string) File {
|
||||
return File{FileLocal: filename}
|
||||
}
|
||||
|
||||
// FromURL constructs a new file on provided HTTP URL.
|
||||
//
|
||||
// Note, it returns File, not *File for a very good reason:
|
||||
// in telebot, File is pretty much an embeddable struct,
|
||||
// so upon uploading media you'll need to set embedded File
|
||||
// with something. NewFile() returning File makes it a one-liner.
|
||||
//
|
||||
// photo := &tb.Photo{File: tb.FromURL("https://site.com/picture.jpg")}
|
||||
//
|
||||
func FromURL(url string) File {
|
||||
return File{FileURL: url}
|
||||
}
|
||||
|
||||
func (f *File) stealRef(g *File) {
|
||||
if g.OnDisk() {
|
||||
f.FileLocal = g.FileLocal
|
||||
}
|
||||
|
||||
if g.FileURL != "" {
|
||||
f.FileURL = g.FileURL
|
||||
}
|
||||
}
|
||||
|
||||
// InCloud tells whether the file is present on Telegram servers.
|
||||
func (f *File) InCloud() bool {
|
||||
return f.FileID != ""
|
||||
}
|
||||
|
||||
// OnDisk will return true if file is present on disk.
|
||||
func (f *File) OnDisk() bool {
|
||||
if _, err := os.Stat(f.FileLocal); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
66
vendor/gopkg.in/tucnak/telebot.v2/filters.go
generated
vendored
Normal file
66
vendor/gopkg.in/tucnak/telebot.v2/filters.go
generated
vendored
Normal file
@@ -0,0 +1,66 @@
|
||||
package telebot
|
||||
|
||||
// Filter is some thing that does filtering for
|
||||
// incoming updates.
|
||||
//
|
||||
// Return false if you wish to sieve the update out.
|
||||
type Filter interface {
|
||||
Filter(*Update) bool
|
||||
}
|
||||
|
||||
// FilterFunc is basically a lightweight version of Filter.
|
||||
type FilterFunc func(*Update) bool
|
||||
|
||||
func NewChain(parent Poller) *Chain {
|
||||
c := &Chain{}
|
||||
c.Poller = parent
|
||||
c.Filter = func(upd *Update) bool {
|
||||
for _, filter := range c.Filters {
|
||||
switch f := filter.(type) {
|
||||
case Filter:
|
||||
if !f.Filter(upd) {
|
||||
return false
|
||||
}
|
||||
|
||||
case FilterFunc:
|
||||
if !f(upd) {
|
||||
return false
|
||||
}
|
||||
|
||||
case func(*Update) bool:
|
||||
if !f(upd) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
|
||||
// Chain is a chain of middle
|
||||
type Chain struct {
|
||||
MiddlewarePoller
|
||||
|
||||
// (Filter | FilterFunc | func(*Update) bool)
|
||||
Filters []interface{}
|
||||
}
|
||||
|
||||
// Add accepts either Filter interface or FilterFunc
|
||||
func (c *Chain) Add(filter interface{}) {
|
||||
switch filter.(type) {
|
||||
case Filter:
|
||||
break
|
||||
case FilterFunc:
|
||||
break
|
||||
case func(*Update) bool:
|
||||
break
|
||||
default:
|
||||
panic("telebot: unsupported filter type")
|
||||
}
|
||||
|
||||
c.Filters = append(c.Filters, filter)
|
||||
}
|
120
vendor/gopkg.in/tucnak/telebot.v2/inline.go
generated
vendored
Normal file
120
vendor/gopkg.in/tucnak/telebot.v2/inline.go
generated
vendored
Normal file
@@ -0,0 +1,120 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// Query is an incoming inline query. When the user sends
|
||||
// an empty query, your bot could return some default or
|
||||
// trending results.
|
||||
type Query struct {
|
||||
// Unique identifier for this query. 1-64 bytes.
|
||||
ID string `json:"id"`
|
||||
|
||||
// Sender.
|
||||
From User `json:"from"`
|
||||
|
||||
// Sender location, only for bots that request user location.
|
||||
Location *Location `json:"location"`
|
||||
|
||||
// Text of the query (up to 512 characters).
|
||||
Text string `json:"query"`
|
||||
|
||||
// Offset of the results to be returned, can be controlled by the bot.
|
||||
Offset string `json:"offset"`
|
||||
}
|
||||
|
||||
// QueryResponse builds a response to an inline Query.
|
||||
// See also: https://core.telegram.org/bots/api#answerinlinequery
|
||||
type QueryResponse struct {
|
||||
// The ID of the query to which this is a response.
|
||||
//
|
||||
// Note: Telebot sets this field automatically!
|
||||
QueryID string `json:"inline_query_id"`
|
||||
|
||||
// The results for the inline query.
|
||||
Results Results `json:"results"`
|
||||
|
||||
// (Optional) The maximum amount of time in seconds that the result
|
||||
// of the inline query may be cached on the server.
|
||||
CacheTime int `json:"cache_time,omitempty"`
|
||||
|
||||
// (Optional) Pass True, if results may be cached on the server side
|
||||
// only for the user that sent the query. By default, results may
|
||||
// be returned to any user who sends the same query.
|
||||
IsPersonal bool `json:"is_personal"`
|
||||
|
||||
// (Optional) Pass the offset that a client should send in the next
|
||||
// query with the same text to receive more results. Pass an empty
|
||||
// string if there are no more results or if you don‘t support
|
||||
// pagination. Offset length can’t exceed 64 bytes.
|
||||
NextOffset string `json:"next_offset"`
|
||||
|
||||
// (Optional) If passed, clients will display a button with specified
|
||||
// text that switches the user to a private chat with the bot and sends
|
||||
// the bot a start message with the parameter switch_pm_parameter.
|
||||
SwitchPMText string `json:"switch_pm_text,omitempty"`
|
||||
|
||||
// (Optional) Parameter for the start message sent to the bot when user
|
||||
// presses the switch button.
|
||||
SwitchPMParameter string `json:"switch_pm_parameter,omitempty"`
|
||||
}
|
||||
|
||||
// Result represents one result of an inline query.
|
||||
type Result interface {
|
||||
ResultID() string
|
||||
SetResultID(string)
|
||||
Process()
|
||||
}
|
||||
|
||||
// Results is a slice wrapper for convenient marshalling.
|
||||
type Results []Result
|
||||
|
||||
// MarshalJSON makes sure IQRs have proper IDs and Type variables set.
|
||||
func (results Results) MarshalJSON() ([]byte, error) {
|
||||
for _, result := range results {
|
||||
if result.ResultID() == "" {
|
||||
result.SetResultID(fmt.Sprintf("%d", &result))
|
||||
}
|
||||
|
||||
if err := inferIQR(result); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return json.Marshal([]Result(results))
|
||||
}
|
||||
|
||||
func inferIQR(result Result) error {
|
||||
switch r := result.(type) {
|
||||
case *ArticleResult:
|
||||
r.Type = "article"
|
||||
case *AudioResult:
|
||||
r.Type = "audio"
|
||||
case *ContactResult:
|
||||
r.Type = "contact"
|
||||
case *DocumentResult:
|
||||
r.Type = "document"
|
||||
case *GifResult:
|
||||
r.Type = "gif"
|
||||
case *LocationResult:
|
||||
r.Type = "location"
|
||||
case *Mpeg4GifResult:
|
||||
r.Type = "mpeg4_gif"
|
||||
case *PhotoResult:
|
||||
r.Type = "photo"
|
||||
case *VenueResult:
|
||||
r.Type = "venue"
|
||||
case *VideoResult:
|
||||
r.Type = "video"
|
||||
case *VoiceResult:
|
||||
r.Type = "voice"
|
||||
case *StickerResult:
|
||||
r.Type = "sticker"
|
||||
default:
|
||||
return fmt.Errorf("result %v is not supported", result)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
309
vendor/gopkg.in/tucnak/telebot.v2/inline_types.go
generated
vendored
Normal file
309
vendor/gopkg.in/tucnak/telebot.v2/inline_types.go
generated
vendored
Normal file
@@ -0,0 +1,309 @@
|
||||
package telebot
|
||||
|
||||
// ResultBase must be embedded into all IQRs.
|
||||
type ResultBase struct {
|
||||
// Unique identifier for this result, 1-64 Bytes.
|
||||
// If left unspecified, a 64-bit FNV-1 hash will be calculated
|
||||
ID string `json:"id"`
|
||||
|
||||
// Ignore. This field gets set automatically.
|
||||
Type string `json:"type"`
|
||||
|
||||
// Optional. Content of the message to be sent.
|
||||
Content *InputMessageContent `json:"input_message_content,omitempty"`
|
||||
|
||||
// Optional. Inline keyboard attached to the message.
|
||||
ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"`
|
||||
}
|
||||
|
||||
// ResultID returns ResultBase.ID.
|
||||
func (r *ResultBase) ResultID() string {
|
||||
return r.ID
|
||||
}
|
||||
|
||||
// SetResultID sets ResultBase.ID.
|
||||
func (r *ResultBase) SetResultID(id string) {
|
||||
r.ID = id
|
||||
}
|
||||
|
||||
func (r *ResultBase) Process() {
|
||||
if r.ReplyMarkup != nil {
|
||||
processButtons(r.ReplyMarkup.InlineKeyboard)
|
||||
}
|
||||
}
|
||||
|
||||
// ArticleResult represents a link to an article or web page.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultarticle
|
||||
type ArticleResult struct {
|
||||
ResultBase
|
||||
|
||||
// Title of the result.
|
||||
Title string `json:"title"`
|
||||
|
||||
// Message text. Shortcut (and mutually exclusive to) specifying
|
||||
// InputMessageContent.
|
||||
Text string `json:"message_text,omitempty"`
|
||||
|
||||
// Optional. URL of the result.
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// Optional. Pass True, if you don't want the URL to be shown in the message.
|
||||
HideURL bool `json:"hide_url,omitempty"`
|
||||
|
||||
// Optional. Short description of the result.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// Optional. URL of the thumbnail for the result.
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
}
|
||||
|
||||
// AudioResult represents a link to an mp3 audio file.
|
||||
type AudioResult struct {
|
||||
ResultBase
|
||||
|
||||
// Title.
|
||||
Title string `json:"title"`
|
||||
|
||||
// A valid URL for the audio file.
|
||||
URL string `json:"audio_url"`
|
||||
|
||||
// Optional. Performer.
|
||||
Performer string `json:"performer,omitempty"`
|
||||
|
||||
// Optional. Audio duration in seconds.
|
||||
Duration int `json:"audio_duration,omitempty"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"audio_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// ContentResult represents a contact with a phone number.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultcontact
|
||||
type ContactResult struct {
|
||||
ResultBase
|
||||
|
||||
// Contact's phone number.
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
|
||||
// Contact's first name.
|
||||
FirstName string `json:"first_name"`
|
||||
|
||||
// Optional. Contact's last name.
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
|
||||
// Optional. URL of the thumbnail for the result.
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
}
|
||||
|
||||
// DocumentResult represents a link to a file.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultdocument
|
||||
type DocumentResult struct {
|
||||
ResultBase
|
||||
|
||||
// Title for the result.
|
||||
Title string `json:"title"`
|
||||
|
||||
// A valid URL for the file
|
||||
URL string `json:"document_url"`
|
||||
|
||||
// Mime type of the content of the file, either “application/pdf” or
|
||||
// “application/zip”.
|
||||
MIME string `json:"mime_type"`
|
||||
|
||||
// Optional. Caption of the document to be sent, 0-200 characters.
|
||||
Caption string `json:"caption,omitempty"`
|
||||
|
||||
// Optional. Short description of the result.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// Optional. URL of the thumbnail (jpeg only) for the file.
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"document_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// GifResult represents a link to an animated GIF file.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultgif
|
||||
type GifResult struct {
|
||||
ResultBase
|
||||
|
||||
// A valid URL for the GIF file. File size must not exceed 1MB.
|
||||
URL string `json:"gif_url"`
|
||||
|
||||
// Optional. Width of the GIF.
|
||||
Width int `json:"gif_width,omitempty"`
|
||||
|
||||
// Optional. Height of the GIF.
|
||||
Height int `json:"gif_height,omitempty"`
|
||||
|
||||
// Optional. Title for the result.
|
||||
Title string `json:"title,omitempty"`
|
||||
|
||||
// Optional. Caption of the GIF file to be sent, 0-200 characters.
|
||||
Caption string `json:"caption,omitempty"`
|
||||
|
||||
// URL of the static thumbnail for the result (jpeg or gif).
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"gif_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// LocationResult represents a location on a map.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultlocation
|
||||
type LocationResult struct {
|
||||
ResultBase
|
||||
|
||||
Location
|
||||
|
||||
// Location title.
|
||||
Title string `json:"title"`
|
||||
|
||||
// Optional. Url of the thumbnail for the result.
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
}
|
||||
|
||||
// ResultMpeg4Gif represents a link to a video animation
|
||||
// (H.264/MPEG-4 AVC video without sound).
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultmpeg4gif
|
||||
type Mpeg4GifResult struct {
|
||||
ResultBase
|
||||
|
||||
// A valid URL for the MP4 file.
|
||||
URL string `json:"mpeg4_url"`
|
||||
|
||||
// Optional. Video width.
|
||||
Width int `json:"mpeg4_width,omitempty"`
|
||||
|
||||
// Optional. Video height.
|
||||
Height int `json:"mpeg4_height,omitempty"`
|
||||
|
||||
// URL of the static thumbnail (jpeg or gif) for the result.
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
|
||||
// Optional. Title for the result.
|
||||
Title string `json:"title,omitempty"`
|
||||
|
||||
// Optional. Caption of the MPEG-4 file to be sent, 0-200 characters.
|
||||
Caption string `json:"caption,omitempty"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"mpeg4_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// ResultResult represents a link to a photo.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultphoto
|
||||
type PhotoResult struct {
|
||||
ResultBase
|
||||
|
||||
// A valid URL of the photo. Photo must be in jpeg format.
|
||||
// Photo size must not exceed 5MB.
|
||||
URL string `json:"photo_url"`
|
||||
|
||||
// Optional. Width of the photo.
|
||||
Width int `json:"photo_width,omitempty"`
|
||||
|
||||
// Optional. Height of the photo.
|
||||
Height int `json:"photo_height,omitempty"`
|
||||
|
||||
// Optional. Title for the result.
|
||||
Title string `json:"title,omitempty"`
|
||||
|
||||
// Optional. Short description of the result.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// Optional. Caption of the photo to be sent, 0-200 characters.
|
||||
Caption string `json:"caption,omitempty"`
|
||||
|
||||
// URL of the thumbnail for the photo.
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"photo_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// VenueResult represents a venue.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultvenue
|
||||
type VenueResult struct {
|
||||
ResultBase
|
||||
|
||||
Location
|
||||
|
||||
// Title of the venue.
|
||||
Title string `json:"title"`
|
||||
|
||||
// Address of the venue.
|
||||
Address string `json:"address"`
|
||||
|
||||
// Optional. Foursquare identifier of the venue if known.
|
||||
FoursquareID string `json:"foursquare_id,omitempty"`
|
||||
|
||||
// Optional. URL of the thumbnail for the result.
|
||||
ThumbURL string `json:"thumb_url,omitempty"`
|
||||
}
|
||||
|
||||
// VideoResult represents a link to a page containing an embedded
|
||||
// video player or a video file.
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultvideo
|
||||
type VideoResult struct {
|
||||
ResultBase
|
||||
|
||||
// A valid URL for the embedded video player or video file.
|
||||
URL string `json:"video_url"`
|
||||
|
||||
// Mime type of the content of video url, “text/html” or “video/mp4”.
|
||||
MIME string `json:"mime_type"`
|
||||
|
||||
// URL of the thumbnail (jpeg only) for the video.
|
||||
ThumbURL string `json:"thumb_url"`
|
||||
|
||||
// Title for the result.
|
||||
Title string `json:"title"`
|
||||
|
||||
// Optional. Caption of the video to be sent, 0-200 characters.
|
||||
Caption string `json:"caption,omitempty"`
|
||||
|
||||
// Optional. Video width.
|
||||
Width int `json:"video_width,omitempty"`
|
||||
|
||||
// Optional. Video height.
|
||||
Height int `json:"video_height,omitempty"`
|
||||
|
||||
// Optional. Video duration in seconds.
|
||||
Duration int `json:"video_duration,omitempty"`
|
||||
|
||||
// Optional. Short description of the result.
|
||||
Description string `json:"description,omitempty"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"video_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// VoiceResult represents a link to a voice recording in an .ogg
|
||||
// container encoded with OPUS.
|
||||
//
|
||||
// See also: https://core.telegram.org/bots/api#inlinequeryresultvoice
|
||||
type VoiceResult struct {
|
||||
ResultBase
|
||||
|
||||
// A valid URL for the voice recording.
|
||||
URL string `json:"voice_url"`
|
||||
|
||||
// Recording title.
|
||||
Title string `json:"title"`
|
||||
|
||||
// Optional. Recording duration in seconds.
|
||||
Duration int `json:"voice_duration"`
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"voice_file_id,omitempty"`
|
||||
}
|
||||
|
||||
// StickerResult represents an inline cached sticker response.
|
||||
type StickerResult struct {
|
||||
ResultBase
|
||||
|
||||
// If Cache != "", it'll be used instead
|
||||
Cache string `json:"sticker_file_id,omitempty"`
|
||||
}
|
78
vendor/gopkg.in/tucnak/telebot.v2/input_types.go
generated
vendored
Normal file
78
vendor/gopkg.in/tucnak/telebot.v2/input_types.go
generated
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
package telebot
|
||||
|
||||
// InputMessageContent objects represent the content of a message to be sent
|
||||
// as a result of an inline query.
|
||||
// See also: https://core.telegram.org/bots/api#inputmessagecontent
|
||||
type InputMessageContent interface {
|
||||
IsInputMessageContent() bool
|
||||
}
|
||||
|
||||
// InputTextMessageContent represents the content of a text message to be
|
||||
// sent as the result of an inline query.
|
||||
// See also: https://core.telegram.org/bots/api#inputtextmessagecontent
|
||||
type InputTextMessageContent struct {
|
||||
// Text of the message to be sent, 1-4096 characters.
|
||||
Text string `json:"message_text"`
|
||||
|
||||
// Optional. Send Markdown or HTML, if you want Telegram apps to show
|
||||
// bold, italic, fixed-width text or inline URLs in your bot's message.
|
||||
ParseMode string `json:"parse_mode,omitempty"`
|
||||
|
||||
// Optional. Disables link previews for links in the sent message.
|
||||
DisablePreview bool `json:"disable_web_page_preview"`
|
||||
}
|
||||
|
||||
func (input *InputTextMessageContent) IsInputMessageContent() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// InputLocationMessageContent represents the content of a location message
|
||||
// to be sent as the result of an inline query.
|
||||
// See also: https://core.telegram.org/bots/api#inputlocationmessagecontent
|
||||
type InputLocationMessageContent struct {
|
||||
Lat float32 `json:"latitude"`
|
||||
Lng float32 `json:"longitude"`
|
||||
}
|
||||
|
||||
func (input *InputLocationMessageContent) IsInputMessageContent() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// InputVenueMessageContent represents the content of a venue message to
|
||||
// be sent as the result of an inline query.
|
||||
// See also: https://core.telegram.org/bots/api#inputvenuemessagecontent
|
||||
type InputVenueMessageContent struct {
|
||||
Lat float32 `json:"latitude"`
|
||||
Lng float32 `json:"longitude"`
|
||||
|
||||
// Name of the venue.
|
||||
Title string `json:"title"`
|
||||
|
||||
// Address of the venue.
|
||||
Address string `json:"address"`
|
||||
|
||||
// Optional. Foursquare identifier of the venue, if known.
|
||||
FoursquareID string `json:"foursquare_id,omitempty"`
|
||||
}
|
||||
|
||||
func (input *InputVenueMessageContent) IsInputMessageContent() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// InputContactMessageContent represents the content of a contact
|
||||
// message to be sent as the result of an inline query.
|
||||
// See also: https://core.telegram.org/bots/api#inputcontactmessagecontent
|
||||
type InputContactMessageContent struct {
|
||||
// Contact's phone number.
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
|
||||
// Contact's first name.
|
||||
FirstName string `json:"first_name"`
|
||||
|
||||
// Optional. Contact's last name.
|
||||
LastName string `json:"last_name,omitempty"`
|
||||
}
|
||||
|
||||
func (input *InputContactMessageContent) IsInputMessageContent() bool {
|
||||
return true
|
||||
}
|
176
vendor/gopkg.in/tucnak/telebot.v2/media.go
generated
vendored
Normal file
176
vendor/gopkg.in/tucnak/telebot.v2/media.go
generated
vendored
Normal file
@@ -0,0 +1,176 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
// Album lets you group multiple media (so-called InputMedia)
|
||||
// into a single messsage.
|
||||
//
|
||||
// On older clients albums look like N regular messages.
|
||||
type Album []InputMedia
|
||||
|
||||
// InputMedia is a generic type for all kinds of media you
|
||||
// can put into an album.
|
||||
type InputMedia interface {
|
||||
// As some files must be uploaded (instead of referencing)
|
||||
// outer layers of Telebot require it.
|
||||
MediaFile() *File
|
||||
}
|
||||
|
||||
// Photo object represents a single photo file.
|
||||
type Photo struct {
|
||||
File
|
||||
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
|
||||
// (Optional)
|
||||
Caption string `json:"caption,omitempty"`
|
||||
}
|
||||
|
||||
type photoSize struct {
|
||||
File
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
}
|
||||
|
||||
// MediaFile returns &Photo.File
|
||||
func (p *Photo) MediaFile() *File {
|
||||
return &p.File
|
||||
}
|
||||
|
||||
// UnmarshalJSON is custom unmarshaller required to abstract
|
||||
// away the hassle of treating different thumbnail sizes.
|
||||
// Instead, Telebot chooses the hi-res one and just sticks to
|
||||
// it.
|
||||
//
|
||||
// I really do find it a beautiful solution.
|
||||
func (p *Photo) UnmarshalJSON(jsonStr []byte) error {
|
||||
var hq photoSize
|
||||
|
||||
if jsonStr[0] == '{' {
|
||||
if err := json.Unmarshal(jsonStr, &hq); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
var sizes []photoSize
|
||||
|
||||
if err := json.Unmarshal(jsonStr, &sizes); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
hq = sizes[len(sizes)-1]
|
||||
}
|
||||
|
||||
p.File = hq.File
|
||||
p.Width = hq.Width
|
||||
p.Height = hq.Height
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Audio object represents an audio file.
|
||||
type Audio struct {
|
||||
File
|
||||
|
||||
// Duration of the recording in seconds as defined by sender.
|
||||
Duration int `json:"duration,omitempty"`
|
||||
|
||||
// (Optional)
|
||||
Caption string `json:"caption,omitempty"`
|
||||
Title string `json:"title,omitempty"`
|
||||
Performer string `json:"performer,omitempty"`
|
||||
MIME string `json:"mime_type,omitempty"`
|
||||
}
|
||||
|
||||
// Document object represents a general file (as opposed to Photo or Audio).
|
||||
// Telegram users can send files of any type of up to 1.5 GB in size.
|
||||
type Document struct {
|
||||
File
|
||||
|
||||
// Original filename as defined by sender.
|
||||
FileName string `json:"file_name"`
|
||||
|
||||
// (Optional)
|
||||
Thumbnail *Photo `json:"thumb,omitempty"`
|
||||
Caption string `json:"caption,omitempty"`
|
||||
MIME string `json:"mime_type"`
|
||||
}
|
||||
|
||||
// Video object represents a video file.
|
||||
type Video struct {
|
||||
File
|
||||
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
|
||||
Duration int `json:"duration,omitempty"`
|
||||
|
||||
// (Optional)
|
||||
Caption string `json:"caption,omitempty"`
|
||||
Thumbnail *Photo `json:"thumb,omitempty"`
|
||||
MIME string `json:"mime_type,omitempty"`
|
||||
}
|
||||
|
||||
// MediaFile returns &Video.File
|
||||
func (v *Video) MediaFile() *File {
|
||||
return &v.File
|
||||
}
|
||||
|
||||
// Voice object represents a voice note.
|
||||
type Voice struct {
|
||||
File
|
||||
|
||||
// Duration of the recording in seconds as defined by sender.
|
||||
Duration int `json:"duration"`
|
||||
|
||||
// (Optional)
|
||||
MIME string `json:"mime_type,omitempty"`
|
||||
}
|
||||
|
||||
// VideoNote represents a video message (available in Telegram apps
|
||||
// as of v.4.0).
|
||||
type VideoNote struct {
|
||||
File
|
||||
|
||||
// Duration of the recording in seconds as defined by sender.
|
||||
Duration int `json:"duration"`
|
||||
|
||||
// (Optional)
|
||||
Thumbnail *Photo `json:"thumb,omitempty"`
|
||||
}
|
||||
|
||||
// Contact object represents a contact to Telegram user
|
||||
type Contact struct {
|
||||
PhoneNumber string `json:"phone_number"`
|
||||
FirstName string `json:"first_name"`
|
||||
|
||||
// (Optional)
|
||||
LastName string `json:"last_name"`
|
||||
UserID int `json:"user_id,omitempty"`
|
||||
}
|
||||
|
||||
// Location object represents geographic position.
|
||||
type Location struct {
|
||||
// Latitude
|
||||
Lat float32 `json:"latitude"`
|
||||
// Longitude
|
||||
Lng float32 `json:"longitude"`
|
||||
|
||||
// Period in seconds for which the location will be updated
|
||||
// (see Live Locations, should be between 60 and 86400.)
|
||||
LivePeriod int `json:"live_period,omitempty"`
|
||||
}
|
||||
|
||||
// Venue object represents a venue location with name, address and
|
||||
// optional foursquare ID.
|
||||
type Venue struct {
|
||||
Location Location `json:"location"`
|
||||
Title string `json:"title"`
|
||||
Address string `json:"address"`
|
||||
|
||||
// (Optional)
|
||||
FoursquareID string `json:"foursquare_id,omitempty"`
|
||||
}
|
267
vendor/gopkg.in/tucnak/telebot.v2/message.go
generated
vendored
Normal file
267
vendor/gopkg.in/tucnak/telebot.v2/message.go
generated
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Message object represents a message.
|
||||
type Message struct {
|
||||
ID int `json:"message_id"`
|
||||
|
||||
// For message sent to channels, Sender will be nil
|
||||
Sender *User `json:"from"`
|
||||
|
||||
// Unixtime, use Message.Time() to get time.Time
|
||||
Unixtime int64 `json:"date"`
|
||||
|
||||
// Conversation the message belongs to.
|
||||
Chat *Chat `json:"chat"`
|
||||
|
||||
// For forwarded messages, sender of the original message.
|
||||
OriginalSender *User `json:"forward_from"`
|
||||
|
||||
// For forwarded messages, chat of the original message when
|
||||
// forwarded from a channel.
|
||||
OriginalChat *Chat `json:"forward_from_chat"`
|
||||
|
||||
// For forwarded messages, unixtime of the original message.
|
||||
OriginalUnixtime int `json:"forward_date"`
|
||||
|
||||
// For replies, ReplyTo represents the original message.
|
||||
//
|
||||
// Note that the Message object in this field will not
|
||||
// contain further ReplyTo fields even if it
|
||||
// itself is a reply.
|
||||
ReplyTo *Message `json:"reply_to_message"`
|
||||
|
||||
// (Optional) Time of last edit in Unix
|
||||
LastEdit int64 `json:"edit_date"`
|
||||
|
||||
// AlbumID is the unique identifier of a media message group
|
||||
// this message belongs to.
|
||||
AlbumID string `json:"media_group_id"`
|
||||
|
||||
// Author signature (in channels).
|
||||
Signature string `json:"author_signature"`
|
||||
|
||||
// For a text message, the actual UTF-8 text of the message.
|
||||
Text string `json:"text"`
|
||||
|
||||
// For registered commands, will contain the string payload:
|
||||
//
|
||||
// Ex: `/command <payload>` or `/command@botname <payload>`
|
||||
Payload string `json:"-"`
|
||||
|
||||
// For text messages, special entities like usernames, URLs, bot commands,
|
||||
// etc. that appear in the text.
|
||||
Entities []MessageEntity `json:"entities,omitempty"`
|
||||
|
||||
// Some messages containing media, may as well have a caption.
|
||||
Caption string `json:"caption,omitempty"`
|
||||
|
||||
// For messages with a caption, special entities like usernames, URLs,
|
||||
// bot commands, etc. that appear in the caption.
|
||||
CaptionEntities []MessageEntity `json:"caption_entities,omitempty"`
|
||||
|
||||
// For an audio recording, information about it.
|
||||
Audio *Audio `json:"audio"`
|
||||
|
||||
// For a gneral file, information about it.
|
||||
Document *Document `json:"document"`
|
||||
|
||||
// For a photo, all available sizes (thumbnails).
|
||||
Photo *Photo `json:"photo"`
|
||||
|
||||
// For a sticker, information about it.
|
||||
Sticker *Sticker `json:"sticker"`
|
||||
|
||||
// For a voice message, information about it.
|
||||
Voice *Voice `json:"voice"`
|
||||
|
||||
// For a video note, information about it.
|
||||
VideoNote *VideoNote `json:"video_note"`
|
||||
|
||||
// For a video, information about it.
|
||||
Video *Video `json:"video"`
|
||||
|
||||
// For a contact, contact information itself.
|
||||
Contact *Contact `json:"contact"`
|
||||
|
||||
// For a location, its longitude and latitude.
|
||||
Location *Location `json:"location"`
|
||||
|
||||
// For a venue, information about it.
|
||||
Venue *Venue `json:"venue"`
|
||||
|
||||
// For a service message, represents a user,
|
||||
// that just got added to chat, this message came from.
|
||||
//
|
||||
// Sender leads to User, capable of invite.
|
||||
//
|
||||
// UserJoined might be the Bot itself.
|
||||
UserJoined *User `json:"new_chat_member"`
|
||||
|
||||
// For a service message, represents a user,
|
||||
// that just left chat, this message came from.
|
||||
//
|
||||
// If user was kicked, Sender leads to a User,
|
||||
// capable of this kick.
|
||||
//
|
||||
// UserLeft might be the Bot itself.
|
||||
UserLeft *User `json:"left_chat_member"`
|
||||
|
||||
// For a service message, represents a new title
|
||||
// for chat this message came from.
|
||||
//
|
||||
// Sender would lead to a User, capable of change.
|
||||
NewGroupTitle string `json:"new_chat_title"`
|
||||
|
||||
// For a service message, represents all available
|
||||
// thumbnails of the new chat photo.
|
||||
//
|
||||
// Sender would lead to a User, capable of change.
|
||||
NewGroupPhoto *Photo `json:"new_chat_photo"`
|
||||
|
||||
// For a service message, new members that were added to
|
||||
// the group or supergroup and information about them
|
||||
// (the bot itself may be one of these members).
|
||||
UsersJoined []User `json:"new_chat_members"`
|
||||
|
||||
// For a service message, true if chat photo just
|
||||
// got removed.
|
||||
//
|
||||
// Sender would lead to a User, capable of change.
|
||||
GroupPhotoDeleted bool `json:"delete_chat_photo"`
|
||||
|
||||
// For a service message, true if group has been created.
|
||||
//
|
||||
// You would recieve such a message if you are one of
|
||||
// initial group chat members.
|
||||
//
|
||||
// Sender would lead to creator of the chat.
|
||||
GroupCreated bool `json:"group_chat_created"`
|
||||
|
||||
// For a service message, true if super group has been created.
|
||||
//
|
||||
// You would recieve such a message if you are one of
|
||||
// initial group chat members.
|
||||
//
|
||||
// Sender would lead to creator of the chat.
|
||||
SuperGroupCreated bool `json:"supergroup_chat_created"`
|
||||
|
||||
// For a service message, true if channel has been created.
|
||||
//
|
||||
// You would recieve such a message if you are one of
|
||||
// initial channel administrators.
|
||||
//
|
||||
// Sender would lead to creator of the chat.
|
||||
ChannelCreated bool `json:"channel_chat_created"`
|
||||
|
||||
// For a service message, the destination (super group) you
|
||||
// migrated to.
|
||||
//
|
||||
// You would recieve such a message when your chat has migrated
|
||||
// to a super group.
|
||||
//
|
||||
// Sender would lead to creator of the migration.
|
||||
MigrateTo int64 `json:"migrate_to_chat_id"`
|
||||
|
||||
// For a service message, the Origin (normal group) you migrated
|
||||
// from.
|
||||
//
|
||||
// You would recieve such a message when your chat has migrated
|
||||
// to a super group.
|
||||
//
|
||||
// Sender would lead to creator of the migration.
|
||||
MigrateFrom int64 `json:"migrate_from_chat_id"`
|
||||
|
||||
// Specified message was pinned. Note that the Message object
|
||||
// in this field will not contain further ReplyTo fields even
|
||||
// if it is itself a reply.
|
||||
PinnedMessage *Message `json:"pinned_message"`
|
||||
}
|
||||
|
||||
// MessageEntity object represents "special" parts of text messages,
|
||||
// including hashtags, usernames, URLs, etc.
|
||||
type MessageEntity struct {
|
||||
// Specifies entity type.
|
||||
Type EntityType `json:"type"`
|
||||
|
||||
// Offset in UTF-16 code units to the start of the entity.
|
||||
Offset int `json:"offset"`
|
||||
|
||||
// Length of the entity in UTF-16 code units.
|
||||
Length int `json:"length"`
|
||||
|
||||
// (Optional) For EntityTextLink entity type only.
|
||||
//
|
||||
// URL will be opened after user taps on the text.
|
||||
URL string `json:"url,omitempty"`
|
||||
|
||||
// (Optional) For EntityTMention entity type only.
|
||||
User *User `json:"user,omitempty"`
|
||||
}
|
||||
|
||||
// MessageSig satisfies Editable interface (see Editable.)
|
||||
func (m *Message) MessageSig() (string, int64) {
|
||||
return strconv.Itoa(m.ID), m.Chat.ID
|
||||
}
|
||||
|
||||
// Time returns the moment of message creation in local time.
|
||||
func (m *Message) Time() time.Time {
|
||||
return time.Unix(m.Unixtime, 0)
|
||||
}
|
||||
|
||||
// LastEdited returns time.Time of last edit.
|
||||
func (m *Message) LastEdited() time.Time {
|
||||
return time.Unix(m.LastEdit, 0)
|
||||
}
|
||||
|
||||
// IsForwarded says whether message is forwarded copy of another
|
||||
// message or not.
|
||||
func (m *Message) IsForwarded() bool {
|
||||
return m.OriginalSender != nil || m.OriginalChat != nil
|
||||
}
|
||||
|
||||
// IsReply says whether message is a reply to another message.
|
||||
func (m *Message) IsReply() bool {
|
||||
return m.ReplyTo != nil
|
||||
}
|
||||
|
||||
// Private returns true, if it's a personal message.
|
||||
func (m *Message) Private() bool {
|
||||
return m.Chat.Type == ChatPrivate
|
||||
}
|
||||
|
||||
// FromGroup returns true, if message came from a group OR
|
||||
// a super group.
|
||||
func (m *Message) FromGroup() bool {
|
||||
return m.Chat.Type == ChatGroup || m.Chat.Type == ChatSuperGroup
|
||||
}
|
||||
|
||||
// FromChannel returns true, if message came from a channel.
|
||||
func (m *Message) FromChannel() bool {
|
||||
return m.Chat.Type == ChatChannel
|
||||
}
|
||||
|
||||
// IsService returns true, if message is a service message,
|
||||
// returns false otherwise.
|
||||
//
|
||||
// Service messages are automatically sent messages, which
|
||||
// typically occur on some global action. For instance, when
|
||||
// anyone leaves the chat or chat title changes.
|
||||
func (m *Message) IsService() bool {
|
||||
fact := false
|
||||
|
||||
fact = fact || m.UserJoined != nil
|
||||
fact = fact || len(m.UsersJoined) > 0
|
||||
fact = fact || m.UserLeft != nil
|
||||
fact = fact || m.NewGroupTitle != ""
|
||||
fact = fact || m.NewGroupPhoto != nil
|
||||
fact = fact || m.GroupPhotoDeleted
|
||||
fact = fact || m.GroupCreated || m.SuperGroupCreated
|
||||
fact = fact || (m.MigrateTo != m.MigrateFrom)
|
||||
|
||||
return fact
|
||||
}
|
146
vendor/gopkg.in/tucnak/telebot.v2/options.go
generated
vendored
Normal file
146
vendor/gopkg.in/tucnak/telebot.v2/options.go
generated
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
package telebot
|
||||
|
||||
// Option is a shorcut flag type for certain message features
|
||||
// (so-called options). It means that instead of passing
|
||||
// fully-fledged SendOptions* to Send(), you can use these
|
||||
// flags instead.
|
||||
//
|
||||
// Supported options are defined as iota-constants.
|
||||
type Option int
|
||||
|
||||
const (
|
||||
// NoPreview = SendOptions.DisableWebPagePreview
|
||||
NoPreview Option = iota
|
||||
|
||||
// Silent = SendOptions.DisableNotification
|
||||
Silent
|
||||
|
||||
// ForceReply = ReplyMarkup.ForceReply
|
||||
ForceReply
|
||||
|
||||
// OneTimeKeyboard = ReplyMarkup.OneTimeKeyboard
|
||||
OneTimeKeyboard
|
||||
)
|
||||
|
||||
// SendOptions has most complete control over in what way the message
|
||||
// must be sent, providing an API-complete set of custom properties
|
||||
// and options.
|
||||
//
|
||||
// Despite its power, SendOptions is rather inconvenient to use all
|
||||
// the way through bot logic, so you might want to consider storing
|
||||
// and re-using it somewhere or be using Option flags instead.
|
||||
type SendOptions struct {
|
||||
// If the message is a reply, original message.
|
||||
ReplyTo *Message
|
||||
|
||||
// See ReplyMarkup struct definition.
|
||||
ReplyMarkup *ReplyMarkup
|
||||
|
||||
// For text messages, disables previews for links in this message.
|
||||
DisableWebPagePreview bool
|
||||
|
||||
// Sends the message silently. iOS users will not receive a notification, Android users will receive a notification with no sound.
|
||||
DisableNotification bool
|
||||
|
||||
// ParseMode controls how client apps render your message.
|
||||
ParseMode ParseMode
|
||||
}
|
||||
|
||||
func (og *SendOptions) copy() *SendOptions {
|
||||
cp := *og
|
||||
if cp.ReplyMarkup != nil {
|
||||
cp.ReplyMarkup = cp.ReplyMarkup.copy()
|
||||
}
|
||||
|
||||
return &cp
|
||||
}
|
||||
|
||||
// ReplyMarkup controls two convenient options for bot-user communications
|
||||
// such as reply keyboard and inline "keyboard" (a grid of buttons as a part
|
||||
// of the message).
|
||||
type ReplyMarkup struct {
|
||||
// InlineKeyboard is a grid of InlineButtons displayed in the message.
|
||||
//
|
||||
// Note: DO NOT confuse with ReplyKeyboard and other keyboard properties!
|
||||
InlineKeyboard [][]InlineButton `json:"inline_keyboard,omitempty"`
|
||||
|
||||
// ReplyKeyboard is a grid, consisting of keyboard buttons.
|
||||
//
|
||||
// Note: you don't need to set HideCustomKeyboard field to show custom keyboard.
|
||||
ReplyKeyboard [][]ReplyButton `json:"keyboard,omitempty"`
|
||||
|
||||
// ForceReply forces Telegram clients to display
|
||||
// a reply interface to the user (act as if the user
|
||||
// has selected the bot‘s message and tapped "Reply").
|
||||
ForceReply bool `json:"force_reply,omitempty"`
|
||||
|
||||
// Requests clients to resize the keyboard vertically for optimal fit
|
||||
// (e.g. make the keyboard smaller if there are just two rows of buttons).
|
||||
//
|
||||
// Defaults to false, in which case the custom keyboard is always of the
|
||||
// same height as the app's standard keyboard.
|
||||
ResizeReplyKeyboard bool `json:"resize_keyboard,omitempty"`
|
||||
|
||||
// Requests clients to hide the reply keyboard as soon as it's been used.
|
||||
//
|
||||
// Defaults to false.
|
||||
OneTimeKeyboard bool `json:"one_time_keyboard,omitempty"`
|
||||
|
||||
// Requests clients to remove the reply keyboard.
|
||||
//
|
||||
// Dafaults to false.
|
||||
ReplyKeyboardRemove bool `json:"remove_keyboard,omitempty"`
|
||||
|
||||
// Use this param if you want to force reply from
|
||||
// specific users only.
|
||||
//
|
||||
// Targets:
|
||||
// 1) Users that are @mentioned in the text of the Message object;
|
||||
// 2) If the bot's message is a reply (has SendOptions.ReplyTo),
|
||||
// sender of the original message.
|
||||
Selective bool `json:"selective,omitempty"`
|
||||
}
|
||||
|
||||
func (og *ReplyMarkup) copy() *ReplyMarkup {
|
||||
cp := *og
|
||||
|
||||
cp.ReplyKeyboard = make([][]ReplyButton, len(og.ReplyKeyboard))
|
||||
for i, row := range og.ReplyKeyboard {
|
||||
cp.ReplyKeyboard[i] = make([]ReplyButton, len(row))
|
||||
for j, btn := range row {
|
||||
cp.ReplyKeyboard[i][j] = btn
|
||||
}
|
||||
}
|
||||
|
||||
cp.InlineKeyboard = make([][]InlineButton, len(og.InlineKeyboard))
|
||||
for i, row := range og.InlineKeyboard {
|
||||
cp.InlineKeyboard[i] = make([]InlineButton, len(row))
|
||||
for j, btn := range row {
|
||||
cp.InlineKeyboard[i][j] = btn
|
||||
}
|
||||
}
|
||||
|
||||
return &cp
|
||||
}
|
||||
|
||||
// ReplyButton represents a button displayed in reply-keyboard.
|
||||
//
|
||||
// Set either Contact or Location to true in order to request
|
||||
// sensitive info, such as user's phone number or current location.
|
||||
// (Available in private chats only.)
|
||||
type ReplyButton struct {
|
||||
Text string `json:"text"`
|
||||
|
||||
Contact bool `json:"request_contact,omitempty"`
|
||||
Location bool `json:"request_location,omitempty"`
|
||||
|
||||
Action func(*Callback) `json:"-"`
|
||||
}
|
||||
|
||||
// InlineKeyboardMarkup represents an inline keyboard that appears
|
||||
// right next to the message it belongs to.
|
||||
type InlineKeyboardMarkup struct {
|
||||
// Array of button rows, each represented by
|
||||
// an Array of KeyboardButton objects.
|
||||
InlineKeyboard [][]InlineButton `json:"inline_keyboard,omitempty"`
|
||||
}
|
106
vendor/gopkg.in/tucnak/telebot.v2/poller.go
generated
vendored
Normal file
106
vendor/gopkg.in/tucnak/telebot.v2/poller.go
generated
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrCouldNotUpdate = errors.New("getUpdates() failed")
|
||||
)
|
||||
|
||||
// Poller is a provider of Updates.
|
||||
//
|
||||
// All pollers must implement Poll(), which accepts bot
|
||||
// pointer and subscription channel and start polling
|
||||
// synchronously straight away.
|
||||
type Poller interface {
|
||||
// Poll is supposed to take the bot object
|
||||
// subscription channel and start polling
|
||||
// for Updates immediately.
|
||||
//
|
||||
// Poller must listen for stop constantly and close
|
||||
// it as soon as it's done polling.
|
||||
Poll(b *Bot, updates chan Update, stop chan struct{})
|
||||
}
|
||||
|
||||
// MiddlewarePoller is a special kind of poller that acts
|
||||
// like a filter for updates. It could be used for spam
|
||||
// handling, banning or whatever.
|
||||
//
|
||||
// For heavy middleware, use increased capacity.
|
||||
//
|
||||
type MiddlewarePoller struct {
|
||||
Capacity int // Default: 1
|
||||
Poller Poller
|
||||
Filter func(*Update) bool
|
||||
}
|
||||
|
||||
// NewMiddlewarePoller wait for it... constructs a new middleware poller.
|
||||
func NewMiddlewarePoller(original Poller, filter func(*Update) bool) *MiddlewarePoller {
|
||||
return &MiddlewarePoller{
|
||||
Poller: original,
|
||||
Filter: filter,
|
||||
}
|
||||
}
|
||||
|
||||
// Poll sieves updates through middleware filter.
|
||||
func (p *MiddlewarePoller) Poll(b *Bot, dest chan Update, stop chan struct{}) {
|
||||
cap := 1
|
||||
if p.Capacity > 1 {
|
||||
cap = p.Capacity
|
||||
}
|
||||
|
||||
middle := make(chan Update, cap)
|
||||
stopPoller := make(chan struct{})
|
||||
|
||||
go p.Poller.Poll(b, middle, stopPoller)
|
||||
|
||||
for {
|
||||
select {
|
||||
// call to stop
|
||||
case <-stop:
|
||||
stopPoller <- struct{}{}
|
||||
|
||||
// poller is done
|
||||
case <-stopPoller:
|
||||
close(stop)
|
||||
return
|
||||
|
||||
case upd := <-middle:
|
||||
if p.Filter(&upd) {
|
||||
dest <- upd
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LongPoller is a classic LongPoller with timeout.
|
||||
type LongPoller struct {
|
||||
Timeout time.Duration
|
||||
|
||||
LastUpdateID int
|
||||
}
|
||||
|
||||
// Poll does long polling.
|
||||
func (p *LongPoller) Poll(b *Bot, dest chan Update, stop chan struct{}) {
|
||||
go func(stop chan struct{}) {
|
||||
<-stop
|
||||
close(stop)
|
||||
}(stop)
|
||||
|
||||
for {
|
||||
updates, err := b.getUpdates(p.LastUpdateID+1, p.Timeout)
|
||||
|
||||
if err != nil {
|
||||
b.debug(ErrCouldNotUpdate)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, update := range updates {
|
||||
p.LastUpdateID = update.ID
|
||||
dest <- update
|
||||
}
|
||||
}
|
||||
}
|
188
vendor/gopkg.in/tucnak/telebot.v2/sendable.go
generated
vendored
Normal file
188
vendor/gopkg.in/tucnak/telebot.v2/sendable.go
generated
vendored
Normal file
@@ -0,0 +1,188 @@
|
||||
package telebot
|
||||
|
||||
import "fmt"
|
||||
|
||||
// Recipient is any possible endpoint you can send
|
||||
// messages to: either user, group or a channel.
|
||||
type Recipient interface {
|
||||
// Must return legit Telegram chat_id or username
|
||||
Recipient() string
|
||||
}
|
||||
|
||||
// Sendable is any object that can send itself.
|
||||
//
|
||||
// This is pretty cool, since it lets bots implement
|
||||
// custom Sendables for complex kind of media or
|
||||
// chat objects spanning across multiple messages.
|
||||
type Sendable interface {
|
||||
Send(*Bot, Recipient, *SendOptions) (*Message, error)
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (p *Photo) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"caption": p.Caption,
|
||||
}
|
||||
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&p.File, "photo", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Photo.File.stealRef(&p.File)
|
||||
*p = *msg.Photo
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (a *Audio) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"caption": a.Caption,
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&a.File, "audio", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Audio.File.stealRef(&a.File)
|
||||
*a = *msg.Audio
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (d *Document) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"caption": d.Caption,
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&d.File, "document", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Document.File.stealRef(&d.File)
|
||||
*d = *msg.Document
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (s *Sticker) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&s.File, "sticker", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Sticker.File.stealRef(&s.File)
|
||||
*s = *msg.Sticker
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (v *Video) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"caption": v.Caption,
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&v.File, "video", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Video.File.stealRef(&v.File)
|
||||
*v = *msg.Video
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (v *Voice) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&v.File, "voice", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.Voice.File.stealRef(&v.File)
|
||||
*v = *msg.Voice
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (v *VideoNote) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
msg, err := b.sendObject(&v.File, "videoNote", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
msg.VideoNote.File.stealRef(&v.File)
|
||||
*v = *msg.VideoNote
|
||||
|
||||
return msg, nil
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (x *Location) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"latitude": fmt.Sprintf("%f", x.Lat),
|
||||
"longitude": fmt.Sprintf("%f", x.Lng),
|
||||
"live_period": fmt.Sprintf("%d", x.LivePeriod),
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
respJSON, err := b.Raw("sendLocation", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return extractMsgResponse(respJSON)
|
||||
}
|
||||
|
||||
// Send delivers media through bot b to recipient.
|
||||
func (v *Venue) Send(b *Bot, to Recipient, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"latitude": fmt.Sprintf("%f", v.Location.Lat),
|
||||
"longitude": fmt.Sprintf("%f", v.Location.Lng),
|
||||
"title": v.Title,
|
||||
"address": v.Address,
|
||||
"foursquare_id": v.FoursquareID,
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
respJSON, err := b.Raw("sendVenue", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return extractMsgResponse(respJSON)
|
||||
}
|
23
vendor/gopkg.in/tucnak/telebot.v2/stickers.go
generated
vendored
Normal file
23
vendor/gopkg.in/tucnak/telebot.v2/stickers.go
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
package telebot
|
||||
|
||||
// Sticker object represents a WebP image, so-called sticker.
|
||||
type Sticker struct {
|
||||
File
|
||||
|
||||
Width int `json:"width"`
|
||||
Height int `json:"height"`
|
||||
|
||||
Thumbnail *Photo `json:"thumb,omitempty"`
|
||||
Emoji string `json:"emoji,omitempty"`
|
||||
SetName string `json:"set_name,omitempty"`
|
||||
MaskPosition *MaskPosition `json:"mask_position,omitempty"`
|
||||
}
|
||||
|
||||
// MaskPosition describes the position on faces where
|
||||
// a mask should be placed by default.
|
||||
type MaskPosition struct {
|
||||
Feature MaskFeature `json:"point"`
|
||||
XShift float32 `json:"x_shift"`
|
||||
YShift float32 `json:"y_shift"`
|
||||
Scale float32 `json:"scale"`
|
||||
}
|
158
vendor/gopkg.in/tucnak/telebot.v2/telebot.go
generated
vendored
Normal file
158
vendor/gopkg.in/tucnak/telebot.v2/telebot.go
generated
vendored
Normal file
@@ -0,0 +1,158 @@
|
||||
// Package telebot is a framework for Telegram bots.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// import (
|
||||
// "time"
|
||||
// tb "gopkg.in/tucnak/telebot.v2"
|
||||
// )
|
||||
//
|
||||
// func main() {
|
||||
// b, err := tb.NewBot(tb.Settings{
|
||||
// Token: "TOKEN_HERE",
|
||||
// Poller: &tb.LongPoller{10 * time.Second},
|
||||
// })
|
||||
//
|
||||
// if err != nil {
|
||||
// return
|
||||
// }
|
||||
//
|
||||
// b.Handle(tb.OnMessage, func(m *tb.Message) {
|
||||
// b.Send(m.Sender, "hello world")
|
||||
// }
|
||||
//
|
||||
// b.Start()
|
||||
// }
|
||||
//
|
||||
package telebot
|
||||
|
||||
// These are one of the possible events Handle() can deal with.
|
||||
//
|
||||
// For convenience, all Telebot-provided endpoints start with
|
||||
// an "alert" character \a.
|
||||
const (
|
||||
// Basic message handlers.
|
||||
//
|
||||
// Handler: func(*Message)
|
||||
OnText = "\atext"
|
||||
OnPhoto = "\aphoto"
|
||||
OnAudio = "\aaudio"
|
||||
OnDocument = "\adocument"
|
||||
OnSticker = "\asticker"
|
||||
OnVideo = "\avideo"
|
||||
OnVoice = "\avoice"
|
||||
OnVideoNote = "\avideo_note"
|
||||
OnContact = "\acontact"
|
||||
OnLocation = "\alocation"
|
||||
OnVenue = "\avenue"
|
||||
OnEdited = "\aedited"
|
||||
OnPinned = "\apinned"
|
||||
OnChannelPost = "\achan_post"
|
||||
OnEditedChannelPost = "\achan_edited_post"
|
||||
|
||||
// Will fire when bot is added to a group.
|
||||
OnAddedToGroup = "\aadded_to_group"
|
||||
// Group events:
|
||||
OnUserJoined = "\auser_joined"
|
||||
OnUserLeft = "\auser_left"
|
||||
OnNewGroupTitle = "\anew_chat_title"
|
||||
OnNewGroupPhoto = "\anew_chat_photo"
|
||||
OnGroupPhotoDeleted = "\achat_photo_del"
|
||||
|
||||
// Migration happens when group switches to
|
||||
// a super group. You might want to update
|
||||
// your internal references to this chat
|
||||
// upon switching as its ID will change.
|
||||
//
|
||||
// Handler: func(from, to int64)
|
||||
OnMigration = "\amigration"
|
||||
|
||||
// Will fire on callback requests.
|
||||
//
|
||||
// Handler: func(*Callback)
|
||||
OnCallback = "\acallback"
|
||||
|
||||
// Will fire on incoming inline queries.
|
||||
//
|
||||
// Handler: func(*Query)
|
||||
OnQuery = "\aquery"
|
||||
|
||||
// Will fire on chosen inline results.
|
||||
//
|
||||
// Handler: func(*ChosenInlineResult)
|
||||
OnChosenInlineResult = "\achosen_inline_result"
|
||||
)
|
||||
|
||||
// ChatAction is a client-side status indicating bot activity.
|
||||
type ChatAction string
|
||||
|
||||
const (
|
||||
Typing ChatAction = "typing"
|
||||
UploadingPhoto ChatAction = "upload_photo"
|
||||
UploadingVideo ChatAction = "upload_video"
|
||||
UploadingAudio ChatAction = "upload_audio"
|
||||
UploadingDocument ChatAction = "upload_document"
|
||||
UploadingVNote ChatAction = "upload_video_note"
|
||||
RecordingVideo ChatAction = "record_video"
|
||||
RecordingAudio ChatAction = "record_audio"
|
||||
FindingLocation ChatAction = "find_location"
|
||||
)
|
||||
|
||||
// ParseMode determines the way client applications treat the text of the message
|
||||
type ParseMode string
|
||||
|
||||
const (
|
||||
ModeDefault ParseMode = ""
|
||||
ModeMarkdown ParseMode = "Markdown"
|
||||
ModeHTML ParseMode = "HTML"
|
||||
)
|
||||
|
||||
// EntityType is a MessageEntity type.
|
||||
type EntityType string
|
||||
|
||||
const (
|
||||
EntityMention EntityType = "mention"
|
||||
EntityTMention EntityType = "text_mention"
|
||||
EntityHashtag EntityType = "hashtag"
|
||||
EntityCommand EntityType = "bot_command"
|
||||
EntityURL EntityType = "url"
|
||||
EntityEmail EntityType = "email"
|
||||
EntityBold EntityType = "bold"
|
||||
EntityItalic EntityType = "italic"
|
||||
EntityCode EntityType = "code"
|
||||
EntityCodeBlock EntityType = "pre"
|
||||
EntityTextLink EntityType = "text_link"
|
||||
)
|
||||
|
||||
// ChatType represents one of the possible chat types.
|
||||
type ChatType string
|
||||
|
||||
const (
|
||||
ChatPrivate ChatType = "private"
|
||||
ChatGroup ChatType = "group"
|
||||
ChatSuperGroup ChatType = "supergroup"
|
||||
ChatChannel ChatType = "channel"
|
||||
ChatChannelPrivate ChatType = "privatechannel"
|
||||
)
|
||||
|
||||
// MemberStatus is one's chat status
|
||||
type MemberStatus string
|
||||
|
||||
const (
|
||||
Creator MemberStatus = "creator"
|
||||
Administrator MemberStatus = "administrator"
|
||||
Member MemberStatus = "member"
|
||||
Restricted MemberStatus = "restricted"
|
||||
Left MemberStatus = "left"
|
||||
Kicked MemberStatus = "kicked"
|
||||
)
|
||||
|
||||
// MaskFeature defines sticker mask position.
|
||||
type MaskFeature string
|
||||
|
||||
const (
|
||||
FeatureForehead MaskFeature = "forehead"
|
||||
FeatureEyes MaskFeature = "eyes"
|
||||
FeatureMouth MaskFeature = "mouth"
|
||||
FeatureChin MaskFeature = "chin"
|
||||
)
|
209
vendor/gopkg.in/tucnak/telebot.v2/util.go
generated
vendored
Normal file
209
vendor/gopkg.in/tucnak/telebot.v2/util.go
generated
vendored
Normal file
@@ -0,0 +1,209 @@
|
||||
package telebot
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"strconv"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func (b *Bot) debug(err error) {
|
||||
if b.reporter != nil {
|
||||
b.reporter(errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) deferDebug() {
|
||||
if r := recover(); r != nil {
|
||||
if err, ok := r.(error); ok {
|
||||
b.debug(err)
|
||||
} else if str, ok := r.(string); ok {
|
||||
b.debug(errors.Errorf("%s", str))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (b *Bot) sendText(to Recipient, text string, opt *SendOptions) (*Message, error) {
|
||||
params := map[string]string{
|
||||
"chat_id": to.Recipient(),
|
||||
"text": text,
|
||||
}
|
||||
embedSendOptions(params, opt)
|
||||
|
||||
respJSON, err := b.Raw("sendMessage", params)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return extractMsgResponse(respJSON)
|
||||
}
|
||||
|
||||
func wrapSystem(err error) error {
|
||||
return errors.Wrap(err, "system error")
|
||||
}
|
||||
|
||||
func isUserInList(user *User, list []User) bool {
|
||||
for _, user2 := range list {
|
||||
if user.ID == user2.ID {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func extractMsgResponse(respJSON []byte) (*Message, error) {
|
||||
var resp struct {
|
||||
Ok bool
|
||||
Result *Message
|
||||
Description string
|
||||
}
|
||||
|
||||
err := json.Unmarshal(respJSON, &resp)
|
||||
if err != nil {
|
||||
var resp struct {
|
||||
Ok bool
|
||||
Result bool
|
||||
Description string
|
||||
}
|
||||
|
||||
err := json.Unmarshal(respJSON, &resp)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "bad response json")
|
||||
}
|
||||
|
||||
if !resp.Ok {
|
||||
return nil, errors.Errorf("api error: %s", resp.Description)
|
||||
}
|
||||
}
|
||||
|
||||
if !resp.Ok {
|
||||
return nil, errors.Errorf("api error: %s", resp.Description)
|
||||
}
|
||||
|
||||
return resp.Result, nil
|
||||
}
|
||||
|
||||
func extractOkResponse(respJSON []byte) error {
|
||||
var resp struct {
|
||||
Ok bool
|
||||
Description string
|
||||
}
|
||||
|
||||
err := json.Unmarshal(respJSON, &resp)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "bad response json")
|
||||
}
|
||||
|
||||
if !resp.Ok {
|
||||
return errors.Errorf("api error: %s", resp.Description)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractOptions(how []interface{}) *SendOptions {
|
||||
var opts *SendOptions
|
||||
|
||||
for _, prop := range how {
|
||||
switch opt := prop.(type) {
|
||||
case *SendOptions:
|
||||
opts = opt.copy()
|
||||
|
||||
case *ReplyMarkup:
|
||||
if opts == nil {
|
||||
opts = &SendOptions{}
|
||||
}
|
||||
opts.ReplyMarkup = opt.copy()
|
||||
|
||||
case Option:
|
||||
if opts == nil {
|
||||
opts = &SendOptions{}
|
||||
}
|
||||
|
||||
switch opt {
|
||||
case NoPreview:
|
||||
opts.DisableWebPagePreview = true
|
||||
case Silent:
|
||||
opts.DisableNotification = true
|
||||
case ForceReply:
|
||||
if opts.ReplyMarkup == nil {
|
||||
opts.ReplyMarkup = &ReplyMarkup{}
|
||||
}
|
||||
opts.ReplyMarkup.ForceReply = true
|
||||
case OneTimeKeyboard:
|
||||
if opts.ReplyMarkup == nil {
|
||||
opts.ReplyMarkup = &ReplyMarkup{}
|
||||
}
|
||||
opts.ReplyMarkup.OneTimeKeyboard = true
|
||||
default:
|
||||
panic("telebot: unsupported flag-option")
|
||||
}
|
||||
|
||||
case ParseMode:
|
||||
if opts == nil {
|
||||
opts = &SendOptions{}
|
||||
}
|
||||
opts.ParseMode = opt
|
||||
|
||||
default:
|
||||
panic("telebot: unsupported send-option")
|
||||
}
|
||||
}
|
||||
|
||||
return opts
|
||||
}
|
||||
|
||||
func embedSendOptions(params map[string]string, opt *SendOptions) {
|
||||
if opt == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if opt.ReplyTo != nil && opt.ReplyTo.ID != 0 {
|
||||
params["reply_to_message_id"] = strconv.Itoa(opt.ReplyTo.ID)
|
||||
}
|
||||
|
||||
if opt.DisableWebPagePreview {
|
||||
params["disable_web_page_preview"] = "true"
|
||||
}
|
||||
|
||||
if opt.DisableNotification {
|
||||
params["disable_notification"] = "true"
|
||||
}
|
||||
|
||||
if opt.ParseMode != ModeDefault {
|
||||
params["parse_mode"] = string(opt.ParseMode)
|
||||
}
|
||||
|
||||
if opt.ReplyMarkup != nil {
|
||||
processButtons(opt.ReplyMarkup.InlineKeyboard)
|
||||
replyMarkup, _ := json.Marshal(opt.ReplyMarkup)
|
||||
params["reply_markup"] = string(replyMarkup)
|
||||
}
|
||||
}
|
||||
|
||||
func processButtons(keys [][]InlineButton) {
|
||||
if keys == nil || len(keys) < 1 || len(keys[0]) < 1 {
|
||||
return
|
||||
}
|
||||
|
||||
for i, _ := range keys {
|
||||
for j, _ := range keys[i] {
|
||||
key := &keys[i][j]
|
||||
if key.Unique != "" {
|
||||
// Format: "\f<callback_name>|<data>"
|
||||
data := key.Data
|
||||
if data == "" {
|
||||
key.Data = "\f" + key.Unique
|
||||
} else {
|
||||
key.Data = "\f" + key.Unique + "|" + data
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func embedRights(p map[string]string, prv Rights) {
|
||||
jsonRepr, _ := json.Marshal(prv)
|
||||
json.Unmarshal(jsonRepr, p)
|
||||
}
|
Reference in New Issue
Block a user