From 76862b626bd6355a2357d2d52cc73ccf79fbdd69 Mon Sep 17 00:00:00 2001 From: Tom Moor Date: Thu, 21 Sep 2023 22:37:27 -0400 Subject: [PATCH] Allow setting createdAt, emoji properties through `documents.create` (#5864) --- server/commands/documentCreator.ts | 2 +- server/routes/api/documents/documents.test.ts | 36 ++++++++++++++++++- server/routes/api/documents/documents.ts | 8 +++-- server/routes/api/documents/schema.ts | 25 +++++++++---- 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/server/commands/documentCreator.ts b/server/commands/documentCreator.ts index fd86a0322..4995ed7a3 100644 --- a/server/commands/documentCreator.ts +++ b/server/commands/documentCreator.ts @@ -75,7 +75,7 @@ export default async function documentCreator({ teamId: user.teamId, userId: user.id, createdAt, - updatedAt, + updatedAt: updatedAt ?? createdAt, lastModifiedById: user.id, createdById: user.id, template, diff --git a/server/routes/api/documents/documents.test.ts b/server/routes/api/documents/documents.test.ts index 1a5ee34d6..51dde1a48 100644 --- a/server/routes/api/documents/documents.test.ts +++ b/server/routes/api/documents/documents.test.ts @@ -1,4 +1,4 @@ -import { subDays } from "date-fns"; +import { addMinutes, subDays } from "date-fns"; import { CollectionPermission } from "@shared/types"; import { Document, @@ -2537,6 +2537,38 @@ describe("#documents.create", () => { expect(res.status).toEqual(200); }); + it("should succeed with specific createdAt date in the past", async () => { + const user = await buildUser(); + const createdAt = new Date().toISOString(); + const res = await server.post("/api/documents.create", { + body: { + token: user.getJwtToken(), + collectionId: null, + title: "new document", + createdAt, + text: "hello", + }, + }); + const body = await res.json(); + expect(res.status).toEqual(200); + expect(body.data.createdAt).toEqual(createdAt); + expect(body.data.updatedAt).toEqual(createdAt); + }); + + it("should fail with createdAt date in the future", async () => { + const user = await buildUser(); + const res = await server.post("/api/documents.create", { + body: { + token: user.getJwtToken(), + collectionId: null, + title: "new document", + createdAt: addMinutes(new Date(), 1).toISOString(), + text: "hello", + }, + }); + expect(res.status).toEqual(400); + }); + it("should fail for invalid parentDocumentId", async () => { const team = await buildTeam(); const user = await buildUser({ teamId: team.id }); @@ -2569,6 +2601,7 @@ describe("#documents.create", () => { body: { token: user.getJwtToken(), collectionId: collection.id, + emoji: "🚢", title: "new document", text: "hello", publish: true, @@ -2579,6 +2612,7 @@ describe("#documents.create", () => { expect(res.status).toEqual(200); expect(newDocument!.parentDocumentId).toBe(null); expect(newDocument!.collectionId).toBe(collection.id); + expect(newDocument!.emoji).toBe("🚢"); expect(body.policies[0].abilities.update).toEqual(true); }); diff --git a/server/routes/api/documents/documents.ts b/server/routes/api/documents/documents.ts index 6ccd2017e..b391fe50e 100644 --- a/server/routes/api/documents/documents.ts +++ b/server/routes/api/documents/documents.ts @@ -1289,14 +1289,16 @@ router.post( transaction(), async (ctx: APIContext) => { const { - title = "", - text = "", + title, + text, + emoji, publish, collectionId, parentDocumentId, fullWidth, templateId, template, + createdAt, } = ctx.input.body; const editorVersion = ctx.headers["x-editor-version"] as string | undefined; @@ -1343,6 +1345,8 @@ router.post( const document = await documentCreator({ title, text, + emoji, + createdAt, publish, collectionId, parentDocumentId, diff --git a/server/routes/api/documents/schema.ts b/server/routes/api/documents/schema.ts index 03f697040..f8dc3f56c 100644 --- a/server/routes/api/documents/schema.ts +++ b/server/routes/api/documents/schema.ts @@ -280,28 +280,39 @@ export type DocumentsImportReq = z.infer; export const DocumentsCreateSchema = BaseSchema.extend({ body: z.object({ - /** Doc title */ + /** Document title */ title: z.string().default(""), - /** Doc text */ + /** Document text */ text: z.string().default(""), + /** Emoji displayed alongside doc title */ + emoji: z.string().regex(emojiRegex()).optional(), + /** Boolean to denote if the doc should be published */ publish: z.boolean().optional(), - /** Create Doc under this collection */ + /** Collection to create document within */ collectionId: z.string().uuid().nullish(), - /** Create Doc under this parent */ + /** Parent document to create within */ parentDocumentId: z.string().uuid().nullish(), - /** Create doc with this template */ + /** A template to create the document from */ templateId: z.string().uuid().optional(), - /** Boolean to denote if the doc should occupy full width */ + /** Optionally set the created date in the past */ + createdAt: z.coerce + .date() + .optional() + .refine((data) => !data || data < new Date(), { + message: "createdAt must be in the past", + }), + + /** Boolean to denote if the document should occupy full width */ fullWidth: z.boolean().optional(), - /** Whether to create a template doc */ + /** Whether this should be considered a template */ template: z.boolean().optional(), }), })