github.com/goravel/framework@v1.13.9/auth/access/gate.go (about) 1 package access 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/goravel/framework/contracts/auth/access" 8 ) 9 10 type Gate struct { 11 ctx context.Context 12 abilities map[string]func(ctx context.Context, arguments map[string]any) access.Response 13 beforeCallbacks []func(ctx context.Context, ability string, arguments map[string]any) access.Response 14 afterCallbacks []func(ctx context.Context, ability string, arguments map[string]any, result access.Response) access.Response 15 } 16 17 func NewGate(ctx context.Context) *Gate { 18 return &Gate{ 19 ctx: ctx, 20 abilities: make(map[string]func(ctx context.Context, arguments map[string]any) access.Response), 21 } 22 } 23 24 func (r *Gate) WithContext(ctx context.Context) access.Gate { 25 return &Gate{ 26 ctx: ctx, 27 abilities: r.abilities, 28 beforeCallbacks: r.beforeCallbacks, 29 afterCallbacks: r.afterCallbacks, 30 } 31 } 32 33 func (r *Gate) Allows(ability string, arguments map[string]any) bool { 34 return r.Inspect(ability, arguments).Allowed() 35 } 36 37 func (r *Gate) Denies(ability string, arguments map[string]any) bool { 38 return !r.Allows(ability, arguments) 39 } 40 41 func (r *Gate) Inspect(ability string, arguments map[string]any) access.Response { 42 result := r.callBeforeCallbacks(r.ctx, ability, arguments) 43 if result == nil { 44 if _, exist := r.abilities[ability]; exist { 45 result = r.abilities[ability](r.ctx, arguments) 46 } else { 47 result = NewDenyResponse(fmt.Sprintf("ability doesn't exist: %s", ability)) 48 } 49 } 50 51 return r.callAfterCallbacks(r.ctx, ability, arguments, result) 52 } 53 54 func (r *Gate) Define(ability string, callback func(ctx context.Context, arguments map[string]any) access.Response) { 55 r.abilities[ability] = callback 56 } 57 58 func (r *Gate) Any(abilities []string, arguments map[string]any) bool { 59 var res bool 60 for _, ability := range abilities { 61 res = res || r.Allows(ability, arguments) 62 } 63 64 return res 65 } 66 67 func (r *Gate) None(abilities []string, arguments map[string]any) bool { 68 return !r.Any(abilities, arguments) 69 } 70 71 func (r *Gate) Before(callback func(ctx context.Context, ability string, arguments map[string]any) access.Response) { 72 r.beforeCallbacks = append(r.beforeCallbacks, callback) 73 } 74 75 func (r *Gate) After(callback func(ctx context.Context, ability string, arguments map[string]any, result access.Response) access.Response) { 76 r.afterCallbacks = append(r.afterCallbacks, callback) 77 } 78 79 func (r *Gate) callBeforeCallbacks(ctx context.Context, ability string, arguments map[string]any) access.Response { 80 for _, before := range r.beforeCallbacks { 81 result := before(ctx, ability, arguments) 82 if result != nil { 83 return result 84 } 85 } 86 87 return nil 88 } 89 90 func (r *Gate) callAfterCallbacks(ctx context.Context, ability string, arguments map[string]any, result access.Response) access.Response { 91 for _, after := range r.afterCallbacks { 92 afterResult := after(ctx, ability, arguments, result) 93 if result == nil && afterResult != nil { 94 result = afterResult 95 } 96 } 97 98 return result 99 }