Example #1
0
// 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
}
Example #2
0
// 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
}