aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Kiryukhin <a.kiryukhin@mail.ru>2019-09-05 22:43:32 +0300
committerAlexander Kiryukhin <a.kiryukhin@mail.ru>2019-09-05 22:43:32 +0300
commit6e4ade909d9b3a0a4a8dd8c11a4b1984b84f09e4 (patch)
tree11e5e2017501f68ac9b1705edfccd6af3134a3eb
parent29322bf303815d477a83fee0e598006b651599a4 (diff)
Fully refactored high level APIv0.3.0v0.3
-rw-r--r--README.md63
-rw-r--r--api.go94
-rw-r--r--bots.go10
-rw-r--r--chats.go40
-rw-r--r--client.go4
-rw-r--r--examples/example.go45
-rw-r--r--examples/example_longpolling.go8
-rw-r--r--examples/example_webhook.go10
-rw-r--r--keyboard.go46
-rw-r--r--message.go81
-rw-r--r--messages.go100
-rw-r--r--schemes/schemes.go (renamed from models.go)2
-rw-r--r--subscriptions.go16
-rw-r--r--uploads.go154
14 files changed, 338 insertions, 335 deletions
diff --git a/README.md b/README.md
index 1c3f3d2..60124ec 100644
--- a/README.md
+++ b/README.md
@@ -19,66 +19,9 @@
## Пример
-```go
-package main
-
-import (
- "context"
- "fmt"
- "log"
- "os"
- "os/signal"
-
- "github.com/neonxp/tamtam"
-)
-
-func main() {
- api := tamtam.New(os.Getenv("TOKEN"))
-
- info, err := api.Bots.GetBot() // Простой метод
- log.Printf("Get me: %#v %#v", info, err)
- ctx, cancel := context.WithCancel(context.Background())
- go func() {
- exit := make(chan os.Signal)
- signal.Notify(exit, os.Kill, os.Interrupt)
- <-exit
- cancel()
- }()
- for upd := range api.GetUpdates(ctx) { // Чтение из канала с обновлениями
- log.Printf("Received: %#v", upd)
- switch upd := upd.(type) { // Определение типа пришедшего обновления
- case *tamtam.MessageCreatedUpdate:
- // Создание клавиатуры
- keyboard := api.Messages.NewKeyboardBuilder()
- keyboard.
- AddRow().
- AddGeolocation("Прислать геолокацию", true).
- AddContact("Прислать контакт")
- keyboard.
- AddRow().
- AddLink("Библиотека", tamtam.POSITIVE, "https://github.com/neonxp/tamtam").
- AddCallback("Колбек 1", tamtam.NEGATIVE, "callback_1").
- AddCallback("Колбек 2", tamtam.NEGATIVE, "callback_2")
-
- // Отправка сообщения с клавиатурой
- res, err := api.Messages.SendMessage(0, upd.Message.Sender.UserId, &tamtam.NewMessageBody{
- Text: fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text),
- Attachments: []interface{}{
- tamtam.NewInlineKeyboardAttachmentRequest(keyboard.Build()),
- },
- })
- log.Printf("Answer: %#v %#v", res, err)
- case *tamtam.MessageCallbackUpdate:
- res, err := api.Messages.SendMessage(0, upd.Callback.User.UserId, &tamtam.NewMessageBody{
- Text: "Callback: " + upd.Callback.Payload,
- })
- log.Printf("Answer: %#v %#v", res, err)
- default:
- log.Printf("Unknown type: %#v", upd)
- }
- }
-}
-```
+* [Пример с отправкой фото](https://github.com/neonxp/tamtam/blob/master/examples/example.go)
+* [Пример с longpolling](https://github.com/neonxp/tamtam/blob/master/examples/example_longpolling.go)
+* [Пример с webhook](https://github.com/neonxp/tamtam/blob/master/examples/example_webhook.go)
## Автор
diff --git a/api.go b/api.go
index aa91a48..4be13e3 100644
--- a/api.go
+++ b/api.go
@@ -11,6 +11,8 @@ import (
"net/url"
"strconv"
"time"
+
+ "github.com/neonxp/tamtam/schemes"
)
//Api implements main part of TamTam API
@@ -42,106 +44,106 @@ func New(key string) *Api {
}
}
-func (a *Api) bytesToProperUpdate(b []byte) UpdateInterface {
- u := new(Update)
+func (a *Api) bytesToProperUpdate(b []byte) schemes.UpdateInterface {
+ u := new(schemes.Update)
_ = json.Unmarshal(b, u)
switch u.GetUpdateType() {
- case TypeMessageCallback:
- upd := new(MessageCallbackUpdate)
+ case schemes.TypeMessageCallback:
+ upd := new(schemes.MessageCallbackUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeMessageCreated:
- upd := new(MessageCreatedUpdate)
+ case schemes.TypeMessageCreated:
+ upd := new(schemes.MessageCreatedUpdate)
_ = json.Unmarshal(b, upd)
for _, att := range upd.Message.Body.RawAttachments {
upd.Message.Body.Attachments = append(upd.Message.Body.Attachments, a.bytesToProperAttachment(att))
}
return upd
- case TypeMessageRemoved:
- upd := new(MessageRemovedUpdate)
+ case schemes.TypeMessageRemoved:
+ upd := new(schemes.MessageRemovedUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeMessageEdited:
- upd := new(MessageEditedUpdate)
+ case schemes.TypeMessageEdited:
+ upd := new(schemes.MessageEditedUpdate)
_ = json.Unmarshal(b, upd)
for _, att := range upd.Message.Body.RawAttachments {
upd.Message.Body.Attachments = append(upd.Message.Body.Attachments, a.bytesToProperAttachment(att))
}
return upd
- case TypeBotAdded:
- upd := new(BotAddedToChatUpdate)
+ case schemes.TypeBotAdded:
+ upd := new(schemes.BotAddedToChatUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeBotRemoved:
- upd := new(BotRemovedFromChatUpdate)
+ case schemes.TypeBotRemoved:
+ upd := new(schemes.BotRemovedFromChatUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeUserAdded:
- upd := new(UserAddedToChatUpdate)
+ case schemes.TypeUserAdded:
+ upd := new(schemes.UserAddedToChatUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeUserRemoved:
- upd := new(UserRemovedFromChatUpdate)
+ case schemes.TypeUserRemoved:
+ upd := new(schemes.UserRemovedFromChatUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeBotStarted:
- upd := new(BotStartedUpdate)
+ case schemes.TypeBotStarted:
+ upd := new(schemes.BotStartedUpdate)
_ = json.Unmarshal(b, upd)
return upd
- case TypeChatTitleChanged:
- upd := new(ChatTitleChangedUpdate)
+ case schemes.TypeChatTitleChanged:
+ upd := new(schemes.ChatTitleChangedUpdate)
_ = json.Unmarshal(b, upd)
return upd
}
return nil
}
-func (a *Api) bytesToProperAttachment(b []byte) AttachmentInterface {
- attachment := new(Attachment)
+func (a *Api) bytesToProperAttachment(b []byte) schemes.AttachmentInterface {
+ attachment := new(schemes.Attachment)
_ = json.Unmarshal(b, attachment)
switch attachment.GetAttachmentType() {
- case AttachmentAudio:
- res := new(AudioAttachment)
+ case schemes.AttachmentAudio:
+ res := new(schemes.AudioAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentContact:
- res := new(ContactAttachment)
+ case schemes.AttachmentContact:
+ res := new(schemes.ContactAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentFile:
- res := new(FileAttachment)
+ case schemes.AttachmentFile:
+ res := new(schemes.FileAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentImage:
- res := new(PhotoAttachment)
+ case schemes.AttachmentImage:
+ res := new(schemes.PhotoAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentKeyboard:
- res := new(InlineKeyboardAttachment)
+ case schemes.AttachmentKeyboard:
+ res := new(schemes.InlineKeyboardAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentLocation:
- res := new(LocationAttachment)
+ case schemes.AttachmentLocation:
+ res := new(schemes.LocationAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentShare:
- res := new(ShareAttachment)
+ case schemes.AttachmentShare:
+ res := new(schemes.ShareAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentSticker:
- res := new(StickerAttachment)
+ case schemes.AttachmentSticker:
+ res := new(schemes.StickerAttachment)
_ = json.Unmarshal(b, res)
return res
- case AttachmentVideo:
- res := new(VideoAttachment)
+ case schemes.AttachmentVideo:
+ res := new(schemes.VideoAttachment)
_ = json.Unmarshal(b, res)
return res
}
return attachment
}
-func (a *Api) getUpdates(limit int, timeout int, marker int, types []string) (*UpdateList, error) {
- result := new(UpdateList)
+func (a *Api) getUpdates(limit int, timeout int, marker int, types []string) (*schemes.UpdateList, error) {
+ result := new(schemes.UpdateList)
values := url.Values{}
if limit > 0 {
values.Set("limit", strconv.Itoa(limit))
@@ -171,8 +173,8 @@ func (a *Api) getUpdates(limit int, timeout int, marker int, types []string) (*U
}
//GetUpdates returns updates channel
-func (a *Api) GetUpdates(ctx context.Context) chan UpdateInterface {
- ch := make(chan UpdateInterface)
+func (a *Api) GetUpdates(ctx context.Context) chan schemes.UpdateInterface {
+ ch := make(chan schemes.UpdateInterface)
go func() {
for {
select {
diff --git a/bots.go b/bots.go
index 582f07c..ea43ddb 100644
--- a/bots.go
+++ b/bots.go
@@ -5,6 +5,8 @@ import (
"log"
"net/http"
"net/url"
+
+ "github.com/neonxp/tamtam/schemes"
)
type bots struct {
@@ -16,8 +18,8 @@ func newBots(client *client) *bots {
}
//GetBot returns info about current bot. Current bot can be identified by access token. Method returns bot identifier, name and avatar (if any)
-func (a *bots) GetBot() (*BotInfo, error) {
- result := new(BotInfo)
+func (a *bots) GetBot() (*schemes.BotInfo, error) {
+ result := new(schemes.BotInfo)
values := url.Values{}
body, err := a.client.request(http.MethodGet, "me", values, nil)
if err != nil {
@@ -32,8 +34,8 @@ func (a *bots) GetBot() (*BotInfo, error) {
}
//PatchBot edits current bot info. Fill only the fields you want to update. All remaining fields will stay untouched
-func (a *bots) PatchBot(patch *BotPatch) (*BotInfo, error) {
- result := new(BotInfo)
+func (a *bots) PatchBot(patch *schemes.BotPatch) (*schemes.BotInfo, error) {
+ result := new(schemes.BotInfo)
values := url.Values{}
body, err := a.client.request(http.MethodPatch, "me", values, patch)
if err != nil {
diff --git a/chats.go b/chats.go
index adb0c07..414b4f4 100644
--- a/chats.go
+++ b/chats.go
@@ -7,6 +7,8 @@ import (
"net/http"
"net/url"
"strconv"
+
+ "github.com/neonxp/tamtam/schemes"
)
type chats struct {
@@ -18,8 +20,8 @@ func newChats(client *client) *chats {
}
//GetChats returns information about chats that bot participated in: a result list and marker points to the next page
-func (a *chats) GetChats(count, marker int) (*ChatList, error) {
- result := new(ChatList)
+func (a *chats) GetChats(count, marker int) (*schemes.ChatList, error) {
+ result := new(schemes.ChatList)
values := url.Values{}
if count > 0 {
values.Set("count", strconv.Itoa(int(count)))
@@ -40,8 +42,8 @@ func (a *chats) GetChats(count, marker int) (*ChatList, error) {
}
//GetChat returns info about chat
-func (a *chats) GetChat(chatID int) (*Chat, error) {
- result := new(Chat)
+func (a *chats) GetChat(chatID int) (*schemes.Chat, error) {
+ result := new(schemes.Chat)
values := url.Values{}
body, err := a.client.request(http.MethodGet, fmt.Sprintf("chats/%d", chatID), values, nil)
if err != nil {
@@ -56,8 +58,8 @@ func (a *chats) GetChat(chatID int) (*Chat, error) {
}
//GetChatMembership returns chat membership info for current bot
-func (a *chats) GetChatMembership(chatID int) (*ChatMember, error) {
- result := new(ChatMember)
+func (a *chats) GetChatMembership(chatID int) (*schemes.ChatMember, error) {
+ result := new(schemes.ChatMember)
values := url.Values{}
body, err := a.client.request(http.MethodGet, fmt.Sprintf("chats/%d/members/me", chatID), values, nil)
if err != nil {
@@ -72,8 +74,8 @@ func (a *chats) GetChatMembership(chatID int) (*ChatMember, error) {
}
//GetChatMembers returns users participated in chat
-func (a *chats) GetChatMembers(chatID, count, marker int) (*ChatMembersList, error) {
- result := new(ChatMembersList)
+func (a *chats) GetChatMembers(chatID, count, marker int) (*schemes.ChatMembersList, error) {
+ result := new(schemes.ChatMembersList)
values := url.Values{}
if count > 0 {
values.Set("count", strconv.Itoa(int(count)))
@@ -94,8 +96,8 @@ func (a *chats) GetChatMembers(chatID, count, marker int) (*ChatMembersList, err
}
//LeaveChat removes bot from chat members
-func (a *chats) LeaveChat(chatID int) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+func (a *chats) LeaveChat(chatID int) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
body, err := a.client.request(http.MethodDelete, fmt.Sprintf("chats/%d/members/me", chatID), values, nil)
if err != nil {
@@ -110,8 +112,8 @@ func (a *chats) LeaveChat(chatID int) (*SimpleQueryResult, error) {
}
//EditChat edits chat info: title, icon, etc…
-func (a *chats) EditChat(chatID int, update *ChatPatch) (*Chat, error) {
- result := new(Chat)
+func (a *chats) EditChat(chatID int, update *schemes.ChatPatch) (*schemes.Chat, error) {
+ result := new(schemes.Chat)
values := url.Values{}
body, err := a.client.request(http.MethodPatch, fmt.Sprintf("chats/%d", chatID), values, update)
if err != nil {
@@ -126,8 +128,8 @@ func (a *chats) EditChat(chatID int, update *ChatPatch) (*Chat, error) {
}
//AddMember adds members to chat. Additional permissions may require.
-func (a *chats) AddMember(chatID int, users UserIdsList) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+func (a *chats) AddMember(chatID int, users schemes.UserIdsList) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
body, err := a.client.request(http.MethodPost, fmt.Sprintf("chats/%d/members", chatID), values, users)
if err != nil {
@@ -142,8 +144,8 @@ func (a *chats) AddMember(chatID int, users UserIdsList) (*SimpleQueryResult, er
}
//RemoveMember removes member from chat. Additional permissions may require.
-func (a *chats) RemoveMember(chatID int, userID int) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+func (a *chats) RemoveMember(chatID int, userID int) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
values.Set("user_id", strconv.Itoa(int(userID)))
body, err := a.client.request(http.MethodDelete, fmt.Sprintf("chats/%d/members", chatID), values, nil)
@@ -159,10 +161,10 @@ func (a *chats) RemoveMember(chatID int, userID int) (*SimpleQueryResult, error)
}
//SendAction send bot action to chat
-func (a *chats) SendAction(chatID int, action SenderAction) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+func (a *chats) SendAction(chatID int, action schemes.SenderAction) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
- body, err := a.client.request(http.MethodPost, fmt.Sprintf("chats/%d/actions", chatID), values, ActionRequestBody{Action: action})
+ body, err := a.client.request(http.MethodPost, fmt.Sprintf("chats/%d/actions", chatID), values, schemes.ActionRequestBody{Action: action})
if err != nil {
return result, err
}
diff --git a/client.go b/client.go
index 7c918b9..83551fb 100644
--- a/client.go
+++ b/client.go
@@ -6,6 +6,8 @@ import (
"io"
"net/http"
"net/url"
+
+ "github.com/neonxp/tamtam/schemes"
)
type client struct {
@@ -42,7 +44,7 @@ func (cl *client) requestReader(method, path string, query url.Values, body io.R
return nil, err
}
if resp.StatusCode != http.StatusOK {
- errObj := new(Error)
+ errObj := new(schemes.Error)
err = json.NewDecoder(resp.Body).Decode(errObj)
if err != nil {
return nil, err
diff --git a/examples/example.go b/examples/example.go
index b769e8a..d6b7ab4 100644
--- a/examples/example.go
+++ b/examples/example.go
@@ -2,12 +2,12 @@ package main
import (
"context"
- "fmt"
"log"
"os"
"os/signal"
"github.com/neonxp/tamtam"
+ "github.com/neonxp/tamtam/schemes"
)
func main() {
@@ -25,7 +25,7 @@ func main() {
for upd := range api.GetUpdates(ctx) { // Чтение из канала с обновлениями
log.Printf("Received: %#v", upd)
switch upd := upd.(type) { // Определение типа пришедшего обновления
- case *tamtam.MessageCreatedUpdate:
+ case *schemes.MessageCreatedUpdate:
// Создание клавиатуры
keyboard := api.Messages.NewKeyboardBuilder()
keyboard.
@@ -34,46 +34,27 @@ func main() {
AddContact("Прислать контакт")
keyboard.
AddRow().
- AddLink("Библиотека", tamtam.POSITIVE, "https://github.com/neonxp/tamtam").
- AddCallback("Колбек 1", tamtam.NEGATIVE, "callback_1").
- AddCallback("Колбек 2", tamtam.NEGATIVE, "callback_2")
+ AddLink("Библиотека", schemes.POSITIVE, "https://github.com/neonxp/tamtam").
+ AddCallback("Колбек 1", schemes.NEGATIVE, "callback_1").
+ AddCallback("Колбек 2", schemes.NEGATIVE, "callback_2")
keyboard.
AddRow().
- AddCallback("Картинка", tamtam.POSITIVE, "picture")
+ AddCallback("Картинка", schemes.POSITIVE, "picture")
// Отправка сообщения с клавиатурой
- res, err := api.Messages.SendMessage(0, upd.Message.Sender.UserId, &tamtam.NewMessageBody{
- Text: fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text),
- Attachments: []interface{}{
- tamtam.NewInlineKeyboardAttachmentRequest(keyboard.Build()),
- },
- })
- log.Printf("Answer: %#v %#v", res, err)
- case *tamtam.MessageCallbackUpdate:
+ err := api.Messages.Send(tamtam.NewMessage().SetUser(upd.Message.Sender.UserId).AddKeyboard(keyboard))
+ log.Printf("Answer: %#v", err)
+ case *schemes.MessageCallbackUpdate:
// Ответ на коллбек
- attachments := make([]interface{}, 0)
if upd.Callback.Payload == "picture" {
- photo, err := api.Uploads.UploadPhoto("./examples/example.jpg")
+ photo, err := api.Uploads.UploadPhotoFromFile("./examples/example.jpg")
if err != nil {
log.Fatal(err)
}
- attachments = append(attachments, tamtam.NewPhotoAttachmentRequest(tamtam.PhotoAttachmentRequestPayload{Photos: photo.Photos}))
+ if err := api.Messages.Send(tamtam.NewMessage().SetUser(upd.Message.Sender.UserId).AddPhoto(photo)); err != nil {
+ log.Fatal(err)
+ }
}
- res, err := api.Messages.AnswerOnCallback(
- upd.Callback.CallbackID,
- &tamtam.CallbackAnswer{
- UserId: upd.Callback.User.UserId,
- Message: &tamtam.NewMessageBody{
- Text: "OK!",
- },
- Notification: "Callback is ok",
- })
- log.Printf("Answer: %#v %#v", res, err)
- res2, err := api.Messages.SendMessage(0, upd.Callback.User.UserId, &tamtam.NewMessageBody{
- Text: upd.Callback.Payload + " at " + upd.GetUpdateTime().String(),
- Attachments: attachments,
- })
- log.Printf("Answer: %#v %#v", res2, err)
default:
log.Printf("Unknown type: %#v", upd)
}
diff --git a/examples/example_longpolling.go b/examples/example_longpolling.go
index 3dbc66b..6bb4727 100644
--- a/examples/example_longpolling.go
+++ b/examples/example_longpolling.go
@@ -29,9 +29,11 @@ func main() {
log.Printf("Received: %#v", upd)
switch upd := upd.(type) {
case *tamtam.MessageCreatedUpdate:
- res, err := api.Messages.SendMessage(0, upd.Message.Sender.UserId, &tamtam.NewMessageBody{
- Text: fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text),
- })
+ err := api.Messages.Send(
+ tamtam.NewMessage().
+ SetUser(upd.Message.Sender.UserId).
+ SetText(fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text)),
+ )
log.Printf("Answer: %#v %#v", res, err)
default:
log.Printf("Unknown type: %#v", upd)
diff --git a/examples/example_webhook.go b/examples/example_webhook.go
index ad1bdae..b4857c1 100644
--- a/examples/example_webhook.go
+++ b/examples/example_webhook.go
@@ -39,10 +39,12 @@ func main() {
log.Printf("Received: %#v", upd)
switch upd := upd.(type) {
case tamtam.MessageCreatedUpdate:
- res, err := api.Messages.SendMessage(0, upd.Message.Sender.UserId, &tamtam.NewMessageBody{
- Text: fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text),
- })
- log.Printf("Answer: %#v %#v", res, err)
+ err := api.Messages.Send(
+ tamtam.NewMessage().
+ SetUser(upd.Message.Sender.UserId).
+ SetText(fmt.Sprintf("Hello, %s! Your message: %s", upd.Message.Sender.Name, upd.Message.Body.Text)),
+ )
+ log.Printf("Answer: %#v", err)
default:
log.Printf("Unknown type: %#v", upd)
}
diff --git a/keyboard.go b/keyboard.go
index 5d38bd2..5259b7a 100644
--- a/keyboard.go
+++ b/keyboard.go
@@ -1,43 +1,45 @@
package tamtam
-//KeyboardBuilder implements builder for inline keyboard
-type KeyboardBuilder struct {
+import "github.com/neonxp/tamtam/schemes"
+
+//Keyboard implements builder for inline keyboard
+type Keyboard struct {
rows []*KeyboardRow
}
//AddRow adds row to inline keyboard
-func (k *KeyboardBuilder) AddRow() *KeyboardRow {
+func (k *Keyboard) AddRow() *KeyboardRow {
kr := &KeyboardRow{}
k.rows = append(k.rows, kr)
return kr
}
//Build returns result keyboard
-func (k *KeyboardBuilder) Build() Keyboard {
- buttons := make([][]ButtonInterface, 0, len(k.rows))
+func (k *Keyboard) Build() schemes.Keyboard {
+ buttons := make([][]schemes.ButtonInterface, 0, len(k.rows))
for _, r := range k.rows {
buttons = append(buttons, r.Build())
}
- return Keyboard{Buttons: buttons}
+ return schemes.Keyboard{Buttons: buttons}
}
//KeyboardRow represents buttons row
type KeyboardRow struct {
- cols []ButtonInterface
+ cols []schemes.ButtonInterface
}
//Build returns result keyboard row
-func (k *KeyboardRow) Build() []ButtonInterface {
+func (k *KeyboardRow) Build() []schemes.ButtonInterface {
return k.cols
}
//AddLink button
-func (k *KeyboardRow) AddLink(text string, intent Intent, url string) *KeyboardRow {
- b := LinkButton{
+func (k *KeyboardRow) AddLink(text string, intent schemes.Intent, url string) *KeyboardRow {
+ b := schemes.LinkButton{
Url: url,
- Button: Button{
+ Button: schemes.Button{
Text: text,
- Type: LINK,
+ Type: schemes.LINK,
},
}
k.cols = append(k.cols, b)
@@ -45,13 +47,13 @@ func (k *KeyboardRow) AddLink(text string, intent Intent, url string) *KeyboardR
}
//AddCallback button
-func (k *KeyboardRow) AddCallback(text string, intent Intent, payload string) *KeyboardRow {
- b := CallbackButton{
+func (k *KeyboardRow) AddCallback(text string, intent schemes.Intent, payload string) *KeyboardRow {
+ b := schemes.CallbackButton{
Payload: payload,
Intent: intent,
- Button: Button{
+ Button: schemes.Button{
Text: text,
- Type: CALLBACK,
+ Type: schemes.CALLBACK,
},
}
k.cols = append(k.cols, b)
@@ -60,10 +62,10 @@ func (k *KeyboardRow) AddCallback(text string, intent Intent, payload string) *K
//AddContact button
func (k *KeyboardRow) AddContact(text string) *KeyboardRow {
- b := RequestContactButton{
- Button: Button{
+ b := schemes.RequestContactButton{
+ Button: schemes.Button{
Text: text,
- Type: CONTACT,
+ Type: schemes.CONTACT,
},
}
k.cols = append(k.cols, b)
@@ -72,11 +74,11 @@ func (k *KeyboardRow) AddContact(text string) *KeyboardRow {
//AddGeolocation button
func (k *KeyboardRow) AddGeolocation(text string, quick bool) *KeyboardRow {
- b := RequestGeoLocationButton{
+ b := schemes.RequestGeoLocationButton{
Quick: quick,
- Button: Button{
+ Button: schemes.Button{
Text: text,
- Type: GEOLOCATION,
+ Type: schemes.GEOLOCATION,
},
}
k.cols = append(k.cols, b)
diff --git a/message.go b/message.go
new file mode 100644
index 0000000..20e0ff4
--- /dev/null
+++ b/message.go
@@ -0,0 +1,81 @@
+package tamtam
+
+import "github.com/neonxp/tamtam/schemes"
+
+type Message struct {
+ userID int
+ chatID int
+ message *schemes.NewMessageBody
+}
+
+func NewMessage() *Message {
+ return &Message{userID: 0, chatID: 0, message: &schemes.NewMessageBody{Attachments: []interface{}{}}}
+}
+
+func (m *Message) SetUser(userID int) *Message {
+ m.userID = userID
+ return m
+}
+func (m *Message) SetChat(chatID int) *Message {
+ m.chatID = chatID
+ return m
+}
+
+func (m *Message) SetText(text string) *Message {
+ m.message.Text = text
+ return m
+}
+
+func (m *Message) SetNotify(notify bool) *Message {
+ m.message.Notify = notify
+ return m
+}
+
+func (m *Message) AddKeyboard(keyboard *Keyboard) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewInlineKeyboardAttachmentRequest(keyboard.Build()))
+ return m
+}
+
+func (m *Message) AddPhoto(photo *schemes.PhotoTokens) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewPhotoAttachmentRequest(schemes.PhotoAttachmentRequestPayload{
+ Photos: photo.Photos,
+ }))
+ return m
+}
+
+func (m *Message) AddAudio(audio *schemes.UploadedInfo) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewAudioAttachmentRequest(*audio))
+ return m
+}
+
+func (m *Message) AddVideo(video *schemes.UploadedInfo) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewVideoAttachmentRequest(*video))
+ return m
+}
+
+func (m *Message) AddFile(file *schemes.UploadedInfo) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewFileAttachmentRequest(*file))
+ return m
+}
+
+func (m *Message) AddLocation(lat float64, lon float64) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewLocationAttachmentRequest(lat, lon))
+ return m
+}
+
+func (m *Message) AddContact(name string, contactID int, vcfInfo string, vcfPhone string) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewContactAttachmentRequest(schemes.ContactAttachmentRequestPayload{
+ Name: name,
+ ContactId: contactID,
+ VcfInfo: vcfInfo,
+ VcfPhone: vcfPhone,
+ }))
+ return m
+}
+
+func (m *Message) AddSticker(code string) *Message {
+ m.message.Attachments = append(m.message.Attachments, schemes.NewStickerAttachmentRequest(schemes.StickerAttachmentRequestPayload{
+ Code: code,
+ }))
+ return m
+}
diff --git a/messages.go b/messages.go
index 5131479..7c20e05 100644
--- a/messages.go
+++ b/messages.go
@@ -2,10 +2,13 @@ package tamtam
import (
"encoding/json"
+ "errors"
"log"
"net/http"
"net/url"
"strconv"
+
+ "github.com/neonxp/tamtam/schemes"
)
type messages struct {
@@ -17,8 +20,8 @@ func newMessages(client *client) *messages {
}
//GetMessages returns messages in chat: result page and marker referencing to the next page. Messages traversed in reverse direction so the latest message in chat will be first in result array. Therefore if you use from and to parameters, to must be less than from
-func (a *messages) GetMessages(chatID int, messageIDs []string, from int, to int, count int) (*MessageList, error) {
- result := new(MessageList)
+func (a *messages) GetMessages(chatID int, messageIDs []string, from int, to int, count int) (*schemes.MessageList, error) {
+ result := new(schemes.MessageList)
values := url.Values{}
if chatID != 0 {
values.Set("chat_id", strconv.Itoa(int(chatID)))
@@ -49,17 +52,24 @@ func (a *messages) GetMessages(chatID int, messageIDs []string, from int, to int
return result, json.NewDecoder(body).Decode(result)
}
-//SendMessage sends a message to a chat. As a result for this method new message identifier returns.
-func (a *messages) SendMessage(chatID int, userID int, message *NewMessageBody) (*Message, error) {
- result := new(Message)
- values := url.Values{}
- if chatID != 0 {
- values.Set("chat_id", strconv.Itoa(int(chatID)))
+//EditMessage updates message by id
+func (a *messages) EditMessage(messageID int, message *Message) error {
+ s, err := a.editMessage(messageID, message.message)
+ if err != nil {
+ return err
}
- if userID != 0 {
- values.Set("user_id", strconv.Itoa(int(userID)))
+ if !s.Success {
+ return errors.New(s.Message)
}
- body, err := a.client.request(http.MethodPost, "messages", values, message)
+ return nil
+}
+
+//DeleteMessage deletes message by id
+func (a *messages) DeleteMessage(messageID int) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
+ values := url.Values{}
+ values.Set("message_id", strconv.Itoa(int(messageID)))
+ body, err := a.client.request(http.MethodDelete, "messages", values, nil)
if err != nil {
return result, err
}
@@ -71,12 +81,12 @@ func (a *messages) SendMessage(chatID int, userID int, message *NewMessageBody)
return result, json.NewDecoder(body).Decode(result)
}
-//EditMessage updates message by id
-func (a *messages) EditMessage(messageID int, message *NewMessageBody) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+//AnswerOnCallback should be called to send an answer after a user has clicked the button. The answer may be an updated message or/and a one-time user notification.
+func (a *messages) AnswerOnCallback(callbackID string, callback *schemes.CallbackAnswer) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
- values.Set("message_id", strconv.Itoa(int(messageID)))
- body, err := a.client.request(http.MethodPut, "messages", values, message)
+ values.Set("callback_id", callbackID)
+ body, err := a.client.request(http.MethodPost, "answers", values, callback)
if err != nil {
return result, err
}
@@ -88,29 +98,46 @@ func (a *messages) EditMessage(messageID int, message *NewMessageBody) (*SimpleQ
return result, json.NewDecoder(body).Decode(result)
}
-//DeleteMessage deletes message by id
-func (a *messages) DeleteMessage(messageID int) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+//NewKeyboardBuilder returns new keyboard builder helper
+func (a *messages) NewKeyboardBuilder() *Keyboard {
+ return &Keyboard{
+ rows: make([]*KeyboardRow, 0),
+ }
+}
+
+//Send sends a message to a chat. As a result for this method new message identifier returns.
+func (a *messages) Send(m *Message) error {
+ return a.sendMessage(m.chatID, m.userID, m.message)
+}
+
+func (a *messages) sendMessage(chatID int, userID int, message *schemes.NewMessageBody) error {
+ result := new(schemes.Error)
values := url.Values{}
- values.Set("message_id", strconv.Itoa(int(messageID)))
- body, err := a.client.request(http.MethodDelete, "messages", values, nil)
+ if chatID != 0 {
+ values.Set("chat_id", strconv.Itoa(int(chatID)))
+ }
+ if userID != 0 {
+ values.Set("user_id", strconv.Itoa(int(userID)))
+ }
+ body, err := a.client.request(http.MethodPost, "messages", values, message)
if err != nil {
- return result, err
+ return err
}
- defer func() {
- if err := body.Close(); err != nil {
- log.Println(err)
- }
- }()
- return result, json.NewDecoder(body).Decode(result)
+ defer body.Close()
+ if err := json.NewDecoder(body).Decode(result); err != nil {
+ return err
+ }
+ if result.Code == "" {
+ return nil
+ }
+ return result
}
-//AnswerOnCallback should be called to send an answer after a user has clicked the button. The answer may be an updated message or/and a one-time user notification.
-func (a *messages) AnswerOnCallback(callbackID string, callback *CallbackAnswer) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+func (a *messages) editMessage(messageID int, message *schemes.NewMessageBody) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
- values.Set("callback_id", callbackID)
- body, err := a.client.request(http.MethodPost, "answers", values, callback)
+ values.Set("message_id", strconv.Itoa(int(messageID)))
+ body, err := a.client.request(http.MethodPut, "messages", values, message)
if err != nil {
return result, err
}
@@ -121,10 +148,3 @@ func (a *messages) AnswerOnCallback(callbackID string, callback *CallbackAnswer)
}()
return result, json.NewDecoder(body).Decode(result)
}
-
-//NewKeyboardBuilder returns new keyboard builder helper
-func (a *messages) NewKeyboardBuilder() *KeyboardBuilder {
- return &KeyboardBuilder{
- rows: make([]*KeyboardRow, 0),
- }
-}
diff --git a/models.go b/schemes/schemes.go
index 5870cb9..2f81487 100644
--- a/models.go
+++ b/schemes/schemes.go
@@ -1,4 +1,4 @@
-package tamtam
+package schemes
import (
"encoding/json"
diff --git a/subscriptions.go b/subscriptions.go
index ec97adc..1090183 100644
--- a/subscriptions.go
+++ b/subscriptions.go
@@ -5,6 +5,8 @@ import (
"log"
"net/http"
"net/url"
+
+ "github.com/neonxp/tamtam/schemes"
)
type subscriptions struct {
@@ -16,8 +18,8 @@ func newSubscriptions(client *client) *subscriptions {
}
//GetSubscriptions returns list of all subscriptions
-func (a *subscriptions) GetSubscriptions() (*GetSubscriptionsResult, error) {
- result := new(GetSubscriptionsResult)
+func (a *subscriptions) GetSubscriptions() (*schemes.GetSubscriptionsResult, error) {
+ result := new(schemes.GetSubscriptionsResult)
values := url.Values{}
body, err := a.client.request(http.MethodGet, "subscriptions", values, nil)
if err != nil {
@@ -32,13 +34,13 @@ func (a *subscriptions) GetSubscriptions() (*GetSubscriptionsResult, error) {
}
//Subscribe subscribes bot to receive updates via WebHook
-func (a *subscriptions) Subscribe(subscribeURL string, updateTypes []string) (*SimpleQueryResult, error) {
- subscription := &SubscriptionRequestBody{
+func (a *subscriptions) Subscribe(subscribeURL string, updateTypes []string) (*schemes.SimpleQueryResult, error) {
+ subscription := &schemes.SubscriptionRequestBody{
Url: subscribeURL,
UpdateTypes: updateTypes,
Version: a.client.version,
}
- result := new(SimpleQueryResult)
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
body, err := a.client.request(http.MethodPost, "subscriptions", values, subscription)
if err != nil {
@@ -53,8 +55,8 @@ func (a *subscriptions) Subscribe(subscribeURL string, updateTypes []string) (*S
}
//Unsubscribe unsubscribes bot from receiving updates via WebHook
-func (a *subscriptions) Unsubscribe(subscriptionURL string) (*SimpleQueryResult, error) {
- result := new(SimpleQueryResult)
+func (a *subscriptions) Unsubscribe(subscriptionURL string) (*schemes.SimpleQueryResult, error) {
+ result := new(schemes.SimpleQueryResult)
values := url.Values{}
values.Set("url", subscriptionURL)
body, err := a.client.request(http.MethodDelete, "subscriptions", values, nil)
diff --git a/uploads.go b/uploads.go
index b6f30dc..51b5a40 100644
--- a/uploads.go
+++ b/uploads.go
@@ -9,7 +9,8 @@ import (
"net/http"
"net/url"
"os"
- "path"
+
+ "github.com/neonxp/tamtam/schemes"
)
type uploads struct {
@@ -20,145 +21,106 @@ func newUploads(client *client) *uploads {
return &uploads{client: client}
}
-//GetUploadURL returns url to upload files
-func (a *uploads) GetUploadURL(uploadType UploadType) (*UploadEndpoint, error) {
- result := new(UploadEndpoint)
- values := url.Values{}
- values.Set("type", string(uploadType))
- body, err := a.client.request(http.MethodPost, "uploads", values, nil)
- if err != nil {
- return result, err
- }
- defer func() {
- if err := body.Close(); err != nil {
- log.Println(err)
- }
- }()
- return result, json.NewDecoder(body).Decode(result)
-}
-
//UploadMedia uploads file to TamTam server
-func (a *uploads) UploadMedia(endpoint *UploadEndpoint, filename string) (*UploadedInfo, error) {
- bodyBuf := &bytes.Buffer{}
- bodyWriter := multipart.NewWriter(bodyBuf)
-
- fileWriter, err := bodyWriter.CreateFormFile("data", filename)
- if err != nil {
- return nil, err
- }
-
+func (a *uploads) UploadMediaFromFile(uploadType schemes.UploadType, filename string) (*schemes.UploadedInfo, error) {
fh, err := os.Open(filename)
if err != nil {
return nil, err
}
- defer func() {
- if err := fh.Close(); err != nil {
- log.Println(err)
- }
- }()
- _, err = io.Copy(fileWriter, fh)
- if err != nil {
- return nil, err
- }
-
- if err := bodyWriter.Close(); err != nil {
- return nil, err
- }
- contentType := bodyWriter.FormDataContentType()
- resp, err := http.Post(endpoint.Url, contentType, bodyBuf)
- if err != nil {
- return nil, err
- }
- defer func() {
- if err := resp.Body.Close(); err != nil {
- log.Println(err)
- }
- }()
- result := new(UploadedInfo)
- return result, json.NewDecoder(resp.Body).Decode(result)
+ defer fh.Close()
+ return a.UploadMediaFromReader(uploadType, fh)
}
//UploadMediaFromUrl uploads file from remote server to TamTam server
-func (a *uploads) UploadMediaFromUrl(endpoint *UploadEndpoint, u url.URL) (*UploadedInfo, error) {
+func (a *uploads) UploadMediaFromUrl(uploadType schemes.UploadType, u url.URL) (*schemes.UploadedInfo, error) {
respFile, err := http.Get(u.String())
if err != nil {
return nil, err
}
defer respFile.Body.Close()
- bodyBuf := &bytes.Buffer{}
- bodyWriter := multipart.NewWriter(bodyBuf)
- fileWriter, err := bodyWriter.CreateFormFile("data", path.Base(u.Path))
+ return a.UploadMediaFromReader(uploadType, respFile.Body)
+}
+
+func (a *uploads) UploadMediaFromReader(uploadType schemes.UploadType, reader io.Reader) (*schemes.UploadedInfo, error) {
+ result := new(schemes.UploadedInfo)
+ return result, a.uploadMediaFromReader(uploadType, reader, result)
+}
+
+//UploadPhotoFromFile uploads photos to TamTam server
+func (a *uploads) UploadPhotoFromFile(filename string) (*schemes.PhotoTokens, error) {
+ fh, err := os.Open(filename)
if err != nil {
return nil, err
}
- _, err = io.Copy(fileWriter, respFile.Body)
+ defer fh.Close()
+ result := new(schemes.PhotoTokens)
+ return result, a.uploadMediaFromReader(schemes.PHOTO, fh, result)
+}
+
+//UploadPhotoFromUrl uploads photo from remote server to TamTam server
+func (a *uploads) UploadPhotoFromUrl(u url.URL) (*schemes.PhotoTokens, error) {
+ respFile, err := http.Get(u.String())
if err != nil {
return nil, err
}
+ defer respFile.Body.Close()
+ result := new(schemes.PhotoTokens)
+ return result, a.uploadMediaFromReader(schemes.PHOTO, respFile.Body, result)
+}
- if err := bodyWriter.Close(); err != nil {
- return nil, err
- }
- contentType := bodyWriter.FormDataContentType()
- if err := bodyWriter.Close(); err != nil {
- return nil, err
- }
- resp, err := http.Post(endpoint.Url, contentType, bodyBuf)
+//UploadPhotoFromReader uploads photo from reader
+func (a *uploads) UploadPhotoFromReader(reader io.Reader) (*schemes.PhotoTokens, error) {
+ result := new(schemes.PhotoTokens)
+ return result, a.uploadMediaFromReader(schemes.PHOTO, reader, result)
+}
+
+func (a *uploads) getUploadURL(uploadType schemes.UploadType) (*schemes.UploadEndpoint, error) {
+ result := new(schemes.UploadEndpoint)
+ values := url.Values{}
+ values.Set("type", string(uploadType))
+ body, err := a.client.request(http.MethodPost, "uploads", values, nil)
if err != nil {
- return nil, err
+ return result, err
}
defer func() {
- if err := resp.Body.Close(); err != nil {
+ if err := body.Close(); err != nil {
log.Println(err)
}
}()
- result := new(UploadedInfo)
- return result, json.NewDecoder(resp.Body).Decode(result)
+ return result, json.NewDecoder(body).Decode(result)
}
-//UploadPhoto uploads photos to TamTam server
-func (a *uploads) UploadPhoto(filename string) (*PhotoTokens, error) {
- bodyBuf := &bytes.Buffer{}
- bodyWriter := multipart.NewWriter(bodyBuf)
-
- fileWriter, err := bodyWriter.CreateFormFile("data", filename)
+func (a *uploads) uploadMediaFromReader(uploadType schemes.UploadType, reader io.Reader, result interface{}) error {
+ endpoint, err := a.getUploadURL(uploadType)
if err != nil {
- return nil, err
+ return err
}
-
- fh, err := os.Open(filename)
+ bodyBuf := &bytes.Buffer{}
+ bodyWriter := multipart.NewWriter(bodyBuf)
+ fileWriter, err := bodyWriter.CreateFormFile("data", "file")
if err != nil {
- return nil, err
+ return err
}
- defer func() {
- if err := fh.Close(); err != nil {
- log.Println(err)
- }
- }()
- _, err = io.Copy(fileWriter, fh)
+ _, err = io.Copy(fileWriter, reader)
if err != nil {
- return nil, err
+ return err
}
if err := bodyWriter.Close(); err != nil {
- return nil, err
- }
-
- endpoint, err := a.GetUploadURL(PHOTO)
- if err != nil {
- return nil, err
+ return err
}
contentType := bodyWriter.FormDataContentType()
-
+ if err := bodyWriter.Close(); err != nil {
+ return err
+ }
resp, err := http.Post(endpoint.Url, contentType, bodyBuf)
if err != nil {
- return nil, err
+ return err
}
defer func() {
if err := resp.Body.Close(); err != nil {
log.Println(err)
}
}()
- result := new(PhotoTokens)
- return result, json.NewDecoder(resp.Body).Decode(result)
+ return json.NewDecoder(resp.Body).Decode(result)
}