From dff7a08e9a9b8644c68c6c7e5e70e9fc11d9057b Mon Sep 17 00:00:00 2001 From: DmitryZagorulko Date: Wed, 28 Nov 2018 16:17:13 +0300 Subject: [PATCH] add file and images transfer --- go.mod | 4 +- go.sum | 8 +- src/routing.go | 225 ++++++++++++++++++++++++++++++++++++++++---- src/routing_test.go | 14 +++ 4 files changed, 227 insertions(+), 24 deletions(-) diff --git a/go.mod b/go.mod index 71cd701..443393c 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/gin-gonic/gin v1.3.0 github.com/go-ini/ini v1.38.2 // indirect github.com/go-sql-driver/mysql v1.4.0 // indirect - github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180602093832-4c16a90966d1 + github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible github.com/golang-migrate/migrate v3.4.0+incompatible github.com/golang/protobuf v1.2.0 // indirect github.com/google/go-cmp v0.2.0 // indirect @@ -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.1.0 - github.com/retailcrm/mg-transport-api-client-go v1.1.11 + github.com/retailcrm/mg-transport-api-client-go v1.1.17 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 64e8d2b..3d741a8 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/go-ini/ini v1.38.2 h1:6Hl/z3p3iFkA0dlDfzYxuFuUGD+kaweypF6btsR2/Q4= github.com/go-ini/ini v1.38.2/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8= github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk= github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180602093832-4c16a90966d1 h1:FlRoyZCY3snE+M9jTruqOzPwZg8KIwQBXr//t215K8E= -github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180602093832-4c16a90966d1/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible h1:2cauKuaELYAEARXRkq2LrJ0yDDv1rW7+wrTEdVL3uaU= +github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM= github.com/golang-migrate/migrate v3.4.0+incompatible h1:9yjg5lYsbeEpWXGc80RylvPMKZ0tZEGsyO3CpYLK3jU= github.com/golang-migrate/migrate v3.4.0+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk= github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM= @@ -95,8 +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.1.0 h1:APPO6ccJAeMV7Jz7BhrtDKSOm2r1j5Ft6fuEXNP2ij4= github.com/retailcrm/api-client-go v1.1.0/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c= -github.com/retailcrm/mg-transport-api-client-go v1.1.11 h1:jAIOKqkjA2r0v/V6lTHYQsD8q0lFpfpqzAffHAJlhCQ= -github.com/retailcrm/mg-transport-api-client-go v1.1.11/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= +github.com/retailcrm/mg-transport-api-client-go v1.1.17 h1:8L0meFJFZwr3TyiF/xypI+g0xRXIGkWhyQ6qiCfojqw= +github.com/retailcrm/mg-transport-api-client-go v1.1.17/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/routing.go b/src/routing.go index 6a9cde1..58db220 100644 --- a/src/routing.go +++ b/src/routing.go @@ -343,6 +343,20 @@ func getChannelSettings(cid ...uint64) v1.Channel { Creating: v1.ChannelFeatureReceive, Editing: v1.ChannelFeatureReceive, }, + File: v1.ChannelSettingsFilesBase{ + Creating: v1.ChannelFeatureBoth, + Editing: v1.ChannelFeatureBoth, + Quoting: v1.ChannelFeatureBoth, + Deleting: v1.ChannelFeatureReceive, + Max: 1, + }, + Image: v1.ChannelSettingsFilesBase{ + Creating: v1.ChannelFeatureBoth, + Editing: v1.ChannelFeatureBoth, + Quoting: v1.ChannelFeatureBoth, + Deleting: v1.ChannelFeatureReceive, + Max: 10, + }, }, } } @@ -437,11 +451,6 @@ func telegramWebhookHandler(c *gin.Context) { client.Debug = config.Debug if update.Message != nil { - if update.Message.Text == "" { - setLocale(update.Message.From.LanguageCode) - update.Message.Text = getLocalizedMessage(getMessageID(update.Message)) - } - nickname := update.Message.From.UserName user := getUserByExternalID(update.Message.From.ID) @@ -510,6 +519,17 @@ func telegramWebhookHandler(c *gin.Context) { snd.Quote = &v1.SendMessageRequestQuote{ExternalID: strconv.Itoa(update.Message.ReplyToMessage.MessageID)} } + if snd.Message.Text == "" { + setLocale(update.Message.From.LanguageCode) + + err := setAttachment(update.Message, client, &snd, b.Token) + if err != nil { + logger.Error(client.Token, err.Error()) + c.AbortWithStatus(http.StatusBadRequest) + return + } + } + data, st, err := client.Messages(snd) if err != nil { logger.Error(b.Token, err.Error(), st, data) @@ -528,13 +548,10 @@ func telegramWebhookHandler(c *gin.Context) { update.EditedMessage.Text = getLocalizedMessage(getMessageID(update.Message)) } - snd := v1.UpdateData{ - Message: v1.UpdateMessage{ - Message: v1.Message{ - ExternalID: strconv.Itoa(update.EditedMessage.MessageID), - Type: "text", - Text: update.EditedMessage.Text, - }, + snd := v1.EditMessageRequest{ + Message: v1.EditMessageRequestMessage{ + ExternalID: strconv.Itoa(update.EditedMessage.MessageID), + Text: update.EditedMessage.Text, }, Channel: b.Channel, } @@ -585,10 +602,13 @@ func mgWebhookHandler(c *gin.Context) { bot.Debug = config.Debug setLocale(b.Lang) + mgClient := v1.New(conn.MGURL, conn.MGToken) switch msg.Type { case "message_sent": var mb string + var m tgbotapi.Chattable + switch msg.Data.Type { case v1.MsgTypeProduct: mb = fmt.Sprintf("*%s*\n", replaceMarkdownSymbols(msg.Data.Product.Name)) @@ -616,20 +636,37 @@ func mgWebhookHandler(c *gin.Context) { mb = getOrderMessage(msg.Data.Order) case v1.MsgTypeText: mb = replaceMarkdownSymbols(msg.Data.Content) + case v1.MsgTypeImage: + m, err = photoMessage(*msg.Data.Items, mgClient, cid) + if err != nil { + logger.Errorf( + "GetFile request apiURL: %s, clientID: %s, err: %s", + conn.APIURL, conn.ClientID, err.Error(), + ) + return + } + case v1.MsgTypeFile: + items := *msg.Data.Items + if len(items) > 0 { + m, err = documentMessage(items[0], mgClient, cid) + if err != nil { + logger.Errorf( + "GetFile request apiURL: %s, clientID: %s, err: %s", + conn.APIURL, conn.ClientID, err.Error(), + ) + return + } + } } - m := tgbotapi.NewMessage(cid, mb) - if msg.Data.QuoteExternalID != "" { - qid, err := strconv.Atoi(msg.Data.QuoteExternalID) + if mb != "" { + m, err = textMessage(cid, mb, msg.Data.QuoteExternalID) if err != nil { c.Error(err) return } - m.ReplyToMessageID = qid } - m.ParseMode = "Markdown" - msgSend, err := bot.Send(m) if err != nil { logger.Error(err) @@ -805,3 +842,155 @@ func getOrderMessage(dataOrder *v1.MessageDataOrder) string { return mb } + +func photoMessage(items []v1.FileItem, mgClient *v1.MgClient, cid int64) (chattable tgbotapi.Chattable, err error) { + if len(items) == 1 { + v := items + + file, _, err := mgClient.GetFile(v[0].ID) + if err != nil { + return chattable, err + } + + msg := tgbotapi.NewPhotoUpload(cid, nil) + msg.FileID = file.Url + msg.UseExisting = true + + chattable = msg + } else if len(items) > 1 { + var it []interface{} + + for _, v := range items { + file, _, err := mgClient.GetFile(v.ID) + if err != nil { + logger.Errorf( + "GetFile request fileID: %s, err: %s", + v.ID, err.Error(), + ) + continue + } + + ip := tgbotapi.NewInputMediaPhoto(file.Url) + it = append(it, ip) + } + + chattable = tgbotapi.NewMediaGroup(cid, it) + } + + return +} + +func documentMessage(item v1.FileItem, mgClient *v1.MgClient, cid int64) (chattable tgbotapi.Chattable, err error) { + file, _, err := mgClient.GetFile(item.ID) + if err != nil { + return chattable, err + } + + data, err := http.Get(file.Url) + if err != nil { + return chattable, err + } + + tt := tgbotapi.FileReader{ + Name: item.Caption, + Reader: data.Body, + Size: int64(item.Size), + } + + chattable = tgbotapi.NewDocumentUpload(cid, tt) + return +} + +func textMessage(cid int64, mb string, quoteExternalID string) (chattable tgbotapi.Chattable, err error) { + var qid int + m := tgbotapi.NewMessage(cid, mb) + + if quoteExternalID != "" { + qid, err = strconv.Atoi(quoteExternalID) + if err != nil { + return + } + m.ReplyToMessageID = qid + } + + m.ParseMode = "Markdown" + + chattable = m + return +} + +func setAttachment(attachments *tgbotapi.Message, client *v1.MgClient, snd *v1.SendData, botToken string) error { + var ( + items []v1.Item + fileID string + caption string + ) + + t := getMessageID(attachments) + bot, err := tgbotapi.NewBotAPI(botToken) + if err != nil { + return err + } + + switch t { + case "photo": + for _, v := range *attachments.Photo { + fileID = v.FileID + } + + snd.Message.Type = v1.MsgTypeImage + caption = getLocalizedMessage(t) + case "document": + fileID = attachments.Document.FileID + snd.Message.Type = v1.MsgTypeFile + caption = attachments.Document.FileName + default: + snd.Message.Text = getLocalizedMessage(t) + } + + if fileID != "" { + file, err := getFileURL(fileID, bot) + if err != nil { + return err + } + + item, _, err := getItemData( + client, + fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", botToken, file.FilePath), + caption, + ) + if err != nil { + return err + } + + items = append(items, item) + } + + if len(items) > 0 { + snd.Message.Items = items + } + + return nil +} + +func getItemData(client *v1.MgClient, url string, caption string) (v1.Item, int, error) { + item := v1.Item{} + + data, st, err := client.UploadFileByURL( + v1.UploadFileByUrlRequest{ + Url: url, + }, + ) + if err != nil { + return item, st, err + } + + item.ID = data.ID + item.Caption = caption + + return item, st, err +} + +func getFileURL(fileID string, b *tgbotapi.BotAPI) (tgbotapi.File, error) { + return b.GetFile(tgbotapi.FileConfig{FileID: fileID}) +} diff --git a/src/routing_test.go b/src/routing_test.go index f4b9445..2504e8c 100644 --- a/src/routing_test.go +++ b/src/routing_test.go @@ -79,6 +79,20 @@ func TestRouting_addBotHandler(t *testing.T) { Creating: v1.ChannelFeatureReceive, Editing: v1.ChannelFeatureReceive, }, + File: v1.ChannelSettingsFilesBase{ + Creating: v1.ChannelFeatureBoth, + Editing: v1.ChannelFeatureBoth, + Quoting: v1.ChannelFeatureBoth, + Deleting: v1.ChannelFeatureReceive, + Max: 1, + }, + Image: v1.ChannelSettingsFilesBase{ + Creating: v1.ChannelFeatureBoth, + Editing: v1.ChannelFeatureBoth, + Quoting: v1.ChannelFeatureBoth, + Deleting: v1.ChannelFeatureReceive, + Max: 10, + }, }, }