From e8c917affd8d2958b56c3bb46556548f670e1111 Mon Sep 17 00:00:00 2001 From: Mohamed Marrouchi Date: Thu, 9 Jan 2025 07:54:00 +0100 Subject: [PATCH] feat: migrate setting attachments --- .../1735836154221-v-2-2-0.migration.ts | 146 +++++++++++------- 1 file changed, 89 insertions(+), 57 deletions(-) diff --git a/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts b/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts index 99f8ad57..19cd0a10 100644 --- a/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts +++ b/api/src/migration/migrations/1735836154221-v-2-2-0.migration.ts @@ -22,6 +22,8 @@ import subscriberSchema, { Subscriber } from '@/chat/schemas/subscriber.schema'; import { StdOutgoingAttachmentMessage } from '@/chat/schemas/types/message'; import contentSchema, { Content } from '@/cms/schemas/content.schema'; import { config } from '@/config'; +import settingSchema, { Setting } from '@/setting/schemas/setting.schema'; +import { SettingType } from '@/setting/schemas/types'; import roleSchema, { Role } from '@/user/schemas/role.schema'; import userSchema, { User } from '@/user/schemas/user.schema'; import { moveFile, moveFiles } from '@/utils/helpers/fs'; @@ -43,6 +45,50 @@ const getAdminUser = async () => { return user; }; +/** + * Updates setting attachment documents to populate new attributes (context, owner, ownerType) + * + * @returns Resolves when the migration process is complete. + */ +const populateSettingAttachment = async ({ logger }: MigrationServices) => { + const AttachmentModel = mongoose.model( + Attachment.name, + attachmentSchema, + ); + const SettingModel = mongoose.model(Setting.name, settingSchema); + const user = await getAdminUser(); + + if (!user) { + logger.warn('Unable to populate setting attachments, no admin user found'); + } + + const cursor = SettingModel.find({ + type: SettingType.attachment, + }).cursor(); + + for await (const setting of cursor) { + try { + if (setting.value) { + await AttachmentModel.updateOne( + { _id: setting.value }, + { + $set: { + context: AttachmentContext.SettingAttachment, + ownerType: AttachmentOwnerType.User, + owner: user._id, + }, + }, + ); + logger.log(`User ${user._id} avatar attributes successfully populated`); + } + } catch (error) { + logger.error( + `Failed to populate avatar attributes for user ${user._id}: ${error.message}`, + ); + } + } +}; + /** * Updates user attachment documents to populate new attributes (context, owner, ownerType) * @@ -80,44 +126,6 @@ const populateUserAvatar = async ({ logger }: MigrationServices) => { } }; -/** - * Reverts what the previous function does - * - * @returns Resolves when the migration process is complete. - */ -const unpopulateUserAvatar = async ({ logger }: MigrationServices) => { - const AttachmentModel = mongoose.model( - Attachment.name, - attachmentSchema, - ); - const UserModel = mongoose.model(User.name, userSchema); - - const cursor = UserModel.find({ - avatar: { $exists: true, $ne: null }, - }).cursor(); - - for await (const user of cursor) { - try { - // Undo the updates made by populateUserAvatar - await AttachmentModel.updateOne( - { _id: user.avatar }, - { - $unset: { - context: '', - ownerType: '', - owner: '', - }, - }, - ); - logger.log(`User ${user._id} avatar attributes successfully reverted`); - } catch (error) { - logger.error( - `Failed to revert avatar attributes for user ${user._id}: ${error.message}`, - ); - } - } -}; - /** * Updates subscriber documents with their corresponding avatar attachments, * populate new attributes (context, owner, ownerType) and moves avatar files to a new directory. @@ -257,29 +265,11 @@ const unpopulateSubscriberAvatar = async ({ logger }: MigrationServices) => { { _id: subscriber._id }, { $set: { avatar: null }, - $unset: { - context: 1, - ownerType: 1, - owner: 1, - }, }, ); logger.log( `Subscriber ${subscriber._id} avatar attribute successfully reverted to null`, ); - await AttachmentModel.updateOne( - { _id: attachment._id }, - { - $unset: { - context: 1, - ownerType: 1, - owner: 1, - }, - }, - ); - logger.log( - `Subscriber ${subscriber._id} avatar attachment attributes successfully unpopulated`, - ); } else { logger.warn( `No avatar attachment found for subscriber ${subscriber._id}`, @@ -289,6 +279,47 @@ const unpopulateSubscriberAvatar = async ({ logger }: MigrationServices) => { } }; +/** + * Reverts the attachments additional attribute populate + * + * @returns Resolves when the migration process is complete. + */ +const undoPopulateAttachment = async ({ logger }: MigrationServices) => { + const AttachmentModel = mongoose.model( + Attachment.name, + attachmentSchema, + ); + + try { + const result = await AttachmentModel.updateMany( + { + context: { + $in: [ + AttachmentContext.SettingAttachment, + AttachmentContext.UserAvatar, + AttachmentContext.SubscriberAvatar, + ], + }, + }, + { + $unset: { + context: '', + ownerType: '', + owner: '', + }, + }, + ); + + logger.log( + `Successfully reverted attributes for ${result.modifiedCount} attachments with context 'setting_attachment'`, + ); + } catch (error) { + logger.error( + `Failed to revert attributes for attachments with context 'setting_attachment': ${error.message}`, + ); + } +}; + /** * Migrates and updates the paths of old folder "avatars" files for subscribers and users. * @@ -614,6 +645,7 @@ const migrateAttachmentMessages = async ({ module.exports = { async up(services: MigrationServices) { + await populateSettingAttachment(services); await populateUserAvatar(services); await populateSubscriberAvatar(services); await updateOldAvatarsPath(services); @@ -625,8 +657,8 @@ module.exports = { return true; }, async down(services: MigrationServices) { - await unpopulateUserAvatar(services); await unpopulateSubscriberAvatar(services); + await undoPopulateAttachment(services); await restoreOldAvatarsPath(services); await migrateAttachmentBlocks(MigrationAction.DOWN, services); await migrateAttachmentContents(MigrationAction.DOWN, services);