Skip to content

Commit cab8458

Browse files
authored
Merge pull request beego#2651 from astaxie/develop
v1.8.3
2 parents 83814a7 + f0b95c5 commit cab8458

30 files changed

+1065
-116
lines changed

.travis.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ install:
3333
- go get github.com/ssdb/gossdb/ssdb
3434
- go get github.com/cloudflare/golz4
3535
- go get github.com/gogo/protobuf/proto
36+
- go get github.com/Knetic/govaluate
37+
- go get github.com/hsluoyz/casbin
3638
- go get -u honnef.co/go/tools/cmd/gosimple
3739
- go get -u github.com/mdempsky/unconvert
3840
- go get -u github.com/gordonklaus/ineffassign

beego.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323

2424
const (
2525
// VERSION represent beego web framework version.
26-
VERSION = "1.8.2"
26+
VERSION = "1.8.3"
2727

2828
// DEV is for develop
2929
DEV = "dev"

cache/conv.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func GetString(v interface{}) string {
2828
return string(result)
2929
default:
3030
if v != nil {
31-
return fmt.Sprintf("%v", result)
31+
return fmt.Sprint(result)
3232
}
3333
}
3434
return ""

context/context.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,22 @@ func (ctx *Context) CheckXSRFCookie() bool {
171171
return true
172172
}
173173

174+
// RenderMethodResult renders the return value of a controller method to the output
175+
func (ctx *Context) RenderMethodResult(result interface{}) {
176+
if result != nil {
177+
renderer, ok := result.(Renderer)
178+
if !ok {
179+
err, ok := result.(error)
180+
if ok {
181+
renderer = errorRenderer(err)
182+
} else {
183+
renderer = jsonRenderer(result)
184+
}
185+
}
186+
renderer.Render(ctx)
187+
}
188+
}
189+
174190
//Response is a wrapper for the http.ResponseWriter
175191
//started set to true if response was written to then don't execute other handler
176192
type Response struct {

context/output.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,19 @@ func sanitizeValue(v string) string {
168168
return cookieValueSanitizer.Replace(v)
169169
}
170170

171+
func jsonRenderer(value interface{}) Renderer {
172+
return rendererFunc(func(ctx *Context) {
173+
ctx.Output.JSON(value, false, false)
174+
})
175+
}
176+
177+
func errorRenderer(err error) Renderer {
178+
return rendererFunc(func(ctx *Context) {
179+
ctx.Output.SetStatus(500)
180+
ctx.WriteString(err.Error())
181+
})
182+
}
183+
171184
// JSON writes json to response body.
172185
// if coding is true, it converts utf-8 to \u0000 type.
173186
func (output *BeegoOutput) JSON(data interface{}, hasIndent bool, coding bool) error {
@@ -330,9 +343,8 @@ func (output *BeegoOutput) IsServerError() bool {
330343
}
331344

332345
func stringsToJSON(str string) string {
333-
rs := []rune(str)
334346
var jsons bytes.Buffer
335-
for _, r := range rs {
347+
for _, r := range str {
336348
rint := int(r)
337349
if rint < 128 {
338350
jsons.WriteRune(r)

context/param/conv.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package param
2+
3+
import (
4+
"fmt"
5+
"reflect"
6+
7+
beecontext "github.com/astaxie/beego/context"
8+
"github.com/astaxie/beego/logs"
9+
)
10+
11+
// ConvertParams converts http method params to values that will be passed to the method controller as arguments
12+
func ConvertParams(methodParams []*MethodParam, methodType reflect.Type, ctx *beecontext.Context) (result []reflect.Value) {
13+
result = make([]reflect.Value, 0, len(methodParams))
14+
for i := 0; i < len(methodParams); i++ {
15+
reflectValue := convertParam(methodParams[i], methodType.In(i), ctx)
16+
result = append(result, reflectValue)
17+
}
18+
return
19+
}
20+
21+
func convertParam(param *MethodParam, paramType reflect.Type, ctx *beecontext.Context) (result reflect.Value) {
22+
paramValue := getParamValue(param, ctx)
23+
if paramValue == "" {
24+
if param.required {
25+
ctx.Abort(400, fmt.Sprintf("Missing parameter %s", param.name))
26+
} else {
27+
paramValue = param.defaultValue
28+
}
29+
}
30+
31+
reflectValue, err := parseValue(param, paramValue, paramType)
32+
if err != nil {
33+
logs.Debug(fmt.Sprintf("Error converting param %s to type %s. Value: %v, Error: %s", param.name, paramType, paramValue, err))
34+
ctx.Abort(400, fmt.Sprintf("Invalid parameter %s. Can not convert %v to type %s", param.name, paramValue, paramType))
35+
}
36+
37+
return reflectValue
38+
}
39+
40+
func getParamValue(param *MethodParam, ctx *beecontext.Context) string {
41+
switch param.in {
42+
case body:
43+
return string(ctx.Input.RequestBody)
44+
case header:
45+
return ctx.Input.Header(param.name)
46+
case path:
47+
return ctx.Input.Query(":" + param.name)
48+
default:
49+
return ctx.Input.Query(param.name)
50+
}
51+
}
52+
53+
func parseValue(param *MethodParam, paramValue string, paramType reflect.Type) (result reflect.Value, err error) {
54+
if paramValue == "" {
55+
return reflect.Zero(paramType), nil
56+
}
57+
parser := getParser(param, paramType)
58+
value, err := parser.parse(paramValue, paramType)
59+
if err != nil {
60+
return result, err
61+
}
62+
63+
return safeConvert(reflect.ValueOf(value), paramType)
64+
}
65+
66+
func safeConvert(value reflect.Value, t reflect.Type) (result reflect.Value, err error) {
67+
defer func() {
68+
if r := recover(); r != nil {
69+
var ok bool
70+
err, ok = r.(error)
71+
if !ok {
72+
err = fmt.Errorf("%v", r)
73+
}
74+
}
75+
}()
76+
result = value.Convert(t)
77+
return
78+
}

context/param/methodparams.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package param
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
//MethodParam keeps param information to be auto passed to controller methods
9+
type MethodParam struct {
10+
name string
11+
in paramType
12+
required bool
13+
defaultValue string
14+
}
15+
16+
type paramType byte
17+
18+
const (
19+
param paramType = iota
20+
path
21+
body
22+
header
23+
)
24+
25+
//New creates a new MethodParam with name and specific options
26+
func New(name string, opts ...MethodParamOption) *MethodParam {
27+
return newParam(name, nil, opts)
28+
}
29+
30+
func newParam(name string, parser paramParser, opts []MethodParamOption) (param *MethodParam) {
31+
param = &MethodParam{name: name}
32+
for _, option := range opts {
33+
option(param)
34+
}
35+
return
36+
}
37+
38+
//Make creates an array of MethodParmas or an empty array
39+
func Make(list ...*MethodParam) []*MethodParam {
40+
if len(list) > 0 {
41+
return list
42+
}
43+
return nil
44+
}
45+
46+
func (mp *MethodParam) String() string {
47+
options := []string{}
48+
result := "param.New(\"" + mp.name + "\""
49+
if mp.required {
50+
options = append(options, "param.IsRequired")
51+
}
52+
switch mp.in {
53+
case path:
54+
options = append(options, "param.InPath")
55+
case body:
56+
options = append(options, "param.InBody")
57+
case header:
58+
options = append(options, "param.InHeader")
59+
}
60+
if mp.defaultValue != "" {
61+
options = append(options, fmt.Sprintf(`param.Default("%s")`, mp.defaultValue))
62+
}
63+
if len(options) > 0 {
64+
result += ", "
65+
}
66+
result += strings.Join(options, ", ")
67+
result += ")"
68+
return result
69+
}

context/param/options.go

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package param
2+
3+
import (
4+
"fmt"
5+
)
6+
7+
// MethodParamOption defines a func which apply options on a MethodParam
8+
type MethodParamOption func(*MethodParam)
9+
10+
// IsRequired indicates that this param is required and can not be ommited from the http request
11+
var IsRequired MethodParamOption = func(p *MethodParam) {
12+
p.required = true
13+
}
14+
15+
// InHeader indicates that this param is passed via an http header
16+
var InHeader MethodParamOption = func(p *MethodParam) {
17+
p.in = header
18+
}
19+
20+
// InPath indicates that this param is part of the URL path
21+
var InPath MethodParamOption = func(p *MethodParam) {
22+
p.in = path
23+
}
24+
25+
// InBody indicates that this param is passed as an http request body
26+
var InBody MethodParamOption = func(p *MethodParam) {
27+
p.in = body
28+
}
29+
30+
// Default provides a default value for the http param
31+
func Default(defaultValue interface{}) MethodParamOption {
32+
return func(p *MethodParam) {
33+
if defaultValue != nil {
34+
p.defaultValue = fmt.Sprint(defaultValue)
35+
}
36+
}
37+
}

0 commit comments

Comments
 (0)