1
0
mirror of synced 2024-11-25 21:26:02 +03:00

fix remarks pr, improve tests

This commit is contained in:
DmitryZagorulko 2018-05-25 18:09:38 +03:00
parent ce7f72d4b9
commit 5c6cab9fbf
7 changed files with 207 additions and 125 deletions

View File

@ -8,8 +8,6 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"regexp" "regexp"
"strconv"
"time"
"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"
@ -62,6 +60,8 @@ func setWrapperRoutes() {
http.HandleFunc("/save/", saveHandler) http.HandleFunc("/save/", saveHandler)
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("/activity-bot/", activityBotHandler)
} }
func renderTemplate(w http.ResponseWriter, tmpl string, c interface{}) { func renderTemplate(w http.ResponseWriter, tmpl string, c interface{}) {
@ -100,7 +100,7 @@ func connectHandler(w http.ResponseWriter, r *http.Request) {
}{ }{
&p, &p,
map[string]interface{}{ map[string]interface{}{
"ButConnect": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "but_connect"}), "ButtonSave": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "button_save"}),
"ApiKey": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "api_key"}), "ApiKey": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "api_key"}),
"Title": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "title"}), "Title": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "title"}),
}, },
@ -131,6 +131,13 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
c := getConnection(b.ClientID)
if c.MGURL == "" || c.MGToken == "" {
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "not_found_account"}), http.StatusBadRequest)
logger.Error(b.ClientID, "MGURL or MGToken is empty")
return
}
cl := getBotByToken(b.Token) cl := getBotByToken(b.Token)
if cl.ID != 0 { if cl.ID != 0 {
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "bot_already_created"}), http.StatusBadRequest) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "bot_already_created"}), http.StatusBadRequest)
@ -146,13 +153,19 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
bot.Debug = false bot.Debug = false
_, err = bot.SetWebhook(tgbotapi.NewWebhook("https://" + config.HTTPServer.Host + "/telegram/" + bot.Token)) wr, err := bot.SetWebhook(tgbotapi.NewWebhook("https://" + config.HTTPServer.Host + "/telegram/" + bot.Token))
if err != nil { if err != nil {
logger.Error(b.Token, err.Error()) logger.Error(b.Token, err.Error())
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_creating_webhook"}), http.StatusBadRequest) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_creating_webhook"}), http.StatusBadRequest)
return return
} }
if !wr.Ok {
logger.Error(b.Token, wr.ErrorCode, wr.Result)
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_creating_webhook"}), http.StatusBadRequest)
return
}
_, err = bot.GetWebhookInfo() _, err = bot.GetWebhookInfo()
if err != nil { if err != nil {
logger.Error(b.Token, err.Error()) logger.Error(b.Token, err.Error())
@ -162,13 +175,6 @@ func addBotHandler(w http.ResponseWriter, r *http.Request) {
b.Name = GetBotName(bot) b.Name = GetBotName(bot)
c := getConnection(b.ClientID)
if c.MGURL == "" || c.MGToken == "" {
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "not_found_account"}), http.StatusBadRequest)
logger.Error(b.ClientID, "MGURL or MGToken is empty")
return
}
ch := v1.Channel{ ch := v1.Channel{
Type: "telegram", Type: "telegram",
Events: []string{ Events: []string{
@ -227,6 +233,13 @@ func activityBotHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
c := getConnection(b.ClientID)
if c.MGURL == "" || c.MGToken == "" {
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "not_found_account"}), http.StatusBadRequest)
logger.Error(b.ClientID, "MGURL or MGToken is empty")
return
}
ch := v1.Channel{ ch := v1.Channel{
ID: getBotChannelByToken(b.Token), ID: getBotChannelByToken(b.Token),
Type: "telegram", Type: "telegram",
@ -238,13 +251,6 @@ func activityBotHandler(w http.ResponseWriter, r *http.Request) {
}, },
} }
c := getConnection(b.ClientID)
if c.MGURL == "" || c.MGToken == "" {
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "not_found_account"}), http.StatusBadRequest)
logger.Error(b.ClientID, "MGURL or MGToken is empty")
return
}
var client = v1.New(c.MGURL, c.MGToken) var client = v1.New(c.MGURL, c.MGToken)
if b.Active { if b.Active {
@ -265,6 +271,7 @@ func activityBotHandler(w http.ResponseWriter, r *http.Request) {
err = b.setBotActivity() err = b.setBotActivity()
if err != nil { if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(b.ClientID, err.Error()) logger.Error(b.ClientID, err.Error())
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_save"}), http.StatusInternalServerError) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_save"}), http.StatusInternalServerError)
return return
@ -297,7 +304,7 @@ func settingsHandler(w http.ResponseWriter, r *http.Request, uid string) {
p, p,
bots, bots,
map[string]interface{}{ map[string]interface{}{
"ButConnect": localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "but_connect"}), "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"}),
@ -331,7 +338,7 @@ func saveHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
err = validate(c) err = validateCrmSettings(c)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
logger.Error(c.APIURL, err.Error()) logger.Error(c.APIURL, err.Error())
@ -371,7 +378,7 @@ func createHandler(w http.ResponseWriter, r *http.Request) {
c.ClientID = GenerateToken() c.ClientID = GenerateToken()
err = validate(c) err = validateCrmSettings(c)
if err != nil { if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest) http.Error(w, err.Error(), http.StatusBadRequest)
logger.Error(c.APIURL, err.Error()) logger.Error(c.APIURL, err.Error())
@ -400,6 +407,8 @@ func createHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
//TODO: проверка на необходимые методы cr.Credentials
integration := v5.IntegrationModule{ integration := v5.IntegrationModule{
Code: transport, Code: transport,
IntegrationCode: transport, IntegrationCode: transport,
@ -466,7 +475,7 @@ func createHandler(w http.ResponseWriter, r *http.Request) {
jss, err := json.Marshal(res) jss, err := json.Marshal(res)
if err != nil { if err != nil {
raven.CaptureErrorAndWait(err, nil) raven.CaptureErrorAndWait(err, nil)
http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_creating_connection"}), http.StatusBadRequest) http.Error(w, localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "error_creating_connection"}), http.StatusInternalServerError)
return return
} }
@ -544,7 +553,7 @@ func activityHandler(w http.ResponseWriter, r *http.Request) {
w.Write(jsonString) w.Write(jsonString)
} }
func validate(c Connection) error { func validateCrmSettings(c Connection) error {
if c.APIURL == "" || c.APIKEY == "" { if c.APIURL == "" || c.APIKEY == "" {
return errors.New(localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "missing_url_key"})) return errors.New(localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: "missing_url_key"}))
} }
@ -555,98 +564,3 @@ func validate(c Connection) error {
return nil return nil
} }
func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string) {
ok := make(chan bool)
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(token, err)
return
}
go func() {
b := getBotByToken(token)
if b.ID == 0 {
logger.Error(token, "missing")
return
}
if !b.Active {
logger.Error(token, "deactivated")
return
}
var update tgbotapi.Update
err = json.Unmarshal(bytes, &update)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(token, err)
return
}
c := getConnection(b.ClientID)
if c.MGURL == "" || c.MGToken == "" {
logger.Error(token, "MGURL or MGToken is empty")
return
}
var client = v1.New(c.MGURL, c.MGToken)
if update.Message != nil {
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: update.Message.From.UserName,
Firstname: update.Message.From.FirstName,
},
Channel: b.Channel,
}
data, status, err := client.Messages(snd)
if err != nil {
logger.Error(token, err.Error(), status, data)
ok <- false
return
}
}
if update.EditedMessage != nil {
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, status, err := client.UpdateMessages(snd)
if err != nil {
logger.Error(token, err.Error(), status, data)
ok <- false
return
}
}
ok <- true
}()
if <-ok {
w.WriteHeader(http.StatusOK)
w.Write([]byte("SendMessage"))
} else {
w.WriteHeader(http.StatusBadRequest)
}
}

View File

@ -3,6 +3,7 @@ package main
import ( import (
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url"
"strings" "strings"
"testing" "testing"
@ -41,6 +42,8 @@ func TestRouting_connectHandler(t *testing.T) {
func TestRouting_addBotHandler(t *testing.T) { func TestRouting_addBotHandler(t *testing.T) {
defer gock.Off() defer gock.Off()
p := url.Values{"url": {"https://test.com/telegram/123123:Qwerty"}}
gock.New("https://api.telegram.org"). gock.New("https://api.telegram.org").
Post("/bot123123:Qwerty/getMe"). Post("/bot123123:Qwerty/getMe").
Reply(200). Reply(200).
@ -49,7 +52,7 @@ func TestRouting_addBotHandler(t *testing.T) {
gock.New("https://api.telegram.org"). gock.New("https://api.telegram.org").
Post("/bot123123:Qwerty/setWebhook"). Post("/bot123123:Qwerty/setWebhook").
MatchType("url"). MatchType("url").
BodyString("url=https%3A%2F%2Ftest.com%2Ftelegram%2F123123%3AQwerty"). BodyString(p.Encode()).
Reply(201). Reply(201).
BodyString(`{"ok":true}`) BodyString(`{"ok":true}`)
@ -144,6 +147,74 @@ func TestRouting_saveHandler(t *testing.T) {
} }
} }
//
//func TestRouting_createHandler(t *testing.T) {
// defer gock.Off()
//
// gock.New("https://test2.retailcrm.ru").
// Get("/api/credentials").
// Reply(200).
// BodyString(`{"success": true}`)
//
// integrationModule := v5.IntegrationModule{
// Code: transport,
// IntegrationCode: transport,
// Active: true,
// Name: "Telegram",
// ClientID: "123",
// Logo: fmt.Sprintf(
// "https://%s/web/telegram_logo.svg",
// config.HTTPServer.Host,
// ),
// BaseURL: fmt.Sprintf(
// "https://%s",
// config.HTTPServer.Host,
// ),
// AccountURL: fmt.Sprintf(
// "https://%s/settings/%s",
// config.HTTPServer.Host,
// "123",
// ),
// Actions: map[string]string{"activity": "/actions/activity"},
// Integrations: &v5.Integrations{
// MgTransport: &v5.MgTransport{
// WebhookUrl: fmt.Sprintf(
// "https://%s/webhook",
// config.HTTPServer.Host,
// ),
// },
// },
// }
//
// updateJSON, _ := json.Marshal(&integrationModule)
// p := url.Values{"integrationModule": {string(updateJSON[:])}}
//
// gock.New("https://test2.retailcrm.ru").
// Post(fmt.Sprintf("/api/v5/integration-modules/%s/edit", integrationModule.Code)).
// MatchType("url").
// BodyString(p.Encode()).
// MatchHeader("X-API-KEY", "test").
// Reply(201).
// BodyString(`{"success": true, "info": {"baseUrl": "http://test.te", "token": "test"}}`)
//
// req, err := http.NewRequest("POST", "/create/",
// strings.NewReader(
// `{"api_url": "https://test2.retailcrm.ru","api_key": "test"}`,
// ))
// if err != nil {
// t.Fatal(err)
// }
//
// rr := httptest.NewRecorder()
// handler := http.HandlerFunc(createHandler)
// handler.ServeHTTP(rr, req)
//
// if rr.Code != http.StatusFound {
// t.Errorf("handler returned wrong status code: got %v want %v",
// rr.Code, http.StatusFound)
// }
//}
func TestRouting_activityHandler(t *testing.T) { func TestRouting_activityHandler(t *testing.T) {
req, err := http.NewRequest("POST", "/actions/activity", req, err := http.NewRequest("POST", "/actions/activity",
strings.NewReader( strings.NewReader(

View File

@ -3,12 +3,17 @@ package main
import ( import (
"net/http" "net/http"
"encoding/json"
"io/ioutil"
"strconv"
"time"
"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/retailcrm/mg-transport-api-client-go/v1"
) )
func setTransportRoutes() { func setTransportRoutes() {
http.HandleFunc("/add-bot/", addBotHandler)
http.HandleFunc("/activity-bot/", activityBotHandler)
http.HandleFunc("/telegram/", makeHandler(telegramWebhookHandler)) http.HandleFunc("/telegram/", makeHandler(telegramWebhookHandler))
} }
@ -25,3 +30,95 @@ func GetBotInfo(token string) (*tgbotapi.BotAPI, error) {
func GetBotName(bot *tgbotapi.BotAPI) string { func GetBotName(bot *tgbotapi.BotAPI) string {
return bot.Self.FirstName return bot.Self.FirstName
} }
func telegramWebhookHandler(w http.ResponseWriter, r *http.Request, token string) {
b := getBotByToken(token)
if b.ID == 0 {
logger.Error(token, "missing")
w.WriteHeader(http.StatusBadRequest)
return
}
if !b.Active {
logger.Error(token, "deactivated")
w.WriteHeader(http.StatusBadRequest)
return
}
c := getConnection(b.ClientID)
if c.MGURL == "" || c.MGToken == "" {
logger.Error(token, "MGURL or MGToken is empty")
w.WriteHeader(http.StatusBadRequest)
return
}
var update tgbotapi.Update
bytes, err := ioutil.ReadAll(r.Body)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
w.WriteHeader(http.StatusInternalServerError)
logger.Error(token, err)
return
}
err = json.Unmarshal(bytes, &update)
if err != nil {
raven.CaptureErrorAndWait(err, nil)
logger.Error(token, err)
w.WriteHeader(http.StatusInternalServerError)
return
}
var client = v1.New(c.MGURL, c.MGToken)
if update.Message != nil {
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: update.Message.From.UserName,
Firstname: update.Message.From.FirstName,
Lastname: update.Message.From.LastName,
Language: update.Message.From.LanguageCode,
},
Channel: b.Channel,
}
data, st, err := client.Messages(snd)
if err != nil {
logger.Error(token, err.Error(), st, data)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
if update.EditedMessage != nil {
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(token, err.Error(), st, data)
w.WriteHeader(http.StatusInternalServerError)
return
}
}
w.WriteHeader(http.StatusOK)
}

View File

@ -23,7 +23,7 @@
<div class="row"> <div class="row">
<div class="input-field col s12 center-align"> <div class="input-field col s12 center-align">
<button class="btn waves-effect waves-light light-blue darken-1" type="submit" name="action"> <button class="btn waves-effect waves-light light-blue darken-1" type="submit" name="action">
{{.Locale.ButConnect}} {{.Locale.ButtonSave}}
<i class="material-icons right">sync</i> <i class="material-icons right">sync</i>
</button> </button>
</div> </div>

View File

@ -15,7 +15,7 @@
<div class="row"> <div class="row">
<div class="input-field col s12 center-align"> <div class="input-field col s12 center-align">
<button class="btn waves-effect waves-light light-blue darken-1" type="submit" name="action"> <button class="btn waves-effect waves-light light-blue darken-1" type="submit" name="action">
{{.Locale.ButConnect}} {{.Locale.ButtonSave}}
<i class="material-icons right">sync</i> <i class="material-icons right">sync</i>
</button> </button>
</div> </div>

View File

@ -1,4 +1,4 @@
but_connect: Save button_save: Save
tab_settings: Connection settings tab_settings: Connection settings
tab_bots: Bots tab_bots: Bots
table_name: Bot name table_name: Bot name

View File

@ -1,4 +1,4 @@
but_connect: Сохранить button_save: Сохранить
tab_settings: Настройки CRM tab_settings: Настройки CRM
tab_bots: Боты tab_bots: Боты
table_name: Имя table_name: Имя