2018-05-17 18:35:53 +03:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
2018-05-25 18:09:38 +03:00
|
|
|
"encoding/json"
|
2018-06-04 16:48:04 +03:00
|
|
|
"errors"
|
2018-05-25 18:09:38 +03:00
|
|
|
"io/ioutil"
|
2018-05-31 16:18:52 +03:00
|
|
|
"net/http"
|
2018-05-25 18:09:38 +03:00
|
|
|
"strconv"
|
|
|
|
"time"
|
|
|
|
|
2018-06-04 16:48:04 +03:00
|
|
|
"fmt"
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
"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"
|
2018-05-25 18:09:38 +03:00
|
|
|
"github.com/getsentry/raven-go"
|
2018-05-17 18:35:53 +03:00
|
|
|
"github.com/go-telegram-bot-api/telegram-bot-api"
|
2018-05-25 18:09:38 +03:00
|
|
|
"github.com/retailcrm/mg-transport-api-client-go/v1"
|
2018-05-17 18:35:53 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
func setTransportRoutes() {
|
2018-05-23 18:03:11 +03:00
|
|
|
http.HandleFunc("/telegram/", makeHandler(telegramWebhookHandler))
|
2018-05-28 18:08:15 +03:00
|
|
|
http.HandleFunc("/webhook/", mgWebhookHandler)
|
2018-05-17 18:35:53 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetBotName function
|
|
|
|
func GetBotName(bot *tgbotapi.BotAPI) string {
|
|
|
|
return bot.Self.FirstName
|
|
|
|
}
|
2018-05-25 18:09:38 +03:00
|
|
|
|
|
|
|
func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string) {
|
2018-05-31 19:44:23 +03:00
|
|
|
b, err := getBotByToken(token)
|
2018-05-31 16:18:52 +03:00
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(token, err.Error())
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2018-05-25 18:09:38 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-04 16:48:04 +03:00
|
|
|
if b.ID == 0 || !b.Active {
|
|
|
|
logger.Error(token, "missing or deactivated")
|
2018-05-25 18:09:38 +03:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-31 19:44:23 +03:00
|
|
|
c := getConnectionById(b.ConnectionID)
|
2018-06-04 16:48:04 +03:00
|
|
|
if !c.Active {
|
|
|
|
logger.Error(c.ClientID, " connection deativated")
|
2018-05-31 19:44:23 +03:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-05-25 18:09:38 +03:00
|
|
|
var update tgbotapi.Update
|
|
|
|
|
|
|
|
bytes, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(token, err)
|
2018-06-04 16:48:04 +03:00
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2018-05-25 18:09:38 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-01 14:46:07 +03:00
|
|
|
if config.Debug {
|
|
|
|
logger.Debugf("telegramWebhookHandler: %v", string(bytes))
|
|
|
|
}
|
|
|
|
|
2018-05-25 18:09:38 +03:00
|
|
|
err = json.Unmarshal(bytes, &update)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(token, err)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-04 16:48:04 +03:00
|
|
|
user := getUserByExternalID(update.Message.From.ID)
|
|
|
|
|
2018-06-07 15:35:27 +03:00
|
|
|
if time.Now().After(user.UpdatedAt.Add(time.Hour*time.Duration(config.UpdateInterval))) || user.ID == 0 {
|
2018-06-04 16:48:04 +03:00
|
|
|
|
|
|
|
fileID, fileURL, err := getFileIDAndURL(b.Token, update.Message.From.ID)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if fileID != user.UserPhotoID && fileURL != "" {
|
|
|
|
picURL, err := UploadUserAvatar(fileURL)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
user.UserPhotoID = fileID
|
|
|
|
user.UserPhotoURL = picURL
|
|
|
|
}
|
|
|
|
|
|
|
|
if user.ExternalID == 0 {
|
|
|
|
user.ExternalID = update.Message.From.ID
|
|
|
|
}
|
|
|
|
|
|
|
|
err = user.saveUser()
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-25 18:09:38 +03:00
|
|
|
var client = v1.New(c.MGURL, c.MGToken)
|
|
|
|
|
|
|
|
if update.Message != nil {
|
2018-06-01 15:14:29 +03:00
|
|
|
if update.Message.Text != "" {
|
|
|
|
snd := v1.SendData{
|
|
|
|
Message: v1.SendMessage{
|
|
|
|
Message: v1.Message{
|
|
|
|
ExternalID: strconv.Itoa(update.Message.MessageID),
|
|
|
|
Type: "text",
|
|
|
|
Text: update.Message.Text,
|
|
|
|
},
|
|
|
|
SentAt: time.Now(),
|
2018-05-25 18:09:38 +03:00
|
|
|
},
|
2018-06-01 15:14:29 +03:00
|
|
|
User: v1.User{
|
|
|
|
ExternalID: strconv.Itoa(update.Message.From.ID),
|
|
|
|
Nickname: update.Message.From.UserName,
|
|
|
|
Firstname: update.Message.From.FirstName,
|
2018-06-04 16:48:04 +03:00
|
|
|
Avatar: user.UserPhotoURL,
|
2018-06-01 15:14:29 +03:00
|
|
|
Lastname: update.Message.From.LastName,
|
|
|
|
Language: update.Message.From.LanguageCode,
|
|
|
|
},
|
2018-06-01 18:17:47 +03:00
|
|
|
Channel: b.Channel,
|
|
|
|
ExternalChatID: strconv.FormatInt(update.Message.Chat.ID, 10),
|
2018-06-01 15:14:29 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
data, st, err := client.Messages(snd)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(token, err.Error(), st, data)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.Debug {
|
|
|
|
logger.Debugf("telegramWebhookHandler Type: SendMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data)
|
|
|
|
}
|
2018-06-01 12:08:22 +03:00
|
|
|
}
|
2018-05-25 18:09:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if update.EditedMessage != nil {
|
2018-06-01 15:14:29 +03:00
|
|
|
if update.EditedMessage.Text != "" {
|
|
|
|
snd := v1.UpdateData{
|
|
|
|
Message: v1.UpdateMessage{
|
|
|
|
Message: v1.Message{
|
|
|
|
ExternalID: strconv.Itoa(update.EditedMessage.MessageID),
|
|
|
|
Type: "text",
|
|
|
|
Text: update.EditedMessage.Text,
|
|
|
|
},
|
2018-05-25 18:09:38 +03:00
|
|
|
},
|
2018-06-01 15:14:29 +03:00
|
|
|
Channel: b.Channel,
|
|
|
|
}
|
|
|
|
|
|
|
|
data, st, err := client.UpdateMessages(snd)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(token, err.Error(), st, data)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.Debug {
|
|
|
|
logger.Debugf("telegramWebhookHandler Type: UpdateMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data)
|
|
|
|
}
|
2018-06-01 12:08:22 +03:00
|
|
|
}
|
2018-05-25 18:09:38 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
}
|
2018-05-29 17:20:56 +03:00
|
|
|
|
|
|
|
func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
|
|
|
|
bytes, err := ioutil.ReadAll(r.Body)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
2018-06-04 16:48:04 +03:00
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2018-05-29 17:20:56 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-01 14:46:07 +03:00
|
|
|
if config.Debug {
|
2018-06-01 14:57:48 +03:00
|
|
|
logger.Debugf("mgWebhookHandler request: %v", string(bytes))
|
2018-06-01 14:46:07 +03:00
|
|
|
}
|
|
|
|
|
2018-05-29 17:20:56 +03:00
|
|
|
var msg v1.WebhookRequest
|
|
|
|
err = json.Unmarshal(bytes, &msg)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
2018-06-04 16:48:04 +03:00
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2018-05-29 17:20:56 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
uid, _ := strconv.Atoi(msg.Data.ExternalMessageID)
|
2018-06-01 15:24:04 +03:00
|
|
|
cid, _ := strconv.ParseInt(msg.Data.ExternalChatID, 10, 64)
|
2018-05-29 17:20:56 +03:00
|
|
|
|
|
|
|
b := getBotByChannel(msg.Data.ChannelID)
|
|
|
|
if b.ID == 0 {
|
|
|
|
logger.Error(msg.Data.ChannelID, "missing")
|
2018-06-04 16:48:04 +03:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
w.Write([]byte("Bot missing"))
|
2018-05-29 17:20:56 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if !b.Active {
|
|
|
|
logger.Error(msg.Data.ChannelID, "deactivated")
|
2018-06-04 16:48:04 +03:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
w.Write([]byte("Bot deactivated"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c := getConnectionById(b.ConnectionID)
|
|
|
|
if !c.Active {
|
|
|
|
logger.Error(c.ClientID, " connection deativated")
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
w.Write([]byte("Connection deactivated"))
|
2018-05-29 17:20:56 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
bot, err := tgbotapi.NewBotAPI(b.Token)
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
2018-06-04 16:48:04 +03:00
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
2018-05-29 17:20:56 +03:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type == "message_sent" {
|
2018-06-01 15:24:04 +03:00
|
|
|
msg, err := bot.Send(tgbotapi.NewMessage(cid, msg.Data.Content))
|
2018-05-29 17:20:56 +03:00
|
|
|
if err != nil {
|
2018-05-31 16:18:52 +03:00
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
2018-05-29 17:20:56 +03:00
|
|
|
logger.Error(err)
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-01 12:08:22 +03:00
|
|
|
if config.Debug {
|
2018-06-01 14:57:48 +03:00
|
|
|
logger.Debugf("mgWebhookHandler sent %v", msg)
|
2018-06-01 12:08:22 +03:00
|
|
|
}
|
|
|
|
|
2018-06-06 12:48:00 +03:00
|
|
|
rsp, err := json.Marshal(map[string]string{"external_message_id": strconv.Itoa(msg.MessageID)})
|
|
|
|
if err != nil {
|
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
|
|
|
logger.Error(err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if config.Debug {
|
2018-06-06 12:54:40 +03:00
|
|
|
logger.Debugf("mgWebhookHandler sent response %v", rsp)
|
2018-06-06 12:48:00 +03:00
|
|
|
}
|
|
|
|
|
2018-05-29 17:20:56 +03:00
|
|
|
w.WriteHeader(http.StatusOK)
|
2018-06-06 12:48:00 +03:00
|
|
|
w.Write(rsp)
|
2018-05-29 17:20:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type == "message_updated" {
|
2018-06-01 15:24:04 +03:00
|
|
|
msg, err := bot.Send(tgbotapi.NewEditMessageText(cid, uid, msg.Data.Content))
|
2018-05-29 17:20:56 +03:00
|
|
|
if err != nil {
|
2018-05-31 16:18:52 +03:00
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
2018-05-29 17:20:56 +03:00
|
|
|
logger.Error(err)
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-01 12:08:22 +03:00
|
|
|
if config.Debug {
|
2018-06-01 14:57:48 +03:00
|
|
|
logger.Debugf("mgWebhookHandler update %v", msg)
|
2018-06-01 12:08:22 +03:00
|
|
|
}
|
|
|
|
|
2018-05-29 17:20:56 +03:00
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
w.Write([]byte("Message updated"))
|
|
|
|
}
|
|
|
|
|
|
|
|
if msg.Type == "message_deleted" {
|
2018-06-01 15:24:04 +03:00
|
|
|
msg, err := bot.Send(tgbotapi.NewDeleteMessage(cid, uid))
|
2018-05-29 17:20:56 +03:00
|
|
|
if err != nil {
|
2018-05-31 16:18:52 +03:00
|
|
|
raven.CaptureErrorAndWait(err, nil)
|
2018-05-29 17:20:56 +03:00
|
|
|
logger.Error(err)
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2018-06-01 12:08:22 +03:00
|
|
|
if config.Debug {
|
2018-06-01 14:57:48 +03:00
|
|
|
logger.Debugf("mgWebhookHandler delete %v", msg)
|
2018-06-01 12:08:22 +03:00
|
|
|
}
|
|
|
|
|
2018-05-29 17:20:56 +03:00
|
|
|
w.WriteHeader(http.StatusOK)
|
|
|
|
w.Write([]byte("Message deleted"))
|
|
|
|
}
|
|
|
|
}
|
2018-06-04 16:48:04 +03:00
|
|
|
|
|
|
|
func getFileIDAndURL(token string, userID int) (fileID, fileURL string, err error) {
|
|
|
|
bot, err := tgbotapi.NewBotAPI(token)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
bot.Debug = config.Debug
|
|
|
|
|
|
|
|
res, err := bot.GetUserProfilePhotos(
|
|
|
|
tgbotapi.UserProfilePhotosConfig{
|
|
|
|
UserID: userID,
|
|
|
|
Limit: 1,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(res.Photos) > 0 {
|
|
|
|
fileID = res.Photos[0][len(res.Photos[0])-1].FileID
|
|
|
|
fileURL, err = bot.GetFileDirectURL(fileID)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func UploadUserAvatar(url string) (picURLs3 string, err error) {
|
|
|
|
s3Config := &aws.Config{
|
|
|
|
Credentials: credentials.NewStaticCredentials(
|
|
|
|
config.ConfigAWS.AccessKeyID,
|
|
|
|
config.ConfigAWS.SecretAccessKey,
|
|
|
|
""),
|
|
|
|
Region: aws.String(config.ConfigAWS.Region),
|
|
|
|
}
|
|
|
|
|
|
|
|
s := session.Must(session.NewSession(s3Config))
|
|
|
|
uploader := s3manager.NewUploader(s)
|
|
|
|
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
if resp.StatusCode >= http.StatusBadRequest {
|
|
|
|
return "", errors.New(fmt.Sprintf("get: %v code: %v", url, resp.StatusCode))
|
|
|
|
}
|
|
|
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
result, err := uploader.Upload(&s3manager.UploadInput{
|
|
|
|
Bucket: aws.String(config.ConfigAWS.Bucket),
|
|
|
|
Key: aws.String(fmt.Sprintf("%v.jpg", GenerateToken())),
|
|
|
|
Body: resp.Body,
|
|
|
|
ContentType: aws.String(config.ConfigAWS.ContentType),
|
|
|
|
ACL: aws.String("public-read"),
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
picURLs3 = result.Location
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|