From 8e61a6a6de6a53e2854af88c6f768c9a500abf07 Mon Sep 17 00:00:00 2001 From: Waleed Gadelkareem Date: Sat, 28 Apr 2018 17:15:19 +0200 Subject: [PATCH 01/12] Allow access log regardless of the log level --- logs/accesslog.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/logs/accesslog.go b/logs/accesslog.go index cf799dc1..3f37879a 100644 --- a/logs/accesslog.go +++ b/logs/accesslog.go @@ -16,9 +16,10 @@ package logs import ( "bytes" + "strings" "encoding/json" - "time" "fmt" + "time" ) const ( @@ -53,10 +54,9 @@ func (r *AccessLogRecord) json() ([]byte, error) { } func disableEscapeHTML(i interface{}) { - e, ok := i.(interface { + if e, ok := i.(interface { SetEscapeHTML(bool) - }); - if ok { + }); ok { e.SetEscapeHTML(false) } } @@ -81,6 +81,5 @@ func AccessLog(r *AccessLogRecord, format string) { msg = string(jsonData) } } - - beeLogger.Debug(msg) + beeLogger.writeMsg(levelLoggerImpl, strings.TrimSpace(msg)) } From d5c1c0e9a4a819dd7d3a2969f3261b7f90ddb2fb Mon Sep 17 00:00:00 2001 From: Waleed Gadelkareem Date: Sat, 28 Apr 2018 20:03:39 +0200 Subject: [PATCH 02/12] log errors in access log and make static request logging optional --- admin_test.go | 1 + config.go | 2 ++ error.go | 5 ++- router.go | 92 ++++++++++++++++++++++++++++++--------------------- 4 files changed, 62 insertions(+), 38 deletions(-) diff --git a/admin_test.go b/admin_test.go index a99da6fc..03a3c044 100644 --- a/admin_test.go +++ b/admin_test.go @@ -67,6 +67,7 @@ func oldMap() map[string]interface{} { m["BConfig.WebConfig.Session.SessionDomain"] = BConfig.WebConfig.Session.SessionDomain m["BConfig.WebConfig.Session.SessionDisableHTTPOnly"] = BConfig.WebConfig.Session.SessionDisableHTTPOnly m["BConfig.Log.AccessLogs"] = BConfig.Log.AccessLogs + m["BConfig.Log.EnableStaticLogs"] = BConfig.Log.EnableStaticLogs m["BConfig.Log.AccessLogsFormat"] = BConfig.Log.AccessLogsFormat m["BConfig.Log.FileLineNum"] = BConfig.Log.FileLineNum m["BConfig.Log.Outputs"] = BConfig.Log.Outputs diff --git a/config.go b/config.go index eeeac8ee..0dc1bfbf 100644 --- a/config.go +++ b/config.go @@ -106,6 +106,7 @@ type SessionConfig struct { // LogConfig holds Log related config type LogConfig struct { AccessLogs bool + EnableStaticLogs bool //log static files requests default: false AccessLogsFormat string //access log format: JSON_FORMAT, APACHE_FORMAT or empty string FileLineNum bool Outputs map[string]string // Store Adaptor : config @@ -247,6 +248,7 @@ func newBConfig() *Config { }, Log: LogConfig{ AccessLogs: false, + EnableStaticLogs: false, AccessLogsFormat: "APACHE_FORMAT", FileLineNum: true, Outputs: map[string]string{"console": ""}, diff --git a/error.go b/error.go index b913db39..7958e367 100644 --- a/error.go +++ b/error.go @@ -28,7 +28,7 @@ import ( ) const ( - errorTypeHandler = iota + errorTypeHandler = iota errorTypeController ) @@ -439,6 +439,9 @@ func exception(errCode string, ctx *context.Context) { } func executeError(err *errorInfo, ctx *context.Context, code int) { + //make sure to log the error in the access log + logAccess(ctx, nil, code) + if err.errorType == errorTypeHandler { ctx.ResponseWriter.WriteHeader(code) err.handler(ctx.ResponseWriter, ctx.Request) diff --git a/router.go b/router.go index 11cb4aa8..fa15c35f 100644 --- a/router.go +++ b/router.go @@ -43,7 +43,7 @@ const ( ) const ( - routerTypeBeego = iota + routerTypeBeego = iota routerTypeRESTFul routerTypeHandler ) @@ -877,13 +877,15 @@ func (p *ControllerRegister) ServeHTTP(rw http.ResponseWriter, r *http.Request) } Admin: - //admin module record QPS +//admin module record QPS statusCode := context.ResponseWriter.Status if statusCode == 0 { statusCode = 200 } + logAccess(context, &startTime, statusCode) + if BConfig.Listen.EnableAdmin { timeDur := time.Since(startTime) pattern := "" @@ -900,49 +902,30 @@ Admin: } } - if BConfig.RunMode == DEV || BConfig.Log.AccessLogs { - timeDur := time.Since(startTime) + if BConfig.RunMode == DEV && !BConfig.Log.AccessLogs { var devInfo string - + timeDur := time.Since(startTime) iswin := (runtime.GOOS == "windows") statusColor := logs.ColorByStatus(iswin, statusCode) methodColor := logs.ColorByMethod(iswin, r.Method) resetColor := logs.ColorByMethod(iswin, "") - if BConfig.Log.AccessLogsFormat != "" { - record := &logs.AccessLogRecord{ - RemoteAddr: context.Input.IP(), - RequestTime: startTime, - RequestMethod: r.Method, - Request: fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto), - ServerProtocol: r.Proto, - Host: r.Host, - Status: statusCode, - ElapsedTime: timeDur, - HTTPReferrer: r.Header.Get("Referer"), - HTTPUserAgent: r.Header.Get("User-Agent"), - RemoteUser: r.Header.Get("Remote-User"), - BodyBytesSent: 0, //@todo this one is missing! - } - logs.AccessLog(record, BConfig.Log.AccessLogsFormat) - } else { - if findRouter { - if routerInfo != nil { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s r:%s", context.Input.IP(), statusColor, statusCode, - resetColor, timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path, - routerInfo.pattern) - } else { - devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, - timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path) - } + if findRouter { + if routerInfo != nil { + devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s r:%s", context.Input.IP(), statusColor, statusCode, + resetColor, timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path, + routerInfo.pattern) } else { devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, - timeDur.String(), "nomatch", methodColor, r.Method, resetColor, r.URL.Path) - } - if iswin { - logs.W32Debug(devInfo) - } else { - logs.Debug(devInfo) + timeDur.String(), "match", methodColor, r.Method, resetColor, r.URL.Path) } + } else { + devInfo = fmt.Sprintf("|%15s|%s %3d %s|%13s|%8s|%s %-7s %s %-3s", context.Input.IP(), statusColor, statusCode, resetColor, + timeDur.String(), "nomatch", methodColor, r.Method, resetColor, r.URL.Path) + } + if iswin { + logs.W32Debug(devInfo) + } else { + logs.Debug(devInfo) } } // Call WriteHeader if status code has been set changed @@ -991,3 +974,38 @@ func toURL(params map[string]string) string { } return strings.TrimRight(u, "&") } + +func logAccess(ctx *beecontext.Context, startTime *time.Time, statusCode int) { + //Skip logging if AccessLogs config is false + if !BConfig.Log.AccessLogs { + return + } + //Skip logging static requests unless EnableStaticLogs config is true + if !BConfig.Log.EnableStaticLogs && DefaultAccessLogFilter.Filter(ctx) { + return + } + var ( + requestTime time.Time + elapsedTime time.Duration + r = ctx.Request + ) + if startTime != nil { + requestTime = *startTime + elapsedTime = time.Since(*startTime) + } + record := &logs.AccessLogRecord{ + RemoteAddr: ctx.Input.IP(), + RequestTime: requestTime, + RequestMethod: r.Method, + Request: fmt.Sprintf("%s %s %s", r.Method, r.RequestURI, r.Proto), + ServerProtocol: r.Proto, + Host: r.Host, + Status: statusCode, + ElapsedTime: elapsedTime, + HTTPReferrer: r.Header.Get("Referer"), + HTTPUserAgent: r.Header.Get("User-Agent"), + RemoteUser: r.Header.Get("Remote-User"), + BodyBytesSent: 0, //@todo this one is missing! + } + logs.AccessLog(record, BConfig.Log.AccessLogsFormat) +} From 6df42d63e2d9c44845379d838ca00ad39c15fdae Mon Sep 17 00:00:00 2001 From: Amit Ashkenazi Date: Sun, 29 Apr 2018 15:12:32 +0300 Subject: [PATCH 03/12] Fix response http code --- config.go | 5 +++++ error.go | 5 ----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/config.go b/config.go index eeeac8ee..0725445b 100644 --- a/config.go +++ b/config.go @@ -182,6 +182,11 @@ func recoverPanic(ctx *context.Context) { if BConfig.RunMode == DEV && BConfig.EnableErrorsRender { showErr(err, ctx, stack) } + if ctx.Output.Status != 0 { + ctx.ResponseWriter.WriteHeader(ctx.Output.Status) + } else { + ctx.ResponseWriter.WriteHeader(500) + } } } diff --git a/error.go b/error.go index b913db39..77ddec26 100644 --- a/error.go +++ b/error.go @@ -93,11 +93,6 @@ func showErr(err interface{}, ctx *context.Context, stack string) { "BeegoVersion": VERSION, "GoVersion": runtime.Version(), } - if ctx.Output.Status != 0 { - ctx.ResponseWriter.WriteHeader(ctx.Output.Status) - } else { - ctx.ResponseWriter.WriteHeader(500) - } t.Execute(ctx.ResponseWriter, data) } From 896c258e449aedf77a4c342d136847dfbee4b957 Mon Sep 17 00:00:00 2001 From: Waleed Gadelkareem Date: Mon, 30 Apr 2018 17:48:01 +0200 Subject: [PATCH 04/12] Log redirects and abort after redirect --- controller.go | 2 ++ logs/accesslog.go | 2 -- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/controller.go b/controller.go index c104eb2a..c66c7d88 100644 --- a/controller.go +++ b/controller.go @@ -272,7 +272,9 @@ func (c *Controller) viewPath() string { // Redirect sends the redirection response to url with status code. func (c *Controller) Redirect(url string, code int) { + logAccess(c.Ctx, nil, code) c.Ctx.Redirect(code, url) + panic(ErrAbort) } // Abort stops controller handler and show the error data if code is defined in ErrorMap or code string. diff --git a/logs/accesslog.go b/logs/accesslog.go index 3f37879a..5790f97e 100644 --- a/logs/accesslog.go +++ b/logs/accesslog.go @@ -64,9 +64,7 @@ func disableEscapeHTML(i interface{}) { // AccessLog - Format and print access log. func AccessLog(r *AccessLogRecord, format string) { var msg string - switch format { - case apacheFormat: timeFormatted := r.RequestTime.Format("02/Jan/2006 03:04:05") msg = fmt.Sprintf(apacheFormatPattern, r.RemoteAddr, timeFormatted, r.Request, r.Status, r.BodyBytesSent, From 0f730505674bd4569efbefef4189d010d74cdcc9 Mon Sep 17 00:00:00 2001 From: Wang-Kai Date: Thu, 3 May 2018 12:05:59 +0800 Subject: [PATCH 05/12] add code style for logs README --- logs/README.md | 57 +++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/logs/README.md b/logs/README.md index 57d7abc3..d326cfa1 100644 --- a/logs/README.md +++ b/logs/README.md @@ -16,48 +16,57 @@ As of now this logs support console, file,smtp and conn. First you must import it - import ( - "github.com/astaxie/beego/logs" - ) +```golang +import ( + "github.com/astaxie/beego/logs" +) +``` Then init a Log (example with console adapter) - log := NewLogger(10000) - log.SetLogger("console", "") +```golang +log := NewLogger(10000) +log.SetLogger("console", "") +``` > the first params stand for how many channel -Use it like this: +Use it like this: - log.Trace("trace") - log.Info("info") - log.Warn("warning") - log.Debug("debug") - log.Critical("critical") - +```golang +log.Trace("trace") +log.Info("info") +log.Warn("warning") +log.Debug("debug") +log.Critical("critical") +``` ## File adapter Configure file adapter like this: - - log := NewLogger(10000) - log.SetLogger("file", `{"filename":"test.log"}`) - + +```golang +log := NewLogger(10000) +log.SetLogger("file", `{"filename":"test.log"}`) +``` ## Conn adapter Configure like this: - log := NewLogger(1000) - log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`) - log.Info("info") - +```golang +log := NewLogger(1000) +log.SetLogger("conn", `{"net":"tcp","addr":":7020"}`) +log.Info("info") +``` ## Smtp adapter Configure like this: - log := NewLogger(10000) - log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`) - log.Critical("sendmail critical") - time.Sleep(time.Second * 30) +```golang +log := NewLogger(10000) +log.SetLogger("smtp", `{"username":"beegotest@gmail.com","password":"xxxxxxxx","host":"smtp.gmail.com:587","sendTos":["xiemengjun@gmail.com"]}`) +log.Critical("sendmail critical") +time.Sleep(time.Second * 30) +``` From 1fd7fa5df7be08e15ee989a5951148f278a3476e Mon Sep 17 00:00:00 2001 From: Wang-Kai Date: Thu, 3 May 2018 22:04:49 +0800 Subject: [PATCH 06/12] make example runable --- logs/README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/logs/README.md b/logs/README.md index d326cfa1..c05bcc04 100644 --- a/logs/README.md +++ b/logs/README.md @@ -25,15 +25,15 @@ import ( Then init a Log (example with console adapter) ```golang -log := NewLogger(10000) -log.SetLogger("console", "") +log := logs.NewLogger(10000) +log.SetLogger("console", "") ``` > the first params stand for how many channel Use it like this: - -```golang + +```golang log.Trace("trace") log.Info("info") log.Warn("warning") @@ -44,8 +44,8 @@ log.Critical("critical") ## File adapter Configure file adapter like this: - -```golang + +```golang log := NewLogger(10000) log.SetLogger("file", `{"filename":"test.log"}`) ``` From 98a3cda2602b57dffb8b8c9aebfb4817cdad5b4a Mon Sep 17 00:00:00 2001 From: Amit Yadav <154998+ayadav@users.noreply.github.com> Date: Mon, 7 May 2018 12:57:13 +0530 Subject: [PATCH 07/12] Fix Unexpected EOF bug in staticfile --- staticfile.go | 24 +++++++++++++++--------- staticfile_test.go | 8 ++++---- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/staticfile.go b/staticfile.go index bbb2a1fb..30ee3dfb 100644 --- a/staticfile.go +++ b/staticfile.go @@ -74,7 +74,7 @@ func serverStaticRouter(ctx *context.Context) { if enableCompress { acceptEncoding = context.ParseEncoding(ctx.Request) } - b, n, sch, err := openFile(filePath, fileInfo, acceptEncoding) + b, n, sch, reader, err := openFile(filePath, fileInfo, acceptEncoding) if err != nil { if BConfig.RunMode == DEV { logs.Warn("Can't compress the file:", filePath, err) @@ -89,47 +89,53 @@ func serverStaticRouter(ctx *context.Context) { ctx.Output.Header("Content-Length", strconv.FormatInt(sch.size, 10)) } - http.ServeContent(ctx.ResponseWriter, ctx.Request, filePath, sch.modTime, sch) + http.ServeContent(ctx.ResponseWriter, ctx.Request, filePath, sch.modTime, reader) } type serveContentHolder struct { - *bytes.Reader + data []byte modTime time.Time size int64 encoding string } +type serveContentReader struct { + *bytes.Reader +} + var ( staticFileMap = make(map[string]*serveContentHolder) mapLock sync.RWMutex ) -func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, error) { +func openFile(filePath string, fi os.FileInfo, acceptEncoding string) (bool, string, *serveContentHolder, *serveContentReader, error) { mapKey := acceptEncoding + ":" + filePath mapLock.RLock() mapFile := staticFileMap[mapKey] mapLock.RUnlock() if isOk(mapFile, fi) { - return mapFile.encoding != "", mapFile.encoding, mapFile, nil + reader := &serveContentReader{Reader: bytes.NewReader(mapFile.data)} + return mapFile.encoding != "", mapFile.encoding, mapFile, reader, nil } mapLock.Lock() defer mapLock.Unlock() if mapFile = staticFileMap[mapKey]; !isOk(mapFile, fi) { file, err := os.Open(filePath) if err != nil { - return false, "", nil, err + return false, "", nil, nil, err } defer file.Close() var bufferWriter bytes.Buffer _, n, err := context.WriteFile(acceptEncoding, &bufferWriter, file) if err != nil { - return false, "", nil, err + return false, "", nil, nil, err } - mapFile = &serveContentHolder{Reader: bytes.NewReader(bufferWriter.Bytes()), modTime: fi.ModTime(), size: int64(bufferWriter.Len()), encoding: n} + mapFile = &serveContentHolder{data: bufferWriter.Bytes(), modTime: fi.ModTime(), size: int64(bufferWriter.Len()), encoding: n} staticFileMap[mapKey] = mapFile } - return mapFile.encoding != "", mapFile.encoding, mapFile, nil + reader := &serveContentReader{Reader: bytes.NewReader(mapFile.data)} + return mapFile.encoding != "", mapFile.encoding, mapFile, reader, nil } func isOk(s *serveContentHolder, fi os.FileInfo) bool { diff --git a/staticfile_test.go b/staticfile_test.go index a043b4fd..69667bf8 100644 --- a/staticfile_test.go +++ b/staticfile_test.go @@ -16,7 +16,7 @@ var licenseFile = filepath.Join(currentWorkDir, "LICENSE") func testOpenFile(encoding string, content []byte, t *testing.T) { fi, _ := os.Stat(licenseFile) - b, n, sch, err := openFile(licenseFile, fi, encoding) + b, n, sch, reader, err := openFile(licenseFile, fi, encoding) if err != nil { t.Log(err) t.Fail() @@ -24,7 +24,7 @@ func testOpenFile(encoding string, content []byte, t *testing.T) { t.Log("open static file encoding "+n, b) - assetOpenFileAndContent(sch, content, t) + assetOpenFileAndContent(sch, reader, content, t) } func TestOpenStaticFile_1(t *testing.T) { file, _ := os.Open(licenseFile) @@ -53,13 +53,13 @@ func TestOpenStaticFileDeflate_1(t *testing.T) { testOpenFile("deflate", content, t) } -func assetOpenFileAndContent(sch *serveContentHolder, content []byte, t *testing.T) { +func assetOpenFileAndContent(sch *serveContentHolder, reader *serveContentReader, content []byte, t *testing.T) { t.Log(sch.size, len(content)) if sch.size != int64(len(content)) { t.Log("static content file size not same") t.Fail() } - bs, _ := ioutil.ReadAll(sch) + bs, _ := ioutil.ReadAll(reader) for i, v := range content { if v != bs[i] { t.Log("content not same") From 45b68d444d2e7f659643a9b3899ac11c7f87de54 Mon Sep 17 00:00:00 2001 From: Ruben Cid Date: Fri, 1 Jun 2018 19:11:01 +0200 Subject: [PATCH 08/12] Add method to set the data depending on the accepted --- controller.go | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/controller.go b/controller.go index c104eb2a..92d2188b 100644 --- a/controller.go +++ b/controller.go @@ -275,6 +275,19 @@ func (c *Controller) Redirect(url string, code int) { c.Ctx.Redirect(code, url) } +// Set the data depending on the accepted +func (c *Controller) SetData(data interface{}) { + accept := c.Ctx.Input.Header("Accept") + switch accept { + case applicationJSON: + c.Data["json"] = data + case applicationXML, textXML: + c.Data["xml"] = data + default: + c.Data["json"] = data + } +} + // Abort stops controller handler and show the error data if code is defined in ErrorMap or code string. func (c *Controller) Abort(code string) { status, err := strconv.Atoi(code) From 464d080518e165b143763089e11c7c4571d86936 Mon Sep 17 00:00:00 2001 From: zhujianjian Date: Mon, 2 Jul 2018 11:21:06 +0800 Subject: [PATCH 09/12] fix httpcode in prod --- config.go | 1 + 1 file changed, 1 insertion(+) diff --git a/config.go b/config.go index eeeac8ee..c24709ff 100644 --- a/config.go +++ b/config.go @@ -182,6 +182,7 @@ func recoverPanic(ctx *context.Context) { if BConfig.RunMode == DEV && BConfig.EnableErrorsRender { showErr(err, ctx, stack) } + ctx.ResponseWriter.WriteHeader(500) } } From 6fec0a7831b4c05c9a583db04cb0ff233f26b15f Mon Sep 17 00:00:00 2001 From: guoshaowei Date: Thu, 12 Jul 2018 10:48:50 +0800 Subject: [PATCH 10/12] add session redis IdleTimeout config --- session/redis/sess_redis.go | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/session/redis/sess_redis.go b/session/redis/sess_redis.go index 54583152..5c382d61 100644 --- a/session/redis/sess_redis.go +++ b/session/redis/sess_redis.go @@ -37,6 +37,7 @@ import ( "strconv" "strings" "sync" + "time" "github.com/astaxie/beego/session" @@ -118,8 +119,8 @@ type Provider struct { } // SessionInit init redis session -// savepath like redis server addr,pool size,password,dbnum -// e.g. 127.0.0.1:6379,100,astaxie,0 +// savepath like redis server addr,pool size,password,dbnum,IdleTimeout second +// e.g. 127.0.0.1:6379,100,astaxie,0,30 func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { rp.maxlifetime = maxlifetime configs := strings.Split(savePath, ",") @@ -149,6 +150,13 @@ func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { } else { rp.dbNum = 0 } + var idleTimeout time.Duration = 0 + if len(configs) > 4 { + timeout, err := strconv.Atoi(configs[4]) + if err == nil && timeout > 0 { + idleTimeout = time.Duration(timeout) * time.Second + } + } rp.poollist = &redis.Pool{ Dial: func() (redis.Conn, error) { c, err := redis.Dial("tcp", rp.savePath) @@ -171,9 +179,11 @@ func (rp *Provider) SessionInit(maxlifetime int64, savePath string) error { } return c, err }, - MaxIdle: rp.poolsize, + MaxIdle: rp.poolsize, } + rp.poollist.IdleTimeout = idleTimeout + return rp.poollist.Get().Err() } From 0e0718d110268bb68652a087088c9054f50d97d4 Mon Sep 17 00:00:00 2001 From: Xingang Zhang <0x0400@users.noreply.github.com> Date: Tue, 17 Jul 2018 23:32:11 +0800 Subject: [PATCH 11/12] fix typo hasReuired --> hasRequired --- validation/validation.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/validation/validation.go b/validation/validation.go index 2781a72e..ca1e211f 100644 --- a/validation/validation.go +++ b/validation/validation.go @@ -365,10 +365,10 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { return } - var hasReuired bool + var hasRequired bool for _, vf := range vfs { if vf.Name == "Required" { - hasReuired = true + hasRequired = true } currentField := objV.Field(i).Interface() @@ -382,7 +382,7 @@ func (v *Validation) Valid(obj interface{}) (b bool, err error) { chk := Required{""}.IsSatisfied(currentField) - if !hasReuired && v.RequiredFirst && !chk { + if !hasRequired && v.RequiredFirst && !chk { if _, ok := CanSkipFuncs[vf.Name]; ok { continue } From 293b54192f2bb0627c5b0f7f5de75411f409ed2c Mon Sep 17 00:00:00 2001 From: mohan2808 Date: Thu, 19 Jul 2018 18:51:16 +0530 Subject: [PATCH 12/12] send ErrNoRows if the query returns zero rows ... in method orm_queryset.All() --- orm/orm_queryset.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/orm/orm_queryset.go b/orm/orm_queryset.go index 4bab1d98..8b5d6fd2 100644 --- a/orm/orm_queryset.go +++ b/orm/orm_queryset.go @@ -198,7 +198,11 @@ func (o *querySet) PrepareInsert() (Inserter, error) { // query all data and map to containers. // cols means the columns when querying. func (o *querySet) All(container interface{}, cols ...string) (int64, error) { - return o.orm.alias.DbBaser.ReadBatch(o.orm.db, o, o.mi, o.cond, container, o.orm.alias.TZ, cols) + num, err := o.orm.alias.DbBaser.ReadBatch(o.orm.db, o, o.mi, o.cond, container, o.orm.alias.TZ, cols) + if num == 0 { + return 0, ErrNoRows + } + return num, err } // query one row data and map to containers.