Merge branch 'filter-sort' of https://gitclone.com/github.com/flycash/beego into session-filter
This commit is contained in:
commit
4491894c00
32
.github/workflows/golangci-lint.yml
vendored
Normal file
32
.github/workflows/golangci-lint.yml
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
name: golangci-lint
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- v*
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
pull_request:
|
||||
jobs:
|
||||
golangci:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v2
|
||||
with:
|
||||
# Required: the version of golangci-lint is required and must be specified without patch version: we always use the latest patch version.
|
||||
version: v1.29
|
||||
|
||||
# Optional: working directory, useful for monorepos
|
||||
# working-directory: ./
|
||||
|
||||
# Optional: golangci-lint command line arguments.
|
||||
args: --timeout=5m --print-issued-lines=true --print-linter-name=true --uniq-by-line=true
|
||||
|
||||
# Optional: show only new issues if it's a pull request. The default value is `false`.
|
||||
only-new-issues: true
|
||||
|
||||
# Optional: if set to true then the action will use pre-installed Go
|
||||
# skip-go-installation: true
|
||||
@ -74,7 +74,7 @@ func oldMiddlewareToNew(mws []MiddleWare) []web.MiddleWare {
|
||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *App {
|
||||
return (*App)(web.Router(rootpath, c, web.SetRouterMethods(c, mappingMethods...)))
|
||||
return (*App)(web.Router(rootpath, c, mappingMethods...))
|
||||
}
|
||||
|
||||
// UnregisterFixedRoute unregisters the route with the specified fixedRoute. It is particularly useful
|
||||
|
||||
@ -87,7 +87,7 @@ func NewControllerRegister() *ControllerRegister {
|
||||
// Add("/api",&RestController{},"get,post:ApiFunc"
|
||||
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, mappingMethods ...string) {
|
||||
(*web.ControllerRegister)(p).Add(pattern, c, web.SetRouterMethods(c, mappingMethods...))
|
||||
(*web.ControllerRegister)(p).Add(pattern, c, web.WithRouterMethods(c, mappingMethods...))
|
||||
}
|
||||
|
||||
// Include only when the Runmode is dev will generate router file in the router/auto.go from the controller
|
||||
|
||||
@ -301,6 +301,28 @@ func TestAddFilter(t *testing.T) {
|
||||
assert.Equal(t, 1, len(req.setting.FilterChains)-len(r.setting.FilterChains))
|
||||
}
|
||||
|
||||
func TestFilterChainOrder(t *testing.T) {
|
||||
req := Get("http://beego.me")
|
||||
req.AddFilters(func(next Filter) Filter {
|
||||
return func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) {
|
||||
return NewHttpResponseWithJsonBody("first"), nil
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
req.AddFilters(func(next Filter) Filter {
|
||||
return func(ctx context.Context, req *BeegoHTTPRequest) (*http.Response, error) {
|
||||
return NewHttpResponseWithJsonBody("second"), nil
|
||||
}
|
||||
})
|
||||
|
||||
resp, err := req.DoRequestWithCtx(context.Background())
|
||||
assert.Nil(t, err)
|
||||
data := make([]byte, 5)
|
||||
_, _ = resp.Body.Read(data)
|
||||
assert.Equal(t, "first", string(data))
|
||||
}
|
||||
|
||||
func TestHead(t *testing.T) {
|
||||
req := Head("http://beego.me")
|
||||
assert.NotNil(t, req)
|
||||
|
||||
@ -948,9 +948,10 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
||||
val := reflect.ValueOf(container)
|
||||
ind := reflect.Indirect(val)
|
||||
|
||||
errTyp := true
|
||||
unregister := true
|
||||
one := true
|
||||
isPtr := true
|
||||
name := ""
|
||||
|
||||
if val.Kind() == reflect.Ptr {
|
||||
fn := ""
|
||||
@ -963,19 +964,17 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
||||
case reflect.Struct:
|
||||
isPtr = false
|
||||
fn = getFullName(typ)
|
||||
name = getTableName(reflect.New(typ))
|
||||
}
|
||||
} else {
|
||||
fn = getFullName(ind.Type())
|
||||
name = getTableName(ind)
|
||||
}
|
||||
errTyp = fn != mi.fullName
|
||||
unregister = fn != mi.fullName
|
||||
}
|
||||
|
||||
if errTyp {
|
||||
if one {
|
||||
panic(fmt.Errorf("wrong object type `%s` for rows scan, need *%s", val.Type(), mi.fullName))
|
||||
} else {
|
||||
panic(fmt.Errorf("wrong object type `%s` for rows scan, need *[]*%s or *[]%s", val.Type(), mi.fullName, mi.fullName))
|
||||
}
|
||||
if unregister {
|
||||
RegisterModel(container)
|
||||
}
|
||||
|
||||
rlimit := qs.limit
|
||||
@ -1040,6 +1039,9 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
||||
if qs.distinct {
|
||||
sqlSelect += " DISTINCT"
|
||||
}
|
||||
if qs.aggregate != "" {
|
||||
sels = qs.aggregate
|
||||
}
|
||||
query := fmt.Sprintf("%s %s FROM %s%s%s T0 %s%s%s%s%s%s",
|
||||
sqlSelect, sels, Q, mi.table, Q,
|
||||
specifyIndexes, join, where, groupBy, orderBy, limit)
|
||||
@ -1064,16 +1066,20 @@ func (d *dbBase) ReadBatch(q dbQuerier, qs *querySet, mi *modelInfo, cond *Condi
|
||||
}
|
||||
}
|
||||
|
||||
defer rs.Close()
|
||||
|
||||
slice := ind
|
||||
if unregister {
|
||||
mi, _ = modelCache.get(name)
|
||||
tCols = mi.fields.dbcols
|
||||
colsNum = len(tCols)
|
||||
}
|
||||
|
||||
refs := make([]interface{}, colsNum)
|
||||
for i := range refs {
|
||||
var ref interface{}
|
||||
refs[i] = &ref
|
||||
}
|
||||
|
||||
defer rs.Close()
|
||||
|
||||
slice := ind
|
||||
|
||||
var cnt int64
|
||||
for rs.Next() {
|
||||
if one && cnt == 0 || !one {
|
||||
|
||||
@ -332,10 +332,6 @@ end:
|
||||
|
||||
// register register models to model cache
|
||||
func (mc *_modelCache) register(prefixOrSuffixStr string, prefixOrSuffix bool, models ...interface{}) (err error) {
|
||||
if mc.done {
|
||||
err = fmt.Errorf("register must be run before BootStrap")
|
||||
return
|
||||
}
|
||||
|
||||
for _, model := range models {
|
||||
val := reflect.ValueOf(model)
|
||||
@ -352,7 +348,9 @@ func (mc *_modelCache) register(prefixOrSuffixStr string, prefixOrSuffix bool, m
|
||||
err = fmt.Errorf("<orm.RegisterModel> only allow ptr model struct, it looks you use two reference to the struct `%s`", typ)
|
||||
return
|
||||
}
|
||||
|
||||
if val.Elem().Kind() == reflect.Slice {
|
||||
val = reflect.New(val.Elem().Type().Elem())
|
||||
}
|
||||
table := getTableName(val)
|
||||
|
||||
if prefixOrSuffixStr != "" {
|
||||
@ -371,8 +369,7 @@ func (mc *_modelCache) register(prefixOrSuffixStr string, prefixOrSuffix bool, m
|
||||
}
|
||||
|
||||
if _, ok := mc.get(table); ok {
|
||||
err = fmt.Errorf("<orm.RegisterModel> table name `%s` repeat register, must be unique\n", table)
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
mi := newModelInfo(val)
|
||||
@ -389,12 +386,6 @@ func (mc *_modelCache) register(prefixOrSuffixStr string, prefixOrSuffix bool, m
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if mi.fields.pk == nil {
|
||||
err = fmt.Errorf("<orm.RegisterModel> `%s` needs a primary key field, default is to use 'id' if not set\n", name)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
mi.table = table
|
||||
|
||||
@ -255,6 +255,22 @@ func NewTM() *TM {
|
||||
return obj
|
||||
}
|
||||
|
||||
type DeptInfo struct {
|
||||
ID int `orm:"column(id)"`
|
||||
Created time.Time `orm:"auto_now_add"`
|
||||
DeptName string
|
||||
EmployeeName string
|
||||
Salary int
|
||||
}
|
||||
|
||||
type UnregisterModel struct {
|
||||
ID int `orm:"column(id)"`
|
||||
Created time.Time `orm:"auto_now_add"`
|
||||
DeptName string
|
||||
EmployeeName string
|
||||
Salary int
|
||||
}
|
||||
|
||||
type User struct {
|
||||
ID int `orm:"column(id)"`
|
||||
UserName string `orm:"size(30);unique"`
|
||||
|
||||
@ -109,6 +109,9 @@ func getTableUnique(val reflect.Value) [][]string {
|
||||
|
||||
// get whether the table needs to be created for the database alias
|
||||
func isApplicableTableForDB(val reflect.Value, db string) bool {
|
||||
if !val.IsValid() {
|
||||
return true
|
||||
}
|
||||
fun := val.MethodByName("IsApplicableTableForDB")
|
||||
if fun.IsValid() {
|
||||
vals := fun.Call([]reflect.Value{reflect.ValueOf(db)})
|
||||
|
||||
@ -79,6 +79,7 @@ type querySet struct {
|
||||
orm *ormBase
|
||||
ctx context.Context
|
||||
forContext bool
|
||||
aggregate string
|
||||
}
|
||||
|
||||
var _ QuerySeter = new(querySet)
|
||||
@ -323,3 +324,9 @@ func newQuerySet(orm *ormBase, mi *modelInfo) QuerySeter {
|
||||
o.orm = orm
|
||||
return o
|
||||
}
|
||||
|
||||
// aggregate func
|
||||
func (o querySet) Aggregate(s string) QuerySeter {
|
||||
o.aggregate = s
|
||||
return &o
|
||||
}
|
||||
@ -205,6 +205,7 @@ func TestSyncDb(t *testing.T) {
|
||||
RegisterModel(new(Index))
|
||||
RegisterModel(new(StrPk))
|
||||
RegisterModel(new(TM))
|
||||
RegisterModel(new(DeptInfo))
|
||||
|
||||
err := RunSyncdb("default", true, Debug)
|
||||
throwFail(t, err)
|
||||
@ -232,6 +233,7 @@ func TestRegisterModels(t *testing.T) {
|
||||
RegisterModel(new(Index))
|
||||
RegisterModel(new(StrPk))
|
||||
RegisterModel(new(TM))
|
||||
RegisterModel(new(DeptInfo))
|
||||
|
||||
BootStrap()
|
||||
|
||||
@ -333,6 +335,73 @@ func TestTM(t *testing.T) {
|
||||
throwFail(t, AssertIs(recTM.TMPrecision2.String(), "2020-08-07 02:07:04.1235 +0000 UTC"))
|
||||
}
|
||||
|
||||
func TestUnregisterModel(t *testing.T) {
|
||||
data := []*DeptInfo{
|
||||
{
|
||||
DeptName: "A",
|
||||
EmployeeName: "A1",
|
||||
Salary: 1000,
|
||||
},
|
||||
{
|
||||
DeptName: "A",
|
||||
EmployeeName: "A2",
|
||||
Salary: 2000,
|
||||
},
|
||||
{
|
||||
DeptName: "B",
|
||||
EmployeeName: "B1",
|
||||
Salary: 2000,
|
||||
},
|
||||
{
|
||||
DeptName: "B",
|
||||
EmployeeName: "B2",
|
||||
Salary: 4000,
|
||||
},
|
||||
{
|
||||
DeptName: "B",
|
||||
EmployeeName: "B3",
|
||||
Salary: 3000,
|
||||
},
|
||||
}
|
||||
qs := dORM.QueryTable("dept_info")
|
||||
i, _ := qs.PrepareInsert()
|
||||
for _, d := range data {
|
||||
_, err := i.Insert(d)
|
||||
if err != nil {
|
||||
throwFail(t, err)
|
||||
}
|
||||
}
|
||||
|
||||
f := func() {
|
||||
var res []UnregisterModel
|
||||
n, err := dORM.QueryTable("dept_info").All(&res)
|
||||
throwFail(t, err)
|
||||
throwFail(t, AssertIs(n, 5))
|
||||
throwFail(t, AssertIs(res[0].EmployeeName, "A1"))
|
||||
|
||||
type Sum struct {
|
||||
DeptName string
|
||||
Total int
|
||||
}
|
||||
var sun []Sum
|
||||
qs.Aggregate("dept_name,sum(salary) as total").GroupBy("dept_name").OrderBy("dept_name").All(&sun)
|
||||
throwFail(t, AssertIs(sun[0].DeptName, "A"))
|
||||
throwFail(t, AssertIs(sun[0].Total, 3000))
|
||||
|
||||
type Max struct {
|
||||
DeptName string
|
||||
Max float64
|
||||
}
|
||||
var max []Max
|
||||
qs.Aggregate("dept_name,max(salary) as max").GroupBy("dept_name").OrderBy("dept_name").All(&max)
|
||||
throwFail(t, AssertIs(max[1].DeptName, "B"))
|
||||
throwFail(t, AssertIs(max[1].Max, 4000))
|
||||
}
|
||||
for i := 0; i < 5; i++ {
|
||||
f()
|
||||
}
|
||||
}
|
||||
|
||||
func TestNullDataTypes(t *testing.T) {
|
||||
d := DataNull{}
|
||||
|
||||
|
||||
@ -405,6 +405,15 @@ type QuerySeter interface {
|
||||
// Found int
|
||||
// }
|
||||
RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error)
|
||||
// aggregate func.
|
||||
// for example:
|
||||
// type result struct {
|
||||
// DeptName string
|
||||
// Total int
|
||||
// }
|
||||
// var res []result
|
||||
// o.QueryTable("dept_info").Aggregate("dept_name,sum(salary) as total").GroupBy("dept_name").All(&res)
|
||||
Aggregate(s string) QuerySeter
|
||||
}
|
||||
|
||||
// QueryM2Mer model to model query struct
|
||||
|
||||
@ -112,13 +112,13 @@ func registerAdmin() error {
|
||||
HttpServer: NewHttpServerWithCfg(BConfig),
|
||||
}
|
||||
// keep in mind that all data should be html escaped to avoid XSS attack
|
||||
beeAdminApp.Router("/", c, SetRouterMethods(c, "get:AdminIndex"))
|
||||
beeAdminApp.Router("/qps", c, SetRouterMethods(c, "get:QpsIndex"))
|
||||
beeAdminApp.Router("/prof", c, SetRouterMethods(c, "get:ProfIndex"))
|
||||
beeAdminApp.Router("/healthcheck", c, SetRouterMethods(c, "get:Healthcheck"))
|
||||
beeAdminApp.Router("/task", c, SetRouterMethods(c, "get:TaskStatus"))
|
||||
beeAdminApp.Router("/listconf", c, SetRouterMethods(c, "get:ListConf"))
|
||||
beeAdminApp.Router("/metrics", c, SetRouterMethods(c, "get:PrometheusMetrics"))
|
||||
beeAdminApp.Router("/", c, "get:AdminIndex")
|
||||
beeAdminApp.Router("/qps", c, "get:QpsIndex")
|
||||
beeAdminApp.Router("/prof", c, "get:ProfIndex")
|
||||
beeAdminApp.Router("/healthcheck", c, "get:Healthcheck")
|
||||
beeAdminApp.Router("/task", c, "get:TaskStatus")
|
||||
beeAdminApp.Router("/listconf", c, "get:ListConf")
|
||||
beeAdminApp.Router("/metrics", c, "get:PrometheusMetrics")
|
||||
|
||||
go beeAdminApp.Run()
|
||||
}
|
||||
|
||||
@ -15,9 +15,12 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strconv"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
@ -36,13 +39,46 @@ func TestControllerRegister_InsertFilterChain(t *testing.T) {
|
||||
ns := NewNamespace("/chain")
|
||||
|
||||
ns.Get("/*", func(ctx *context.Context) {
|
||||
ctx.Output.Body([]byte("hello"))
|
||||
_ = ctx.Output.Body([]byte("hello"))
|
||||
})
|
||||
|
||||
r, _ := http.NewRequest("GET", "/chain/user", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
BeeApp.Handlers.Init()
|
||||
BeeApp.Handlers.ServeHTTP(w, r)
|
||||
|
||||
assert.Equal(t, "filter-chain", w.Header().Get("filter"))
|
||||
}
|
||||
|
||||
func TestControllerRegister_InsertFilterChain_Order(t *testing.T) {
|
||||
InsertFilterChain("/abc", func(next FilterFunc) FilterFunc {
|
||||
return func(ctx *context.Context) {
|
||||
ctx.Output.Header("first", fmt.Sprintf("%d", time.Now().UnixNano()))
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
next(ctx)
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
InsertFilterChain("/abc", func(next FilterFunc) FilterFunc {
|
||||
return func(ctx *context.Context) {
|
||||
ctx.Output.Header("second", fmt.Sprintf("%d", time.Now().UnixNano()))
|
||||
time.Sleep(time.Millisecond * 10)
|
||||
next(ctx)
|
||||
}
|
||||
})
|
||||
|
||||
r, _ := http.NewRequest("GET", "/abc", nil)
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
BeeApp.Handlers.Init()
|
||||
BeeApp.Handlers.ServeHTTP(w, r)
|
||||
first := w.Header().Get("first")
|
||||
second := w.Header().Get("second")
|
||||
|
||||
ft, _ := strconv.ParseInt(first, 10, 64)
|
||||
st, _ := strconv.ParseInt(second, 10, 64)
|
||||
|
||||
assert.True(t, st > ft)
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ func TestFlashHeader(t *testing.T) {
|
||||
|
||||
// setup the handler
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestFlashController{}, SetRouterMethods(&TestFlashController{}, "get:TestWriteFlash"))
|
||||
handler.Add("/", &TestFlashController{}, WithRouterMethods(&TestFlashController{}, "get:TestWriteFlash"))
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
// get the Set-Cookie value
|
||||
|
||||
@ -99,7 +99,7 @@ func (n *Namespace) Filter(action string, filter ...FilterFunc) *Namespace {
|
||||
// Router same as beego.Rourer
|
||||
// refer: https://godoc.org/github.com/beego/beego/v2#Router
|
||||
func (n *Namespace) Router(rootpath string, c ControllerInterface, mappingMethods ...string) *Namespace {
|
||||
n.handlers.Add(rootpath, c, SetRouterMethods(c, mappingMethods...))
|
||||
n.handlers.Add(rootpath, c, WithRouterMethods(c, mappingMethods...))
|
||||
return n
|
||||
}
|
||||
|
||||
|
||||
@ -121,24 +121,30 @@ type ControllerInfo struct {
|
||||
sessionOn bool
|
||||
}
|
||||
|
||||
type ControllerOptions func(*ControllerInfo)
|
||||
type ControllerOption func(*ControllerInfo)
|
||||
|
||||
func (c *ControllerInfo) GetPattern() string {
|
||||
return c.pattern
|
||||
}
|
||||
|
||||
func SetRouterMethods(ctrlInterface ControllerInterface, mappingMethod ...string) ControllerOptions {
|
||||
func WithRouterMethods(ctrlInterface ControllerInterface, mappingMethod ...string) ControllerOption {
|
||||
return func(c *ControllerInfo) {
|
||||
c.methods = parseMappingMethods(ctrlInterface, mappingMethod)
|
||||
}
|
||||
}
|
||||
|
||||
func SetRouterSessionOn(sessionOn bool) ControllerOptions {
|
||||
func WithRouterSessionOn(sessionOn bool) ControllerOption {
|
||||
return func(c *ControllerInfo) {
|
||||
c.sessionOn = sessionOn
|
||||
}
|
||||
}
|
||||
|
||||
type filterChainConfig struct {
|
||||
pattern string
|
||||
chain FilterChain
|
||||
opts []FilterOpt
|
||||
}
|
||||
|
||||
// ControllerRegister containers registered router rules, controller handlers and filters.
|
||||
type ControllerRegister struct {
|
||||
routers map[string]*Tree
|
||||
@ -151,6 +157,9 @@ type ControllerRegister struct {
|
||||
// the filter created by FilterChain
|
||||
chainRoot *FilterRouter
|
||||
|
||||
// keep registered chain and build it when serve http
|
||||
filterChains []filterChainConfig
|
||||
|
||||
cfg *Config
|
||||
}
|
||||
|
||||
@ -171,11 +180,23 @@ func NewControllerRegisterWithCfg(cfg *Config) *ControllerRegister {
|
||||
},
|
||||
},
|
||||
cfg: cfg,
|
||||
filterChains: make([]filterChainConfig, 0, 4),
|
||||
}
|
||||
res.chainRoot = newFilterRouter("/*", res.serveHttp, WithCaseSensitive(false))
|
||||
return res
|
||||
}
|
||||
|
||||
// Init will be executed when HttpServer start running
|
||||
func (p *ControllerRegister) Init() {
|
||||
for i := len(p.filterChains) - 1; i >= 0 ; i -- {
|
||||
fc := p.filterChains[i]
|
||||
root := p.chainRoot
|
||||
filterFunc := fc.chain(root.filterFunc)
|
||||
p.chainRoot = newFilterRouter(fc.pattern, filterFunc, fc.opts...)
|
||||
p.chainRoot.next = root
|
||||
}
|
||||
}
|
||||
|
||||
// Add controller handler and pattern rules to ControllerRegister.
|
||||
// usage:
|
||||
// default methods is the same name as method
|
||||
@ -186,7 +207,7 @@ func NewControllerRegisterWithCfg(cfg *Config) *ControllerRegister {
|
||||
// Add("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
// Add("/api",&RestController{},"get,post:ApiFunc"
|
||||
// Add("/simple",&SimpleController{},"get:GetFunc;post:PostFunc")
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, opts ...ControllerOptions) {
|
||||
func (p *ControllerRegister) Add(pattern string, c ControllerInterface, opts ...ControllerOption) {
|
||||
p.addWithMethodParams(pattern, c, nil, opts...)
|
||||
}
|
||||
|
||||
@ -239,7 +260,7 @@ func (p *ControllerRegister) addRouterForMethod(route *ControllerInfo) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, opts ...ControllerOptions) {
|
||||
func (p *ControllerRegister) addWithMethodParams(pattern string, c ControllerInterface, methodParams []*param.MethodParam, opts ...ControllerOption) {
|
||||
reflectVal := reflect.ValueOf(c)
|
||||
t := reflect.Indirect(reflectVal).Type()
|
||||
|
||||
@ -311,7 +332,7 @@ func (p *ControllerRegister) Include(cList ...ControllerInterface) {
|
||||
p.InsertFilter(f.Pattern, f.Pos, f.Filter, WithReturnOnOutput(f.ReturnOnOutput), WithResetParams(f.ResetParams))
|
||||
}
|
||||
|
||||
p.addWithMethodParams(a.Router, c, a.MethodParams, SetRouterMethods(c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method))
|
||||
p.addWithMethodParams(a.Router, c, a.MethodParams, WithRouterMethods(c, strings.Join(a.AllowHTTPMethods, ",")+":"+a.Method))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -513,12 +534,13 @@ func (p *ControllerRegister) InsertFilter(pattern string, pos int, filter Filter
|
||||
// }
|
||||
// }
|
||||
func (p *ControllerRegister) InsertFilterChain(pattern string, chain FilterChain, opts ...FilterOpt) {
|
||||
root := p.chainRoot
|
||||
filterFunc := chain(root.filterFunc)
|
||||
opts = append(opts, WithCaseSensitive(p.cfg.RouterCaseSensitive))
|
||||
p.chainRoot = newFilterRouter(pattern, filterFunc, opts...)
|
||||
p.chainRoot.next = root
|
||||
|
||||
opts = append(opts, WithCaseSensitive(p.cfg.RouterCaseSensitive))
|
||||
p.filterChains = append(p.filterChains, filterChainConfig{
|
||||
pattern: pattern,
|
||||
chain: chain,
|
||||
opts: opts,
|
||||
})
|
||||
}
|
||||
|
||||
// add Filter into
|
||||
|
||||
@ -97,7 +97,7 @@ func (jc *JSONController) Get() {
|
||||
|
||||
func TestPrefixUrlFor(t *testing.T){
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/my/prefix/list", &PrefixTestController{}, "get:PrefixList")
|
||||
handler.Add("/my/prefix/list", &PrefixTestController{}, WithRouterMethods(&PrefixTestController{}, "get:PrefixList"))
|
||||
|
||||
if a := handler.URLFor(`PrefixTestController.PrefixList`); a != `/my/prefix/list` {
|
||||
logs.Info(a)
|
||||
@ -111,8 +111,8 @@ func TestPrefixUrlFor(t *testing.T){
|
||||
|
||||
func TestUrlFor(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/api/list", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/person/:last/:first", &TestController{}, SetRouterMethods(&TestController{}, "*:Param"))
|
||||
handler.Add("/api/list", &TestController{}, WithRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/person/:last/:first", &TestController{}, WithRouterMethods(&TestController{}, "*:Param"))
|
||||
if a := handler.URLFor("TestController.List"); a != "/api/list" {
|
||||
logs.Info(a)
|
||||
t.Errorf("TestController.List must equal to /api/list")
|
||||
@ -135,9 +135,9 @@ func TestUrlFor3(t *testing.T) {
|
||||
|
||||
func TestUrlFor2(t *testing.T) {
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/v1/:username/edit", &TestController{}, SetRouterMethods(&TestController{}, "get:GetURL"))
|
||||
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, SetRouterMethods(&TestController{}, "*:Param"))
|
||||
handler.Add("/v1/:v/cms_:id(.+)_:page(.+).html", &TestController{}, WithRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/v1/:username/edit", &TestController{}, WithRouterMethods(&TestController{}, "get:GetURL"))
|
||||
handler.Add("/v1/:v(.+)_cms/ttt_:id(.+)_:page(.+).html", &TestController{}, WithRouterMethods(&TestController{}, "*:Param"))
|
||||
handler.Add("/:year:int/:month:int/:title/:entid", &TestController{})
|
||||
if handler.URLFor("TestController.GetURL", ":username", "astaxie") != "/v1/astaxie/edit" {
|
||||
logs.Info(handler.URLFor("TestController.GetURL"))
|
||||
@ -167,7 +167,7 @@ func TestUserFunc(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/api/list", &TestController{}, SetRouterMethods(&TestController{}, "*:List"))
|
||||
handler.Add("/api/list", &TestController{}, WithRouterMethods(&TestController{}, "*:List"))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Body.String() != "i am list" {
|
||||
t.Errorf("user define func can't run")
|
||||
@ -257,7 +257,7 @@ func TestRouteOk(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/person/:last/:first", &TestController{}, SetRouterMethods(&TestController{}, "get:GetParams"))
|
||||
handler.Add("/person/:last/:first", &TestController{}, WithRouterMethods(&TestController{}, "get:GetParams"))
|
||||
handler.ServeHTTP(w, r)
|
||||
body := w.Body.String()
|
||||
if body != "anderson+thomas+kungfu" {
|
||||
@ -271,7 +271,7 @@ func TestManyRoute(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, SetRouterMethods(&TestController{}, "get:GetManyRouter"))
|
||||
handler.Add("/beego:id([0-9]+)-:page([0-9]+).html", &TestController{}, WithRouterMethods(&TestController{}, "get:GetManyRouter"))
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
body := w.Body.String()
|
||||
@ -288,7 +288,7 @@ func TestEmptyResponse(t *testing.T) {
|
||||
w := httptest.NewRecorder()
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/beego-empty.html", &TestController{}, SetRouterMethods(&TestController{}, "get:GetEmptyBody"))
|
||||
handler.Add("/beego-empty.html", &TestController{}, WithRouterMethods(&TestController{}, "get:GetEmptyBody"))
|
||||
handler.ServeHTTP(w, r)
|
||||
|
||||
if body := w.Body.String(); body != "" {
|
||||
@ -783,8 +783,8 @@ func TestRouterSessionSet(t *testing.T) {
|
||||
r, _ := http.NewRequest("GET", "/user", nil)
|
||||
w := httptest.NewRecorder()
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(false))
|
||||
handler.Add("/user", &TestController{}, WithRouterMethods(&TestController{}, "get:Get"),
|
||||
WithRouterSessionOn(false))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") != "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
@ -794,8 +794,8 @@ func TestRouterSessionSet(t *testing.T) {
|
||||
r, _ = http.NewRequest("GET", "/user", nil)
|
||||
w = httptest.NewRecorder()
|
||||
handler = NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(true))
|
||||
handler.Add("/user", &TestController{}, WithRouterMethods(&TestController{}, "get:Get"),
|
||||
WithRouterSessionOn(true))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") != "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
@ -809,8 +809,8 @@ func TestRouterSessionSet(t *testing.T) {
|
||||
r, _ = http.NewRequest("GET", "/user", nil)
|
||||
w = httptest.NewRecorder()
|
||||
handler = NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(false))
|
||||
handler.Add("/user", &TestController{}, WithRouterMethods(&TestController{}, "get:Get"),
|
||||
WithRouterSessionOn(false))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") != "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
@ -820,8 +820,8 @@ func TestRouterSessionSet(t *testing.T) {
|
||||
r, _ = http.NewRequest("GET", "/user", nil)
|
||||
w = httptest.NewRecorder()
|
||||
handler = NewControllerRegister()
|
||||
handler.Add("/user", &TestController{}, SetRouterMethods(&TestController{}, "get:Get"),
|
||||
SetRouterSessionOn(true))
|
||||
handler.Add("/user", &TestController{}, WithRouterMethods(&TestController{}, "get:Get"),
|
||||
WithRouterSessionOn(true))
|
||||
handler.ServeHTTP(w, r)
|
||||
if w.Header().Get("Set-Cookie") == "" {
|
||||
t.Errorf("TestRotuerSessionSet failed")
|
||||
|
||||
@ -84,7 +84,9 @@ func (app *HttpServer) Run(addr string, mws ...MiddleWare) {
|
||||
|
||||
initBeforeHTTPRun()
|
||||
|
||||
// init...
|
||||
app.initAddr(addr)
|
||||
app.Handlers.Init()
|
||||
|
||||
addr = app.Cfg.Listen.HTTPAddr
|
||||
|
||||
@ -266,8 +268,12 @@ func (app *HttpServer) Run(addr string, mws ...MiddleWare) {
|
||||
}
|
||||
|
||||
// Router see HttpServer.Router
|
||||
func Router(rootpath string, c ControllerInterface, opts ...ControllerOptions) *HttpServer {
|
||||
return BeeApp.Router(rootpath, c, opts...)
|
||||
func Router(rootpath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
|
||||
return RouterWithOpts(rootpath, c, WithRouterMethods(c, mappingMethods...))
|
||||
}
|
||||
|
||||
func RouterWithOpts(rootpath string, c ControllerInterface, opts ...ControllerOption) *HttpServer {
|
||||
return BeeApp.RouterWithOpts(rootpath, c, opts...)
|
||||
}
|
||||
|
||||
// Router adds a patterned controller handler to BeeApp.
|
||||
@ -286,7 +292,11 @@ func Router(rootpath string, c ControllerInterface, opts ...ControllerOptions) *
|
||||
// beego.Router("/api/create",&RestController{},"post:CreateFood")
|
||||
// beego.Router("/api/update",&RestController{},"put:UpdateFood")
|
||||
// beego.Router("/api/delete",&RestController{},"delete:DeleteFood")
|
||||
func (app *HttpServer) Router(rootPath string, c ControllerInterface, opts ...ControllerOptions) *HttpServer {
|
||||
func (app *HttpServer) Router(rootPath string, c ControllerInterface, mappingMethods ...string) *HttpServer {
|
||||
return app.RouterWithOpts(rootPath, c, WithRouterMethods(c, mappingMethods...))
|
||||
}
|
||||
|
||||
func (app *HttpServer) RouterWithOpts(rootPath string, c ControllerInterface, opts ...ControllerOption) *HttpServer {
|
||||
app.Handlers.Add(rootPath, c, opts...)
|
||||
return app
|
||||
}
|
||||
|
||||
@ -75,9 +75,9 @@ func TestUnregisterFixedRouteRoot(t *testing.T) {
|
||||
var method = "GET"
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
handler.Add("/", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test original root
|
||||
testHelperFnContentCheck(t, handler, "Test original root",
|
||||
@ -96,7 +96,7 @@ func TestUnregisterFixedRouteRoot(t *testing.T) {
|
||||
|
||||
// Replace the root path TestPreUnregController action with the action from
|
||||
// TestPostUnregController
|
||||
handler.Add("/", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/", &TestPostUnregController{}, WithRouterMethods(&TestPostUnregController{}, "get:GetFixedRoot"))
|
||||
|
||||
// Test replacement root (expect change)
|
||||
testHelperFnContentCheck(t, handler, "Test replacement root (expect change)", method, "/", contentRootReplacement)
|
||||
@ -117,9 +117,9 @@ func TestUnregisterFixedRouteLevel1(t *testing.T) {
|
||||
var method = "GET"
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
handler.Add("/", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test original root
|
||||
testHelperFnContentCheck(t, handler,
|
||||
@ -146,7 +146,7 @@ func TestUnregisterFixedRouteLevel1(t *testing.T) {
|
||||
|
||||
// Replace the "level1" path TestPreUnregController action with the action from
|
||||
// TestPostUnregController
|
||||
handler.Add("/level1", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1", &TestPostUnregController{}, WithRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel1"))
|
||||
|
||||
// Test replacement root (expect no change from the original)
|
||||
testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal)
|
||||
@ -167,9 +167,9 @@ func TestUnregisterFixedRouteLevel2(t *testing.T) {
|
||||
var method = "GET"
|
||||
|
||||
handler := NewControllerRegister()
|
||||
handler.Add("/", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, SetRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
handler.Add("/", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedRoot"))
|
||||
handler.Add("/level1", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel1"))
|
||||
handler.Add("/level1/level2", &TestPreUnregController{}, WithRouterMethods(&TestPreUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test original root
|
||||
testHelperFnContentCheck(t, handler,
|
||||
@ -196,7 +196,7 @@ func TestUnregisterFixedRouteLevel2(t *testing.T) {
|
||||
|
||||
// Replace the "/level1/level2" path TestPreUnregController action with the action from
|
||||
// TestPostUnregController
|
||||
handler.Add("/level1/level2", &TestPostUnregController{}, SetRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel2"))
|
||||
handler.Add("/level1/level2", &TestPostUnregController{}, WithRouterMethods(&TestPostUnregController{}, "get:GetFixedLevel2"))
|
||||
|
||||
// Test replacement root (expect no change from the original)
|
||||
testHelperFnContentCheck(t, handler, "Test replacement root (expect no change from the original)", method, "/", contentRootOriginal)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user