1
0
mirror of synced 2024-11-30 07:06:02 +03:00

merge master

This commit is contained in:
Alex Lushpai 2018-09-21 19:46:18 +03:00
commit 8e5268a285
20 changed files with 407 additions and 49 deletions

2
go.mod
View File

@ -45,7 +45,7 @@ require (
github.com/pkg/errors v0.8.0 github.com/pkg/errors v0.8.0
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/retailcrm/api-client-go v1.0.6 github.com/retailcrm/api-client-go v1.0.6
github.com/retailcrm/mg-transport-api-client-go v1.1.9 github.com/retailcrm/mg-transport-api-client-go v1.1.10
github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf // indirect github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf // indirect
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect github.com/stevvooe/resumable v0.0.0-20180830230917-22b14a53ba50 // indirect

2
go.sum
View File

@ -97,6 +97,8 @@ github.com/retailcrm/api-client-go v1.0.6 h1:4Q3e4ve8GOOHIQdq3/wTGqgWuWa1cKMKqmg
github.com/retailcrm/api-client-go v1.0.6/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c= github.com/retailcrm/api-client-go v1.0.6/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c=
github.com/retailcrm/mg-transport-api-client-go v1.1.9 h1:ogh5ThoqZJM5v4ZY6CqctUj01pVVHfBLXkrmX+BFjHE= github.com/retailcrm/mg-transport-api-client-go v1.1.9 h1:ogh5ThoqZJM5v4ZY6CqctUj01pVVHfBLXkrmX+BFjHE=
github.com/retailcrm/mg-transport-api-client-go v1.1.9/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= github.com/retailcrm/mg-transport-api-client-go v1.1.9/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI=
github.com/retailcrm/mg-transport-api-client-go v1.1.10 h1:RR8S5NA6FPVrF6UVXaLwu/gJyKUg5aUObQ97S98M3Yc=
github.com/retailcrm/mg-transport-api-client-go v1.1.10/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI=
github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf h1:6V1qxN6Usn4jy8unvggSJz/NC790tefw8Zdy6OZS5co=
github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180820201707-7c9eb446e3cf/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo= github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a h1:JSvGDIbmil4Ui/dDdFBExb7/cmkNjyX5F97oglmvCDo=

View File

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

View File

@ -0,0 +1 @@
alter table bot add column channel_settings_hash varchar(70);

View File

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

View File

@ -0,0 +1 @@
alter table bot add column lang varchar(2);

View File

@ -41,6 +41,13 @@ func getLocalizedMessage(messageID string) string {
return localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID}) return localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID})
} }
func getLocalizedTemplateMessage(messageID string, templateData map[string]interface{}) string {
return localizer.MustLocalize(&i18n.LocalizeConfig{
MessageID: messageID,
TemplateData: templateData,
})
}
func getLocale() map[string]interface{} { func getLocale() map[string]interface{} {
return map[string]interface{}{ return map[string]interface{}{
"ButtonSave": getLocalizedMessage("button_save"), "ButtonSave": getLocalizedMessage("button_save"),
@ -52,6 +59,7 @@ func getLocale() map[string]interface{} {
"AddBot": getLocalizedMessage("add_bot"), "AddBot": getLocalizedMessage("add_bot"),
"TableDelete": getLocalizedMessage("table_delete"), "TableDelete": getLocalizedMessage("table_delete"),
"Title": getLocalizedMessage("title"), "Title": getLocalizedMessage("title"),
"Language": getLocalizedMessage("language"),
"InfoBot": template.HTML(getLocalizedMessage("info_bot")), "InfoBot": template.HTML(getLocalizedMessage("info_bot")),
"CRMLink": template.HTML(getLocalizedMessage("crm_link")), "CRMLink": template.HTML(getLocalizedMessage("crm_link")),
"DocLink": template.HTML(getLocalizedMessage("doc_link")), "DocLink": template.HTML(getLocalizedMessage("doc_link")),

View File

@ -14,6 +14,8 @@ type Options struct {
Config string `short:"c" long:"config" default:"config.yml" description:"Path to configuration file"` Config string `short:"c" long:"config" default:"config.yml" description:"Path to configuration file"`
} }
const Type = "telegram"
var ( var (
config *TransportConfig config *TransportConfig
orm *Orm orm *Orm

View File

@ -18,13 +18,15 @@ type Connection struct {
// Bot model // Bot model
type Bot struct { type Bot struct {
ID int `gorm:"primary_key"` ID int `gorm:"primary_key"`
ConnectionID int `gorm:"connection_id" json:"connectionId,omitempty"` ConnectionID int `gorm:"connection_id" json:"connectionId,omitempty"`
Channel uint64 `gorm:"channel;not null;unique" json:"channel,omitempty"` Channel uint64 `gorm:"channel;not null;unique" json:"channel,omitempty"`
Token string `gorm:"token type:varchar(100);not null;unique" json:"token,omitempty"` ChannelSettingsHash string `gorm:"channel_settings_hash type:varchar(70)"`
Name string `gorm:"name type:varchar(40)" json:"name,omitempty"` Token string `gorm:"token type:varchar(100);not null;unique" json:"token,omitempty"`
CreatedAt time.Time Name string `gorm:"name type:varchar(40)" json:"name,omitempty"`
UpdatedAt time.Time Lang string `gorm:"lang type:varchar(2)" json:"lang,omitempty"`
CreatedAt time.Time
UpdatedAt time.Time
} }
// User model // User model

View File

@ -13,6 +13,13 @@ func getConnection(uid string) *Connection {
return &connection return &connection
} }
func getConnections() []*Connection {
var connection []*Connection
orm.DB.Find(&connection)
return connection
}
func getConnectionByURL(urlCrm string) *Connection { func getConnectionByURL(urlCrm string) *Connection {
var connection Connection var connection Connection
orm.DB.First(&connection, "api_url = ?", urlCrm) orm.DB.First(&connection, "api_url = ?", urlCrm)
@ -52,6 +59,10 @@ func getBotByToken(token string) (*Bot, error) {
return &bot, nil return &bot, nil
} }
func (b *Bot) save() error {
return orm.DB.Save(b).Error
}
func (b *Bot) deleteBot() error { func (b *Bot) deleteBot() error {
return orm.DB.Delete(b, "token = ?", b.Token).Error return orm.DB.Delete(b, "token = ?", b.Token).Error
} }

View File

@ -58,36 +58,10 @@ func addBotHandler(c *gin.Context) {
} }
b.Name = bot.Self.FirstName b.Name = bot.Self.FirstName
ch := v1.Channel{
Type: "telegram",
Settings: v1.ChannelSettings{
SpamAllowed: false,
Status: v1.Status{
Delivered: v1.ChannelFeatureSend,
Read: v1.ChannelFeatureNone,
},
Text: v1.ChannelSettingsText{
Creating: v1.ChannelFeatureBoth,
Editing: v1.ChannelFeatureBoth,
Quoting: v1.ChannelFeatureBoth,
Deleting: v1.ChannelFeatureReceive,
},
Product: v1.Product{
Creating: v1.ChannelFeatureReceive,
Editing: v1.ChannelFeatureReceive,
},
Order: v1.Order{
Creating: v1.ChannelFeatureReceive,
Editing: v1.ChannelFeatureReceive,
},
},
}
conn := getConnectionById(b.ConnectionID) conn := getConnectionById(b.ConnectionID)
client := v1.New(conn.MGURL, conn.MGToken)
var client = v1.New(conn.MGURL, conn.MGToken) data, status, err := client.ActivateTransportChannel(getChannelSettings())
data, status, err := client.ActivateTransportChannel(ch)
if status != http.StatusCreated { if status != http.StatusCreated {
c.AbortWithStatusJSON(BadRequest("error_activating_channel")) c.AbortWithStatusJSON(BadRequest("error_activating_channel"))
logger.Error(conn.APIURL, status, err.Error(), data) logger.Error(conn.APIURL, status, err.Error(), data)
@ -143,15 +117,17 @@ func settingsHandler(c *gin.Context) {
bots := p.getBotsByClientID() bots := p.getBotsByClientID()
res := struct { res := struct {
Conn *Connection Conn *Connection
Bots Bots Bots Bots
Locale map[string]interface{} Locale map[string]interface{}
Year int Year int
LangCode []string
}{ }{
p, p,
bots, bots,
getLocale(), getLocale(),
time.Now().Year(), time.Now().Year(),
[]string{"en", "ru", "es"},
} }
c.HTML(http.StatusOK, "form", &res) c.HTML(http.StatusOK, "form", &res)
@ -272,6 +248,25 @@ func activityHandler(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"success": true}) c.JSON(http.StatusOK, gin.H{"success": true})
} }
func setLangBotHandler(c *gin.Context) {
b := c.MustGet("bot").(Bot)
cl, err := getBotByToken(b.Token)
if err != nil {
c.Error(err)
return
}
cl.Lang = b.Lang
err = cl.save()
if err != nil {
c.Error(err)
return
}
c.JSON(http.StatusOK, gin.H{})
}
func getIntegrationModule(clientId string) v5.IntegrationModule { func getIntegrationModule(clientId string) v5.IntegrationModule {
return v5.IntegrationModule{ return v5.IntegrationModule{
Code: config.TransportInfo.Code, Code: config.TransportInfo.Code,
@ -305,6 +300,98 @@ func getIntegrationModule(clientId string) v5.IntegrationModule {
} }
} }
func getChannelSettings(cid ...uint64) v1.Channel {
var channelID uint64
if len(cid) > 0 {
channelID = cid[0]
}
return v1.Channel{
ID: channelID,
Type: Type,
Settings: v1.ChannelSettings{
SpamAllowed: false,
Status: v1.Status{
Delivered: v1.ChannelFeatureSend,
Read: v1.ChannelFeatureNone,
},
Text: v1.ChannelSettingsText{
Creating: v1.ChannelFeatureBoth,
Editing: v1.ChannelFeatureBoth,
Quoting: v1.ChannelFeatureBoth,
Deleting: v1.ChannelFeatureReceive,
},
Product: v1.Product{
Creating: v1.ChannelFeatureReceive,
Editing: v1.ChannelFeatureReceive,
},
Order: v1.Order{
Creating: v1.ChannelFeatureReceive,
Editing: v1.ChannelFeatureReceive,
},
},
}
}
func updateChannelsSettings() {
hashSettings, err := getChannelSettingsHash()
if err != nil {
logger.Error(err.Error())
return
}
connections := getConnections()
if len(connections) > 0 {
for _, conn := range connections {
if !conn.Active {
logger.Infof(
"updateChannelsSettings connection %s deactivated",
conn.APIURL,
)
continue
}
updateBots(conn, hashSettings)
}
}
return
}
func updateBots(conn *Connection, hashSettings string) {
bots := conn.getBotsByClientID()
if len(bots) > 0 {
client := v1.New(conn.MGURL, conn.MGToken)
for _, bot := range bots {
if bot.ChannelSettingsHash == hashSettings {
continue
}
data, status, err := client.UpdateTransportChannel(getChannelSettings(bot.Channel))
if config.Debug {
logger.Infof(
"updateChannelsSettings apiURL: %s, ChannelID: %d, Data: %v, Status: %d, err: %v",
conn.APIURL, bot.Channel, data, status, err,
)
}
if err == nil {
bot.ChannelSettingsHash = hashSettings
err = bot.save()
if err != nil {
logger.Error(
"updateChannelsSettings bot.save apiURL: %s, bot.Channel: %d , err: %v",
conn.APIURL, bot.Channel, err,
)
}
}
}
}
return
}
func telegramWebhookHandler(c *gin.Context) { func telegramWebhookHandler(c *gin.Context) {
token := c.Param("token") token := c.Param("token")
b, err := getBotByToken(token) b, err := getBotByToken(token)
@ -493,17 +580,36 @@ func mgWebhookHandler(c *gin.Context) {
return return
} }
setLocale(b.Lang)
switch msg.Type { switch msg.Type {
case "message_sent": case "message_sent":
var mb string var mb string
<<<<<<< HEAD
if msg.Data.Type == v1.MsgTypeProduct { if msg.Data.Type == v1.MsgTypeProduct {
=======
switch msg.Data.Type {
case v1.MsgTypeProduct:
>>>>>>> master
mb = fmt.Sprintf("%s\n", msg.Data.Product.Name) mb = fmt.Sprintf("%s\n", msg.Data.Product.Name)
if msg.Data.Product.Cost != nil && msg.Data.Product.Cost.Value != 0 { if msg.Data.Product.Cost != nil && msg.Data.Product.Cost.Value != 0 {
mb += fmt.Sprintf( mb += fmt.Sprintf(
<<<<<<< HEAD
"\n%v %s\n", "\n%v %s\n",
msg.Data.Product.Cost.Value, msg.Data.Product.Cost.Value,
currency[strings.ToLower(msg.Data.Product.Cost.Currency)], currency[strings.ToLower(msg.Data.Product.Cost.Currency)],
=======
"\n%s: %s\n",
getLocalizedMessage("item_cost"),
getLocalizedTemplateMessage(
"cost_currency",
map[string]interface{}{
"Amount": msg.Data.Product.Cost.Value,
"Currency": currency[strings.ToLower(msg.Data.Product.Cost.Currency)],
},
),
>>>>>>> master
) )
} }
@ -511,6 +617,7 @@ func mgWebhookHandler(c *gin.Context) {
mb += msg.Data.Product.Url mb += msg.Data.Product.Url
} else { } else {
mb += msg.Data.Product.Img mb += msg.Data.Product.Img
<<<<<<< HEAD
} }
} else if msg.Data.Type == v1.MsgTypeOrder { } else if msg.Data.Type == v1.MsgTypeOrder {
mb = "Заказ" mb = "Заказ"
@ -532,6 +639,12 @@ func mgWebhookHandler(c *gin.Context) {
mb += fmt.Sprintf("Сумма: %v %s", msg.Data.Order.Cost.Value, currency[strings.ToLower(msg.Data.Order.Cost.Currency)]) mb += fmt.Sprintf("Сумма: %v %s", msg.Data.Order.Cost.Value, currency[strings.ToLower(msg.Data.Order.Cost.Currency)])
} else { } else {
=======
}
case v1.MsgTypeOrder:
mb = getOrderMessage(msg.Data.Order)
case v1.MsgTypeText:
>>>>>>> master
mb = msg.Data.Content mb = msg.Data.Content
} }
@ -588,3 +701,135 @@ func mgWebhookHandler(c *gin.Context) {
} }
} }
func getOrderMessage(dataOrder *v1.MessageDataOrder) string {
mb := getLocalizedMessage("order")
if dataOrder.Number != "" {
mb += " " + dataOrder.Number
}
if dataOrder.Date != "" {
mb += fmt.Sprintf(" (%s)", dataOrder.Date)
}
mb += "\n"
if len(dataOrder.Items) > 0 {
mb += "\n"
for k, v := range dataOrder.Items {
mb += fmt.Sprintf(
"%d. %s",
k+1,
v.Name,
)
if v.Quantity != nil {
if v.Quantity.Value != 0 {
mb += fmt.Sprintf(
" %v",
v.Quantity.Value,
)
}
}
if v.Price != nil {
if val, ok := currency[strings.ToLower(v.Price.Currency)]; ok {
mb += fmt.Sprintf(
" x %s\n",
getLocalizedTemplateMessage(
"cost_currency",
map[string]interface{}{
"Amount": v.Price.Value,
"Currency": val,
},
),
)
}
} else {
mb += "\n"
}
}
}
if dataOrder.Delivery != nil {
if dataOrder.Delivery.Name != "" {
mb += fmt.Sprintf(
"\n%s:\n%s",
getLocalizedMessage("delivery"),
dataOrder.Delivery.Name,
)
}
if dataOrder.Delivery.Amount != nil {
if val, ok := currency[strings.ToLower(dataOrder.Delivery.Amount.Currency)]; ok && dataOrder.Delivery.Amount.Value != 0 {
mb += fmt.Sprintf(
"; %s",
getLocalizedTemplateMessage(
"cost_currency",
map[string]interface{}{
"Amount": dataOrder.Delivery.Amount.Value,
"Currency": val,
},
),
)
}
}
if dataOrder.Delivery.Address != "" {
mb += ";\n" + dataOrder.Delivery.Address
}
mb += "\n"
}
if len(dataOrder.Payments) > 0 {
mb += fmt.Sprintf(
"\n%s:\n",
getLocalizedMessage("payment"),
)
for _, v := range dataOrder.Payments {
mb += v.Name
if v.Amount != nil {
if val, ok := currency[strings.ToLower(v.Amount.Currency)]; ok && v.Amount.Value != 0 {
mb += fmt.Sprintf(
"; %s",
getLocalizedTemplateMessage(
"cost_currency",
map[string]interface{}{
"Amount": v.Amount.Value,
"Currency": val,
},
),
)
}
}
if v.Status != nil && v.Status.Name != "" {
mb += fmt.Sprintf(
" (%s)",
v.Status.Name,
)
}
mb += "\n"
}
}
if dataOrder.Cost != nil {
if val, ok := currency[strings.ToLower(dataOrder.Cost.Currency)]; ok && dataOrder.Cost.Value != 0 {
mb += fmt.Sprintf(
"\n%s: %s",
getLocalizedMessage("order_total"),
getLocalizedTemplateMessage(
"cost_currency",
map[string]interface{}{
"Amount": dataOrder.Cost.Value,
"Currency": val,
},
),
)
}
}
return mb
}

View File

@ -53,6 +53,7 @@ func start() {
func setup() *gin.Engine { func setup() *gin.Engine {
loadTranslateFile() loadTranslateFile()
setValidation() setValidation()
updateChannelsSettings()
if config.Debug == false { if config.Debug == false {
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
@ -89,6 +90,7 @@ func setup() *gin.Engine {
r.POST("/create/", checkConnectionForRequest(), createHandler) r.POST("/create/", checkConnectionForRequest(), createHandler)
r.POST("/add-bot/", checkBotForRequest(), addBotHandler) r.POST("/add-bot/", checkBotForRequest(), addBotHandler)
r.POST("/delete-bot/", checkBotForRequest(), deleteBotHandler) r.POST("/delete-bot/", checkBotForRequest(), deleteBotHandler)
r.POST("/set-lang/", checkBotForRequest(), setLangBotHandler)
r.POST("/actions/activity", activityHandler) r.POST("/actions/activity", activityHandler)
r.POST("/telegram/:token", telegramWebhookHandler) r.POST("/telegram/:token", telegramWebhookHandler)
r.POST("/webhook/", mgWebhookHandler) r.POST("/webhook/", mgWebhookHandler)

View File

@ -1,7 +1,9 @@
package main package main
import ( import (
"crypto/sha1"
"crypto/sha256" "crypto/sha256"
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"net/http" "net/http"
@ -13,7 +15,6 @@ import (
"github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session" "github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/s3/s3manager" "github.com/aws/aws-sdk-go/service/s3/s3manager"
"github.com/nicksnyder/go-i18n/v2/i18n"
"github.com/retailcrm/api-client-go/v5" "github.com/retailcrm/api-client-go/v5"
) )
@ -50,12 +51,14 @@ func getAPIClient(url, key string) (*v5.Client, error, int) {
if res := checkCredentials(cr.Credentials); len(res) != 0 { if res := checkCredentials(cr.Credentials); len(res) != 0 {
logger.Error(url, status, res) logger.Error(url, status, res)
return nil, return nil,
errors.New(localizer.MustLocalize(&i18n.LocalizeConfig{ errors.New(
MessageID: "missing_credentials", getLocalizedTemplateMessage(
TemplateData: map[string]interface{}{ "missing_credentials",
"Credentials": strings.Join(res, ", "), map[string]interface{}{
}, "Credentials": strings.Join(res, ", "),
})), },
),
),
http.StatusBadRequest http.StatusBadRequest
} }
@ -119,3 +122,13 @@ func UploadUserAvatar(url string) (picURLs3 string, err error) {
return return
} }
func getChannelSettingsHash() (hash string, err error) {
res, err := json.Marshal(getChannelSettings())
h := sha1.New()
h.Write(res)
hash = fmt.Sprintf("%x", h.Sum(nil))
return
}

View File

@ -1,3 +1,16 @@
$(document).on("change", "select", function(e) {
send(
"/set-lang/",
{
token: $(this).attr("data-token"),
lang: $(this).find(":selected").text()
},
function () {
return 0;
}
)
});
$('#save-crm').on("submit", function(e) { $('#save-crm').on("submit", function(e) {
e.preventDefault(); e.preventDefault();
send( send(
@ -39,6 +52,7 @@ $("#add-bot").on("submit", function(e) {
} }
$("#bots tbody").append(getBotTemplate(data)); $("#bots tbody").append(getBotTemplate(data));
$("#token").val(""); $("#token").val("");
$('select').formSelect();
} }
) )
}); });
@ -101,6 +115,15 @@ function getBotTemplate(data) {
`<tr> `<tr>
<td>${data.name}</td> <td>${data.name}</td>
<td>${data.token}</td> <td>${data.token}</td>
<td>
<div class="col s3 sel-lang">
<select data-token="${data.token}">
<option value="en" selected>en</option>
<option value="ru">ru</option>
<option value="es">es</option>
</select>
</div>
</td>
<td> <td>
<button class="delete-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-token="${data.token}"> data-token="${data.token}">
@ -120,6 +143,7 @@ function formDataToObj(formArray) {
} }
$( document ).ready(function() { $( document ).ready(function() {
$('select').formSelect();
M.Tabs.init(document.getElementById("tab")); M.Tabs.init(document.getElementById("tab"));
if ($("table tbody").children().length === 0) { if ($("table tbody").children().length === 0) {
$("#bots").addClass("hide"); $("#bots").addClass("hide");

View File

@ -32,10 +32,19 @@ main {
float: right; float: right;
} }
#bots .select-wrapper input.select-dropdown,
#bots { #bots {
font-size: 12px; font-size: 12px;
} }
#bots .sel-lang{
padding: 0;
}
#bots .select-wrapper ul li span{
color: #039be5;
}
#msg{ #msg{
height: 23px; height: 23px;
} }

View File

@ -51,19 +51,31 @@
</div> </div>
</div> </div>
</form> </form>
{{$LangCode := .LangCode}}
<table id="bots" class="tab-el-center"> <table id="bots" class="tab-el-center">
<thead> <thead>
<tr> <tr>
<th>{{.Locale.TableName}}</th> <th>{{.Locale.TableName}}</th>
<th>{{.Locale.TableToken}}</th> <th>{{.Locale.TableToken}}</th>
<th>{{.Locale.Language}}</th>
<th class="text-left">{{.Locale.TableDelete}}</th> <th class="text-left">{{.Locale.TableDelete}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{{range .Bots}} {{range .Bots}}
{{$lang := .Lang}}
<tr> <tr>
<td>{{.Name}}</td> <td>{{.Name}}</td>
<td>{{.Token}}</td> <td>{{.Token}}</td>
<td>
<div class="col s3 sel-lang">
<select data-token="{{.Token}}">
{{range $key, $value := $LangCode}}
<option value="{{$value}}" {{if eq $value $lang}}selected{{end}}>{{$value}}</option>
{{end}}
</select>
</div>
</td>
<td> <td>
<button class="delete-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-token="{{.Token}}"> data-token="{{.Token}}">

View File

@ -3,9 +3,9 @@
<meta title="Telegram transport"> <meta title="Telegram transport">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>{{.Locale.Title}}</title> <title>{{.Locale.Title}}</title>
<link rel="stylesheet" href="/static/materialize.min.css">
<link rel="stylesheet" href="/static/font.css" > <link rel="stylesheet" href="/static/font.css" >
<link rel="stylesheet" href="/static/jquery-confirm.min.css"> <link rel="stylesheet" href="/static/jquery-confirm.min.css">
<link rel="stylesheet" href="/static/materialize.min.css">
<link rel="stylesheet" href="/static/style.css" > <link rel="stylesheet" href="/static/style.css" >
</head> </head>
<body> <body>
@ -29,8 +29,8 @@
</div> </div>
</div> </div>
</footer> </footer>
<script src="/static/materialize.min.js"></script>
<script src="/static/jquery-3.3.1.min.js"></script> <script src="/static/jquery-3.3.1.min.js"></script>
<script src="/static/materialize.min.js"></script>
<script src="/static/jquery-confirm.min.js"></script> <script src="/static/jquery-confirm.min.js"></script>
<script src="/static/script.js"></script> <script src="/static/script.js"></script>
</body> </body>

View File

@ -8,6 +8,7 @@ api_key: API key
add_bot: Add a bot add_bot: Add a bot
title: Module of connecting Telegram to retailCRM title: Module of connecting Telegram to retailCRM
successful: Data was updated successfully successful: Data was updated successfully
language: Language
no_bot_token: Enter a token no_bot_token: Enter a token
wrong_data: Wrong data wrong_data: Wrong data
@ -41,3 +42,10 @@ video: "[video]"
voice: "[voice message]" voice: "[voice message]"
photo: "[photo]" photo: "[photo]"
undefined: "[undefined format of a message]" undefined: "[undefined format of a message]"
item_cost: "Cost"
order: "Order"
delivery: "Delivery"
payment: "Payment"
order_total: "Order total"
cost_currency: "{{.Amount}} {{.Currency}}"

View File

@ -8,6 +8,7 @@ api_key: API key
add_bot: Añadir un bot add_bot: Añadir un bot
title: Múdulo de conexión de Telegram a retailCRM title: Múdulo de conexión de Telegram a retailCRM
successful: Datos actualizados con éxito successful: Datos actualizados con éxito
language: Idioma
no_bot_token: Introduzca un token no_bot_token: Introduzca un token
wrong_data: Datos erróneos wrong_data: Datos erróneos
@ -41,3 +42,10 @@ video: "[video]"
voice: "[mensaje de voz]" voice: "[mensaje de voz]"
photo: "[foto]" photo: "[foto]"
other: "[formato indefinido de mensaje]" other: "[formato indefinido de mensaje]"
item_cost: "Precio"
order: "Pedido"
delivery: "Entrega"
payment: "Pago"
order_total: "Total pedido"
cost_currency: "{{.Amount}} {{.Currency}}"

View File

@ -8,6 +8,7 @@ api_key: API Ключ
add_bot: Добавить бота add_bot: Добавить бота
title: Модуль подключения Telegram к retailCRM title: Модуль подключения Telegram к retailCRM
successful: Данные успешно обновлены successful: Данные успешно обновлены
language: Язык
no_bot_token: Введите токен no_bot_token: Введите токен
wrong_data: Неверные данные wrong_data: Неверные данные
@ -41,3 +42,10 @@ video: "[видео]"
voice: "[голосовое сообщение]" voice: "[голосовое сообщение]"
photo: "[изображение]" photo: "[изображение]"
undefined: "[неопределенный формат сообщения]" undefined: "[неопределенный формат сообщения]"
item_cost: "Цена"
order: "Заказ"
delivery: "Доставка"
payment: "Оплата"
order_total: "Сумма"
cost_currency: "{{.Amount}} {{.Currency}}"