Beispiel #1
0
// Extend extends target schema
func (schema *Schema) Extend(fromSchema *Schema) error {
	if schema.Parent == "" {
		schema.Parent = fromSchema.Parent
	}
	if schema.Prefix == "" {
		schema.Prefix = fromSchema.Prefix
	}
	if schema.URL == "" {
		schema.URL = fromSchema.URL
	}
	if schema.NamespaceID == "" {
		schema.NamespaceID = fromSchema.NamespaceID
	}
	schema.JSONSchema["properties"] = util.ExtendMap(
		util.MaybeMap(schema.JSONSchema["properties"]),
		util.MaybeMap(fromSchema.JSONSchema["properties"]))

	schema.JSONSchema["propertiesOrder"] = util.ExtendStringList(
		util.MaybeStringList(fromSchema.JSONSchema["propertiesOrder"]),
		util.MaybeStringList(schema.JSONSchema["propertiesOrder"]))

MergeAction:
	for _, action := range fromSchema.Actions {
		for _, existingAction := range schema.Actions {
			if action.ID == existingAction.ID {
				continue MergeAction
			}
		}
		schema.Actions = append(schema.Actions, action)
	}
	schema.Metadata = util.ExtendMap(schema.Metadata, fromSchema.Metadata)
	return schema.Init()
}
Beispiel #2
0
func filterSchemaByPermission(schema map[string]interface{}, permission string) map[string]interface{} {
	filteredSchema := map[string]interface{}{"type": "object"}
	filteredProperties := map[string]map[string]interface{}{}
	filteredRequirements := []string{}
	for id, property := range util.MaybeMap(schema["properties"]) {
		propertyMap := util.MaybeMap(property)
		allowedList := util.MaybeStringList(propertyMap["permission"])
		for _, allowed := range allowedList {
			if allowed == permission {
				filteredProperties[id] = propertyMap
			}
		}
	}

	filteredSchema["properties"] = filteredProperties
	requirements := util.MaybeStringList(schema["required"])

	if permission != "create" {
		// required property is used on only create event
		requirements = []string{}
	}

	for _, requirement := range requirements {
		if _, ok := filteredProperties[requirement]; ok {
			filteredRequirements = append(filteredRequirements, requirement)
		}
	}

	filteredSchema["required"] = filteredRequirements
	filteredSchema["additionalProperties"] = false
	return filteredSchema
}
Beispiel #3
0
//GetSchema returns the schema filtered and trimmed for a specific user or nil when the user shouldn't see it at all
func GetSchema(s *schema.Schema, authorization schema.Authorization) (result *schema.Resource, err error) {
	manager := schema.GetManager()
	metaschema, _ := manager.Schema("schema")
	policy, _ := manager.PolicyValidate("read", s.GetPluralURL(), authorization)
	if policy == nil {
		return
	}
	if s.IsAbstract() {
		return
	}
	rawSchema := s.JSON()
	filteredSchema := util.ExtendMap(nil, s.JSONSchema)
	rawSchema["schema"] = filteredSchema
	schemaProperties, schemaPropertiesOrder, schemaRequired := policy.FilterSchema(
		util.MaybeMap(s.JSONSchema["properties"]),
		util.MaybeStringList(s.JSONSchema["propertiesOrder"]),
		util.MaybeStringList(s.JSONSchema["required"]))

	filteredSchema["properties"] = schemaProperties
	filteredSchema["propertiesOrder"] = schemaPropertiesOrder
	filteredSchema["required"] = schemaRequired

	result, err = schema.NewResource(metaschema, rawSchema)
	if err != nil {
		log.Warning("%s %s", result, err)
		return
	}
	return
}
Beispiel #4
0
func include(stmt *Stmt) (func(*Context) (interface{}, error), error) {

	source := util.MaybeString(stmt.RawData["include"])
	if !filepath.IsAbs(source) {
		currentSource := stmt.File
		source = filepath.Clean(filepath.Join(filepath.Dir(currentSource), source))
	}
	importedCode, err := LoadYAMLFile(source)
	if err != nil {
		return nil, stmt.Errorf("yaml parse error: %s", err)
	}
	stmt.Args = map[string]Value{}
	for key, value := range stmt.RawData {
		stmt.Args[key], err = NewValue(value)
		if err != nil {
			return nil, stmt.Errorf("yaml parse error: %s", err)
		}
	}
	stmt.File = source
	stmts, err := MakeStmts(stmt.File, importedCode)
	if err != nil {
		return nil, stmt.Errorf("import code parse error: %s", err)
	}
	stmt.Vars, err = MapToValue(util.MaybeMap(stmt.RawData["vars"]))
	if err != nil {
		return nil, stmt.Errorf("yaml parse error: %s", err)
	}
	return StmtsToFunc(stmt.funcName, stmts)
}
Beispiel #5
0
func serveResponse(w http.ResponseWriter, context map[string]interface{}) {
	response := context["response"]
	responseCode, ok := context["code"].(int)
	if !ok {
		responseCode = 200
	}
	if 200 <= responseCode && responseCode < 300 {
		w.WriteHeader(responseCode)
		routes.ServeJson(w, response)
	} else {
		message := util.MaybeMap(context["exception"])
		middleware.HTTPJSONError(w, message["message"].(string), responseCode)
	}
}
Beispiel #6
0
func parseCode(key string, code interface{}) map[string]interface{} {
	switch c := code.(type) {
	case string:
		l := newLexer(c)
		result := l.parseDict()
		if l.err != nil {
			args := map[string]interface{}{}
			args[key] = c
			return args
		}
		return result
	case map[string]interface{}:
		return c
	case map[interface{}]interface{}:
		return util.MaybeMap(c)
	}
	return map[string]interface{}{key: code}
}
Beispiel #7
0
// Init initializes schema
func (schema *Schema) Init() error {
	if schema.IsAbstract() {
		return nil
	}
	jsonSchema := schema.JSONSchema
	parent := schema.Parent

	required := util.MaybeStringList(jsonSchema["required"])
	properties := util.MaybeMap(jsonSchema["properties"])
	propertiesOrder := util.MaybeStringList(jsonSchema["propertiesOrder"])
	if parent != "" && properties[FormatParentID(parent)] == nil {
		properties[FormatParentID(parent)] = getParentPropertyObj(parent, parent)
		propertiesOrder = append(propertiesOrder, FormatParentID(parent))
		required = append(required, FormatParentID(parent))
	}

	jsonSchema["required"] = required

	schema.JSONSchemaOnCreate = filterSchemaByPermission(jsonSchema, "create")
	schema.JSONSchemaOnUpdate = filterSchemaByPermission(jsonSchema, "update")

	schema.Properties = []Property{}
	for key := range properties {
		if !util.ContainsString(propertiesOrder, key) {
			propertiesOrder = append(propertiesOrder, key)
		}
	}
	jsonSchema["propertiesOrder"] = propertiesOrder

	for _, id := range propertiesOrder {
		property, ok := properties[id]
		if !ok {
			continue
		}
		propertyRequired := util.ContainsString(required, id)
		propertyObj, err := NewPropertyFromObj(id, property, propertyRequired)
		if err != nil {
			return fmt.Errorf("Invalid schema: Properties is missing %v", err)
		}
		schema.Properties = append(schema.Properties, *propertyObj)
	}
	return nil
}
Beispiel #8
0
func define(stmt *Stmt) (func(*Context) (interface{}, error), error) {
	var err error
	funcName := util.MaybeString(stmt.Args["name"].Value(nil))
	defineNode := MappingNodeToMap(stmt.RawNode["define"])
	funcArgs := util.MaybeMap(stmt.Args["args"].Value(nil))
	stmts, err := MakeStmts(stmt.File, defineNode["body"])
	if err != nil {
		return nil, stmt.Errorf("error in define body: %s", err)
	}
	var body func(*Context) (interface{}, error)
	RegisterStmtParser(
		funcName,
		func(aStmt *Stmt) (func(*Context) (interface{}, error), error) {
			for key := range funcArgs {
				_, ok := aStmt.Args[key]
				if !ok {
					return nil, fmt.Errorf("missing augument %s", key)
				}
			}
			return func(context *Context) (value interface{}, err error) {
				vm := context.VM
				newContext := NewContext(vm)
				for key := range funcArgs {
					newContext.Set(key, aStmt.Arg(key, context))
				}
				value, err = body(newContext)

				if vm.debugReturn {
					vm.debugReturn = false
					vm.debug = true
				}
				return
			}, nil
		})
	body, err = StmtsToFunc("funcName", stmts)
	if err != nil {
		return nil, err
	}
	return func(context *Context) (interface{}, error) {
		return nil, nil
	}, nil
}
Beispiel #9
0
func command(stmt *gohanscript.Stmt) (func(*gohanscript.Context) (interface{}, error), error) {
	var err error
	stmt.Args, err = gohanscript.MapToValue(util.MaybeMap(stmt.RawData["args"]))
	if err != nil {
		return nil, err
	}
	stmt.Args["command"], err = gohanscript.NewValue(stmt.RawData["command"])
	if err != nil {
		return nil, err
	}
	return func(context *gohanscript.Context) (interface{}, error) {
		chdir := stmt.Arg("chdir", context)
		if chdir != nil {
			currentDir, _ := filepath.Abs(".")
			os.Chdir(util.MaybeString(chdir))
			defer os.Chdir(currentDir)
		}
		command := util.MaybeString(stmt.Arg("command", context))
		parts := strings.Fields(command)
		result, err := exec.Command(parts[0], parts[1:]...).CombinedOutput()
		return string(result), err
	}, nil
}
Beispiel #10
0
//NewSchemaFromObj is a constructor for a schema by obj
func NewSchemaFromObj(rawTypeData interface{}) (*Schema, error) {
	typeData := rawTypeData.(map[string]interface{})

	metaschema, ok := GetManager().Schema("schema")
	if ok {
		err := metaschema.Validate(metaschema.JSONSchema, typeData)
		if err != nil {
			return nil, err
		}
	}

	id := util.MaybeString(typeData["id"])
	if id == "" {
		return nil, &typeAssertionError{"id"}
	}
	plural := util.MaybeString(typeData["plural"])
	if plural == "" {
		return nil, &typeAssertionError{"plural"}
	}
	title := util.MaybeString(typeData["title"])
	if title == "" {
		return nil, &typeAssertionError{"title"}
	}
	description := util.MaybeString(typeData["description"])
	if description == "" {
		return nil, &typeAssertionError{"description"}
	}
	singular := util.MaybeString(typeData["singular"])
	if singular == "" {
		return nil, &typeAssertionError{"singular"}
	}

	schema := NewSchema(id, plural, title, description, singular)

	schema.Prefix = util.MaybeString(typeData["prefix"])
	schema.URL = util.MaybeString(typeData["url"])
	schema.Type = util.MaybeString(typeData["type"])
	schema.Parent = util.MaybeString(typeData["parent"])
	schema.OnParentDeleteCascade, _ = typeData["on_parent_delete_cascade"].(bool)
	schema.NamespaceID = util.MaybeString(typeData["namespace"])
	schema.IsolationLevel = util.MaybeMap(typeData["isolation_level"])
	jsonSchema, ok := typeData["schema"].(map[string]interface{})
	if !ok {
		return nil, &typeAssertionError{"schema"}
	}
	schema.JSONSchema = jsonSchema

	schema.Metadata = util.MaybeMap(typeData["metadata"])
	schema.Extends = util.MaybeStringList(typeData["extends"])

	actions := util.MaybeMap(typeData["actions"])
	schema.Actions = []Action{}
	for actionID, actionBody := range actions {
		action, err := NewActionFromObject(actionID, actionBody)
		if err != nil {
			return nil, err
		}
		schema.Actions = append(schema.Actions, action)
	}

	if err := schema.Init(); err != nil {
		return nil, err
	}
	return schema, nil
}
Beispiel #11
0
func httpServer(stmt *gohanscript.Stmt) (func(*gohanscript.Context) (interface{}, error), error) {
	return func(globalContext *gohanscript.Context) (interface{}, error) {
		m := martini.Classic()
		var mutex = &sync.Mutex{}
		history := []interface{}{}
		server := map[string]interface{}{
			"history": history,
		}
		m.Handlers()
		m.Use(middleware.Logging())
		m.Use(martini.Recovery())
		rawBody := util.MaybeMap(stmt.RawData["http_server"])
		paths := util.MaybeMap(rawBody["paths"])
		middlewareCode := util.MaybeString(rawBody["middleware"])
		if middlewareCode != "" {
			vm := gohanscript.NewVM()
			err := vm.LoadString(stmt.File, middlewareCode)

			if err != nil {
				return nil, err
			}
			m.Use(func(w http.ResponseWriter, r *http.Request) {
				context := globalContext.Extend(nil)
				fillInContext(context.Data(), r, w, nil)

				reqData, _ := ioutil.ReadAll(r.Body)
				buff := ioutil.NopCloser(bytes.NewBuffer(reqData))
				r.Body = buff
				var data interface{}
				if reqData != nil {
					json.Unmarshal(reqData, &data)
				}

				context.Set("request", data)
				vm.Run(context.Data())
			})
		}
		m.Use(func(w http.ResponseWriter, r *http.Request) {
			reqData, _ := ioutil.ReadAll(r.Body)
			buff := ioutil.NopCloser(bytes.NewBuffer(reqData))
			r.Body = buff
			var data interface{}
			if reqData != nil {
				json.Unmarshal(reqData, &data)
			}
			mutex.Lock()
			server["history"] = append(server["history"].([]interface{}),
				map[string]interface{}{
					"method": r.Method,
					"path":   r.URL.String(),
					"data":   data,
				})
			mutex.Unlock()
		})
		for path, body := range paths {
			methods, ok := body.(map[string]interface{})
			if !ok {
				continue
			}
			for method, rawRouteBody := range methods {
				routeBody, ok := rawRouteBody.(map[string]interface{})
				if !ok {
					continue
				}
				code := util.MaybeString(routeBody["code"])
				vm := gohanscript.NewVM()
				err := vm.LoadString(stmt.File, code)
				if err != nil {
					return nil, err
				}
				switch method {
				case "get":
					m.Get(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) {
						context := globalContext.Extend(nil)
						fillInContext(context.Data(), r, w, p)
						vm.Run(context.Data())
						serveResponse(w, context.Data())
					})
				case "post":
					m.Post(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) {
						context := globalContext.Extend(nil)
						fillInContext(context.Data(), r, w, p)
						requestData, _ := middleware.ReadJSON(r)
						context.Set("request", requestData)
						vm.Run(context.Data())
						serveResponse(w, context.Data())
					})
				case "put":
					m.Put(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) {
						context := globalContext.Extend(nil)
						fillInContext(context.Data(), r, w, p)
						requestData, _ := middleware.ReadJSON(r)
						context.Set("request", requestData)
						vm.Run(context.Data())
						serveResponse(w, context.Data())
					})
				case "delete":
					m.Delete(path, func(w http.ResponseWriter, r *http.Request, p martini.Params) {
						context := globalContext.Extend(nil)
						fillInContext(context.Data(), r, w, p)
						vm.Run(context.Data())
						serveResponse(w, context.Data())
					})
				}
			}
		}
		testMode := stmt.Args["test"].Value(globalContext).(bool)
		if testMode {
			ts := httptest.NewServer(m)
			server["server"] = ts
			return server, nil
		}
		m.RunOnAddr(stmt.Args["address"].Value(globalContext).(string))
		return nil, nil
	}, nil
}
Beispiel #12
0
//NewStmt makes gohan statement from yaml node
func NewStmt(FileName string, node *yaml.Node) (stmt *Stmt, err error) {
	if node == nil {
		return nil, nil
	}
	stmt = &Stmt{}
	stmt.RawNode = MappingNodeToMap(node)
	stmt.Line = node.Line + 1
	stmt.Column = node.Column
	var rawData interface{}
	yaml.UnmarshalNode(node, &rawData)
	stmt.RawData = util.MaybeMap(convertMapformat(rawData))
	stmt.Name = util.MaybeString(stmt.RawData["name"])
	stmt.File, _ = filepath.Abs(FileName)
	stmt.Dir = filepath.Dir(stmt.File)
	stmt.Always, err = MakeStmts(FileName, stmt.RawNode["always"])
	if err != nil {
		return nil, stmt.Error(err)
	}
	stmt.Rescue, err = MakeStmts(FileName, stmt.RawNode["rescue"])
	if err != nil {
		return nil, stmt.Error(err)
	}
	stmt.ElseStmt, err = MakeStmts(FileName, stmt.RawNode["else"])
	if err != nil {
		return nil, stmt.Error(err)
	}
	stmt.Retry = util.MaybeInt(stmt.RawData["retries"])
	stmt.Worker = util.MaybeInt(stmt.RawData["worker"])
	stmt.LoopVar = util.MaybeString(stmt.RawData["loop_var"])
	if stmt.LoopVar == "" {
		stmt.LoopVar = "item"
	}
	if stmt.Retry == 0 {
		stmt.Retry = 1
	}
	stmt.Delay = util.MaybeInt(stmt.RawData["delay"])
	stmt.WithItems, err = NewValue(stmt.RawData["with_items"])
	if err != nil {
		return nil, stmt.Error(err)
	}
	stmt.WithDict, err = NewValue(stmt.RawData["with_dict"])
	if err != nil {
		return nil, stmt.Error(err)
	}
	if stmt.RawData["when"] != nil {
		stmt.When, err = CompileExpr(util.MaybeString(stmt.RawData["when"]))
		if err != nil {
			return nil, stmt.Error(err)
		}
	}
	if stmt.RawData["until"] != nil {
		stmt.Until, err = CompileExpr(util.MaybeString(stmt.RawData["until"]))
		if err != nil {
			return nil, stmt.Error(err)
		}
	}
	stmt.Register = util.MaybeString(stmt.RawData["register"])
	stmt.Vars, err = MapToValue(util.MaybeMap(stmt.RawData["vars"]))
	if err != nil {
		return nil, stmt.Error(err)
	}
	return stmt, nil
}
Beispiel #13
0
// MaybeMap resturns a Map or nil
func (context *Context) MaybeMap(key string) map[string]interface{} {
	return util.MaybeMap(context.MayGet(key))
}