]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/process/process-update.ts
Add banner tests
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / process / process-update.ts
CommitLineData
de6310b2 1import { ActivityUpdate, CacheFileObject, VideoObject } from '../../../../shared/models/activitypub'
265ba139 2import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor'
06215f15 3import { resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers/database-utils'
da854ddd 4import { logger } from '../../../helpers/logger'
80fdaf06 5import { sequelizeTypescript } from '../../../initializers/database'
265ba139 6import { AccountModel } from '../../../models/account/account'
50d6de9c 7import { ActorModel } from '../../../models/activitypub/actor'
2422c46b 8import { VideoChannelModel } from '../../../models/video/video-channel'
2cb03dc1 9import { getImageInfoIfExists, updateActorImageInstance, updateActorInstance } from '../actor'
e587e0ec 10import { getOrCreateVideoAndAccountAndChannel, getOrCreateVideoChannelFromVideoObject, updateVideoFromAP } from '../videos'
3cd0734f 11import { sanitizeAndCheckVideoTorrentObject } from '../../../helpers/custom-validators/activitypub/videos'
c48e82b5 12import { isCacheFileObjectValid } from '../../../helpers/custom-validators/activitypub/cache-file'
b88a4596 13import { createOrUpdateCacheFile } from '../cache-file'
e5565833 14import { forwardVideoRelatedActivity } from '../send/utils'
418d092a
C
15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
16import { createOrUpdateVideoPlaylist } from '../playlist'
26d6bf65
C
17import { APProcessorOptions } from '../../../types/activitypub-processor.model'
18import { MActorSignature, MAccountIdActor } from '../../../types/models'
8c9e7875 19import { isRedundancyAccepted } from '@server/lib/redundancy'
2cb03dc1 20import { ActorImageType } from '@shared/models'
1198edf4
C
21
22async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) {
23 const { activity, byActor } = options
0d0e8dd0 24
2422c46b 25 const objectType = activity.object.type
e4f97bab 26
2422c46b 27 if (objectType === 'Video') {
e587e0ec 28 return retryTransactionWrapper(processUpdateVideo, byActor, activity)
c48e82b5
C
29 }
30
31 if (objectType === 'Person' || objectType === 'Application' || objectType === 'Group') {
e587e0ec
C
32 // We need more attributes
33 const byActorFull = await ActorModel.loadByUrlAndPopulateAccountAndChannel(byActor.url)
34 return retryTransactionWrapper(processUpdateActor, byActorFull, activity)
e4f97bab 35 }
0d0e8dd0 36
c48e82b5 37 if (objectType === 'CacheFile') {
e587e0ec
C
38 // We need more attributes
39 const byActorFull = await ActorModel.loadByUrlAndPopulateAccountAndChannel(byActor.url)
40 return retryTransactionWrapper(processUpdateCacheFile, byActorFull, activity)
c48e82b5
C
41 }
42
418d092a
C
43 if (objectType === 'Playlist') {
44 return retryTransactionWrapper(processUpdatePlaylist, byActor, activity)
45 }
46
3cd0734f 47 return undefined
e4f97bab
C
48}
49
50// ---------------------------------------------------------------------------
51
52export {
53 processUpdateActivity
54}
55
56// ---------------------------------------------------------------------------
57
453e83ea 58async function processUpdateVideo (actor: MActorSignature, activity: ActivityUpdate) {
de6310b2 59 const videoObject = activity.object as VideoObject
50d6de9c 60
3cd0734f
C
61 if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) {
62 logger.debug('Video sent by update is not valid.', { videoObject })
63 return undefined
64 }
2186386c 65
92315d97
C
66 const { video, created } = await getOrCreateVideoAndAccountAndChannel({
67 videoObject: videoObject.id,
68 allowRefresh: false,
69 fetchType: 'all'
70 })
71 // We did not have this video, it has been created so no need to update
72 if (created) return
73
74 // Load new channel
f37dc0dd 75 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject)
2ccaeeb3 76
f92e7f76
C
77 const account = actor.Account as MAccountIdActor
78 account.Actor = actor
79
d4defe07
C
80 const updateOptions = {
81 video,
82 videoObject,
f92e7f76 83 account,
d4defe07 84 channel: channelActor.VideoChannel,
d4defe07
C
85 overrideTo: activity.to
86 }
87 return updateVideoFromAP(updateOptions)
c48e82b5
C
88}
89
453e83ea 90async function processUpdateCacheFile (byActor: MActorSignature, activity: ActivityUpdate) {
8c9e7875
C
91 if (await isRedundancyAccepted(activity, byActor) !== true) return
92
c48e82b5
C
93 const cacheFileObject = activity.object as CacheFileObject
94
e5565833
C
95 if (!isCacheFileObjectValid(cacheFileObject)) {
96 logger.debug('Cache file object sent by update is not valid.', { cacheFileObject })
c48e82b5
C
97 return undefined
98 }
99
e5565833
C
100 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object })
101
102 await sequelizeTypescript.transaction(async t => {
b88a4596 103 await createOrUpdateCacheFile(cacheFileObject, video, byActor, t)
e5565833 104 })
c48e82b5 105
e5565833
C
106 if (video.isOwned()) {
107 // Don't resend the activity to the sender
108 const exceptions = [ byActor ]
109
110 await forwardVideoRelatedActivity(activity, undefined, exceptions, video)
111 }
0d0e8dd0 112}
265ba139 113
90d4bb81 114async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) {
2422c46b 115 const actorAttributesToUpdate = activity.object as ActivityPubActor
265ba139 116
57cfff78 117 logger.debug('Updating remote account "%s".', actorAttributesToUpdate.url)
2422c46b 118 let accountOrChannelInstance: AccountModel | VideoChannelModel
265ba139 119 let actorFieldsSave: object
2422c46b 120 let accountOrChannelFieldsSave: object
265ba139
C
121
122 // Fetch icon?
2cb03dc1
C
123 const avatarInfo = getImageInfoIfExists(actorAttributesToUpdate, ActorImageType.AVATAR)
124 const bannerInfo = getImageInfoIfExists(actorAttributesToUpdate, ActorImageType.BANNER)
265ba139
C
125
126 try {
127 await sequelizeTypescript.transaction(async t => {
a5625b41 128 actorFieldsSave = actor.toJSON()
265ba139 129
2422c46b
C
130 if (actorAttributesToUpdate.type === 'Group') accountOrChannelInstance = actor.VideoChannel
131 else accountOrChannelInstance = actor.Account
132
133 accountOrChannelFieldsSave = accountOrChannelInstance.toJSON()
134
135 await updateActorInstance(actor, actorAttributesToUpdate)
265ba139 136
213e30ef
C
137 await updateActorImageInstance(actor, ActorImageType.AVATAR, avatarInfo, t)
138 await updateActorImageInstance(actor, ActorImageType.BANNER, bannerInfo, t)
265ba139
C
139
140 await actor.save({ transaction: t })
141
1735c825
C
142 accountOrChannelInstance.name = actorAttributesToUpdate.name || actorAttributesToUpdate.preferredUsername
143 accountOrChannelInstance.description = actorAttributesToUpdate.summary
144
145 if (accountOrChannelInstance instanceof VideoChannelModel) accountOrChannelInstance.support = actorAttributesToUpdate.support
146
2422c46b 147 await accountOrChannelInstance.save({ transaction: t })
265ba139
C
148 })
149
57cfff78 150 logger.info('Remote account %s updated', actorAttributesToUpdate.url)
265ba139 151 } catch (err) {
a5625b41
C
152 if (actor !== undefined && actorFieldsSave !== undefined) {
153 resetSequelizeInstance(actor, actorFieldsSave)
265ba139
C
154 }
155
2422c46b
C
156 if (accountOrChannelInstance !== undefined && accountOrChannelFieldsSave !== undefined) {
157 resetSequelizeInstance(accountOrChannelInstance, accountOrChannelFieldsSave)
265ba139
C
158 }
159
160 // This is just a debug because we will retry the insert
d5b7d911 161 logger.debug('Cannot update the remote account.', { err })
265ba139
C
162 throw err
163 }
164}
418d092a 165
453e83ea 166async function processUpdatePlaylist (byActor: MActorSignature, activity: ActivityUpdate) {
418d092a
C
167 const playlistObject = activity.object as PlaylistObject
168 const byAccount = byActor.Account
169
170 if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url)
171
172 await createOrUpdateVideoPlaylist(playlistObject, byAccount, activity.to)
173}