mirror of
https://github.com/retailcrm/mg-transport-core.git
synced 2024-11-24 22:26:04 +03:00
updated gin, better code
This commit is contained in:
parent
bf689e15b0
commit
6290301815
@ -7,6 +7,7 @@ import (
|
|||||||
"github.com/retailcrm/mg-transport-core/core"
|
"github.com/retailcrm/mg-transport-core/core"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Options for tool command
|
||||||
type Options struct{}
|
type Options struct{}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -16,7 +16,8 @@ var (
|
|||||||
"/api/integration-modules/{code}/edit",
|
"/api/integration-modules/{code}/edit",
|
||||||
}
|
}
|
||||||
markdownSymbols = []string{"*", "_", "`", "["}
|
markdownSymbols = []string{"*", "_", "`", "["}
|
||||||
regCommandName = regexp.MustCompile(`^https://?[\da-z.-]+\.(retailcrm\.(ru|pro|es)|ecomlogic\.com|simlachat\.(com|ru))/?$`)
|
regCommandName = regexp.MustCompile(
|
||||||
|
`^https://?[\da-z.-]+\.(retailcrm\.(ru|pro|es)|ecomlogic\.com|simlachat\.(com|ru))/?$`)
|
||||||
slashRegex = regexp.MustCompile(`/+$`)
|
slashRegex = regexp.MustCompile(`/+$`)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -29,7 +30,7 @@ type ConfigInterface interface {
|
|||||||
GetDBConfig() DatabaseConfig
|
GetDBConfig() DatabaseConfig
|
||||||
GetAWSConfig() ConfigAWS
|
GetAWSConfig() ConfigAWS
|
||||||
GetTransportInfo() InfoInterface
|
GetTransportInfo() InfoInterface
|
||||||
GetHTTPClientConfig() *HTTPClientConfig
|
GetHTTPClientConfig() HTTPClientConfigInterface
|
||||||
GetUpdateInterval() int
|
GetUpdateInterval() int
|
||||||
IsDebug() bool
|
IsDebug() bool
|
||||||
}
|
}
|
||||||
@ -41,6 +42,14 @@ type InfoInterface interface {
|
|||||||
GetLogoPath() string
|
GetLogoPath() string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// HTTPClientConfigInterface can be used to provide alternative way for configuring HTTP server
|
||||||
|
type HTTPClientConfigInterface interface {
|
||||||
|
GetTimeout() time.Duration
|
||||||
|
IsSSLVerificationEnabled() bool
|
||||||
|
GetMockAddress() string
|
||||||
|
GetMockedDomains() []string
|
||||||
|
}
|
||||||
|
|
||||||
// Config struct
|
// Config struct
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Version string `yaml:"version"`
|
Version string `yaml:"version"`
|
||||||
@ -52,7 +61,7 @@ type Config struct {
|
|||||||
UpdateInterval int `yaml:"update_interval"`
|
UpdateInterval int `yaml:"update_interval"`
|
||||||
ConfigAWS ConfigAWS `yaml:"config_aws"`
|
ConfigAWS ConfigAWS `yaml:"config_aws"`
|
||||||
TransportInfo Info `yaml:"transport_info"`
|
TransportInfo Info `yaml:"transport_info"`
|
||||||
HTTPClientConfig *HTTPClientConfig `yaml:"http_client"`
|
HTTPClientConfig HTTPClientConfigInterface `yaml:"http_client"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Info struct
|
// Info struct
|
||||||
@ -85,7 +94,7 @@ type DatabaseConfig struct {
|
|||||||
// HTTPClientConfig struct
|
// HTTPClientConfig struct
|
||||||
type HTTPClientConfig struct {
|
type HTTPClientConfig struct {
|
||||||
Timeout time.Duration `yaml:"timeout"`
|
Timeout time.Duration `yaml:"timeout"`
|
||||||
SSLVerification bool `yaml:"ssl_verification"`
|
SSLVerification *bool `yaml:"ssl_verification"`
|
||||||
MockAddress string `yaml:"mock_address"`
|
MockAddress string `yaml:"mock_address"`
|
||||||
MockedDomains []string `yaml:"mocked_domains"`
|
MockedDomains []string `yaml:"mocked_domains"`
|
||||||
}
|
}
|
||||||
@ -180,7 +189,7 @@ func (c Config) GetUpdateInterval() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetHTTPClientConfig returns http client config
|
// GetHTTPClientConfig returns http client config
|
||||||
func (c Config) GetHTTPClientConfig() *HTTPClientConfig {
|
func (c Config) GetHTTPClientConfig() HTTPClientConfigInterface {
|
||||||
return c.HTTPClientConfig
|
return c.HTTPClientConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,3 +207,31 @@ func (t Info) GetCode() string {
|
|||||||
func (t Info) GetLogoPath() string {
|
func (t Info) GetLogoPath() string {
|
||||||
return t.LogoPath
|
return t.LogoPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTimeout returns timeout for HTTP client (default is 30 seconds)
|
||||||
|
func (h *HTTPClientConfig) GetTimeout() time.Duration {
|
||||||
|
if h.Timeout <= 0 {
|
||||||
|
h.Timeout = 30 * time.Second
|
||||||
|
}
|
||||||
|
|
||||||
|
return h.Timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsSSLVerificationEnabled returns SSL verification flag (default is true)
|
||||||
|
func (h *HTTPClientConfig) IsSSLVerificationEnabled() bool {
|
||||||
|
if h.SSLVerification == nil {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return *h.SSLVerification
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMockAddress returns mock address
|
||||||
|
func (h *HTTPClientConfig) GetMockAddress() string {
|
||||||
|
return h.MockAddress
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMockedDomains returns mocked domains list
|
||||||
|
func (h *HTTPClientConfig) GetMockedDomains() []string {
|
||||||
|
return h.MockedDomains
|
||||||
|
}
|
||||||
|
22
core/csrf.go
22
core/csrf.go
@ -2,6 +2,7 @@ package core
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
// nolint:gosec
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
"io"
|
"io"
|
||||||
@ -44,6 +45,7 @@ var DefaultCSRFTokenGetter = func(c *gin.Context) string {
|
|||||||
// DefaultIgnoredMethods ignored methods for CSRF verifier middleware
|
// DefaultIgnoredMethods ignored methods for CSRF verifier middleware
|
||||||
var DefaultIgnoredMethods = []string{"GET", "HEAD", "OPTIONS"}
|
var DefaultIgnoredMethods = []string{"GET", "HEAD", "OPTIONS"}
|
||||||
|
|
||||||
|
// CSRF struct. Provides CSRF token verification.
|
||||||
type CSRF struct {
|
type CSRF struct {
|
||||||
salt string
|
salt string
|
||||||
secret string
|
secret string
|
||||||
@ -51,7 +53,6 @@ type CSRF struct {
|
|||||||
abortFunc gin.HandlerFunc
|
abortFunc gin.HandlerFunc
|
||||||
csrfTokenGetter CSRFTokenGetter
|
csrfTokenGetter CSRFTokenGetter
|
||||||
store sessions.Store
|
store sessions.Store
|
||||||
locale *Localizer
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCSRF creates CSRF struct with specified configuration and session store.
|
// NewCSRF creates CSRF struct with specified configuration and session store.
|
||||||
@ -115,8 +116,12 @@ func (x *CSRF) strInSlice(slice []string, v string) bool {
|
|||||||
|
|
||||||
// generateCSRFToken generates new CSRF token
|
// generateCSRFToken generates new CSRF token
|
||||||
func (x *CSRF) generateCSRFToken() string {
|
func (x *CSRF) generateCSRFToken() string {
|
||||||
|
// nolint:gosec
|
||||||
h := sha1.New()
|
h := sha1.New()
|
||||||
io.WriteString(h, x.salt+"#"+x.secret)
|
// Fallback to less secure method - token must be always filled even if we cannot properly generate it
|
||||||
|
if _, err := io.WriteString(h, x.salt+"#"+x.secret); err != nil {
|
||||||
|
return base64.URLEncoding.EncodeToString([]byte(time.Now().String()))
|
||||||
|
}
|
||||||
hash := base64.URLEncoding.EncodeToString(h.Sum(nil))
|
hash := base64.URLEncoding.EncodeToString(h.Sum(nil))
|
||||||
|
|
||||||
return hash
|
return hash
|
||||||
@ -155,12 +160,10 @@ func (x *CSRF) CSRFFromContext(c *gin.Context) string {
|
|||||||
if i, ok := c.Get("csrf_token"); ok {
|
if i, ok := c.Get("csrf_token"); ok {
|
||||||
if token, ok := i.(string); ok {
|
if token, ok := i.(string); ok {
|
||||||
return token
|
return token
|
||||||
} else {
|
|
||||||
return x.generateCSRFToken()
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return x.generateCSRFToken()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return x.generateCSRFToken()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateCSRFMiddleware returns gin.HandlerFunc which will generate CSRF token
|
// GenerateCSRFMiddleware returns gin.HandlerFunc which will generate CSRF token
|
||||||
@ -211,13 +214,14 @@ func (x *CSRF) VerifyCSRFMiddleware(ignoredMethods []string) gin.HandlerFunc {
|
|||||||
session, _ := x.store.Get(c.Request, x.sessionName)
|
session, _ := x.store.Get(c.Request, x.sessionName)
|
||||||
|
|
||||||
if i, ok := session.Values["csrf_token"]; ok {
|
if i, ok := session.Values["csrf_token"]; ok {
|
||||||
if i, ok := i.(string); !ok || i == "" {
|
var v string
|
||||||
|
if v, ok = i.(string); !ok || v == "" {
|
||||||
x.abortFunc(c)
|
x.abortFunc(c)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
} else {
|
|
||||||
token = i
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
token = v
|
||||||
} else {
|
} else {
|
||||||
x.abortFunc(c)
|
x.abortFunc(c)
|
||||||
c.Abort()
|
c.Abort()
|
||||||
|
@ -92,7 +92,7 @@ func (e *Engine) Prepare() *Engine {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// templateFuncMap combines func map for templates
|
// TemplateFuncMap combines func map for templates
|
||||||
func (e *Engine) TemplateFuncMap(functions template.FuncMap) template.FuncMap {
|
func (e *Engine) TemplateFuncMap(functions template.FuncMap) template.FuncMap {
|
||||||
funcMap := e.LocalizationFuncMap()
|
funcMap := e.LocalizationFuncMap()
|
||||||
|
|
||||||
@ -100,6 +100,10 @@ func (e *Engine) TemplateFuncMap(functions template.FuncMap) template.FuncMap {
|
|||||||
funcMap[name] = fn
|
funcMap[name] = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
funcMap["version"] = func() string {
|
||||||
|
return e.Config.GetVersion()
|
||||||
|
}
|
||||||
|
|
||||||
return funcMap
|
return funcMap
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,9 +160,9 @@ func (e *Engine) SetHTTPClient(client *http.Client) *Engine {
|
|||||||
func (e *Engine) HTTPClient() *http.Client {
|
func (e *Engine) HTTPClient() *http.Client {
|
||||||
if e.httpClient == nil {
|
if e.httpClient == nil {
|
||||||
return http.DefaultClient
|
return http.DefaultClient
|
||||||
} else {
|
|
||||||
return e.httpClient
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return e.httpClient
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithCookieSessions generates new CookieStore with optional key length.
|
// WithCookieSessions generates new CookieStore with optional key length.
|
||||||
@ -174,7 +178,7 @@ func (e *Engine) WithCookieSessions(keyLength ...int) *Engine {
|
|||||||
return e
|
return e
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithCookieSessions generates new FilesystemStore with optional key length.
|
// WithFilesystemSessions generates new FilesystemStore with optional key length.
|
||||||
// Default key length is 32 bytes.
|
// Default key length is 32 bytes.
|
||||||
func (e *Engine) WithFilesystemSessions(path string, keyLength ...int) *Engine {
|
func (e *Engine) WithFilesystemSessions(path string, keyLength ...int) *Engine {
|
||||||
length := 32
|
length := 32
|
||||||
|
@ -154,7 +154,7 @@ func (e *EngineTest) Test_BuildHTTPClient() {
|
|||||||
e.engine.Config = &Config{
|
e.engine.Config = &Config{
|
||||||
HTTPClientConfig: &HTTPClientConfig{
|
HTTPClientConfig: &HTTPClientConfig{
|
||||||
Timeout: 30,
|
Timeout: 30,
|
||||||
SSLVerification: true,
|
SSLVerification: boolPtr(true),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
e.engine.BuildHTTPClient()
|
e.engine.BuildHTTPClient()
|
||||||
@ -300,3 +300,8 @@ func (e *EngineTest) Test_Run_Fail() {
|
|||||||
func TestEngine_Suite(t *testing.T) {
|
func TestEngine_Suite(t *testing.T) {
|
||||||
suite.Run(t, new(EngineTest))
|
suite.Run(t, new(EngineTest))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func boolPtr(val bool) *bool {
|
||||||
|
b := val
|
||||||
|
return &b
|
||||||
|
}
|
||||||
|
@ -11,10 +11,11 @@ import (
|
|||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
// DefaultClient stores original http.DefaultClient
|
||||||
DefaultClient = http.DefaultClient
|
var DefaultClient = http.DefaultClient
|
||||||
DefaultTransport = http.DefaultTransport
|
|
||||||
)
|
// DefaultTransport stores original http.DefaultTransport
|
||||||
|
var DefaultTransport = http.DefaultTransport
|
||||||
|
|
||||||
// HTTPClientBuilder builds http client with mocks (if necessary) and timeout.
|
// HTTPClientBuilder builds http client with mocks (if necessary) and timeout.
|
||||||
// Example:
|
// Example:
|
||||||
@ -111,21 +112,21 @@ func (b *HTTPClientBuilder) EnableLogging() *HTTPClientBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FromConfig fulfills mock configuration from HTTPClientConfig
|
// FromConfig fulfills mock configuration from HTTPClientConfig
|
||||||
func (b *HTTPClientBuilder) FromConfig(config *HTTPClientConfig) *HTTPClientBuilder {
|
func (b *HTTPClientBuilder) FromConfig(config HTTPClientConfigInterface) *HTTPClientBuilder {
|
||||||
if config == nil {
|
if config == nil {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.MockAddress != "" {
|
if config.GetMockAddress() != "" {
|
||||||
b.SetMockAddress(config.MockAddress)
|
b.SetMockAddress(config.GetMockAddress())
|
||||||
b.SetMockedDomains(config.MockedDomains)
|
b.SetMockedDomains(config.GetMockedDomains())
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Timeout > 0 {
|
if config.GetTimeout() > 0 {
|
||||||
b.SetTimeout(config.Timeout)
|
b.SetTimeout(config.GetTimeout())
|
||||||
}
|
}
|
||||||
|
|
||||||
b.SetSSLVerification(config.SSLVerification)
|
b.SetSSLVerification(config.IsSSLVerificationEnabled())
|
||||||
|
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
@ -156,10 +157,11 @@ func (b *HTTPClientBuilder) parseAddress() error {
|
|||||||
if host, port, err := net.SplitHostPort(b.mockAddress); err == nil {
|
if host, port, err := net.SplitHostPort(b.mockAddress); err == nil {
|
||||||
b.mockHost = host
|
b.mockHost = host
|
||||||
b.mockPort = port
|
b.mockPort = port
|
||||||
return nil
|
|
||||||
} else {
|
} else {
|
||||||
return errors.Errorf("cannot split host and port: %s", err.Error())
|
return errors.Errorf("cannot split host and port: %s", err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildMocks builds mocks for http client
|
// buildMocks builds mocks for http client
|
||||||
@ -177,9 +179,15 @@ func (b *HTTPClientBuilder) buildMocks() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b.httpTransport.DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, e error) {
|
b.httpTransport.DialContext = func(ctx context.Context, network, addr string) (conn net.Conn, e error) {
|
||||||
if host, port, err := net.SplitHostPort(addr); err != nil {
|
var (
|
||||||
|
host string
|
||||||
|
port string
|
||||||
|
err error
|
||||||
|
)
|
||||||
|
if host, port, err = net.SplitHostPort(addr); err != nil {
|
||||||
return b.dialer.DialContext(ctx, network, addr)
|
return b.dialer.DialContext(ctx, network, addr)
|
||||||
} else {
|
}
|
||||||
|
|
||||||
for _, mock := range b.mockedDomains {
|
for _, mock := range b.mockedDomains {
|
||||||
if mock == host {
|
if mock == host {
|
||||||
oldAddr := addr
|
oldAddr := addr
|
||||||
@ -193,7 +201,6 @@ func (b *HTTPClientBuilder) buildMocks() error {
|
|||||||
b.logf("Mocking \"%s\" with \"%s\"\n", oldAddr, addr)
|
b.logf("Mocking \"%s\" with \"%s\"\n", oldAddr, addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return b.dialer.DialContext(ctx, network, addr)
|
return b.dialer.DialContext(ctx, network, addr)
|
||||||
}
|
}
|
||||||
|
@ -58,14 +58,14 @@ func (t *HTTPClientBuilderTest) Test_SetSSLVerification() {
|
|||||||
|
|
||||||
func (t *HTTPClientBuilderTest) Test_FromConfig() {
|
func (t *HTTPClientBuilderTest) Test_FromConfig() {
|
||||||
config := &HTTPClientConfig{
|
config := &HTTPClientConfig{
|
||||||
SSLVerification: true,
|
SSLVerification: boolPtr(true),
|
||||||
MockAddress: "anothermock.local:3004",
|
MockAddress: "anothermock.local:3004",
|
||||||
MockedDomains: []string{"example.gov"},
|
MockedDomains: []string{"example.gov"},
|
||||||
Timeout: 60,
|
Timeout: 60,
|
||||||
}
|
}
|
||||||
|
|
||||||
t.builder.FromConfig(config)
|
t.builder.FromConfig(config)
|
||||||
assert.Equal(t.T(), !config.SSLVerification, t.builder.httpTransport.TLSClientConfig.InsecureSkipVerify)
|
assert.Equal(t.T(), !config.IsSSLVerificationEnabled(), t.builder.httpTransport.TLSClientConfig.InsecureSkipVerify)
|
||||||
assert.Equal(t.T(), config.MockAddress, t.builder.mockAddress)
|
assert.Equal(t.T(), config.MockAddress, t.builder.mockAddress)
|
||||||
assert.Equal(t.T(), config.MockedDomains[0], t.builder.mockedDomains[0])
|
assert.Equal(t.T(), config.MockedDomains[0], t.builder.mockedDomains[0])
|
||||||
assert.Equal(t.T(), config.Timeout*time.Second, t.builder.timeout)
|
assert.Equal(t.T(), config.Timeout*time.Second, t.builder.timeout)
|
||||||
@ -76,7 +76,7 @@ func (t *HTTPClientBuilderTest) Test_FromEngine() {
|
|||||||
engine := &Engine{
|
engine := &Engine{
|
||||||
Config: Config{
|
Config: Config{
|
||||||
HTTPClientConfig: &HTTPClientConfig{
|
HTTPClientConfig: &HTTPClientConfig{
|
||||||
SSLVerification: true,
|
SSLVerification: boolPtr(true),
|
||||||
MockAddress: "anothermock.local:3004",
|
MockAddress: "anothermock.local:3004",
|
||||||
MockedDomains: []string{"example.gov"},
|
MockedDomains: []string{"example.gov"},
|
||||||
},
|
},
|
||||||
|
@ -145,9 +145,9 @@ func (l *Localizer) loadFromFS() error {
|
|||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
} else {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetLocale will change language for current localizer
|
// SetLocale will change language for current localizer
|
||||||
|
@ -54,7 +54,7 @@ func (m *Migrate) Add(migration *gormigrate.Migration) {
|
|||||||
m.migrations[migration.ID] = migration
|
m.migrations[migration.ID] = migration
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetORM to migrate
|
// SetDB to migrate
|
||||||
func (m *Migrate) SetDB(db *gorm.DB) *Migrate {
|
func (m *Migrate) SetDB(db *gorm.DB) *Migrate {
|
||||||
m.db = db
|
m.db = db
|
||||||
return m
|
return m
|
||||||
@ -86,9 +86,9 @@ func (m *Migrate) Rollback() error {
|
|||||||
if err := m.GORMigrate.RollbackTo(m.first.ID); err == nil {
|
if err := m.GORMigrate.RollbackTo(m.first.ID); err == nil {
|
||||||
if err := m.GORMigrate.RollbackMigration(m.first); err == nil {
|
if err := m.GORMigrate.RollbackMigration(m.first); err == nil {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
} else {
|
} else {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -185,10 +185,10 @@ func (m *Migrate) Current() string {
|
|||||||
|
|
||||||
if err := m.db.Last(&migrationInfo).Error; err == nil {
|
if err := m.db.Last(&migrationInfo).Error; err == nil {
|
||||||
return migrationInfo.ID
|
return migrationInfo.ID
|
||||||
} else {
|
}
|
||||||
|
|
||||||
fmt.Printf("warning => cannot fetch migration version: %s\n", err.Error())
|
fmt.Printf("warning => cannot fetch migration version: %s\n", err.Error())
|
||||||
return "0"
|
return "0"
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextFrom returns next version from passed version
|
// NextFrom returns next version from passed version
|
||||||
@ -197,9 +197,9 @@ func (m *Migrate) NextFrom(version string) (string, error) {
|
|||||||
if ver == version {
|
if ver == version {
|
||||||
if key < (len(m.versions) - 1) {
|
if key < (len(m.versions) - 1) {
|
||||||
return m.versions[key+1], nil
|
return m.versions[key+1], nil
|
||||||
} else {
|
|
||||||
return "", errors.New("this is last migration")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "", errors.New("this is last migration")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,9 +212,9 @@ func (m *Migrate) PreviousFrom(version string) (string, error) {
|
|||||||
if ver == version {
|
if ver == version {
|
||||||
if key > 0 {
|
if key > 0 {
|
||||||
return m.versions[key-1], nil
|
return m.versions[key-1], nil
|
||||||
} else {
|
|
||||||
return "0", nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return "0", nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,7 +54,7 @@ func (m *MigrateTest) RefreshMigrate() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MigrateTest) Migration_TestModelFirst() *gormigrate.Migration {
|
func (m *MigrateTest) MigrationTestModelFirst() *gormigrate.Migration {
|
||||||
return &gormigrate.Migration{
|
return &gormigrate.Migration{
|
||||||
ID: "1",
|
ID: "1",
|
||||||
Migrate: func(db *gorm.DB) error {
|
Migrate: func(db *gorm.DB) error {
|
||||||
@ -66,7 +66,7 @@ func (m *MigrateTest) Migration_TestModelFirst() *gormigrate.Migration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *MigrateTest) Migration_TestModelSecond() *gormigrate.Migration {
|
func (m *MigrateTest) MigrationTestModelSecond() *gormigrate.Migration {
|
||||||
return &gormigrate.Migration{
|
return &gormigrate.Migration{
|
||||||
ID: "2",
|
ID: "2",
|
||||||
Migrate: func(db *gorm.DB) error {
|
Migrate: func(db *gorm.DB) error {
|
||||||
@ -81,7 +81,7 @@ func (m *MigrateTest) Migration_TestModelSecond() *gormigrate.Migration {
|
|||||||
func (m *MigrateTest) Test_Add() {
|
func (m *MigrateTest) Test_Add() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(nil)
|
m.Migrate.Add(nil)
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
assert.Equal(m.T(), 1, len(m.Migrate.migrations))
|
assert.Equal(m.T(), 1, len(m.Migrate.migrations))
|
||||||
i, ok := m.Migrate.migrations["1"]
|
i, ok := m.Migrate.migrations["1"]
|
||||||
@ -112,7 +112,7 @@ func (m *MigrateTest) Test_prepareMigrations_AlreadyPrepared() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_prepareMigrations_OK() {
|
func (m *MigrateTest) Test_prepareMigrations_OK() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
err := m.Migrate.prepareMigrations()
|
err := m.Migrate.prepareMigrations()
|
||||||
|
|
||||||
require.NoError(m.T(), err)
|
require.NoError(m.T(), err)
|
||||||
@ -124,7 +124,7 @@ func (m *MigrateTest) Test_prepareMigrations_OK() {
|
|||||||
func (m *MigrateTest) Test_Migrate_Fail_NilDB() {
|
func (m *MigrateTest) Test_Migrate_Fail_NilDB() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.SetDB(nil)
|
m.Migrate.SetDB(nil)
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
err := m.Migrate.Migrate()
|
err := m.Migrate.Migrate()
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ func (m *MigrateTest) Test_Migrate_Fail_NilDB() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_Migrate_Success_NoMigrations() {
|
func (m *MigrateTest) Test_Migrate_Success_NoMigrations() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
m.mock.ExpectBegin()
|
m.mock.ExpectBegin()
|
||||||
m.mock.
|
m.mock.
|
||||||
@ -157,7 +157,7 @@ func (m *MigrateTest) Test_Migrate_Success_NoMigrations() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_Migrate_Success() {
|
func (m *MigrateTest) Test_Migrate_Success() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
m.mock.ExpectBegin()
|
m.mock.ExpectBegin()
|
||||||
m.mock.
|
m.mock.
|
||||||
@ -188,7 +188,7 @@ func (m *MigrateTest) Test_Migrate_Success() {
|
|||||||
func (m *MigrateTest) Test_Rollback_Fail_NilDB() {
|
func (m *MigrateTest) Test_Rollback_Fail_NilDB() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.SetDB(nil)
|
m.Migrate.SetDB(nil)
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
err := m.Migrate.Rollback()
|
err := m.Migrate.Rollback()
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ func (m *MigrateTest) Test_Rollback_Fail_NilDB() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_Rollback_Fail_NoMigrations() {
|
func (m *MigrateTest) Test_Rollback_Fail_NoMigrations() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.first = m.Migration_TestModelFirst()
|
m.Migrate.first = m.MigrationTestModelFirst()
|
||||||
|
|
||||||
err := m.Migrate.Rollback()
|
err := m.Migrate.Rollback()
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ func (m *MigrateTest) Test_Rollback_Fail_NoMigrations() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_Rollback_Fail_NoFirstMigration() {
|
func (m *MigrateTest) Test_Rollback_Fail_NoFirstMigration() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
m.Migrate.first = nil
|
m.Migrate.first = nil
|
||||||
|
|
||||||
err := m.Migrate.Rollback()
|
err := m.Migrate.Rollback()
|
||||||
@ -229,7 +229,7 @@ func (m *MigrateTest) Test_MigrateTo_Fail_NilDB() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_MigrateTo_DoNothing() {
|
func (m *MigrateTest) Test_MigrateTo_DoNothing() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
m.mock.
|
m.mock.
|
||||||
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
||||||
@ -247,7 +247,7 @@ func (m *MigrateTest) Test_MigrateTo_DoNothing() {
|
|||||||
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
|
WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1))
|
||||||
m.mock.ExpectCommit()
|
m.mock.ExpectCommit()
|
||||||
|
|
||||||
err := m.Migrate.MigrateTo(m.Migration_TestModelFirst().ID)
|
err := m.Migrate.MigrateTo(m.MigrationTestModelFirst().ID)
|
||||||
|
|
||||||
assert.NoError(m.T(), err)
|
assert.NoError(m.T(), err)
|
||||||
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
||||||
@ -255,7 +255,7 @@ func (m *MigrateTest) Test_MigrateTo_DoNothing() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_MigrateTo() {
|
func (m *MigrateTest) Test_MigrateTo() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
|
|
||||||
m.mock.
|
m.mock.
|
||||||
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
||||||
@ -280,7 +280,7 @@ func (m *MigrateTest) Test_MigrateTo() {
|
|||||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
m.mock.ExpectCommit()
|
m.mock.ExpectCommit()
|
||||||
|
|
||||||
err := m.Migrate.MigrateTo(m.Migration_TestModelFirst().ID)
|
err := m.Migrate.MigrateTo(m.MigrationTestModelFirst().ID)
|
||||||
|
|
||||||
assert.NoError(m.T(), err)
|
assert.NoError(m.T(), err)
|
||||||
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
||||||
@ -288,13 +288,13 @@ func (m *MigrateTest) Test_MigrateTo() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_RollbackTo() {
|
func (m *MigrateTest) Test_RollbackTo() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
m.Migrate.Add(m.Migration_TestModelSecond())
|
m.Migrate.Add(m.MigrationTestModelSecond())
|
||||||
|
|
||||||
m.mock.ExpectBegin()
|
m.mock.ExpectBegin()
|
||||||
m.mock.ExpectCommit()
|
m.mock.ExpectCommit()
|
||||||
|
|
||||||
err := m.Migrate.RollbackTo(m.Migration_TestModelSecond().ID)
|
err := m.Migrate.RollbackTo(m.MigrationTestModelSecond().ID)
|
||||||
|
|
||||||
assert.NoError(m.T(), err)
|
assert.NoError(m.T(), err)
|
||||||
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
||||||
@ -302,8 +302,8 @@ func (m *MigrateTest) Test_RollbackTo() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_MigrateNextTo() {
|
func (m *MigrateTest) Test_MigrateNextTo() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
m.Migrate.Add(m.Migration_TestModelSecond())
|
m.Migrate.Add(m.MigrationTestModelSecond())
|
||||||
|
|
||||||
m.mock.
|
m.mock.
|
||||||
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
||||||
@ -332,7 +332,7 @@ func (m *MigrateTest) Test_MigrateNextTo() {
|
|||||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
m.mock.ExpectCommit()
|
m.mock.ExpectCommit()
|
||||||
|
|
||||||
err := m.Migrate.MigrateNextTo(m.Migration_TestModelFirst().ID)
|
err := m.Migrate.MigrateNextTo(m.MigrationTestModelFirst().ID)
|
||||||
|
|
||||||
assert.NoError(m.T(), err)
|
assert.NoError(m.T(), err)
|
||||||
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
||||||
@ -340,14 +340,14 @@ func (m *MigrateTest) Test_MigrateNextTo() {
|
|||||||
|
|
||||||
func (m *MigrateTest) Test_MigratePreviousTo() {
|
func (m *MigrateTest) Test_MigratePreviousTo() {
|
||||||
m.RefreshMigrate()
|
m.RefreshMigrate()
|
||||||
m.Migrate.Add(m.Migration_TestModelFirst())
|
m.Migrate.Add(m.MigrationTestModelFirst())
|
||||||
m.Migrate.Add(m.Migration_TestModelSecond())
|
m.Migrate.Add(m.MigrationTestModelSecond())
|
||||||
|
|
||||||
m.mock.
|
m.mock.
|
||||||
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)).
|
||||||
WillReturnResult(sqlmock.NewResult(1, 1))
|
WillReturnResult(sqlmock.NewResult(1, 1))
|
||||||
|
|
||||||
err := m.Migrate.MigratePreviousTo(m.Migration_TestModelSecond().ID)
|
err := m.Migrate.MigratePreviousTo(m.MigrationTestModelSecond().ID)
|
||||||
|
|
||||||
assert.Error(m.T(), err)
|
assert.Error(m.T(), err)
|
||||||
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
assert.NoError(m.T(), m.mock.ExpectationsWereMet())
|
||||||
|
@ -35,6 +35,7 @@ type NewMigrationCommand struct {
|
|||||||
Directory string `short:"d" long:"directory" default:"./migrations" description:"Directory where migration will be created"`
|
Directory string `short:"d" long:"directory" default:"./migrations" description:"Directory where migration will be created"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FileExists returns true if provided file exist and it's not directory
|
||||||
func (x *NewMigrationCommand) FileExists(filename string) bool {
|
func (x *NewMigrationCommand) FileExists(filename string) bool {
|
||||||
info, err := os.Stat(filename)
|
info, err := os.Stat(filename)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
@ -43,6 +44,7 @@ func (x *NewMigrationCommand) FileExists(filename string) bool {
|
|||||||
return !info.IsDir()
|
return !info.IsDir()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute migration generator command
|
||||||
func (x *NewMigrationCommand) Execute(args []string) error {
|
func (x *NewMigrationCommand) Execute(args []string) error {
|
||||||
version := strconv.FormatInt(time.Now().Unix(), 10)
|
version := strconv.FormatInt(time.Now().Unix(), 10)
|
||||||
directory := path.Clean(x.Directory)
|
directory := path.Clean(x.Directory)
|
||||||
|
@ -42,7 +42,7 @@ func (s *MigrationGeneratorSuite) Test_Execute() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, f := range files {
|
for _, f := range files {
|
||||||
if strings.Index(f.Name(), "_app.go") != -1 {
|
if strings.Contains(f.Name(), "_app.go") {
|
||||||
found = true
|
found = true
|
||||||
assert.NoError(s.T(), os.Remove(path.Join(s.command.Directory, f.Name())))
|
assert.NoError(s.T(), os.Remove(path.Join(s.command.Directory, f.Name())))
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import (
|
|||||||
"html/template"
|
"html/template"
|
||||||
|
|
||||||
"github.com/gin-contrib/multitemplate"
|
"github.com/gin-contrib/multitemplate"
|
||||||
"github.com/gobuffalo/packr/v2"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Renderer wraps multitemplate.Renderer in order to make it easier to use
|
// Renderer wraps multitemplate.Renderer in order to make it easier to use
|
||||||
@ -25,7 +24,7 @@ func NewStaticRenderer(funcMap template.FuncMap) Renderer {
|
|||||||
return newRendererWithMultitemplate(funcMap, multitemplate.New())
|
return newRendererWithMultitemplate(funcMap, multitemplate.New())
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewStaticRenderer is a Renderer constructor with multitemplate.DynamicRender
|
// NewDynamicRenderer is a Renderer constructor with multitemplate.DynamicRender
|
||||||
func NewDynamicRenderer(funcMap template.FuncMap) Renderer {
|
func NewDynamicRenderer(funcMap template.FuncMap) Renderer {
|
||||||
return newRendererWithMultitemplate(funcMap, multitemplate.NewDynamic())
|
return newRendererWithMultitemplate(funcMap, multitemplate.NewDynamic())
|
||||||
}
|
}
|
||||||
@ -47,9 +46,9 @@ func (r *Renderer) Push(name string, files ...string) *template.Template {
|
|||||||
|
|
||||||
if r.TemplatesBox == nil {
|
if r.TemplatesBox == nil {
|
||||||
return r.storeTemplate(name, r.AddFromFilesFuncs(name, r.FuncMap, files...))
|
return r.storeTemplate(name, r.AddFromFilesFuncs(name, r.FuncMap, files...))
|
||||||
} else {
|
|
||||||
return r.storeTemplate(name, r.addFromBox(name, r.FuncMap, files...))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return r.storeTemplate(name, r.addFromBox(name, r.FuncMap, files...))
|
||||||
}
|
}
|
||||||
|
|
||||||
// addFromBox adds embedded template
|
// addFromBox adds embedded template
|
||||||
@ -67,7 +66,7 @@ func (r *Renderer) addFromBox(name string, funcMap template.FuncMap, files ...st
|
|||||||
|
|
||||||
// storeTemplate stores built template if multitemplate.DynamicRender is used.
|
// storeTemplate stores built template if multitemplate.DynamicRender is used.
|
||||||
// Dynamic render doesn't store templates - it stores builders, that's why we can't just extract them.
|
// Dynamic render doesn't store templates - it stores builders, that's why we can't just extract them.
|
||||||
// It possibly can cause data inconsistency in developer enviroments where return value from Renderer.Push is used.
|
// It possibly can cause data inconsistency in developer environments where return value from Renderer.Push is used.
|
||||||
func (r *Renderer) storeTemplate(name string, tpl *template.Template) *template.Template {
|
func (r *Renderer) storeTemplate(name string, tpl *template.Template) *template.Template {
|
||||||
if _, ok := r.Renderer.(multitemplate.DynamicRender); ok {
|
if _, ok := r.Renderer.(multitemplate.DynamicRender); ok {
|
||||||
r.alreadyAdded[name] = tpl
|
r.alreadyAdded[name] = tpl
|
||||||
|
@ -23,7 +23,7 @@ type TranslationsExtractor struct {
|
|||||||
TranslationsPath string
|
TranslationsPath string
|
||||||
}
|
}
|
||||||
|
|
||||||
// TranslationsExtractor constructor. Use "translate.{}.yml" as template if your translations are named like "translate.en.yml"
|
// NewTranslationsExtractor constructor. Use "translate.{}.yml" as template if your translations are named like "translate.en.yml"
|
||||||
func NewTranslationsExtractor(fileNameTemplate string) *TranslationsExtractor {
|
func NewTranslationsExtractor(fileNameTemplate string) *TranslationsExtractor {
|
||||||
return &TranslationsExtractor{fileNameTemplate: fileNameTemplate}
|
return &TranslationsExtractor{fileNameTemplate: fileNameTemplate}
|
||||||
}
|
}
|
||||||
@ -43,10 +43,10 @@ func (t *TranslationsExtractor) unmarshalToMap(in []byte) (map[string]interface{
|
|||||||
func (t *TranslationsExtractor) loadYAMLBox(fileName string) (map[string]interface{}, error) {
|
func (t *TranslationsExtractor) loadYAMLBox(fileName string) (map[string]interface{}, error) {
|
||||||
var dataMap map[string]interface{}
|
var dataMap map[string]interface{}
|
||||||
|
|
||||||
if data, err := t.TranslationsBox.Find(fileName); err == nil {
|
if data, err := t.TranslationsBox.Find(fileName); err != nil {
|
||||||
return t.unmarshalToMap(data)
|
|
||||||
} else {
|
|
||||||
return dataMap, err
|
return dataMap, err
|
||||||
|
} else {
|
||||||
|
return t.unmarshalToMap(data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,10 +57,10 @@ func (t *TranslationsExtractor) loadYAMLFile(fileName string) (map[string]interf
|
|||||||
if info, err := os.Stat(fileName); err == nil {
|
if info, err := os.Stat(fileName); err == nil {
|
||||||
if !info.IsDir() {
|
if !info.IsDir() {
|
||||||
if path, err := filepath.Abs(fileName); err == nil {
|
if path, err := filepath.Abs(fileName); err == nil {
|
||||||
if source, err := ioutil.ReadFile(path); err == nil {
|
if source, err := ioutil.ReadFile(path); err != nil {
|
||||||
return t.unmarshalToMap(source)
|
|
||||||
} else {
|
|
||||||
return dataMap, err
|
return dataMap, err
|
||||||
|
} else {
|
||||||
|
return t.unmarshalToMap(source)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return dataMap, err
|
return dataMap, err
|
||||||
@ -106,9 +106,9 @@ func (t *TranslationsExtractor) LoadLocale(locale string) (map[string]interface{
|
|||||||
|
|
||||||
// LoadLocaleKeys returns only sorted keys from translation file
|
// LoadLocaleKeys returns only sorted keys from translation file
|
||||||
func (t *TranslationsExtractor) LoadLocaleKeys(locale string) ([]string, error) {
|
func (t *TranslationsExtractor) LoadLocaleKeys(locale string) ([]string, error) {
|
||||||
if data, err := t.LoadLocale(locale); err == nil {
|
if data, err := t.LoadLocale(locale); err != nil {
|
||||||
return t.GetMapKeys(data), nil
|
|
||||||
} else {
|
|
||||||
return []string{}, err
|
return []string{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return t.GetMapKeys(data), nil
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ func (t *TranslationsExtractorTest) SetupSuite() {
|
|||||||
"another": "second",
|
"another": "second",
|
||||||
}
|
}
|
||||||
data, _ := yaml.Marshal(translation)
|
data, _ := yaml.Marshal(translation)
|
||||||
|
// It's not regular temporary file. Little hack in order to test translations extractor.
|
||||||
|
// nolint:gosec
|
||||||
errWrite := ioutil.WriteFile("/tmp/translate.en.yml", data, os.ModePerm)
|
errWrite := ioutil.WriteFile("/tmp/translate.en.yml", data, os.ModePerm)
|
||||||
require.NoError(t.T(), errWrite)
|
require.NoError(t.T(), errWrite)
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
// nolint:gosec
|
||||||
"crypto/sha1"
|
"crypto/sha1"
|
||||||
"crypto/sha256"
|
"crypto/sha256"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
@ -127,6 +128,7 @@ func (u *Utils) UploadUserAvatar(url string) (picURLs3 string, err error) {
|
|||||||
s := session.Must(session.NewSession(s3Config))
|
s := session.Must(session.NewSession(s3Config))
|
||||||
uploader := s3manager.NewUploader(s)
|
uploader := s3manager.NewUploader(s)
|
||||||
|
|
||||||
|
// nolint:gosec
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@ -181,6 +183,7 @@ func GetMGItemData(client *v1.MgClient, url string, caption string) (v1.Item, in
|
|||||||
func GetEntitySHA1(v interface{}) (hash string, err error) {
|
func GetEntitySHA1(v interface{}) (hash string, err error) {
|
||||||
res, _ := json.Marshal(v)
|
res, _ := json.Marshal(v)
|
||||||
|
|
||||||
|
// nolint:gosec
|
||||||
h := sha1.New()
|
h := sha1.New()
|
||||||
_, err = h.Write(res)
|
_, err = h.Write(res)
|
||||||
hash = fmt.Sprintf("%x", h.Sum(nil))
|
hash = fmt.Sprintf("%x", h.Sum(nil))
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin/binding"
|
"github.com/gin-gonic/gin/binding"
|
||||||
"gopkg.in/go-playground/validator.v8"
|
"gopkg.in/go-playground/validator.v9"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// init here will register `validatecrmurl` function for gin validator
|
||||||
func init() {
|
func init() {
|
||||||
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||||
if err := v.RegisterValidation("validatecrmurl", validateCrmURL); err != nil {
|
if err := v.RegisterValidation("validatecrmurl", validateCrmURL); err != nil {
|
||||||
@ -15,9 +14,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateCrmURL(
|
// validateCrmURL will validate CRM URL
|
||||||
v *validator.Validate, topStruct reflect.Value, currentStructOrField reflect.Value,
|
func validateCrmURL(fl validator.FieldLevel) bool {
|
||||||
field reflect.Value, fieldType reflect.Type, fieldKind reflect.Kind, param string,
|
return regCommandName.Match([]byte(fl.Field().String()))
|
||||||
) bool {
|
|
||||||
return regCommandName.Match([]byte(field.Interface().(string)))
|
|
||||||
}
|
}
|
||||||
|
63
core/validator_test.go
Normal file
63
core/validator_test.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
package core
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin/binding"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"github.com/stretchr/testify/suite"
|
||||||
|
"gopkg.in/go-playground/validator.v9"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ValidatorSuite struct {
|
||||||
|
suite.Suite
|
||||||
|
engine *validator.Validate
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_Validator(t *testing.T) {
|
||||||
|
suite.Run(t, new(ValidatorSuite))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ValidatorSuite) SetupSuite() {
|
||||||
|
if v, ok := binding.Validator.Engine().(*validator.Validate); ok {
|
||||||
|
s.engine = v
|
||||||
|
} else {
|
||||||
|
s.T().Fatal("cannot obtain validation engine")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ValidatorSuite) getError(err error) string {
|
||||||
|
if err == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ValidatorSuite) Test_ValidationInvalidType() {
|
||||||
|
assert.IsType(s.T(), &validator.InvalidValidationError{}, s.engine.Struct(nil))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ValidatorSuite) Test_ValidationFails() {
|
||||||
|
conn := Connection{
|
||||||
|
Key: "key",
|
||||||
|
URL: "url",
|
||||||
|
}
|
||||||
|
err := s.engine.Struct(conn)
|
||||||
|
require.IsType(s.T(), validator.ValidationErrors{}, err)
|
||||||
|
validatorErrors := err.(validator.ValidationErrors)
|
||||||
|
assert.Equal(
|
||||||
|
s.T(),
|
||||||
|
"Key: 'Connection.URL' Error:Field validation for 'URL' failed on the 'validatecrmurl' tag",
|
||||||
|
validatorErrors.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *ValidatorSuite) Test_ValidationSuccess() {
|
||||||
|
conn := Connection{
|
||||||
|
Key: "key",
|
||||||
|
URL: "https://test.retailcrm.pro",
|
||||||
|
}
|
||||||
|
err := s.engine.Struct(conn)
|
||||||
|
assert.NoError(s.T(), err, s.getError(err))
|
||||||
|
}
|
17
go.mod
17
go.mod
@ -9,20 +9,20 @@ require (
|
|||||||
github.com/denisenkom/go-mssqldb v0.0.0-20190830225923-3302f0226fbd // indirect
|
github.com/denisenkom/go-mssqldb v0.0.0-20190830225923-3302f0226fbd // indirect
|
||||||
github.com/getsentry/raven-go v0.2.0
|
github.com/getsentry/raven-go v0.2.0
|
||||||
github.com/gin-contrib/multitemplate v0.0.0-20190914010127-bba2ccfe37ec
|
github.com/gin-contrib/multitemplate v0.0.0-20190914010127-bba2ccfe37ec
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-gonic/gin v1.5.0
|
||||||
github.com/gin-gonic/gin v1.4.0
|
github.com/go-playground/universal-translator v0.17.0 // indirect
|
||||||
github.com/gobuffalo/packd v0.3.0
|
github.com/gobuffalo/packd v0.3.0
|
||||||
github.com/gobuffalo/packr/v2 v2.7.1
|
github.com/gobuffalo/packr/v2 v2.7.1
|
||||||
github.com/golang/protobuf v1.3.2 // indirect
|
|
||||||
github.com/google/go-querystring v1.0.0 // indirect
|
github.com/google/go-querystring v1.0.0 // indirect
|
||||||
github.com/gorilla/securecookie v1.1.1
|
github.com/gorilla/securecookie v1.1.1
|
||||||
github.com/gorilla/sessions v1.2.0
|
github.com/gorilla/sessions v1.2.0
|
||||||
github.com/h2non/gock v1.0.10
|
github.com/h2non/gock v1.0.10
|
||||||
github.com/jessevdk/go-flags v1.4.0
|
github.com/jessevdk/go-flags v1.4.0
|
||||||
github.com/jinzhu/gorm v1.9.11
|
github.com/jinzhu/gorm v1.9.11
|
||||||
github.com/json-iterator/go v1.1.7 // indirect
|
github.com/json-iterator/go v1.1.8 // indirect
|
||||||
|
github.com/leodido/go-urn v1.2.0 // indirect
|
||||||
github.com/lib/pq v1.2.0 // indirect
|
github.com/lib/pq v1.2.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.10 // indirect
|
github.com/mattn/go-isatty v0.0.11 // indirect
|
||||||
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect
|
github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect
|
||||||
github.com/nicksnyder/go-i18n/v2 v2.0.2
|
github.com/nicksnyder/go-i18n/v2 v2.0.2
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
@ -31,12 +31,11 @@ require (
|
|||||||
github.com/retailcrm/mg-transport-api-client-go v1.1.32
|
github.com/retailcrm/mg-transport-api-client-go v1.1.32
|
||||||
github.com/rogpeppe/go-internal v1.5.0 // indirect
|
github.com/rogpeppe/go-internal v1.5.0 // indirect
|
||||||
github.com/stretchr/testify v1.4.0
|
github.com/stretchr/testify v1.4.0
|
||||||
github.com/ugorji/go v1.1.7 // indirect
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550 // indirect
|
||||||
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
|
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 // indirect
|
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 // indirect
|
||||||
golang.org/x/text v0.3.2
|
golang.org/x/text v0.3.2
|
||||||
gopkg.in/go-playground/validator.v8 v8.18.2
|
gopkg.in/go-playground/validator.v9 v9.30.2
|
||||||
gopkg.in/gormigrate.v1 v1.6.0
|
gopkg.in/gormigrate.v1 v1.6.0
|
||||||
gopkg.in/yaml.v2 v2.2.4
|
gopkg.in/yaml.v2 v2.2.7
|
||||||
)
|
)
|
||||||
|
30
go.sum
30
go.sum
@ -48,8 +48,18 @@ github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE
|
|||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
|
github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ=
|
||||||
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM=
|
||||||
|
github.com/gin-gonic/gin v1.5.0 h1:fi+bqFAx/oLK54somfCtEZs9HeH1LHVoEPUgARpTqyc=
|
||||||
|
github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
|
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/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||||
|
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||||
|
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-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||||
|
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
|
||||||
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
@ -114,6 +124,8 @@ github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqx
|
|||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||||
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo=
|
||||||
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
|
github.com/json-iterator/go v1.1.8 h1:QiWkFLKq0T7mpzwOTu6BzNDbfTE8OLrYhVKYMLF46Ok=
|
||||||
|
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
@ -126,14 +138,21 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
|
|||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
|
github.com/leodido/go-urn v1.1.0 h1:Sm1gr51B1kKyfD2BlRcLSiEkffoG96g6TPv6eRoEiB8=
|
||||||
|
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
|
||||||
|
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||||
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0=
|
||||||
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
|
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||||
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
|
||||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||||
|
github.com/mattn/go-isatty v0.0.11 h1:FxPOTFNqGkuDUGi3H/qkUbQO4ZiBa2brKq5r0l8TGeM=
|
||||||
|
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||||
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q=
|
||||||
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||||
@ -259,9 +278,13 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
|
||||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449 h1:gSbV7h1NRL2G1xTg/owz62CST1oJBmxy4QpMMregXVQ=
|
||||||
|
golang.org/x/sys v0.0.0-20191210023423-ac6580df4449/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 h1:z99zHgr7hKfrUcX/KsoJk5FJfjTceCKIp96+biqP4To=
|
||||||
@ -296,8 +319,11 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
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/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.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.29.1 h1:SvGtYmN60a5CVKTOzMSyfzWDeZRxRuGvRQyEAKbw1xc=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.30.2 h1:icxYLlYflpazIV3ufMoNB9h9SYMQ37DZ8CTwkU4pnOs=
|
||||||
|
gopkg.in/go-playground/validator.v9 v9.30.2/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||||
gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI=
|
gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI=
|
||||||
gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw=
|
gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw=
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||||
@ -306,6 +332,8 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
|||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
|
||||||
|
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
Loading…
Reference in New Issue
Block a user