1
0
mirror of synced 2024-11-22 20:36:01 +03:00

Merge pull request #19 from DmitryZagorulko/master

* sending text stub
* translations
* delete bot instead deactivate
This commit is contained in:
Alex Lushpai 2018-06-28 22:38:32 +03:00 committed by GitHub
commit d1054f7653
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 209 additions and 183 deletions

View File

@ -1 +1 @@
alter table mg_user rename to user; alter table mg_user rename to users;

View File

@ -0,0 +1 @@
alter table bot add column active boolean;

View File

@ -0,0 +1 @@
alter table bot drop column active;

View File

@ -25,7 +25,6 @@ type Bot struct {
Name string `gorm:"name type:varchar(40)" json:"name,omitempty"` Name string `gorm:"name type:varchar(40)" json:"name,omitempty"`
CreatedAt time.Time CreatedAt time.Time
UpdatedAt time.Time UpdatedAt time.Time
Active bool `json:"active,omitempty"`
} }
// User model // User model

View File

@ -48,8 +48,8 @@ func getBotByToken(token string) (*Bot, error) {
return &bot, nil return &bot, nil
} }
func (b *Bot) setBotActivity() error { func (b *Bot) deleteBot() error {
return orm.DB.Model(b).Where("token = ?", b.Token).Update("Active", !b.Active).Error return orm.DB.Delete(b, "token = ?", b.Token).Error
} }
func getBotChannelByToken(token string) uint64 { func getBotChannelByToken(token string) uint64 {
@ -69,9 +69,9 @@ func (c Connection) getBotsByClientID() Bots {
return b return b
} }
func getBotByChannelAndCID(connectionID int, ch uint64) *Bot { func getBot(cid int, ch uint64) *Bot {
var bot Bot var bot Bot
orm.DB.First(&bot, "connection_id = ? AND channel = ?", connectionID, ch) orm.DB.First(&bot, "connection_id = ? AND channel = ?", cid, ch)
return &bot return &bot
} }

View File

@ -61,7 +61,7 @@ func setWrapperRoutes() {
http.HandleFunc("/create/", createHandler) http.HandleFunc("/create/", createHandler)
http.HandleFunc("/actions/activity", activityHandler) http.HandleFunc("/actions/activity", activityHandler)
http.HandleFunc("/add-bot/", addBotHandler) http.HandleFunc("/add-bot/", addBotHandler)
http.HandleFunc("/activity-bot/", activityBotHandler) http.HandleFunc("/delete-bot/", deleteBotHandler)
} }
func renderTemplate(w http.ResponseWriter, tmpl string, c interface{}) { func renderTemplate(w http.ResponseWriter, tmpl string, c interface{}) {
@ -200,7 +200,6 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
} }
b.Channel = data.ChannelID b.Channel = data.ChannelID
b.Active = true
err = c.createBot(b) err = c.createBot(b)
if err != nil { if err != nil {
@ -222,7 +221,7 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
w.Write(jsonString) w.Write(jsonString)
} }
func activityBotHandler(w http.ResponseWriter, r *http.Request) { func deleteBotHandler(w http.ResponseWriter, r *http.Request) {
defer r.Body.Close() defer r.Body.Close()
setLocale(r.Header.Get("Accept-Language")) setLocale(r.Header.Get("Accept-Language"))
body, err := ioutil.ReadAll(r.Body) body, err := ioutil.ReadAll(r.Body)
@ -250,36 +249,16 @@ func activityBotHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
ch := v1.Channel{
ID: getBotChannelByToken(b.Token),
Type: "telegram",
Events: []string{
"message_sent",
"message_updated",
"message_deleted",
"message_read",
},
}
var client = v1.New(c.MGURL, c.MGToken) var client = v1.New(c.MGURL, c.MGToken)
if b.Active { data, status, err := client.DeactivateTransportChannel(getBotChannelByToken(b.Token))
data, status, err := client.DeactivateTransportChannel(ch.ID) if status > http.StatusOK {
if status > http.StatusOK { http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_deactivating_channel"}), http.StatusBadRequest)
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_deactivating_channel"}), http.StatusBadRequest) logger.Error(b.ID, status, err.Error(), data)
logger.Error(b.ID, status, err.Error(), data) return
return
}
} else {
data, status, err := client.ActivateTransportChannel(ch)
if status > http.StatusCreated {
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_activating_channel"}), http.StatusBadRequest)
logger.Error(b.ID, status, err.Error(), data)
return
}
} }
err = b.setBotActivity() err = b.deleteBot()
if err != nil { if err != nil {
raven.CaptureErrorAndWait(err, nil) raven.CaptureErrorAndWait(err, nil)
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_save"}), http.StatusInternalServerError) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_save"}), http.StatusInternalServerError)
@ -309,15 +288,15 @@ func settingsHandler(w http.ResponseWriter, r *http.Request, uid string) {
p, p,
bots, bots,
map[string]interface{}{ map[string]interface{}{
"ButtonSave": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "button_save"}), "ButtonSave": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "button_save"}),
"ApiKey": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "api_key"}), "ApiKey": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "api_key"}),
"TabSettings": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_settings"}), "TabSettings": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_settings"}),
"TabBots": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_bots"}), "TabBots": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "tab_bots"}),
"TableName": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_name"}), "TableName": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_name"}),
"TableToken": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_token"}), "TableToken": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_token"}),
"AddBot": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "add_bot"}), "AddBot": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "add_bot"}),
"TableActivity": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_activity"}), "TableDelete": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "table_delete"}),
"Title": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "title"}), "Title": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "title"}),
}, },
} }

View File

@ -103,7 +103,7 @@ func TestRouting_addBotHandler(t *testing.T) {
assert.Equal(t, "123123:Qwerty", res["token"]) assert.Equal(t, "123123:Qwerty", res["token"])
} }
func TestRouting_activityBotHandler(t *testing.T) { func TestRouting_deleteBotHandler(t *testing.T) {
defer gock.Off() defer gock.Off()
gock.New("https://test.retailcrm.pro"). gock.New("https://test.retailcrm.pro").
@ -114,13 +114,13 @@ func TestRouting_activityBotHandler(t *testing.T) {
Reply(200). Reply(200).
BodyString(`{"id": 1}`) BodyString(`{"id": 1}`)
req, err := http.NewRequest("POST", "/activity-bot/", strings.NewReader(`{"token": "123123:Qwerty", "active": false, "connectionId": 1}`)) req, err := http.NewRequest("POST", "/delete-bot/", strings.NewReader(`{"token": "123123:Qwerty", "active": false, "connectionId": 1}`))
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
rr := httptest.NewRecorder() rr := httptest.NewRecorder()
handler := http.HandlerFunc(activityBotHandler) handler := http.HandlerFunc(deleteBotHandler)
handler.ServeHTTP(rr, req) handler.ServeHTTP(rr, req)
assert.Equal(t, http.StatusOK, rr.Code, assert.Equal(t, http.StatusOK, rr.Code,

View File

@ -39,21 +39,17 @@ $("#add-bot").on("submit", function(e) {
) )
}); });
$(document).on("click", ".activity-bot", function(e) { $(document).on("click", ".delete-bot", function(e) {
let but = $(this); let but = $(this);
send("/activity-bot/", send("/delete-bot/",
{ {
token: but.attr("data-token"), token: but.attr("data-token"),
active: (but.attr("data-activity") === 'true'),
connectionId: parseInt($('input[name=connectionId]').val()), connectionId: parseInt($('input[name=connectionId]').val()),
}, },
function () { function () {
if (but.attr("data-activity") === 'true') { but.parents("tr").remove();
but.find('i').replaceWith('<i class="material-icons">play_arrow</i>'); if ($("#bots tbody tr").length === 0) {
but.attr("data-activity", "false") $("#bots").addClass("hide");
} else {
but.find('i').replaceWith('<i class="material-icons">pause</i>');
but.attr("data-activity", "true")
} }
} }
) )
@ -89,9 +85,9 @@ function getBotTemplate(data) {
<td>${bot.name}</td> <td>${bot.name}</td>
<td>${bot.token}</td> <td>${bot.token}</td>
<td> <td>
<button class="activity-bot btn btn-small waves-effect waves-light light-blue darken-1" type="submit" name="action" <button class="delete-bot btn btn-small waves-effect waves-light light-blue darken-1" type="submit" name="action"
data-activity="true" data-token="${bot.token}"> data-token="${bot.token}">
<i class="material-icons">pause</i> <i class="material-icons">delete</i>
</button> </button>
</td> </td>
</tr>`; </tr>`;

View File

@ -16,7 +16,7 @@
margin: 0 auto; margin: 0 auto;
} }
#bots .activity-bot{ #bots .delete-bot{
float: right; float: right;
} }

View File

@ -15,6 +15,7 @@ import (
"github.com/aws/aws-sdk-go/service/s3/s3manager" "github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/getsentry/raven-go" "github.com/getsentry/raven-go"
"github.com/go-telegram-bot-api/telegram-bot-api" "github.com/go-telegram-bot-api/telegram-bot-api"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/retailcrm/mg-transport-api-client-go/v1" "github.com/retailcrm/mg-transport-api-client-go/v1"
) )
@ -38,7 +39,7 @@ func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string
return return
} }
if b.ID == 0 || !b.Active { if b.ID == 0 {
logger.Error(token, "telegramWebhookHandler: missing or deactivated") logger.Error(token, "telegramWebhookHandler: missing or deactivated")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
return return
@ -76,112 +77,118 @@ func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string
var client = v1.New(c.MGURL, c.MGToken) var client = v1.New(c.MGURL, c.MGToken)
if update.Message != nil { if update.Message != nil {
if update.Message.Text != "" { if update.Message.Text == "" {
nickname := update.Message.From.UserName setLocale(update.Message.From.LanguageCode)
user := getUserByExternalID(update.Message.From.ID) update.Message.Text = localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: getMessageID(update.Message)})
}
if update.Message.From.UserName == "" { nickname := update.Message.From.UserName
nickname = update.Message.From.FirstName user := getUserByExternalID(update.Message.From.ID)
}
if user.Expired(config.UpdateInterval) || user.ID == 0 { if update.Message.From.UserName == "" {
fileID, fileURL, err := GetFileIDAndURL(b.Token, update.Message.From.ID) nickname = update.Message.From.FirstName
if err != nil { }
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
if fileID != user.UserPhotoID && fileURL != "" { if user.Expired(config.UpdateInterval) || user.ID == 0 {
picURL, err := UploadUserAvatar(fileURL) 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
}
user.UserPhotoID = fileID
user.UserPhotoURL = picURL
}
if user.ExternalID == 0 {
user.ExternalID = update.Message.From.ID
}
err = user.save()
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
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: update.Message.From.LanguageCode,
},
Channel: b.Channel,
ExternalChatID: strconv.FormatInt(update.Message.Chat.ID, 10),
}
data, st, err := client.Messages(snd)
if err != nil { if err != nil {
raven.CaptureErrorAndWait(err, nil) raven.CaptureErrorAndWait(err, nil)
logger.Error(token, err.Error(), st, data) logger.Error(err)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if config.Debug { if fileID != user.UserPhotoID && fileURL != "" {
logger.Debugf("telegramWebhookHandler Type: SendMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data) 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.save()
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(err)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
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: update.Message.From.LanguageCode,
},
Channel: b.Channel,
ExternalChatID: strconv.FormatInt(update.Message.Chat.ID, 10),
}
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)
} }
} }
if update.EditedMessage != nil { if update.EditedMessage != nil {
if update.EditedMessage.Text != "" { if update.EditedMessage.Text == "" {
snd := v1.UpdateData{ setLocale(update.EditedMessage.From.LanguageCode)
Message: v1.UpdateMessage{ update.EditedMessage.Text = localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: getMessageID(update.Message)})
Message: v1.Message{ }
ExternalID: strconv.Itoa(update.EditedMessage.MessageID),
Type: "text", snd := v1.UpdateData{
Text: update.EditedMessage.Text, Message: v1.UpdateMessage{
}, Message: v1.Message{
ExternalID: strconv.Itoa(update.EditedMessage.MessageID),
Type: "text",
Text: update.EditedMessage.Text,
}, },
Channel: b.Channel, },
} Channel: b.Channel,
}
data, st, err := client.UpdateMessages(snd) data, st, err := client.UpdateMessages(snd)
if err != nil { if err != nil {
raven.CaptureErrorAndWait(err, nil) raven.CaptureErrorAndWait(err, nil)
logger.Error(token, err.Error(), st, data) logger.Error(token, err.Error(), st, data)
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return
} }
if config.Debug { if config.Debug {
logger.Debugf("telegramWebhookHandler Type: UpdateMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data) logger.Debugf("telegramWebhookHandler Type: UpdateMessage, Bot: %v, Message: %v, Response: %v", b.ID, snd, data)
}
} }
} }
@ -229,8 +236,8 @@ func mgWebhookHandler(w http.ResponseWriter, r *http.Request) {
uid, _ := strconv.Atoi(msg.Data.ExternalMessageID) uid, _ := strconv.Atoi(msg.Data.ExternalMessageID)
cid, _ := strconv.ParseInt(msg.Data.ExternalChatID, 10, 64) cid, _ := strconv.ParseInt(msg.Data.ExternalChatID, 10, 64)
b := getBotByChannelAndCID(c.ID, msg.Data.ChannelID) b := getBot(c.ID, msg.Data.ChannelID)
if b.ID == 0 || !b.Active { if b.ID == 0 {
logger.Error(msg.Data.ChannelID, "mgWebhookHandler: missing or deactivated") logger.Error(msg.Data.ChannelID, "mgWebhookHandler: missing or deactivated")
w.WriteHeader(http.StatusBadRequest) w.WriteHeader(http.StatusBadRequest)
w.Write([]byte("missing or deactivated")) w.Write([]byte("missing or deactivated"))
@ -377,3 +384,26 @@ func UploadUserAvatar(url string) (picURLs3 string, err error) {
return 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

@ -53,7 +53,7 @@
<tr> <tr>
<th>{{.Locale.TableName}}</th> <th>{{.Locale.TableName}}</th>
<th>{{.Locale.TableToken}}</th> <th>{{.Locale.TableToken}}</th>
<th class="text-left">{{.Locale.TableActivity}}</th> <th class="text-left">{{.Locale.TableDelete}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@ -62,9 +62,9 @@
<td>{{.Name}}</td> <td>{{.Name}}</td>
<td>{{.Token}}</td> <td>{{.Token}}</td>
<td> <td>
<button class="activity-bot btn btn-small waves-effect waves-light light-blue darken-1" type="submit" name="action" <button class="delete-bot btn btn-small waves-effect waves-light light-blue darken-1" type="submit" name="action"
data-activity="{{.Active}}" data-token="{{.Token}}"> data-token="{{.Token}}">
<i class="material-icons">{{if .Active}}pause{{else}}play_arrow{{end}}</i> <i class="material-icons">delete</i>
</button> </button>
</td> </td>
</tr> </tr>

View File

@ -1,30 +1,40 @@
button_save: Save button_save: Save
tab_settings: Connection settings tab_settings: CRM settings
tab_bots: Bots tab_bots: Bots
table_name: Bot name table_name: Name
table_token: Bot token table_token: Token
table_activity: Activity table_delete: Delete
api_key: API Key api_key: API key
add_bot: Add bot add_bot: Add a bot
title: Telegram transport for retailCRM title: Module of connecting Telegram to retailCRM
successful: Data successfully updated successful: Data was updated successfully
no_bot_token: Enter the bot token no_bot_token: Enter a token
wrong_data: Incorrect data wrong_data: Wrong data
set_method: Set POST method set_method: Set POST method
bot_already_created: Bot already created bot_already_created: Bot is already created
not_found_account: The account could not be found, contact technical support not_found_account: Account is not found, contact technical support
error_activating_channel: Error while activating the channel error_activating_channel: Error when activating a channel
error_deactivating_channel: Error while deactivating the channel error_deactivating_channel: Error when deactivating a channel
incorrect_url_key: Enter the correct CRM url or apiKey incorrect_url_key: Enter the correct URL or API key
error_creating_integration: Error while creating integration error_creating_integration: Error when integrating
error_creating_connection: Error while creating connection error_creating_connection: Error when establishing a connection
connection_already_created: Connection already created connection_already_created: Connection is already established
missing_url_key: Missing crm url or apiKey missing_url_key: URL and API key are missing
incorrect_url: Enter the correct CRM url incorrect_url: Enter the correct URL of CRM
incorrect_token: Set correct bot token incorrect_token: Create the correct token
error_creating_webhook: Error while creating webhook error_creating_webhook: Error when creating a webhook
error_adding_bot: Error while adding bot error_adding_bot: Error when adding a bot
error_save: An error occurred while saving, contact technical support error_save: Error while saving, contact technical support
missing_credentials: "Necessary credentials: {{.Credentials}}" missing_credentials: "Required methods: {{.Credentials}}"
error_activity_mg: Check the activity with MessageGateway in CRM settings error_activity_mg: Check if the integration with MessageGateway is enabled in CRM settings
sticker: "[sticker]"
audio: "[audio file]"
contact: "[contact]"
document: "[document]"
location: "[location]"
video: "[video]"
voice: "[voice message]"
photo: "[photo]"
undefined: "[undefined format of a message]"

View File

@ -3,7 +3,7 @@ tab_settings: Настройки CRM
tab_bots: Боты tab_bots: Боты
table_name: Имя table_name: Имя
table_token: Токен table_token: Токен
table_activity: Активность table_delete: Удалить
api_key: API Ключ api_key: API Ключ
add_bot: Добавить бота add_bot: Добавить бота
title: Модуль подключения Telegram к retailCRM title: Модуль подключения Telegram к retailCRM
@ -28,3 +28,13 @@ error_adding_bot: Ошибка при добавлении бота
error_save: Ошибка при сохранении, обратитесь в службу технической поддержки error_save: Ошибка при сохранении, обратитесь в службу технической поддержки
missing_credentials: "Необходимые методы: {{.Credentials}}" missing_credentials: "Необходимые методы: {{.Credentials}}"
error_activity_mg: Проверьте активность интеграции с MessageGateway в настройках CRM error_activity_mg: Проверьте активность интеграции с MessageGateway в настройках CRM
sticker: "[стикер]"
audio: "[аудио файл]"
contact: "[контакт]"
document: "[документ]"
location: "[местонахождение]"
video: "[видео]"
voice: "[голосовое сообщение]"
photo: "[изображение]"
undefined: "[неопределенный формат сообщения]"