diff --git a/server/models/Document.ts b/server/models/Document.ts index 5af07d18f..8c31e97dc 100644 --- a/server/models/Document.ts +++ b/server/models/Document.ts @@ -17,7 +17,6 @@ import { BelongsTo, Column, Default, - Length, PrimaryKey, Table, BeforeValidate, @@ -51,6 +50,7 @@ import User from "./User"; import View from "./View"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; +import { Length } from "./decorators/Length"; export type SearchResponse = { results: { diff --git a/server/models/decorators/Length.ts b/server/models/decorators/Length.ts new file mode 100644 index 000000000..a8efa1401 --- /dev/null +++ b/server/models/decorators/Length.ts @@ -0,0 +1,27 @@ +import { size } from "lodash"; +import { addAttributeOptions } from "sequelize-typescript"; + +/** + * A decorator that calculates size of the string based on lodash's size function. + * particularly useful for strings with unicode characters of variable lengths. + */ +export function Length({ + msg, + min, + max, +}: { + msg?: string; + min: number; + max: number; +}): (target: any, propertyName: string) => void { + return (target: any, propertyName: string) => + addAttributeOptions(target, propertyName, { + validate: { + validLength(value: string) { + if (size(value) > max || size(value) < min) { + throw new Error(msg); + } + }, + }, + }); +} diff --git a/server/routes/api/documents.test.ts b/server/routes/api/documents.test.ts index dbd62d86d..28efc5c0c 100644 --- a/server/routes/api/documents.test.ts +++ b/server/routes/api/documents.test.ts @@ -1883,6 +1883,25 @@ describe("#documents.create", () => { expect(res.status).toEqual(400); }); + // The length of UTF-8 "🛡" is 2 according to "🛡".length in node, + // so the length of the title totals to be 101. + // This test should not pass but does because length of the character + // calculated by lodash's size function is _.size('🛡') == 1. + // So the sentence's length comes out to be exactly 100. + it("should count variable length unicode character using lodash's size function", async () => { + const { user, collection } = await seed(); + const res = await server.post("/api/documents.create", { + body: { + token: user.getJwtToken(), + collectionId: collection.id, + title: + "This text would be exactly 100 chars long if the following unicode character was counted as 1 char 🛡", + text: " ", + }, + }); + expect(res.status).toEqual(200); + }); + it("should create as a child and add to collection if published", async () => { const { user, document, collection } = await seed(); const res = await server.post("/api/documents.create", {