commit
3431bbe210
2
go.mod
2
go.mod
@ -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
|
||||||
|
4
go.sum
4
go.sum
@ -95,8 +95,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
|||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/retailcrm/api-client-go v1.0.6 h1:4Q3e4ve8GOOHIQdq3/wTGqgWuWa1cKMKqmgrTv4FoDU=
|
github.com/retailcrm/api-client-go v1.0.6 h1:4Q3e4ve8GOOHIQdq3/wTGqgWuWa1cKMKqmgrTv4FoDU=
|
||||||
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.10 h1:RR8S5NA6FPVrF6UVXaLwu/gJyKUg5aUObQ97S98M3Yc=
|
||||||
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/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=
|
||||||
|
1
migrations/1537271655_app.down.sql
Normal file
1
migrations/1537271655_app.down.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
alter table bot drop column channel_settings_hash;
|
1
migrations/1537271655_app.up.sql
Normal file
1
migrations/1537271655_app.up.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
alter table bot add column channel_settings_hash varchar(70);
|
1
migrations/1537452694_app.down.sql
Normal file
1
migrations/1537452694_app.down.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
alter table bot drop column lang;
|
1
migrations/1537452694_app.up.sql
Normal file
1
migrations/1537452694_app.up.sql
Normal file
@ -0,0 +1 @@
|
|||||||
|
alter table bot add column lang varchar(2);
|
@ -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")),
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
323
src/routing.go
323
src/routing.go
@ -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,26 @@ 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
|
||||||
if msg.Data.Type == v1.MsgTypeProduct {
|
switch msg.Data.Type {
|
||||||
|
case v1.MsgTypeProduct:
|
||||||
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(
|
||||||
"\n%v %s\n",
|
"\n%s: %s\n",
|
||||||
msg.Data.Product.Cost.Value,
|
getLocalizedMessage("item_cost"),
|
||||||
currency[strings.ToLower(msg.Data.Product.Cost.Currency)],
|
getLocalizedTemplateMessage(
|
||||||
|
"cost_currency",
|
||||||
|
map[string]interface{}{
|
||||||
|
"Amount": msg.Data.Product.Cost.Value,
|
||||||
|
"Currency": currency[strings.ToLower(msg.Data.Product.Cost.Currency)],
|
||||||
|
},
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -512,26 +608,9 @@ func mgWebhookHandler(c *gin.Context) {
|
|||||||
} else {
|
} else {
|
||||||
mb += msg.Data.Product.Img
|
mb += msg.Data.Product.Img
|
||||||
}
|
}
|
||||||
} else if msg.Data.Type == v1.MsgTypeOrder {
|
case v1.MsgTypeOrder:
|
||||||
mb = "Заказ"
|
mb = getOrderMessage(msg.Data.Order)
|
||||||
|
case v1.MsgTypeText:
|
||||||
if msg.Data.Order.Number != "" {
|
|
||||||
mb += " " + msg.Data.Order.Number
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.Data.Order.Date != "" {
|
|
||||||
mb += fmt.Sprintf(" (%s)", msg.Data.Order.Date)
|
|
||||||
}
|
|
||||||
|
|
||||||
mb += "\n"
|
|
||||||
if len(msg.Data.Order.Items) > 0 {
|
|
||||||
for _, v := range msg.Data.Order.Items {
|
|
||||||
mb += fmt.Sprintf("%s %v x %v %s\n", v.Name, v.Quantity.Value, v.Price.Value, currency[strings.ToLower(v.Price.Currency)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mb += fmt.Sprintf("Сумма: %v %s", msg.Data.Order.Cost.Value, currency[strings.ToLower(msg.Data.Order.Cost.Currency)])
|
|
||||||
} else {
|
|
||||||
mb = msg.Data.Content
|
mb = msg.Data.Content
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -588,3 +667,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
|
||||||
|
}
|
||||||
|
@ -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)
|
||||||
|
27
src/utils.go
27
src/utils.go
@ -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
|
||||||
|
}
|
||||||
|
@ -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");
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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}}">
|
||||||
|
@ -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>
|
||||||
|
@ -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}}"
|
||||||
|
@ -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}}"
|
||||||
|
@ -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}}"
|
||||||
|
Loading…
Reference in New Issue
Block a user