From 274f1309c389221915b40508faffdfc361d48bbf Mon Sep 17 00:00:00 2001 From: Lauri Ojansivu Date: Thu, 5 Mar 2026 17:27:33 +0200 Subject: [PATCH] Fixed unable to delete Avatar, with Meteor 3 compatible avatar and attachments fixes. Thanks to inDane and xet7 ! Fixes #6160 --- client/components/users/userAvatar.js | 3 +- models/attachments.js | 40 ++++++++++++++++++++++- models/avatars.js | 46 +++++++++++++++++++++++++-- 3 files changed, 83 insertions(+), 6 deletions(-) diff --git a/client/components/users/userAvatar.js b/client/components/users/userAvatar.js index 73d2b606c..098a85e98 100644 --- a/client/components/users/userAvatar.js +++ b/client/components/users/userAvatar.js @@ -267,10 +267,9 @@ BlazeComponent.extendComponent({ event.stopPropagation(); this.setAvatar(''); }, - 'click .js-delete-avatar': Popup.afterConfirm('deleteAvatar', function(event) { + 'click .js-delete-avatar': Popup.afterConfirm('deleteAvatar', function() { Avatars.remove(this._id); Popup.back(); - event.stopPropagation(); }), }, ]; diff --git a/models/attachments.js b/models/attachments.js index 5e20cf993..308780462 100644 --- a/models/attachments.js +++ b/models/attachments.js @@ -169,8 +169,14 @@ Attachments = new FilesCollection({ const ret = fileStoreStrategyFactory.getFileStrategy(fileObj, versionName).interceptDownload(http, this.cacheControl); return ret; }, - onAfterRemove(files) { + onAfterRemove(filesInput) { + const files = normalizeRemovedFiles(filesInput); + files.forEach(fileObj => { + if (!fileObj || !fileObj.versions) { + return; + } + Object.keys(fileObj.versions).forEach(versionName => { fileStoreStrategyFactory.getFileStrategy(fileObj, versionName).onAfterRemove(); }); @@ -194,6 +200,38 @@ Attachments = new FilesCollection({ }, }); +function normalizeRemovedFiles(filesInput) { + if (!filesInput) { + return []; + } + + if (Array.isArray(filesInput)) { + return filesInput; + } + + if (typeof filesInput.fetch === 'function') { + return filesInput.fetch(); + } + + if (Array.isArray(filesInput.files)) { + return filesInput.files; + } + + if (typeof filesInput === 'string') { + return Attachments.find({ _id: filesInput }).fetch(); + } + + if (filesInput && typeof filesInput === 'object') { + if (filesInput._id && (filesInput.versions || filesInput.meta)) { + return [filesInput]; + } + + return Attachments.find(filesInput).fetch(); + } + + return []; +} + if (Meteor.isServer) { Attachments.allow({ insert(userId, fileObj) { diff --git a/models/avatars.js b/models/avatars.js index 369eb473b..c806d6804 100644 --- a/models/avatars.js +++ b/models/avatars.js @@ -129,9 +129,11 @@ Avatars = new FilesCollection({ const ret = fileStoreStrategyFactory.getFileStrategy(fileObj, versionName).interceptDownload(http, this.cacheControl); return ret; }, - async onBeforeRemove(files) { + async onBeforeRemove(filesInput) { + const files = normalizeRemovedFiles(filesInput); + for (const fileObj of files) { - if (fileObj.userId) { + if (fileObj && fileObj.userId) { const user = await ReactiveCache.getUser(fileObj.userId); user.setAvatarUrl(''); } @@ -139,8 +141,14 @@ Avatars = new FilesCollection({ return true; }, - onAfterRemove(files) { + onAfterRemove(filesInput) { + const files = normalizeRemovedFiles(filesInput); + files.forEach(fileObj => { + if (!fileObj || !fileObj.versions) { + return; + } + Object.keys(fileObj.versions).forEach(versionName => { fileStoreStrategyFactory.getFileStrategy(fileObj, versionName).onAfterRemove(); }); @@ -148,6 +156,38 @@ Avatars = new FilesCollection({ }, }); +function normalizeRemovedFiles(filesInput) { + if (!filesInput) { + return []; + } + + if (Array.isArray(filesInput)) { + return filesInput; + } + + if (typeof filesInput.fetch === 'function') { + return filesInput.fetch(); + } + + if (Array.isArray(filesInput.files)) { + return filesInput.files; + } + + if (typeof filesInput === 'string') { + return Avatars.find({ _id: filesInput }).fetch(); + } + + if (filesInput && typeof filesInput === 'object') { + if (filesInput._id && (filesInput.versions || filesInput.userId)) { + return [filesInput]; + } + + return Avatars.find(filesInput).fetch(); + } + + return []; +} + function isOwner(userId, doc) { return userId && userId === doc.userId; }