]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/process/process-update.ts
Upgrade server dependencies
[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'
1f7ab4f3 5import { VideoFile } from '../../../../shared/models/videos'
da854ddd
C
6import { retryTransactionWrapper } from '../../../helpers/database-utils'
7import { logger } from '../../../helpers/logger'
8import { resetSequelizeInstance } from '../../../helpers/utils'
3fd3ab2d 9import { sequelizeTypescript } from '../../../initializers'
265ba139 10import { AccountModel } from '../../../models/account/account'
50d6de9c 11import { ActorModel } from '../../../models/activitypub/actor'
3fd3ab2d 12import { TagModel } from '../../../models/video/tag'
3fd3ab2d 13import { VideoFileModel } from '../../../models/video/video-file'
a5625b41 14import { fetchAvatarIfExists, getOrCreateActorAndServerAndModel, updateActorAvatarInstance, updateActorInstance } from '../actor'
2ccaeeb3 15import { getOrCreateAccountAndVideoAndChannel, videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from '../videos'
0d0e8dd0
C
16
17async function processUpdateActivity (activity: ActivityUpdate) {
50d6de9c 18 const actor = await getOrCreateActorAndServerAndModel(activity.actor)
e4f97bab 19
e4f97bab 20 if (activity.object.type === 'Video') {
50d6de9c 21 return processUpdateVideo(actor, activity)
265ba139
C
22 } else if (activity.object.type === 'Person') {
23 return processUpdateAccount(actor, activity)
e4f97bab 24 }
0d0e8dd0 25
b1cbc0dd 26 return
e4f97bab
C
27}
28
29// ---------------------------------------------------------------------------
30
31export {
32 processUpdateActivity
33}
34
35// ---------------------------------------------------------------------------
36
50d6de9c 37function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) {
0d0e8dd0 38 const options = {
50d6de9c 39 arguments: [ actor, activity ],
0d0e8dd0
C
40 errorMessage: 'Cannot update the remote video with many retries'
41 }
e4f97bab 42
0d0e8dd0 43 return retryTransactionWrapper(updateRemoteVideo, options)
e4f97bab
C
44}
45
50d6de9c 46async function updateRemoteVideo (actor: ActorModel, activity: ActivityUpdate) {
265ba139 47 const videoAttributesToUpdate = activity.object as VideoTorrentObject
50d6de9c 48
2ccaeeb3
C
49 const res = await getOrCreateAccountAndVideoAndChannel(videoAttributesToUpdate.id)
50
0d0e8dd0 51 logger.debug('Updating remote video "%s".', videoAttributesToUpdate.uuid)
2ccaeeb3 52 let videoInstance = res.video
265ba139 53 let videoFieldsSave: any
0d0e8dd0
C
54
55 try {
3fd3ab2d 56 await sequelizeTypescript.transaction(async t => {
0d0e8dd0
C
57 const sequelizeOptions = {
58 transaction: t
59 }
60
265ba139
C
61 videoFieldsSave = videoInstance.toJSON()
62
50d6de9c
C
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)
0d0e8dd0
C
66 }
67
50d6de9c 68 const videoData = await videoActivityObjectToDBAttributes(videoChannel, videoAttributesToUpdate, activity.to, activity.cc)
0d0e8dd0 69 videoInstance.set('name', videoData.name)
9a8cbd82
C
70 videoInstance.set('uuid', videoData.uuid)
71 videoInstance.set('url', videoData.url)
0d0e8dd0
C
72 videoInstance.set('category', videoData.category)
73 videoInstance.set('licence', videoData.licence)
74 videoInstance.set('language', videoData.language)
9a8cbd82 75 videoInstance.set('description', videoData.description)
0d0e8dd0 76 videoInstance.set('nsfw', videoData.nsfw)
4e8c8728 77 videoInstance.set('commentsEnabled', videoData.commentsEnabled)
0d0e8dd0
C
78 videoInstance.set('duration', videoData.duration)
79 videoInstance.set('createdAt', videoData.createdAt)
80 videoInstance.set('updatedAt', videoData.updatedAt)
81 videoInstance.set('views', videoData.views)
9a8cbd82 82 videoInstance.set('privacy', videoData.privacy)
0d0e8dd0
C
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
79d5caf9 93 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoInstance, videoAttributesToUpdate)
1f7ab4f3 94 const tasks = videoFileAttributes.map(f => VideoFileModel.create(f))
0d0e8dd0
C
95 await Promise.all(tasks)
96
97 const tags = videoAttributesToUpdate.tag.map(t => t.name)
3fd3ab2d
C
98 const tagInstances = await TagModel.findOrCreateTags(tags, t)
99 await videoInstance.$set('Tags', tagInstances, sequelizeOptions)
0d0e8dd0
C
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}
265ba139
C
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)
265ba139
C
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 => {
a5625b41
C
136 actorFieldsSave = actor.toJSON()
137 accountInstance = actor.Account
138 accountFieldsSave = actor.Account.toJSON()
265ba139 139
a5625b41 140 await updateActorInstance(actor, accountAttributesToUpdate)
265ba139 141
a5625b41
C
142 if (avatarName !== undefined) {
143 await updateActorAvatarInstance(actor, avatarName, t)
265ba139
C
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) {
a5625b41
C
154 if (actor !== undefined && actorFieldsSave !== undefined) {
155 resetSequelizeInstance(actor, actorFieldsSave)
265ba139
C
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}