From 663c1f999c4aef603d57e18cd4c5b4fe41d31ebd Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Fri, 3 Aug 2018 18:11:37 +0300 Subject: [PATCH 1/2] initial client structure --- .gitignore | 29 ++++ .travis.yml | 9 ++ v1/client.go | 381 ++++++++++++++++++++++++++++++++++++++++++++++ v1/client_test.go | 14 ++ v1/request.go | 108 +++++++++++++ v1/types.go | 275 +++++++++++++++++++++++++++++++++ 6 files changed, 816 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 v1/client.go create mode 100644 v1/client_test.go create mode 100644 v1/request.go create mode 100644 v1/types.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d70a5fb --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof + +# IDE's files +.idea +*.iml + +# Project ignores diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..f39aae2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: go +go: + - '1.8' + - '1.9' + - '1.10' +before_install: + - go get -v github.com/google/go-querystring/query + - go get -v github.com/h2non/gock +script: go test -v ./... diff --git a/v1/client.go b/v1/client.go new file mode 100644 index 0000000..17509e7 --- /dev/null +++ b/v1/client.go @@ -0,0 +1,381 @@ +package v1 + +import ( + "encoding/json" + "errors" + "fmt" + "net/http" + "time" + + "github.com/google/go-querystring/query" +) + +// New initialize client +func New(url string, token string) *MgClient { + return &MgClient{ + URL: url, + Token: token, + httpClient: &http.Client{Timeout: 20 * time.Second}, + } +} + +func (c *MgClient) Bots(request BotsRequest) (BotsResponse, int, error) { + var resp BotsResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/bots?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Channels(request ChannelsRequest) (ChannelsResponse, int, error) { + var resp ChannelsResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/channels?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Managers(request ManagersRequest) (ManagersResponse, int, error) { + var resp ManagersResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/managers?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Customers(request CustomersRequest) (CustomersResponse, int, error) { + var resp CustomersResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/customers?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Chats(request ChatsRequest) (ChatsResponse, int, error) { + var resp ChatsResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/chats?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Members(request MembersRequest) (MembersResponse, int, error) { + var resp MembersResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/members?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Dialogs(request DialogsRequest) (DialogsResponse, int, error) { + var resp DialogsResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/dialogs?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) DialogAssign(request DialogAssignRequest) (DialogAssignResponse, int, error) { + var resp DialogAssignResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.PostRequest(fmt.Sprintf("/dialogs/%s/assign", request.ID), []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) DialogClose(request DialogCloseRequest) (DialogCloseResponse, int, error) { + var resp DialogCloseResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.PostRequest(fmt.Sprintf("/dialogs/%s/close", request.ID), []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Messages(request MessagesRequest) (MessagesResponse, int, error) { + var resp MessagesResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/messages?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) MessageSend(request MessageSendRequest) (MessageResponse, int, error) { + var resp MessageResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.PostRequest("/messages", []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) MessageEdit(request MessageEditRequest) (MessageResponse, int, error) { + var resp MessageResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.PatchRequest(fmt.Sprintf("/messages/%s", request.ID), []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) MessageDelete(request MessageDeleteRequest) (MessageResponse, int, error) { + var resp MessageResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.DeleteRequest(fmt.Sprintf("/messages/%s", request.ID), []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Info(request InfoRequest) (InfoResponse, int, error) { + var resp InfoResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.PatchRequest("/messages/info", []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Commands(request CommandsRequest) (CommandsResponse, int, error) { + var resp CommandsResponse + var b []byte + outgoing, _ := query.Values(request) + + data, status, err := c.GetRequest(fmt.Sprintf("/my/commands?%s", outgoing.Encode()), b) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) CommandEdit(request CommandEditRequest) (CommandEditResponse, int, error) { + var resp CommandEditResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.PutRequest(fmt.Sprintf("/my/commands/%s", request.Name), []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) CommandDelete(request CommandDeleteRequest) (CommandDeleteResponse, int, error) { + var resp CommandDeleteResponse + outgoing, _ := json.Marshal(&request) + + data, status, err := c.DeleteRequest(fmt.Sprintf("/my/commands/%s", request.Name), []byte(outgoing)) + if err != nil { + return resp, status, err + } + + if err := json.Unmarshal(data, &resp); err != nil { + return resp, status, err + } + + if status > http.StatusCreated || status < http.StatusOK { + return resp, status, c.Error(data) + } + + return resp, status, err +} + +func (c *MgClient) Error(info []byte) error { + var data map[string]interface{} + + if err := json.Unmarshal(info, &data); err != nil { + return err + } + + values := data["errors"].([]interface{}) + + return errors.New(values[0].(string)) +} diff --git a/v1/client_test.go b/v1/client_test.go new file mode 100644 index 0000000..ef7d324 --- /dev/null +++ b/v1/client_test.go @@ -0,0 +1,14 @@ +package v1 + +import ( + "os" +) + +var ( + mgURL = os.Getenv("MG_URL") + mgToken = os.Getenv("MG_TOKEN") +) + +func client() *MgClient { + return New(mgURL, mgToken) +} diff --git a/v1/request.go b/v1/request.go new file mode 100644 index 0000000..9712d96 --- /dev/null +++ b/v1/request.go @@ -0,0 +1,108 @@ +package v1 + +import ( + "bytes" + "fmt" + "io/ioutil" + "log" + "net/http" +) + +var prefix = "/api/v1" + +// GetRequest implements GET Request +func (c *MgClient) GetRequest(url string, parameters []byte) ([]byte, int, error) { + return makeRequest( + "GET", + fmt.Sprintf("%s%s%s", c.URL, prefix, url), + bytes.NewBuffer(parameters), + c, + ) +} + +// PostRequest implements POST Request +func (c *MgClient) PostRequest(url string, parameters []byte) ([]byte, int, error) { + return makeRequest( + "POST", + fmt.Sprintf("%s%s%s", c.URL, prefix, url), + bytes.NewBuffer(parameters), + c, + ) +} + +// PatchRequest implements PATCH Request +func (c *MgClient) PatchRequest(url string, parameters []byte) ([]byte, int, error) { + return makeRequest( + "PATCH", + fmt.Sprintf("%s%s%s", c.URL, prefix, url), + bytes.NewBuffer(parameters), + c, + ) +} + +// PutRequest implements PUT Request +func (c *MgClient) PutRequest(url string, parameters []byte) ([]byte, int, error) { + return makeRequest( + "PUT", + fmt.Sprintf("%s%s%s", c.URL, prefix, url), + bytes.NewBuffer(parameters), + c, + ) +} + +// DeleteRequest implements DELETE Request +func (c *MgClient) DeleteRequest(url string, parameters []byte) ([]byte, int, error) { + return makeRequest( + "DELETE", + fmt.Sprintf("%s%s%s", c.URL, prefix, url), + bytes.NewBuffer(parameters), + c, + ) +} + +func makeRequest(reqType, url string, buf *bytes.Buffer, c *MgClient) ([]byte, int, error) { + var res []byte + req, err := http.NewRequest(reqType, url, buf) + if err != nil { + return res, 0, err + } + + req.Header.Set("Content-Type", "application/json") + req.Header.Set("X-Bot-Token", c.Token) + + if c.Debug { + log.Printf("MG BOT API Request: %s %s %s %s", reqType, url, c.Token, buf.String()) + } + + resp, err := c.httpClient.Do(req) + if err != nil { + return res, 0, err + } + + if resp.StatusCode >= http.StatusInternalServerError { + err = fmt.Errorf("http request error. Status code: %d", resp.StatusCode) + return res, resp.StatusCode, err + } + + res, err = buildRawResponse(resp) + if err != nil { + return res, 0, err + } + + if c.Debug { + log.Printf("MG BOT API Response: %s", res) + } + + return res, resp.StatusCode, err +} + +func buildRawResponse(resp *http.Response) ([]byte, error) { + defer resp.Body.Close() + + res, err := ioutil.ReadAll(resp.Body) + if err != nil { + return res, err + } + + return res, nil +} diff --git a/v1/types.go b/v1/types.go new file mode 100644 index 0000000..76d7aa4 --- /dev/null +++ b/v1/types.go @@ -0,0 +1,275 @@ +package v1 + +import ( + "net/http" +) + +// MgClient type +type MgClient struct { + URL string `json:"url"` + Token string `json:"token"` + Debug bool `json:"debug"` + httpClient *http.Client +} + +type BotsRequest struct { + ID uint64 + Self string + Active string + Since string + Until string +} + +type ChannelsRequest struct { + ID uint64 + Types string + Active string + Since string + Until string +} + +type ManagersRequest struct { + ID uint64 + ExternalID string `json:"external_id"` + Online string + Active string + Since string + Until string +} + +type CustomersRequest struct { + ID uint64 + ExternalID string `json:"external_id"` + Since string + Until string +} + +type ChatsRequest struct { + ID uint64 + ChannelID string `json:"channel_id"` + ChannelType string `json:"channel_type"` + Since string + Until string +} + +type MembersRequest struct { + ChatID string `json:"chat_id"` + ManagerID string `json:"manager_id"` + CustomerID string `json:"customer_id"` + Status string + Since string + Until string +} + +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 +} + +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 +} + +type MessageSendRequest struct { + Content string `json:"content"` + Scope uint8 `json:"scope"` + ChatID uint64 `json:"chat_id"` + QuoteMessageId uint64 `json:"omitempty,quote_message_id"` +} + +type MessageEditRequest struct { + ID uint64 + Content string `json:"content"` +} + +type CommandsRequest struct { + ID string + Name string + Since string + Until string +} + +type BotsResponse struct { + Bots []BotListItem +} + +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"` +} + +type ChannelsResponse struct { + Channels []ChannelListItem +} + +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"` +} + +type ManagersResponse struct { + Managers []ManagersListItem +} + +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"` +} + +type CustomersResponse struct { + Customers []CustomersListItem +} + +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"` +} + +type ChatsResponse struct { + Chats []ChatListItem +} + +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"` +} + +type MembersResponse struct { + Members []MemberListItem +} + +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"` +} + +type DialogsResponse struct { + Dialogs []DialogListItem +} + +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"` +} + +type MessagesResponse struct { + Messages []MessagesListItem +} + +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"` +} + +type MessageResponse struct { + ID uint64 `json:"id"` + Time string `json:"content"` +} + +type UpdateBotRequest struct { + Name string `json:"name,omitempty"` + Avatar *string `json:"avatar_url"` + Events []string `json:"events,omitempty,brackets"` +} + +type Responsible struct { + Type string `json:"type"` + ID int64 `json:"id"` + AssignAt string `json:"assign_at"` +} + +type DialogResponsibleRequest struct { + ManagerID int64 `json:"manager_id"` + BotID int64 `json:"bot_id"` +} + +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"` +} + +type Sender struct { + ID int64 + Type string +} From 6dcd9b56684369d73d45bcd8bac9d42aef643e2a Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Wed, 29 Aug 2018 02:44:06 +0300 Subject: [PATCH 2/2] 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 + } +)