From 4897f001e4cb9603308221c15c96c6cdc9f89ee6 Mon Sep 17 00:00:00 2001 From: Hemachandar <132386067+hmacr@users.noreply.github.com> Date: Fri, 21 Jun 2024 18:56:20 +0530 Subject: [PATCH] Add icon column to document (#7066) * Add icon column to document * Backfill columns --------- Co-authored-by: Tom Moor --- server/commands/documentCreator.ts | 2 + server/commands/documentDuplicator.test.ts | 3 + server/commands/documentUpdater.ts | 1 + .../20240617151506-add-icon-to-document.js | 79 +++++++++++++++++++ server/models/Document.ts | 13 +++ server/models/Revision.ts | 15 ++++ server/queues/tasks/ImportJSONTask.ts | 2 + server/queues/tasks/ImportMarkdownZipTask.ts | 1 + server/queues/tasks/ImportNotionTask.ts | 1 + server/queues/tasks/ImportTask.ts | 2 + 10 files changed, 119 insertions(+) create mode 100644 server/migrations/20240617151506-add-icon-to-document.js diff --git a/server/commands/documentCreator.ts b/server/commands/documentCreator.ts index 8522db26c..b9e8286f6 100644 --- a/server/commands/documentCreator.ts +++ b/server/commands/documentCreator.ts @@ -97,6 +97,8 @@ export default async function documentCreator({ sourceMetadata, fullWidth: templateDocument ? templateDocument.fullWidth : fullWidth, emoji: templateDocument ? templateDocument.emoji : emoji, + icon: templateDocument ? templateDocument.emoji : emoji, + color: templateDocument ? templateDocument.color : null, title: TextHelper.replaceTemplateVariables( templateDocument ? templateDocument.title : title, user diff --git a/server/commands/documentDuplicator.test.ts b/server/commands/documentDuplicator.test.ts index 4816c7f82..4d88964aa 100644 --- a/server/commands/documentDuplicator.test.ts +++ b/server/commands/documentDuplicator.test.ts @@ -26,6 +26,7 @@ describe("documentDuplicator", () => { expect(response[0].title).toEqual(original.title); expect(response[0].text).toEqual(original.text); expect(response[0].emoji).toEqual(original.emoji); + expect(response[0].icon).toEqual(original.emoji); expect(response[0].publishedAt).toBeInstanceOf(Date); }); @@ -52,6 +53,7 @@ describe("documentDuplicator", () => { expect(response[0].title).toEqual("New title"); expect(response[0].text).toEqual(original.text); expect(response[0].emoji).toEqual(original.emoji); + expect(response[0].icon).toEqual(original.emoji); expect(response[0].publishedAt).toBeInstanceOf(Date); }); @@ -106,6 +108,7 @@ describe("documentDuplicator", () => { expect(response[0].title).toEqual(original.title); expect(response[0].text).toEqual(original.text); expect(response[0].emoji).toEqual(original.emoji); + expect(response[0].icon).toEqual(original.emoji); expect(response[0].publishedAt).toBeNull(); }); }); diff --git a/server/commands/documentUpdater.ts b/server/commands/documentUpdater.ts index 945be1160..80c76bbdd 100644 --- a/server/commands/documentUpdater.ts +++ b/server/commands/documentUpdater.ts @@ -67,6 +67,7 @@ export default async function documentUpdater({ } if (emoji !== undefined) { document.emoji = emoji; + document.icon = emoji; } if (editorVersion) { document.editorVersion = editorVersion; diff --git a/server/migrations/20240617151506-add-icon-to-document.js b/server/migrations/20240617151506-add-icon-to-document.js new file mode 100644 index 000000000..d4f287060 --- /dev/null +++ b/server/migrations/20240617151506-add-icon-to-document.js @@ -0,0 +1,79 @@ +"use strict"; + +/** @type {import('sequelize-cli').Migration} */ +module.exports = { + async up(queryInterface, Sequelize) { + await queryInterface.sequelize.transaction(async transaction => { + await queryInterface.addColumn( + "documents", + "icon", + { + type: Sequelize.STRING, + allowNull: true, + }, + { + transaction, + } + ); + await queryInterface.addColumn( + "revisions", + "icon", + { + type: Sequelize.STRING, + allowNull: true, + }, + { + transaction, + } + ); + await queryInterface.addColumn( + "documents", + "color", + { + type: Sequelize.STRING, + allowNull: true, + }, + { transaction } + ); + await queryInterface.addColumn( + "revisions", + "color", + { + type: Sequelize.STRING, + allowNull: true, + }, + { transaction } + ); + }); + + if (process.env.DEPLOYMENT === "hosted") { + return; + } + + await queryInterface.sequelize.transaction(async (transaction) => { + await queryInterface.sequelize.query( + `UPDATE documents SET icon = emoji`, + { + transaction, + type: queryInterface.sequelize.QueryTypes.UPDATE, + } + ); + await queryInterface.sequelize.query( + `UPDATE revisions SET icon = emoji`, + { + transaction, + type: queryInterface.sequelize.QueryTypes.UPDATE, + } + ); + }); + }, + + async down(queryInterface, Sequelize) { + await queryInterface.sequelize.transaction(async transaction => { + await queryInterface.removeColumn("documents", "icon", { transaction }); + await queryInterface.removeColumn("revisions", "icon", { transaction }); + await queryInterface.removeColumn("documents", "color", { transaction }); + await queryInterface.removeColumn("revisions", "color", { transaction }); + }); + }, +}; diff --git a/server/models/Document.ts b/server/models/Document.ts index 2fe19fcde..b3c4a723f 100644 --- a/server/models/Document.ts +++ b/server/models/Document.ts @@ -64,6 +64,7 @@ import View from "./View"; import ParanoidModel from "./base/ParanoidModel"; import Fix from "./decorators/Fix"; import { DocumentHelper } from "./helpers/DocumentHelper"; +import IsHexColor from "./validators/IsHexColor"; import Length from "./validators/Length"; export const DOCUMENT_VERSION = 2; @@ -262,6 +263,18 @@ class Document extends ParanoidModel< @Column emoji: string | null; + @Length({ + max: 50, + msg: `icon must be 50 characters or less`, + }) + @Column + icon: string | null; + + /** The color of the icon. */ + @IsHexColor + @Column + color: string | null; + /** * The content of the document as Markdown. * diff --git a/server/models/Revision.ts b/server/models/Revision.ts index b812c99bd..f1e8500fe 100644 --- a/server/models/Revision.ts +++ b/server/models/Revision.ts @@ -20,6 +20,7 @@ import Document from "./Document"; import User from "./User"; import IdModel from "./base/IdModel"; import Fix from "./decorators/Fix"; +import IsHexColor from "./validators/IsHexColor"; import Length from "./validators/Length"; @DefaultScope(() => ({ @@ -77,6 +78,18 @@ class Revision extends IdModel< @Column emoji: string | null; + @Length({ + max: 50, + msg: `icon must be 50 characters or less`, + }) + @Column + icon: string | null; + + /** The color of the icon. */ + @IsHexColor + @Column + color: string | null; + // associations @BelongsTo(() => Document, "documentId") @@ -121,6 +134,8 @@ class Revision extends IdModel< title: document.title, text: document.text, emoji: document.emoji, + icon: document.emoji, + color: document.color, content: document.content, userId: document.lastModifiedById, editorVersion: document.editorVersion, diff --git a/server/queues/tasks/ImportJSONTask.ts b/server/queues/tasks/ImportJSONTask.ts index 1cc863720..a7cb25453 100644 --- a/server/queues/tasks/ImportJSONTask.ts +++ b/server/queues/tasks/ImportJSONTask.ts @@ -80,6 +80,8 @@ export default class ImportJSONTask extends ImportTask { // structure directly in the future. text: serializer.serialize(Node.fromJSON(schema, node.data)), emoji: node.emoji, + icon: node.emoji, + color: null, createdAt: node.createdAt ? new Date(node.createdAt) : undefined, updatedAt: node.updatedAt ? new Date(node.updatedAt) : undefined, publishedAt: node.publishedAt ? new Date(node.publishedAt) : null, diff --git a/server/queues/tasks/ImportMarkdownZipTask.ts b/server/queues/tasks/ImportMarkdownZipTask.ts index 4496a0d19..6a7ec2c15 100644 --- a/server/queues/tasks/ImportMarkdownZipTask.ts +++ b/server/queues/tasks/ImportMarkdownZipTask.ts @@ -116,6 +116,7 @@ export default class ImportMarkdownZipTask extends ImportTask { id, title, emoji, + icon: emoji, text, collectionId, parentDocumentId, diff --git a/server/queues/tasks/ImportNotionTask.ts b/server/queues/tasks/ImportNotionTask.ts index b47e4ed8c..86d01d683 100644 --- a/server/queues/tasks/ImportNotionTask.ts +++ b/server/queues/tasks/ImportNotionTask.ts @@ -131,6 +131,7 @@ export default class ImportNotionTask extends ImportTask { id, title, emoji, + icon: emoji, text, collectionId, parentDocumentId, diff --git a/server/queues/tasks/ImportTask.ts b/server/queues/tasks/ImportTask.ts index a3695c661..a0d9d5f99 100644 --- a/server/queues/tasks/ImportTask.ts +++ b/server/queues/tasks/ImportTask.ts @@ -61,6 +61,8 @@ export type StructuredImportData = { urlId?: string; title: string; emoji?: string | null; + icon?: string | null; + color?: string | null; /** * The document text. To reference an attachment or image use the special * formatting <>. It will be replaced with a reference to the