From 450b287a703f6a4c1ba2cf971fe6cc1b737c22f3 Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Thu, 13 Sep 2018 23:09:26 +0300 Subject: [PATCH 01/10] orders & products --- go.mod | 5 +++-- go.sum | 14 ++++++-------- src/main.go | 12 ++++++------ src/routing.go | 27 +++++++++++++++++++++++++-- src/routing_test.go | 8 ++++++++ 5 files changed, 48 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 156135f..ea99b62 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/retailcrm/mg-transport-telegram require ( cloud.google.com/go v0.27.0 // indirect github.com/Microsoft/go-winio v0.4.11 // indirect - github.com/aws/aws-sdk-go v1.15.33 + github.com/aws/aws-sdk-go v1.15.35 github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20180901172138-1eb28afdf9b6 // indirect @@ -31,6 +31,7 @@ require ( github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae // indirect github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af // indirect github.com/json-iterator/go v1.1.5 // indirect + github.com/jstemmer/go-junit-report v0.0.0-20180614143834-385fac0ced9a // indirect github.com/jtolds/gls v4.2.1+incompatible // indirect github.com/kr/pretty v0.1.0 // indirect github.com/lib/pq v1.0.0 // indirect @@ -44,7 +45,7 @@ require ( github.com/pkg/errors v0.8.0 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/retailcrm/api-client-go v1.0.6 - github.com/retailcrm/mg-transport-api-client-go v1.1.8 + github.com/retailcrm/mg-transport-api-client-go v1.1.9 github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect diff --git a/go.sum b/go.sum index 895fa84..9792e97 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.4.11 h1:zoIOcVf0xPN1tnMVbTtEdI+P8OofVk3NObnwOQ6nK2Q= github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= -github.com/aws/aws-sdk-go v1.15.33 h1:Xch3KIkPonPmCiA/BlaRm+RljrWr3M5Jb4EeUpdgmTU= -github.com/aws/aws-sdk-go v1.15.33/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= +github.com/aws/aws-sdk-go v1.15.35 h1:roOTR0eOeCgYwrz3NXmrneLFBYdnK8epLedaRMm1kQg= +github.com/aws/aws-sdk-go v1.15.35/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2 h1:MmeatFT1pTPSVb4nkPmBFN/LRZ97vPjsFKsZrU3KKTs= github.com/certifi/gocertifi v0.0.0-20180905225744-ee1a9a0726d2/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -64,6 +64,8 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/json-iterator/go v1.1.5 h1:gL2yXlmiIo4+t+y32d4WGwOjKGYcGOuyrg46vadswDE= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20180614143834-385fac0ced9a h1:2qq552JOlVHGYvqPc9ynBnGPDHeA7p0/QRn2NkrO8vk= +github.com/jstemmer/go-junit-report v0.0.0-20180614143834-385fac0ced9a/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE= github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= @@ -93,12 +95,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/retailcrm/api-client-go v1.0.6 h1:4Q3e4ve8GOOHIQdq3/wTGqgWuWa1cKMKqmgrTv4FoDU= github.com/retailcrm/api-client-go v1.0.6/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c= -github.com/retailcrm/mg-transport-api-client-go v1.1.6 h1:bwBs+iJbJzTAUFbkz+LmOhpruYebrI26haPPzBlZaRU= -github.com/retailcrm/mg-transport-api-client-go v1.1.6/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= -github.com/retailcrm/mg-transport-api-client-go v1.1.7 h1:dKm2hhR6l1kQvYKjD50C4/W9EzfV6t6YVdhLxSExooU= -github.com/retailcrm/mg-transport-api-client-go v1.1.7/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= -github.com/retailcrm/mg-transport-api-client-go v1.1.8 h1:xLfy9j0VrAoAQUUtB5LllIqPFDvJ9H1xuri34kfZPPY= -github.com/retailcrm/mg-transport-api-client-go v1.1.8/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= +github.com/retailcrm/mg-transport-api-client-go v1.1.9 h1:ogh5ThoqZJM5v4ZY6CqctUj01pVVHfBLXkrmX+BFjHE= +github.com/retailcrm/mg-transport-api-client-go v1.1.9/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= diff --git a/src/main.go b/src/main.go index b003e90..ac990c4 100644 --- a/src/main.go +++ b/src/main.go @@ -15,12 +15,12 @@ type Options struct { } var ( - config *TransportConfig - orm *Orm - logger *logging.Logger - options Options - parser = flags.NewParser(&options, flags.Default) - rx = regexp.MustCompile(`/+$`) + config *TransportConfig + orm *Orm + logger *logging.Logger + options Options + parser = flags.NewParser(&options, flags.Default) + rx = regexp.MustCompile(`/+$`) currency = map[string]string{ "rub": "₽", "uah": "₴", diff --git a/src/routing.go b/src/routing.go index 29d0eef..2d36722 100644 --- a/src/routing.go +++ b/src/routing.go @@ -77,6 +77,10 @@ func addBotHandler(c *gin.Context) { Creating: v1.ChannelFeatureReceive, Editing: v1.ChannelFeatureReceive, }, + Order: v1.Order{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, }, } @@ -506,16 +510,35 @@ func mgWebhookHandler(c *gin.Context) { ) } - if msg.Data.Product.Img != "" { + if msg.Data.Product.Img != "" { mb = fmt.Sprintf("\n%s", msg.Data.Product.Img) } + } else if msg.Data.Type == v1.MsgTypeOrder { + mb = "**Заказ" + + if msg.Data.Order.Number != ""{ + mb += " " + msg.Data.Order.Number + } + + if msg.Data.Order.Date != "" { + mb += fmt.Sprintf(" (%s)", msg.Data.Order.Date) + } + + mb += "**\n" + if len(msg.Data.Order.Items) > 0 { + for _, v := range msg.Data.Order.Items { + mb += fmt.Sprintf("%s %v x %v %s\n", v.Name, v.Quantity.Value, v.Price.Value, currency[strings.ToLower(v.Price.Currency)]) + } + } + + mb += fmt.Sprintf("Сумма: %v %s", msg.Data.Order.Cost.Value, currency[strings.ToLower(msg.Data.Order.Cost.Currency)]) } else { mb = msg.Data.Content } m := tgbotapi.NewMessage(cid, mb) - if msg.Data.Type == v1.MsgTypeProduct { + if msg.Data.Type == v1.MsgTypeProduct || msg.Data.Type == v1.MsgTypeOrder { m.ParseMode = "Markdown" } diff --git a/src/routing_test.go b/src/routing_test.go index af770ad..108bec7 100644 --- a/src/routing_test.go +++ b/src/routing_test.go @@ -70,6 +70,14 @@ func TestRouting_addBotHandler(t *testing.T) { Quoting: v1.ChannelFeatureBoth, Deleting: v1.ChannelFeatureReceive, }, + Product: v1.Product{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, + Order: v1.Order{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, }, } From f0612fa90de5024d1094afe8881e2371aba87847 Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Thu, 13 Sep 2018 23:19:23 +0300 Subject: [PATCH 02/10] tests --- src/routing_test.go | 158 ++++++++++++++++++++++---------------------- 1 file changed, 79 insertions(+), 79 deletions(-) diff --git a/src/routing_test.go b/src/routing_test.go index 108bec7..6fc07af 100644 --- a/src/routing_test.go +++ b/src/routing_test.go @@ -53,85 +53,85 @@ func TestRouting_connectHandler(t *testing.T) { fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK)) } -func TestRouting_addBotHandler(t *testing.T) { - defer gock.Off() - - ch := v1.Channel{ - Type: "telegram", - Settings: v1.ChannelSettings{ - SpamAllowed: false, - Status: v1.Status{ - Delivered: v1.ChannelFeatureSend, - Read: v1.ChannelFeatureNone, - }, - Text: v1.ChannelSettingsText{ - Creating: v1.ChannelFeatureBoth, - Editing: v1.ChannelFeatureBoth, - Quoting: v1.ChannelFeatureBoth, - Deleting: v1.ChannelFeatureReceive, - }, - Product: v1.Product{ - Creating: v1.ChannelFeatureReceive, - Editing: v1.ChannelFeatureReceive, - }, - Order: v1.Order{ - Creating: v1.ChannelFeatureReceive, - Editing: v1.ChannelFeatureReceive, - }, - }, - } - - outgoing, _ := json.Marshal(ch) - p := url.Values{"url": {"https://" + config.HTTPServer.Host + "/telegram/123123:Qwerty"}} - - gock.New("https://api.telegram.org"). - Post("/bot123123:Qwerty/getMe"). - Reply(200). - BodyString(`{"ok":true,"result":{"id":123,"is_bot":true,"first_name":"Test","username":"TestBot"}}`) - - gock.New("https://api.telegram.org"). - Post("/bot123123:Qwerty/setWebhook"). - MatchType("url"). - BodyString(p.Encode()). - Reply(201). - BodyString(`{"ok":true}`) - - gock.New("https://api.telegram.org"). - Post("/bot123123:Qwerty/getWebhookInfo"). - Reply(200). - BodyString(`{"ok":true,"result":{"url":"https://` + config.HTTPServer.Host + `/telegram/123123:Qwerty","has_custom_certificate":false,"pending_update_count":0}}`) - - gock.New("https://test.retailcrm.pro"). - Post("/api/transport/v1/channels"). - JSON([]byte(outgoing)). - MatchHeader("Content-Type", "application/json"). - MatchHeader("X-Transport-Token", "test-token"). - Reply(201). - BodyString(`{"id": 1}`) - - req, err := http.NewRequest("POST", "/add-bot/", strings.NewReader(`{"token": "123123:Qwerty", "connectionId": 1}`)) - if err != nil { - t.Fatal(err) - } - rr := httptest.NewRecorder() - router.ServeHTTP(rr, req) - require.Equal(t, http.StatusCreated, rr.Code, - fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusCreated)) - - bytes, err := ioutil.ReadAll(rr.Body) - if err != nil { - t.Fatal(err) - } - - var res map[string]interface{} - - err = json.Unmarshal(bytes, &res) - if err != nil { - t.Fatal(err) - } - - assert.Equal(t, "123123:Qwerty", res["token"]) -} +// func TestRouting_addBotHandler(t *testing.T) { +// defer gock.Off() +// +// ch := v1.Channel{ +// Type: "telegram", +// Settings: v1.ChannelSettings{ +// SpamAllowed: false, +// Status: v1.Status{ +// Delivered: v1.ChannelFeatureSend, +// Read: v1.ChannelFeatureNone, +// }, +// Text: v1.ChannelSettingsText{ +// Creating: v1.ChannelFeatureBoth, +// Editing: v1.ChannelFeatureBoth, +// Quoting: v1.ChannelFeatureBoth, +// Deleting: v1.ChannelFeatureReceive, +// }, +// Product: v1.Product{ +// Creating: v1.ChannelFeatureReceive, +// Editing: v1.ChannelFeatureReceive, +// }, +// Order: v1.Order{ +// Creating: v1.ChannelFeatureReceive, +// Editing: v1.ChannelFeatureReceive, +// }, +// }, +// } +// +// outgoing, _ := json.Marshal(ch) +// p := url.Values{"url": {"https://" + config.HTTPServer.Host + "/telegram/123123:Qwerty"}} +// +// gock.New("https://api.telegram.org"). +// Post("/bot123123:Qwerty/getMe"). +// Reply(200). +// BodyString(`{"ok":true,"result":{"id":123,"is_bot":true,"first_name":"Test","username":"TestBot"}}`) +// +// gock.New("https://api.telegram.org"). +// Post("/bot123123:Qwerty/setWebhook"). +// MatchType("url"). +// BodyString(p.Encode()). +// Reply(201). +// BodyString(`{"ok":true}`) +// +// gock.New("https://api.telegram.org"). +// Post("/bot123123:Qwerty/getWebhookInfo"). +// Reply(200). +// BodyString(`{"ok":true,"result":{"url":"https://` + config.HTTPServer.Host + `/telegram/123123:Qwerty","has_custom_certificate":false,"pending_update_count":0}}`) +// +// gock.New("https://test.retailcrm.pro"). +// Post("/api/transport/v1/channels"). +// JSON([]byte(outgoing)). +// MatchHeader("Content-Type", "application/json"). +// MatchHeader("X-Transport-Token", "test-token"). +// Reply(201). +// BodyString(`{"id": 1}`) +// +// req, err := http.NewRequest("POST", "/add-bot/", strings.NewReader(`{"token": "123123:Qwerty", "connectionId": 1}`)) +// if err != nil { +// t.Fatal(err) +// } +// rr := httptest.NewRecorder() +// router.ServeHTTP(rr, req) +// require.Equal(t, http.StatusCreated, rr.Code, +// fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusCreated)) +// +// bytes, err := ioutil.ReadAll(rr.Body) +// if err != nil { +// t.Fatal(err) +// } +// +// var res map[string]interface{} +// +// err = json.Unmarshal(bytes, &res) +// if err != nil { +// t.Fatal(err) +// } +// +// assert.Equal(t, "123123:Qwerty", res["token"]) +// } func TestRouting_deleteBotHandler(t *testing.T) { defer gock.Off() From ba86be8604717b74a2875ccb61f753dd4e5e6bdf Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Thu, 13 Sep 2018 23:25:23 +0300 Subject: [PATCH 03/10] test --- src/routing_test.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/routing_test.go b/src/routing_test.go index 6fc07af..24d9028 100644 --- a/src/routing_test.go +++ b/src/routing_test.go @@ -1,9 +1,7 @@ package main import ( - "encoding/json" "fmt" - "io/ioutil" "net/http" "net/http/httptest" "net/url" @@ -15,7 +13,6 @@ import ( "github.com/h2non/gock" "github.com/retailcrm/mg-transport-api-client-go/v1" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" ) var router *gin.Engine From 2b1ee5ca5bc6c60c688e13150a6858bd3a2e2bb1 Mon Sep 17 00:00:00 2001 From: Alex Lushpai Date: Wed, 19 Sep 2018 16:34:13 +0300 Subject: [PATCH 04/10] update for order & products, minor fixes --- Jenkinsfile | 1 - Makefile | 2 +- src/routing.go | 30 ++++----- src/routing_test.go | 161 ++++++++++++++++++++++---------------------- 4 files changed, 95 insertions(+), 99 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 8906707..89489b7 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -17,7 +17,6 @@ pipeline { steps { sh 'cp config_test.yml.dist config_test.yml' compose 'up -d --build postgres_test' - compose 'run --rm mg_telegram_test make migrate_test' } } diff --git a/Makefile b/Makefile index f8a1515..0630871 100644 --- a/Makefile +++ b/Makefile @@ -19,7 +19,7 @@ test: deps fmt @echo "==> Running tests" @cd $(ROOT_DIR) && go test ./... -v -cpu 2 -jenkins_test: deps +jenkins_test: migrate_test @echo "==> Running tests (result in test-report.xml)" @go get -v -u github.com/jstemmer/go-junit-report @go test ./... -v -cpu 2 -race | /go/bin/go-junit-report -set-exit-code > ./test-report.xml diff --git a/src/routing.go b/src/routing.go index 2d36722..046cd74 100644 --- a/src/routing.go +++ b/src/routing.go @@ -497,27 +497,25 @@ func mgWebhookHandler(c *gin.Context) { case "message_sent": var mb string if msg.Data.Type == v1.MsgTypeProduct { - mb = fmt.Sprintf( - "[%s](%s)", - msg.Data.Product.Name, - msg.Data.Product.Url, - ) + mb = fmt.Sprintf("%s\n", msg.Data.Product.Name) + if msg.Data.Product.Cost != nil && msg.Data.Product.Cost.Value != 0 { mb += fmt.Sprintf( - "\n%v %s", + "\n%v %s\n", msg.Data.Product.Cost.Value, currency[strings.ToLower(msg.Data.Product.Cost.Currency)], ) } - if msg.Data.Product.Img != "" { - mb = fmt.Sprintf("\n%s", msg.Data.Product.Img) + if msg.Data.Product.Url != "" { + mb += msg.Data.Product.Url + } else { + mb += msg.Data.Product.Img } - } else if msg.Data.Type == v1.MsgTypeOrder { - mb = "**Заказ" + mb = "Заказ" - if msg.Data.Order.Number != ""{ + if msg.Data.Order.Number != "" { mb += " " + msg.Data.Order.Number } @@ -525,10 +523,10 @@ func mgWebhookHandler(c *gin.Context) { mb += fmt.Sprintf(" (%s)", msg.Data.Order.Date) } - mb += "**\n" + mb += "\n" if len(msg.Data.Order.Items) > 0 { - for _, v := range msg.Data.Order.Items { - mb += fmt.Sprintf("%s %v x %v %s\n", v.Name, v.Quantity.Value, v.Price.Value, currency[strings.ToLower(v.Price.Currency)]) + for _, v := range msg.Data.Order.Items { + mb += fmt.Sprintf("%s %v x %v %s\n", v.Name, v.Quantity.Value, v.Price.Value, currency[strings.ToLower(v.Price.Currency)]) } } @@ -538,10 +536,6 @@ func mgWebhookHandler(c *gin.Context) { } m := tgbotapi.NewMessage(cid, mb) - if msg.Data.Type == v1.MsgTypeProduct || msg.Data.Type == v1.MsgTypeOrder { - m.ParseMode = "Markdown" - } - if msg.Data.QuoteExternalID != "" { qid, err := strconv.Atoi(msg.Data.QuoteExternalID) if err != nil { diff --git a/src/routing_test.go b/src/routing_test.go index 24d9028..e86ac04 100644 --- a/src/routing_test.go +++ b/src/routing_test.go @@ -1,7 +1,9 @@ package main import ( + "encoding/json" "fmt" + "io/ioutil" "net/http" "net/http/httptest" "net/url" @@ -13,6 +15,7 @@ import ( "github.com/h2non/gock" "github.com/retailcrm/mg-transport-api-client-go/v1" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) var router *gin.Engine @@ -50,85 +53,85 @@ func TestRouting_connectHandler(t *testing.T) { fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK)) } -// func TestRouting_addBotHandler(t *testing.T) { -// defer gock.Off() -// -// ch := v1.Channel{ -// Type: "telegram", -// Settings: v1.ChannelSettings{ -// SpamAllowed: false, -// Status: v1.Status{ -// Delivered: v1.ChannelFeatureSend, -// Read: v1.ChannelFeatureNone, -// }, -// Text: v1.ChannelSettingsText{ -// Creating: v1.ChannelFeatureBoth, -// Editing: v1.ChannelFeatureBoth, -// Quoting: v1.ChannelFeatureBoth, -// Deleting: v1.ChannelFeatureReceive, -// }, -// Product: v1.Product{ -// Creating: v1.ChannelFeatureReceive, -// Editing: v1.ChannelFeatureReceive, -// }, -// Order: v1.Order{ -// Creating: v1.ChannelFeatureReceive, -// Editing: v1.ChannelFeatureReceive, -// }, -// }, -// } -// -// outgoing, _ := json.Marshal(ch) -// p := url.Values{"url": {"https://" + config.HTTPServer.Host + "/telegram/123123:Qwerty"}} -// -// gock.New("https://api.telegram.org"). -// Post("/bot123123:Qwerty/getMe"). -// Reply(200). -// BodyString(`{"ok":true,"result":{"id":123,"is_bot":true,"first_name":"Test","username":"TestBot"}}`) -// -// gock.New("https://api.telegram.org"). -// Post("/bot123123:Qwerty/setWebhook"). -// MatchType("url"). -// BodyString(p.Encode()). -// Reply(201). -// BodyString(`{"ok":true}`) -// -// gock.New("https://api.telegram.org"). -// Post("/bot123123:Qwerty/getWebhookInfo"). -// Reply(200). -// BodyString(`{"ok":true,"result":{"url":"https://` + config.HTTPServer.Host + `/telegram/123123:Qwerty","has_custom_certificate":false,"pending_update_count":0}}`) -// -// gock.New("https://test.retailcrm.pro"). -// Post("/api/transport/v1/channels"). -// JSON([]byte(outgoing)). -// MatchHeader("Content-Type", "application/json"). -// MatchHeader("X-Transport-Token", "test-token"). -// Reply(201). -// BodyString(`{"id": 1}`) -// -// req, err := http.NewRequest("POST", "/add-bot/", strings.NewReader(`{"token": "123123:Qwerty", "connectionId": 1}`)) -// if err != nil { -// t.Fatal(err) -// } -// rr := httptest.NewRecorder() -// router.ServeHTTP(rr, req) -// require.Equal(t, http.StatusCreated, rr.Code, -// fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusCreated)) -// -// bytes, err := ioutil.ReadAll(rr.Body) -// if err != nil { -// t.Fatal(err) -// } -// -// var res map[string]interface{} -// -// err = json.Unmarshal(bytes, &res) -// if err != nil { -// t.Fatal(err) -// } -// -// assert.Equal(t, "123123:Qwerty", res["token"]) -// } +func TestRouting_addBotHandler(t *testing.T) { + defer gock.Off() + + ch := v1.Channel{ + Type: "telegram", + Settings: v1.ChannelSettings{ + SpamAllowed: false, + Status: v1.Status{ + Delivered: v1.ChannelFeatureSend, + Read: v1.ChannelFeatureNone, + }, + Text: v1.ChannelSettingsText{ + Creating: v1.ChannelFeatureBoth, + Editing: v1.ChannelFeatureBoth, + Quoting: v1.ChannelFeatureBoth, + Deleting: v1.ChannelFeatureReceive, + }, + Product: v1.Product{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, + Order: v1.Order{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, + }, + } + + outgoing, _ := json.Marshal(&ch) + p := url.Values{"url": {"https://" + config.HTTPServer.Host + "/telegram/123123:Qwerty"}} + + gock.New("https://api.telegram.org"). + Post("/bot123123:Qwerty/getMe"). + Reply(200). + BodyString(`{"ok":true,"result":{"id":123,"is_bot":true,"first_name":"Test","username":"TestBot"}}`) + + gock.New("https://api.telegram.org"). + Post("/bot123123:Qwerty/setWebhook"). + MatchType("url"). + BodyString(p.Encode()). + Reply(201). + BodyString(`{"ok":true}`) + + gock.New("https://api.telegram.org"). + Post("/bot123123:Qwerty/getWebhookInfo"). + Reply(200). + BodyString(`{"ok":true,"result":{"url":"https://` + config.HTTPServer.Host + `/telegram/123123:Qwerty","has_custom_certificate":false,"pending_update_count":0}}`) + + gock.New("https://test.retailcrm.pro"). + Post("/api/transport/v1/channels"). + JSON([]byte(outgoing)). + MatchHeader("Content-Type", "application/json"). + MatchHeader("X-Transport-Token", "test-token"). + Reply(201). + BodyString(`{"id": 1}`) + + req, err := http.NewRequest("POST", "/add-bot/", strings.NewReader(`{"token": "123123:Qwerty", "connectionId": 1}`)) + if err != nil { + t.Fatal(err) + } + rr := httptest.NewRecorder() + router.ServeHTTP(rr, req) + require.Equal(t, http.StatusCreated, rr.Code, + fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusCreated)) + + bytes, err := ioutil.ReadAll(rr.Body) + if err != nil { + t.Fatal(err) + } + + var res map[string]interface{} + + err = json.Unmarshal(bytes, &res) + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "123123:Qwerty", res["token"]) +} func TestRouting_deleteBotHandler(t *testing.T) { defer gock.Off() From 38b6cac55cb49b24e48bd10a641d1baefa9f3358 Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Fri, 21 Sep 2018 12:06:33 +0300 Subject: [PATCH 05/10] add update channels settings --- migrations/1537271655_app.down.sql | 1 + migrations/1537271655_app.up.sql | 1 + src/main.go | 2 + src/models.go | 15 ++-- src/repository.go | 11 +++ src/routing.go | 122 ++++++++++++++++++++++------- src/run.go | 1 + src/utils.go | 12 +++ 8 files changed, 130 insertions(+), 35 deletions(-) create mode 100644 migrations/1537271655_app.down.sql create mode 100644 migrations/1537271655_app.up.sql diff --git a/migrations/1537271655_app.down.sql b/migrations/1537271655_app.down.sql new file mode 100644 index 0000000..b524f32 --- /dev/null +++ b/migrations/1537271655_app.down.sql @@ -0,0 +1 @@ +alter table bot drop column channel_settings_hash; diff --git a/migrations/1537271655_app.up.sql b/migrations/1537271655_app.up.sql new file mode 100644 index 0000000..35f92c5 --- /dev/null +++ b/migrations/1537271655_app.up.sql @@ -0,0 +1 @@ +alter table bot add column channel_settings_hash varchar(70); diff --git a/src/main.go b/src/main.go index ac990c4..35e8319 100644 --- a/src/main.go +++ b/src/main.go @@ -14,6 +14,8 @@ type Options struct { Config string `short:"c" long:"config" default:"config.yml" description:"Path to configuration file"` } +const Type = "telegram" + var ( config *TransportConfig orm *Orm diff --git a/src/models.go b/src/models.go index 7a118f0..4d9622f 100644 --- a/src/models.go +++ b/src/models.go @@ -18,13 +18,14 @@ type Connection struct { // Bot model type Bot struct { - ID int `gorm:"primary_key"` - ConnectionID int `gorm:"connection_id" json:"connectionId,omitempty"` - Channel uint64 `gorm:"channel;not null;unique" json:"channel,omitempty"` - Token string `gorm:"token type:varchar(100);not null;unique" json:"token,omitempty"` - Name string `gorm:"name type:varchar(40)" json:"name,omitempty"` - CreatedAt time.Time - UpdatedAt time.Time + ID int `gorm:"primary_key"` + ConnectionID int `gorm:"connection_id" json:"connectionId,omitempty"` + Channel uint64 `gorm:"channel;not null;unique" json:"channel,omitempty"` + ChannelSettingsHash string `gorm:"channel_settings_hash type:varchar(70)"` + Token string `gorm:"token type:varchar(100);not null;unique" json:"token,omitempty"` + Name string `gorm:"name type:varchar(40)" json:"name,omitempty"` + CreatedAt time.Time + UpdatedAt time.Time } // User model diff --git a/src/repository.go b/src/repository.go index 522f280..089651c 100644 --- a/src/repository.go +++ b/src/repository.go @@ -13,6 +13,13 @@ func getConnection(uid string) *Connection { return &connection } +func getConnections() []*Connection { + var connection []*Connection + orm.DB.Find(&connection) + + return connection +} + func getConnectionByURL(urlCrm string) *Connection { var connection Connection orm.DB.First(&connection, "api_url = ?", urlCrm) @@ -52,6 +59,10 @@ func getBotByToken(token string) (*Bot, error) { return &bot, nil } +func (b *Bot) save() error { + return orm.DB.Save(b).Error +} + func (b *Bot) deleteBot() error { return orm.DB.Delete(b, "token = ?", b.Token).Error } diff --git a/src/routing.go b/src/routing.go index 046cd74..468ebcc 100644 --- a/src/routing.go +++ b/src/routing.go @@ -58,36 +58,10 @@ func addBotHandler(c *gin.Context) { } b.Name = bot.Self.FirstName - - ch := v1.Channel{ - Type: "telegram", - Settings: v1.ChannelSettings{ - SpamAllowed: false, - Status: v1.Status{ - Delivered: v1.ChannelFeatureSend, - Read: v1.ChannelFeatureNone, - }, - Text: v1.ChannelSettingsText{ - Creating: v1.ChannelFeatureBoth, - Editing: v1.ChannelFeatureBoth, - Quoting: v1.ChannelFeatureBoth, - Deleting: v1.ChannelFeatureReceive, - }, - Product: v1.Product{ - Creating: v1.ChannelFeatureReceive, - Editing: v1.ChannelFeatureReceive, - }, - Order: v1.Order{ - Creating: v1.ChannelFeatureReceive, - Editing: v1.ChannelFeatureReceive, - }, - }, - } - conn := getConnectionById(b.ConnectionID) + client := v1.New(conn.MGURL, conn.MGToken) - var client = v1.New(conn.MGURL, conn.MGToken) - data, status, err := client.ActivateTransportChannel(ch) + data, status, err := client.ActivateTransportChannel(getChannelSettings()) if status != http.StatusCreated { c.AbortWithStatusJSON(BadRequest("error_activating_channel")) logger.Error(conn.APIURL, status, err.Error(), data) @@ -305,6 +279,98 @@ func getIntegrationModule(clientId string) v5.IntegrationModule { } } +func getChannelSettings(cid ...uint64) v1.Channel { + var channelID uint64 + + if len(cid) > 0 { + channelID = cid[0] + } + + return v1.Channel{ + ID: channelID, + Type: Type, + Settings: v1.ChannelSettings{ + SpamAllowed: false, + Status: v1.Status{ + Delivered: v1.ChannelFeatureSend, + Read: v1.ChannelFeatureNone, + }, + Text: v1.ChannelSettingsText{ + Creating: v1.ChannelFeatureBoth, + Editing: v1.ChannelFeatureBoth, + Quoting: v1.ChannelFeatureBoth, + Deleting: v1.ChannelFeatureReceive, + }, + Product: v1.Product{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, + Order: v1.Order{ + Creating: v1.ChannelFeatureReceive, + Editing: v1.ChannelFeatureReceive, + }, + }, + } +} + +func updateChannelsSettings() { + hashSettings, err := getChannelSettingsHash() + if err != nil { + logger.Error(err.Error()) + return + } + + connections := getConnections() + if len(connections) > 0 { + for _, conn := range connections { + if !conn.Active { + logger.Infof( + "updateChannelsSettings connection %s deactivated", + conn.APIURL, + ) + continue + } + updateBots(conn, hashSettings) + } + } + + return +} + +func updateBots(conn *Connection, hashSettings string) { + bots := conn.getBotsByClientID() + if len(bots) > 0 { + client := v1.New(conn.MGURL, conn.MGToken) + for _, bot := range bots { + if bot.ChannelSettingsHash == hashSettings { + continue + } + + data, status, err := client.UpdateTransportChannel(getChannelSettings(bot.Channel)) + if config.Debug { + logger.Infof( + "updateChannelsSettings apiURL: %s, ChannelID: %d, Data: %v, Status: %d, err: %v", + conn.APIURL, bot.Channel, data, status, err, + ) + } + + if err == nil { + bot.ChannelSettingsHash = hashSettings + err = bot.save() + if err != nil { + logger.Error( + "updateChannelsSettings bot.save apiURL: %s, bot.Channel: %d , err: %v", + conn.APIURL, bot.Channel, err, + ) + } + } + + } + } + + return +} + func telegramWebhookHandler(c *gin.Context) { token := c.Param("token") b, err := getBotByToken(token) diff --git a/src/run.go b/src/run.go index 3032243..577769a 100644 --- a/src/run.go +++ b/src/run.go @@ -53,6 +53,7 @@ func start() { func setup() *gin.Engine { loadTranslateFile() setValidation() + updateChannelsSettings() if config.Debug == false { gin.SetMode(gin.ReleaseMode) diff --git a/src/utils.go b/src/utils.go index 9da0790..3c8177c 100644 --- a/src/utils.go +++ b/src/utils.go @@ -1,7 +1,9 @@ package main import ( + "crypto/sha1" "crypto/sha256" + "encoding/json" "errors" "fmt" "net/http" @@ -119,3 +121,13 @@ func UploadUserAvatar(url string) (picURLs3 string, err error) { return } + +func getChannelSettingsHash() (hash string, err error) { + res, err := json.Marshal(getChannelSettings()) + + h := sha1.New() + h.Write(res) + hash = fmt.Sprintf("%x", h.Sum(nil)) + + return +} From b4bc035f81e4a1d5856483db26762f9bff863326 Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Fri, 21 Sep 2018 12:18:29 +0300 Subject: [PATCH 06/10] update transport-api-client --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index ea99b62..d2d168d 100644 --- a/go.mod +++ b/go.mod @@ -45,7 +45,7 @@ require ( github.com/pkg/errors v0.8.0 github.com/pmezard/go-difflib v1.0.0 // indirect github.com/retailcrm/api-client-go v1.0.6 - github.com/retailcrm/mg-transport-api-client-go v1.1.9 + github.com/retailcrm/mg-transport-api-client-go v1.1.10 github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect diff --git a/go.sum b/go.sum index 9792e97..bc464c0 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/retailcrm/api-client-go v1.0.6 h1:4Q3e4ve8GOOHIQdq3/wTGqgWuWa1cKMKqmg github.com/retailcrm/api-client-go v1.0.6/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c= github.com/retailcrm/mg-transport-api-client-go v1.1.9 h1:ogh5ThoqZJM5v4ZY6CqctUj01pVVHfBLXkrmX+BFjHE= github.com/retailcrm/mg-transport-api-client-go v1.1.9/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= +github.com/retailcrm/mg-transport-api-client-go v1.1.10 h1:RR8S5NA6FPVrF6UVXaLwu/gJyKUg5aUObQ97S98M3Yc= +github.com/retailcrm/mg-transport-api-client-go v1.1.10/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= From 9d6ebb540f9db728453d921fb3c174484de35c8f Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Fri, 21 Sep 2018 12:25:31 +0300 Subject: [PATCH 07/10] add order message --- src/locale.go | 7 ++ src/routing.go | 135 ++++++++++++++++++++++++++++++------- src/utils.go | 15 +++-- translate/translate.en.yml | 7 ++ translate/translate.es.yml | 7 ++ translate/translate.ru.yml | 7 ++ 6 files changed, 147 insertions(+), 31 deletions(-) diff --git a/src/locale.go b/src/locale.go index 88301bb..8945c9d 100644 --- a/src/locale.go +++ b/src/locale.go @@ -41,6 +41,13 @@ func getLocalizedMessage(messageID string) string { return localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID}) } +func getLocalizedTemplateMessage(messageID string, templateData map[string]interface{}) string { + return localizer.MustLocalize(&i18n.LocalizeConfig{ + MessageID: messageID, + TemplateData: templateData, + }) +} + func getLocale() map[string]interface{} { return map[string]interface{}{ "ButtonSave": getLocalizedMessage("button_save"), diff --git a/src/routing.go b/src/routing.go index 468ebcc..cf9cfb3 100644 --- a/src/routing.go +++ b/src/routing.go @@ -562,14 +562,21 @@ func mgWebhookHandler(c *gin.Context) { switch msg.Type { case "message_sent": var mb string - if msg.Data.Type == v1.MsgTypeProduct { + switch msg.Data.Type { + case v1.MsgTypeProduct: mb = fmt.Sprintf("%s\n", msg.Data.Product.Name) if msg.Data.Product.Cost != nil && msg.Data.Product.Cost.Value != 0 { mb += fmt.Sprintf( - "\n%v %s\n", - msg.Data.Product.Cost.Value, - currency[strings.ToLower(msg.Data.Product.Cost.Currency)], + "\n%s: %s", + getLocalizedMessage("item_cost"), + getLocalizedTemplateMessage( + "cost_currency", + map[string]interface{}{ + "CostValue": msg.Data.Product.Cost.Value, + "CostCurrency": currency[strings.ToLower(msg.Data.Product.Cost.Currency)], + }, + ), ) } @@ -578,26 +585,9 @@ func mgWebhookHandler(c *gin.Context) { } else { mb += msg.Data.Product.Img } - } else if msg.Data.Type == v1.MsgTypeOrder { - mb = "Заказ" - - if msg.Data.Order.Number != "" { - mb += " " + msg.Data.Order.Number - } - - if msg.Data.Order.Date != "" { - mb += fmt.Sprintf(" (%s)", msg.Data.Order.Date) - } - - mb += "\n" - if len(msg.Data.Order.Items) > 0 { - for _, v := range msg.Data.Order.Items { - mb += fmt.Sprintf("%s %v x %v %s\n", v.Name, v.Quantity.Value, v.Price.Value, currency[strings.ToLower(v.Price.Currency)]) - } - } - - mb += fmt.Sprintf("Сумма: %v %s", msg.Data.Order.Cost.Value, currency[strings.ToLower(msg.Data.Order.Cost.Currency)]) - } else { + case v1.MsgTypeOrder: + mb = getOrderMessage(msg.Data.Order) + case v1.MsgTypeText: mb = msg.Data.Content } @@ -654,3 +644,100 @@ func mgWebhookHandler(c *gin.Context) { } } + +func getOrderMessage(dataOrder *v1.MessageDataOrder) string { + mb := getLocalizedMessage("order") + + if dataOrder.Number != "" { + mb += " " + dataOrder.Number + } + + if dataOrder.Date != "" { + mb += fmt.Sprintf(" (%s)", dataOrder.Date) + } + mb += "\n" + if len(dataOrder.Items) > 0 { + mb += "\n" + for k, v := range dataOrder.Items { + mb += fmt.Sprintf( + "%d. %s %v x %s\n", + k+1, + v.Name, + v.Quantity.Value, + getLocalizedTemplateMessage( + "cost_currency", + map[string]interface{}{ + "Amount": v.Price.Value, + "Currency": currency[strings.ToLower(v.Price.Currency)], + }, + ), + ) + } + } + + if dataOrder.Delivery != nil { + mb += fmt.Sprintf( + "\n%s:\n%s; %s", + getLocalizedMessage("delivery"), + dataOrder.Delivery.Name, + getLocalizedTemplateMessage( + "cost_currency", + map[string]interface{}{ + "Amount": dataOrder.Delivery.Amount.Value, + "Currency": currency[strings.ToLower(dataOrder.Delivery.Amount.Currency)], + }, + ), + ) + + if dataOrder.Delivery.Address != "" { + mb += ";\n" + dataOrder.Delivery.Address + } + + mb += "\n" + } + + if len(dataOrder.Payments) > 0 { + mb += fmt.Sprintf( + "\n%s:\n", + getLocalizedMessage("payment"), + ) + for _, v := range dataOrder.Payments { + mb += fmt.Sprintf( + "%s; %s", + v.Name, + getLocalizedTemplateMessage( + "cost_currency", + map[string]interface{}{ + "Amount": v.Amount.Value, + "Currency": currency[strings.ToLower(v.Amount.Currency)], + }, + ), + ) + + if v.Status != nil && v.Status.Name != "" { + mb += fmt.Sprintf( + " (%s)", + v.Status.Name, + ) + } + + mb += "\n" + } + } + + if dataOrder.Cost != nil && dataOrder.Cost.Value != 0 { + mb += fmt.Sprintf( + "\n%s: %s", + getLocalizedMessage("cost"), + getLocalizedTemplateMessage( + "cost_currency", + map[string]interface{}{ + "Amount": dataOrder.Cost.Value, + "Currency": currency[strings.ToLower(dataOrder.Cost.Currency)], + }, + ), + ) + } + + return mb +} diff --git a/src/utils.go b/src/utils.go index 3c8177c..2fc15ac 100644 --- a/src/utils.go +++ b/src/utils.go @@ -15,7 +15,6 @@ import ( "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/service/s3/s3manager" - "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/retailcrm/api-client-go/v5" ) @@ -52,12 +51,14 @@ func getAPIClient(url, key string) (*v5.Client, error, int) { if res := checkCredentials(cr.Credentials); len(res) != 0 { logger.Error(url, status, res) return nil, - errors.New(localizer.MustLocalize(&i18n.LocalizeConfig{ - MessageID: "missing_credentials", - TemplateData: map[string]interface{}{ - "Credentials": strings.Join(res, ", "), - }, - })), + errors.New( + getLocalizedTemplateMessage( + "missing_credentials", + map[string]interface{}{ + "Credentials": strings.Join(res, ", "), + }, + ), + ), http.StatusBadRequest } diff --git a/translate/translate.en.yml b/translate/translate.en.yml index baf1d51..9f000a7 100644 --- a/translate/translate.en.yml +++ b/translate/translate.en.yml @@ -41,3 +41,10 @@ video: "[video]" voice: "[voice message]" photo: "[photo]" undefined: "[undefined format of a message]" + +item_cost: "Cost" +order: "Order" +delivery: "Delivery" +payment: "Payment" +cost: "Amount" +cost_currency: "{{.Amount}} {{.Currency}}" diff --git a/translate/translate.es.yml b/translate/translate.es.yml index 3641cc4..9a2926d 100644 --- a/translate/translate.es.yml +++ b/translate/translate.es.yml @@ -41,3 +41,10 @@ video: "[video]" voice: "[mensaje de voz]" photo: "[foto]" other: "[formato indefinido de mensaje]" + +item_cost: "Costo" +order: "Orden" +delivery: "Entrega" +payment: "Pago" +cost: "Monto" +cost_currency: "{{.Amount}} {{.Currency}}" diff --git a/translate/translate.ru.yml b/translate/translate.ru.yml index 523fe6d..c7708fe 100644 --- a/translate/translate.ru.yml +++ b/translate/translate.ru.yml @@ -41,3 +41,10 @@ video: "[видео]" voice: "[голосовое сообщение]" photo: "[изображение]" undefined: "[неопределенный формат сообщения]" + +item_cost: "Цена" +order: "Заказ" +delivery: "Доставка" +payment: "Оплата" +cost: "Сумма" +cost_currency: "{{.Amount}} {{.Currency}}" From 16922ef0fc1c0d6069fbab08661829ad57975347 Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Fri, 21 Sep 2018 12:48:42 +0300 Subject: [PATCH 08/10] add bots localization --- src/locale.go | 1 + src/models.go | 1 + src/routing.go | 37 ++++++++++++++++++++++++++++++------- src/run.go | 1 + static/script.js | 24 ++++++++++++++++++++++++ static/style.css | 9 +++++++++ templates/form.html | 12 ++++++++++++ templates/layout.html | 4 ++-- translate/translate.en.yml | 1 + translate/translate.es.yml | 1 + translate/translate.ru.yml | 1 + 11 files changed, 83 insertions(+), 9 deletions(-) diff --git a/src/locale.go b/src/locale.go index 8945c9d..cf275c1 100644 --- a/src/locale.go +++ b/src/locale.go @@ -59,6 +59,7 @@ func getLocale() map[string]interface{} { "AddBot": getLocalizedMessage("add_bot"), "TableDelete": getLocalizedMessage("table_delete"), "Title": getLocalizedMessage("title"), + "Language": getLocalizedMessage("language"), "InfoBot": template.HTML(getLocalizedMessage("info_bot")), "CRMLink": template.HTML(getLocalizedMessage("crm_link")), "DocLink": template.HTML(getLocalizedMessage("doc_link")), diff --git a/src/models.go b/src/models.go index 4d9622f..b7f5310 100644 --- a/src/models.go +++ b/src/models.go @@ -24,6 +24,7 @@ type Bot struct { ChannelSettingsHash string `gorm:"channel_settings_hash type:varchar(70)"` Token string `gorm:"token type:varchar(100);not null;unique" json:"token,omitempty"` Name string `gorm:"name type:varchar(40)" json:"name,omitempty"` + Lang string `gorm:"lang type:varchar(2)" json:"lang,omitempty"` CreatedAt time.Time UpdatedAt time.Time } diff --git a/src/routing.go b/src/routing.go index cf9cfb3..2fa7f5b 100644 --- a/src/routing.go +++ b/src/routing.go @@ -117,15 +117,17 @@ func settingsHandler(c *gin.Context) { bots := p.getBotsByClientID() res := struct { - Conn *Connection - Bots Bots - Locale map[string]interface{} - Year int + Conn *Connection + Bots Bots + Locale map[string]interface{} + Year int + LangCode []string }{ p, bots, getLocale(), time.Now().Year(), + []string{"en", "ru", "es"}, } c.HTML(http.StatusOK, "form", &res) @@ -246,6 +248,25 @@ func activityHandler(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"success": true}) } +func setLangBotHandler(c *gin.Context) { + b := c.MustGet("bot").(Bot) + cl, err := getBotByToken(b.Token) + if err != nil { + c.Error(err) + return + } + + cl.Lang = b.Lang + + err = cl.save() + if err != nil { + c.Error(err) + return + } + + c.JSON(http.StatusOK, gin.H{}) +} + func getIntegrationModule(clientId string) v5.IntegrationModule { return v5.IntegrationModule{ Code: config.TransportInfo.Code, @@ -559,6 +580,8 @@ func mgWebhookHandler(c *gin.Context) { return } + setLocale(b.Lang) + switch msg.Type { case "message_sent": var mb string @@ -568,13 +591,13 @@ func mgWebhookHandler(c *gin.Context) { if msg.Data.Product.Cost != nil && msg.Data.Product.Cost.Value != 0 { mb += fmt.Sprintf( - "\n%s: %s", + "\n%s: %s\n", getLocalizedMessage("item_cost"), getLocalizedTemplateMessage( "cost_currency", map[string]interface{}{ - "CostValue": msg.Data.Product.Cost.Value, - "CostCurrency": currency[strings.ToLower(msg.Data.Product.Cost.Currency)], + "Amount": msg.Data.Product.Cost.Value, + "Currency": currency[strings.ToLower(msg.Data.Product.Cost.Currency)], }, ), ) diff --git a/src/run.go b/src/run.go index 577769a..4e8e790 100644 --- a/src/run.go +++ b/src/run.go @@ -90,6 +90,7 @@ func setup() *gin.Engine { r.POST("/create/", checkConnectionForRequest(), createHandler) r.POST("/add-bot/", checkBotForRequest(), addBotHandler) r.POST("/delete-bot/", checkBotForRequest(), deleteBotHandler) + r.POST("/set-lang/", checkBotForRequest(), setLangBotHandler) r.POST("/actions/activity", activityHandler) r.POST("/telegram/:token", telegramWebhookHandler) r.POST("/webhook/", mgWebhookHandler) diff --git a/static/script.js b/static/script.js index 4acb1ea..a2c4cef 100644 --- a/static/script.js +++ b/static/script.js @@ -1,3 +1,16 @@ +$(document).on("change", "select", function(e) { + send( + "/set-lang/", + { + token: $(this).attr("data-token"), + lang: $(this).find(":selected").text() + }, + function () { + return 0; + } + ) +}); + $('#save-crm').on("submit", function(e) { e.preventDefault(); send( @@ -39,6 +52,7 @@ $("#add-bot").on("submit", function(e) { } $("#bots tbody").append(getBotTemplate(data)); $("#token").val(""); + $('select').formSelect(); } ) }); @@ -101,6 +115,15 @@ function getBotTemplate(data) { ` ${data.name} ${data.token} + +
+ +
+