Skip to content

Commit 624e8f3

Browse files
authored
Merge pull request #3453 from owenconti/bug/3414-redo
Reimplemented PR #3427, fix for request body validation
2 parents 81bb7da + 299b609 commit 624e8f3

File tree

8 files changed

+398
-97
lines changed

8 files changed

+398
-97
lines changed

src/core/components/layout-utils.jsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@ export class Select extends React.Component {
129129
value: PropTypes.any,
130130
onChange: PropTypes.func,
131131
multiple: PropTypes.bool,
132-
allowEmptyValue: PropTypes.bool
132+
allowEmptyValue: PropTypes.bool,
133+
className: PropTypes.string
133134
}
134135

135136
static defaultProps = {
@@ -142,7 +143,7 @@ export class Select extends React.Component {
142143

143144
let value
144145

145-
if (props.value !== undefined) {
146+
if (props.value) {
146147
value = props.value
147148
} else {
148149
value = props.multiple ? [""] : ""
@@ -178,7 +179,7 @@ export class Select extends React.Component {
178179
let value = this.state.value.toJS ? this.state.value.toJS() : this.state.value
179180

180181
return (
181-
<select multiple={ multiple } value={ value } onChange={ this.onChange } >
182+
<select className={this.props.className} multiple={ multiple } value={ value } onChange={ this.onChange } >
182183
{ allowEmptyValue ? <option value="">--</option> : null }
183184
{
184185
allowedValues.map(function (item, key) {

src/core/json-schema-components.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export class JsonSchema_string extends Component {
5757

5858
if ( enumValue ) {
5959
const Select = getComponent("Select")
60-
return (<Select allowedValues={ enumValue }
60+
return (<Select className={ errors.length ? "invalid" : ""}
61+
allowedValues={ enumValue }
6162
value={ value }
6263
allowEmptyValue={ !required }
6364
onChange={ this.onEnumChange }/>)
@@ -121,6 +122,7 @@ export class JsonSchema_array extends PureComponent {
121122
render() {
122123
let { getComponent, required, schema, fn } = this.props
123124

125+
let errors = schema.errors || []
124126
let itemSchema = fn.inferSchema(schema.items)
125127

126128
const JsonSchemaForm = getComponent("JsonSchemaForm")
@@ -131,19 +133,17 @@ export class JsonSchema_array extends PureComponent {
131133

132134
if ( enumValue ) {
133135
const Select = getComponent("Select")
134-
return (<Select multiple={ true }
136+
return (<Select className={ errors.length ? "invalid" : ""}
137+
multiple={ true }
135138
value={ value }
136139
allowedValues={ enumValue }
137140
allowEmptyValue={ !required }
138141
onChange={ this.onEnumChange }/>)
139142
}
140143

141-
let errors = schema.errors || []
142-
143144
return (
144145
<div>
145-
{ !value || value.count() < 1 ?
146-
(errors.length ? <span style={{ color: "red", fortWeight: "bold" }}>{ errors[0] }</span> : null) :
146+
{ !value || value.count() < 1 ? null :
147147
value.map( (item,i) => {
148148
let schema = Object.assign({}, itemSchema)
149149
if ( errors.length ) {
@@ -153,12 +153,12 @@ export class JsonSchema_array extends PureComponent {
153153
return (
154154
<div key={i} className="json-schema-form-item">
155155
<JsonSchemaForm fn={fn} getComponent={getComponent} value={item} onChange={(val) => this.onItemChange(val, i)} schema={schema} />
156-
<Button className="json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
156+
<Button className="btn btn-sm json-schema-form-item-remove" onClick={()=> this.removeItem(i)} > - </Button>
157157
</div>
158158
)
159159
}).toArray()
160160
}
161-
<Button className="json-schema-form-item-add" onClick={this.addItem}> Add item </Button>
161+
<Button className={`btn btn-sm json-schema-form-item-add ${errors.length ? "invalid" : null}`} onClick={this.addItem}> Add item </Button>
162162
</div>
163163
)
164164
}
@@ -170,12 +170,14 @@ export class JsonSchema_boolean extends Component {
170170

171171
onEnumChange = (val) => this.props.onChange(val)
172172
render() {
173-
let { getComponent, required, value } = this.props
173+
let { getComponent, value, schema } = this.props
174+
let errors = schema.errors || []
174175
const Select = getComponent("Select")
175176

176-
return (<Select value={ String(value) }
177+
return (<Select className={ errors.length ? "invalid" : ""}
178+
value={ String(value) }
177179
allowedValues={ fromJS(["true", "false"]) }
178-
allowEmptyValue={ !required }
180+
allowEmptyValue={ true }
179181
onChange={ this.onEnumChange }/>)
180182
}
181183
}

src/core/utils.js

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -468,60 +468,88 @@ export const validateFile = ( val ) => {
468468
}
469469
}
470470

471+
export const validateBoolean = ( val ) => {
472+
if ( !(val === "true" || val === "false" || val === true || val === false) ) {
473+
return "Value must be a boolean"
474+
}
475+
}
476+
477+
export const validateString = ( val ) => {
478+
if ( val && typeof val !== "string" ) {
479+
return "Value must be a string"
480+
}
481+
}
482+
471483
// validation of parameters before execute
472484
export const validateParam = (param, isXml) => {
473485
let errors = []
474486
let value = isXml && param.get("in") === "body" ? param.get("value_xml") : param.get("value")
475487
let required = param.get("required")
476488
let type = param.get("type")
477489

478-
let stringCheck = type === "string" && !value
479-
let arrayCheck = type === "array" && Array.isArray(value) && !value.length
480-
let listCheck = type === "array" && Im.List.isList(value) && !value.count()
481-
let fileCheck = type === "file" && !(value instanceof win.File)
482-
let nullUndefinedCheck = value === null || value === undefined
483-
484-
if ( required && (stringCheck || arrayCheck || listCheck || fileCheck || nullUndefinedCheck) ) {
485-
errors.push("Required field is not provided")
486-
return errors
487-
}
488-
489-
if ( value === null || value === undefined ) {
490-
return errors
491-
}
492-
493-
if ( type === "number" ) {
494-
let err = validateNumber(value)
495-
if (!err) return errors
496-
errors.push(err)
497-
} else if ( type === "integer" ) {
498-
let err = validateInteger(value)
499-
if (!err) return errors
500-
errors.push(err)
501-
} else if ( type === "array" ) {
502-
let itemType
503-
504-
if ( !value.count() ) { return errors }
505-
506-
itemType = param.getIn(["items", "type"])
507-
508-
value.forEach((item, index) => {
509-
let err
490+
/*
491+
If the parameter is required OR the parameter has a value (meaning optional, but filled in)
492+
then we should do our validation routine.
493+
Only bother validating the parameter if the type was specified.
494+
*/
495+
if ( type && (required || value) ) {
496+
// These checks should evaluate to true if the parameter's value is valid
497+
let stringCheck = type === "string" && value && !validateString(value)
498+
let arrayCheck = type === "array" && Array.isArray(value) && value.length
499+
let listCheck = type === "array" && Im.List.isList(value) && value.count()
500+
let fileCheck = type === "file" && value instanceof win.File
501+
let booleanCheck = type === "boolean" && !validateBoolean(value)
502+
let numberCheck = type === "number" && !validateNumber(value) // validateNumber returns undefined if the value is a number
503+
let integerCheck = type === "integer" && !validateInteger(value) // validateInteger returns undefined if the value is an integer
504+
505+
if ( required && !(stringCheck || arrayCheck || listCheck || fileCheck || booleanCheck || numberCheck || integerCheck) ) {
506+
errors.push("Required field is not provided")
507+
return errors
508+
}
510509

511-
if (itemType === "number") {
512-
err = validateNumber(item)
513-
} else if (itemType === "integer") {
514-
err = validateInteger(item)
515-
}
510+
if ( type === "string" ) {
511+
let err = validateString(value)
512+
if (!err) return errors
513+
errors.push(err)
514+
} else if ( type === "boolean" ) {
515+
let err = validateBoolean(value)
516+
if (!err) return errors
517+
errors.push(err)
518+
} else if ( type === "number" ) {
519+
let err = validateNumber(value)
520+
if (!err) return errors
521+
errors.push(err)
522+
} else if ( type === "integer" ) {
523+
let err = validateInteger(value)
524+
if (!err) return errors
525+
errors.push(err)
526+
} else if ( type === "array" ) {
527+
let itemType
528+
529+
if ( !value.count() ) { return errors }
530+
531+
itemType = param.getIn(["items", "type"])
532+
533+
value.forEach((item, index) => {
534+
let err
535+
536+
if (itemType === "number") {
537+
err = validateNumber(item)
538+
} else if (itemType === "integer") {
539+
err = validateInteger(item)
540+
} else if (itemType === "string") {
541+
err = validateString(item)
542+
}
516543

517-
if ( err ) {
518-
errors.push({ index: index, error: err})
519-
}
520-
})
521-
} else if ( type === "file" ) {
522-
let err = validateFile(value)
523-
if (!err) return errors
524-
errors.push(err)
544+
if ( err ) {
545+
errors.push({ index: index, error: err})
546+
}
547+
})
548+
} else if ( type === "file" ) {
549+
let err = validateFile(value)
550+
if (!err) return errors
551+
errors.push(err)
552+
}
525553
}
526554

527555
return errors

src/style/_buttons.scss

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@
1414

1515
@include text_headline();
1616

17+
&.btn-sm
18+
{
19+
font-size: 12px;
20+
padding: 4px 23px;
21+
}
22+
1723
&[disabled]
1824
{
1925
cursor: not-allowed;
@@ -165,6 +171,10 @@
165171
button
166172
{
167173
cursor: pointer;
168-
169174
outline: none;
175+
176+
&.invalid
177+
{
178+
@include invalidFormElement();
179+
}
170180
}

src/style/_form.scss

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ select
2121

2222
background: #f7f7f7;
2323
}
24+
25+
&.invalid {
26+
@include invalidFormElement();
27+
}
2428
}
2529

2630
.opblock-body select
@@ -55,10 +59,7 @@ input[type=file]
5559

5660
&.invalid
5761
{
58-
animation: shake .4s 1;
59-
60-
border-color: $_color-delete;
61-
background: lighten($_color-delete, 35%);
62+
@include invalidFormElement();
6263
}
6364
}
6465

src/style/_mixins.scss

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,9 @@ $browser-context: 16;
166166
@warn 'Breakpoint mixin supports: tablet, mobile, desktop';
167167
}
168168
}
169+
170+
@mixin invalidFormElement() {
171+
animation: shake .4s 1;
172+
border-color: $_color-delete;
173+
background: lighten($_color-delete, 35%);
174+
}

src/style/_table.scss

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,10 @@ table
9797
width: 100%;
9898
max-width: 340px;
9999
}
100+
101+
select {
102+
border-width: 1px;
103+
}
100104
}
101105

102106
.parameter__name

0 commit comments

Comments
 (0)