// Validate a stone. func Validate(stoneData interface{}) error { var metaID string // parse stone data to map[string]interface{} stoneData is string var data map[string]interface{} switch d := stoneData.(type) { case string: decoder := json.NewDecoder(strings.NewReader(d)) decoder.UseNumber() if err := decoder.Decode(&data); err != nil { return errors.New("unable to parse json string") } break case map[string]interface{}: data = d break default: return errors.New("unsupported parameter type") } // must have `meta` block if data["meta"] == nil { return errors.New("missing `meta` block") } else { if !util.IsMapOfAny(data["meta"]) { return errors.New("`meta` block value type is invalid. Expects a JSON object") } if err := ValidateMetaBlock(data["meta"].(map[string]interface{})); err != nil { return err } metaBlock := data["meta"].(map[string]interface{}) metaID = metaBlock["id"].(string) } // if `ownership` block exists, it must be a map if data["ownership"] != nil { if !util.IsMapOfAny(data["ownership"]) { return errors.New("`ownership` block value type is invalid. Expects a JSON object") } if !util.IsMapEmpty(data["ownership"].(map[string]interface{})) { if err := ValidateOwnershipBlock(data["ownership"].(map[string]interface{}), metaID); err != nil { return err } } } // if `attributes` block exists, it must be a map if data["attributes"] != nil { if !util.IsMapOfAny(data["attributes"]) { return errors.New("`attributes` block value type is invalid. Expects a JSON object") } if !util.IsMapEmpty(data["attributes"].(map[string]interface{})) { if err := ValidateAttributesBlock(data["attributes"].(map[string]interface{}), metaID); err != nil { return err } } } // if `embeds` block exists, it must be a map if data["embeds"] != nil { if !util.IsMapOfAny(data["embeds"]) { return errors.New("`embeds` block value type is invalid. Expects a JSON object") } if !util.IsMapEmpty(data["embeds"].(map[string]interface{})) { if err := ValidateEmbedsBlock(data["embeds"].(map[string]interface{}), metaID); err != nil { return err } } } return nil }
// Validate ownership block. // // Rules: // // - It must not contain unknown properties. // - A valid ownership block can only contain ref_id, type, sole and status properties. // - `ownership.ref_id` property must be set and value type must be string. // - `ref_id` property must be equal to the meta id. // - A valid ownership block can only contain type, sole and status properties. // - `ownership.type` property must be set, value type must be a string and value must be known. // // If ownership.type is 'sole': // - `ownership.sole` must be set to an object. // - `ownership.sole.address_id` must be set and it must be a string. // - `ownership.status` is optional, but if set. // - `ownership.status` must be a string value. The value must also be known. func ValidateOwnershipBlock(ownership map[string]interface{}, metaID string) error { // must reject unexpected properties accetableProps := []string{"ref_id", "type", "sole", "status"} for prop, _ := range ownership { if !util.InStringSlice(accetableProps, prop) { return errors.New(fmt.Sprintf("`%s` property is unexpected in `ownership` block", prop)) } } // `ref_id` property must be set if ownership["ref_id"] == nil { return errors.New("`ownership` block is missing `ref_id` property") } // `ref_id` property must be a string value if !util.IsStringValue(ownership["ref_id"]) { return errors.New("`ownership.ref_id` value type is invalid. Expects string value") } // `ref_id` property must be equal to meta id if ownership["ref_id"].(string) != metaID { return errors.New("`ownership.ref_id` not equal to `meta.id`") } // `type` property must be set if ownership["type"] == nil { return errors.New("`ownership` block is missing `type` property") } // type property must have string value if !util.IsStringValue(ownership["type"]) { return errors.New("`ownership.type` value type is invalid. Expects a string") } // type property value must be known acceptableValues := []string{"sole"} if !util.InStringSlice(acceptableValues, ownership["type"].(string)) { return errors.New("`ownership.type` property has unexpected value") } // if ownership.type is `sole`, `sole` property is required if ownership["type"].(string) == "sole" && ownership["sole"] == nil { return errors.New("`ownership` block is missing `sole` property") } else { // `sole` property must be a map if !util.IsMapOfAny(ownership["sole"]) { return errors.New("`ownership.sole` value type is invalid. Expects a JSON object") } // `sole` property must have `address_id` property soleProperty := ownership["sole"].(map[string]interface{}) if soleProperty["address_id"] == nil { return errors.New("`ownership.sole` property is missing `address_id` property") } // `sole.address_id` value type must be string if !util.IsStringValue(soleProperty["address_id"]) { return errors.New("`ownership.sole.address_id` value type is invalid. Expects a string") } } // `status` property is optional, but if set, it's type must be string // and must have acceptable values if ownership["status"] != nil { if !util.IsStringValue(ownership["status"]) { return errors.New("`ownership.status` value type is invalid. Expects a string") } if !util.InStringSlice([]string{"transferred"}, ownership["status"].(string)) { return errors.New("`ownership.status` property has unexpected value") } } return nil }