package revel // FilterConfigurator allows the developer configure the filter chain on a // per-controller or per-action basis. The filter configuration is applied by // the FilterConfiguringFilter, which is itself a filter stage. For example, // // Assuming: // Filters = []Filter{ // RouterFilter, // FilterConfiguringFilter, // SessionFilter, // ActionInvoker, // } // // Add: // FilterAction(App.Action). // Add(OtherFilter) // // => RouterFilter, FilterConfiguringFilter, SessionFilter, OtherFilter, ActionInvoker // // Remove: // FilterAction(App.Action). // Remove(SessionFilter) // // => RouterFilter, FilterConfiguringFilter, OtherFilter, ActionInvoker // // Insert: // FilterAction(App.Action). // Insert(OtherFilter, revel.BEFORE, SessionFilter) // // => RouterFilter, FilterConfiguringFilter, OtherFilter, SessionFilter, ActionInvoker // // Filter modifications may be combined between Controller and Action. For example: // FilterController(App{}). // Add(Filter1) // FilterAction(App.Action). // Add(Filter2) // // .. would result in App.Action being filtered by both Filter1 and Filter2. // // Note: the last filter stage is not subject to the configurator. In // particular, Add() adds a filter to the second-to-last place. type FilterConfigurator struct { } // FilterController returns a configurator for the filters applied to all // actions on the given controller instance. For example: // FilterAction(MyController{}) func FilterController(controllerInstance interface{}) FilterConfigurator { t := reflect.TypeOf(controllerInstance) for t.Kind() == reflect.Ptr { t = t.Elem() } return newFilterConfigurator(t.Name(), "") } // FilterAction returns a configurator for the filters applied to the given // controller method. For example: // FilterAction(MyController.MyAction) func FilterAction(methodRef interface{}) FilterConfigurator { var ( methodValue = reflect.ValueOf(methodRef) methodType = methodValue.Type() ) if methodType.Kind() != reflect.Func || methodType.NumIn() == 0 { panic("Expecting a controller method reference (e.g. Controller.Action), got a " + methodType.String()) } controllerType := methodType.In(0) method := FindMethod(controllerType, methodValue) if method == nil { panic("Action not found on controller " + controllerType.Name()) } for controllerType.Kind() == reflect.Ptr { controllerType = controllerType.Elem() } return newFilterConfigurator(controllerType.Name(), method.Name) } // Add the given filter in the second-to-last position in the filter chain. // (Second-to-last so that it is before ActionInvoker) func (conf FilterConfigurator) Add(f Filter) FilterConfigurator { conf.apply(func(fc []Filter) []Filter { return conf.addFilter(f, fc) }) return conf } // Remove a filter from the filter chain. func (conf FilterConfigurator) Remove(target Filter) FilterConfigurator { conf.apply(func(fc []Filter) []Filter { return conf.rmFilter(target, fc) }) return conf } // Insert a filter into the filter chain before or after another. // This may be called with the BEFORE or AFTER constants, for example: // revel.FilterAction(App.Index). // Insert(MyFilter, revel.BEFORE, revel.ActionInvoker). // Insert(MyFilter2, revel.AFTER, revel.PanicFilter) func (conf FilterConfigurator) Insert(insert Filter, where When, target Filter) FilterConfigurator { if where != BEFORE && where != AFTER { panic("where must be BEFORE or AFTER") } conf.apply(func(fc []Filter) []Filter { return conf.insertFilter(insert, where, target, fc) }) return conf } // FilterEq returns true if the two filters reference the same filter. func FilterEq(a, b Filter) bool { return reflect.ValueOf(a).Pointer() == reflect.ValueOf(b).Pointer() } // FilterConfiguringFilter is a filter stage that customizes the remaining // filter chain for the action being invoked. func FilterConfiguringFilter(c *Controller, fc []Filter) { if newChain := getOverrideChain(c.Name, c.Action); newChain != nil { newChain[0](c, newChain[1:]) return } fc[0](c, fc[1:]) }