import { Transaction } from 'sequelize/types' import { logger } from '@server/helpers/logger' import { ActorImageModel } from '@server/models/actor/actor-image' import { MActorImage, MActorImages } from '@server/types/models' import { ActorImageType } from '@shared/models' type ImageInfo = { name: string fileUrl: string height: number width: number onDisk?: boolean } async function updateActorImages (actor: MActorImages, type: ActorImageType, imagesInfo: ImageInfo[], t: Transaction) { const getAvatarsOrBanners = () => { const result = type === ActorImageType.AVATAR ? actor.Avatars : actor.Banners return result || [] } if (imagesInfo.length === 0) { await deleteActorImages(actor, type, t) } // Cleanup old images that did not have a width for (const oldImageModel of getAvatarsOrBanners()) { if (oldImageModel.width) continue await safeDeleteActorImage(actor, oldImageModel, type, t) } for (const imageInfo of imagesInfo) { const oldImageModel = getAvatarsOrBanners().find(i => imageInfo.width && i.width === imageInfo.width) if (oldImageModel) { // Don't update the avatar if the file URL did not change if (imageInfo.fileUrl && oldImageModel.fileUrl === imageInfo.fileUrl) { continue } await safeDeleteActorImage(actor, oldImageModel, type, t) } const imageModel = await ActorImageModel.create({ filename: imageInfo.name, onDisk: imageInfo.onDisk ?? false, fileUrl: imageInfo.fileUrl, height: imageInfo.height, width: imageInfo.width, type, actorId: actor.id }, { transaction: t }) addActorImage(actor, type, imageModel) } return actor } async function deleteActorImages (actor: MActorImages, type: ActorImageType, t: Transaction) { try { const association = buildAssociationName(type) for (const image of actor[association]) { await image.destroy({ transaction: t }) } actor[association] = [] } catch (err) { logger.error('Cannot remove old image of actor %s.', actor.url, { err }) } return actor } async function safeDeleteActorImage (actor: MActorImages, toDelete: MActorImage, type: ActorImageType, t: Transaction) { try { await toDelete.destroy({ transaction: t }) const association = buildAssociationName(type) actor[association] = actor[association].filter(image => image.id !== toDelete.id) } catch (err) { logger.error('Cannot remove old actor image of actor %s.', actor.url, { err }) } } // --------------------------------------------------------------------------- export { ImageInfo, updateActorImages, deleteActorImages } // --------------------------------------------------------------------------- function addActorImage (actor: MActorImages, type: ActorImageType, imageModel: MActorImage) { const association = buildAssociationName(type) if (!actor[association]) actor[association] = [] actor[association].push(imageModel) } function buildAssociationName (type: ActorImageType) { return type === ActorImageType.AVATAR ? 'Avatars' : 'Banners' }