fix: Improved model validation for Collection (#3749)

* fix: Added improved model validation for Collection attributes

* sp

* fix: Enforce title length in UI
This commit is contained in:
Tom Moor
2022-07-08 20:10:22 +02:00
committed by GitHub
parent 98106e7f6f
commit 4a46d19846
8 changed files with 48 additions and 12 deletions

View File

@@ -3,6 +3,7 @@ import { observer } from "mobx-react";
import { useState } from "react"; import { useState } from "react";
import * as React from "react"; import * as React from "react";
import { Trans, useTranslation } from "react-i18next"; import { Trans, useTranslation } from "react-i18next";
import { MAX_TITLE_LENGTH } from "@shared/constants";
import Button from "~/components/Button"; import Button from "~/components/Button";
import Flex from "~/components/Flex"; import Flex from "~/components/Flex";
import IconPicker from "~/components/IconPicker"; import IconPicker from "~/components/IconPicker";
@@ -93,6 +94,7 @@ const CollectionEdit = ({ collectionId, onSubmit }: Props) => {
type="text" type="text"
label={t("Name")} label={t("Name")}
onChange={handleNameChange} onChange={handleNameChange}
maxLength={MAX_TITLE_LENGTH}
value={name} value={name}
required required
autoFocus autoFocus

View File

@@ -3,6 +3,7 @@ import { observable } from "mobx";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import * as React from "react"; import * as React from "react";
import { withTranslation, Trans, WithTranslation } from "react-i18next"; import { withTranslation, Trans, WithTranslation } from "react-i18next";
import { MAX_TITLE_LENGTH } from "@shared/constants";
import RootStore from "~/stores/RootStore"; import RootStore from "~/stores/RootStore";
import Collection from "~/models/Collection"; import Collection from "~/models/Collection";
import Button from "~/components/Button"; import Button from "~/components/Button";
@@ -127,6 +128,7 @@ class CollectionNew extends React.Component<Props> {
type="text" type="text"
label={t("Name")} label={t("Name")}
onChange={this.handleNameChange} onChange={this.handleNameChange}
maxLength={MAX_TITLE_LENGTH}
value={this.name} value={this.name}
required required
autoFocus autoFocus

View File

@@ -20,6 +20,7 @@ import {
DataType, DataType,
} from "sequelize-typescript"; } from "sequelize-typescript";
import isUUID from "validator/lib/isUUID"; import isUUID from "validator/lib/isUUID";
import { MAX_TITLE_LENGTH } from "@shared/constants";
import { sortNavigationNodes } from "@shared/utils/collections"; import { sortNavigationNodes } from "@shared/utils/collections";
import { SLUG_URL_REGEX } from "@shared/utils/urlHelpers"; import { SLUG_URL_REGEX } from "@shared/utils/urlHelpers";
import slugify from "@server/utils/slugify"; import slugify from "@server/utils/slugify";
@@ -33,6 +34,8 @@ import Team from "./Team";
import User from "./User"; import User from "./User";
import ParanoidModel from "./base/ParanoidModel"; import ParanoidModel from "./base/ParanoidModel";
import Fix from "./decorators/Fix"; import Fix from "./decorators/Fix";
import IsHexColor from "./validators/IsHexColor";
import Length from "./validators/Length";
import NotContainsUrl from "./validators/NotContainsUrl"; import NotContainsUrl from "./validators/NotContainsUrl";
// without this indirection, the app crashes on starup // without this indirection, the app crashes on starup
@@ -133,18 +136,35 @@ class Collection extends ParanoidModel {
urlId: string; urlId: string;
@NotContainsUrl @NotContainsUrl
@Length({
max: MAX_TITLE_LENGTH,
msg: `Collection name must be less than ${MAX_TITLE_LENGTH} characters`,
})
@Column @Column
name: string; name: string;
@Length({
max: 1000,
msg: `Collection description must be less than 1000 characters`,
})
@Column @Column
description: string; description: string;
@Length({
max: 50,
msg: `Collection icon must be less than 50 characters`,
})
@Column @Column
icon: string | null; icon: string | null;
@IsHexColor
@Column @Column
color: string | null; color: string | null;
@Length({
max: 50,
msg: `Collection index must be less than 50 characters`,
})
@Column @Column
index: string | null; index: string | null;

View File

@@ -188,7 +188,6 @@ class Document extends ParanoidModel {
urlId: string; urlId: string;
@Length({ @Length({
min: 0,
max: MAX_TITLE_LENGTH, max: MAX_TITLE_LENGTH,
msg: `Document title must be less than ${MAX_TITLE_LENGTH} characters`, msg: `Document title must be less than ${MAX_TITLE_LENGTH} characters`,
}) })

View File

@@ -84,21 +84,17 @@ export enum UserFlag {
@Fix @Fix
class User extends ParanoidModel { class User extends ParanoidModel {
@IsEmail @IsEmail
@Length({ min: 0, max: 255, msg: "email must be less than 255 characters" }) @Length({ max: 255, msg: "User email must be less than 255 characters" })
@Column @Column
email: string | null; email: string | null;
@NotContainsUrl @NotContainsUrl
@Length({ @Length({ max: 255, msg: "User username must be less than 255 characters" })
min: 0,
max: 255,
msg: "username must be less than 255 characters",
})
@Column @Column
username: string | null; username: string | null;
@NotContainsUrl @NotContainsUrl
@Length({ min: 0, max: 255, msg: "name must be less than 255 characters" }) @Length({ max: 255, msg: "User name must be less than 255 characters" })
@Column @Column
name: string; name: string;

View File

@@ -22,13 +22,13 @@ import Length from "./validators/Length";
@Fix @Fix
class WebhookSubscription extends ParanoidModel { class WebhookSubscription extends ParanoidModel {
@NotEmpty @NotEmpty
@Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Length({ max: 255, msg: "Webhook name be less than 255 characters" })
@Column @Column
name: string; name: string;
@IsUrl @IsUrl
@NotEmpty @NotEmpty
@Length({ min: 0, max: 255, msg: "Must be less than 255 characters" }) @Length({ max: 255, msg: "Webhook url be less than 255 characters" })
@Column @Column
url: string; url: string;

View File

@@ -0,0 +1,17 @@
import { isHexColor } from "class-validator";
import { addAttributeOptions } from "sequelize-typescript";
/**
* A decorator that validates that a string is a valid hex color code.
*/
export default function IsHexColor(target: any, propertyName: string) {
return addAttributeOptions(target, propertyName, {
validate: {
validDomain(value: string) {
if (!isHexColor(value)) {
throw new Error("Must be a valid hex color code");
}
},
},
});
}

View File

@@ -7,11 +7,11 @@ import { addAttributeOptions } from "sequelize-typescript";
*/ */
export default function Length({ export default function Length({
msg, msg,
min, min = 0,
max, max,
}: { }: {
msg?: string; msg?: string;
min: number; min?: number;
max: number; max: number;
}): (target: any, propertyName: string) => void { }): (target: any, propertyName: string) => void {
return (target: any, propertyName: string) => return (target: any, propertyName: string) =>