]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/process/process-update.ts
Handle thumbnail update
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / process / process-update.ts
CommitLineData
25ed141c 1import * as Bluebird from 'bluebird'
3fd3ab2d 2import { ActivityUpdate } from '../../../../shared/models/activitypub'
265ba139
C
3import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor'
4import { VideoTorrentObject } from '../../../../shared/models/activitypub/objects'
da854ddd
C
5import { retryTransactionWrapper } from '../../../helpers/database-utils'
6import { logger } from '../../../helpers/logger'
7import { resetSequelizeInstance } from '../../../helpers/utils'
3fd3ab2d 8import { sequelizeTypescript } from '../../../initializers'
265ba139 9import { AccountModel } from '../../../models/account/account'
50d6de9c 10import { ActorModel } from '../../../models/activitypub/actor'
3fd3ab2d 11import { TagModel } from '../../../models/video/tag'
3fd3ab2d 12import { VideoFileModel } from '../../../models/video/video-file'
a5625b41 13import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor'
e3a682a8
C
14import {
15 generateThumbnailFromUrl, getOrCreateAccountAndVideoAndChannel, videoActivityObjectToDBAttributes,
16 videoFileActivityUrlToDBAttributes
17} from '../videos'
0d0e8dd0
C
18
19async function processUpdateActivity (activity: ActivityUpdate) {
50d6de9c 20 const actor = await getOrCreateActorAndServerAndModel(activity.actor)
e4f97bab 21
e4f97bab 22 if (activity.object.type === 'Video') {
50d6de9c 23 return processUpdateVideo(actor, activity)
265ba139
C
24 } else if (activity.object.type === 'Person') {
25 return processUpdateAccount(actor, activity)
e4f97bab 26 }
0d0e8dd0 27
b1cbc0dd 28 return
e4f97bab
C
29}
30
31// ---------------------------------------------------------------------------
32
33export {
34 processUpdateActivity
35}
36
37// ---------------------------------------------------------------------------
38
50d6de9c 39function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) {
0d0e8dd0 40 const options = {
50d6de9c 41 arguments: [ actor, activity ],
0d0e8dd0
C
42 errorMessage: 'Cannot update the remote video with many retries'
43 }
e4f97bab 44
0d0e8dd0 45 return retryTransactionWrapper(updateRemoteVideo, options)
e4f97bab
C
46}
47
50d6de9c 48async function updateRemoteVideo (actor: ActorModel, activity: ActivityUpdate) {
265ba139 49 const videoAttributesToUpdate = activity.object as VideoTorrentObject
50d6de9c 50
2ccaeeb3
C
51 const res = await getOrCreateAccountAndVideoAndChannel(videoAttributesToUpdate.id)
52
0d0e8dd0 53 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.uuid)
2ccaeeb3 54 let videoInstance = res.video
265ba139 55 let videoFieldsSave: any
0d0e8dd0
C
56
57 try {
3fd3ab2d 58 await sequelizeTypescript.transaction(async t => {
0d0e8dd0
C
59 const sequelizeOptions = {
60 transaction: t
61 }
62
265ba139
C
63 videoFieldsSave = videoInstance.toJSON()
64
50d6de9c
C
65 const videoChannel = videoInstance.VideoChannel
66 if (videoChannel.Account.Actor.id !== actor.id) {
67 throw new Error('Account ' + actor.url + ' does not own video channel ' + videoChannel.Actor.url)
0d0e8dd0
C
68 }
69
50d6de9c 70 const videoData = await videoActivityObjectToDBAttributes(videoChannel, videoAttributesToUpdate, activity.to, activity.cc)
0d0e8dd0 71 videoInstance.set('name', videoData.name)
9a8cbd82
C
72 videoInstance.set('uuid', videoData.uuid)
73 videoInstance.set('url', videoData.url)
0d0e8dd0
C
74 videoInstance.set('category', videoData.category)
75 videoInstance.set('licence', videoData.licence)
76 videoInstance.set('language', videoData.language)
9a8cbd82 77 videoInstance.set('description', videoData.description)
0d0e8dd0 78 videoInstance.set('nsfw', videoData.nsfw)
4e8c8728 79 videoInstance.set('commentsEnabled', videoData.commentsEnabled)
0d0e8dd0
C
80 videoInstance.set('duration', videoData.duration)
81 videoInstance.set('createdAt', videoData.createdAt)
82 videoInstance.set('updatedAt', videoData.updatedAt)
83 videoInstance.set('views', videoData.views)
9a8cbd82 84 videoInstance.set('privacy', videoData.privacy)
0d0e8dd0
C
85
86 await videoInstance.save(sequelizeOptions)
87
e3a682a8
C
88 // Don't block on request
89 generateThumbnailFromUrl(videoInstance, videoAttributesToUpdate.icon)
90 .catch(err => logger.warn('Cannot generate thumbnail of %s.', videoAttributesToUpdate.id, err))
91
0d0e8dd0
C
92 // Remove old video files
93 const videoFileDestroyTasks: Bluebird<void>[] = []
94 for (const videoFile of videoInstance.VideoFiles) {
95 videoFileDestroyTasks.push(videoFile.destroy(sequelizeOptions))
96 }
97 await Promise.all(videoFileDestroyTasks)
98
79d5caf9 99 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoInstance, videoAttributesToUpdate)
1f7ab4f3 100 const tasks = videoFileAttributes.map(f => VideoFileModel.create(f))
0d0e8dd0
C
101 await Promise.all(tasks)
102
103 const tags = videoAttributesToUpdate.tag.map(t => t.name)
3fd3ab2d
C
104 const tagInstances = await TagModel.findOrCreateTags(tags, t)
105 await videoInstance.$set('Tags', tagInstances, sequelizeOptions)
0d0e8dd0
C
106 })
107
108 logger.info('Remote video with uuid %s updated', videoAttributesToUpdate.uuid)
109 } catch (err) {
110 if (videoInstance !== undefined && videoFieldsSave !== undefined) {
111 resetSequelizeInstance(videoInstance, videoFieldsSave)
112 }
113
114 // This is just a debug because we will retry the insert
115 logger.debug('Cannot update the remote video.', err)
116 throw err
117 }
118}
265ba139
C
119
120function processUpdateAccount (actor: ActorModel, activity: ActivityUpdate) {
121 const options = {
122 arguments: [ actor, activity ],
123 errorMessage: 'Cannot update the remote account with many retries'
124 }
125
126 return retryTransactionWrapper(updateRemoteAccount, options)
127}
128
129async function updateRemoteAccount (actor: ActorModel, activity: ActivityUpdate) {
130 const accountAttributesToUpdate = activity.object as ActivityPubActor
131
132 logger.debug('Updating remote account "%s".', accountAttributesToUpdate.uuid)
265ba139
C
133 let accountInstance: AccountModel
134 let actorFieldsSave: object
135 let accountFieldsSave: object
136
137 // Fetch icon?
138 const avatarName = await fetchAvatarIfExists(accountAttributesToUpdate)
139
140 try {
141 await sequelizeTypescript.transaction(async t => {
a5625b41
C
142 actorFieldsSave = actor.toJSON()
143 accountInstance = actor.Account
144 accountFieldsSave = actor.Account.toJSON()
265ba139 145
a5625b41 146 await updateActorInstance(actor, accountAttributesToUpdate)
265ba139 147
a5625b41
C
148 if (avatarName !== undefined) {
149 await updateActorAvatarInstance(actor, avatarName, t)
265ba139
C
150 }
151
152 await actor.save({ transaction: t })
153
154 actor.Account.set('name', accountAttributesToUpdate.name || accountAttributesToUpdate.preferredUsername)
155 await actor.Account.save({ transaction: t })
156 })
157
158 logger.info('Remote account with uuid %s updated', accountAttributesToUpdate.uuid)
159 } catch (err) {
a5625b41
C
160 if (actor !== undefined && actorFieldsSave !== undefined) {
161 resetSequelizeInstance(actor, actorFieldsSave)
265ba139
C
162 }
163
164 if (accountInstance !== undefined && accountFieldsSave !== undefined) {
165 resetSequelizeInstance(accountInstance, accountFieldsSave)
166 }
167
168 // This is just a debug because we will retry the insert
169 logger.debug('Cannot update the remote account.', err)
170 throw err
171 }
172}