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