Last active
August 29, 2015 14:21
-
-
Save israelshirk/0fdc158e70d82f6ba90f to your computer and use it in GitHub Desktop.
TV4 with recursive reference lookups... Just in case the graphics card keeps tossing cookies...
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Author: Geraint Luff and others | |
Year: 2013 | |
This code is released into the "public domain" by its author(s). Anybody may use, alter and distribute the code without restriction. The author makes no guarantees, and takes no liability of any kind for use of this code. | |
If you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory. | |
*/ | |
(function (global, factory) { | |
if (typeof define === 'function' && define.amd) { | |
// AMD. Register as an anonymous module. | |
define([], factory); | |
} else if (typeof module !== 'undefined' && module.exports){ | |
// CommonJS. Define export. | |
module.exports = factory(); | |
} else { | |
// Browser globals | |
global.tv4 = factory(); | |
} | |
}(this, function () { | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys | |
if (!Object.keys) { | |
Object.keys = (function () { | |
var hasOwnProperty = Object.prototype.hasOwnProperty, | |
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), | |
dontEnums = [ | |
'toString', | |
'toLocaleString', | |
'valueOf', | |
'hasOwnProperty', | |
'isPrototypeOf', | |
'propertyIsEnumerable', | |
'constructor' | |
], | |
dontEnumsLength = dontEnums.length; | |
return function (obj) { | |
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) { | |
throw new TypeError('Object.keys called on non-object'); | |
} | |
var result = []; | |
for (var prop in obj) { | |
if (hasOwnProperty.call(obj, prop)) { | |
result.push(prop); | |
} | |
} | |
if (hasDontEnumBug) { | |
for (var i=0; i < dontEnumsLength; i++) { | |
if (hasOwnProperty.call(obj, dontEnums[i])) { | |
result.push(dontEnums[i]); | |
} | |
} | |
} | |
return result; | |
}; | |
})(); | |
} | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create | |
if (!Object.create) { | |
Object.create = (function(){ | |
function F(){} | |
return function(o){ | |
if (arguments.length !== 1) { | |
throw new Error('Object.create implementation only accepts one parameter.'); | |
} | |
F.prototype = o; | |
return new F(); | |
}; | |
})(); | |
} | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FisArray | |
if(!Array.isArray) { | |
Array.isArray = function (vArg) { | |
return Object.prototype.toString.call(vArg) === "[object Array]"; | |
}; | |
} | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf | |
if (!Array.prototype.indexOf) { | |
Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) { | |
if (this === null) { | |
throw new TypeError(); | |
} | |
var t = Object(this); | |
var len = t.length >>> 0; | |
if (len === 0) { | |
return -1; | |
} | |
var n = 0; | |
if (arguments.length > 1) { | |
n = Number(arguments[1]); | |
if (n !== n) { // shortcut for verifying if it's NaN | |
n = 0; | |
} else if (n !== 0 && n !== Infinity && n !== -Infinity) { | |
n = (n > 0 || -1) * Math.floor(Math.abs(n)); | |
} | |
} | |
if (n >= len) { | |
return -1; | |
} | |
var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0); | |
for (; k < len; k++) { | |
if (k in t && t[k] === searchElement) { | |
return k; | |
} | |
} | |
return -1; | |
}; | |
} | |
// Grungey Object.isFrozen hack | |
if (!Object.isFrozen) { | |
Object.isFrozen = function (obj) { | |
var key = "tv4_test_frozen_key"; | |
while (obj.hasOwnProperty(key)) { | |
key += Math.random(); | |
} | |
try { | |
obj[key] = true; | |
delete obj[key]; | |
return false; | |
} catch (e) { | |
return true; | |
} | |
}; | |
} | |
// Based on: https://github.com/geraintluff/uri-templates, but with all the de-substitution stuff removed | |
var uriTemplateGlobalModifiers = { | |
"+": true, | |
"#": true, | |
".": true, | |
"/": true, | |
";": true, | |
"?": true, | |
"&": true | |
}; | |
var uriTemplateSuffices = { | |
"*": true | |
}; | |
function notReallyPercentEncode(string) { | |
return encodeURI(string).replace(/%25[0-9][0-9]/g, function (doubleEncoded) { | |
return "%" + doubleEncoded.substring(3); | |
}); | |
} | |
function uriTemplateSubstitution(spec) { | |
var modifier = ""; | |
if (uriTemplateGlobalModifiers[spec.charAt(0)]) { | |
modifier = spec.charAt(0); | |
spec = spec.substring(1); | |
} | |
var separator = ""; | |
var prefix = ""; | |
var shouldEscape = true; | |
var showVariables = false; | |
var trimEmptyString = false; | |
if (modifier === '+') { | |
shouldEscape = false; | |
} else if (modifier === ".") { | |
prefix = "."; | |
separator = "."; | |
} else if (modifier === "/") { | |
prefix = "/"; | |
separator = "/"; | |
} else if (modifier === '#') { | |
prefix = "#"; | |
shouldEscape = false; | |
} else if (modifier === ';') { | |
prefix = ";"; | |
separator = ";"; | |
showVariables = true; | |
trimEmptyString = true; | |
} else if (modifier === '?') { | |
prefix = "?"; | |
separator = "&"; | |
showVariables = true; | |
} else if (modifier === '&') { | |
prefix = "&"; | |
separator = "&"; | |
showVariables = true; | |
} | |
var varNames = []; | |
var varList = spec.split(","); | |
var varSpecs = []; | |
var varSpecMap = {}; | |
for (var i = 0; i < varList.length; i++) { | |
var varName = varList[i]; | |
var truncate = null; | |
if (varName.indexOf(":") !== -1) { | |
var parts = varName.split(":"); | |
varName = parts[0]; | |
truncate = parseInt(parts[1], 10); | |
} | |
var suffices = {}; | |
while (uriTemplateSuffices[varName.charAt(varName.length - 1)]) { | |
suffices[varName.charAt(varName.length - 1)] = true; | |
varName = varName.substring(0, varName.length - 1); | |
} | |
var varSpec = { | |
truncate: truncate, | |
name: varName, | |
suffices: suffices | |
}; | |
varSpecs.push(varSpec); | |
varSpecMap[varName] = varSpec; | |
varNames.push(varName); | |
} | |
var subFunction = function (valueFunction) { | |
var result = ""; | |
var startIndex = 0; | |
for (var i = 0; i < varSpecs.length; i++) { | |
var varSpec = varSpecs[i]; | |
var value = valueFunction(varSpec.name); | |
if (value === null || value === undefined || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0)) { | |
startIndex++; | |
continue; | |
} | |
if (i === startIndex) { | |
result += prefix; | |
} else { | |
result += (separator || ","); | |
} | |
if (Array.isArray(value)) { | |
if (showVariables) { | |
result += varSpec.name + "="; | |
} | |
for (var j = 0; j < value.length; j++) { | |
if (j > 0) { | |
result += varSpec.suffices['*'] ? (separator || ",") : ","; | |
if (varSpec.suffices['*'] && showVariables) { | |
result += varSpec.name + "="; | |
} | |
} | |
result += shouldEscape ? encodeURIComponent(value[j]).replace(/!/g, "%21") : notReallyPercentEncode(value[j]); | |
} | |
} else if (typeof value === "object") { | |
if (showVariables && !varSpec.suffices['*']) { | |
result += varSpec.name + "="; | |
} | |
var first = true; | |
for (var key in value) { | |
if (!first) { | |
result += varSpec.suffices['*'] ? (separator || ",") : ","; | |
} | |
first = false; | |
result += shouldEscape ? encodeURIComponent(key).replace(/!/g, "%21") : notReallyPercentEncode(key); | |
result += varSpec.suffices['*'] ? '=' : ","; | |
result += shouldEscape ? encodeURIComponent(value[key]).replace(/!/g, "%21") : notReallyPercentEncode(value[key]); | |
} | |
} else { | |
if (showVariables) { | |
result += varSpec.name; | |
if (!trimEmptyString || value !== "") { | |
result += "="; | |
} | |
} | |
if (varSpec.truncate != null) { | |
value = value.substring(0, varSpec.truncate); | |
} | |
result += shouldEscape ? encodeURIComponent(value).replace(/!/g, "%21"): notReallyPercentEncode(value); | |
} | |
} | |
return result; | |
}; | |
subFunction.varNames = varNames; | |
return { | |
prefix: prefix, | |
substitution: subFunction | |
}; | |
} | |
function UriTemplate(template) { | |
if (!(this instanceof UriTemplate)) { | |
return new UriTemplate(template); | |
} | |
var parts = template.split("{"); | |
var textParts = [parts.shift()]; | |
var prefixes = []; | |
var substitutions = []; | |
var varNames = []; | |
while (parts.length > 0) { | |
var part = parts.shift(); | |
var spec = part.split("}")[0]; | |
var remainder = part.substring(spec.length + 1); | |
var funcs = uriTemplateSubstitution(spec); | |
substitutions.push(funcs.substitution); | |
prefixes.push(funcs.prefix); | |
textParts.push(remainder); | |
varNames = varNames.concat(funcs.substitution.varNames); | |
} | |
this.fill = function (valueFunction) { | |
var result = textParts[0]; | |
for (var i = 0; i < substitutions.length; i++) { | |
var substitution = substitutions[i]; | |
result += substitution(valueFunction); | |
result += textParts[i + 1]; | |
} | |
return result; | |
}; | |
this.varNames = varNames; | |
this.template = template; | |
} | |
UriTemplate.prototype = { | |
toString: function () { | |
return this.template; | |
}, | |
fillFromObject: function (obj) { | |
return this.fill(function (varName) { | |
return obj[varName]; | |
}); | |
} | |
}; | |
var ValidatorContext = function ValidatorContext(parent, collectMultiple, errorMessages, checkRecursive, trackUnknownProperties) { | |
this.missing = []; | |
this.missingMap = {}; | |
this.formatValidators = parent ? Object.create(parent.formatValidators) : {}; | |
this.schemas = parent ? Object.create(parent.schemas) : {}; | |
this.collectMultiple = collectMultiple; | |
this.errors = []; | |
this.handleError = collectMultiple ? this.collectError : this.returnError; | |
if (checkRecursive) { | |
this.checkRecursive = true; | |
this.scanned = []; | |
this.scannedFrozen = []; | |
this.scannedFrozenSchemas = []; | |
this.scannedFrozenValidationErrors = []; | |
this.validatedSchemasKey = 'tv4_validation_id'; | |
this.validationErrorsKey = 'tv4_validation_errors_id'; | |
} | |
if (trackUnknownProperties) { | |
this.trackUnknownProperties = true; | |
this.knownPropertyPaths = {}; | |
this.unknownPropertyPaths = {}; | |
} | |
this.errorMessages = errorMessages; | |
this.definedKeywords = {}; | |
if (parent) { | |
for (var key in parent.definedKeywords) { | |
this.definedKeywords[key] = parent.definedKeywords[key].slice(0); | |
} | |
} | |
}; | |
ValidatorContext.prototype.defineKeyword = function (keyword, keywordFunction) { | |
this.definedKeywords[keyword] = this.definedKeywords[keyword] || []; | |
this.definedKeywords[keyword].push(keywordFunction); | |
}; | |
ValidatorContext.prototype.createError = function (code, messageParams, dataPath, schemaPath, subErrors) { | |
var messageTemplate = this.errorMessages[code] || ErrorMessagesDefault[code]; | |
if (typeof messageTemplate !== 'string') { | |
return new ValidationError(code, "Unknown error code " + code + ": " + JSON.stringify(messageParams), messageParams, dataPath, schemaPath, subErrors); | |
} | |
// Adapted from Crockford's supplant() | |
var message = messageTemplate.replace(/\{([^{}]*)\}/g, function (whole, varName) { | |
var subValue = messageParams[varName]; | |
return typeof subValue === 'string' || typeof subValue === 'number' ? subValue : whole; | |
}); | |
return new ValidationError(code, message, messageParams, dataPath, schemaPath, subErrors); | |
}; | |
ValidatorContext.prototype.returnError = function (error) { | |
return error; | |
}; | |
ValidatorContext.prototype.collectError = function (error) { | |
if (error) { | |
this.errors.push(error); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.prefixErrors = function (startIndex, dataPath, schemaPath) { | |
for (var i = startIndex; i < this.errors.length; i++) { | |
this.errors[i] = this.errors[i].prefixWith(dataPath, schemaPath); | |
} | |
return this; | |
}; | |
ValidatorContext.prototype.banUnknownProperties = function () { | |
for (var unknownPath in this.unknownPropertyPaths) { | |
var error = this.createError(ErrorCodes.UNKNOWN_PROPERTY, {path: unknownPath}, unknownPath, ""); | |
var result = this.handleError(error); | |
if (result) { | |
return result; | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.addFormat = function (format, validator) { | |
if (typeof format === 'object') { | |
for (var key in format) { | |
this.addFormat(key, format[key]); | |
} | |
return this; | |
} | |
this.formatValidators[format] = validator; | |
}; | |
ValidatorContext.prototype.resolveRefs = function (schema, urlHistory, recursive) { | |
var subSchema; | |
while (schema && typeof schema['$ref'] === "string") { | |
urlHistory = urlHistory || {}; | |
if (urlHistory[schema['$ref']]) { | |
return this.createError(ErrorCodes.CIRCULAR_REFERENCE, {urls: Object.keys(urlHistory).join(', ')}, '', ''); | |
} | |
urlHistory[schema['$ref']] = true; | |
schema = this.getSchema(schema['$ref'], urlHistory, recursive); | |
if (recursive && typeof schema === "object" && typeof schema['$ref'] !== "string") { | |
for (var key in schema) { | |
if (key !== "enum") { | |
subSchema = this.resolveRefs(schema[key], urlHistory, recursive); | |
if (subSchema instanceof ValidationError) { | |
return subSchema; | |
} | |
schema[key] = subSchema; | |
} | |
} | |
} | |
} | |
if (recursive && Array.isArray(schema)) { | |
for (var i = 0; i < schema.length; i++) { | |
subSchema = this.resolveRefs(schema[i], urlHistory, recursive); | |
if (subSchema instanceof ValidationError) { | |
return subSchema; | |
} | |
schema[i] = subSchema; | |
} | |
} | |
return schema; | |
}; | |
ValidatorContext.prototype.getSchema = function (url, urlHistory, recursive) { | |
var schema; | |
if (this.schemas[url] !== undefined) { | |
schema = this.schemas[url]; | |
return this.resolveRefs(schema, urlHistory, recursive); | |
} | |
var baseUrl = url; | |
var fragment = ""; | |
if (url.indexOf('#') !== -1) { | |
fragment = url.substring(url.indexOf("#") + 1); | |
baseUrl = url.substring(0, url.indexOf("#")); | |
} | |
if (typeof this.schemas[baseUrl] === 'object') { | |
schema = this.schemas[baseUrl]; | |
var pointerPath = decodeURIComponent(fragment); | |
if (pointerPath === "") { | |
return this.resolveRefs(schema, urlHistory, recursive); | |
} else if (pointerPath.charAt(0) !== "/") { | |
return undefined; | |
} | |
var parts = pointerPath.split("/").slice(1); | |
for (var i = 0; i < parts.length; i++) { | |
var component = parts[i].replace(/~1/g, "/").replace(/~0/g, "~"); | |
if (schema[component] === undefined) { | |
schema = undefined; | |
break; | |
} | |
schema = schema[component]; | |
} | |
if (schema !== undefined) { | |
return this.resolveRefs(schema, urlHistory, recursive); | |
} | |
} | |
if (this.missing[baseUrl] === undefined) { | |
this.missing.push(baseUrl); | |
this.missing[baseUrl] = baseUrl; | |
this.missingMap[baseUrl] = baseUrl; | |
} | |
}; | |
ValidatorContext.prototype.searchSchemas = function (schema, url) { | |
if (Array.isArray(schema)) { | |
for (var i = 0; i < schema.length; i++) { | |
this.searchSchemas(schema[i], url); | |
} | |
} else if (schema && typeof schema === "object") { | |
if (typeof schema.id === "string") { | |
if (isTrustedUrl(url, schema.id)) { | |
if (this.schemas[schema.id] === undefined) { | |
this.schemas[schema.id] = schema; | |
} | |
} | |
} | |
for (var key in schema) { | |
if (key !== "enum") { | |
if (typeof schema[key] === "object") { | |
this.searchSchemas(schema[key], url); | |
} else if (key === "$ref") { | |
var uri = getDocumentUri(schema[key]); | |
if (uri && this.schemas[uri] === undefined && this.missingMap[uri] === undefined) { | |
this.missingMap[uri] = uri; | |
} | |
} | |
} | |
} | |
} | |
}; | |
ValidatorContext.prototype.addSchema = function (url, schema) { | |
//overload | |
if (typeof url !== 'string' || typeof schema === 'undefined') { | |
if (typeof url === 'object' && typeof url.id === 'string') { | |
schema = url; | |
url = schema.id; | |
} | |
else { | |
return; | |
} | |
} | |
if (url === getDocumentUri(url) + "#") { | |
// Remove empty fragment | |
url = getDocumentUri(url); | |
} | |
this.schemas[url] = schema; | |
delete this.missingMap[url]; | |
normSchema(schema, url); | |
this.searchSchemas(schema, url); | |
}; | |
ValidatorContext.prototype.getSchemaMap = function () { | |
var map = {}; | |
for (var key in this.schemas) { | |
map[key] = this.schemas[key]; | |
} | |
return map; | |
}; | |
ValidatorContext.prototype.getSchemaUris = function (filterRegExp) { | |
var list = []; | |
for (var key in this.schemas) { | |
if (!filterRegExp || filterRegExp.test(key)) { | |
list.push(key); | |
} | |
} | |
return list; | |
}; | |
ValidatorContext.prototype.getMissingUris = function (filterRegExp) { | |
var list = []; | |
for (var key in this.missingMap) { | |
if (!filterRegExp || filterRegExp.test(key)) { | |
list.push(key); | |
} | |
} | |
return list; | |
}; | |
ValidatorContext.prototype.dropSchemas = function () { | |
this.schemas = {}; | |
this.reset(); | |
}; | |
ValidatorContext.prototype.reset = function () { | |
this.missing = []; | |
this.missingMap = {}; | |
this.errors = []; | |
}; | |
ValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) { | |
var topLevel; | |
schema = this.resolveRefs(schema, {}, true); | |
if (!schema) { | |
return null; | |
} else if (schema instanceof ValidationError) { | |
this.errors.push(schema); | |
return schema; | |
} | |
var startErrorCount = this.errors.length; | |
var frozenIndex, scannedFrozenSchemaIndex = null, scannedSchemasIndex = null; | |
if (this.checkRecursive && data && typeof data === 'object') { | |
topLevel = !this.scanned.length; | |
if (data[this.validatedSchemasKey]) { | |
var schemaIndex = data[this.validatedSchemasKey].indexOf(schema); | |
if (schemaIndex !== -1) { | |
this.errors = this.errors.concat(data[this.validationErrorsKey][schemaIndex]); | |
return null; | |
} | |
} | |
if (Object.isFrozen(data)) { | |
frozenIndex = this.scannedFrozen.indexOf(data); | |
if (frozenIndex !== -1) { | |
var frozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].indexOf(schema); | |
if (frozenSchemaIndex !== -1) { | |
this.errors = this.errors.concat(this.scannedFrozenValidationErrors[frozenIndex][frozenSchemaIndex]); | |
return null; | |
} | |
} | |
} | |
this.scanned.push(data); | |
if (Object.isFrozen(data)) { | |
if (frozenIndex === -1) { | |
frozenIndex = this.scannedFrozen.length; | |
this.scannedFrozen.push(data); | |
this.scannedFrozenSchemas.push([]); | |
} | |
scannedFrozenSchemaIndex = this.scannedFrozenSchemas[frozenIndex].length; | |
this.scannedFrozenSchemas[frozenIndex][scannedFrozenSchemaIndex] = schema; | |
this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = []; | |
} else { | |
if (!data[this.validatedSchemasKey]) { | |
try { | |
Object.defineProperty(data, this.validatedSchemasKey, { | |
value: [], | |
configurable: true | |
}); | |
Object.defineProperty(data, this.validationErrorsKey, { | |
value: [], | |
configurable: true | |
}); | |
} catch (e) { | |
//IE 7/8 workaround | |
data[this.validatedSchemasKey] = []; | |
data[this.validationErrorsKey] = []; | |
} | |
} | |
scannedSchemasIndex = data[this.validatedSchemasKey].length; | |
data[this.validatedSchemasKey][scannedSchemasIndex] = schema; | |
data[this.validationErrorsKey][scannedSchemasIndex] = []; | |
} | |
} | |
var errorCount = this.errors.length; | |
var error = this.validateBasic(data, schema, dataPointerPath) | |
|| this.validateNumeric(data, schema, dataPointerPath) | |
|| this.validateString(data, schema, dataPointerPath) | |
|| this.validateArray(data, schema, dataPointerPath) | |
|| this.validateObject(data, schema, dataPointerPath) | |
|| this.validateCombinations(data, schema, dataPointerPath) | |
|| this.validateHypermedia(data, schema, dataPointerPath) | |
|| this.validateFormat(data, schema, dataPointerPath) | |
|| this.validateDefinedKeywords(data, schema, dataPointerPath) | |
|| null; | |
if (topLevel) { | |
while (this.scanned.length) { | |
var item = this.scanned.pop(); | |
delete item[this.validatedSchemasKey]; | |
} | |
this.scannedFrozen = []; | |
this.scannedFrozenSchemas = []; | |
} | |
if (error || errorCount !== this.errors.length) { | |
while ((dataPathParts && dataPathParts.length) || (schemaPathParts && schemaPathParts.length)) { | |
var dataPart = (dataPathParts && dataPathParts.length) ? "" + dataPathParts.pop() : null; | |
var schemaPart = (schemaPathParts && schemaPathParts.length) ? "" + schemaPathParts.pop() : null; | |
if (error) { | |
error = error.prefixWith(dataPart, schemaPart); | |
} | |
this.prefixErrors(errorCount, dataPart, schemaPart); | |
} | |
} | |
if (scannedFrozenSchemaIndex !== null) { | |
this.scannedFrozenValidationErrors[frozenIndex][scannedFrozenSchemaIndex] = this.errors.slice(startErrorCount); | |
} else if (scannedSchemasIndex !== null) { | |
data[this.validationErrorsKey][scannedSchemasIndex] = this.errors.slice(startErrorCount); | |
} | |
return this.handleError(error); | |
}; | |
ValidatorContext.prototype.validateFormat = function (data, schema) { | |
if (typeof schema.format !== 'string' || !this.formatValidators[schema.format]) { | |
return null; | |
} | |
var errorMessage = this.formatValidators[schema.format].call(null, data, schema); | |
if (typeof errorMessage === 'string' || typeof errorMessage === 'number') { | |
return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage}).prefixWith(null, "format"); | |
} else if (errorMessage && typeof errorMessage === 'object') { | |
return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage.message || "?"}, errorMessage.dataPath || null, errorMessage.schemaPath || "/format"); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateDefinedKeywords = function (data, schema, dataPointerPath) { | |
for (var key in this.definedKeywords) { | |
if (typeof schema[key] === 'undefined') { | |
continue; | |
} | |
var validationFunctions = this.definedKeywords[key]; | |
for (var i = 0; i < validationFunctions.length; i++) { | |
var func = validationFunctions[i]; | |
var result = func(data, schema[key], schema, dataPointerPath); | |
if (typeof result === 'string' || typeof result === 'number') { | |
return this.createError(ErrorCodes.KEYWORD_CUSTOM, {key: key, message: result}).prefixWith(null, "format"); | |
} else if (result && typeof result === 'object') { | |
var code = result.code; | |
if (typeof code === 'string') { | |
if (!ErrorCodes[code]) { | |
throw new Error('Undefined error code (use defineError): ' + code); | |
} | |
code = ErrorCodes[code]; | |
} else if (typeof code !== 'number') { | |
code = ErrorCodes.KEYWORD_CUSTOM; | |
} | |
var messageParams = (typeof result.message === 'object') ? result.message : {key: key, message: result.message || "?"}; | |
var schemaPath = result.schemaPath ||( "/" + key.replace(/~/g, '~0').replace(/\//g, '~1')); | |
return this.createError(code, messageParams, result.dataPath || null, schemaPath); | |
} | |
} | |
} | |
return null; | |
}; | |
function recursiveCompare(A, B) { | |
if (A === B) { | |
return true; | |
} | |
if (typeof A === "object" && typeof B === "object") { | |
if (Array.isArray(A) !== Array.isArray(B)) { | |
return false; | |
} else if (Array.isArray(A)) { | |
if (A.length !== B.length) { | |
return false; | |
} | |
for (var i = 0; i < A.length; i++) { | |
if (!recursiveCompare(A[i], B[i])) { | |
return false; | |
} | |
} | |
} else { | |
var key; | |
for (key in A) { | |
if (B[key] === undefined && A[key] !== undefined) { | |
return false; | |
} | |
} | |
for (key in B) { | |
if (A[key] === undefined && B[key] !== undefined) { | |
return false; | |
} | |
} | |
for (key in A) { | |
if (!recursiveCompare(A[key], B[key])) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
return false; | |
} | |
ValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) { | |
var error; | |
if (error = this.validateType(data, schema, dataPointerPath)) { | |
return error.prefixWith(null, "type"); | |
} | |
if (error = this.validateEnum(data, schema, dataPointerPath)) { | |
return error.prefixWith(null, "type"); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateType = function validateType(data, schema) { | |
if (schema.type === undefined) { | |
return null; | |
} | |
var dataType = typeof data; | |
if (data === null) { | |
dataType = "null"; | |
} else if (Array.isArray(data)) { | |
dataType = "array"; | |
} | |
var allowedTypes = schema.type; | |
if (typeof allowedTypes !== "object") { | |
allowedTypes = [allowedTypes]; | |
} | |
for (var i = 0; i < allowedTypes.length; i++) { | |
var type = allowedTypes[i]; | |
if (type === dataType || (type === "integer" && dataType === "number" && (data % 1 === 0))) { | |
return null; | |
} | |
} | |
return this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join("/")}); | |
}; | |
ValidatorContext.prototype.validateEnum = function validateEnum(data, schema) { | |
if (schema["enum"] === undefined) { | |
return null; | |
} | |
for (var i = 0; i < schema["enum"].length; i++) { | |
var enumVal = schema["enum"][i]; | |
if (recursiveCompare(data, enumVal)) { | |
return null; | |
} | |
} | |
return this.createError(ErrorCodes.ENUM_MISMATCH, {value: (typeof JSON !== 'undefined') ? JSON.stringify(data) : data}); | |
}; | |
ValidatorContext.prototype.validateNumeric = function validateNumeric(data, schema, dataPointerPath) { | |
return this.validateMultipleOf(data, schema, dataPointerPath) | |
|| this.validateMinMax(data, schema, dataPointerPath) | |
|| this.validateNaN(data, schema, dataPointerPath) | |
|| null; | |
}; | |
var CLOSE_ENOUGH_LOW = Math.pow(2, -51); | |
var CLOSE_ENOUGH_HIGH = 1 - CLOSE_ENOUGH_LOW; | |
ValidatorContext.prototype.validateMultipleOf = function validateMultipleOf(data, schema) { | |
var multipleOf = schema.multipleOf || schema.divisibleBy; | |
if (multipleOf === undefined) { | |
return null; | |
} | |
if (typeof data === "number") { | |
var remainder = (data/multipleOf)%1; | |
if (remainder >= CLOSE_ENOUGH_LOW && remainder < CLOSE_ENOUGH_HIGH) { | |
return this.createError(ErrorCodes.NUMBER_MULTIPLE_OF, {value: data, multipleOf: multipleOf}); | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema) { | |
if (typeof data !== "number") { | |
return null; | |
} | |
if (schema.minimum !== undefined) { | |
if (data < schema.minimum) { | |
return this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}).prefixWith(null, "minimum"); | |
} | |
if (schema.exclusiveMinimum && data === schema.minimum) { | |
return this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}).prefixWith(null, "exclusiveMinimum"); | |
} | |
} | |
if (schema.maximum !== undefined) { | |
if (data > schema.maximum) { | |
return this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}).prefixWith(null, "maximum"); | |
} | |
if (schema.exclusiveMaximum && data === schema.maximum) { | |
return this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}).prefixWith(null, "exclusiveMaximum"); | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateNaN = function validateNaN(data) { | |
if (typeof data !== "number") { | |
return null; | |
} | |
if (isNaN(data) === true || data === Infinity || data === -Infinity) { | |
return this.createError(ErrorCodes.NUMBER_NOT_A_NUMBER, {value: data}).prefixWith(null, "type"); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateString = function validateString(data, schema, dataPointerPath) { | |
return this.validateStringLength(data, schema, dataPointerPath) | |
|| this.validateStringPattern(data, schema, dataPointerPath) | |
|| null; | |
}; | |
ValidatorContext.prototype.validateStringLength = function validateStringLength(data, schema) { | |
if (typeof data !== "string") { | |
return null; | |
} | |
if (schema.minLength !== undefined) { | |
if (data.length < schema.minLength) { | |
return this.createError(ErrorCodes.STRING_LENGTH_SHORT, {length: data.length, minimum: schema.minLength}).prefixWith(null, "minLength"); | |
} | |
} | |
if (schema.maxLength !== undefined) { | |
if (data.length > schema.maxLength) { | |
return this.createError(ErrorCodes.STRING_LENGTH_LONG, {length: data.length, maximum: schema.maxLength}).prefixWith(null, "maxLength"); | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateStringPattern = function validateStringPattern(data, schema) { | |
if (typeof data !== "string" || schema.pattern === undefined) { | |
return null; | |
} | |
var regexp = new RegExp(schema.pattern); | |
if (!regexp.test(data)) { | |
return this.createError(ErrorCodes.STRING_PATTERN, {pattern: schema.pattern}).prefixWith(null, "pattern"); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateArray = function validateArray(data, schema, dataPointerPath) { | |
if (!Array.isArray(data)) { | |
return null; | |
} | |
return this.validateArrayLength(data, schema, dataPointerPath) | |
|| this.validateArrayUniqueItems(data, schema, dataPointerPath) | |
|| this.validateArrayItems(data, schema, dataPointerPath) | |
|| null; | |
}; | |
ValidatorContext.prototype.validateArrayLength = function validateArrayLength(data, schema) { | |
var error; | |
if (schema.minItems !== undefined) { | |
if (data.length < schema.minItems) { | |
error = (this.createError(ErrorCodes.ARRAY_LENGTH_SHORT, {length: data.length, minimum: schema.minItems})).prefixWith(null, "minItems"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
if (schema.maxItems !== undefined) { | |
if (data.length > schema.maxItems) { | |
error = (this.createError(ErrorCodes.ARRAY_LENGTH_LONG, {length: data.length, maximum: schema.maxItems})).prefixWith(null, "maxItems"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) { | |
if (schema.uniqueItems) { | |
for (var i = 0; i < data.length; i++) { | |
for (var j = i + 1; j < data.length; j++) { | |
if (recursiveCompare(data[i], data[j])) { | |
var error = (this.createError(ErrorCodes.ARRAY_UNIQUE, {match1: i, match2: j})).prefixWith(null, "uniqueItems"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateArrayItems = function validateArrayItems(data, schema, dataPointerPath) { | |
if (schema.items === undefined) { | |
return null; | |
} | |
var error, i; | |
if (Array.isArray(schema.items)) { | |
for (i = 0; i < data.length; i++) { | |
if (i < schema.items.length) { | |
if (error = this.validateAll(data[i], schema.items[i], [i], ["items", i], dataPointerPath + "/" + i)) { | |
return error; | |
} | |
} else if (schema.additionalItems !== undefined) { | |
if (typeof schema.additionalItems === "boolean") { | |
if (!schema.additionalItems) { | |
error = (this.createError(ErrorCodes.ARRAY_ADDITIONAL_ITEMS, {})).prefixWith("" + i, "additionalItems"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} else if (error = this.validateAll(data[i], schema.additionalItems, [i], ["additionalItems"], dataPointerPath + "/" + i)) { | |
return error; | |
} | |
} | |
} | |
} else { | |
for (i = 0; i < data.length; i++) { | |
if (error = this.validateAll(data[i], schema.items, [i], ["items"], dataPointerPath + "/" + i)) { | |
return error; | |
} | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateObject = function validateObject(data, schema, dataPointerPath) { | |
if (typeof data !== "object" || data === null || Array.isArray(data)) { | |
return null; | |
} | |
return this.validateObjectMinMaxProperties(data, schema, dataPointerPath) | |
|| this.validateObjectRequiredProperties(data, schema, dataPointerPath) | |
|| this.validateObjectProperties(data, schema, dataPointerPath) | |
|| this.validateObjectDependencies(data, schema, dataPointerPath) | |
|| null; | |
}; | |
ValidatorContext.prototype.validateObjectMinMaxProperties = function validateObjectMinMaxProperties(data, schema) { | |
var keys = Object.keys(data); | |
var error; | |
if (schema.minProperties !== undefined) { | |
if (keys.length < schema.minProperties) { | |
error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MINIMUM, {propertyCount: keys.length, minimum: schema.minProperties}).prefixWith(null, "minProperties"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
if (schema.maxProperties !== undefined) { | |
if (keys.length > schema.maxProperties) { | |
error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MAXIMUM, {propertyCount: keys.length, maximum: schema.maxProperties}).prefixWith(null, "maxProperties"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateObjectRequiredProperties = function validateObjectRequiredProperties(data, schema) { | |
if (schema.required !== undefined) { | |
for (var i = 0; i < schema.required.length; i++) { | |
var key = schema.required[i]; | |
if (data[key] === undefined) { | |
var error = this.createError(ErrorCodes.OBJECT_REQUIRED, {key: key}).prefixWith(null, "" + i).prefixWith(null, "required"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateObjectProperties = function validateObjectProperties(data, schema, dataPointerPath) { | |
var error; | |
for (var key in data) { | |
var keyPointerPath = dataPointerPath + "/" + key.replace(/~/g, '~0').replace(/\//g, '~1'); | |
var foundMatch = false; | |
if (schema.properties !== undefined && schema.properties[key] !== undefined) { | |
foundMatch = true; | |
if (error = this.validateAll(data[key], schema.properties[key], [key], ["properties", key], keyPointerPath)) { | |
return error; | |
} | |
} | |
if (schema.patternProperties !== undefined) { | |
for (var patternKey in schema.patternProperties) { | |
var regexp = new RegExp(patternKey); | |
if (regexp.test(key)) { | |
foundMatch = true; | |
if (error = this.validateAll(data[key], schema.patternProperties[patternKey], [key], ["patternProperties", patternKey], keyPointerPath)) { | |
return error; | |
} | |
} | |
} | |
} | |
if (!foundMatch) { | |
if (schema.additionalProperties !== undefined) { | |
if (this.trackUnknownProperties) { | |
this.knownPropertyPaths[keyPointerPath] = true; | |
delete this.unknownPropertyPaths[keyPointerPath]; | |
} | |
if (typeof schema.additionalProperties === "boolean") { | |
if (!schema.additionalProperties) { | |
error = this.createError(ErrorCodes.OBJECT_ADDITIONAL_PROPERTIES, {}).prefixWith(key, "additionalProperties"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} else { | |
if (error = this.validateAll(data[key], schema.additionalProperties, [key], ["additionalProperties"], keyPointerPath)) { | |
return error; | |
} | |
} | |
} else if (this.trackUnknownProperties && !this.knownPropertyPaths[keyPointerPath]) { | |
this.unknownPropertyPaths[keyPointerPath] = true; | |
} | |
} else if (this.trackUnknownProperties) { | |
this.knownPropertyPaths[keyPointerPath] = true; | |
delete this.unknownPropertyPaths[keyPointerPath]; | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateObjectDependencies = function validateObjectDependencies(data, schema, dataPointerPath) { | |
var error; | |
if (schema.dependencies !== undefined) { | |
for (var depKey in schema.dependencies) { | |
if (data[depKey] !== undefined) { | |
var dep = schema.dependencies[depKey]; | |
if (typeof dep === "string") { | |
if (data[dep] === undefined) { | |
error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: dep}).prefixWith(null, depKey).prefixWith(null, "dependencies"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} else if (Array.isArray(dep)) { | |
for (var i = 0; i < dep.length; i++) { | |
var requiredKey = dep[i]; | |
if (data[requiredKey] === undefined) { | |
error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: requiredKey}).prefixWith(null, "" + i).prefixWith(null, depKey).prefixWith(null, "dependencies"); | |
if (this.handleError(error)) { | |
return error; | |
} | |
} | |
} | |
} else { | |
if (error = this.validateAll(data, dep, [], ["dependencies", depKey], dataPointerPath)) { | |
return error; | |
} | |
} | |
} | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateCombinations = function validateCombinations(data, schema, dataPointerPath) { | |
return this.validateAllOf(data, schema, dataPointerPath) | |
|| this.validateAnyOf(data, schema, dataPointerPath) | |
|| this.validateOneOf(data, schema, dataPointerPath) | |
|| this.validateNot(data, schema, dataPointerPath) | |
|| null; | |
}; | |
ValidatorContext.prototype.validateAllOf = function validateAllOf(data, schema, dataPointerPath) { | |
if (schema.allOf === undefined) { | |
return null; | |
} | |
var error; | |
for (var i = 0; i < schema.allOf.length; i++) { | |
var subSchema = schema.allOf[i]; | |
if (error = this.validateAll(data, subSchema, [], ["allOf", i], dataPointerPath)) { | |
return error; | |
} | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateAnyOf = function validateAnyOf(data, schema, dataPointerPath) { | |
if (schema.anyOf === undefined) { | |
return null; | |
} | |
var errors = []; | |
var startErrorCount = this.errors.length; | |
var oldUnknownPropertyPaths, oldKnownPropertyPaths; | |
if (this.trackUnknownProperties) { | |
oldUnknownPropertyPaths = this.unknownPropertyPaths; | |
oldKnownPropertyPaths = this.knownPropertyPaths; | |
} | |
var errorAtEnd = true; | |
for (var i = 0; i < schema.anyOf.length; i++) { | |
if (this.trackUnknownProperties) { | |
this.unknownPropertyPaths = {}; | |
this.knownPropertyPaths = {}; | |
} | |
var subSchema = schema.anyOf[i]; | |
var errorCount = this.errors.length; | |
var error = this.validateAll(data, subSchema, [], ["anyOf", i], dataPointerPath); | |
if (error === null && errorCount === this.errors.length) { | |
this.errors = this.errors.slice(0, startErrorCount); | |
if (this.trackUnknownProperties) { | |
for (var knownKey in this.knownPropertyPaths) { | |
oldKnownPropertyPaths[knownKey] = true; | |
delete oldUnknownPropertyPaths[knownKey]; | |
} | |
for (var unknownKey in this.unknownPropertyPaths) { | |
if (!oldKnownPropertyPaths[unknownKey]) { | |
oldUnknownPropertyPaths[unknownKey] = true; | |
} | |
} | |
// We need to continue looping so we catch all the property definitions, but we don't want to return an error | |
errorAtEnd = false; | |
continue; | |
} | |
return null; | |
} | |
if (error) { | |
errors.push(error.prefixWith(null, "" + i).prefixWith(null, "anyOf")); | |
} | |
} | |
if (this.trackUnknownProperties) { | |
this.unknownPropertyPaths = oldUnknownPropertyPaths; | |
this.knownPropertyPaths = oldKnownPropertyPaths; | |
} | |
if (errorAtEnd) { | |
errors = errors.concat(this.errors.slice(startErrorCount)); | |
this.errors = this.errors.slice(0, startErrorCount); | |
return this.createError(ErrorCodes.ANY_OF_MISSING, {}, "", "/anyOf", errors); | |
} | |
}; | |
ValidatorContext.prototype.validateOneOf = function validateOneOf(data, schema, dataPointerPath) { | |
if (schema.oneOf === undefined) { | |
return null; | |
} | |
var validIndex = null; | |
var errors = []; | |
var startErrorCount = this.errors.length; | |
var oldUnknownPropertyPaths, oldKnownPropertyPaths; | |
if (this.trackUnknownProperties) { | |
oldUnknownPropertyPaths = this.unknownPropertyPaths; | |
oldKnownPropertyPaths = this.knownPropertyPaths; | |
} | |
for (var i = 0; i < schema.oneOf.length; i++) { | |
if (this.trackUnknownProperties) { | |
this.unknownPropertyPaths = {}; | |
this.knownPropertyPaths = {}; | |
} | |
var subSchema = schema.oneOf[i]; | |
var errorCount = this.errors.length; | |
var error = this.validateAll(data, subSchema, [], ["oneOf", i], dataPointerPath); | |
if (error === null && errorCount === this.errors.length) { | |
if (validIndex === null) { | |
validIndex = i; | |
} else { | |
this.errors = this.errors.slice(0, startErrorCount); | |
return this.createError(ErrorCodes.ONE_OF_MULTIPLE, {index1: validIndex, index2: i}, "", "/oneOf"); | |
} | |
if (this.trackUnknownProperties) { | |
for (var knownKey in this.knownPropertyPaths) { | |
oldKnownPropertyPaths[knownKey] = true; | |
delete oldUnknownPropertyPaths[knownKey]; | |
} | |
for (var unknownKey in this.unknownPropertyPaths) { | |
if (!oldKnownPropertyPaths[unknownKey]) { | |
oldUnknownPropertyPaths[unknownKey] = true; | |
} | |
} | |
} | |
} else if (error) { | |
errors.push(error); | |
} | |
} | |
if (this.trackUnknownProperties) { | |
this.unknownPropertyPaths = oldUnknownPropertyPaths; | |
this.knownPropertyPaths = oldKnownPropertyPaths; | |
} | |
if (validIndex === null) { | |
errors = errors.concat(this.errors.slice(startErrorCount)); | |
this.errors = this.errors.slice(0, startErrorCount); | |
return this.createError(ErrorCodes.ONE_OF_MISSING, {}, "", "/oneOf", errors); | |
} else { | |
this.errors = this.errors.slice(0, startErrorCount); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateNot = function validateNot(data, schema, dataPointerPath) { | |
if (schema.not === undefined) { | |
return null; | |
} | |
var oldErrorCount = this.errors.length; | |
var oldUnknownPropertyPaths, oldKnownPropertyPaths; | |
if (this.trackUnknownProperties) { | |
oldUnknownPropertyPaths = this.unknownPropertyPaths; | |
oldKnownPropertyPaths = this.knownPropertyPaths; | |
this.unknownPropertyPaths = {}; | |
this.knownPropertyPaths = {}; | |
} | |
var error = this.validateAll(data, schema.not, null, null, dataPointerPath); | |
var notErrors = this.errors.slice(oldErrorCount); | |
this.errors = this.errors.slice(0, oldErrorCount); | |
if (this.trackUnknownProperties) { | |
this.unknownPropertyPaths = oldUnknownPropertyPaths; | |
this.knownPropertyPaths = oldKnownPropertyPaths; | |
} | |
if (error === null && notErrors.length === 0) { | |
return this.createError(ErrorCodes.NOT_PASSED, {}, "", "/not"); | |
} | |
return null; | |
}; | |
ValidatorContext.prototype.validateHypermedia = function validateCombinations(data, schema, dataPointerPath) { | |
if (!schema.links) { | |
return null; | |
} | |
var error; | |
for (var i = 0; i < schema.links.length; i++) { | |
var ldo = schema.links[i]; | |
if (ldo.rel === "describedby") { | |
var template = new UriTemplate(ldo.href); | |
var allPresent = true; | |
for (var j = 0; j < template.varNames.length; j++) { | |
if (!(template.varNames[j] in data)) { | |
allPresent = false; | |
break; | |
} | |
} | |
if (allPresent) { | |
var schemaUrl = template.fillFromObject(data); | |
var subSchema = {"$ref": schemaUrl}; | |
if (error = this.validateAll(data, subSchema, [], ["links", i], dataPointerPath)) { | |
return error; | |
} | |
} | |
} | |
} | |
}; | |
// parseURI() and resolveUrl() are from https://gist.github.com/1088850 | |
// - released as public domain by author ("Yaffle") - see comments on gist | |
function parseURI(url) { | |
var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/); | |
// authority = '//' + user + ':' + pass '@' + hostname + ':' port | |
return (m ? { | |
href : m[0] || '', | |
protocol : m[1] || '', | |
authority: m[2] || '', | |
host : m[3] || '', | |
hostname : m[4] || '', | |
port : m[5] || '', | |
pathname : m[6] || '', | |
search : m[7] || '', | |
hash : m[8] || '' | |
} : null); | |
} | |
function resolveUrl(base, href) {// RFC 3986 | |
function removeDotSegments(input) { | |
var output = []; | |
input.replace(/^(\.\.?(\/|$))+/, '') | |
.replace(/\/(\.(\/|$))+/g, '/') | |
.replace(/\/\.\.$/, '/../') | |
.replace(/\/?[^\/]*/g, function (p) { | |
if (p === '/..') { | |
output.pop(); | |
} else { | |
output.push(p); | |
} | |
}); | |
return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : ''); | |
} | |
href = parseURI(href || ''); | |
base = parseURI(base || ''); | |
return !href || !base ? null : (href.protocol || base.protocol) + | |
(href.protocol || href.authority ? href.authority : base.authority) + | |
removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) + | |
(href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) + | |
href.hash; | |
} | |
function getDocumentUri(uri) { | |
return uri.split('#')[0]; | |
} | |
function normSchema(schema, baseUri) { | |
if (schema && typeof schema === "object") { | |
if (baseUri === undefined) { | |
baseUri = schema.id; | |
} else if (typeof schema.id === "string") { | |
baseUri = resolveUrl(baseUri, schema.id); | |
schema.id = baseUri; | |
} | |
if (Array.isArray(schema)) { | |
for (var i = 0; i < schema.length; i++) { | |
normSchema(schema[i], baseUri); | |
} | |
} else { | |
if (typeof schema['$ref'] === "string") { | |
schema['$ref'] = resolveUrl(baseUri, schema['$ref']); | |
} | |
for (var key in schema) { | |
if (key !== "enum") { | |
normSchema(schema[key], baseUri); | |
} | |
} | |
} | |
} | |
} | |
var ErrorCodes = { | |
INVALID_TYPE: 0, | |
ENUM_MISMATCH: 1, | |
ANY_OF_MISSING: 10, | |
ONE_OF_MISSING: 11, | |
ONE_OF_MULTIPLE: 12, | |
NOT_PASSED: 13, | |
// Numeric errors | |
NUMBER_MULTIPLE_OF: 100, | |
NUMBER_MINIMUM: 101, | |
NUMBER_MINIMUM_EXCLUSIVE: 102, | |
NUMBER_MAXIMUM: 103, | |
NUMBER_MAXIMUM_EXCLUSIVE: 104, | |
NUMBER_NOT_A_NUMBER: 105, | |
// String errors | |
STRING_LENGTH_SHORT: 200, | |
STRING_LENGTH_LONG: 201, | |
STRING_PATTERN: 202, | |
// Object errors | |
OBJECT_PROPERTIES_MINIMUM: 300, | |
OBJECT_PROPERTIES_MAXIMUM: 301, | |
OBJECT_REQUIRED: 302, | |
OBJECT_ADDITIONAL_PROPERTIES: 303, | |
OBJECT_DEPENDENCY_KEY: 304, | |
// Array errors | |
ARRAY_LENGTH_SHORT: 400, | |
ARRAY_LENGTH_LONG: 401, | |
ARRAY_UNIQUE: 402, | |
ARRAY_ADDITIONAL_ITEMS: 403, | |
// Custom/user-defined errors | |
FORMAT_CUSTOM: 500, | |
KEYWORD_CUSTOM: 501, | |
// Schema structure | |
CIRCULAR_REFERENCE: 600, | |
// Non-standard validation options | |
UNKNOWN_PROPERTY: 1000 | |
}; | |
var ErrorCodeLookup = {}; | |
for (var key in ErrorCodes) { | |
ErrorCodeLookup[ErrorCodes[key]] = key; | |
} | |
var ErrorMessagesDefault = { | |
INVALID_TYPE: "Invalid type: {type} (expected {expected})", | |
ENUM_MISMATCH: "No enum match for: {value}", | |
ANY_OF_MISSING: "Data does not match any schemas from \"anyOf\"", | |
ONE_OF_MISSING: "Data does not match any schemas from \"oneOf\"", | |
ONE_OF_MULTIPLE: "Data is valid against more than one schema from \"oneOf\": indices {index1} and {index2}", | |
NOT_PASSED: "Data matches schema from \"not\"", | |
// Numeric errors | |
NUMBER_MULTIPLE_OF: "Value {value} is not a multiple of {multipleOf}", | |
NUMBER_MINIMUM: "Value {value} is less than minimum {minimum}", | |
NUMBER_MINIMUM_EXCLUSIVE: "Value {value} is equal to exclusive minimum {minimum}", | |
NUMBER_MAXIMUM: "Value {value} is greater than maximum {maximum}", | |
NUMBER_MAXIMUM_EXCLUSIVE: "Value {value} is equal to exclusive maximum {maximum}", | |
NUMBER_NOT_A_NUMBER: "Value {value} is not a valid number", | |
// String errors | |
STRING_LENGTH_SHORT: "String is too short ({length} chars), minimum {minimum}", | |
STRING_LENGTH_LONG: "String is too long ({length} chars), maximum {maximum}", | |
STRING_PATTERN: "String does not match pattern: {pattern}", | |
// Object errors | |
OBJECT_PROPERTIES_MINIMUM: "Too few properties defined ({propertyCount}), minimum {minimum}", | |
OBJECT_PROPERTIES_MAXIMUM: "Too many properties defined ({propertyCount}), maximum {maximum}", | |
OBJECT_REQUIRED: "Missing required property: {key}", | |
OBJECT_ADDITIONAL_PROPERTIES: "Additional properties not allowed", | |
OBJECT_DEPENDENCY_KEY: "Dependency failed - key must exist: {missing} (due to key: {key})", | |
// Array errors | |
ARRAY_LENGTH_SHORT: "Array is too short ({length}), minimum {minimum}", | |
ARRAY_LENGTH_LONG: "Array is too long ({length}), maximum {maximum}", | |
ARRAY_UNIQUE: "Array items are not unique (indices {match1} and {match2})", | |
ARRAY_ADDITIONAL_ITEMS: "Additional items not allowed", | |
// Format errors | |
FORMAT_CUSTOM: "Format validation failed ({message})", | |
KEYWORD_CUSTOM: "Keyword failed: {key} ({message})", | |
// Schema structure | |
CIRCULAR_REFERENCE: "Circular $refs: {urls}", | |
// Non-standard validation options | |
UNKNOWN_PROPERTY: "Unknown property (not in schema)" | |
}; | |
function ValidationError(code, message, params, dataPath, schemaPath, subErrors) { | |
Error.call(this); | |
if (code === undefined) { | |
throw new Error ("No code supplied for error: "+ message); | |
} | |
this.message = message; | |
this.params = params; | |
this.code = code; | |
this.dataPath = dataPath || ""; | |
this.schemaPath = schemaPath || ""; | |
this.subErrors = subErrors || null; | |
var err = new Error(this.message); | |
this.stack = err.stack || err.stacktrace; | |
if (!this.stack) { | |
try { | |
throw err; | |
} | |
catch(err) { | |
this.stack = err.stack || err.stacktrace; | |
} | |
} | |
} | |
ValidationError.prototype = Object.create(Error.prototype); | |
ValidationError.prototype.constructor = ValidationError; | |
ValidationError.prototype.name = 'ValidationError'; | |
ValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) { | |
if (dataPrefix !== null) { | |
dataPrefix = dataPrefix.replace(/~/g, "~0").replace(/\//g, "~1"); | |
this.dataPath = "/" + dataPrefix + this.dataPath; | |
} | |
if (schemaPrefix !== null) { | |
schemaPrefix = schemaPrefix.replace(/~/g, "~0").replace(/\//g, "~1"); | |
this.schemaPath = "/" + schemaPrefix + this.schemaPath; | |
} | |
if (this.subErrors !== null) { | |
for (var i = 0; i < this.subErrors.length; i++) { | |
this.subErrors[i].prefixWith(dataPrefix, schemaPrefix); | |
} | |
} | |
return this; | |
}; | |
function isTrustedUrl(baseUrl, testUrl) { | |
if(testUrl.substring(0, baseUrl.length) === baseUrl){ | |
var remainder = testUrl.substring(baseUrl.length); | |
if ((testUrl.length > 0 && testUrl.charAt(baseUrl.length - 1) === "/") | |
|| remainder.charAt(0) === "#" | |
|| remainder.charAt(0) === "?") { | |
return true; | |
} | |
} | |
return false; | |
} | |
var languages = {}; | |
function createApi(language) { | |
var globalContext = new ValidatorContext(); | |
var currentLanguage = language || 'en'; | |
var api = { | |
addFormat: function () { | |
globalContext.addFormat.apply(globalContext, arguments); | |
}, | |
language: function (code) { | |
if (!code) { | |
return currentLanguage; | |
} | |
if (!languages[code]) { | |
code = code.split('-')[0]; // fall back to base language | |
} | |
if (languages[code]) { | |
currentLanguage = code; | |
return code; // so you can tell if fall-back has happened | |
} | |
return false; | |
}, | |
addLanguage: function (code, messageMap) { | |
var key; | |
for (key in ErrorCodes) { | |
if (messageMap[key] && !messageMap[ErrorCodes[key]]) { | |
messageMap[ErrorCodes[key]] = messageMap[key]; | |
} | |
} | |
var rootCode = code.split('-')[0]; | |
if (!languages[rootCode]) { // use for base language if not yet defined | |
languages[code] = messageMap; | |
languages[rootCode] = messageMap; | |
} else { | |
languages[code] = Object.create(languages[rootCode]); | |
for (key in messageMap) { | |
if (typeof languages[rootCode][key] === 'undefined') { | |
languages[rootCode][key] = messageMap[key]; | |
} | |
languages[code][key] = messageMap[key]; | |
} | |
} | |
return this; | |
}, | |
freshApi: function (language) { | |
var result = createApi(); | |
if (language) { | |
result.language(language); | |
} | |
return result; | |
}, | |
validate: function (data, schema, checkRecursive, banUnknownProperties) { | |
var context = new ValidatorContext(globalContext, false, languages[currentLanguage], checkRecursive, banUnknownProperties); | |
if (typeof schema === "string") { | |
schema = {"$ref": schema}; | |
} | |
context.addSchema("", schema); | |
var error = context.validateAll(data, schema, null, null, ""); | |
if (!error && banUnknownProperties) { | |
error = context.banUnknownProperties(); | |
} | |
this.error = error; | |
this.missing = context.missing; | |
this.valid = (error === null); | |
return this.valid; | |
}, | |
validateResult: function () { | |
var result = {}; | |
this.validate.apply(result, arguments); | |
return result; | |
}, | |
validateMultiple: function (data, schema, checkRecursive, banUnknownProperties) { | |
var context = new ValidatorContext(globalContext, true, languages[currentLanguage], checkRecursive, banUnknownProperties); | |
if (typeof schema === "string") { | |
schema = {"$ref": schema}; | |
} | |
context.addSchema("", schema); | |
context.validateAll(data, schema, null, null, ""); | |
if (banUnknownProperties) { | |
context.banUnknownProperties(); | |
} | |
var result = {}; | |
result.errors = context.errors; | |
result.missing = context.missing; | |
result.valid = (result.errors.length === 0); | |
return result; | |
}, | |
addSchema: function () { | |
return globalContext.addSchema.apply(globalContext, arguments); | |
}, | |
getSchema: function () { | |
return globalContext.getSchema.apply(globalContext, arguments); | |
}, | |
getSchemaMap: function () { | |
return globalContext.getSchemaMap.apply(globalContext, arguments); | |
}, | |
getSchemaUris: function () { | |
return globalContext.getSchemaUris.apply(globalContext, arguments); | |
}, | |
getMissingUris: function () { | |
return globalContext.getMissingUris.apply(globalContext, arguments); | |
}, | |
dropSchemas: function () { | |
globalContext.dropSchemas.apply(globalContext, arguments); | |
}, | |
defineKeyword: function () { | |
globalContext.defineKeyword.apply(globalContext, arguments); | |
}, | |
defineError: function (codeName, codeNumber, defaultMessage) { | |
if (typeof codeName !== 'string' || !/^[A-Z]+(_[A-Z]+)*$/.test(codeName)) { | |
throw new Error('Code name must be a string in UPPER_CASE_WITH_UNDERSCORES'); | |
} | |
if (typeof codeNumber !== 'number' || codeNumber%1 !== 0 || codeNumber < 10000) { | |
throw new Error('Code number must be an integer > 10000'); | |
} | |
if (typeof ErrorCodes[codeName] !== 'undefined') { | |
throw new Error('Error already defined: ' + codeName + ' as ' + ErrorCodes[codeName]); | |
} | |
if (typeof ErrorCodeLookup[codeNumber] !== 'undefined') { | |
throw new Error('Error code already used: ' + ErrorCodeLookup[codeNumber] + ' as ' + codeNumber); | |
} | |
ErrorCodes[codeName] = codeNumber; | |
ErrorCodeLookup[codeNumber] = codeName; | |
ErrorMessagesDefault[codeName] = ErrorMessagesDefault[codeNumber] = defaultMessage; | |
for (var langCode in languages) { | |
var language = languages[langCode]; | |
if (language[codeName]) { | |
language[codeNumber] = language[codeNumber] || language[codeName]; | |
} | |
} | |
}, | |
reset: function () { | |
globalContext.reset(); | |
this.error = null; | |
this.missing = []; | |
this.valid = true; | |
}, | |
missing: [], | |
error: null, | |
valid: true, | |
normSchema: normSchema, | |
resolveUrl: resolveUrl, | |
getDocumentUri: getDocumentUri, | |
errorCodes: ErrorCodes | |
}; | |
return api; | |
} | |
var tv4 = createApi(); | |
tv4.addLanguage('en-gb', ErrorMessagesDefault); | |
//legacy property | |
tv4.tv4 = tv4; | |
return tv4; // used by _header.js to globalise. | |
})); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"$schema": "http://json-schema.org/draft-04/hyper-schema", | |
"definitions": { | |
"definitions": { | |
"$schema": "http://json-schema.org/draft-04/schema#", | |
"type": [ | |
"object" | |
], | |
"title": "Type Definitions", | |
"description": "Type Definitions", | |
"name": "definitions", | |
"definitions": { | |
"id": { | |
"id": "#/definitions/id", | |
"type": [ | |
"integer" | |
], | |
"multipleOf": 1, | |
"minimum": 1, | |
"title": "Object ID", | |
"description": "Unique ID for an object", | |
"name": "id" | |
}, | |
"polymorphic_type": { | |
"id": "#/definitions/polymorphic_type", | |
"type": [ | |
"string" | |
], | |
"title": "Polymporphic object type", | |
"name": "polymorphic_type", | |
"description": "Polymorphic type base" | |
}, | |
"user_id": { | |
"id": "#/definitions/user_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "User ID", | |
"description": "User ID", | |
"name": "user_id" | |
}, | |
"group_id": { | |
"id": "#/definitions/group_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Group ID", | |
"description": "Group ID", | |
"name": "group_id" | |
}, | |
"group_member_id": { | |
"id": "#/definitions/group_member_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Group Member ID", | |
"description": "Group Member ID", | |
"name": "group_member_id" | |
}, | |
"role_id": { | |
"id": "#/definitions/role_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Role ID", | |
"description": "Role ID", | |
"name": "role_id" | |
}, | |
"permission_id": { | |
"id": "#/definitions/permission_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Permission ID", | |
"description": "Permission ID", | |
"name": "permission_id" | |
}, | |
"message_template_id": { | |
"id": "#/definitions/message_template_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Message Template ID", | |
"description": "Message Template ID", | |
"name": "message_template_id" | |
}, | |
"message_template_domain_id": { | |
"id": "#/definitions/message_template_domain_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Message Template Domain ID", | |
"description": "Message Template Domain ID", | |
"name": "message_template_domain_id" | |
}, | |
"subscription_id": { | |
"id": "#/definitions/subscription_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Subscription ID", | |
"description": "Subscription ID", | |
"name": "subscription_id" | |
}, | |
"subscription_type_id": { | |
"id": "#/definitions/subscription_type_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Subscription Type ID", | |
"description": "Subscription Type ID", | |
"name": "subscription_type_id" | |
}, | |
"subscription_asset_id": { | |
"id": "#/definitions/subscription_asset_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Subscription Asset ID", | |
"description": "Subscription Asset ID", | |
"name": "subscription_asset_id" | |
}, | |
"subscription_type_asset_id": { | |
"id": "#/definitions/subscription_type_asset_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Subscription Type Asset ID", | |
"description": "Subscription Type Asset ID", | |
"name": "subscription_type_asset_id" | |
}, | |
"subscription_type_price_id": { | |
"id": "#/definitions/subscription_type_price_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Subscription Type Price ID", | |
"description": "Subscription Type Price ID", | |
"name": "subscription_type_price_id" | |
}, | |
"ticket_id": { | |
"id": "#/definitions/ticket_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Ticket ID", | |
"description": "Ticket ID", | |
"name": "ticket_id" | |
}, | |
"tocket_lock_id": { | |
"id": "#/definitions/tocket_lock_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Ticket Lock ID", | |
"description": "Ticket Lock ID", | |
"name": "tocket_lock_id" | |
}, | |
"ticket_message_id": { | |
"id": "#/definitions/ticket_message_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Ticket Message ID", | |
"description": "Ticket Message ID", | |
"name": "ticket_message_id" | |
}, | |
"ticket_message_draft_id": { | |
"id": "#/definitions/ticket_message_draft_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Ticket Message Draft ID", | |
"description": "Ticket Message Draft ID", | |
"name": "ticket_message_draft_id" | |
}, | |
"ticket_message_draft_archive_id": { | |
"id": "#/definitions/ticket_message_draft_archive_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Ticket Message Draft Archive ID", | |
"description": "Ticket Message Draft Archive ID", | |
"name": "ticket_message_draft_archive_id" | |
}, | |
"ticket_subscriber_id": { | |
"id": "#/definitions/ticket_subscriber_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Ticket Subscriber ID", | |
"description": "Ticket Subscriber ID", | |
"name": "ticket_subscriber_id" | |
}, | |
"owner_id": { | |
"id": "#/definitions/owner_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Owner ID", | |
"description": "Owner ID", | |
"name": "owner_id" | |
}, | |
"owner_type": { | |
"id": "#/definitions/owner_type", | |
"$ref": "#/definitions/definitions/definitions/polymorphic_type", | |
"title": "Owner type", | |
"description": "Owner type", | |
"name": "owner_type", | |
"default": "Yeti\\User\\Models\\User" | |
}, | |
"object_id": { | |
"id": "#/definitions/object_id", | |
"allOf": [ | |
{ | |
"$ref": "#/definitions/definitions/definitions/id" | |
} | |
], | |
"title": "Reference Object ID", | |
"description": "Reference Object ID", | |
"name": "object_id" | |
}, | |
"object_type": { | |
"id": "#/definitions/object_type", | |
"$ref": "#/definitions/definitions/definitions/polymorphic_type", | |
"title": "Reference Object Type", | |
"description": "Reference Object Type", | |
"name": "object_type", | |
"default": "Yeti\\Item\\Models\\Item" | |
}, | |
"actor_id": { | |
"id": "#/definitions/actor_id", | |
"type": [ | |
"integer" | |
], | |
"title": "ACL Actor ID", | |
"description": "ACL Actor ID", | |
"name": "actor_id" | |
}, | |
"actor_type": { | |
"id": "#/definitions/actor_type", | |
"$ref": "#/definitions/definitions/definitions/polymorphic_type", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "ACL Actor Type", | |
"description": "ACL Actor Type", | |
"name": "actor_type" | |
}, | |
"end_user_id": { | |
"id": "#/definitions/end_user_id", | |
"type": [ | |
"integer" | |
], | |
"title": "End User ID", | |
"description": "End User ID", | |
"name": "end_user_id" | |
}, | |
"end_user_type": { | |
"id": "#/definitions/end_user_type", | |
"$ref": "#/definitions/definitions/definitions/polymorphic_type", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "End User Type", | |
"description": "End User Type", | |
"name": "end_user_type" | |
}, | |
"item_id": { | |
"id": "#/definitions/item_id", | |
"type": [ | |
"integer" | |
], | |
"title": "Item ID", | |
"description": "Item ID", | |
"name": "item_id" | |
}, | |
"item_type": { | |
"id": "#/definitions/item_type", | |
"$ref": "#/definitions/definitions/definitions/polymorphic_type", | |
"title": "Item Type", | |
"description": "Item Type", | |
"name": "item_type" | |
}, | |
"name": { | |
"id": "#/definitions/name", | |
"type": [ | |
"string" | |
], | |
"title": "Name", | |
"minLength": 6, | |
"description": "Name", | |
"name": "name" | |
}, | |
"slug": { | |
"id": "#/definitions/slug", | |
"type": [ | |
"string" | |
], | |
"minLength": 6, | |
"title": "Slug", | |
"description": "Slug", | |
"name": "slug" | |
}, | |
"created_at": { | |
"id": "#/definitions/created_at", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Creation date", | |
"description": "Creation date", | |
"name": "created_at" | |
}, | |
"updated_at": { | |
"id": "#/definitions/updated_at", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Modification date", | |
"description": "Modification date", | |
"name": "updated_at" | |
}, | |
"deleted_at": { | |
"id": "#/definitions/deleted_at", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Deletion date", | |
"description": "Deletion date", | |
"name": "deleted_at" | |
}, | |
"group_type": { | |
"id": "#/definitions/group_type", | |
"type": [ | |
"string" | |
], | |
"title": "Group type", | |
"description": "Group type", | |
"name": "group_type", | |
"default": "team" | |
}, | |
"spam": { | |
"id": "#/definitions/spam", | |
"type": [ | |
"boolean" | |
], | |
"title": "Spam", | |
"description": "Indicates whether the item is marked as spam", | |
"name": "spam", | |
"default": false | |
}, | |
"leader": { | |
"id": "#/definitions/leader", | |
"type": [ | |
"integer" | |
], | |
"title": "Leader", | |
"description": "Leader", | |
"name": "leader" | |
}, | |
"message_template_content": { | |
"id": "#/definitions/message_template_content", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Message Template Content", | |
"description": "Message Template Content", | |
"name": "content", | |
"default": "Message" | |
}, | |
"action": { | |
"id": "#/definitions/action", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Action", | |
"description": "Action the given permission line", | |
"name": "action" | |
}, | |
"asset_type": { | |
"id": "#/definitions/asset_type", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Asset Type", | |
"description": "Asset Type", | |
"name": "asset_type", | |
"default": "Yeti\\Item\\Models\\Item" | |
}, | |
"asset_size": { | |
"id": "#/definitions/asset_size", | |
"type": [ | |
"integer" | |
], | |
"multipleOf": 1, | |
"maximum": 100, | |
"minimum": 1, | |
"exclusiveMaximum": false, | |
"exclusiveMinimum": false, | |
"title": "Size of an individual asset", | |
"description": "Size of an asset, applicable for subscription assets such as user groups which may have N members", | |
"name": "asset_size", | |
"default": 1 | |
}, | |
"asset_count": { | |
"id": "#/definitions/asset_count", | |
"type": [ | |
"integer" | |
], | |
"multipleOf": 1, | |
"maximum": 100, | |
"minimum": 1, | |
"exclusiveMaximum": false, | |
"exclusiveMinimum": false, | |
"title": "Asset count", | |
"description": "Maximum allowed asset count", | |
"name": "asset_count", | |
"default": 5 | |
}, | |
"price": { | |
"id": "#/definitions/price", | |
"type": [ | |
"number" | |
], | |
"multipleOf": 0.01, | |
"maximum": 100, | |
"minimum": 1, | |
"exclusiveMaximum": false, | |
"exclusiveMinimum": false, | |
"title": "", | |
"description": "", | |
"name": "price" | |
}, | |
"coupon_code": { | |
"id": "#/definitions/coupon_code", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Coupon Code", | |
"description": "Coupon Code", | |
"name": "coupon_code" | |
}, | |
"starts": { | |
"id": "#/definitions/starts", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Start date", | |
"description": "Start date", | |
"name": "starts" | |
}, | |
"ends": { | |
"id": "#/definitions/ends", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "End date", | |
"description": "End date", | |
"name": "ends" | |
}, | |
"ticket_status": { | |
"id": "#/definitions/status", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Status", | |
"description": "Indicates the ticket's status", | |
"name": "status" | |
}, | |
"ticket_lock_exclusivity": { | |
"id": "#/definitions/ticket_lock_exclusivity", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Ticket lock exclusivity", | |
"description": "Ticket lock exclusivity", | |
"name": "ticket_lock_exclusivity", | |
"default": "global-exclusive" | |
}, | |
"ticket_lock_type": { | |
"id": "#/definitions/ticket_lock_type", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Ticket Lock Type", | |
"description": "Ticket Lock Type", | |
"name": "ticket_lock_type", | |
"default": "support" | |
}, | |
"format": { | |
"id": "#/definitions/format", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Message Format", | |
"description": "Message Format", | |
"name": "format", | |
"default": "html" | |
}, | |
"subject": { | |
"id": "#/definitions/subject", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Message Subject", | |
"description": "Message Subject", | |
"name": "subject" | |
}, | |
"message": { | |
"id": "#/definitions/message", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Message Content", | |
"description": "Message Content", | |
"name": "message" | |
}, | |
"ticket_subscription_type": { | |
"id": "#/definitions/ticket_subscription_type", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Ticket subscription type", | |
"description": "Ticket subscription type", | |
"name": "ticket_subscription_type", | |
"default": "watcher" | |
}, | |
"ticket_subscription_expiration": { | |
"id": "#/definitions/ticket_subscription_expiration", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Ticket Subscription Expiration", | |
"description": "Ticket Subscription Expiration", | |
"name": "ticket_subscription_expiration" | |
}, | |
"first_name": { | |
"id": "#/definitions/first_name", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "First Name", | |
"description": "First Name", | |
"name": "first_name" | |
}, | |
"last_name": { | |
"id": "#/definitions/last_name", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Last Name", | |
"description": "Last Name", | |
"name": "last_name" | |
}, | |
"password": { | |
"id": "#/definitions/password", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Password", | |
"description": "Password", | |
"name": "password", | |
"default": "Password" | |
}, | |
"two_factor_token": { | |
"id": "#/definitions/two_factor_token", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Google 2FA Token", | |
"description": "Google 2FA Token", | |
"name": "two_factor_token" | |
}, | |
"email": { | |
"id": "#/definitions/email", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "E-mail Address", | |
"description": "E-mail Address", | |
"name": "email", | |
"default": "[email protected]" | |
} | |
}, | |
"additionalProperties": false | |
}, | |
"group": { | |
"$schema": "http://json-schema.org/draft-04/hyper-schema", | |
"title": "FIXME - Group", | |
"definitions": { | |
"id": { | |
"$ref": "#/definitions/definitions/definitions/group_id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/definitions/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/definitions/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/definitions/definitions/deleted_at" | |
}, | |
"name": { | |
"$ref": "#/definitions/definitions/definitions/name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/definitions/definitions/slug" | |
}, | |
"group_type": { | |
"$ref": "#/definitions/definitions/definitions/group_type" | |
}, | |
"spam": { | |
"$ref": "#/definitions/definitions/definitions/spam" | |
}, | |
"leader": { | |
"$ref": "#/definitions/definitions/definitions/leader" | |
}, | |
"members": { | |
"type": [ | |
"array" | |
], | |
"items": { | |
"$ref": "#/definitions/definitions/definitions/group_member" | |
} | |
} | |
}, | |
"required": [ | |
], | |
"description": "FIXME", | |
"links": [ | |
{ | |
"description": "Create a new group.", | |
"href": "/group", | |
"method": "POST", | |
"rel": "create", | |
"schema": { | |
"properties": { | |
"name": { | |
"$ref": "#/definitions/group//definitions/name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/group//definitions/slug" | |
}, | |
"group_type": { | |
"$ref": "#/definitions/group//definitions/group_type" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Create" | |
}, | |
{ | |
"description": "Delete an existing group.", | |
"href": "/group/{id}", | |
"method": "DELETE", | |
"rel": "destroy", | |
"title": "Delete" | |
}, | |
{ | |
"description": "Info for existing group.", | |
"href": "/group/{id}", | |
"method": "GET", | |
"rel": "self", | |
"title": "Info" | |
}, | |
{ | |
"description": "List existing groups.", | |
"href": "/groups", | |
"method": "GET", | |
"rel": "instances", | |
"title": "List" | |
}, | |
{ | |
"description": "Update an existing group.", | |
"href": "/group/{id}", | |
"method": "PATCH", | |
"rel": "update", | |
"schema": { | |
"properties": { | |
"id": { | |
"$ref": "#/definitions/definitions/id" | |
}, | |
"name": { | |
"$ref": "#/definitions/definitions/name" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Update" | |
} | |
], | |
"properties": { | |
"id": { | |
"$ref": "#/definitions/definitions/id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/definitions/deleted_at" | |
}, | |
"name": { | |
"$ref": "#/definitions/definitions/name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/definitions/slug" | |
}, | |
"group_type": { | |
"$ref": "#/definitions/definitions/group_type" | |
}, | |
"spam": { | |
"$ref": "#/definitions/definitions/spam" | |
}, | |
"leader": { | |
"$ref": "#/definitions/definitions/leader" | |
}, | |
"members": { | |
"$ref": "#/definitions/definitions/members" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"group_member": { | |
"$schema": "http://json-schema.org/draft-04/hyper-schema", | |
"title": "FIXME - Group_member", | |
"definitions": { | |
"id": { | |
"$ref": "#/definitions/definitions/definitions/group_member_id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/definitions/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/definitions/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/definitions/definitions/deleted_at" | |
}, | |
"user_id": { | |
"$ref": "#/definitions/definitions/definitions/user_id" | |
}, | |
"group_id": { | |
"$ref": "#/definitions/definitions/definitions/group_id" | |
}, | |
"role_id": { | |
"$ref": "#/definitions/definitions/definitions/role_id" | |
} | |
}, | |
"required": [ | |
], | |
"description": "FIXME", | |
"links": [ | |
{ | |
"description": "Create a new group_member.", | |
"href": "/group/{group_id}/member", | |
"method": "POST", | |
"rel": "create", | |
"schema": { | |
"properties": { | |
"user_id": { | |
"$ref": "#/definitions/group_member/definitions//user_id" | |
}, | |
"group_id": { | |
"$ref": "#/definitions/group_member/definitions//group_id" | |
}, | |
"role_id": { | |
"$ref": "#/definitions/group_member/definitions//role_id" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Create" | |
}, | |
{ | |
"description": "Delete an existing group_member.", | |
"href": "/group/{group_id}/member/{id}", | |
"method": "DELETE", | |
"rel": "destroy", | |
"title": "Delete" | |
}, | |
{ | |
"description": "Info for existing group_member.", | |
"href": "/group/{group_id}/member/{id}", | |
"method": "GET", | |
"rel": "self", | |
"title": "Info" | |
}, | |
{ | |
"description": "List existing group_members.", | |
"href": "/group/{group_id}/member", | |
"method": "GET", | |
"rel": "instances", | |
"title": "List" | |
} | |
], | |
"properties": { | |
"id": { | |
"$ref": "#/definitions/group_member/definitions//id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/group_member/definitions//created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/group_member/definitions//updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/group_member/definitions//deleted_at" | |
}, | |
"user_id": { | |
"$ref": "#/definitions/group_member/definitions//user_id" | |
}, | |
"group_id": { | |
"$ref": "#/definitions/group_member/definitions//group_id" | |
}, | |
"role_id": { | |
"$ref": "#/definitions/group_member/definitions//role_id" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"item": { | |
"$schema": "http://json-schema.org/draft-04/hyper-schema", | |
"title": "FIXME - Item", | |
"definitions": { | |
"id": { | |
"$ref": "#/definitions/definitions/definitions/item_id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/definitions/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/definitions/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/definitions/definitions/deleted_at" | |
}, | |
"name": { | |
"$ref": "#/definitions/definitions/definitions/name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/definitions/definitions/slug" | |
}, | |
"owner_id": { | |
"$ref": "#/definitions/definitions/definitions/owner_id" | |
}, | |
"owner_type": { | |
"$ref": "#/definitions/definitions/definitions/owner_type" | |
} | |
}, | |
"required": [ | |
], | |
"description": "FIXME", | |
"links": [ | |
{ | |
"description": "Create a new item.", | |
"href": "/items", | |
"method": "POST", | |
"rel": "create", | |
"schema": { | |
"properties": { | |
"name": { | |
"$ref": "#/definitions/item/definitions/name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/item/definitions/slug" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Create" | |
}, | |
{ | |
"description": "Delete an existing item.", | |
"href": "/items/{id}", | |
"method": "DELETE", | |
"rel": "destroy", | |
"title": "Delete" | |
}, | |
{ | |
"description": "Info for existing item.", | |
"href": "/items/{id}", | |
"method": "GET", | |
"rel": "self", | |
"title": "Info" | |
}, | |
{ | |
"description": "List existing items.", | |
"href": "/items", | |
"method": "GET", | |
"rel": "instances", | |
"title": "List" | |
}, | |
{ | |
"description": "Update an existing item.", | |
"href": "/items/{id}", | |
"method": "PATCH", | |
"rel": "update", | |
"schema": { | |
"properties": { | |
"name": { | |
"$ref": "#/definitions/item/definitions/name" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Update" | |
} | |
], | |
"properties": { | |
"id": { | |
"$ref": "#/definitions/item/definitions/id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/item/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/item/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/item/definitions/deleted_at" | |
}, | |
"name": { | |
"$ref": "#/definitions/item/definitions/name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/item/definitions/slug" | |
}, | |
"owner_id": { | |
"$ref": "#/definitions/item/definitions/owner_id" | |
}, | |
"owner_type": { | |
"$ref": "#/definitions/item/definitions/owner_type" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"user": { | |
"$schema": "http://json-schema.org/draft-04/hyper-schema", | |
"title": "FIXME - User", | |
"definitions": { | |
"id": { | |
"$ref": "#/definitions/definitions/definitions/user_id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/definitions/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/definitions/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/definitions/definitions/deleted_at" | |
}, | |
"first_name": { | |
"$ref": "#/definitions/definitions/definitions/first_name" | |
}, | |
"last_name": { | |
"$ref": "#/definitions/definitions/definitions/last_name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/definitions/definitions/slug" | |
}, | |
"password": { | |
"$ref": "#/definitions/definitions/definitions/password" | |
}, | |
"spam": { | |
"$ref": "#/definitions/definitions/definitions/spam" | |
}, | |
"two_factor_token": { | |
"$ref": "#/definitions/definitions/definitions/two_factor_token" | |
}, | |
"emails": { | |
"$ref": "#/definitions/definitions/definitions/email" | |
} | |
}, | |
"required": [ | |
"id", | |
"created_at", | |
"modified_at", | |
"deleted_at", | |
"first_name", | |
"last_name", | |
"slug", | |
"password", | |
"spam", | |
"two_factor_token", | |
"email" | |
], | |
"description": "FIXME", | |
"links": [ | |
{ | |
"description": "Create a new user.", | |
"href": "/users", | |
"method": "POST", | |
"rel": "create", | |
"schema": { | |
"properties": { | |
"id": { | |
"$ref": "#/definitions/user/definitions/id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/user/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/user/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/user/definitions/deleted_at" | |
}, | |
"first_name": { | |
"$ref": "#/definitions/user/definitions/first_name" | |
}, | |
"last_name": { | |
"$ref": "#/definitions/user/definitions/last_name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/user/definitions/slug" | |
}, | |
"password": { | |
"$ref": "#/definitions/user/definitions/password" | |
}, | |
"spam": { | |
"$ref": "#/definitions/user/definitions/spam" | |
}, | |
"two_factor_token": { | |
"$ref": "#/definitions/user/definitions/two_factor_token" | |
}, | |
"email": { | |
"$ref": "#/definitions/user/definitions/email" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Create" | |
}, | |
{ | |
"description": "Delete an existing user.", | |
"href": "/users/{id}", | |
"method": "DELETE", | |
"rel": "destroy", | |
"title": "Delete" | |
}, | |
{ | |
"description": "Info for existing user.", | |
"href": "/users/{id}", | |
"method": "GET", | |
"rel": "self", | |
"title": "Info" | |
}, | |
{ | |
"description": "List existing users.", | |
"href": "/users", | |
"method": "GET", | |
"rel": "instances", | |
"title": "List" | |
}, | |
{ | |
"description": "Update an existing user.", | |
"href": "/users/{id}", | |
"method": "PATCH", | |
"rel": "update", | |
"schema": { | |
"properties": { | |
"first_name": { | |
"$ref": "#/definitions/user/definitions/first_name" | |
}, | |
"last_name": { | |
"$ref": "#/definitions/user/definitions/last_name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/user/definitions/slug" | |
}, | |
"password": { | |
"$ref": "#/definitions/user/definitions/password" | |
}, | |
"spam": { | |
"$ref": "#/definitions/user/definitions/spam" | |
}, | |
"two_factor_token": { | |
"$ref": "#/definitions/user/definitions/two_factor_token" | |
}, | |
"email": { | |
"$ref": "#/definitions/user/definitions/email" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
}, | |
"title": "Update" | |
} | |
], | |
"properties": { | |
"id": { | |
"$ref": "#/definitions/user/definitions/id" | |
}, | |
"created_at": { | |
"$ref": "#/definitions/user/definitions/created_at" | |
}, | |
"updated_at": { | |
"$ref": "#/definitions/user/definitions/updated_at" | |
}, | |
"deleted_at": { | |
"$ref": "#/definitions/user/definitions/deleted_at" | |
}, | |
"first_name": { | |
"$ref": "#/definitions/user/definitions/first_name" | |
}, | |
"last_name": { | |
"$ref": "#/definitions/user/definitions/last_name" | |
}, | |
"slug": { | |
"$ref": "#/definitions/user/definitions/slug" | |
}, | |
"password": { | |
"$ref": "#/definitions/user/definitions/password" | |
}, | |
"spam": { | |
"$ref": "#/definitions/user/definitions/spam" | |
}, | |
"two_factor_token": { | |
"$ref": "#/definitions/user/definitions/two_factor_token" | |
}, | |
"email": { | |
"$ref": "#/definitions/user/definitions/email" | |
} | |
}, | |
"type": [ | |
"object" | |
] | |
} | |
}, | |
"properties": { | |
"definitions": { | |
"$ref": "#/definitions/definitions" | |
}, | |
"group": { | |
"$ref": "#/definitions/group" | |
}, | |
"group_member": { | |
"$ref": "#/definitions/group_member" | |
}, | |
"item": { | |
"$ref": "#/definitions/item" | |
}, | |
"user": { | |
"$ref": "#/definitions/user" | |
} | |
}, | |
"type": [ | |
"object" | |
], | |
"description": "Yeti Support API", | |
"id": "http://api.yeti-support.com", | |
"links": [ | |
{ | |
"href": "https://api.yeti-support.com", | |
"rel": "self" | |
} | |
], | |
"title": "Yeti Support" | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"id": { | |
"id": "http://api.yeti-support.com#/definitions/user_id", | |
"allOf": [ | |
{ | |
"id": "http://api.yeti-support.com#/definitions/id", | |
"type": [ | |
"integer" | |
], | |
"multipleOf": 1, | |
"minimum": 1, | |
"title": "Object ID", | |
"description": "Unique ID for an object", | |
"name": "id" | |
} | |
], | |
"title": "User ID", | |
"description": "User ID", | |
"name": "user_id" | |
}, | |
"created_at": { | |
"id": "http://api.yeti-support.com#/definitions/created_at", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Creation date", | |
"description": "Creation date", | |
"name": "created_at" | |
}, | |
"updated_at": { | |
"id": "http://api.yeti-support.com#/definitions/updated_at", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Modification date", | |
"description": "Modification date", | |
"name": "updated_at" | |
}, | |
"deleted_at": { | |
"id": "http://api.yeti-support.com#/definitions/deleted_at", | |
"type": [ | |
"string" | |
], | |
"format": "date-time", | |
"title": "Deletion date", | |
"description": "Deletion date", | |
"name": "deleted_at" | |
}, | |
"first_name": { | |
"id": "http://api.yeti-support.com#/definitions/first_name", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "First Name", | |
"description": "First Name", | |
"name": "first_name" | |
}, | |
"last_name": { | |
"id": "http://api.yeti-support.com#/definitions/last_name", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Last Name", | |
"description": "Last Name", | |
"name": "last_name" | |
}, | |
"slug": { | |
"id": "http://api.yeti-support.com#/definitions/slug", | |
"type": [ | |
"string" | |
], | |
"minLength": 6, | |
"title": "Slug", | |
"description": "Slug", | |
"name": "slug" | |
}, | |
"password": { | |
"id": "http://api.yeti-support.com#/definitions/password", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Password", | |
"description": "Password", | |
"name": "password", | |
"default": "Password" | |
}, | |
"spam": { | |
"id": "http://api.yeti-support.com#/definitions/spam", | |
"type": [ | |
"boolean" | |
], | |
"title": "Spam", | |
"description": "Indicates whether the item is marked as spam", | |
"name": "spam", | |
"default": false | |
}, | |
"two_factor_token": { | |
"id": "http://api.yeti-support.com#/definitions/two_factor_token", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "Google 2FA Token", | |
"description": "Google 2FA Token", | |
"name": "two_factor_token" | |
}, | |
"email": { | |
"id": "http://api.yeti-support.com#/definitions/email", | |
"type": [ | |
"string" | |
], | |
"minLength": 1, | |
"title": "E-mail Address", | |
"description": "E-mail Address", | |
"name": "email", | |
"default": "[email protected]" | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment