mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #15102 from mjtrangoni/fix-golint-issues
Fix golint issues
This commit is contained in:
commit
416562bd90
@ -35,7 +35,7 @@ func (hs *HTTPServer) initAppPluginRoutes(r *macaron.Macaron) {
|
||||
|
||||
for _, plugin := range plugins.Apps {
|
||||
for _, route := range plugin.Routes {
|
||||
url := util.JoinUrlFragments("/api/plugin-proxy/"+plugin.Id, route.Path)
|
||||
url := util.JoinURLFragments("/api/plugin-proxy/"+plugin.Id, route.Path)
|
||||
handlers := make([]macaron.Handler, 0)
|
||||
handlers = append(handlers, middleware.Auth(&middleware.AuthOptions{
|
||||
ReqSignedIn: true,
|
||||
|
@ -30,7 +30,7 @@ func ReverseProxyGnetReq(proxyPath string) *httputil.ReverseProxy {
|
||||
req.URL.Host = url.Host
|
||||
req.Host = url.Host
|
||||
|
||||
req.URL.Path = util.JoinUrlFragments(url.Path+"/api", proxyPath)
|
||||
req.URL.Path = util.JoinURLFragments(url.Path+"/api", proxyPath)
|
||||
|
||||
// clear cookie headers
|
||||
req.Header.Del("Cookie")
|
||||
|
@ -39,7 +39,7 @@ func ApplyRoute(ctx context.Context, req *http.Request, proxyPath string, route
|
||||
req.URL.Scheme = routeURL.Scheme
|
||||
req.URL.Host = routeURL.Host
|
||||
req.Host = routeURL.Host
|
||||
req.URL.Path = util.JoinUrlFragments(routeURL.Path, proxyPath)
|
||||
req.URL.Path = util.JoinURLFragments(routeURL.Path, proxyPath)
|
||||
|
||||
if err := addHeaders(&req.Header, route, data); err != nil {
|
||||
logger.Error("Failed to render plugin headers", "error", err)
|
||||
|
@ -139,19 +139,19 @@ func (proxy *DataSourceProxy) getDirector() func(req *http.Request) {
|
||||
reqQueryVals := req.URL.Query()
|
||||
|
||||
if proxy.ds.Type == m.DS_INFLUXDB_08 {
|
||||
req.URL.Path = util.JoinUrlFragments(proxy.targetUrl.Path, "db/"+proxy.ds.Database+"/"+proxy.proxyPath)
|
||||
req.URL.Path = util.JoinURLFragments(proxy.targetUrl.Path, "db/"+proxy.ds.Database+"/"+proxy.proxyPath)
|
||||
reqQueryVals.Add("u", proxy.ds.User)
|
||||
reqQueryVals.Add("p", proxy.ds.Password)
|
||||
req.URL.RawQuery = reqQueryVals.Encode()
|
||||
} else if proxy.ds.Type == m.DS_INFLUXDB {
|
||||
req.URL.Path = util.JoinUrlFragments(proxy.targetUrl.Path, proxy.proxyPath)
|
||||
req.URL.Path = util.JoinURLFragments(proxy.targetUrl.Path, proxy.proxyPath)
|
||||
req.URL.RawQuery = reqQueryVals.Encode()
|
||||
if !proxy.ds.BasicAuth {
|
||||
req.Header.Del("Authorization")
|
||||
req.Header.Add("Authorization", util.GetBasicAuthHeader(proxy.ds.User, proxy.ds.Password))
|
||||
}
|
||||
} else {
|
||||
req.URL.Path = util.JoinUrlFragments(proxy.targetUrl.Path, proxy.proxyPath)
|
||||
req.URL.Path = util.JoinURLFragments(proxy.targetUrl.Path, proxy.proxyPath)
|
||||
}
|
||||
if proxy.ds.BasicAuth {
|
||||
req.Header.Del("Authorization")
|
||||
|
@ -46,7 +46,7 @@ func NewApiPluginProxy(ctx *m.ReqContext, proxyPath string, route *plugins.AppPl
|
||||
req.URL.Host = targetURL.Host
|
||||
req.Host = targetURL.Host
|
||||
|
||||
req.URL.Path = util.JoinUrlFragments(targetURL.Path, proxyPath)
|
||||
req.URL.Path = util.JoinURLFragments(targetURL.Path, proxyPath)
|
||||
|
||||
// clear cookie headers
|
||||
req.Header.Del("Cookie")
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
)
|
||||
|
||||
func (hs *HTTPServer) RenderToPng(c *m.ReqContext) {
|
||||
queryReader, err := util.NewUrlQueryReader(c.Req.URL)
|
||||
queryReader, err := util.NewURLQueryReader(c.Req.URL)
|
||||
if err != nil {
|
||||
c.Handle(400, "Render parameters error", err)
|
||||
return
|
||||
|
@ -20,7 +20,7 @@ func TestMiddlewareDashboardRedirect(t *testing.T) {
|
||||
fakeDash.Id = 1
|
||||
fakeDash.FolderId = 1
|
||||
fakeDash.HasAcl = false
|
||||
fakeDash.Uid = util.GenerateShortUid()
|
||||
fakeDash.Uid = util.GenerateShortUID()
|
||||
|
||||
bus.AddHandler("test", func(query *m.GetDashboardQuery) error {
|
||||
query.Result = fakeDash
|
||||
|
@ -45,9 +45,9 @@ func (fp *FrontendPluginBase) setPathsBasedOnApp(app *AppPlugin) {
|
||||
fp.BaseUrl = app.BaseUrl
|
||||
|
||||
if isExternalPlugin(app.PluginDir) {
|
||||
fp.Module = util.JoinUrlFragments("plugins/"+app.Id, appSubPath) + "/module"
|
||||
fp.Module = util.JoinURLFragments("plugins/"+app.Id, appSubPath) + "/module"
|
||||
} else {
|
||||
fp.Module = util.JoinUrlFragments("app/plugins/app/"+app.Id, appSubPath) + "/module"
|
||||
fp.Module = util.JoinURLFragments("app/plugins/app/"+app.Id, appSubPath) + "/module"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,7 +169,7 @@ func (scanner *PluginScanner) walker(currentPath string, f os.FileInfo, err erro
|
||||
}
|
||||
|
||||
if f.Name() == "node_modules" {
|
||||
return util.WalkSkipDir
|
||||
return util.ErrWalkSkipDir
|
||||
}
|
||||
|
||||
if f.IsDir() {
|
||||
|
@ -80,7 +80,7 @@ func (dr *dashboardServiceImpl) buildSaveDashboardCommand(dto *SaveDashboardDTO,
|
||||
return nil, models.ErrDashboardFolderNameExists
|
||||
}
|
||||
|
||||
if !util.IsValidShortUid(dash.Uid) {
|
||||
if !util.IsValidShortUID(dash.Uid) {
|
||||
return nil, models.ErrDashboardInvalidUid
|
||||
} else if len(dash.Uid) > 40 {
|
||||
return nil, models.ErrDashboardUidToLong
|
||||
|
@ -27,7 +27,7 @@ func init() {
|
||||
bus.AddHandler("sql", HasEditPermissionInFolders)
|
||||
}
|
||||
|
||||
var generateNewUid func() string = util.GenerateShortUid
|
||||
var generateNewUid func() string = util.GenerateShortUID
|
||||
|
||||
func SaveDashboard(cmd *m.SaveDashboardCommand) error {
|
||||
return inTransaction(func(sess *DBSession) error {
|
||||
|
@ -106,7 +106,7 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
if timesCalled <= 2 {
|
||||
return savedDash.Uid
|
||||
}
|
||||
return util.GenerateShortUid()
|
||||
return util.GenerateShortUID()
|
||||
}
|
||||
cmd := m.SaveDashboardCommand{
|
||||
OrgId: 1,
|
||||
@ -119,7 +119,7 @@ func TestDashboardDataAccess(t *testing.T) {
|
||||
err := SaveDashboard(&cmd)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
generateNewUid = util.GenerateShortUid
|
||||
generateNewUid = util.GenerateShortUID
|
||||
})
|
||||
|
||||
Convey("Should be able to create dashboard", func() {
|
||||
|
@ -242,7 +242,7 @@ func (ss *SqlStore) buildConnectionString() (string, error) {
|
||||
|
||||
cnnstr += ss.buildExtraConnectionString('&')
|
||||
case migrator.POSTGRES:
|
||||
host, port, err := util.SplitIpPort(ss.dbCfg.Host, "5432")
|
||||
host, port, err := util.SplitIPPort(ss.dbCfg.Host, "5432")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ func generateConnectionString(datasource *models.DataSource) (string, error) {
|
||||
}
|
||||
}
|
||||
|
||||
server, port, err := util.SplitIpPort(datasource.Url, "1433")
|
||||
server, port, err := util.SplitIPPort(datasource.Url, "1433")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// GetRandomString generate random string by specify chars.
|
||||
// source: https://github.com/gogits/gogs/blob/9ee80e3e5426821f03a4e99fad34418f5c736413/modules/base/tool.go#L58
|
||||
func GetRandomString(n int, alphabets ...byte) string {
|
||||
const alphanum = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
|
||||
@ -27,18 +28,21 @@ func GetRandomString(n int, alphabets ...byte) string {
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// EncodePassword encodes a password using PBKDF2.
|
||||
func EncodePassword(password string, salt string) string {
|
||||
newPasswd := PBKDF2([]byte(password), []byte(salt), 10000, 50, sha256.New)
|
||||
return hex.EncodeToString(newPasswd)
|
||||
}
|
||||
|
||||
// Encode string to md5 hex value.
|
||||
// EncodeMd5 encodes a string to md5 hex value.
|
||||
func EncodeMd5(str string) string {
|
||||
m := md5.New()
|
||||
m.Write([]byte(str))
|
||||
return hex.EncodeToString(m.Sum(nil))
|
||||
}
|
||||
|
||||
// PBKDF2 implements Password-Based Key Derivation Function 2), aimed to reduce
|
||||
// the vulnerability of encrypted keys to brute force attacks.
|
||||
// http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
|
||||
func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
|
||||
prf := hmac.New(h, password)
|
||||
@ -77,11 +81,13 @@ func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte
|
||||
return dk[:keyLen]
|
||||
}
|
||||
|
||||
// GetBasicAuthHeader returns a base64 encoded string from user and password.
|
||||
func GetBasicAuthHeader(user string, password string) string {
|
||||
var userAndPass = user + ":" + password
|
||||
return "Basic " + base64.StdEncoding.EncodeToString([]byte(userAndPass))
|
||||
}
|
||||
|
||||
// DecodeBasicAuthHeader decodes user and password from a basic auth header.
|
||||
func DecodeBasicAuthHeader(header string) (string, string, error) {
|
||||
var code string
|
||||
parts := strings.SplitN(header, " ", 2)
|
||||
@ -102,6 +108,7 @@ func DecodeBasicAuthHeader(header string) (string, string, error) {
|
||||
return userAndPass[0], userAndPass[1], nil
|
||||
}
|
||||
|
||||
// RandomHex returns a random string from a n seed.
|
||||
func RandomHex(n int) (string, error) {
|
||||
bytes := make([]byte, n)
|
||||
if _, err := rand.Read(bytes); err != nil {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
|
||||
const saltLength = 8
|
||||
|
||||
// Decrypt decrypts a payload with a given secret.
|
||||
func Decrypt(payload []byte, secret string) ([]byte, error) {
|
||||
salt := payload[:saltLength]
|
||||
key := encryptionKeyToBytes(secret, string(salt))
|
||||
@ -36,6 +37,7 @@ func Decrypt(payload []byte, secret string) ([]byte, error) {
|
||||
return payloadDst, nil
|
||||
}
|
||||
|
||||
// Encrypt encrypts a payload with a given secret.
|
||||
func Encrypt(payload []byte, secret string) ([]byte, error) {
|
||||
salt := GetRandomString(saltLength)
|
||||
|
||||
|
@ -8,8 +8,8 @@ import (
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
//WalkSkipDir is the Error returned when we want to skip descending into a directory
|
||||
var WalkSkipDir = errors.New("skip this directory")
|
||||
//ErrWalkSkipDir is the Error returned when we want to skip descending into a directory
|
||||
var ErrWalkSkipDir = errors.New("skip this directory")
|
||||
|
||||
//WalkFunc is a callback function called for each path as a directory is walked
|
||||
//If resolvedPath != "", then we are following symbolic links.
|
||||
@ -50,7 +50,7 @@ func walk(path string, info os.FileInfo, resolvedPath string, symlinkPathsFollow
|
||||
}
|
||||
err := walkFn(resolvedPath, info, nil)
|
||||
if err != nil {
|
||||
if info.IsDir() && err == WalkSkipDir {
|
||||
if info.IsDir() && err == ErrWalkSkipDir {
|
||||
err = nil
|
||||
}
|
||||
return err
|
||||
|
@ -4,7 +4,8 @@ import (
|
||||
"net"
|
||||
)
|
||||
|
||||
func SplitIpPort(ipStr string, portDefault string) (ip string, port string, err error) {
|
||||
// SplitIPPort splits the ip string and port.
|
||||
func SplitIPPort(ipStr string, portDefault string) (ip string, port string, err error) {
|
||||
ipAddr := net.ParseIP(ipStr)
|
||||
|
||||
if ipAddr == nil {
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestSplitIpPort(t *testing.T) {
|
||||
func TestSplitIPPort(t *testing.T) {
|
||||
|
||||
Convey("When parsing an IPv4 without explicit port", t, func() {
|
||||
ip, port, err := SplitIpPort("1.2.3.4", "5678")
|
||||
ip, port, err := SplitIPPort("1.2.3.4", "5678")
|
||||
|
||||
So(err, ShouldEqual, nil)
|
||||
So(ip, ShouldEqual, "1.2.3.4")
|
||||
@ -17,7 +17,7 @@ func TestSplitIpPort(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("When parsing an IPv6 without explicit port", t, func() {
|
||||
ip, port, err := SplitIpPort("::1", "5678")
|
||||
ip, port, err := SplitIPPort("::1", "5678")
|
||||
|
||||
So(err, ShouldEqual, nil)
|
||||
So(ip, ShouldEqual, "::1")
|
||||
@ -25,7 +25,7 @@ func TestSplitIpPort(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("When parsing an IPv4 with explicit port", t, func() {
|
||||
ip, port, err := SplitIpPort("1.2.3.4:56", "78")
|
||||
ip, port, err := SplitIPPort("1.2.3.4:56", "78")
|
||||
|
||||
So(err, ShouldEqual, nil)
|
||||
So(ip, ShouldEqual, "1.2.3.4")
|
||||
@ -33,7 +33,7 @@ func TestSplitIpPort(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("When parsing an IPv6 with explicit port", t, func() {
|
||||
ip, port, err := SplitIpPort("[::1]:56", "78")
|
||||
ip, port, err := SplitIPPort("[::1]:56", "78")
|
||||
|
||||
So(err, ShouldEqual, nil)
|
||||
So(ip, ShouldEqual, "::1")
|
||||
|
@ -1,3 +1,4 @@
|
||||
package util
|
||||
|
||||
// DynMap defines a dynamic map interface.
|
||||
type DynMap map[string]interface{}
|
||||
|
@ -19,7 +19,7 @@ func Md5Sum(reader io.Reader) (string, error) {
|
||||
return returnMD5String, nil
|
||||
}
|
||||
|
||||
// Md5Sum calculates the md5sum of a string
|
||||
// Md5SumString calculates the md5sum of a string
|
||||
func Md5SumString(input string) (string, error) {
|
||||
buffer := strings.NewReader(input)
|
||||
return Md5Sum(buffer)
|
||||
|
@ -8,19 +8,19 @@ import (
|
||||
|
||||
var allowedChars = shortid.DefaultABC
|
||||
|
||||
var validUidPattern = regexp.MustCompile(`^[a-zA-Z0-9\-\_]*$`).MatchString
|
||||
var validUIDPattern = regexp.MustCompile(`^[a-zA-Z0-9\-\_]*$`).MatchString
|
||||
|
||||
func init() {
|
||||
gen, _ := shortid.New(1, allowedChars, 1)
|
||||
shortid.SetDefault(gen)
|
||||
}
|
||||
|
||||
// IsValidShortUid checks if short unique identifier contains valid characters
|
||||
func IsValidShortUid(uid string) bool {
|
||||
return validUidPattern(uid)
|
||||
// IsValidShortUID checks if short unique identifier contains valid characters
|
||||
func IsValidShortUID(uid string) bool {
|
||||
return validUIDPattern(uid)
|
||||
}
|
||||
|
||||
// GenerateShortUid generates a short unique identifier.
|
||||
func GenerateShortUid() string {
|
||||
// GenerateShortUID generates a short unique identifier.
|
||||
func GenerateShortUID() string {
|
||||
return shortid.MustGenerate()
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import "testing"
|
||||
|
||||
func TestAllowedCharMatchesUidPattern(t *testing.T) {
|
||||
for _, c := range allowedChars {
|
||||
if !IsValidShortUid(string(c)) {
|
||||
if !IsValidShortUID(string(c)) {
|
||||
t.Fatalf("charset for creating new shortids contains chars not present in uid pattern")
|
||||
}
|
||||
}
|
||||
|
@ -7,10 +7,12 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// StringsFallback2 returns the first of two not empty strings.
|
||||
func StringsFallback2(val1 string, val2 string) string {
|
||||
return stringsFallback(val1, val2)
|
||||
}
|
||||
|
||||
// StringsFallback3 returns the first of three not empty strings.
|
||||
func StringsFallback3(val1 string, val2 string, val3 string) string {
|
||||
return stringsFallback(val1, val2, val3)
|
||||
}
|
||||
@ -24,6 +26,7 @@ func stringsFallback(vals ...string) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// SplitString splits a string by commas or empty spaces.
|
||||
func SplitString(str string) []string {
|
||||
if len(str) == 0 {
|
||||
return []string{}
|
||||
@ -32,6 +35,7 @@ func SplitString(str string) []string {
|
||||
return regexp.MustCompile("[, ]+").Split(str, -1)
|
||||
}
|
||||
|
||||
// GetAgeString returns a string representing certain time from years to minutes.
|
||||
func GetAgeString(t time.Time) string {
|
||||
if t.IsZero() {
|
||||
return "?"
|
||||
|
@ -5,22 +5,26 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
type UrlQueryReader struct {
|
||||
// URLQueryReader is a URL query type.
|
||||
type URLQueryReader struct {
|
||||
values url.Values
|
||||
}
|
||||
|
||||
func NewUrlQueryReader(urlInfo *url.URL) (*UrlQueryReader, error) {
|
||||
// NewURLQueryReader parses a raw query and returns it as a URLQueryReader type.
|
||||
func NewURLQueryReader(urlInfo *url.URL) (*URLQueryReader, error) {
|
||||
u, err := url.ParseQuery(urlInfo.RawQuery)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &UrlQueryReader{
|
||||
return &URLQueryReader{
|
||||
values: u,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (r *UrlQueryReader) Get(name string, def string) string {
|
||||
// Get parse parameters from an URL. If the parameter does not exist, it returns
|
||||
// the default value.
|
||||
func (r *URLQueryReader) Get(name string, def string) string {
|
||||
val := r.values[name]
|
||||
if len(val) == 0 {
|
||||
return def
|
||||
@ -29,7 +33,8 @@ func (r *UrlQueryReader) Get(name string, def string) string {
|
||||
return val[0]
|
||||
}
|
||||
|
||||
func JoinUrlFragments(a, b string) string {
|
||||
// JoinURLFragments joins two URL fragments into only one URL string.
|
||||
func JoinURLFragments(a, b string) string {
|
||||
aslash := strings.HasSuffix(a, "/")
|
||||
bslash := strings.HasPrefix(b, "/")
|
||||
|
||||
|
@ -1,60 +1,60 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func TestUrl(t *testing.T) {
|
||||
|
||||
Convey("When joining two urls where right hand side is empty", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080", "")
|
||||
result := JoinURLFragments("http://localhost:8080", "")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080")
|
||||
})
|
||||
|
||||
Convey("When joining two urls where right hand side is empty and lefthand side has a trailing slash", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080/", "")
|
||||
result := JoinURLFragments("http://localhost:8080/", "")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080/")
|
||||
})
|
||||
|
||||
Convey("When joining two urls where neither has a trailing slash", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080", "api")
|
||||
result := JoinURLFragments("http://localhost:8080", "api")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080/api")
|
||||
})
|
||||
|
||||
Convey("When joining two urls where lefthand side has a trailing slash", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080/", "api")
|
||||
result := JoinURLFragments("http://localhost:8080/", "api")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080/api")
|
||||
})
|
||||
|
||||
Convey("When joining two urls where righthand side has preceding slash", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080", "/api")
|
||||
result := JoinURLFragments("http://localhost:8080", "/api")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080/api")
|
||||
})
|
||||
|
||||
Convey("When joining two urls where righthand side has trailing slash", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080", "api/")
|
||||
result := JoinURLFragments("http://localhost:8080", "api/")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080/api/")
|
||||
})
|
||||
|
||||
Convey("When joining two urls where lefthand side has a trailing slash and righthand side has preceding slash", t, func() {
|
||||
result := JoinUrlFragments("http://localhost:8080/", "/api/")
|
||||
result := JoinURLFragments("http://localhost:8080/", "/api/")
|
||||
|
||||
So(result, ShouldEqual, "http://localhost:8080/api/")
|
||||
})
|
||||
}
|
||||
|
||||
func TestNewUrlQueryReader(t *testing.T) {
|
||||
func TestNewURLQueryReader(t *testing.T) {
|
||||
u, _ := url.Parse("http://www.abc.com/foo?bar=baz&bar2=baz2")
|
||||
uqr, _ := NewUrlQueryReader(u)
|
||||
uqr, _ := NewURLQueryReader(u)
|
||||
|
||||
Convey("when trying to retrieve the first query value", t, func() {
|
||||
result := uqr.Get("bar", "foodef")
|
||||
|
@ -13,6 +13,7 @@ var (
|
||||
regexEmail = regexp.MustCompile(emailRegexPattern)
|
||||
)
|
||||
|
||||
// IsEmail checks if a string is a valid email address.
|
||||
func IsEmail(str string) bool {
|
||||
return regexEmail.MatchString(strings.ToLower(str))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user