From 6dcd9b56684369d73d45bcd8bac9d42aef643e2a Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Wed, 29 Aug 2018 02:44:06 +0300 Subject: [PATCH] add initial set of methods --- .gitignore | 1 + .travis.yml | 6 +- README.md | 47 +++- v1/client.go | 369 +++++++++++++++++++++++++++---- v1/client_test.go | 306 +++++++++++++++++++++++++- v1/request.go | 2 +- v1/types.go | 541 ++++++++++++++++++++++++++-------------------- 7 files changed, 998 insertions(+), 274 deletions(-) diff --git a/.gitignore b/.gitignore index d70a5fb..c3ebba8 100644 --- a/.gitignore +++ b/.gitignore @@ -25,5 +25,6 @@ _testmain.go # IDE's files .idea *.iml +.env # Project ignores diff --git a/.travis.yml b/.travis.yml index f39aae2..e7f2fd7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,11 @@ language: go go: - - '1.8' - '1.9' - '1.10' + - '1.11' before_install: - go get -v github.com/google/go-querystring/query - - go get -v github.com/h2non/gock + - go get -v github.com/stretchr/testify/assert + - go get -v github.com/joho/godotenv + script: go test -v ./... diff --git a/README.md b/README.md index 18cdbcb..2a9fc9f 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,45 @@ -# mg-bot-api-client-go -Go client for MG Bot API +[![Build Status](https://img.shields.io/travis/retailcrm/mg-bot-api-client-go/master.svg?style=flat-square)](https://travis-ci.org/retailcrm/mg-bot-api-client-go) +[![GitHub release](https://img.shields.io/github/release/retailcrm/mg-bot-api-client-go.svg?style=flat-square)](https://github.com/retailcrm/mg-bot-api-client-go/releases) +[![GoLang version](https://img.shields.io/badge/GoLang-1.9%2C%201.10%2C%201.11-blue.svg?style=flat-square)](https://golang.org/dl/) + + +# retailCRM Message Gateway Bot API Go client + +## Install + +```bash +go get -u -v github.com/retailcrm/mg-bot-api-client-go +``` + +## Usage + +```golang +package main + +import ( + "fmt" + "net/http" + + "github.com/retailcrm/mg-bot-api-client-go/v1" +) + +func main() { + var client = v1.New("https://token.url", "cb8ccf05e38a47543ad8477d49bcba99be73bff503ea6") + message := MessageSendRequest{ + Scope: "public", + Content: "test", + ChatID: 12, + } + + data, status, err := c.MessageSend(message) + if err != nil { + t.Errorf("%d %v", status, err) + } + + fmt.Printf("%v", data.MessageID) +} +``` + +## Documentation + +* [GoDoc](https://godoc.org/github.com/retailcrm/mg-bot-api-client-go) diff --git a/v1/client.go b/v1/client.go index 17509e7..ddd0c95 100644 --- a/v1/client.go +++ b/v1/client.go @@ -19,8 +19,27 @@ func New(url string, token string) *MgClient { } } -func (c *MgClient) Bots(request BotsRequest) (BotsResponse, int, error) { - var resp BotsResponse +// Bots get all available bots +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Bots() +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, bot := range data { +// fmt.Printf("%v %v\n", bot.Name, bot.CreatedAt) +// } +func (c *MgClient) Bots(request BotsRequest) ([]BotsResponseItem, int, error) { + var resp []BotsResponseItem var b []byte outgoing, _ := query.Values(request) @@ -40,8 +59,27 @@ func (c *MgClient) Bots(request BotsRequest) (BotsResponse, int, error) { return resp, status, err } -func (c *MgClient) Channels(request ChannelsRequest) (ChannelsResponse, int, error) { - var resp ChannelsResponse +// Channels get all available channels +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Channels() +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, channel := range data { +// fmt.Printf("%v %v\n", channel.Type, channel.CreatedAt) +// } +func (c *MgClient) Channels(request ChannelsRequest) ([]ChannelResponseItem, int, error) { + var resp []ChannelResponseItem var b []byte outgoing, _ := query.Values(request) @@ -61,12 +99,31 @@ func (c *MgClient) Channels(request ChannelsRequest) (ChannelsResponse, int, err return resp, status, err } -func (c *MgClient) Managers(request ManagersRequest) (ManagersResponse, int, error) { - var resp ManagersResponse +// Users get all available users +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Users(UsersRequest:{Active:1}) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, user := range data { +// fmt.Printf("%v %v\n", user.FirstName, user.IsOnline) +// } +func (c *MgClient) Users(request UsersRequest) ([]UsersResponseItem, int, error) { + var resp []UsersResponseItem var b []byte outgoing, _ := query.Values(request) - data, status, err := c.GetRequest(fmt.Sprintf("/managers?%s", outgoing.Encode()), b) + data, status, err := c.GetRequest(fmt.Sprintf("/users?%s", outgoing.Encode()), b) if err != nil { return resp, status, err } @@ -82,8 +139,27 @@ func (c *MgClient) Managers(request ManagersRequest) (ManagersResponse, int, err return resp, status, err } -func (c *MgClient) Customers(request CustomersRequest) (CustomersResponse, int, error) { - var resp CustomersResponse +// Customers get all available customers +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Customers() +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, customer := range data { +// fmt.Printf("%v %v\n", customer.FirstName, customer.Avatar) +// } +func (c *MgClient) Customers(request CustomersRequest) ([]CustomersResponseItem, int, error) { + var resp []CustomersResponseItem var b []byte outgoing, _ := query.Values(request) @@ -103,8 +179,27 @@ func (c *MgClient) Customers(request CustomersRequest) (CustomersResponse, int, return resp, status, err } -func (c *MgClient) Chats(request ChatsRequest) (ChatsResponse, int, error) { - var resp ChatsResponse +// Chats get all available chats +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Chats(ChatsRequest{ChannelType:ChannelTypeWhatsapp}) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, chat := range data { +// fmt.Printf("%v %v\n", chat.Customer, chat.LastMessage) +// } +func (c *MgClient) Chats(request ChatsRequest) ([]ChatResponseItem, int, error) { + var resp []ChatResponseItem var b []byte outgoing, _ := query.Values(request) @@ -124,8 +219,27 @@ func (c *MgClient) Chats(request ChatsRequest) (ChatsResponse, int, error) { return resp, status, err } -func (c *MgClient) Members(request MembersRequest) (MembersResponse, int, error) { - var resp MembersResponse +// Members get all available chat members +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Members(MembersRequest{State:ChatMemberStateActive}) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, member := range data { +// fmt.Printf("%v\n", member.CreatedAt) +// } +func (c *MgClient) Members(request MembersRequest) ([]MemberResponseItem, int, error) { + var resp []MemberResponseItem var b []byte outgoing, _ := query.Values(request) @@ -145,8 +259,27 @@ func (c *MgClient) Members(request MembersRequest) (MembersResponse, int, error) return resp, status, err } -func (c *MgClient) Dialogs(request DialogsRequest) (DialogsResponse, int, error) { - var resp DialogsResponse +// Dialogs get all available dialogs +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Dialogs(DialogsRequest{Active:1}) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, dialog := range data { +// fmt.Printf("%v %v\n", dialog.ChatID, dialog.CreatedAt) +// } +func (c *MgClient) Dialogs(request DialogsRequest) ([]DialogResponseItem, int, error) { + var resp []DialogResponseItem var b []byte outgoing, _ := query.Values(request) @@ -170,7 +303,7 @@ func (c *MgClient) DialogAssign(request DialogAssignRequest) (DialogAssignRespon var resp DialogAssignResponse outgoing, _ := json.Marshal(&request) - data, status, err := c.PostRequest(fmt.Sprintf("/dialogs/%s/assign", request.ID), []byte(outgoing)) + data, status, err := c.PatchRequest(fmt.Sprintf("/dialogs/%d/assign", request.DialogID), []byte(outgoing)) if err != nil { return resp, status, err } @@ -186,11 +319,26 @@ func (c *MgClient) DialogAssign(request DialogAssignRequest) (DialogAssignRespon return resp, status, err } -func (c *MgClient) DialogClose(request DialogCloseRequest) (DialogCloseResponse, int, error) { - var resp DialogCloseResponse +// DialogClose close selected dialog +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// _, status, err := client.DialogClose(123) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +func (c *MgClient) DialogClose(request uint64) (map[string]interface{}, int, error) { + var resp map[string]interface{} outgoing, _ := json.Marshal(&request) - data, status, err := c.PostRequest(fmt.Sprintf("/dialogs/%s/close", request.ID), []byte(outgoing)) + data, status, err := c.DeleteRequest(fmt.Sprintf("/dialogs/%d/close", request), []byte(outgoing)) if err != nil { return resp, status, err } @@ -206,8 +354,27 @@ func (c *MgClient) DialogClose(request DialogCloseRequest) (DialogCloseResponse, return resp, status, err } -func (c *MgClient) Messages(request MessagesRequest) (MessagesResponse, int, error) { - var resp MessagesResponse +// Messages get all available messages +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Messages(MessagesRequest{ManagerID:5}) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, message := range data { +// fmt.Printf("%v %v %v\n", message.ChatID, message.CreatedAt, message.CustomerID) +// } +func (c *MgClient) Messages(request MessagesRequest) ([]MessagesResponseItem, int, error) { + var resp []MessagesResponseItem var b []byte outgoing, _ := query.Values(request) @@ -227,8 +394,29 @@ func (c *MgClient) Messages(request MessagesRequest) (MessagesResponse, int, err return resp, status, err } -func (c *MgClient) MessageSend(request MessageSendRequest) (MessageResponse, int, error) { - var resp MessageResponse +// MessageSend send message +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.MessageSend(MessageSendRequest{ +// Scope: "public", +// Content: "test", +// ChatID: i, +// }) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// fmt.Printf("%v \n", data.MessageID, data.Time) +func (c *MgClient) MessageSend(request MessageSendRequest) (MessageSendResponse, int, error) { + var resp MessageSendResponse outgoing, _ := json.Marshal(&request) data, status, err := c.PostRequest("/messages", []byte(outgoing)) @@ -247,11 +435,29 @@ func (c *MgClient) MessageSend(request MessageSendRequest) (MessageResponse, int return resp, status, err } -func (c *MgClient) MessageEdit(request MessageEditRequest) (MessageResponse, int, error) { - var resp MessageResponse +// MessageEdit update selected message +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// _, status, err := client.MessageEdit(MessageEditRequest{ +// ID: 123, +// Content: "test", +// }) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +func (c *MgClient) MessageEdit(request MessageEditRequest) (map[string]interface{}, int, error) { + var resp map[string]interface{} outgoing, _ := json.Marshal(&request) - data, status, err := c.PatchRequest(fmt.Sprintf("/messages/%s", request.ID), []byte(outgoing)) + data, status, err := c.PatchRequest(fmt.Sprintf("/messages/%d", request.ID), []byte(outgoing)) if err != nil { return resp, status, err } @@ -267,11 +473,26 @@ func (c *MgClient) MessageEdit(request MessageEditRequest) (MessageResponse, int return resp, status, err } -func (c *MgClient) MessageDelete(request MessageDeleteRequest) (MessageResponse, int, error) { - var resp MessageResponse +// MessageDelete delete selected message +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// _, status, err := client.MessageDelete(123) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +func (c *MgClient) MessageDelete(request uint64) (map[string]interface{}, int, error) { + var resp map[string]interface{} outgoing, _ := json.Marshal(&request) - data, status, err := c.DeleteRequest(fmt.Sprintf("/messages/%s", request.ID), []byte(outgoing)) + data, status, err := c.DeleteRequest(fmt.Sprintf("/messages/%d", request), []byte(outgoing)) if err != nil { return resp, status, err } @@ -287,11 +508,26 @@ func (c *MgClient) MessageDelete(request MessageDeleteRequest) (MessageResponse, return resp, status, err } -func (c *MgClient) Info(request InfoRequest) (InfoResponse, int, error) { - var resp InfoResponse +// Info updates bot information +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// _, status, err := client.Info(InfoRequest{Name: "AWESOME", Avatar: "https://example.com/logo.svg"}) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +func (c *MgClient) Info(request InfoRequest) (map[string]interface{}, int, error) { + var resp map[string]interface{} outgoing, _ := json.Marshal(&request) - data, status, err := c.PatchRequest("/messages/info", []byte(outgoing)) + data, status, err := c.PatchRequest("/my/info", []byte(outgoing)) if err != nil { return resp, status, err } @@ -307,8 +543,27 @@ func (c *MgClient) Info(request InfoRequest) (InfoResponse, int, error) { return resp, status, err } -func (c *MgClient) Commands(request CommandsRequest) (CommandsResponse, int, error) { - var resp CommandsResponse +// Commands get all available commands for bot +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.Commands() +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// for _, command := range data { +// fmt.Printf("%v %v\n", command.Name, command.Description) +// } +func (c *MgClient) Commands(request CommandsRequest) ([]CommandsResponseItem, int, error) { + var resp []CommandsResponseItem var b []byte outgoing, _ := query.Values(request) @@ -328,8 +583,29 @@ func (c *MgClient) Commands(request CommandsRequest) (CommandsResponse, int, err return resp, status, err } -func (c *MgClient) CommandEdit(request CommandEditRequest) (CommandEditResponse, int, error) { - var resp CommandEditResponse +// CommandEdit create or change command for bot +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// data, status, err := client.CommandEdit(CommandEditRequest{ +// BotID: 1, +// Name: "show_payment_types", +// Description: "Get available payment types", +// }) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +// +// fmt.Printf("%v %v\n", data.Name, data.Description) +func (c *MgClient) CommandEdit(request CommandEditRequest) (CommandsResponseItem, int, error) { + var resp CommandsResponseItem outgoing, _ := json.Marshal(&request) data, status, err := c.PutRequest(fmt.Sprintf("/my/commands/%s", request.Name), []byte(outgoing)) @@ -348,11 +624,26 @@ func (c *MgClient) CommandEdit(request CommandEditRequest) (CommandEditResponse, return resp, status, err } -func (c *MgClient) CommandDelete(request CommandDeleteRequest) (CommandDeleteResponse, int, error) { - var resp CommandDeleteResponse +// CommandDelete delete selected command for bot +// +// Example: +// +// var client = v1.New("https://demo.url", "09jIJ") +// +// _, status, err := client.CommandDelete(show_payment_types) +// +// if err != nil { +// fmt.Printf("%v", err) +// } +// +// if status >= http.StatusBadRequest { +// fmt.Printf("%v", err) +// } +func (c *MgClient) CommandDelete(request string) (map[string]interface{}, int, error) { + var resp map[string]interface{} outgoing, _ := json.Marshal(&request) - data, status, err := c.DeleteRequest(fmt.Sprintf("/my/commands/%s", request.Name), []byte(outgoing)) + data, status, err := c.DeleteRequest(fmt.Sprintf("/my/commands/%s", request), []byte(outgoing)) if err != nil { return resp, status, err } diff --git a/v1/client_test.go b/v1/client_test.go index ef7d324..b641767 100644 --- a/v1/client_test.go +++ b/v1/client_test.go @@ -1,14 +1,318 @@ package v1 import ( + "log" + "net/http" "os" + "strconv" + "testing" + + "github.com/joho/godotenv" + + "github.com/stretchr/testify/assert" ) +func TestMain(m *testing.M) { + if os.Getenv("DEVELOPER_NODE") == "1" { + err := godotenv.Load("../.env") + if err != nil { + log.Fatal("Error loading .env file") + } + + os.Exit(m.Run()) + } +} + var ( mgURL = os.Getenv("MG_URL") - mgToken = os.Getenv("MG_TOKEN") + mgToken = os.Getenv("MG_BOT_TOKEN") ) func client() *MgClient { return New(mgURL, mgToken) } + +func TestMgClient_Bots(t *testing.T) { + c := client() + req := BotsRequest{Active: 1} + + data, status, err := c.Bots(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, bot := range data { + assert.NotEmpty(t, bot.CreatedAt) + } +} + +func TestMgClient_Channels(t *testing.T) { + c := client() + req := ChannelsRequest{Active: 1} + + data, status, err := c.Channels(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, channel := range data { + assert.NotEmpty(t, channel.Type) + } +} + +func TestMgClient_Users(t *testing.T) { + c := client() + req := UsersRequest{Active: 1} + + data, status, err := c.Users(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, user := range data { + assert.NotEmpty(t, user.FirstName) + } +} + +func TestMgClient_Customers(t *testing.T) { + c := client() + req := CustomersRequest{} + + data, status, err := c.Customers(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, customer := range data { + assert.NotEmpty(t, customer.ChannelId) + } +} + +func TestMgClient_Chats(t *testing.T) { + c := client() + req := ChatsRequest{ChannelType: ChannelTypeTelegram} + + data, status, err := c.Chats(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, chat := range data { + assert.NotEmpty(t, chat.Customer.Name) + } +} + +func TestMgClient_Members(t *testing.T) { + c := client() + req := MembersRequest{State: ChatMemberStateLeaved} + + data, status, err := c.Members(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, member := range data { + assert.NotEmpty(t, member.ChatID) + } +} + +func TestMgClient_Dialogs(t *testing.T) { + c := client() + req := DialogsRequest{Active: 0} + + data, status, err := c.Dialogs(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, dialog := range data { + assert.NotEmpty(t, dialog.ChatID) + } +} + +func TestMgClient_DialogAssign(t *testing.T) { + c := client() + i, err := strconv.ParseUint(os.Getenv("MG_BOT_DIALOG"), 10, 64) + m, err := strconv.ParseUint(os.Getenv("MG_BOT_USER"), 10, 64) + req := DialogAssignRequest{DialogID: i, ManagerID: m} + + _, status, err := c.DialogAssign(req) + + assert.Error(t, err) + assert.Equal(t, http.StatusBadRequest, status) +} + +func TestMgClient_DialogClose(t *testing.T) { + c := client() + i, err := strconv.ParseUint(os.Getenv("MG_BOT_DIALOG"), 10, 64) + _, status, err := c.DialogClose(i) + + assert.Error(t, err) + assert.Equal(t, http.StatusBadRequest, status) +} + +func TestMgClient_Messages(t *testing.T) { + c := client() + req := MessagesRequest{ChannelType: ChannelTypeTelegram, Scope: MessageScopePublic} + + data, status, err := c.Messages(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, message := range data { + assert.NotEmpty(t, message.Content) + } +} + +func TestMgClient_MessageSend(t *testing.T) { + c := client() + i, err := strconv.ParseUint(os.Getenv("MG_BOT_CHAT"), 10, 64) + message := MessageSendRequest{ + Scope: "public", + Content: "test", + ChatID: i, + } + + data, status, err := c.MessageSend(message) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data.MessageID) +} + +func TestMgClient_MessageEdit(t *testing.T) { + c := client() + i, err := strconv.ParseUint(os.Getenv("MG_BOT_CHAT"), 10, 64) + message := MessageSendRequest{ + Scope: "public", + Content: "test", + ChatID: i, + } + + s, status, err := c.MessageSend(message) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, s.MessageID) + + edit := MessageEditRequest{ + ID: s.MessageID, + Content: "test", + } + + e, status, err := c.MessageEdit(edit) + if err != nil { + t.Errorf("%d %v", status, err) + } + + t.Logf("Message edit: %v", e) +} + +func TestMgClient_MessageDelete(t *testing.T) { + c := client() + i, err := strconv.ParseUint(os.Getenv("MG_BOT_CHAT"), 10, 64) + message := MessageSendRequest{ + Scope: "public", + Content: "test", + ChatID: i, + } + + s, status, err := c.MessageSend(message) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, s.MessageID) + + d, status, err := c.MessageDelete(s.MessageID) + if err != nil { + t.Errorf("%d %v", status, err) + } + + t.Logf("Message delete: %v", d) +} + +func TestMgClient_Info(t *testing.T) { + c := client() + req := InfoRequest{Name: "AWESOME", Avatar: os.Getenv("MG_BOT_LOGO")} + + _, status, err := c.Info(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) +} + +func TestMgClient_Commands(t *testing.T) { + c := client() + req := CommandsRequest{} + + data, status, err := c.Commands(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, data) + + for _, command := range data { + assert.NotEmpty(t, command.Description) + } +} + +func TestMgClient_CommandEditDelete(t *testing.T) { + c := client() + i, err := strconv.ParseUint(os.Getenv("MG_BOT_ID"), 10, 64) + req := CommandEditRequest{ + BotID: i, + Name: "show_payment_types", + Description: "Get available payment types", + } + + n, status, err := c.CommandEdit(req) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + assert.NotEmpty(t, n.ID) + + d, status, err := c.CommandDelete(n.Name) + if err != nil { + t.Errorf("%d %v", status, err) + } + + assert.NoError(t, err) + t.Logf("%v", d) +} diff --git a/v1/request.go b/v1/request.go index 9712d96..54f298e 100644 --- a/v1/request.go +++ b/v1/request.go @@ -8,7 +8,7 @@ import ( "net/http" ) -var prefix = "/api/v1" +var prefix = "/api/bot/v1" // GetRequest implements GET Request func (c *MgClient) GetRequest(url string, parameters []byte) ([]byte, int, error) { diff --git a/v1/types.go b/v1/types.go index 76d7aa4..beea0d3 100644 --- a/v1/types.go +++ b/v1/types.go @@ -4,6 +4,37 @@ import ( "net/http" ) +const ( + ChannelTypeTelegram string = "telegram" + ChannelTypeFacebook string = "fbmessenger" + ChannelTypeViber string = "viber" + ChannelTypeWhatsapp string = "whatsapp" + ChannelTypeSkype string = "skype" + ChannelTypeVk string = "vk" + ChannelTypeInstagram string = "instagram" + ChannelTypeConsultant string = "consultant" + ChannelTypeCustom string = "custom" + + ChatMemberStateActive string = "active" + ChatMemberStateKicked string = "kicked" + ChatMemberStateLeaved string = "leaved" + + MessageScopePublic string = "public" + MessageScopePrivate string = "private" + + BotEventMessageNew string = "message_new" + BotEventMessageUpdated string = "message_updated" + BotEventMessageDeleted string = "message_deleted" + BotEventDialogOpened string = "dialog_opened" + BotEventDialogClosed string = "dialog_closed" + BotEventDialogAssing string = "dialog_assign" + BotEventChatCreated string = "chat_created" + BotEventChatUpdated string = "chat_updated" + BotEventUserJoined string = "user_joined_chat" + BotEventUserLeave string = "user_left_chat" + BotEventUserUpdated string = "user_updated" +) + // MgClient type type MgClient struct { URL string `json:"url"` @@ -12,264 +43,316 @@ type MgClient struct { httpClient *http.Client } -type BotsRequest struct { - ID uint64 - Self string - Active string - Since string - Until string -} +// Request types +type ( + BotsRequest struct { + ID uint64 `url:"id,omitempty"` + Self bool `url:"self,omitempty"` + Active uint8 `url:"active,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type ChannelsRequest struct { - ID uint64 - Types string - Active string - Since string - Until string -} + ChannelsRequest struct { + ID uint64 `url:"id,omitempty"` + Types string `url:"types,omitempty"` + Active uint8 `url:"active,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type ManagersRequest struct { - ID uint64 - ExternalID string `json:"external_id"` - Online string - Active string - Since string - Until string -} + UsersRequest struct { + ID uint64 `url:"id,omitempty"` + ExternalID string `url:"external_id,omitempty" json:"external_id"` + Online uint8 `url:"online,omitempty"` + Active uint8 `url:"active,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type CustomersRequest struct { - ID uint64 - ExternalID string `json:"external_id"` - Since string - Until string -} + CustomersRequest struct { + ID uint64 `url:"id,omitempty"` + ExternalID string `url:"external_id,omitempty" json:"external_id"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type ChatsRequest struct { - ID uint64 - ChannelID string `json:"channel_id"` - ChannelType string `json:"channel_type"` - Since string - Until string -} + ChatsRequest struct { + ID uint64 `url:"id,omitempty"` + ChannelID uint64 `url:"channel_id,omitempty" json:"channel_id"` + ChannelType string `url:"channel_type,omitempty" json:"channel_type"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type MembersRequest struct { - ChatID string `json:"chat_id"` - ManagerID string `json:"manager_id"` - CustomerID string `json:"customer_id"` - Status string - Since string - Until string -} + MembersRequest struct { + ChatID uint64 `url:"chat_id,omitempty" json:"chat_id"` + ManagerID string `url:"manager_id,omitempty" json:"manager_id"` + CustomerID string `url:"customer_id,omitempty" json:"customer_id"` + State string `url:"state,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type DialogsRequest struct { - ID uint64 - ChatID string `json:"chat_id"` - ManagerID string `json:"manager_id"` - BotID string `json:"bot_id"` - Active string - Assigned string - Since string - Until string -} + DialogsRequest struct { + ID uint64 `url:"id,omitempty"` + ChatID string `url:"chat_id,omitempty" json:"chat_id"` + ManagerID string `url:"manager_id,omitempty" json:"manager_id"` + BotID string `url:"bot_id,omitempty" json:"bot_id"` + Assigned uint8 `url:"assigned,omitempty"` + Active uint8 `url:"active,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type MessagesRequest struct { - ID uint64 - ChatID string `json:"chat_id"` - DialogID string `json:"dialog_id"` - ManagerID string `json:"manager_id"` - CustomerID string `json:"customer_id"` - BotID string `json:"bot_id"` - ChannelID string `json:"channel_id"` - ChannelType string `json:"channel_type"` - Scope string - Since string - Until string -} + DialogAssignRequest struct { + DialogID uint64 `url:"dialog_id,omitempty" json:"dialog_id"` + ManagerID uint64 `url:"manager_id,omitempty" json:"manager_id"` + BotID uint64 `url:"bot_id,omitempty" json:"bot_id"` + } -type MessageSendRequest struct { - Content string `json:"content"` - Scope uint8 `json:"scope"` - ChatID uint64 `json:"chat_id"` - QuoteMessageId uint64 `json:"omitempty,quote_message_id"` -} + MessagesRequest struct { + ID uint64 `url:"id,omitempty"` + ChatID uint64 `url:"chat_id,omitempty" json:"chat_id"` + DialogID uint64 `url:"dialog_id,omitempty" json:"dialog_id"` + ManagerID uint64 `url:"manager_id,omitempty" json:"manager_id"` + CustomerID uint64 `url:"customer_id,omitempty" json:"customer_id"` + BotID uint64 `url:"bot_id,omitempty" json:"bot_id"` + ChannelID uint64 `url:"channel_id,omitempty" json:"channel_id"` + ChannelType string `url:"channel_type,omitempty" json:"channel_type"` + Scope string `url:"scope,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type MessageEditRequest struct { - ID uint64 - Content string `json:"content"` -} + MessageSendRequest struct { + Content string `url:"content,omitempty" json:"content"` + Scope string `url:"scope,omitempty" json:"scope"` + ChatID uint64 `url:"chat_id,omitempty" json:"chat_id"` + QuoteMessageId uint64 `url:"quote_message_id,omitempty" json:"quote_message_id"` + } -type CommandsRequest struct { - ID string - Name string - Since string - Until string -} + MessageEditRequest struct { + ID uint64 `url:"id,omitempty"` + Content string `url:"content,omitempty" json:"content"` + } -type BotsResponse struct { - Bots []BotListItem -} + InfoRequest struct { + Name string `url:"name,omitempty" json:"name"` + Avatar string `url:"avatar_url,omitempty" json:"avatar_url"` + Events []string `url:"events,omitempty" json:"events,brackets"` + } -type BotListItem struct { - ID uint64 `json:"id"` - Name string `json:"name"` - Description string `json:"description"` - Events []string `json:"events,omitempty,brackets"` - ClientID string `json:"client_id"` - AvatarUrl string `json:"avatar_url"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at"` - DeactivatedAt *string `json:"deactivated_at"` - IsActive bool `json:"is_active"` - IsSelf bool `json:"is_self"` -} + CommandsRequest struct { + ID uint64 `url:"id,omitempty"` + Name string `url:"name,omitempty"` + Since string `url:"since,omitempty"` + Until string `url:"until,omitempty"` + } -type ChannelsResponse struct { - Channels []ChannelListItem -} + CommandEditRequest struct { + BotID uint64 `url:"bot_id,omitempty" json:"bot_id"` + Name string `url:"name,omitempty" json:"name"` + Description string `url:"description,omitempty" json:"description"` + } +) -type ChannelListItem struct { - ID uint64 `json:"id"` - Type string `json:"type"` - Events []string `json:"events,omitempty,brackets"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at"` - ActivatedAt string `json:"activated_at"` - DeactivatedAt *string `json:"deactivated_at"` - IsActive bool `json:"is_active"` -} +// Response types +type ( + BotsResponseItem struct { + ID uint64 `json:"id"` + Name string `json:"name"` + Description string `json:"description,omitempty"` + Events []string `json:"events,omitempty,brackets"` + ClientID string `json:"client_id,omitempty"` + AvatarUrl string `json:"avatar_url,omitempty"` + CreatedAt string `json:"created_at,omitempty"` + UpdatedAt string `json:"updated_at,omitempty"` + DeactivatedAt string `json:"deactivated_at,omitempty"` + IsActive bool `json:"is_active"` + IsSelf bool `json:"is_self"` + } -type ManagersResponse struct { - Managers []ManagersListItem -} + ChannelResponseItem struct { + ID uint64 `json:"id"` + Type string `json:"type"` + Events []string `json:"events,omitempty,brackets"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + ActivatedAt string `json:"activated_at"` + DeactivatedAt string `json:"deactivated_at"` + IsActive bool `json:"is_active"` + } -type ManagersListItem struct { - ID uint64 `json:"id"` - ExternalID *string `json:"external_id,omitempty"` - Username *string `json:"username,omitempty"` - FirstName *string `json:"first_name,omitempty"` - LastName *string `json:"last_name,omitempty"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at,omitempty"` - RevokedAt *string `json:"revoked_at,omitempty"` - IsOnline bool `json:"is_online"` - IsActive bool `json:"is_active"` - Avatar *string `json:"avatar_url,omitempty"` -} + UsersResponseItem struct { + ID uint64 `json:"id"` + ExternalID string `json:"external_id,omitempty"` + Username string `json:"username,omitempty"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at,omitempty"` + RevokedAt string `json:"revoked_at,omitempty"` + IsOnline bool `json:"is_online"` + IsActive bool `json:"is_active"` + Avatar string `json:"avatar_url,omitempty"` + } -type CustomersResponse struct { - Customers []CustomersListItem -} + CustomersResponseItem struct { + ID uint64 `json:"id"` + ExternalID string `json:"external_id,omitempty"` + ChannelId uint64 `json:"channel_id,omitempty"` + Username string `json:"username,omitempty"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at,omitempty"` + RevokedAt string `json:"revoked_at,omitempty"` + Avatar string `json:"avatar_url,omitempty"` + ProfileURL string `json:"profile_url,omitempty"` + Country string `json:"country,omitempty"` + Language string `json:"language,omitempty"` + Phone string `json:"phone,omitempty"` + } -type CustomersListItem struct { - ID uint64 `json:"id"` - ExternalID *string `json:"external_id,omitempty"` - ChannelId *uint64 `json:"channel_id,omitempty"` - Username *string `json:"username,omitempty"` - FirstName *string `json:"first_name,omitempty"` - LastName *string `json:"last_name,omitempty"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at,omitempty"` - RevokedAt *string `json:"revoked_at,omitempty"` - Avatar *string `json:"avatar_url,omitempty"` - ProfileURL *string `json:"profile_url,omitempty"` - Country *string `json:"country,omitempty"` - Language *string `json:"language,omitempty"` - Phone *string `json:"phone,omitempty"` -} + ChatResponseItem struct { + ID uint64 `json:"id"` + Avatar string `json:"avatar"` + Name string `json:"name"` + Channel Channel `json:"channel,omitempty"` + Customer UserRef `json:"customer"` + AuthorID uint64 `json:"author_id"` + LastMessage Message `json:"last_message"` + LastActivity string `json:"last_activity"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + } -type ChatsResponse struct { - Chats []ChatListItem -} + MemberResponseItem struct { + ID uint64 `json:"id"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at,omitempty"` + IsAuthor bool `json:"is_author"` + State string `json:"state"` + ChatID uint64 `json:"chat_id"` + UserID uint64 `json:"user_id"` + } -type ChatListItem struct { - ID uint64 `json:"id"` - CreatedAt string `json:"created_at"` - UpdatedAt string `json:"updated_at"` - Channel *string `json:"channel,omitempty"` - ChannelId *uint64 `json:"channel_id,omitempty"` -} + DialogResponseItem struct { + ID uint64 `json:"id"` + ChatID uint64 `json:"chat_id"` + BeginMessageID uint64 `json:"begin_message_id,omitempty"` + EndingMessageID uint64 `json:"ending_message_id,omitempty"` + BotID uint64 `json:"bot_id,omitempty"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at,omitempty"` + ClosedAt string `json:"closed_at,omitempty"` + IsAssigned bool `json:"is_assigned"` + Responsible Responsible `json:"responsible,omitempty"` + IsActive bool `json:"is_active"` + } -type MembersResponse struct { - Members []MemberListItem -} + DialogAssignResponse struct { + Responsible Responsible `json:"responsible"` + PreviousResponsible Responsible `json:"previous_responsible,omitempty"` + LeftManagerID uint64 `json:"left_manager_id,omitempty"` + IsReAssign bool `json:"is_reassign"` + } -type MemberListItem struct { - ID uint64 `json:"id"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at,omitempty"` - IsAuthor bool `json:"is_author"` - State string `json:"state"` - ChatID uint64 `json:"chat_id"` - UserID uint64 `json:"user_id"` -} + MessagesResponseItem struct { + Message + ChannelID uint64 `json:"channel_id,omitempty"` + ChannelSentAt string `json:"channel_sent_at,omitempty"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at"` + } -type DialogsResponse struct { - Dialogs []DialogListItem -} + MessageSendResponse struct { + MessageID uint64 `json:"message_id"` + Time string `json:"time"` + } -type DialogListItem struct { - ID uint64 `json:"id"` - ChatID uint64 `json:"chat_id"` - BotID *uint64 `json:"bot_id,omitempty"` - BeginMessageID *uint64 `json:"begin_message_id,omitempty"` - EndingMessageID *uint64 `json:"ending_message_id,omitempty"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at,omitempty"` - ClosedAt *string `json:"closed_at,omitempty"` - IsAssign bool `json:"is_assign"` - Responsible *Responsible `json:"responsible,omitempty"` - IsActive bool `json:"is_active"` -} + CommandsResponseItem struct { + ID uint64 `json:"id"` + Name string `json:"name"` + Description string `json:"description"` + CreatedAt string `json:"created_at"` + UpdatedAt string `json:"updated_at,omitempty"` + } +) -type MessagesResponse struct { - Messages []MessagesListItem -} +// Single entity types +type ( + Message struct { + ID uint64 `json:"id"` + Time string `json:"time"` + Type string `json:"type"` + ChatID uint64 `json:"chat_id"` + IsRead bool `json:"is_read"` + Status string `json:"status"` + TextMessage + SystemMessage + } -type MessagesListItem struct { - ID uint64 `json:"id"` - Content string `json:"content"` - CreatedAt string `json:"created_at"` - UpdatedAt *string `json:"updated_at"` - Scope uint8 `json:"scope"` - ChatID uint64 `json:"chat_id"` - Sender Sender `json:"sender"` - ChannelID *uint64 `json:"channel_id,omitempty"` - ChannelSentAt *string `json:"channel_sent_at,omitempty"` - QuoteMessageId *uint64 `json:"quote_message_id,omitempty"` - EditedAt *string `json:"edited_at,omitempty"` - DeletedAt *string `json:"deleted_at,omitempty"` -} + TextMessage struct { + Scope string `json:"scope"` + Content string `json:"content"` + From UserRef `json:"from"` + Quote QuoteMessage `json:"quote"` + IsEdit bool `json:"is_edit"` + Actions []string `json:"actions"` + } -type MessageResponse struct { - ID uint64 `json:"id"` - Time string `json:"content"` -} + SystemMessage struct { + Action string `json:"action"` + Dialog SystemMessageDialog `json:"dialog,omitempty"` + User UserRef `json:"user,omitempty"` + } -type UpdateBotRequest struct { - Name string `json:"name,omitempty"` - Avatar *string `json:"avatar_url"` - Events []string `json:"events,omitempty,brackets"` -} + SystemMessageDialog struct { + ID uint64 `json:"id"` + } -type Responsible struct { - Type string `json:"type"` - ID int64 `json:"id"` - AssignAt string `json:"assign_at"` -} + QuoteMessage struct { + ID uint64 `json:"id"` + Content string `json:"content"` + Time string `json:"time"` + From UserRef `json:"from"` + } -type DialogResponsibleRequest struct { - ManagerID int64 `json:"manager_id"` - BotID int64 `json:"bot_id"` -} + UserRef struct { + ID uint64 `json:"id"` + Avatar string `json:"avatar"` + Type string `json:"type"` + Name string `json:"name"` + Phone string `json:"phone,omitempty"` + Email string `json:"email,omitempty"` + } -type AssignResponse struct { - Responsible Responsible `json:"responsible"` - IsReAssign bool `json:"is_reassign"` - PreviousResponsible *Responsible `json:"previous_responsible,omitempty"` - LeftManagerID *uint64 `json:"left_manager_id,omitempty"` -} + Channel struct { + ID uint64 `json:"id"` + TransportID uint64 `json:"transport_id"` + Type string `json:"type"` + Supports ChannelSupports `json:"supports"` + } -type Sender struct { - ID int64 - Type string -} + ChannelSupports struct { + Messages []string `json:"messages"` + Statuses []string `json:"statuses"` + } + + Responsible struct { + ID int64 `json:"id"` + Type string `json:"type"` + AssignAt string `json:"assigned_at"` + } + + Command struct { + ID uint64 + BotID uint64 + Name string + Description string + CreatedAt string + UpdatedAt string + } +)