aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib/activitypub
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-08-15 11:53:26 +0200
committerChocobozzz <me@florianbigard.com>2019-08-19 17:26:35 +0200
commit453e83ea5d81d203ba34bc43cd5c2c750ba40568 (patch)
tree604e02f4343d13a4ba42e1fb7527ba6ab9111712 /server/lib/activitypub
parent13176a07a95984a53cc59aec5217f2ce9806d1bc (diff)
downloadPeerTube-453e83ea5d81d203ba34bc43cd5c2c750ba40568.tar.gz
PeerTube-453e83ea5d81d203ba34bc43cd5c2c750ba40568.tar.zst
PeerTube-453e83ea5d81d203ba34bc43cd5c2c750ba40568.zip
Stronger model typings
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r--server/lib/activitypub/actor.ts75
-rw-r--r--server/lib/activitypub/audience.ts27
-rw-r--r--server/lib/activitypub/cache-file.ts14
-rw-r--r--server/lib/activitypub/playlist.ts19
-rw-r--r--server/lib/activitypub/process/process-accept.ts5
-rw-r--r--server/lib/activitypub/process/process-announce.ts7
-rw-r--r--server/lib/activitypub/process/process-create.ts14
-rw-r--r--server/lib/activitypub/process/process-delete.ts26
-rw-r--r--server/lib/activitypub/process/process-dislike.ts4
-rw-r--r--server/lib/activitypub/process/process-flag.ts6
-rw-r--r--server/lib/activitypub/process/process-follow.ts21
-rw-r--r--server/lib/activitypub/process/process-like.ts4
-rw-r--r--server/lib/activitypub/process/process-reject.ts4
-rw-r--r--server/lib/activitypub/process/process-undo.ts12
-rw-r--r--server/lib/activitypub/process/process-update.ts12
-rw-r--r--server/lib/activitypub/process/process-view.ts6
-rw-r--r--server/lib/activitypub/process/process.ts11
-rw-r--r--server/lib/activitypub/send/send-accept.ts7
-rw-r--r--server/lib/activitypub/send/send-announce.ts15
-rw-r--r--server/lib/activitypub/send/send-create.ts34
-rw-r--r--server/lib/activitypub/send/send-delete.ts12
-rw-r--r--server/lib/activitypub/send/send-dislike.ts7
-rw-r--r--server/lib/activitypub/send/send-flag.ts9
-rw-r--r--server/lib/activitypub/send/send-follow.ts6
-rw-r--r--server/lib/activitypub/send/send-like.ts7
-rw-r--r--server/lib/activitypub/send/send-reject.ts7
-rw-r--r--server/lib/activitypub/send/send-undo.ts34
-rw-r--r--server/lib/activitypub/send/send-update.ts31
-rw-r--r--server/lib/activitypub/send/send-view.ts6
-rw-r--r--server/lib/activitypub/send/utils.ts35
-rw-r--r--server/lib/activitypub/share.ts21
-rw-r--r--server/lib/activitypub/url.ts60
-rw-r--r--server/lib/activitypub/video-comments.ts16
-rw-r--r--server/lib/activitypub/video-rates.ts24
-rw-r--r--server/lib/activitypub/videos.ts143
35 files changed, 412 insertions, 329 deletions
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts
index 9f5d12eb4..7862b0f00 100644
--- a/server/lib/activitypub/actor.ts
+++ b/server/lib/activitypub/actor.ts
@@ -22,13 +22,25 @@ import { JobQueue } from '../job-queue'
22import { getServerActor } from '../../helpers/utils' 22import { getServerActor } from '../../helpers/utils'
23import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor' 23import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor'
24import { sequelizeTypescript } from '../../initializers/database' 24import { sequelizeTypescript } from '../../initializers/database'
25import {
26 MAccount,
27 MActor,
28 MActorAccountChannelId,
29 MActorAccountId,
30 MActorDefault,
31 MActorFull,
32 MActorId,
33 MActorAccountChannelIdActor,
34 MChannel,
35 MActorFullActor, MAccountActorDefault, MChannelActorDefault, MChannelActorAccountDefault
36} from '../../typings/models'
25 37
26// Set account keys, this could be long so process after the account creation and do not block the client 38// Set account keys, this could be long so process after the account creation and do not block the client
27function setAsyncActorKeys (actor: ActorModel) { 39function setAsyncActorKeys (actor: MActor) {
28 return createPrivateAndPublicKeys() 40 return createPrivateAndPublicKeys()
29 .then(({ publicKey, privateKey }) => { 41 .then(({ publicKey, privateKey }) => {
30 actor.set('publicKey', publicKey) 42 actor.publicKey = publicKey
31 actor.set('privateKey', privateKey) 43 actor.privateKey = privateKey
32 return actor.save() 44 return actor.save()
33 }) 45 })
34 .catch(err => { 46 .catch(err => {
@@ -37,12 +49,26 @@ function setAsyncActorKeys (actor: ActorModel) {
37 }) 49 })
38} 50}
39 51
52function getOrCreateActorAndServerAndModel (
53 activityActor: string | ActivityPubActor,
54 fetchType: 'all',
55 recurseIfNeeded?: boolean,
56 updateCollections?: boolean
57): Promise<MActorFullActor>
58
59function getOrCreateActorAndServerAndModel (
60 activityActor: string | ActivityPubActor,
61 fetchType?: 'association-ids',
62 recurseIfNeeded?: boolean,
63 updateCollections?: boolean
64): Promise<MActorAccountChannelId>
65
40async function getOrCreateActorAndServerAndModel ( 66async function getOrCreateActorAndServerAndModel (
41 activityActor: string | ActivityPubActor, 67 activityActor: string | ActivityPubActor,
42 fetchType: ActorFetchByUrlType = 'actor-and-association-ids', 68 fetchType: ActorFetchByUrlType = 'association-ids',
43 recurseIfNeeded = true, 69 recurseIfNeeded = true,
44 updateCollections = false 70 updateCollections = false
45) { 71): Promise<MActorFullActor | MActorAccountChannelId> {
46 const actorUrl = getAPId(activityActor) 72 const actorUrl = getAPId(activityActor)
47 let created = false 73 let created = false
48 let accountPlaylistsUrl: string 74 let accountPlaylistsUrl: string
@@ -61,7 +87,7 @@ async function getOrCreateActorAndServerAndModel (
61 87
62 // Create the attributed to actor 88 // Create the attributed to actor
63 // In PeerTube a video channel is owned by an account 89 // In PeerTube a video channel is owned by an account
64 let ownerActor: ActorModel = undefined 90 let ownerActor: MActorFullActor
65 if (recurseIfNeeded === true && result.actor.type === 'Group') { 91 if (recurseIfNeeded === true && result.actor.type === 'Group') {
66 const accountAttributedTo = result.attributedTo.find(a => a.type === 'Person') 92 const accountAttributedTo = result.attributedTo.find(a => a.type === 'Person')
67 if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actor.url) 93 if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actor.url)
@@ -85,8 +111,8 @@ async function getOrCreateActorAndServerAndModel (
85 accountPlaylistsUrl = result.playlists 111 accountPlaylistsUrl = result.playlists
86 } 112 }
87 113
88 if (actor.Account) actor.Account.Actor = actor 114 if (actor.Account) (actor as MActorAccountChannelIdActor).Account.Actor = actor
89 if (actor.VideoChannel) actor.VideoChannel.Actor = actor 115 if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor
90 116
91 const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType) 117 const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType)
92 if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.') 118 if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.')
@@ -140,7 +166,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ
140 actorInstance.followingUrl = attributes.following 166 actorInstance.followingUrl = attributes.following
141} 167}
142 168
143async function updateActorAvatarInstance (actor: ActorModel, info: { name: string, onDisk: boolean, fileUrl: string }, t: Transaction) { 169type AvatarInfo = { name: string, onDisk: boolean, fileUrl: string }
170async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo, t: Transaction) {
144 if (info.name !== undefined) { 171 if (info.name !== undefined) {
145 if (actor.avatarId) { 172 if (actor.avatarId) {
146 try { 173 try {
@@ -212,14 +239,16 @@ async function addFetchOutboxJob (actor: Pick<ActorModel, 'id' | 'outboxUrl'>) {
212 return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) 239 return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })
213} 240}
214 241
215async function refreshActorIfNeeded ( 242async function refreshActorIfNeeded <T extends MActorFull | MActorAccountChannelId> (
216 actorArg: ActorModel, 243 actorArg: T,
217 fetchedType: ActorFetchByUrlType 244 fetchedType: ActorFetchByUrlType
218): Promise<{ actor: ActorModel, refreshed: boolean }> { 245): Promise<{ actor: T | MActorFull, refreshed: boolean }> {
219 if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } 246 if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false }
220 247
221 // We need more attributes 248 // We need more attributes
222 const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) 249 const actor = fetchedType === 'all'
250 ? actorArg as MActorFull
251 : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url)
223 252
224 try { 253 try {
225 let actorUrl: string 254 let actorUrl: string
@@ -297,9 +326,9 @@ export {
297 326
298function saveActorAndServerAndModelIfNotExist ( 327function saveActorAndServerAndModelIfNotExist (
299 result: FetchRemoteActorResult, 328 result: FetchRemoteActorResult,
300 ownerActor?: ActorModel, 329 ownerActor?: MActorFullActor,
301 t?: Transaction 330 t?: Transaction
302): Bluebird<ActorModel> | Promise<ActorModel> { 331): Bluebird<MActorFullActor> | Promise<MActorFullActor> {
303 let actor = result.actor 332 let actor = result.actor
304 333
305 if (t !== undefined) return save(t) 334 if (t !== undefined) return save(t)
@@ -336,7 +365,7 @@ function saveActorAndServerAndModelIfNotExist (
336 365
337 // Force the actor creation, sometimes Sequelize skips the save() when it thinks the instance already exists 366 // Force the actor creation, sometimes Sequelize skips the save() when it thinks the instance already exists
338 // (which could be false in a retried query) 367 // (which could be false in a retried query)
339 const [ actorCreated ] = await ActorModel.findOrCreate({ 368 const [ actorCreated ] = await ActorModel.findOrCreate<MActorFullActor>({
340 defaults: actor.toJSON(), 369 defaults: actor.toJSON(),
341 where: { 370 where: {
342 url: actor.url 371 url: actor.url
@@ -345,10 +374,10 @@ function saveActorAndServerAndModelIfNotExist (
345 }) 374 })
346 375
347 if (actorCreated.type === 'Person' || actorCreated.type === 'Application') { 376 if (actorCreated.type === 'Person' || actorCreated.type === 'Application') {
348 actorCreated.Account = await saveAccount(actorCreated, result, t) 377 actorCreated.Account = await saveAccount(actorCreated, result, t) as MAccountActorDefault
349 actorCreated.Account.Actor = actorCreated 378 actorCreated.Account.Actor = actorCreated
350 } else if (actorCreated.type === 'Group') { // Video channel 379 } else if (actorCreated.type === 'Group') { // Video channel
351 actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) 380 actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) as MChannelActorAccountDefault
352 actorCreated.VideoChannel.Actor = actorCreated 381 actorCreated.VideoChannel.Actor = actorCreated
353 actorCreated.VideoChannel.Account = ownerActor.Account 382 actorCreated.VideoChannel.Account = ownerActor.Account
354 } 383 }
@@ -360,7 +389,7 @@ function saveActorAndServerAndModelIfNotExist (
360} 389}
361 390
362type FetchRemoteActorResult = { 391type FetchRemoteActorResult = {
363 actor: ActorModel 392 actor: MActor
364 name: string 393 name: string
365 summary: string 394 summary: string
366 support?: string 395 support?: string
@@ -429,7 +458,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe
429 } 458 }
430} 459}
431 460
432async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) { 461async function saveAccount (actor: MActorId, result: FetchRemoteActorResult, t: Transaction) {
433 const [ accountCreated ] = await AccountModel.findOrCreate({ 462 const [ accountCreated ] = await AccountModel.findOrCreate({
434 defaults: { 463 defaults: {
435 name: result.name, 464 name: result.name,
@@ -442,10 +471,10 @@ async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t
442 transaction: t 471 transaction: t
443 }) 472 })
444 473
445 return accountCreated 474 return accountCreated as MAccount
446} 475}
447 476
448async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) { 477async function saveVideoChannel (actor: MActorId, result: FetchRemoteActorResult, ownerActor: MActorAccountId, t: Transaction) {
449 const [ videoChannelCreated ] = await VideoChannelModel.findOrCreate({ 478 const [ videoChannelCreated ] = await VideoChannelModel.findOrCreate({
450 defaults: { 479 defaults: {
451 name: result.name, 480 name: result.name,
@@ -460,5 +489,5 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu
460 transaction: t 489 transaction: t
461 }) 490 })
462 491
463 return videoChannelCreated 492 return videoChannelCreated as MChannel
464} 493}
diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts
index 0e3d78590..f2ab54cf7 100644
--- a/server/lib/activitypub/audience.ts
+++ b/server/lib/activitypub/audience.ts
@@ -3,11 +3,10 @@ import { ActivityAudience } from '../../../shared/models/activitypub'
3import { ACTIVITY_PUB } from '../../initializers/constants' 3import { ACTIVITY_PUB } from '../../initializers/constants'
4import { ActorModel } from '../../models/activitypub/actor' 4import { ActorModel } from '../../models/activitypub/actor'
5import { VideoModel } from '../../models/video/video' 5import { VideoModel } from '../../models/video/video'
6import { VideoCommentModel } from '../../models/video/video-comment'
7import { VideoShareModel } from '../../models/video/video-share' 6import { VideoShareModel } from '../../models/video/video-share'
8import { ActorModelOnly } from '../../typings/models' 7import { MActorFollowersUrl, MActorLight, MCommentOwner, MCommentOwnerVideo, MVideo, MVideoAccountLight } from '../../typings/models'
9 8
10function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience { 9function getRemoteVideoAudience (video: MVideoAccountLight, actorsInvolvedInVideo: MActorFollowersUrl[]): ActivityAudience {
11 return { 10 return {
12 to: [ video.VideoChannel.Account.Actor.url ], 11 to: [ video.VideoChannel.Account.Actor.url ],
13 cc: actorsInvolvedInVideo.map(a => a.followersUrl) 12 cc: actorsInvolvedInVideo.map(a => a.followersUrl)
@@ -15,9 +14,9 @@ function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: Actor
15} 14}
16 15
17function getVideoCommentAudience ( 16function getVideoCommentAudience (
18 videoComment: VideoCommentModel, 17 videoComment: MCommentOwnerVideo,
19 threadParentComments: VideoCommentModel[], 18 threadParentComments: MCommentOwner[],
20 actorsInvolvedInVideo: ActorModel[], 19 actorsInvolvedInVideo: MActorFollowersUrl[],
21 isOrigin = false 20 isOrigin = false
22): ActivityAudience { 21): ActivityAudience {
23 const to = [ ACTIVITY_PUB.PUBLIC ] 22 const to = [ ACTIVITY_PUB.PUBLIC ]
@@ -42,26 +41,28 @@ function getVideoCommentAudience (
42 } 41 }
43} 42}
44 43
45function getAudienceFromFollowersOf (actorsInvolvedInObject: ActorModel[]): ActivityAudience { 44function getAudienceFromFollowersOf (actorsInvolvedInObject: MActorFollowersUrl[]): ActivityAudience {
46 return { 45 return {
47 to: [ ACTIVITY_PUB.PUBLIC ].concat(actorsInvolvedInObject.map(a => a.followersUrl)), 46 to: [ ACTIVITY_PUB.PUBLIC ].concat(actorsInvolvedInObject.map(a => a.followersUrl)),
48 cc: [] 47 cc: []
49 } 48 }
50} 49}
51 50
52async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) { 51async function getActorsInvolvedInVideo (video: MVideo, t: Transaction) {
53 const actors = await VideoShareModel.loadActorsByShare(video.id, t) 52 const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t)
54 53
55 const videoActor = video.VideoChannel && video.VideoChannel.Account 54 const videoAll = video as VideoModel
56 ? video.VideoChannel.Account.Actor 55
57 : await ActorModel.loadAccountActorByVideoId(video.id, t) 56 const videoActor = videoAll.VideoChannel && videoAll.VideoChannel.Account
57 ? videoAll.VideoChannel.Account.Actor
58 : await ActorModel.loadFromAccountByVideoId(video.id, t)
58 59
59 actors.push(videoActor) 60 actors.push(videoActor)
60 61
61 return actors 62 return actors
62} 63}
63 64
64function getAudience (actorSender: ActorModelOnly, isPublic = true) { 65function getAudience (actorSender: MActorFollowersUrl, isPublic = true) {
65 return buildAudience([ actorSender.followersUrl ], isPublic) 66 return buildAudience([ actorSender.followersUrl ], isPublic)
66} 67}
67 68
diff --git a/server/lib/activitypub/cache-file.ts b/server/lib/activitypub/cache-file.ts
index de5cc54ac..65b2dcb49 100644
--- a/server/lib/activitypub/cache-file.ts
+++ b/server/lib/activitypub/cache-file.ts
@@ -1,10 +1,10 @@
1import { CacheFileObject } from '../../../shared/index' 1import { CacheFileObject } from '../../../shared/index'
2import { VideoModel } from '../../models/video/video'
3import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' 2import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy'
4import { Transaction } from 'sequelize' 3import { Transaction } from 'sequelize'
5import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' 4import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type'
5import { MActorId, MVideoRedundancy, MVideoWithAllFiles } from '@server/typings/models'
6 6
7function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject, video: VideoModel, byActor: { id?: number }) { 7function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId) {
8 8
9 if (cacheFileObject.url.mediaType === 'application/x-mpegURL') { 9 if (cacheFileObject.url.mediaType === 'application/x-mpegURL') {
10 const url = cacheFileObject.url 10 const url = cacheFileObject.url
@@ -39,7 +39,7 @@ function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject
39 } 39 }
40} 40}
41 41
42async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: VideoModel, byActor: { id?: number }, t: Transaction) { 42async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId, t: Transaction) {
43 const redundancyModel = await VideoRedundancyModel.loadByUrl(cacheFileObject.id, t) 43 const redundancyModel = await VideoRedundancyModel.loadByUrl(cacheFileObject.id, t)
44 44
45 if (!redundancyModel) { 45 if (!redundancyModel) {
@@ -49,7 +49,7 @@ async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video:
49 } 49 }
50} 50}
51 51
52function createCacheFile (cacheFileObject: CacheFileObject, video: VideoModel, byActor: { id?: number }, t: Transaction) { 52function createCacheFile (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId, t: Transaction) {
53 const attributes = cacheFileActivityObjectToDBAttributes(cacheFileObject, video, byActor) 53 const attributes = cacheFileActivityObjectToDBAttributes(cacheFileObject, video, byActor)
54 54
55 return VideoRedundancyModel.create(attributes, { transaction: t }) 55 return VideoRedundancyModel.create(attributes, { transaction: t })
@@ -57,9 +57,9 @@ function createCacheFile (cacheFileObject: CacheFileObject, video: VideoModel, b
57 57
58function updateCacheFile ( 58function updateCacheFile (
59 cacheFileObject: CacheFileObject, 59 cacheFileObject: CacheFileObject,
60 redundancyModel: VideoRedundancyModel, 60 redundancyModel: MVideoRedundancy,
61 video: VideoModel, 61 video: MVideoWithAllFiles,
62 byActor: { id?: number }, 62 byActor: MActorId,
63 t: Transaction 63 t: Transaction
64) { 64) {
65 if (redundancyModel.actorId !== byActor.id) { 65 if (redundancyModel.actorId !== byActor.id) {
diff --git a/server/lib/activitypub/playlist.ts b/server/lib/activitypub/playlist.ts
index c2e2a3283..c52b715ef 100644
--- a/server/lib/activitypub/playlist.ts
+++ b/server/lib/activitypub/playlist.ts
@@ -1,7 +1,6 @@
1import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' 1import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object'
2import { crawlCollectionPage } from './crawl' 2import { crawlCollectionPage } from './crawl'
3import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 3import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
4import { AccountModel } from '../../models/account/account'
5import { isArray } from '../../helpers/custom-validators/misc' 4import { isArray } from '../../helpers/custom-validators/misc'
6import { getOrCreateActorAndServerAndModel } from './actor' 5import { getOrCreateActorAndServerAndModel } from './actor'
7import { logger } from '../../helpers/logger' 6import { logger } from '../../helpers/logger'
@@ -13,14 +12,14 @@ import { PlaylistElementObject } from '../../../shared/models/activitypub/object
13import { getOrCreateVideoAndAccountAndChannel } from './videos' 12import { getOrCreateVideoAndAccountAndChannel } from './videos'
14import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist' 13import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist'
15import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element' 14import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element'
16import { VideoModel } from '../../models/video/video'
17import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' 15import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model'
18import { sequelizeTypescript } from '../../initializers/database' 16import { sequelizeTypescript } from '../../initializers/database'
19import { createPlaylistMiniatureFromUrl } from '../thumbnail' 17import { createPlaylistMiniatureFromUrl } from '../thumbnail'
20import { FilteredModelAttributes } from '../../typings/sequelize' 18import { FilteredModelAttributes } from '../../typings/sequelize'
21import { AccountModelId } from '../../typings/models' 19import { MAccountDefault, MAccountId, MVideoId } from '../../typings/models'
20import { MVideoPlaylist, MVideoPlaylistId, MVideoPlaylistOwner } from '../../typings/models/video/video-playlist'
22 21
23function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) { 22function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) {
24 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED 23 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED
25 24
26 return { 25 return {
@@ -36,7 +35,7 @@ function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount
36 } 35 }
37} 36}
38 37
39function playlistElementObjectToDBAttributes (elementObject: PlaylistElementObject, videoPlaylist: VideoPlaylistModel, video: VideoModel) { 38function playlistElementObjectToDBAttributes (elementObject: PlaylistElementObject, videoPlaylist: MVideoPlaylistId, video: MVideoId) {
40 return { 39 return {
41 position: elementObject.position, 40 position: elementObject.position,
42 url: elementObject.id, 41 url: elementObject.id,
@@ -47,7 +46,7 @@ function playlistElementObjectToDBAttributes (elementObject: PlaylistElementObje
47 } 46 }
48} 47}
49 48
50async function createAccountPlaylists (playlistUrls: string[], account: AccountModel) { 49async function createAccountPlaylists (playlistUrls: string[], account: MAccountDefault) {
51 await Bluebird.map(playlistUrls, async playlistUrl => { 50 await Bluebird.map(playlistUrls, async playlistUrl => {
52 try { 51 try {
53 const exists = await VideoPlaylistModel.doesPlaylistExist(playlistUrl) 52 const exists = await VideoPlaylistModel.doesPlaylistExist(playlistUrl)
@@ -75,7 +74,7 @@ async function createAccountPlaylists (playlistUrls: string[], account: AccountM
75 }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) 74 }, { concurrency: CRAWL_REQUEST_CONCURRENCY })
76} 75}
77 76
78async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) { 77async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) {
79 const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to) 78 const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to)
80 79
81 if (isArray(playlistObject.attributedTo) && playlistObject.attributedTo.length === 1) { 80 if (isArray(playlistObject.attributedTo) && playlistObject.attributedTo.length === 1) {
@@ -88,7 +87,7 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc
88 } 87 }
89 } 88 }
90 89
91 const [ playlist ] = await VideoPlaylistModel.upsert<VideoPlaylistModel>(playlistAttributes, { returning: true }) 90 const [ playlist ] = await VideoPlaylistModel.upsert<MVideoPlaylist>(playlistAttributes, { returning: true })
92 91
93 let accItems: string[] = [] 92 let accItems: string[] = []
94 await crawlCollectionPage<string>(playlistObject.id, items => { 93 await crawlCollectionPage<string>(playlistObject.id, items => {
@@ -114,7 +113,7 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc
114 return resetVideoPlaylistElements(accItems, refreshedPlaylist) 113 return resetVideoPlaylistElements(accItems, refreshedPlaylist)
115} 114}
116 115
117async function refreshVideoPlaylistIfNeeded (videoPlaylist: VideoPlaylistModel): Promise<VideoPlaylistModel> { 116async function refreshVideoPlaylistIfNeeded (videoPlaylist: MVideoPlaylistOwner): Promise<MVideoPlaylistOwner> {
118 if (!videoPlaylist.isOutdated()) return videoPlaylist 117 if (!videoPlaylist.isOutdated()) return videoPlaylist
119 118
120 try { 119 try {
@@ -157,7 +156,7 @@ export {
157 156
158// --------------------------------------------------------------------------- 157// ---------------------------------------------------------------------------
159 158
160async function resetVideoPlaylistElements (elementUrls: string[], playlist: VideoPlaylistModel) { 159async function resetVideoPlaylistElements (elementUrls: string[], playlist: MVideoPlaylist) {
161 const elementsToCreate: FilteredModelAttributes<VideoPlaylistElementModel>[] = [] 160 const elementsToCreate: FilteredModelAttributes<VideoPlaylistElementModel>[] = []
162 161
163 await Bluebird.map(elementUrls, async elementUrl => { 162 await Bluebird.map(elementUrls, async elementUrl => {
diff --git a/server/lib/activitypub/process/process-accept.ts b/server/lib/activitypub/process/process-accept.ts
index cf27e6c32..86f7c764d 100644
--- a/server/lib/activitypub/process/process-accept.ts
+++ b/server/lib/activitypub/process/process-accept.ts
@@ -1,9 +1,8 @@
1import { ActivityAccept } from '../../../../shared/models/activitypub' 1import { ActivityAccept } from '../../../../shared/models/activitypub'
2import { ActorModel } from '../../../models/activitypub/actor'
3import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 2import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
4import { addFetchOutboxJob } from '../actor' 3import { addFetchOutboxJob } from '../actor'
5import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 4import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
6import { SignatureActorModel } from '../../../typings/models' 5import { MActorDefault, MActorSignature } from '../../../typings/models'
7 6
8async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) { 7async function processAcceptActivity (options: APProcessorOptions<ActivityAccept>) {
9 const { byActor: targetActor, inboxActor } = options 8 const { byActor: targetActor, inboxActor } = options
@@ -20,7 +19,7 @@ export {
20 19
21// --------------------------------------------------------------------------- 20// ---------------------------------------------------------------------------
22 21
23async function processAccept (actor: ActorModel, targetActor: SignatureActorModel) { 22async function processAccept (actor: MActorDefault, targetActor: MActorSignature) {
24 const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id) 23 const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id)
25 if (!follow) throw new Error('Cannot find associated follow.') 24 if (!follow) throw new Error('Cannot find associated follow.')
26 25
diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts
index b3cdc4441..91a9ad72c 100644
--- a/server/lib/activitypub/process/process-announce.ts
+++ b/server/lib/activitypub/process/process-announce.ts
@@ -5,10 +5,9 @@ import { VideoShareModel } from '../../../models/video/video-share'
5import { forwardVideoRelatedActivity } from '../send/utils' 5import { forwardVideoRelatedActivity } from '../send/utils'
6import { getOrCreateVideoAndAccountAndChannel } from '../videos' 6import { getOrCreateVideoAndAccountAndChannel } from '../videos'
7import { Notifier } from '../../notifier' 7import { Notifier } from '../../notifier'
8import { VideoModel } from '../../../models/video/video'
9import { logger } from '../../../helpers/logger' 8import { logger } from '../../../helpers/logger'
10import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 9import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
11import { SignatureActorModel } from '../../../typings/models' 10import { MActorSignature, MVideoAccountAllFiles } from '../../../typings/models'
12 11
13async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) { 12async function processAnnounceActivity (options: APProcessorOptions<ActivityAnnounce>) {
14 const { activity, byActor: actorAnnouncer } = options 13 const { activity, byActor: actorAnnouncer } = options
@@ -26,10 +25,10 @@ export {
26 25
27// --------------------------------------------------------------------------- 26// ---------------------------------------------------------------------------
28 27
29async function processVideoShare (actorAnnouncer: SignatureActorModel, activity: ActivityAnnounce, notify: boolean) { 28async function processVideoShare (actorAnnouncer: MActorSignature, activity: ActivityAnnounce, notify: boolean) {
30 const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id 29 const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id
31 30
32 let video: VideoModel 31 let video: MVideoAccountAllFiles
33 let videoCreated: boolean 32 let videoCreated: boolean
34 33
35 try { 34 try {
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts
index 6815c6997..c45f09f52 100644
--- a/server/lib/activitypub/process/process-create.ts
+++ b/server/lib/activitypub/process/process-create.ts
@@ -10,10 +10,8 @@ import { createOrUpdateCacheFile } from '../cache-file'
10import { Notifier } from '../../notifier' 10import { Notifier } from '../../notifier'
11import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' 11import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
12import { createOrUpdateVideoPlaylist } from '../playlist' 12import { createOrUpdateVideoPlaylist } from '../playlist'
13import { VideoModel } from '../../../models/video/video'
14import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 13import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
15import { VideoCommentModel } from '../../../models/video/video-comment' 14import { MActorSignature, MCommentOwnerVideo, MVideoAccountAllFiles } from '../../../typings/models'
16import { SignatureActorModel } from '../../../typings/models'
17 15
18async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) { 16async function processCreateActivity (options: APProcessorOptions<ActivityCreate>) {
19 const { activity, byActor } = options 17 const { activity, byActor } = options
@@ -61,7 +59,7 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) {
61 return video 59 return video
62} 60}
63 61
64async function processCreateCacheFile (activity: ActivityCreate, byActor: SignatureActorModel) { 62async function processCreateCacheFile (activity: ActivityCreate, byActor: MActorSignature) {
65 const cacheFile = activity.object as CacheFileObject 63 const cacheFile = activity.object as CacheFileObject
66 64
67 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object }) 65 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object })
@@ -77,15 +75,15 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: Signat
77 } 75 }
78} 76}
79 77
80async function processCreateVideoComment (activity: ActivityCreate, byActor: SignatureActorModel, notify: boolean) { 78async function processCreateVideoComment (activity: ActivityCreate, byActor: MActorSignature, notify: boolean) {
81 const commentObject = activity.object as VideoCommentObject 79 const commentObject = activity.object as VideoCommentObject
82 const byAccount = byActor.Account 80 const byAccount = byActor.Account
83 81
84 if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) 82 if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url)
85 83
86 let video: VideoModel 84 let video: MVideoAccountAllFiles
87 let created: boolean 85 let created: boolean
88 let comment: VideoCommentModel 86 let comment: MCommentOwnerVideo
89 try { 87 try {
90 const resolveThreadResult = await resolveThread({ url: commentObject.id, isVideo: false }) 88 const resolveThreadResult = await resolveThread({ url: commentObject.id, isVideo: false })
91 video = resolveThreadResult.video 89 video = resolveThreadResult.video
@@ -110,7 +108,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Sig
110 if (created && notify) Notifier.Instance.notifyOnNewComment(comment) 108 if (created && notify) Notifier.Instance.notifyOnNewComment(comment)
111} 109}
112 110
113async function processCreatePlaylist (activity: ActivityCreate, byActor: SignatureActorModel) { 111async function processCreatePlaylist (activity: ActivityCreate, byActor: MActorSignature) {
114 const playlistObject = activity.object as PlaylistObject 112 const playlistObject = activity.object as PlaylistObject
115 const byAccount = byActor.Account 113 const byAccount = byActor.Account
116 114
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts
index 344d14322..79d0e0d79 100644
--- a/server/lib/activitypub/process/process-delete.ts
+++ b/server/lib/activitypub/process/process-delete.ts
@@ -2,15 +2,13 @@ import { ActivityDelete } from '../../../../shared/models/activitypub'
2import { retryTransactionWrapper } from '../../../helpers/database-utils' 2import { retryTransactionWrapper } from '../../../helpers/database-utils'
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { sequelizeTypescript } from '../../../initializers' 4import { sequelizeTypescript } from '../../../initializers'
5import { AccountModel } from '../../../models/account/account'
6import { ActorModel } from '../../../models/activitypub/actor' 5import { ActorModel } from '../../../models/activitypub/actor'
7import { VideoModel } from '../../../models/video/video' 6import { VideoModel } from '../../../models/video/video'
8import { VideoChannelModel } from '../../../models/video/video-channel'
9import { VideoCommentModel } from '../../../models/video/video-comment' 7import { VideoCommentModel } from '../../../models/video/video-comment'
10import { forwardVideoRelatedActivity } from '../send/utils' 8import { forwardVideoRelatedActivity } from '../send/utils'
11import { VideoPlaylistModel } from '../../../models/video/video-playlist' 9import { VideoPlaylistModel } from '../../../models/video/video-playlist'
12import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 10import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
13import { SignatureActorModel } from '../../../typings/models' 11import { MAccountActor, MActor, MActorSignature, MChannelActor, MChannelActorAccountActor } from '../../../typings/models'
14 12
15async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) { 13async function processDeleteActivity (options: APProcessorOptions<ActivityDelete>) {
16 const { activity, byActor } = options 14 const { activity, byActor } = options
@@ -24,13 +22,17 @@ async function processDeleteActivity (options: APProcessorOptions<ActivityDelete
24 if (byActorFull.type === 'Person') { 22 if (byActorFull.type === 'Person') {
25 if (!byActorFull.Account) throw new Error('Actor ' + byActorFull.url + ' is a person but we cannot find it in database.') 23 if (!byActorFull.Account) throw new Error('Actor ' + byActorFull.url + ' is a person but we cannot find it in database.')
26 24
27 byActorFull.Account.Actor = await byActorFull.Account.$get('Actor') as ActorModel 25 const accountToDelete = byActorFull.Account as MAccountActor
28 return retryTransactionWrapper(processDeleteAccount, byActorFull.Account) 26 accountToDelete.Actor = byActorFull
27
28 return retryTransactionWrapper(processDeleteAccount, accountToDelete)
29 } else if (byActorFull.type === 'Group') { 29 } else if (byActorFull.type === 'Group') {
30 if (!byActorFull.VideoChannel) throw new Error('Actor ' + byActorFull.url + ' is a group but we cannot find it in database.') 30 if (!byActorFull.VideoChannel) throw new Error('Actor ' + byActorFull.url + ' is a group but we cannot find it in database.')
31 31
32 byActorFull.VideoChannel.Actor = await byActorFull.VideoChannel.$get('Actor') as ActorModel 32 const channelToDelete = byActorFull.VideoChannel as MChannelActorAccountActor
33 return retryTransactionWrapper(processDeleteVideoChannel, byActorFull.VideoChannel) 33 channelToDelete.Actor = byActorFull
34
35 return retryTransactionWrapper(processDeleteVideoChannel, channelToDelete)
34 } 36 }
35 } 37 }
36 38
@@ -70,7 +72,7 @@ export {
70 72
71// --------------------------------------------------------------------------- 73// ---------------------------------------------------------------------------
72 74
73async function processDeleteVideo (actor: ActorModel, videoToDelete: VideoModel) { 75async function processDeleteVideo (actor: MActor, videoToDelete: VideoModel) {
74 logger.debug('Removing remote video "%s".', videoToDelete.uuid) 76 logger.debug('Removing remote video "%s".', videoToDelete.uuid)
75 77
76 await sequelizeTypescript.transaction(async t => { 78 await sequelizeTypescript.transaction(async t => {
@@ -84,7 +86,7 @@ async function processDeleteVideo (actor: ActorModel, videoToDelete: VideoModel)
84 logger.info('Remote video with uuid %s removed.', videoToDelete.uuid) 86 logger.info('Remote video with uuid %s removed.', videoToDelete.uuid)
85} 87}
86 88
87async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete: VideoPlaylistModel) { 89async function processDeleteVideoPlaylist (actor: MActor, playlistToDelete: VideoPlaylistModel) {
88 logger.debug('Removing remote video playlist "%s".', playlistToDelete.uuid) 90 logger.debug('Removing remote video playlist "%s".', playlistToDelete.uuid)
89 91
90 await sequelizeTypescript.transaction(async t => { 92 await sequelizeTypescript.transaction(async t => {
@@ -98,7 +100,7 @@ async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete:
98 logger.info('Remote video playlist with uuid %s removed.', playlistToDelete.uuid) 100 logger.info('Remote video playlist with uuid %s removed.', playlistToDelete.uuid)
99} 101}
100 102
101async function processDeleteAccount (accountToRemove: AccountModel) { 103async function processDeleteAccount (accountToRemove: MAccountActor) {
102 logger.debug('Removing remote account "%s".', accountToRemove.Actor.url) 104 logger.debug('Removing remote account "%s".', accountToRemove.Actor.url)
103 105
104 await sequelizeTypescript.transaction(async t => { 106 await sequelizeTypescript.transaction(async t => {
@@ -108,7 +110,7 @@ async function processDeleteAccount (accountToRemove: AccountModel) {
108 logger.info('Remote account %s removed.', accountToRemove.Actor.url) 110 logger.info('Remote account %s removed.', accountToRemove.Actor.url)
109} 111}
110 112
111async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { 113async function processDeleteVideoChannel (videoChannelToRemove: MChannelActor) {
112 logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url) 114 logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url)
113 115
114 await sequelizeTypescript.transaction(async t => { 116 await sequelizeTypescript.transaction(async t => {
@@ -118,7 +120,7 @@ async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelMode
118 logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) 120 logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url)
119} 121}
120 122
121function processDeleteVideoComment (byActor: SignatureActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { 123function processDeleteVideoComment (byActor: MActorSignature, videoComment: VideoCommentModel, activity: ActivityDelete) {
122 logger.debug('Removing remote video comment "%s".', videoComment.url) 124 logger.debug('Removing remote video comment "%s".', videoComment.url)
123 125
124 return sequelizeTypescript.transaction(async t => { 126 return sequelizeTypescript.transaction(async t => {
diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts
index 727fcfee0..debd8a67c 100644
--- a/server/lib/activitypub/process/process-dislike.ts
+++ b/server/lib/activitypub/process/process-dislike.ts
@@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos'
7import { forwardVideoRelatedActivity } from '../send/utils' 7import { forwardVideoRelatedActivity } from '../send/utils'
8import { getVideoDislikeActivityPubUrl } from '../url' 8import { getVideoDislikeActivityPubUrl } from '../url'
9import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 9import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
10import { SignatureActorModel } from '../../../typings/models' 10import { MActorSignature } from '../../../typings/models'
11 11
12async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) { 12async function processDislikeActivity (options: APProcessorOptions<ActivityCreate | ActivityDislike>) {
13 const { activity, byActor } = options 13 const { activity, byActor } = options
@@ -22,7 +22,7 @@ export {
22 22
23// --------------------------------------------------------------------------- 23// ---------------------------------------------------------------------------
24 24
25async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: SignatureActorModel) { 25async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: MActorSignature) {
26 const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object 26 const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object
27 const byAccount = byActor.Account 27 const byAccount = byActor.Account
28 28
diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts
index 1f8a80c14..422386540 100644
--- a/server/lib/activitypub/process/process-flag.ts
+++ b/server/lib/activitypub/process/process-flag.ts
@@ -8,7 +8,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos'
8import { Notifier } from '../../notifier' 8import { Notifier } from '../../notifier'
9import { getAPId } from '../../../helpers/activitypub' 9import { getAPId } from '../../../helpers/activitypub'
10import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 10import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
11import { SignatureActorModel } from '../../../typings/models' 11import { MActorSignature, MVideoAbuseVideo } from '../../../typings/models'
12 12
13async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) { 13async function processFlagActivity (options: APProcessorOptions<ActivityCreate | ActivityFlag>) {
14 const { activity, byActor } = options 14 const { activity, byActor } = options
@@ -23,7 +23,7 @@ export {
23 23
24// --------------------------------------------------------------------------- 24// ---------------------------------------------------------------------------
25 25
26async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: SignatureActorModel) { 26async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) {
27 const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) 27 const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject)
28 28
29 logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object)) 29 logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object))
@@ -41,7 +41,7 @@ async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag,
41 state: VideoAbuseState.PENDING 41 state: VideoAbuseState.PENDING
42 } 42 }
43 43
44 const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) 44 const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo
45 videoAbuseInstance.Video = video 45 videoAbuseInstance.Video = video
46 46
47 logger.info('Remote abuse for video uuid %s created', flag.object) 47 logger.info('Remote abuse for video uuid %s created', flag.object)
diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts
index 240aa5799..bc5660395 100644
--- a/server/lib/activitypub/process/process-follow.ts
+++ b/server/lib/activitypub/process/process-follow.ts
@@ -10,8 +10,7 @@ import { getAPId } from '../../../helpers/activitypub'
10import { getServerActor } from '../../../helpers/utils' 10import { getServerActor } from '../../../helpers/utils'
11import { CONFIG } from '../../../initializers/config' 11import { CONFIG } from '../../../initializers/config'
12import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 12import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
13import { SignatureActorModel } from '../../../typings/models' 13import { MAccount, MActorFollowActors, MActorFollowFull, MActorSignature } from '../../../typings/models'
14import { ActorFollowModelLight } from '../../../typings/models/actor-follow'
15 14
16async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) { 15async function processFollowActivity (options: APProcessorOptions<ActivityFollow>) {
17 const { activity, byActor } = options 16 const { activity, byActor } = options
@@ -28,7 +27,7 @@ export {
28 27
29// --------------------------------------------------------------------------- 28// ---------------------------------------------------------------------------
30 29
31async function processFollow (byActor: SignatureActorModel, targetActorURL: string) { 30async function processFollow (byActor: MActorSignature, targetActorURL: string) {
32 const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { 31 const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => {
33 const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) 32 const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t)
34 33
@@ -43,10 +42,10 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri
43 42
44 await sendReject(byActor, targetActor) 43 await sendReject(byActor, targetActor)
45 44
46 return { actorFollow: undefined } 45 return { actorFollow: undefined as MActorFollowActors }
47 } 46 }
48 47
49 const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ 48 const [ actorFollow, created ] = await ActorFollowModel.findOrCreate<MActorFollowActors>({
50 where: { 49 where: {
51 actorId: byActor.id, 50 actorId: byActor.id,
52 targetActorId: targetActor.id 51 targetActorId: targetActor.id
@@ -57,7 +56,7 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri
57 state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' 56 state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted'
58 }, 57 },
59 transaction: t 58 transaction: t
60 }) as [ ActorFollowModelLight, boolean ] 59 })
61 60
62 if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { 61 if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) {
63 actorFollow.state = 'accepted' 62 actorFollow.state = 'accepted'
@@ -77,8 +76,14 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri
77 if (!actorFollow) return 76 if (!actorFollow) return
78 77
79 if (created) { 78 if (created) {
80 if (isFollowingInstance) Notifier.Instance.notifyOfNewInstanceFollow(actorFollow) 79 if (isFollowingInstance) {
81 else Notifier.Instance.notifyOfNewUserFollow(actorFollow) 80 Notifier.Instance.notifyOfNewInstanceFollow(actorFollow)
81 } else {
82 const actorFollowFull = actorFollow as MActorFollowFull
83 actorFollowFull.ActorFollower.Account = await actorFollow.ActorFollower.$get('Account') as MAccount
84
85 Notifier.Instance.notifyOfNewUserFollow(actorFollowFull)
86 }
82 } 87 }
83 88
84 logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url) 89 logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url)
diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts
index cf559af72..62be0de42 100644
--- a/server/lib/activitypub/process/process-like.ts
+++ b/server/lib/activitypub/process/process-like.ts
@@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos'
7import { getVideoLikeActivityPubUrl } from '../url' 7import { getVideoLikeActivityPubUrl } from '../url'
8import { getAPId } from '../../../helpers/activitypub' 8import { getAPId } from '../../../helpers/activitypub'
9import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 9import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
10import { SignatureActorModel } from '../../../typings/models' 10import { MActorSignature } from '../../../typings/models'
11 11
12async function processLikeActivity (options: APProcessorOptions<ActivityLike>) { 12async function processLikeActivity (options: APProcessorOptions<ActivityLike>) {
13 const { activity, byActor } = options 13 const { activity, byActor } = options
@@ -22,7 +22,7 @@ export {
22 22
23// --------------------------------------------------------------------------- 23// ---------------------------------------------------------------------------
24 24
25async function processLikeVideo (byActor: SignatureActorModel, activity: ActivityLike) { 25async function processLikeVideo (byActor: MActorSignature, activity: ActivityLike) {
26 const videoUrl = getAPId(activity.object) 26 const videoUrl = getAPId(activity.object)
27 27
28 const byAccount = byActor.Account 28 const byAccount = byActor.Account
diff --git a/server/lib/activitypub/process/process-reject.ts b/server/lib/activitypub/process/process-reject.ts
index 22e311ceb..00e9afa10 100644
--- a/server/lib/activitypub/process/process-reject.ts
+++ b/server/lib/activitypub/process/process-reject.ts
@@ -2,7 +2,7 @@ import { ActivityReject } from '../../../../shared/models/activitypub/activity'
2import { sequelizeTypescript } from '../../../initializers' 2import { sequelizeTypescript } from '../../../initializers'
3import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 3import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
4import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 4import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
5import { ActorModelOnly } from '../../../typings/models' 5import { MActor } from '../../../typings/models'
6 6
7async function processRejectActivity (options: APProcessorOptions<ActivityReject>) { 7async function processRejectActivity (options: APProcessorOptions<ActivityReject>) {
8 const { byActor: targetActor, inboxActor } = options 8 const { byActor: targetActor, inboxActor } = options
@@ -19,7 +19,7 @@ export {
19 19
20// --------------------------------------------------------------------------- 20// ---------------------------------------------------------------------------
21 21
22async function processReject (follower: ActorModelOnly, targetActor: ActorModelOnly) { 22async function processReject (follower: MActor, targetActor: MActor) {
23 return sequelizeTypescript.transaction(async t => { 23 return sequelizeTypescript.transaction(async t => {
24 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t) 24 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t)
25 25
diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts
index c37ee38bb..10643b2e9 100644
--- a/server/lib/activitypub/process/process-undo.ts
+++ b/server/lib/activitypub/process/process-undo.ts
@@ -11,7 +11,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos'
11import { VideoShareModel } from '../../../models/video/video-share' 11import { VideoShareModel } from '../../../models/video/video-share'
12import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' 12import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
13import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 13import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
14import { SignatureActorModel } from '../../../typings/models' 14import { MActorSignature } from '../../../typings/models'
15 15
16async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) { 16async function processUndoActivity (options: APProcessorOptions<ActivityUndo>) {
17 const { activity, byActor } = options 17 const { activity, byActor } = options
@@ -54,7 +54,7 @@ export {
54 54
55// --------------------------------------------------------------------------- 55// ---------------------------------------------------------------------------
56 56
57async function processUndoLike (byActor: SignatureActorModel, activity: ActivityUndo) { 57async function processUndoLike (byActor: MActorSignature, activity: ActivityUndo) {
58 const likeActivity = activity.object as ActivityLike 58 const likeActivity = activity.object as ActivityLike
59 59
60 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object }) 60 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object })
@@ -77,7 +77,7 @@ async function processUndoLike (byActor: SignatureActorModel, activity: Activity
77 }) 77 })
78} 78}
79 79
80async function processUndoDislike (byActor: SignatureActorModel, activity: ActivityUndo) { 80async function processUndoDislike (byActor: MActorSignature, activity: ActivityUndo) {
81 const dislike = activity.object.type === 'Dislike' 81 const dislike = activity.object.type === 'Dislike'
82 ? activity.object 82 ? activity.object
83 : activity.object.object as DislikeObject 83 : activity.object.object as DislikeObject
@@ -102,7 +102,7 @@ async function processUndoDislike (byActor: SignatureActorModel, activity: Activ
102 }) 102 })
103} 103}
104 104
105async function processUndoCacheFile (byActor: SignatureActorModel, activity: ActivityUndo) { 105async function processUndoCacheFile (byActor: MActorSignature, activity: ActivityUndo) {
106 const cacheFileObject = activity.object.object as CacheFileObject 106 const cacheFileObject = activity.object.object as CacheFileObject
107 107
108 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object }) 108 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object })
@@ -127,7 +127,7 @@ async function processUndoCacheFile (byActor: SignatureActorModel, activity: Act
127 }) 127 })
128} 128}
129 129
130function processUndoFollow (follower: SignatureActorModel, followActivity: ActivityFollow) { 130function processUndoFollow (follower: MActorSignature, followActivity: ActivityFollow) {
131 return sequelizeTypescript.transaction(async t => { 131 return sequelizeTypescript.transaction(async t => {
132 const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t) 132 const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t)
133 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t) 133 const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t)
@@ -140,7 +140,7 @@ function processUndoFollow (follower: SignatureActorModel, followActivity: Activ
140 }) 140 })
141} 141}
142 142
143function processUndoAnnounce (byActor: SignatureActorModel, announceActivity: ActivityAnnounce) { 143function processUndoAnnounce (byActor: MActorSignature, announceActivity: ActivityAnnounce) {
144 return sequelizeTypescript.transaction(async t => { 144 return sequelizeTypescript.transaction(async t => {
145 const share = await VideoShareModel.loadByUrl(announceActivity.id, t) 145 const share = await VideoShareModel.loadByUrl(announceActivity.id, t)
146 if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) 146 if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`)
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts
index 414f9e375..9f80a0ce9 100644
--- a/server/lib/activitypub/process/process-update.ts
+++ b/server/lib/activitypub/process/process-update.ts
@@ -15,7 +15,7 @@ import { forwardVideoRelatedActivity } from '../send/utils'
15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' 15import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object'
16import { createOrUpdateVideoPlaylist } from '../playlist' 16import { createOrUpdateVideoPlaylist } from '../playlist'
17import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 17import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
18import { SignatureActorModel } from '../../../typings/models' 18import { MActorSignature } from '../../../typings/models'
19 19
20async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) { 20async function processUpdateActivity (options: APProcessorOptions<ActivityUpdate>) {
21 const { activity, byActor } = options 21 const { activity, byActor } = options
@@ -53,7 +53,7 @@ export {
53 53
54// --------------------------------------------------------------------------- 54// ---------------------------------------------------------------------------
55 55
56async function processUpdateVideo (actor: SignatureActorModel, activity: ActivityUpdate) { 56async function processUpdateVideo (actor: MActorSignature, activity: ActivityUpdate) {
57 const videoObject = activity.object as VideoTorrentObject 57 const videoObject = activity.object as VideoTorrentObject
58 58
59 if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { 59 if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) {
@@ -61,20 +61,20 @@ async function processUpdateVideo (actor: SignatureActorModel, activity: Activit
61 return undefined 61 return undefined
62 } 62 }
63 63
64 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false }) 64 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false, fetchType: 'all' })
65 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) 65 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject)
66 66
67 const updateOptions = { 67 const updateOptions = {
68 video, 68 video,
69 videoObject, 69 videoObject,
70 account: actor.Account, 70 account: channelActor.VideoChannel.Account,
71 channel: channelActor.VideoChannel, 71 channel: channelActor.VideoChannel,
72 overrideTo: activity.to 72 overrideTo: activity.to
73 } 73 }
74 return updateVideoFromAP(updateOptions) 74 return updateVideoFromAP(updateOptions)
75} 75}
76 76
77async function processUpdateCacheFile (byActor: SignatureActorModel, activity: ActivityUpdate) { 77async function processUpdateCacheFile (byActor: MActorSignature, activity: ActivityUpdate) {
78 const cacheFileObject = activity.object as CacheFileObject 78 const cacheFileObject = activity.object as CacheFileObject
79 79
80 if (!isCacheFileObjectValid(cacheFileObject)) { 80 if (!isCacheFileObjectValid(cacheFileObject)) {
@@ -150,7 +150,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate)
150 } 150 }
151} 151}
152 152
153async function processUpdatePlaylist (byActor: SignatureActorModel, activity: ActivityUpdate) { 153async function processUpdatePlaylist (byActor: MActorSignature, activity: ActivityUpdate) {
154 const playlistObject = activity.object as PlaylistObject 154 const playlistObject = activity.object as PlaylistObject
155 const byAccount = byActor.Account 155 const byAccount = byActor.Account
156 156
diff --git a/server/lib/activitypub/process/process-view.ts b/server/lib/activitypub/process/process-view.ts
index e4997b828..df29ee968 100644
--- a/server/lib/activitypub/process/process-view.ts
+++ b/server/lib/activitypub/process/process-view.ts
@@ -3,7 +3,7 @@ import { forwardVideoRelatedActivity } from '../send/utils'
3import { Redis } from '../../redis' 3import { Redis } from '../../redis'
4import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub' 4import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub'
5import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 5import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
6import { SignatureActorModel } from '../../../typings/models' 6import { MActorSignature } from '../../../typings/models'
7 7
8async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) { 8async function processViewActivity (options: APProcessorOptions<ActivityCreate | ActivityView>) {
9 const { activity, byActor } = options 9 const { activity, byActor } = options
@@ -18,11 +18,11 @@ export {
18 18
19// --------------------------------------------------------------------------- 19// ---------------------------------------------------------------------------
20 20
21async function processCreateView (activity: ActivityView | ActivityCreate, byActor: SignatureActorModel) { 21async function processCreateView (activity: ActivityView | ActivityCreate, byActor: MActorSignature) {
22 const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object 22 const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object
23 23
24 const options = { 24 const options = {
25 videoObject: videoObject, 25 videoObject,
26 fetchType: 'only-video' as 'only-video' 26 fetchType: 'only-video' as 'only-video'
27 } 27 }
28 const { video } = await getOrCreateVideoAndAccountAndChannel(options) 28 const { video } = await getOrCreateVideoAndAccountAndChannel(options)
diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts
index d108fe321..c602bf218 100644
--- a/server/lib/activitypub/process/process.ts
+++ b/server/lib/activitypub/process/process.ts
@@ -1,7 +1,6 @@
1import { Activity, ActivityType } from '../../../../shared/models/activitypub' 1import { Activity, ActivityType } from '../../../../shared/models/activitypub'
2import { checkUrlsSameHost, getAPId } from '../../../helpers/activitypub' 2import { checkUrlsSameHost, getAPId } from '../../../helpers/activitypub'
3import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
4import { ActorModel } from '../../../models/activitypub/actor'
5import { processAcceptActivity } from './process-accept' 4import { processAcceptActivity } from './process-accept'
6import { processAnnounceActivity } from './process-announce' 5import { processAnnounceActivity } from './process-announce'
7import { processCreateActivity } from './process-create' 6import { processCreateActivity } from './process-create'
@@ -16,7 +15,7 @@ import { processDislikeActivity } from './process-dislike'
16import { processFlagActivity } from './process-flag' 15import { processFlagActivity } from './process-flag'
17import { processViewActivity } from './process-view' 16import { processViewActivity } from './process-view'
18import { APProcessorOptions } from '../../../typings/activitypub-processor.model' 17import { APProcessorOptions } from '../../../typings/activitypub-processor.model'
19import { SignatureActorModel } from '../../../typings/models' 18import { MActorDefault, MActorSignature } from '../../../typings/models'
20 19
21const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = { 20const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Activity>) => Promise<any> } = {
22 Create: processCreateActivity, 21 Create: processCreateActivity,
@@ -36,15 +35,15 @@ const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions<Act
36async function processActivities ( 35async function processActivities (
37 activities: Activity[], 36 activities: Activity[],
38 options: { 37 options: {
39 signatureActor?: SignatureActorModel 38 signatureActor?: MActorSignature
40 inboxActor?: ActorModel 39 inboxActor?: MActorDefault
41 outboxUrl?: string 40 outboxUrl?: string
42 fromFetch?: boolean 41 fromFetch?: boolean
43 } = {} 42 } = {}
44) { 43) {
45 const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options 44 const { outboxUrl, signatureActor, inboxActor, fromFetch = false } = options
46 45
47 const actorsCache: { [ url: string ]: SignatureActorModel } = {} 46 const actorsCache: { [ url: string ]: MActorSignature } = {}
48 47
49 for (const activity of activities) { 48 for (const activity of activities) {
50 if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) { 49 if (!signatureActor && [ 'Create', 'Announce', 'Like' ].includes(activity.type) === false) {
@@ -75,7 +74,7 @@ async function processActivities (
75 } 74 }
76 75
77 try { 76 try {
78 await activityProcessor({ activity, byActor, inboxActor: inboxActor, fromFetch }) 77 await activityProcessor({ activity, byActor, inboxActor, fromFetch })
79 } catch (err) { 78 } catch (err) {
80 logger.warn('Cannot process activity %s.', activity.type, { err }) 79 logger.warn('Cannot process activity %s.', activity.type, { err })
81 } 80 }
diff --git a/server/lib/activitypub/send/send-accept.ts b/server/lib/activitypub/send/send-accept.ts
index 813c42e15..9f0225b64 100644
--- a/server/lib/activitypub/send/send-accept.ts
+++ b/server/lib/activitypub/send/send-accept.ts
@@ -3,10 +3,9 @@ import { getActorFollowAcceptActivityPubUrl, getActorFollowActivityPubUrl } from
3import { unicastTo } from './utils' 3import { unicastTo } from './utils'
4import { buildFollowActivity } from './send-follow' 4import { buildFollowActivity } from './send-follow'
5import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
6import { ActorFollowModelLight } from '../../../typings/models/actor-follow' 6import { MActor, MActorFollowActors } from '../../../typings/models'
7import { ActorModelOnly } from '../../../typings/models'
8 7
9async function sendAccept (actorFollow: ActorFollowModelLight) { 8async function sendAccept (actorFollow: MActorFollowActors) {
10 const follower = actorFollow.ActorFollower 9 const follower = actorFollow.ActorFollower
11 const me = actorFollow.ActorFollowing 10 const me = actorFollow.ActorFollowing
12 11
@@ -34,7 +33,7 @@ export {
34 33
35// --------------------------------------------------------------------------- 34// ---------------------------------------------------------------------------
36 35
37function buildAcceptActivity (url: string, byActor: ActorModelOnly, followActivityData: ActivityFollow): ActivityAccept { 36function buildAcceptActivity (url: string, byActor: MActor, followActivityData: ActivityFollow): ActivityAccept {
38 return { 37 return {
39 type: 'Accept', 38 type: 'Accept',
40 id: url, 39 id: url,
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts
index 7fe4ca180..a0f33852c 100644
--- a/server/lib/activitypub/send/send-announce.ts
+++ b/server/lib/activitypub/send/send-announce.ts
@@ -1,16 +1,15 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub' 2import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub'
3import { VideoModel } from '../../../models/video/video'
4import { broadcastToFollowers } from './utils' 3import { broadcastToFollowers } from './utils'
5import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience' 4import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience'
6import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
7import { ActorModelOnly } from '../../../typings/models' 6import { MActorLight, MVideo } from '../../../typings/models'
8import { VideoShareModelOnly } from '../../../typings/models/video-share' 7import { MVideoShare } from '../../../typings/models/video'
9 8
10async function buildAnnounceWithVideoAudience ( 9async function buildAnnounceWithVideoAudience (
11 byActor: ActorModelOnly, 10 byActor: MActorLight,
12 videoShare: VideoShareModelOnly, 11 videoShare: MVideoShare,
13 video: VideoModel, 12 video: MVideo,
14 t: Transaction 13 t: Transaction
15) { 14) {
16 const announcedObject = video.url 15 const announcedObject = video.url
@@ -23,7 +22,7 @@ async function buildAnnounceWithVideoAudience (
23 return { activity, actorsInvolvedInVideo } 22 return { activity, actorsInvolvedInVideo }
24} 23}
25 24
26async function sendVideoAnnounce (byActor: ActorModelOnly, videoShare: VideoShareModelOnly, video: VideoModel, t: Transaction) { 25async function sendVideoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) {
27 const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t) 26 const { activity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t)
28 27
29 logger.info('Creating job to send announce %s.', videoShare.url) 28 logger.info('Creating job to send announce %s.', videoShare.url)
@@ -32,7 +31,7 @@ async function sendVideoAnnounce (byActor: ActorModelOnly, videoShare: VideoShar
32 return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException) 31 return broadcastToFollowers(activity, byActor, actorsInvolvedInVideo, t, followersException)
33} 32}
34 33
35function buildAnnounceActivity (url: string, byActor: ActorModelOnly, object: string, audience?: ActivityAudience): ActivityAnnounce { 34function buildAnnounceActivity (url: string, byActor: MActorLight, object: string, audience?: ActivityAudience): ActivityAnnounce {
36 if (!audience) audience = getAudience(byActor) 35 if (!audience) audience = getAudience(byActor)
37 36
38 return audiencify({ 37 return audiencify({
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts
index 9c21149f2..26ec3e948 100644
--- a/server/lib/activitypub/send/send-create.ts
+++ b/server/lib/activitypub/send/send-create.ts
@@ -1,19 +1,23 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub' 2import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub'
3import { VideoPrivacy } from '../../../../shared/models/videos' 3import { VideoPrivacy } from '../../../../shared/models/videos'
4import { ActorModel } from '../../../models/activitypub/actor'
5import { VideoModel } from '../../../models/video/video'
6import { VideoCommentModel } from '../../../models/video/video-comment' 4import { VideoCommentModel } from '../../../models/video/video-comment'
7import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' 5import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils'
8import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf, getVideoCommentAudience } from '../audience' 6import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf, getVideoCommentAudience } from '../audience'
9import { logger } from '../../../helpers/logger' 7import { logger } from '../../../helpers/logger'
10import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
11import { VideoPlaylistModel } from '../../../models/video/video-playlist'
12import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' 8import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
13import { getServerActor } from '../../../helpers/utils' 9import { getServerActor } from '../../../helpers/utils'
14import * as Bluebird from 'bluebird' 10import {
15 11 MActorLight,
16async function sendCreateVideo (video: VideoModel, t: Transaction) { 12 MCommentOwnerVideo,
13 MVideoAccountLight,
14 MVideoAP,
15 MVideoPlaylistFull,
16 MVideoRedundancyFileVideo,
17 MVideoRedundancyStreamingPlaylistVideo
18} from '../../../typings/models'
19
20async function sendCreateVideo (video: MVideoAP, t: Transaction) {
17 if (video.privacy === VideoPrivacy.PRIVATE) return undefined 21 if (video.privacy === VideoPrivacy.PRIVATE) return undefined
18 22
19 logger.info('Creating job to send video creation of %s.', video.url) 23 logger.info('Creating job to send video creation of %s.', video.url)
@@ -27,7 +31,11 @@ async function sendCreateVideo (video: VideoModel, t: Transaction) {
27 return broadcastToFollowers(createActivity, byActor, [ byActor ], t) 31 return broadcastToFollowers(createActivity, byActor, [ byActor ], t)
28} 32}
29 33
30async function sendCreateCacheFile (byActor: ActorModel, video: VideoModel, fileRedundancy: VideoRedundancyModel) { 34async function sendCreateCacheFile (
35 byActor: MActorLight,
36 video: MVideoAccountLight,
37 fileRedundancy: MVideoRedundancyStreamingPlaylistVideo | MVideoRedundancyFileVideo
38) {
31 logger.info('Creating job to send file cache of %s.', fileRedundancy.url) 39 logger.info('Creating job to send file cache of %s.', fileRedundancy.url)
32 40
33 return sendVideoRelatedCreateActivity({ 41 return sendVideoRelatedCreateActivity({
@@ -38,7 +46,7 @@ async function sendCreateCacheFile (byActor: ActorModel, video: VideoModel, file
38 }) 46 })
39} 47}
40 48
41async function sendCreateVideoPlaylist (playlist: VideoPlaylistModel, t: Transaction) { 49async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, t: Transaction) {
42 if (playlist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined 50 if (playlist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined
43 51
44 logger.info('Creating job to send create video playlist of %s.', playlist.url) 52 logger.info('Creating job to send create video playlist of %s.', playlist.url)
@@ -57,7 +65,7 @@ async function sendCreateVideoPlaylist (playlist: VideoPlaylistModel, t: Transac
57 return broadcastToFollowers(createActivity, byActor, toFollowersOf, t) 65 return broadcastToFollowers(createActivity, byActor, toFollowersOf, t)
58} 66}
59 67
60async function sendCreateVideoComment (comment: VideoCommentModel, t: Transaction) { 68async function sendCreateVideoComment (comment: MCommentOwnerVideo, t: Transaction) {
61 logger.info('Creating job to send comment %s.', comment.url) 69 logger.info('Creating job to send comment %s.', comment.url)
62 70
63 const isOrigin = comment.Video.isOwned() 71 const isOrigin = comment.Video.isOwned()
@@ -95,7 +103,7 @@ async function sendCreateVideoComment (comment: VideoCommentModel, t: Transactio
95 t.afterCommit(() => unicastTo(createActivity, byActor, comment.Video.VideoChannel.Account.Actor.sharedInboxUrl)) 103 t.afterCommit(() => unicastTo(createActivity, byActor, comment.Video.VideoChannel.Account.Actor.sharedInboxUrl))
96} 104}
97 105
98function buildCreateActivity (url: string, byActor: ActorModel, object: any, audience?: ActivityAudience): ActivityCreate { 106function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate {
99 if (!audience) audience = getAudience(byActor) 107 if (!audience) audience = getAudience(byActor)
100 108
101 return audiencify( 109 return audiencify(
@@ -122,8 +130,8 @@ export {
122// --------------------------------------------------------------------------- 130// ---------------------------------------------------------------------------
123 131
124async function sendVideoRelatedCreateActivity (options: { 132async function sendVideoRelatedCreateActivity (options: {
125 byActor: ActorModel, 133 byActor: MActorLight,
126 video: VideoModel, 134 video: MVideoAccountLight,
127 url: string, 135 url: string,
128 object: any, 136 object: any,
129 transaction?: Transaction 137 transaction?: Transaction
diff --git a/server/lib/activitypub/send/send-delete.ts b/server/lib/activitypub/send/send-delete.ts
index 6c7fb8449..4b1ff8dc5 100644
--- a/server/lib/activitypub/send/send-delete.ts
+++ b/server/lib/activitypub/send/send-delete.ts
@@ -1,17 +1,17 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAudience, ActivityDelete } from '../../../../shared/models/activitypub' 2import { ActivityAudience, ActivityDelete } from '../../../../shared/models/activitypub'
3import { ActorModel } from '../../../models/activitypub/actor' 3import { ActorModel } from '../../../models/activitypub/actor'
4import { VideoModel } from '../../../models/video/video'
5import { VideoCommentModel } from '../../../models/video/video-comment' 4import { VideoCommentModel } from '../../../models/video/video-comment'
6import { VideoShareModel } from '../../../models/video/video-share' 5import { VideoShareModel } from '../../../models/video/video-share'
7import { getDeleteActivityPubUrl } from '../url' 6import { getDeleteActivityPubUrl } from '../url'
8import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' 7import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils'
9import { audiencify, getActorsInvolvedInVideo, getVideoCommentAudience } from '../audience' 8import { audiencify, getActorsInvolvedInVideo, getVideoCommentAudience } from '../audience'
10import { logger } from '../../../helpers/logger' 9import { logger } from '../../../helpers/logger'
11import { VideoPlaylistModel } from '../../../models/video/video-playlist'
12import { getServerActor } from '../../../helpers/utils' 10import { getServerActor } from '../../../helpers/utils'
11import { MCommentOwnerVideoReply, MVideoAccountLight, MVideoPlaylistFullSummary } from '../../../typings/models/video'
12import { MActorUrl } from '../../../typings/models'
13 13
14async function sendDeleteVideo (video: VideoModel, transaction: Transaction) { 14async function sendDeleteVideo (video: MVideoAccountLight, transaction: Transaction) {
15 logger.info('Creating job to broadcast delete of video %s.', video.url) 15 logger.info('Creating job to broadcast delete of video %s.', video.url)
16 16
17 const byActor = video.VideoChannel.Account.Actor 17 const byActor = video.VideoChannel.Account.Actor
@@ -42,7 +42,7 @@ async function sendDeleteActor (byActor: ActorModel, t: Transaction) {
42 return broadcastToFollowers(activity, byActor, actorsInvolved, t) 42 return broadcastToFollowers(activity, byActor, actorsInvolved, t)
43} 43}
44 44
45async function sendDeleteVideoComment (videoComment: VideoCommentModel, t: Transaction) { 45async function sendDeleteVideoComment (videoComment: MCommentOwnerVideoReply, t: Transaction) {
46 logger.info('Creating job to send delete of comment %s.', videoComment.url) 46 logger.info('Creating job to send delete of comment %s.', videoComment.url)
47 47
48 const isVideoOrigin = videoComment.Video.isOwned() 48 const isVideoOrigin = videoComment.Video.isOwned()
@@ -74,7 +74,7 @@ async function sendDeleteVideoComment (videoComment: VideoCommentModel, t: Trans
74 t.afterCommit(() => unicastTo(activity, byActor, videoComment.Video.VideoChannel.Account.Actor.sharedInboxUrl)) 74 t.afterCommit(() => unicastTo(activity, byActor, videoComment.Video.VideoChannel.Account.Actor.sharedInboxUrl))
75} 75}
76 76
77async function sendDeleteVideoPlaylist (videoPlaylist: VideoPlaylistModel, t: Transaction) { 77async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary, t: Transaction) {
78 logger.info('Creating job to send delete of playlist %s.', videoPlaylist.url) 78 logger.info('Creating job to send delete of playlist %s.', videoPlaylist.url)
79 79
80 const byActor = videoPlaylist.OwnerAccount.Actor 80 const byActor = videoPlaylist.OwnerAccount.Actor
@@ -101,7 +101,7 @@ export {
101 101
102// --------------------------------------------------------------------------- 102// ---------------------------------------------------------------------------
103 103
104function buildDeleteActivity (url: string, object: string, byActor: ActorModel, audience?: ActivityAudience): ActivityDelete { 104function buildDeleteActivity (url: string, object: string, byActor: MActorUrl, audience?: ActivityAudience): ActivityDelete {
105 const activity = { 105 const activity = {
106 type: 'Delete' as 'Delete', 106 type: 'Delete' as 'Delete',
107 id: url, 107 id: url,
diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts
index a88436f2c..6e41f241f 100644
--- a/server/lib/activitypub/send/send-dislike.ts
+++ b/server/lib/activitypub/send/send-dislike.ts
@@ -1,13 +1,12 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActorModel } from '../../../models/activitypub/actor'
3import { VideoModel } from '../../../models/video/video'
4import { getVideoDislikeActivityPubUrl } from '../url' 2import { getVideoDislikeActivityPubUrl } from '../url'
5import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
6import { ActivityAudience, ActivityDislike } from '../../../../shared/models/activitypub' 4import { ActivityAudience, ActivityDislike } from '../../../../shared/models/activitypub'
7import { sendVideoRelatedActivity } from './utils' 5import { sendVideoRelatedActivity } from './utils'
8import { audiencify, getAudience } from '../audience' 6import { audiencify, getAudience } from '../audience'
7import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models'
9 8
10async function sendDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { 9async function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
11 logger.info('Creating job to dislike %s.', video.url) 10 logger.info('Creating job to dislike %s.', video.url)
12 11
13 const activityBuilder = (audience: ActivityAudience) => { 12 const activityBuilder = (audience: ActivityAudience) => {
@@ -19,7 +18,7 @@ async function sendDislike (byActor: ActorModel, video: VideoModel, t: Transacti
19 return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) 18 return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t })
20} 19}
21 20
22function buildDislikeActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityDislike { 21function buildDislikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityDislike {
23 if (!audience) audience = getAudience(byActor) 22 if (!audience) audience = getAudience(byActor)
24 23
25 return audiencify( 24 return audiencify(
diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts
index 61ee389a6..5ae1614ab 100644
--- a/server/lib/activitypub/send/send-flag.ts
+++ b/server/lib/activitypub/send/send-flag.ts
@@ -1,14 +1,13 @@
1import { ActorModel } from '../../../models/activitypub/actor'
2import { VideoModel } from '../../../models/video/video'
3import { VideoAbuseModel } from '../../../models/video/video-abuse'
4import { getVideoAbuseActivityPubUrl } from '../url' 1import { getVideoAbuseActivityPubUrl } from '../url'
5import { unicastTo } from './utils' 2import { unicastTo } from './utils'
6import { logger } from '../../../helpers/logger' 3import { logger } from '../../../helpers/logger'
7import { ActivityAudience, ActivityFlag } from '../../../../shared/models/activitypub' 4import { ActivityAudience, ActivityFlag } from '../../../../shared/models/activitypub'
8import { audiencify, getAudience } from '../audience' 5import { audiencify, getAudience } from '../audience'
9import { Transaction } from 'sequelize' 6import { Transaction } from 'sequelize'
7import { MActor, MVideoFullLight } from '../../../typings/models'
8import { MVideoAbuseVideo } from '../../../typings/models/video'
10 9
11async function sendVideoAbuse (byActor: ActorModel, videoAbuse: VideoAbuseModel, video: VideoModel, t: Transaction) { 10async function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) {
12 if (!video.VideoChannel.Account.Actor.serverId) return // Local user 11 if (!video.VideoChannel.Account.Actor.serverId) return // Local user
13 12
14 const url = getVideoAbuseActivityPubUrl(videoAbuse) 13 const url = getVideoAbuseActivityPubUrl(videoAbuse)
@@ -22,7 +21,7 @@ async function sendVideoAbuse (byActor: ActorModel, videoAbuse: VideoAbuseModel,
22 t.afterCommit(() => unicastTo(flagActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl)) 21 t.afterCommit(() => unicastTo(flagActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl))
23} 22}
24 23
25function buildFlagActivity (url: string, byActor: ActorModel, videoAbuse: VideoAbuseModel, audience: ActivityAudience): ActivityFlag { 24function buildFlagActivity (url: string, byActor: MActor, videoAbuse: MVideoAbuseVideo, audience: ActivityAudience): ActivityFlag {
26 if (!audience) audience = getAudience(byActor) 25 if (!audience) audience = getAudience(byActor)
27 26
28 const activity = Object.assign( 27 const activity = Object.assign(
diff --git a/server/lib/activitypub/send/send-follow.ts b/server/lib/activitypub/send/send-follow.ts
index a59ed50cf..6b17b25da 100644
--- a/server/lib/activitypub/send/send-follow.ts
+++ b/server/lib/activitypub/send/send-follow.ts
@@ -4,9 +4,9 @@ import { getActorFollowActivityPubUrl } from '../url'
4import { unicastTo } from './utils' 4import { unicastTo } from './utils'
5import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
6import { Transaction } from 'sequelize' 6import { Transaction } from 'sequelize'
7import { ActorModelOnly } from '../../../typings/models' 7import { MActor, MActorFollowActors } from '../../../typings/models'
8 8
9function sendFollow (actorFollow: ActorFollowModel, t: Transaction) { 9function sendFollow (actorFollow: MActorFollowActors, t: Transaction) {
10 const me = actorFollow.ActorFollower 10 const me = actorFollow.ActorFollower
11 const following = actorFollow.ActorFollowing 11 const following = actorFollow.ActorFollowing
12 12
@@ -21,7 +21,7 @@ function sendFollow (actorFollow: ActorFollowModel, t: Transaction) {
21 t.afterCommit(() => unicastTo(data, me, following.inboxUrl)) 21 t.afterCommit(() => unicastTo(data, me, following.inboxUrl))
22} 22}
23 23
24function buildFollowActivity (url: string, byActor: ActorModelOnly, targetActor: ActorModelOnly): ActivityFollow { 24function buildFollowActivity (url: string, byActor: MActor, targetActor: MActor): ActivityFollow {
25 return { 25 return {
26 type: 'Follow', 26 type: 'Follow',
27 id: url, 27 id: url,
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts
index 35227887a..e84a6f98b 100644
--- a/server/lib/activitypub/send/send-like.ts
+++ b/server/lib/activitypub/send/send-like.ts
@@ -1,13 +1,12 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAudience, ActivityLike } from '../../../../shared/models/activitypub' 2import { ActivityAudience, ActivityLike } from '../../../../shared/models/activitypub'
3import { ActorModel } from '../../../models/activitypub/actor'
4import { VideoModel } from '../../../models/video/video'
5import { getVideoLikeActivityPubUrl } from '../url' 3import { getVideoLikeActivityPubUrl } from '../url'
6import { sendVideoRelatedActivity } from './utils' 4import { sendVideoRelatedActivity } from './utils'
7import { audiencify, getAudience } from '../audience' 5import { audiencify, getAudience } from '../audience'
8import { logger } from '../../../helpers/logger' 6import { logger } from '../../../helpers/logger'
7import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models'
9 8
10async function sendLike (byActor: ActorModel, video: VideoModel, t: Transaction) { 9async function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
11 logger.info('Creating job to like %s.', video.url) 10 logger.info('Creating job to like %s.', video.url)
12 11
13 const activityBuilder = (audience: ActivityAudience) => { 12 const activityBuilder = (audience: ActivityAudience) => {
@@ -19,7 +18,7 @@ async function sendLike (byActor: ActorModel, video: VideoModel, t: Transaction)
19 return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) 18 return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t })
20} 19}
21 20
22function buildLikeActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityLike { 21function buildLikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityLike {
23 if (!audience) audience = getAudience(byActor) 22 if (!audience) audience = getAudience(byActor)
24 23
25 return audiencify( 24 return audiencify(
diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts
index 63110b433..4258a3c36 100644
--- a/server/lib/activitypub/send/send-reject.ts
+++ b/server/lib/activitypub/send/send-reject.ts
@@ -1,12 +1,11 @@
1import { ActivityFollow, ActivityReject } from '../../../../shared/models/activitypub' 1import { ActivityFollow, ActivityReject } from '../../../../shared/models/activitypub'
2import { ActorModel } from '../../../models/activitypub/actor'
3import { getActorFollowActivityPubUrl, getActorFollowRejectActivityPubUrl } from '../url' 2import { getActorFollowActivityPubUrl, getActorFollowRejectActivityPubUrl } from '../url'
4import { unicastTo } from './utils' 3import { unicastTo } from './utils'
5import { buildFollowActivity } from './send-follow' 4import { buildFollowActivity } from './send-follow'
6import { logger } from '../../../helpers/logger' 5import { logger } from '../../../helpers/logger'
7import { SignatureActorModel } from '../../../typings/models' 6import { MActor } from '../../../typings/models'
8 7
9async function sendReject (follower: SignatureActorModel, following: ActorModel) { 8async function sendReject (follower: MActor, following: MActor) {
10 if (!follower.serverId) { // This should never happen 9 if (!follower.serverId) { // This should never happen
11 logger.warn('Do not sending reject to local follower.') 10 logger.warn('Do not sending reject to local follower.')
12 return 11 return
@@ -31,7 +30,7 @@ export {
31 30
32// --------------------------------------------------------------------------- 31// ---------------------------------------------------------------------------
33 32
34function buildRejectActivity (url: string, byActor: ActorModel, followActivityData: ActivityFollow): ActivityReject { 33function buildRejectActivity (url: string, byActor: MActor, followActivityData: ActivityFollow): ActivityReject {
35 return { 34 return {
36 type: 'Reject', 35 type: 'Reject',
37 id: url, 36 id: url,
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts
index 8fcbbac5c..e9ab5b3c5 100644
--- a/server/lib/activitypub/send/send-undo.ts
+++ b/server/lib/activitypub/send/send-undo.ts
@@ -2,13 +2,12 @@ import { Transaction } from 'sequelize'
2import { 2import {
3 ActivityAnnounce, 3 ActivityAnnounce,
4 ActivityAudience, 4 ActivityAudience,
5 ActivityCreate, ActivityDislike, 5 ActivityCreate,
6 ActivityDislike,
6 ActivityFollow, 7 ActivityFollow,
7 ActivityLike, 8 ActivityLike,
8 ActivityUndo 9 ActivityUndo
9} from '../../../../shared/models/activitypub' 10} from '../../../../shared/models/activitypub'
10import { ActorModel } from '../../../models/activitypub/actor'
11import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
12import { VideoModel } from '../../../models/video/video' 11import { VideoModel } from '../../../models/video/video'
13import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' 12import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url'
14import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' 13import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils'
@@ -16,13 +15,20 @@ import { audiencify, getAudience } from '../audience'
16import { buildCreateActivity } from './send-create' 15import { buildCreateActivity } from './send-create'
17import { buildFollowActivity } from './send-follow' 16import { buildFollowActivity } from './send-follow'
18import { buildLikeActivity } from './send-like' 17import { buildLikeActivity } from './send-like'
19import { VideoShareModel } from '../../../models/video/video-share'
20import { buildAnnounceWithVideoAudience } from './send-announce' 18import { buildAnnounceWithVideoAudience } from './send-announce'
21import { logger } from '../../../helpers/logger' 19import { logger } from '../../../helpers/logger'
22import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
23import { buildDislikeActivity } from './send-dislike' 20import { buildDislikeActivity } from './send-dislike'
24 21import {
25async function sendUndoFollow (actorFollow: ActorFollowModel, t: Transaction) { 22 MActor, MActorAudience,
23 MActorFollowActors,
24 MActorLight,
25 MVideo,
26 MVideoAccountLight,
27 MVideoRedundancyVideo,
28 MVideoShare
29} from '../../../typings/models'
30
31async function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) {
26 const me = actorFollow.ActorFollower 32 const me = actorFollow.ActorFollower
27 const following = actorFollow.ActorFollowing 33 const following = actorFollow.ActorFollowing
28 34
@@ -40,7 +46,7 @@ async function sendUndoFollow (actorFollow: ActorFollowModel, t: Transaction) {
40 t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl)) 46 t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl))
41} 47}
42 48
43async function sendUndoAnnounce (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { 49async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) {
44 logger.info('Creating job to undo announce %s.', videoShare.url) 50 logger.info('Creating job to undo announce %s.', videoShare.url)
45 51
46 const undoUrl = getUndoActivityPubUrl(videoShare.url) 52 const undoUrl = getUndoActivityPubUrl(videoShare.url)
@@ -52,7 +58,7 @@ async function sendUndoAnnounce (byActor: ActorModel, videoShare: VideoShareMode
52 return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) 58 return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException)
53} 59}
54 60
55async function sendUndoLike (byActor: ActorModel, video: VideoModel, t: Transaction) { 61async function sendUndoLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
56 logger.info('Creating job to undo a like of video %s.', video.url) 62 logger.info('Creating job to undo a like of video %s.', video.url)
57 63
58 const likeUrl = getVideoLikeActivityPubUrl(byActor, video) 64 const likeUrl = getVideoLikeActivityPubUrl(byActor, video)
@@ -61,7 +67,7 @@ async function sendUndoLike (byActor: ActorModel, video: VideoModel, t: Transact
61 return sendUndoVideoRelatedActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t }) 67 return sendUndoVideoRelatedActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t })
62} 68}
63 69
64async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { 70async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) {
65 logger.info('Creating job to undo a dislike of video %s.', video.url) 71 logger.info('Creating job to undo a dislike of video %s.', video.url)
66 72
67 const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video) 73 const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video)
@@ -70,7 +76,7 @@ async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Trans
70 return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t }) 76 return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t })
71} 77}
72 78
73async function sendUndoCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel, t: Transaction) { 79async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedundancyVideo, t: Transaction) {
74 logger.info('Creating job to undo cache file %s.', redundancyModel.url) 80 logger.info('Creating job to undo cache file %s.', redundancyModel.url)
75 81
76 const videoId = redundancyModel.getVideo().id 82 const videoId = redundancyModel.getVideo().id
@@ -94,7 +100,7 @@ export {
94 100
95function undoActivityData ( 101function undoActivityData (
96 url: string, 102 url: string,
97 byActor: ActorModel, 103 byActor: MActorAudience,
98 object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, 104 object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce,
99 audience?: ActivityAudience 105 audience?: ActivityAudience
100): ActivityUndo { 106): ActivityUndo {
@@ -112,8 +118,8 @@ function undoActivityData (
112} 118}
113 119
114async function sendUndoVideoRelatedActivity (options: { 120async function sendUndoVideoRelatedActivity (options: {
115 byActor: ActorModel, 121 byActor: MActor,
116 video: VideoModel, 122 video: MVideoAccountLight,
117 url: string, 123 url: string,
118 activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, 124 activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce,
119 transaction: Transaction 125 transaction: Transaction
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts
index 5bf092894..3a5cc1853 100644
--- a/server/lib/activitypub/send/send-update.ts
+++ b/server/lib/activitypub/send/send-update.ts
@@ -2,21 +2,29 @@ import { Transaction } from 'sequelize'
2import { ActivityAudience, ActivityUpdate } from '../../../../shared/models/activitypub' 2import { ActivityAudience, ActivityUpdate } from '../../../../shared/models/activitypub'
3import { VideoPrivacy } from '../../../../shared/models/videos' 3import { VideoPrivacy } from '../../../../shared/models/videos'
4import { AccountModel } from '../../../models/account/account' 4import { AccountModel } from '../../../models/account/account'
5import { ActorModel } from '../../../models/activitypub/actor'
6import { VideoModel } from '../../../models/video/video' 5import { VideoModel } from '../../../models/video/video'
7import { VideoChannelModel } from '../../../models/video/video-channel'
8import { VideoShareModel } from '../../../models/video/video-share' 6import { VideoShareModel } from '../../../models/video/video-share'
9import { getUpdateActivityPubUrl } from '../url' 7import { getUpdateActivityPubUrl } from '../url'
10import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' 8import { broadcastToFollowers, sendVideoRelatedActivity } from './utils'
11import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' 9import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience'
12import { logger } from '../../../helpers/logger' 10import { logger } from '../../../helpers/logger'
13import { VideoCaptionModel } from '../../../models/video/video-caption' 11import { VideoCaptionModel } from '../../../models/video/video-caption'
14import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy'
15import { VideoPlaylistModel } from '../../../models/video/video-playlist'
16import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' 12import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
17import { getServerActor } from '../../../helpers/utils' 13import { getServerActor } from '../../../helpers/utils'
14import {
15 MAccountActor,
16 MActor,
17 MActorLight,
18 MChannelActor,
19 MVideoAP,
20 MVideoAPWithoutCaption,
21 MVideoPlaylistFull,
22 MVideoRedundancyVideo
23} from '../../../typings/models'
24
25async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction, overrodeByActor?: MActor) {
26 const video = videoArg as MVideoAP
18 27
19async function sendUpdateVideo (video: VideoModel, t: Transaction, overrodeByActor?: ActorModel) {
20 if (video.privacy === VideoPrivacy.PRIVATE) return undefined 28 if (video.privacy === VideoPrivacy.PRIVATE) return undefined
21 29
22 logger.info('Creating job to update video %s.', video.url) 30 logger.info('Creating job to update video %s.', video.url)
@@ -41,7 +49,7 @@ async function sendUpdateVideo (video: VideoModel, t: Transaction, overrodeByAct
41 return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) 49 return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t)
42} 50}
43 51
44async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelModel, t: Transaction) { 52async function sendUpdateActor (accountOrChannel: MAccountActor | MChannelActor, t: Transaction) {
45 const byActor = accountOrChannel.Actor 53 const byActor = accountOrChannel.Actor
46 54
47 logger.info('Creating job to update actor %s.', byActor.url) 55 logger.info('Creating job to update actor %s.', byActor.url)
@@ -51,7 +59,7 @@ async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelMod
51 const audience = getAudience(byActor) 59 const audience = getAudience(byActor)
52 const updateActivity = buildUpdateActivity(url, byActor, accountOrChannelObject, audience) 60 const updateActivity = buildUpdateActivity(url, byActor, accountOrChannelObject, audience)
53 61
54 let actorsInvolved: ActorModel[] 62 let actorsInvolved: MActor[]
55 if (accountOrChannel instanceof AccountModel) { 63 if (accountOrChannel instanceof AccountModel) {
56 // Actors that shared my videos are involved too 64 // Actors that shared my videos are involved too
57 actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t) 65 actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t)
@@ -65,7 +73,7 @@ async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelMod
65 return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) 73 return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t)
66} 74}
67 75
68async function sendUpdateCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel) { 76async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVideoRedundancyVideo) {
69 logger.info('Creating job to update cache file %s.', redundancyModel.url) 77 logger.info('Creating job to update cache file %s.', redundancyModel.url)
70 78
71 const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.getVideo().id) 79 const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.getVideo().id)
@@ -80,7 +88,7 @@ async function sendUpdateCacheFile (byActor: ActorModel, redundancyModel: VideoR
80 return sendVideoRelatedActivity(activityBuilder, { byActor, video }) 88 return sendVideoRelatedActivity(activityBuilder, { byActor, video })
81} 89}
82 90
83async function sendUpdateVideoPlaylist (videoPlaylist: VideoPlaylistModel, t: Transaction) { 91async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Transaction) {
84 if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined 92 if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined
85 93
86 const byActor = videoPlaylist.OwnerAccount.Actor 94 const byActor = videoPlaylist.OwnerAccount.Actor
@@ -113,7 +121,7 @@ export {
113 121
114// --------------------------------------------------------------------------- 122// ---------------------------------------------------------------------------
115 123
116function buildUpdateActivity (url: string, byActor: ActorModel, object: any, audience?: ActivityAudience): ActivityUpdate { 124function buildUpdateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityUpdate {
117 if (!audience) audience = getAudience(byActor) 125 if (!audience) audience = getAudience(byActor)
118 126
119 return audiencify( 127 return audiencify(
@@ -121,8 +129,7 @@ function buildUpdateActivity (url: string, byActor: ActorModel, object: any, aud
121 type: 'Update' as 'Update', 129 type: 'Update' as 'Update',
122 id: url, 130 id: url,
123 actor: byActor.url, 131 actor: byActor.url,
124 object: audiencify(object, audience 132 object: audiencify(object, audience)
125 )
126 }, 133 },
127 audience 134 audience
128 ) 135 )
diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts
index 8ad126be0..8809417f9 100644
--- a/server/lib/activitypub/send/send-view.ts
+++ b/server/lib/activitypub/send/send-view.ts
@@ -1,13 +1,13 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub' 2import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub'
3import { ActorModel } from '../../../models/activitypub/actor' 3import { ActorModel } from '../../../models/activitypub/actor'
4import { VideoModel } from '../../../models/video/video'
5import { getVideoLikeActivityPubUrl } from '../url' 4import { getVideoLikeActivityPubUrl } from '../url'
6import { sendVideoRelatedActivity } from './utils' 5import { sendVideoRelatedActivity } from './utils'
7import { audiencify, getAudience } from '../audience' 6import { audiencify, getAudience } from '../audience'
8import { logger } from '../../../helpers/logger' 7import { logger } from '../../../helpers/logger'
8import { MActorAudience, MVideoAccountLight, MVideoUrl } from '@server/typings/models'
9 9
10async function sendView (byActor: ActorModel, video: VideoModel, t: Transaction) { 10async function sendView (byActor: ActorModel, video: MVideoAccountLight, t: Transaction) {
11 logger.info('Creating job to send view of %s.', video.url) 11 logger.info('Creating job to send view of %s.', video.url)
12 12
13 const activityBuilder = (audience: ActivityAudience) => { 13 const activityBuilder = (audience: ActivityAudience) => {
@@ -19,7 +19,7 @@ async function sendView (byActor: ActorModel, video: VideoModel, t: Transaction)
19 return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) 19 return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t })
20} 20}
21 21
22function buildViewActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityView { 22function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView {
23 if (!audience) audience = getAudience(byActor) 23 if (!audience) audience = getAudience(byActor)
24 24
25 return audiencify( 25 return audiencify(
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts
index 4f69afb00..8129ab32a 100644
--- a/server/lib/activitypub/send/utils.ts
+++ b/server/lib/activitypub/send/utils.ts
@@ -4,15 +4,14 @@ import { logger } from '../../../helpers/logger'
4import { ActorModel } from '../../../models/activitypub/actor' 4import { ActorModel } from '../../../models/activitypub/actor'
5import { ActorFollowModel } from '../../../models/activitypub/actor-follow' 5import { ActorFollowModel } from '../../../models/activitypub/actor-follow'
6import { JobQueue } from '../../job-queue' 6import { JobQueue } from '../../job-queue'
7import { VideoModel } from '../../../models/video/video'
8import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' 7import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience'
9import { getServerActor } from '../../../helpers/utils' 8import { getServerActor } from '../../../helpers/utils'
10import { afterCommitIfTransaction } from '../../../helpers/database-utils' 9import { afterCommitIfTransaction } from '../../../helpers/database-utils'
11import { ActorFollowerException, ActorModelId, ActorModelOnly } from '../../../typings/models' 10import { MActorFollowerException, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models'
12 11
13async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { 12async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: {
14 byActor: ActorModelOnly, 13 byActor: MActorLight,
15 video: VideoModel, 14 video: MVideoAccountLight,
16 transaction?: Transaction 15 transaction?: Transaction
17}) { 16}) {
18 const { byActor, video, transaction } = options 17 const { byActor, video, transaction } = options
@@ -41,8 +40,8 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud
41async function forwardVideoRelatedActivity ( 40async function forwardVideoRelatedActivity (
42 activity: Activity, 41 activity: Activity,
43 t: Transaction, 42 t: Transaction,
44 followersException: ActorFollowerException[] = [], 43 followersException: MActorFollowerException[] = [],
45 video: VideoModel 44 video: MVideo
46) { 45) {
47 // Mastodon does not add our announces in audience, so we forward to them manually 46 // Mastodon does not add our announces in audience, so we forward to them manually
48 const additionalActors = await getActorsInvolvedInVideo(video, t) 47 const additionalActors = await getActorsInvolvedInVideo(video, t)
@@ -54,7 +53,7 @@ async function forwardVideoRelatedActivity (
54async function forwardActivity ( 53async function forwardActivity (
55 activity: Activity, 54 activity: Activity,
56 t: Transaction, 55 t: Transaction,
57 followersException: ActorFollowerException[] = [], 56 followersException: MActorFollowerException[] = [],
58 additionalFollowerUrls: string[] = [] 57 additionalFollowerUrls: string[] = []
59) { 58) {
60 logger.info('Forwarding activity %s.', activity.id) 59 logger.info('Forwarding activity %s.', activity.id)
@@ -88,10 +87,10 @@ async function forwardActivity (
88 87
89async function broadcastToFollowers ( 88async function broadcastToFollowers (
90 data: any, 89 data: any,
91 byActor: ActorModelId, 90 byActor: MActorId,
92 toFollowersOf: ActorModelId[], 91 toFollowersOf: MActorId[],
93 t: Transaction, 92 t: Transaction,
94 actorsException: ActorFollowerException[] = [] 93 actorsException: MActorFollowerException[] = []
95) { 94) {
96 const uris = await computeFollowerUris(toFollowersOf, actorsException, t) 95 const uris = await computeFollowerUris(toFollowersOf, actorsException, t)
97 96
@@ -100,16 +99,16 @@ async function broadcastToFollowers (
100 99
101async function broadcastToActors ( 100async function broadcastToActors (
102 data: any, 101 data: any,
103 byActor: ActorModelId, 102 byActor: MActorId,
104 toActors: ActorModelOnly[], 103 toActors: MActor[],
105 t?: Transaction, 104 t?: Transaction,
106 actorsException: ActorFollowerException[] = [] 105 actorsException: MActorFollowerException[] = []
107) { 106) {
108 const uris = await computeUris(toActors, actorsException) 107 const uris = await computeUris(toActors, actorsException)
109 return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) 108 return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor))
110} 109}
111 110
112function broadcastTo (uris: string[], data: any, byActor: ActorModelId) { 111function broadcastTo (uris: string[], data: any, byActor: MActorId) {
113 if (uris.length === 0) return undefined 112 if (uris.length === 0) return undefined
114 113
115 logger.debug('Creating broadcast job.', { uris }) 114 logger.debug('Creating broadcast job.', { uris })
@@ -123,7 +122,7 @@ function broadcastTo (uris: string[], data: any, byActor: ActorModelId) {
123 return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) 122 return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload })
124} 123}
125 124
126function unicastTo (data: any, byActor: ActorModelId, toActorUrl: string) { 125function unicastTo (data: any, byActor: MActorId, toActorUrl: string) {
127 logger.debug('Creating unicast job.', { uri: toActorUrl }) 126 logger.debug('Creating unicast job.', { uri: toActorUrl })
128 127
129 const payload = { 128 const payload = {
@@ -148,7 +147,7 @@ export {
148 147
149// --------------------------------------------------------------------------- 148// ---------------------------------------------------------------------------
150 149
151async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsException: ActorFollowerException[], t: Transaction) { 150async function computeFollowerUris (toFollowersOf: MActorId[], actorsException: MActorFollowerException[], t: Transaction) {
152 const toActorFollowerIds = toFollowersOf.map(a => a.id) 151 const toActorFollowerIds = toFollowersOf.map(a => a.id)
153 152
154 const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t) 153 const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t)
@@ -157,7 +156,7 @@ async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsExcepti
157 return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) 156 return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
158} 157}
159 158
160async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFollowerException[] = []) { 159async function computeUris (toActors: MActor[], actorsException: MActorFollowerException[] = []) {
161 const serverActor = await getServerActor() 160 const serverActor = await getServerActor()
162 const targetUrls = toActors 161 const targetUrls = toActors
163 .filter(a => a.id !== serverActor.id) // Don't send to ourselves 162 .filter(a => a.id !== serverActor.id) // Don't send to ourselves
@@ -170,7 +169,7 @@ async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFo
170 .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) 169 .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1)
171} 170}
172 171
173async function buildSharedInboxesException (actorsException: ActorFollowerException[]) { 172async function buildSharedInboxesException (actorsException: MActorFollowerException[]) {
174 const serverActor = await getServerActor() 173 const serverActor = await getServerActor()
175 174
176 return actorsException 175 return actorsException
diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts
index 7f38402b6..fdca9bed7 100644
--- a/server/lib/activitypub/share.ts
+++ b/server/lib/activitypub/share.ts
@@ -1,19 +1,18 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { VideoPrivacy } from '../../../shared/models/videos' 2import { VideoPrivacy } from '../../../shared/models/videos'
3import { getServerActor } from '../../helpers/utils' 3import { getServerActor } from '../../helpers/utils'
4import { VideoModel } from '../../models/video/video'
5import { VideoShareModel } from '../../models/video/video-share' 4import { VideoShareModel } from '../../models/video/video-share'
6import { sendUndoAnnounce, sendVideoAnnounce } from './send' 5import { sendUndoAnnounce, sendVideoAnnounce } from './send'
7import { getVideoAnnounceActivityPubUrl } from './url' 6import { getVideoAnnounceActivityPubUrl } from './url'
8import { VideoChannelModel } from '../../models/video/video-channel'
9import * as Bluebird from 'bluebird' 7import * as Bluebird from 'bluebird'
10import { doRequest } from '../../helpers/requests' 8import { doRequest } from '../../helpers/requests'
11import { getOrCreateActorAndServerAndModel } from './actor' 9import { getOrCreateActorAndServerAndModel } from './actor'
12import { logger } from '../../helpers/logger' 10import { logger } from '../../helpers/logger'
13import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 11import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
14import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 12import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
13import { MChannelActor, MChannelActorLight, MVideo, MVideoAccountLight, MVideoId } from '../../typings/models/video'
15 14
16async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) { 15async function shareVideoByServerAndChannel (video: MVideoAccountLight, t: Transaction) {
17 if (video.privacy === VideoPrivacy.PRIVATE) return undefined 16 if (video.privacy === VideoPrivacy.PRIVATE) return undefined
18 17
19 return Promise.all([ 18 return Promise.all([
@@ -22,7 +21,11 @@ async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction)
22 ]) 21 ])
23} 22}
24 23
25async function changeVideoChannelShare (video: VideoModel, oldVideoChannel: VideoChannelModel, t: Transaction) { 24async function changeVideoChannelShare (
25 video: MVideoAccountLight,
26 oldVideoChannel: MChannelActorLight,
27 t: Transaction
28) {
26 logger.info('Updating video channel of video %s: %s -> %s.', video.uuid, oldVideoChannel.name, video.VideoChannel.name) 29 logger.info('Updating video channel of video %s: %s -> %s.', video.uuid, oldVideoChannel.name, video.VideoChannel.name)
27 30
28 await undoShareByVideoChannel(video, oldVideoChannel, t) 31 await undoShareByVideoChannel(video, oldVideoChannel, t)
@@ -30,7 +33,7 @@ async function changeVideoChannelShare (video: VideoModel, oldVideoChannel: Vide
30 await shareByVideoChannel(video, t) 33 await shareByVideoChannel(video, t)
31} 34}
32 35
33async function addVideoShares (shareUrls: string[], instance: VideoModel) { 36async function addVideoShares (shareUrls: string[], video: MVideoId) {
34 await Bluebird.map(shareUrls, async shareUrl => { 37 await Bluebird.map(shareUrls, async shareUrl => {
35 try { 38 try {
36 // Fetch url 39 // Fetch url
@@ -50,7 +53,7 @@ async function addVideoShares (shareUrls: string[], instance: VideoModel) {
50 53
51 const entry = { 54 const entry = {
52 actorId: actor.id, 55 actorId: actor.id,
53 videoId: instance.id, 56 videoId: video.id,
54 url: shareUrl 57 url: shareUrl
55 } 58 }
56 59
@@ -69,7 +72,7 @@ export {
69 72
70// --------------------------------------------------------------------------- 73// ---------------------------------------------------------------------------
71 74
72async function shareByServer (video: VideoModel, t: Transaction) { 75async function shareByServer (video: MVideo, t: Transaction) {
73 const serverActor = await getServerActor() 76 const serverActor = await getServerActor()
74 77
75 const serverShareUrl = getVideoAnnounceActivityPubUrl(serverActor, video) 78 const serverShareUrl = getVideoAnnounceActivityPubUrl(serverActor, video)
@@ -88,7 +91,7 @@ async function shareByServer (video: VideoModel, t: Transaction) {
88 return sendVideoAnnounce(serverActor, serverShare, video, t) 91 return sendVideoAnnounce(serverActor, serverShare, video, t)
89} 92}
90 93
91async function shareByVideoChannel (video: VideoModel, t: Transaction) { 94async function shareByVideoChannel (video: MVideoAccountLight, t: Transaction) {
92 const videoChannelShareUrl = getVideoAnnounceActivityPubUrl(video.VideoChannel.Actor, video) 95 const videoChannelShareUrl = getVideoAnnounceActivityPubUrl(video.VideoChannel.Actor, video)
93 const [ videoChannelShare ] = await VideoShareModel.findOrCreate({ 96 const [ videoChannelShare ] = await VideoShareModel.findOrCreate({
94 defaults: { 97 defaults: {
@@ -105,7 +108,7 @@ async function shareByVideoChannel (video: VideoModel, t: Transaction) {
105 return sendVideoAnnounce(video.VideoChannel.Actor, videoChannelShare, video, t) 108 return sendVideoAnnounce(video.VideoChannel.Actor, videoChannelShare, video, t)
106} 109}
107 110
108async function undoShareByVideoChannel (video: VideoModel, oldVideoChannel: VideoChannelModel, t: Transaction) { 111async function undoShareByVideoChannel (video: MVideo, oldVideoChannel: MChannelActorLight, t: Transaction) {
109 // Load old share 112 // Load old share
110 const oldShare = await VideoShareModel.load(oldVideoChannel.actorId, video.id, t) 113 const oldShare = await VideoShareModel.load(oldVideoChannel.actorId, video.id, t)
111 if (!oldShare) return new Error('Cannot find old video channel share ' + oldVideoChannel.actorId + ' for video ' + video.id) 114 if (!oldShare) return new Error('Cannot find old video channel share ' + oldVideoChannel.actorId + ' for video ' + video.id)
diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts
index dfcb3c668..6290af34b 100644
--- a/server/lib/activitypub/url.ts
+++ b/server/lib/activitypub/url.ts
@@ -1,36 +1,42 @@
1import { WEBSERVER } from '../../initializers/constants' 1import { WEBSERVER } from '../../initializers/constants'
2import { VideoModel } from '../../models/video/video' 2import {
3import { VideoAbuseModel } from '../../models/video/video-abuse' 3 MActor,
4import { VideoCommentModel } from '../../models/video/video-comment' 4 MActorFollowActors,
5import { VideoFileModel } from '../../models/video/video-file' 5 MActorId,
6import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' 6 MActorUrl,
7import { VideoPlaylistModel } from '../../models/video/video-playlist' 7 MCommentId,
8import { ActorModelOnly, ActorModelUrl } from '../../typings/models' 8 MVideoAbuseId,
9import { ActorFollowModelLight } from '../../typings/models/actor-follow' 9 MVideoId,
10 10 MVideoUrl,
11function getVideoActivityPubUrl (video: VideoModel) { 11 MVideoUUID
12} from '../../typings/models'
13import { MVideoPlaylist, MVideoPlaylistUUID } from '../../typings/models/video/video-playlist'
14import { MVideoFileVideoUUID } from '../../typings/models/video/video-file'
15import { MStreamingPlaylist } from '../../typings/models/video/video-streaming-playlist'
16
17function getVideoActivityPubUrl (video: MVideoUUID) {
12 return WEBSERVER.URL + '/videos/watch/' + video.uuid 18 return WEBSERVER.URL + '/videos/watch/' + video.uuid
13} 19}
14 20
15function getVideoPlaylistActivityPubUrl (videoPlaylist: VideoPlaylistModel) { 21function getVideoPlaylistActivityPubUrl (videoPlaylist: MVideoPlaylist) {
16 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid 22 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid
17} 23}
18 24
19function getVideoPlaylistElementActivityPubUrl (videoPlaylist: VideoPlaylistModel, video: VideoModel) { 25function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, video: MVideoUUID) {
20 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/' + video.uuid 26 return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/' + video.uuid
21} 27}
22 28
23function getVideoCacheFileActivityPubUrl (videoFile: VideoFileModel) { 29function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) {
24 const suffixFPS = videoFile.fps && videoFile.fps !== -1 ? '-' + videoFile.fps : '' 30 const suffixFPS = videoFile.fps && videoFile.fps !== -1 ? '-' + videoFile.fps : ''
25 31
26 return `${WEBSERVER.URL}/redundancy/videos/${videoFile.Video.uuid}/${videoFile.resolution}${suffixFPS}` 32 return `${WEBSERVER.URL}/redundancy/videos/${videoFile.Video.uuid}/${videoFile.resolution}${suffixFPS}`
27} 33}
28 34
29function getVideoCacheStreamingPlaylistActivityPubUrl (video: VideoModel, playlist: VideoStreamingPlaylistModel) { 35function getVideoCacheStreamingPlaylistActivityPubUrl (video: MVideoUUID, playlist: MStreamingPlaylist) {
30 return `${WEBSERVER.URL}/redundancy/streaming-playlists/${playlist.getStringType()}/${video.uuid}` 36 return `${WEBSERVER.URL}/redundancy/streaming-playlists/${playlist.getStringType()}/${video.uuid}`
31} 37}
32 38
33function getVideoCommentActivityPubUrl (video: VideoModel, videoComment: VideoCommentModel) { 39function getVideoCommentActivityPubUrl (video: MVideoUUID, videoComment: MCommentId) {
34 return WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id 40 return WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id
35} 41}
36 42
@@ -42,54 +48,54 @@ function getAccountActivityPubUrl (accountName: string) {
42 return WEBSERVER.URL + '/accounts/' + accountName 48 return WEBSERVER.URL + '/accounts/' + accountName
43} 49}
44 50
45function getVideoAbuseActivityPubUrl (videoAbuse: VideoAbuseModel) { 51function getVideoAbuseActivityPubUrl (videoAbuse: MVideoAbuseId) {
46 return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id 52 return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id
47} 53}
48 54
49function getVideoViewActivityPubUrl (byActor: ActorModelUrl, video: VideoModel) { 55function getVideoViewActivityPubUrl (byActor: MActorUrl, video: MVideoId) {
50 return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString() 56 return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString()
51} 57}
52 58
53function getVideoLikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) { 59function getVideoLikeActivityPubUrl (byActor: MActorUrl, video: MVideoId) {
54 return byActor.url + '/likes/' + video.id 60 return byActor.url + '/likes/' + video.id
55} 61}
56 62
57function getVideoDislikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) { 63function getVideoDislikeActivityPubUrl (byActor: MActorUrl, video: MVideoId) {
58 return byActor.url + '/dislikes/' + video.id 64 return byActor.url + '/dislikes/' + video.id
59} 65}
60 66
61function getVideoSharesActivityPubUrl (video: VideoModel) { 67function getVideoSharesActivityPubUrl (video: MVideoUrl) {
62 return video.url + '/announces' 68 return video.url + '/announces'
63} 69}
64 70
65function getVideoCommentsActivityPubUrl (video: VideoModel) { 71function getVideoCommentsActivityPubUrl (video: MVideoUrl) {
66 return video.url + '/comments' 72 return video.url + '/comments'
67} 73}
68 74
69function getVideoLikesActivityPubUrl (video: VideoModel) { 75function getVideoLikesActivityPubUrl (video: MVideoUrl) {
70 return video.url + '/likes' 76 return video.url + '/likes'
71} 77}
72 78
73function getVideoDislikesActivityPubUrl (video: VideoModel) { 79function getVideoDislikesActivityPubUrl (video: MVideoUrl) {
74 return video.url + '/dislikes' 80 return video.url + '/dislikes'
75} 81}
76 82
77function getActorFollowActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) { 83function getActorFollowActivityPubUrl (follower: MActor, following: MActorId) {
78 return follower.url + '/follows/' + following.id 84 return follower.url + '/follows/' + following.id
79} 85}
80 86
81function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModelLight) { 87function getActorFollowAcceptActivityPubUrl (actorFollow: MActorFollowActors) {
82 const follower = actorFollow.ActorFollower 88 const follower = actorFollow.ActorFollower
83 const me = actorFollow.ActorFollowing 89 const me = actorFollow.ActorFollowing
84 90
85 return follower.url + '/accepts/follows/' + me.id 91 return follower.url + '/accepts/follows/' + me.id
86} 92}
87 93
88function getActorFollowRejectActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) { 94function getActorFollowRejectActivityPubUrl (follower: MActorUrl, following: MActorId) {
89 return follower.url + '/rejects/follows/' + following.id 95 return follower.url + '/rejects/follows/' + following.id
90} 96}
91 97
92function getVideoAnnounceActivityPubUrl (byActor: ActorModelOnly, video: VideoModel) { 98function getVideoAnnounceActivityPubUrl (byActor: MActorId, video: MVideoUrl) {
93 return video.url + '/announces/' + byActor.id 99 return video.url + '/announces/' + byActor.id
94} 100}
95 101
diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts
index 8d2c1ade3..375ac0aad 100644
--- a/server/lib/activitypub/video-comments.ts
+++ b/server/lib/activitypub/video-comments.ts
@@ -2,20 +2,20 @@ import { sanitizeAndCheckVideoCommentObject } from '../../helpers/custom-validat
2import { logger } from '../../helpers/logger' 2import { logger } from '../../helpers/logger'
3import { doRequest } from '../../helpers/requests' 3import { doRequest } from '../../helpers/requests'
4import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 4import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
5import { VideoModel } from '../../models/video/video'
6import { VideoCommentModel } from '../../models/video/video-comment' 5import { VideoCommentModel } from '../../models/video/video-comment'
7import { getOrCreateActorAndServerAndModel } from './actor' 6import { getOrCreateActorAndServerAndModel } from './actor'
8import { getOrCreateVideoAndAccountAndChannel } from './videos' 7import { getOrCreateVideoAndAccountAndChannel } from './videos'
9import * as Bluebird from 'bluebird' 8import * as Bluebird from 'bluebird'
10import { checkUrlsSameHost } from '../../helpers/activitypub' 9import { checkUrlsSameHost } from '../../helpers/activitypub'
10import { MCommentOwner, MCommentOwnerVideo, MVideoAccountAllFiles } from '../../typings/models/video'
11 11
12type ResolveThreadParams = { 12type ResolveThreadParams = {
13 url: string, 13 url: string,
14 comments?: VideoCommentModel[], 14 comments?: MCommentOwner[],
15 isVideo?: boolean, 15 isVideo?: boolean,
16 commentCreated?: boolean 16 commentCreated?: boolean
17} 17}
18type ResolveThreadResult = Promise<{ video: VideoModel, comment: VideoCommentModel, commentCreated: boolean }> 18type ResolveThreadResult = Promise<{ video: MVideoAccountAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }>
19 19
20async function addVideoComments (commentUrls: string[]) { 20async function addVideoComments (commentUrls: string[]) {
21 return Bluebird.map(commentUrls, commentUrl => { 21 return Bluebird.map(commentUrls, commentUrl => {
@@ -85,9 +85,9 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) {
85 const syncParam = { likes: true, dislikes: true, shares: true, comments: false, thumbnail: true, refreshVideo: false } 85 const syncParam = { likes: true, dislikes: true, shares: true, comments: false, thumbnail: true, refreshVideo: false }
86 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: url, syncParam }) 86 const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: url, syncParam })
87 87
88 let resultComment: VideoCommentModel 88 let resultComment: MCommentOwnerVideo
89 if (comments.length !== 0) { 89 if (comments.length !== 0) {
90 const firstReply = comments[ comments.length - 1 ] 90 const firstReply = comments[ comments.length - 1 ] as MCommentOwnerVideo
91 firstReply.inReplyToCommentId = null 91 firstReply.inReplyToCommentId = null
92 firstReply.originCommentId = null 92 firstReply.originCommentId = null
93 firstReply.videoId = video.id 93 firstReply.videoId = video.id
@@ -97,7 +97,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) {
97 comments[comments.length - 1] = await firstReply.save() 97 comments[comments.length - 1] = await firstReply.save()
98 98
99 for (let i = comments.length - 2; i >= 0; i--) { 99 for (let i = comments.length - 2; i >= 0; i--) {
100 const comment = comments[ i ] 100 const comment = comments[ i ] as MCommentOwnerVideo
101 comment.originCommentId = firstReply.id 101 comment.originCommentId = firstReply.id
102 comment.inReplyToCommentId = comments[ i + 1 ].id 102 comment.inReplyToCommentId = comments[ i + 1 ].id
103 comment.videoId = video.id 103 comment.videoId = video.id
@@ -107,7 +107,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) {
107 comments[i] = await comment.save() 107 comments[i] = await comment.save()
108 } 108 }
109 109
110 resultComment = comments[0] 110 resultComment = comments[0] as MCommentOwnerVideo
111 } 111 }
112 112
113 return { video, comment: resultComment, commentCreated } 113 return { video, comment: resultComment, commentCreated }
@@ -151,7 +151,7 @@ async function resolveParentComment (params: ResolveThreadParams) {
151 originCommentId: null, 151 originCommentId: null,
152 createdAt: new Date(body.published), 152 createdAt: new Date(body.published),
153 updatedAt: new Date(body.updated) 153 updatedAt: new Date(body.updated)
154 }) 154 }) as MCommentOwner
155 comment.Account = actor.Account 155 comment.Account = actor.Account
156 156
157 return resolveThread({ 157 return resolveThread({
diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts
index cda5b2981..6bd46bb58 100644
--- a/server/lib/activitypub/video-rates.ts
+++ b/server/lib/activitypub/video-rates.ts
@@ -1,6 +1,4 @@
1import { Transaction } from 'sequelize' 1import { Transaction } from 'sequelize'
2import { AccountModel } from '../../models/account/account'
3import { VideoModel } from '../../models/video/video'
4import { sendLike, sendUndoDislike, sendUndoLike } from './send' 2import { sendLike, sendUndoDislike, sendUndoLike } from './send'
5import { VideoRateType } from '../../../shared/models/videos' 3import { VideoRateType } from '../../../shared/models/videos'
6import * as Bluebird from 'bluebird' 4import * as Bluebird from 'bluebird'
@@ -10,11 +8,11 @@ import { logger } from '../../helpers/logger'
10import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' 8import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants'
11import { doRequest } from '../../helpers/requests' 9import { doRequest } from '../../helpers/requests'
12import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 10import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
13import { ActorModel } from '../../models/activitypub/actor'
14import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from './url' 11import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from './url'
15import { sendDislike } from './send/send-dislike' 12import { sendDislike } from './send/send-dislike'
13import { MAccountActor, MActorUrl, MVideo, MVideoAccountLight, MVideoId } from '../../typings/models'
16 14
17async function createRates (ratesUrl: string[], video: VideoModel, rate: VideoRateType) { 15async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateType) {
18 let rateCounts = 0 16 let rateCounts = 0
19 17
20 await Bluebird.map(ratesUrl, async rateUrl => { 18 await Bluebird.map(ratesUrl, async rateUrl => {
@@ -64,11 +62,13 @@ async function createRates (ratesUrl: string[], video: VideoModel, rate: VideoRa
64 return 62 return
65} 63}
66 64
67async function sendVideoRateChange (account: AccountModel, 65async function sendVideoRateChange (
68 video: VideoModel, 66 account: MAccountActor,
69 likes: number, 67 video: MVideoAccountLight,
70 dislikes: number, 68 likes: number,
71 t: Transaction) { 69 dislikes: number,
70 t: Transaction
71) {
72 const actor = account.Actor 72 const actor = account.Actor
73 73
74 // Keep the order: first we undo and then we create 74 // Keep the order: first we undo and then we create
@@ -84,8 +84,10 @@ async function sendVideoRateChange (account: AccountModel,
84 if (dislikes > 0) await sendDislike(actor, video, t) 84 if (dislikes > 0) await sendDislike(actor, video, t)
85} 85}
86 86
87function getRateUrl (rateType: VideoRateType, actor: ActorModel, video: VideoModel) { 87function getRateUrl (rateType: VideoRateType, actor: MActorUrl, video: MVideoId) {
88 return rateType === 'like' ? getVideoLikeActivityPubUrl(actor, video) : getVideoDislikeActivityPubUrl(actor, video) 88 return rateType === 'like'
89 ? getVideoLikeActivityPubUrl(actor, video)
90 : getVideoDislikeActivityPubUrl(actor, video)
89} 91}
90 92
91export { 93export {
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 3a8451a32..5c10f9764 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -24,7 +24,6 @@ import {
24 REMOTE_SCHEME, 24 REMOTE_SCHEME,
25 STATIC_PATHS 25 STATIC_PATHS
26} from '../../initializers/constants' 26} from '../../initializers/constants'
27import { ActorModel } from '../../models/activitypub/actor'
28import { TagModel } from '../../models/video/tag' 27import { TagModel } from '../../models/video/tag'
29import { VideoModel } from '../../models/video/video' 28import { VideoModel } from '../../models/video/video'
30import { VideoFileModel } from '../../models/video/video-file' 29import { VideoFileModel } from '../../models/video/video-file'
@@ -38,7 +37,6 @@ import { JobQueue } from '../job-queue'
38import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub-http-fetcher' 37import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub-http-fetcher'
39import { createRates } from './video-rates' 38import { createRates } from './video-rates'
40import { addVideoShares, shareVideoByServerAndChannel } from './share' 39import { addVideoShares, shareVideoByServerAndChannel } from './share'
41import { AccountModel } from '../../models/account/account'
42import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' 40import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video'
43import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' 41import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub'
44import { Notifier } from '../notifier' 42import { Notifier } from '../notifier'
@@ -49,15 +47,33 @@ import { VideoShareModel } from '../../models/video/video-share'
49import { VideoCommentModel } from '../../models/video/video-comment' 47import { VideoCommentModel } from '../../models/video/video-comment'
50import { sequelizeTypescript } from '../../initializers/database' 48import { sequelizeTypescript } from '../../initializers/database'
51import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail' 49import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail'
52import { ThumbnailModel } from '../../models/video/thumbnail'
53import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' 50import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type'
54import { join } from 'path' 51import { join } from 'path'
55import { FilteredModelAttributes } from '../../typings/sequelize' 52import { FilteredModelAttributes } from '../../typings/sequelize'
56import { autoBlacklistVideoIfNeeded } from '../video-blacklist' 53import { autoBlacklistVideoIfNeeded } from '../video-blacklist'
57import { ActorFollowScoreCache } from '../files-cache' 54import { ActorFollowScoreCache } from '../files-cache'
58import { AccountModelIdActor, VideoChannelModelId, VideoChannelModelIdActor } from '../../typings/models' 55import {
56 MAccountActor,
57 MChannelAccountLight,
58 MChannelDefault,
59 MChannelId,
60 MVideo,
61 MVideoAccountAllFiles,
62 MVideoAccountLight,
63 MVideoAP,
64 MVideoAPWithoutCaption,
65 MVideoFile,
66 MVideoFullLight,
67 MVideoId,
68 MVideoTag,
69 MVideoThumbnail,
70 MVideoWithAllFiles
71} from '../../typings/models'
72import { MThumbnail } from '../../typings/models/video/thumbnail'
73
74async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) {
75 const video = videoArg as MVideoAP
59 76
60async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) {
61 if ( 77 if (
62 // Check this is not a blacklisted video, or unfederated blacklisted video 78 // Check this is not a blacklisted video, or unfederated blacklisted video
63 (video.isBlacklisted() === false || (isNewVideo === false && video.VideoBlacklist.unfederated === false)) && 79 (video.isBlacklisted() === false || (isNewVideo === false && video.VideoBlacklist.unfederated === false)) &&
@@ -102,7 +118,7 @@ async function fetchRemoteVideo (videoUrl: string): Promise<{ response: request.
102 return { response, videoObject: body } 118 return { response, videoObject: body }
103} 119}
104 120
105async function fetchRemoteVideoDescription (video: VideoModel) { 121async function fetchRemoteVideoDescription (video: MVideoAccountLight) {
106 const host = video.VideoChannel.Account.Actor.Server.host 122 const host = video.VideoChannel.Account.Actor.Server.host
107 const path = video.getDescriptionAPIPath() 123 const path = video.getDescriptionAPIPath()
108 const options = { 124 const options = {
@@ -114,14 +130,14 @@ async function fetchRemoteVideoDescription (video: VideoModel) {
114 return body.description ? body.description : '' 130 return body.description ? body.description : ''
115} 131}
116 132
117function fetchRemoteVideoStaticFile (video: VideoModel, path: string, destPath: string) { 133function fetchRemoteVideoStaticFile (video: MVideoAccountLight, path: string, destPath: string) {
118 const url = buildRemoteBaseUrl(video, path) 134 const url = buildRemoteBaseUrl(video, path)
119 135
120 // We need to provide a callback, if no we could have an uncaught exception 136 // We need to provide a callback, if no we could have an uncaught exception
121 return doRequestAndSaveToFile({ uri: url }, destPath) 137 return doRequestAndSaveToFile({ uri: url }, destPath)
122} 138}
123 139
124function buildRemoteBaseUrl (video: VideoModel, path: string) { 140function buildRemoteBaseUrl (video: MVideoAccountLight, path: string) {
125 const host = video.VideoChannel.Account.Actor.Server.host 141 const host = video.VideoChannel.Account.Actor.Server.host
126 142
127 return REMOTE_SCHEME.HTTP + '://' + host + path 143 return REMOTE_SCHEME.HTTP + '://' + host + path
@@ -146,7 +162,7 @@ type SyncParam = {
146 thumbnail: boolean 162 thumbnail: boolean
147 refreshVideo?: boolean 163 refreshVideo?: boolean
148} 164}
149async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: VideoTorrentObject, syncParam: SyncParam) { 165async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTorrentObject, syncParam: SyncParam) {
150 logger.info('Adding likes/dislikes/shares/comments of video %s.', video.uuid) 166 logger.info('Adding likes/dislikes/shares/comments of video %s.', video.uuid)
151 167
152 const jobPayloads: ActivitypubHttpFetcherPayload[] = [] 168 const jobPayloads: ActivitypubHttpFetcherPayload[] = []
@@ -194,12 +210,24 @@ async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: Vid
194 await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) 210 await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }))
195} 211}
196 212
213function getOrCreateVideoAndAccountAndChannel (options: {
214 videoObject: { id: string } | string,
215 syncParam?: SyncParam,
216 fetchType?: 'all',
217 allowRefresh?: boolean
218}): Promise<{ video: MVideoAccountAllFiles, created: boolean, autoBlacklisted?: boolean }>
219function getOrCreateVideoAndAccountAndChannel (options: {
220 videoObject: { id: string } | string,
221 syncParam?: SyncParam,
222 fetchType?: VideoFetchByUrlType,
223 allowRefresh?: boolean
224}): Promise<{ video: MVideoAccountAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }>
197async function getOrCreateVideoAndAccountAndChannel (options: { 225async function getOrCreateVideoAndAccountAndChannel (options: {
198 videoObject: { id: string } | string, 226 videoObject: { id: string } | string,
199 syncParam?: SyncParam, 227 syncParam?: SyncParam,
200 fetchType?: VideoFetchByUrlType, 228 fetchType?: VideoFetchByUrlType,
201 allowRefresh?: boolean // true by default 229 allowRefresh?: boolean // true by default
202}) { 230}): Promise<{ video: MVideoAccountAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> {
203 // Default params 231 // Default params
204 const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } 232 const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false }
205 const fetchType = options.fetchType || 'all' 233 const fetchType = options.fetchType || 'all'
@@ -227,8 +255,9 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
227 const { videoObject: fetchedVideo } = await fetchRemoteVideo(videoUrl) 255 const { videoObject: fetchedVideo } = await fetchRemoteVideo(videoUrl)
228 if (!fetchedVideo) throw new Error('Cannot fetch remote video with url: ' + videoUrl) 256 if (!fetchedVideo) throw new Error('Cannot fetch remote video with url: ' + videoUrl)
229 257
230 const channelActor = await getOrCreateVideoChannelFromVideoObject(fetchedVideo) 258 const actor = await getOrCreateVideoChannelFromVideoObject(fetchedVideo)
231 const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(createVideo, fetchedVideo, channelActor, syncParam.thumbnail) 259 const videoChannel = actor.VideoChannel
260 const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(createVideo, fetchedVideo, videoChannel, syncParam.thumbnail)
232 261
233 await syncVideoExternalAttributes(videoCreated, fetchedVideo, syncParam) 262 await syncVideoExternalAttributes(videoCreated, fetchedVideo, syncParam)
234 263
@@ -236,22 +265,22 @@ async function getOrCreateVideoAndAccountAndChannel (options: {
236} 265}
237 266
238async function updateVideoFromAP (options: { 267async function updateVideoFromAP (options: {
239 video: VideoModel, 268 video: MVideoAccountAllFiles,
240 videoObject: VideoTorrentObject, 269 videoObject: VideoTorrentObject,
241 account: AccountModelIdActor, 270 account: MAccountActor,
242 channel: VideoChannelModelIdActor, 271 channel: MChannelDefault,
243 overrideTo?: string[] 272 overrideTo?: string[]
244}) { 273}) {
245 const { video, videoObject, account, channel, overrideTo } = options 274 const { video, videoObject, account, channel, overrideTo } = options
246 275
247 logger.debug('Updating remote video "%s".', options.videoObject.uuid) 276 logger.debug('Updating remote video "%s".', options.videoObject.uuid, { account, channel })
248 277
249 let videoFieldsSave: any 278 let videoFieldsSave: any
250 const wasPrivateVideo = video.privacy === VideoPrivacy.PRIVATE 279 const wasPrivateVideo = video.privacy === VideoPrivacy.PRIVATE
251 const wasUnlistedVideo = video.privacy === VideoPrivacy.UNLISTED 280 const wasUnlistedVideo = video.privacy === VideoPrivacy.UNLISTED
252 281
253 try { 282 try {
254 let thumbnailModel: ThumbnailModel 283 let thumbnailModel: MThumbnail
255 284
256 try { 285 try {
257 thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) 286 thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE)
@@ -259,7 +288,7 @@ async function updateVideoFromAP (options: {
259 logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) 288 logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err })
260 } 289 }
261 290
262 await sequelizeTypescript.transaction(async t => { 291 const videoUpdated = await sequelizeTypescript.transaction(async t => {
263 const sequelizeOptions = { transaction: t } 292 const sequelizeOptions = { transaction: t }
264 293
265 videoFieldsSave = video.toJSON() 294 videoFieldsSave = video.toJSON()
@@ -293,21 +322,21 @@ async function updateVideoFromAP (options: {
293 video.channelId = videoData.channelId 322 video.channelId = videoData.channelId
294 video.views = videoData.views 323 video.views = videoData.views
295 324
296 await video.save(sequelizeOptions) 325 const videoUpdated = await video.save(sequelizeOptions) as MVideoFullLight
297 326
298 if (thumbnailModel) await video.addAndSaveThumbnail(thumbnailModel, t) 327 if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t)
299 328
300 // FIXME: use icon URL instead 329 // FIXME: use icon URL instead
301 const previewUrl = buildRemoteBaseUrl(video, join(STATIC_PATHS.PREVIEWS, video.getPreview().filename)) 330 const previewUrl = buildRemoteBaseUrl(videoUpdated, join(STATIC_PATHS.PREVIEWS, videoUpdated.getPreview().filename))
302 const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) 331 const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE)
303 await video.addAndSaveThumbnail(previewModel, t) 332 await videoUpdated.addAndSaveThumbnail(previewModel, t)
304 333
305 { 334 {
306 const videoFileAttributes = videoFileActivityUrlToDBAttributes(video, videoObject) 335 const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoUpdated, videoObject)
307 const newVideoFiles = videoFileAttributes.map(a => new VideoFileModel(a)) 336 const newVideoFiles = videoFileAttributes.map(a => new VideoFileModel(a))
308 337
309 // Remove video files that do not exist anymore 338 // Remove video files that do not exist anymore
310 const destroyTasks = video.VideoFiles 339 const destroyTasks = videoUpdated.VideoFiles
311 .filter(f => !newVideoFiles.find(newFile => newFile.hasSameUniqueKeysThan(f))) 340 .filter(f => !newVideoFiles.find(newFile => newFile.hasSameUniqueKeysThan(f)))
312 .map(f => f.destroy(sequelizeOptions)) 341 .map(f => f.destroy(sequelizeOptions))
313 await Promise.all(destroyTasks) 342 await Promise.all(destroyTasks)
@@ -318,15 +347,15 @@ async function updateVideoFromAP (options: {
318 .then(([ file ]) => file) 347 .then(([ file ]) => file)
319 }) 348 })
320 349
321 video.VideoFiles = await Promise.all(upsertTasks) 350 videoUpdated.VideoFiles = await Promise.all(upsertTasks)
322 } 351 }
323 352
324 { 353 {
325 const streamingPlaylistAttributes = streamingPlaylistActivityUrlToDBAttributes(video, videoObject, video.VideoFiles) 354 const streamingPlaylistAttributes = streamingPlaylistActivityUrlToDBAttributes(videoUpdated, videoObject, videoUpdated.VideoFiles)
326 const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a)) 355 const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a))
327 356
328 // Remove video files that do not exist anymore 357 // Remove video files that do not exist anymore
329 const destroyTasks = video.VideoStreamingPlaylists 358 const destroyTasks = videoUpdated.VideoStreamingPlaylists
330 .filter(f => !newStreamingPlaylists.find(newPlaylist => newPlaylist.hasSameUniqueKeysThan(f))) 359 .filter(f => !newStreamingPlaylists.find(newPlaylist => newPlaylist.hasSameUniqueKeysThan(f)))
331 .map(f => f.destroy(sequelizeOptions)) 360 .map(f => f.destroy(sequelizeOptions))
332 await Promise.all(destroyTasks) 361 await Promise.all(destroyTasks)
@@ -337,38 +366,42 @@ async function updateVideoFromAP (options: {
337 .then(([ streamingPlaylist ]) => streamingPlaylist) 366 .then(([ streamingPlaylist ]) => streamingPlaylist)
338 }) 367 })
339 368
340 video.VideoStreamingPlaylists = await Promise.all(upsertTasks) 369 videoUpdated.VideoStreamingPlaylists = await Promise.all(upsertTasks)
341 } 370 }
342 371
343 { 372 {
344 // Update Tags 373 // Update Tags
345 const tags = videoObject.tag.map(tag => tag.name) 374 const tags = videoObject.tag.map(tag => tag.name)
346 const tagInstances = await TagModel.findOrCreateTags(tags, t) 375 const tagInstances = await TagModel.findOrCreateTags(tags, t)
347 await video.$set('Tags', tagInstances, sequelizeOptions) 376 await videoUpdated.$set('Tags', tagInstances, sequelizeOptions)
348 } 377 }
349 378
350 { 379 {
351 // Update captions 380 // Update captions
352 await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(video.id, t) 381 await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t)
353 382
354 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { 383 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => {
355 return VideoCaptionModel.insertOrReplaceLanguage(video.id, c.identifier, t) 384 return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, t)
356 }) 385 })
357 video.VideoCaptions = await Promise.all(videoCaptionsPromises) 386 await Promise.all(videoCaptionsPromises)
358 } 387 }
388
389 return videoUpdated
359 }) 390 })
360 391
361 await autoBlacklistVideoIfNeeded({ 392 await autoBlacklistVideoIfNeeded({
362 video, 393 video: videoUpdated,
363 user: undefined, 394 user: undefined,
364 isRemote: true, 395 isRemote: true,
365 isNew: false, 396 isNew: false,
366 transaction: undefined 397 transaction: undefined
367 }) 398 })
368 399
369 if (wasPrivateVideo || wasUnlistedVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(video) // Notify our users? 400 if (wasPrivateVideo || wasUnlistedVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(videoUpdated) // Notify our users?
370 401
371 logger.info('Remote video with uuid %s updated', videoObject.uuid) 402 logger.info('Remote video with uuid %s updated', videoObject.uuid)
403
404 return videoUpdated
372 } catch (err) { 405 } catch (err) {
373 if (video !== undefined && videoFieldsSave !== undefined) { 406 if (video !== undefined && videoFieldsSave !== undefined) {
374 resetSequelizeInstance(video, videoFieldsSave) 407 resetSequelizeInstance(video, videoFieldsSave)
@@ -381,15 +414,15 @@ async function updateVideoFromAP (options: {
381} 414}
382 415
383async function refreshVideoIfNeeded (options: { 416async function refreshVideoIfNeeded (options: {
384 video: VideoModel, 417 video: MVideoThumbnail,
385 fetchedType: VideoFetchByUrlType, 418 fetchedType: VideoFetchByUrlType,
386 syncParam: SyncParam 419 syncParam: SyncParam
387}): Promise<VideoModel> { 420}): Promise<MVideoThumbnail> {
388 if (!options.video.isOutdated()) return options.video 421 if (!options.video.isOutdated()) return options.video
389 422
390 // We need more attributes if the argument video was fetched with not enough joints 423 // We need more attributes if the argument video was fetched with not enough joints
391 const video = options.fetchedType === 'all' 424 const video = options.fetchedType === 'all'
392 ? options.video 425 ? options.video as MVideoAccountAllFiles
393 : await VideoModel.loadByUrlAndPopulateAccount(options.video.url) 426 : await VideoModel.loadByUrlAndPopulateAccount(options.video.url)
394 427
395 try { 428 try {
@@ -410,12 +443,11 @@ async function refreshVideoIfNeeded (options: {
410 } 443 }
411 444
412 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) 445 const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject)
413 const account = await AccountModel.load(channelActor.VideoChannel.accountId)
414 446
415 const updateOptions = { 447 const updateOptions = {
416 video, 448 video,
417 videoObject, 449 videoObject,
418 account, 450 account: channelActor.VideoChannel.Account,
419 channel: channelActor.VideoChannel 451 channel: channelActor.VideoChannel
420 } 452 }
421 await retryTransactionWrapper(updateVideoFromAP, updateOptions) 453 await retryTransactionWrapper(updateVideoFromAP, updateOptions)
@@ -467,15 +499,15 @@ function isAPPlaylistSegmentHashesUrlObject (tag: any): tag is ActivityPlaylistS
467 return tag.name === 'sha256' && tag.type === 'Link' && urlMediaType === 'application/json' 499 return tag.name === 'sha256' && tag.type === 'Link' && urlMediaType === 'application/json'
468} 500}
469 501
470async function createVideo (videoObject: VideoTorrentObject, channelActor: ActorModel, waitThumbnail = false) { 502async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAccountLight, waitThumbnail = false) {
471 logger.debug('Adding remote video %s.', videoObject.id) 503 logger.debug('Adding remote video %s.', videoObject.id)
472 504
473 const videoData = await videoActivityObjectToDBAttributes(channelActor.VideoChannel, videoObject, videoObject.to) 505 const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to)
474 const video = VideoModel.build(videoData) 506 const video = VideoModel.build(videoData) as MVideoThumbnail
475 507
476 const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) 508 const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE)
477 509
478 let thumbnailModel: ThumbnailModel 510 let thumbnailModel: MThumbnail
479 if (waitThumbnail === true) { 511 if (waitThumbnail === true) {
480 thumbnailModel = await promiseThumbnail 512 thumbnailModel = await promiseThumbnail
481 } 513 }
@@ -483,8 +515,8 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
483 const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => { 515 const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => {
484 const sequelizeOptions = { transaction: t } 516 const sequelizeOptions = { transaction: t }
485 517
486 const videoCreated = await video.save(sequelizeOptions) 518 const videoCreated = await video.save(sequelizeOptions) as MVideoFullLight
487 videoCreated.VideoChannel = channelActor.VideoChannel 519 videoCreated.VideoChannel = channel
488 520
489 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) 521 if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t)
490 522
@@ -517,15 +549,14 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
517 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { 549 const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => {
518 return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t) 550 return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t)
519 }) 551 })
520 const captions = await Promise.all(videoCaptionsPromises) 552 await Promise.all(videoCaptionsPromises)
521 553
522 video.VideoFiles = videoFiles 554 videoCreated.VideoFiles = videoFiles
523 video.VideoStreamingPlaylists = streamingPlaylists 555 videoCreated.VideoStreamingPlaylists = streamingPlaylists
524 video.Tags = tagInstances 556 videoCreated.Tags = tagInstances
525 video.VideoCaptions = captions
526 557
527 const autoBlacklisted = await autoBlacklistVideoIfNeeded({ 558 const autoBlacklisted = await autoBlacklistVideoIfNeeded({
528 video, 559 video: videoCreated,
529 user: undefined, 560 user: undefined,
530 isRemote: true, 561 isRemote: true,
531 isNew: true, 562 isNew: true,
@@ -548,11 +579,7 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor
548 return { autoBlacklisted, videoCreated } 579 return { autoBlacklisted, videoCreated }
549} 580}
550 581
551async function videoActivityObjectToDBAttributes ( 582async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) {
552 videoChannel: VideoChannelModelId,
553 videoObject: VideoTorrentObject,
554 to: string[] = []
555) {
556 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED 583 const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED
557 const duration = videoObject.duration.replace(/[^\d]+/, '') 584 const duration = videoObject.duration.replace(/[^\d]+/, '')
558 585
@@ -603,7 +630,7 @@ async function videoActivityObjectToDBAttributes (
603 } 630 }
604} 631}
605 632
606function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: VideoTorrentObject) { 633function videoFileActivityUrlToDBAttributes (video: MVideo, videoObject: VideoTorrentObject) {
607 const fileUrls = videoObject.url.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[] 634 const fileUrls = videoObject.url.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[]
608 635
609 if (fileUrls.length === 0) { 636 if (fileUrls.length === 0) {
@@ -641,7 +668,7 @@ function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: Vid
641 return attributes 668 return attributes
642} 669}
643 670
644function streamingPlaylistActivityUrlToDBAttributes (video: VideoModel, videoObject: VideoTorrentObject, videoFiles: VideoFileModel[]) { 671function streamingPlaylistActivityUrlToDBAttributes (video: MVideoId, videoObject: VideoTorrentObject, videoFiles: MVideoFile[]) {
645 const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[] 672 const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[]
646 if (playlistUrls.length === 0) return [] 673 if (playlistUrls.length === 0) return []
647 674