112 lines
3.1 KiB
TypeScript
112 lines
3.1 KiB
TypeScript
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'
|
|
}
|