From a8a2dffc5918b6439e36d9117c96efb4e1d041ca Mon Sep 17 00:00:00 2001 From: chesedo Date: Fri, 6 Jan 2017 10:11:08 +0200 Subject: [PATCH 01/82] Have Required validator trim strings to fix #2361 This will cause the Required validator not to consider fields that has only spaces or new lines to be regarded as valid. This is done by checking if the trimmed version of the string is valid. --- validation/validation_test.go | 6 ++++++ validation/validators.go | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/validation/validation_test.go b/validation/validation_test.go index ec65b6d0..d8e880df 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -35,6 +35,12 @@ func TestRequired(t *testing.T) { if valid.Required("", "string").Ok { t.Error("\"'\" string should be false") } + if valid.Required(" ", "string").Ok { + t.Error("\" \" string should be false") // For #2361 + } + if valid.Required("\n", "string").Ok { + t.Error("new line string should be false") // For #2361 + } if !valid.Required("astaxie", "string").Ok { t.Error("string should be true") } diff --git a/validation/validators.go b/validation/validators.go index 9b04c5ce..78b10373 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -18,6 +18,7 @@ import ( "fmt" "reflect" "regexp" + "strings" "time" "unicode/utf8" ) @@ -98,7 +99,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { } if str, ok := obj.(string); ok { - return len(str) > 0 + return len(strings.TrimSpace(str)) > 0 } if _, ok := obj.(bool); ok { return true From 49fffe3ebe6f54ce848c9ebf502f33f104b34cd8 Mon Sep 17 00:00:00 2001 From: Guohua Ouyang Date: Mon, 27 Feb 2017 14:43:16 +0800 Subject: [PATCH 02/82] Parse form time by its length Fix #2451 Signed-off-by: Guohua Ouyang --- templatefunc.go | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index 01751717..8ecacbfe 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -26,6 +26,12 @@ import ( "time" ) +const ( + formatTime = "15:04:05" + formatDate = "2006-01-02" + formatDateTime = "2006-01-02 15:04:05" +) + // Substr returns the substr from start to length. func Substr(s string, start, length int) string { bt := []rune(s) @@ -352,11 +358,25 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e case reflect.Struct: switch fieldT.Type.String() { case "time.Time": - format := time.RFC3339 - if len(tags) > 1 { - format = tags[1] + var ( + t time.Time + err error + ) + if len(value) >= 19 { + value = value[:19] + t, err = time.ParseInLocation(formatDateTime, value, time.Local) + } else if len(value) >= 10 { + if len(value) > 10 { + value = value[:10] + } + t, err = time.ParseInLocation(formatDate, value, time.Local) + } else if len(value) >= 8 { + if len(value) > 8 { + value = value[:8] + } + t, err = time.ParseInLocation(formatTime, value, time.Local) } - t, err := time.ParseInLocation(format, value, time.Local) + if err != nil { return err } From 8e46decc8ea690797be773b9713a1f024707d305 Mon Sep 17 00:00:00 2001 From: chendingxing Date: Fri, 10 Mar 2017 09:28:25 +0800 Subject: [PATCH 03/82] fix routing bug for splat --- tree.go | 25 +++++++++++++++---------- tree_test.go | 2 +- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/tree.go b/tree.go index 25b78e50..2d6c3fc3 100644 --- a/tree.go +++ b/tree.go @@ -288,10 +288,10 @@ func (t *Tree) Match(pattern string, ctx *context.Context) (runObject interface{ return nil } w := make([]string, 0, 20) - return t.match(pattern, w, ctx) + return t.match(pattern[1:], pattern, w, ctx) } -func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Context) (runObject interface{}) { +func (t *Tree) match(treePattern string, pattern string, wildcardValues []string, ctx *context.Context) (runObject interface{}) { if len(pattern) > 0 { i := 0 for ; i < len(pattern) && pattern[i] == '/'; i++ { @@ -301,13 +301,13 @@ func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Conte // Handle leaf nodes: if len(pattern) == 0 { for _, l := range t.leaves { - if ok := l.match(wildcardValues, ctx); ok { + if ok := l.match(treePattern, wildcardValues, ctx); ok { return l.runObject } } if t.wildcard != nil { for _, l := range t.wildcard.leaves { - if ok := l.match(wildcardValues, ctx); ok { + if ok := l.match(treePattern, wildcardValues, ctx); ok { return l.runObject } } @@ -327,7 +327,12 @@ func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Conte } for _, subTree := range t.fixrouters { if subTree.prefix == seg { - runObject = subTree.match(pattern, wildcardValues, ctx) + if len(pattern) != 0 && pattern[0] == '/' { + treePattern = pattern[1:] + } else { + treePattern = pattern + } + runObject = subTree.match(treePattern, pattern, wildcardValues, ctx) if runObject != nil { break } @@ -339,7 +344,7 @@ func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Conte if strings.HasSuffix(seg, str) { for _, subTree := range t.fixrouters { if subTree.prefix == seg[:len(seg)-len(str)] { - runObject = subTree.match(pattern, wildcardValues, ctx) + runObject = subTree.match(treePattern, pattern, wildcardValues, ctx) if runObject != nil { ctx.Input.SetParam(":ext", str[1:]) } @@ -349,7 +354,7 @@ func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Conte } } if runObject == nil && t.wildcard != nil { - runObject = t.wildcard.match(pattern, append(wildcardValues, seg), ctx) + runObject = t.wildcard.match(treePattern, pattern, append(wildcardValues, seg), ctx) } if runObject == nil && len(t.leaves) > 0 { @@ -368,7 +373,7 @@ func (t *Tree) match(pattern string, wildcardValues []string, ctx *context.Conte wildcardValues = append(wildcardValues, pattern[start:i]) } for _, l := range t.leaves { - if ok := l.match(wildcardValues, ctx); ok { + if ok := l.match(treePattern, wildcardValues, ctx); ok { return l.runObject } } @@ -386,7 +391,7 @@ type leafInfo struct { runObject interface{} } -func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok bool) { +func (leaf *leafInfo) match(treePattern string, wildcardValues []string, ctx *context.Context) (ok bool) { //fmt.Println("Leaf:", wildcardValues, leaf.wildcards, leaf.regexps) if leaf.regexps == nil { if len(wildcardValues) == 0 && len(leaf.wildcards) == 0 { // static path @@ -394,7 +399,7 @@ func (leaf *leafInfo) match(wildcardValues []string, ctx *context.Context) (ok b } // match * if len(leaf.wildcards) == 1 && leaf.wildcards[0] == ":splat" { - ctx.Input.SetParam(":splat", path.Join(wildcardValues...)) + ctx.Input.SetParam(":splat", treePattern) return true } // match *.* or :id diff --git a/tree_test.go b/tree_test.go index 81ff7edd..d412a348 100644 --- a/tree_test.go +++ b/tree_test.go @@ -42,7 +42,7 @@ func init() { routers = append(routers, testinfo{"/", "/", nil}) routers = append(routers, testinfo{"/customer/login", "/customer/login", nil}) routers = append(routers, testinfo{"/customer/login", "/customer/login.json", map[string]string{":ext": "json"}}) - routers = append(routers, testinfo{"/*", "/customer/123", map[string]string{":splat": "customer/123"}}) + routers = append(routers, testinfo{"/*", "/http://customer/123/", map[string]string{":splat": "http://customer/123/"}}) routers = append(routers, testinfo{"/*", "/customer/2009/12/11", map[string]string{":splat": "customer/2009/12/11"}}) routers = append(routers, testinfo{"/aa/*/bb", "/aa/2009/bb", map[string]string{":splat": "2009"}}) routers = append(routers, testinfo{"/cc/*/dd", "/cc/2009/11/dd", map[string]string{":splat": "2009/11"}}) From d41f4c0a3aa9aa6b5c621f2c72532389293ba454 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 12 Mar 2017 19:23:46 +0800 Subject: [PATCH 04/82] validation: fix email valid --- validation/validators.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/validators.go b/validation/validators.go index 9b04c5ce..01aed443 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -518,7 +518,7 @@ func (a AlphaDash) GetLimitValue() interface{} { return nil } -var emailPattern = regexp.MustCompile("[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?") +var emailPattern = regexp.MustCompile("^[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?$") // Email check struct type Email struct { From b34853f8cc29c6734f543669e4914ef12f098c70 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 12 Mar 2017 19:30:23 +0800 Subject: [PATCH 05/82] validattion: add test case for email valid --- validation/validation_test.go | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/validation/validation_test.go b/validation/validation_test.go index ec65b6d0..2b287a1e 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -214,6 +214,12 @@ func TestEmail(t *testing.T) { if !valid.Email("suchuangji@gmail.com", "email").Ok { t.Error("\"suchuangji@gmail.com\" is a valid email address should be true") } + if valid.Email("@suchuangji@gmail.com", "email").Ok { + t.Error("\"@suchuangji@gmail.com\" is a valid email address should be false") + } + if valid.Email("@suchuangji@gmail.com", "email").Ok { + t.Error("\"suchuangji@gmail.com ok\" is a valid email address should be false") + } } func TestIP(t *testing.T) { From c9cc642d37d07f19e1a0f30b175551b3743b08b8 Mon Sep 17 00:00:00 2001 From: miraclesu Date: Sun, 12 Mar 2017 20:27:09 +0800 Subject: [PATCH 06/82] validation: amend email test case --- validation/validation_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/validation/validation_test.go b/validation/validation_test.go index 2b287a1e..83e881bf 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -217,7 +217,7 @@ func TestEmail(t *testing.T) { if valid.Email("@suchuangji@gmail.com", "email").Ok { t.Error("\"@suchuangji@gmail.com\" is a valid email address should be false") } - if valid.Email("@suchuangji@gmail.com", "email").Ok { + if valid.Email("suchuangji@gmail.com ok", "email").Ok { t.Error("\"suchuangji@gmail.com ok\" is a valid email address should be false") } } From 24d4a278427159811fa83ff9fa6de504f01c86a6 Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Mon, 13 Mar 2017 08:46:57 +0200 Subject: [PATCH 07/82] Don't panic during AddViewPath if adding the same path twice --- template.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/template.go b/template.go index 2dba9d1f..0524f3cb 100644 --- a/template.go +++ b/template.go @@ -72,7 +72,7 @@ func ExecuteViewPathTemplate(wr io.Writer, name string, viewPath string, data in } panic("can't find templatefile in the path:" + viewPath + "/" + name) } - panic("Uknown view path:" + viewPath) + panic("Unknown view path:" + viewPath) } func init() { @@ -165,6 +165,9 @@ func AddTemplateExt(ext string) { //will panic if called after beego.Run() func AddViewPath(viewPath string) error { if beeViewPathTemplateLocked { + if _, exist := beeViewPathTemplates[viewPath]; exist { + return nil //Ignore if viewpath already exists + } panic("Can not add new view paths after beego.Run()") } beeViewPathTemplates[viewPath] = make(map[string]*template.Template) From 3e37b97549f2293ede78d12850f38a62b6a6537e Mon Sep 17 00:00:00 2001 From: Sergey Lanzman Date: Tue, 14 Mar 2017 12:55:40 +0200 Subject: [PATCH 08/82] temple parse error write in log as trace. change to error --- template.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/template.go b/template.go index 89d38b80..4e0d6384 100644 --- a/template.go +++ b/template.go @@ -217,7 +217,7 @@ func BuildTemplate(dir string, files ...string) error { t, err = getTemplate(self.root, file, v...) } if err != nil { - logs.Trace("parse template err:", file, err) + logs.Error("parse template err:", file, err) } else { beeTemplates[file] = t } From f5fc2edfd36e8f1aa9a88d1b728a170032343fd3 Mon Sep 17 00:00:00 2001 From: Sergey Lanzman Date: Fri, 17 Mar 2017 19:32:31 +0200 Subject: [PATCH 09/82] add support go1.7/8 to travis yml --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index df3e923f..4c068baf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,8 @@ go: - 1.6 - 1.5.3 - 1.4.3 + - 1.7 + - 1.8 services: - redis-server - mysql From 3204d7631bfce56ad3e3a28c927ab3481f71b699 Mon Sep 17 00:00:00 2001 From: Sergey Lanzman Date: Fri, 17 Mar 2017 19:33:54 +0200 Subject: [PATCH 10/82] drop support go1.4/5 in travis yml --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index df3e923f..37cbe0c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,8 +2,6 @@ language: go go: - 1.6 - - 1.5.3 - - 1.4.3 services: - redis-server - mysql From 856fde28dc37705a4a97593abbb1f12eb37621de Mon Sep 17 00:00:00 2001 From: Sergey Lanzman Date: Fri, 17 Mar 2017 19:45:30 +0200 Subject: [PATCH 11/82] add unconverted support --- .travis.yml | 2 ++ cache/ssdb/ssdb.go | 4 ++-- config.go | 2 +- logs/alils/log.pb.go | 2 +- logs/smtp.go | 2 +- orm/utils.go | 8 ++++---- session/ledis/ledis_session.go | 2 +- templatefunc.go | 30 ++++++++++++------------------ utils/captcha/image.go | 2 +- 9 files changed, 25 insertions(+), 29 deletions(-) diff --git a/.travis.yml b/.travis.yml index df3e923f..fe47739a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ install: - go get github.com/ssdb/gossdb/ssdb - go get github.com/cloudflare/golz4 - go get github.com/gogo/protobuf/proto + - go get -u github.com/mdempsky/unconvert before_script: - psql --version - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -47,5 +48,6 @@ after_script: - rm -rf ./res/var/* script: - go test -v ./... + - unconvert $(go list ./... | grep -v /vendor/) addons: postgresql: "9.4" diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go index bbc43606..479d4d9a 100644 --- a/cache/ssdb/ssdb.go +++ b/cache/ssdb/ssdb.go @@ -53,7 +53,7 @@ func (rc *Cache) GetMulti(keys []string) []interface{} { resSize := len(res) if err == nil { for i := 1; i < resSize; i += 2 { - values = append(values, string(res[i+1])) + values = append(values, res[i+1]) } return values } @@ -175,7 +175,7 @@ func (rc *Cache) ClearAll() error { } keys := []string{} for i := 1; i < size; i += 2 { - keys = append(keys, string(resp[i])) + keys = append(keys, resp[i]) } _, e := rc.conn.Do("multi_del", keys) if e != nil { diff --git a/config.go b/config.go index 3c202e53..e6e99570 100644 --- a/config.go +++ b/config.go @@ -345,7 +345,7 @@ func assignSingleConfig(p interface{}, ac config.Configer) { case reflect.String: pf.SetString(ac.DefaultString(name, pf.String())) case reflect.Int, reflect.Int64: - pf.SetInt(int64(ac.DefaultInt64(name, pf.Int()))) + pf.SetInt(ac.DefaultInt64(name, pf.Int())) case reflect.Bool: pf.SetBool(ac.DefaultBool(name, pf.Bool())) case reflect.Struct: diff --git a/logs/alils/log.pb.go b/logs/alils/log.pb.go index 42f7e892..b60ca200 100755 --- a/logs/alils/log.pb.go +++ b/logs/alils/log.pb.go @@ -395,7 +395,7 @@ func sovLog(x uint64) (n int) { return n } func sozLog(x uint64) (n int) { - return sovLog(uint64((x << 1) ^ uint64((int64(x) >> 63)))) + return sovLog((x << 1) ^ (x >> 63)) } func (m *Log) Unmarshal(data []byte) error { var hasFields [1]uint64 diff --git a/logs/smtp.go b/logs/smtp.go index 834130ef..a07947e6 100644 --- a/logs/smtp.go +++ b/logs/smtp.go @@ -106,7 +106,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd if err != nil { return err } - _, err = w.Write([]byte(msgContent)) + _, err = w.Write(msgContent) if err != nil { return err } diff --git a/orm/utils.go b/orm/utils.go index 6aac8e5d..3cfc1e7d 100644 --- a/orm/utils.go +++ b/orm/utils.go @@ -92,11 +92,11 @@ func (f StrTo) Int64() (int64, error) { i := new(big.Int) ni, ok := i.SetString(f.String(), 10) // octal if !ok { - return int64(v), err + return v, err } return ni.Int64(), nil } - return int64(v), err + return v, err } // Uint string to uint @@ -130,11 +130,11 @@ func (f StrTo) Uint64() (uint64, error) { i := new(big.Int) ni, ok := i.SetString(f.String(), 10) if !ok { - return uint64(v), err + return v, err } return ni.Uint64(), nil } - return uint64(v), err + return v, err } // String string to string diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 68f37b08..1366104e 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -150,7 +150,7 @@ func (lp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) if len(kvs) == 0 { kv = make(map[interface{}]interface{}) } else { - kv, err = session.DecodeGob([]byte(kvs)) + kv, err = session.DecodeGob(kvs) if err != nil { return nil, err } diff --git a/templatefunc.go b/templatefunc.go index 01751717..b54c0b42 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -46,26 +46,25 @@ func Substr(s string, start, length int) string { // HTML2str returns escaping text convert from html. func HTML2str(html string) string { - src := string(html) re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") - src = re.ReplaceAllStringFunc(src, strings.ToLower) + html = re.ReplaceAllStringFunc(html, strings.ToLower) //remove STYLE re, _ = regexp.Compile("\\") - src = re.ReplaceAllString(src, "") + html = re.ReplaceAllString(html, "") //remove SCRIPT re, _ = regexp.Compile("\\") - src = re.ReplaceAllString(src, "") + html = re.ReplaceAllString(html, "") re, _ = regexp.Compile("\\<[\\S\\s]+?\\>") - src = re.ReplaceAllString(src, "\n") + html = re.ReplaceAllString(html, "\n") re, _ = regexp.Compile("\\s{2,}") - src = re.ReplaceAllString(src, "\n") + html = re.ReplaceAllString(html, "\n") - return strings.TrimSpace(src) + return strings.TrimSpace(html) } // DateFormat takes a time and a layout string and returns a string with the formatted date. Used by the template parser as "dateformat" @@ -193,7 +192,7 @@ func Str2html(raw string) template.HTML { } // Htmlquote returns quoted html string. -func Htmlquote(src string) string { +func Htmlquote(text string) string { //HTML编码为实体符号 /* Encodes `text` for raw use in HTML. @@ -201,8 +200,6 @@ func Htmlquote(src string) string { '<'&">' */ - text := string(src) - text = strings.Replace(text, "&", "&", -1) // Must be done first! text = strings.Replace(text, "<", "<", -1) text = strings.Replace(text, ">", ">", -1) @@ -216,7 +213,7 @@ func Htmlquote(src string) string { } // Htmlunquote returns unquoted html string. -func Htmlunquote(src string) string { +func Htmlunquote(text string) string { //实体符号解释为HTML /* Decodes `text` that's HTML quoted. @@ -227,7 +224,6 @@ func Htmlunquote(src string) string { // strings.Replace(s, old, new, n) // 在s字符串中,把old字符串替换为new字符串,n表示替换的次数,小于0表示全部替换 - text := string(src) text = strings.Replace(text, " ", " ", -1) text = strings.Replace(text, "”", "”", -1) text = strings.Replace(text, "“", "“", -1) @@ -262,19 +258,17 @@ func URLFor(endpoint string, values ...interface{}) string { } // AssetsJs returns script tag with src string. -func AssetsJs(src string) template.HTML { - text := string(src) +func AssetsJs(text string) template.HTML { - text = "" + text = "" return template.HTML(text) } // AssetsCSS returns stylesheet link tag with src string. -func AssetsCSS(src string) template.HTML { - text := string(src) +func AssetsCSS(text string) template.HTML { - text = "" + text = "" return template.HTML(text) } diff --git a/utils/captcha/image.go b/utils/captcha/image.go index 0ceb8e42..c3c9a83a 100644 --- a/utils/captcha/image.go +++ b/utils/captcha/image.go @@ -474,7 +474,7 @@ func randomBrightness(c color.RGBA, max uint8) color.RGBA { uint8(int(c.R) + n), uint8(int(c.G) + n), uint8(int(c.B) + n), - uint8(c.A), + c.A, } } From 37c1ffc57a0d46ba32718712bdd27b89c6391e92 Mon Sep 17 00:00:00 2001 From: Sergey Lanzman Date: Fri, 17 Mar 2017 19:24:45 +0200 Subject: [PATCH 12/82] add go simple support --- .gosimpleignore | 4 +++ .travis.yml | 2 ++ admin.go | 22 ++++++++-------- cache/conv_test.go | 6 ++--- cache/memcache/memcache.go | 5 +--- cache/redis/redis.go | 2 +- cache/ssdb/ssdb.go | 15 +++-------- config/ini.go | 7 ++--- config/ini_test.go | 2 +- controller.go | 6 ++--- flash_test.go | 2 +- grace/listener.go | 2 +- httplib/httplib.go | 2 +- logs/file.go | 14 +++++----- logs/jianliao.go | 6 +---- logs/log.go | 8 ++---- logs/slack.go | 6 +---- logs/smtp.go | 13 ++-------- namespace_test.go | 5 +--- orm/cmd.go | 4 +-- orm/cmd_utils.go | 8 +++--- orm/db.go | 28 ++++++++++---------- orm/db_alias.go | 4 +-- orm/db_tables.go | 12 ++++----- orm/models_boot.go | 14 +++++----- orm/models_info_f.go | 6 ++--- orm/models_info_m.go | 2 +- orm/orm.go | 26 +++++-------------- orm/orm_querym2m.go | 10 +++----- orm/orm_test.go | 4 +-- orm/utils.go | 2 +- router_test.go | 40 ++++++++++++++--------------- session/ledis/ledis_session.go | 5 +--- session/memcache/sess_memcache.go | 6 +---- session/mysql/sess_mysql.go | 5 +--- session/postgres/sess_postgresql.go | 6 +---- session/sess_file.go | 5 +--- session/sess_test.go | 2 +- session/ssdb/sess_ssdb.go | 16 +++--------- staticfile.go | 4 +-- template.go | 20 +++++++-------- templatefunc_test.go | 18 ++++++------- validation/validation.go | 2 +- 43 files changed, 150 insertions(+), 228 deletions(-) create mode 100644 .gosimpleignore diff --git a/.gosimpleignore b/.gosimpleignore new file mode 100644 index 00000000..84df9b95 --- /dev/null +++ b/.gosimpleignore @@ -0,0 +1,4 @@ +github.com/astaxie/beego/*/*:S1012 +github.com/astaxie/beego/*:S1012 +github.com/astaxie/beego/*/*:S1007 +github.com/astaxie/beego/*:S1007 \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index df3e923f..abee35f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ install: - go get github.com/ssdb/gossdb/ssdb - go get github.com/cloudflare/golz4 - go get github.com/gogo/protobuf/proto + - go get -u honnef.co/go/tools/cmd/gosimple before_script: - psql --version - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -47,5 +48,6 @@ after_script: - rm -rf ./res/var/* script: - go test -v ./... + - gosimple -ignore "$(cat .gosimpleignore)" $(go list ./... | grep -v /vendor/) addons: postgresql: "9.4" diff --git a/admin.go b/admin.go index a2b2f53a..b4e3068f 100644 --- a/admin.go +++ b/admin.go @@ -157,8 +157,8 @@ func listConf(rw http.ResponseWriter, r *http.Request) { resultList := new([][]string) for _, f := range bf { var result = []string{ - fmt.Sprintf("%s", f.pattern), - fmt.Sprintf("%s", utils.GetFuncName(f.filterFunc)), + f.pattern, + utils.GetFuncName(f.filterFunc), } *resultList = append(*resultList, result) } @@ -213,7 +213,7 @@ func printTree(resultList *[][]string, t *Tree) { var result = []string{ v.pattern, fmt.Sprintf("%s", v.methods), - fmt.Sprintf("%s", v.controllerType), + v.controllerType.String(), } *resultList = append(*resultList, result) } else if v.routerType == routerTypeRESTFul { @@ -287,16 +287,16 @@ func healthcheck(rw http.ResponseWriter, req *http.Request) { for name, h := range toolbox.AdminCheckList { if err := h.Check(); err != nil { result = []string{ - fmt.Sprintf("error"), - fmt.Sprintf("%s", name), - fmt.Sprintf("%s", err.Error()), + "error", + name, + err.Error(), } } else { result = []string{ - fmt.Sprintf("success"), - fmt.Sprintf("%s", name), - fmt.Sprintf("OK"), + "success", + name, + "OK", } } @@ -341,8 +341,8 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { for tname, tk := range toolbox.AdminTaskList { result = []string{ tname, - fmt.Sprintf("%s", tk.GetSpec()), - fmt.Sprintf("%s", tk.GetStatus()), + tk.GetSpec(), + tk.GetStatus(), tk.GetPrev().String(), } *resultList = append(*resultList, result) diff --git a/cache/conv_test.go b/cache/conv_test.go index cf792fa6..b90e224a 100644 --- a/cache/conv_test.go +++ b/cache/conv_test.go @@ -118,14 +118,14 @@ func TestGetFloat64(t *testing.T) { func TestGetBool(t *testing.T) { var t1 = true - if true != GetBool(t1) { + if !GetBool(t1) { t.Error("get bool from bool error") } var t2 = "true" - if true != GetBool(t2) { + if !GetBool(t2) { t.Error("get bool from string error") } - if false != GetBool(nil) { + if GetBool(nil) { t.Error("get bool from nil error") } } diff --git a/cache/memcache/memcache.go b/cache/memcache/memcache.go index 972361f7..0624f5fa 100644 --- a/cache/memcache/memcache.go +++ b/cache/memcache/memcache.go @@ -146,10 +146,7 @@ func (rc *Cache) IsExist(key string) bool { } } _, err := rc.conn.Get(key) - if err != nil { - return false - } - return true + return !(err != nil) } // ClearAll clear all cached in memcache. diff --git a/cache/redis/redis.go b/cache/redis/redis.go index 781e3836..3e71fb53 100644 --- a/cache/redis/redis.go +++ b/cache/redis/redis.go @@ -137,7 +137,7 @@ func (rc *Cache) IsExist(key string) bool { if err != nil { return false } - if v == false { + if !v { if _, err = rc.do("HDEL", rc.key, key); err != nil { return false } diff --git a/cache/ssdb/ssdb.go b/cache/ssdb/ssdb.go index bbc43606..0b59503c 100644 --- a/cache/ssdb/ssdb.go +++ b/cache/ssdb/ssdb.go @@ -71,10 +71,7 @@ func (rc *Cache) DelMulti(keys []string) error { } } _, err := rc.conn.Do("multi_del", keys) - if err != nil { - return err - } - return nil + return err } // Put put value to memcache. only support string. @@ -113,10 +110,7 @@ func (rc *Cache) Delete(key string) error { } } _, err := rc.conn.Del(key) - if err != nil { - return err - } - return nil + return err } // Incr increase counter. @@ -229,10 +223,7 @@ func (rc *Cache) connectInit() error { } var err error rc.conn, err = ssdb.Connect(host, port) - if err != nil { - return err - } - return nil + return err } func init() { diff --git a/config/ini.go b/config/ini.go index 27220f90..42d218d6 100644 --- a/config/ini.go +++ b/config/ini.go @@ -397,11 +397,8 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { } } } - - if _, err = buf.WriteTo(f); err != nil { - return err - } - return nil + _, err = buf.WriteTo(f) + return err } // Set writes a new value for key. diff --git a/config/ini_test.go b/config/ini_test.go index 83ff3668..ffcdb294 100644 --- a/config/ini_test.go +++ b/config/ini_test.go @@ -181,7 +181,7 @@ name=mysql cfgData := string(data) datas := strings.Split(saveResult, "\n") for _, line := range datas { - if strings.Contains(cfgData, line+"\n") == false { + if !strings.Contains(cfgData, line+"\n") { t.Fatalf("different after save ini config file. need contains %q", line) } } diff --git a/controller.go b/controller.go index 488ffcda..c2a327b3 100644 --- a/controller.go +++ b/controller.go @@ -223,7 +223,7 @@ func (c *Controller) RenderBytes() ([]byte, error) { } buf.Reset() - ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath() ,c.Data) + ExecuteViewPathTemplate(&buf, c.Layout, c.viewPath(), c.Data) } return buf.Bytes(), err } @@ -249,7 +249,7 @@ func (c *Controller) renderTemplate() (bytes.Buffer, error) { } } } - BuildTemplate(c.viewPath() , buildFiles...) + BuildTemplate(c.viewPath(), buildFiles...) } return buf, ExecuteViewPathTemplate(&buf, c.TplName, c.viewPath(), c.Data) } @@ -314,7 +314,7 @@ func (c *Controller) ServeJSON(encoding ...bool) { if BConfig.RunMode == PROD { hasIndent = false } - if len(encoding) > 0 && encoding[0] == true { + if len(encoding) > 0 && encoding[0] { hasEncoding = true } c.Ctx.Output.JSON(c.Data["json"], hasIndent, hasEncoding) diff --git a/flash_test.go b/flash_test.go index 640d54de..d5e9608d 100644 --- a/flash_test.go +++ b/flash_test.go @@ -48,7 +48,7 @@ func TestFlashHeader(t *testing.T) { // match for the expected header res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00") // validate the assertion - if res != true { + if !res { t.Errorf("TestFlashHeader() unable to validate flash message") } } diff --git a/grace/listener.go b/grace/listener.go index 5439d0b2..823d3cce 100644 --- a/grace/listener.go +++ b/grace/listener.go @@ -21,7 +21,7 @@ func newGraceListener(l net.Listener, srv *Server) (el *graceListener) { server: srv, } go func() { - _ = <-el.stop + <-el.stop el.stopped = true el.stop <- el.Listener.Close() }() diff --git a/httplib/httplib.go b/httplib/httplib.go index 39480469..32edc5c4 100644 --- a/httplib/httplib.go +++ b/httplib/httplib.go @@ -335,7 +335,7 @@ func (b *BeegoHTTPRequest) JSONBody(obj interface{}) (*BeegoHTTPRequest, error) func (b *BeegoHTTPRequest) buildURL(paramBody string) { // build GET url with query string if b.req.Method == "GET" && len(paramBody) > 0 { - if strings.Index(b.url, "?") != -1 { + if strings.Contains(b.url, "?") { b.url += "&" + paramBody } else { b.url = b.url + "?" + paramBody diff --git a/logs/file.go b/logs/file.go index bd3c22a9..d00cbfc6 100644 --- a/logs/file.go +++ b/logs/file.go @@ -193,16 +193,14 @@ func (w *fileLogWriter) dailyRotate(openTime time.Time) { y, m, d := openTime.Add(24 * time.Hour).Date() nextDay := time.Date(y, m, d, 0, 0, 0, 0, openTime.Location()) tm := time.NewTimer(time.Duration(nextDay.UnixNano() - openTime.UnixNano() + 100)) - select { - case <-tm.C: - w.Lock() - if w.needRotate(0, time.Now().Day()) { - if err := w.doRotate(time.Now()); err != nil { - fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) - } + <-tm.C + w.Lock() + if w.needRotate(0, time.Now().Day()) { + if err := w.doRotate(time.Now()); err != nil { + fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) } - w.Unlock() } + w.Unlock() } func (w *fileLogWriter) lines() (int, error) { diff --git a/logs/jianliao.go b/logs/jianliao.go index 16773c93..16bbdc2e 100644 --- a/logs/jianliao.go +++ b/logs/jianliao.go @@ -25,11 +25,7 @@ func newJLWriter() Logger { // Init JLWriter with json config string func (s *JLWriter) Init(jsonconfig string) error { - err := json.Unmarshal([]byte(jsonconfig), s) - if err != nil { - return err - } - return nil + return json.Unmarshal([]byte(jsonconfig), s) } // WriteMsg write message in smtp writer. diff --git a/logs/log.go b/logs/log.go index c351c473..a5e0a9ea 100644 --- a/logs/log.go +++ b/logs/log.go @@ -275,7 +275,7 @@ func (bl *BeeLogger) writeMsg(logLevel int, msg string, v ...interface{}) error line = 0 } _, filename := path.Split(file) - msg = "[" + filename + ":" + strconv.FormatInt(int64(line), 10) + "] " + msg + msg = "[" + filename + ":" + strconv.Itoa(line) + "] " + msg } //set level info in front of filename info @@ -561,11 +561,7 @@ func SetLogFuncCallDepth(d int) { // SetLogger sets a new logger. func SetLogger(adapter string, config ...string) error { - err := beeLogger.SetLogger(adapter, config...) - if err != nil { - return err - } - return nil + return beeLogger.SetLogger(adapter, config...) } // Emergency logs a message at emergency level. diff --git a/logs/slack.go b/logs/slack.go index 90f009cb..d8482b3e 100644 --- a/logs/slack.go +++ b/logs/slack.go @@ -21,11 +21,7 @@ func newSLACKWriter() Logger { // Init SLACKWriter with json config string func (s *SLACKWriter) Init(jsonconfig string) error { - err := json.Unmarshal([]byte(jsonconfig), s) - if err != nil { - return err - } - return nil + return json.Unmarshal([]byte(jsonconfig), s) } // WriteMsg write message in smtp writer. diff --git a/logs/smtp.go b/logs/smtp.go index 834130ef..bf603f2b 100644 --- a/logs/smtp.go +++ b/logs/smtp.go @@ -52,11 +52,7 @@ func newSMTPWriter() Logger { // "level":LevelError // } func (s *SMTPWriter) Init(jsonconfig string) error { - err := json.Unmarshal([]byte(jsonconfig), s) - if err != nil { - return err - } - return nil + return json.Unmarshal([]byte(jsonconfig), s) } func (s *SMTPWriter) getSMTPAuth(host string) smtp.Auth { @@ -116,12 +112,7 @@ func (s *SMTPWriter) sendMail(hostAddressWithPort string, auth smtp.Auth, fromAd return err } - err = client.Quit() - if err != nil { - return err - } - - return nil + return client.Quit() } // WriteMsg write message in smtp writer. diff --git a/namespace_test.go b/namespace_test.go index fc02b5fb..b3f20dff 100644 --- a/namespace_test.go +++ b/namespace_test.go @@ -139,10 +139,7 @@ func TestNamespaceCond(t *testing.T) { ns := NewNamespace("/v2") ns.Cond(func(ctx *context.Context) bool { - if ctx.Input.Domain() == "beego.me" { - return true - } - return false + return ctx.Input.Domain() == "beego.me" }). AutoRouter(&TestController{}) AddNamespace(ns) diff --git a/orm/cmd.go b/orm/cmd.go index 3638a75c..0ff4dc40 100644 --- a/orm/cmd.go +++ b/orm/cmd.go @@ -150,7 +150,7 @@ func (d *commandSyncDb) Run() error { } for _, fi := range mi.fields.fieldsDB { - if _, ok := columns[fi.column]; ok == false { + if _, ok := columns[fi.column]; !ok { fields = append(fields, fi) } } @@ -175,7 +175,7 @@ func (d *commandSyncDb) Run() error { } for _, idx := range indexes[mi.table] { - if d.al.DbBaser.IndexExists(db, idx.Table, idx.Name) == false { + if !d.al.DbBaser.IndexExists(db, idx.Table, idx.Name) { if !d.noInfo { fmt.Printf("create index `%s` for table `%s`\n", idx.Name, idx.Table) } diff --git a/orm/cmd_utils.go b/orm/cmd_utils.go index 8119b70b..de47cb02 100644 --- a/orm/cmd_utils.go +++ b/orm/cmd_utils.go @@ -89,7 +89,7 @@ checkColumn: col = T["float64"] case TypeDecimalField: s := T["float64-decimal"] - if strings.Index(s, "%d") == -1 { + if !strings.Contains(s, "%d") { col = s } else { col = fmt.Sprintf(s, fi.digits, fi.decimals) @@ -120,7 +120,7 @@ func getColumnAddQuery(al *alias, fi *fieldInfo) string { Q := al.DbBaser.TableQuote() typ := getColumnTyp(al, fi) - if fi.null == false { + if !fi.null { typ += " " + "NOT NULL" } @@ -172,7 +172,7 @@ func getDbCreateSQL(al *alias) (sqls []string, tableIndexes map[string][]dbIndex } else { column += col - if fi.null == false { + if !fi.null { column += " " + "NOT NULL" } @@ -192,7 +192,7 @@ func getDbCreateSQL(al *alias) (sqls []string, tableIndexes map[string][]dbIndex } } - if strings.Index(column, "%COL%") != -1 { + if strings.Contains(column, "%COL%") { column = strings.Replace(column, "%COL%", fi.column, -1) } diff --git a/orm/db.go b/orm/db.go index bca6071d..1544c479 100644 --- a/orm/db.go +++ b/orm/db.go @@ -48,7 +48,7 @@ var ( "lte": true, "eq": true, "nq": true, - "ne": true, + "ne": true, "startswith": true, "endswith": true, "istartswith": true, @@ -87,7 +87,7 @@ func (d *dbBase) collectValues(mi *modelInfo, ind reflect.Value, cols []string, } else { panic(fmt.Errorf("wrong db field/column name `%s` for model `%s`", column, mi.fullName)) } - if fi.dbcol == false || fi.auto && skipAuto { + if !fi.dbcol || fi.auto && skipAuto { continue } value, err := d.collectFieldValue(mi, fi, ind, insert, tz) @@ -224,7 +224,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val value = nil } } - if fi.null == false && value == nil { + if !fi.null && value == nil { return nil, fmt.Errorf("field `%s` cannot be NULL", fi.fullName) } } @@ -271,7 +271,7 @@ func (d *dbBase) PrepareInsert(q dbQuerier, mi *modelInfo) (stmtQuerier, string, dbcols := make([]string, 0, len(mi.fields.dbcols)) marks := make([]string, 0, len(mi.fields.dbcols)) for _, fi := range mi.fields.fieldsDB { - if fi.auto == false { + if !fi.auto { dbcols = append(dbcols, fi.column) marks = append(marks, "?") } @@ -326,7 +326,7 @@ func (d *dbBase) Read(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Lo } else { // default use pk value as where condtion. pkColumn, pkValue, ok := getExistPk(mi, ind) - if ok == false { + if !ok { return ErrMissPK } whereCols = []string{pkColumn} @@ -601,7 +601,7 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a // execute update sql dbQuerier with given struct reflect.Value. func (d *dbBase) Update(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location, cols []string) (int64, error) { pkName, pkValue, ok := getExistPk(mi, ind) - if ok == false { + if !ok { return 0, ErrMissPK } @@ -654,7 +654,7 @@ func (d *dbBase) Delete(q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time. } else { // default use pk value as where condtion. pkColumn, pkValue, ok := getExistPk(mi, ind) - if ok == false { + if !ok { return 0, ErrMissPK } whereCols = []string{pkColumn} @@ -699,7 +699,7 @@ func (d *dbBase) UpdateBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con columns := make([]string, 0, len(params)) values := make([]interface{}, 0, len(params)) for col, val := range params { - if fi, ok := mi.fields.GetByAny(col); ok == false || fi.dbcol == false { + if fi, ok := mi.fields.GetByAny(col); !ok || !fi.dbcol { panic(fmt.Errorf("wrong field/column name `%s`", col)) } else { columns = append(columns, fi.column) @@ -929,7 +929,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi if hasRel { for _, fi := range mi.fields.fieldsDB { if fi.fieldType&IsRelField > 0 { - if maps[fi.column] == false { + if !maps[fi.column] { tCols = append(tCols, fi.column) } } @@ -987,7 +987,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi var cnt int64 for rs.Next() { - if one && cnt == 0 || one == false { + if one && cnt == 0 || !one { if err := rs.Scan(refs...); err != nil { return 0, err } @@ -1067,7 +1067,7 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi cnt++ } - if one == false { + if !one { if cnt > 0 { ind.Set(slice) } else { @@ -1357,7 +1357,7 @@ end: func (d *dbBase) setFieldValue(fi *fieldInfo, value interface{}, field reflect.Value) (interface{}, error) { fieldType := fi.fieldType - isNative := fi.isFielder == false + isNative := !fi.isFielder setValue: switch { @@ -1533,7 +1533,7 @@ setValue: } } - if isNative == false { + if !isNative { fd := field.Addr().Interface().(Fielder) err := fd.SetRaw(value) if err != nil { @@ -1594,7 +1594,7 @@ func (d *dbBase) ReadValues(q dbQuerier, qs *querySet, mi *modelInfo, cond *Cond infos = make([]*fieldInfo, 0, len(exprs)) for _, ex := range exprs { index, name, fi, suc := tables.parseExprs(mi, strings.Split(ex, ExprSep)) - if suc == false { + if !suc { panic(fmt.Errorf("unknown field/column name `%s`", ex)) } cols = append(cols, fmt.Sprintf("%s.%s%s%s %s%s%s", index, Q, fi.column, Q, Q, name, Q)) diff --git a/orm/db_alias.go b/orm/db_alias.go index c95d49c9..8daa4b23 100644 --- a/orm/db_alias.go +++ b/orm/db_alias.go @@ -186,7 +186,7 @@ func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) { return nil, fmt.Errorf("register db Ping `%s`, %s", aliasName, err.Error()) } - if dataBaseCache.add(aliasName, al) == false { + if !dataBaseCache.add(aliasName, al) { return nil, fmt.Errorf("DataBase alias name `%s` already registered, cannot reuse", aliasName) } @@ -244,7 +244,7 @@ end: // RegisterDriver Register a database driver use specify driver name, this can be definition the driver is which database type. func RegisterDriver(driverName string, typ DriverType) error { - if t, ok := drivers[driverName]; ok == false { + if t, ok := drivers[driverName]; !ok { drivers[driverName] = typ } else { if t != typ { diff --git a/orm/db_tables.go b/orm/db_tables.go index e4c74ace..42be5550 100644 --- a/orm/db_tables.go +++ b/orm/db_tables.go @@ -63,7 +63,7 @@ func (t *dbTables) set(names []string, mi *modelInfo, fi *fieldInfo, inner bool) // add table info to collection. func (t *dbTables) add(names []string, mi *modelInfo, fi *fieldInfo, inner bool) (*dbTable, bool) { name := strings.Join(names, ExprSep) - if _, ok := t.tablesM[name]; ok == false { + if _, ok := t.tablesM[name]; !ok { i := len(t.tables) + 1 jt := &dbTable{i, fmt.Sprintf("T%d", i), name, names, false, inner, mi, fi, nil} t.tablesM[name] = jt @@ -261,7 +261,7 @@ loopFor: fiN, okN = mmi.fields.GetByAny(exprs[i+1]) } - if isRel && (fi.mi.isThrough == false || num != i) { + if isRel && (!fi.mi.isThrough || num != i) { if fi.null || t.skipEnd { inner = false } @@ -364,7 +364,7 @@ func (t *dbTables) getCondSQL(cond *Condition, sub bool, tz *time.Location) (whe } index, _, fi, suc := t.parseExprs(mi, exprs) - if suc == false { + if !suc { panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(p.exprs, ExprSep))) } @@ -383,7 +383,7 @@ func (t *dbTables) getCondSQL(cond *Condition, sub bool, tz *time.Location) (whe } } - if sub == false && where != "" { + if !sub && where != "" { where = "WHERE " + where } @@ -403,7 +403,7 @@ func (t *dbTables) getGroupSQL(groups []string) (groupSQL string) { exprs := strings.Split(group, ExprSep) index, _, fi, suc := t.parseExprs(t.mi, exprs) - if suc == false { + if !suc { panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep))) } @@ -432,7 +432,7 @@ func (t *dbTables) getOrderSQL(orders []string) (orderSQL string) { exprs := strings.Split(order, ExprSep) index, _, fi, suc := t.parseExprs(t.mi, exprs) - if suc == false { + if !suc { panic(fmt.Errorf("unknown field/column name `%s`", strings.Join(exprs, ExprSep))) } diff --git a/orm/models_boot.go b/orm/models_boot.go index 4ba5affd..85d0917f 100644 --- a/orm/models_boot.go +++ b/orm/models_boot.go @@ -128,7 +128,7 @@ func bootStrap() { if i := strings.LastIndex(fi.relThrough, "."); i != -1 && len(fi.relThrough) > (i+1) { pn := fi.relThrough[:i] rmi, ok := modelCache.getByFullName(fi.relThrough) - if ok == false || pn != rmi.pkg { + if !ok || pn != rmi.pkg { err = fmt.Errorf("field `%s` wrong rel_through value `%s` cannot find table", fi.fullName, fi.relThrough) goto end } @@ -171,7 +171,7 @@ func bootStrap() { break } } - if inModel == false { + if !inModel { rmi := fi.relModelInfo ffi := new(fieldInfo) ffi.name = mi.name @@ -185,7 +185,7 @@ func bootStrap() { } else { ffi.fieldType = RelReverseMany } - if rmi.fields.Add(ffi) == false { + if !rmi.fields.Add(ffi) { added := false for cnt := 0; cnt < 5; cnt++ { ffi.name = fmt.Sprintf("%s%d", mi.name, cnt) @@ -195,7 +195,7 @@ func bootStrap() { break } } - if added == false { + if !added { panic(fmt.Errorf("cannot generate auto reverse field info `%s` to `%s`", fi.fullName, ffi.fullName)) } } @@ -248,7 +248,7 @@ func bootStrap() { break mForA } } - if found == false { + if !found { err = fmt.Errorf("reverse field `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName) goto end } @@ -267,7 +267,7 @@ func bootStrap() { break mForB } } - if found == false { + if !found { mForC: for _, ffi := range fi.relModelInfo.fields.fieldsByType[RelManyToMany] { conditions := fi.relThrough != "" && fi.relThrough == ffi.relThrough || @@ -287,7 +287,7 @@ func bootStrap() { } } } - if found == false { + if !found { err = fmt.Errorf("reverse field for `%s` not found in model `%s`", fi.fullName, fi.relModelInfo.fullName) goto end } diff --git a/orm/models_info_f.go b/orm/models_info_f.go index 4b3d3e27..bbb7d71f 100644 --- a/orm/models_info_f.go +++ b/orm/models_info_f.go @@ -47,7 +47,7 @@ func (f *fields) Add(fi *fieldInfo) (added bool) { } else { return } - if _, ok := f.fieldsByType[fi.fieldType]; ok == false { + if _, ok := f.fieldsByType[fi.fieldType]; !ok { f.fieldsByType[fi.fieldType] = make([]*fieldInfo, 0) } f.fieldsByType[fi.fieldType] = append(f.fieldsByType[fi.fieldType], fi) @@ -334,12 +334,12 @@ checkType: switch onDelete { case odCascade, odDoNothing: case odSetDefault: - if initial.Exist() == false { + if !initial.Exist() { err = errors.New("on_delete: set_default need set field a default value") goto end } case odSetNULL: - if fi.null == false { + if !fi.null { err = errors.New("on_delete: set_null need set field null") goto end } diff --git a/orm/models_info_m.go b/orm/models_info_m.go index d6ba1dca..4a3a37f9 100644 --- a/orm/models_info_m.go +++ b/orm/models_info_m.go @@ -78,7 +78,7 @@ func addModelFields(mi *modelInfo, ind reflect.Value, mName string, index []int) fi.fieldIndex = append(index, i) fi.mi = mi fi.inModel = true - if mi.fields.Add(fi) == false { + if !mi.fields.Add(fi) { err = fmt.Errorf("duplicate column name: %s", fi.column) break } diff --git a/orm/orm.go b/orm/orm.go index d9d1cd77..d364e621 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -122,21 +122,13 @@ func (o *orm) getFieldInfo(mi *modelInfo, name string) *fieldInfo { // read data to model func (o *orm) Read(md interface{}, cols ...string) error { mi, ind := o.getMiInd(md, true) - err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, false) - if err != nil { - return err - } - return nil + return o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, false) } // read data to model, like Read(), but use "SELECT FOR UPDATE" form func (o *orm) ReadForUpdate(md interface{}, cols ...string) error { mi, ind := o.getMiInd(md, true) - err := o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, true) - if err != nil { - return err - } - return nil + return o.alias.DbBaser.Read(o.db, mi, ind, o.alias.TZ, cols, true) } // Try to read a row from the database, or insert one if it doesn't exist @@ -238,15 +230,11 @@ func (o *orm) InsertOrUpdate(md interface{}, colConflitAndArgs ...string) (int64 // cols set the columns those want to update. func (o *orm) Update(md interface{}, cols ...string) (int64, error) { mi, ind := o.getMiInd(md, true) - num, err := o.alias.DbBaser.Update(o.db, mi, ind, o.alias.TZ, cols) - if err != nil { - return num, err - } - return num, nil + return o.alias.DbBaser.Update(o.db, mi, ind, o.alias.TZ, cols) } // delete model in database -// cols shows the delete conditions values read from. deafult is pk +// cols shows the delete conditions values read from. default is pk func (o *orm) Delete(md interface{}, cols ...string) (int64, error) { mi, ind := o.getMiInd(md, true) num, err := o.alias.DbBaser.Delete(o.db, mi, ind, o.alias.TZ, cols) @@ -361,7 +349,7 @@ func (o *orm) queryRelated(md interface{}, name string) (*modelInfo, *fieldInfo, fi := o.getFieldInfo(mi, name) _, _, exist := getExistPk(mi, ind) - if exist == false { + if !exist { panic(ErrMissPK) } @@ -489,7 +477,7 @@ func (o *orm) Begin() error { // commit transaction func (o *orm) Commit() error { - if o.isTx == false { + if !o.isTx { return ErrTxDone } err := o.db.(txEnder).Commit() @@ -504,7 +492,7 @@ func (o *orm) Commit() error { // rollback transaction func (o *orm) Rollback() error { - if o.isTx == false { + if !o.isTx { return ErrTxDone } err := o.db.(txEnder).Rollback() diff --git a/orm/orm_querym2m.go b/orm/orm_querym2m.go index b220bda6..6a270a0d 100644 --- a/orm/orm_querym2m.go +++ b/orm/orm_querym2m.go @@ -72,7 +72,7 @@ func (o *queryM2M) Add(mds ...interface{}) (int64, error) { } _, v1, exist := getExistPk(o.mi, o.ind) - if exist == false { + if !exist { panic(ErrMissPK) } @@ -87,7 +87,7 @@ func (o *queryM2M) Add(mds ...interface{}) (int64, error) { v2 = ind.Interface() } else { _, v2, exist = getExistPk(fi.relModelInfo, ind) - if exist == false { + if !exist { panic(ErrMissPK) } } @@ -104,11 +104,7 @@ func (o *queryM2M) Remove(mds ...interface{}) (int64, error) { fi := o.fi qs := o.qs.Filter(fi.reverseFieldInfo.name, o.md) - nums, err := qs.Filter(fi.reverseFieldInfoTwo.name+ExprSep+"in", mds).Delete() - if err != nil { - return nums, err - } - return nums, nil + return qs.Filter(fi.reverseFieldInfoTwo.name+ExprSep+"in", mds).Delete() } // check model is existed in relationship of origin model diff --git a/orm/orm_test.go b/orm/orm_test.go index 8738952b..a8b4fe69 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -93,14 +93,14 @@ wrongArg: } func AssertIs(a interface{}, args ...interface{}) error { - if ok, err := ValuesCompare(true, a, args...); ok == false { + if ok, err := ValuesCompare(true, a, args...); !ok { return err } return nil } func AssertNot(a interface{}, args ...interface{}) error { - if ok, err := ValuesCompare(false, a, args...); ok == false { + if ok, err := ValuesCompare(false, a, args...); !ok { return err } return nil diff --git a/orm/utils.go b/orm/utils.go index 6aac8e5d..7340715d 100644 --- a/orm/utils.go +++ b/orm/utils.go @@ -225,7 +225,7 @@ func camelString(s string) string { if d == '_' { flag = true continue - } else if flag == true { + } else if flag { if d >= 'a' && d <= 'z' { d = d - 32 } diff --git a/router_test.go b/router_test.go index 936fd5e8..25804d67 100644 --- a/router_test.go +++ b/router_test.go @@ -502,10 +502,10 @@ func TestFilterBeforeRouter(t *testing.T) { rw, r := testRequest("GET", url) mux.ServeHTTP(rw, r) - if strings.Contains(rw.Body.String(), "BeforeRouter1") == false { + if !strings.Contains(rw.Body.String(), "BeforeRouter1") { t.Errorf(testName + " BeforeRouter did not run") } - if strings.Contains(rw.Body.String(), "hello") == true { + if strings.Contains(rw.Body.String(), "hello") { t.Errorf(testName + " BeforeRouter did not return properly") } } @@ -525,13 +525,13 @@ func TestFilterBeforeExec(t *testing.T) { rw, r := testRequest("GET", url) mux.ServeHTTP(rw, r) - if strings.Contains(rw.Body.String(), "BeforeExec1") == false { + if !strings.Contains(rw.Body.String(), "BeforeExec1") { t.Errorf(testName + " BeforeExec did not run") } - if strings.Contains(rw.Body.String(), "hello") == true { + if strings.Contains(rw.Body.String(), "hello") { t.Errorf(testName + " BeforeExec did not return properly") } - if strings.Contains(rw.Body.String(), "BeforeRouter") == true { + if strings.Contains(rw.Body.String(), "BeforeRouter") { t.Errorf(testName + " BeforeRouter ran in error") } } @@ -552,16 +552,16 @@ func TestFilterAfterExec(t *testing.T) { rw, r := testRequest("GET", url) mux.ServeHTTP(rw, r) - if strings.Contains(rw.Body.String(), "AfterExec1") == false { + if !strings.Contains(rw.Body.String(), "AfterExec1") { t.Errorf(testName + " AfterExec did not run") } - if strings.Contains(rw.Body.String(), "hello") == false { + if !strings.Contains(rw.Body.String(), "hello") { t.Errorf(testName + " handler did not run properly") } - if strings.Contains(rw.Body.String(), "BeforeRouter") == true { + if strings.Contains(rw.Body.String(), "BeforeRouter") { t.Errorf(testName + " BeforeRouter ran in error") } - if strings.Contains(rw.Body.String(), "BeforeExec") == true { + if strings.Contains(rw.Body.String(), "BeforeExec") { t.Errorf(testName + " BeforeExec ran in error") } } @@ -583,19 +583,19 @@ func TestFilterFinishRouter(t *testing.T) { rw, r := testRequest("GET", url) mux.ServeHTTP(rw, r) - if strings.Contains(rw.Body.String(), "FinishRouter1") == true { + if strings.Contains(rw.Body.String(), "FinishRouter1") { t.Errorf(testName + " FinishRouter did not run") } - if strings.Contains(rw.Body.String(), "hello") == false { + if !strings.Contains(rw.Body.String(), "hello") { t.Errorf(testName + " handler did not run properly") } - if strings.Contains(rw.Body.String(), "AfterExec1") == true { + if strings.Contains(rw.Body.String(), "AfterExec1") { t.Errorf(testName + " AfterExec ran in error") } - if strings.Contains(rw.Body.String(), "BeforeRouter") == true { + if strings.Contains(rw.Body.String(), "BeforeRouter") { t.Errorf(testName + " BeforeRouter ran in error") } - if strings.Contains(rw.Body.String(), "BeforeExec") == true { + if strings.Contains(rw.Body.String(), "BeforeExec") { t.Errorf(testName + " BeforeExec ran in error") } } @@ -615,14 +615,14 @@ func TestFilterFinishRouterMultiFirstOnly(t *testing.T) { rw, r := testRequest("GET", url) mux.ServeHTTP(rw, r) - if strings.Contains(rw.Body.String(), "FinishRouter1") == false { + if !strings.Contains(rw.Body.String(), "FinishRouter1") { t.Errorf(testName + " FinishRouter1 did not run") } - if strings.Contains(rw.Body.String(), "hello") == false { + if !strings.Contains(rw.Body.String(), "hello") { t.Errorf(testName + " handler did not run properly") } // not expected in body - if strings.Contains(rw.Body.String(), "FinishRouter2") == true { + if strings.Contains(rw.Body.String(), "FinishRouter2") { t.Errorf(testName + " FinishRouter2 did run") } } @@ -642,13 +642,13 @@ func TestFilterFinishRouterMulti(t *testing.T) { rw, r := testRequest("GET", url) mux.ServeHTTP(rw, r) - if strings.Contains(rw.Body.String(), "FinishRouter1") == false { + if !strings.Contains(rw.Body.String(), "FinishRouter1") { t.Errorf(testName + " FinishRouter1 did not run") } - if strings.Contains(rw.Body.String(), "hello") == false { + if !strings.Contains(rw.Body.String(), "hello") { t.Errorf(testName + " handler did not run properly") } - if strings.Contains(rw.Body.String(), "FinishRouter2") == false { + if !strings.Contains(rw.Body.String(), "FinishRouter2") { t.Errorf(testName + " FinishRouter2 did not run properly") } } diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 68f37b08..7dcc080d 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -125,10 +125,7 @@ func (lp *Provider) SessionRead(sid string) (session.Store, error) { // SessionExist check ledis session exist by sid func (lp *Provider) SessionExist(sid string) bool { count, _ := c.Exists([]byte(sid)) - if count == 0 { - return false - } - return true + return !(count == 0) } // SessionRegenerate generate new sid for ledis session diff --git a/session/memcache/sess_memcache.go b/session/memcache/sess_memcache.go index f1069bc9..cad02258 100644 --- a/session/memcache/sess_memcache.go +++ b/session/memcache/sess_memcache.go @@ -205,11 +205,7 @@ func (rp *MemProvider) SessionDestroy(sid string) error { } } - err := client.Delete(sid) - if err != nil { - return err - } - return nil + return client.Delete(sid) } func (rp *MemProvider) connectInit() error { diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index 7683ee1f..37c45283 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -171,10 +171,7 @@ func (mp *Provider) SessionExist(sid string) bool { row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid) var sessiondata []byte err := row.Scan(&sessiondata) - if err == sql.ErrNoRows { - return false - } - return true + return !(err == sql.ErrNoRows) } // SessionRegenerate generate new sid for mysql session diff --git a/session/postgres/sess_postgresql.go b/session/postgres/sess_postgresql.go index 73f9c13a..f00e0711 100644 --- a/session/postgres/sess_postgresql.go +++ b/session/postgres/sess_postgresql.go @@ -184,11 +184,7 @@ func (mp *Provider) SessionExist(sid string) bool { row := c.QueryRow("select session_data from session where session_key=$1", sid) var sessiondata []byte err := row.Scan(&sessiondata) - - if err == sql.ErrNoRows { - return false - } - return true + return !(err == sql.ErrNoRows) } // SessionRegenerate generate new sid for postgresql session diff --git a/session/sess_file.go b/session/sess_file.go index 50687c9e..12cf1f3f 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -163,10 +163,7 @@ func (fp *FileProvider) SessionExist(sid string) bool { defer filepder.lock.Unlock() _, err := os.Stat(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) - if err == nil { - return true - } - return false + return err == nil } // SessionDestroy Remove all files in this save path diff --git a/session/sess_test.go b/session/sess_test.go index b40865f3..60b47dd4 100644 --- a/session/sess_test.go +++ b/session/sess_test.go @@ -115,7 +115,7 @@ func TestParseConfig(t *testing.T) { if cf2.Gclifetime != 3600 { t.Fatal("parseconfig get gclifetime error") } - if cf2.EnableSetCookie != false { + if cf2.EnableSetCookie { t.Fatal("parseconfig get enableSetCookie error") } cconfig := new(cookieConfig) diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index 4dcf160a..c846e73a 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -26,10 +26,7 @@ func (p *SsdbProvider) connectInit() error { return errors.New("SessionInit First") } p.client, err = ssdb.Connect(p.host, p.port) - if err != nil { - return err - } - return nil + return err } func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { @@ -41,11 +38,7 @@ func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { if e != nil { return e } - err := p.connectInit() - if err != nil { - return err - } - return nil + return p.connectInit() } func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) { @@ -126,10 +119,7 @@ func (p *SsdbProvider) SessionDestroy(sid string) error { } } _, err := p.client.Del(sid) - if err != nil { - return err - } - return nil + return err } func (p *SsdbProvider) SessionGC() { diff --git a/staticfile.go b/staticfile.go index b7be24f3..7c270947 100644 --- a/staticfile.go +++ b/staticfile.go @@ -109,14 +109,14 @@ var ( func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, error) { mapKey := acceptEncoding + ":" + filePath mapLock.RLock() - mapFile, _ := staticFileMap[mapKey] + mapFile := staticFileMap[mapKey] mapLock.RUnlock() if isOk(mapFile, fi) { return mapFile.encoding != "", mapFile.encoding, mapFile, nil } mapLock.Lock() defer mapLock.Unlock() - if mapFile, _ = staticFileMap[mapKey]; !isOk(mapFile, fi) { + if mapFile = staticFileMap[mapKey]; !isOk(mapFile, fi) { file, err := os.Open(filePath) if err != nil { return false, "", nil, err diff --git a/template.go b/template.go index 4e0d6384..0d69a29e 100644 --- a/template.go +++ b/template.go @@ -31,11 +31,11 @@ import ( ) var ( - beegoTplFuncMap = make(template.FuncMap) + beegoTplFuncMap = make(template.FuncMap) beeViewPathTemplateLocked = false // beeViewPathTemplates caching map and supported template file extensions per view - beeViewPathTemplates = make(map[string]map[string]*template.Template) - templatesLock sync.RWMutex + beeViewPathTemplates = make(map[string]map[string]*template.Template) + templatesLock sync.RWMutex // beeTemplateExt stores the template extension which will build beeTemplateExt = []string{"tpl", "html"} // beeTemplatePreprocessors stores associations of extension -> preprocessor handler @@ -46,7 +46,7 @@ var ( // writing the output to wr. // A template will be executed safely in parallel. func ExecuteTemplate(wr io.Writer, name string, data interface{}) error { - return ExecuteViewPathTemplate(wr,name, BConfig.WebConfig.ViewsPath, data) + return ExecuteViewPathTemplate(wr, name, BConfig.WebConfig.ViewsPath, data) } // ExecuteViewPathTemplate applies the template with name and from specific viewPath to the specified data object, @@ -57,7 +57,7 @@ func ExecuteViewPathTemplate(wr io.Writer, name string, viewPath string, data in templatesLock.RLock() defer templatesLock.RUnlock() } - if beeTemplates,ok := beeViewPathTemplates[viewPath]; ok { + if beeTemplates, ok := beeViewPathTemplates[viewPath]; ok { if t, ok := beeTemplates[name]; ok { var err error if t.Lookup(name) != nil { @@ -160,9 +160,9 @@ func AddTemplateExt(ext string) { beeTemplateExt = append(beeTemplateExt, ext) } -// AddViewPath adds a new path to the supported view paths. +// AddViewPath adds a new path to the supported view paths. //Can later be used by setting a controller ViewPath to this folder -//will panic if called after beego.Run() +//will panic if called after beego.Run() func AddViewPath(viewPath string) error { if beeViewPathTemplateLocked { if _, exist := beeViewPathTemplates[viewPath]; exist { @@ -187,7 +187,7 @@ func BuildTemplate(dir string, files ...string) error { } return errors.New("dir open err") } - beeTemplates,ok := beeViewPathTemplates[dir]; + beeTemplates, ok := beeViewPathTemplates[dir] if !ok { panic("Unknown view path: " + dir) } @@ -296,7 +296,7 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others t, subMods1, err = getTplDeep(root, otherFile, "", t) if err != nil { logs.Trace("template parse file err:", err) - } else if subMods1 != nil && len(subMods1) > 0 { + } else if len(subMods1) > 0 { t, err = _getTemplate(t, root, subMods1, others...) } break @@ -317,7 +317,7 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others t, subMods1, err = getTplDeep(root, otherFile, "", t) if err != nil { logs.Trace("template parse file err:", err) - } else if subMods1 != nil && len(subMods1) > 0 { + } else if len(subMods1) > 0 { t, err = _getTemplate(t, root, subMods1, others...) } break diff --git a/templatefunc_test.go b/templatefunc_test.go index a1ec1136..20d9b850 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -173,7 +173,7 @@ func TestParseForm(t *testing.T) { if u.Intro != "I am an engineer!" { t.Errorf("Intro should equal `I am an engineer!` but got `%v`", u.Intro) } - if u.StrBool != true { + if !u.StrBool { t.Errorf("strboll should equal `true`, but got `%v`", u.StrBool) } y, m, d := u.Date.Date() @@ -255,43 +255,43 @@ func TestParseFormTag(t *testing.T) { objT := reflect.TypeOf(&user{}).Elem() label, name, fType, id, class, ignored, required := parseFormTag(objT.Field(0)) - if !(name == "name" && label == "年龄:" && fType == "text" && ignored == false) { + if !(name == "name" && label == "年龄:" && fType == "text" && !ignored) { t.Errorf("Form Tag with name, label and type was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(1)) - if !(name == "NoName" && label == "年龄:" && fType == "hidden" && ignored == false) { + if !(name == "NoName" && label == "年龄:" && fType == "hidden" && !ignored) { t.Errorf("Form Tag with label and type but without name was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(2)) - if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && ignored == false) { + if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && !ignored) { t.Errorf("Form Tag containing only label was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(3)) - if !(name == "name" && label == "OnlyName: " && fType == "text" && ignored == false && + if !(name == "name" && label == "OnlyName: " && fType == "text" && !ignored && id == "name" && class == "form-name") { t.Errorf("Form Tag containing only name was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(4)) - if ignored == false { + if !ignored { t.Errorf("Form Tag that should be ignored was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(5)) - if !(name == "name" && required == true) { + if !(name == "name" && required) { t.Errorf("Form Tag containing only name and required was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(6)) - if !(name == "name" && required == false) { + if !(name == "name" && !required) { t.Errorf("Form Tag containing only name and ignore required was not correctly parsed.") } label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(7)) - if !(name == "name" && required == false) { + if !(name == "name" && !required) { t.Errorf("Form Tag containing only name and not required was not correctly parsed.") } diff --git a/validation/validation.go b/validation/validation.go index 489dfa5e..9dc51106 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -349,7 +349,7 @@ func (v *Validation) RecursiveValid(objc interface{}) (bool, error) { //Step 1: validate obj itself firstly // fails if objc is not struct pass, err := v.Valid(objc) - if err != nil || false == pass { + if err != nil || !pass { return pass, err // Stop recursive validation } // Step 2: Validate struct's struct fields From b0e2012a170832c899ba6264fab7373a8712995f Mon Sep 17 00:00:00 2001 From: liaoziqian Date: Tue, 21 Mar 2017 09:15:30 +0800 Subject: [PATCH 13/82] Fix set cookie bug, zero max age is not valid. --- context/output.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/output.go b/context/output.go index 564ef96d..c15f9fe7 100644 --- a/context/output.go +++ b/context/output.go @@ -105,7 +105,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface switch { case maxAge > 0: fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge) - case maxAge < 0: + case maxAge <= 0: fmt.Fprintf(&b, "; Max-Age=0") } } From ae0a75c464e3373c89f296e698a1679f80e566f9 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 21 Mar 2017 23:55:40 +0800 Subject: [PATCH 14/82] console debug use diffrent color --- logs/console.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logs/console.go b/logs/console.go index e6bf6c29..e75f2a1b 100644 --- a/logs/console.go +++ b/logs/console.go @@ -41,7 +41,7 @@ var colors = []brush{ newBrush("1;33"), // Warning yellow newBrush("1;32"), // Notice green newBrush("1;34"), // Informational blue - newBrush("1;34"), // Debug blue + newBrush("1;44"), // Debug Background blue } // consoleWriter implements LoggerInterface and writes messages to terminal. From 83d4385f1f94acde7972801abec35b6508db8cb6 Mon Sep 17 00:00:00 2001 From: Guohua Ouyang Date: Sat, 25 Mar 2017 07:52:43 +0800 Subject: [PATCH 15/82] Support time.RFC3339 Signed-off-by: Guohua Ouyang --- templatefunc.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/templatefunc.go b/templatefunc.go index 8ecacbfe..5bd7b73f 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -362,7 +362,10 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e t time.Time err error ) - if len(value) >= 19 { + if len(value) >= 25 { + value = value[:25] + t, err = time.ParseInLocation(time.RFC3339, value, time.Local) + } else if len(value) >= 19 { value = value[:19] t, err = time.ParseInLocation(formatDateTime, value, time.Local) } else if len(value) >= 10 { From c387aeeb363ea65ec18b5f3fecbcde06f6506c49 Mon Sep 17 00:00:00 2001 From: Jisu Kim Date: Mon, 27 Mar 2017 14:30:42 +0900 Subject: [PATCH 16/82] fix markdown formatting --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d3c92d84..c8a964f8 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific feature More info [beego.me](http://beego.me) -##Quick Start -######Download and install +## Quick Start +###### Download and install go get github.com/astaxie/beego -######Create file `hello.go` +###### Create file `hello.go` ```go package main @@ -24,12 +24,12 @@ func main(){ beego.Run() } ``` -######Build and run +###### Build and run ```bash go build hello.go ./hello ``` -######Congratulations! +###### Congratulations! You just built your first beego app. Open your browser and visit `http://localhost:8080`. Please see [Documentation](http://beego.me/docs) for more. From 7c3a99773590c37aac84ebea32364a6eeba02b3c Mon Sep 17 00:00:00 2001 From: xia hao Date: Mon, 27 Mar 2017 23:34:58 +0800 Subject: [PATCH 17/82] poolsize could set to zero sometimes we may want disable the redis pool --- session/redis/sess_redis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index c46fa7cd..14bbd4c1 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -128,7 +128,7 @@ func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { } if len(configs) > 1 { poolsize, err := strconv.Atoi(configs[1]) - if err != nil || poolsize <= 0 { + if err != nil || poolsize < 0 { rp.poolsize = MaxPoolSize } else { rp.poolsize = poolsize From fdb2660a2a67f923637d78b0570d62ee44ee066b Mon Sep 17 00:00:00 2001 From: Ketan Gupta Date: Tue, 28 Mar 2017 11:29:20 +0530 Subject: [PATCH 18/82] Update README.md --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d3c92d84..c8a964f8 100644 --- a/README.md +++ b/README.md @@ -9,12 +9,12 @@ It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific feature More info [beego.me](http://beego.me) -##Quick Start -######Download and install +## Quick Start +###### Download and install go get github.com/astaxie/beego -######Create file `hello.go` +###### Create file `hello.go` ```go package main @@ -24,12 +24,12 @@ func main(){ beego.Run() } ``` -######Build and run +###### Build and run ```bash go build hello.go ./hello ``` -######Congratulations! +###### Congratulations! You just built your first beego app. Open your browser and visit `http://localhost:8080`. Please see [Documentation](http://beego.me/docs) for more. From 2808a13f0774880901f31714838793ef0dc0d7b8 Mon Sep 17 00:00:00 2001 From: Christoph Pech Date: Tue, 28 Mar 2017 12:38:27 +0200 Subject: [PATCH 19/82] Fix for IndexExists in SQLite driver, they added the "origin" and "partial" columns to the index_list pragma. see: https://www.sqlite.org/src/info/2743846cdba572f6 --- orm/db_sqlite.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/db_sqlite.go b/orm/db_sqlite.go index a3cb69a7..a43a5594 100644 --- a/orm/db_sqlite.go +++ b/orm/db_sqlite.go @@ -134,7 +134,7 @@ func (d *dbBaseSqlite) IndexExists(db dbQuerier, table string, name string) bool defer rows.Close() for rows.Next() { var tmp, index sql.NullString - rows.Scan(&tmp, &index, &tmp) + rows.Scan(&tmp, &index, &tmp, &tmp, &tmp) if name == index.String { return true } From bf469f0b550cda35f2c0ef543d7a7c14ed77a05b Mon Sep 17 00:00:00 2001 From: astaxie Date: Wed, 29 Mar 2017 09:57:18 +0800 Subject: [PATCH 20/82] Revert "close mysql connection" --- session/mysql/sess_mysql.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index 37c45283..7bcf959c 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -143,7 +143,6 @@ func (mp *Provider) SessionInit(maxlifetime int64, savePath string) error { // SessionRead get mysql session by sid func (mp *Provider) SessionRead(sid string) (session.Store, error) { c := mp.connectInit() - defer c.Close() row := c.QueryRow("select session_data from "+TableName+" where session_key=?", sid) var sessiondata []byte err := row.Scan(&sessiondata) @@ -177,7 +176,6 @@ func (mp *Provider) SessionExist(sid string) bool { // SessionRegenerate generate new sid for mysql session func (mp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { c := mp.connectInit() - defer c.Close() row := c.QueryRow("select session_data from "+TableName+" where session_key=?", oldsid) var sessiondata []byte err := row.Scan(&sessiondata) From 5c7673e73da9addeede1a97c7ebd1097aee99a4f Mon Sep 17 00:00:00 2001 From: astaxie Date: Wed, 29 Mar 2017 10:22:27 +0800 Subject: [PATCH 21/82] update to 1.8.1 --- beego.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beego.go b/beego.go index c06b499c..7acf4a13 100644 --- a/beego.go +++ b/beego.go @@ -23,7 +23,7 @@ import ( const ( // VERSION represent beego web framework version. - VERSION = "1.8.0" + VERSION = "1.8.1" // DEV is for develop DEV = "dev" From fb04d3cff18fe575d7fbdc465a9f88e65bcefa5b Mon Sep 17 00:00:00 2001 From: Vladimir Shteinman Date: Thu, 30 Mar 2017 11:44:31 +0300 Subject: [PATCH 22/82] Fix example for Hander func --- app.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app.go b/app.go index 32776298..25ea2a04 100644 --- a/app.go +++ b/app.go @@ -348,9 +348,9 @@ func Any(rootpath string, f FilterFunc) *App { // Handler used to register a Handler router // usage: -// beego.Handler("/api", func(ctx *context.Context){ -// ctx.Output.Body("hello world") -// }) +// beego.Handler("/api", http.HandlerFunc(func (w http.ResponseWriter, r *http.Request) { +// fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) +// })) func Handler(rootpath string, h http.Handler, options ...interface{}) *App { BeeApp.Handlers.Handler(rootpath, h, options...) return BeeApp From 6a32b048bd996790db417b40428aaa0f5b747167 Mon Sep 17 00:00:00 2001 From: Ondrej Fabry Date: Sun, 2 Apr 2017 11:04:08 +0200 Subject: [PATCH 23/82] Update README.md --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index d3c92d84..32c8e25e 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,18 @@ -## Beego - -[![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) -[![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) -[![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) +# Beego [![Build Status](https://travis-ci.org/astaxie/beego.svg?branch=master)](https://travis-ci.org/astaxie/beego) [![GoDoc](http://godoc.org/github.com/astaxie/beego?status.svg)](http://godoc.org/github.com/astaxie/beego) [![Foundation](https://img.shields.io/badge/Golang-Foundation-green.svg)](http://golangfoundation.org) beego is used for rapid development of RESTful APIs, web apps and backend services in Go. It is inspired by Tornado, Sinatra and Flask. beego has some Go-specific features such as interfaces and struct embedding. -More info [beego.me](http://beego.me) +###### More info at [beego.me](http://beego.me). -##Quick Start -######Download and install +## Quick Start + +#### Download and install go get github.com/astaxie/beego -######Create file `hello.go` +#### Create file `hello.go` + ```go package main @@ -24,15 +22,17 @@ func main(){ beego.Run() } ``` -######Build and run -```bash - go build hello.go + +#### Build and run + + go build main.go ./hello -``` -######Congratulations! -You just built your first beego app. -Open your browser and visit `http://localhost:8080`. -Please see [Documentation](http://beego.me/docs) for more. + +#### Go to [http://localhost:8080](http://localhost:8080) + +Congratulations! You've just built your first **beego** app. + +###### Please see [Documentation](http://beego.me/docs) for more. ## Features @@ -56,7 +56,7 @@ Please see [Documentation](http://beego.me/docs) for more. * [http://beego.me/community](http://beego.me/community) * Welcome to join us in Slack: [https://beego.slack.com](https://beego.slack.com), you can get invited from [here](https://github.com/beego/beedoc/issues/232) -## LICENSE +## License beego source code is licensed under the Apache Licence, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0.html). From d5c03f5b8f577a702a76f735ec490488bcf62785 Mon Sep 17 00:00:00 2001 From: Liaodd Date: Mon, 10 Apr 2017 11:30:23 +0800 Subject: [PATCH 24/82] Update ini.go change the key to lowercase when set a new key for ini configer --- config/ini.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/ini.go b/config/ini.go index 27220f90..8fdbc2ea 100644 --- a/config/ini.go +++ b/config/ini.go @@ -416,7 +416,7 @@ func (c *IniConfigContainer) Set(key, value string) error { var ( section, k string - sectionKey = strings.Split(key, "::") + sectionKey = strings.Split(strings.ToLower(key), "::") ) if len(sectionKey) >= 2 { From 932019770deeb0651233e4bebfa87fa9e6b345d7 Mon Sep 17 00:00:00 2001 From: zjjott Date: Mon, 10 Apr 2017 17:36:17 +0800 Subject: [PATCH 25/82] fix: log mode 0440 should not be 440 --- logs/file.go | 2 +- logs/file_test.go | 22 +++++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/logs/file.go b/logs/file.go index bd3c22a9..a7276523 100644 --- a/logs/file.go +++ b/logs/file.go @@ -270,7 +270,7 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { // Rename the file to its new found name // even if occurs error,we MUST guarantee to restart new logger err = os.Rename(w.Filename, fName) - err = os.Chmod(fName, os.FileMode(440)) + err = os.Chmod(fName, os.FileMode(0440)) // re-start logger RESTART_LOGGER: diff --git a/logs/file_test.go b/logs/file_test.go index 69a66d84..a1b226bf 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -162,7 +162,27 @@ func TestFileRotate_05(t *testing.T) { testFileDailyRotate(t, fn1, fn2) os.Remove(fn) } - +func TestFileRotate_06(t *testing.T) {//test file mode + log := NewLogger(10000) + log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`) + log.Debug("debug") + log.Info("info") + log.Notice("notice") + log.Warning("warning") + log.Error("error") + log.Alert("alert") + log.Critical("critical") + log.Emergency("emergency") + rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log" + s,_:=os.Lstat(rotateName) + if s.Mode() != 0440 { + os.Remove(rotateName) + os.Remove("test3.log") + t.Fatal("rotate file mode error") + } + os.Remove(rotateName) + os.Remove("test3.log") +} func testFileRotate(t *testing.T, fn1, fn2 string) { fw := &fileLogWriter{ Daily: true, From 0cd31a247f898e782f1730beb2f542963988a73c Mon Sep 17 00:00:00 2001 From: Orefa Date: Wed, 19 Apr 2017 07:47:05 +0800 Subject: [PATCH 26/82] fix Template nesting problem --- template.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/template.go b/template.go index 17c18591..163ed620 100644 --- a/template.go +++ b/template.go @@ -227,9 +227,12 @@ func BuildTemplate(dir string, files ...string) error { func getTplDeep(root, file, parent string, t *template.Template) (*template.Template, [][]string, error) { var fileAbsPath string + var rParent string if filepath.HasPrefix(file, "../") { + rParent = filepath.Join(filepath.Dir(parent), file) fileAbsPath = filepath.Join(root, filepath.Dir(parent), file) } else { + rParent = file fileAbsPath = filepath.Join(root, file) } if e := utils.FileExists(fileAbsPath); !e { @@ -254,7 +257,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp if !HasTemplateExt(m[1]) { continue } - _, _, err = getTplDeep(root, m[1], file, t) + _, _, err = getTplDeep(root, m[1], rParent, t) if err != nil { return nil, [][]string{}, err } From 0cb8de421857b4b084d50a7df2cb24073938e3c6 Mon Sep 17 00:00:00 2001 From: PaulChen2016 <747766706@qq.com> Date: Wed, 19 Apr 2017 16:22:58 +0800 Subject: [PATCH 27/82] =?UTF-8?q?Beego=20=E8=BF=90=E8=A1=8C=E8=BF=87?= =?UTF-8?q?=E7=A8=8B=E4=B8=AD=E5=8A=A8=E6=80=81=E5=A2=9E=E5=87=8F=E5=AE=9A?= =?UTF-8?q?=E6=97=B6=E4=BB=BB=E5=8A=A1=E6=97=B6=EF=BC=8Cnow=E7=9A=84?= =?UTF-8?q?=E6=97=B6=E9=97=B4=E9=9C=80=E8=A6=81=E6=9B=B4=E6=96=B0=EF=BC=8C?= =?UTF-8?q?=E5=90=A6=E5=88=99=E7=AD=89=E5=BE=85=E6=97=B6=E9=97=B4=E4=BC=9A?= =?UTF-8?q?=E4=B8=8D=E6=AD=A3=E7=A1=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit beego 启动时,执行toolbox.StartTask() 运行过程中,动态添加定时任务(这个是now时间已经不是starttask的时间了,需要刷新) case <-changed: now = time.Now().Local() continue --- toolbox/task.go | 1 + 1 file changed, 1 insertion(+) diff --git a/toolbox/task.go b/toolbox/task.go index abd411c8..672717cd 100644 --- a/toolbox/task.go +++ b/toolbox/task.go @@ -427,6 +427,7 @@ func run() { } continue case <-changed: + now = time.Now().Local() continue case <-stop: return From d1a2583972ffdc743a9bb87e0ccb8ae40f4d7124 Mon Sep 17 00:00:00 2001 From: Ggicci Date: Wed, 19 Apr 2017 19:50:11 +0800 Subject: [PATCH 28/82] Fix ini parsing error for multiple users on one machine. If there were multiple users working on one machine, it's common that "/tmp/beego" will be owned by one of them, and the others won't be able to access to it. So, it's better to add an "id-like" postfix to the temporary directory. --- config/ini.go | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/config/ini.go b/config/ini.go index 27220f90..7711b010 100644 --- a/config/ini.go +++ b/config/ini.go @@ -21,6 +21,7 @@ import ( "io" "io/ioutil" "os" + "os/user" "path/filepath" "strconv" "strings" @@ -184,10 +185,17 @@ func (ini *IniConfig) parseData(dir string, data []byte) (*IniConfigContainer, e // ParseData parse ini the data // When include other.conf,other.conf is either absolute directory -// or under beego in default temporary directory(/tmp/beego). +// or under beego in default temporary directory(/tmp/beego[-username]). func (ini *IniConfig) ParseData(data []byte) (Configer, error) { - dir := filepath.Join(os.TempDir(), "beego") - os.MkdirAll(dir, os.ModePerm) + dir := "beego" + currentUser, err := user.Current() + if err == nil { + dir = "beego-" + currentUser.Username + } + dir = filepath.Join(os.TempDir(), dir) + if err = os.MkdirAll(dir, os.ModePerm); err != nil { + return nil, err + } return ini.parseData(dir, data) } From 453691728ab73e569c32df3055e941ff35405e5c Mon Sep 17 00:00:00 2001 From: astaxie Date: Thu, 20 Apr 2017 10:56:09 +0800 Subject: [PATCH 29/82] gofmt simplify --- context/input_test.go | 4 ++-- controller_test.go | 4 ++-- logs/alils/signature.go | 3 +-- logs/file_test.go | 4 ++-- toolbox/statistics.go | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/context/input_test.go b/context/input_test.go index 9853e398..db812a0f 100644 --- a/context/input_test.go +++ b/context/input_test.go @@ -73,8 +73,8 @@ func TestBind(t *testing.T) { {"/?human.ID=888&human.Nick=astaxie&human.Ms=true&human[Pwd]=pass", []testItem{{"human", Human{}, Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass"}}}}, {"/?human[0].ID=888&human[0].Nick=astaxie&human[0].Ms=true&human[0][Pwd]=pass01&human[1].ID=999&human[1].Nick=ysqi&human[1].Ms=On&human[1].Pwd=pass02", []testItem{{"human", []Human{}, []Human{ - Human{ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass01"}, - Human{ID: 999, Nick: "ysqi", Ms: true, Pwd: "pass02"}, + {ID: 888, Nick: "astaxie", Ms: true, Pwd: "pass01"}, + {ID: 999, Nick: "ysqi", Ms: true, Pwd: "pass02"}, }}}}, { diff --git a/controller_test.go b/controller_test.go index c2025860..1e53416d 100644 --- a/controller_test.go +++ b/controller_test.go @@ -172,10 +172,10 @@ func TestAdditionalViewPaths(t *testing.T) { t.Fatal("TestAdditionalViewPaths expected error") } }() - ctrl.RenderString(); + ctrl.RenderString() }() ctrl.TplName = "file2.tpl" ctrl.ViewPath = dir2 - ctrl.RenderString(); + ctrl.RenderString() } diff --git a/logs/alils/signature.go b/logs/alils/signature.go index e0e4b3f7..2d611307 100755 --- a/logs/alils/signature.go +++ b/logs/alils/signature.go @@ -76,7 +76,7 @@ func signature(project *LogProject, method, uri string, var keys sort.StringSlice vals := u.Query() - for k, _ := range vals { + for k := range vals { keys = append(keys, k) } @@ -109,4 +109,3 @@ func signature(project *LogProject, method, uri string, digest = base64.StdEncoding.EncodeToString(mac.Sum(nil)) return } - diff --git a/logs/file_test.go b/logs/file_test.go index a1b226bf..f345ff20 100644 --- a/logs/file_test.go +++ b/logs/file_test.go @@ -162,7 +162,7 @@ func TestFileRotate_05(t *testing.T) { testFileDailyRotate(t, fn1, fn2) os.Remove(fn) } -func TestFileRotate_06(t *testing.T) {//test file mode +func TestFileRotate_06(t *testing.T) { //test file mode log := NewLogger(10000) log.SetLogger("file", `{"filename":"test3.log","maxlines":4}`) log.Debug("debug") @@ -174,7 +174,7 @@ func TestFileRotate_06(t *testing.T) {//test file mode log.Critical("critical") log.Emergency("emergency") rotateName := "test3" + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), 1) + ".log" - s,_:=os.Lstat(rotateName) + s, _ := os.Lstat(rotateName) if s.Mode() != 0440 { os.Remove(rotateName) os.Remove("test3.log") diff --git a/toolbox/statistics.go b/toolbox/statistics.go index c6a9489f..d014544c 100644 --- a/toolbox/statistics.go +++ b/toolbox/statistics.go @@ -119,7 +119,7 @@ func (m *URLMap) GetMap() map[string]interface{} { func (m *URLMap) GetMapData() []map[string]interface{} { m.lock.Lock() defer m.lock.Unlock() - + var resultLists []map[string]interface{} for k, v := range m.urlmap { From 9aedb4d05a70937533ff8cf657b365a80257406d Mon Sep 17 00:00:00 2001 From: eyalpost Date: Fri, 21 Apr 2017 15:26:41 +0300 Subject: [PATCH 30/82] phase #1 --- controller.go | 2 + param/methodparams.go | 101 ++++++++++++++++++++++++++++++++++++++++++ param/options.go | 15 +++++++ param/parsers.go | 41 +++++++++++++++++ response/renderer.go | 27 +++++++++++ response/responses.go | 44 ++++++++++++++++++ router.go | 42 ++++++++++++++---- 7 files changed, 264 insertions(+), 8 deletions(-) create mode 100644 param/methodparams.go create mode 100644 param/options.go create mode 100644 param/parsers.go create mode 100644 response/renderer.go create mode 100644 response/responses.go diff --git a/controller.go b/controller.go index c2a327b3..02e45738 100644 --- a/controller.go +++ b/controller.go @@ -28,6 +28,7 @@ import ( "strings" "github.com/astaxie/beego/context" + "github.com/astaxie/beego/param" "github.com/astaxie/beego/session" ) @@ -51,6 +52,7 @@ type ControllerComments struct { Router string AllowHTTPMethods []string Params []map[string]string + MethodParams []*param.MethodParam } // Controller defines some basic http request handler operations, such as diff --git a/param/methodparams.go b/param/methodparams.go new file mode 100644 index 00000000..2e6e6840 --- /dev/null +++ b/param/methodparams.go @@ -0,0 +1,101 @@ +package param + +import ( + "fmt" + "reflect" + + beecontext "github.com/astaxie/beego/context" +) + +//Keeps param information to be auto passed to controller methods +type MethodParam struct { + name string + parser paramParser + location paramLocation + required bool + defValue interface{} +} + +type paramLocation byte + +const ( + param paramLocation = iota + body + header +) + +type MethodParamOption func(*MethodParam) + +func Bool(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, boolParser{}, opts) +} + +func String(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, stringParser{}, opts) +} + +func Int(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, intParser{}, opts) +} + +func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { + param = &MethodParam{name: name, parser: parser} + for _, option := range opts { + option(param) + } + return +} + +func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { + result = make([]reflect.Value, 0, len(methodParams)) + i := 0 + for _, p := range methodParams { + var strValue string + var value interface{} + switch p.location { + case body: + strValue = string(ctx.Input.RequestBody) + case header: + strValue = ctx.Input.Header(p.name) + default: + strValue = ctx.Input.Query(p.name) + } + + if strValue == "" { + if p.required { + ctx.Abort(400, "Missing argument "+p.name) + } else if p.defValue != nil { + value = p.defValue + } else { + value = p.parser.zeroValue() + } + } else { + var err error + value, err = p.parser.parse(strValue) + if err != nil { + //TODO: handle err + } + } + reflectValue, err := safeConvert(reflect.ValueOf(value), methodType.In(i)) + if err != nil { + //TODO: handle err + } + result = append(result, reflectValue) + i++ + } + return +} + +func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + err, ok = r.(error) + if !ok { + err = fmt.Errorf("%v", r) + } + } + }() + result = value.Convert(t) + return +} diff --git a/param/options.go b/param/options.go new file mode 100644 index 00000000..91d01ac3 --- /dev/null +++ b/param/options.go @@ -0,0 +1,15 @@ +package param + +var InHeader MethodParamOption = func(p *MethodParam) { + p.location = header +} + +var IsRequired MethodParamOption = func(p *MethodParam) { + p.required = true +} + +func Default(defValue interface{}) MethodParamOption { + return func(p *MethodParam) { + p.defValue = defValue + } +} diff --git a/param/parsers.go b/param/parsers.go new file mode 100644 index 00000000..eec0bb79 --- /dev/null +++ b/param/parsers.go @@ -0,0 +1,41 @@ +package param + +import "strconv" + +type paramParser interface { + parse(value string) (interface{}, error) + zeroValue() interface{} +} + +type boolParser struct { +} + +func (p boolParser) parse(value string) (interface{}, error) { + return strconv.ParseBool(value) +} + +func (p boolParser) zeroValue() interface{} { + return false +} + +type stringParser struct { +} + +func (p stringParser) parse(value string) (interface{}, error) { + return value, nil +} + +func (p stringParser) zeroValue() interface{} { + return "" +} + +type intParser struct { +} + +func (p intParser) parse(value string) (interface{}, error) { + return strconv.Atoi(value) +} + +func (p intParser) zeroValue() interface{} { + return 0 +} diff --git a/response/renderer.go b/response/renderer.go new file mode 100644 index 00000000..ca5936db --- /dev/null +++ b/response/renderer.go @@ -0,0 +1,27 @@ +package response + +import ( + "strconv" + + beecontext "github.com/astaxie/beego/context" +) + +type Renderer interface { + Render(ctx *beecontext.Context) +} + +type rendererFunc func(ctx *beecontext.Context) + +func (f rendererFunc) Render(ctx *beecontext.Context) { + f(ctx) +} + +type StatusCode int + +func (s StatusCode) Error() string { + return strconv.Itoa(int(s)) +} + +func (s StatusCode) Render(ctx *beecontext.Context) { + ctx.Output.SetStatus(int(s)) +} diff --git a/response/responses.go b/response/responses.go new file mode 100644 index 00000000..aa042a35 --- /dev/null +++ b/response/responses.go @@ -0,0 +1,44 @@ +package response + +import ( + beecontext "github.com/astaxie/beego/context" +) + +func Json(value interface{}, encoding ...bool) Renderer { + return rendererFunc(func(ctx *beecontext.Context) { + var ( + hasIndent = true + hasEncoding = false + ) + //TODO: need access to BConfig :( + // if BConfig.RunMode == PROD { + // hasIndent = false + // } + if len(encoding) > 0 && encoding[0] { + hasEncoding = true + } + ctx.Output.JSON(value, hasIndent, hasEncoding) + }) +} + +func Error(err error) Renderer { + return rendererFunc(func(ctx *beecontext.Context) { + ctx.Output.SetStatus(500) + ctx.WriteString(err.Error()) + }) +} + +func RenderMethodResult(result interface{}, ctx *beecontext.Context) { + if result != nil { + renderer, ok := result.(Renderer) + if !ok { + err, ok := result.(error) + if ok { + renderer = Error(err) + } else { + renderer = Json(result) + } + } + renderer.Render(ctx) + } +} diff --git a/router.go b/router.go index 9f573f26..4937354a 100644 --- a/router.go +++ b/router.go @@ -29,6 +29,8 @@ import ( beecontext "github.com/astaxie/beego/context" "github.com/astaxie/beego/logs" + "github.com/astaxie/beego/param" + "github.com/astaxie/beego/response" "github.com/astaxie/beego/toolbox" "github.com/astaxie/beego/utils" ) @@ -116,6 +118,7 @@ type controllerInfo struct { handler http.Handler runFunction FilterFunc routerType int + methodParams []*param.MethodParam } // ControllerRegister containers registered router rules, controller handlers and filters. @@ -151,6 +154,10 @@ func NewControllerRegister() *ControllerRegister { // Add("/api",&RestController{},"get,post:ApiFunc" // Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc") func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) { + p.addWithMethodParams(pattern, c, nil, mappingMethods...) +} + +func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, mappingMethods ...string) { reflectVal := reflect.ValueOf(c) t := reflect.Indirect(reflectVal).Type() methods := make(map[string]string) @@ -181,6 +188,7 @@ func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingM route.methods = methods route.routerType = routerTypeBeego route.controllerType = t + route.methodParams = methodParams if len(methods) == 0 { for _, m := range HTTPMETHOD { p.addToRouter(m, pattern, route) @@ -247,7 +255,7 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) { key := t.PkgPath() + ":" + t.Name() if comm, ok := GlobalControllerRouter[key]; ok { for _, a := range comm { - p.Add(a.Router, c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method) + p.addWithMethodParams(a.Router, c, a.MethodParams, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method) } } } @@ -626,11 +634,12 @@ func (p *ControllerRegister) execFilter(context *beecontext.Context, urlPath str func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) { startTime := time.Now() var ( - runRouter reflect.Type - findRouter bool - runMethod string - routerInfo *controllerInfo - isRunnable bool + runRouter reflect.Type + findRouter bool + runMethod string + methodParams []*param.MethodParam + routerInfo *controllerInfo + isRunnable bool ) context := p.pool.Get().(*beecontext.Context) context.Reset(rw, r) @@ -742,6 +751,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) routerInfo.handler.ServeHTTP(rw, r) } else { runRouter = routerInfo.controllerType + methodParams = routerInfo.methodParams method := r.Method if r.Method == "POST" && context.Input.Query("_method") == "PUT" { method = "PUT" @@ -804,9 +814,14 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) execController.Options() default: if !execController.HandlerFunc(runMethod) { - var in []reflect.Value method := vc.MethodByName(runMethod) - method.Call(in) + var in []reflect.Value = param.ConvertParams(methodParams, method.Type(), context) + out := method.Call(in) + + //For backward compatibility we only handle response if we had incoming methodParams + if methodParams != nil { + p.handleParamResponse(context, execController, out) + } } } @@ -886,6 +901,17 @@ Admin: } } +func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, execController ControllerInterface, results []reflect.Value) { + //looping in reverse order for the case when both error and value are returned and error sets the response status code + for i := len(results) - 1; i >= 0; i-- { + result := results[i] + if !result.IsNil() { + resultValue := result.Interface() + response.RenderMethodResult(resultValue, context) + } + } +} + // FindRouter Find Router info for URL func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *controllerInfo, isFind bool) { var urlPath = context.Input.URL() From 712df81c99796febb88d6c1a374bc1f1d99f9330 Mon Sep 17 00:00:00 2001 From: OlegFX Date: Fri, 21 Apr 2017 19:57:04 +0300 Subject: [PATCH 31/82] Fixed InsertOrUpdate bug --- orm/db.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/db.go b/orm/db.go index 1544c479..e9508ee0 100644 --- a/orm/db.go +++ b/orm/db.go @@ -592,7 +592,7 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a row := q.QueryRow(query, values...) var id int64 err = row.Scan(&id) - if err.Error() == `pq: syntax error at or near "ON"` { + if err != nil && err.Error() == `pq: syntax error at or near "ON"` { err = fmt.Errorf("postgres version must 9.5 or higher") } return id, err From 89e01d125c274d636f4c7eeb545be38bdefef139 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Sun, 23 Apr 2017 01:33:50 +0300 Subject: [PATCH 32/82] all types implemented --- param/methodparams.go | 82 ++++++++++++++++++++++++++----------------- param/options.go | 18 +++++++--- param/parsers.go | 58 +++++++++++++++++++++--------- response/renderer.go | 9 +++++ response/responses.go | 10 ++++-- 5 files changed, 123 insertions(+), 54 deletions(-) diff --git a/param/methodparams.go b/param/methodparams.go index 2e6e6840..9cd2b1d6 100644 --- a/param/methodparams.go +++ b/param/methodparams.go @@ -5,6 +5,7 @@ import ( "reflect" beecontext "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" ) //Keeps param information to be auto passed to controller methods @@ -13,7 +14,7 @@ type MethodParam struct { parser paramParser location paramLocation required bool - defValue interface{} + defValue string } type paramLocation byte @@ -38,6 +39,18 @@ func Int(name string, opts ...MethodParamOption) *MethodParam { return newParam(name, intParser{}, opts) } +func Float(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, floatParser{}, opts) +} + +func Time(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, timeParser{}, opts) +} + +func Json(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, jsonParser{}, opts) +} + func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { param = &MethodParam{name: name, parser: parser} for _, option := range opts { @@ -46,42 +59,47 @@ func newParam(name string, parser paramParser, opts []MethodParamOption) (param return } -func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { - result = make([]reflect.Value, 0, len(methodParams)) - i := 0 - for _, p := range methodParams { - var strValue string - var value interface{} - switch p.location { - case body: - strValue = string(ctx.Input.RequestBody) - case header: - strValue = ctx.Input.Header(p.name) - default: - strValue = ctx.Input.Query(p.name) +func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { + var strValue string + var reflectValue reflect.Value + switch param.location { + case body: + strValue = string(ctx.Input.RequestBody) + case header: + strValue = ctx.Input.Header(param.name) + default: + strValue = ctx.Input.Query(param.name) + } + + if strValue == "" { + if param.required { + ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) + } else { + strValue = param.defValue + } + } + if strValue == "" { + reflectValue = reflect.Zero(paramType) + } else { + value, err := param.parser.parse(strValue, paramType) + if err != nil { + logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %s, Parser: %s, Error: %s", param.name, paramType.Name(), strValue, reflect.TypeOf(param.parser).Name(), err)) + ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %s to type %s", param.name, strValue, paramType.Name())) } - if strValue == "" { - if p.required { - ctx.Abort(400, "Missing argument "+p.name) - } else if p.defValue != nil { - value = p.defValue - } else { - value = p.parser.zeroValue() - } - } else { - var err error - value, err = p.parser.parse(strValue) - if err != nil { - //TODO: handle err - } - } - reflectValue, err := safeConvert(reflect.ValueOf(value), methodType.In(i)) + reflectValue, err = safeConvert(reflect.ValueOf(value), paramType) if err != nil { - //TODO: handle err + panic(err) } + } + return reflectValue +} + +func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { + result = make([]reflect.Value, 0, len(methodParams)) + for i := 0; i < len(methodParams); i++ { + reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) result = append(result, reflectValue) - i++ } return } diff --git a/param/options.go b/param/options.go index 91d01ac3..6fe10108 100644 --- a/param/options.go +++ b/param/options.go @@ -1,15 +1,25 @@ package param -var InHeader MethodParamOption = func(p *MethodParam) { - p.location = header -} +import ( + "fmt" +) var IsRequired MethodParamOption = func(p *MethodParam) { p.required = true } +var InHeader MethodParamOption = func(p *MethodParam) { + p.location = header +} + +var InBody MethodParamOption = func(p *MethodParam) { + p.location = body +} + func Default(defValue interface{}) MethodParamOption { return func(p *MethodParam) { - p.defValue = defValue + if defValue != nil { + p.defValue = fmt.Sprintf("%v", defValue) + } } } diff --git a/param/parsers.go b/param/parsers.go index eec0bb79..e3032e20 100644 --- a/param/parsers.go +++ b/param/parsers.go @@ -1,41 +1,67 @@ package param -import "strconv" +import ( + "encoding/json" + "reflect" + "strconv" + "time" +) type paramParser interface { - parse(value string) (interface{}, error) - zeroValue() interface{} + parse(value string, toType reflect.Type) (interface{}, error) } type boolParser struct { } -func (p boolParser) parse(value string) (interface{}, error) { +func (p boolParser) parse(value string, toType reflect.Type) (interface{}, error) { return strconv.ParseBool(value) } -func (p boolParser) zeroValue() interface{} { - return false -} - type stringParser struct { } -func (p stringParser) parse(value string) (interface{}, error) { +func (p stringParser) parse(value string, toType reflect.Type) (interface{}, error) { return value, nil } -func (p stringParser) zeroValue() interface{} { - return "" -} - type intParser struct { } -func (p intParser) parse(value string) (interface{}, error) { +func (p intParser) parse(value string, toType reflect.Type) (interface{}, error) { return strconv.Atoi(value) } -func (p intParser) zeroValue() interface{} { - return 0 +type floatParser struct { +} + +func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) { + if toType.Kind() == reflect.Float32 { + return strconv.ParseFloat(value, 32) + } + return strconv.ParseFloat(value, 64) +} + +type timeParser struct { +} + +func (p timeParser) parse(value string, toType reflect.Type) (result interface{}, err error) { + result, err = time.Parse(time.RFC3339, value) + if err != nil { + result, err = time.Parse("2006-01-02", value) + } + return +} + +type jsonParser struct { +} + +func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error) { + pResult := reflect.New(toType) + v := pResult.Interface() + err := json.Unmarshal([]byte(value), v) + if err != nil { + return nil, err + } + return pResult.Elem().Interface(), nil } diff --git a/response/renderer.go b/response/renderer.go index ca5936db..f5f9a52d 100644 --- a/response/renderer.go +++ b/response/renderer.go @@ -25,3 +25,12 @@ func (s StatusCode) Error() string { func (s StatusCode) Render(ctx *beecontext.Context) { ctx.Output.SetStatus(int(s)) } + +type statusCodeWithRender struct { + statusCode int + rendererFunc +} + +func (s statusCodeWithRender) Error() string { + return strconv.Itoa(s.statusCode) +} diff --git a/response/responses.go b/response/responses.go index aa042a35..5fbe4be1 100644 --- a/response/responses.go +++ b/response/responses.go @@ -21,20 +21,26 @@ func Json(value interface{}, encoding ...bool) Renderer { }) } -func Error(err error) Renderer { +func errorRenderer(err error) Renderer { return rendererFunc(func(ctx *beecontext.Context) { ctx.Output.SetStatus(500) ctx.WriteString(err.Error()) }) } +func Redirect(localurl string) statusCodeWithRender { + return statusCodeWithRender{302, func(ctx *beecontext.Context) { + ctx.Redirect(302, localurl) + }} +} + func RenderMethodResult(result interface{}, ctx *beecontext.Context) { if result != nil { renderer, ok := result.(Renderer) if !ok { err, ok := result.(error) if ok { - renderer = Error(err) + renderer = errorRenderer(err) } else { renderer = Json(result) } From bf6bd6b292a9c8c1d3835ef607daa1446f7b8a7d Mon Sep 17 00:00:00 2001 From: Faissal Elamraoui Date: Sun, 23 Apr 2017 19:07:12 +0200 Subject: [PATCH 33/82] Fixes #2587 Fixes warnings and errors raised by gometalinter and gosimple. --- admin.go | 10 +++--- grace/server.go | 1 - logs/jianliao.go | 2 -- logs/slack.go | 2 -- logs/smtp.go | 2 -- namespace.go | 11 +++---- router.go | 49 +++++++++++++++-------------- router_test.go | 10 +++++- session/couchbase/sess_couchbase.go | 10 +++--- session/ledis/ledis_session.go | 47 ++++++++++++++------------- session/memcache/sess_memcache.go | 1 - session/mysql/sess_mysql.go | 1 - session/postgres/sess_postgresql.go | 1 - session/redis/sess_redis.go | 33 ++++++++----------- session/sess_cookie.go | 24 ++++++-------- session/ssdb/sess_ssdb.go | 11 +++---- staticfile.go | 2 -- 17 files changed, 99 insertions(+), 118 deletions(-) diff --git a/admin.go b/admin.go index b4e3068f..80615957 100644 --- a/admin.go +++ b/admin.go @@ -208,7 +208,7 @@ func printTree(resultList *[][]string, t *Tree) { printTree(resultList, t.wildcard) } for _, l := range t.leaves { - if v, ok := l.runObject.(*controllerInfo); ok { + if v, ok := l.runObject.(*ControllerInfo); ok { if v.routerType == routerTypeBeego { var result = []string{ v.pattern, @@ -276,8 +276,8 @@ func profIndex(rw http.ResponseWriter, r *http.Request) { // it's in "/healthcheck" pattern in admin module. func healthcheck(rw http.ResponseWriter, req *http.Request) { var ( + result []string data = make(map[interface{}]interface{}) - result = []string{} resultList = new([][]string) content = map[string]interface{}{ "Fields": []string{"Name", "Message", "Status"}, @@ -291,17 +291,16 @@ func healthcheck(rw http.ResponseWriter, req *http.Request) { name, err.Error(), } - } else { result = []string{ "success", name, "OK", } - } *resultList = append(*resultList, result) } + content["Data"] = resultList data["Content"] = content data["Title"] = "Health Check" @@ -330,7 +329,6 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { // List Tasks content := make(map[string]interface{}) resultList := new([][]string) - var result = []string{} var fields = []string{ "Task Name", "Task Spec", @@ -339,7 +337,7 @@ func taskStatus(rw http.ResponseWriter, req *http.Request) { "", } for tname, tk := range toolbox.AdminTaskList { - result = []string{ + result := []string{ tname, tk.GetSpec(), tk.GetStatus(), diff --git a/grace/server.go b/grace/server.go index cc985552..c71193ad 100644 --- a/grace/server.go +++ b/grace/server.go @@ -196,7 +196,6 @@ func (srv *Server) signalHooks(ppFlag int, sig os.Signal) { for _, f := range srv.SignalHooks[ppFlag][sig] { f() } - return } // shutdown closes the listener so that no new connections are accepted. it also diff --git a/logs/jianliao.go b/logs/jianliao.go index 16bbdc2e..88ba0f9a 100644 --- a/logs/jianliao.go +++ b/logs/jianliao.go @@ -61,12 +61,10 @@ func (s *JLWriter) WriteMsg(when time.Time, msg string, level int) error { // Flush implementing method. empty. func (s *JLWriter) Flush() { - return } // Destroy implementing method. empty. func (s *JLWriter) Destroy() { - return } func init() { diff --git a/logs/slack.go b/logs/slack.go index d8482b3e..1cd2e5ae 100644 --- a/logs/slack.go +++ b/logs/slack.go @@ -49,12 +49,10 @@ func (s *SLACKWriter) WriteMsg(when time.Time, msg string, level int) error { // Flush implementing method. empty. func (s *SLACKWriter) Flush() { - return } // Destroy implementing method. empty. func (s *SLACKWriter) Destroy() { - return } func init() { diff --git a/logs/smtp.go b/logs/smtp.go index 2ec0514d..6208d7b8 100644 --- a/logs/smtp.go +++ b/logs/smtp.go @@ -138,12 +138,10 @@ func (s *SMTPWriter) WriteMsg(when time.Time, msg string, level int) error { // Flush implementing method. empty. func (s *SMTPWriter) Flush() { - return } // Destroy implementing method. empty. func (s *SMTPWriter) Destroy() { - return } func init() { diff --git a/namespace.go b/namespace.go index cfde0111..72f22a72 100644 --- a/namespace.go +++ b/namespace.go @@ -267,13 +267,12 @@ func addPrefix(t *Tree, prefix string) { addPrefix(t.wildcard, prefix) } for _, l := range t.leaves { - if c, ok := l.runObject.(*controllerInfo); ok { + if c, ok := l.runObject.(*ControllerInfo); ok { if !strings.HasPrefix(c.pattern, prefix) { c.pattern = prefix + c.pattern } } } - } // NSCond is Namespace Condition @@ -284,16 +283,16 @@ func NSCond(cond namespaceCond) LinkNamespace { } // NSBefore Namespace BeforeRouter filter -func NSBefore(filiterList ...FilterFunc) LinkNamespace { +func NSBefore(filterList ...FilterFunc) LinkNamespace { return func(ns *Namespace) { - ns.Filter("before", filiterList...) + ns.Filter("before", filterList...) } } // NSAfter add Namespace FinishRouter filter -func NSAfter(filiterList ...FilterFunc) LinkNamespace { +func NSAfter(filterList ...FilterFunc) LinkNamespace { return func(ns *Namespace) { - ns.Filter("after", filiterList...) + ns.Filter("after", filterList...) } } diff --git a/router.go b/router.go index 9f573f26..c6ec8af6 100644 --- a/router.go +++ b/router.go @@ -109,7 +109,8 @@ func ExceptMethodAppend(action string) { exceptMethod = append(exceptMethod, action) } -type controllerInfo struct { +// ControllerInfo holds information about the controller. +type ControllerInfo struct { pattern string controllerType reflect.Type methods map[string]string @@ -176,7 +177,7 @@ func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingM } } - route := &controllerInfo{} + route := &ControllerInfo{} route.pattern = pattern route.methods = methods route.routerType = routerTypeBeego @@ -198,7 +199,7 @@ func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingM } } -func (p *ControllerRegister) addToRouter(method, pattern string, r *controllerInfo) { +func (p *ControllerRegister) addToRouter(method, pattern string, r *ControllerInfo) { if !BConfig.RouterCaseSensitive { pattern = strings.ToLower(pattern) } @@ -335,7 +336,7 @@ func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) { if _, ok := HTTPMETHOD[method]; method != "*" && !ok { panic("not support http method: " + method) } - route := &controllerInfo{} + route := &ControllerInfo{} route.pattern = pattern route.routerType = routerTypeRESTFul route.runFunction = f @@ -361,7 +362,7 @@ func (p *ControllerRegister) AddMethod(method, pattern string, f FilterFunc) { // Handler add user defined Handler func (p *ControllerRegister) Handler(pattern string, h http.Handler, options ...interface{}) { - route := &controllerInfo{} + route := &ControllerInfo{} route.pattern = pattern route.routerType = routerTypeHandler route.handler = h @@ -396,7 +397,7 @@ func (p *ControllerRegister) AddAutoPrefix(prefix string, c ControllerInterface) controllerName := strings.TrimSuffix(ct.Name(), "Controller") for i := 0; i < rt.NumMethod(); i++ { if !utils.InSlice(rt.Method(i).Name, exceptMethod) { - route := &controllerInfo{} + route := &ControllerInfo{} route.routerType = routerTypeBeego route.methods = map[string]string{"*": rt.Method(i).Name} route.controllerType = ct @@ -502,7 +503,7 @@ func (p *ControllerRegister) geturl(t *Tree, url, controllName, methodName strin } } for _, l := range t.leaves { - if c, ok := l.runObject.(*controllerInfo); ok { + if c, ok := l.runObject.(*ControllerInfo); ok { if c.routerType == routerTypeBeego && strings.HasSuffix(path.Join(c.controllerType.PkgPath(), c.controllerType.Name()), controllName) { find := false @@ -629,7 +630,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) runRouter reflect.Type findRouter bool runMethod string - routerInfo *controllerInfo + routerInfo *ControllerInfo isRunnable bool ) context := p.pool.Get().(*beecontext.Context) @@ -670,7 +671,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) goto Admin } - if r.Method != "GET" && r.Method != "HEAD" { + if r.Method != http.MethodGet && r.Method != http.MethodHead { if BConfig.CopyRequestBody && !context.Input.IsUpload() { context.Input.CopyBody(BConfig.MaxMemory) } @@ -743,11 +744,11 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } else { runRouter = routerInfo.controllerType method := r.Method - if r.Method == "POST" && context.Input.Query("_method") == "PUT" { - method = "PUT" + if r.Method == http.MethodPost && context.Input.Query("_method") == http.MethodPost { + method = http.MethodPut } - if r.Method == "POST" && context.Input.Query("_method") == "DELETE" { - method = "DELETE" + if r.Method == http.MethodPost && context.Input.Query("_method") == http.MethodDelete { + method = http.MethodDelete } if m, ok := routerInfo.methods[method]; ok { runMethod = m @@ -777,8 +778,8 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) //if XSRF is Enable then check cookie where there has any cookie in the request's cookie _csrf if BConfig.WebConfig.EnableXSRF { execController.XSRFToken() - if r.Method == "POST" || r.Method == "DELETE" || r.Method == "PUT" || - (r.Method == "POST" && (context.Input.Query("_method") == "DELETE" || context.Input.Query("_method") == "PUT")) { + if r.Method == http.MethodPost || r.Method == http.MethodDelete || r.Method == http.MethodPut || + (r.Method == http.MethodPost && (context.Input.Query("_method") == http.MethodDelete || context.Input.Query("_method") == http.MethodPut)) { execController.CheckXSRFCookie() } } @@ -788,19 +789,19 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) if !context.ResponseWriter.Started { //exec main logic switch runMethod { - case "GET": + case http.MethodGet: execController.Get() - case "POST": + case http.MethodPost: execController.Post() - case "DELETE": + case http.MethodDelete: execController.Delete() - case "PUT": + case http.MethodPut: execController.Put() - case "HEAD": + case http.MethodHead: execController.Head() - case "PATCH": + case http.MethodPatch: execController.Patch() - case "OPTIONS": + case http.MethodOptions: execController.Options() default: if !execController.HandlerFunc(runMethod) { @@ -887,7 +888,7 @@ Admin: } // FindRouter Find Router info for URL -func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *controllerInfo, isFind bool) { +func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo *ControllerInfo, isFind bool) { var urlPath = context.Input.URL() if !BConfig.RouterCaseSensitive { urlPath = strings.ToLower(urlPath) @@ -895,7 +896,7 @@ func (p *ControllerRegister) FindRouter(context *beecontext.Context) (routerInfo httpMethod := context.Input.Method() if t, ok := p.routers[httpMethod]; ok { runObject := t.Match(urlPath, context) - if r, ok := runObject.(*controllerInfo); ok { + if r, ok := runObject.(*ControllerInfo); ok { return r, true } } diff --git a/router_test.go b/router_test.go index 25804d67..720b4ca8 100644 --- a/router_test.go +++ b/router_test.go @@ -654,32 +654,40 @@ func TestFilterFinishRouterMulti(t *testing.T) { } func beegoFilterNoOutput(ctx *context.Context) { - return } + func beegoBeforeRouter1(ctx *context.Context) { ctx.WriteString("|BeforeRouter1") } + func beegoBeforeRouter2(ctx *context.Context) { ctx.WriteString("|BeforeRouter2") } + func beegoBeforeExec1(ctx *context.Context) { ctx.WriteString("|BeforeExec1") } + func beegoBeforeExec2(ctx *context.Context) { ctx.WriteString("|BeforeExec2") } + func beegoAfterExec1(ctx *context.Context) { ctx.WriteString("|AfterExec1") } + func beegoAfterExec2(ctx *context.Context) { ctx.WriteString("|AfterExec2") } + func beegoFinishRouter1(ctx *context.Context) { ctx.WriteString("|FinishRouter1") } + func beegoFinishRouter2(ctx *context.Context) { ctx.WriteString("|FinishRouter2") } + func beegoResetParams(ctx *context.Context) { ctx.ResponseWriter.Header().Set("splat", ctx.Input.Param(":splat")) } diff --git a/session/couchbase/sess_couchbase.go b/session/couchbase/sess_couchbase.go index d5be11d0..791a6cc7 100644 --- a/session/couchbase/sess_couchbase.go +++ b/session/couchbase/sess_couchbase.go @@ -155,10 +155,13 @@ func (cp *Provider) SessionInit(maxlifetime int64, savePath string) error { func (cp *Provider) SessionRead(sid string) (session.Store, error) { cp.b = cp.getBucket() - var doc []byte + var ( + kv map[interface{}]interface{} + err error + doc []byte + ) - err := cp.b.Get(sid, &doc) - var kv map[interface{}]interface{} + err = cp.b.Get(sid, &doc) if doc == nil { kv = make(map[interface{}]interface{}) } else { @@ -230,7 +233,6 @@ func (cp *Provider) SessionDestroy(sid string) error { // SessionGC Recycle func (cp *Provider) SessionGC() { - return } // SessionAll return all active session diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 4892a8ab..18b27708 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -12,8 +12,10 @@ import ( "github.com/siddontang/ledisdb/ledis" ) -var ledispder = &Provider{} -var c *ledis.DB +var ( + ledispder = &Provider{} + c *ledis.DB +) // SessionStore ledis session store type SessionStore struct { @@ -97,27 +99,36 @@ func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error { } cfg := new(config.Config) cfg.DataDir = lp.savePath - nowLedis, err := ledis.Open(cfg) - c, err = nowLedis.Select(lp.db) + + var ledisInstance *ledis.Ledis + ledisInstance, err = ledis.Open(cfg) if err != nil { - println(err) - return nil + return err } - return nil + c, err = ledisInstance.Select(lp.db) + return err } // SessionRead read ledis session by sid func (lp *Provider) SessionRead(sid string) (session.Store, error) { - kvs, err := c.Get([]byte(sid)) - var kv map[interface{}]interface{} + var ( + kv map[interface{}]interface{} + kvs []byte + err error + ) + + if kvs, err = c.Get([]byte(sid)); err != nil { + return nil, err + } + if len(kvs) == 0 { kv = make(map[interface{}]interface{}) } else { - kv, err = session.DecodeGob(kvs) - if err != nil { + if kv, err = session.DecodeGob(kvs); err != nil { return nil, err } } + ls := &SessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime} return ls, nil } @@ -142,18 +153,7 @@ func (lp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) c.Set([]byte(sid), data) c.Expire([]byte(sid), lp.maxlifetime) } - kvs, err := c.Get([]byte(sid)) - var kv map[interface{}]interface{} - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob(kvs) - if err != nil { - return nil, err - } - } - ls := &SessionStore{sid: sid, values: kv, maxlifetime: lp.maxlifetime} - return ls, nil + return lp.SessionRead(sid) } // SessionDestroy delete ledis session by id @@ -164,7 +164,6 @@ func (lp *Provider) SessionDestroy(sid string) error { // SessionGC Impelment method, no used. func (lp *Provider) SessionGC() { - return } // SessionAll return all active session diff --git a/session/memcache/sess_memcache.go b/session/memcache/sess_memcache.go index cad02258..755979c4 100644 --- a/session/memcache/sess_memcache.go +++ b/session/memcache/sess_memcache.go @@ -215,7 +215,6 @@ func (rp *MemProvider) connectInit() error { // SessionGC Impelment method, no used. func (rp *MemProvider) SessionGC() { - return } // SessionAll return all activeSession diff --git a/session/mysql/sess_mysql.go b/session/mysql/sess_mysql.go index 7bcf959c..4c9251e7 100644 --- a/session/mysql/sess_mysql.go +++ b/session/mysql/sess_mysql.go @@ -209,7 +209,6 @@ func (mp *Provider) SessionGC() { c := mp.connectInit() c.Exec("DELETE from "+TableName+" where session_expiry < ?", time.Now().Unix()-mp.maxlifetime) c.Close() - return } // SessionAll count values in mysql session diff --git a/session/postgres/sess_postgresql.go b/session/postgres/sess_postgresql.go index f00e0711..ffc27def 100644 --- a/session/postgres/sess_postgresql.go +++ b/session/postgres/sess_postgresql.go @@ -224,7 +224,6 @@ func (mp *Provider) SessionGC() { c := mp.connectInit() c.Exec("DELETE from session where EXTRACT(EPOCH FROM (current_timestamp - session_expiry)) > $1", mp.maxlifetime) c.Close() - return } // SessionAll count values in postgresql session diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 14bbd4c1..08efa6e1 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -155,7 +155,7 @@ func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { return nil, err } if rp.password != "" { - if _, err := c.Do("AUTH", rp.password); err != nil { + if _, err = c.Do("AUTH", rp.password); err != nil { c.Close() return nil, err } @@ -176,13 +176,20 @@ func (rp *Provider) SessionRead(sid string) (session.Store, error) { c := rp.poollist.Get() defer c.Close() - kvs, err := redis.String(c.Do("GET", sid)) - var kv map[interface{}]interface{} + var ( + kv map[interface{}]interface{} + kvs string + err error + ) + + if kvs, err = redis.String(c.Do("GET", sid)); err != nil { + return nil, err + } + if len(kvs) == 0 { kv = make(map[interface{}]interface{}) } else { - kv, err = session.DecodeGob([]byte(kvs)) - if err != nil { + if kv, err = session.DecodeGob([]byte(kvs)); err != nil { return nil, err } } @@ -216,20 +223,7 @@ func (rp *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) c.Do("RENAME", oldsid, sid) c.Do("EXPIRE", sid, rp.maxlifetime) } - - kvs, err := redis.String(c.Do("GET", sid)) - var kv map[interface{}]interface{} - if len(kvs) == 0 { - kv = make(map[interface{}]interface{}) - } else { - kv, err = session.DecodeGob([]byte(kvs)) - if err != nil { - return nil, err - } - } - - rs := &SessionStore{p: rp.poollist, sid: sid, values: kv, maxlifetime: rp.maxlifetime} - return rs, nil + return rp.SessionRead(sid) } // SessionDestroy delete redis session by id @@ -243,7 +237,6 @@ func (rp *Provider) SessionDestroy(sid string) error { // SessionGC Impelment method, no used. func (rp *Provider) SessionGC() { - return } // SessionAll return all activeSession diff --git a/session/sess_cookie.go b/session/sess_cookie.go index 3fefa360..145e53c9 100644 --- a/session/sess_cookie.go +++ b/session/sess_cookie.go @@ -74,21 +74,16 @@ func (st *CookieSessionStore) SessionID() string { // SessionRelease Write cookie session to http response cookie func (st *CookieSessionStore) SessionRelease(w http.ResponseWriter) { - str, err := encodeCookie(cookiepder.block, - cookiepder.config.SecurityKey, - cookiepder.config.SecurityName, - st.values) - if err != nil { - return + encodedCookie, err := encodeCookie(cookiepder.block, cookiepder.config.SecurityKey, cookiepder.config.SecurityName, st.values) + if err == nil { + cookie := &http.Cookie{Name: cookiepder.config.CookieName, + Value: url.QueryEscape(encodedCookie), + Path: "/", + HttpOnly: true, + Secure: cookiepder.config.Secure, + MaxAge: cookiepder.config.Maxage} + http.SetCookie(w, cookie) } - cookie := &http.Cookie{Name: cookiepder.config.CookieName, - Value: url.QueryEscape(str), - Path: "/", - HttpOnly: true, - Secure: cookiepder.config.Secure, - MaxAge: cookiepder.config.Maxage} - http.SetCookie(w, cookie) - return } type cookieConfig struct { @@ -166,7 +161,6 @@ func (pder *CookieProvider) SessionDestroy(sid string) error { // SessionGC Implement method, no used. func (pder *CookieProvider) SessionGC() { - return } // SessionAll Implement method, return 0. diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index c846e73a..03b60793 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -30,13 +30,13 @@ func (p *SsdbProvider) connectInit() error { } func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { - var e error = nil p.maxLifetime = maxLifetime address := strings.Split(savePath, ":") p.host = address[0] - p.port, e = strconv.Atoi(address[1]) - if e != nil { - return e + + var err error + if p.port, err = strconv.Atoi(address[1]); err != nil { + return err } return p.connectInit() } @@ -78,8 +78,8 @@ func (p *SsdbProvider) SessionExist(sid string) bool { return false } return true - } + func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { //conn.Do("setx", key, v, ttl) if p.client == nil { @@ -123,7 +123,6 @@ func (p *SsdbProvider) SessionDestroy(sid string) error { } func (p *SsdbProvider) SessionGC() { - return } func (p *SsdbProvider) SessionAll() int { diff --git a/staticfile.go b/staticfile.go index 7c270947..bbb2a1fb 100644 --- a/staticfile.go +++ b/staticfile.go @@ -90,8 +90,6 @@ func serverStaticRouter(ctx *context.Context) { } http.ServeContent(ctx.ResponseWriter, ctx.Request, filePath, sch.modTime, sch) - return - } type serveContentHolder struct { From 19f4a6ac0b51cc685fc966b7e8ca12fd89e5bc43 Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Sun, 23 Apr 2017 21:37:09 +0300 Subject: [PATCH 34/82] slice support --- param/conv.go | 68 ++++++++++++++++++++++++++++++++++++++++ param/methodparams.go | 72 +++---------------------------------------- param/parsers.go | 29 ++++++++++++++++- router.go | 2 +- 4 files changed, 102 insertions(+), 69 deletions(-) create mode 100644 param/conv.go diff --git a/param/conv.go b/param/conv.go new file mode 100644 index 00000000..e909c4ea --- /dev/null +++ b/param/conv.go @@ -0,0 +1,68 @@ +package param + +import ( + "fmt" + "reflect" + + beecontext "github.com/astaxie/beego/context" + "github.com/astaxie/beego/logs" +) + +func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { + var strValue string + var reflectValue reflect.Value + switch param.location { + case body: + strValue = string(ctx.Input.RequestBody) + case header: + strValue = ctx.Input.Header(param.name) + default: + strValue = ctx.Input.Query(param.name) + } + + if strValue == "" { + if param.required { + ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) + } else { + strValue = param.defValue + } + } + if strValue == "" { + reflectValue = reflect.Zero(paramType) + } else { + value, err := param.parser.parse(strValue, paramType) + if err != nil { + logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %s, Error: %s", param.name, paramType, strValue, err)) + ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %s to type %s", param.name, strValue, paramType)) + } + + reflectValue, err = safeConvert(reflect.ValueOf(value), paramType) + if err != nil { + panic(err) + } + } + return reflectValue +} + +func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { + result = make([]reflect.Value, 0, len(methodParams)) + for i := 0; i < len(methodParams); i++ { + reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) + result = append(result, reflectValue) + } + return +} + +func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { + defer func() { + if r := recover(); r != nil { + var ok bool + err, ok = r.(error) + if !ok { + err = fmt.Errorf("%v", r) + } + } + }() + result = value.Convert(t) + return +} diff --git a/param/methodparams.go b/param/methodparams.go index 9cd2b1d6..a3e25a55 100644 --- a/param/methodparams.go +++ b/param/methodparams.go @@ -1,13 +1,5 @@ package param -import ( - "fmt" - "reflect" - - beecontext "github.com/astaxie/beego/context" - "github.com/astaxie/beego/logs" -) - //Keeps param information to be auto passed to controller methods type MethodParam struct { name string @@ -51,6 +43,11 @@ func Json(name string, opts ...MethodParamOption) *MethodParam { return newParam(name, jsonParser{}, opts) } +func AsSlice(param *MethodParam) *MethodParam { + param.parser = sliceParser(param.parser) + return param +} + func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { param = &MethodParam{name: name, parser: parser} for _, option := range opts { @@ -58,62 +55,3 @@ func newParam(name string, parser paramParser, opts []MethodParamOption) (param } return } - -func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { - var strValue string - var reflectValue reflect.Value - switch param.location { - case body: - strValue = string(ctx.Input.RequestBody) - case header: - strValue = ctx.Input.Header(param.name) - default: - strValue = ctx.Input.Query(param.name) - } - - if strValue == "" { - if param.required { - ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) - } else { - strValue = param.defValue - } - } - if strValue == "" { - reflectValue = reflect.Zero(paramType) - } else { - value, err := param.parser.parse(strValue, paramType) - if err != nil { - logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %s, Parser: %s, Error: %s", param.name, paramType.Name(), strValue, reflect.TypeOf(param.parser).Name(), err)) - ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %s to type %s", param.name, strValue, paramType.Name())) - } - - reflectValue, err = safeConvert(reflect.ValueOf(value), paramType) - if err != nil { - panic(err) - } - } - return reflectValue -} - -func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { - result = make([]reflect.Value, 0, len(methodParams)) - for i := 0; i < len(methodParams); i++ { - reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) - result = append(result, reflectValue) - } - return -} - -func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { - defer func() { - if r := recover(); r != nil { - var ok bool - err, ok = r.(error) - if !ok { - err = fmt.Errorf("%v", r) - } - } - }() - result = value.Convert(t) - return -} diff --git a/param/parsers.go b/param/parsers.go index e3032e20..cfa1a981 100644 --- a/param/parsers.go +++ b/param/parsers.go @@ -4,6 +4,7 @@ import ( "encoding/json" "reflect" "strconv" + "strings" "time" ) @@ -11,6 +12,12 @@ type paramParser interface { parse(value string, toType reflect.Type) (interface{}, error) } +type parserFunc func(value string, toType reflect.Type) (interface{}, error) + +func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) { + return f(value, toType) +} + type boolParser struct { } @@ -37,7 +44,11 @@ type floatParser struct { func (p floatParser) parse(value string, toType reflect.Type) (interface{}, error) { if toType.Kind() == reflect.Float32 { - return strconv.ParseFloat(value, 32) + res, err := strconv.ParseFloat(value, 32) + if err != nil { + return nil, err + } + return float32(res), nil } return strconv.ParseFloat(value, 64) } @@ -65,3 +76,19 @@ func (p jsonParser) parse(value string, toType reflect.Type) (interface{}, error } return pResult.Elem().Interface(), nil } + +func sliceParser(elemParser paramParser) paramParser { + return parserFunc(func(value string, toType reflect.Type) (interface{}, error) { + values := strings.Split(value, ",") + result := reflect.MakeSlice(toType, 0, len(values)) + elemType := toType.Elem() + for _, v := range values { + parsedValue, err := elemParser.parse(v, elemType) + if err != nil { + return nil, err + } + result = reflect.Append(result, reflect.ValueOf(parsedValue)) + } + return result.Interface(), nil + }) +} diff --git a/router.go b/router.go index 4937354a..be69419c 100644 --- a/router.go +++ b/router.go @@ -905,7 +905,7 @@ func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, ex //looping in reverse order for the case when both error and value are returned and error sets the response status code for i := len(results) - 1; i >= 0; i-- { result := results[i] - if !result.IsNil() { + if result.Kind() != reflect.Interface || !result.IsNil() { resultValue := result.Interface() response.RenderMethodResult(resultValue, context) } From 864693d2f840374460950e3f393ee48e5b8e868f Mon Sep 17 00:00:00 2001 From: eyalpost Date: Mon, 24 Apr 2017 02:35:04 +0300 Subject: [PATCH 35/82] mall fixes --- cache/conv.go | 2 +- param/options.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cache/conv.go b/cache/conv.go index dbdff1c7..87800586 100644 --- a/cache/conv.go +++ b/cache/conv.go @@ -28,7 +28,7 @@ func GetString(v interface{}) string { return string(result) default: if v != nil { - return fmt.Sprintf("%v", result) + return fmt.Sprint(result) } } return "" diff --git a/param/options.go b/param/options.go index 6fe10108..0692f9d1 100644 --- a/param/options.go +++ b/param/options.go @@ -19,7 +19,7 @@ var InBody MethodParamOption = func(p *MethodParam) { func Default(defValue interface{}) MethodParamOption { return func(p *MethodParam) { if defValue != nil { - p.defValue = fmt.Sprintf("%v", defValue) + p.defValue = fmt.Sprint(defValue) } } } From 52f916a28a8b73e81606ac2b6142e113f64e1e8d Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 24 Apr 2017 21:10:03 +0800 Subject: [PATCH 36/82] support Go1.8 default GOPATH --- router.go | 7 ++----- utils/utils.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 utils/utils.go diff --git a/router.go b/router.go index 9f573f26..55a6553f 100644 --- a/router.go +++ b/router.go @@ -17,7 +17,6 @@ package beego import ( "fmt" "net/http" - "os" "path" "path/filepath" "reflect" @@ -219,13 +218,11 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) { for _, c := range cList { reflectVal := reflect.ValueOf(c) t := reflect.Indirect(reflectVal).Type() - gopath := os.Getenv("GOPATH") - if gopath == "" { + wgopath := utils.GetGOPATHs() + if len(wgopath) == 0 { panic("you are in dev mode. So please set gopath") } pkgpath := "" - - wgopath := filepath.SplitList(gopath) for _, wg := range wgopath { wg, _ = filepath.EvalSymlinks(filepath.Join(wg, "src", t.PkgPath())) if utils.FileExists(wg) { diff --git a/utils/utils.go b/utils/utils.go new file mode 100644 index 00000000..ed885787 --- /dev/null +++ b/utils/utils.go @@ -0,0 +1,30 @@ +package utils + +import ( + "os" + "path/filepath" + "runtime" + "strings" +) + +// GetGOPATHs returns all paths in GOPATH variable. +func GetGOPATHs() []string { + gopath := os.Getenv("GOPATH") + if gopath == "" && strings.Compare(runtime.Version(), "go1.8") >= 0 { + gopath = defaultGOPATH() + } + return filepath.SplitList(gopath) +} + +func defaultGOPATH() string { + env := "HOME" + if runtime.GOOS == "windows" { + env = "USERPROFILE" + } else if runtime.GOOS == "plan9" { + env = "home" + } + if home := os.Getenv(env); home != "" { + return filepath.Join(home, "go") + } + return "" +} From e810f2e93070919cb9afe287f0091d905408e4d6 Mon Sep 17 00:00:00 2001 From: astaxie Date: Mon, 24 Apr 2017 21:36:07 +0800 Subject: [PATCH 37/82] add more oracle alias --- orm/db_alias.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/orm/db_alias.go b/orm/db_alias.go index 8daa4b23..e70db9f0 100644 --- a/orm/db_alias.go +++ b/orm/db_alias.go @@ -60,6 +60,8 @@ var ( "sqlite3": DRSqlite, "tidb": DRTiDB, "oracle": DROracle, + "oci8": DROracle, // github.com/mattn/go-oci8 + "ora": DROracle, //https://github.com/rana/ora } dbBasers = map[DriverType]dbBaser{ DRMySQL: newdbBaseMysql(), From 3742d1178ca9b2c429ed8fe91360002a941d4b89 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 25 Apr 2017 20:42:43 +0800 Subject: [PATCH 38/82] httplib support delete params fix #2593 --- httplib/httplib.go | 2 +- httplib/httplib_test.go | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/httplib/httplib.go b/httplib/httplib.go index 32edc5c4..f232f31b 100644 --- a/httplib/httplib.go +++ b/httplib/httplib.go @@ -344,7 +344,7 @@ func (b *BeegoHTTPRequest) buildURL(paramBody string) { } // build POST/PUT/PATCH url and body - if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH") && b.req.Body == nil { + if (b.req.Method == "POST" || b.req.Method == "PUT" || b.req.Method == "PATCH" || b.req.Method == "DELETE") && b.req.Body == nil { // with files if len(b.files) > 0 { pr, pw := io.Pipe() diff --git a/httplib/httplib_test.go b/httplib/httplib_test.go index 05815054..32d3e7f6 100644 --- a/httplib/httplib_test.go +++ b/httplib/httplib_test.go @@ -102,6 +102,14 @@ func TestSimpleDelete(t *testing.T) { t.Log(str) } +func TestSimpleDeleteParam(t *testing.T) { + str, err := Delete("http://httpbin.org/delete").Param("key", "val").String() + if err != nil { + t.Fatal(err) + } + t.Log(str) +} + func TestWithCookie(t *testing.T) { v := "smallfish" str, err := Get("http://httpbin.org/cookies/set?k1=" + v).SetEnableCookie(true).String() From 9b79437778cf2b78f00d71c963cfc4732a01b39e Mon Sep 17 00:00:00 2001 From: eyalpost Date: Tue, 25 Apr 2017 16:00:49 +0300 Subject: [PATCH 39/82] all types working + controller comments generation --- param/conv.go | 58 +++++++----- param/methodparams.go | 72 ++++++++------- param/options.go | 6 ++ param/parsers.go | 57 ++++++++++++ parser.go | 209 +++++++++++++++++++++++++++++++++++------- router.go | 3 + 6 files changed, 317 insertions(+), 88 deletions(-) diff --git a/param/conv.go b/param/conv.go index e909c4ea..4938f45f 100644 --- a/param/conv.go +++ b/param/conv.go @@ -9,39 +9,51 @@ import ( ) func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { - var strValue string - var reflectValue reflect.Value - switch param.location { - case body: - strValue = string(ctx.Input.RequestBody) - case header: - strValue = ctx.Input.Header(param.name) - default: - strValue = ctx.Input.Query(param.name) - } - - if strValue == "" { + paramValue := getParamValue(param, ctx) + if paramValue == "" { if param.required { ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) } else { - strValue = param.defValue + paramValue = param.defValue } } - if strValue == "" { - reflectValue = reflect.Zero(paramType) + + reflectValue, err := parseValue(paramValue, paramType) + if err != nil { + logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err)) + ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType)) + } + + return reflectValue +} + +func getParamValue(param *MethodParam, ctx *beecontext.Context) string { + switch param.location { + case body: + return string(ctx.Input.RequestBody) + case header: + return ctx.Input.Header(param.name) + // if strValue == "" && strings.Contains(param.name, "_") { //magically handle X-Headers? + // strValue = ctx.Input.Header(strings.Replace(param.name, "_", "-", -1)) + // } + case path: + return ctx.Input.Query(":" + param.name) + default: + return ctx.Input.Query(param.name) + } +} + +func parseValue(paramValue string, paramType reflect.Type) (result reflect.Value, err error) { + if paramValue == "" { + return reflect.Zero(paramType), nil } else { - value, err := param.parser.parse(strValue, paramType) + value, err := parse(paramValue, paramType) if err != nil { - logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %s, Error: %s", param.name, paramType, strValue, err)) - ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %s to type %s", param.name, strValue, paramType)) + return result, err } - reflectValue, err = safeConvert(reflect.ValueOf(value), paramType) - if err != nil { - panic(err) - } + return safeConvert(reflect.ValueOf(value), paramType) } - return reflectValue } func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { diff --git a/param/methodparams.go b/param/methodparams.go index a3e25a55..23fd6661 100644 --- a/param/methodparams.go +++ b/param/methodparams.go @@ -1,9 +1,13 @@ package param +import ( + "fmt" + "strings" +) + //Keeps param information to be auto passed to controller methods type MethodParam struct { name string - parser paramParser location paramLocation required bool defValue string @@ -13,45 +17,51 @@ type paramLocation byte const ( param paramLocation = iota + path body header ) -type MethodParamOption func(*MethodParam) - -func Bool(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, boolParser{}, opts) -} - -func String(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, stringParser{}, opts) -} - -func Int(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, intParser{}, opts) -} - -func Float(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, floatParser{}, opts) -} - -func Time(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, timeParser{}, opts) -} - -func Json(name string, opts ...MethodParamOption) *MethodParam { - return newParam(name, jsonParser{}, opts) -} - -func AsSlice(param *MethodParam) *MethodParam { - param.parser = sliceParser(param.parser) - return param +func New(name string, opts ...MethodParamOption) *MethodParam { + return newParam(name, nil, opts) } func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) { - param = &MethodParam{name: name, parser: parser} + param = &MethodParam{name: name} for _, option := range opts { option(param) } return } + +func Make(list ...*MethodParam) []*MethodParam { + if len(list) > 0 { + return list + } + return nil +} + +func (mp *MethodParam) String() string { + options := []string{} + result := "param.New(\"" + mp.name + "\"" + if mp.required { + options = append(options, "param.IsRequired") + } + switch mp.location { + case path: + options = append(options, "param.InPath") + case body: + options = append(options, "param.InBody") + case header: + options = append(options, "param.InHeader") + } + if mp.defValue != "" { + options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defValue)) + } + if len(options) > 0 { + result += ", " + } + result += strings.Join(options, ", ") + result += ")" + return result +} diff --git a/param/options.go b/param/options.go index 0692f9d1..0013c31e 100644 --- a/param/options.go +++ b/param/options.go @@ -4,6 +4,8 @@ import ( "fmt" ) +type MethodParamOption func(*MethodParam) + var IsRequired MethodParamOption = func(p *MethodParam) { p.required = true } @@ -12,6 +14,10 @@ var InHeader MethodParamOption = func(p *MethodParam) { p.location = header } +var InPath MethodParamOption = func(p *MethodParam) { + p.location = path +} + var InBody MethodParamOption = func(p *MethodParam) { p.location = body } diff --git a/param/parsers.go b/param/parsers.go index cfa1a981..64cabe49 100644 --- a/param/parsers.go +++ b/param/parsers.go @@ -12,6 +12,45 @@ type paramParser interface { parse(value string, toType reflect.Type) (interface{}, error) } +func parse(value string, t reflect.Type) (interface{}, error) { + parser := getParser(t) + return parser.parse(value, t) +} + +func getParser(t reflect.Type) paramParser { + switch t.Kind() { + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, + reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: + return intParser{} + case reflect.Slice: + if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string + return stringParser{} + } + elemParser := getParser(t.Elem()) + if elemParser == (jsonParser{}) { + return elemParser + } + return sliceParser(elemParser) + case reflect.Bool: + return boolParser{} + case reflect.String: + return stringParser{} + case reflect.Float32, reflect.Float64: + return floatParser{} + case reflect.Ptr: + elemParser := getParser(t.Elem()) + if elemParser == (jsonParser{}) { + return elemParser + } + return ptrParser(elemParser) + default: + if t.PkgPath() == "time" && t.Name() == "Time" { + return timeParser{} + } + return jsonParser{} + } +} + type parserFunc func(value string, toType reflect.Type) (interface{}, error) func (f parserFunc) parse(value string, toType reflect.Type) (interface{}, error) { @@ -92,3 +131,21 @@ func sliceParser(elemParser paramParser) paramParser { return result.Interface(), nil }) } + +func ptrParser(elemParser paramParser) paramParser { + return parserFunc(func(value string, toType reflect.Type) (interface{}, error) { + parsedValue, err := elemParser.parse(value, toType.Elem()) + if err != nil { + return nil, err + } + newValPtr := reflect.New(toType.Elem()) + newVal := reflect.Indirect(newValPtr) + convertedVal, err := safeConvert(reflect.ValueOf(parsedValue), toType.Elem()) + if err != nil { + return nil, err + } + + newVal.Set(convertedVal) + return newValPtr.Interface(), nil + }) +} diff --git a/parser.go b/parser.go index d40ee3ce..43e052bd 100644 --- a/parser.go +++ b/parser.go @@ -24,10 +24,14 @@ import ( "io/ioutil" "os" "path/filepath" + "regexp" "sort" + "strconv" "strings" + "unicode" "github.com/astaxie/beego/logs" + "github.com/astaxie/beego/param" "github.com/astaxie/beego/utils" ) @@ -35,6 +39,7 @@ var globalRouterTemplate = `package routers import ( "github.com/astaxie/beego" + "github.com/astaxie/beego/param" ) func init() { @@ -81,7 +86,7 @@ func parserPkg(pkgRealpath, pkgpath string) error { if specDecl.Recv != nil { exp, ok := specDecl.Recv.List[0].Type.(*ast.StarExpr) // Check that the type is correct first beforing throwing to parser if ok { - parserComments(specDecl.Doc, specDecl.Name.String(), fmt.Sprint(exp.X), pkgpath) + parserComments(specDecl, fmt.Sprint(exp.X), pkgpath) } } } @@ -93,44 +98,168 @@ func parserPkg(pkgRealpath, pkgpath string) error { return nil } -func parserComments(comments *ast.CommentGroup, funcName, controllerName, pkgpath string) error { - if comments != nil && comments.List != nil { - for _, c := range comments.List { - t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) - if strings.HasPrefix(t, "@router") { - elements := strings.TrimLeft(t, "@router ") - e1 := strings.SplitN(elements, " ", 2) - if len(e1) < 1 { - return errors.New("you should has router information") - } - key := pkgpath + ":" + controllerName - cc := ControllerComments{} - cc.Method = funcName - cc.Router = e1[0] - if len(e1) == 2 && e1[1] != "" { - e1 = strings.SplitN(e1[1], " ", 2) - if len(e1) >= 1 { - cc.AllowHTTPMethods = strings.Split(strings.Trim(e1[0], "[]"), ",") - } else { - cc.AllowHTTPMethods = append(cc.AllowHTTPMethods, "get") - } - } else { - cc.AllowHTTPMethods = append(cc.AllowHTTPMethods, "get") - } - if len(e1) == 2 && e1[1] != "" { - keyval := strings.Split(strings.Trim(e1[1], "[]"), " ") - for _, kv := range keyval { - kk := strings.Split(kv, ":") - cc.Params = append(cc.Params, map[string]string{strings.Join(kk[:len(kk)-1], ":"): kk[len(kk)-1]}) - } - } - genInfoList[key] = append(genInfoList[key], cc) - } +type parsedComment struct { + routerPath string + methods []string + params map[string]parsedParam +} + +type parsedParam struct { + name string + datatype string + location string + defValue string + required bool +} + +func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error { + if f.Doc != nil { + parsedComment, err := parseComment(f.Doc.List) + if err != nil { + return err } + key := pkgpath + ":" + controllerName + cc := ControllerComments{} + cc.Method = f.Name.String() + cc.Router = parsedComment.routerPath + cc.AllowHTTPMethods = parsedComment.methods + cc.MethodParams = buildMethodParams(f.Type.Params.List, parsedComment) + genInfoList[key] = append(genInfoList[key], cc) + } return nil } +func buildMethodParams(funcParams []*ast.Field, pc *parsedComment) []*param.MethodParam { + result := make([]*param.MethodParam, 0, len(funcParams)) + for _, fparam := range funcParams { + methodParam := buildMethodParam(fparam, pc) + result = append(result, methodParam) + } + return result +} + +func buildMethodParam(fparam *ast.Field, pc *parsedComment) *param.MethodParam { + options := []param.MethodParamOption{} + name := fparam.Names[0].Name + if cparam, ok := pc.params[name]; ok { + //Build param from comment info + name = cparam.name + if cparam.required { + options = append(options, param.IsRequired) + } + switch cparam.location { + case "body": + options = append(options, param.InBody) + case "header": + options = append(options, param.InHeader) + case "path": + options = append(options, param.InPath) + } + if cparam.defValue != "" { + options = append(options, param.Default(cparam.defValue)) + } + } else { + if paramInPath(name, pc.routerPath) { + options = append(options, param.InPath) + } + } + return param.New(name, options...) +} + +func paramInPath(name, route string) bool { + return strings.HasSuffix(route, ":"+name) || + strings.Contains(route, ":"+name+"/") +} + +var routeRegex = regexp.MustCompile(`@router\s+(\S+)(?:\s+\[(\S+)\])?`) + +func parseComment(lines []*ast.Comment) (pc *parsedComment, err error) { + pc = &parsedComment{} + for _, c := range lines { + t := strings.TrimSpace(strings.TrimLeft(c.Text, "//")) + if strings.HasPrefix(t, "@router") { + matches := routeRegex.FindStringSubmatch(t) + if len(matches) == 3 { + pc.routerPath = matches[1] + methods := matches[2] + if methods == "" { + pc.methods = []string{"get"} + //pc.hasGet = true + } else { + pc.methods = strings.Split(methods, ",") + //pc.hasGet = strings.Contains(methods, "get") + } + } else { + return nil, errors.New("Router information is missing") + } + } else if strings.HasPrefix(t, "@Param") { + pv := getparams(strings.TrimSpace(strings.TrimLeft(t, "@Param"))) + if len(pv) < 4 { + logs.Error("Invalid @Param format. Needs at least 4 parameters") + } + p := parsedParam{} + names := strings.Split(pv[0], "=") + funcParamName := names[0] + if len(names) > 1 { + p.name = names[1] + } else { + p.name = funcParamName + } + p.location = pv[1] + p.datatype = pv[2] + switch len(pv) { + case 5: + p.required, _ = strconv.ParseBool(pv[3]) + case 6: + p.defValue = pv[3] + p.required, _ = strconv.ParseBool(pv[4]) + } + if pc.params == nil { + pc.params = map[string]parsedParam{} + } + pc.params[funcParamName] = p + } + } + return +} + +// direct copy from bee\g_docs.go +// analisys params return []string +// @Param query form string true "The email for login" +// [query form string true "The email for login"] +func getparams(str string) []string { + var s []rune + var j int + var start bool + var r []string + var quoted int8 + for _, c := range []rune(str) { + if unicode.IsSpace(c) && quoted == 0 { + if !start { + continue + } else { + start = false + j++ + r = append(r, string(s)) + s = make([]rune, 0) + continue + } + } + + start = true + if c == '"' { + quoted ^= 1 + continue + } + s = append(s, c) + } + if len(s) > 0 { + r = append(r, string(s)) + } + return r +} + func genRouterCode(pkgRealpath string) { os.Mkdir(getRouterDir(pkgRealpath), 0755) logs.Info("generate router from comments") @@ -163,12 +292,24 @@ func genRouterCode(pkgRealpath string) { } params = strings.TrimRight(params, ",") + "}" } + methodParams := "param.Make(" + if len(c.MethodParams) > 0 { + lines := make([]string, 0, len(c.MethodParams)) + for _, m := range c.MethodParams { + lines = append(lines, fmt.Sprint(m)) + } + methodParams += "\n " + + strings.Join(lines, ",\n ") + + ",\n " + } + methodParams += ")" globalinfo = globalinfo + ` beego.GlobalControllerRouter["` + k + `"] = append(beego.GlobalControllerRouter["` + k + `"], beego.ControllerComments{ Method: "` + strings.TrimSpace(c.Method) + `", ` + "Router: `" + c.Router + "`" + `, AllowHTTPMethods: ` + allmethod + `, + MethodParams: ` + methodParams + `, Params: ` + params + `}) ` } diff --git a/router.go b/router.go index 57479248..546db22d 100644 --- a/router.go +++ b/router.go @@ -908,6 +908,9 @@ func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, ex response.RenderMethodResult(resultValue, context) } } + if !context.ResponseWriter.Started && context.Output.Status == 0 { + context.Output.SetStatus(200) + } } // FindRouter Find Router info for URL From 0f554d9b1a498580006ff6140fae2b5e0ab8e328 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 25 Apr 2017 22:21:08 +0800 Subject: [PATCH 40/82] update travis to latest go version --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4b19015..e3960c70 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: go go: - - 1.6 - - 1.7 - - 1.8 + - 1.6.4 + - 1.7.5 + - 1.8.1 services: - redis-server - mysql From cd67f13bf91666ac78363dfd9ed1c7e69ee6c9f8 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 25 Apr 2017 22:21:27 +0800 Subject: [PATCH 41/82] add template layout test #2481 --- template_test.go | 114 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/template_test.go b/template_test.go index 17690965..16967382 100644 --- a/template_test.go +++ b/template_test.go @@ -15,6 +15,7 @@ package beego import ( + "bytes" "os" "path/filepath" "testing" @@ -142,3 +143,116 @@ func TestRelativeTemplate(t *testing.T) { } os.RemoveAll(dir) } + +var add = `{{ template "layout_blog.tpl" . }} +{{ define "css" }} + +{{ end}} + + +{{ define "content" }} +

{{ .Title }}

+

This is SomeVar: {{ .SomeVar }}

+{{ end }} + +{{ define "js" }} + +{{ end}}` + +var layout_blog = ` + + + Lin Li + + + + + {{ block "css" . }}{{ end }} + + + +
+ {{ block "content" . }}{{ end }} +
+ + + {{ block "js" . }}{{ end }} + +` + +var output = ` + + + Lin Li + + + + + + + + + + +
+ +

Hello

+

This is SomeVar: val

+ +
+ + + + + + + + + + + + +` + +func TestTemplateLayout(t *testing.T) { + dir := "_beeTmp" + files := []string{ + "add.tpl", + "layout_blog.tpl", + } + if err := os.MkdirAll(dir, 0777); err != nil { + t.Fatal(err) + } + for k, name := range files { + os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0777) + if f, err := os.Create(filepath.Join(dir, name)); err != nil { + t.Fatal(err) + } else { + if k == 0 { + f.WriteString(add) + } else if k == 1 { + f.WriteString(layout_blog) + } + f.Close() + } + } + if err := AddViewPath(dir); err != nil { + t.Fatal(err) + } + beeTemplates := beeViewPathTemplates[dir] + if len(beeTemplates) != 2 { + t.Fatalf("should be 2 but got %v", len(beeTemplates)) + } + out := bytes.NewBufferString("") + if err := beeTemplates["add.tpl"].ExecuteTemplate(out, "add.tpl", map[string]string{"Title": "Hello", "SomeVar": "val"}); err != nil { + t.Fatal(err) + } + if out.String() != output { + t.Log(out.String()) + t.Fatal("Compare failed") + } + for _, name := range files { + os.RemoveAll(filepath.Join(dir, name)) + } + os.RemoveAll(dir) +} From cbd831042a34af663669a2fb4cce2f0ab78e7064 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Tue, 25 Apr 2017 18:39:42 +0300 Subject: [PATCH 42/82] move under context --- {param => context/param}/conv.go | 0 {param => context/param}/methodparams.go | 0 {param => context/param}/options.go | 0 {param => context/param}/parsers.go | 0 {response => context/response}/renderer.go | 0 {response => context/response}/responses.go | 0 controller.go | 2 +- parser.go | 4 ++-- router.go | 4 ++-- 9 files changed, 5 insertions(+), 5 deletions(-) rename {param => context/param}/conv.go (100%) rename {param => context/param}/methodparams.go (100%) rename {param => context/param}/options.go (100%) rename {param => context/param}/parsers.go (100%) rename {response => context/response}/renderer.go (100%) rename {response => context/response}/responses.go (100%) diff --git a/param/conv.go b/context/param/conv.go similarity index 100% rename from param/conv.go rename to context/param/conv.go diff --git a/param/methodparams.go b/context/param/methodparams.go similarity index 100% rename from param/methodparams.go rename to context/param/methodparams.go diff --git a/param/options.go b/context/param/options.go similarity index 100% rename from param/options.go rename to context/param/options.go diff --git a/param/parsers.go b/context/param/parsers.go similarity index 100% rename from param/parsers.go rename to context/param/parsers.go diff --git a/response/renderer.go b/context/response/renderer.go similarity index 100% rename from response/renderer.go rename to context/response/renderer.go diff --git a/response/responses.go b/context/response/responses.go similarity index 100% rename from response/responses.go rename to context/response/responses.go diff --git a/controller.go b/controller.go index 02e45738..510e16b8 100644 --- a/controller.go +++ b/controller.go @@ -28,7 +28,7 @@ import ( "strings" "github.com/astaxie/beego/context" - "github.com/astaxie/beego/param" + "github.com/astaxie/beego/context/param" "github.com/astaxie/beego/session" ) diff --git a/parser.go b/parser.go index 43e052bd..17d9a5d2 100644 --- a/parser.go +++ b/parser.go @@ -30,8 +30,8 @@ import ( "strings" "unicode" + "github.com/astaxie/beego/context/param" "github.com/astaxie/beego/logs" - "github.com/astaxie/beego/param" "github.com/astaxie/beego/utils" ) @@ -39,7 +39,7 @@ var globalRouterTemplate = `package routers import ( "github.com/astaxie/beego" - "github.com/astaxie/beego/param" + "github.com/astaxie/beego/context/param" ) func init() { diff --git a/router.go b/router.go index 546db22d..ebe70e72 100644 --- a/router.go +++ b/router.go @@ -27,9 +27,9 @@ import ( "time" beecontext "github.com/astaxie/beego/context" + "github.com/astaxie/beego/context/param" + "github.com/astaxie/beego/context/response" "github.com/astaxie/beego/logs" - "github.com/astaxie/beego/param" - "github.com/astaxie/beego/response" "github.com/astaxie/beego/toolbox" "github.com/astaxie/beego/utils" ) From f311ae9ebe799b6a66737b58c1258d2311551643 Mon Sep 17 00:00:00 2001 From: ansiz Date: Wed, 26 Apr 2017 00:12:03 +0800 Subject: [PATCH 43/82] feature: Export function printTree (#2597) This exports PrintTree function which allow to set Role Based Access Control, Create our own requests statistics...etc --- admin.go | 49 +++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/admin.go b/admin.go index 80615957..875cd0e8 100644 --- a/admin.go +++ b/admin.go @@ -105,29 +105,12 @@ func listConf(rw http.ResponseWriter, r *http.Request) { tmpl.Execute(rw, data) case "router": - var ( - content = map[string]interface{}{ - "Fields": []string{ - "Router Pattern", - "Methods", - "Controller", - }, - } - methods = []string{} - methodsData = make(map[string]interface{}) - ) - for method, t := range BeeApp.Handlers.routers { - - resultList := new([][]string) - - printTree(resultList, t) - - methods = append(methods, method) - methodsData[method] = resultList + content := PrintTree() + content["Fields"] = []string{ + "Router Pattern", + "Methods", + "Controller", } - - content["Data"] = methodsData - content["Methods"] = methods data["Content"] = content data["Title"] = "Routers" execTpl(rw, data, routerAndFilterTpl, defaultScriptsTpl) @@ -200,6 +183,28 @@ func list(root string, p interface{}, m map[string]interface{}) { } } +// PrintTree prints all registered routers. +func PrintTree() map[string]interface{} { + var ( + content = map[string]interface{}{} + methods = []string{} + methodsData = make(map[string]interface{}) + ) + for method, t := range BeeApp.Handlers.routers { + + resultList := new([][]string) + + printTree(resultList, t) + + methods = append(methods, method) + methodsData[method] = resultList + } + + content["Data"] = methodsData + content["Methods"] = methods + return content +} + func printTree(resultList *[][]string, t *Tree) { for _, tr := range t.fixrouters { printTree(resultList, tr) From 4cba78afd948470826c0bed5eda222f9824b8da7 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Tue, 25 Apr 2017 23:42:35 +0300 Subject: [PATCH 44/82] small fixes --- context/param/conv.go | 25 +++++++++++++------------ context/param/parsers.go | 14 ++++++-------- parser.go | 9 ++++----- 3 files changed, 23 insertions(+), 25 deletions(-) diff --git a/context/param/conv.go b/context/param/conv.go index 4938f45f..8e580c2e 100644 --- a/context/param/conv.go +++ b/context/param/conv.go @@ -8,6 +8,15 @@ import ( "github.com/astaxie/beego/logs" ) +func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { + result = make([]reflect.Value, 0, len(methodParams)) + for i := 0; i < len(methodParams); i++ { + reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) + result = append(result, reflectValue) + } + return +} + func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) { paramValue := getParamValue(param, ctx) if paramValue == "" { @@ -18,7 +27,7 @@ func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Co } } - reflectValue, err := parseValue(paramValue, paramType) + reflectValue, err := parseValue(param, paramValue, paramType) if err != nil { logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err)) ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType)) @@ -43,11 +52,12 @@ func getParamValue(param *MethodParam, ctx *beecontext.Context) string { } } -func parseValue(paramValue string, paramType reflect.Type) (result reflect.Value, err error) { +func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) { if paramValue == "" { return reflect.Zero(paramType), nil } else { - value, err := parse(paramValue, paramType) + parser := getParser(param, paramType) + value, err := parser.parse(paramValue, paramType) if err != nil { return result, err } @@ -56,15 +66,6 @@ func parseValue(paramValue string, paramType reflect.Type) (result reflect.Value } } -func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { - result = make([]reflect.Value, 0, len(methodParams)) - for i := 0; i < len(methodParams); i++ { - reflectValue := convertParam(methodParams[i], methodType.In(i), ctx) - result = append(result, reflectValue) - } - return -} - func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { defer func() { if r := recover(); r != nil { diff --git a/context/param/parsers.go b/context/param/parsers.go index 64cabe49..2b48e878 100644 --- a/context/param/parsers.go +++ b/context/param/parsers.go @@ -12,12 +12,7 @@ type paramParser interface { parse(value string, toType reflect.Type) (interface{}, error) } -func parse(value string, t reflect.Type) (interface{}, error) { - parser := getParser(t) - return parser.parse(value, t) -} - -func getParser(t reflect.Type) paramParser { +func getParser(param *MethodParam, t reflect.Type) paramParser { switch t.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: @@ -26,7 +21,10 @@ func getParser(t reflect.Type) paramParser { if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string return stringParser{} } - elemParser := getParser(t.Elem()) + if param.location == body { + return jsonParser{} + } + elemParser := getParser(param, t.Elem()) if elemParser == (jsonParser{}) { return elemParser } @@ -38,7 +36,7 @@ func getParser(t reflect.Type) paramParser { case reflect.Float32, reflect.Float64: return floatParser{} case reflect.Ptr: - elemParser := getParser(t.Elem()) + elemParser := getParser(param, t.Elem()) if elemParser == (jsonParser{}) { return elemParser } diff --git a/parser.go b/parser.go index 17d9a5d2..66f51d0b 100644 --- a/parser.go +++ b/parser.go @@ -199,12 +199,11 @@ func parseComment(lines []*ast.Comment) (pc *parsedComment, err error) { logs.Error("Invalid @Param format. Needs at least 4 parameters") } p := parsedParam{} - names := strings.Split(pv[0], "=") - funcParamName := names[0] + names := strings.SplitN(pv[0], "=>", 2) + p.name = names[0] + funcParamName := p.name if len(names) > 1 { - p.name = names[1] - } else { - p.name = funcParamName + funcParamName = names[1] } p.location = pv[1] p.datatype = pv[2] From a1bc94e648dbb04b02a06ddfd76aef3006ba52c9 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Wed, 26 Apr 2017 01:00:25 +0300 Subject: [PATCH 45/82] dont generate comment if router not found --- parser.go | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/parser.go b/parser.go index 66f51d0b..037d5376 100644 --- a/parser.go +++ b/parser.go @@ -118,13 +118,15 @@ func parserComments(f *ast.FuncDecl, controllerName, pkgpath string) error { if err != nil { return err } - key := pkgpath + ":" + controllerName - cc := ControllerComments{} - cc.Method = f.Name.String() - cc.Router = parsedComment.routerPath - cc.AllowHTTPMethods = parsedComment.methods - cc.MethodParams = buildMethodParams(f.Type.Params.List, parsedComment) - genInfoList[key] = append(genInfoList[key], cc) + if parsedComment.routerPath != "" { + key := pkgpath + ":" + controllerName + cc := ControllerComments{} + cc.Method = f.Name.String() + cc.Router = parsedComment.routerPath + cc.AllowHTTPMethods = parsedComment.methods + cc.MethodParams = buildMethodParams(f.Type.Params.List, parsedComment) + genInfoList[key] = append(genInfoList[key], cc) + } } return nil From 3e29078f68399a18e5a3d3bfac618b38eea8ee18 Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 28 Apr 2017 21:38:08 +0800 Subject: [PATCH 46/82] add check ineffect and gofmt --- .travis.yml | 3 +++ httplib/httplib.go | 4 ++-- logs/alils/alils.go | 7 +++---- orm/orm_test.go | 4 +++- session/sess_file.go | 9 ++++++++- templatefunc_test.go | 10 +++++----- 6 files changed, 24 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index e3960c70..c5f11b9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ install: - go get github.com/gogo/protobuf/proto - go get -u honnef.co/go/tools/cmd/gosimple - go get -u github.com/mdempsky/unconvert + - go get -u github.com/gordonklaus/ineffassign before_script: - psql --version - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -51,5 +52,7 @@ script: - go test -v ./... - gosimple -ignore "$(cat .gosimpleignore)" $(go list ./... | grep -v /vendor/) - unconvert $(go list ./... | grep -v /vendor/) + - ineffassign . + - find . ! \( -path './vendor' -prune \) -type f -name '*.go' -print0 | xargs -0 gofmt -l -s addons: postgresql: "9.4" diff --git a/httplib/httplib.go b/httplib/httplib.go index f232f31b..4fd572d6 100644 --- a/httplib/httplib.go +++ b/httplib/httplib.go @@ -520,9 +520,9 @@ func (b *BeegoHTTPRequest) Bytes() ([]byte, error) { return nil, err } b.body, err = ioutil.ReadAll(reader) - } else { - b.body, err = ioutil.ReadAll(resp.Body) + return b.body, err } + b.body, err = ioutil.ReadAll(resp.Body) return b.body, err } diff --git a/logs/alils/alils.go b/logs/alils/alils.go index 30a09243..aaee228a 100644 --- a/logs/alils/alils.go +++ b/logs/alils/alils.go @@ -2,11 +2,12 @@ package alils import ( "encoding/json" - "github.com/astaxie/beego/logs" - "github.com/gogo/protobuf/proto" "strings" "sync" "time" + + "github.com/astaxie/beego/logs" + "github.com/gogo/protobuf/proto" ) const ( @@ -124,12 +125,10 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error // 默认发到空Topic if lg == nil { - topic = "" content = msg lg = c.group[0] } } else { - topic = "" content = msg lg = c.group[0] } diff --git a/orm/orm_test.go b/orm/orm_test.go index a8b4fe69..128a86f3 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -135,7 +135,7 @@ func getCaller(skip int) string { if i := strings.LastIndex(funName, "."); i > -1 { funName = funName[i+1:] } - return fmt.Sprintf("%s:%d: \n%s", fn, line, strings.Join(codes, "\n")) + return fmt.Sprintf("%s:%s:%d: \n%s", fn, funName, line, strings.Join(codes, "\n")) } func throwFail(t *testing.T, err error, args ...interface{}) { @@ -1014,6 +1014,8 @@ func TestAll(t *testing.T) { var users3 []*User qs = dORM.QueryTable("user") num, err = qs.Filter("user_name", "nothing").All(&users3) + throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 0)) throwFailNow(t, AssertIs(users3 == nil, false)) } diff --git a/session/sess_file.go b/session/sess_file.go index 12cf1f3f..3ca93d55 100644 --- a/session/sess_file.go +++ b/session/sess_file.go @@ -87,9 +87,16 @@ func (fs *FileSessionStore) SessionRelease(w http.ResponseWriter) { var f *os.File if err == nil { f, err = os.OpenFile(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid), os.O_RDWR, 0777) + if err != nil { + SLogger.Println(err) + return + } } else if os.IsNotExist(err) { f, err = os.Create(path.Join(filepder.savePath, string(fs.sid[0]), string(fs.sid[1]), fs.sid)) - + if err != nil { + SLogger.Println(err) + return + } } else { return } diff --git a/templatefunc_test.go b/templatefunc_test.go index 20d9b850..f40b5985 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -269,28 +269,28 @@ func TestParseFormTag(t *testing.T) { t.Errorf("Form Tag containing only label was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(3)) + label, name, fType, id, class, ignored, _ = parseFormTag(objT.Field(3)) if !(name == "name" && label == "OnlyName: " && fType == "text" && !ignored && id == "name" && class == "form-name") { t.Errorf("Form Tag containing only name was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(4)) + _, _, _, _, _, ignored, _ = parseFormTag(objT.Field(4)) if !ignored { t.Errorf("Form Tag that should be ignored was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(5)) + _, name, _, _, _, _, required = parseFormTag(objT.Field(5)) if !(name == "name" && required) { t.Errorf("Form Tag containing only name and required was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(6)) + _, name, _, _, _, _, required = parseFormTag(objT.Field(6)) if !(name == "name" && !required) { t.Errorf("Form Tag containing only name and ignore required was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(7)) + _, name, _, _, _, _, required = parseFormTag(objT.Field(7)) if !(name == "name" && !required) { t.Errorf("Form Tag containing only name and not required was not correctly parsed.") } From aa8f7bc146da539b90d3f2ce7c3359c7872358e7 Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 28 Apr 2017 22:36:28 +0800 Subject: [PATCH 47/82] fix ineffectual --- config/ini.go | 5 ++++- logs/color_windows.go | 2 +- logs/file.go | 10 ++++++---- orm/db.go | 2 +- orm/db_mysql.go | 3 +-- orm/orm.go | 2 +- orm/orm_raw.go | 2 +- orm/orm_test.go | 7 +++++++ session/couchbase/sess_couchbase.go | 4 +++- session/sess_test.go | 3 +-- template.go | 3 ++- templatefunc_test.go | 10 +++++----- utils/file.go | 2 +- validation/util_test.go | 2 +- 14 files changed, 35 insertions(+), 22 deletions(-) diff --git a/config/ini.go b/config/ini.go index 3572b955..a681bc1b 100644 --- a/config/ini.go +++ b/config/ini.go @@ -325,7 +325,10 @@ func (c *IniConfigContainer) SaveConfigFile(filename string) (err error) { // Get section or key comments. Fixed #1607 getCommentStr := func(section, key string) string { - comment, ok := "", false + var ( + comment string + ok bool + ) if len(key) == 0 { comment, ok = c.sectionComment[section] } else { diff --git a/logs/color_windows.go b/logs/color_windows.go index deee4c87..4e28f188 100644 --- a/logs/color_windows.go +++ b/logs/color_windows.go @@ -361,7 +361,7 @@ func isParameterChar(b byte) bool { } func (cw *ansiColorWriter) Write(p []byte) (int, error) { - r, nw, first, last := 0, 0, 0, 0 + var r, nw, first, last int if cw.mode != DiscardNonColorEscSeq { cw.state = outsideCsiCode cw.resetBuffer() diff --git a/logs/file.go b/logs/file.go index 32595ec4..20ef167d 100644 --- a/logs/file.go +++ b/logs/file.go @@ -259,7 +259,7 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { } // return error if the last file checked still existed if err == nil { - return fmt.Errorf("Rotate: Cannot find free log number to rename %s\n", w.Filename) + return fmt.Errorf("Rotate: Cannot find free log number to rename %s", w.Filename) } // close fileWriter before rename @@ -268,6 +268,9 @@ func (w *fileLogWriter) doRotate(logTime time.Time) error { // Rename the file to its new found name // even if occurs error,we MUST guarantee to restart new logger err = os.Rename(w.Filename, fName) + if err != nil { + goto RESTART_LOGGER + } err = os.Chmod(fName, os.FileMode(0440)) // re-start logger RESTART_LOGGER: @@ -276,13 +279,12 @@ RESTART_LOGGER: go w.deleteOldLog() if startLoggerErr != nil { - return fmt.Errorf("Rotate StartLogger: %s\n", startLoggerErr) + return fmt.Errorf("Rotate StartLogger: %s", startLoggerErr) } if err != nil { - return fmt.Errorf("Rotate: %s\n", err) + return fmt.Errorf("Rotate: %s", err) } return nil - } func (w *fileLogWriter) deleteOldLog() { diff --git a/orm/db.go b/orm/db.go index e9508ee0..a3251906 100644 --- a/orm/db.go +++ b/orm/db.go @@ -1110,7 +1110,7 @@ func (d *dbBase) Count(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condition // generate sql with replacing operator string placeholders and replaced values. func (d *dbBase) GenerateOperatorSQL(mi *modelInfo, fi *fieldInfo, operator string, args []interface{}, tz *time.Location) (string, []interface{}) { - sql := "" + var sql string params := getFlatParams(fi, args, tz) if len(params) == 0 { diff --git a/orm/db_mysql.go b/orm/db_mysql.go index 1016de2b..51185563 100644 --- a/orm/db_mysql.go +++ b/orm/db_mysql.go @@ -103,8 +103,7 @@ func (d *dbBaseMysql) IndexExists(db dbQuerier, table string, name string) bool // If no will insert // Add "`" for mysql sql building func (d *dbBaseMysql) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a *alias, args ...string) (int64, error) { - - iouStr := "" + var iouStr string argsMap := map[string]string{} iouStr = "ON DUPLICATE KEY UPDATE" diff --git a/orm/orm.go b/orm/orm.go index d364e621..5db79386 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -420,7 +420,7 @@ func (o *orm) getRelQs(md interface{}, mi *modelInfo, fi *fieldInfo) *querySet { // table name can be string or struct. // e.g. QueryTable("user"), QueryTable(&user{}) or QueryTable((*User)(nil)), func (o *orm) QueryTable(ptrStructOrTableName interface{}) (qs QuerySeter) { - name := "" + var name string if table, ok := ptrStructOrTableName.(string); ok { name = snakeString(table) if mi, ok := modelCache.get(name); ok { diff --git a/orm/orm_raw.go b/orm/orm_raw.go index a968b1a1..1e86212a 100644 --- a/orm/orm_raw.go +++ b/orm/orm_raw.go @@ -671,7 +671,7 @@ func (o *rawSet) queryRowsTo(container interface{}, keyCol, valueCol string) (in ind *reflect.Value ) - typ := 0 + var typ int switch container.(type) { case *Params: typ = 1 diff --git a/orm/orm_test.go b/orm/orm_test.go index 128a86f3..fdc6473c 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -1140,6 +1140,7 @@ func TestRelatedSel(t *testing.T) { } err = qs.Filter("user_name", "nobody").RelatedSel("profile").One(&user) + throwFail(t, err) throwFail(t, AssertIs(num, 1)) throwFail(t, AssertIs(user.Profile, nil)) @@ -1248,20 +1249,24 @@ func TestLoadRelated(t *testing.T) { num, err = dORM.LoadRelated(&user, "Posts", true) throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 2)) throwFailNow(t, AssertIs(len(user.Posts), 2)) throwFailNow(t, AssertIs(user.Posts[0].User.UserName, "astaxie")) num, err = dORM.LoadRelated(&user, "Posts", true, 1) throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 1)) throwFailNow(t, AssertIs(len(user.Posts), 1)) num, err = dORM.LoadRelated(&user, "Posts", true, 0, 0, "-Id") throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 2)) throwFailNow(t, AssertIs(len(user.Posts), 2)) throwFailNow(t, AssertIs(user.Posts[0].Title, "Formatting")) num, err = dORM.LoadRelated(&user, "Posts", true, 1, 1, "Id") throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 1)) throwFailNow(t, AssertIs(len(user.Posts), 1)) throwFailNow(t, AssertIs(user.Posts[0].Title, "Formatting")) @@ -1978,6 +1983,7 @@ func TestReadOrCreate(t *testing.T) { created, pk, err := dORM.ReadOrCreate(u, "UserName") throwFail(t, err) throwFail(t, AssertIs(created, true)) + throwFail(t, AssertIs(u.ID, pk)) throwFail(t, AssertIs(u.UserName, "Kyle")) throwFail(t, AssertIs(u.Email, "kylemcc@gmail.com")) throwFail(t, AssertIs(u.Password, "other_pass")) @@ -2134,6 +2140,7 @@ func TestUintPk(t *testing.T) { created, pk, err := dORM.ReadOrCreate(u, "ID") throwFail(t, err) + throwFail(t, AssertIs(pk, u.ID)) throwFail(t, AssertIs(created, true)) throwFail(t, AssertIs(u.Name, name)) diff --git a/session/couchbase/sess_couchbase.go b/session/couchbase/sess_couchbase.go index 791a6cc7..707d042c 100644 --- a/session/couchbase/sess_couchbase.go +++ b/session/couchbase/sess_couchbase.go @@ -162,7 +162,9 @@ func (cp *Provider) SessionRead(sid string) (session.Store, error) { ) err = cp.b.Get(sid, &doc) - if doc == nil { + if err != nil { + return nil, err + } else if doc == nil { kv = make(map[interface{}]interface{}) } else { kv, err = session.DecodeGob(doc) diff --git a/session/sess_test.go b/session/sess_test.go index 60b47dd4..906abec2 100644 --- a/session/sess_test.go +++ b/session/sess_test.go @@ -74,8 +74,7 @@ func TestCookieEncodeDecode(t *testing.T) { if err != nil { t.Fatal("encodeCookie:", err) } - dst := make(map[interface{}]interface{}) - dst, err = decodeCookie(block, hashKey, securityName, str, 3600) + dst, err := decodeCookie(block, hashKey, securityName, str, 3600) if err != nil { t.Fatal("decodeCookie", err) } diff --git a/template.go b/template.go index 104383c9..73a14977 100644 --- a/template.go +++ b/template.go @@ -307,8 +307,9 @@ func _getTemplate(t0 *template.Template, root string, subMods [][]string, others } //second check define for _, otherFile := range others { + var data []byte fileAbsPath := filepath.Join(root, otherFile) - data, err := ioutil.ReadFile(fileAbsPath) + data, err = ioutil.ReadFile(fileAbsPath) if err != nil { continue } diff --git a/templatefunc_test.go b/templatefunc_test.go index f40b5985..9df61125 100644 --- a/templatefunc_test.go +++ b/templatefunc_test.go @@ -254,22 +254,22 @@ func TestParseFormTag(t *testing.T) { objT := reflect.TypeOf(&user{}).Elem() - label, name, fType, id, class, ignored, required := parseFormTag(objT.Field(0)) + label, name, fType, _, _, ignored, _ := parseFormTag(objT.Field(0)) if !(name == "name" && label == "年龄:" && fType == "text" && !ignored) { t.Errorf("Form Tag with name, label and type was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(1)) + label, name, fType, _, _, ignored, _ = parseFormTag(objT.Field(1)) if !(name == "NoName" && label == "年龄:" && fType == "hidden" && !ignored) { t.Errorf("Form Tag with label and type but without name was not correctly parsed.") } - label, name, fType, id, class, ignored, required = parseFormTag(objT.Field(2)) + label, name, fType, _, _, ignored, _ = parseFormTag(objT.Field(2)) if !(name == "OnlyLabel" && label == "年龄:" && fType == "text" && !ignored) { t.Errorf("Form Tag containing only label was not correctly parsed.") } - label, name, fType, id, class, ignored, _ = parseFormTag(objT.Field(3)) + label, name, fType, id, class, ignored, _ := parseFormTag(objT.Field(3)) if !(name == "name" && label == "OnlyName: " && fType == "text" && !ignored && id == "name" && class == "form-name") { t.Errorf("Form Tag containing only name was not correctly parsed.") @@ -280,7 +280,7 @@ func TestParseFormTag(t *testing.T) { t.Errorf("Form Tag that should be ignored was not correctly parsed.") } - _, name, _, _, _, _, required = parseFormTag(objT.Field(5)) + _, name, _, _, _, _, required := parseFormTag(objT.Field(5)) if !(name == "name" && required) { t.Errorf("Form Tag containing only name and required was not correctly parsed.") } diff --git a/utils/file.go b/utils/file.go index db197882..6090eb17 100644 --- a/utils/file.go +++ b/utils/file.go @@ -72,7 +72,7 @@ func GrepFile(patten string, filename string) (lines []string, err error) { lines = make([]string, 0) reader := bufio.NewReader(fd) prefix := "" - isLongLine := false + var isLongLine bool for { byteLine, isPrefix, er := reader.ReadLine() if er != nil && er != io.EOF { diff --git a/validation/util_test.go b/validation/util_test.go index d7e10506..e74d50ed 100644 --- a/validation/util_test.go +++ b/validation/util_test.go @@ -42,7 +42,7 @@ func TestGetValidFuncs(t *testing.T) { } f, _ = tf.FieldByName("Tag") - if vfs, err = getValidFuncs(f); err.Error() != "doesn't exsits Maxx valid function" { + if _, err = getValidFuncs(f); err.Error() != "doesn't exsits Maxx valid function" { t.Fatal(err) } From 64b475d7d640117219d6246ea154282bf3c0c34f Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 28 Apr 2017 22:58:17 +0800 Subject: [PATCH 48/82] fix ReadOrCreate test case --- orm/orm_test.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/orm/orm_test.go b/orm/orm_test.go index fdc6473c..71b614f3 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2138,9 +2138,8 @@ func TestUintPk(t *testing.T) { Name: name, } - created, pk, err := dORM.ReadOrCreate(u, "ID") + created, _, err := dORM.ReadOrCreate(u, "ID") throwFail(t, err) - throwFail(t, AssertIs(pk, u.ID)) throwFail(t, AssertIs(created, true)) throwFail(t, AssertIs(u.Name, name)) From 1c32c011a1a9d6ebda2b79e0625f0626104feee3 Mon Sep 17 00:00:00 2001 From: astaxie Date: Fri, 28 Apr 2017 23:37:40 +0800 Subject: [PATCH 49/82] fix misspell --- httplib/README.md | 2 +- orm/db.go | 2 +- utils/file_test.go | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/httplib/README.md b/httplib/README.md index 6a72cf7c..97df8e6b 100644 --- a/httplib/README.md +++ b/httplib/README.md @@ -32,7 +32,7 @@ The default timeout is `60` seconds, function prototype: SetTimeout(connectTimeout, readWriteTimeout time.Duration) -Exmaple: +Example: // GET httplib.Get("http://beego.me/").SetTimeout(100 * time.Second, 30 * time.Second) diff --git a/orm/db.go b/orm/db.go index a3251906..2bd525c2 100644 --- a/orm/db.go +++ b/orm/db.go @@ -1733,7 +1733,7 @@ func (d *dbBase) TableQuote() string { return "`" } -// replace value placeholer in parametered sql string. +// replace value placeholder in parametered sql string. func (d *dbBase) ReplaceMarks(query *string) { // default use `?` as mark, do nothing } diff --git a/utils/file_test.go b/utils/file_test.go index 86d1a700..b2644157 100644 --- a/utils/file_test.go +++ b/utils/file_test.go @@ -54,7 +54,7 @@ func TestSearchFile(t *testing.T) { _, err = SearchFile(noExistedFile, ".") if err == nil { - t.Errorf("err shouldnot be nil, got path: %s", SelfDir()) + t.Errorf("err shouldnt be nil, got path: %s", SelfDir()) } } From ea3d0690cf5218db7b6154f6225f699b2ded1cf7 Mon Sep 17 00:00:00 2001 From: astaxie Date: Sat, 29 Apr 2017 09:13:28 +0800 Subject: [PATCH 50/82] golint --- policy.go | 4 ++-- template.go | 1 + template_test.go | 4 ++-- templatefunc.go | 6 +++--- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/policy.go b/policy.go index 2b91fdcc..ab23f927 100644 --- a/policy.go +++ b/policy.go @@ -23,7 +23,7 @@ import ( // PolicyFunc defines a policy function which is invoked before the controller handler is executed. type PolicyFunc func(*context.Context) -// FindRouter Find Router info for URL +// FindPolicy Find Router info for URL func (p *ControllerRegister) FindPolicy(cont *context.Context) []PolicyFunc { var urlPath = cont.Input.URL() if !BConfig.RouterCaseSensitive { @@ -71,7 +71,7 @@ func (p *ControllerRegister) addToPolicy(method, pattern string, r ...PolicyFunc } } -// Register new policy in beego +// Policy Register new policy in beego func Policy(pattern, method string, policy ...PolicyFunc) { BeeApp.Handlers.addToPolicy(method, pattern, policy...) } diff --git a/template.go b/template.go index 73a14977..d4859cd7 100644 --- a/template.go +++ b/template.go @@ -365,6 +365,7 @@ func DelStaticPath(url string) *App { return BeeApp } +// AddTemplateEngine add a new templatePreProcessor which support extension func AddTemplateEngine(extension string, fn templatePreProcessor) *App { AddTemplateExt(extension) beeTemplateEngines[extension] = fn diff --git a/template_test.go b/template_test.go index 16967382..2153ef72 100644 --- a/template_test.go +++ b/template_test.go @@ -159,7 +159,7 @@ var add = `{{ template "layout_blog.tpl" . }} {{ end}}` -var layout_blog = ` +var layoutBlog = ` Lin Li @@ -231,7 +231,7 @@ func TestTemplateLayout(t *testing.T) { if k == 0 { f.WriteString(add) } else if k == 1 { - f.WriteString(layout_blog) + f.WriteString(layoutBlog) } f.Close() } diff --git a/templatefunc.go b/templatefunc.go index 4fdc936d..a6f9c961 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -507,9 +507,9 @@ func parseFormTag(fieldT reflect.StructField) (label, name, fType string, id str class = fieldT.Tag.Get("class") required = false - required_field := fieldT.Tag.Get("required") - if required_field != "-" && required_field != "" { - required, _ = strconv.ParseBool(required_field) + requiredField := fieldT.Tag.Get("required") + if requiredField != "-" && requiredField != "" { + required, _ = strconv.ParseBool(requiredField) } switch len(tags) { From a91e2e99508e2e3696d6b2644fd61b2b01a1c76d Mon Sep 17 00:00:00 2001 From: astaxie Date: Sun, 30 Apr 2017 22:41:23 +0800 Subject: [PATCH 51/82] add golint check and fix all golints --- .travis.yml | 2 + config/env/env.go | 2 + context/acceptencoder.go | 1 + grace/server.go | 4 +- hooks.go | 6 +- logs/alils/alils.go | 39 +++---- logs/alils/log.pb.go | 218 ++++++++++++++++++++++-------------- logs/alils/log_config.go | 3 + logs/alils/log_project.go | 9 +- logs/alils/log_store.go | 20 ++-- logs/alils/machine_group.go | 16 ++- logs/alils/request.go | 4 +- logs/file.go | 2 +- logs/log.go | 5 +- logs/logger.go | 17 ++- orm/db.go | 5 +- orm/db_alias.go | 6 +- session/session.go | 45 ++++---- session/ssdb/sess_ssdb.go | 40 +++++-- swagger/swagger.go | 2 +- 20 files changed, 271 insertions(+), 175 deletions(-) diff --git a/.travis.yml b/.travis.yml index c5f11b9f..479d70ca 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,6 +36,7 @@ install: - go get -u honnef.co/go/tools/cmd/gosimple - go get -u github.com/mdempsky/unconvert - go get -u github.com/gordonklaus/ineffassign + - go get -u github.com/golang/lint/golint before_script: - psql --version - sh -c "if [ '$ORM_DRIVER' = 'postgres' ]; then psql -c 'create database orm_test;' -U postgres; fi" @@ -54,5 +55,6 @@ script: - unconvert $(go list ./... | grep -v /vendor/) - ineffassign . - find . ! \( -path './vendor' -prune \) -type f -name '*.go' -print0 | xargs -0 gofmt -l -s + - golint ./... addons: postgresql: "9.4" diff --git a/config/env/env.go b/config/env/env.go index a819e51a..34f094fe 100644 --- a/config/env/env.go +++ b/config/env/env.go @@ -12,6 +12,8 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. + +// Package env is used to parse environment. package env import ( diff --git a/context/acceptencoder.go b/context/acceptencoder.go index 350b560d..b4e2492c 100644 --- a/context/acceptencoder.go +++ b/context/acceptencoder.go @@ -39,6 +39,7 @@ var ( getMethodOnly bool ) +// InitGzip init the gzipcompress func InitGzip(minLength, compressLevel int, methods []string) { if minLength >= 0 { gzipMinLength = minLength diff --git a/grace/server.go b/grace/server.go index c71193ad..b8242335 100644 --- a/grace/server.go +++ b/grace/server.go @@ -291,7 +291,7 @@ func (srv *Server) fork() (err error) { // RegisterSignalHook registers a function to be run PreSignal or PostSignal for a given signal. func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err error) { if ppFlag != PreSignal && ppFlag != PostSignal { - err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal.") + err = fmt.Errorf("Invalid ppFlag argument. Must be either grace.PreSignal or grace.PostSignal") return } for _, s := range hookableSignals { @@ -300,6 +300,6 @@ func (srv *Server) RegisterSignalHook(ppFlag int, sig os.Signal, f func()) (err return } } - err = fmt.Errorf("Signal '%v' is not supported.", sig) + err = fmt.Errorf("Signal '%v' is not supported", sig) return } diff --git a/hooks.go b/hooks.go index 091ecbc7..0fddc82f 100644 --- a/hooks.go +++ b/hooks.go @@ -55,9 +55,9 @@ func registerSession() error { conf.ProviderConfig = filepath.ToSlash(BConfig.WebConfig.Session.SessionProviderConfig) conf.DisableHTTPOnly = BConfig.WebConfig.Session.SessionDisableHTTPOnly conf.Domain = BConfig.WebConfig.Session.SessionDomain - conf.EnableSidInHttpHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader - conf.SessionNameInHttpHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader - conf.EnableSidInUrlQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery + conf.EnableSidInHTTPHeader = BConfig.WebConfig.Session.SessionEnableSidInHTTPHeader + conf.SessionNameInHTTPHeader = BConfig.WebConfig.Session.SessionNameInHTTPHeader + conf.EnableSidInURLQuery = BConfig.WebConfig.Session.SessionEnableSidInURLQuery } else { if err = json.Unmarshal([]byte(sessionConfig), conf); err != nil { return err diff --git a/logs/alils/alils.go b/logs/alils/alils.go index aaee228a..867ff4cb 100644 --- a/logs/alils/alils.go +++ b/logs/alils/alils.go @@ -11,11 +11,14 @@ import ( ) const ( - CacheSize int = 64 + // CacheSize set the flush size + CacheSize int = 64 + // Delimiter define the topic delimiter Delimiter string = "##" ) -type AliLSConfig struct { +// Config is the Config for Ali Log +type Config struct { Project string `json:"project"` Endpoint string `json:"endpoint"` KeyID string `json:"key_id"` @@ -35,18 +38,17 @@ type aliLSWriter struct { withMap bool groupMap map[string]*LogGroup lock *sync.Mutex - AliLSConfig + Config } -// 创建提供Logger接口的日志服务 +// NewAliLS create a new Logger func NewAliLS() logs.Logger { alils := new(aliLSWriter) alils.Level = logs.LevelTrace return alils } -// 读取配置 -// 初始化必要的数据结构 +// Init parse config and init struct func (c *aliLSWriter) Init(jsonConfig string) (err error) { json.Unmarshal([]byte(jsonConfig), c) @@ -55,28 +57,26 @@ func (c *aliLSWriter) Init(jsonConfig string) (err error) { c.FlushWhen = CacheSize } - // 初始化Project prj := &LogProject{ Name: c.Project, Endpoint: c.Endpoint, - AccessKeyId: c.KeyID, + AccessKeyID: c.KeyID, AccessKeySecret: c.KeySecret, } - // 获取logstore c.store, err = prj.GetLogStore(c.LogStore) if err != nil { return err } - // 创建默认Log Group + // Create default Log Group c.group = append(c.group, &LogGroup{ Topic: proto.String(""), Source: proto.String(c.Source), Logs: make([]*Log, 0, c.FlushWhen), }) - // 创建其它Log Group + // Create other Log Group c.groupMap = make(map[string]*LogGroup) for _, topic := range c.Topics { @@ -114,7 +114,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error var lg *LogGroup if c.withMap { - // 解析出Topic,并匹配LogGroup + // Topic,LogGroup strs := strings.SplitN(msg, Delimiter, 2) if len(strs) == 2 { pos := strings.LastIndex(strs[0], " ") @@ -123,7 +123,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error lg = c.groupMap[topic] } - // 默认发到空Topic + // send to empty Topic if lg == nil { content = msg lg = c.group[0] @@ -133,15 +133,14 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error lg = c.group[0] } - // 生成日志 - c1 := &Log_Content{ + c1 := &LogContent{ Key: proto.String("msg"), Value: proto.String(content), } l := &Log{ - Time: proto.Uint32(uint32(when.Unix())), // 填写日志时间 - Contents: []*Log_Content{ + Time: proto.Uint32(uint32(when.Unix())), + Contents: []*LogContent{ c1, }, } @@ -150,7 +149,6 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error lg.Logs = append(lg.Logs, l) c.lock.Unlock() - // 满足条件则Flush if len(lg.Logs) >= c.FlushWhen { c.flush(lg) } @@ -161,7 +159,7 @@ func (c *aliLSWriter) WriteMsg(when time.Time, msg string, level int) (err error // Flush implementing method. empty. func (c *aliLSWriter) Flush() { - // flush所有group + // flush all group for _, lg := range c.group { c.flush(lg) } @@ -175,9 +173,6 @@ func (c *aliLSWriter) flush(lg *LogGroup) { c.lock.Lock() defer c.lock.Unlock() - - // 把以上的LogGroup推送到SLS服务器, - // SLS服务器会根据该logstore的shard个数自动进行负载均衡。 err := c.store.PutLogs(lg) if err != nil { return diff --git a/logs/alils/log.pb.go b/logs/alils/log.pb.go index b60ca200..601b0d78 100755 --- a/logs/alils/log.pb.go +++ b/logs/alils/log.pb.go @@ -1,30 +1,43 @@ package alils -import "github.com/gogo/protobuf/proto" -import "fmt" -import "math" +import ( + "fmt" + "io" + "math" -// discarding unused import gogoproto "." - -import github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" - -import "io" + "github.com/gogo/protobuf/proto" + github_com_gogo_protobuf_proto "github.com/gogo/protobuf/proto" +) // Reference imports to suppress errors if they are not otherwise used. var _ = proto.Marshal var _ = fmt.Errorf var _ = math.Inf +var ( + // ErrInvalidLengthLog invalid proto + ErrInvalidLengthLog = fmt.Errorf("proto: negative length found during unmarshaling") + // ErrIntOverflowLog overflow + ErrIntOverflowLog = fmt.Errorf("proto: integer overflow") +) + +// Log define the proto Log type Log struct { - Time *uint32 `protobuf:"varint,1,req,name=Time" json:"Time,omitempty"` - Contents []*Log_Content `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"` - XXX_unrecognized []byte `json:"-"` + Time *uint32 `protobuf:"varint,1,req,name=Time" json:"Time,omitempty"` + Contents []*LogContent `protobuf:"bytes,2,rep,name=Contents" json:"Contents,omitempty"` + XXXUnrecognized []byte `json:"-"` } -func (m *Log) Reset() { *m = Log{} } -func (m *Log) String() string { return proto.CompactTextString(m) } -func (*Log) ProtoMessage() {} +// Reset the Log +func (m *Log) Reset() { *m = Log{} } +// String return the Compact Log +func (m *Log) String() string { return proto.CompactTextString(m) } + +// ProtoMessage not implemented +func (*Log) ProtoMessage() {} + +// GetTime return the Log's Time func (m *Log) GetTime() uint32 { if m != nil && m.Time != nil { return *m.Time @@ -32,49 +45,65 @@ func (m *Log) GetTime() uint32 { return 0 } -func (m *Log) GetContents() []*Log_Content { +// GetContents return the Log's Contents +func (m *Log) GetContents() []*LogContent { if m != nil { return m.Contents } return nil } -type Log_Content struct { - Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"` - Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"` - XXX_unrecognized []byte `json:"-"` +// LogContent define the Log content struct +type LogContent struct { + Key *string `protobuf:"bytes,1,req,name=Key" json:"Key,omitempty"` + Value *string `protobuf:"bytes,2,req,name=Value" json:"Value,omitempty"` + XXXUnrecognized []byte `json:"-"` } -func (m *Log_Content) Reset() { *m = Log_Content{} } -func (m *Log_Content) String() string { return proto.CompactTextString(m) } -func (*Log_Content) ProtoMessage() {} +// Reset LogContent +func (m *LogContent) Reset() { *m = LogContent{} } -func (m *Log_Content) GetKey() string { +// String return the compact text +func (m *LogContent) String() string { return proto.CompactTextString(m) } + +// ProtoMessage not implemented +func (*LogContent) ProtoMessage() {} + +// GetKey return the Key +func (m *LogContent) GetKey() string { if m != nil && m.Key != nil { return *m.Key } return "" } -func (m *Log_Content) GetValue() string { +// GetValue return the Value +func (m *LogContent) GetValue() string { if m != nil && m.Value != nil { return *m.Value } return "" } +// LogGroup define the logs struct type LogGroup struct { - Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"` - Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"` - Topic *string `protobuf:"bytes,3,opt,name=Topic" json:"Topic,omitempty"` - Source *string `protobuf:"bytes,4,opt,name=Source" json:"Source,omitempty"` - XXX_unrecognized []byte `json:"-"` + Logs []*Log `protobuf:"bytes,1,rep,name=Logs" json:"Logs,omitempty"` + Reserved *string `protobuf:"bytes,2,opt,name=Reserved" json:"Reserved,omitempty"` + Topic *string `protobuf:"bytes,3,opt,name=Topic" json:"Topic,omitempty"` + Source *string `protobuf:"bytes,4,opt,name=Source" json:"Source,omitempty"` + XXXUnrecognized []byte `json:"-"` } -func (m *LogGroup) Reset() { *m = LogGroup{} } -func (m *LogGroup) String() string { return proto.CompactTextString(m) } -func (*LogGroup) ProtoMessage() {} +// Reset LogGroup +func (m *LogGroup) Reset() { *m = LogGroup{} } +// String return the compact text +func (m *LogGroup) String() string { return proto.CompactTextString(m) } + +// ProtoMessage not implemented +func (*LogGroup) ProtoMessage() {} + +// GetLogs return the loggroup logs func (m *LogGroup) GetLogs() []*Log { if m != nil { return m.Logs @@ -82,6 +111,7 @@ func (m *LogGroup) GetLogs() []*Log { return nil } +// GetReserved return Reserved func (m *LogGroup) GetReserved() string { if m != nil && m.Reserved != nil { return *m.Reserved @@ -89,6 +119,7 @@ func (m *LogGroup) GetReserved() string { return "" } +// GetTopic return Topic func (m *LogGroup) GetTopic() string { if m != nil && m.Topic != nil { return *m.Topic @@ -96,6 +127,7 @@ func (m *LogGroup) GetTopic() string { return "" } +// GetSource return Source func (m *LogGroup) GetSource() string { if m != nil && m.Source != nil { return *m.Source @@ -103,15 +135,22 @@ func (m *LogGroup) GetSource() string { return "" } +// LogGroupList define the LogGroups type LogGroupList struct { - LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"` - XXX_unrecognized []byte `json:"-"` + LogGroups []*LogGroup `protobuf:"bytes,1,rep,name=logGroups" json:"logGroups,omitempty"` + XXXUnrecognized []byte `json:"-"` } -func (m *LogGroupList) Reset() { *m = LogGroupList{} } -func (m *LogGroupList) String() string { return proto.CompactTextString(m) } -func (*LogGroupList) ProtoMessage() {} +// Reset LogGroupList +func (m *LogGroupList) Reset() { *m = LogGroupList{} } +// String return compact text +func (m *LogGroupList) String() string { return proto.CompactTextString(m) } + +// ProtoMessage not implemented +func (*LogGroupList) ProtoMessage() {} + +// GetLogGroups return the LogGroups func (m *LogGroupList) GetLogGroups() []*LogGroup { if m != nil { return m.LogGroups @@ -119,6 +158,7 @@ func (m *LogGroupList) GetLogGroups() []*LogGroup { return nil } +// Marshal the logs to byte slice func (m *Log) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -129,6 +169,7 @@ func (m *Log) Marshal() (data []byte, err error) { return data[:n], nil } +// MarshalTo data func (m *Log) MarshalTo(data []byte) (int, error) { var i int _ = i @@ -136,11 +177,10 @@ func (m *Log) MarshalTo(data []byte) (int, error) { _ = l if m.Time == nil { return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Time") - } else { - data[i] = 0x8 - i++ - i = encodeVarintLog(data, i, uint64(*m.Time)) } + data[i] = 0x8 + i++ + i = encodeVarintLog(data, i, uint64(*m.Time)) if len(m.Contents) > 0 { for _, msg := range m.Contents { data[i] = 0x12 @@ -153,13 +193,14 @@ func (m *Log) MarshalTo(data []byte) (int, error) { i += n } } - if m.XXX_unrecognized != nil { - i += copy(data[i:], m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + i += copy(data[i:], m.XXXUnrecognized) } return i, nil } -func (m *Log_Content) Marshal() (data []byte, err error) { +// Marshal LogContent +func (m *LogContent) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) n, err := m.MarshalTo(data) @@ -169,33 +210,34 @@ func (m *Log_Content) Marshal() (data []byte, err error) { return data[:n], nil } -func (m *Log_Content) MarshalTo(data []byte) (int, error) { +// MarshalTo logcontent to data +func (m *LogContent) MarshalTo(data []byte) (int, error) { var i int _ = i var l int _ = l if m.Key == nil { return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Key") - } else { - data[i] = 0xa - i++ - i = encodeVarintLog(data, i, uint64(len(*m.Key))) - i += copy(data[i:], *m.Key) } + data[i] = 0xa + i++ + i = encodeVarintLog(data, i, uint64(len(*m.Key))) + i += copy(data[i:], *m.Key) + if m.Value == nil { return 0, github_com_gogo_protobuf_proto.NewRequiredNotSetError("Value") - } else { - data[i] = 0x12 - i++ - i = encodeVarintLog(data, i, uint64(len(*m.Value))) - i += copy(data[i:], *m.Value) } - if m.XXX_unrecognized != nil { - i += copy(data[i:], m.XXX_unrecognized) + data[i] = 0x12 + i++ + i = encodeVarintLog(data, i, uint64(len(*m.Value))) + i += copy(data[i:], *m.Value) + if m.XXXUnrecognized != nil { + i += copy(data[i:], m.XXXUnrecognized) } return i, nil } +// Marshal LogGroup func (m *LogGroup) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -206,6 +248,7 @@ func (m *LogGroup) Marshal() (data []byte, err error) { return data[:n], nil } +// MarshalTo LogGroup to data func (m *LogGroup) MarshalTo(data []byte) (int, error) { var i int _ = i @@ -241,12 +284,13 @@ func (m *LogGroup) MarshalTo(data []byte) (int, error) { i = encodeVarintLog(data, i, uint64(len(*m.Source))) i += copy(data[i:], *m.Source) } - if m.XXX_unrecognized != nil { - i += copy(data[i:], m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + i += copy(data[i:], m.XXXUnrecognized) } return i, nil } +// Marshal LogGroupList func (m *LogGroupList) Marshal() (data []byte, err error) { size := m.Size() data = make([]byte, size) @@ -257,6 +301,7 @@ func (m *LogGroupList) Marshal() (data []byte, err error) { return data[:n], nil } +// MarshalTo LogGroupList to data func (m *LogGroupList) MarshalTo(data []byte) (int, error) { var i int _ = i @@ -274,8 +319,8 @@ func (m *LogGroupList) MarshalTo(data []byte) (int, error) { i += n } } - if m.XXX_unrecognized != nil { - i += copy(data[i:], m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + i += copy(data[i:], m.XXXUnrecognized) } return i, nil } @@ -307,6 +352,8 @@ func encodeVarintLog(data []byte, offset int, v uint64) int { data[offset] = uint8(v) return offset + 1 } + +// Size return the log's size func (m *Log) Size() (n int) { var l int _ = l @@ -319,13 +366,14 @@ func (m *Log) Size() (n int) { n += 1 + l + sovLog(uint64(l)) } } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + n += len(m.XXXUnrecognized) } return n } -func (m *Log_Content) Size() (n int) { +// Size return LogContent size based on Key and Value +func (m *LogContent) Size() (n int) { var l int _ = l if m.Key != nil { @@ -336,12 +384,13 @@ func (m *Log_Content) Size() (n int) { l = len(*m.Value) n += 1 + l + sovLog(uint64(l)) } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + n += len(m.XXXUnrecognized) } return n } +// Size return LogGroup size based on Logs func (m *LogGroup) Size() (n int) { var l int _ = l @@ -363,12 +412,13 @@ func (m *LogGroup) Size() (n int) { l = len(*m.Source) n += 1 + l + sovLog(uint64(l)) } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + n += len(m.XXXUnrecognized) } return n } +// Size return LogGroupList size func (m *LogGroupList) Size() (n int) { var l int _ = l @@ -378,8 +428,8 @@ func (m *LogGroupList) Size() (n int) { n += 1 + l + sovLog(uint64(l)) } } - if m.XXX_unrecognized != nil { - n += len(m.XXX_unrecognized) + if m.XXXUnrecognized != nil { + n += len(m.XXXUnrecognized) } return n } @@ -397,6 +447,8 @@ func sovLog(x uint64) (n int) { func sozLog(x uint64) (n int) { return sovLog((x << 1) ^ (x >> 63)) } + +// Unmarshal data to log func (m *Log) Unmarshal(data []byte) error { var hasFields [1]uint64 l := len(data) @@ -474,7 +526,7 @@ func (m *Log) Unmarshal(data []byte) error { if postIndex > l { return io.ErrUnexpectedEOF } - m.Contents = append(m.Contents, &Log_Content{}) + m.Contents = append(m.Contents, &LogContent{}) if err := m.Contents[len(m.Contents)-1].Unmarshal(data[iNdEx:postIndex]); err != nil { return err } @@ -491,7 +543,7 @@ func (m *Log) Unmarshal(data []byte) error { if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...) + m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -504,7 +556,9 @@ func (m *Log) Unmarshal(data []byte) error { } return nil } -func (m *Log_Content) Unmarshal(data []byte) error { + +// Unmarshal data to LogContent +func (m *LogContent) Unmarshal(data []byte) error { var hasFields [1]uint64 l := len(data) iNdEx := 0 @@ -608,7 +662,7 @@ func (m *Log_Content) Unmarshal(data []byte) error { if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...) + m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -624,6 +678,8 @@ func (m *Log_Content) Unmarshal(data []byte) error { } return nil } + +// Unmarshal data to LogGroup func (m *LogGroup) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -786,7 +842,7 @@ func (m *LogGroup) Unmarshal(data []byte) error { if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...) + m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -796,6 +852,8 @@ func (m *LogGroup) Unmarshal(data []byte) error { } return nil } + +// Unmarshal data to LogGroupList func (m *LogGroupList) Unmarshal(data []byte) error { l := len(data) iNdEx := 0 @@ -868,7 +926,7 @@ func (m *LogGroupList) Unmarshal(data []byte) error { if (iNdEx + skippy) > l { return io.ErrUnexpectedEOF } - m.XXX_unrecognized = append(m.XXX_unrecognized, data[iNdEx:iNdEx+skippy]...) + m.XXXUnrecognized = append(m.XXXUnrecognized, data[iNdEx:iNdEx+skippy]...) iNdEx += skippy } } @@ -878,6 +936,7 @@ func (m *LogGroupList) Unmarshal(data []byte) error { } return nil } + func skipLog(data []byte) (n int, err error) { l := len(data) iNdEx := 0 @@ -940,7 +999,7 @@ func skipLog(data []byte) (n int, err error) { case 3: for { var innerWire uint64 - var start int = iNdEx + var start = iNdEx for shift := uint(0); ; shift += 7 { if shift >= 64 { return 0, ErrIntOverflowLog @@ -977,8 +1036,3 @@ func skipLog(data []byte) (n int, err error) { } panic("unreachable") } - -var ( - ErrInvalidLengthLog = fmt.Errorf("proto: negative length found during unmarshaling") - ErrIntOverflowLog = fmt.Errorf("proto: integer overflow") -) diff --git a/logs/alils/log_config.go b/logs/alils/log_config.go index 41fa0959..e8564efb 100755 --- a/logs/alils/log_config.go +++ b/logs/alils/log_config.go @@ -1,5 +1,6 @@ package alils +// InputDetail define log detail type InputDetail struct { LogType string `json:"logType"` LogPath string `json:"logPath"` @@ -14,11 +15,13 @@ type InputDetail struct { TopicFormat string `json:"topicFormat"` } +// OutputDetail define the output detail type OutputDetail struct { Endpoint string `json:"endpoint"` LogStoreName string `json:"logstoreName"` } +// LogConfig define Log Config type LogConfig struct { Name string `json:"configName"` InputType string `json:"inputType"` diff --git a/logs/alils/log_project.go b/logs/alils/log_project.go index 63ab07f8..59db8cbf 100755 --- a/logs/alils/log_project.go +++ b/logs/alils/log_project.go @@ -1,5 +1,5 @@ /* -Package sls implements the SDK(v0.5.0) of Simple Log Service(abbr. SLS). +Package alils implements the SDK(v0.5.0) of Simple Log Service(abbr. SLS). For more description about SLS, please read this article: http://gitlab.alibaba-inc.com/sls/doc. @@ -20,19 +20,20 @@ type errorMessage struct { Message string `json:"errorMessage"` } +// LogProject Define the Ali Project detail type LogProject struct { Name string // Project name Endpoint string // IP or hostname of SLS endpoint - AccessKeyId string + AccessKeyID string AccessKeySecret string } // NewLogProject creates a new SLS project. -func NewLogProject(name, endpoint, accessKeyId, accessKeySecret string) (p *LogProject, err error) { +func NewLogProject(name, endpoint, AccessKeyID, accessKeySecret string) (p *LogProject, err error) { p = &LogProject{ Name: name, Endpoint: endpoint, - AccessKeyId: accessKeyId, + AccessKeyID: AccessKeyID, AccessKeySecret: accessKeySecret, } return p, nil diff --git a/logs/alils/log_store.go b/logs/alils/log_store.go index 009e39c4..fa502736 100755 --- a/logs/alils/log_store.go +++ b/logs/alils/log_store.go @@ -12,6 +12,7 @@ import ( "github.com/gogo/protobuf/proto" ) +// LogStore Store the logs type LogStore struct { Name string `json:"logstoreName"` TTL int @@ -23,6 +24,7 @@ type LogStore struct { project *LogProject } +// Shard define the Log Shard type Shard struct { ShardID int `json:"shardID"` } @@ -116,16 +118,16 @@ func (s *LogStore) PutLogs(lg *LogGroup) (err error) { return } -// GetCursor gets log cursor of one shard specified by shardId. +// GetCursor gets log cursor of one shard specified by shardID. // The from can be in three form: a) unix timestamp in seccond, b) "begin", c) "end". // For more detail please read: http://gitlab.alibaba-inc.com/sls/doc/blob/master/api/shard.md#logstore -func (s *LogStore) GetCursor(shardId int, from string) (cursor string, err error) { +func (s *LogStore) GetCursor(shardID int, from string) (cursor string, err error) { h := map[string]string{ "x-sls-bodyrawsize": "0", } uri := fmt.Sprintf("/logstores/%v/shards/%v?type=cursor&from=%v", - s.Name, shardId, from) + s.Name, shardID, from) r, err := request(s.project, "GET", uri, h, nil) if err != nil { @@ -163,10 +165,10 @@ func (s *LogStore) GetCursor(shardId int, from string) (cursor string, err error return } -// GetLogsBytes gets logs binary data from shard specified by shardId according cursor. +// GetLogsBytes gets logs binary data from shard specified by shardID according cursor. // The logGroupMaxCount is the max number of logGroup could be returned. // The nextCursor is the next curosr can be used to read logs at next time. -func (s *LogStore) GetLogsBytes(shardId int, cursor string, +func (s *LogStore) GetLogsBytes(shardID int, cursor string, logGroupMaxCount int) (out []byte, nextCursor string, err error) { h := map[string]string{ @@ -176,7 +178,7 @@ func (s *LogStore) GetLogsBytes(shardId int, cursor string, } uri := fmt.Sprintf("/logstores/%v/shards/%v?type=logs&cursor=%v&count=%v", - s.Name, shardId, cursor, logGroupMaxCount) + s.Name, shardID, cursor, logGroupMaxCount) r, err := request(s.project, "GET", uri, h, nil) if err != nil { @@ -249,13 +251,13 @@ func LogsBytesDecode(data []byte) (gl *LogGroupList, err error) { return } -// GetLogs gets logs from shard specified by shardId according cursor. +// GetLogs gets logs from shard specified by shardID according cursor. // The logGroupMaxCount is the max number of logGroup could be returned. // The nextCursor is the next curosr can be used to read logs at next time. -func (s *LogStore) GetLogs(shardId int, cursor string, +func (s *LogStore) GetLogs(shardID int, cursor string, logGroupMaxCount int) (gl *LogGroupList, nextCursor string, err error) { - out, nextCursor, err := s.GetLogsBytes(shardId, cursor, logGroupMaxCount) + out, nextCursor, err := s.GetLogsBytes(shardID, cursor, logGroupMaxCount) if err != nil { return } diff --git a/logs/alils/machine_group.go b/logs/alils/machine_group.go index 7a0aace1..b6c69a14 100755 --- a/logs/alils/machine_group.go +++ b/logs/alils/machine_group.go @@ -8,18 +8,20 @@ import ( "net/http/httputil" ) -type MachinGroupAttribute struct { +// MachineGroupAttribute define the Attribute +type MachineGroupAttribute struct { ExternalName string `json:"externalName"` TopicName string `json:"groupTopic"` } +// MachineGroup define the machine Group type MachineGroup struct { Name string `json:"groupName"` Type string `json:"groupType"` - MachineIdType string `json:"machineIdentifyType"` - MachineIdList []string `json:"machineList"` + MachineIDType string `json:"machineIdentifyType"` + MachineIDList []string `json:"machineList"` - Attribute MachinGroupAttribute `json:"groupAttribute"` + Attribute MachineGroupAttribute `json:"groupAttribute"` CreateTime uint32 LastModifyTime uint32 @@ -27,12 +29,14 @@ type MachineGroup struct { project *LogProject } +// Machine define the Machine type Machine struct { IP string - UniqueId string `json:"machine-uniqueid"` - UserdefinedId string `json:"userdefined-id"` + UniqueID string `json:"machine-uniqueid"` + UserdefinedID string `json:"userdefined-id"` } +// MachineList define the Machine List type MachineList struct { Total int Machines []*Machine diff --git a/logs/alils/request.go b/logs/alils/request.go index 20df45b4..50d9c43c 100755 --- a/logs/alils/request.go +++ b/logs/alils/request.go @@ -33,12 +33,12 @@ func request(project *LogProject, method, uri string, headers map[string]string, } // Calc Authorization - // Authorization = "SLS :" + // Authorization = "SLS :" digest, err := signature(project, method, uri, headers) if err != nil { return } - auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyId, digest) + auth := fmt.Sprintf("SLS %v:%v", project.AccessKeyID, digest) headers["Authorization"] = auth // Initialize http request diff --git a/logs/file.go b/logs/file.go index 20ef167d..1c2db882 100644 --- a/logs/file.go +++ b/logs/file.go @@ -170,7 +170,7 @@ func (w *fileLogWriter) initFd() error { fd := w.fileWriter fInfo, err := fd.Stat() if err != nil { - return fmt.Errorf("get stat err: %s\n", err) + return fmt.Errorf("get stat err: %s", err) } w.maxSizeCurSize = int(fInfo.Size()) w.dailyOpenTime = time.Now() diff --git a/logs/log.go b/logs/log.go index a5e0a9ea..0e97a70e 100644 --- a/logs/log.go +++ b/logs/log.go @@ -492,9 +492,9 @@ func (bl *BeeLogger) flush() { } // beeLogger references the used application logger. -var beeLogger *BeeLogger = NewLogger() +var beeLogger = NewLogger() -// GetLogger returns the default BeeLogger +// GetBeeLogger returns the default BeeLogger func GetBeeLogger() *BeeLogger { return beeLogger } @@ -534,6 +534,7 @@ func Reset() { beeLogger.Reset() } +// Async set the beelogger with Async mode and hold msglen messages func Async(msgLen ...int64) *BeeLogger { return beeLogger.Async(msgLen...) } diff --git a/logs/logger.go b/logs/logger.go index e0abfdc4..b5d7255f 100644 --- a/logs/logger.go +++ b/logs/logger.go @@ -139,6 +139,11 @@ var ( reset = string([]byte{27, 91, 48, 109}) ) +// ColorByStatus return color by http code +// 2xx return Green +// 3xx return White +// 4xx return Yellow +// 5xx return Red func ColorByStatus(cond bool, code int) string { switch { case code >= 200 && code < 300: @@ -152,6 +157,14 @@ func ColorByStatus(cond bool, code int) string { } } +// ColorByMethod return color by http code +// GET return Blue +// POST return Cyan +// PUT return Yellow +// DELETE return Red +// PATCH return Green +// HEAD return Magenta +// OPTIONS return WHITE func ColorByMethod(cond bool, method string) string { switch method { case "GET": @@ -173,10 +186,10 @@ func ColorByMethod(cond bool, method string) string { } } -// Guard Mutex to guarantee atomicity of W32Debug(string) function +// Guard Mutex to guarantee atomic of W32Debug(string) function var mu sync.Mutex -// Helper method to output colored logs in Windows terminals +// W32Debug Helper method to output colored logs in Windows terminals func W32Debug(msg string) { mu.Lock() defer mu.Unlock() diff --git a/orm/db.go b/orm/db.go index 2bd525c2..2a05797a 100644 --- a/orm/db.go +++ b/orm/db.go @@ -507,10 +507,9 @@ func (d *dbBase) InsertOrUpdate(q dbQuerier, mi *modelInfo, ind reflect.Value, a case DRPostgres: if len(args) == 0 { return 0, fmt.Errorf("`%s` use InsertOrUpdate must have a conflict column", a.DriverName) - } else { - args0 = strings.ToLower(args[0]) - iouStr = fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET", args0) } + args0 = strings.ToLower(args[0]) + iouStr = fmt.Sprintf("ON CONFLICT (%s) DO UPDATE SET", args0) default: return 0, fmt.Errorf("`%s` nonsupport InsertOrUpdate in beego", a.DriverName) } diff --git a/orm/db_alias.go b/orm/db_alias.go index e70db9f0..c7089239 100644 --- a/orm/db_alias.go +++ b/orm/db_alias.go @@ -250,7 +250,7 @@ func RegisterDriver(driverName string, typ DriverType) error { drivers[driverName] = typ } else { if t != typ { - return fmt.Errorf("driverName `%s` db driver already registered and is other type\n", driverName) + return fmt.Errorf("driverName `%s` db driver already registered and is other type", driverName) } } return nil @@ -261,7 +261,7 @@ func SetDataBaseTZ(aliasName string, tz *time.Location) error { if al, ok := dataBaseCache.get(aliasName); ok { al.TZ = tz } else { - return fmt.Errorf("DataBase alias name `%s` not registered\n", aliasName) + return fmt.Errorf("DataBase alias name `%s` not registered", aliasName) } return nil } @@ -296,5 +296,5 @@ func GetDB(aliasNames ...string) (*sql.DB, error) { if ok { return al.DB, nil } - return nil, fmt.Errorf("DataBase of alias name `%s` not found\n", name) + return nil, fmt.Errorf("DataBase of alias name `%s` not found", name) } diff --git a/session/session.go b/session/session.go index fb4b2821..cf647521 100644 --- a/session/session.go +++ b/session/session.go @@ -81,6 +81,7 @@ func Register(name string, provide Provider) { provides[name] = provide } +// ManagerConfig define the session config type ManagerConfig struct { CookieName string `json:"cookieName"` EnableSetCookie bool `json:"enableSetCookie,omitempty"` @@ -92,9 +93,9 @@ type ManagerConfig struct { ProviderConfig string `json:"providerConfig"` Domain string `json:"domain"` SessionIDLength int64 `json:"sessionIDLength"` - EnableSidInHttpHeader bool `json:"enableSidInHttpHeader"` - SessionNameInHttpHeader string `json:"sessionNameInHttpHeader"` - EnableSidInUrlQuery bool `json:"enableSidInUrlQuery"` + EnableSidInHTTPHeader bool `json:"EnableSidInHTTPHeader"` + SessionNameInHTTPHeader string `json:"SessionNameInHTTPHeader"` + EnableSidInURLQuery bool `json:"EnableSidInURLQuery"` } // Manager contains Provider and its configuration. @@ -125,14 +126,14 @@ func NewManager(provideName string, cf *ManagerConfig) (*Manager, error) { cf.Maxlifetime = cf.Gclifetime } - if cf.EnableSidInHttpHeader { - if cf.SessionNameInHttpHeader == "" { - panic(errors.New("SessionNameInHttpHeader is empty")) + if cf.EnableSidInHTTPHeader { + if cf.SessionNameInHTTPHeader == "" { + panic(errors.New("SessionNameInHTTPHeader is empty")) } - strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHttpHeader) - if cf.SessionNameInHttpHeader != strMimeHeader { - strErrMsg := "SessionNameInHttpHeader (" + cf.SessionNameInHttpHeader + ") has the wrong format, it should be like this : " + strMimeHeader + strMimeHeader := textproto.CanonicalMIMEHeaderKey(cf.SessionNameInHTTPHeader) + if cf.SessionNameInHTTPHeader != strMimeHeader { + strErrMsg := "SessionNameInHTTPHeader (" + cf.SessionNameInHTTPHeader + ") has the wrong format, it should be like this : " + strMimeHeader panic(errors.New(strErrMsg)) } } @@ -163,7 +164,7 @@ func (manager *Manager) getSid(r *http.Request) (string, error) { cookie, errs := r.Cookie(manager.config.CookieName) if errs != nil || cookie.Value == "" { var sid string - if manager.config.EnableSidInUrlQuery { + if manager.config.EnableSidInURLQuery { errs := r.ParseForm() if errs != nil { return "", errs @@ -173,8 +174,8 @@ func (manager *Manager) getSid(r *http.Request) (string, error) { } // if not found in Cookie / param, then read it from request headers - if manager.config.EnableSidInHttpHeader && sid == "" { - sids, isFound := r.Header[manager.config.SessionNameInHttpHeader] + if manager.config.EnableSidInHTTPHeader && sid == "" { + sids, isFound := r.Header[manager.config.SessionNameInHTTPHeader] if isFound && len(sids) != 0 { return sids[0], nil } @@ -226,9 +227,9 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se } r.AddCookie(cookie) - if manager.config.EnableSidInHttpHeader { - r.Header.Set(manager.config.SessionNameInHttpHeader, sid) - w.Header().Set(manager.config.SessionNameInHttpHeader, sid) + if manager.config.EnableSidInHTTPHeader { + r.Header.Set(manager.config.SessionNameInHTTPHeader, sid) + w.Header().Set(manager.config.SessionNameInHTTPHeader, sid) } return @@ -236,9 +237,9 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se // SessionDestroy Destroy session by its id in http request cookie. func (manager *Manager) SessionDestroy(w http.ResponseWriter, r *http.Request) { - if manager.config.EnableSidInHttpHeader { - r.Header.Del(manager.config.SessionNameInHttpHeader) - w.Header().Del(manager.config.SessionNameInHttpHeader) + if manager.config.EnableSidInHTTPHeader { + r.Header.Del(manager.config.SessionNameInHTTPHeader) + w.Header().Del(manager.config.SessionNameInHTTPHeader) } cookie, err := r.Cookie(manager.config.CookieName) @@ -306,9 +307,9 @@ func (manager *Manager) SessionRegenerateID(w http.ResponseWriter, r *http.Reque } r.AddCookie(cookie) - if manager.config.EnableSidInHttpHeader { - r.Header.Set(manager.config.SessionNameInHttpHeader, sid) - w.Header().Set(manager.config.SessionNameInHttpHeader, sid) + if manager.config.EnableSidInHTTPHeader { + r.Header.Set(manager.config.SessionNameInHTTPHeader, sid) + w.Header().Set(manager.config.SessionNameInHTTPHeader, sid) } return @@ -328,7 +329,7 @@ func (manager *Manager) sessionID() (string, error) { b := make([]byte, manager.config.SessionIDLength) n, err := rand.Read(b) if n != len(b) || err != nil { - return "", fmt.Errorf("Could not successfully read from the system CSPRNG.") + return "", fmt.Errorf("Could not successfully read from the system CSPRNG") } return hex.EncodeToString(b), nil } diff --git a/session/ssdb/sess_ssdb.go b/session/ssdb/sess_ssdb.go index 03b60793..de0c6360 100644 --- a/session/ssdb/sess_ssdb.go +++ b/session/ssdb/sess_ssdb.go @@ -11,16 +11,17 @@ import ( "github.com/ssdb/gossdb/ssdb" ) -var ssdbProvider = &SsdbProvider{} +var ssdbProvider = &Provider{} -type SsdbProvider struct { +// Provider holds ssdb client and configs +type Provider struct { client *ssdb.Client host string port int maxLifetime int64 } -func (p *SsdbProvider) connectInit() error { +func (p *Provider) connectInit() error { var err error if p.host == "" || p.port == 0 { return errors.New("SessionInit First") @@ -29,7 +30,8 @@ func (p *SsdbProvider) connectInit() error { return err } -func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { +// SessionInit init the ssdb with the config +func (p *Provider) SessionInit(maxLifetime int64, savePath string) error { p.maxLifetime = maxLifetime address := strings.Split(savePath, ":") p.host = address[0] @@ -41,7 +43,8 @@ func (p *SsdbProvider) SessionInit(maxLifetime int64, savePath string) error { return p.connectInit() } -func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) { +// SessionRead return a ssdb client session Store +func (p *Provider) SessionRead(sid string) (session.Store, error) { if p.client == nil { if err := p.connectInit(); err != nil { return nil, err @@ -64,7 +67,8 @@ func (p *SsdbProvider) SessionRead(sid string) (session.Store, error) { return rs, nil } -func (p *SsdbProvider) SessionExist(sid string) bool { +// SessionExist judged whether sid is exist in session +func (p *Provider) SessionExist(sid string) bool { if p.client == nil { if err := p.connectInit(); err != nil { panic(err) @@ -80,7 +84,8 @@ func (p *SsdbProvider) SessionExist(sid string) bool { return true } -func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, error) { +// SessionRegenerate regenerate session with new sid and delete oldsid +func (p *Provider) SessionRegenerate(oldsid, sid string) (session.Store, error) { //conn.Do("setx", key, v, ttl) if p.client == nil { if err := p.connectInit(); err != nil { @@ -112,7 +117,8 @@ func (p *SsdbProvider) SessionRegenerate(oldsid, sid string) (session.Store, err return rs, nil } -func (p *SsdbProvider) SessionDestroy(sid string) error { +// SessionDestroy destroy the sid +func (p *Provider) SessionDestroy(sid string) error { if p.client == nil { if err := p.connectInit(); err != nil { return err @@ -122,13 +128,16 @@ func (p *SsdbProvider) SessionDestroy(sid string) error { return err } -func (p *SsdbProvider) SessionGC() { +// SessionGC not implemented +func (p *Provider) SessionGC() { } -func (p *SsdbProvider) SessionAll() int { +// SessionAll not implemented +func (p *Provider) SessionAll() int { return 0 } +// SessionStore holds the session information which stored in ssdb type SessionStore struct { sid string lock sync.RWMutex @@ -137,12 +146,15 @@ type SessionStore struct { client *ssdb.Client } +// Set the key and value func (s *SessionStore) Set(key, value interface{}) error { s.lock.Lock() defer s.lock.Unlock() s.values[key] = value return nil } + +// Get return the value by the key func (s *SessionStore) Get(key interface{}) interface{} { s.lock.Lock() defer s.lock.Unlock() @@ -152,30 +164,36 @@ func (s *SessionStore) Get(key interface{}) interface{} { return nil } +// Delete the key in session store func (s *SessionStore) Delete(key interface{}) error { s.lock.Lock() defer s.lock.Unlock() delete(s.values, key) return nil } + +// Flush delete all keys and values func (s *SessionStore) Flush() error { s.lock.Lock() defer s.lock.Unlock() s.values = make(map[interface{}]interface{}) return nil } + +// SessionID return the sessionID func (s *SessionStore) SessionID() string { return s.sid } +// SessionRelease Store the keyvalues into ssdb func (s *SessionStore) SessionRelease(w http.ResponseWriter) { b, err := session.EncodeGob(s.values) if err != nil { return } s.client.Do("setx", s.sid, string(b), s.maxLifetime) - } + func init() { session.Register("ssdb", ssdbProvider) } diff --git a/swagger/swagger.go b/swagger/swagger.go index e0ac5cf5..c687fb8e 100644 --- a/swagger/swagger.go +++ b/swagger/swagger.go @@ -100,7 +100,7 @@ type Parameter struct { Default interface{} `json:"default,omitempty" yaml:"default,omitempty"` } -// A limited subset of JSON-Schema's items object. It is used by parameter definitions that are not located in "body". +// ParameterItems A limited subset of JSON-Schema's items object. It is used by parameter definitions that are not located in "body". // http://swagger.io/specification/#itemsObject type ParameterItems struct { Type string `json:"type,omitempty" yaml:"type,omitempty"` From 79b66ef05304e0ff5d3fe724b714841f57cf6f4e Mon Sep 17 00:00:00 2001 From: astaxie Date: Sun, 30 Apr 2017 22:55:39 +0800 Subject: [PATCH 52/82] fix the beego ORM test --- orm/orm_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/orm_test.go b/orm/orm_test.go index 71b614f3..c5bfa8b9 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -2144,7 +2144,7 @@ func TestUintPk(t *testing.T) { throwFail(t, AssertIs(u.Name, name)) nu := &UintPk{ID: 8} - created, pk, err = dORM.ReadOrCreate(nu, "ID") + created, pk, err := dORM.ReadOrCreate(nu, "ID") throwFail(t, err) throwFail(t, AssertIs(created, false)) throwFail(t, AssertIs(nu.ID, u.ID)) From 44bdf1df6313496c8bf5da5b3aa58fd4291a78e6 Mon Sep 17 00:00:00 2001 From: astaxie Date: Sun, 30 Apr 2017 23:38:48 +0800 Subject: [PATCH 53/82] ignore NilErr --- session/ledis/ledis_session.go | 5 +---- session/redis/sess_redis.go | 10 +++------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/session/ledis/ledis_session.go b/session/ledis/ledis_session.go index 18b27708..77685d1e 100644 --- a/session/ledis/ledis_session.go +++ b/session/ledis/ledis_session.go @@ -113,13 +113,10 @@ func (lp *Provider) SessionInit(maxlifetime int64, savePath string) error { func (lp *Provider) SessionRead(sid string) (session.Store, error) { var ( kv map[interface{}]interface{} - kvs []byte err error ) - if kvs, err = c.Get([]byte(sid)); err != nil { - return nil, err - } + kvs, _ := c.Get([]byte(sid)) if len(kvs) == 0 { kv = make(map[interface{}]interface{}) diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 08efa6e1..20dbe030 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -176,16 +176,12 @@ func (rp *Provider) SessionRead(sid string) (session.Store, error) { c := rp.poollist.Get() defer c.Close() - var ( - kv map[interface{}]interface{} - kvs string - err error - ) + var kv map[interface{}]interface{} - if kvs, err = redis.String(c.Do("GET", sid)); err != nil { + kvs, err := redis.String(c.Do("GET", sid)) + if err != redis.ErrNil { return nil, err } - if len(kvs) == 0 { kv = make(map[interface{}]interface{}) } else { From 947980b5ebe522e60de6e40d25cc93bef5525498 Mon Sep 17 00:00:00 2001 From: astaxie Date: Sun, 30 Apr 2017 23:43:46 +0800 Subject: [PATCH 54/82] beego 1.8.2 --- beego.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beego.go b/beego.go index 7acf4a13..7a8db390 100644 --- a/beego.go +++ b/beego.go @@ -23,7 +23,7 @@ import ( const ( // VERSION represent beego web framework version. - VERSION = "1.8.1" + VERSION = "1.8.2" // DEV is for develop DEV = "dev" From e76423e6dc646c6caa77618282fd7ffebd7a2241 Mon Sep 17 00:00:00 2001 From: astaxie Date: Sun, 30 Apr 2017 23:59:38 +0800 Subject: [PATCH 55/82] revert #2518, fix #2605 --- context/output.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/output.go b/context/output.go index c15f9fe7..564ef96d 100644 --- a/context/output.go +++ b/context/output.go @@ -105,7 +105,7 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface switch { case maxAge > 0: fmt.Fprintf(&b, "; Expires=%s; Max-Age=%d", time.Now().Add(time.Duration(maxAge)*time.Second).UTC().Format(time.RFC1123), maxAge) - case maxAge <= 0: + case maxAge < 0: fmt.Fprintf(&b, "; Max-Age=0") } } From 1b8f05cef15029e184036c081b9d5b9542d1ecbe Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Sun, 30 Apr 2017 19:28:26 +0300 Subject: [PATCH 56/82] golint fixes --- context/param/conv.go | 16 ++++++++-------- context/param/methodparams.go | 4 +++- context/param/options.go | 6 ++++++ context/response/renderer.go | 3 +++ context/response/responses.go | 9 ++++++--- router.go | 2 +- 6 files changed, 27 insertions(+), 13 deletions(-) diff --git a/context/param/conv.go b/context/param/conv.go index 8e580c2e..e961b4ad 100644 --- a/context/param/conv.go +++ b/context/param/conv.go @@ -8,6 +8,7 @@ import ( "github.com/astaxie/beego/logs" ) +// ConvertParams converts http method params to values that will be passed to the method controller as arguments func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) { result = make([]reflect.Value, 0, len(methodParams)) for i := 0; i < len(methodParams); i++ { @@ -55,15 +56,14 @@ func getParamValue(param *MethodParam, ctx *beecontext.Context) string { func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) { if paramValue == "" { return reflect.Zero(paramType), nil - } else { - parser := getParser(param, paramType) - value, err := parser.parse(paramValue, paramType) - if err != nil { - return result, err - } - - return safeConvert(reflect.ValueOf(value), paramType) } + parser := getParser(param, paramType) + value, err := parser.parse(paramValue, paramType) + if err != nil { + return result, err + } + + return safeConvert(reflect.ValueOf(value), paramType) } func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) { diff --git a/context/param/methodparams.go b/context/param/methodparams.go index 23fd6661..28772504 100644 --- a/context/param/methodparams.go +++ b/context/param/methodparams.go @@ -5,7 +5,7 @@ import ( "strings" ) -//Keeps param information to be auto passed to controller methods +//MethodParam keeps param information to be auto passed to controller methods type MethodParam struct { name string location paramLocation @@ -22,6 +22,7 @@ const ( header ) +//New creates a new MethodParam with name and specific options func New(name string, opts ...MethodParamOption) *MethodParam { return newParam(name, nil, opts) } @@ -34,6 +35,7 @@ func newParam(name string, parser paramParser, opts []MethodParamOption) (param return } +//Make creates an array of MethodParmas or an empty array func Make(list ...*MethodParam) []*MethodParam { if len(list) > 0 { return list diff --git a/context/param/options.go b/context/param/options.go index 0013c31e..846a59f6 100644 --- a/context/param/options.go +++ b/context/param/options.go @@ -4,24 +4,30 @@ import ( "fmt" ) +// MethodParamOption defines a func which apply options on a MethodParam type MethodParamOption func(*MethodParam) +// IsRequired indicates that this param is required and can not be ommited from the http request var IsRequired MethodParamOption = func(p *MethodParam) { p.required = true } +// InHeader indicates that this param is passed via an http header var InHeader MethodParamOption = func(p *MethodParam) { p.location = header } +// InPath indicates that this param is part of the URL path var InPath MethodParamOption = func(p *MethodParam) { p.location = path } +// InBody indicates that this param is passed as an http request body var InBody MethodParamOption = func(p *MethodParam) { p.location = body } +// Default provides a default value for the http param func Default(defValue interface{}) MethodParamOption { return func(p *MethodParam) { if defValue != nil { diff --git a/context/response/renderer.go b/context/response/renderer.go index f5f9a52d..2a4d2797 100644 --- a/context/response/renderer.go +++ b/context/response/renderer.go @@ -6,6 +6,7 @@ import ( beecontext "github.com/astaxie/beego/context" ) +// Renderer defines an http response renderer type Renderer interface { Render(ctx *beecontext.Context) } @@ -16,12 +17,14 @@ func (f rendererFunc) Render(ctx *beecontext.Context) { f(ctx) } +// StatusCode sets the http response status code type StatusCode int func (s StatusCode) Error() string { return strconv.Itoa(int(s)) } +// Render sets the http status code func (s StatusCode) Render(ctx *beecontext.Context) { ctx.Output.SetStatus(int(s)) } diff --git a/context/response/responses.go b/context/response/responses.go index 5fbe4be1..c033edf7 100644 --- a/context/response/responses.go +++ b/context/response/responses.go @@ -4,7 +4,8 @@ import ( beecontext "github.com/astaxie/beego/context" ) -func Json(value interface{}, encoding ...bool) Renderer { +// JSON renders value to the response as JSON +func JSON(value interface{}, encoding ...bool) Renderer { return rendererFunc(func(ctx *beecontext.Context) { var ( hasIndent = true @@ -28,12 +29,14 @@ func errorRenderer(err error) Renderer { }) } -func Redirect(localurl string) statusCodeWithRender { +// Redirect renders http 302 with a URL +func Redirect(localurl string) Renderer { return statusCodeWithRender{302, func(ctx *beecontext.Context) { ctx.Redirect(302, localurl) }} } +// RenderMethodResult renders the return value of a controller method to the output func RenderMethodResult(result interface{}, ctx *beecontext.Context) { if result != nil { renderer, ok := result.(Renderer) @@ -42,7 +45,7 @@ func RenderMethodResult(result interface{}, ctx *beecontext.Context) { if ok { renderer = errorRenderer(err) } else { - renderer = Json(result) + renderer = JSON(result) } } renderer.Render(ctx) diff --git a/router.go b/router.go index ebe70e72..33096039 100644 --- a/router.go +++ b/router.go @@ -813,7 +813,7 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) default: if !execController.HandlerFunc(runMethod) { method := vc.MethodByName(runMethod) - var in []reflect.Value = param.ConvertParams(methodParams, method.Type(), context) + in := param.ConvertParams(methodParams, method.Type(), context) out := method.Call(in) //For backward compatibility we only handle response if we had incoming methodParams From d3a16dca85d1c4ceae415134718411c7758689fc Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Mon, 1 May 2017 08:57:57 +0300 Subject: [PATCH 57/82] Redirect should returns error --- context/response/responses.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/context/response/responses.go b/context/response/responses.go index c033edf7..10d1ed3f 100644 --- a/context/response/responses.go +++ b/context/response/responses.go @@ -30,7 +30,7 @@ func errorRenderer(err error) Renderer { } // Redirect renders http 302 with a URL -func Redirect(localurl string) Renderer { +func Redirect(localurl string) error { return statusCodeWithRender{302, func(ctx *beecontext.Context) { ctx.Redirect(302, localurl) }} From 83814a76cc77279d5d979780e82f4464b33677c3 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 2 May 2017 12:47:15 +0800 Subject: [PATCH 58/82] hotfix: err nil --- session/redis/sess_redis.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 20dbe030..d0424515 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -179,7 +179,7 @@ func (rp *Provider) SessionRead(sid string) (session.Store, error) { var kv map[interface{}]interface{} kvs, err := redis.String(c.Do("GET", sid)) - if err != redis.ErrNil { + if err != nil && err != redis.ErrNil { return nil, err } if len(kvs) == 0 { From b2e7720fcd26a82d3a00d9846c26ba5931ca75b8 Mon Sep 17 00:00:00 2001 From: Yang Luo Date: Thu, 4 May 2017 14:02:21 +0800 Subject: [PATCH 59/82] Add an authorization plugin that supports ACL, RBAC based on casbin. It requires the built-in HTTP basic authentication by default. --- .travis.yml | 2 + plugins/authz/authz.go | 86 ++++++++++++++++++++++++++ plugins/authz/authz_model.conf | 14 +++++ plugins/authz/authz_policy.csv | 7 +++ plugins/authz/authz_test.go | 107 +++++++++++++++++++++++++++++++++ 5 files changed, 216 insertions(+) create mode 100644 plugins/authz/authz.go create mode 100644 plugins/authz/authz_model.conf create mode 100644 plugins/authz/authz_policy.csv create mode 100644 plugins/authz/authz_test.go diff --git a/.travis.yml b/.travis.yml index 479d70ca..aa88a44d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,8 @@ install: - go get github.com/ssdb/gossdb/ssdb - go get github.com/cloudflare/golz4 - go get github.com/gogo/protobuf/proto + - go get github.com/Knetic/govaluate + - go get github.com/hsluoyz/casbin - go get -u honnef.co/go/tools/cmd/gosimple - go get -u github.com/mdempsky/unconvert - go get -u github.com/gordonklaus/ineffassign diff --git a/plugins/authz/authz.go b/plugins/authz/authz.go new file mode 100644 index 00000000..709a613a --- /dev/null +++ b/plugins/authz/authz.go @@ -0,0 +1,86 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// Package authz provides handlers to enable ACL, RBAC, ABAC authorization support. +// Simple Usage: +// import( +// "github.com/astaxie/beego" +// "github.com/astaxie/beego/plugins/authz" +// "github.com/hsluoyz/casbin" +// ) +// +// func main(){ +// // mediate the access for every request +// beego.InsertFilter("*", beego.BeforeRouter, authz.NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"))) +// beego.Run() +// } +// +// +// Advanced Usage: +// +// func main(){ +// e := casbin.NewEnforcer("authz_model.conf", "") +// e.AddRoleForUser("alice", "admin") +// e.AddPolicy(...) +// +// beego.InsertFilter("*", beego.BeforeRouter, authz.NewAuthorizer(e)) +// beego.Run() +// } +package authz + +import ( + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" + "github.com/hsluoyz/casbin" + "net/http" +) + +// NewAuthorizer returns the authorizer. +// Use a casbin enforcer as input +func NewAuthorizer(e *casbin.Enforcer) beego.FilterFunc { + return func(ctx *context.Context) { + a := &BasicAuthorizer{enforcer: e} + + if !a.CheckPermission(ctx.Request) { + a.RequirePermission(ctx.ResponseWriter) + } + } +} + +// BasicAuthorizer stores the casbin handler +type BasicAuthorizer struct { + enforcer *casbin.Enforcer +} + +// GetUserName gets the user name from the request. +// Currently, only HTTP basic authentication is supported +func (a *BasicAuthorizer) GetUserName(r *http.Request) string { + username, _, _ := r.BasicAuth() + return username +} + +// CheckPermission checks the user/method/path combination from the request. +// Returns true (permission granted) or false (permission forbidden) +func (a *BasicAuthorizer) CheckPermission(r *http.Request) bool { + user := a.GetUserName(r) + method := r.Method + path := r.URL.Path + return a.enforcer.Enforce(user, path, method) +} + +// RequirePermission returns the 403 Forbidden to the client +func (a *BasicAuthorizer) RequirePermission(w http.ResponseWriter) { + w.WriteHeader(403) + w.Write([]byte("403 Forbidden\n")) +} diff --git a/plugins/authz/authz_model.conf b/plugins/authz/authz_model.conf new file mode 100644 index 00000000..d1b3dbd7 --- /dev/null +++ b/plugins/authz/authz_model.conf @@ -0,0 +1,14 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") \ No newline at end of file diff --git a/plugins/authz/authz_policy.csv b/plugins/authz/authz_policy.csv new file mode 100644 index 00000000..c062dd3e --- /dev/null +++ b/plugins/authz/authz_policy.csv @@ -0,0 +1,7 @@ +p, alice, /dataset1/*, GET +p, alice, /dataset1/resource1, POST +p, bob, /dataset2/resource1, * +p, bob, /dataset2/resource2, GET +p, bob, /dataset2/folder1/*, POST +p, dataset1_admin, /dataset1/*, * +g, cathy, dataset1_admin \ No newline at end of file diff --git a/plugins/authz/authz_test.go b/plugins/authz/authz_test.go new file mode 100644 index 00000000..4003582c --- /dev/null +++ b/plugins/authz/authz_test.go @@ -0,0 +1,107 @@ +// Copyright 2014 beego Author. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package authz + +import ( + "github.com/astaxie/beego" + "github.com/astaxie/beego/context" + "github.com/astaxie/beego/plugins/auth" + "github.com/hsluoyz/casbin" + "net/http" + "net/http/httptest" + "testing" +) + +func testRequest(t *testing.T, handler *beego.ControllerRegister, user string, path string, method string, code int) { + r, _ := http.NewRequest(method, path, nil) + r.SetBasicAuth(user, "123") + w := httptest.NewRecorder() + handler.ServeHTTP(w, r) + + if w.Code != code { + t.Errorf("%s, %s, %s: %d, supposed to be %d", user, path, method, w.Code, code) + } +} + +func TestBasic(t *testing.T) { + handler := beego.NewControllerRegister() + + handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("alice", "123")) + handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"))) + + handler.Any("*", func(ctx *context.Context) { + ctx.Output.SetStatus(200) + }) + + testRequest(t, handler, "alice", "/dataset1/resource1", "GET", 200) + testRequest(t, handler, "alice", "/dataset1/resource1", "POST", 200) + testRequest(t, handler, "alice", "/dataset1/resource2", "GET", 200) + testRequest(t, handler, "alice", "/dataset1/resource2", "POST", 403) +} + +func TestPathWildcard(t *testing.T) { + handler := beego.NewControllerRegister() + + handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("bob", "123")) + handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(casbin.NewEnforcer("authz_model.conf", "authz_policy.csv"))) + + handler.Any("*", func(ctx *context.Context) { + ctx.Output.SetStatus(200) + }) + + testRequest(t, handler, "bob", "/dataset2/resource1", "GET", 200) + testRequest(t, handler, "bob", "/dataset2/resource1", "POST", 200) + testRequest(t, handler, "bob", "/dataset2/resource1", "DELETE", 200) + testRequest(t, handler, "bob", "/dataset2/resource2", "GET", 200) + testRequest(t, handler, "bob", "/dataset2/resource2", "POST", 403) + testRequest(t, handler, "bob", "/dataset2/resource2", "DELETE", 403) + + testRequest(t, handler, "bob", "/dataset2/folder1/item1", "GET", 403) + testRequest(t, handler, "bob", "/dataset2/folder1/item1", "POST", 200) + testRequest(t, handler, "bob", "/dataset2/folder1/item1", "DELETE", 403) + testRequest(t, handler, "bob", "/dataset2/folder1/item2", "GET", 403) + testRequest(t, handler, "bob", "/dataset2/folder1/item2", "POST", 200) + testRequest(t, handler, "bob", "/dataset2/folder1/item2", "DELETE", 403) +} + +func TestRBAC(t *testing.T) { + handler := beego.NewControllerRegister() + + handler.InsertFilter("*", beego.BeforeRouter, auth.Basic("cathy", "123")) + e := casbin.NewEnforcer("authz_model.conf", "authz_policy.csv") + handler.InsertFilter("*", beego.BeforeRouter, NewAuthorizer(e)) + + handler.Any("*", func(ctx *context.Context) { + ctx.Output.SetStatus(200) + }) + + // cathy can access all /dataset1/* resources via all methods because it has the dataset1_admin role. + testRequest(t, handler, "cathy", "/dataset1/item", "GET", 200) + testRequest(t, handler, "cathy", "/dataset1/item", "POST", 200) + testRequest(t, handler, "cathy", "/dataset1/item", "DELETE", 200) + testRequest(t, handler, "cathy", "/dataset2/item", "GET", 403) + testRequest(t, handler, "cathy", "/dataset2/item", "POST", 403) + testRequest(t, handler, "cathy", "/dataset2/item", "DELETE", 403) + + // delete all roles on user cathy, so cathy cannot access any resources now. + e.DeleteRolesForUser("cathy") + + testRequest(t, handler, "cathy", "/dataset1/item", "GET", 403) + testRequest(t, handler, "cathy", "/dataset1/item", "POST", 403) + testRequest(t, handler, "cathy", "/dataset1/item", "DELETE", 403) + testRequest(t, handler, "cathy", "/dataset2/item", "GET", 403) + testRequest(t, handler, "cathy", "/dataset2/item", "POST", 403) + testRequest(t, handler, "cathy", "/dataset2/item", "DELETE", 403) +} From 9b01b1c63d6f6dfd722d315d29dbaf86c78b2e05 Mon Sep 17 00:00:00 2001 From: guanly Date: Thu, 11 May 2017 14:49:01 +0800 Subject: [PATCH 60/82] =?UTF-8?q?ISSUE2630=20=20=E4=BD=BF=E7=94=A8sqlite?= =?UTF-8?q?=EF=BC=8Corm=E4=B8=AD=E9=80=9A=E8=BF=87filter=E5=90=8E=E7=9A=84?= =?UTF-8?q?delete=E5=88=A0=E9=99=A4=E4=B8=8D=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/astaxie/beego/issues/2630 --- orm/db.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/orm/db.go b/orm/db.go index 2a05797a..21030eef 100644 --- a/orm/db.go +++ b/orm/db.go @@ -833,7 +833,11 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con if err := rs.Scan(&ref); err != nil { return 0, err } - args = append(args, reflect.ValueOf(ref).Interface()) + pkValue, err := d.convertValueFromDB(mi.fields.pk, reflect.ValueOf(ref).Interface(), tz) + if err != nil { + panic(fmt.Errorf("get pk value failed: `%s` ", ref)) + } + args = append(args, pkValue) cnt++ } From 10cd1070f45ceda87c19519e00b11e0ad1227ffd Mon Sep 17 00:00:00 2001 From: guanly Date: Thu, 11 May 2017 21:45:38 +0800 Subject: [PATCH 61/82] =?UTF-8?q?=E4=BD=BF=E7=94=A8sqlite=EF=BC=8Corm?= =?UTF-8?q?=E4=B8=AD=E9=80=9A=E8=BF=87filter=E5=90=8E=E7=9A=84delete?= =?UTF-8?q?=E5=88=A0=E9=99=A4=E4=B8=8D=E6=88=90=E5=8A=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://github.com/astaxie/beego/issues/2630 --- orm/db.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/db.go b/orm/db.go index 21030eef..12f0f54d 100644 --- a/orm/db.go +++ b/orm/db.go @@ -835,7 +835,7 @@ func (d *dbBase) DeleteBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Con } pkValue, err := d.convertValueFromDB(mi.fields.pk, reflect.ValueOf(ref).Interface(), tz) if err != nil { - panic(fmt.Errorf("get pk value failed: `%s` ", ref)) + return 0, err } args = append(args, pkValue) cnt++ From cb4f252a06455ac1a4f9e15d7d83e3c33cd188fb Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Thu, 11 May 2017 17:58:25 +0300 Subject: [PATCH 62/82] defValue -> defaultValue --- context/param/conv.go | 5 +---- context/param/methodparams.go | 12 ++++++------ context/param/options.go | 6 +++--- 3 files changed, 10 insertions(+), 13 deletions(-) diff --git a/context/param/conv.go b/context/param/conv.go index e961b4ad..596d2b1e 100644 --- a/context/param/conv.go +++ b/context/param/conv.go @@ -24,7 +24,7 @@ func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Co if param.required { ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name)) } else { - paramValue = param.defValue + paramValue = param.defaultValue } } @@ -43,9 +43,6 @@ func getParamValue(param *MethodParam, ctx *beecontext.Context) string { return string(ctx.Input.RequestBody) case header: return ctx.Input.Header(param.name) - // if strValue == "" && strings.Contains(param.name, "_") { //magically handle X-Headers? - // strValue = ctx.Input.Header(strings.Replace(param.name, "_", "-", -1)) - // } case path: return ctx.Input.Query(":" + param.name) default: diff --git a/context/param/methodparams.go b/context/param/methodparams.go index 28772504..fe4ab421 100644 --- a/context/param/methodparams.go +++ b/context/param/methodparams.go @@ -7,10 +7,10 @@ import ( //MethodParam keeps param information to be auto passed to controller methods type MethodParam struct { - name string - location paramLocation - required bool - defValue string + name string + location paramLocation + required bool + defaultValue string } type paramLocation byte @@ -57,8 +57,8 @@ func (mp *MethodParam) String() string { case header: options = append(options, "param.InHeader") } - if mp.defValue != "" { - options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defValue)) + if mp.defaultValue != "" { + options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defaultValue)) } if len(options) > 0 { result += ", " diff --git a/context/param/options.go b/context/param/options.go index 846a59f6..32402194 100644 --- a/context/param/options.go +++ b/context/param/options.go @@ -28,10 +28,10 @@ var InBody MethodParamOption = func(p *MethodParam) { } // Default provides a default value for the http param -func Default(defValue interface{}) MethodParamOption { +func Default(defaultValue interface{}) MethodParamOption { return func(p *MethodParam) { - if defValue != nil { - p.defValue = fmt.Sprint(defValue) + if defaultValue != nil { + p.defaultValue = fmt.Sprint(defaultValue) } } } From 74dc3c750028aee134e648f988b2f270e4985645 Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Thu, 11 May 2017 19:32:44 +0300 Subject: [PATCH 63/82] tests --- context/param/parsers_test.go | 45 +++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 context/param/parsers_test.go diff --git a/context/param/parsers_test.go b/context/param/parsers_test.go new file mode 100644 index 00000000..6d305018 --- /dev/null +++ b/context/param/parsers_test.go @@ -0,0 +1,45 @@ +package param + +import "testing" +import "reflect" +import "time" + +type testDefinition struct { + strValue string + expectedValue interface{} + expectedParser paramParser +} + +func Test_Parsers(t *testing.T) { + checkParser(testDefinition{"1", 1, intParser{}}, t) + + checkParser(testDefinition{"1.0", 1.0, floatParser{}}, t) + + checkParser(testDefinition{"1", "1", stringParser{}}, t) + + checkParser(testDefinition{"true", true, boolParser{}}, t) + + checkParser(testDefinition{"2017-05-30T13:54:53Z", time.Date(2017, 5, 30, 13, 54, 53, 0, time.UTC), timeParser{}}, t) + + checkParser(testDefinition{`{"X": 5}`, struct{ X int }{5}, jsonParser{}}, t) + + checkParser(testDefinition{`1,2`, []int{1, 2}, sliceParser(intParser{})}, t) +} + +func checkParser(def testDefinition, t *testing.T) { + toType := reflect.TypeOf(def.expectedValue) + parser := getParser(&MethodParam{}, toType) + + if reflect.TypeOf(parser) != reflect.TypeOf(def.expectedParser) { + t.Errorf("Invalid parser for value %v. Expected: %v, actual: %v", def.strValue, reflect.TypeOf(def.expectedParser).Name(), reflect.TypeOf(parser).Name()) + return + } + result, err := parser.parse(def.strValue, toType) + if err != nil { + t.Errorf("Parsing error for value %v. Expected result: %v, error: %v", def.strValue, def.expectedValue, err) + return + } + if !reflect.DeepEqual(result, def.expectedValue) { + t.Errorf("Parsing error for value %v. Expected result: %v, actual: %v", def.strValue, def.expectedValue, result) + } +} From b6a35a8944ee928dbbcc4fbfb3b1760a6c21d5c2 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Fri, 12 May 2017 09:25:12 +0300 Subject: [PATCH 64/82] more tests --- context/param/parsers_test.go | 51 ++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/context/param/parsers_test.go b/context/param/parsers_test.go index 6d305018..cc97c735 100644 --- a/context/param/parsers_test.go +++ b/context/param/parsers_test.go @@ -11,24 +11,58 @@ type testDefinition struct { } func Test_Parsers(t *testing.T) { + + //ints checkParser(testDefinition{"1", 1, intParser{}}, t) + checkParser(testDefinition{"-1", int64(-1), intParser{}}, t) + checkParser(testDefinition{"1", uint64(1), intParser{}}, t) - checkParser(testDefinition{"1.0", 1.0, floatParser{}}, t) + //floats + checkParser(testDefinition{"1.0", float32(1.0), floatParser{}}, t) + checkParser(testDefinition{"-1.0", float64(-1.0), floatParser{}}, t) - checkParser(testDefinition{"1", "1", stringParser{}}, t) + //strings + checkParser(testDefinition{"AB", "AB", stringParser{}}, t) + checkParser(testDefinition{"AB", []byte{65, 66}, stringParser{}}, t) + //bools checkParser(testDefinition{"true", true, boolParser{}}, t) + checkParser(testDefinition{"0", false, boolParser{}}, t) + //timeParser checkParser(testDefinition{"2017-05-30T13:54:53Z", time.Date(2017, 5, 30, 13, 54, 53, 0, time.UTC), timeParser{}}, t) + checkParser(testDefinition{"2017-05-30", time.Date(2017, 5, 30, 0, 0, 0, 0, time.UTC), timeParser{}}, t) - checkParser(testDefinition{`{"X": 5}`, struct{ X int }{5}, jsonParser{}}, t) + //json + checkParser(testDefinition{`{"X": 5, "Y":"Z"}`, struct { + X int + Y string + }{5, "Z"}, jsonParser{}}, t) + //slice in query is parsed as comma delimited checkParser(testDefinition{`1,2`, []int{1, 2}, sliceParser(intParser{})}, t) + + //slice in body is parsed as json + checkParser(testDefinition{`["a","b"]`, []string{"a", "b"}, jsonParser{}}, t, MethodParam{location: body}) + + //pointers + var someInt = 1 + checkParser(testDefinition{`1`, &someInt, ptrParser(intParser{})}, t) + + var someStruct = struct{ X int }{5} + checkParser(testDefinition{`{"X": 5}`, &someStruct, jsonParser{}}, t) + } -func checkParser(def testDefinition, t *testing.T) { +func checkParser(def testDefinition, t *testing.T, methodParam ...MethodParam) { toType := reflect.TypeOf(def.expectedValue) - parser := getParser(&MethodParam{}, toType) + var mp MethodParam + if len(methodParam) == 0 { + mp = MethodParam{} + } else { + mp = methodParam[0] + } + parser := getParser(&mp, toType) if reflect.TypeOf(parser) != reflect.TypeOf(def.expectedParser) { t.Errorf("Invalid parser for value %v. Expected: %v, actual: %v", def.strValue, reflect.TypeOf(def.expectedParser).Name(), reflect.TypeOf(parser).Name()) @@ -39,7 +73,12 @@ func checkParser(def testDefinition, t *testing.T) { t.Errorf("Parsing error for value %v. Expected result: %v, error: %v", def.strValue, def.expectedValue, err) return } - if !reflect.DeepEqual(result, def.expectedValue) { + convResult, err := safeConvert(reflect.ValueOf(result), toType) + if err != nil { + t.Errorf("Convertion error for %v. from value: %v, toType: %v, error: %v", def.strValue, result, toType, err) + return + } + if !reflect.DeepEqual(convResult.Interface(), def.expectedValue) { t.Errorf("Parsing error for value %v. Expected result: %v, actual: %v", def.strValue, def.expectedValue, result) } } From 0ac2e4716248cd0ec1e77e704f394fe87442a674 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Fri, 12 May 2017 09:28:46 +0300 Subject: [PATCH 65/82] location=>paramType --- context/param/conv.go | 2 +- context/param/methodparams.go | 8 ++++---- context/param/options.go | 6 +++--- context/param/parsers.go | 2 +- context/param/parsers_test.go | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/context/param/conv.go b/context/param/conv.go index 596d2b1e..c200e008 100644 --- a/context/param/conv.go +++ b/context/param/conv.go @@ -38,7 +38,7 @@ func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Co } func getParamValue(param *MethodParam, ctx *beecontext.Context) string { - switch param.location { + switch param.in { case body: return string(ctx.Input.RequestBody) case header: diff --git a/context/param/methodparams.go b/context/param/methodparams.go index fe4ab421..cd6708a2 100644 --- a/context/param/methodparams.go +++ b/context/param/methodparams.go @@ -8,15 +8,15 @@ import ( //MethodParam keeps param information to be auto passed to controller methods type MethodParam struct { name string - location paramLocation + in paramType required bool defaultValue string } -type paramLocation byte +type paramType byte const ( - param paramLocation = iota + param paramType = iota path body header @@ -49,7 +49,7 @@ func (mp *MethodParam) String() string { if mp.required { options = append(options, "param.IsRequired") } - switch mp.location { + switch mp.in { case path: options = append(options, "param.InPath") case body: diff --git a/context/param/options.go b/context/param/options.go index 32402194..58bdc3d0 100644 --- a/context/param/options.go +++ b/context/param/options.go @@ -14,17 +14,17 @@ var IsRequired MethodParamOption = func(p *MethodParam) { // InHeader indicates that this param is passed via an http header var InHeader MethodParamOption = func(p *MethodParam) { - p.location = header + p.in = header } // InPath indicates that this param is part of the URL path var InPath MethodParamOption = func(p *MethodParam) { - p.location = path + p.in = path } // InBody indicates that this param is passed as an http request body var InBody MethodParamOption = func(p *MethodParam) { - p.location = body + p.in = body } // Default provides a default value for the http param diff --git a/context/param/parsers.go b/context/param/parsers.go index 2b48e878..421aecf0 100644 --- a/context/param/parsers.go +++ b/context/param/parsers.go @@ -21,7 +21,7 @@ func getParser(param *MethodParam, t reflect.Type) paramParser { if t.Elem().Kind() == reflect.Uint8 { //treat []byte as string return stringParser{} } - if param.location == body { + if param.in == body { return jsonParser{} } elemParser := getParser(param, t.Elem()) diff --git a/context/param/parsers_test.go b/context/param/parsers_test.go index cc97c735..b946ba08 100644 --- a/context/param/parsers_test.go +++ b/context/param/parsers_test.go @@ -43,7 +43,7 @@ func Test_Parsers(t *testing.T) { checkParser(testDefinition{`1,2`, []int{1, 2}, sliceParser(intParser{})}, t) //slice in body is parsed as json - checkParser(testDefinition{`["a","b"]`, []string{"a", "b"}, jsonParser{}}, t, MethodParam{location: body}) + checkParser(testDefinition{`["a","b"]`, []string{"a", "b"}, jsonParser{}}, t, MethodParam{in: body}) //pointers var someInt = 1 From 1004678005135f5d7a6eb940613724ec56a87741 Mon Sep 17 00:00:00 2001 From: eyalpost Date: Fri, 12 May 2017 09:57:56 +0300 Subject: [PATCH 66/82] popular status codes --- context/response/renderer.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/context/response/renderer.go b/context/response/renderer.go index 2a4d2797..38d0cdf6 100644 --- a/context/response/renderer.go +++ b/context/response/renderer.go @@ -3,9 +3,16 @@ package response import ( "strconv" + "net/http" + beecontext "github.com/astaxie/beego/context" ) +const ( + NotFound StatusCode = http.StatusNotFound + BadRequest StatusCode = http.StatusBadRequest +) + // Renderer defines an http response renderer type Renderer interface { Render(ctx *beecontext.Context) From 589f3755f07cbdddeb92f6451bbb60b343eae7c9 Mon Sep 17 00:00:00 2001 From: sunxinle Date: Fri, 12 May 2017 18:11:42 +0800 Subject: [PATCH 67/82] =?UTF-8?q?=E5=85=81=E8=AE=B8o.Raw(sql).QueryRows(&c?= =?UTF-8?q?ontainer)=20=E4=BC=A0=E5=85=A5=E7=9A=84container=E5=8C=85?= =?UTF-8?q?=E5=90=AB=E7=BB=93=E6=9E=84=E7=9A=84=E5=B5=8C=E5=A5=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- orm/orm_raw.go | 36 +++++++++++++++++++++++++----------- 1 file changed, 25 insertions(+), 11 deletions(-) diff --git a/orm/orm_raw.go b/orm/orm_raw.go index 1e86212a..c8e741ea 100644 --- a/orm/orm_raw.go +++ b/orm/orm_raw.go @@ -493,19 +493,33 @@ func (o *rawSet) QueryRows(containers ...interface{}) (int64, error) { } } } else { - for i := 0; i < ind.NumField(); i++ { - f := ind.Field(i) - fe := ind.Type().Field(i) - _, tags := parseStructTag(fe.Tag.Get(defaultStructTagName)) - var col string - if col = tags["column"]; col == "" { - col = snakeString(fe.Name) - } - if v, ok := columnsMp[col]; ok { - value := reflect.ValueOf(v).Elem().Interface() - o.setFieldValue(f, value) + // define recursive function + var recursiveSetField func(rv reflect.Value) + recursiveSetField = func(rv reflect.Value) { + for i := 0; i < rv.NumField(); i++ { + f := rv.Field(i) + fe := rv.Type().Field(i) + + // check if the field is a Struct + // recursive the Struct type + if fe.Type.Kind() == reflect.Struct { + recursiveSetField(f) + } + + _, tags := parseStructTag(fe.Tag.Get(defaultStructTagName)) + var col string + if col = tags["column"]; col == "" { + col = snakeString(fe.Name) + } + if v, ok := columnsMp[col]; ok { + value := reflect.ValueOf(v).Elem().Interface() + o.setFieldValue(f, value) + } } } + + // init call the recursive function + recursiveSetField(ind) } if eTyps[0].Kind() == reflect.Ptr { From 40bc52b844c39ce2a306e91d811f8c5c1326d998 Mon Sep 17 00:00:00 2001 From: franzwilhelm Date: Sun, 14 May 2017 00:42:09 +0200 Subject: [PATCH 68/82] fix security struct placement and formatting --- swagger/swagger.go | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/swagger/swagger.go b/swagger/swagger.go index c687fb8e..fb5da8ad 100644 --- a/swagger/swagger.go +++ b/swagger/swagger.go @@ -32,7 +32,6 @@ type Swagger struct { Paths map[string]*Item `json:"paths" yaml:"paths"` Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"` SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` - Security map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"` ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` } @@ -75,16 +74,17 @@ type Item struct { // Operation Describes a single API operation on a path. type Operation struct { - Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` - Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` - Description string `json:"description,omitempty" yaml:"description,omitempty"` - OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"` - Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` - Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` - Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` - Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` - Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` - Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` + Tags []string `json:"tags,omitempty" yaml:"tags,omitempty"` + Summary string `json:"summary,omitempty" yaml:"summary,omitempty"` + Description string `json:"description,omitempty" yaml:"description,omitempty"` + OperationID string `json:"operationId,omitempty" yaml:"operationId,omitempty"` + Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` + Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` + Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` + Parameters []Parameter `json:"parameters,omitempty" yaml:"parameters,omitempty"` + Responses map[string]Response `json:"responses,omitempty" yaml:"responses,omitempty"` + Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` + Deprecated bool `json:"deprecated,omitempty" yaml:"deprecated,omitempty"` } // Parameter Describes a single operation parameter. From 23250901018690f888de783a117c6858b9d3ca46 Mon Sep 17 00:00:00 2001 From: alexsunxl Date: Sun, 14 May 2017 12:03:34 +0800 Subject: [PATCH 69/82] add test case that used nested struct test QueryRows --- orm/orm_test.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/orm/orm_test.go b/orm/orm_test.go index c5bfa8b9..f1f2d85e 100644 --- a/orm/orm_test.go +++ b/orm/orm_test.go @@ -1661,6 +1661,13 @@ func TestRawQueryRow(t *testing.T) { throwFail(t, AssertIs(pid, nil)) } +// user_profile table +type userProfile struct { + User + Age int + Money float64 +} + func TestQueryRows(t *testing.T) { Q := dDbBaser.TableQuote() @@ -1731,6 +1738,19 @@ func TestQueryRows(t *testing.T) { throwFailNow(t, AssertIs(usernames[1], "astaxie")) throwFailNow(t, AssertIs(ids[2], 4)) throwFailNow(t, AssertIs(usernames[2], "nobody")) + + //test query rows by nested struct + var l []userProfile + query = fmt.Sprintf("SELECT * FROM %suser_profile%s LEFT JOIN %suser%s ON %suser_profile%s.%sid%s = %suser%s.%sid%s", Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q, Q) + num, err = dORM.Raw(query).QueryRows(&l) + throwFailNow(t, err) + throwFailNow(t, AssertIs(num, 2)) + throwFailNow(t, AssertIs(len(l), 2)) + throwFailNow(t, AssertIs(l[0].UserName, "slene")) + throwFailNow(t, AssertIs(l[0].Age, 28)) + throwFailNow(t, AssertIs(l[1].UserName, "astaxie")) + throwFailNow(t, AssertIs(l[1].Age, 30)) + } func TestRawValues(t *testing.T) { From c814893d65d10ae5e186d33cd19b7c2fca2ba8a2 Mon Sep 17 00:00:00 2001 From: franzwilhelm Date: Sun, 14 May 2017 12:13:35 +0200 Subject: [PATCH 70/82] add support for global security --- swagger/swagger.go | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/swagger/swagger.go b/swagger/swagger.go index fb5da8ad..035d5a49 100644 --- a/swagger/swagger.go +++ b/swagger/swagger.go @@ -22,18 +22,19 @@ package swagger // Swagger list the resource type Swagger struct { - SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"` - Infos Information `json:"info" yaml:"info"` - Host string `json:"host,omitempty" yaml:"host,omitempty"` - BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` - Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` - Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` - Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` - Paths map[string]*Item `json:"paths" yaml:"paths"` - Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"` - SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` - Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"` - ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` + SwaggerVersion string `json:"swagger,omitempty" yaml:"swagger,omitempty"` + Infos Information `json:"info" yaml:"info"` + Host string `json:"host,omitempty" yaml:"host,omitempty"` + BasePath string `json:"basePath,omitempty" yaml:"basePath,omitempty"` + Schemes []string `json:"schemes,omitempty" yaml:"schemes,omitempty"` + Consumes []string `json:"consumes,omitempty" yaml:"consumes,omitempty"` + Produces []string `json:"produces,omitempty" yaml:"produces,omitempty"` + Paths map[string]*Item `json:"paths" yaml:"paths"` + Definitions map[string]Schema `json:"definitions,omitempty" yaml:"definitions,omitempty"` + SecurityDefinitions map[string]Security `json:"securityDefinitions,omitempty" yaml:"securityDefinitions,omitempty"` + Security []map[string][]string `json:"security,omitempty" yaml:"security,omitempty"` + Tags []Tag `json:"tags,omitempty" yaml:"tags,omitempty"` + ExternalDocs *ExternalDocs `json:"externalDocs,omitempty" yaml:"externalDocs,omitempty"` } // Information Provides metadata about the API. The metadata can be used by the clients if needed. From e1c90bfc09108111a8290ecb7535c9ec60f34b59 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Tue, 16 May 2017 00:27:57 +0200 Subject: [PATCH 71/82] Table not found spelling fixes --- orm/orm.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/orm.go b/orm/orm.go index 5db79386..fcf82590 100644 --- a/orm/orm.go +++ b/orm/orm.go @@ -107,7 +107,7 @@ func (o *orm) getMiInd(md interface{}, needPtr bool) (mi *modelInfo, ind reflect if mi, ok := modelCache.getByFullName(name); ok { return mi, ind } - panic(fmt.Errorf(" table: `%s` not found, maybe not RegisterModel", name)) + panic(fmt.Errorf(" table: `%s` not found, make sure it was registered with `RegisterModel()`", name)) } // get field info from model info by given field name From b5c6eb54d28efd3a655fa676f11542305106a7c6 Mon Sep 17 00:00:00 2001 From: Robert Wikman Date: Tue, 16 May 2017 00:58:20 +0200 Subject: [PATCH 72/82] Missing PK error spelling fix --- orm/models_boot.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/orm/models_boot.go b/orm/models_boot.go index 85d0917f..5327f754 100644 --- a/orm/models_boot.go +++ b/orm/models_boot.go @@ -75,7 +75,7 @@ func registerModel(PrefixOrSuffix string, model interface{}, isPrefix bool) { } if mi.fields.pk == nil { - fmt.Printf(" `%s` need a primary key field, default use 'id' if not set\n", name) + fmt.Printf(" `%s` needs a primary key field, default is to use 'id' if not set\n", name) os.Exit(2) } From 69f0b947452dc1723e0f693d64fc5ee712b8d1d0 Mon Sep 17 00:00:00 2001 From: astaxie Date: Tue, 16 May 2017 22:21:43 +0800 Subject: [PATCH 73/82] fix gosimple --- templatefunc.go | 10 ++++----- validation/validation_test.go | 8 ++++---- validation/validators.go | 38 +++++++++++++++++------------------ 3 files changed, 28 insertions(+), 28 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index a6f9c961..2591c88e 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -53,21 +53,21 @@ func Substr(s string, start, length int) string { // HTML2str returns escaping text convert from html. func HTML2str(html string) string { - re, _ := regexp.Compile("\\<[\\S\\s]+?\\>") + re, _ := regexp.Compile(`\<[\S\s]+?\>`) html = re.ReplaceAllStringFunc(html, strings.ToLower) //remove STYLE - re, _ = regexp.Compile("\\") + re, _ = regexp.Compile(`\`) html = re.ReplaceAllString(html, "") //remove SCRIPT - re, _ = regexp.Compile("\\") + re, _ = regexp.Compile(`\`) html = re.ReplaceAllString(html, "") - re, _ = regexp.Compile("\\<[\\S\\s]+?\\>") + re, _ = regexp.Compile(`\<[\S\s]+?\>`) html = re.ReplaceAllString(html, "\n") - re, _ = regexp.Compile("\\s{2,}") + re, _ = regexp.Compile(`\s{2,}`) html = re.ReplaceAllString(html, "\n") return strings.TrimSpace(html) diff --git a/validation/validation_test.go b/validation/validation_test.go index 83e881bf..cb7a297e 100644 --- a/validation/validation_test.go +++ b/validation/validation_test.go @@ -175,10 +175,10 @@ func TestAlphaNumeric(t *testing.T) { func TestMatch(t *testing.T) { valid := Validation{} - if valid.Match("suchuangji@gmail", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok { + if valid.Match("suchuangji@gmail", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok { t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be false") } - if !valid.Match("suchuangji@gmail.com", regexp.MustCompile("^\\w+@\\w+\\.\\w+$"), "match").Ok { + if !valid.Match("suchuangji@gmail.com", regexp.MustCompile(`^\w+@\w+\.\w+$`), "match").Ok { t.Error("\"suchuangji@gmail\" match \"^\\w+@\\w+\\.\\w+$\" should be true") } } @@ -186,10 +186,10 @@ func TestMatch(t *testing.T) { func TestNoMatch(t *testing.T) { valid := Validation{} - if valid.NoMatch("123@gmail", regexp.MustCompile("[^\\w\\d]"), "nomatch").Ok { + if valid.NoMatch("123@gmail", regexp.MustCompile(`[^\w\d]`), "nomatch").Ok { t.Error("\"123@gmail\" not match \"[^\\w\\d]\" should be false") } - if !valid.NoMatch("123gmail", regexp.MustCompile("[^\\w\\d]"), "match").Ok { + if !valid.NoMatch("123gmail", regexp.MustCompile(`[^\w\d]`), "match").Ok { t.Error("\"123@gmail\" not match \"[^\\w\\d@]\" should be true") } } diff --git a/validation/validators.go b/validation/validators.go index 01aed443..2b5ae38b 100644 --- a/validation/validators.go +++ b/validation/validators.go @@ -145,7 +145,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default error message func (r Required) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Required"]) + return MessageTmpls["Required"] } // GetKey return the r.Key @@ -364,7 +364,7 @@ func (a Alpha) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Length error message func (a Alpha) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Alpha"]) + return MessageTmpls["Alpha"] } // GetKey return the m.Key @@ -397,7 +397,7 @@ func (n Numeric) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Length error message func (n Numeric) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Numeric"]) + return MessageTmpls["Numeric"] } // GetKey return the n.Key @@ -430,7 +430,7 @@ func (a AlphaNumeric) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Length error message func (a AlphaNumeric) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["AlphaNumeric"]) + return MessageTmpls["AlphaNumeric"] } // GetKey return the a.Key @@ -495,7 +495,7 @@ func (n NoMatch) GetLimitValue() interface{} { return n.Regexp.String() } -var alphaDashPattern = regexp.MustCompile("[^\\d\\w-_]") +var alphaDashPattern = regexp.MustCompile(`[^\d\w-_]`) // AlphaDash check not Alpha type AlphaDash struct { @@ -505,7 +505,7 @@ type AlphaDash struct { // DefaultMessage return the default AlphaDash error message func (a AlphaDash) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["AlphaDash"]) + return MessageTmpls["AlphaDash"] } // GetKey return the n.Key @@ -518,7 +518,7 @@ func (a AlphaDash) GetLimitValue() interface{} { return nil } -var emailPattern = regexp.MustCompile("^[\\w!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\w!#$%&'*+/=?^_`{|}~-]+)*@(?:[\\w](?:[\\w-]*[\\w])?\\.)+[a-zA-Z0-9](?:[\\w-]*[\\w])?$") +var emailPattern = regexp.MustCompile(`^[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+(?:\.[\w!#$%&'*+/=?^_` + "`" + `{|}~-]+)*@(?:[\w](?:[\w-]*[\w])?\.)+[a-zA-Z0-9](?:[\w-]*[\w])?$`) // Email check struct type Email struct { @@ -528,7 +528,7 @@ type Email struct { // DefaultMessage return the default Email error message func (e Email) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Email"]) + return MessageTmpls["Email"] } // GetKey return the n.Key @@ -541,7 +541,7 @@ func (e Email) GetLimitValue() interface{} { return nil } -var ipPattern = regexp.MustCompile("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$") +var ipPattern = regexp.MustCompile(`^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$`) // IP check struct type IP struct { @@ -551,7 +551,7 @@ type IP struct { // DefaultMessage return the default IP error message func (i IP) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["IP"]) + return MessageTmpls["IP"] } // GetKey return the i.Key @@ -564,7 +564,7 @@ func (i IP) GetLimitValue() interface{} { return nil } -var base64Pattern = regexp.MustCompile("^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$") +var base64Pattern = regexp.MustCompile(`^(?:[A-Za-z0-99+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$`) // Base64 check struct type Base64 struct { @@ -574,7 +574,7 @@ type Base64 struct { // DefaultMessage return the default Base64 error message func (b Base64) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Base64"]) + return MessageTmpls["Base64"] } // GetKey return the b.Key @@ -588,7 +588,7 @@ func (b Base64) GetLimitValue() interface{} { } // just for chinese mobile phone number -var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\\d{8}$") +var mobilePattern = regexp.MustCompile(`^((\+86)|(86))?(1(([35][0-9])|[8][0-9]|[7][06789]|[4][579]))\d{8}$`) // Mobile check struct type Mobile struct { @@ -598,7 +598,7 @@ type Mobile struct { // DefaultMessage return the default Mobile error message func (m Mobile) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Mobile"]) + return MessageTmpls["Mobile"] } // GetKey return the m.Key @@ -612,7 +612,7 @@ func (m Mobile) GetLimitValue() interface{} { } // just for chinese telephone number -var telPattern = regexp.MustCompile("^(0\\d{2,3}(\\-)?)?\\d{7,8}$") +var telPattern = regexp.MustCompile(`^(0\d{2,3}(\-)?)?\d{7,8}$`) // Tel check telephone struct type Tel struct { @@ -622,7 +622,7 @@ type Tel struct { // DefaultMessage return the default Tel error message func (t Tel) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Tel"]) + return MessageTmpls["Tel"] } // GetKey return the t.Key @@ -649,7 +649,7 @@ func (p Phone) IsSatisfied(obj interface{}) bool { // DefaultMessage return the default Phone error message func (p Phone) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["Phone"]) + return MessageTmpls["Phone"] } // GetKey return the p.Key @@ -663,7 +663,7 @@ func (p Phone) GetLimitValue() interface{} { } // just for chinese zipcode -var zipCodePattern = regexp.MustCompile("^[1-9]\\d{5}$") +var zipCodePattern = regexp.MustCompile(`^[1-9]\d{5}$`) // ZipCode check the zip struct type ZipCode struct { @@ -673,7 +673,7 @@ type ZipCode struct { // DefaultMessage return the default Zip error message func (z ZipCode) DefaultMessage() string { - return fmt.Sprint(MessageTmpls["ZipCode"]) + return MessageTmpls["ZipCode"] } // GetKey return the z.Key From 828cbbdf5d265d521bcc12300d9c750e7df505cc Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Wed, 17 May 2017 20:38:59 +0300 Subject: [PATCH 74/82] Refactor a bit to consolidate packages --- context/context.go | 16 +++++++++++ context/output.go | 13 +++++++++ context/renderer.go | 12 ++++++++ context/response/renderer.go | 46 ------------------------------ context/response/responses.go | 53 ----------------------------------- httpResponse/response.go | 52 ++++++++++++++++++++++++++++++++++ router.go | 3 +- 7 files changed, 94 insertions(+), 101 deletions(-) create mode 100644 context/renderer.go delete mode 100644 context/response/renderer.go delete mode 100644 context/response/responses.go create mode 100644 httpResponse/response.go diff --git a/context/context.go b/context/context.go index 03286097..8b32062c 100644 --- a/context/context.go +++ b/context/context.go @@ -171,6 +171,22 @@ func (ctx *Context) CheckXSRFCookie() bool { return true } +// RenderMethodResult renders the return value of a controller method to the output +func (ctx *Context) RenderMethodResult(result interface{}) { + if result != nil { + renderer, ok := result.(Renderer) + if !ok { + err, ok := result.(error) + if ok { + renderer = errorRenderer(err) + } else { + renderer = jsonRenderer(result) + } + } + renderer.Render(ctx) + } +} + //Response is a wrapper for the http.ResponseWriter //started set to true if response was written to then don't execute other handler type Response struct { diff --git a/context/output.go b/context/output.go index 564ef96d..835552b0 100644 --- a/context/output.go +++ b/context/output.go @@ -168,6 +168,19 @@ func sanitizeValue(v string) string { return cookieValueSanitizer.Replace(v) } +func jsonRenderer(value interface{}) Renderer { + return rendererFunc(func(ctx *Context) { + ctx.Output.JSON(value, false, false) + }) +} + +func errorRenderer(err error) Renderer { + return rendererFunc(func(ctx *Context) { + ctx.Output.SetStatus(500) + ctx.WriteString(err.Error()) + }) +} + // JSON writes json to response body. // if coding is true, it converts utf-8 to \u0000 type. func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) error { diff --git a/context/renderer.go b/context/renderer.go new file mode 100644 index 00000000..36a7cb53 --- /dev/null +++ b/context/renderer.go @@ -0,0 +1,12 @@ +package context + +// Renderer defines an http response renderer +type Renderer interface { + Render(ctx *Context) +} + +type rendererFunc func(ctx *Context) + +func (f rendererFunc) Render(ctx *Context) { + f(ctx) +} diff --git a/context/response/renderer.go b/context/response/renderer.go deleted file mode 100644 index 38d0cdf6..00000000 --- a/context/response/renderer.go +++ /dev/null @@ -1,46 +0,0 @@ -package response - -import ( - "strconv" - - "net/http" - - beecontext "github.com/astaxie/beego/context" -) - -const ( - NotFound StatusCode = http.StatusNotFound - BadRequest StatusCode = http.StatusBadRequest -) - -// Renderer defines an http response renderer -type Renderer interface { - Render(ctx *beecontext.Context) -} - -type rendererFunc func(ctx *beecontext.Context) - -func (f rendererFunc) Render(ctx *beecontext.Context) { - f(ctx) -} - -// StatusCode sets the http response status code -type StatusCode int - -func (s StatusCode) Error() string { - return strconv.Itoa(int(s)) -} - -// Render sets the http status code -func (s StatusCode) Render(ctx *beecontext.Context) { - ctx.Output.SetStatus(int(s)) -} - -type statusCodeWithRender struct { - statusCode int - rendererFunc -} - -func (s statusCodeWithRender) Error() string { - return strconv.Itoa(s.statusCode) -} diff --git a/context/response/responses.go b/context/response/responses.go deleted file mode 100644 index 10d1ed3f..00000000 --- a/context/response/responses.go +++ /dev/null @@ -1,53 +0,0 @@ -package response - -import ( - beecontext "github.com/astaxie/beego/context" -) - -// JSON renders value to the response as JSON -func JSON(value interface{}, encoding ...bool) Renderer { - return rendererFunc(func(ctx *beecontext.Context) { - var ( - hasIndent = true - hasEncoding = false - ) - //TODO: need access to BConfig :( - // if BConfig.RunMode == PROD { - // hasIndent = false - // } - if len(encoding) > 0 && encoding[0] { - hasEncoding = true - } - ctx.Output.JSON(value, hasIndent, hasEncoding) - }) -} - -func errorRenderer(err error) Renderer { - return rendererFunc(func(ctx *beecontext.Context) { - ctx.Output.SetStatus(500) - ctx.WriteString(err.Error()) - }) -} - -// Redirect renders http 302 with a URL -func Redirect(localurl string) error { - return statusCodeWithRender{302, func(ctx *beecontext.Context) { - ctx.Redirect(302, localurl) - }} -} - -// RenderMethodResult renders the return value of a controller method to the output -func RenderMethodResult(result interface{}, ctx *beecontext.Context) { - if result != nil { - renderer, ok := result.(Renderer) - if !ok { - err, ok := result.(error) - if ok { - renderer = errorRenderer(err) - } else { - renderer = JSON(result) - } - } - renderer.Render(ctx) - } -} diff --git a/httpResponse/response.go b/httpResponse/response.go new file mode 100644 index 00000000..ca74b85c --- /dev/null +++ b/httpResponse/response.go @@ -0,0 +1,52 @@ +package httpResponse + +import ( + "strconv" + + "net/http" + + beecontext "github.com/astaxie/beego/context" +) + +const ( + //BadRequest indicates http error 400 + BadRequest StatusCode = http.StatusBadRequest + + //NotFound indicates http error 404 + NotFound StatusCode = http.StatusNotFound +) + +// Redirect renders http 302 with a URL +func Redirect(localurl string) error { + return statusCodeWithRender{302, func(ctx *beecontext.Context) { + ctx.Redirect(302, localurl) + }} +} + +// StatusCode sets the http response status code +type StatusCode int + +func (s StatusCode) Error() string { + return strconv.Itoa(int(s)) +} + +// Render sets the http status code +func (s StatusCode) Render(ctx *beecontext.Context) { + ctx.Output.SetStatus(int(s)) +} + +type statusCodeWithRender struct { + statusCode int + f func(ctx *beecontext.Context) +} + +//assert that statusCodeWithRender implements Renderer interface +var _r beecontext.Renderer = (*statusCodeWithRender)(nil) + +func (s statusCodeWithRender) Error() string { + return strconv.Itoa(s.statusCode) +} + +func (s statusCodeWithRender) Render(ctx *beecontext.Context) { + s.f(ctx) +} diff --git a/router.go b/router.go index 33096039..72476ae8 100644 --- a/router.go +++ b/router.go @@ -28,7 +28,6 @@ import ( beecontext "github.com/astaxie/beego/context" "github.com/astaxie/beego/context/param" - "github.com/astaxie/beego/context/response" "github.com/astaxie/beego/logs" "github.com/astaxie/beego/toolbox" "github.com/astaxie/beego/utils" @@ -905,7 +904,7 @@ func (p *ControllerRegister) handleParamResponse(context *beecontext.Context, ex result := results[i] if result.Kind() != reflect.Interface || !result.IsNil() { resultValue := result.Interface() - response.RenderMethodResult(resultValue, context) + context.RenderMethodResult(resultValue) } } if !context.ResponseWriter.Started && context.Output.Status == 0 { From ee1d8bc30ea2d89ecdb70402c7b1213ac8a4e5f1 Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Wed, 17 May 2017 20:50:41 +0300 Subject: [PATCH 75/82] fix gosimple --- parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parser.go b/parser.go index 037d5376..a9cfd894 100644 --- a/parser.go +++ b/parser.go @@ -235,7 +235,7 @@ func getparams(str string) []string { var start bool var r []string var quoted int8 - for _, c := range []rune(str) { + for _, c := range str { if unicode.IsSpace(c) && quoted == 0 { if !start { continue From e32a18203b95391f627539c440834d65f704492a Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Wed, 17 May 2017 21:27:32 +0300 Subject: [PATCH 76/82] fix gosimple --- context/output.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/context/output.go b/context/output.go index 835552b0..cf9e7a7e 100644 --- a/context/output.go +++ b/context/output.go @@ -343,9 +343,8 @@ func (output *BeegoOutput) IsServerError() bool { } func stringsToJSON(str string) string { - rs := []rune(str) var jsons bytes.Buffer - for _, r := range rs { + for _, r := range str { rint := int(r) if rint < 128 { jsons.WriteRune(r) From 3e51823c0faba9dcf541ec72c90664a30fedceb6 Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Thu, 18 May 2017 09:05:49 +0300 Subject: [PATCH 77/82] move response --- {httpResponse => context/httpResponse}/response.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename {httpResponse => context/httpResponse}/response.go (100%) diff --git a/httpResponse/response.go b/context/httpResponse/response.go similarity index 100% rename from httpResponse/response.go rename to context/httpResponse/response.go From 2513bcf584f655379bd5195dcaba83649aab9e8f Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Thu, 18 May 2017 10:32:51 +0300 Subject: [PATCH 78/82] remove Redirect to avoid confusion --- context/httpResponse/response.go | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/context/httpResponse/response.go b/context/httpResponse/response.go index ca74b85c..0b013719 100644 --- a/context/httpResponse/response.go +++ b/context/httpResponse/response.go @@ -16,13 +16,6 @@ const ( NotFound StatusCode = http.StatusNotFound ) -// Redirect renders http 302 with a URL -func Redirect(localurl string) error { - return statusCodeWithRender{302, func(ctx *beecontext.Context) { - ctx.Redirect(302, localurl) - }} -} - // StatusCode sets the http response status code type StatusCode int @@ -34,19 +27,3 @@ func (s StatusCode) Error() string { func (s StatusCode) Render(ctx *beecontext.Context) { ctx.Output.SetStatus(int(s)) } - -type statusCodeWithRender struct { - statusCode int - f func(ctx *beecontext.Context) -} - -//assert that statusCodeWithRender implements Renderer interface -var _r beecontext.Renderer = (*statusCodeWithRender)(nil) - -func (s statusCodeWithRender) Error() string { - return strconv.Itoa(s.statusCode) -} - -func (s statusCodeWithRender) Render(ctx *beecontext.Context) { - s.f(ctx) -} From 11b4bf8aaa7ba08f7ca0aba61ebf1cee0c7d83a6 Mon Sep 17 00:00:00 2001 From: Eyal Post Date: Thu, 18 May 2017 10:38:12 +0300 Subject: [PATCH 79/82] move to context --- context/{httpResponse => }/response.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) rename context/{httpResponse => }/response.go (77%) diff --git a/context/httpResponse/response.go b/context/response.go similarity index 77% rename from context/httpResponse/response.go rename to context/response.go index 0b013719..9c3c715a 100644 --- a/context/httpResponse/response.go +++ b/context/response.go @@ -1,11 +1,9 @@ -package httpResponse +package context import ( "strconv" "net/http" - - beecontext "github.com/astaxie/beego/context" ) const ( @@ -24,6 +22,6 @@ func (s StatusCode) Error() string { } // Render sets the http status code -func (s StatusCode) Render(ctx *beecontext.Context) { +func (s StatusCode) Render(ctx *Context) { ctx.Output.SetStatus(int(s)) } From 248beab557b9090d28dc5dfd0806ee3a8113843d Mon Sep 17 00:00:00 2001 From: astaxie Date: Thu, 18 May 2017 22:55:10 +0800 Subject: [PATCH 80/82] v1.8.3 --- beego.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/beego.go b/beego.go index 7a8db390..22079a20 100644 --- a/beego.go +++ b/beego.go @@ -23,7 +23,7 @@ import ( const ( // VERSION represent beego web framework version. - VERSION = "1.8.2" + VERSION = "1.8.3" // DEV is for develop DEV = "dev" From 47e351e11db86d120ccb3976d3c4388d07954139 Mon Sep 17 00:00:00 2001 From: Guohua Ouyang Date: Fri, 19 May 2017 09:22:27 +0800 Subject: [PATCH 81/82] Support timeformat "2006-01-02T15:04:05" Fixes #2649 Signed-off-by: Guohua Ouyang --- templatefunc.go | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/templatefunc.go b/templatefunc.go index 2591c88e..a104fd24 100644 --- a/templatefunc.go +++ b/templatefunc.go @@ -27,9 +27,10 @@ import ( ) const ( - formatTime = "15:04:05" - formatDate = "2006-01-02" - formatDateTime = "2006-01-02 15:04:05" + formatTime = "15:04:05" + formatDate = "2006-01-02" + formatDateTime = "2006-01-02 15:04:05" + formatDateTimeT = "2006-01-02T15:04:05" ) // Substr returns the substr from start to length. @@ -360,8 +361,13 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e value = value[:25] t, err = time.ParseInLocation(time.RFC3339, value, time.Local) } else if len(value) >= 19 { - value = value[:19] - t, err = time.ParseInLocation(formatDateTime, value, time.Local) + if strings.Contains(value, "T") { + value = value[:19] + t, err = time.ParseInLocation(formatDateTimeT, value, time.Local) + } else { + value = value[:19] + t, err = time.ParseInLocation(formatDateTime, value, time.Local) + } } else if len(value) >= 10 { if len(value) > 10 { value = value[:10] @@ -373,7 +379,6 @@ func parseFormToStruct(form url.Values, objT reflect.Type, objV reflect.Value) e } t, err = time.ParseInLocation(formatTime, value, time.Local) } - if err != nil { return err } From ce677202e557b330e2c06fde64922c609d66e822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E0=AE=AA=E0=AE=BE=E0=AE=B2=E0=AE=BE=E0=AE=9C=E0=AE=BF?= Date: Tue, 6 Dec 2016 19:25:31 +0530 Subject: [PATCH 82/82] issue no:#2261 fix for xsrf panic error --- error.go | 24 ++++++++++++++++++++++++ hooks.go | 2 ++ 2 files changed, 26 insertions(+) diff --git a/error.go b/error.go index ab626247..b913db39 100644 --- a/error.go +++ b/error.go @@ -252,6 +252,30 @@ func forbidden(rw http.ResponseWriter, r *http.Request) { ) } +// show 422 missing xsrf token +func missingxsrf(rw http.ResponseWriter, r *http.Request) { + responseError(rw, r, + 422, + "
The page you have requested is forbidden."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    '_xsrf' argument missing from POST"+ + "
", + ) +} + +// show 417 invalid xsrf token +func invalidxsrf(rw http.ResponseWriter, r *http.Request) { + responseError(rw, r, + 417, + "
The page you have requested is forbidden."+ + "
Perhaps you are here because:"+ + "

    "+ + "
    expected XSRF not found"+ + "
", + ) +} + // show 404 not found error. func notFound(rw http.ResponseWriter, r *http.Request) { responseError(rw, r, diff --git a/hooks.go b/hooks.go index b5a5e6c5..edf1485a 100644 --- a/hooks.go +++ b/hooks.go @@ -32,6 +32,8 @@ func registerDefaultErrorHandler() error { "502": badGateway, "503": serviceUnavailable, "504": gatewayTimeout, + "417": invalidxsrf, + "422": missingxsrf, } for e, h := range m { if _, ok := ErrorMaps[e]; !ok {