add go.mod, improve test, minor fixes
This commit is contained in:
parent
747b73ff87
commit
e6855456b0
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,3 +3,4 @@ config_test.yml
|
||||
.idea/
|
||||
/bin/*
|
||||
*.xml
|
||||
/vendor
|
||||
|
113
error_handler.go
Normal file
113
error_handler.go
Normal file
@ -0,0 +1,113 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/getsentry/raven-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type (
|
||||
ErrorHandlerFunc func(recovery interface{}, c *gin.Context)
|
||||
)
|
||||
|
||||
func ErrorHandler(handlers ...ErrorHandlerFunc) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
rec := recover()
|
||||
for _, handler := range handlers {
|
||||
handler(rec, c)
|
||||
}
|
||||
|
||||
if rec != nil || len(c.Errors) > 0 {
|
||||
c.Abort()
|
||||
}
|
||||
}()
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorResponseHandler() ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
publicErrors := c.Errors.ByType(gin.ErrorTypePublic)
|
||||
privateLen := len(c.Errors.ByType(gin.ErrorTypePrivate))
|
||||
publicLen := len(publicErrors)
|
||||
|
||||
if privateLen == 0 && publicLen == 0 && recovery == nil {
|
||||
return
|
||||
}
|
||||
|
||||
messagesLen := publicLen
|
||||
if privateLen > 0 || recovery != nil {
|
||||
messagesLen++
|
||||
}
|
||||
|
||||
messages := make([]string, messagesLen)
|
||||
index := 0
|
||||
for _, err := range publicErrors {
|
||||
messages[index] = err.Error()
|
||||
index++
|
||||
}
|
||||
|
||||
if privateLen > 0 || recovery != nil {
|
||||
messages[index] = "Something went wrong"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": messages})
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorCaptureHandler(client *raven.Client, errorsStacktrace bool) ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
tags := map[string]string{
|
||||
"endpoint": c.Request.RequestURI,
|
||||
}
|
||||
|
||||
if recovery != nil {
|
||||
stacktrace := raven.NewStacktrace(4, 3, nil)
|
||||
recStr := fmt.Sprint(recovery)
|
||||
err := errors.New(recStr)
|
||||
go client.CaptureMessageAndWait(
|
||||
recStr,
|
||||
tags,
|
||||
raven.NewException(err, stacktrace),
|
||||
raven.NewHttp(c.Request),
|
||||
)
|
||||
}
|
||||
|
||||
for _, err := range c.Errors {
|
||||
if errorsStacktrace {
|
||||
stacktrace := NewRavenStackTrace(client, err.Err, 0)
|
||||
go client.CaptureMessageAndWait(
|
||||
err.Error(),
|
||||
tags,
|
||||
raven.NewException(err.Err, stacktrace),
|
||||
raven.NewHttp(c.Request),
|
||||
)
|
||||
} else {
|
||||
go client.CaptureErrorAndWait(err.Err, tags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PanicLogger() ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
if recovery != nil {
|
||||
logger.Error(recovery)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorLogger() ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
for _, err := range c.Errors {
|
||||
logger.Error(err.Err)
|
||||
}
|
||||
}
|
||||
}
|
211
errors.go
211
errors.go
@ -1,211 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"runtime/debug"
|
||||
|
||||
"github.com/getsentry/raven-go"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type (
|
||||
ErrorHandlerFunc func(recovery interface{}, c *gin.Context)
|
||||
)
|
||||
|
||||
func ErrorHandler(handlers ...ErrorHandlerFunc) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
defer func() {
|
||||
rec := recover()
|
||||
for _, handler := range handlers {
|
||||
handler(rec, c)
|
||||
}
|
||||
|
||||
if rec != nil || len(c.Errors) > 0 {
|
||||
c.Abort()
|
||||
}
|
||||
}()
|
||||
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorResponseHandler() ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
publicErrors := c.Errors.ByType(gin.ErrorTypePublic)
|
||||
privateLen := len(c.Errors.ByType(gin.ErrorTypePrivate))
|
||||
publicLen := len(publicErrors)
|
||||
|
||||
if privateLen == 0 && publicLen == 0 && recovery == nil {
|
||||
return
|
||||
}
|
||||
|
||||
messagesLen := publicLen
|
||||
if privateLen > 0 || recovery != nil {
|
||||
messagesLen++
|
||||
}
|
||||
|
||||
messages := make([]string, messagesLen)
|
||||
index := 0
|
||||
for _, err := range publicErrors {
|
||||
messages[index] = err.Error()
|
||||
index++
|
||||
}
|
||||
|
||||
if privateLen > 0 || recovery != nil {
|
||||
messages[index] = "Something went wrong"
|
||||
}
|
||||
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": messages})
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorCaptureHandler(client *raven.Client, errorsStacktrace bool) ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
tags := map[string]string{
|
||||
"endpoint": c.Request.RequestURI,
|
||||
}
|
||||
|
||||
if recovery != nil {
|
||||
stacktrace := raven.NewStacktrace(4, 3, nil)
|
||||
recStr := fmt.Sprint(recovery)
|
||||
err := errors.New(recStr)
|
||||
go client.CaptureMessageAndWait(
|
||||
recStr,
|
||||
tags,
|
||||
raven.NewException(err, stacktrace),
|
||||
raven.NewHttp(c.Request),
|
||||
)
|
||||
}
|
||||
|
||||
for _, err := range c.Errors {
|
||||
if errorsStacktrace {
|
||||
stacktrace := NewRavenStackTrace(client, err.Err, 0)
|
||||
go client.CaptureMessageAndWait(
|
||||
err.Error(),
|
||||
tags,
|
||||
raven.NewException(err.Err, stacktrace),
|
||||
raven.NewHttp(c.Request),
|
||||
)
|
||||
} else {
|
||||
go client.CaptureErrorAndWait(err.Err, tags)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func PanicLogger() ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
if recovery != nil {
|
||||
fmt.Printf("===\n%+v\n", recovery)
|
||||
debug.PrintStack()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func ErrorLogger() ErrorHandlerFunc {
|
||||
return func(recovery interface{}, c *gin.Context) {
|
||||
for _, err := range c.Errors {
|
||||
fmt.Printf("===\n%+v\n", err.Err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func NewRavenStackTrace(client *raven.Client, myerr error, skip int) *raven.Stacktrace {
|
||||
st := getErrorStackTraceConverted(myerr, 3, client.IncludePaths())
|
||||
if st == nil {
|
||||
st = raven.NewStacktrace(skip, 3, client.IncludePaths())
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func getErrorStackTraceConverted(err error, context int, appPackagePrefixes []string) *raven.Stacktrace {
|
||||
st := getErrorCauseStackTrace(err)
|
||||
if st == nil {
|
||||
return nil
|
||||
}
|
||||
return convertStackTrace(st, context, appPackagePrefixes)
|
||||
}
|
||||
|
||||
func getErrorCauseStackTrace(err error) errors.StackTrace {
|
||||
// This code is inspired by github.com/pkg/errors.Cause().
|
||||
var st errors.StackTrace
|
||||
for err != nil {
|
||||
s := getErrorStackTrace(err)
|
||||
if s != nil {
|
||||
st = s
|
||||
}
|
||||
err = getErrorCause(err)
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func convertStackTrace(st errors.StackTrace, context int, appPackagePrefixes []string) *raven.Stacktrace {
|
||||
// This code is borrowed from github.com/getsentry/raven-go.NewStacktrace().
|
||||
var frames []*raven.StacktraceFrame
|
||||
for _, f := range st {
|
||||
frame := convertFrame(f, context, appPackagePrefixes)
|
||||
if frame != nil {
|
||||
frames = append(frames, frame)
|
||||
}
|
||||
}
|
||||
if len(frames) == 0 {
|
||||
return nil
|
||||
}
|
||||
for i, j := 0, len(frames)-1; i < j; i, j = i+1, j-1 {
|
||||
frames[i], frames[j] = frames[j], frames[i]
|
||||
}
|
||||
return &raven.Stacktrace{Frames: frames}
|
||||
}
|
||||
|
||||
func convertFrame(f errors.Frame, context int, appPackagePrefixes []string) *raven.StacktraceFrame {
|
||||
// This code is borrowed from github.com/pkg/errors.Frame.
|
||||
pc := uintptr(f) - 1
|
||||
fn := runtime.FuncForPC(pc)
|
||||
var file string
|
||||
var line int
|
||||
if fn != nil {
|
||||
file, line = fn.FileLine(pc)
|
||||
} else {
|
||||
file = "unknown"
|
||||
}
|
||||
return raven.NewStacktraceFrame(pc, file, line, context, appPackagePrefixes)
|
||||
}
|
||||
|
||||
func getErrorStackTrace(err error) errors.StackTrace {
|
||||
ster, ok := err.(interface {
|
||||
StackTrace() errors.StackTrace
|
||||
})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return ster.StackTrace()
|
||||
}
|
||||
|
||||
func getErrorCause(err error) error {
|
||||
cer, ok := err.(interface {
|
||||
Cause() error
|
||||
})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return cer.Cause()
|
||||
}
|
||||
|
||||
type errorResponse struct {
|
||||
Errors []string `json:"errors"`
|
||||
}
|
||||
|
||||
func NotFound(errors ...string) (int, interface{}) {
|
||||
return http.StatusNotFound, errorResponse{
|
||||
Errors: errors,
|
||||
}
|
||||
}
|
||||
|
||||
func BadRequest(errors ...string) (int, interface{}) {
|
||||
return http.StatusBadRequest, errorResponse{
|
||||
Errors: errors,
|
||||
}
|
||||
}
|
63
go.mod
Normal file
63
go.mod
Normal file
@ -0,0 +1,63 @@
|
||||
module github.com/retailcrm/mg-transport-telegram
|
||||
|
||||
require (
|
||||
cloud.google.com/go v0.26.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.4.9 // indirect
|
||||
github.com/aws/aws-sdk-go v1.15.12
|
||||
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect
|
||||
github.com/davecgh/go-spew v1.1.0 // indirect
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20180707235734-242fa5aa1b45 // indirect
|
||||
github.com/docker/distribution v2.6.2+incompatible // indirect
|
||||
github.com/docker/docker v1.13.1 // indirect
|
||||
github.com/docker/go-connections v0.4.0 // indirect
|
||||
github.com/docker/go-units v0.3.3 // indirect
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect
|
||||
github.com/getsentry/raven-go v0.0.0-20180801005657-7535a8fa2ace
|
||||
github.com/gin-contrib/multitemplate v0.0.0-20180607024123-41d1d62d1df3
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 // indirect
|
||||
github.com/gin-gonic/gin v1.3.0
|
||||
github.com/go-playground/locales v0.12.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.16.0 // indirect
|
||||
github.com/go-sql-driver/mysql v1.4.0 // indirect
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180602093832-4c16a90966d1
|
||||
github.com/golang-migrate/migrate v3.4.0+incompatible
|
||||
github.com/golang/protobuf v1.1.0 // indirect
|
||||
github.com/google/go-cmp v0.2.0 // indirect
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f // indirect
|
||||
github.com/h2non/gock v1.0.9
|
||||
github.com/jessevdk/go-flags v1.4.0
|
||||
github.com/jinzhu/gorm v1.9.1
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a // indirect
|
||||
github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae // indirect
|
||||
github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b // indirect
|
||||
github.com/jtolds/gls v4.2.1+incompatible // indirect
|
||||
github.com/lib/pq v0.0.0-20180523175426-90697d60dd84 // indirect
|
||||
github.com/mattn/go-isatty v0.0.3 // indirect
|
||||
github.com/mattn/go-sqlite3 v1.9.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v0.0.0-20180718012357-94122c33edd3 // indirect
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||
github.com/pkg/errors v0.8.0
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/retailcrm/api-client-go v1.0.4
|
||||
github.com/retailcrm/mg-transport-api-client-go v1.1.0
|
||||
github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 // indirect
|
||||
github.com/smartystreets/goconvey v0.0.0-20180222194500-ef6db91d284a // indirect
|
||||
github.com/stevvooe/resumable v0.0.0-20170302213456-2aaf90b2ceea // indirect
|
||||
github.com/stretchr/testify v1.2.2
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
|
||||
github.com/ugorji/go v1.1.1 // indirect
|
||||
golang.org/x/crypto v0.0.0-20180808211826-de0752318171 // indirect
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332 // indirect
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f // indirect
|
||||
golang.org/x/sys v0.0.0-20180815093151-14742f9018cd // indirect
|
||||
golang.org/x/text v0.3.0
|
||||
google.golang.org/appengine v1.1.0 // indirect
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 // indirect
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
|
||||
gopkg.in/go-playground/validator.v9 v9.21.0
|
||||
gopkg.in/yaml.v2 v2.2.1
|
||||
)
|
127
go.sum
Normal file
127
go.sum
Normal file
@ -0,0 +1,127 @@
|
||||
cloud.google.com/go v0.26.0 h1:e0WKqKTd5BnrG8aKH3J3h+QvEIQtSUcf2n5UZ5ZgLtQ=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY=
|
||||
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Microsoft/go-winio v0.4.9 h1:3RbgqgGVqmcpbOiwrjbVtDHLlJBGF6aE+yHmNtBNsFQ=
|
||||
github.com/Microsoft/go-winio v0.4.9/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
|
||||
github.com/aws/aws-sdk-go v1.15.12 h1:iHNrTnYV37nlnL3zX7R3sniehzrTvCjRgtHqhf31VLI=
|
||||
github.com/aws/aws-sdk-go v1.15.12/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 h1:6/yVvBsKeAw05IUj4AzvrxaCnDjN4nUqKjW9+w5wixg=
|
||||
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20180707235734-242fa5aa1b45 h1:UW8VerkZA1zCt3uWhQ2wbMae76OLn7s7Utz8wyKtJUk=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20180707235734-242fa5aa1b45/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc=
|
||||
github.com/docker/distribution v2.6.2+incompatible h1:4FI6af79dfCS/CYb+RRtkSHw3q1L/bnDjG1PcPZtQhM=
|
||||
github.com/docker/distribution v2.6.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v1.13.1 h1:5VBhsO6ckUxB0A8CE5LlUJdXzik9cbEbBTQ/ggeml7M=
|
||||
github.com/docker/docker v1.13.1/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
|
||||
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
|
||||
github.com/docker/go-units v0.3.3 h1:Xk8S3Xj5sLGlG5g67hJmYMmUgXv5N4PhkjJHHqrwnTk=
|
||||
github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y=
|
||||
github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0=
|
||||
github.com/getsentry/raven-go v0.0.0-20180801005657-7535a8fa2ace h1:M5ZUuRO+XFqhTa9PlaqyWgfzMNWKSraCWm7z4PzM1GA=
|
||||
github.com/getsentry/raven-go v0.0.0-20180801005657-7535a8fa2ace/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
||||
github.com/gin-contrib/multitemplate v0.0.0-20180607024123-41d1d62d1df3 h1:nKrMd5DcMWMxZbGzSEscZ7zsnA0vLf46rGKV1R7c4Kc=
|
||||
github.com/gin-contrib/multitemplate v0.0.0-20180607024123-41d1d62d1df3/go.mod h1:62qM8p4crGvNKE413gTzn4eMFin1VOJfMDWMRzHdvqM=
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7 h1:AzN37oI0cOS+cougNAV9szl6CVoj2RYwzS3DpUQNtlY=
|
||||
github.com/gin-contrib/sse v0.0.0-20170109093832-22d885f9ecc7/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s=
|
||||
github.com/gin-gonic/gin v1.3.0 h1:kCmZyPklC0gVdL728E6Aj20uYBJV93nj/TkwBTKhFbs=
|
||||
github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6mUr7Y=
|
||||
github.com/go-ini/ini v1.25.4 h1:Mujh4R/dH6YL8bxuISne3xX2+qcQ9p0IxKAP6ExWoUo=
|
||||
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
|
||||
github.com/go-playground/locales v0.12.1 h1:2FITxuFt/xuCNP1Acdhv62OzaCiviiE4kotfhkmOqEc=
|
||||
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
|
||||
github.com/go-playground/universal-translator v0.16.0 h1:X++omBR/4cE2MNg91AoC3rmGrCjJ8eAeUP/K/EKx4DM=
|
||||
github.com/go-playground/universal-translator v0.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
|
||||
github.com/go-sql-driver/mysql v1.4.0 h1:7LxgVwFb2hIQtMm87NdgAVfXjnt4OePseqT1tKx+opk=
|
||||
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180602093832-4c16a90966d1 h1:FlRoyZCY3snE+M9jTruqOzPwZg8KIwQBXr//t215K8E=
|
||||
github.com/go-telegram-bot-api/telegram-bot-api v0.0.0-20180602093832-4c16a90966d1/go.mod h1:qf9acutJ8cwBUhm1bqgz6Bei9/C/c93FPDljKWwsOgM=
|
||||
github.com/golang-migrate/migrate v3.4.0+incompatible h1:9yjg5lYsbeEpWXGc80RylvPMKZ0tZEGsyO3CpYLK3jU=
|
||||
github.com/golang-migrate/migrate v3.4.0+incompatible/go.mod h1:IsVUlFN5puWOmXrqjgGUfIRIbU7mr8oNBE2tyERd9Wk=
|
||||
github.com/golang/protobuf v1.1.0 h1:0iH4Ffd/meGoXqF2lSAhZHt8X+cPgkfn/cb6Cce5Vpc=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135 h1:zLTLjkaOFEFIOxY5BWLFLwh+cL8vOBW4XJ2aqLE/Tf0=
|
||||
github.com/google/go-querystring v0.0.0-20170111101155-53e6ce116135/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f h1:FDM3EtwZLyhW48YRiyqjivNlNZjAObv4xt4NnJaU+NQ=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20180628210949-0892b62f0d9f/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/h2non/gock v1.0.9 h1:17gCehSo8ZOgEsFKpQgqHiR7VLyjxdAG3lkhVvO9QZU=
|
||||
github.com/h2non/gock v1.0.9/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE=
|
||||
github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jinzhu/gorm v1.9.1 h1:lDSDtsCt5AGGSKTs8AHlSDbbgif4G4+CKJ8ETBDVHTA=
|
||||
github.com/jinzhu/gorm v1.9.1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a h1:eeaG9XMUvRBYXJi4pg1ZKM7nxc5AfXfojeLLW7O5J3k=
|
||||
github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae h1:8bBMcboXYVuo0WYH+rPe5mB8obO89a993hdTZ3phTjc=
|
||||
github.com/jinzhu/now v0.0.0-20180511015916-ed742868f2ae/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8 h1:12VvqtR6Aowv3l/EQUlocDHW2Cp4G9WJVH7uyH8QFJE=
|
||||
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
|
||||
github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b h1:X61dhFTE1Au92SvyF8HyAwdjWqiSdfBgFR7wTxC0+uU=
|
||||
github.com/json-iterator/go v0.0.0-20180806060727-1624edc4454b/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/jtolds/gls v4.2.1+incompatible h1:fSuqC+Gmlu6l/ZYAoZzx2pyucC8Xza35fpRVWLVmUEE=
|
||||
github.com/jtolds/gls v4.2.1+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/lib/pq v0.0.0-20180523175426-90697d60dd84 h1:it29sI2IM490luSc3RAhp5WuCYnc6RtbfLVAB7nmC5M=
|
||||
github.com/lib/pq v0.0.0-20180523175426-90697d60dd84/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0 h1:pDRiWfl+++eC2FEFRy6jXmQlvp4Yh3z1MJKg4UeYM/4=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180718012357-94122c33edd3 h1:YFBuDro+e1UCqlJpDWGucQaO/UNhBX1GlS8Du0GNfPw=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180718012357-94122c33edd3/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4=
|
||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5 h1:/TjjTS4kg7vC+05gD0LE4+97f/+PRFICnK/7wJPk7kE=
|
||||
github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5/go.mod h1:4Opqa6/HIv0lhG3WRAkqzO0afezkRhxXI0P8EJkqeRU=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
|
||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/retailcrm/api-client-go v1.0.4 h1:pYlkdQhesc8MN/huU4qp9XpLLRxfr0SIICf2RmEVnoA=
|
||||
github.com/retailcrm/api-client-go v1.0.4/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c=
|
||||
github.com/retailcrm/mg-transport-api-client-go v1.1.0 h1:hIxiOhVwA2jil3XcHKX9pxXnoEaq8LdYapD/RPwJcy8=
|
||||
github.com/retailcrm/mg-transport-api-client-go v1.1.0/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI=
|
||||
github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9 h1:lXQ+j+KwZcbwrbgU0Rp4Eglg3EJLHbuZU3BbOqAGBmg=
|
||||
github.com/smartystreets/assertions v0.0.0-20180803164922-886ec427f6b9/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/go.mod h1:XDJAKZRPZ1CvBcN2aX5YOUTYGHki24fSF0Iv48Ibg0s=
|
||||
github.com/stevvooe/resumable v0.0.0-20170302213456-2aaf90b2ceea h1:KR90QmB10LunzqE3lvSRq0epy66wkQi2bDmkJdkkxi8=
|
||||
github.com/stevvooe/resumable v0.0.0-20170302213456-2aaf90b2ceea/go.mod h1:1pdIZTAHUz+HDKDVZ++5xg/duPlhKAIzw9qy42CWYp4=
|
||||
github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
|
||||
github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
|
||||
github.com/ugorji/go v1.1.1 h1:gmervu+jDMvXTbcHQ0pd2wee85nEoE0BsVyEuzkfK8w=
|
||||
github.com/ugorji/go v1.1.1/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
|
||||
golang.org/x/crypto v0.0.0-20180808211826-de0752318171 h1:vYogbvSFj2YXcjQxFHu/rASSOt9sLytpCaSkiwQ135I=
|
||||
golang.org/x/crypto v0.0.0-20180808211826-de0752318171/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332 h1:efGso+ep0DjyCBJPjvoz0HI6UldX4Md2F1rZFe1ir0E=
|
||||
golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180815093151-14742f9018cd h1:Vdp9FdQnZJQQF78wgpudgkchp80Nu37AWr8+mprtgAo=
|
||||
golang.org/x/sys v0.0.0-20180815093151-14742f9018cd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.0.0-20171214130843-f21a4dfb5e38/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
google.golang.org/appengine v1.1.0 h1:igQkv0AAhEIvTEpD5LIpAfav2eeVO9HBTjvKHVJPRSs=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/go-playground/validator.v9 v9.21.0 h1:wSDJGBpQBYC1wLpVnGHLmshm2JicoSNdrb38Zj+8yHI=
|
||||
gopkg.in/go-playground/validator.v9 v9.21.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
55
locale.go
Normal file
55
locale.go
Normal file
@ -0,0 +1,55 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"golang.org/x/text/language"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
var (
|
||||
localizer *i18n.Localizer
|
||||
bundle = &i18n.Bundle{DefaultLanguage: language.English}
|
||||
matcher = language.NewMatcher([]language.Tag{
|
||||
language.English,
|
||||
language.Russian,
|
||||
language.Spanish,
|
||||
})
|
||||
)
|
||||
|
||||
func loadTranslateFile() {
|
||||
bundle.RegisterUnmarshalFunc("yml", yaml.Unmarshal)
|
||||
files, err := ioutil.ReadDir("translate")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
bundle.MustLoadMessageFile("translate/" + f.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setLocale(al string) {
|
||||
tag, _ := language.MatchStrings(matcher, al)
|
||||
localizer = i18n.NewLocalizer(bundle, tag.String())
|
||||
}
|
||||
|
||||
func getLocalizedMessage(messageID string) string {
|
||||
return localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID})
|
||||
}
|
||||
|
||||
func getLocale() map[string]string {
|
||||
return map[string]string{
|
||||
"ButtonSave": getLocalizedMessage("button_save"),
|
||||
"ApiKey": getLocalizedMessage("api_key"),
|
||||
"TabSettings": getLocalizedMessage("tab_settings"),
|
||||
"TabBots": getLocalizedMessage("tab_bots"),
|
||||
"TableName": getLocalizedMessage("table_name"),
|
||||
"TableToken": getLocalizedMessage("table_token"),
|
||||
"AddBot": getLocalizedMessage("add_bot"),
|
||||
"TableDelete": getLocalizedMessage("table_delete"),
|
||||
"Title": getLocalizedMessage("title"),
|
||||
}
|
||||
}
|
9
main.go
9
main.go
@ -5,9 +5,7 @@ import (
|
||||
|
||||
"github.com/jessevdk/go-flags"
|
||||
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/op/go-logging"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
// Options struct
|
||||
@ -24,13 +22,6 @@ var (
|
||||
options Options
|
||||
parser = flags.NewParser(&options, flags.Default)
|
||||
tokenCounter uint32
|
||||
localizer *i18n.Localizer
|
||||
bundle = &i18n.Bundle{DefaultLanguage: language.English}
|
||||
matcher = language.NewMatcher([]language.Tag{
|
||||
language.English,
|
||||
language.Russian,
|
||||
language.Spanish,
|
||||
})
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
126
routing.go
126
routing.go
@ -1,10 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/go-telegram-bot-api/telegram-bot-api"
|
||||
@ -13,17 +12,11 @@ import (
|
||||
)
|
||||
|
||||
func connectHandler(c *gin.Context) {
|
||||
rx := regexp.MustCompile(`/+$`)
|
||||
ra := rx.ReplaceAllString(c.Query("account"), ``)
|
||||
p := Connection{
|
||||
APIURL: ra,
|
||||
}
|
||||
|
||||
res := struct {
|
||||
Conn *Connection
|
||||
Conn Connection
|
||||
Locale map[string]string
|
||||
}{
|
||||
&p,
|
||||
c.MustGet("account").(Connection),
|
||||
getLocale(),
|
||||
}
|
||||
|
||||
@ -31,18 +24,7 @@ func connectHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func addBotHandler(c *gin.Context) {
|
||||
var b Bot
|
||||
|
||||
if err := c.ShouldBindJSON(&b); err != nil {
|
||||
c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if b.Token == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": getLocalizedMessage("no_bot_token")})
|
||||
return
|
||||
}
|
||||
|
||||
b := c.MustGet("bot").(Bot)
|
||||
cl, err := getBotByToken(b.Token)
|
||||
if err != nil {
|
||||
c.Error(err)
|
||||
@ -106,23 +88,11 @@ func addBotHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
jsonString, err := json.Marshal(b)
|
||||
if err != nil {
|
||||
c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusCreated, jsonString)
|
||||
c.JSON(http.StatusCreated, b)
|
||||
}
|
||||
|
||||
func deleteBotHandler(c *gin.Context) {
|
||||
var b Bot
|
||||
|
||||
if err := c.ShouldBindJSON(&b); err != nil {
|
||||
c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
b := c.MustGet("bot").(Bot)
|
||||
conn := getConnectionById(b.ConnectionID)
|
||||
if conn.MGURL == "" || conn.MGToken == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": getLocalizedMessage("not_found_account")})
|
||||
@ -173,13 +143,7 @@ func settingsHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func saveHandler(c *gin.Context) {
|
||||
var conn Connection
|
||||
|
||||
if err := c.BindJSON(&conn); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": getLocalizedMessage("incorrect_url_key")})
|
||||
return
|
||||
}
|
||||
|
||||
conn := c.MustGet("connection").(Connection)
|
||||
_, err, code := getAPIClient(conn.APIURL, conn.APIKEY)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(code, gin.H{"error": err.Error()})
|
||||
@ -196,14 +160,7 @@ func saveHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
func createHandler(c *gin.Context) {
|
||||
var conn Connection
|
||||
|
||||
if err := c.BindJSON(&conn); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": getLocalizedMessage("incorrect_url_key")})
|
||||
return
|
||||
}
|
||||
|
||||
conn.ClientID = GenerateToken()
|
||||
conn := c.MustGet("connection").(Connection)
|
||||
|
||||
cl := getConnectionByURL(conn.APIURL)
|
||||
if cl.ID != 0 {
|
||||
@ -217,37 +174,8 @@ func createHandler(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
integration := v5.IntegrationModule{
|
||||
Code: transport,
|
||||
IntegrationCode: transport,
|
||||
Active: true,
|
||||
Name: "Telegram",
|
||||
ClientID: conn.ClientID,
|
||||
Logo: fmt.Sprintf(
|
||||
"https://%s/static/telegram_logo.svg",
|
||||
config.HTTPServer.Host,
|
||||
),
|
||||
BaseURL: fmt.Sprintf(
|
||||
"https://%s",
|
||||
config.HTTPServer.Host,
|
||||
),
|
||||
AccountURL: fmt.Sprintf(
|
||||
"https://%s/settings/%s",
|
||||
config.HTTPServer.Host,
|
||||
conn.ClientID,
|
||||
),
|
||||
Actions: map[string]string{"activity": "/actions/activity"},
|
||||
Integrations: &v5.Integrations{
|
||||
MgTransport: &v5.MgTransport{
|
||||
WebhookUrl: fmt.Sprintf(
|
||||
"https://%s/webhook/",
|
||||
config.HTTPServer.Host,
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
data, status, errr := client.IntegrationModuleEdit(integration)
|
||||
conn.ClientID = GenerateToken()
|
||||
data, status, errr := client.IntegrationModuleEdit(getIntegrationModule(conn.ClientID))
|
||||
if errr.RuntimeErr != nil {
|
||||
c.Error(errr.RuntimeErr)
|
||||
return
|
||||
@ -306,3 +234,35 @@ func activityHandler(c *gin.Context) {
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"success": true})
|
||||
}
|
||||
|
||||
func getIntegrationModule(clientId string) v5.IntegrationModule {
|
||||
return v5.IntegrationModule{
|
||||
Code: transport,
|
||||
IntegrationCode: transport,
|
||||
Active: true,
|
||||
Name: "Telegram",
|
||||
ClientID: clientId,
|
||||
Logo: fmt.Sprintf(
|
||||
"https://%s/static/telegram_logo.svg",
|
||||
config.HTTPServer.Host,
|
||||
),
|
||||
BaseURL: fmt.Sprintf(
|
||||
"https://%s",
|
||||
config.HTTPServer.Host,
|
||||
),
|
||||
AccountURL: fmt.Sprintf(
|
||||
"https://%s/settings/%s",
|
||||
config.HTTPServer.Host,
|
||||
clientId,
|
||||
),
|
||||
Actions: map[string]string{"activity": "/actions/activity"},
|
||||
Integrations: &v5.Integrations{
|
||||
MgTransport: &v5.MgTransport{
|
||||
WebhookUrl: fmt.Sprintf(
|
||||
"https://%s/webhook/",
|
||||
config.HTTPServer.Host,
|
||||
),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -10,15 +10,19 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/h2non/gock"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var router *gin.Engine
|
||||
|
||||
func init() {
|
||||
config = LoadConfig("config_test.yml")
|
||||
orm = NewDb(config)
|
||||
logger = newLogger()
|
||||
router = setup()
|
||||
|
||||
c := Connection{
|
||||
ID: 1,
|
||||
@ -41,9 +45,8 @@ func TestRouting_connectHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := http.HandlerFunc(connectHandler)
|
||||
router.ServeHTTP(rr, req)
|
||||
|
||||
handler.ServeHTTP(rr, req)
|
||||
assert.Equal(t, http.StatusOK, rr.Code,
|
||||
fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK))
|
||||
}
|
||||
@ -83,8 +86,7 @@ func TestRouting_addBotHandler(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rr := httptest.NewRecorder()
|
||||
handler := http.HandlerFunc(addBotHandler)
|
||||
handler.ServeHTTP(rr, req)
|
||||
router.ServeHTTP(rr, req)
|
||||
require.Equal(t, http.StatusCreated, rr.Code,
|
||||
fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusCreated))
|
||||
|
||||
@ -120,8 +122,7 @@ func TestRouting_deleteBotHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := http.HandlerFunc(deleteBotHandler)
|
||||
handler.ServeHTTP(rr, req)
|
||||
router.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rr.Code,
|
||||
fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK))
|
||||
@ -134,8 +135,7 @@ func TestRouting_settingsHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := http.HandlerFunc(makeHandler(settingsHandler))
|
||||
handler.ServeHTTP(rr, req)
|
||||
router.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rr.Code,
|
||||
fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK))
|
||||
@ -160,8 +160,7 @@ func TestRouting_saveHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := http.HandlerFunc(saveHandler)
|
||||
handler.ServeHTTP(rr, req)
|
||||
router.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rr.Code,
|
||||
fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK))
|
||||
@ -177,8 +176,7 @@ func TestRouting_activityHandler(t *testing.T) {
|
||||
}
|
||||
|
||||
rr := httptest.NewRecorder()
|
||||
handler := http.HandlerFunc(activityHandler)
|
||||
handler.ServeHTTP(rr, req)
|
||||
router.ServeHTTP(rr, req)
|
||||
|
||||
assert.Equal(t, http.StatusOK, rr.Code,
|
||||
fmt.Sprintf("handler returned wrong status code: got %v want %v", rr.Code, http.StatusOK))
|
||||
|
70
run.go
70
run.go
@ -1,20 +1,17 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"regexp"
|
||||
"syscall"
|
||||
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/getsentry/raven-go"
|
||||
"github.com/gin-contrib/multitemplate"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gin-gonic/gin/binding"
|
||||
_ "github.com/golang-migrate/migrate/database/postgres"
|
||||
_ "github.com/golang-migrate/migrate/source/file"
|
||||
"gopkg.in/go-playground/validator.v9"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -57,12 +54,7 @@ func start() {
|
||||
|
||||
func setup() *gin.Engine {
|
||||
loadTranslateFile()
|
||||
|
||||
binding.Validator = new(defaultValidator)
|
||||
|
||||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||
v.RegisterValidation("validatecrmurl", validateCrmURL)
|
||||
}
|
||||
setValidation()
|
||||
|
||||
if config.Debug == false {
|
||||
gin.SetMode(gin.ReleaseMode)
|
||||
@ -94,12 +86,12 @@ func setup() *gin.Engine {
|
||||
|
||||
r.Use(ErrorHandler(errorHandlers...))
|
||||
|
||||
r.GET("/", connectHandler)
|
||||
r.GET("/", checkAccountForRequest(), connectHandler)
|
||||
r.GET("/settings/:uid", settingsHandler)
|
||||
r.POST("/save/", saveHandler)
|
||||
r.POST("/create/", createHandler)
|
||||
r.POST("/add-bot/", addBotHandler)
|
||||
r.POST("/delete-bot/", deleteBotHandler)
|
||||
r.POST("/save/", checkConnectionForRequest(), saveHandler)
|
||||
r.POST("/create/", checkConnectionForRequest(), createHandler)
|
||||
r.POST("/add-bot/", checkBotForRequest(), addBotHandler)
|
||||
r.POST("/delete-bot/", checkBotForRequest(), deleteBotHandler)
|
||||
r.POST("/actions/activity", activityHandler)
|
||||
r.POST("/telegram/:token", telegramWebhookHandler)
|
||||
r.POST("/webhook/", mgWebhookHandler)
|
||||
@ -114,15 +106,45 @@ func createHTMLRender() multitemplate.Renderer {
|
||||
return r
|
||||
}
|
||||
|
||||
func loadTranslateFile() {
|
||||
bundle.RegisterUnmarshalFunc("yml", yaml.Unmarshal)
|
||||
files, err := ioutil.ReadDir("translate")
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
func checkAccountForRequest() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
rx := regexp.MustCompile(`/+$`)
|
||||
ra := rx.ReplaceAllString(c.Query("account"), ``)
|
||||
p := Connection{
|
||||
APIURL: ra,
|
||||
}
|
||||
for _, f := range files {
|
||||
if !f.IsDir() {
|
||||
bundle.MustLoadMessageFile("translate/" + f.Name())
|
||||
|
||||
c.Set("account", p)
|
||||
}
|
||||
}
|
||||
|
||||
func checkBotForRequest() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var b Bot
|
||||
|
||||
if err := c.ShouldBindJSON(&b); err != nil {
|
||||
c.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
if b.Token == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": getLocalizedMessage("no_bot_token")})
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("bot", b)
|
||||
}
|
||||
}
|
||||
|
||||
func checkConnectionForRequest() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
var conn Connection
|
||||
|
||||
if err := c.BindJSON(&conn); err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": getLocalizedMessage("incorrect_url_key")})
|
||||
return
|
||||
}
|
||||
|
||||
c.Set("connection", conn)
|
||||
}
|
||||
}
|
||||
|
89
stacktrace.go
Normal file
89
stacktrace.go
Normal file
@ -0,0 +1,89 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
|
||||
"github.com/getsentry/raven-go"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
func NewRavenStackTrace(client *raven.Client, myerr error, skip int) *raven.Stacktrace {
|
||||
st := getErrorStackTraceConverted(myerr, 3, client.IncludePaths())
|
||||
if st == nil {
|
||||
st = raven.NewStacktrace(skip, 3, client.IncludePaths())
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func getErrorStackTraceConverted(err error, context int, appPackagePrefixes []string) *raven.Stacktrace {
|
||||
st := getErrorCauseStackTrace(err)
|
||||
if st == nil {
|
||||
return nil
|
||||
}
|
||||
return convertStackTrace(st, context, appPackagePrefixes)
|
||||
}
|
||||
|
||||
func getErrorCauseStackTrace(err error) errors.StackTrace {
|
||||
// This code is inspired by github.com/pkg/errors.Cause().
|
||||
var st errors.StackTrace
|
||||
for err != nil {
|
||||
s := getErrorStackTrace(err)
|
||||
if s != nil {
|
||||
st = s
|
||||
}
|
||||
err = getErrorCause(err)
|
||||
}
|
||||
return st
|
||||
}
|
||||
|
||||
func convertStackTrace(st errors.StackTrace, context int, appPackagePrefixes []string) *raven.Stacktrace {
|
||||
// This code is borrowed from github.com/getsentry/raven-go.NewStacktrace().
|
||||
var frames []*raven.StacktraceFrame
|
||||
for _, f := range st {
|
||||
frame := convertFrame(f, context, appPackagePrefixes)
|
||||
if frame != nil {
|
||||
frames = append(frames, frame)
|
||||
}
|
||||
}
|
||||
if len(frames) == 0 {
|
||||
return nil
|
||||
}
|
||||
for i, j := 0, len(frames)-1; i < j; i, j = i+1, j-1 {
|
||||
frames[i], frames[j] = frames[j], frames[i]
|
||||
}
|
||||
return &raven.Stacktrace{Frames: frames}
|
||||
}
|
||||
|
||||
func convertFrame(f errors.Frame, context int, appPackagePrefixes []string) *raven.StacktraceFrame {
|
||||
// This code is borrowed from github.com/pkg/errors.Frame.
|
||||
pc := uintptr(f) - 1
|
||||
fn := runtime.FuncForPC(pc)
|
||||
var file string
|
||||
var line int
|
||||
if fn != nil {
|
||||
file, line = fn.FileLine(pc)
|
||||
} else {
|
||||
file = "unknown"
|
||||
}
|
||||
return raven.NewStacktraceFrame(pc, file, line, context, appPackagePrefixes)
|
||||
}
|
||||
|
||||
func getErrorStackTrace(err error) errors.StackTrace {
|
||||
ster, ok := err.(interface {
|
||||
StackTrace() errors.StackTrace
|
||||
})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return ster.StackTrace()
|
||||
}
|
||||
|
||||
func getErrorCause(err error) error {
|
||||
cer, ok := err.(interface {
|
||||
Cause() error
|
||||
})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return cer.Cause()
|
||||
}
|
@ -74,14 +74,14 @@ function send(url, data, callback) {
|
||||
}
|
||||
|
||||
function getBotTemplate(data) {
|
||||
let bot = JSON.parse(data);
|
||||
// let bot = JSON.parse(data);
|
||||
tmpl =
|
||||
`<tr>
|
||||
<td>${bot.name}</td>
|
||||
<td>${bot.token}</td>
|
||||
<td>${data.name}</td>
|
||||
<td>${data.token}</td>
|
||||
<td>
|
||||
<button class="delete-bot btn btn-small waves-effect waves-light light-blue darken-1" type="submit" name="action"
|
||||
data-token="${bot.token}">
|
||||
data-token="${data.token}">
|
||||
<i class="material-icons">delete</i>
|
||||
</button>
|
||||
</td>
|
||||
|
31
telegram.go
31
telegram.go
@ -126,7 +126,7 @@ func telegramWebhookHandler(c *gin.Context) {
|
||||
|
||||
data, st, err := client.Messages(snd)
|
||||
if err != nil {
|
||||
logger.Error(token, err.Error(), st, data)
|
||||
logger.Error(b.Token, err.Error(), st, data)
|
||||
c.Error(err)
|
||||
return
|
||||
}
|
||||
@ -155,7 +155,7 @@ func telegramWebhookHandler(c *gin.Context) {
|
||||
|
||||
data, st, err := client.UpdateMessages(snd)
|
||||
if err != nil {
|
||||
logger.Error(token, err.Error(), st, data)
|
||||
logger.Error(b.Token, err.Error(), st, data)
|
||||
c.Error(err)
|
||||
return
|
||||
}
|
||||
@ -165,21 +165,19 @@ func telegramWebhookHandler(c *gin.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
c.AbortWithStatus(http.StatusOK)
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
}
|
||||
|
||||
func mgWebhookHandler(c *gin.Context) {
|
||||
clientID := c.GetHeader("Clientid")
|
||||
if clientID == "" {
|
||||
logger.Error("mgWebhookHandler clientID is empty")
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
conn := getConnection(clientID)
|
||||
if !conn.Active {
|
||||
logger.Error(conn.ClientID, "mgWebhookHandler: connection deactivated")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Connection deactivated"})
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@ -198,8 +196,7 @@ func mgWebhookHandler(c *gin.Context) {
|
||||
|
||||
b := getBot(conn.ID, msg.Data.ChannelID)
|
||||
if b.ID == 0 {
|
||||
logger.Error(msg.Data.ChannelID, "mgWebhookHandler: missing or deactivated")
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing or deactivated"})
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@ -221,7 +218,7 @@ func mgWebhookHandler(c *gin.Context) {
|
||||
m.ReplyToMessageID = qid
|
||||
}
|
||||
|
||||
msg, err := bot.Send(m)
|
||||
msgSend, err := bot.Send(m)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
@ -229,14 +226,14 @@ func mgWebhookHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
if config.Debug {
|
||||
logger.Debugf("mgWebhookHandler sent %v", msg)
|
||||
logger.Debugf("mgWebhookHandler sent %v", msgSend)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"external_message_id": strconv.Itoa(msg.MessageID)})
|
||||
c.JSON(http.StatusOK, gin.H{"external_message_id": strconv.Itoa(msgSend.MessageID)})
|
||||
}
|
||||
|
||||
if msg.Type == "message_updated" {
|
||||
msg, err := bot.Send(tgbotapi.NewEditMessageText(cid, uid, msg.Data.Content))
|
||||
msgSend, err := bot.Send(tgbotapi.NewEditMessageText(cid, uid, msg.Data.Content))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
@ -244,14 +241,14 @@ func mgWebhookHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
if config.Debug {
|
||||
logger.Debugf("mgWebhookHandler update %v", msg)
|
||||
logger.Debugf("mgWebhookHandler update %v", msgSend)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Message updated"})
|
||||
c.AbortWithStatus(http.StatusOK)
|
||||
}
|
||||
|
||||
if msg.Type == "message_deleted" {
|
||||
msg, err := bot.Send(tgbotapi.NewDeleteMessage(cid, uid))
|
||||
msgSend, err := bot.Send(tgbotapi.NewDeleteMessage(cid, uid))
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
c.AbortWithStatus(http.StatusBadRequest)
|
||||
@ -259,10 +256,10 @@ func mgWebhookHandler(c *gin.Context) {
|
||||
}
|
||||
|
||||
if config.Debug {
|
||||
logger.Debugf("mgWebhookHandler delete %v", msg)
|
||||
logger.Debugf("mgWebhookHandler delete %v", msgSend)
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"message": "Message deleted"})
|
||||
c.JSON(http.StatusOK, gin.H{})
|
||||
}
|
||||
}
|
||||
|
||||
|
24
utils.go
24
utils.go
@ -11,32 +11,8 @@ import (
|
||||
|
||||
"github.com/nicksnyder/go-i18n/v2/i18n"
|
||||
"github.com/retailcrm/api-client-go/v5"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func setLocale(al string) {
|
||||
tag, _ := language.MatchStrings(matcher, al)
|
||||
localizer = i18n.NewLocalizer(bundle, tag.String())
|
||||
}
|
||||
|
||||
func getLocale() map[string]string {
|
||||
return map[string]string{
|
||||
"ButtonSave": getLocalizedMessage("button_save"),
|
||||
"ApiKey": getLocalizedMessage("api_key"),
|
||||
"TabSettings": getLocalizedMessage("tab_settings"),
|
||||
"TabBots": getLocalizedMessage("tab_bots"),
|
||||
"TableName": getLocalizedMessage("table_name"),
|
||||
"TableToken": getLocalizedMessage("table_token"),
|
||||
"AddBot": getLocalizedMessage("add_bot"),
|
||||
"TableDelete": getLocalizedMessage("table_delete"),
|
||||
"Title": getLocalizedMessage("title"),
|
||||
}
|
||||
}
|
||||
|
||||
func getLocalizedMessage(messageID string) string {
|
||||
return localizer.MustLocalize(&i18n.LocalizeConfig{MessageID: messageID})
|
||||
}
|
||||
|
||||
// GenerateToken function
|
||||
func GenerateToken() string {
|
||||
c := atomic.AddUint32(&tokenCounter, 1)
|
||||
|
@ -50,6 +50,14 @@ func kindOfData(data interface{}) reflect.Kind {
|
||||
return valueType
|
||||
}
|
||||
|
||||
func setValidation() {
|
||||
binding.Validator = new(defaultValidator)
|
||||
|
||||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||
v.RegisterValidation("validatecrmurl", validateCrmURL)
|
||||
}
|
||||
}
|
||||
|
||||
func validateCrmURL(field validator.FieldLevel) bool {
|
||||
regCommandName := regexp.MustCompile(`https://?[\da-z.-]+\.(retailcrm\.(ru|pro)|ecomlogic\.com)`)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user