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