2019-09-04 15:22:27 +03:00
|
|
|
|
package core
|
|
|
|
|
|
|
|
|
|
import (
|
2019-12-12 09:35:05 +03:00
|
|
|
|
// nolint:gosec
|
2019-09-04 15:22:27 +03:00
|
|
|
|
"crypto/sha1"
|
|
|
|
|
"crypto/sha256"
|
|
|
|
|
"encoding/json"
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
"net/http"
|
|
|
|
|
"regexp"
|
|
|
|
|
"strings"
|
|
|
|
|
"sync/atomic"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws"
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws/credentials"
|
|
|
|
|
"github.com/aws/aws-sdk-go/aws/session"
|
|
|
|
|
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
|
|
|
|
v5 "github.com/retailcrm/api-client-go/v5"
|
|
|
|
|
v1 "github.com/retailcrm/mg-transport-api-client-go/v1"
|
|
|
|
|
)
|
|
|
|
|
|
2020-10-20 15:19:36 +03:00
|
|
|
|
var defaultCurrencies = map[string]string{
|
|
|
|
|
"rub": "₽",
|
|
|
|
|
"uah": "₴",
|
|
|
|
|
"byn": "Br",
|
|
|
|
|
"kzt": "₸",
|
|
|
|
|
"usd": "$",
|
|
|
|
|
"eur": "€",
|
|
|
|
|
"prb": "PRB",
|
|
|
|
|
"mdl": "L",
|
|
|
|
|
"kgs": "с",
|
|
|
|
|
"pln": "zł",
|
|
|
|
|
"azn": "₼",
|
|
|
|
|
"amd": "֏",
|
|
|
|
|
"thb": "฿",
|
|
|
|
|
"aed": "AED",
|
|
|
|
|
"nok": "kr",
|
|
|
|
|
"cad": "C$",
|
|
|
|
|
"czk": "Kč",
|
|
|
|
|
"sek": "kr",
|
|
|
|
|
"dkk": "kr",
|
|
|
|
|
"ron": "lei",
|
|
|
|
|
"uzs": "So'm",
|
|
|
|
|
"aud": "$",
|
|
|
|
|
"chf": "₣",
|
|
|
|
|
"inr": "₹",
|
|
|
|
|
"bgn": "лв",
|
|
|
|
|
"ngn": "₦",
|
|
|
|
|
"huf": "ƒ",
|
|
|
|
|
"ils": "₪",
|
|
|
|
|
"try": "₺",
|
|
|
|
|
"stn": "₡",
|
|
|
|
|
"ars": "$",
|
|
|
|
|
"bob": "Bs",
|
|
|
|
|
"ves": "Bs",
|
|
|
|
|
"gtq": "Q",
|
|
|
|
|
"hnl": "L",
|
|
|
|
|
"dop": "RD$",
|
|
|
|
|
"cop": "COL$",
|
|
|
|
|
"crc": "₡",
|
|
|
|
|
"cup": "$MN",
|
|
|
|
|
"mxn": "NP$",
|
|
|
|
|
"nio": "C$",
|
|
|
|
|
"pab": "B/",
|
|
|
|
|
"pyg": "₲",
|
|
|
|
|
"pen": "S/",
|
|
|
|
|
"svc": "₡",
|
|
|
|
|
"uyu": "$U",
|
|
|
|
|
"clp": "Ch$",
|
|
|
|
|
"gel": "₾",
|
|
|
|
|
"gbp": "£",
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 15:22:27 +03:00
|
|
|
|
// Utils service object
|
|
|
|
|
type Utils struct {
|
|
|
|
|
IsDebug bool
|
2019-12-12 10:08:26 +03:00
|
|
|
|
TokenCounter uint32
|
2019-09-04 15:22:27 +03:00
|
|
|
|
ConfigAWS ConfigAWS
|
2019-12-25 17:36:02 +03:00
|
|
|
|
Logger LoggerInterface
|
2019-09-04 15:22:27 +03:00
|
|
|
|
slashRegex *regexp.Regexp
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewUtils will create new Utils instance
|
2019-12-25 17:36:02 +03:00
|
|
|
|
func NewUtils(awsConfig ConfigAWS, logger LoggerInterface, debug bool) *Utils {
|
2019-09-04 15:22:27 +03:00
|
|
|
|
return &Utils{
|
|
|
|
|
IsDebug: debug,
|
|
|
|
|
ConfigAWS: awsConfig,
|
|
|
|
|
Logger: logger,
|
|
|
|
|
TokenCounter: 0,
|
2019-09-04 15:52:41 +03:00
|
|
|
|
slashRegex: slashRegex,
|
2019-09-04 15:22:27 +03:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// resetUtils
|
|
|
|
|
func (u *Utils) resetUtils(awsConfig ConfigAWS, debug bool, tokenCounter uint32) {
|
|
|
|
|
u.TokenCounter = tokenCounter
|
|
|
|
|
u.ConfigAWS = awsConfig
|
|
|
|
|
u.IsDebug = debug
|
2019-09-04 15:52:41 +03:00
|
|
|
|
u.slashRegex = slashRegex
|
2019-09-04 15:22:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GenerateToken will generate long pseudo-random string.
|
|
|
|
|
func (u *Utils) GenerateToken() string {
|
|
|
|
|
c := atomic.AddUint32(&u.TokenCounter, 1)
|
|
|
|
|
|
|
|
|
|
return fmt.Sprintf("%x", sha256.Sum256([]byte(fmt.Sprintf("%d%d", time.Now().UnixNano(), c))))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetAPIClient will initialize retailCRM api client from url and key
|
|
|
|
|
func (u *Utils) GetAPIClient(url, key string) (*v5.Client, int, error) {
|
|
|
|
|
client := v5.New(url, key)
|
|
|
|
|
client.Debug = u.IsDebug
|
|
|
|
|
|
|
|
|
|
cr, status, e := client.APICredentials()
|
2019-10-17 13:11:20 +03:00
|
|
|
|
if e != nil && e.Error() != "" {
|
|
|
|
|
u.Logger.Error(url, status, e.Error(), cr)
|
|
|
|
|
return nil, http.StatusInternalServerError, errors.New(e.Error())
|
2019-09-04 15:22:27 +03:00
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !cr.Success {
|
2019-10-17 13:11:20 +03:00
|
|
|
|
errMsg := "unknown error"
|
|
|
|
|
|
|
|
|
|
if e != nil {
|
|
|
|
|
if e.ApiError() != "" {
|
|
|
|
|
errMsg = e.ApiError()
|
|
|
|
|
} else if e.ApiErrors() != nil {
|
|
|
|
|
errMsg = ""
|
|
|
|
|
|
|
|
|
|
for key, errText := range e.ApiErrors() {
|
|
|
|
|
errMsg += fmt.Sprintf("[%s: %s] ", key, errText)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
u.Logger.Error(url, status, errMsg, cr)
|
2019-09-04 15:52:41 +03:00
|
|
|
|
return nil, http.StatusBadRequest, errors.New("invalid credentials")
|
2019-09-04 15:22:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if res := u.checkCredentials(cr.Credentials); len(res) != 0 {
|
|
|
|
|
u.Logger.Error(url, status, res)
|
2019-09-04 15:52:41 +03:00
|
|
|
|
return nil, http.StatusBadRequest, errors.New("missing credentials")
|
2019-09-04 15:22:27 +03:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return client, 0, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (u *Utils) checkCredentials(credential []string) []string {
|
2019-09-04 15:52:41 +03:00
|
|
|
|
rc := make([]string, len(credentialsTransport))
|
|
|
|
|
copy(rc, credentialsTransport)
|
2019-09-04 15:22:27 +03:00
|
|
|
|
|
|
|
|
|
for _, vc := range credential {
|
|
|
|
|
for kn, vn := range rc {
|
|
|
|
|
if vn == vc {
|
|
|
|
|
if len(rc) == 1 {
|
|
|
|
|
rc = rc[:0]
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
rc = append(rc[:kn], rc[kn+1:]...)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return rc
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// UploadUserAvatar will upload avatar for user
|
|
|
|
|
func (u *Utils) UploadUserAvatar(url string) (picURLs3 string, err error) {
|
|
|
|
|
s3Config := &aws.Config{
|
|
|
|
|
Credentials: credentials.NewStaticCredentials(
|
|
|
|
|
u.ConfigAWS.AccessKeyID,
|
|
|
|
|
u.ConfigAWS.SecretAccessKey,
|
|
|
|
|
""),
|
|
|
|
|
Region: aws.String(u.ConfigAWS.Region),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
s := session.Must(session.NewSession(s3Config))
|
|
|
|
|
uploader := s3manager.NewUploader(s)
|
|
|
|
|
|
2019-12-12 09:35:05 +03:00
|
|
|
|
// nolint:gosec
|
2019-09-04 15:22:27 +03:00
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
defer resp.Body.Close()
|
|
|
|
|
|
|
|
|
|
if resp.StatusCode >= http.StatusBadRequest {
|
|
|
|
|
return "", fmt.Errorf("get: %v code: %v", url, resp.StatusCode)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result, err := uploader.Upload(&s3manager.UploadInput{
|
|
|
|
|
Bucket: aws.String(u.ConfigAWS.Bucket),
|
|
|
|
|
Key: aws.String(fmt.Sprintf("%v/%v.jpg", u.ConfigAWS.FolderName, u.GenerateToken())),
|
|
|
|
|
Body: resp.Body,
|
|
|
|
|
ContentType: aws.String(u.ConfigAWS.ContentType),
|
|
|
|
|
ACL: aws.String("public-read"),
|
|
|
|
|
})
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
picURLs3 = result.Location
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-18 18:02:40 +03:00
|
|
|
|
// RemoveTrailingSlash will remove slash at the end of any string
|
|
|
|
|
func (u *Utils) RemoveTrailingSlash(crmURL string) string {
|
|
|
|
|
return u.slashRegex.ReplaceAllString(crmURL, ``)
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-04 15:22:27 +03:00
|
|
|
|
// GetMGItemData will upload file to MG by URL and return information about attachable item
|
|
|
|
|
func GetMGItemData(client *v1.MgClient, url string, caption string) (v1.Item, int, error) {
|
|
|
|
|
item := v1.Item{}
|
|
|
|
|
|
|
|
|
|
data, st, err := client.UploadFileByURL(
|
|
|
|
|
v1.UploadFileByUrlRequest{
|
|
|
|
|
Url: url,
|
|
|
|
|
},
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return item, st, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
item.ID = data.ID
|
|
|
|
|
item.Caption = caption
|
|
|
|
|
|
|
|
|
|
return item, st, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetEntitySHA1 will serialize any value to JSON and return SHA1 hash of this JSON
|
|
|
|
|
func GetEntitySHA1(v interface{}) (hash string, err error) {
|
|
|
|
|
res, _ := json.Marshal(v)
|
|
|
|
|
|
2019-12-12 09:35:05 +03:00
|
|
|
|
// nolint:gosec
|
2019-09-04 15:22:27 +03:00
|
|
|
|
h := sha1.New()
|
|
|
|
|
_, err = h.Write(res)
|
|
|
|
|
hash = fmt.Sprintf("%x", h.Sum(nil))
|
|
|
|
|
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ReplaceMarkdownSymbols will remove markdown symbols from text
|
|
|
|
|
func ReplaceMarkdownSymbols(s string) string {
|
2019-09-04 15:52:41 +03:00
|
|
|
|
for _, v := range markdownSymbols {
|
2019-09-04 15:22:27 +03:00
|
|
|
|
s = strings.Replace(s, v, "\\"+v, -1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// DefaultCurrencies will return default currencies list for all bots
|
|
|
|
|
func DefaultCurrencies() map[string]string {
|
2020-10-20 15:19:36 +03:00
|
|
|
|
return defaultCurrencies
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetCurrencySymbol returns currency symbol by it's ISO 4127 code.
|
|
|
|
|
// It returns provided currency code in uppercase if currency symbol cannot be found
|
|
|
|
|
func GetCurrencySymbol(code string) string {
|
|
|
|
|
if i, ok := DefaultCurrencies()[strings.ToLower(code)]; ok {
|
|
|
|
|
return i
|
2019-09-04 15:22:27 +03:00
|
|
|
|
}
|
2020-10-20 15:19:36 +03:00
|
|
|
|
|
|
|
|
|
return strings.ToUpper(code)
|
2019-09-04 15:22:27 +03:00
|
|
|
|
}
|