github.com/jbking/gohan@v0.0.0-20151217002006-b41ccf1c2a96/extension/otto/gohan_resource_management.go (about)

     1  // Copyright (C) 2015 NTT Innovation Institute, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  package otto
    17  
    18  import (
    19  	"github.com/dop251/otto"
    20  
    21  	"github.com/cloudwan/gohan/extension"
    22  	"github.com/cloudwan/gohan/schema"
    23  	"github.com/cloudwan/gohan/server/resources"
    24  )
    25  
    26  const (
    27  	noEnvironmentForSchemaErrorMessageFormat = "No environment for schema '%s'"
    28  	wrongResponseErrorMessageFormat          = "Wrong response from %s"
    29  	notADictionaryErrorMessageFormat         = "Not a dictionary: '%v'"
    30  )
    31  
    32  func handleChainError(env *Environment, call *otto.FunctionCall, err error) {
    33  	switch err := err.(type) {
    34  	default:
    35  		ThrowOttoException(call, err.Error())
    36  	case resources.ResourceError:
    37  		throwOtto(call, "ResourceException", err.Message, err.Problem)
    38  	case extension.Error:
    39  		exceptionInfo, _ := env.VM.ToValue(err.ExceptionInfo)
    40  		throwOtto(call, "ExtensionException", err.Error(), exceptionInfo)
    41  	}
    42  }
    43  
    44  func init() {
    45  	gohanChainingInit := func(env *Environment) {
    46  		vm := env.VM
    47  		builtins := map[string]interface{}{
    48  			"gohan_model_list": func(call otto.FunctionCall) otto.Value {
    49  				VerifyCallArguments(&call, "gohan_model_list", 3)
    50  				rawContext, _ := call.Argument(0).Export()
    51  				context, ok := rawContext.(map[string]interface{})
    52  				if !ok {
    53  					ThrowOttoException(&call, noContextMessage)
    54  				}
    55  				schemaID := call.Argument(1).String()
    56  				manager := schema.GetManager()
    57  				currentSchema, ok := manager.Schema(schemaID)
    58  				if !ok {
    59  					ThrowOttoException(&call, unknownSchemaErrorMesssageFormat, schemaID)
    60  				}
    61  				context["schema"] = currentSchema
    62  				context["path"] = currentSchema.GetPluralURL()
    63  				filterObj, _ := call.Argument(2).Export()
    64  				filter := map[string]interface{}{}
    65  				if filterObj != nil {
    66  					filterMap := filterObj.(map[string]interface{})
    67  					for key, value := range filterMap {
    68  						switch value := value.(type) {
    69  						default:
    70  							ThrowOttoException(&call, "Filter not a string nor array of strings")
    71  						case string:
    72  							filter[key] = value
    73  						case []interface{}:
    74  							for _, val := range value {
    75  								v, ok := val.(string)
    76  								if !ok {
    77  									ThrowOttoException(&call, "Filter not a string nor array of strings")
    78  								}
    79  								filter[key] = v
    80  							}
    81  						}
    82  					}
    83  				}
    84  				if err := resources.GetResourcesInTransaction(
    85  					context, currentSchema, filter, nil); err != nil {
    86  					handleChainError(env, &call, err)
    87  				}
    88  				response, ok := context["response"].(map[string]interface{})
    89  				if !ok {
    90  					ThrowOttoException(&call, "No response")
    91  				}
    92  				resources, ok := response[currentSchema.Plural]
    93  				if !ok {
    94  					ThrowOttoException(&call, wrongResponseErrorMessageFormat, "GetMultipleResources.")
    95  				}
    96  				value, _ := vm.ToValue(resources)
    97  				return value
    98  			},
    99  			"gohan_model_fetch": func(call otto.FunctionCall) otto.Value {
   100  				VerifyCallArguments(&call, "gohan_model_fetch", 4)
   101  				rawContext, _ := call.Argument(0).Export()
   102  				context, ok := rawContext.(map[string]interface{})
   103  				if !ok {
   104  					ThrowOttoException(&call, noContextMessage)
   105  				}
   106  				schemaID := call.Argument(1).String()
   107  				manager := schema.GetManager()
   108  				currentSchema, ok := manager.Schema(schemaID)
   109  				if !ok {
   110  					ThrowOttoException(&call, unknownSchemaErrorMesssageFormat, schemaID)
   111  				}
   112  				context["schema"] = currentSchema
   113  				context["path"] = currentSchema.GetPluralURL()
   114  				resourceID := call.Argument(2).String()
   115  				rawTenantIDs, _ := call.Argument(3).Export()
   116  				tenantIDs, ok := rawTenantIDs.([]string)
   117  				if !ok {
   118  					tenantIDs = nil
   119  				}
   120  				if err := resources.GetSingleResourceInTransaction(
   121  					context, currentSchema, resourceID, tenantIDs); err != nil {
   122  					handleChainError(env, &call, err)
   123  				}
   124  				response, ok := context["response"].(map[string]interface{})
   125  				if !ok {
   126  					ThrowOttoException(&call, "No response")
   127  				}
   128  				resource := response[currentSchema.Singular]
   129  				value, _ := vm.ToValue(resource)
   130  				return value
   131  			},
   132  			"gohan_model_create": func(call otto.FunctionCall) otto.Value {
   133  				VerifyCallArguments(&call, "gohan_model_create", 3)
   134  				rawContext, _ := call.Argument(0).Export()
   135  				context, ok := rawContext.(map[string]interface{})
   136  				if !ok {
   137  					ThrowOttoException(&call, noContextMessage)
   138  				}
   139  				schemaID := call.Argument(1).String()
   140  				manager := schema.GetManager()
   141  				currentSchema, ok := manager.Schema(schemaID)
   142  				if !ok {
   143  					ThrowOttoException(&call, unknownSchemaErrorMesssageFormat, schemaID)
   144  				}
   145  				context["schema"] = currentSchema
   146  				context["path"] = currentSchema.GetPluralURL()
   147  				data, _ := call.Argument(2).Export()
   148  				dataMap, ok := data.(map[string]interface{})
   149  				if !ok {
   150  					ThrowOttoException(&call, notADictionaryErrorMessageFormat, dataMap)
   151  				}
   152  				resourceObj, err := manager.LoadResource(currentSchema.ID, dataMap)
   153  				if err != nil {
   154  					handleChainError(env, &call, err)
   155  				}
   156  				if err := resources.CreateResourceInTransaction(
   157  					context, resourceObj); err != nil {
   158  					handleChainError(env, &call, err)
   159  				}
   160  				response, ok := context["response"].(map[string]interface{})
   161  				if !ok {
   162  					ThrowOttoException(&call, "No response")
   163  				}
   164  				resource := response[currentSchema.Singular]
   165  				value, _ := vm.ToValue(resource)
   166  				return value
   167  			},
   168  			"gohan_model_update": func(call otto.FunctionCall) otto.Value {
   169  				VerifyCallArguments(&call, "gohan_model_update", 5)
   170  				rawContext, _ := call.Argument(0).Export()
   171  				context, ok := rawContext.(map[string]interface{})
   172  				if !ok {
   173  					ThrowOttoException(&call, noContextMessage)
   174  				}
   175  				schemaID := call.Argument(1).String()
   176  				manager := schema.GetManager()
   177  				currentSchema, ok := manager.Schema(schemaID)
   178  				if !ok {
   179  					ThrowOttoException(&call, unknownSchemaErrorMesssageFormat, schemaID)
   180  				}
   181  				context["schema"] = currentSchema
   182  				context["path"] = currentSchema.GetPluralURL()
   183  				resourceID := call.Argument(2).String()
   184  				data, _ := call.Argument(3).Export()
   185  
   186  				rawTenantIDs, _ := call.Argument(4).Export()
   187  				tenantIDs, ok := rawTenantIDs.([]string)
   188  				if !ok {
   189  					tenantIDs = nil
   190  				}
   191  
   192  				dataMap, ok := data.(map[string]interface{})
   193  				if !ok {
   194  					ThrowOttoException(&call, notADictionaryErrorMessageFormat, dataMap)
   195  				}
   196  				err := resources.UpdateResourceInTransaction(context, currentSchema, resourceID, dataMap, tenantIDs)
   197  				if err != nil {
   198  					handleChainError(env, &call, err)
   199  				}
   200  				response, ok := context["response"].(map[string]interface{})
   201  				if !ok {
   202  					ThrowOttoException(&call, "No response")
   203  				}
   204  				resource := response[currentSchema.Singular]
   205  				value, _ := vm.ToValue(resource)
   206  				return value
   207  			},
   208  			"gohan_model_delete": func(call otto.FunctionCall) otto.Value {
   209  				VerifyCallArguments(&call, "gohan_model_delete", 3)
   210  				rawContext, _ := call.Argument(0).Export()
   211  				context, ok := rawContext.(map[string]interface{})
   212  				if !ok {
   213  					ThrowOttoException(&call, noContextMessage)
   214  				}
   215  				schemaID := call.Argument(1).String()
   216  				manager := schema.GetManager()
   217  				currentSchema, ok := manager.Schema(schemaID)
   218  				if !ok {
   219  					ThrowOttoException(&call, unknownSchemaErrorMesssageFormat, schemaID)
   220  				}
   221  				context["schema"] = currentSchema
   222  				context["path"] = currentSchema.GetPluralURL()
   223  				resourceID := call.Argument(2).String()
   224  				err := resources.DeleteResourceInTransaction(context, currentSchema, resourceID)
   225  				if err != nil {
   226  					handleChainError(env, &call, err)
   227  				}
   228  				return otto.Value{}
   229  			},
   230  		}
   231  
   232  		for name, object := range builtins {
   233  			vm.Set(name, object)
   234  		}
   235  	}
   236  	RegisterInit(gohanChainingInit)
   237  }