]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/activitypub/actors/image.ts
Merge branch 'release/4.2.0' into develop
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / actors / image.ts
1 import { Transaction } from 'sequelize/types'
2 import { logger } from '@server/helpers/logger'
3 import { ActorImageModel } from '@server/models/actor/actor-image'
4 import { MActorImage, MActorImages } from '@server/types/models'
5 import { ActorImageType } from '@shared/models'
6
7 type ImageInfo = {
8 name: string
9 fileUrl: string
10 height: number
11 width: number
12 onDisk?: boolean
13 }
14
15 async function updateActorImages (actor: MActorImages, type: ActorImageType, imagesInfo: ImageInfo[], t: Transaction) {
16 const avatarsOrBanners = type === ActorImageType.AVATAR
17 ? actor.Avatars
18 : actor.Banners
19
20 if (imagesInfo.length === 0) {
21 await deleteActorImages(actor, type, t)
22 }
23
24 for (const imageInfo of imagesInfo) {
25 const oldImageModel = (avatarsOrBanners || []).find(i => i.width === imageInfo.width)
26
27 if (oldImageModel) {
28 // Don't update the avatar if the file URL did not change
29 if (imageInfo?.fileUrl && oldImageModel.fileUrl === imageInfo.fileUrl) {
30 continue
31 }
32
33 await safeDeleteActorImage(actor, oldImageModel, type, t)
34 }
35
36 const imageModel = await ActorImageModel.create({
37 filename: imageInfo.name,
38 onDisk: imageInfo.onDisk ?? false,
39 fileUrl: imageInfo.fileUrl,
40 height: imageInfo.height,
41 width: imageInfo.width,
42 type,
43 actorId: actor.id
44 }, { transaction: t })
45
46 addActorImage(actor, type, imageModel)
47 }
48
49 return actor
50 }
51
52 async function deleteActorImages (actor: MActorImages, type: ActorImageType, t: Transaction) {
53 try {
54 const association = buildAssociationName(type)
55
56 for (const image of actor[association]) {
57 await image.destroy({ transaction: t })
58 }
59
60 actor[association] = []
61 } catch (err) {
62 logger.error('Cannot remove old image of actor %s.', actor.url, { err })
63 }
64
65 return actor
66 }
67
68 async function safeDeleteActorImage (actor: MActorImages, toDelete: MActorImage, type: ActorImageType, t: Transaction) {
69 try {
70 await toDelete.destroy({ transaction: t })
71
72 const association = buildAssociationName(type)
73 actor[association] = actor[association].filter(image => image.id !== toDelete.id)
74 } catch (err) {
75 logger.error('Cannot remove old actor image of actor %s.', actor.url, { err })
76 }
77 }
78
79 // ---------------------------------------------------------------------------
80
81 export {
82 ImageInfo,
83
84 updateActorImages,
85 deleteActorImages
86 }
87
88 // ---------------------------------------------------------------------------
89
90 function addActorImage (actor: MActorImages, type: ActorImageType, imageModel: MActorImage) {
91 const association = buildAssociationName(type)
92 if (!actor[association]) actor[association] = []
93
94 actor[association].push(imageModel)
95 }
96
97 function buildAssociationName (type: ActorImageType) {
98 return type === ActorImageType.AVATAR
99 ? 'Avatars'
100 : 'Banners'
101 }