6497f29e by astaxie

version 1.1.2 release

2 parents 443aaadc 1705b425
1 .DS_Store 1 .DS_Store
2 *.swp
3 *.swo
......
...@@ -2,6 +2,7 @@ package beego ...@@ -2,6 +2,7 @@ package beego
2 2
3 import ( 3 import (
4 "net/http" 4 "net/http"
5 "os"
5 "path" 6 "path"
6 "path/filepath" 7 "path/filepath"
7 "strconv" 8 "strconv"
...@@ -12,7 +13,7 @@ import ( ...@@ -12,7 +13,7 @@ import (
12 ) 13 )
13 14
14 // beego web framework version. 15 // beego web framework version.
15 const VERSION = "1.1.1" 16 const VERSION = "1.1.2"
16 17
17 type hookfunc func() error //hook function to run 18 type hookfunc func() error //hook function to run
18 var hooks []hookfunc //hook function slice to store the hookfunc 19 var hooks []hookfunc //hook function slice to store the hookfunc
...@@ -174,6 +175,16 @@ func AddAPPStartHook(hf hookfunc) { ...@@ -174,6 +175,16 @@ func AddAPPStartHook(hf hookfunc) {
174 // Run beego application. 175 // Run beego application.
175 // it's alias of App.Run. 176 // it's alias of App.Run.
176 func Run() { 177 func Run() {
178 initBeforeHttpRun()
179
180 if EnableAdmin {
181 go BeeAdminApp.Run()
182 }
183
184 BeeApp.Run()
185 }
186
187 func initBeforeHttpRun() {
177 // if AppConfigPath not In the conf/app.conf reParse config 188 // if AppConfigPath not In the conf/app.conf reParse config
178 if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") { 189 if AppConfigPath != filepath.Join(AppPath, "conf", "app.conf") {
179 err := ParseConfig() 190 err := ParseConfig()
...@@ -222,12 +233,13 @@ func Run() { ...@@ -222,12 +233,13 @@ func Run() {
222 middleware.VERSION = VERSION 233 middleware.VERSION = VERSION
223 middleware.AppName = AppName 234 middleware.AppName = AppName
224 middleware.RegisterErrorHandler() 235 middleware.RegisterErrorHandler()
236 }
225 237
226 if EnableAdmin { 238 func TestBeegoInit(apppath string) {
227 go BeeAdminApp.Run() 239 AppPath = apppath
228 } 240 AppConfigPath = filepath.Join(AppPath, "conf", "app.conf")
229 241 os.Chdir(AppPath)
230 BeeApp.Run() 242 initBeforeHttpRun()
231 } 243 }
232 244
233 func init() { 245 func init() {
......
...@@ -11,12 +11,14 @@ import ( ...@@ -11,12 +11,14 @@ import (
11 "github.com/astaxie/beego/config" 11 "github.com/astaxie/beego/config"
12 "github.com/astaxie/beego/logs" 12 "github.com/astaxie/beego/logs"
13 "github.com/astaxie/beego/session" 13 "github.com/astaxie/beego/session"
14 "github.com/astaxie/beego/utils"
14 ) 15 )
15 16
16 var ( 17 var (
17 BeeApp *App // beego application 18 BeeApp *App // beego application
18 AppName string 19 AppName string
19 AppPath string 20 AppPath string
21 workPath string
20 AppConfigPath string 22 AppConfigPath string
21 StaticDir map[string]string 23 StaticDir map[string]string
22 TemplateCache map[string]*template.Template // template caching map 24 TemplateCache map[string]*template.Template // template caching map
...@@ -58,15 +60,28 @@ var ( ...@@ -58,15 +60,28 @@ var (
58 EnableAdmin bool // flag of enable admin module to log every request info. 60 EnableAdmin bool // flag of enable admin module to log every request info.
59 AdminHttpAddr string // http server configurations for admin module. 61 AdminHttpAddr string // http server configurations for admin module.
60 AdminHttpPort int 62 AdminHttpPort int
63 FlashName string // name of the flash variable found in response header and cookie
64 FlashSeperator string // used to seperate flash key:value
61 ) 65 )
62 66
63 func init() { 67 func init() {
64 // create beego application 68 // create beego application
65 BeeApp = NewApp() 69 BeeApp = NewApp()
66 70
71 workPath, _ = os.Getwd()
72 workPath, _ = filepath.Abs(workPath)
67 // initialize default configurations 73 // initialize default configurations
68 AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0])) 74 AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
69 os.Chdir(AppPath) 75
76 AppConfigPath = filepath.Join(AppPath, "conf", "app.conf")
77
78 if workPath != AppPath {
79 if utils.FileExists(AppConfigPath) {
80 os.Chdir(AppPath)
81 } else {
82 AppConfigPath = filepath.Join(workPath, "conf", "app.conf")
83 }
84 }
70 85
71 StaticDir = make(map[string]string) 86 StaticDir = make(map[string]string)
72 StaticDir["/static"] = "static" 87 StaticDir["/static"] = "static"
...@@ -105,8 +120,6 @@ func init() { ...@@ -105,8 +120,6 @@ func init() {
105 120
106 EnableGzip = false 121 EnableGzip = false
107 122
108 AppConfigPath = filepath.Join(AppPath, "conf", "app.conf")
109
110 HttpServerTimeOut = 0 123 HttpServerTimeOut = 0
111 124
112 ErrorsShow = true 125 ErrorsShow = true
...@@ -123,6 +136,9 @@ func init() { ...@@ -123,6 +136,9 @@ func init() {
123 AdminHttpAddr = "127.0.0.1" 136 AdminHttpAddr = "127.0.0.1"
124 AdminHttpPort = 8088 137 AdminHttpPort = 8088
125 138
139 FlashName = "BEEGO_FLASH"
140 FlashSeperator = "BEEGOFLASH"
141
126 runtime.GOMAXPROCS(runtime.NumCPU()) 142 runtime.GOMAXPROCS(runtime.NumCPU())
127 143
128 // init BeeLogger 144 // init BeeLogger
...@@ -271,6 +287,14 @@ func ParseConfig() (err error) { ...@@ -271,6 +287,14 @@ func ParseConfig() (err error) {
271 BeegoServerName = serverName 287 BeegoServerName = serverName
272 } 288 }
273 289
290 if flashname := AppConfig.String("FlashName"); flashname != "" {
291 FlashName = flashname
292 }
293
294 if flashseperator := AppConfig.String("FlashSeperator"); flashseperator != "" {
295 FlashSeperator = flashseperator
296 }
297
274 if sd := AppConfig.String("StaticDir"); sd != "" { 298 if sd := AppConfig.String("StaticDir"); sd != "" {
275 for k := range StaticDir { 299 for k := range StaticDir {
276 delete(StaticDir, k) 300 delete(StaticDir, k)
......
1 package beego
2
3 import (
4 "testing"
5 )
6
7 func TestDefaults(t *testing.T) {
8 if FlashName != "BEEGO_FLASH" {
9 t.Errorf("FlashName was not set to default.")
10 }
11
12 if FlashSeperator != "BEEGOFLASH" {
13 t.Errorf("FlashName was not set to default.")
14 }
15 }
...@@ -4,6 +4,7 @@ import ( ...@@ -4,6 +4,7 @@ import (
4 "bytes" 4 "bytes"
5 "io/ioutil" 5 "io/ioutil"
6 "net/http" 6 "net/http"
7 "reflect"
7 "strconv" 8 "strconv"
8 "strings" 9 "strings"
9 10
...@@ -13,11 +14,13 @@ import ( ...@@ -13,11 +14,13 @@ import (
13 // BeegoInput operates the http request header ,data ,cookie and body. 14 // BeegoInput operates the http request header ,data ,cookie and body.
14 // it also contains router params and current session. 15 // it also contains router params and current session.
15 type BeegoInput struct { 16 type BeegoInput struct {
16 CruSession session.SessionStore 17 CruSession session.SessionStore
17 Params map[string]string 18 Params map[string]string
18 Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller. 19 Data map[interface{}]interface{} // store some values in this context when calling context in filter or controller.
19 Request *http.Request 20 Request *http.Request
20 RequestBody []byte 21 RequestBody []byte
22 RunController reflect.Type
23 RunMethod string
21 } 24 }
22 25
23 // NewInput return BeegoInput generated by http.Request. 26 // NewInput return BeegoInput generated by http.Request.
......
...@@ -62,7 +62,6 @@ type ControllerInterface interface { ...@@ -62,7 +62,6 @@ type ControllerInterface interface {
62 62
63 // Init generates default values of controller operations. 63 // Init generates default values of controller operations.
64 func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) { 64 func (c *Controller) Init(ctx *context.Context, controllerName, actionName string, app interface{}) {
65 c.Data = make(map[interface{}]interface{})
66 c.Layout = "" 65 c.Layout = ""
67 c.TplNames = "" 66 c.TplNames = ""
68 c.controllerName = controllerName 67 c.controllerName = controllerName
......
...@@ -6,9 +6,6 @@ import ( ...@@ -6,9 +6,6 @@ import (
6 "strings" 6 "strings"
7 ) 7 )
8 8
9 // the separation string when encoding flash data.
10 const BEEGO_FLASH_SEP = "#BEEGOFLASH#"
11
12 // FlashData is a tools to maintain data when using across request. 9 // FlashData is a tools to maintain data when using across request.
13 type FlashData struct { 10 type FlashData struct {
14 Data map[string]string 11 Data map[string]string
...@@ -54,29 +51,27 @@ func (fd *FlashData) Store(c *Controller) { ...@@ -54,29 +51,27 @@ func (fd *FlashData) Store(c *Controller) {
54 c.Data["flash"] = fd.Data 51 c.Data["flash"] = fd.Data
55 var flashValue string 52 var flashValue string
56 for key, value := range fd.Data { 53 for key, value := range fd.Data {
57 flashValue += "\x00" + key + BEEGO_FLASH_SEP + value + "\x00" 54 flashValue += "\x00" + key + "\x23" + FlashSeperator + "\x23" + value + "\x00"
58 } 55 }
59 c.Ctx.SetCookie("BEEGO_FLASH", url.QueryEscape(flashValue), 0, "/") 56 c.Ctx.SetCookie(FlashName, url.QueryEscape(flashValue), 0, "/")
60 } 57 }
61 58
62 // ReadFromRequest parsed flash data from encoded values in cookie. 59 // ReadFromRequest parsed flash data from encoded values in cookie.
63 func ReadFromRequest(c *Controller) *FlashData { 60 func ReadFromRequest(c *Controller) *FlashData {
64 flash := &FlashData{ 61 flash := NewFlash()
65 Data: make(map[string]string), 62 if cookie, err := c.Ctx.Request.Cookie(FlashName); err == nil {
66 }
67 if cookie, err := c.Ctx.Request.Cookie("BEEGO_FLASH"); err == nil {
68 v, _ := url.QueryUnescape(cookie.Value) 63 v, _ := url.QueryUnescape(cookie.Value)
69 vals := strings.Split(v, "\x00") 64 vals := strings.Split(v, "\x00")
70 for _, v := range vals { 65 for _, v := range vals {
71 if len(v) > 0 { 66 if len(v) > 0 {
72 kv := strings.Split(v, BEEGO_FLASH_SEP) 67 kv := strings.Split(v, FlashSeperator)
73 if len(kv) == 2 { 68 if len(kv) == 2 {
74 flash.Data[kv[0]] = kv[1] 69 flash.Data[kv[0]] = kv[1]
75 } 70 }
76 } 71 }
77 } 72 }
78 //read one time then delete it 73 //read one time then delete it
79 c.Ctx.SetCookie("BEEGO_FLASH", "", -1, "/") 74 c.Ctx.SetCookie(FlashName, "", -1, "/")
80 } 75 }
81 c.Data["flash"] = flash.Data 76 c.Data["flash"] = flash.Data
82 return flash 77 return flash
......
1 package beego
2
3 import (
4 "net/http"
5 "net/http/httptest"
6 "strings"
7 "testing"
8 )
9
10 type TestFlashController struct {
11 Controller
12 }
13
14 func (this *TestFlashController) TestWriteFlash() {
15 flash := NewFlash()
16 flash.Notice("TestFlashString")
17 flash.Store(&this.Controller)
18 // we choose to serve json because we don't want to load a template html file
19 this.ServeJson(true)
20 }
21
22 func TestFlashHeader(t *testing.T) {
23 // create fake GET request
24 r, _ := http.NewRequest("GET", "/", nil)
25 w := httptest.NewRecorder()
26
27 // setup the handler
28 handler := NewControllerRegistor()
29 handler.Add("/", &TestFlashController{}, "get:TestWriteFlash")
30 handler.ServeHTTP(w, r)
31
32 // get the Set-Cookie value
33 sc := w.Header().Get("Set-Cookie")
34 // match for the expected header
35 res := strings.Contains(sc, "BEEGO_FLASH=%00notice%23BEEGOFLASH%23TestFlashString%00")
36 // validate the assertion
37 if res != true {
38 t.Errorf("TestFlashHeader() unable to validate flash message")
39 }
40 }
...@@ -22,12 +22,21 @@ func SetLevel(l int) { ...@@ -22,12 +22,21 @@ func SetLevel(l int) {
22 BeeLogger.SetLevel(l) 22 BeeLogger.SetLevel(l)
23 } 23 }
24 24
25 func SetLogFuncCall(b bool) {
26 BeeLogger.EnableFuncCallDepth(b)
27 BeeLogger.SetLogFuncCallDepth(3)
28 }
29
25 // logger references the used application logger. 30 // logger references the used application logger.
26 var BeeLogger *logs.BeeLogger 31 var BeeLogger *logs.BeeLogger
27 32
28 // SetLogger sets a new logger. 33 // SetLogger sets a new logger.
29 func SetLogger(adaptername string, config string) { 34 func SetLogger(adaptername string, config string) error {
30 BeeLogger.SetLogger(adaptername, config) 35 err := BeeLogger.SetLogger(adaptername, config)
36 if err != nil {
37 return err
38 }
39 return nil
31 } 40 }
32 41
33 // Trace logs a message at trace level. 42 // Trace logs a message at trace level.
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
6 6
7 func TestConsole(t *testing.T) { 7 func TestConsole(t *testing.T) {
8 log := NewLogger(10000) 8 log := NewLogger(10000)
9 log.EnableFuncCallDepth(true)
9 log.SetLogger("console", "") 10 log.SetLogger("console", "")
10 log.Trace("trace") 11 log.Trace("trace")
11 log.Info("info") 12 log.Info("info")
...@@ -23,6 +24,7 @@ func TestConsole(t *testing.T) { ...@@ -23,6 +24,7 @@ func TestConsole(t *testing.T) {
23 24
24 func BenchmarkConsole(b *testing.B) { 25 func BenchmarkConsole(b *testing.B) {
25 log := NewLogger(10000) 26 log := NewLogger(10000)
27 log.EnableFuncCallDepth(true)
26 log.SetLogger("console", "") 28 log.SetLogger("console", "")
27 for i := 0; i < b.N; i++ { 29 for i := 0; i < b.N; i++ {
28 log.Trace("trace") 30 log.Trace("trace")
......
...@@ -97,12 +97,12 @@ func (w *FileLogWriter) Init(jsonconfig string) error { ...@@ -97,12 +97,12 @@ func (w *FileLogWriter) Init(jsonconfig string) error {
97 if len(w.Filename) == 0 { 97 if len(w.Filename) == 0 {
98 return errors.New("jsonconfig must have filename") 98 return errors.New("jsonconfig must have filename")
99 } 99 }
100 err = w.StartLogger() 100 err = w.startLogger()
101 return err 101 return err
102 } 102 }
103 103
104 // start file logger. create log file and set to locker-inside file writer. 104 // start file logger. create log file and set to locker-inside file writer.
105 func (w *FileLogWriter) StartLogger() error { 105 func (w *FileLogWriter) startLogger() error {
106 fd, err := w.createLogFile() 106 fd, err := w.createLogFile()
107 if err != nil { 107 if err != nil {
108 return err 108 return err
...@@ -199,7 +199,7 @@ func (w *FileLogWriter) DoRotate() error { ...@@ -199,7 +199,7 @@ func (w *FileLogWriter) DoRotate() error {
199 } 199 }
200 200
201 // re-start logger 201 // re-start logger
202 err = w.StartLogger() 202 err = w.startLogger()
203 if err != nil { 203 if err != nil {
204 return fmt.Errorf("Rotate StartLogger: %s\n", err) 204 return fmt.Errorf("Rotate StartLogger: %s\n", err)
205 } 205 }
......
...@@ -2,6 +2,8 @@ package logs ...@@ -2,6 +2,8 @@ package logs
2 2
3 import ( 3 import (
4 "fmt" 4 "fmt"
5 "path"
6 "runtime"
5 "sync" 7 "sync"
6 ) 8 )
7 9
...@@ -43,10 +45,12 @@ func Register(name string, log loggerType) { ...@@ -43,10 +45,12 @@ func Register(name string, log loggerType) {
43 // BeeLogger is default logger in beego application. 45 // BeeLogger is default logger in beego application.
44 // it can contain several providers and log message into all providers. 46 // it can contain several providers and log message into all providers.
45 type BeeLogger struct { 47 type BeeLogger struct {
46 lock sync.Mutex 48 lock sync.Mutex
47 level int 49 level int
48 msg chan *logMsg 50 enableFuncCallDepth bool
49 outputs map[string]LoggerInterface 51 loggerFuncCallDepth int
52 msg chan *logMsg
53 outputs map[string]LoggerInterface
50 } 54 }
51 55
52 type logMsg struct { 56 type logMsg struct {
...@@ -59,10 +63,11 @@ type logMsg struct { ...@@ -59,10 +63,11 @@ type logMsg struct {
59 // if the buffering chan is full, logger adapters write to file or other way. 63 // if the buffering chan is full, logger adapters write to file or other way.
60 func NewLogger(channellen int64) *BeeLogger { 64 func NewLogger(channellen int64) *BeeLogger {
61 bl := new(BeeLogger) 65 bl := new(BeeLogger)
66 bl.loggerFuncCallDepth = 2
62 bl.msg = make(chan *logMsg, channellen) 67 bl.msg = make(chan *logMsg, channellen)
63 bl.outputs = make(map[string]LoggerInterface) 68 bl.outputs = make(map[string]LoggerInterface)
64 //bl.SetLogger("console", "") // default output to console 69 //bl.SetLogger("console", "") // default output to console
65 go bl.StartLogger() 70 go bl.startLogger()
66 return bl 71 return bl
67 } 72 }
68 73
...@@ -73,7 +78,10 @@ func (bl *BeeLogger) SetLogger(adaptername string, config string) error { ...@@ -73,7 +78,10 @@ func (bl *BeeLogger) SetLogger(adaptername string, config string) error {
73 defer bl.lock.Unlock() 78 defer bl.lock.Unlock()
74 if log, ok := adapters[adaptername]; ok { 79 if log, ok := adapters[adaptername]; ok {
75 lg := log() 80 lg := log()
76 lg.Init(config) 81 err := lg.Init(config)
82 if err != nil {
83 return err
84 }
77 bl.outputs[adaptername] = lg 85 bl.outputs[adaptername] = lg
78 return nil 86 return nil
79 } else { 87 } else {
...@@ -100,7 +108,17 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error { ...@@ -100,7 +108,17 @@ func (bl *BeeLogger) writerMsg(loglevel int, msg string) error {
100 } 108 }
101 lm := new(logMsg) 109 lm := new(logMsg)
102 lm.level = loglevel 110 lm.level = loglevel
103 lm.msg = msg 111 if bl.enableFuncCallDepth {
112 _, file, line, ok := runtime.Caller(bl.loggerFuncCallDepth)
113 if ok {
114 _, filename := path.Split(file)
115 lm.msg = fmt.Sprintf("[%s:%d] %s", filename, line, msg)
116 } else {
117 lm.msg = msg
118 }
119 } else {
120 lm.msg = msg
121 }
104 bl.msg <- lm 122 bl.msg <- lm
105 return nil 123 return nil
106 } 124 }
...@@ -111,9 +129,19 @@ func (bl *BeeLogger) SetLevel(l int) { ...@@ -111,9 +129,19 @@ func (bl *BeeLogger) SetLevel(l int) {
111 bl.level = l 129 bl.level = l
112 } 130 }
113 131
132 // set log funcCallDepth
133 func (bl *BeeLogger) SetLogFuncCallDepth(d int) {
134 bl.loggerFuncCallDepth = d
135 }
136
137 // enable log funcCallDepth
138 func (bl *BeeLogger) EnableFuncCallDepth(b bool) {
139 bl.enableFuncCallDepth = b
140 }
141
114 // start logger chan reading. 142 // start logger chan reading.
115 // when chan is full, write logs. 143 // when chan is full, write logs.
116 func (bl *BeeLogger) StartLogger() { 144 func (bl *BeeLogger) startLogger() {
117 for { 145 for {
118 select { 146 select {
119 case bm := <-bl.msg: 147 case bm := <-bl.msg:
......
...@@ -51,9 +51,16 @@ outFor: ...@@ -51,9 +51,16 @@ outFor:
51 continue 51 continue
52 } 52 }
53 53
54 switch v := arg.(type) { 54 kind := val.Kind()
55 case []byte: 55 if kind == reflect.Ptr {
56 case string: 56 val = val.Elem()
57 kind = val.Kind()
58 arg = val.Interface()
59 }
60
61 switch kind {
62 case reflect.String:
63 v := val.String()
57 if fi != nil { 64 if fi != nil {
58 if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField { 65 if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField {
59 var t time.Time 66 var t time.Time
...@@ -78,61 +85,66 @@ outFor: ...@@ -78,61 +85,66 @@ outFor:
78 } 85 }
79 } 86 }
80 arg = v 87 arg = v
81 case time.Time: 88 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
82 if fi != nil && fi.fieldType == TypeDateField { 89 arg = val.Int()
83 arg = v.In(tz).Format(format_Date) 90 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
84 } else { 91 arg = val.Uint()
85 arg = v.In(tz).Format(format_DateTime) 92 case reflect.Float32:
93 arg, _ = StrTo(ToStr(arg)).Float64()
94 case reflect.Float64:
95 arg = val.Float()
96 case reflect.Bool:
97 arg = val.Bool()
98 case reflect.Slice, reflect.Array:
99 if _, ok := arg.([]byte); ok {
100 continue outFor
86 } 101 }
87 default:
88 kind := val.Kind()
89 switch kind {
90 case reflect.Slice, reflect.Array:
91
92 var args []interface{}
93 for i := 0; i < val.Len(); i++ {
94 v := val.Index(i)
95
96 var vu interface{}
97 if v.CanInterface() {
98 vu = v.Interface()
99 }
100 102
101 if vu == nil { 103 var args []interface{}
102 continue 104 for i := 0; i < val.Len(); i++ {
103 } 105 v := val.Index(i)
104 106
105 args = append(args, vu) 107 var vu interface{}
108 if v.CanInterface() {
109 vu = v.Interface()
106 } 110 }
107 111
108 if len(args) > 0 { 112 if vu == nil {
109 p := getFlatParams(fi, args, tz) 113 continue
110 params = append(params, p...)
111 } 114 }
112 continue outFor
113 115
114 case reflect.Ptr, reflect.Struct: 116 args = append(args, vu)
115 ind := reflect.Indirect(val) 117 }
116 118
117 if ind.Kind() == reflect.Struct { 119 if len(args) > 0 {
118 typ := ind.Type() 120 p := getFlatParams(fi, args, tz)
119 name := getFullName(typ) 121 params = append(params, p...)
120 var value interface{} 122 }
121 if mmi, ok := modelCache.getByFN(name); ok { 123 continue outFor
122 if _, vu, exist := getExistPk(mmi, ind); exist { 124 case reflect.Struct:
123 value = vu 125 if v, ok := arg.(time.Time); ok {
124 } 126 if fi != nil && fi.fieldType == TypeDateField {
127 arg = v.In(tz).Format(format_Date)
128 } else {
129 arg = v.In(tz).Format(format_DateTime)
130 }
131 } else {
132 typ := val.Type()
133 name := getFullName(typ)
134 var value interface{}
135 if mmi, ok := modelCache.getByFN(name); ok {
136 if _, vu, exist := getExistPk(mmi, val); exist {
137 value = vu
125 } 138 }
126 arg = value 139 }
140 arg = value
127 141
128 if arg == nil { 142 if arg == nil {
129 panic(fmt.Errorf("need a valid args value, unknown table or value `%s`", name)) 143 panic(fmt.Errorf("need a valid args value, unknown table or value `%s`", name))
130 }
131 } else {
132 arg = ind.Interface()
133 } 144 }
134 } 145 }
135 } 146 }
147
136 params = append(params, arg) 148 params = append(params, arg)
137 } 149 }
138 return 150 return
......
...@@ -144,6 +144,45 @@ type DataNull struct { ...@@ -144,6 +144,45 @@ type DataNull struct {
144 NullInt64 sql.NullInt64 `orm:"null"` 144 NullInt64 sql.NullInt64 `orm:"null"`
145 } 145 }
146 146
147 type String string
148 type Boolean bool
149 type Byte byte
150 type Rune rune
151 type Int int
152 type Int8 int8
153 type Int16 int16
154 type Int32 int32
155 type Int64 int64
156 type Uint uint
157 type Uint8 uint8
158 type Uint16 uint16
159 type Uint32 uint32
160 type Uint64 uint64
161 type Float32 float64
162 type Float64 float64
163
164 type DataCustom struct {
165 Id int
166 Boolean Boolean
167 Char string `orm:"size(50)"`
168 Text string `orm:"type(text)"`
169 Byte Byte
170 Rune Rune
171 Int Int
172 Int8 Int8
173 Int16 Int16
174 Int32 Int32
175 Int64 Int64
176 Uint Uint
177 Uint8 Uint8
178 Uint16 Uint16
179 Uint32 Uint32
180 Uint64 Uint64
181 Float32 Float32
182 Float64 Float64
183 Decimal Float64 `orm:"digits(8);decimals(4)"`
184 }
185
147 // only for mysql 186 // only for mysql
148 type UserBig struct { 187 type UserBig struct {
149 Id uint64 188 Id uint64
...@@ -155,7 +194,7 @@ type User struct { ...@@ -155,7 +194,7 @@ type User struct {
155 UserName string `orm:"size(30);unique"` 194 UserName string `orm:"size(30);unique"`
156 Email string `orm:"size(100)"` 195 Email string `orm:"size(100)"`
157 Password string `orm:"size(100)"` 196 Password string `orm:"size(100)"`
158 Status int16 197 Status int16 `orm:"column(Status)"`
159 IsStaff bool 198 IsStaff bool
160 IsActive bool `orm:"default(1)"` 199 IsActive bool `orm:"default(1)"`
161 Created time.Time `orm:"auto_now_add;type(date)"` 200 Created time.Time `orm:"auto_now_add;type(date)"`
......
...@@ -80,7 +80,6 @@ func getTableUnique(val reflect.Value) [][]string { ...@@ -80,7 +80,6 @@ func getTableUnique(val reflect.Value) [][]string {
80 80
81 // get snaked column name 81 // get snaked column name
82 func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string { 82 func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col string) string {
83 col = strings.ToLower(col)
84 column := col 83 column := col
85 if col == "" { 84 if col == "" {
86 column = snakeString(sf.Name) 85 column = snakeString(sf.Name)
...@@ -99,34 +98,41 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col ...@@ -99,34 +98,41 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col
99 // return field type as type constant from reflect.Value 98 // return field type as type constant from reflect.Value
100 func getFieldType(val reflect.Value) (ft int, err error) { 99 func getFieldType(val reflect.Value) (ft int, err error) {
101 elm := reflect.Indirect(val) 100 elm := reflect.Indirect(val)
102 switch elm.Interface().(type) { 101 switch elm.Kind() {
103 case int8: 102 case reflect.Int8:
104 ft = TypeBitField 103 ft = TypeBitField
105 case int16: 104 case reflect.Int16:
106 ft = TypeSmallIntegerField 105 ft = TypeSmallIntegerField
107 case int32, int: 106 case reflect.Int32, reflect.Int:
108 ft = TypeIntegerField 107 ft = TypeIntegerField
109 case int64, sql.NullInt64: 108 case reflect.Int64:
110 ft = TypeBigIntegerField 109 ft = TypeBigIntegerField
111 case uint8: 110 case reflect.Uint8:
112 ft = TypePositiveBitField 111 ft = TypePositiveBitField
113 case uint16: 112 case reflect.Uint16:
114 ft = TypePositiveSmallIntegerField 113 ft = TypePositiveSmallIntegerField
115 case uint32, uint: 114 case reflect.Uint32, reflect.Uint:
116 ft = TypePositiveIntegerField 115 ft = TypePositiveIntegerField
117 case uint64: 116 case reflect.Uint64:
118 ft = TypePositiveBigIntegerField 117 ft = TypePositiveBigIntegerField
119 case float32, float64, sql.NullFloat64: 118 case reflect.Float32, reflect.Float64:
120 ft = TypeFloatField 119 ft = TypeFloatField
121 case bool, sql.NullBool: 120 case reflect.Bool:
122 ft = TypeBooleanField 121 ft = TypeBooleanField
123 case string, sql.NullString: 122 case reflect.String:
124 ft = TypeCharField 123 ft = TypeCharField
125 default: 124 default:
126 if elm.CanInterface() { 125 switch elm.Interface().(type) {
127 if _, ok := elm.Interface().(time.Time); ok { 126 case sql.NullInt64:
128 ft = TypeDateTimeField 127 ft = TypeBigIntegerField
129 } 128 case sql.NullFloat64:
129 ft = TypeFloatField
130 case sql.NullBool:
131 ft = TypeBooleanField
132 case sql.NullString:
133 ft = TypeCharField
134 case time.Time:
135 ft = TypeDateTimeField
130 } 136 }
131 } 137 }
132 if ft&IsFieldType == 0 { 138 if ft&IsFieldType == 0 {
......
...@@ -149,7 +149,7 @@ func TestGetDB(t *testing.T) { ...@@ -149,7 +149,7 @@ func TestGetDB(t *testing.T) {
149 } 149 }
150 150
151 func TestSyncDb(t *testing.T) { 151 func TestSyncDb(t *testing.T) {
152 RegisterModel(new(Data), new(DataNull)) 152 RegisterModel(new(Data), new(DataNull), new(DataCustom))
153 RegisterModel(new(User)) 153 RegisterModel(new(User))
154 RegisterModel(new(Profile)) 154 RegisterModel(new(Profile))
155 RegisterModel(new(Post)) 155 RegisterModel(new(Post))
...@@ -165,7 +165,7 @@ func TestSyncDb(t *testing.T) { ...@@ -165,7 +165,7 @@ func TestSyncDb(t *testing.T) {
165 } 165 }
166 166
167 func TestRegisterModels(t *testing.T) { 167 func TestRegisterModels(t *testing.T) {
168 RegisterModel(new(Data), new(DataNull)) 168 RegisterModel(new(Data), new(DataNull), new(DataCustom))
169 RegisterModel(new(User)) 169 RegisterModel(new(User))
170 RegisterModel(new(Profile)) 170 RegisterModel(new(Profile))
171 RegisterModel(new(Post)) 171 RegisterModel(new(Post))
...@@ -309,6 +309,39 @@ func TestNullDataTypes(t *testing.T) { ...@@ -309,6 +309,39 @@ func TestNullDataTypes(t *testing.T) {
309 throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42)) 309 throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42))
310 } 310 }
311 311
312 func TestDataCustomTypes(t *testing.T) {
313 d := DataCustom{}
314 ind := reflect.Indirect(reflect.ValueOf(&d))
315
316 for name, value := range Data_Values {
317 e := ind.FieldByName(name)
318 if !e.IsValid() {
319 continue
320 }
321 e.Set(reflect.ValueOf(value).Convert(e.Type()))
322 }
323
324 id, err := dORM.Insert(&d)
325 throwFail(t, err)
326 throwFail(t, AssertIs(id, 1))
327
328 d = DataCustom{Id: 1}
329 err = dORM.Read(&d)
330 throwFail(t, err)
331
332 ind = reflect.Indirect(reflect.ValueOf(&d))
333
334 for name, value := range Data_Values {
335 e := ind.FieldByName(name)
336 if !e.IsValid() {
337 continue
338 }
339 vu := e.Interface()
340 value = reflect.ValueOf(value).Convert(e.Type()).Interface()
341 throwFail(t, AssertIs(vu == value, true), value, vu)
342 }
343 }
344
312 func TestCRUD(t *testing.T) { 345 func TestCRUD(t *testing.T) {
313 profile := NewProfile() 346 profile := NewProfile()
314 profile.Age = 30 347 profile.Age = 30
...@@ -562,6 +595,10 @@ func TestOperators(t *testing.T) { ...@@ -562,6 +595,10 @@ func TestOperators(t *testing.T) {
562 throwFail(t, err) 595 throwFail(t, err)
563 throwFail(t, AssertIs(num, 1)) 596 throwFail(t, AssertIs(num, 1))
564 597
598 num, err = qs.Filter("user_name__exact", String("slene")).Count()
599 throwFail(t, err)
600 throwFail(t, AssertIs(num, 1))
601
565 num, err = qs.Filter("user_name__exact", "slene").Count() 602 num, err = qs.Filter("user_name__exact", "slene").Count()
566 throwFail(t, err) 603 throwFail(t, err)
567 throwFail(t, AssertIs(num, 1)) 604 throwFail(t, AssertIs(num, 1))
...@@ -602,11 +639,11 @@ func TestOperators(t *testing.T) { ...@@ -602,11 +639,11 @@ func TestOperators(t *testing.T) {
602 throwFail(t, err) 639 throwFail(t, err)
603 throwFail(t, AssertIs(num, 3)) 640 throwFail(t, AssertIs(num, 3))
604 641
605 num, err = qs.Filter("status__lt", 3).Count() 642 num, err = qs.Filter("status__lt", Uint(3)).Count()
606 throwFail(t, err) 643 throwFail(t, err)
607 throwFail(t, AssertIs(num, 2)) 644 throwFail(t, AssertIs(num, 2))
608 645
609 num, err = qs.Filter("status__lte", 3).Count() 646 num, err = qs.Filter("status__lte", Int(3)).Count()
610 throwFail(t, err) 647 throwFail(t, err)
611 throwFail(t, AssertIs(num, 3)) 648 throwFail(t, AssertIs(num, 3))
612 649
...@@ -1380,7 +1417,7 @@ func TestRawQueryRow(t *testing.T) { ...@@ -1380,7 +1417,7 @@ func TestRawQueryRow(t *testing.T) {
1380 ) 1417 )
1381 1418
1382 cols = []string{ 1419 cols = []string{
1383 "id", "status", "profile_id", 1420 "id", "Status", "profile_id",
1384 } 1421 }
1385 query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s WHERE id = ?", Q, strings.Join(cols, sep), Q, Q, Q) 1422 query = fmt.Sprintf("SELECT %s%s%s FROM %suser%s WHERE id = ?", Q, strings.Join(cols, sep), Q, Q, Q)
1386 err = dORM.Raw(query, 4).QueryRow(&uid, &status, &pid) 1423 err = dORM.Raw(query, 4).QueryRow(&uid, &status, &pid)
...@@ -1460,7 +1497,7 @@ func TestRawValues(t *testing.T) { ...@@ -1460,7 +1497,7 @@ func TestRawValues(t *testing.T) {
1460 Q := dDbBaser.TableQuote() 1497 Q := dDbBaser.TableQuote()
1461 1498
1462 var maps []Params 1499 var maps []Params
1463 query := fmt.Sprintf("SELECT %suser_name%s FROM %suser%s WHERE %sstatus%s = ?", Q, Q, Q, Q, Q, Q) 1500 query := fmt.Sprintf("SELECT %suser_name%s FROM %suser%s WHERE %sStatus%s = ?", Q, Q, Q, Q, Q, Q)
1464 num, err := dORM.Raw(query, 1).Values(&maps) 1501 num, err := dORM.Raw(query, 1).Values(&maps)
1465 throwFail(t, err) 1502 throwFail(t, err)
1466 throwFail(t, AssertIs(num, 1)) 1503 throwFail(t, AssertIs(num, 1))
......
...@@ -44,6 +44,11 @@ var ( ...@@ -44,6 +44,11 @@ var (
44 "GetControllerAndAction"} 44 "GetControllerAndAction"}
45 ) 45 )
46 46
47 // To append a slice's value into "exceptMethod", for controller's methods shouldn't reflect to AutoRouter
48 func ExceptMethodAppend(action string) {
49 exceptMethod = append(exceptMethod, action)
50 }
51
47 type controllerInfo struct { 52 type controllerInfo struct {
48 pattern string 53 pattern string
49 regex *regexp.Regexp 54 regex *regexp.Regexp
...@@ -621,29 +626,37 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) ...@@ -621,29 +626,37 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request)
621 context.Input.Body() 626 context.Input.Body()
622 } 627 }
623 628
629 if context.Input.RunController != nil && context.Input.RunMethod != "" {
630 findrouter = true
631 runMethod = context.Input.RunMethod
632 runrouter = context.Input.RunController
633 }
634
624 //first find path from the fixrouters to Improve Performance 635 //first find path from the fixrouters to Improve Performance
625 for _, route := range p.fixrouters { 636 if !findrouter {
626 n := len(requestPath) 637 for _, route := range p.fixrouters {
627 if requestPath == route.pattern { 638 n := len(requestPath)
628 runMethod = p.getRunMethod(r.Method, context, route) 639 if requestPath == route.pattern {
629 if runMethod != "" { 640 runMethod = p.getRunMethod(r.Method, context, route)
630 runrouter = route.controllerType 641 if runMethod != "" {
631 findrouter = true 642 runrouter = route.controllerType
632 break 643 findrouter = true
644 break
645 }
633 } 646 }
634 } 647 // pattern /admin url /admin 200 /admin/ 200
635 // pattern /admin url /admin 200 /admin/ 200 648 // pattern /admin/ url /admin 301 /admin/ 200
636 // pattern /admin/ url /admin 301 /admin/ 200 649 if requestPath[n-1] != '/' && requestPath+"/" == route.pattern {
637 if requestPath[n-1] != '/' && requestPath+"/" == route.pattern { 650 http.Redirect(w, r, requestPath+"/", 301)
638 http.Redirect(w, r, requestPath+"/", 301) 651 goto Admin
639 goto Admin 652 }
640 } 653 if requestPath[n-1] == '/' && route.pattern+"/" == requestPath {
641 if requestPath[n-1] == '/' && route.pattern+"/" == requestPath { 654 runMethod = p.getRunMethod(r.Method, context, route)
642 runMethod = p.getRunMethod(r.Method, context, route) 655 if runMethod != "" {
643 if runMethod != "" { 656 runrouter = route.controllerType
644 runrouter = route.controllerType 657 findrouter = true
645 findrouter = true 658 break
646 break 659 }
647 } 660 }
648 } 661 }
649 } 662 }
......
...@@ -118,6 +118,7 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error ...@@ -118,6 +118,7 @@ func (pder *CookieProvider) SessionInit(maxlifetime int64, config string) error
118 if err != nil { 118 if err != nil {
119 return err 119 return err
120 } 120 }
121 pder.maxlifetime = maxlifetime
121 return nil 122 return nil
122 } 123 }
123 124
......
1 package session
2
3 /*
4
5 beego session provider for postgresql
6 -------------------------------------
7
8 depends on github.com/lib/pq:
9
10 go install github.com/lib/pq
11
12
13 needs this table in your database:
14
15 CREATE TABLE session (
16 session_key char(64) NOT NULL,
17 session_data bytea,
18 session_expiry timestamp NOT NULL,
19 CONSTRAINT session_key PRIMARY KEY(session_key)
20 );
21
22
23 will be activated with these settings in app.conf:
24
25 SessionOn = true
26 SessionProvider = postgresql
27 SessionSavePath = "user=a password=b dbname=c sslmode=disable"
28 SessionName = session
29
30 */
31
32 import (
33 "database/sql"
34 "net/http"
35 "sync"
36 "time"
37 _ "github.com/lib/pq"
38 )
39
40 var postgresqlpder = &PostgresqlProvider{}
41
42 // postgresql session store
43 type PostgresqlSessionStore struct {
44 c *sql.DB
45 sid string
46 lock sync.RWMutex
47 values map[interface{}]interface{}
48 }
49
50 // set value in postgresql session.
51 // it is temp value in map.
52 func (st *PostgresqlSessionStore) Set(key, value interface{}) error {
53 st.lock.Lock()
54 defer st.lock.Unlock()
55 st.values[key] = value
56 return nil
57 }
58
59 // get value from postgresql session
60 func (st *PostgresqlSessionStore) Get(key interface{}) interface{} {
61 st.lock.RLock()
62 defer st.lock.RUnlock()
63 if v, ok := st.values[key]; ok {
64 return v
65 } else {
66 return nil
67 }
68 return nil
69 }
70
71 // delete value in postgresql session
72 func (st *PostgresqlSessionStore) Delete(key interface{}) error {
73 st.lock.Lock()
74 defer st.lock.Unlock()
75 delete(st.values, key)
76 return nil
77 }
78
79 // clear all values in postgresql session
80 func (st *PostgresqlSessionStore) Flush() error {
81 st.lock.Lock()
82 defer st.lock.Unlock()
83 st.values = make(map[interface{}]interface{})
84 return nil
85 }
86
87 // get session id of this postgresql session store
88 func (st *PostgresqlSessionStore) SessionID() string {
89 return st.sid
90 }
91
92 // save postgresql session values to database.
93 // must call this method to save values to database.
94 func (st *PostgresqlSessionStore) SessionRelease(w http.ResponseWriter) {
95 defer st.c.Close()
96 b, err := encodeGob(st.values)
97 if err != nil {
98 return
99 }
100 st.c.Exec("UPDATE session set session_data=$1, session_expiry=$2 where session_key=$3",
101 b, time.Now().Format(time.RFC3339), st.sid)
102
103 }
104
105 // postgresql session provider
106 type PostgresqlProvider struct {
107 maxlifetime int64
108 savePath string
109 }
110
111 // connect to postgresql
112 func (mp *PostgresqlProvider) connectInit() *sql.DB {
113 db, e := sql.Open("postgres", mp.savePath)
114 if e != nil {
115 return nil
116 }
117 return db
118 }
119
120 // init postgresql session.
121 // savepath is the connection string of postgresql.
122 func (mp *PostgresqlProvider) SessionInit(maxlifetime int64, savePath string) error {
123 mp.maxlifetime = maxlifetime
124 mp.savePath = savePath
125 return nil
126 }
127
128 // get postgresql session by sid
129 func (mp *PostgresqlProvider) SessionRead(sid string) (SessionStore, error) {
130 c := mp.connectInit()
131 row := c.QueryRow("select session_data from session where session_key=$1", sid)
132 var sessiondata []byte
133 err := row.Scan(&sessiondata)
134 if err == sql.ErrNoRows {
135 _, err = c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)",
136 sid, "", time.Now().Format(time.RFC3339))
137
138 if err != nil {
139 return nil, err
140 }
141 } else if err != nil {
142 return nil, err
143 }
144
145 var kv map[interface{}]interface{}
146 if len(sessiondata) == 0 {
147 kv = make(map[interface{}]interface{})
148 } else {
149 kv, err = decodeGob(sessiondata)
150 if err != nil {
151 return nil, err
152 }
153 }
154 rs := &PostgresqlSessionStore{c: c, sid: sid, values: kv}
155 return rs, nil
156 }
157
158 // check postgresql session exist
159 func (mp *PostgresqlProvider) SessionExist(sid string) bool {
160 c := mp.connectInit()
161 defer c.Close()
162 row := c.QueryRow("select session_data from session where session_key=$1", sid)
163 var sessiondata []byte
164 err := row.Scan(&sessiondata)
165
166 if err == sql.ErrNoRows {
167 return false
168 } else {
169 return true
170 }
171 }
172
173 // generate new sid for postgresql session
174 func (mp *PostgresqlProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) {
175 c := mp.connectInit()
176 row := c.QueryRow("select session_data from session where session_key=$1", oldsid)
177 var sessiondata []byte
178 err := row.Scan(&sessiondata)
179 if err == sql.ErrNoRows {
180 c.Exec("insert into session(session_key,session_data,session_expiry) values($1,$2,$3)",
181 oldsid, "", time.Now().Format(time.RFC3339))
182 }
183 c.Exec("update session set session_key=$1 where session_key=$2", sid, oldsid)
184 var kv map[interface{}]interface{}
185 if len(sessiondata) == 0 {
186 kv = make(map[interface{}]interface{})
187 } else {
188 kv, err = decodeGob(sessiondata)
189 if err != nil {
190 return nil, err
191 }
192 }
193 rs := &PostgresqlSessionStore{c: c, sid: sid, values: kv}
194 return rs, nil
195 }
196
197 // delete postgresql session by sid
198 func (mp *PostgresqlProvider) SessionDestroy(sid string) error {
199 c := mp.connectInit()
200 c.Exec("DELETE FROM session where session_key=$1", sid)
201 c.Close()
202 return nil
203 }
204
205 // delete expired values in postgresql session
206 func (mp *PostgresqlProvider) SessionGC() {
207 c := mp.connectInit()
208 c.Exec("DELETE from session where EXTRACT(EPOCH FROM (current_timestamp - session_expiry)) > $1", mp.maxlifetime)
209 c.Close()
210 return
211 }
212
213 // count values in postgresql session
214 func (mp *PostgresqlProvider) SessionAll() int {
215 c := mp.connectInit()
216 defer c.Close()
217 var total int
218 err := c.QueryRow("SELECT count(*) as num from session").Scan(&total)
219 if err != nil {
220 return 0
221 }
222 return total
223 }
224
225 func init() {
226 Register("postgresql", postgresqlpder)
227 }
...@@ -151,7 +151,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp ...@@ -151,7 +151,7 @@ func getTplDeep(root, file, parent string, t *template.Template) (*template.Temp
151 fileabspath = filepath.Join(root, file) 151 fileabspath = filepath.Join(root, file)
152 } 152 }
153 if e := utils.FileExists(fileabspath); !e { 153 if e := utils.FileExists(fileabspath); !e {
154 panic("can't find template file" + file) 154 panic("can't find template file:" + file)
155 } 155 }
156 data, err := ioutil.ReadFile(fileabspath) 156 data, err := ioutil.ReadFile(fileabspath)
157 if err != nil { 157 if err != nil {
......
...@@ -67,7 +67,7 @@ func (r Required) IsSatisfied(obj interface{}) bool { ...@@ -67,7 +67,7 @@ func (r Required) IsSatisfied(obj interface{}) bool {
67 } 67 }
68 68
69 func (r Required) DefaultMessage() string { 69 func (r Required) DefaultMessage() string {
70 return "Required" 70 return fmt.Sprint(MessageTmpls["Required"])
71 } 71 }
72 72
73 func (r Required) GetKey() string { 73 func (r Required) GetKey() string {
......
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!