diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 911162b..e3a31b2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,9 +10,6 @@ on: env: GO111MODULE: on - MG_URL: ${{ secrets.MG_URL }} - MG_TOKEN: ${{ secrets.MG_TOKEN }} - MG_CHANNEL: ${{ secrets.MG_CHANNEL }} jobs: golangci: @@ -31,9 +28,8 @@ jobs: name: Tests runs-on: ubuntu-latest strategy: - max-parallel: 1 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: - name: Set up Go ${{ matrix.go-version }} uses: actions/setup-go@v2 diff --git a/go.mod b/go.mod index ad616cb..fb4861d 100644 --- a/go.mod +++ b/go.mod @@ -5,4 +5,5 @@ go 1.11 require ( github.com/google/go-querystring v1.0.0 github.com/stretchr/testify v1.4.0 + gopkg.in/h2non/gock.v1 v1.1.2 ) diff --git a/go.sum b/go.sum index b13bde2..055b07e 100644 --- a/go.sum +++ b/go.sum @@ -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/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/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/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/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= 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/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/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/v1/client.go b/v1/client.go index 18d0d95..daf6e2e 100644 --- a/v1/client.go +++ b/v1/client.go @@ -7,18 +7,19 @@ import ( "fmt" "io" "net/http" + "net/url" "strconv" "time" "github.com/google/go-querystring/query" ) -// New initialize client +// New initialize client. func New(url string, token string) *MgClient { 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 { return &MgClient{ URL: url, @@ -59,7 +60,7 @@ func (c *MgClient) TransportTemplates() ([]Template, int, error) { return resp, status, err } -// ActivateTransportChannel implements template activation +// ActivateTemplate implements template activation // // Example: // 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") } - 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 { 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) { 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 { return status, err } @@ -313,7 +315,7 @@ func (c *MgClient) UpdateTransportChannel(request Channel) (UpdateResponse, int, var resp UpdateResponse 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 { return resp, status, err } @@ -442,7 +444,7 @@ func (c *MgClient) UpdateMessages(request EditMessageRequest) (MessagesResponse, var resp MessagesResponse outgoing, _ := json.Marshal(&request) - data, status, err := c.PutRequest("/messages", []byte(outgoing)) + data, status, err := c.PutRequest("/messages", outgoing) if err != nil { return resp, status, err } @@ -554,7 +556,7 @@ func (c *MgClient) DeleteMessage(request DeleteData) (*MessagesResponse, int, er data, status, err := c.DeleteRequest( "/messages", - []byte(outgoing), + outgoing, ) if err != nil { return nil, status, err @@ -605,7 +607,7 @@ func (c *MgClient) GetFile(request string) (FullFileResponse, int, error) { return resp, status, err } -// UploadFile upload file +// UploadFile upload file. func (c *MgClient) UploadFile(request io.Reader) (UploadFileResponse, int, error) { var resp UploadFileResponse @@ -625,7 +627,7 @@ func (c *MgClient) UploadFile(request io.Reader) (UploadFileResponse, int, error return resp, status, err } -// UploadFileByURL upload file by url +// UploadFileByURL upload file by url. func (c *MgClient) UploadFileByURL(request UploadFileByUrlRequest) (UploadFileResponse, int, error) { var resp UploadFileResponse outgoing, _ := json.Marshal(&request) @@ -658,7 +660,7 @@ func (c *MgClient) Error(info []byte) error { return errors.New(values[0].(string)) } -// MakeTimestamp returns current unix timestamp +// MakeTimestamp returns current unix timestamp. func MakeTimestamp() int64 { return time.Now().UnixNano() / (int64(time.Millisecond) / int64(time.Nanosecond)) } diff --git a/v1/client_test.go b/v1/client_test.go index b6be346..4fb112e 100644 --- a/v1/client_test.go +++ b/v1/client_test.go @@ -5,105 +5,113 @@ import ( "encoding/base64" "fmt" "net/http" - "os" - "strconv" + "strings" "testing" "time" - "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/suite" + "gopkg.in/h2non/gock.v1" ) -var ( - mgURL = os.Getenv("MG_URL") - 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 -) +type MGClientTest struct { + suite.Suite +} -func client() *MgClient { - c := New(mgURL, mgToken) +func TestMGClient(t *testing.T) { + suite.Run(t, new(MGClientTest)) +} + +func (t *MGClientTest) client() *MgClient { + c := New("https://mg-test.retailcrm.pro", "mg_token") c.Debug = true return c } -func templateChannel(t *testing.T) uint64 { - if tplChannel == 0 { - c := client() - resp, _, err := c.ActivateTransportChannel(Channel{ - Type: "telegram", - Name: "@test_channel_templates", +func (t *MGClientTest) gock() *gock.Request { + return gock.New("https://mg-test.retailcrm.pro").MatchHeader("x-transport-token", "mg_token") +} + +func (t *MGClientTest) transportURL(path string) string { + 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{ Status: Status{ - Delivered: ChannelFeatureBoth, - Read: ChannelFeatureBoth, + Delivered: ChannelFeatureNone, + Read: ChannelFeatureSend, }, Text: ChannelSettingsText{ Creating: ChannelFeatureBoth, Editing: ChannelFeatureBoth, Quoting: ChannelFeatureBoth, - Deleting: ChannelFeatureBoth, - MaxCharsCount: 5000, + Deleting: ChannelFeatureReceive, + MaxCharsCount: 4096, }, Product: Product{ - Creating: ChannelFeatureBoth, - Editing: ChannelFeatureBoth, - Deleting: ChannelFeatureBoth, + Creating: ChannelFeatureReceive, + Editing: ChannelFeatureReceive, }, Order: Order{ - Creating: ChannelFeatureBoth, - Editing: ChannelFeatureBoth, - Deleting: ChannelFeatureBoth, + Creating: ChannelFeatureReceive, + Editing: ChannelFeatureReceive, }, File: ChannelSettingsFilesBase{ - Creating: ChannelFeatureBoth, - Editing: ChannelFeatureBoth, - Quoting: ChannelFeatureBoth, - Deleting: ChannelFeatureBoth, - Max: 1000000, - CommentMaxCharsCount: 128, + Creating: ChannelFeatureBoth, + Editing: ChannelFeatureBoth, + Quoting: ChannelFeatureBoth, + Deleting: ChannelFeatureReceive, + Max: 1, }, Image: ChannelSettingsFilesBase{ Creating: ChannelFeatureBoth, Editing: ChannelFeatureBoth, Quoting: ChannelFeatureBoth, - Deleting: ChannelFeatureBoth, + Deleting: ChannelFeatureReceive, + Max: 1, // nolint:gomnd + }, + Suggestions: ChannelSettingsSuggestions{ + Text: ChannelFeatureBoth, + Phone: ChannelFeatureBoth, + Email: ChannelFeatureBoth, }, CustomerExternalID: ChannelFeatureCustomerExternalIDPhone, SendingPolicy: SendingPolicy{ NewCustomer: ChannelFeatureSendingPolicyTemplate, }, }, - }) - - if err != nil { - t.FailNow() - } - - tplChannel = resp.ChannelID - } - - return tplChannel -} - -func TestMgClient_TransportChannels(t *testing.T) { - c := client() + CreatedAt: createdAt, + UpdatedAt: &createdAt, + ActivatedAt: createdAt, + DeactivatedAt: nil, + IsActive: true, + }}) data, status, err := c.TransportChannels(Channels{Active: true}) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) - if err != nil { - t.Errorf("%d %v", status, err) - } - - t.Logf("Channels found: %v", len(data)) + t.Assert().Len(data, 1) } -func TestMgClient_ActivateTransportChannel(t *testing.T) { - c := client() +func (t *MGClientTest) Test_ActivateTransportChannel() { + c := t.client() ch := Channel{ - ID: channelID, + ID: 1, Type: "telegram", Name: "@my_shopping_bot", 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) + t.Require().NoError(err) + t.Assert().Equal(http.StatusCreated, status) - if err != nil { - t.Errorf("%d %v", status, err) - } - - t.Logf("Activate selected channel: %v", data.ChannelID) + t.Assert().Equal(uint64(1), data.ChannelID) + t.Assert().Equal("external_id_1", data.ExternalID) + t.Assert().NotEmpty(data.ActivatedAt.String()) } -func TestMgClient_ActivateNewTransportChannel(t *testing.T) { - c := client() +func (t *MGClientTest) Test_ActivateNewTransportChannel() { + c := t.client() ch := Channel{ Type: "telegram", 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) + t.Require().NoError(err) + t.Assert().Equal(http.StatusCreated, status) - if err != nil { - t.Errorf("%d %v", status, err) - } - - t.Logf("New channel ID %v", data.ChannelID) + t.Assert().Equal(uint64(1), data.ChannelID) + t.Assert().Equal("external_id_1", data.ExternalID) + t.Assert().NotEmpty(data.ActivatedAt.String()) deleteData, status, err := c.DeactivateTransportChannel(data.ChannelID) - - if err != nil { - t.Errorf("%d %v", status, err) - } - - if deleteData.DeactivatedAt.String() == "" { - t.Errorf("%v", err) - } - - t.Logf("Deactivate new channel with ID %v", deleteData.ChannelID) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().NotEmpty(deleteData.DeactivatedAt.String()) + t.Assert().Equal(uint64(1), deleteData.ChannelID) } -func TestMgClient_UpdateTransportChannel(t *testing.T) { - c := client() +func (t *MGClientTest) Test_UpdateTransportChannel() { + c := t.client() ch := Channel{ - ID: channelID, + ID: 1, Name: "@my_shopping_bot_2", Settings: ChannelSettings{ 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) - - if status != http.StatusOK { - t.Errorf("%v", err) - } - - t.Logf("Update selected channel: %v", data.ChannelID) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().Equal(uint64(1), data.ChannelID) + t.Assert().Equal("external_id_1", data.ExternalID) + t.Assert().NotEmpty(data.UpdatedAt.String()) } -func TestMgClient_TransportTemplates(t *testing.T) { - c := client() +func (t *MGClientTest) Test_TransportTemplates() { + 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() - assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) - - t.Logf("Templates found: %#v", len(data)) + t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err)) + t.Assert().Equal(http.StatusOK, status) + t.Assert().Len(data, 1) for _, item := range data { for _, tpl := range item.Template { if tpl.Type == TemplateItemTypeText { - assert.Empty(t, tpl.VarType) + t.Assert().Empty(tpl.VarType) } else { - assert.Empty(t, tpl.Text) - assert.NotEmpty(t, tpl.VarType) + t.Assert().Empty(tpl.Text) + t.Assert().NotEmpty(tpl.VarType) 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) { - c := client() +func (t *MGClientTest) Test_ActivateTemplate() { + c := t.client() req := ActivateTemplateRequest{ - Code: tplCode, - Name: tplCode, + Code: "tplCode", + Name: "tplCode", Type: TemplateTypeText, Template: []TemplateItem{ { @@ -286,17 +352,22 @@ func TestMgClient_ActivateTemplate(t *testing.T) { }, } - status, err := c.ActivateTemplate(templateChannel(t), req) - assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) + defer gock.Off() + 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) { - c := client() +func (t *MGClientTest) Test_UpdateTemplate() { + c := t.client() tpl := Template{ - Code: tplCode, - ChannelID: templateChannel(t), + Code: "encodable#code", + ChannelID: 1, Name: "updated name", Enabled: true, 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) - 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() - assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) + t.Assert().NoError(err, fmt.Sprintf("%d %s", status, err)) for _, template := range templates { 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) { - c := client() +func (t *MGClientTest) Test_UpdateTemplateFail() { + c := t.client() tpl := Template{ Name: "updated name", 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) - 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) { - c := client() - status, err := c.DeactivateTemplate(templateChannel(t), tplCode) - assert.NoError(t, err, fmt.Sprintf("%d %s", status, err)) +func (t *MGClientTest) Test_DeactivateTemplate() { + c := t.client() + + 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) { - c := client() - t.Logf("%v", ext) +func (t *MGClientTest) Test_TextMessages() { + c := t.client() snd := SendData{ Message: Message{ - ExternalID: ext, + ExternalID: "external_id", Type: MsgTypeText, Text: "hello!", }, @@ -377,38 +479,61 @@ func TestMgClient_TextMessages(t *testing.T) { Nickname: "octopus", Firstname: "Joe", }, - Channel: channelID, + Channel: 1, 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) - - if status != http.StatusOK { - t.Errorf("%v", err) - } - - if data.Time.String() == "" { - t.Errorf("%v", err) - } - - t.Logf("Message %v is sent", data.MessageID) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().NotEmpty(data.Time.String()) + t.Assert().Equal(1, data.MessageID) } -func TestMgClient_ImageMessages(t *testing.T) { - c := client() - t.Logf("%v", ext) +func (t *MGClientTest) Test_ImageMessages() { + c := t.client() + + 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{ Url: "https://via.placeholder.com/1", }) - - if st != http.StatusOK { - t.Errorf("%v", err) - } + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, st) + t.Assert().Equal("1", uploadFileResponse.ID) snd := SendData{ Message: Message{ - ExternalID: ext + "file", + ExternalID: "file", Type: MsgTypeImage, Items: []Item{{ID: uploadFileResponse.ID}}, }, @@ -418,135 +543,138 @@ func TestMgClient_ImageMessages(t *testing.T) { Nickname: "octopus", Firstname: "Joe", }, - Channel: channelID, + Channel: 1, ExternalChatID: "24798237492374", } data, status, err := c.Messages(snd) - - if status != http.StatusOK { - t.Errorf("%v", err) - } - - if data.Time.String() == "" { - t.Errorf("%v", err) - } - - t.Logf("Message %v is sent", data.MessageID) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().NotEmpty(data.Time.String()) + t.Assert().Equal(1, data.MessageID) } -func TestMgClient_UpdateMessages(t *testing.T) { - c := client() - t.Logf("%v", ext) +func (t *MGClientTest) Test_UpdateMessages() { + c := t.client() sndU := EditMessageRequest{ EditMessageRequestMessage{ - ExternalID: ext, + ExternalID: "editing", 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) - - if status != http.StatusOK { - t.Errorf("%v", err) - } - - if dataU.Time.String() == "" { - t.Errorf("%v", err) - } - - t.Logf("Message %v updated", dataU.MessageID) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().NotEmpty(dataU.Time.String()) + t.Assert().Equal(1, dataU.MessageID) } -func TestMgClient_MarkMessageReadAndDelete(t *testing.T) { - c := client() - t.Logf("%v", ext) +func (t *MGClientTest) Test_MarkMessageReadAndDelete() { + c := t.client() snd := MarkMessageReadRequest{ 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) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) - if status != http.StatusOK { - t.Errorf("%v", err) - } - - t.Logf("Message ext marked as read") - - sndD := DeleteData{ + previousChatMessage, status, err := c.DeleteMessage(DeleteData{ Message{ - ExternalID: ext, + ExternalID: "deleted", }, - channelID, - } - - previousChatMessage, status, err := c.DeleteMessage(sndD) - - 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) - } + 1, + }) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().Equal(2, previousChatMessage.MessageID) } -func TestMgClient_DeactivateTransportChannel(t *testing.T) { - c := client() - deleteData, status, err := c.DeactivateTransportChannel(channelID) +func (t *MGClientTest) Test_DeactivateTransportChannel() { + c := t.client() - if err != nil { - t.Errorf("%d %v", status, err) - } + defer gock.Off() + t.gock(). + Delete(t.transportURL("channels/1")). + Reply(http.StatusOK). + JSON(DeleteResponse{ + ChannelID: 1, + DeactivatedAt: time.Now(), + }) - if deleteData.DeactivatedAt.String() == "" { - t.Errorf("%v", err) - } - - t.Logf("Deactivate selected channel: %v", deleteData.ChannelID) + deleteData, status, err := c.DeactivateTransportChannel(1) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) + t.Assert().NotEmpty(deleteData.DeactivatedAt.String()) + t.Assert().Equal(uint64(1), deleteData.ChannelID) } -func TestMgClient_UploadFile(t *testing.T) { - c := client() - t.Logf("%v", ext) +func (t *MGClientTest) Test_UploadFile() { + c := t.client() // 1x1 png picture img := "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEX/TQBcNTh/AAAAAXRSTlPM0jRW/QAAAApJREFUeJxjYgAAAAYAAzY3fKgAAAAASUVORK5CYII=" binary, err := base64.StdEncoding.DecodeString(img) 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)) + t.Require().NoError(err) + t.Assert().Equal(http.StatusOK, status) - if status != http.StatusOK { - t.Errorf("%v", err) - } - - t.Logf("Message %+v is sent", data) + resp.CreatedAt = data.CreatedAt + t.Assert().Equal(resp, data) } diff --git a/v1/request.go b/v1/request.go index 73c8813..11fd018 100644 --- a/v1/request.go +++ b/v1/request.go @@ -12,7 +12,7 @@ import ( var prefix = "/api/transport/v1" -// GetRequest implements GET Request +// GetRequest implements GET Request. func (c *MgClient) GetRequest(url string, parameters []byte) ([]byte, int, error) { return makeRequest( "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) { return makeRequest( "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) { return makeRequest( "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) { return makeRequest( "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) 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) } else { log.Printf("MG TRANSPORT API Request: %s %s %s %v", reqType, url, c.Token, buf) diff --git a/v1/template.go b/v1/template.go index d852047..7e37632 100644 --- a/v1/template.go +++ b/v1/template.go @@ -10,24 +10,24 @@ import ( const TemplateTypeText = "text" const ( - // TemplateItemTypeText is a type for text chunk in template + // TemplateItemTypeText is a type for text chunk in template. TemplateItemTypeText uint8 = iota - // TemplateItemTypeVar is a type for variable in template + // TemplateItemTypeVar is a type for variable in template. TemplateItemTypeVar ) const ( - // TemplateVarCustom is a custom variable type + // TemplateVarCustom is a custom variable type. TemplateVarCustom = "custom" - // TemplateVarName is a name variable type + // TemplateVarName is a name variable type. TemplateVarName = "name" - // TemplateVarFirstName is a first name variable type + // TemplateVarFirstName is a first name variable type. TemplateVarFirstName = "first_name" - // TemplateVarLastName is a last name variable type + // TemplateVarLastName is a last name variable type. 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{}{ TemplateVarCustom: nil, TemplateVarName: nil, @@ -35,7 +35,7 @@ var templateVarAssoc = map[string]interface{}{ TemplateVarLastName: nil, } -// Template struct +// Template struct. type Template struct { Code string `json:"code"` ChannelID uint64 `json:"channel_id,omitempty"` @@ -45,14 +45,14 @@ type Template struct { Template []TemplateItem `json:"template"` } -// TemplateItem is a part of template +// TemplateItem is a part of template. type TemplateItem struct { Type uint8 Text 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) { switch t.Type { case TemplateItemTypeText: @@ -71,7 +71,7 @@ func (t TemplateItem) MarshalJSON() ([]byte, error) { return nil, errors.New("unknown TemplateItem type") } -// UnmarshalJSON will correctly unmarshal TemplateItem +// UnmarshalJSON will correctly unmarshal TemplateItem. func (t *TemplateItem) UnmarshalJSON(b []byte) error { var obj interface{} err := json.Unmarshal(b, &obj) diff --git a/v1/types.go b/v1/types.go index 7551cc8..5e5362c 100644 --- a/v1/types.go +++ b/v1/types.go @@ -7,62 +7,62 @@ import ( "time" ) -//noinspection ALL +// noinspection ALL. const ( - // ChannelFeatureNone channel can not implement feature + // ChannelFeatureNone channel can not implement feature. ChannelFeatureNone string = "none" - // ChannelFeatureReceive channel implement feature on receive + // ChannelFeatureReceive channel implement feature on receive. ChannelFeatureReceive string = "receive" - // ChannelFeatureSend channel implement feature on send + // ChannelFeatureSend channel implement feature on send. ChannelFeatureSend string = "send" - // ChannelFeatureBoth channel implement feature on both directions + // ChannelFeatureBoth channel implement feature on both directions. ChannelFeatureBoth string = "both" - // ChannelFeatureAny channel implement feature on any + // ChannelFeatureAny channel implement feature on any. ChannelFeatureAny string = "any" - // ChannelFeatureSendingPolicyNo channel can not implement feature + // ChannelFeatureSendingPolicyNo channel can not implement feature. ChannelFeatureSendingPolicyNo string = "no" - // ChannelFeatureSendingPolicyTemplate channel can implement template + // ChannelFeatureSendingPolicyTemplate channel can implement template. ChannelFeatureSendingPolicyTemplate string = "template" - // ChannelFeatureCustomerExternalIDPhone customer externalId is phone + // ChannelFeatureCustomerExternalIDPhone customer externalId is phone. ChannelFeatureCustomerExternalIDPhone string = "phone" - // MsgTypeText text message + // MsgTypeText text message. MsgTypeText string = "text" - // MsgTypeSystem system message + // MsgTypeSystem system message. MsgTypeSystem string = "system" - // MsgTypeCommand command (for bots) + // MsgTypeCommand command (for bots). MsgTypeCommand string = "command" - // MsgTypeOrder order card + // MsgTypeOrder order card. MsgTypeOrder string = "order" - // MsgTypeProduct product card + // MsgTypeProduct product card. MsgTypeProduct string = "product" - // MsgTypeFile file card + // MsgTypeFile file card. MsgTypeFile string = "file" - // MsgTypeImage image card + // MsgTypeImage image card. MsgTypeImage string = "image" - // MsgTypeAudio audio + // MsgTypeAudio audio. MsgTypeAudio string = "audio" - // MsgOrderStatusCodeNew order status group new + // MsgOrderStatusCodeNew order status group new. MsgOrderStatusCodeNew = "new" - // MsgOrderStatusCodeApproval order status group approval + // MsgOrderStatusCodeApproval order status group approval. MsgOrderStatusCodeApproval = "approval" - // MsgOrderStatusCodeAssembling order status group assembling + // MsgOrderStatusCodeAssembling order status group assembling. MsgOrderStatusCodeAssembling = "assembling" - // MsgOrderStatusCodeDelivery order status group delivery + // MsgOrderStatusCodeDelivery order status group delivery. MsgOrderStatusCodeDelivery = "delivery" - // MsgOrderStatusCodeComplete order status group complete + // MsgOrderStatusCodeComplete order status group complete. MsgOrderStatusCodeComplete = "complete" - // MsgOrderStatusCodeCancel order status group cancel + // MsgOrderStatusCodeCancel order status group cancel. MsgOrderStatusCodeCancel = "cancel" FileSizeLimit = 20 * 1024 * 1024 ) const ( - // OriginatorCustomer means message was created by customer + // OriginatorCustomer means message was created by customer. 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 ) @@ -70,13 +70,13 @@ type ErrorType string const ( GeneralError ErrorType = "general" - CustomerNotExistsError = "customer_not_exists" - ReplyTimedOutError = "reply_timed_out" - SpamSuspicionError = "spam_suspicion" - AccessRestrictedError = "access_restricted" + CustomerNotExistsError ErrorType = "customer_not_exists" + ReplyTimedOutError ErrorType = "reply_timed_out" + SpamSuspicionError ErrorType = "spam_suspicion" + AccessRestrictedError ErrorType = "access_restricted" ) -// MgClient type +// MgClient type. type MgClient struct { URL string `json:"url"` Token string `json:"token"` @@ -84,17 +84,17 @@ type MgClient struct { httpClient *http.Client `json:"-"` } -// Channel type +// Channel type. type Channel struct { ID uint64 `json:"id,omitempty"` ExternalID string `json:"external_id,omitempty"` Type string `json:"type,omitempty"` Name string `json:"name,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 { Status Status `json:"status"` Text ChannelSettingsText `json:"text"` @@ -107,27 +107,27 @@ type ChannelSettings struct { Suggestions ChannelSettingsSuggestions `json:"suggestions,omitempty"` } -// Product type +// Product type. type Product struct { Creating string `json:"creating,omitempty"` Editing string `json:"editing,omitempty"` Deleting string `json:"deleting,omitempty"` } -// Order type +// Order type. type Order struct { Creating string `json:"creating,omitempty"` Editing string `json:"editing,omitempty"` Deleting string `json:"deleting,omitempty"` } -// Status struct +// Status struct. type Status struct { Delivered string `json:"delivered,omitempty"` Read string `json:"read,omitempty"` } -// ChannelSettingsText struct +// ChannelSettingsText struct. type ChannelSettingsText struct { Creating string `json:"creating,omitempty"` Editing string `json:"editing,omitempty"` @@ -136,7 +136,7 @@ type ChannelSettingsText struct { MaxCharsCount uint16 `json:"max_chars_count,omitempty"` } -// ChannelSettingsFilesBase struct +// ChannelSettingsFilesBase struct. type ChannelSettingsFilesBase struct { Creating string `json:"creating,omitempty"` Editing string `json:"editing,omitempty"` @@ -158,7 +158,7 @@ type ChannelSettingsSuggestions struct { Email string `json:"email,omitempty"` } -// FullFileResponse uploaded file data +// FullFileResponse uploaded file data. type FullFileResponse struct { ID string `json:"id,omitempty"` Type string `json:"type,omitempty"` @@ -166,7 +166,7 @@ type FullFileResponse struct { Url string `json:"url,omitempty"` } -// UploadFileResponse uploaded file data +// UploadFileResponse uploaded file data. type UploadFileResponse struct { ID string `json:"id"` Hash string `json:"hash"` @@ -178,38 +178,38 @@ type UploadFileResponse struct { CreatedAt time.Time `json:"created_at"` } -// FileMeta file metadata +// FileMeta file metadata. type FileMeta struct { Width *int `json:"width,omitempty"` Height *int `json:"height,omitempty"` } -// UploadFileByUrlRequest file url to upload +// UploadFileByUrlRequest file url to upload. type UploadFileByUrlRequest struct { Url string `json:"url"` } -// ActivateResponse channel activation response +// ActivateResponse channel activation response. type ActivateResponse struct { ChannelID uint64 `json:"id"` ExternalID string `json:"external_id"` ActivatedAt time.Time `json:"activated_at"` } -// UpdateResponse channel update response +// UpdateResponse channel update response. type UpdateResponse struct { ChannelID uint64 `json:"id"` ExternalID string `json:"external_id"` UpdatedAt time.Time `json:"updated_at"` } -// DeleteResponse channel deactivation response +// DeleteResponse channel deactivation response. type DeleteResponse struct { ChannelID uint64 `json:"id"` DeactivatedAt time.Time `json:"deactivated_at"` } -// ChannelListItem response struct +// ChannelListItem response struct. type ChannelListItem struct { ID uint64 `json:"id"` ExternalID string `json:"external_id"` @@ -223,7 +223,7 @@ type ChannelListItem struct { IsActive bool `json:"is_active"` } -// Channels request type +// Channels request type. type Channels struct { ID int `url:"id,omitempty" json:"id,omitempty"` Types []string `url:"types,omitempty" json:"types,omitempty"` @@ -235,7 +235,7 @@ type Channels struct { Limit int `url:"limit,omitempty" json:"limit,omitempty"` } -// Customer struct +// Customer struct. type Customer struct { ExternalID string `json:"external_id"` Nickname string `json:"nickname"` @@ -249,7 +249,7 @@ type Customer struct { Email string `json:"email,omitempty"` } -// Message struct +// Message struct. type Message struct { ExternalID string `json:"external_id"` Type string `json:"type,omitempty"` @@ -258,26 +258,26 @@ type Message struct { Items []Item `json:"items,omitempty"` } -// SendMessage struct +// SendMessage struct. type SendMessage struct { Message SentAt time.Time `json:"sent_at,omitempty"` } -// EditMessageRequest type +// EditMessageRequest type. type EditMessageRequest struct { Message EditMessageRequestMessage `json:"message"` Channel uint64 `json:"channel"` } -// EditMessageRequestMessage type +// EditMessageRequestMessage type. type EditMessageRequestMessage struct { ExternalID string `json:"external_id"` Text string `json:"text"` EditedAt int64 `json:"edited_at"` } -// SendData struct +// SendData struct. type SendData struct { Message Message `json:"message"` Originator Originator `json:"originator,omitempty"` @@ -288,51 +288,51 @@ type SendData struct { ReplyDeadline *time.Time `json:"reply_deadline,omitempty"` } -// Item struct +// Item struct. type Item struct { ID string `json:"id"` Caption string `json:"caption"` } -// SendMessageRequestQuote type +// SendMessageRequestQuote type. type SendMessageRequestQuote struct { ExternalID string `json:"external_id"` } -// MarkMessageReadResponse type +// MarkMessageReadResponse type. type MarkMessageReadResponse struct{} -// MarkMessageReadRequest type +// MarkMessageReadRequest type. type MarkMessageReadRequest struct { Message MarkMessageReadRequestMessage `json:"message"` ChannelID uint64 `json:"channel_id"` } -// MarkMessageReadRequestMessage type +// MarkMessageReadRequestMessage type. type MarkMessageReadRequestMessage struct { ExternalID string `json:"external_id"` } -// AckMessageRequest type +// AckMessageRequest type. type AckMessageRequest struct { ExternalMessageID string `json:"external_message_id"` Channel uint64 `json:"channel"` Error *MessageSentError `json:"error,omitempty"` } -// DeleteData struct +// DeleteData struct. type DeleteData struct { Message Message `json:"message"` Channel uint64 `json:"channel"` } -// MessagesResponse message event response +// MessagesResponse message event response. type MessagesResponse struct { MessageID int `json:"message_id,omitempty"` Time time.Time `json:"time,omitempty"` } -// WebhookRequest type +// WebhookRequest type. type WebhookRequest struct { Type string `json:"type"` Meta TransportRequestMeta `json:"meta"` @@ -340,20 +340,20 @@ type WebhookRequest struct { } // WebhookMessageSentResponse type -// Consider using this structure while processing webhook request +// Consider using this structure while processing webhook request. type WebhookMessageSentResponse struct { ExternalMessageID string `json:"external_message_id"` Error *MessageSentError `json:"error,omitempty"` Async bool `json:"async"` } -// MessageSentError type +// MessageSentError type. type MessageSentError struct { Code ErrorType `json:"code"` Message string `json:"message"` } -// WebhookData request data +// WebhookData request data. type WebhookData struct { ExternalUserID string `json:"external_user_id"` ExternalMessageID string `json:"external_message_id,omitempty"` @@ -394,7 +394,7 @@ type TemplateInfo struct { Args []string `json:"args,omitempty"` } -// FileItem struct +// FileItem struct. type FileItem struct { ID string `json:"id"` Size int `json:"size"` @@ -403,20 +403,20 @@ type FileItem struct { Width *int `json:"width,omitempty"` } -// MessageDataUser user data from webhook +// MessageDataUser user data from webhook. type MessageDataUser struct { FirstName string `json:"first_name"` LastName string `json:"last_name"` Avatar string `json:"avatar"` } -// MessageDataBot bot data from webhook +// MessageDataBot bot data from webhook. type MessageDataBot struct { Name string `json:"name"` Avatar string `json:"avatar"` } -// MessageDataProduct product data from webhook +// MessageDataProduct product data from webhook. type MessageDataProduct struct { ID uint64 `json:"id"` Name string `json:"name"` @@ -429,7 +429,7 @@ type MessageDataProduct struct { Quantity *MessageDataOrderQuantity `json:"quantity,omitempty"` } -// MessageDataOrder order data from webhook +// MessageDataOrder order data from webhook. type MessageDataOrder struct { Number string `json:"number"` Url string `json:"url,omitempty"` @@ -442,13 +442,13 @@ type MessageDataOrder struct { Items []MessageDataOrderItem `json:"items,omitempty"` } -// MessageDataOrderStatus type +// MessageDataOrderStatus type. type MessageDataOrderStatus struct { Code string `json:"code,omitempty"` Name string `json:"name,omitempty"` } -// MessageDataOrderItem type +// MessageDataOrderItem type. type MessageDataOrderItem struct { Name string `json:"name,omitempty"` Url string `json:"url,omitempty"` @@ -457,32 +457,32 @@ type MessageDataOrderItem struct { Price *MessageDataOrderCost `json:"price,omitempty"` } -// MessageDataOrderCost type +// MessageDataOrderCost type. type MessageDataOrderCost struct { Value float32 `json:"value,omitempty"` Currency string `json:"currency"` } -// MessageDataOrderQuantity type +// MessageDataOrderQuantity type. type MessageDataOrderQuantity struct { Value float32 `json:"value"` Unit string `json:"unit"` } -// MessageDataOrderPayment type +// MessageDataOrderPayment type. type MessageDataOrderPayment struct { Name string `json:"name"` Status *MessageDataOrderPaymentStatus `json:"status"` Amount *MessageDataOrderCost `json:"amount"` } -// MessageDataOrderPaymentStatus type +// MessageDataOrderPaymentStatus type. type MessageDataOrderPaymentStatus struct { - Name string `json:"name"` - Payed bool `json:"payed"` + Name string `json:"name"` + Paid bool `json:"paid"` } -// MessageDataOrderDelivery type +// MessageDataOrderDelivery type. type MessageDataOrderDelivery struct { Name string `json:"name"` Price *MessageDataOrderCost `json:"price"` @@ -490,7 +490,7 @@ type MessageDataOrderDelivery struct { Comment string `json:"comment,omitempty"` } -// TransportRequestMeta request metadata +// TransportRequestMeta request metadata. type TransportRequestMeta struct { ID uint64 `json:"id"` Timestamp int64 `json:"timestamp"` @@ -505,10 +505,10 @@ type ActivateTemplateRequest struct { var ErrInvalidOriginator = errors.New("invalid originator") -// Originator of message +// Originator of message. type Originator byte -// MarshalText marshals originator to text +// MarshalText marshals originator to text. func (o Originator) MarshalText() ([]byte, error) { switch o { case OriginatorCustomer: diff --git a/v1/types_test_1.13.go b/v1/types_test_1.13.go index 014f825..abb3f9d 100644 --- a/v1/types_test_1.13.go +++ b/v1/types_test_1.13.go @@ -1,3 +1,4 @@ +//go:build !go1.14 // +build !go1.14 package v1 diff --git a/v1/types_test_1.14.go b/v1/types_test_1.14.go index f2c31b6..557996b 100644 --- a/v1/types_test_1.14.go +++ b/v1/types_test_1.14.go @@ -1,3 +1,4 @@ +//go:build go1.14 // +build go1.14 package v1