1
0
mirror of synced 2024-11-25 13:16:02 +03:00

add src dir, improve makefile

This commit is contained in:
DmitryZagorulko 2018-08-17 16:31:55 +03:00
parent 3e8fb7c1a9
commit 30b00da6bc
18 changed files with 352 additions and 367 deletions

View File

@ -1,20 +1,14 @@
ROOT_DIR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) ROOT_DIR=$(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
SRC_DIR=$(ROOT_DIR) SRC_DIR=$(ROOT_DIR)/src
MIGRATIONS_DIR=$(ROOT_DIR)/migrations MIGRATIONS_DIR=$(ROOT_DIR)/migrations
CONFIG_FILE=$(ROOT_DIR)/config.yml CONFIG_FILE=$(ROOT_DIR)/config.yml
CONFIG_TEST_FILE=$(ROOT_DIR)/config_test.yml CONFIG_TEST_FILE=$(ROOT_DIR)/config_test.yml
BIN=$(ROOT_DIR)/bin/transport BIN=$(ROOT_DIR)/bin/transport
REVISION=$(shell git describe --tags 2>/dev/null || git log --format="v0.0-%h" -n 1 || echo "v0.0-unknown") REVISION=$(shell git describe --tags 2>/dev/null || git log --format="v0.0-%h" -n 1 || echo "v0.0-unknown")
ifndef GOPATH
$(error GOPATH must be defined)
endif
export GOPATH := $(GOPATH):$(ROOT_DIR)
build: deps fmt build: deps fmt
@echo "==> Building" @echo "==> Building"
@cd $(ROOT_DIR) && CGO_ENABLED=0 go build -o $(BIN) -ldflags "-X common.build=${REVISION}" . @cd $(SRC_DIR) && CGO_ENABLED=0 go build -o $(BIN) -ldflags "-X common.build=${REVISION}" .
@echo $(BIN) @echo $(BIN)
run: migrate run: migrate

View File

View File

@ -1,9 +1,10 @@
package main package main
import ( import (
"net/http"
"fmt" "fmt"
"net/http"
"strconv"
"time"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-telegram-bot-api/telegram-bot-api" "github.com/go-telegram-bot-api/telegram-bot-api"
@ -271,3 +272,250 @@ func getIntegrationModule(clientId string) v5.IntegrationModule {
}, },
} }
} }
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{
Message: v1.SendMessage{
Message: v1.Message{
ExternalID: strconv.Itoa(update.Message.MessageID),
Type: "text",
Text: update.Message.Text,
},
SentAt: time.Now(),
},
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 {
c.Error(err)
return
}
if msg.Type == "message_sent" {
m := tgbotapi.NewMessage(cid, msg.Data.Content)
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)})
}
if msg.Type == "message_updated" {
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)
}
if msg.Type == "message_deleted" {
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{})
}
}

View File

57
src/telegram.go Normal file
View File

@ -0,0 +1,57 @@
package main
import "github.com/go-telegram-bot-api/telegram-bot-api"
//GetFileIDAndURL function
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 config.Debug {
logger.Debugf("GetFileIDAndURL Photos: %v", res.Photos)
}
if len(res.Photos) > 0 {
fileID = res.Photos[0][len(res.Photos[0])-1].FileID
fileURL, err = bot.GetFileDirectURL(fileID)
}
return
}
func getMessageID(data *tgbotapi.Message) string {
switch {
case data.Sticker != nil:
return "sticker"
case data.Audio != nil:
return "audio"
case data.Contact != nil:
return "contact"
case data.Document != nil:
return "document"
case data.Location != nil:
return "location"
case data.Video != nil:
return "video"
case data.Voice != nil:
return "voice"
case data.Photo != nil:
return "photo"
default:
return "undefined"
}
}

View File

@ -9,6 +9,10 @@ import (
"sync/atomic" "sync/atomic"
"time" "time"
"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"
"github.com/nicksnyder/go-i18n/v2/i18n" "github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/retailcrm/api-client-go/v5" "github.com/retailcrm/api-client-go/v5"
) )
@ -68,3 +72,42 @@ func checkCredentials(credential []string) []string {
return rc return rc
} }
//UploadUserAvatar function
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
}
defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest {
return "", errors.New(fmt.Sprintf("get: %v code: %v", url, resp.StatusCode))
}
result, err := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(config.ConfigAWS.Bucket),
Key: aws.String(fmt.Sprintf("%v/%v.jpg", config.ConfigAWS.FolderName, GenerateToken())),
Body: resp.Body,
ContentType: aws.String(config.ConfigAWS.ContentType),
ACL: aws.String("public-read"),
})
if err != nil {
return
}
picURLs3 = result.Location
return
}

View File

@ -1,357 +0,0 @@
package main
import (
"errors"
"fmt"
"net/http"
"strconv"
"time"
"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"
"github.com/gin-gonic/gin"
"github.com/go-telegram-bot-api/telegram-bot-api"
"github.com/retailcrm/mg-transport-api-client-go/v1"
)
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{
Message: v1.SendMessage{
Message: v1.Message{
ExternalID: strconv.Itoa(update.Message.MessageID),
Type: "text",
Text: update.Message.Text,
},
SentAt: time.Now(),
},
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 {
c.Error(err)
return
}
if msg.Type == "message_sent" {
m := tgbotapi.NewMessage(cid, msg.Data.Content)
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)})
}
if msg.Type == "message_updated" {
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)
}
if msg.Type == "message_deleted" {
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{})
}
}
//GetFileIDAndURL function
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 config.Debug {
logger.Debugf("GetFileIDAndURL Photos: %v", res.Photos)
}
if len(res.Photos) > 0 {
fileID = res.Photos[0][len(res.Photos[0])-1].FileID
fileURL, err = bot.GetFileDirectURL(fileID)
}
return
}
//UploadUserAvatar function
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
}
defer resp.Body.Close()
if resp.StatusCode >= http.StatusBadRequest {
return "", errors.New(fmt.Sprintf("get: %v code: %v", url, resp.StatusCode))
}
result, err := uploader.Upload(&s3manager.UploadInput{
Bucket: aws.String(config.ConfigAWS.Bucket),
Key: aws.String(fmt.Sprintf("%v/%v.jpg", config.ConfigAWS.FolderName, GenerateToken())),
Body: resp.Body,
ContentType: aws.String(config.ConfigAWS.ContentType),
ACL: aws.String("public-read"),
})
if err != nil {
return
}
picURLs3 = result.Location
return
}
func getMessageID(data *tgbotapi.Message) string {
switch {
case data.Sticker != nil:
return "sticker"
case data.Audio != nil:
return "audio"
case data.Contact != nil:
return "contact"
case data.Document != nil:
return "document"
case data.Location != nil:
return "location"
case data.Video != nil:
return "video"
case data.Voice != nil:
return "voice"
case data.Photo != nil:
return "photo"
default:
return "undefined"
}
}