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  }