1
0
mirror of synced 2024-11-24 05:56:04 +03:00

Mock data in tests (#76)

* mock all data in tests
* update test matrix config
This commit is contained in:
Pavel 2021-11-22 16:08:53 +03:00 committed by GitHub
parent b5df3a70bc
commit 1306d648f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 481 additions and 347 deletions

View File

@ -10,9 +10,6 @@ on:
env: env:
GO111MODULE: on GO111MODULE: on
MG_URL: ${{ secrets.MG_URL }}
MG_TOKEN: ${{ secrets.MG_TOKEN }}
MG_CHANNEL: ${{ secrets.MG_CHANNEL }}
jobs: jobs:
golangci: golangci:
@ -31,9 +28,8 @@ jobs:
name: Tests name: Tests
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
max-parallel: 1
matrix: matrix:
go-version: ['1.11', '1.12', '1.13', '1.14', '1.15'] go-version: ['1.11', '1.12', '1.13', '1.14', '1.15', '1.16', '1.17']
steps: steps:
- name: Set up Go ${{ matrix.go-version }} - name: Set up Go ${{ matrix.go-version }}
uses: actions/setup-go@v2 uses: actions/setup-go@v2

1
go.mod
View File

@ -5,4 +5,5 @@ go 1.11
require ( require (
github.com/google/go-querystring v1.0.0 github.com/google/go-querystring v1.0.0
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.4.0
gopkg.in/h2non/gock.v1 v1.1.2
) )

7
go.sum
View File

@ -2,13 +2,18 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY=
gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

View File

@ -7,18 +7,19 @@ import (
"fmt" "fmt"
"io" "io"
"net/http" "net/http"
"net/url"
"strconv" "strconv"
"time" "time"
"github.com/google/go-querystring/query" "github.com/google/go-querystring/query"
) )
// New initialize client // New initialize client.
func New(url string, token string) *MgClient { func New(url string, token string) *MgClient {
return NewWithClient(url, token, &http.Client{Timeout: time.Minute}) return NewWithClient(url, token, &http.Client{Timeout: time.Minute})
} }
// NewWithClient initializes client with provided http client // NewWithClient initializes client with provided http client.
func NewWithClient(url string, token string, client *http.Client) *MgClient { func NewWithClient(url string, token string, client *http.Client) *MgClient {
return &MgClient{ return &MgClient{
URL: url, URL: url,
@ -59,7 +60,7 @@ func (c *MgClient) TransportTemplates() ([]Template, int, error) {
return resp, status, err return resp, status, err
} }
// ActivateTransportChannel implements template activation // ActivateTemplate implements template activation
// //
// Example: // Example:
// var client = v1.New("https://token.url", "cb8ccf05e38a47543ad8477d4999be73bff503ea6") // var client = v1.New("https://token.url", "cb8ccf05e38a47543ad8477d4999be73bff503ea6")
@ -140,7 +141,8 @@ func (c *MgClient) UpdateTemplate(request Template) (int, error) {
return 0, errors.New("`ChannelID` and `Code` cannot be blank") return 0, errors.New("`ChannelID` and `Code` cannot be blank")
} }
data, status, err := c.PutRequest(fmt.Sprintf("/channels/%d/templates/%s", request.ChannelID, request.Code), outgoing) data, status, err := c.PutRequest(
fmt.Sprintf("/channels/%d/templates/%s", request.ChannelID, url.PathEscape(request.Code)), outgoing)
if err != nil { if err != nil {
return status, err return status, err
} }
@ -165,7 +167,7 @@ func (c *MgClient) UpdateTemplate(request Template) (int, error) {
// } // }
func (c *MgClient) DeactivateTemplate(channelID uint64, templateCode string) (int, error) { func (c *MgClient) DeactivateTemplate(channelID uint64, templateCode string) (int, error) {
data, status, err := c.DeleteRequest( data, status, err := c.DeleteRequest(
fmt.Sprintf("/channels/%d/templates/%s", channelID, templateCode), []byte{}) fmt.Sprintf("/channels/%d/templates/%s", channelID, url.PathEscape(templateCode)), []byte{})
if err != nil { if err != nil {
return status, err return status, err
} }
@ -313,7 +315,7 @@ func (c *MgClient) UpdateTransportChannel(request Channel) (UpdateResponse, int,
var resp UpdateResponse var resp UpdateResponse
outgoing, _ := json.Marshal(&request) outgoing, _ := json.Marshal(&request)
data, status, err := c.PutRequest(fmt.Sprintf("/channels/%d", request.ID), []byte(outgoing)) data, status, err := c.PutRequest(fmt.Sprintf("/channels/%d", request.ID), outgoing)
if err != nil { if err != nil {
return resp, status, err return resp, status, err
} }
@ -442,7 +444,7 @@ func (c *MgClient) UpdateMessages(request EditMessageRequest) (MessagesResponse,
var resp MessagesResponse var resp MessagesResponse
outgoing, _ := json.Marshal(&request) outgoing, _ := json.Marshal(&request)
data, status, err := c.PutRequest("/messages", []byte(outgoing)) data, status, err := c.PutRequest("/messages", outgoing)
if err != nil { if err != nil {
return resp, status, err return resp, status, err
} }
@ -554,7 +556,7 @@ func (c *MgClient) DeleteMessage(request DeleteData) (*MessagesResponse, int, er
data, status, err := c.DeleteRequest( data, status, err := c.DeleteRequest(
"/messages", "/messages",
[]byte(outgoing), outgoing,
) )
if err != nil { if err != nil {
return nil, status, err return nil, status, err
@ -605,7 +607,7 @@ func (c *MgClient) GetFile(request string) (FullFileResponse, int, error) {
return resp, status, err return resp, status, err
} }
// UploadFile upload file // UploadFile upload file.
func (c *MgClient) UploadFile(request io.Reader) (UploadFileResponse, int, error) { func (c *MgClient) UploadFile(request io.Reader) (UploadFileResponse, int, error) {
var resp UploadFileResponse var resp UploadFileResponse
@ -625,7 +627,7 @@ func (c *MgClient) UploadFile(request io.Reader) (UploadFileResponse, int, error
return resp, status, err return resp, status, err
} }
// UploadFileByURL upload file by url // UploadFileByURL upload file by url.
func (c *MgClient) UploadFileByURL(request UploadFileByUrlRequest) (UploadFileResponse, int, error) { func (c *MgClient) UploadFileByURL(request UploadFileByUrlRequest) (UploadFileResponse, int, error) {
var resp UploadFileResponse var resp UploadFileResponse
outgoing, _ := json.Marshal(&request) outgoing, _ := json.Marshal(&request)
@ -658,7 +660,7 @@ func (c *MgClient) Error(info []byte) error {
return errors.New(values[0].(string)) return errors.New(values[0].(string))
} }
// MakeTimestamp returns current unix timestamp // MakeTimestamp returns current unix timestamp.
func MakeTimestamp() int64 { func MakeTimestamp() int64 {
return time.Now().UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) return time.Now().UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond))
} }

View File

@ -5,105 +5,113 @@ import (
"encoding/base64" "encoding/base64"
"fmt" "fmt"
"net/http" "net/http"
"os" "strings"
"strconv"
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite"
"gopkg.in/h2non/gock.v1"
) )
var ( type MGClientTest struct {
mgURL = os.Getenv("MG_URL") suite.Suite
mgToken = os.Getenv("MG_TOKEN") }
channelID, _ = strconv.ParseUint(os.Getenv("MG_CHANNEL"), 10, 64)
ext = strconv.FormatInt(time.Now().UTC().UnixNano(), 10)
tplCode = fmt.Sprintf("testTemplate_%d", time.Now().UnixNano())
tplChannel uint64 = 0
)
func client() *MgClient { func TestMGClient(t *testing.T) {
c := New(mgURL, mgToken) suite.Run(t, new(MGClientTest))
}
func (t *MGClientTest) client() *MgClient {
c := New("https://mg-test.retailcrm.pro", "mg_token")
c.Debug = true c.Debug = true
return c return c
} }
func templateChannel(t *testing.T) uint64 { func (t *MGClientTest) gock() *gock.Request {
if tplChannel == 0 { return gock.New("https://mg-test.retailcrm.pro").MatchHeader("x-transport-token", "mg_token")
c := client() }
resp, _, err := c.ActivateTransportChannel(Channel{
Type: "telegram", func (t *MGClientTest) transportURL(path string) string {
Name: "@test_channel_templates", return "/api/transport/v1/" + strings.TrimLeft(path, "/")
}
func (t *MGClientTest) Test_TransportChannels() {
c := t.client()
chName := "WhatsApp Channel"
createdAt := "2021-11-22T08:20:46.479979Z"
defer gock.Off()
t.gock().
Get(t.transportURL("channels")).
Reply(http.StatusOK).
JSON([]ChannelListItem{{
ID: 1,
ExternalID: "external_id",
Type: "whatsapp",
Name: &chName,
Settings: ChannelSettings{ Settings: ChannelSettings{
Status: Status{ Status: Status{
Delivered: ChannelFeatureBoth, Delivered: ChannelFeatureNone,
Read: ChannelFeatureBoth, Read: ChannelFeatureSend,
}, },
Text: ChannelSettingsText{ Text: ChannelSettingsText{
Creating: ChannelFeatureBoth, Creating: ChannelFeatureBoth,
Editing: ChannelFeatureBoth, Editing: ChannelFeatureBoth,
Quoting: ChannelFeatureBoth, Quoting: ChannelFeatureBoth,
Deleting: ChannelFeatureBoth, Deleting: ChannelFeatureReceive,
MaxCharsCount: 5000, MaxCharsCount: 4096,
}, },
Product: Product{ Product: Product{
Creating: ChannelFeatureBoth, Creating: ChannelFeatureReceive,
Editing: ChannelFeatureBoth, Editing: ChannelFeatureReceive,
Deleting: ChannelFeatureBoth,
}, },
Order: Order{ Order: Order{
Creating: ChannelFeatureBoth, Creating: ChannelFeatureReceive,
Editing: ChannelFeatureBoth, Editing: ChannelFeatureReceive,
Deleting: ChannelFeatureBoth,
}, },
File: ChannelSettingsFilesBase{ File: ChannelSettingsFilesBase{
Creating: ChannelFeatureBoth, Creating: ChannelFeatureBoth,
Editing: ChannelFeatureBoth, Editing: ChannelFeatureBoth,
Quoting: ChannelFeatureBoth, Quoting: ChannelFeatureBoth,
Deleting: ChannelFeatureBoth, Deleting: ChannelFeatureReceive,
Max: 1000000, Max: 1,
CommentMaxCharsCount: 128,
}, },
Image: ChannelSettingsFilesBase{ Image: ChannelSettingsFilesBase{
Creating: ChannelFeatureBoth, Creating: ChannelFeatureBoth,
Editing: ChannelFeatureBoth, Editing: ChannelFeatureBoth,
Quoting: ChannelFeatureBoth, Quoting: ChannelFeatureBoth,
Deleting: ChannelFeatureBoth, Deleting: ChannelFeatureReceive,
Max: 1, // nolint:gomnd
},
Suggestions: ChannelSettingsSuggestions{
Text: ChannelFeatureBoth,
Phone: ChannelFeatureBoth,
Email: ChannelFeatureBoth,
}, },
CustomerExternalID: ChannelFeatureCustomerExternalIDPhone, CustomerExternalID: ChannelFeatureCustomerExternalIDPhone,
SendingPolicy: SendingPolicy{ SendingPolicy: SendingPolicy{
NewCustomer: ChannelFeatureSendingPolicyTemplate, NewCustomer: ChannelFeatureSendingPolicyTemplate,
}, },
}, },
}) CreatedAt: createdAt,
UpdatedAt: &createdAt,
if err != nil { ActivatedAt: createdAt,
t.FailNow() DeactivatedAt: nil,
} IsActive: true,
}})
tplChannel = resp.ChannelID
}
return tplChannel
}
func TestMgClient_TransportChannels(t *testing.T) {
c := client()
data, status, err := c.TransportChannels(Channels{Active: true}) data, status, err := c.TransportChannels(Channels{Active: true})
t.Require().NoError(err)
t.Assert().Equal(http.StatusOK, status)
if err != nil { t.Assert().Len(data, 1)
t.Errorf("%d %v", status, err)
}
t.Logf("Channels found: %v", len(data))
} }
func TestMgClient_ActivateTransportChannel(t *testing.T) { func (t *MGClientTest) Test_ActivateTransportChannel() {
c := client() c := t.client()
ch := Channel{ ch := Channel{
ID: channelID, ID: 1,
Type: "telegram", Type: "telegram",
Name: "@my_shopping_bot", Name: "@my_shopping_bot",
Settings: ChannelSettings{ Settings: ChannelSettings{
@ -135,17 +143,27 @@ func TestMgClient_ActivateTransportChannel(t *testing.T) {
}, },
} }
defer gock.Off()
t.gock().
Post(t.transportURL("channels")).
Reply(http.StatusCreated).
JSON(ActivateResponse{
ChannelID: 1,
ExternalID: "external_id_1",
ActivatedAt: time.Now(),
})
data, status, err := c.ActivateTransportChannel(ch) data, status, err := c.ActivateTransportChannel(ch)
t.Require().NoError(err)
t.Assert().Equal(http.StatusCreated, status)
if err != nil { t.Assert().Equal(uint64(1), data.ChannelID)
t.Errorf("%d %v", status, err) t.Assert().Equal("external_id_1", data.ExternalID)
} t.Assert().NotEmpty(data.ActivatedAt.String())
t.Logf("Activate selected channel: %v", data.ChannelID)
} }
func TestMgClient_ActivateNewTransportChannel(t *testing.T) { func (t *MGClientTest) Test_ActivateNewTransportChannel() {
c := client() c := t.client()
ch := Channel{ ch := Channel{
Type: "telegram", Type: "telegram",
Name: "@my_shopping_bot", Name: "@my_shopping_bot",
@ -177,31 +195,44 @@ func TestMgClient_ActivateNewTransportChannel(t *testing.T) {
}, },
} }
defer gock.Off()
t.gock().
Post(t.transportURL("channels")).
Reply(http.StatusCreated).
JSON(ActivateResponse{
ChannelID: 1,
ExternalID: "external_id_1",
ActivatedAt: time.Now(),
})
t.gock().
Delete(t.transportURL("channels/1")).
Reply(http.StatusOK).
JSON(DeleteResponse{
ChannelID: 1,
DeactivatedAt: time.Now(),
})
data, status, err := c.ActivateTransportChannel(ch) data, status, err := c.ActivateTransportChannel(ch)
t.Require().NoError(err)
t.Assert().Equal(http.StatusCreated, status)
if err != nil { t.Assert().Equal(uint64(1), data.ChannelID)
t.Errorf("%d %v", status, err) t.Assert().Equal("external_id_1", data.ExternalID)
} t.Assert().NotEmpty(data.ActivatedAt.String())
t.Logf("New channel ID %v", data.ChannelID)
deleteData, status, err := c.DeactivateTransportChannel(data.ChannelID) deleteData, status, err := c.DeactivateTransportChannel(data.ChannelID)
t.Require().NoError(err)
if err != nil { t.Assert().Equal(http.StatusOK, status)
t.Errorf("%d %v", status, err) t.Assert().NotEmpty(deleteData.DeactivatedAt.String())
} t.Assert().Equal(uint64(1), deleteData.ChannelID)
if deleteData.DeactivatedAt.String() == "" {
t.Errorf("%v", err)
}
t.Logf("Deactivate new channel with ID %v", deleteData.ChannelID)
} }
func TestMgClient_UpdateTransportChannel(t *testing.T) { func (t *MGClientTest) Test_UpdateTransportChannel() {
c := client() c := t.client()
ch := Channel{ ch := Channel{
ID: channelID, ID: 1,
Name: "@my_shopping_bot_2", Name: "@my_shopping_bot_2",
Settings: ChannelSettings{ Settings: ChannelSettings{
Status: Status{ Status: Status{
@ -231,44 +262,79 @@ func TestMgClient_UpdateTransportChannel(t *testing.T) {
}, },
} }
defer gock.Off()
t.gock().
Put(t.transportURL("channels/1")).
Reply(http.StatusOK).
JSON(UpdateResponse{
ChannelID: uint64(1),
ExternalID: "external_id_1",
UpdatedAt: time.Now(),
})
data, status, err := c.UpdateTransportChannel(ch) data, status, err := c.UpdateTransportChannel(ch)
t.Require().NoError(err)
if status != http.StatusOK { t.Assert().Equal(http.StatusOK, status)
t.Errorf("%v", err) t.Assert().Equal(uint64(1), data.ChannelID)
} t.Assert().Equal("external_id_1", data.ExternalID)
t.Assert().NotEmpty(data.UpdatedAt.String())
t.Logf("Update selected channel: %v", data.ChannelID)
} }
func TestMgClient_TransportTemplates(t *testing.T) { func (t *MGClientTest) Test_TransportTemplates() {
c := client() c := t.client()
defer gock.Off()
t.gock().
Get(t.transportURL("templates")).
Reply(http.StatusOK).
JSON([]Template{{
Code: "tpl_code",
ChannelID: 1,
Name: "Test Template",
Enabled: true,
Type: TemplateTypeText,
Template: []TemplateItem{
{
Type: TemplateItemTypeText,
Text: "Hello, ",
},
{
Type: TemplateItemTypeVar,
VarType: TemplateVarFirstName,
},
{
Type: TemplateItemTypeText,
Text: "! We're glad to see you back in our store.",
},
},
}})
data, status, err := c.TransportTemplates() data, status, err := c.TransportTemplates()
assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
t.Assert().Equal(http.StatusOK, status)
t.Logf("Templates found: %#v", len(data)) t.Assert().Len(data, 1)
for _, item := range data { for _, item := range data {
for _, tpl := range item.Template { for _, tpl := range item.Template {
if tpl.Type == TemplateItemTypeText { if tpl.Type == TemplateItemTypeText {
assert.Empty(t, tpl.VarType) t.Assert().Empty(tpl.VarType)
} else { } else {
assert.Empty(t, tpl.Text) t.Assert().Empty(tpl.Text)
assert.NotEmpty(t, tpl.VarType) t.Assert().NotEmpty(tpl.VarType)
if _, ok := templateVarAssoc[tpl.VarType]; !ok { if _, ok := templateVarAssoc[tpl.VarType]; !ok {
t.Errorf("unknown TemplateVar type %s", tpl.VarType) t.T().Errorf("unknown TemplateVar type %s", tpl.VarType)
} }
} }
} }
} }
} }
func TestMgClient_ActivateTemplate(t *testing.T) { func (t *MGClientTest) Test_ActivateTemplate() {
c := client() c := t.client()
req := ActivateTemplateRequest{ req := ActivateTemplateRequest{
Code: tplCode, Code: "tplCode",
Name: tplCode, Name: "tplCode",
Type: TemplateTypeText, Type: TemplateTypeText,
Template: []TemplateItem{ Template: []TemplateItem{
{ {
@ -286,17 +352,22 @@ func TestMgClient_ActivateTemplate(t *testing.T) {
}, },
} }
status, err := c.ActivateTemplate(templateChannel(t), req) defer gock.Off()
assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) t.gock().
Post("/channels/1/templates").
Reply(http.StatusCreated).
JSON(map[string]interface{}{})
t.Logf("Activated template with code `%s`", req.Code) status, err := c.ActivateTemplate(1, req)
t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
t.Assert().Equal(http.StatusCreated, status)
} }
func TestMgClient_UpdateTemplate(t *testing.T) { func (t *MGClientTest) Test_UpdateTemplate() {
c := client() c := t.client()
tpl := Template{ tpl := Template{
Code: tplCode, Code: "encodable#code",
ChannelID: templateChannel(t), ChannelID: 1,
Name: "updated name", Name: "updated name",
Enabled: true, Enabled: true,
Type: TemplateTypeText, Type: TemplateTypeText,
@ -316,21 +387,36 @@ func TestMgClient_UpdateTemplate(t *testing.T) {
}, },
} }
defer gock.Off()
t.gock().
Filter(func(r *http.Request) bool {
return r.Method == http.MethodPut &&
r.URL.Path == "/api/transport/v1/channels/1/templates/encodable#code"
}).
Reply(http.StatusOK).
JSON(map[string]interface{}{})
t.gock().
Get(t.transportURL("templates")).
Reply(http.StatusOK).
JSON([]Template{tpl})
status, err := c.UpdateTemplate(tpl) status, err := c.UpdateTemplate(tpl)
assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
templates, status, err := c.TransportTemplates() templates, status, err := c.TransportTemplates()
assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
for _, template := range templates { for _, template := range templates {
if template.Code == tpl.Code { if template.Code == tpl.Code {
assert.Equal(t, tpl.Name, template.Name) t.Assert().Equal(tpl.Name, template.Name)
} }
} }
} }
func TestMgClient_UpdateTemplateFail(t *testing.T) { func (t *MGClientTest) Test_UpdateTemplateFail() {
c := client() c := t.client()
tpl := Template{ tpl := Template{
Name: "updated name", Name: "updated name",
Enabled: true, Enabled: true,
@ -351,23 +437,39 @@ func TestMgClient_UpdateTemplateFail(t *testing.T) {
}, },
} }
defer gock.Off()
t.gock().
Reply(http.StatusBadRequest).
JSON(map[string][]string{
"errors": {"Some weird error message..."},
})
status, err := c.UpdateTemplate(tpl) status, err := c.UpdateTemplate(tpl)
assert.Error(t, err, fmt.Sprintf("%d %s", status, err)) t.Assert().Error(err, fmt.Sprintf("%d %s", status, err))
} }
func TestMgClient_DeactivateTemplate(t *testing.T) { func (t *MGClientTest) Test_DeactivateTemplate() {
c := client() c := t.client()
status, err := c.DeactivateTemplate(templateChannel(t), tplCode)
assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) defer gock.Off()
t.gock().
Filter(func(r *http.Request) bool {
return r.Method == http.MethodDelete &&
r.URL.Path == t.transportURL("channels/1/templates/test_template#code")
}).
Reply(http.StatusOK).
JSON(map[string]interface{}{})
status, err := c.DeactivateTemplate(1, "test_template#code")
t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err))
} }
func TestMgClient_TextMessages(t *testing.T) { func (t *MGClientTest) Test_TextMessages() {
c := client() c := t.client()
t.Logf("%v", ext)
snd := SendData{ snd := SendData{
Message: Message{ Message: Message{
ExternalID: ext, ExternalID: "external_id",
Type: MsgTypeText, Type: MsgTypeText,
Text: "hello!", Text: "hello!",
}, },
@ -377,38 +479,61 @@ func TestMgClient_TextMessages(t *testing.T) {
Nickname: "octopus", Nickname: "octopus",
Firstname: "Joe", Firstname: "Joe",
}, },
Channel: channelID, Channel: 1,
ExternalChatID: "24798237492374", ExternalChatID: "24798237492374",
} }
defer gock.Off()
t.gock().
Post(t.transportURL("messages")).
Reply(http.StatusOK).
JSON(MessagesResponse{
MessageID: 1,
Time: time.Now(),
})
data, status, err := c.Messages(snd) data, status, err := c.Messages(snd)
t.Require().NoError(err)
if status != http.StatusOK { t.Assert().Equal(http.StatusOK, status)
t.Errorf("%v", err) t.Assert().NotEmpty(data.Time.String())
} t.Assert().Equal(1, data.MessageID)
if data.Time.String() == "" {
t.Errorf("%v", err)
}
t.Logf("Message %v is sent", data.MessageID)
} }
func TestMgClient_ImageMessages(t *testing.T) { func (t *MGClientTest) Test_ImageMessages() {
c := client() c := t.client()
t.Logf("%v", ext)
defer gock.Off()
t.gock().
Post(t.transportURL("files/upload_by_url")).
Reply(http.StatusOK).
JSON(UploadFileResponse{
ID: "1",
Hash: "1",
Type: "image/png",
MimeType: "",
Size: 1024,
CreatedAt: time.Now(),
})
t.gock().
Post(t.transportURL("messages")).
Reply(http.StatusOK).
JSON(MessagesResponse{
MessageID: 1,
Time: time.Now(),
})
uploadFileResponse, st, err := c.UploadFileByURL(UploadFileByUrlRequest{ uploadFileResponse, st, err := c.UploadFileByURL(UploadFileByUrlRequest{
Url: "https://via.placeholder.com/1", Url: "https://via.placeholder.com/1",
}) })
t.Require().NoError(err)
if st != http.StatusOK { t.Assert().Equal(http.StatusOK, st)
t.Errorf("%v", err) t.Assert().Equal("1", uploadFileResponse.ID)
}
snd := SendData{ snd := SendData{
Message: Message{ Message: Message{
ExternalID: ext + "file", ExternalID: "file",
Type: MsgTypeImage, Type: MsgTypeImage,
Items: []Item{{ID: uploadFileResponse.ID}}, Items: []Item{{ID: uploadFileResponse.ID}},
}, },
@ -418,135 +543,138 @@ func TestMgClient_ImageMessages(t *testing.T) {
Nickname: "octopus", Nickname: "octopus",
Firstname: "Joe", Firstname: "Joe",
}, },
Channel: channelID, Channel: 1,
ExternalChatID: "24798237492374", ExternalChatID: "24798237492374",
} }
data, status, err := c.Messages(snd) data, status, err := c.Messages(snd)
t.Require().NoError(err)
if status != http.StatusOK { t.Assert().Equal(http.StatusOK, status)
t.Errorf("%v", err) t.Assert().NotEmpty(data.Time.String())
} t.Assert().Equal(1, data.MessageID)
if data.Time.String() == "" {
t.Errorf("%v", err)
}
t.Logf("Message %v is sent", data.MessageID)
} }
func TestMgClient_UpdateMessages(t *testing.T) { func (t *MGClientTest) Test_UpdateMessages() {
c := client() c := t.client()
t.Logf("%v", ext)
sndU := EditMessageRequest{ sndU := EditMessageRequest{
EditMessageRequestMessage{ EditMessageRequestMessage{
ExternalID: ext, ExternalID: "editing",
Text: "hello hello!", Text: "hello hello!",
}, },
channelID, 1,
} }
defer gock.Off()
t.gock().
Put(t.transportURL("messages")).
Reply(http.StatusOK).
JSON(MessagesResponse{
MessageID: 1,
Time: time.Now(),
})
dataU, status, err := c.UpdateMessages(sndU) dataU, status, err := c.UpdateMessages(sndU)
t.Require().NoError(err)
if status != http.StatusOK { t.Assert().Equal(http.StatusOK, status)
t.Errorf("%v", err) t.Assert().NotEmpty(dataU.Time.String())
} t.Assert().Equal(1, dataU.MessageID)
if dataU.Time.String() == "" {
t.Errorf("%v", err)
}
t.Logf("Message %v updated", dataU.MessageID)
} }
func TestMgClient_MarkMessageReadAndDelete(t *testing.T) { func (t *MGClientTest) Test_MarkMessageReadAndDelete() {
c := client() c := t.client()
t.Logf("%v", ext)
snd := MarkMessageReadRequest{ snd := MarkMessageReadRequest{
MarkMessageReadRequestMessage{ MarkMessageReadRequestMessage{
ExternalID: ext, ExternalID: "external_1",
}, },
channelID, 1,
} }
defer gock.Off()
t.gock().
Post(t.transportURL("messages/read")).
Reply(http.StatusOK).
JSON(MarkMessageReadResponse{})
t.gock().
Delete(t.transportURL("messages")).
JSON(DeleteData{
Message: Message{
ExternalID: "deleted",
},
Channel: 1,
}).
Reply(http.StatusOK).
JSON(MessagesResponse{
MessageID: 2,
Time: time.Now(),
})
_, status, err := c.MarkMessageRead(snd) _, status, err := c.MarkMessageRead(snd)
t.Require().NoError(err)
t.Assert().Equal(http.StatusOK, status)
if status != http.StatusOK { previousChatMessage, status, err := c.DeleteMessage(DeleteData{
t.Errorf("%v", err)
}
t.Logf("Message ext marked as read")
sndD := DeleteData{
Message{ Message{
ExternalID: ext, ExternalID: "deleted",
}, },
channelID, 1,
} })
t.Require().NoError(err)
previousChatMessage, status, err := c.DeleteMessage(sndD) t.Assert().Equal(http.StatusOK, status)
t.Assert().Equal(2, previousChatMessage.MessageID)
if status != http.StatusOK {
t.Errorf("%v", err)
}
t.Logf("Message %v deleted", ext)
if previousChatMessage != nil {
t.Logf("Previous chat message %+v", *previousChatMessage)
}
sndD = DeleteData{
Message{
ExternalID: ext + "file",
},
channelID,
}
previousChatMessage, status, err = c.DeleteMessage(sndD)
if status != http.StatusOK {
t.Errorf("%v", err)
}
t.Logf("Message %v deleted", ext+"file")
if previousChatMessage != nil {
t.Logf("Previous chat message %+v", *previousChatMessage)
}
} }
func TestMgClient_DeactivateTransportChannel(t *testing.T) { func (t *MGClientTest) Test_DeactivateTransportChannel() {
c := client() c := t.client()
deleteData, status, err := c.DeactivateTransportChannel(channelID)
if err != nil { defer gock.Off()
t.Errorf("%d %v", status, err) t.gock().
} Delete(t.transportURL("channels/1")).
Reply(http.StatusOK).
JSON(DeleteResponse{
ChannelID: 1,
DeactivatedAt: time.Now(),
})
if deleteData.DeactivatedAt.String() == "" { deleteData, status, err := c.DeactivateTransportChannel(1)
t.Errorf("%v", err) t.Require().NoError(err)
} t.Assert().Equal(http.StatusOK, status)
t.Assert().NotEmpty(deleteData.DeactivatedAt.String())
t.Logf("Deactivate selected channel: %v", deleteData.ChannelID) t.Assert().Equal(uint64(1), deleteData.ChannelID)
} }
func TestMgClient_UploadFile(t *testing.T) { func (t *MGClientTest) Test_UploadFile() {
c := client() c := t.client()
t.Logf("%v", ext)
// 1x1 png picture // 1x1 png picture
img := "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=" img := "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII="
binary, err := base64.StdEncoding.DecodeString(img) binary, err := base64.StdEncoding.DecodeString(img)
if err != nil { if err != nil {
t.Errorf("cannot convert base64 to binary: %s", err) t.T().Errorf("cannot convert base64 to binary: %s", err)
} }
resp := UploadFileResponse{
ID: "1",
Hash: "1",
Type: "image/png",
MimeType: "",
Size: 1024,
CreatedAt: time.Now(),
}
defer gock.Off()
t.gock().
Post(t.transportURL("files/upload")).
Body(bytes.NewReader(binary)).
Reply(http.StatusOK).
JSON(resp)
data, status, err := c.UploadFile(bytes.NewReader(binary)) data, status, err := c.UploadFile(bytes.NewReader(binary))
t.Require().NoError(err)
t.Assert().Equal(http.StatusOK, status)
if status != http.StatusOK { resp.CreatedAt = data.CreatedAt
t.Errorf("%v", err) t.Assert().Equal(resp, data)
}
t.Logf("Message %+v is sent", data)
} }

View File

@ -12,7 +12,7 @@ import (
var prefix = "/api/transport/v1" var prefix = "/api/transport/v1"
// GetRequest implements GET Request // GetRequest implements GET Request.
func (c *MgClient) GetRequest(url string, parameters []byte) ([]byte, int, error) { func (c *MgClient) GetRequest(url string, parameters []byte) ([]byte, int, error) {
return makeRequest( return makeRequest(
"GET", "GET",
@ -22,7 +22,7 @@ func (c *MgClient) GetRequest(url string, parameters []byte) ([]byte, int, error
) )
} }
// PostRequest implements POST Request // PostRequest implements POST Request.
func (c *MgClient) PostRequest(url string, parameters io.Reader) ([]byte, int, error) { func (c *MgClient) PostRequest(url string, parameters io.Reader) ([]byte, int, error) {
return makeRequest( return makeRequest(
"POST", "POST",
@ -32,7 +32,7 @@ func (c *MgClient) PostRequest(url string, parameters io.Reader) ([]byte, int, e
) )
} }
// PutRequest implements PUT Request // PutRequest implements PUT Request.
func (c *MgClient) PutRequest(url string, parameters []byte) ([]byte, int, error) { func (c *MgClient) PutRequest(url string, parameters []byte) ([]byte, int, error) {
return makeRequest( return makeRequest(
"PUT", "PUT",
@ -42,7 +42,7 @@ func (c *MgClient) PutRequest(url string, parameters []byte) ([]byte, int, error
) )
} }
// DeleteRequest implements DELETE Request // DeleteRequest implements DELETE Request.
func (c *MgClient) DeleteRequest(url string, parameters []byte) ([]byte, int, error) { func (c *MgClient) DeleteRequest(url string, parameters []byte) ([]byte, int, error) {
return makeRequest( return makeRequest(
"DELETE", "DELETE",
@ -63,7 +63,7 @@ func makeRequest(reqType, url string, buf io.Reader, c *MgClient) ([]byte, int,
req.Header.Set("X-Transport-Token", c.Token) req.Header.Set("X-Transport-Token", c.Token)
if c.Debug { if c.Debug {
if strings.Index(url, "/files/upload") != -1 { if strings.Contains(url, "/files/upload") {
log.Printf("MG TRANSPORT API Request: %s %s %s [file data]", reqType, url, c.Token) log.Printf("MG TRANSPORT API Request: %s %s %s [file data]", reqType, url, c.Token)
} else { } else {
log.Printf("MG TRANSPORT API Request: %s %s %s %v", reqType, url, c.Token, buf) log.Printf("MG TRANSPORT API Request: %s %s %s %v", reqType, url, c.Token, buf)

View File

@ -10,24 +10,24 @@ import (
const TemplateTypeText = "text" const TemplateTypeText = "text"
const ( const (
// TemplateItemTypeText is a type for text chunk in template // TemplateItemTypeText is a type for text chunk in template.
TemplateItemTypeText uint8 = iota TemplateItemTypeText uint8 = iota
// TemplateItemTypeVar is a type for variable in template // TemplateItemTypeVar is a type for variable in template.
TemplateItemTypeVar TemplateItemTypeVar
) )
const ( const (
// TemplateVarCustom is a custom variable type // TemplateVarCustom is a custom variable type.
TemplateVarCustom = "custom" TemplateVarCustom = "custom"
// TemplateVarName is a name variable type // TemplateVarName is a name variable type.
TemplateVarName = "name" TemplateVarName = "name"
// TemplateVarFirstName is a first name variable type // TemplateVarFirstName is a first name variable type.
TemplateVarFirstName = "first_name" TemplateVarFirstName = "first_name"
// TemplateVarLastName is a last name variable type // TemplateVarLastName is a last name variable type.
TemplateVarLastName = "last_name" TemplateVarLastName = "last_name"
) )
// templateVarAssoc for checking variable validity, only for internal use // templateVarAssoc for checking variable validity, only for internal use.
var templateVarAssoc = map[string]interface{}{ var templateVarAssoc = map[string]interface{}{
TemplateVarCustom: nil, TemplateVarCustom: nil,
TemplateVarName: nil, TemplateVarName: nil,
@ -35,7 +35,7 @@ var templateVarAssoc = map[string]interface{}{
TemplateVarLastName: nil, TemplateVarLastName: nil,
} }
// Template struct // Template struct.
type Template struct { type Template struct {
Code string `json:"code"` Code string `json:"code"`
ChannelID uint64 `json:"channel_id,omitempty"` ChannelID uint64 `json:"channel_id,omitempty"`
@ -45,14 +45,14 @@ type Template struct {
Template []TemplateItem `json:"template"` Template []TemplateItem `json:"template"`
} }
// TemplateItem is a part of template // TemplateItem is a part of template.
type TemplateItem struct { type TemplateItem struct {
Type uint8 Type uint8
Text string Text string
VarType string VarType string
} }
// MarshalJSON controls how TemplateItem will be marshaled into JSON // MarshalJSON controls how TemplateItem will be marshaled into JSON.
func (t TemplateItem) MarshalJSON() ([]byte, error) { func (t TemplateItem) MarshalJSON() ([]byte, error) {
switch t.Type { switch t.Type {
case TemplateItemTypeText: case TemplateItemTypeText:
@ -71,7 +71,7 @@ func (t TemplateItem) MarshalJSON() ([]byte, error) {
return nil, errors.New("unknown TemplateItem type") return nil, errors.New("unknown TemplateItem type")
} }
// UnmarshalJSON will correctly unmarshal TemplateItem // UnmarshalJSON will correctly unmarshal TemplateItem.
func (t *TemplateItem) UnmarshalJSON(b []byte) error { func (t *TemplateItem) UnmarshalJSON(b []byte) error {
var obj interface{} var obj interface{}
err := json.Unmarshal(b, &obj) err := json.Unmarshal(b, &obj)

View File

@ -7,62 +7,62 @@ import (
"time" "time"
) )
//noinspection ALL // noinspection ALL.
const ( const (
// ChannelFeatureNone channel can not implement feature // ChannelFeatureNone channel can not implement feature.
ChannelFeatureNone string = "none" ChannelFeatureNone string = "none"
// ChannelFeatureReceive channel implement feature on receive // ChannelFeatureReceive channel implement feature on receive.
ChannelFeatureReceive string = "receive" ChannelFeatureReceive string = "receive"
// ChannelFeatureSend channel implement feature on send // ChannelFeatureSend channel implement feature on send.
ChannelFeatureSend string = "send" ChannelFeatureSend string = "send"
// ChannelFeatureBoth channel implement feature on both directions // ChannelFeatureBoth channel implement feature on both directions.
ChannelFeatureBoth string = "both" ChannelFeatureBoth string = "both"
// ChannelFeatureAny channel implement feature on any // ChannelFeatureAny channel implement feature on any.
ChannelFeatureAny string = "any" ChannelFeatureAny string = "any"
// ChannelFeatureSendingPolicyNo channel can not implement feature // ChannelFeatureSendingPolicyNo channel can not implement feature.
ChannelFeatureSendingPolicyNo string = "no" ChannelFeatureSendingPolicyNo string = "no"
// ChannelFeatureSendingPolicyTemplate channel can implement template // ChannelFeatureSendingPolicyTemplate channel can implement template.
ChannelFeatureSendingPolicyTemplate string = "template" ChannelFeatureSendingPolicyTemplate string = "template"
// ChannelFeatureCustomerExternalIDPhone customer externalId is phone // ChannelFeatureCustomerExternalIDPhone customer externalId is phone.
ChannelFeatureCustomerExternalIDPhone string = "phone" ChannelFeatureCustomerExternalIDPhone string = "phone"
// MsgTypeText text message // MsgTypeText text message.
MsgTypeText string = "text" MsgTypeText string = "text"
// MsgTypeSystem system message // MsgTypeSystem system message.
MsgTypeSystem string = "system" MsgTypeSystem string = "system"
// MsgTypeCommand command (for bots) // MsgTypeCommand command (for bots).
MsgTypeCommand string = "command" MsgTypeCommand string = "command"
// MsgTypeOrder order card // MsgTypeOrder order card.
MsgTypeOrder string = "order" MsgTypeOrder string = "order"
// MsgTypeProduct product card // MsgTypeProduct product card.
MsgTypeProduct string = "product" MsgTypeProduct string = "product"
// MsgTypeFile file card // MsgTypeFile file card.
MsgTypeFile string = "file" MsgTypeFile string = "file"
// MsgTypeImage image card // MsgTypeImage image card.
MsgTypeImage string = "image" MsgTypeImage string = "image"
// MsgTypeAudio audio // MsgTypeAudio audio.
MsgTypeAudio string = "audio" MsgTypeAudio string = "audio"
// MsgOrderStatusCodeNew order status group new // MsgOrderStatusCodeNew order status group new.
MsgOrderStatusCodeNew = "new" MsgOrderStatusCodeNew = "new"
// MsgOrderStatusCodeApproval order status group approval // MsgOrderStatusCodeApproval order status group approval.
MsgOrderStatusCodeApproval = "approval" MsgOrderStatusCodeApproval = "approval"
// MsgOrderStatusCodeAssembling order status group assembling // MsgOrderStatusCodeAssembling order status group assembling.
MsgOrderStatusCodeAssembling = "assembling" MsgOrderStatusCodeAssembling = "assembling"
// MsgOrderStatusCodeDelivery order status group delivery // MsgOrderStatusCodeDelivery order status group delivery.
MsgOrderStatusCodeDelivery = "delivery" MsgOrderStatusCodeDelivery = "delivery"
// MsgOrderStatusCodeComplete order status group complete // MsgOrderStatusCodeComplete order status group complete.
MsgOrderStatusCodeComplete = "complete" MsgOrderStatusCodeComplete = "complete"
// MsgOrderStatusCodeCancel order status group cancel // MsgOrderStatusCodeCancel order status group cancel.
MsgOrderStatusCodeCancel = "cancel" MsgOrderStatusCodeCancel = "cancel"
FileSizeLimit = 20 * 1024 * 1024 FileSizeLimit = 20 * 1024 * 1024
) )
const ( const (
// OriginatorCustomer means message was created by customer // OriginatorCustomer means message was created by customer.
OriginatorCustomer Originator = iota + 1 OriginatorCustomer Originator = iota + 1
// OriginatorChannel means message was created by channel, for example via messenger mobile application // OriginatorChannel means message was created by channel, for example via messenger mobile application.
OriginatorChannel OriginatorChannel
) )
@ -70,13 +70,13 @@ type ErrorType string
const ( const (
GeneralError ErrorType = "general" GeneralError ErrorType = "general"
CustomerNotExistsError = "customer_not_exists" CustomerNotExistsError ErrorType = "customer_not_exists"
ReplyTimedOutError = "reply_timed_out" ReplyTimedOutError ErrorType = "reply_timed_out"
SpamSuspicionError = "spam_suspicion" SpamSuspicionError ErrorType = "spam_suspicion"
AccessRestrictedError = "access_restricted" AccessRestrictedError ErrorType = "access_restricted"
) )
// MgClient type // MgClient type.
type MgClient struct { type MgClient struct {
URL string `json:"url"` URL string `json:"url"`
Token string `json:"token"` Token string `json:"token"`
@ -84,17 +84,17 @@ type MgClient struct {
httpClient *http.Client `json:"-"` httpClient *http.Client `json:"-"`
} }
// Channel type // Channel type.
type Channel struct { type Channel struct {
ID uint64 `json:"id,omitempty"` ID uint64 `json:"id,omitempty"`
ExternalID string `json:"external_id,omitempty"` ExternalID string `json:"external_id,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
AvatarUrl string `json:"avatar_url,omitempty"` AvatarUrl string `json:"avatar_url,omitempty"`
Settings ChannelSettings `json:"settings,omitempty,brackets"` Settings ChannelSettings `json:"settings,omitempty"`
} }
// ChannelSettings struct // ChannelSettings struct.
type ChannelSettings struct { type ChannelSettings struct {
Status Status `json:"status"` Status Status `json:"status"`
Text ChannelSettingsText `json:"text"` Text ChannelSettingsText `json:"text"`
@ -107,27 +107,27 @@ type ChannelSettings struct {
Suggestions ChannelSettingsSuggestions `json:"suggestions,omitempty"` Suggestions ChannelSettingsSuggestions `json:"suggestions,omitempty"`
} }
// Product type // Product type.
type Product struct { type Product struct {
Creating string `json:"creating,omitempty"` Creating string `json:"creating,omitempty"`
Editing string `json:"editing,omitempty"` Editing string `json:"editing,omitempty"`
Deleting string `json:"deleting,omitempty"` Deleting string `json:"deleting,omitempty"`
} }
// Order type // Order type.
type Order struct { type Order struct {
Creating string `json:"creating,omitempty"` Creating string `json:"creating,omitempty"`
Editing string `json:"editing,omitempty"` Editing string `json:"editing,omitempty"`
Deleting string `json:"deleting,omitempty"` Deleting string `json:"deleting,omitempty"`
} }
// Status struct // Status struct.
type Status struct { type Status struct {
Delivered string `json:"delivered,omitempty"` Delivered string `json:"delivered,omitempty"`
Read string `json:"read,omitempty"` Read string `json:"read,omitempty"`
} }
// ChannelSettingsText struct // ChannelSettingsText struct.
type ChannelSettingsText struct { type ChannelSettingsText struct {
Creating string `json:"creating,omitempty"` Creating string `json:"creating,omitempty"`
Editing string `json:"editing,omitempty"` Editing string `json:"editing,omitempty"`
@ -136,7 +136,7 @@ type ChannelSettingsText struct {
MaxCharsCount uint16 `json:"max_chars_count,omitempty"` MaxCharsCount uint16 `json:"max_chars_count,omitempty"`
} }
// ChannelSettingsFilesBase struct // ChannelSettingsFilesBase struct.
type ChannelSettingsFilesBase struct { type ChannelSettingsFilesBase struct {
Creating string `json:"creating,omitempty"` Creating string `json:"creating,omitempty"`
Editing string `json:"editing,omitempty"` Editing string `json:"editing,omitempty"`
@ -158,7 +158,7 @@ type ChannelSettingsSuggestions struct {
Email string `json:"email,omitempty"` Email string `json:"email,omitempty"`
} }
// FullFileResponse uploaded file data // FullFileResponse uploaded file data.
type FullFileResponse struct { type FullFileResponse struct {
ID string `json:"id,omitempty"` ID string `json:"id,omitempty"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
@ -166,7 +166,7 @@ type FullFileResponse struct {
Url string `json:"url,omitempty"` Url string `json:"url,omitempty"`
} }
// UploadFileResponse uploaded file data // UploadFileResponse uploaded file data.
type UploadFileResponse struct { type UploadFileResponse struct {
ID string `json:"id"` ID string `json:"id"`
Hash string `json:"hash"` Hash string `json:"hash"`
@ -178,38 +178,38 @@ type UploadFileResponse struct {
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
} }
// FileMeta file metadata // FileMeta file metadata.
type FileMeta struct { type FileMeta struct {
Width *int `json:"width,omitempty"` Width *int `json:"width,omitempty"`
Height *int `json:"height,omitempty"` Height *int `json:"height,omitempty"`
} }
// UploadFileByUrlRequest file url to upload // UploadFileByUrlRequest file url to upload.
type UploadFileByUrlRequest struct { type UploadFileByUrlRequest struct {
Url string `json:"url"` Url string `json:"url"`
} }
// ActivateResponse channel activation response // ActivateResponse channel activation response.
type ActivateResponse struct { type ActivateResponse struct {
ChannelID uint64 `json:"id"` ChannelID uint64 `json:"id"`
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
ActivatedAt time.Time `json:"activated_at"` ActivatedAt time.Time `json:"activated_at"`
} }
// UpdateResponse channel update response // UpdateResponse channel update response.
type UpdateResponse struct { type UpdateResponse struct {
ChannelID uint64 `json:"id"` ChannelID uint64 `json:"id"`
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
// DeleteResponse channel deactivation response // DeleteResponse channel deactivation response.
type DeleteResponse struct { type DeleteResponse struct {
ChannelID uint64 `json:"id"` ChannelID uint64 `json:"id"`
DeactivatedAt time.Time `json:"deactivated_at"` DeactivatedAt time.Time `json:"deactivated_at"`
} }
// ChannelListItem response struct // ChannelListItem response struct.
type ChannelListItem struct { type ChannelListItem struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
@ -223,7 +223,7 @@ type ChannelListItem struct {
IsActive bool `json:"is_active"` IsActive bool `json:"is_active"`
} }
// Channels request type // Channels request type.
type Channels struct { type Channels struct {
ID int `url:"id,omitempty" json:"id,omitempty"` ID int `url:"id,omitempty" json:"id,omitempty"`
Types []string `url:"types,omitempty" json:"types,omitempty"` Types []string `url:"types,omitempty" json:"types,omitempty"`
@ -235,7 +235,7 @@ type Channels struct {
Limit int `url:"limit,omitempty" json:"limit,omitempty"` Limit int `url:"limit,omitempty" json:"limit,omitempty"`
} }
// Customer struct // Customer struct.
type Customer struct { type Customer struct {
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
Nickname string `json:"nickname"` Nickname string `json:"nickname"`
@ -249,7 +249,7 @@ type Customer struct {
Email string `json:"email,omitempty"` Email string `json:"email,omitempty"`
} }
// Message struct // Message struct.
type Message struct { type Message struct {
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
Type string `json:"type,omitempty"` Type string `json:"type,omitempty"`
@ -258,26 +258,26 @@ type Message struct {
Items []Item `json:"items,omitempty"` Items []Item `json:"items,omitempty"`
} }
// SendMessage struct // SendMessage struct.
type SendMessage struct { type SendMessage struct {
Message Message
SentAt time.Time `json:"sent_at,omitempty"` SentAt time.Time `json:"sent_at,omitempty"`
} }
// EditMessageRequest type // EditMessageRequest type.
type EditMessageRequest struct { type EditMessageRequest struct {
Message EditMessageRequestMessage `json:"message"` Message EditMessageRequestMessage `json:"message"`
Channel uint64 `json:"channel"` Channel uint64 `json:"channel"`
} }
// EditMessageRequestMessage type // EditMessageRequestMessage type.
type EditMessageRequestMessage struct { type EditMessageRequestMessage struct {
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
Text string `json:"text"` Text string `json:"text"`
EditedAt int64 `json:"edited_at"` EditedAt int64 `json:"edited_at"`
} }
// SendData struct // SendData struct.
type SendData struct { type SendData struct {
Message Message `json:"message"` Message Message `json:"message"`
Originator Originator `json:"originator,omitempty"` Originator Originator `json:"originator,omitempty"`
@ -288,51 +288,51 @@ type SendData struct {
ReplyDeadline *time.Time `json:"reply_deadline,omitempty"` ReplyDeadline *time.Time `json:"reply_deadline,omitempty"`
} }
// Item struct // Item struct.
type Item struct { type Item struct {
ID string `json:"id"` ID string `json:"id"`
Caption string `json:"caption"` Caption string `json:"caption"`
} }
// SendMessageRequestQuote type // SendMessageRequestQuote type.
type SendMessageRequestQuote struct { type SendMessageRequestQuote struct {
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
} }
// MarkMessageReadResponse type // MarkMessageReadResponse type.
type MarkMessageReadResponse struct{} type MarkMessageReadResponse struct{}
// MarkMessageReadRequest type // MarkMessageReadRequest type.
type MarkMessageReadRequest struct { type MarkMessageReadRequest struct {
Message MarkMessageReadRequestMessage `json:"message"` Message MarkMessageReadRequestMessage `json:"message"`
ChannelID uint64 `json:"channel_id"` ChannelID uint64 `json:"channel_id"`
} }
// MarkMessageReadRequestMessage type // MarkMessageReadRequestMessage type.
type MarkMessageReadRequestMessage struct { type MarkMessageReadRequestMessage struct {
ExternalID string `json:"external_id"` ExternalID string `json:"external_id"`
} }
// AckMessageRequest type // AckMessageRequest type.
type AckMessageRequest struct { type AckMessageRequest struct {
ExternalMessageID string `json:"external_message_id"` ExternalMessageID string `json:"external_message_id"`
Channel uint64 `json:"channel"` Channel uint64 `json:"channel"`
Error *MessageSentError `json:"error,omitempty"` Error *MessageSentError `json:"error,omitempty"`
} }
// DeleteData struct // DeleteData struct.
type DeleteData struct { type DeleteData struct {
Message Message `json:"message"` Message Message `json:"message"`
Channel uint64 `json:"channel"` Channel uint64 `json:"channel"`
} }
// MessagesResponse message event response // MessagesResponse message event response.
type MessagesResponse struct { type MessagesResponse struct {
MessageID int `json:"message_id,omitempty"` MessageID int `json:"message_id,omitempty"`
Time time.Time `json:"time,omitempty"` Time time.Time `json:"time,omitempty"`
} }
// WebhookRequest type // WebhookRequest type.
type WebhookRequest struct { type WebhookRequest struct {
Type string `json:"type"` Type string `json:"type"`
Meta TransportRequestMeta `json:"meta"` Meta TransportRequestMeta `json:"meta"`
@ -340,20 +340,20 @@ type WebhookRequest struct {
} }
// WebhookMessageSentResponse type // WebhookMessageSentResponse type
// Consider using this structure while processing webhook request // Consider using this structure while processing webhook request.
type WebhookMessageSentResponse struct { type WebhookMessageSentResponse struct {
ExternalMessageID string `json:"external_message_id"` ExternalMessageID string `json:"external_message_id"`
Error *MessageSentError `json:"error,omitempty"` Error *MessageSentError `json:"error,omitempty"`
Async bool `json:"async"` Async bool `json:"async"`
} }
// MessageSentError type // MessageSentError type.
type MessageSentError struct { type MessageSentError struct {
Code ErrorType `json:"code"` Code ErrorType `json:"code"`
Message string `json:"message"` Message string `json:"message"`
} }
// WebhookData request data // WebhookData request data.
type WebhookData struct { type WebhookData struct {
ExternalUserID string `json:"external_user_id"` ExternalUserID string `json:"external_user_id"`
ExternalMessageID string `json:"external_message_id,omitempty"` ExternalMessageID string `json:"external_message_id,omitempty"`
@ -394,7 +394,7 @@ type TemplateInfo struct {
Args []string `json:"args,omitempty"` Args []string `json:"args,omitempty"`
} }
// FileItem struct // FileItem struct.
type FileItem struct { type FileItem struct {
ID string `json:"id"` ID string `json:"id"`
Size int `json:"size"` Size int `json:"size"`
@ -403,20 +403,20 @@ type FileItem struct {
Width *int `json:"width,omitempty"` Width *int `json:"width,omitempty"`
} }
// MessageDataUser user data from webhook // MessageDataUser user data from webhook.
type MessageDataUser struct { type MessageDataUser struct {
FirstName string `json:"first_name"` FirstName string `json:"first_name"`
LastName string `json:"last_name"` LastName string `json:"last_name"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
} }
// MessageDataBot bot data from webhook // MessageDataBot bot data from webhook.
type MessageDataBot struct { type MessageDataBot struct {
Name string `json:"name"` Name string `json:"name"`
Avatar string `json:"avatar"` Avatar string `json:"avatar"`
} }
// MessageDataProduct product data from webhook // MessageDataProduct product data from webhook.
type MessageDataProduct struct { type MessageDataProduct struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Name string `json:"name"` Name string `json:"name"`
@ -429,7 +429,7 @@ type MessageDataProduct struct {
Quantity *MessageDataOrderQuantity `json:"quantity,omitempty"` Quantity *MessageDataOrderQuantity `json:"quantity,omitempty"`
} }
// MessageDataOrder order data from webhook // MessageDataOrder order data from webhook.
type MessageDataOrder struct { type MessageDataOrder struct {
Number string `json:"number"` Number string `json:"number"`
Url string `json:"url,omitempty"` Url string `json:"url,omitempty"`
@ -442,13 +442,13 @@ type MessageDataOrder struct {
Items []MessageDataOrderItem `json:"items,omitempty"` Items []MessageDataOrderItem `json:"items,omitempty"`
} }
// MessageDataOrderStatus type // MessageDataOrderStatus type.
type MessageDataOrderStatus struct { type MessageDataOrderStatus struct {
Code string `json:"code,omitempty"` Code string `json:"code,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
} }
// MessageDataOrderItem type // MessageDataOrderItem type.
type MessageDataOrderItem struct { type MessageDataOrderItem struct {
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Url string `json:"url,omitempty"` Url string `json:"url,omitempty"`
@ -457,32 +457,32 @@ type MessageDataOrderItem struct {
Price *MessageDataOrderCost `json:"price,omitempty"` Price *MessageDataOrderCost `json:"price,omitempty"`
} }
// MessageDataOrderCost type // MessageDataOrderCost type.
type MessageDataOrderCost struct { type MessageDataOrderCost struct {
Value float32 `json:"value,omitempty"` Value float32 `json:"value,omitempty"`
Currency string `json:"currency"` Currency string `json:"currency"`
} }
// MessageDataOrderQuantity type // MessageDataOrderQuantity type.
type MessageDataOrderQuantity struct { type MessageDataOrderQuantity struct {
Value float32 `json:"value"` Value float32 `json:"value"`
Unit string `json:"unit"` Unit string `json:"unit"`
} }
// MessageDataOrderPayment type // MessageDataOrderPayment type.
type MessageDataOrderPayment struct { type MessageDataOrderPayment struct {
Name string `json:"name"` Name string `json:"name"`
Status *MessageDataOrderPaymentStatus `json:"status"` Status *MessageDataOrderPaymentStatus `json:"status"`
Amount *MessageDataOrderCost `json:"amount"` Amount *MessageDataOrderCost `json:"amount"`
} }
// MessageDataOrderPaymentStatus type // MessageDataOrderPaymentStatus type.
type MessageDataOrderPaymentStatus struct { type MessageDataOrderPaymentStatus struct {
Name string `json:"name"` Name string `json:"name"`
Payed bool `json:"payed"` Paid bool `json:"paid"`
} }
// MessageDataOrderDelivery type // MessageDataOrderDelivery type.
type MessageDataOrderDelivery struct { type MessageDataOrderDelivery struct {
Name string `json:"name"` Name string `json:"name"`
Price *MessageDataOrderCost `json:"price"` Price *MessageDataOrderCost `json:"price"`
@ -490,7 +490,7 @@ type MessageDataOrderDelivery struct {
Comment string `json:"comment,omitempty"` Comment string `json:"comment,omitempty"`
} }
// TransportRequestMeta request metadata // TransportRequestMeta request metadata.
type TransportRequestMeta struct { type TransportRequestMeta struct {
ID uint64 `json:"id"` ID uint64 `json:"id"`
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
@ -505,10 +505,10 @@ type ActivateTemplateRequest struct {
var ErrInvalidOriginator = errors.New("invalid originator") var ErrInvalidOriginator = errors.New("invalid originator")
// Originator of message // Originator of message.
type Originator byte type Originator byte
// MarshalText marshals originator to text // MarshalText marshals originator to text.
func (o Originator) MarshalText() ([]byte, error) { func (o Originator) MarshalText() ([]byte, error) {
switch o { switch o {
case OriginatorCustomer: case OriginatorCustomer:

View File

@ -1,3 +1,4 @@
//go:build !go1.14
// +build !go1.14 // +build !go1.14
package v1 package v1

View File

@ -1,3 +1,4 @@
//go:build go1.14
// +build go1.14 // +build go1.14
package v1 package v1