mirror of
https://github.com/rancher/norman.git
synced 2025-09-06 17:50:25 +00:00
Add edit/export modes and drop default resource fields if empty
This commit is contained in:
@@ -30,11 +30,15 @@ type Builder struct {
|
|||||||
Version *types.APIVersion
|
Version *types.APIVersion
|
||||||
Schemas *types.Schemas
|
Schemas *types.Schemas
|
||||||
RefValidator types.ReferenceValidator
|
RefValidator types.ReferenceValidator
|
||||||
|
edit bool
|
||||||
|
export bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBuilder(apiRequest *types.APIContext) *Builder {
|
func NewBuilder(apiRequest *types.APIContext) *Builder {
|
||||||
return &Builder{
|
return &Builder{
|
||||||
apiContext: apiRequest,
|
apiContext: apiRequest,
|
||||||
|
edit: apiRequest.Option("edit") == "true",
|
||||||
|
export: apiRequest.Option("export") == "true",
|
||||||
Version: apiRequest.Version,
|
Version: apiRequest.Version,
|
||||||
Schemas: apiRequest.Schemas,
|
Schemas: apiRequest.Schemas,
|
||||||
RefValidator: apiRequest.ReferenceValidator,
|
RefValidator: apiRequest.ReferenceValidator,
|
||||||
@@ -99,7 +103,7 @@ func (b *Builder) copyInputs(schema *types.Schema, input map[string]interface{},
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if op.IsList() {
|
if op.IsList() && !b.edit && !b.export {
|
||||||
if !convert.IsEmpty(input["type"]) {
|
if !convert.IsEmpty(input["type"]) {
|
||||||
result["type"] = input["type"]
|
result["type"] = input["type"]
|
||||||
}
|
}
|
||||||
@@ -142,9 +146,69 @@ func (b *Builder) checkDefaultAndRequired(schema *types.Schema, input map[string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if op.IsList() && b.edit {
|
||||||
|
b.populateMissingFieldsForEdit(schema, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
if op.IsList() && b.export {
|
||||||
|
b.dropDefaults(schema, result)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *Builder) dropDefaults(schema *types.Schema, result map[string]interface{}) {
|
||||||
|
for name, existingVal := range result {
|
||||||
|
field, ok := schema.ResourceFields[name]
|
||||||
|
if !ok {
|
||||||
|
delete(result, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !field.Create {
|
||||||
|
delete(result, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.Default == existingVal {
|
||||||
|
delete(result, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
val, err := b.convert(field.Type, nil, List)
|
||||||
|
if err == nil && val == existingVal {
|
||||||
|
delete(result, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if convert.IsEmpty(existingVal) {
|
||||||
|
delete(result, name)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (b *Builder) populateMissingFieldsForEdit(schema *types.Schema, result map[string]interface{}) {
|
||||||
|
for name, field := range schema.ResourceFields {
|
||||||
|
if !field.Update {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
_, hasKey := result[name]
|
||||||
|
if hasKey {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if field.Default != nil {
|
||||||
|
result[name] = field.Default
|
||||||
|
} else {
|
||||||
|
val, err := b.convert(field.Type, nil, List)
|
||||||
|
if err == nil {
|
||||||
|
result[name] = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (b *Builder) copyFields(schema *types.Schema, input map[string]interface{}, op Operation) (map[string]interface{}, error) {
|
func (b *Builder) copyFields(schema *types.Schema, input map[string]interface{}, op Operation) (map[string]interface{}, error) {
|
||||||
result := map[string]interface{}{}
|
result := map[string]interface{}{}
|
||||||
|
|
||||||
|
@@ -343,7 +343,28 @@ type MultiErrors struct {
|
|||||||
Errors []error
|
Errors []error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewErrors(errors ...error) error {
|
type Errors struct {
|
||||||
|
errors []error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Errors) Add(err error) {
|
||||||
|
if err != nil {
|
||||||
|
e.errors = append(e.errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Errors) Err() error {
|
||||||
|
return NewErrors(e.errors...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewErrors(inErrors ...error) error {
|
||||||
|
var errors []error
|
||||||
|
for _, err := range inErrors {
|
||||||
|
if err != nil {
|
||||||
|
errors = append(errors, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(errors) == 0 {
|
if len(errors) == 0 {
|
||||||
return nil
|
return nil
|
||||||
} else if len(errors) == 1 {
|
} else if len(errors) == 1 {
|
||||||
|
@@ -12,13 +12,14 @@ type ValuesMap struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type RawResource struct {
|
type RawResource struct {
|
||||||
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
ID string `json:"id,omitempty" yaml:"id,omitempty"`
|
||||||
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
Type string `json:"type,omitempty" yaml:"type,omitempty"`
|
||||||
Schema *Schema `json:"-" yaml:"-"`
|
Schema *Schema `json:"-" yaml:"-"`
|
||||||
Links map[string]string `json:"links" yaml:"links"`
|
Links map[string]string `json:"links,omitempty" yaml:"links,omitempty"`
|
||||||
Actions map[string]string `json:"actions" yaml:"actions"`
|
Actions map[string]string `json:"actions,omitempty" yaml:"actions,omitempty"`
|
||||||
Values map[string]interface{} `json:",inline"`
|
Values map[string]interface{} `json:",inline" yaml:",inline"`
|
||||||
ActionLinks bool `json:"-"`
|
ActionLinks bool `json:"-" yaml:"-"`
|
||||||
|
DropReadOnly bool `json:"-" yaml:"-"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RawResource) AddAction(apiContext *APIContext, name string) {
|
func (r *RawResource) AddAction(apiContext *APIContext, name string) {
|
||||||
@@ -26,23 +27,38 @@ func (r *RawResource) AddAction(apiContext *APIContext, name string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (r *RawResource) MarshalJSON() ([]byte, error) {
|
func (r *RawResource) MarshalJSON() ([]byte, error) {
|
||||||
|
return json.Marshal(r.ToMap())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *RawResource) ToMap() map[string]interface{} {
|
||||||
data := map[string]interface{}{}
|
data := map[string]interface{}{}
|
||||||
for k, v := range r.Values {
|
for k, v := range r.Values {
|
||||||
data[k] = v
|
data[k] = v
|
||||||
}
|
}
|
||||||
if r.ID != "" {
|
|
||||||
|
if r.ID != "" && !r.DropReadOnly {
|
||||||
data["id"] = r.ID
|
data["id"] = r.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
data["type"] = r.Type
|
if r.Type != "" && !r.DropReadOnly {
|
||||||
data["baseType"] = r.Schema.BaseType
|
data["type"] = r.Type
|
||||||
data["links"] = r.Links
|
|
||||||
if r.ActionLinks {
|
|
||||||
data["actionLinks"] = r.Actions
|
|
||||||
} else {
|
|
||||||
data["actions"] = r.Actions
|
|
||||||
}
|
}
|
||||||
return json.Marshal(data)
|
if r.Schema.BaseType != "" && !r.DropReadOnly {
|
||||||
|
data["baseType"] = r.Schema.BaseType
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.Links) > 0 && !r.DropReadOnly {
|
||||||
|
data["links"] = r.Links
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(r.Actions) > 0 && !r.DropReadOnly {
|
||||||
|
if r.ActionLinks {
|
||||||
|
data["actionLinks"] = r.Actions
|
||||||
|
} else {
|
||||||
|
data["actions"] = r.Actions
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
type ActionHandler func(actionName string, action *Action, request *APIContext) error
|
type ActionHandler func(actionName string, action *Action, request *APIContext) error
|
||||||
@@ -124,6 +140,10 @@ func GetAPIContext(ctx context.Context) *APIContext {
|
|||||||
return apiContext
|
return apiContext
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *APIContext) Option(key string) string {
|
||||||
|
return r.Query.Get("_" + key)
|
||||||
|
}
|
||||||
|
|
||||||
func (r *APIContext) WriteResponse(code int, obj interface{}) {
|
func (r *APIContext) WriteResponse(code int, obj interface{}) {
|
||||||
r.ResponseWriter.Write(r, code, obj)
|
r.ResponseWriter.Write(r, code, obj)
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user