Merge branch 'release/1.1.1'
Showing
20 changed files
with
619 additions
and
154 deletions
| ... | @@ -12,7 +12,7 @@ import ( | ... | @@ -12,7 +12,7 @@ import ( |
| 12 | ) | 12 | ) |
| 13 | 13 | ||
| 14 | // beego web framework version. | 14 | // beego web framework version. |
| 15 | const VERSION = "1.1.0" | 15 | const VERSION = "1.1.1" |
| 16 | 16 | ||
| 17 | type hookfunc func() error //hook function to run | 17 | type hookfunc func() error //hook function to run |
| 18 | var hooks []hookfunc //hook function slice to store the hookfunc | 18 | var hooks []hookfunc //hook function slice to store the hookfunc |
| ... | @@ -28,12 +28,12 @@ type GroupRouters []groupRouter | ... | @@ -28,12 +28,12 @@ type GroupRouters []groupRouter |
| 28 | 28 | ||
| 29 | // Get a new GroupRouters | 29 | // Get a new GroupRouters |
| 30 | func NewGroupRouters() GroupRouters { | 30 | func NewGroupRouters() GroupRouters { |
| 31 | return make([]groupRouter, 0) | 31 | return make(GroupRouters, 0) |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | // Add Router in the GroupRouters | 34 | // Add Router in the GroupRouters |
| 35 | // it is for plugin or module to register router | 35 | // it is for plugin or module to register router |
| 36 | func (gr GroupRouters) AddRouter(pattern string, c ControllerInterface, mappingMethod ...string) { | 36 | func (gr *GroupRouters) AddRouter(pattern string, c ControllerInterface, mappingMethod ...string) { |
| 37 | var newRG groupRouter | 37 | var newRG groupRouter |
| 38 | if len(mappingMethod) > 0 { | 38 | if len(mappingMethod) > 0 { |
| 39 | newRG = groupRouter{ | 39 | newRG = groupRouter{ |
| ... | @@ -48,16 +48,16 @@ func (gr GroupRouters) AddRouter(pattern string, c ControllerInterface, mappingM | ... | @@ -48,16 +48,16 @@ func (gr GroupRouters) AddRouter(pattern string, c ControllerInterface, mappingM |
| 48 | "", | 48 | "", |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| 51 | gr = append(gr, newRG) | 51 | *gr = append(*gr, newRG) |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | func (gr GroupRouters) AddAuto(c ControllerInterface) { | 54 | func (gr *GroupRouters) AddAuto(c ControllerInterface) { |
| 55 | newRG := groupRouter{ | 55 | newRG := groupRouter{ |
| 56 | "", | 56 | "", |
| 57 | c, | 57 | c, |
| 58 | "", | 58 | "", |
| 59 | } | 59 | } |
| 60 | gr = append(gr, newRG) | 60 | *gr = append(*gr, newRG) |
| 61 | } | 61 | } |
| 62 | 62 | ||
| 63 | // AddGroupRouter with the prefix | 63 | // AddGroupRouter with the prefix | ... | ... |
| ... | @@ -147,6 +147,8 @@ func (this *FileCache) Get(key string) interface{} { | ... | @@ -147,6 +147,8 @@ func (this *FileCache) Get(key string) interface{} { |
| 147 | // timeout means how long to keep this file, unit of ms. | 147 | // timeout means how long to keep this file, unit of ms. |
| 148 | // if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever. | 148 | // if timeout equals FileCacheEmbedExpiry(default is 0), cache this item forever. |
| 149 | func (this *FileCache) Put(key string, val interface{}, timeout int64) error { | 149 | func (this *FileCache) Put(key string, val interface{}, timeout int64) error { |
| 150 | gob.Register(val) | ||
| 151 | |||
| 150 | filename := this.getCacheFileName(key) | 152 | filename := this.getCacheFileName(key) |
| 151 | var item FileCacheItem | 153 | var item FileCacheItem |
| 152 | item.Data = val | 154 | item.Data = val | ... | ... |
| 1 | package context | 1 | package context |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "crypto/hmac" | ||
| 5 | "crypto/sha1" | ||
| 6 | "encoding/base64" | ||
| 7 | "fmt" | ||
| 4 | "net/http" | 8 | "net/http" |
| 9 | "strconv" | ||
| 10 | "strings" | ||
| 11 | "time" | ||
| 5 | 12 | ||
| 6 | "github.com/astaxie/beego/middleware" | 13 | "github.com/astaxie/beego/middleware" |
| 7 | ) | 14 | ) |
| ... | @@ -59,3 +66,41 @@ func (ctx *Context) GetCookie(key string) string { | ... | @@ -59,3 +66,41 @@ func (ctx *Context) GetCookie(key string) string { |
| 59 | func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { | 66 | func (ctx *Context) SetCookie(name string, value string, others ...interface{}) { |
| 60 | ctx.Output.Cookie(name, value, others...) | 67 | ctx.Output.Cookie(name, value, others...) |
| 61 | } | 68 | } |
| 69 | |||
| 70 | // Get secure cookie from request by a given key. | ||
| 71 | func (ctx *Context) GetSecureCookie(Secret, key string) (string, bool) { | ||
| 72 | val := ctx.Input.Cookie(key) | ||
| 73 | if val == "" { | ||
| 74 | return "", false | ||
| 75 | } | ||
| 76 | |||
| 77 | parts := strings.SplitN(val, "|", 3) | ||
| 78 | |||
| 79 | if len(parts) != 3 { | ||
| 80 | return "", false | ||
| 81 | } | ||
| 82 | |||
| 83 | vs := parts[0] | ||
| 84 | timestamp := parts[1] | ||
| 85 | sig := parts[2] | ||
| 86 | |||
| 87 | h := hmac.New(sha1.New, []byte(Secret)) | ||
| 88 | fmt.Fprintf(h, "%s%s", vs, timestamp) | ||
| 89 | |||
| 90 | if fmt.Sprintf("%02x", h.Sum(nil)) != sig { | ||
| 91 | return "", false | ||
| 92 | } | ||
| 93 | res, _ := base64.URLEncoding.DecodeString(vs) | ||
| 94 | return string(res), true | ||
| 95 | } | ||
| 96 | |||
| 97 | // Set Secure cookie for response. | ||
| 98 | func (ctx *Context) SetSecureCookie(Secret, name, value string, others ...interface{}) { | ||
| 99 | vs := base64.URLEncoding.EncodeToString([]byte(value)) | ||
| 100 | timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) | ||
| 101 | h := hmac.New(sha1.New, []byte(Secret)) | ||
| 102 | fmt.Fprintf(h, "%s%s", vs, timestamp) | ||
| 103 | sig := fmt.Sprintf("%02x", h.Sum(nil)) | ||
| 104 | cookie := strings.Join([]string{vs, timestamp, sig}, "|") | ||
| 105 | ctx.Output.Cookie(name, cookie, others...) | ||
| 106 | } | ... | ... |
| ... | @@ -77,39 +77,77 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface | ... | @@ -77,39 +77,77 @@ func (output *BeegoOutput) Cookie(name string, value string, others ...interface |
| 77 | var b bytes.Buffer | 77 | var b bytes.Buffer |
| 78 | fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) | 78 | fmt.Fprintf(&b, "%s=%s", sanitizeName(name), sanitizeValue(value)) |
| 79 | if len(others) > 0 { | 79 | if len(others) > 0 { |
| 80 | switch others[0].(type) { | 80 | switch v := others[0].(type) { |
| 81 | case int: | 81 | case int: |
| 82 | if others[0].(int) > 0 { | 82 | if v > 0 { |
| 83 | fmt.Fprintf(&b, "; Max-Age=%d", others[0].(int)) | 83 | fmt.Fprintf(&b, "; Max-Age=%d", v) |
| 84 | } else if others[0].(int) < 0 { | 84 | } else if v < 0 { |
| 85 | fmt.Fprintf(&b, "; Max-Age=0") | 85 | fmt.Fprintf(&b, "; Max-Age=0") |
| 86 | } | 86 | } |
| 87 | case int64: | 87 | case int64: |
| 88 | if others[0].(int64) > 0 { | 88 | if v > 0 { |
| 89 | fmt.Fprintf(&b, "; Max-Age=%d", others[0].(int64)) | 89 | fmt.Fprintf(&b, "; Max-Age=%d", v) |
| 90 | } else if others[0].(int64) < 0 { | 90 | } else if v < 0 { |
| 91 | fmt.Fprintf(&b, "; Max-Age=0") | 91 | fmt.Fprintf(&b, "; Max-Age=0") |
| 92 | } | 92 | } |
| 93 | case int32: | 93 | case int32: |
| 94 | if others[0].(int32) > 0 { | 94 | if v > 0 { |
| 95 | fmt.Fprintf(&b, "; Max-Age=%d", others[0].(int32)) | 95 | fmt.Fprintf(&b, "; Max-Age=%d", v) |
| 96 | } else if others[0].(int32) < 0 { | 96 | } else if v < 0 { |
| 97 | fmt.Fprintf(&b, "; Max-Age=0") | 97 | fmt.Fprintf(&b, "; Max-Age=0") |
| 98 | } | 98 | } |
| 99 | } | 99 | } |
| 100 | } | 100 | } |
| 101 | |||
| 102 | // the settings below | ||
| 103 | // Path, Domain, Secure, HttpOnly | ||
| 104 | // can use nil skip set | ||
| 105 | |||
| 106 | // default "/" | ||
| 101 | if len(others) > 1 { | 107 | if len(others) > 1 { |
| 102 | fmt.Fprintf(&b, "; Path=%s", sanitizeValue(others[1].(string))) | 108 | if v, ok := others[1].(string); ok && len(v) > 0 { |
| 109 | fmt.Fprintf(&b, "; Path=%s", sanitizeValue(v)) | ||
| 110 | } | ||
| 111 | } else { | ||
| 112 | fmt.Fprintf(&b, "; Path=%s", "/") | ||
| 103 | } | 113 | } |
| 114 | |||
| 115 | // default empty | ||
| 104 | if len(others) > 2 { | 116 | if len(others) > 2 { |
| 105 | fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(others[2].(string))) | 117 | if v, ok := others[2].(string); ok && len(v) > 0 { |
| 118 | fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(v)) | ||
| 119 | } | ||
| 106 | } | 120 | } |
| 121 | |||
| 122 | // default empty | ||
| 107 | if len(others) > 3 { | 123 | if len(others) > 3 { |
| 108 | fmt.Fprintf(&b, "; Secure") | 124 | var secure bool |
| 125 | switch v := others[3].(type) { | ||
| 126 | case bool: | ||
| 127 | secure = v | ||
| 128 | default: | ||
| 129 | if others[3] != nil { | ||
| 130 | secure = true | ||
| 131 | } | ||
| 132 | } | ||
| 133 | if secure { | ||
| 134 | fmt.Fprintf(&b, "; Secure") | ||
| 135 | } | ||
| 109 | } | 136 | } |
| 137 | |||
| 138 | // default true | ||
| 139 | httponly := true | ||
| 110 | if len(others) > 4 { | 140 | if len(others) > 4 { |
| 141 | if v, ok := others[4].(bool); ok && !v || others[4] == nil { | ||
| 142 | // HttpOnly = false | ||
| 143 | httponly = false | ||
| 144 | } | ||
| 145 | } | ||
| 146 | |||
| 147 | if httponly { | ||
| 111 | fmt.Fprintf(&b, "; HttpOnly") | 148 | fmt.Fprintf(&b, "; HttpOnly") |
| 112 | } | 149 | } |
| 150 | |||
| 113 | output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String()) | 151 | output.Context.ResponseWriter.Header().Add("Set-Cookie", b.String()) |
| 114 | } | 152 | } |
| 115 | 153 | ... | ... |
| ... | @@ -2,11 +2,7 @@ package beego | ... | @@ -2,11 +2,7 @@ package beego |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "bytes" | 4 | "bytes" |
| 5 | "crypto/hmac" | ||
| 6 | "crypto/sha1" | ||
| 7 | "encoding/base64" | ||
| 8 | "errors" | 5 | "errors" |
| 9 | "fmt" | ||
| 10 | "html/template" | 6 | "html/template" |
| 11 | "io" | 7 | "io" |
| 12 | "io/ioutil" | 8 | "io/ioutil" |
| ... | @@ -17,7 +13,6 @@ import ( | ... | @@ -17,7 +13,6 @@ import ( |
| 17 | "reflect" | 13 | "reflect" |
| 18 | "strconv" | 14 | "strconv" |
| 19 | "strings" | 15 | "strings" |
| 20 | "time" | ||
| 21 | 16 | ||
| 22 | "github.com/astaxie/beego/context" | 17 | "github.com/astaxie/beego/context" |
| 23 | "github.com/astaxie/beego/session" | 18 | "github.com/astaxie/beego/session" |
| ... | @@ -313,11 +308,11 @@ func (c *Controller) GetString(key string) string { | ... | @@ -313,11 +308,11 @@ func (c *Controller) GetString(key string) string { |
| 313 | // GetStrings returns the input string slice by key string. | 308 | // GetStrings returns the input string slice by key string. |
| 314 | // it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection. | 309 | // it's designed for multi-value input field such as checkbox(input[type=checkbox]), multi-selection. |
| 315 | func (c *Controller) GetStrings(key string) []string { | 310 | func (c *Controller) GetStrings(key string) []string { |
| 316 | r := c.Ctx.Request | 311 | f := c.Input() |
| 317 | if r.Form == nil { | 312 | if f == nil { |
| 318 | return []string{} | 313 | return []string{} |
| 319 | } | 314 | } |
| 320 | vs := r.Form[key] | 315 | vs := f[key] |
| 321 | if len(vs) > 0 { | 316 | if len(vs) > 0 { |
| 322 | return vs | 317 | return vs |
| 323 | } | 318 | } |
| ... | @@ -417,40 +412,12 @@ func (c *Controller) IsAjax() bool { | ... | @@ -417,40 +412,12 @@ func (c *Controller) IsAjax() bool { |
| 417 | 412 | ||
| 418 | // GetSecureCookie returns decoded cookie value from encoded browser cookie values. | 413 | // GetSecureCookie returns decoded cookie value from encoded browser cookie values. |
| 419 | func (c *Controller) GetSecureCookie(Secret, key string) (string, bool) { | 414 | func (c *Controller) GetSecureCookie(Secret, key string) (string, bool) { |
| 420 | val := c.Ctx.GetCookie(key) | 415 | return c.Ctx.GetSecureCookie(Secret, key) |
| 421 | if val == "" { | ||
| 422 | return "", false | ||
| 423 | } | ||
| 424 | |||
| 425 | parts := strings.SplitN(val, "|", 3) | ||
| 426 | |||
| 427 | if len(parts) != 3 { | ||
| 428 | return "", false | ||
| 429 | } | ||
| 430 | |||
| 431 | vs := parts[0] | ||
| 432 | timestamp := parts[1] | ||
| 433 | sig := parts[2] | ||
| 434 | |||
| 435 | h := hmac.New(sha1.New, []byte(Secret)) | ||
| 436 | fmt.Fprintf(h, "%s%s", vs, timestamp) | ||
| 437 | |||
| 438 | if fmt.Sprintf("%02x", h.Sum(nil)) != sig { | ||
| 439 | return "", false | ||
| 440 | } | ||
| 441 | res, _ := base64.URLEncoding.DecodeString(vs) | ||
| 442 | return string(res), true | ||
| 443 | } | 416 | } |
| 444 | 417 | ||
| 445 | // SetSecureCookie puts value into cookie after encoded the value. | 418 | // SetSecureCookie puts value into cookie after encoded the value. |
| 446 | func (c *Controller) SetSecureCookie(Secret, name, val string, age int64) { | 419 | func (c *Controller) SetSecureCookie(Secret, name, value string, others ...interface{}) { |
| 447 | vs := base64.URLEncoding.EncodeToString([]byte(val)) | 420 | c.Ctx.SetSecureCookie(Secret, name, value, others...) |
| 448 | timestamp := strconv.FormatInt(time.Now().UnixNano(), 10) | ||
| 449 | h := hmac.New(sha1.New, []byte(Secret)) | ||
| 450 | fmt.Fprintf(h, "%s%s", vs, timestamp) | ||
| 451 | sig := fmt.Sprintf("%02x", h.Sum(nil)) | ||
| 452 | cookie := strings.Join([]string{vs, timestamp, sig}, "|") | ||
| 453 | c.Ctx.SetCookie(name, cookie, age, "/") | ||
| 454 | } | 421 | } |
| 455 | 422 | ||
| 456 | // XsrfToken creates a xsrf token string and returns. | 423 | // XsrfToken creates a xsrf token string and returns. | ... | ... |
| ... | @@ -24,7 +24,7 @@ func Get(url string) *BeegoHttpRequest { | ... | @@ -24,7 +24,7 @@ func Get(url string) *BeegoHttpRequest { |
| 24 | req.Method = "GET" | 24 | req.Method = "GET" |
| 25 | req.Header = http.Header{} | 25 | req.Header = http.Header{} |
| 26 | req.Header.Set("User-Agent", defaultUserAgent) | 26 | req.Header.Set("User-Agent", defaultUserAgent) |
| 27 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil} | 27 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil} |
| 28 | } | 28 | } |
| 29 | 29 | ||
| 30 | // Post returns *BeegoHttpRequest with POST method. | 30 | // Post returns *BeegoHttpRequest with POST method. |
| ... | @@ -33,7 +33,7 @@ func Post(url string) *BeegoHttpRequest { | ... | @@ -33,7 +33,7 @@ func Post(url string) *BeegoHttpRequest { |
| 33 | req.Method = "POST" | 33 | req.Method = "POST" |
| 34 | req.Header = http.Header{} | 34 | req.Header = http.Header{} |
| 35 | req.Header.Set("User-Agent", defaultUserAgent) | 35 | req.Header.Set("User-Agent", defaultUserAgent) |
| 36 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil} | 36 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil} |
| 37 | } | 37 | } |
| 38 | 38 | ||
| 39 | // Put returns *BeegoHttpRequest with PUT method. | 39 | // Put returns *BeegoHttpRequest with PUT method. |
| ... | @@ -42,7 +42,7 @@ func Put(url string) *BeegoHttpRequest { | ... | @@ -42,7 +42,7 @@ func Put(url string) *BeegoHttpRequest { |
| 42 | req.Method = "PUT" | 42 | req.Method = "PUT" |
| 43 | req.Header = http.Header{} | 43 | req.Header = http.Header{} |
| 44 | req.Header.Set("User-Agent", defaultUserAgent) | 44 | req.Header.Set("User-Agent", defaultUserAgent) |
| 45 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil} | 45 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil} |
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | // Delete returns *BeegoHttpRequest DELETE GET method. | 48 | // Delete returns *BeegoHttpRequest DELETE GET method. |
| ... | @@ -51,7 +51,7 @@ func Delete(url string) *BeegoHttpRequest { | ... | @@ -51,7 +51,7 @@ func Delete(url string) *BeegoHttpRequest { |
| 51 | req.Method = "DELETE" | 51 | req.Method = "DELETE" |
| 52 | req.Header = http.Header{} | 52 | req.Header = http.Header{} |
| 53 | req.Header.Set("User-Agent", defaultUserAgent) | 53 | req.Header.Set("User-Agent", defaultUserAgent) |
| 54 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil} | 54 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil} |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | // Head returns *BeegoHttpRequest with HEAD method. | 57 | // Head returns *BeegoHttpRequest with HEAD method. |
| ... | @@ -60,7 +60,7 @@ func Head(url string) *BeegoHttpRequest { | ... | @@ -60,7 +60,7 @@ func Head(url string) *BeegoHttpRequest { |
| 60 | req.Method = "HEAD" | 60 | req.Method = "HEAD" |
| 61 | req.Header = http.Header{} | 61 | req.Header = http.Header{} |
| 62 | req.Header.Set("User-Agent", defaultUserAgent) | 62 | req.Header.Set("User-Agent", defaultUserAgent) |
| 63 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil} | 63 | return &BeegoHttpRequest{url, &req, map[string]string{}, false, 60 * time.Second, 60 * time.Second, nil, nil, nil} |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | // BeegoHttpRequest provides more useful methods for requesting one url than http.Request. | 66 | // BeegoHttpRequest provides more useful methods for requesting one url than http.Request. |
| ... | @@ -72,6 +72,8 @@ type BeegoHttpRequest struct { | ... | @@ -72,6 +72,8 @@ type BeegoHttpRequest struct { |
| 72 | connectTimeout time.Duration | 72 | connectTimeout time.Duration |
| 73 | readWriteTimeout time.Duration | 73 | readWriteTimeout time.Duration |
| 74 | tlsClientConfig *tls.Config | 74 | tlsClientConfig *tls.Config |
| 75 | proxy func(*http.Request) (*url.URL, error) | ||
| 76 | transport http.RoundTripper | ||
| 75 | } | 77 | } |
| 76 | 78 | ||
| 77 | // Debug sets show debug or not when executing request. | 79 | // Debug sets show debug or not when executing request. |
| ... | @@ -105,6 +107,24 @@ func (b *BeegoHttpRequest) SetCookie(cookie *http.Cookie) *BeegoHttpRequest { | ... | @@ -105,6 +107,24 @@ func (b *BeegoHttpRequest) SetCookie(cookie *http.Cookie) *BeegoHttpRequest { |
| 105 | return b | 107 | return b |
| 106 | } | 108 | } |
| 107 | 109 | ||
| 110 | // Set transport to | ||
| 111 | func (b *BeegoHttpRequest) SetTransport(transport http.RoundTripper) *BeegoHttpRequest { | ||
| 112 | b.transport = transport | ||
| 113 | return b | ||
| 114 | } | ||
| 115 | |||
| 116 | // Set http proxy | ||
| 117 | // example: | ||
| 118 | // | ||
| 119 | // func(req *http.Request) (*url.URL, error) { | ||
| 120 | // u, _ := url.ParseRequestURI("http://127.0.0.1:8118") | ||
| 121 | // return u, nil | ||
| 122 | // } | ||
| 123 | func (b *BeegoHttpRequest) SetProxy(proxy func(*http.Request) (*url.URL, error)) *BeegoHttpRequest { | ||
| 124 | b.proxy = proxy | ||
| 125 | return b | ||
| 126 | } | ||
| 127 | |||
| 108 | // Param adds query param in to request. | 128 | // Param adds query param in to request. |
| 109 | // params build query string as ?key1=value1&key2=value2... | 129 | // params build query string as ?key1=value1&key2=value2... |
| 110 | func (b *BeegoHttpRequest) Param(key, value string) *BeegoHttpRequest { | 130 | func (b *BeegoHttpRequest) Param(key, value string) *BeegoHttpRequest { |
| ... | @@ -171,12 +191,34 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { | ... | @@ -171,12 +191,34 @@ func (b *BeegoHttpRequest) getResponse() (*http.Response, error) { |
| 171 | println(string(dump)) | 191 | println(string(dump)) |
| 172 | } | 192 | } |
| 173 | 193 | ||
| 174 | client := &http.Client{ | 194 | trans := b.transport |
| 175 | Transport: &http.Transport{ | 195 | |
| 196 | if trans == nil { | ||
| 197 | // create default transport | ||
| 198 | trans = &http.Transport{ | ||
| 176 | TLSClientConfig: b.tlsClientConfig, | 199 | TLSClientConfig: b.tlsClientConfig, |
| 200 | Proxy: b.proxy, | ||
| 177 | Dial: TimeoutDialer(b.connectTimeout, b.readWriteTimeout), | 201 | Dial: TimeoutDialer(b.connectTimeout, b.readWriteTimeout), |
| 178 | }, | 202 | } |
| 203 | } else { | ||
| 204 | // if b.transport is *http.Transport then set the settings. | ||
| 205 | if t, ok := trans.(*http.Transport); ok { | ||
| 206 | if t.TLSClientConfig == nil { | ||
| 207 | t.TLSClientConfig = b.tlsClientConfig | ||
| 208 | } | ||
| 209 | if t.Proxy == nil { | ||
| 210 | t.Proxy = b.proxy | ||
| 211 | } | ||
| 212 | if t.Dial == nil { | ||
| 213 | t.Dial = TimeoutDialer(b.connectTimeout, b.readWriteTimeout) | ||
| 214 | } | ||
| 215 | } | ||
| 179 | } | 216 | } |
| 217 | |||
| 218 | client := &http.Client{ | ||
| 219 | Transport: trans, | ||
| 220 | } | ||
| 221 | |||
| 180 | resp, err := client.Do(b.req) | 222 | resp, err := client.Do(b.req) |
| 181 | if err != nil { | 223 | if err != nil { |
| 182 | return nil, err | 224 | return nil, err | ... | ... |
| ... | @@ -35,7 +35,7 @@ var ( | ... | @@ -35,7 +35,7 @@ var ( |
| 35 | "istartswith": true, | 35 | "istartswith": true, |
| 36 | "iendswith": true, | 36 | "iendswith": true, |
| 37 | "in": true, | 37 | "in": true, |
| 38 | // "range": true, | 38 | "between": true, |
| 39 | // "year": true, | 39 | // "year": true, |
| 40 | // "month": true, | 40 | // "month": true, |
| 41 | // "day": true, | 41 | // "day": true, |
| ... | @@ -103,15 +103,36 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val | ... | @@ -103,15 +103,36 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val |
| 103 | } else { | 103 | } else { |
| 104 | switch fi.fieldType { | 104 | switch fi.fieldType { |
| 105 | case TypeBooleanField: | 105 | case TypeBooleanField: |
| 106 | value = field.Bool() | 106 | if nb, ok := field.Interface().(sql.NullBool); ok { |
| 107 | value = nil | ||
| 108 | if nb.Valid { | ||
| 109 | value = nb.Bool | ||
| 110 | } | ||
| 111 | } else { | ||
| 112 | value = field.Bool() | ||
| 113 | } | ||
| 107 | case TypeCharField, TypeTextField: | 114 | case TypeCharField, TypeTextField: |
| 108 | value = field.String() | 115 | if ns, ok := field.Interface().(sql.NullString); ok { |
| 116 | value = nil | ||
| 117 | if ns.Valid { | ||
| 118 | value = ns.String | ||
| 119 | } | ||
| 120 | } else { | ||
| 121 | value = field.String() | ||
| 122 | } | ||
| 109 | case TypeFloatField, TypeDecimalField: | 123 | case TypeFloatField, TypeDecimalField: |
| 110 | vu := field.Interface() | 124 | if nf, ok := field.Interface().(sql.NullFloat64); ok { |
| 111 | if _, ok := vu.(float32); ok { | 125 | value = nil |
| 112 | value, _ = StrTo(ToStr(vu)).Float64() | 126 | if nf.Valid { |
| 127 | value = nf.Float64 | ||
| 128 | } | ||
| 113 | } else { | 129 | } else { |
| 114 | value = field.Float() | 130 | vu := field.Interface() |
| 131 | if _, ok := vu.(float32); ok { | ||
| 132 | value, _ = StrTo(ToStr(vu)).Float64() | ||
| 133 | } else { | ||
| 134 | value = field.Float() | ||
| 135 | } | ||
| 115 | } | 136 | } |
| 116 | case TypeDateField, TypeDateTimeField: | 137 | case TypeDateField, TypeDateTimeField: |
| 117 | value = field.Interface() | 138 | value = field.Interface() |
| ... | @@ -124,7 +145,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val | ... | @@ -124,7 +145,14 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val |
| 124 | case fi.fieldType&IsPostiveIntegerField > 0: | 145 | case fi.fieldType&IsPostiveIntegerField > 0: |
| 125 | value = field.Uint() | 146 | value = field.Uint() |
| 126 | case fi.fieldType&IsIntegerField > 0: | 147 | case fi.fieldType&IsIntegerField > 0: |
| 127 | value = field.Int() | 148 | if ni, ok := field.Interface().(sql.NullInt64); ok { |
| 149 | value = nil | ||
| 150 | if ni.Valid { | ||
| 151 | value = ni.Int64 | ||
| 152 | } | ||
| 153 | } else { | ||
| 154 | value = field.Int() | ||
| 155 | } | ||
| 128 | case fi.fieldType&IsRelField > 0: | 156 | case fi.fieldType&IsRelField > 0: |
| 129 | if field.IsNil() { | 157 | if field.IsNil() { |
| 130 | value = nil | 158 | value = nil |
| ... | @@ -144,6 +172,11 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val | ... | @@ -144,6 +172,11 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val |
| 144 | switch fi.fieldType { | 172 | switch fi.fieldType { |
| 145 | case TypeDateField, TypeDateTimeField: | 173 | case TypeDateField, TypeDateTimeField: |
| 146 | if fi.auto_now || fi.auto_now_add && insert { | 174 | if fi.auto_now || fi.auto_now_add && insert { |
| 175 | if insert { | ||
| 176 | if t, ok := value.(time.Time); ok && !t.IsZero() { | ||
| 177 | break | ||
| 178 | } | ||
| 179 | } | ||
| 147 | tnow := time.Now() | 180 | tnow := time.Now() |
| 148 | d.ins.TimeToDB(&tnow, tz) | 181 | d.ins.TimeToDB(&tnow, tz) |
| 149 | value = tnow | 182 | value = tnow |
| ... | @@ -883,13 +916,19 @@ func (d *dbBase) GenerateOperatorSql(mi *modelInfo, fi *fieldInfo, operator stri | ... | @@ -883,13 +916,19 @@ func (d *dbBase) GenerateOperatorSql(mi *modelInfo, fi *fieldInfo, operator stri |
| 883 | } | 916 | } |
| 884 | arg := params[0] | 917 | arg := params[0] |
| 885 | 918 | ||
| 886 | if operator == "in" { | 919 | switch operator { |
| 920 | case "in": | ||
| 887 | marks := make([]string, len(params)) | 921 | marks := make([]string, len(params)) |
| 888 | for i, _ := range marks { | 922 | for i, _ := range marks { |
| 889 | marks[i] = "?" | 923 | marks[i] = "?" |
| 890 | } | 924 | } |
| 891 | sql = fmt.Sprintf("IN (%s)", strings.Join(marks, ", ")) | 925 | sql = fmt.Sprintf("IN (%s)", strings.Join(marks, ", ")) |
| 892 | } else { | 926 | case "between": |
| 927 | if len(params) != 2 { | ||
| 928 | panic(fmt.Errorf("operator `%s` need 2 args not %d", operator, len(params))) | ||
| 929 | } | ||
| 930 | sql = "BETWEEN ? AND ?" | ||
| 931 | default: | ||
| 893 | if len(params) > 1 { | 932 | if len(params) > 1 { |
| 894 | panic(fmt.Errorf("operator `%s` need 1 args not %d", operator, len(params))) | 933 | panic(fmt.Errorf("operator `%s` need 1 args not %d", operator, len(params))) |
| 895 | } | 934 | } |
| ... | @@ -1117,17 +1156,37 @@ setValue: | ... | @@ -1117,17 +1156,37 @@ setValue: |
| 1117 | switch { | 1156 | switch { |
| 1118 | case fieldType == TypeBooleanField: | 1157 | case fieldType == TypeBooleanField: |
| 1119 | if isNative { | 1158 | if isNative { |
| 1120 | if value == nil { | 1159 | if nb, ok := field.Interface().(sql.NullBool); ok { |
| 1121 | value = false | 1160 | if value == nil { |
| 1161 | nb.Valid = false | ||
| 1162 | } else { | ||
| 1163 | nb.Bool = value.(bool) | ||
| 1164 | nb.Valid = true | ||
| 1165 | } | ||
| 1166 | field.Set(reflect.ValueOf(nb)) | ||
| 1167 | } else { | ||
| 1168 | if value == nil { | ||
| 1169 | value = false | ||
| 1170 | } | ||
| 1171 | field.SetBool(value.(bool)) | ||
| 1122 | } | 1172 | } |
| 1123 | field.SetBool(value.(bool)) | ||
| 1124 | } | 1173 | } |
| 1125 | case fieldType == TypeCharField || fieldType == TypeTextField: | 1174 | case fieldType == TypeCharField || fieldType == TypeTextField: |
| 1126 | if isNative { | 1175 | if isNative { |
| 1127 | if value == nil { | 1176 | if ns, ok := field.Interface().(sql.NullString); ok { |
| 1128 | value = "" | 1177 | if value == nil { |
| 1178 | ns.Valid = false | ||
| 1179 | } else { | ||
| 1180 | ns.String = value.(string) | ||
| 1181 | ns.Valid = true | ||
| 1182 | } | ||
| 1183 | field.Set(reflect.ValueOf(ns)) | ||
| 1184 | } else { | ||
| 1185 | if value == nil { | ||
| 1186 | value = "" | ||
| 1187 | } | ||
| 1188 | field.SetString(value.(string)) | ||
| 1129 | } | 1189 | } |
| 1130 | field.SetString(value.(string)) | ||
| 1131 | } | 1190 | } |
| 1132 | case fieldType == TypeDateField || fieldType == TypeDateTimeField: | 1191 | case fieldType == TypeDateField || fieldType == TypeDateTimeField: |
| 1133 | if isNative { | 1192 | if isNative { |
| ... | @@ -1146,18 +1205,39 @@ setValue: | ... | @@ -1146,18 +1205,39 @@ setValue: |
| 1146 | } | 1205 | } |
| 1147 | } else { | 1206 | } else { |
| 1148 | if isNative { | 1207 | if isNative { |
| 1149 | if value == nil { | 1208 | if ni, ok := field.Interface().(sql.NullInt64); ok { |
| 1150 | value = int64(0) | 1209 | if value == nil { |
| 1210 | ni.Valid = false | ||
| 1211 | } else { | ||
| 1212 | ni.Int64 = value.(int64) | ||
| 1213 | ni.Valid = true | ||
| 1214 | } | ||
| 1215 | field.Set(reflect.ValueOf(ni)) | ||
| 1216 | } else { | ||
| 1217 | if value == nil { | ||
| 1218 | value = int64(0) | ||
| 1219 | } | ||
| 1220 | field.SetInt(value.(int64)) | ||
| 1151 | } | 1221 | } |
| 1152 | field.SetInt(value.(int64)) | ||
| 1153 | } | 1222 | } |
| 1154 | } | 1223 | } |
| 1155 | case fieldType == TypeFloatField || fieldType == TypeDecimalField: | 1224 | case fieldType == TypeFloatField || fieldType == TypeDecimalField: |
| 1156 | if isNative { | 1225 | if isNative { |
| 1157 | if value == nil { | 1226 | if nf, ok := field.Interface().(sql.NullFloat64); ok { |
| 1158 | value = float64(0) | 1227 | if value == nil { |
| 1228 | nf.Valid = false | ||
| 1229 | } else { | ||
| 1230 | nf.Float64 = value.(float64) | ||
| 1231 | nf.Valid = true | ||
| 1232 | } | ||
| 1233 | field.Set(reflect.ValueOf(nf)) | ||
| 1234 | } else { | ||
| 1235 | |||
| 1236 | if value == nil { | ||
| 1237 | value = float64(0) | ||
| 1238 | } | ||
| 1239 | field.SetFloat(value.(float64)) | ||
| 1159 | } | 1240 | } |
| 1160 | field.SetFloat(value.(float64)) | ||
| 1161 | } | 1241 | } |
| 1162 | case fieldType&IsRelField > 0: | 1242 | case fieldType&IsRelField > 0: |
| 1163 | if value != nil { | 1243 | if value != nil { | ... | ... |
| ... | @@ -168,7 +168,7 @@ func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) { | ... | @@ -168,7 +168,7 @@ func addAliasWthDB(aliasName, driverName string, db *sql.DB) (*alias, error) { |
| 168 | } | 168 | } |
| 169 | 169 | ||
| 170 | if dataBaseCache.add(aliasName, al) == false { | 170 | if dataBaseCache.add(aliasName, al) == false { |
| 171 | return nil, fmt.Errorf("db name `%s` already registered, cannot reuse", aliasName) | 171 | return nil, fmt.Errorf("DataBase alias name `%s` already registered, cannot reuse", aliasName) |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | return al, nil | 174 | return al, nil |
| ... | @@ -239,7 +239,7 @@ func SetDataBaseTZ(aliasName string, tz *time.Location) error { | ... | @@ -239,7 +239,7 @@ func SetDataBaseTZ(aliasName string, tz *time.Location) error { |
| 239 | if al, ok := dataBaseCache.get(aliasName); ok { | 239 | if al, ok := dataBaseCache.get(aliasName); ok { |
| 240 | al.TZ = tz | 240 | al.TZ = tz |
| 241 | } else { | 241 | } else { |
| 242 | return fmt.Errorf("DataBase name `%s` not registered\n", aliasName) | 242 | return fmt.Errorf("DataBase alias name `%s` not registered\n", aliasName) |
| 243 | } | 243 | } |
| 244 | return nil | 244 | return nil |
| 245 | } | 245 | } |
| ... | @@ -260,3 +260,19 @@ func SetMaxOpenConns(aliasName string, maxOpenConns int) { | ... | @@ -260,3 +260,19 @@ func SetMaxOpenConns(aliasName string, maxOpenConns int) { |
| 260 | fun.Call([]reflect.Value{reflect.ValueOf(maxOpenConns)}) | 260 | fun.Call([]reflect.Value{reflect.ValueOf(maxOpenConns)}) |
| 261 | } | 261 | } |
| 262 | } | 262 | } |
| 263 | |||
| 264 | // Get *sql.DB from registered database by db alias name. | ||
| 265 | // Use "default" as alias name if you not set. | ||
| 266 | func GetDB(aliasNames ...string) (*sql.DB, error) { | ||
| 267 | var name string | ||
| 268 | if len(aliasNames) > 0 { | ||
| 269 | name = aliasNames[0] | ||
| 270 | } else { | ||
| 271 | name = "default" | ||
| 272 | } | ||
| 273 | if al, ok := dataBaseCache.get(name); ok { | ||
| 274 | return al.DB, nil | ||
| 275 | } else { | ||
| 276 | return nil, fmt.Errorf("DataBase of alias name `%s` not found\n", name) | ||
| 277 | } | ||
| 278 | } | ... | ... |
| ... | @@ -98,3 +98,9 @@ func (mc *_modelCache) clean() { | ... | @@ -98,3 +98,9 @@ func (mc *_modelCache) clean() { |
| 98 | mc.cacheByFN = make(map[string]*modelInfo) | 98 | mc.cacheByFN = make(map[string]*modelInfo) |
| 99 | mc.done = false | 99 | mc.done = false |
| 100 | } | 100 | } |
| 101 | |||
| 102 | // Clean model cache. Then you can re-RegisterModel. | ||
| 103 | // Common use this api for test case. | ||
| 104 | func ResetModelCache() { | ||
| 105 | modelCache.clean() | ||
| 106 | } | ... | ... |
| 1 | package orm | 1 | package orm |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "database/sql" | ||
| 4 | "encoding/json" | 5 | "encoding/json" |
| 5 | "fmt" | 6 | "fmt" |
| 6 | "os" | 7 | "os" |
| ... | @@ -116,27 +117,31 @@ type Data struct { | ... | @@ -116,27 +117,31 @@ type Data struct { |
| 116 | } | 117 | } |
| 117 | 118 | ||
| 118 | type DataNull struct { | 119 | type DataNull struct { |
| 119 | Id int | 120 | Id int |
| 120 | Boolean bool `orm:"null"` | 121 | Boolean bool `orm:"null"` |
| 121 | Char string `orm:"null;size(50)"` | 122 | Char string `orm:"null;size(50)"` |
| 122 | Text string `orm:"null;type(text)"` | 123 | Text string `orm:"null;type(text)"` |
| 123 | Date time.Time `orm:"null;type(date)"` | 124 | Date time.Time `orm:"null;type(date)"` |
| 124 | DateTime time.Time `orm:"null;column(datetime)""` | 125 | DateTime time.Time `orm:"null;column(datetime)""` |
| 125 | Byte byte `orm:"null"` | 126 | Byte byte `orm:"null"` |
| 126 | Rune rune `orm:"null"` | 127 | Rune rune `orm:"null"` |
| 127 | Int int `orm:"null"` | 128 | Int int `orm:"null"` |
| 128 | Int8 int8 `orm:"null"` | 129 | Int8 int8 `orm:"null"` |
| 129 | Int16 int16 `orm:"null"` | 130 | Int16 int16 `orm:"null"` |
| 130 | Int32 int32 `orm:"null"` | 131 | Int32 int32 `orm:"null"` |
| 131 | Int64 int64 `orm:"null"` | 132 | Int64 int64 `orm:"null"` |
| 132 | Uint uint `orm:"null"` | 133 | Uint uint `orm:"null"` |
| 133 | Uint8 uint8 `orm:"null"` | 134 | Uint8 uint8 `orm:"null"` |
| 134 | Uint16 uint16 `orm:"null"` | 135 | Uint16 uint16 `orm:"null"` |
| 135 | Uint32 uint32 `orm:"null"` | 136 | Uint32 uint32 `orm:"null"` |
| 136 | Uint64 uint64 `orm:"null"` | 137 | Uint64 uint64 `orm:"null"` |
| 137 | Float32 float32 `orm:"null"` | 138 | Float32 float32 `orm:"null"` |
| 138 | Float64 float64 `orm:"null"` | 139 | Float64 float64 `orm:"null"` |
| 139 | Decimal float64 `orm:"digits(8);decimals(4);null"` | 140 | Decimal float64 `orm:"digits(8);decimals(4);null"` |
| 141 | NullString sql.NullString `orm:"null"` | ||
| 142 | NullBool sql.NullBool `orm:"null"` | ||
| 143 | NullFloat64 sql.NullFloat64 `orm:"null"` | ||
| 144 | NullInt64 sql.NullInt64 `orm:"null"` | ||
| 140 | } | 145 | } |
| 141 | 146 | ||
| 142 | // only for mysql | 147 | // only for mysql |
| ... | @@ -303,9 +308,8 @@ go test -v github.com/astaxie/beego/orm | ... | @@ -303,9 +308,8 @@ go test -v github.com/astaxie/beego/orm |
| 303 | 308 | ||
| 304 | 309 | ||
| 305 | #### Sqlite3 | 310 | #### Sqlite3 |
| 306 | touch /path/to/orm_test.db | ||
| 307 | export ORM_DRIVER=sqlite3 | 311 | export ORM_DRIVER=sqlite3 |
| 308 | export ORM_SOURCE=/path/to/orm_test.db | 312 | export ORM_SOURCE='file:memory_test?mode=memory' |
| 309 | go test -v github.com/astaxie/beego/orm | 313 | go test -v github.com/astaxie/beego/orm |
| 310 | 314 | ||
| 311 | 315 | ... | ... |
| 1 | package orm | 1 | package orm |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "database/sql" | ||
| 4 | "fmt" | 5 | "fmt" |
| 5 | "reflect" | 6 | "reflect" |
| 6 | "strings" | 7 | "strings" |
| ... | @@ -98,30 +99,29 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col | ... | @@ -98,30 +99,29 @@ func getColumnName(ft int, addrField reflect.Value, sf reflect.StructField, col |
| 98 | // return field type as type constant from reflect.Value | 99 | // return field type as type constant from reflect.Value |
| 99 | func getFieldType(val reflect.Value) (ft int, err error) { | 100 | func getFieldType(val reflect.Value) (ft int, err error) { |
| 100 | elm := reflect.Indirect(val) | 101 | elm := reflect.Indirect(val) |
| 101 | switch elm.Kind() { | 102 | switch elm.Interface().(type) { |
| 102 | case reflect.Int8: | 103 | case int8: |
| 103 | ft = TypeBitField | 104 | ft = TypeBitField |
| 104 | case reflect.Int16: | 105 | case int16: |
| 105 | ft = TypeSmallIntegerField | 106 | ft = TypeSmallIntegerField |
| 106 | case reflect.Int32, reflect.Int: | 107 | case int32, int: |
| 107 | ft = TypeIntegerField | 108 | ft = TypeIntegerField |
| 108 | case reflect.Int64: | 109 | case int64, sql.NullInt64: |
| 109 | ft = TypeBigIntegerField | 110 | ft = TypeBigIntegerField |
| 110 | case reflect.Uint8: | 111 | case uint8: |
| 111 | ft = TypePositiveBitField | 112 | ft = TypePositiveBitField |
| 112 | case reflect.Uint16: | 113 | case uint16: |
| 113 | ft = TypePositiveSmallIntegerField | 114 | ft = TypePositiveSmallIntegerField |
| 114 | case reflect.Uint32, reflect.Uint: | 115 | case uint32, uint: |
| 115 | ft = TypePositiveIntegerField | 116 | ft = TypePositiveIntegerField |
| 116 | case reflect.Uint64: | 117 | case uint64: |
| 117 | ft = TypePositiveBigIntegerField | 118 | ft = TypePositiveBigIntegerField |
| 118 | case reflect.Float32, reflect.Float64: | 119 | case float32, float64, sql.NullFloat64: |
| 119 | ft = TypeFloatField | 120 | ft = TypeFloatField |
| 120 | case reflect.Bool: | 121 | case bool, sql.NullBool: |
| 121 | ft = TypeBooleanField | 122 | ft = TypeBooleanField |
| 122 | case reflect.String: | 123 | case string, sql.NullString: |
| 123 | ft = TypeCharField | 124 | ft = TypeCharField |
| 124 | case reflect.Invalid: | ||
| 125 | default: | 125 | default: |
| 126 | if elm.CanInterface() { | 126 | if elm.CanInterface() { |
| 127 | if _, ok := elm.Interface().(time.Time); ok { | 127 | if _, ok := elm.Interface().(time.Time); ok { | ... | ... |
| ... | @@ -2,6 +2,7 @@ package orm | ... | @@ -2,6 +2,7 @@ package orm |
| 2 | 2 | ||
| 3 | import ( | 3 | import ( |
| 4 | "bytes" | 4 | "bytes" |
| 5 | "database/sql" | ||
| 5 | "fmt" | 6 | "fmt" |
| 6 | "io/ioutil" | 7 | "io/ioutil" |
| 7 | "os" | 8 | "os" |
| ... | @@ -138,6 +139,15 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { | ... | @@ -138,6 +139,15 @@ func throwFailNow(t *testing.T, err error, args ...interface{}) { |
| 138 | } | 139 | } |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 142 | func TestGetDB(t *testing.T) { | ||
| 143 | if db, err := GetDB(); err != nil { | ||
| 144 | throwFailNow(t, err) | ||
| 145 | } else { | ||
| 146 | err = db.Ping() | ||
| 147 | throwFailNow(t, err) | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 141 | func TestSyncDb(t *testing.T) { | 151 | func TestSyncDb(t *testing.T) { |
| 142 | RegisterModel(new(Data), new(DataNull)) | 152 | RegisterModel(new(Data), new(DataNull)) |
| 143 | RegisterModel(new(User)) | 153 | RegisterModel(new(User)) |
| ... | @@ -258,12 +268,45 @@ func TestNullDataTypes(t *testing.T) { | ... | @@ -258,12 +268,45 @@ func TestNullDataTypes(t *testing.T) { |
| 258 | err = dORM.Read(&d) | 268 | err = dORM.Read(&d) |
| 259 | throwFail(t, err) | 269 | throwFail(t, err) |
| 260 | 270 | ||
| 271 | throwFail(t, AssertIs(d.NullBool.Valid, false)) | ||
| 272 | throwFail(t, AssertIs(d.NullString.Valid, false)) | ||
| 273 | throwFail(t, AssertIs(d.NullInt64.Valid, false)) | ||
| 274 | throwFail(t, AssertIs(d.NullFloat64.Valid, false)) | ||
| 275 | |||
| 261 | _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec() | 276 | _, err = dORM.Raw(`INSERT INTO data_null (boolean) VALUES (?)`, nil).Exec() |
| 262 | throwFail(t, err) | 277 | throwFail(t, err) |
| 263 | 278 | ||
| 264 | d = DataNull{Id: 2} | 279 | d = DataNull{Id: 2} |
| 265 | err = dORM.Read(&d) | 280 | err = dORM.Read(&d) |
| 266 | throwFail(t, err) | 281 | throwFail(t, err) |
| 282 | |||
| 283 | d = DataNull{ | ||
| 284 | DateTime: time.Now(), | ||
| 285 | NullString: sql.NullString{"test", true}, | ||
| 286 | NullBool: sql.NullBool{true, true}, | ||
| 287 | NullInt64: sql.NullInt64{42, true}, | ||
| 288 | NullFloat64: sql.NullFloat64{42.42, true}, | ||
| 289 | } | ||
| 290 | |||
| 291 | id, err = dORM.Insert(&d) | ||
| 292 | throwFail(t, err) | ||
| 293 | throwFail(t, AssertIs(id, 3)) | ||
| 294 | |||
| 295 | d = DataNull{Id: 3} | ||
| 296 | err = dORM.Read(&d) | ||
| 297 | throwFail(t, err) | ||
| 298 | |||
| 299 | throwFail(t, AssertIs(d.NullBool.Valid, true)) | ||
| 300 | throwFail(t, AssertIs(d.NullBool.Bool, true)) | ||
| 301 | |||
| 302 | throwFail(t, AssertIs(d.NullString.Valid, true)) | ||
| 303 | throwFail(t, AssertIs(d.NullString.String, "test")) | ||
| 304 | |||
| 305 | throwFail(t, AssertIs(d.NullInt64.Valid, true)) | ||
| 306 | throwFail(t, AssertIs(d.NullInt64.Int64, 42)) | ||
| 307 | |||
| 308 | throwFail(t, AssertIs(d.NullFloat64.Valid, true)) | ||
| 309 | throwFail(t, AssertIs(d.NullFloat64.Float64, 42.42)) | ||
| 267 | } | 310 | } |
| 268 | 311 | ||
| 269 | func TestCRUD(t *testing.T) { | 312 | func TestCRUD(t *testing.T) { |
| ... | @@ -619,6 +662,14 @@ func TestOperators(t *testing.T) { | ... | @@ -619,6 +662,14 @@ func TestOperators(t *testing.T) { |
| 619 | num, err = qs.Filter("status__in", []*int{&n1}, &n2).Count() | 662 | num, err = qs.Filter("status__in", []*int{&n1}, &n2).Count() |
| 620 | throwFail(t, err) | 663 | throwFail(t, err) |
| 621 | throwFail(t, AssertIs(num, 2)) | 664 | throwFail(t, AssertIs(num, 2)) |
| 665 | |||
| 666 | num, err = qs.Filter("id__between", 2, 3).Count() | ||
| 667 | throwFail(t, err) | ||
| 668 | throwFail(t, AssertIs(num, 2)) | ||
| 669 | |||
| 670 | num, err = qs.Filter("id__between", []int{2, 3}).Count() | ||
| 671 | throwFail(t, err) | ||
| 672 | throwFail(t, AssertIs(num, 2)) | ||
| 622 | } | 673 | } |
| 623 | 674 | ||
| 624 | func TestSetCond(t *testing.T) { | 675 | func TestSetCond(t *testing.T) { |
| ... | @@ -1577,7 +1628,6 @@ func TestDelete(t *testing.T) { | ... | @@ -1577,7 +1628,6 @@ func TestDelete(t *testing.T) { |
| 1577 | throwFail(t, err) | 1628 | throwFail(t, err) |
| 1578 | throwFail(t, AssertIs(num, 4)) | 1629 | throwFail(t, AssertIs(num, 4)) |
| 1579 | 1630 | ||
| 1580 | fmt.Println("...") | ||
| 1581 | qs = dORM.QueryTable("comment") | 1631 | qs = dORM.QueryTable("comment") |
| 1582 | num, err = qs.Filter("Post__User", 3).Delete() | 1632 | num, err = qs.Filter("Post__User", 3).Delete() |
| 1583 | throwFail(t, err) | 1633 | throwFail(t, err) |
| ... | @@ -1646,10 +1696,10 @@ func TestTransaction(t *testing.T) { | ... | @@ -1646,10 +1696,10 @@ func TestTransaction(t *testing.T) { |
| 1646 | func TestReadOrCreate(t *testing.T) { | 1696 | func TestReadOrCreate(t *testing.T) { |
| 1647 | u := &User{ | 1697 | u := &User{ |
| 1648 | UserName: "Kyle", | 1698 | UserName: "Kyle", |
| 1649 | Email: "kylemcc@gmail.com", | 1699 | Email: "kylemcc@gmail.com", |
| 1650 | Password: "other_pass", | 1700 | Password: "other_pass", |
| 1651 | Status: 7, | 1701 | Status: 7, |
| 1652 | IsStaff: false, | 1702 | IsStaff: false, |
| 1653 | IsActive: true, | 1703 | IsActive: true, |
| 1654 | } | 1704 | } |
| 1655 | 1705 | ... | ... |
| ... | @@ -8,7 +8,7 @@ package auth | ... | @@ -8,7 +8,7 @@ package auth |
| 8 | // } | 8 | // } |
| 9 | // return false | 9 | // return false |
| 10 | // } | 10 | // } |
| 11 | // authPlugin := auth.NewBasicAuthenticator(SecretAuth) | 11 | // authPlugin := auth.NewBasicAuthenticator(SecretAuth, "My Realm") |
| 12 | // beego.AddFilter("*","AfterStatic",authPlugin) | 12 | // beego.AddFilter("*","AfterStatic",authPlugin) |
| 13 | 13 | ||
| 14 | import ( | 14 | import ( | ... | ... |
| ... | @@ -8,6 +8,7 @@ import ( | ... | @@ -8,6 +8,7 @@ import ( |
| 8 | "net/http" | 8 | "net/http" |
| 9 | "net/url" | 9 | "net/url" |
| 10 | "os" | 10 | "os" |
| 11 | "path" | ||
| 11 | "reflect" | 12 | "reflect" |
| 12 | "regexp" | 13 | "regexp" |
| 13 | "runtime" | 14 | "runtime" |
| ... | @@ -545,14 +546,26 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) | ... | @@ -545,14 +546,26 @@ func (p *ControllerRegistor) ServeHTTP(rw http.ResponseWriter, r *http.Request) |
| 545 | 546 | ||
| 546 | //static file server | 547 | //static file server |
| 547 | for prefix, staticDir := range StaticDir { | 548 | for prefix, staticDir := range StaticDir { |
| 549 | if len(prefix) == 0 { | ||
| 550 | continue | ||
| 551 | } | ||
| 548 | if r.URL.Path == "/favicon.ico" { | 552 | if r.URL.Path == "/favicon.ico" { |
| 549 | file := staticDir + r.URL.Path | 553 | file := path.Join(staticDir, r.URL.Path) |
| 550 | http.ServeFile(w, r, file) | 554 | if utils.FileExists(file) { |
| 551 | w.started = true | 555 | http.ServeFile(w, r, file) |
| 552 | goto Admin | 556 | w.started = true |
| 557 | goto Admin | ||
| 558 | } | ||
| 553 | } | 559 | } |
| 554 | if strings.HasPrefix(r.URL.Path, prefix) { | 560 | if strings.HasPrefix(r.URL.Path, prefix) { |
| 555 | file := staticDir + r.URL.Path[len(prefix):] | 561 | if len(r.URL.Path) > len(prefix) && r.URL.Path[len(prefix)] != '/' { |
| 562 | continue | ||
| 563 | } | ||
| 564 | if r.URL.Path == prefix && prefix[len(prefix)-1] != '/' { | ||
| 565 | http.Redirect(rw, r, r.URL.Path+"/", 302) | ||
| 566 | goto Admin | ||
| 567 | } | ||
| 568 | file := path.Join(staticDir, r.URL.Path[len(prefix):]) | ||
| 556 | finfo, err := os.Stat(file) | 569 | finfo, err := os.Stat(file) |
| 557 | if err != nil { | 570 | if err != nil { |
| 558 | if RunMode == "dev" { | 571 | if RunMode == "dev" { | ... | ... |
session/sess_couchbase.go
0 → 100644
| 1 | package session | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "github.com/couchbaselabs/go-couchbase" | ||
| 5 | "net/http" | ||
| 6 | "strings" | ||
| 7 | "sync" | ||
| 8 | ) | ||
| 9 | |||
| 10 | var couchbpder = &CouchbaseProvider{} | ||
| 11 | |||
| 12 | type CouchbaseSessionStore struct { | ||
| 13 | b *couchbase.Bucket | ||
| 14 | sid string | ||
| 15 | lock sync.RWMutex | ||
| 16 | values map[interface{}]interface{} | ||
| 17 | maxlifetime int64 | ||
| 18 | } | ||
| 19 | |||
| 20 | type CouchbaseProvider struct { | ||
| 21 | maxlifetime int64 | ||
| 22 | savePath string | ||
| 23 | pool string | ||
| 24 | bucket string | ||
| 25 | b *couchbase.Bucket | ||
| 26 | } | ||
| 27 | |||
| 28 | func (cs *CouchbaseSessionStore) Set(key, value interface{}) error { | ||
| 29 | cs.lock.Lock() | ||
| 30 | defer cs.lock.Unlock() | ||
| 31 | cs.values[key] = value | ||
| 32 | return nil | ||
| 33 | } | ||
| 34 | |||
| 35 | func (cs *CouchbaseSessionStore) Get(key interface{}) interface{} { | ||
| 36 | cs.lock.RLock() | ||
| 37 | defer cs.lock.RUnlock() | ||
| 38 | if v, ok := cs.values[key]; ok { | ||
| 39 | return v | ||
| 40 | } else { | ||
| 41 | return nil | ||
| 42 | } | ||
| 43 | return nil | ||
| 44 | } | ||
| 45 | |||
| 46 | func (cs *CouchbaseSessionStore) Delete(key interface{}) error { | ||
| 47 | cs.lock.Lock() | ||
| 48 | defer cs.lock.Unlock() | ||
| 49 | delete(cs.values, key) | ||
| 50 | return nil | ||
| 51 | } | ||
| 52 | |||
| 53 | func (cs *CouchbaseSessionStore) Flush() error { | ||
| 54 | cs.lock.Lock() | ||
| 55 | defer cs.lock.Unlock() | ||
| 56 | cs.values = make(map[interface{}]interface{}) | ||
| 57 | return nil | ||
| 58 | } | ||
| 59 | |||
| 60 | func (cs *CouchbaseSessionStore) SessionID() string { | ||
| 61 | return cs.sid | ||
| 62 | } | ||
| 63 | |||
| 64 | func (cs *CouchbaseSessionStore) SessionRelease(w http.ResponseWriter) { | ||
| 65 | defer cs.b.Close() | ||
| 66 | |||
| 67 | // if rs.values is empty, return directly | ||
| 68 | if len(cs.values) < 1 { | ||
| 69 | cs.b.Delete(cs.sid) | ||
| 70 | return | ||
| 71 | } | ||
| 72 | |||
| 73 | bo, err := encodeGob(cs.values) | ||
| 74 | if err != nil { | ||
| 75 | return | ||
| 76 | } | ||
| 77 | |||
| 78 | cs.b.Set(cs.sid, int(cs.maxlifetime), bo) | ||
| 79 | } | ||
| 80 | |||
| 81 | func (cp *CouchbaseProvider) getBucket() *couchbase.Bucket { | ||
| 82 | c, err := couchbase.Connect(cp.savePath) | ||
| 83 | if err != nil { | ||
| 84 | return nil | ||
| 85 | } | ||
| 86 | |||
| 87 | pool, err := c.GetPool(cp.pool) | ||
| 88 | if err != nil { | ||
| 89 | return nil | ||
| 90 | } | ||
| 91 | |||
| 92 | bucket, err := pool.GetBucket(cp.bucket) | ||
| 93 | if err != nil { | ||
| 94 | return nil | ||
| 95 | } | ||
| 96 | |||
| 97 | return bucket | ||
| 98 | } | ||
| 99 | |||
| 100 | // init couchbase session | ||
| 101 | // savepath like couchbase server REST/JSON URL | ||
| 102 | // e.g. http://host:port/, Pool, Bucket | ||
| 103 | func (cp *CouchbaseProvider) SessionInit(maxlifetime int64, savePath string) error { | ||
| 104 | cp.maxlifetime = maxlifetime | ||
| 105 | configs := strings.Split(savePath, ",") | ||
| 106 | if len(configs) > 0 { | ||
| 107 | cp.savePath = configs[0] | ||
| 108 | } | ||
| 109 | if len(configs) > 1 { | ||
| 110 | cp.pool = configs[1] | ||
| 111 | } | ||
| 112 | if len(configs) > 2 { | ||
| 113 | cp.bucket = configs[2] | ||
| 114 | } | ||
| 115 | |||
| 116 | return nil | ||
| 117 | } | ||
| 118 | |||
| 119 | // read couchbase session by sid | ||
| 120 | func (cp *CouchbaseProvider) SessionRead(sid string) (SessionStore, error) { | ||
| 121 | cp.b = cp.getBucket() | ||
| 122 | |||
| 123 | var doc []byte | ||
| 124 | |||
| 125 | err := cp.b.Get(sid, &doc) | ||
| 126 | var kv map[interface{}]interface{} | ||
| 127 | if doc == nil { | ||
| 128 | kv = make(map[interface{}]interface{}) | ||
| 129 | } else { | ||
| 130 | kv, err = decodeGob(doc) | ||
| 131 | if err != nil { | ||
| 132 | return nil, err | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | cs := &CouchbaseSessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime} | ||
| 137 | return cs, nil | ||
| 138 | } | ||
| 139 | |||
| 140 | func (cp *CouchbaseProvider) SessionExist(sid string) bool { | ||
| 141 | cp.b = cp.getBucket() | ||
| 142 | defer cp.b.Close() | ||
| 143 | |||
| 144 | var doc []byte | ||
| 145 | |||
| 146 | if err := cp.b.Get(sid, &doc); err != nil || doc == nil { | ||
| 147 | return false | ||
| 148 | } else { | ||
| 149 | return true | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | func (cp *CouchbaseProvider) SessionRegenerate(oldsid, sid string) (SessionStore, error) { | ||
| 154 | cp.b = cp.getBucket() | ||
| 155 | |||
| 156 | var doc []byte | ||
| 157 | if err := cp.b.Get(oldsid, &doc); err != nil || doc == nil { | ||
| 158 | cp.b.Set(sid, int(cp.maxlifetime), "") | ||
| 159 | } else { | ||
| 160 | err := cp.b.Delete(oldsid) | ||
| 161 | if err != nil { | ||
| 162 | return nil, err | ||
| 163 | } | ||
| 164 | _, _ = cp.b.Add(sid, int(cp.maxlifetime), doc) | ||
| 165 | } | ||
| 166 | |||
| 167 | err := cp.b.Get(sid, &doc) | ||
| 168 | if err != nil { | ||
| 169 | return nil, err | ||
| 170 | } | ||
| 171 | var kv map[interface{}]interface{} | ||
| 172 | if doc == nil { | ||
| 173 | kv = make(map[interface{}]interface{}) | ||
| 174 | } else { | ||
| 175 | kv, err = decodeGob(doc) | ||
| 176 | if err != nil { | ||
| 177 | return nil, err | ||
| 178 | } | ||
| 179 | } | ||
| 180 | |||
| 181 | cs := &CouchbaseSessionStore{b: cp.b, sid: sid, values: kv, maxlifetime: cp.maxlifetime} | ||
| 182 | return cs, nil | ||
| 183 | } | ||
| 184 | |||
| 185 | func (cp *CouchbaseProvider) SessionDestroy(sid string) error { | ||
| 186 | cp.b = cp.getBucket() | ||
| 187 | defer cp.b.Close() | ||
| 188 | |||
| 189 | cp.b.Delete(sid) | ||
| 190 | return nil | ||
| 191 | } | ||
| 192 | |||
| 193 | func (cp *CouchbaseProvider) SessionGC() { | ||
| 194 | return | ||
| 195 | } | ||
| 196 | |||
| 197 | func (cp *CouchbaseProvider) SessionAll() int { | ||
| 198 | return 0 | ||
| 199 | } | ||
| 200 | |||
| 201 | func init() { | ||
| 202 | Register("couchbase", couchbpder) | ||
| 203 | } |
| ... | @@ -152,8 +152,7 @@ func (fp *FileProvider) SessionExist(sid string) bool { | ... | @@ -152,8 +152,7 @@ func (fp *FileProvider) SessionExist(sid string) bool { |
| 152 | func (fp *FileProvider) SessionDestroy(sid string) error { | 152 | func (fp *FileProvider) SessionDestroy(sid string) error { |
| 153 | filepder.lock.Lock() | 153 | filepder.lock.Lock() |
| 154 | defer filepder.lock.Unlock() | 154 | defer filepder.lock.Unlock() |
| 155 | 155 | os.Remove(path.Join(fp.savePath, string(sid[0]), string(sid[1]), sid)) | |
| 156 | os.Remove(path.Join(fp.savePath)) | ||
| 157 | return nil | 156 | return nil |
| 158 | } | 157 | } |
| 159 | 158 | ... | ... |
| ... | @@ -129,7 +129,8 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { | ... | @@ -129,7 +129,8 @@ func (rp *RedisProvider) SessionInit(maxlifetime int64, savePath string) error { |
| 129 | } | 129 | } |
| 130 | return c, err | 130 | return c, err |
| 131 | }, rp.poolsize) | 131 | }, rp.poolsize) |
| 132 | return nil | 132 | |
| 133 | return rp.poollist.Get().Err() | ||
| 133 | } | 134 | } |
| 134 | 135 | ||
| 135 | // read redis session by sid | 136 | // read redis session by sid | ... | ... |
| ... | @@ -56,11 +56,10 @@ type managerConfig struct { | ... | @@ -56,11 +56,10 @@ type managerConfig struct { |
| 56 | EnableSetCookie bool `json:"enableSetCookie,omitempty"` | 56 | EnableSetCookie bool `json:"enableSetCookie,omitempty"` |
| 57 | Gclifetime int64 `json:"gclifetime"` | 57 | Gclifetime int64 `json:"gclifetime"` |
| 58 | Maxlifetime int64 `json:"maxLifetime"` | 58 | Maxlifetime int64 `json:"maxLifetime"` |
| 59 | Maxage int `json:"maxage"` | ||
| 60 | Secure bool `json:"secure"` | 59 | Secure bool `json:"secure"` |
| 61 | SessionIDHashFunc string `json:"sessionIDHashFunc"` | 60 | SessionIDHashFunc string `json:"sessionIDHashFunc"` |
| 62 | SessionIDHashKey string `json:"sessionIDHashKey"` | 61 | SessionIDHashKey string `json:"sessionIDHashKey"` |
| 63 | CookieLifeTime int64 `json:"cookieLifeTime"` | 62 | CookieLifeTime int `json:"cookieLifeTime"` |
| 64 | ProviderConfig string `json:"providerConfig"` | 63 | ProviderConfig string `json:"providerConfig"` |
| 65 | } | 64 | } |
| 66 | 65 | ||
| ... | @@ -125,8 +124,8 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se | ... | @@ -125,8 +124,8 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se |
| 125 | Path: "/", | 124 | Path: "/", |
| 126 | HttpOnly: true, | 125 | HttpOnly: true, |
| 127 | Secure: manager.config.Secure} | 126 | Secure: manager.config.Secure} |
| 128 | if manager.config.Maxage >= 0 { | 127 | if manager.config.CookieLifeTime >= 0 { |
| 129 | cookie.MaxAge = manager.config.Maxage | 128 | cookie.MaxAge = manager.config.CookieLifeTime |
| 130 | } | 129 | } |
| 131 | if manager.config.EnableSetCookie { | 130 | if manager.config.EnableSetCookie { |
| 132 | http.SetCookie(w, cookie) | 131 | http.SetCookie(w, cookie) |
| ... | @@ -144,8 +143,8 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se | ... | @@ -144,8 +143,8 @@ func (manager *Manager) SessionStart(w http.ResponseWriter, r *http.Request) (se |
| 144 | Path: "/", | 143 | Path: "/", |
| 145 | HttpOnly: true, | 144 | HttpOnly: true, |
| 146 | Secure: manager.config.Secure} | 145 | Secure: manager.config.Secure} |
| 147 | if manager.config.Maxage >= 0 { | 146 | if manager.config.CookieLifeTime >= 0 { |
| 148 | cookie.MaxAge = manager.config.Maxage | 147 | cookie.MaxAge = manager.config.CookieLifeTime |
| 149 | } | 148 | } |
| 150 | if manager.config.EnableSetCookie { | 149 | if manager.config.EnableSetCookie { |
| 151 | http.SetCookie(w, cookie) | 150 | http.SetCookie(w, cookie) |
| ... | @@ -206,8 +205,8 @@ func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Reque | ... | @@ -206,8 +205,8 @@ func (manager *Manager) SessionRegenerateId(w http.ResponseWriter, r *http.Reque |
| 206 | cookie.HttpOnly = true | 205 | cookie.HttpOnly = true |
| 207 | cookie.Path = "/" | 206 | cookie.Path = "/" |
| 208 | } | 207 | } |
| 209 | if manager.config.Maxage >= 0 { | 208 | if manager.config.CookieLifeTime >= 0 { |
| 210 | cookie.MaxAge = manager.config.Maxage | 209 | cookie.MaxAge = manager.config.CookieLifeTime |
| 211 | } | 210 | } |
| 212 | http.SetCookie(w, cookie) | 211 | http.SetCookie(w, cookie) |
| 213 | r.AddCookie(cookie) | 212 | r.AddCookie(cookie) | ... | ... |
| ... | @@ -67,7 +67,7 @@ const ( | ... | @@ -67,7 +67,7 @@ const ( |
| 67 | fieldIdName = "captcha_id" | 67 | fieldIdName = "captcha_id" |
| 68 | fieldCaptchaName = "captcha" | 68 | fieldCaptchaName = "captcha" |
| 69 | cachePrefix = "captcha_" | 69 | cachePrefix = "captcha_" |
| 70 | urlPrefix = "/captcha/" | 70 | defaultURLPrefix = "/captcha/" |
| 71 | ) | 71 | ) |
| 72 | 72 | ||
| 73 | // Captcha struct | 73 | // Captcha struct |
| ... | @@ -76,7 +76,7 @@ type Captcha struct { | ... | @@ -76,7 +76,7 @@ type Captcha struct { |
| 76 | store cache.Cache | 76 | store cache.Cache |
| 77 | 77 | ||
| 78 | // url prefix for captcha image | 78 | // url prefix for captcha image |
| 79 | urlPrefix string | 79 | URLPrefix string |
| 80 | 80 | ||
| 81 | // specify captcha id input field name | 81 | // specify captcha id input field name |
| 82 | FieldIdName string | 82 | FieldIdName string |
| ... | @@ -155,7 +155,7 @@ func (c *Captcha) CreateCaptchaHtml() template.HTML { | ... | @@ -155,7 +155,7 @@ func (c *Captcha) CreateCaptchaHtml() template.HTML { |
| 155 | return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`+ | 155 | return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`+ |
| 156 | `<a class="captcha" href="javascript:">`+ | 156 | `<a class="captcha" href="javascript:">`+ |
| 157 | `<img onclick="this.src=('%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s.png">`+ | 157 | `<img onclick="this.src=('%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s.png">`+ |
| 158 | `</a>`, c.FieldIdName, value, c.urlPrefix, value, c.urlPrefix, value)) | 158 | `</a>`, c.FieldIdName, value, c.URLPrefix, value, c.URLPrefix, value)) |
| 159 | } | 159 | } |
| 160 | 160 | ||
| 161 | // create a new captcha id | 161 | // create a new captcha id |
| ... | @@ -224,14 +224,14 @@ func NewCaptcha(urlPrefix string, store cache.Cache) *Captcha { | ... | @@ -224,14 +224,14 @@ func NewCaptcha(urlPrefix string, store cache.Cache) *Captcha { |
| 224 | cpt.StdHeight = stdHeight | 224 | cpt.StdHeight = stdHeight |
| 225 | 225 | ||
| 226 | if len(urlPrefix) == 0 { | 226 | if len(urlPrefix) == 0 { |
| 227 | urlPrefix = urlPrefix | 227 | urlPrefix = defaultURLPrefix |
| 228 | } | 228 | } |
| 229 | 229 | ||
| 230 | if urlPrefix[len(urlPrefix)-1] != '/' { | 230 | if urlPrefix[len(urlPrefix)-1] != '/' { |
| 231 | urlPrefix += "/" | 231 | urlPrefix += "/" |
| 232 | } | 232 | } |
| 233 | 233 | ||
| 234 | cpt.urlPrefix = urlPrefix | 234 | cpt.URLPrefix = urlPrefix |
| 235 | 235 | ||
| 236 | return cpt | 236 | return cpt |
| 237 | } | 237 | } |
| ... | @@ -242,7 +242,7 @@ func NewWithFilter(urlPrefix string, store cache.Cache) *Captcha { | ... | @@ -242,7 +242,7 @@ func NewWithFilter(urlPrefix string, store cache.Cache) *Captcha { |
| 242 | cpt := NewCaptcha(urlPrefix, store) | 242 | cpt := NewCaptcha(urlPrefix, store) |
| 243 | 243 | ||
| 244 | // create filter for serve captcha image | 244 | // create filter for serve captcha image |
| 245 | beego.AddFilter(urlPrefix+":", "BeforeRouter", cpt.Handler) | 245 | beego.AddFilter(cpt.URLPrefix+":", "BeforeRouter", cpt.Handler) |
| 246 | 246 | ||
| 247 | // add to template func map | 247 | // add to template func map |
| 248 | beego.AddFuncMap("create_captcha", cpt.CreateCaptchaHtml) | 248 | beego.AddFuncMap("create_captcha", cpt.CreateCaptchaHtml) | ... | ... |
| ... | @@ -443,7 +443,7 @@ func (b Base64) GetLimitValue() interface{} { | ... | @@ -443,7 +443,7 @@ func (b Base64) GetLimitValue() interface{} { |
| 443 | } | 443 | } |
| 444 | 444 | ||
| 445 | // just for chinese mobile phone number | 445 | // just for chinese mobile phone number |
| 446 | var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|(47)|[8][01236789]))\\d{8}$") | 446 | var mobilePattern = regexp.MustCompile("^((\\+86)|(86))?(1(([35][0-9])|(47)|[8][012356789]))\\d{8}$") |
| 447 | 447 | ||
| 448 | type Mobile struct { | 448 | type Mobile struct { |
| 449 | Match | 449 | Match | ... | ... |
-
Please register or sign in to post a comment