1
|
|
// Copyright 2019 Aporeto Inc.
|
2
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
3
|
|
// you may not use this file except in compliance with the License.
|
4
|
|
// You may obtain a copy of the License at
|
5
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
6
|
|
// Unless required by applicable law or agreed to in writing, software
|
7
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
8
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
9
|
|
// See the License for the specific language governing permissions and
|
10
|
|
// limitations under the License.
|
11
|
|
|
12
|
|
package elemental
|
13
|
|
|
14
|
|
import (
|
15
|
|
"fmt"
|
16
|
|
"net/http"
|
17
|
|
"reflect"
|
18
|
|
)
|
19
|
|
|
20
|
|
const (
|
21
|
|
readOnlyErrorTitle = "Read Only Error"
|
22
|
|
creationOnlyErrorTitle = "Creation Only Error"
|
23
|
|
)
|
24
|
|
|
25
|
|
// ValidateAdvancedSpecification verifies advanced specifications attributes like ReadOnly and CreationOnly.
|
26
|
|
//
|
27
|
|
// For instance, it will check if the given Manipulable has field marked as
|
28
|
|
// readonly, that it has not changed according to the db.
|
29
|
|
func ValidateAdvancedSpecification(obj AttributeSpecifiable, pristine AttributeSpecifiable, op Operation) error {
|
30
|
|
|
31
|
14
|
errors := NewErrors()
|
32
|
|
|
33
|
|
for _, field := range extractFieldNames(obj) {
|
34
|
|
|
35
|
14
|
spec := obj.SpecificationForAttribute(field)
|
36
|
|
|
37
|
|
// If the field is not exposed, we don't enforce anything.
|
38
|
14
|
if !spec.Exposed || spec.Transient {
|
39
|
14
|
continue
|
40
|
|
}
|
41
|
|
|
42
|
14
|
switch op {
|
43
|
14
|
case OperationCreate:
|
44
|
14
|
if spec.ReadOnly && !isFieldValueZero(field, obj) && !areFieldsValueEqualValue(field, obj, spec.DefaultValue) {
|
45
|
|
|
46
|
|
// Special case here. If we have a pristine object, and the fields are equal, it is fine.
|
47
|
14
|
if pristine != nil && areFieldValuesEqual(field, obj, pristine) {
|
48
|
14
|
continue
|
49
|
|
}
|
50
|
|
|
51
|
14
|
e := NewError(
|
52
|
14
|
readOnlyErrorTitle,
|
53
|
14
|
fmt.Sprintf("Field %s is read only. You cannot set its value.", spec.Name),
|
54
|
14
|
"elemental",
|
55
|
14
|
http.StatusUnprocessableEntity,
|
56
|
14
|
)
|
57
|
14
|
e.Data = map[string]string{"attribute": spec.Name}
|
58
|
14
|
errors = append(errors, e)
|
59
|
|
}
|
60
|
|
|
61
|
14
|
case OperationUpdate:
|
62
|
14
|
if !spec.CreationOnly && spec.ReadOnly && !areFieldValuesEqual(field, obj, pristine) {
|
63
|
14
|
e := NewError(
|
64
|
14
|
readOnlyErrorTitle,
|
65
|
14
|
fmt.Sprintf("Field %s is read only. You cannot modify its value.", spec.Name),
|
66
|
14
|
"elemental",
|
67
|
14
|
http.StatusUnprocessableEntity,
|
68
|
14
|
)
|
69
|
14
|
e.Data = map[string]string{"attribute": spec.Name}
|
70
|
14
|
errors = append(errors, e)
|
71
|
|
}
|
72
|
|
|
73
|
14
|
if spec.CreationOnly && !areFieldValuesEqual(field, obj, pristine) {
|
74
|
14
|
e := NewError(
|
75
|
14
|
creationOnlyErrorTitle,
|
76
|
14
|
fmt.Sprintf("Field %s can only be set during creation. You cannot modify its value.", spec.Name),
|
77
|
14
|
"elemental",
|
78
|
14
|
http.StatusUnprocessableEntity,
|
79
|
14
|
)
|
80
|
14
|
e.Data = map[string]string{"attribute": spec.Name}
|
81
|
14
|
errors = append(errors, e)
|
82
|
|
}
|
83
|
|
}
|
84
|
|
}
|
85
|
|
|
86
|
14
|
if len(errors) > 0 {
|
87
|
14
|
return errors
|
88
|
|
}
|
89
|
|
|
90
|
14
|
return nil
|
91
|
|
}
|
92
|
|
|
93
|
|
// BackportUnexposedFields copy the values of unexposed fields from src to dest.
|
94
|
|
func BackportUnexposedFields(src, dest AttributeSpecifiable) {
|
95
|
|
|
96
|
|
for _, field := range extractFieldNames(src) {
|
97
|
|
|
98
|
14
|
spec := src.SpecificationForAttribute(field)
|
99
|
|
|
100
|
14
|
if !spec.Exposed {
|
101
|
14
|
reflect.Indirect(reflect.ValueOf(dest)).FieldByName(field).Set(reflect.Indirect(reflect.ValueOf(src)).FieldByName(field))
|
102
|
|
}
|
103
|
|
|
104
|
14
|
if spec.Secret && isFieldValueZero(field, dest) {
|
105
|
14
|
reflect.Indirect(reflect.ValueOf(dest)).FieldByName(field).Set(reflect.Indirect(reflect.ValueOf(src)).FieldByName(field))
|
106
|
|
}
|
107
|
|
}
|
108
|
|
}
|
109
|
|
|
110
|
|
// ResetDefaultForZeroValues reset the default value from the specification when a field is Zero.
|
111
|
|
// If the given object is not an elemental.AttributeSpecifiable this function
|
112
|
|
// does nothing.
|
113
|
|
func ResetDefaultForZeroValues(obj interface{}) {
|
114
|
|
|
115
|
14
|
o, ok := obj.(AttributeSpecifiable)
|
116
|
14
|
if !ok {
|
117
|
0
|
return
|
118
|
|
}
|
119
|
|
|
120
|
|
for _, field := range extractFieldNames(o) {
|
121
|
|
|
122
|
14
|
spec := o.SpecificationForAttribute(field)
|
123
|
|
|
124
|
14
|
if spec.DefaultValue == nil || !isFieldValueZero(field, o) {
|
125
|
14
|
continue
|
126
|
|
}
|
127
|
|
|
128
|
14
|
reflect.Indirect(reflect.ValueOf(o)).FieldByName(field).Set(reflect.ValueOf(spec.DefaultValue))
|
129
|
|
}
|
130
|
|
}
|
131
|
|
|
132
|
|
// ResetMaps recursively empty all kinds of maps in the given
|
133
|
|
// reflect.Value.
|
134
|
|
func ResetMaps(v reflect.Value) {
|
135
|
|
|
136
|
14
|
indirect := func(vv reflect.Value) reflect.Value {
|
137
|
|
for ; vv.Kind() == reflect.Ptr; vv = vv.Elem() {
|
138
|
|
}
|
139
|
14
|
return vv
|
140
|
|
}
|
141
|
|
|
142
|
14
|
v = indirect(v)
|
143
|
|
|
144
|
14
|
if !v.IsValid() {
|
145
|
14
|
return
|
146
|
|
}
|
147
|
|
|
148
|
14
|
reset := func(f reflect.Value) {
|
149
|
|
|
150
|
14
|
switch f.Kind() {
|
151
|
14
|
case reflect.Map:
|
152
|
|
|
153
|
14
|
if f.IsNil() {
|
154
|
14
|
return
|
155
|
|
}
|
156
|
|
|
157
|
|
for _, k := range f.MapKeys() {
|
158
|
14
|
f.SetMapIndex(k, reflect.Value{})
|
159
|
|
}
|
160
|
|
|
161
|
14
|
case reflect.Struct, reflect.Slice:
|
162
|
14
|
ResetMaps(f)
|
163
|
|
}
|
164
|
|
}
|
165
|
|
|
166
|
14
|
switch v.Kind() {
|
167
|
|
|
168
|
14
|
case reflect.Map:
|
169
|
14
|
reset(v)
|
170
|
|
|
171
|
14
|
case reflect.Slice:
|
172
|
|
for i := 0; i < v.Len(); i++ {
|
173
|
14
|
reset(indirect(v.Index(i)))
|
174
|
|
}
|
175
|
|
|
176
|
14
|
case reflect.Struct:
|
177
|
|
for i := 0; i < v.NumField(); i++ {
|
178
|
14
|
reset(indirect(v.Field(i)))
|
179
|
|
}
|
180
|
|
}
|
181
|
|
}
|