-
Notifications
You must be signed in to change notification settings - Fork 3
/
condition.go
117 lines (94 loc) · 2.9 KB
/
condition.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
package redtape
import (
"fmt"
"github.com/mitchellh/mapstructure"
)
// ConditionBuilder is a typed function that returns a Condition.
type ConditionBuilder func() Condition
// ConditionRegistry is a map contiaining named ConditionBuilders.
type ConditionRegistry map[string]ConditionBuilder
// NewConditionRegistry returns a ConditionRegistry containing the default Conditions and accepts an array
// of map[string]ConditionBuilder to add custom conditions to the set.
func NewConditionRegistry(conds ...map[string]ConditionBuilder) ConditionRegistry {
reg := ConditionRegistry{
new(BoolCondition).Name(): func() Condition {
return new(BoolCondition)
},
new(RoleEqualsCondition).Name(): func() Condition {
return new(RoleEqualsCondition)
},
}
for _, ce := range conds {
for k, c := range ce {
reg[k] = c
}
}
return reg
}
// Condition is the interface allowing different types of conditional expressions.
type Condition interface {
Name() string
Meets(interface{}, *Request) bool
}
// Conditions is a map of named Conditions.
type Conditions map[string]Condition
// NewConditions accepts an array of options and an optional ConditionRegistry and returns a Conditions map.
func NewConditions(opts []ConditionOptions, reg ConditionRegistry) (Conditions, error) {
if reg == nil {
reg = NewConditionRegistry()
}
cond := make(map[string]Condition)
for _, co := range opts {
if cf, ok := reg[co.Type]; ok {
nc := cf()
if len(co.Options) > 0 {
if err := mapstructure.Decode(co.Options, &nc); err != nil {
return nil, err
}
}
cond[co.Name] = nc
} else {
return nil, fmt.Errorf("unknown condition type %s, is it registered?", co.Type)
}
}
return cond, nil
}
// ConditionOptions contains the values used to build a Condition.
type ConditionOptions struct {
Name string `json:"name"`
Type string `json:"type"`
Options map[string]interface{} `json:"options"`
}
// BoolCondition matches a boolean value from context to the preconfigured value.
type BoolCondition struct {
Value bool `json:"value"`
}
// Name fulfills the Name method of Condition.
func (c *BoolCondition) Name() string {
return "bool"
}
// Meets evaluates whether parameter val matches the Condition Value.
func (c *BoolCondition) Meets(val interface{}, _ *Request) bool {
v, ok := val.(bool)
return ok && v == c.Value
}
// RoleEqualsCondition matches the Request role against the required role passed to the condition.
type RoleEqualsCondition struct{}
// Name fulfills the Name method of Condition.
func (c *RoleEqualsCondition) Name() string {
return "role_equals"
}
// Meets evaluates true when the role val matches Request#Role.
func (c *RoleEqualsCondition) Meets(val interface{}, r *Request) bool {
switch v := val.(type) {
case string:
return v == r.Role
case []string:
for _, s := range v {
if s == r.Role {
return true
}
}
}
return false
}