1
0
mirror of synced 2025-02-25 00:13:14 +03:00

574 lines
12 KiB
Go
Raw Normal View History

package main
import (
"encoding/json"
2018-08-15 17:56:36 +03:00
"fmt"
2018-08-17 16:31:55 +03:00
"net/http"
"strconv"
2018-09-13 21:17:23 +03:00
"strings"
2018-08-17 16:31:55 +03:00
"time"
"github.com/gin-gonic/gin"
"github.com/go-telegram-bot-api/telegram-bot-api"
"github.com/retailcrm/api-client-go/v5"
"github.com/retailcrm/mg-transport-api-client-go/v1"
)
func connectHandler(c *gin.Context) {
2018-05-18 18:11:09 +03:00
res := struct {
2018-08-15 17:56:36 +03:00
Conn Connection
Locale map[string]interface{}
Year int
2018-05-18 18:11:09 +03:00
}{
2018-08-15 17:56:36 +03:00
c.MustGet("account").(Connection),
getLocale(),
time.Now().Year(),
2018-05-18 18:11:09 +03:00
}
c.HTML(http.StatusOK, "home", &res)
}
func addBotHandler(c *gin.Context) {
2018-08-15 17:56:36 +03:00
b := c.MustGet("bot").(Bot)
2018-05-31 19:44:23 +03:00
cl, err := getBotByToken(b.Token)
if err != nil {
c.Error(err)
2018-05-25 18:09:38 +03:00
return
}
2018-05-31 19:44:23 +03:00
if cl.ID != 0 {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("bot_already_created"))
return
}
bot, err := tgbotapi.NewBotAPI(b.Token)
if err != nil {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("incorrect_token"))
2018-08-16 18:13:01 +03:00
logger.Error(b.Token, err.Error())
return
}
2018-06-01 12:08:22 +03:00
bot.Debug = config.Debug
2018-05-25 18:09:38 +03:00
wr, err := bot.SetWebhook(tgbotapi.NewWebhook("https://" + config.HTTPServer.Host + "/telegram/" + bot.Token))
2018-08-20 13:51:45 +03:00
if err != nil || !wr.Ok {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("error_creating_webhook"))
2018-08-20 13:51:45 +03:00
logger.Error(b.Token, err.Error(), wr)
2018-05-25 18:09:38 +03:00
return
}
b.Name = bot.Self.FirstName
ch := v1.Channel{
Type: "telegram",
2018-08-20 13:51:45 +03:00
Settings: v1.ChannelSettings{
SpamAllowed: false,
Status: v1.Status{
2018-08-23 15:52:32 +03:00
Delivered: v1.ChannelFeatureSend,
2018-08-20 13:51:45 +03:00
Read: v1.ChannelFeatureNone,
},
Text: v1.ChannelSettingsText{
Creating: v1.ChannelFeatureBoth,
Editing: v1.ChannelFeatureBoth,
Quoting: v1.ChannelFeatureBoth,
2018-08-23 15:52:32 +03:00
Deleting: v1.ChannelFeatureReceive,
2018-08-20 13:51:45 +03:00
},
2018-09-13 21:17:23 +03:00
Product: v1.Product{
Creating: v1.ChannelFeatureReceive,
Editing: v1.ChannelFeatureReceive,
},
},
}
conn := getConnectionById(b.ConnectionID)
2018-05-31 18:17:19 +03:00
var client = v1.New(conn.MGURL, conn.MGToken)
data, status, err := client.ActivateTransportChannel(ch)
if status != http.StatusCreated {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("error_activating_channel"))
2018-08-16 18:13:01 +03:00
logger.Error(conn.APIURL, status, err.Error(), data)
return
}
b.Channel = data.ChannelID
err = conn.createBot(b)
if err != nil {
c.Error(err)
2018-05-24 17:16:21 +03:00
return
}
2018-08-15 17:56:36 +03:00
c.JSON(http.StatusCreated, b)
}
func deleteBotHandler(c *gin.Context) {
2018-08-15 17:56:36 +03:00
b := c.MustGet("bot").(Bot)
conn := getConnectionById(b.ConnectionID)
if conn.MGURL == "" || conn.MGToken == "" {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("not_found_account"))
2018-05-25 18:09:38 +03:00
return
}
var client = v1.New(conn.MGURL, conn.MGToken)
data, status, err := client.DeactivateTransportChannel(getBotChannelByToken(b.Token))
if status > http.StatusOK {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("error_deactivating_channel"))
logger.Error(b.ID, status, err.Error(), data)
return
}
err = b.deleteBot()
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusOK, gin.H{})
}
func settingsHandler(c *gin.Context) {
uid := c.Param("uid")
2018-05-18 18:11:09 +03:00
2018-05-24 18:08:48 +03:00
p := getConnection(uid)
if p.ID == 0 {
c.Redirect(http.StatusFound, "/")
2018-05-29 10:08:38 +03:00
return
}
bots := p.getBotsByClientID()
res := struct {
2018-05-18 18:11:09 +03:00
Conn *Connection
Bots Bots
Locale map[string]interface{}
Year int
}{
p,
bots,
getLocale(),
time.Now().Year(),
}
c.HTML(http.StatusOK, "form", &res)
}
func saveHandler(c *gin.Context) {
2018-08-15 17:56:36 +03:00
conn := c.MustGet("connection").(Connection)
_, err, code := getAPIClient(conn.APIURL, conn.APIKEY)
2018-05-28 18:16:13 +03:00
if err != nil {
2018-08-23 15:52:32 +03:00
if code == http.StatusInternalServerError {
c.Error(err)
} else {
c.AbortWithStatusJSON(BadRequest(err.Error()))
}
2018-05-28 18:16:13 +03:00
return
}
err = conn.saveConnectionByClientID()
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusOK, gin.H{"message": getLocalizedMessage("successful")})
}
func createHandler(c *gin.Context) {
2018-08-15 17:56:36 +03:00
conn := c.MustGet("connection").(Connection)
2018-05-22 10:34:39 +03:00
cl := getConnectionByURL(conn.APIURL)
if cl.ID != 0 {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("connection_already_created"))
return
}
2018-08-16 18:13:01 +03:00
client, err, code := getAPIClient(conn.APIURL, conn.APIKEY)
2018-05-28 18:16:13 +03:00
if err != nil {
2018-08-16 18:13:01 +03:00
if code == http.StatusInternalServerError {
c.Error(err)
} else {
2018-08-17 13:36:25 +03:00
c.AbortWithStatusJSON(code, gin.H{"error": err.Error()})
2018-08-16 18:13:01 +03:00
}
return
}
2018-08-15 17:56:36 +03:00
conn.ClientID = GenerateToken()
data, status, errr := client.IntegrationModuleEdit(getIntegrationModule(conn.ClientID))
if errr.RuntimeErr != nil {
c.Error(errr.RuntimeErr)
return
}
if status >= http.StatusBadRequest {
2018-08-23 15:52:32 +03:00
c.AbortWithStatusJSON(BadRequest("error_activity_mg"))
logger.Error(conn.APIURL, status, errr.ApiErr, data)
return
}
2018-09-03 11:52:35 +03:00
conn.MGURL = data.Info.MgTransportInfo.EndpointUrl
conn.MGToken = data.Info.MgTransportInfo.Token
conn.Active = true
err = conn.createConnection()
if err != nil {
c.Error(err)
return
}
c.JSON(
http.StatusCreated,
gin.H{
"url": "/settings/" + conn.ClientID,
"message": getLocalizedMessage("successful"),
},
)
}
func activityHandler(c *gin.Context) {
var (
activity v5.Activity
systemUrl = c.PostForm("systemUrl")
clientId = c.PostForm("clientId")
)
conn := getConnection(clientId)
if conn.ID == 0 {
c.AbortWithStatusJSON(http.StatusBadRequest,
gin.H{
"success": false,
"error": "Wrong data",
},
)
return
}
err := json.Unmarshal([]byte(c.PostForm("activity")), &activity)
if err != nil {
2018-08-17 13:36:25 +03:00
c.AbortWithStatusJSON(http.StatusBadRequest,
gin.H{
"success": false,
"error": "Wrong data",
},
)
2018-05-24 17:16:21 +03:00
return
}
conn.Active = activity.Active && !activity.Freeze
if systemUrl != "" {
conn.APIURL = systemUrl
}
2018-05-28 18:16:13 +03:00
if err := conn.saveConnection(); err != nil {
c.Error(err)
return
2018-05-28 18:16:13 +03:00
}
c.JSON(http.StatusOK, gin.H{"success": true})
2018-05-28 18:16:13 +03:00
}
2018-08-15 17:56:36 +03:00
func getIntegrationModule(clientId string) v5.IntegrationModule {
return v5.IntegrationModule{
2018-08-16 18:13:01 +03:00
Code: config.TransportInfo.Code,
IntegrationCode: config.TransportInfo.Code,
2018-08-15 17:56:36 +03:00
Active: true,
2018-08-16 18:13:01 +03:00
Name: config.TransportInfo.Name,
2018-08-15 17:56:36 +03:00
ClientID: clientId,
Logo: fmt.Sprintf(
2018-08-16 18:13:01 +03:00
"https://%s%s",
2018-08-15 17:56:36 +03:00
config.HTTPServer.Host,
2018-08-16 18:13:01 +03:00
config.TransportInfo.LogoPath,
2018-08-15 17:56:36 +03:00
),
BaseURL: fmt.Sprintf(
"https://%s",
config.HTTPServer.Host,
),
AccountURL: fmt.Sprintf(
"https://%s/settings/%s",
config.HTTPServer.Host,
clientId,
),
Actions: map[string]string{"activity": "/actions/activity"},
Integrations: &v5.Integrations{
MgTransport: &v5.MgTransport{
WebhookUrl: fmt.Sprintf(
"https://%s/webhook/",
config.HTTPServer.Host,
),
},
},
}
}
2018-08-17 16:31:55 +03:00
func telegramWebhookHandler(c *gin.Context) {
token := c.Param("token")
b, err := getBotByToken(token)
if err != nil {
c.Error(err)
return
}
if b.ID == 0 {
c.AbortWithStatus(http.StatusOK)
return
}
conn := getConnectionById(b.ConnectionID)
if !conn.Active {
c.AbortWithStatus(http.StatusOK)
return
}
var update tgbotapi.Update
if err := c.ShouldBindJSON(&update); err != nil {
c.Error(err)
return
}
if config.Debug {
logger.Debugf("mgWebhookHandler request: %v", update)
}
var client = v1.New(conn.MGURL, conn.MGToken)
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)
if update.Message.From.UserName == "" {
nickname = update.Message.From.FirstName
}
if user.Expired(config.UpdateInterval) || user.ID == 0 {
fileID, fileURL, err := GetFileIDAndURL(b.Token, update.Message.From.ID)
if err != nil {
c.Error(err)
return
}
if fileID != user.UserPhotoID && fileURL != "" {
picURL, err := UploadUserAvatar(fileURL)
if err != nil {
c.Error(err)
return
}
user.UserPhotoID = fileID
user.UserPhotoURL = picURL
}
if user.ExternalID == 0 {
user.ExternalID = update.Message.From.ID
}
err = user.save()
if err != nil {
c.Error(err)
return
}
}
lang := update.Message.From.LanguageCode
if len(update.Message.From.LanguageCode) > 2 {
lang = update.Message.From.LanguageCode[:2]
}
if config.Debug {
logger.Debugf("telegramWebhookHandler user %v", user)
}
snd := v1.SendData{
2018-09-12 11:24:44 +03:00
Message: v1.Message{
ExternalID: strconv.Itoa(update.Message.MessageID),
Type: "text",
Text: update.Message.Text,
2018-08-17 16:31:55 +03:00
},
User: v1.User{
ExternalID: strconv.Itoa(update.Message.From.ID),
Nickname: nickname,
Firstname: update.Message.From.FirstName,
Avatar: user.UserPhotoURL,
Lastname: update.Message.From.LastName,
Language: lang,
},
Channel: b.Channel,
ExternalChatID: strconv.FormatInt(update.Message.Chat.ID, 10),
}
if update.Message.ReplyToMessage != nil {
snd.Quote = &v1.SendMessageRequestQuote{ExternalID: strconv.Itoa(update.Message.ReplyToMessage.MessageID)}
}
data, st, err := client.Messages(snd)
if err != nil {
logger.Error(b.Token, err.Error(), st, data)
c.Error(err)
return
}
if config.Debug {
logger.Debugf("telegramWebhookHandler Type: SendMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data)
}
}
if update.EditedMessage != nil {
if update.EditedMessage.Text == "" {
setLocale(update.EditedMessage.From.LanguageCode)
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,
},
},
Channel: b.Channel,
}
data, st, err := client.UpdateMessages(snd)
if err != nil {
logger.Error(b.Token, err.Error(), st, data)
c.Error(err)
return
}
if config.Debug {
logger.Debugf("telegramWebhookHandler Type: UpdateMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data)
}
}
c.JSON(http.StatusOK, gin.H{})
}
func mgWebhookHandler(c *gin.Context) {
clientID := c.GetHeader("Clientid")
if clientID == "" {
c.AbortWithStatus(http.StatusBadRequest)
return
}
conn := getConnection(clientID)
if !conn.Active {
c.AbortWithStatus(http.StatusBadRequest)
return
}
var msg v1.WebhookRequest
if err := c.ShouldBindJSON(&msg); err != nil {
c.Error(err)
return
}
if config.Debug {
logger.Debugf("mgWebhookHandler request: %v", msg)
}
uid, _ := strconv.Atoi(msg.Data.ExternalMessageID)
cid, _ := strconv.ParseInt(msg.Data.ExternalChatID, 10, 64)
b := getBot(conn.ID, msg.Data.ChannelID)
if b.ID == 0 {
c.AbortWithStatus(http.StatusBadRequest)
return
}
bot, err := tgbotapi.NewBotAPI(b.Token)
if err != nil {
2018-08-20 13:51:45 +03:00
logger.Error(b, err)
c.AbortWithStatus(http.StatusBadRequest)
2018-08-17 16:31:55 +03:00
return
}
2018-09-13 16:32:50 +03:00
switch msg.Type {
case "message_sent":
2018-09-13 17:25:06 +03:00
var mb string
if msg.Data.Type == v1.MsgTypeProduct {
2018-09-13 21:17:23 +03:00
mb = fmt.Sprintf(
"[%s](%s)",
msg.Data.Product.Name,
msg.Data.Product.Url,
)
2018-09-13 17:25:06 +03:00
if msg.Data.Product.Cost != nil && msg.Data.Product.Cost.Value != 0 {
mb += fmt.Sprintf(
"\n%v %s",
msg.Data.Product.Cost.Value,
2018-09-13 21:17:23 +03:00
currency[strings.ToLower(msg.Data.Product.Cost.Currency)],
2018-09-13 17:25:06 +03:00
)
}
if msg.Data.Product.Img != "" {
mb = fmt.Sprintf("\n%s", msg.Data.Product.Img)
}
} else {
mb = msg.Data.Content
}
m := tgbotapi.NewMessage(cid, mb)
2018-09-13 21:17:23 +03:00
if msg.Data.Type == v1.MsgTypeProduct {
m.ParseMode = "Markdown"
}
2018-08-17 16:31:55 +03:00
if msg.Data.QuoteExternalID != "" {
qid, err := strconv.Atoi(msg.Data.QuoteExternalID)
if err != nil {
c.Error(err)
return
}
m.ReplyToMessageID = qid
}
msgSend, err := bot.Send(m)
if err != nil {
logger.Error(err)
c.AbortWithStatus(http.StatusBadRequest)
return
}
if config.Debug {
logger.Debugf("mgWebhookHandler sent %v", msgSend)
}
c.JSON(http.StatusOK, gin.H{"external_message_id": strconv.Itoa(msgSend.MessageID)})
2018-09-13 16:32:50 +03:00
case "message_updated":
2018-08-17 16:31:55 +03:00
msgSend, err := bot.Send(tgbotapi.NewEditMessageText(cid, uid, msg.Data.Content))
if err != nil {
logger.Error(err)
c.AbortWithStatus(http.StatusBadRequest)
return
}
if config.Debug {
logger.Debugf("mgWebhookHandler update %v", msgSend)
}
c.AbortWithStatus(http.StatusOK)
2018-09-13 16:32:50 +03:00
case "message_deleted":
2018-08-17 16:31:55 +03:00
msgSend, err := bot.Send(tgbotapi.NewDeleteMessage(cid, uid))
if err != nil {
logger.Error(err)
c.AbortWithStatus(http.StatusBadRequest)
return
}
if config.Debug {
logger.Debugf("mgWebhookHandler delete %v", msgSend)
}
c.JSON(http.StatusOK, gin.H{})
2018-09-13 16:32:50 +03:00
2018-08-17 16:31:55 +03:00
}
}