Skip to content

Commit

Permalink
[CVAT-UI] Better labels validation and fixed React warning (#1727)
Browse files Browse the repository at this point in the history
* Better validation

* Temporary ID generation for created labels and attributes (fixes React warning)

* Updated version and changelog

* Fixed bug with existing labels
  • Loading branch information
bsekachev authored Jun 16, 2020
1 parent b4600be commit 3adaf7e
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Shortcut to change color of an activated shape in new UI (Enter) (<https://github.com/opencv/cvat/pull/1683>)
- Shortcut to switch split mode (<https://github.com/opencv/cvat/pull/1683>)
- Built-in search for labels when create an object or change a label (<https://github.com/opencv/cvat/pull/1683>)
- Better validation of labels and attributes in raw viewer (<https://github.com/opencv/cvat/pull/1727>)

### Changed
- Removed information about e-mail from the basic user information (<https://github.com/opencv/cvat/pull/1627>)
Expand All @@ -32,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Wrong rexex for account name validation (<https://github.com/opencv/cvat/pull/1667>)
- Wrong description on register view for the username field (<https://github.com/opencv/cvat/pull/1667>)
- Wrong resolution for resizing a shape (<https://github.com/opencv/cvat/pull/1667>)
- React warning because of not unique keys in labels viewer (<https://github.com/opencv/cvat/pull/1727>)


### Security
- SQL injection in Django `CVE-2020-9402` (<https://github.com/opencv/cvat/pull/1657>)
Expand Down
2 changes: 1 addition & 1 deletion cvat-ui/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cvat-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "cvat-ui",
"version": "1.3.0",
"version": "1.3.1",
"description": "CVAT single-page application",
"main": "src/index.tsx",
"scripts": {
Expand Down
53 changes: 53 additions & 0 deletions cvat-ui/src/components/labels-editor/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,59 @@ export interface Label {

let id = 0;

function validateParsedAttribute(attr: Attribute): void {
if (typeof (attr.name) !== 'string') {
throw new Error(`Type of attribute name must be a string. Got value ${attr.name}`);
}

if (!['number', 'undefined'].includes(typeof (attr.id))) {
throw new Error(`Attribute: "${attr.name}". `
+ `Type of attribute id must be a number or undefined. Got value ${attr.id}`);
}

if (!['checkbox', 'number', 'text', 'radio', 'select'].includes((attr.input_type || '').toLowerCase())) {
throw new Error(`Attribute: "${attr.name}". `
+ `Unknown input type: ${attr.input_type}`);
}

if (typeof (attr.mutable) !== 'boolean') {
throw new Error(`Attribute: "${attr.name}". `
+ `Mutable flag must be a boolean value. Got value ${attr.mutable}`);
}

if (!Array.isArray(attr.values)) {
throw new Error(`Attribute: "${attr.name}". `
+ `Attribute values must be an array. Got type ${typeof (attr.values)}`);
}

for (const value of attr.values) {
if (typeof (value) !== 'string') {
throw new Error(`Attribute: "${attr.name}". `
+ `Each value must be a string. Got value ${value}`);
}
}
}

export function validateParsedLabel(label: Label): void {
if (typeof (label.name) !== 'string') {
throw new Error(`Type of label name must be a string. Got value ${label.name}`);
}

if (!['number', 'undefined'].includes(typeof (label.id))) {
throw new Error(`Label "${label.name}". `
+ `Type of label id must be only a number or undefined. Got value ${label.id}`);
}

if (!Array.isArray(label.attributes)) {
throw new Error(`Label "${label.name}". `
+ `attributes must be an array. Got type ${typeof (label.attributes)}`);
}

for (const attr of label.attributes) {
validateParsedAttribute(attr);
}
}

export function idGenerator(): number {
return --id;
}
Expand Down
24 changes: 22 additions & 2 deletions cvat-ui/src/components/labels-editor/raw-viewer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import Form, { FormComponentProps } from 'antd/lib/form/Form';
import {
Label,
Attribute,
validateParsedLabel,
idGenerator,
} from './common';

type Props = FormComponentProps & {
Expand All @@ -22,7 +24,18 @@ type Props = FormComponentProps & {
class RawViewer extends React.PureComponent<Props> {
private validateLabels = (_: any, value: string, callback: any): void => {
try {
JSON.parse(value);
const parsed = JSON.parse(value);
if (!Array.isArray(parsed)) {
callback('Field is expected to be a JSON array');
}

for (const label of parsed) {
try {
validateParsedLabel(label);
} catch (error) {
callback(error.toString());
}
}
} catch (error) {
callback(error.toString());
}
Expand All @@ -39,7 +52,14 @@ class RawViewer extends React.PureComponent<Props> {
e.preventDefault();
form.validateFields((error, values): void => {
if (!error) {
onSubmit(JSON.parse(values.labels));
const parsed = JSON.parse(values.labels);
for (const label of parsed) {
label.id = label.id || idGenerator();
for (const attr of label.attributes) {
attr.id = attr.id || idGenerator();
}
}
onSubmit(parsed);
}
});
};
Expand Down

0 comments on commit 3adaf7e

Please sign in to comment.