diff options
-rw-r--r-- | server/controllers/api/videos/index.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/audience.ts | 10 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-delete.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-announce.ts | 4 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-create.ts | 95 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-delete.ts | 13 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-like.ts | 23 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-undo.ts | 85 | ||||
-rw-r--r-- | server/lib/activitypub/send/send-update.ts | 16 | ||||
-rw-r--r-- | server/lib/activitypub/send/utils.ts | 30 | ||||
-rw-r--r-- | server/tests/api/server/stats.ts | 3 |
11 files changed, 135 insertions, 150 deletions
diff --git a/server/controllers/api/videos/index.ts b/server/controllers/api/videos/index.ts index 0c9e6c2d1..8353a649a 100644 --- a/server/controllers/api/videos/index.ts +++ b/server/controllers/api/videos/index.ts | |||
@@ -393,9 +393,9 @@ async function viewVideo (req: express.Request, res: express.Response) { | |||
393 | Redis.Instance.setIPVideoView(ip, videoInstance.uuid) | 393 | Redis.Instance.setIPVideoView(ip, videoInstance.uuid) |
394 | ]) | 394 | ]) |
395 | 395 | ||
396 | const serverAccount = await getServerActor() | 396 | const serverActor = await getServerActor() |
397 | 397 | ||
398 | await sendCreateView(serverAccount, videoInstance, undefined) | 398 | await sendCreateView(serverActor, videoInstance, undefined) |
399 | 399 | ||
400 | return res.status(204).end() | 400 | return res.status(204).end() |
401 | } | 401 | } |
diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts index 7b4067c11..a86428461 100644 --- a/server/lib/activitypub/audience.ts +++ b/server/lib/activitypub/audience.ts | |||
@@ -6,7 +6,7 @@ import { VideoModel } from '../../models/video/video' | |||
6 | import { VideoCommentModel } from '../../models/video/video-comment' | 6 | import { VideoCommentModel } from '../../models/video/video-comment' |
7 | import { VideoShareModel } from '../../models/video/video-share' | 7 | import { VideoShareModel } from '../../models/video/video-share' |
8 | 8 | ||
9 | function getVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]) { | 9 | function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience { |
10 | return { | 10 | return { |
11 | to: [ video.VideoChannel.Account.Actor.url ], | 11 | to: [ video.VideoChannel.Account.Actor.url ], |
12 | cc: actorsInvolvedInVideo.map(a => a.followersUrl) | 12 | cc: actorsInvolvedInVideo.map(a => a.followersUrl) |
@@ -18,7 +18,7 @@ function getVideoCommentAudience ( | |||
18 | threadParentComments: VideoCommentModel[], | 18 | threadParentComments: VideoCommentModel[], |
19 | actorsInvolvedInVideo: ActorModel[], | 19 | actorsInvolvedInVideo: ActorModel[], |
20 | isOrigin = false | 20 | isOrigin = false |
21 | ) { | 21 | ): ActivityAudience { |
22 | const to = [ ACTIVITY_PUB.PUBLIC ] | 22 | const to = [ ACTIVITY_PUB.PUBLIC ] |
23 | const cc: string[] = [] | 23 | const cc: string[] = [] |
24 | 24 | ||
@@ -41,7 +41,7 @@ function getVideoCommentAudience ( | |||
41 | } | 41 | } |
42 | } | 42 | } |
43 | 43 | ||
44 | function getObjectFollowersAudience (actorsInvolvedInObject: ActorModel[]) { | 44 | function getAudienceFromFollowersOf (actorsInvolvedInObject: ActorModel[]): ActivityAudience { |
45 | return { | 45 | return { |
46 | to: [ ACTIVITY_PUB.PUBLIC ].concat(actorsInvolvedInObject.map(a => a.followersUrl)), | 46 | to: [ ACTIVITY_PUB.PUBLIC ].concat(actorsInvolvedInObject.map(a => a.followersUrl)), |
47 | cc: [] | 47 | cc: [] |
@@ -83,9 +83,9 @@ function audiencify<T> (object: T, audience: ActivityAudience) { | |||
83 | export { | 83 | export { |
84 | buildAudience, | 84 | buildAudience, |
85 | getAudience, | 85 | getAudience, |
86 | getVideoAudience, | 86 | getRemoteVideoAudience, |
87 | getActorsInvolvedInVideo, | 87 | getActorsInvolvedInVideo, |
88 | getObjectFollowersAudience, | 88 | getAudienceFromFollowersOf, |
89 | audiencify, | 89 | audiencify, |
90 | getVideoCommentAudience | 90 | getVideoCommentAudience |
91 | } | 91 | } |
diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index 3c830abea..4c034a81c 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts | |||
@@ -41,6 +41,8 @@ async function processDeleteActivity (activity: ActivityDelete) { | |||
41 | { | 41 | { |
42 | const videoInstance = await VideoModel.loadByUrlAndPopulateAccount(objectUrl) | 42 | const videoInstance = await VideoModel.loadByUrlAndPopulateAccount(objectUrl) |
43 | if (videoInstance) { | 43 | if (videoInstance) { |
44 | if (videoInstance.isOwned()) throw new Error(`Remote instance cannot delete owned video ${videoInstance.url}.`) | ||
45 | |||
44 | return retryTransactionWrapper(processDeleteVideo, actor, videoInstance) | 46 | return retryTransactionWrapper(processDeleteVideo, actor, videoInstance) |
45 | } | 47 | } |
46 | } | 48 | } |
diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index f137217f8..cd0cab7ee 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts | |||
@@ -4,14 +4,14 @@ import { ActorModel } from '../../../models/activitypub/actor' | |||
4 | import { VideoModel } from '../../../models/video/video' | 4 | import { VideoModel } from '../../../models/video/video' |
5 | import { VideoShareModel } from '../../../models/video/video-share' | 5 | import { VideoShareModel } from '../../../models/video/video-share' |
6 | import { broadcastToFollowers } from './utils' | 6 | import { broadcastToFollowers } from './utils' |
7 | import { audiencify, getActorsInvolvedInVideo, getAudience, getObjectFollowersAudience } from '../audience' | 7 | import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience' |
8 | import { logger } from '../../../helpers/logger' | 8 | import { logger } from '../../../helpers/logger' |
9 | 9 | ||
10 | async function buildAnnounceWithVideoAudience (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { | 10 | async function buildAnnounceWithVideoAudience (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { |
11 | const announcedObject = video.url | 11 | const announcedObject = video.url |
12 | 12 | ||
13 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | 13 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) |
14 | const audience = getObjectFollowersAudience(actorsInvolvedInVideo) | 14 | const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) |
15 | 15 | ||
16 | const activity = buildAnnounceActivity(videoShare.url, byActor, announcedObject, audience) | 16 | const activity = buildAnnounceActivity(videoShare.url, byActor, announcedObject, audience) |
17 | 17 | ||
diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index 6f89b1a22..285edba3b 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts | |||
@@ -1,21 +1,13 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub' | 2 | import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub' |
3 | import { VideoPrivacy } from '../../../../shared/models/videos' | 3 | import { VideoPrivacy } from '../../../../shared/models/videos' |
4 | import { getServerActor } from '../../../helpers/utils' | ||
5 | import { ActorModel } from '../../../models/activitypub/actor' | 4 | import { ActorModel } from '../../../models/activitypub/actor' |
6 | import { VideoModel } from '../../../models/video/video' | 5 | import { VideoModel } from '../../../models/video/video' |
7 | import { VideoAbuseModel } from '../../../models/video/video-abuse' | 6 | import { VideoAbuseModel } from '../../../models/video/video-abuse' |
8 | import { VideoCommentModel } from '../../../models/video/video-comment' | 7 | import { VideoCommentModel } from '../../../models/video/video-comment' |
9 | import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url' | 8 | import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url' |
10 | import { broadcastToActors, broadcastToFollowers, unicastTo } from './utils' | 9 | import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' |
11 | import { | 10 | import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf, getVideoCommentAudience } from '../audience' |
12 | audiencify, | ||
13 | getActorsInvolvedInVideo, | ||
14 | getAudience, | ||
15 | getObjectFollowersAudience, | ||
16 | getVideoAudience, | ||
17 | getVideoCommentAudience | ||
18 | } from '../audience' | ||
19 | import { logger } from '../../../helpers/logger' | 11 | import { logger } from '../../../helpers/logger' |
20 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' | 12 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' |
21 | 13 | ||
@@ -40,6 +32,7 @@ async function sendVideoAbuse (byActor: ActorModel, videoAbuse: VideoAbuseModel, | |||
40 | 32 | ||
41 | logger.info('Creating job to send video abuse %s.', url) | 33 | logger.info('Creating job to send video abuse %s.', url) |
42 | 34 | ||
35 | // Custom audience, we only send the abuse to the origin instance | ||
43 | const audience = { to: [ video.VideoChannel.Account.Actor.url ], cc: [] } | 36 | const audience = { to: [ video.VideoChannel.Account.Actor.url ], cc: [] } |
44 | const createActivity = buildCreateActivity(url, byActor, videoAbuse.toActivityPubObject(), audience) | 37 | const createActivity = buildCreateActivity(url, byActor, videoAbuse.toActivityPubObject(), audience) |
45 | 38 | ||
@@ -49,15 +42,15 @@ async function sendVideoAbuse (byActor: ActorModel, videoAbuse: VideoAbuseModel, | |||
49 | async function sendCreateCacheFile (byActor: ActorModel, fileRedundancy: VideoRedundancyModel) { | 42 | async function sendCreateCacheFile (byActor: ActorModel, fileRedundancy: VideoRedundancyModel) { |
50 | logger.info('Creating job to send file cache of %s.', fileRedundancy.url) | 43 | logger.info('Creating job to send file cache of %s.', fileRedundancy.url) |
51 | 44 | ||
52 | const redundancyObject = fileRedundancy.toActivityPubObject() | ||
53 | |||
54 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(fileRedundancy.VideoFile.Video.id) | 45 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(fileRedundancy.VideoFile.Video.id) |
55 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, undefined) | 46 | const redundancyObject = fileRedundancy.toActivityPubObject() |
56 | |||
57 | const audience = getVideoAudience(video, actorsInvolvedInVideo) | ||
58 | const createActivity = buildCreateActivity(fileRedundancy.url, byActor, redundancyObject, audience) | ||
59 | 47 | ||
60 | return unicastTo(createActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | 48 | return sendVideoRelatedCreateActivity({ |
49 | byActor, | ||
50 | video, | ||
51 | url: fileRedundancy.url, | ||
52 | object: redundancyObject | ||
53 | }) | ||
61 | } | 54 | } |
62 | 55 | ||
63 | async function sendCreateVideoComment (comment: VideoCommentModel, t: Transaction) { | 56 | async function sendCreateVideoComment (comment: VideoCommentModel, t: Transaction) { |
@@ -70,6 +63,7 @@ async function sendCreateVideoComment (comment: VideoCommentModel, t: Transactio | |||
70 | const commentObject = comment.toActivityPubObject(threadParentComments) | 63 | const commentObject = comment.toActivityPubObject(threadParentComments) |
71 | 64 | ||
72 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, t) | 65 | const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, t) |
66 | // Add the actor that commented too | ||
73 | actorsInvolvedInComment.push(byActor) | 67 | actorsInvolvedInComment.push(byActor) |
74 | 68 | ||
75 | const parentsCommentActors = threadParentComments.map(c => c.Account.Actor) | 69 | const parentsCommentActors = threadParentComments.map(c => c.Account.Actor) |
@@ -78,7 +72,7 @@ async function sendCreateVideoComment (comment: VideoCommentModel, t: Transactio | |||
78 | if (isOrigin) { | 72 | if (isOrigin) { |
79 | audience = getVideoCommentAudience(comment, threadParentComments, actorsInvolvedInComment, isOrigin) | 73 | audience = getVideoCommentAudience(comment, threadParentComments, actorsInvolvedInComment, isOrigin) |
80 | } else { | 74 | } else { |
81 | audience = getObjectFollowersAudience(actorsInvolvedInComment.concat(parentsCommentActors)) | 75 | audience = getAudienceFromFollowersOf(actorsInvolvedInComment.concat(parentsCommentActors)) |
82 | } | 76 | } |
83 | 77 | ||
84 | const createActivity = buildCreateActivity(comment.url, byActor, commentObject, audience) | 78 | const createActivity = buildCreateActivity(comment.url, byActor, commentObject, audience) |
@@ -103,24 +97,14 @@ async function sendCreateView (byActor: ActorModel, video: VideoModel, t: Transa | |||
103 | const url = getVideoViewActivityPubUrl(byActor, video) | 97 | const url = getVideoViewActivityPubUrl(byActor, video) |
104 | const viewActivity = buildViewActivity(byActor, video) | 98 | const viewActivity = buildViewActivity(byActor, video) |
105 | 99 | ||
106 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | 100 | return sendVideoRelatedCreateActivity({ |
107 | 101 | // Use the server actor to send the view | |
108 | // Send to origin | 102 | byActor, |
109 | if (video.isOwned() === false) { | 103 | video, |
110 | const audience = getVideoAudience(video, actorsInvolvedInVideo) | 104 | url, |
111 | const createActivity = buildCreateActivity(url, byActor, viewActivity, audience) | 105 | object: viewActivity, |
112 | 106 | transaction: t | |
113 | return unicastTo(createActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | 107 | }) |
114 | } | ||
115 | |||
116 | // Send to followers | ||
117 | const audience = getObjectFollowersAudience(actorsInvolvedInVideo) | ||
118 | const createActivity = buildCreateActivity(url, byActor, viewActivity, audience) | ||
119 | |||
120 | // Use the server actor to send the view | ||
121 | const serverActor = await getServerActor() | ||
122 | const actorsException = [ byActor ] | ||
123 | return broadcastToFollowers(createActivity, serverActor, actorsInvolvedInVideo, t, actorsException) | ||
124 | } | 108 | } |
125 | 109 | ||
126 | async function sendCreateDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { | 110 | async function sendCreateDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { |
@@ -129,22 +113,13 @@ async function sendCreateDislike (byActor: ActorModel, video: VideoModel, t: Tra | |||
129 | const url = getVideoDislikeActivityPubUrl(byActor, video) | 113 | const url = getVideoDislikeActivityPubUrl(byActor, video) |
130 | const dislikeActivity = buildDislikeActivity(byActor, video) | 114 | const dislikeActivity = buildDislikeActivity(byActor, video) |
131 | 115 | ||
132 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | 116 | return sendVideoRelatedCreateActivity({ |
133 | 117 | byActor, | |
134 | // Send to origin | 118 | video, |
135 | if (video.isOwned() === false) { | 119 | url, |
136 | const audience = getVideoAudience(video, actorsInvolvedInVideo) | 120 | object: dislikeActivity, |
137 | const createActivity = buildCreateActivity(url, byActor, dislikeActivity, audience) | 121 | transaction: t |
138 | 122 | }) | |
139 | return unicastTo(createActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | ||
140 | } | ||
141 | |||
142 | // Send to followers | ||
143 | const audience = getObjectFollowersAudience(actorsInvolvedInVideo) | ||
144 | const createActivity = buildCreateActivity(url, byActor, dislikeActivity, audience) | ||
145 | |||
146 | const actorsException = [ byActor ] | ||
147 | return broadcastToFollowers(createActivity, byActor, actorsInvolvedInVideo, t, actorsException) | ||
148 | } | 123 | } |
149 | 124 | ||
150 | function buildCreateActivity (url: string, byActor: ActorModel, object: any, audience?: ActivityAudience): ActivityCreate { | 125 | function buildCreateActivity (url: string, byActor: ActorModel, object: any, audience?: ActivityAudience): ActivityCreate { |
@@ -189,3 +164,19 @@ export { | |||
189 | sendCreateVideoComment, | 164 | sendCreateVideoComment, |
190 | sendCreateCacheFile | 165 | sendCreateCacheFile |
191 | } | 166 | } |
167 | |||
168 | // --------------------------------------------------------------------------- | ||
169 | |||
170 | async function sendVideoRelatedCreateActivity (options: { | ||
171 | byActor: ActorModel, | ||
172 | video: VideoModel, | ||
173 | url: string, | ||
174 | object: any, | ||
175 | transaction?: Transaction | ||
176 | }) { | ||
177 | const activityBuilder = (audience: ActivityAudience) => { | ||
178 | return buildCreateActivity(options.url, options.byActor, options.object, audience) | ||
179 | } | ||
180 | |||
181 | return sendVideoRelatedActivity(activityBuilder, options) | ||
182 | } | ||
diff --git a/server/lib/activitypub/send/send-delete.ts b/server/lib/activitypub/send/send-delete.ts index 479182543..18969433a 100644 --- a/server/lib/activitypub/send/send-delete.ts +++ b/server/lib/activitypub/send/send-delete.ts | |||
@@ -5,21 +5,22 @@ import { VideoModel } from '../../../models/video/video' | |||
5 | import { VideoCommentModel } from '../../../models/video/video-comment' | 5 | import { VideoCommentModel } from '../../../models/video/video-comment' |
6 | import { VideoShareModel } from '../../../models/video/video-share' | 6 | import { VideoShareModel } from '../../../models/video/video-share' |
7 | import { getDeleteActivityPubUrl } from '../url' | 7 | import { getDeleteActivityPubUrl } from '../url' |
8 | import { broadcastToActors, broadcastToFollowers, unicastTo } from './utils' | 8 | import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' |
9 | import { audiencify, getActorsInvolvedInVideo, getVideoCommentAudience } from '../audience' | 9 | import { audiencify, getActorsInvolvedInVideo, getVideoCommentAudience } from '../audience' |
10 | import { logger } from '../../../helpers/logger' | 10 | import { logger } from '../../../helpers/logger' |
11 | 11 | ||
12 | async function sendDeleteVideo (video: VideoModel, t: Transaction) { | 12 | async function sendDeleteVideo (video: VideoModel, transaction: Transaction) { |
13 | logger.info('Creating job to broadcast delete of video %s.', video.url) | 13 | logger.info('Creating job to broadcast delete of video %s.', video.url) |
14 | 14 | ||
15 | const url = getDeleteActivityPubUrl(video.url) | ||
16 | const byActor = video.VideoChannel.Account.Actor | 15 | const byActor = video.VideoChannel.Account.Actor |
17 | 16 | ||
18 | const activity = buildDeleteActivity(url, video.url, byActor) | 17 | const activityBuilder = (audience: ActivityAudience) => { |
18 | const url = getDeleteActivityPubUrl(video.url) | ||
19 | 19 | ||
20 | const actorsInvolved = await getActorsInvolvedInVideo(video, t) | 20 | return buildDeleteActivity(url, video.url, byActor, audience) |
21 | } | ||
21 | 22 | ||
22 | return broadcastToFollowers(activity, byActor, actorsInvolved, t) | 23 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction }) |
23 | } | 24 | } |
24 | 25 | ||
25 | async function sendDeleteActor (byActor: ActorModel, t: Transaction) { | 26 | async function sendDeleteActor (byActor: ActorModel, t: Transaction) { |
diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index a5408ac6a..89307acc6 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts | |||
@@ -3,31 +3,20 @@ import { ActivityAudience, ActivityLike } from '../../../../shared/models/activi | |||
3 | import { ActorModel } from '../../../models/activitypub/actor' | 3 | import { ActorModel } from '../../../models/activitypub/actor' |
4 | import { VideoModel } from '../../../models/video/video' | 4 | import { VideoModel } from '../../../models/video/video' |
5 | import { getVideoLikeActivityPubUrl } from '../url' | 5 | import { getVideoLikeActivityPubUrl } from '../url' |
6 | import { broadcastToFollowers, unicastTo } from './utils' | 6 | import { sendVideoRelatedActivity } from './utils' |
7 | import { audiencify, getActorsInvolvedInVideo, getAudience, getObjectFollowersAudience, getVideoAudience } from '../audience' | 7 | import { audiencify, getAudience } from '../audience' |
8 | import { logger } from '../../../helpers/logger' | 8 | import { logger } from '../../../helpers/logger' |
9 | 9 | ||
10 | async function sendLike (byActor: ActorModel, video: VideoModel, t: Transaction) { | 10 | async function sendLike (byActor: ActorModel, video: VideoModel, t: Transaction) { |
11 | logger.info('Creating job to like %s.', video.url) | 11 | logger.info('Creating job to like %s.', video.url) |
12 | 12 | ||
13 | const url = getVideoLikeActivityPubUrl(byActor, video) | 13 | const activityBuilder = (audience: ActivityAudience) => { |
14 | const url = getVideoLikeActivityPubUrl(byActor, video) | ||
14 | 15 | ||
15 | const accountsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | 16 | return buildLikeActivity(url, byActor, video, audience) |
16 | |||
17 | // Send to origin | ||
18 | if (video.isOwned() === false) { | ||
19 | const audience = getVideoAudience(video, accountsInvolvedInVideo) | ||
20 | const data = buildLikeActivity(url, byActor, video, audience) | ||
21 | |||
22 | return unicastTo(data, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | ||
23 | } | 17 | } |
24 | 18 | ||
25 | // Send to followers | 19 | return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) |
26 | const audience = getObjectFollowersAudience(accountsInvolvedInVideo) | ||
27 | const activity = buildLikeActivity(url, byActor, video, audience) | ||
28 | |||
29 | const followersException = [ byActor ] | ||
30 | return broadcastToFollowers(activity, byActor, accountsInvolvedInVideo, t, followersException) | ||
31 | } | 20 | } |
32 | 21 | ||
33 | function buildLikeActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityLike { | 22 | function buildLikeActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityLike { |
diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index a50673c79..5236d2cb3 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts | |||
@@ -11,8 +11,8 @@ import { ActorModel } from '../../../models/activitypub/actor' | |||
11 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 11 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
12 | import { VideoModel } from '../../../models/video/video' | 12 | import { VideoModel } from '../../../models/video/video' |
13 | import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' | 13 | import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' |
14 | import { broadcastToFollowers, unicastTo } from './utils' | 14 | import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' |
15 | import { audiencify, getActorsInvolvedInVideo, getAudience, getObjectFollowersAudience, getVideoAudience } from '../audience' | 15 | import { audiencify, getAudience } from '../audience' |
16 | import { buildCreateActivity, buildDislikeActivity } from './send-create' | 16 | import { buildCreateActivity, buildDislikeActivity } from './send-create' |
17 | import { buildFollowActivity } from './send-follow' | 17 | import { buildFollowActivity } from './send-follow' |
18 | import { buildLikeActivity } from './send-like' | 18 | import { buildLikeActivity } from './send-like' |
@@ -39,79 +39,44 @@ async function sendUndoFollow (actorFollow: ActorFollowModel, t: Transaction) { | |||
39 | return unicastTo(undoActivity, me, following.inboxUrl) | 39 | return unicastTo(undoActivity, me, following.inboxUrl) |
40 | } | 40 | } |
41 | 41 | ||
42 | async function sendUndoLike (byActor: ActorModel, video: VideoModel, t: Transaction) { | 42 | async function sendUndoAnnounce (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { |
43 | logger.info('Creating job to undo a like of video %s.', video.url) | 43 | logger.info('Creating job to undo announce %s.', videoShare.url) |
44 | 44 | ||
45 | const likeUrl = getVideoLikeActivityPubUrl(byActor, video) | 45 | const undoUrl = getUndoActivityPubUrl(videoShare.url) |
46 | const undoUrl = getUndoActivityPubUrl(likeUrl) | ||
47 | 46 | ||
48 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | 47 | const { activity: announceActivity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t) |
49 | const likeActivity = buildLikeActivity(likeUrl, byActor, video) | 48 | const undoActivity = undoActivityData(undoUrl, byActor, announceActivity) |
50 | 49 | ||
51 | // Send to origin | 50 | const followersException = [ byActor ] |
52 | if (video.isOwned() === false) { | 51 | return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) |
53 | const audience = getVideoAudience(video, actorsInvolvedInVideo) | 52 | } |
54 | const undoActivity = undoActivityData(undoUrl, byActor, likeActivity, audience) | ||
55 | 53 | ||
56 | return unicastTo(undoActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | 54 | async function sendUndoLike (byActor: ActorModel, video: VideoModel, t: Transaction) { |
57 | } | 55 | logger.info('Creating job to undo a like of video %s.', video.url) |
58 | 56 | ||
59 | const audience = getObjectFollowersAudience(actorsInvolvedInVideo) | 57 | const likeUrl = getVideoLikeActivityPubUrl(byActor, video) |
60 | const undoActivity = undoActivityData(undoUrl, byActor, likeActivity, audience) | 58 | const likeActivity = buildLikeActivity(likeUrl, byActor, video) |
61 | 59 | ||
62 | const followersException = [ byActor ] | 60 | return sendUndoVideoRelatedActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t }) |
63 | return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) | ||
64 | } | 61 | } |
65 | 62 | ||
66 | async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { | 63 | async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { |
67 | logger.info('Creating job to undo a dislike of video %s.', video.url) | 64 | logger.info('Creating job to undo a dislike of video %s.', video.url) |
68 | 65 | ||
69 | const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video) | 66 | const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video) |
70 | const undoUrl = getUndoActivityPubUrl(dislikeUrl) | ||
71 | |||
72 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | ||
73 | const dislikeActivity = buildDislikeActivity(byActor, video) | 67 | const dislikeActivity = buildDislikeActivity(byActor, video) |
74 | const createDislikeActivity = buildCreateActivity(dislikeUrl, byActor, dislikeActivity) | 68 | const createDislikeActivity = buildCreateActivity(dislikeUrl, byActor, dislikeActivity) |
75 | 69 | ||
76 | if (video.isOwned() === false) { | 70 | return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: createDislikeActivity, transaction: t }) |
77 | const audience = getVideoAudience(video, actorsInvolvedInVideo) | ||
78 | const undoActivity = undoActivityData(undoUrl, byActor, createDislikeActivity, audience) | ||
79 | |||
80 | return unicastTo(undoActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | ||
81 | } | ||
82 | |||
83 | const undoActivity = undoActivityData(undoUrl, byActor, createDislikeActivity) | ||
84 | |||
85 | const followersException = [ byActor ] | ||
86 | return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) | ||
87 | } | ||
88 | |||
89 | async function sendUndoAnnounce (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { | ||
90 | logger.info('Creating job to undo announce %s.', videoShare.url) | ||
91 | |||
92 | const undoUrl = getUndoActivityPubUrl(videoShare.url) | ||
93 | |||
94 | const { activity: announceActivity, actorsInvolvedInVideo } = await buildAnnounceWithVideoAudience(byActor, videoShare, video, t) | ||
95 | const undoActivity = undoActivityData(undoUrl, byActor, announceActivity) | ||
96 | |||
97 | const followersException = [ byActor ] | ||
98 | return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) | ||
99 | } | 71 | } |
100 | 72 | ||
101 | async function sendUndoCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel, t: Transaction) { | 73 | async function sendUndoCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel, t: Transaction) { |
102 | logger.info('Creating job to undo cache file %s.', redundancyModel.url) | 74 | logger.info('Creating job to undo cache file %s.', redundancyModel.url) |
103 | 75 | ||
104 | const undoUrl = getUndoActivityPubUrl(redundancyModel.url) | ||
105 | |||
106 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.VideoFile.Video.id) | 76 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.VideoFile.Video.id) |
107 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(video, t) | ||
108 | |||
109 | const audience = getVideoAudience(video, actorsInvolvedInVideo) | ||
110 | const createActivity = buildCreateActivity(redundancyModel.url, byActor, redundancyModel.toActivityPubObject()) | 77 | const createActivity = buildCreateActivity(redundancyModel.url, byActor, redundancyModel.toActivityPubObject()) |
111 | 78 | ||
112 | const undoActivity = undoActivityData(undoUrl, byActor, createActivity, audience) | 79 | return sendUndoVideoRelatedActivity({ byActor, video, url: redundancyModel.url, activity: createActivity, transaction: t }) |
113 | |||
114 | return unicastTo(undoActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | ||
115 | } | 80 | } |
116 | 81 | ||
117 | // --------------------------------------------------------------------------- | 82 | // --------------------------------------------------------------------------- |
@@ -144,3 +109,19 @@ function undoActivityData ( | |||
144 | audience | 109 | audience |
145 | ) | 110 | ) |
146 | } | 111 | } |
112 | |||
113 | async function sendUndoVideoRelatedActivity (options: { | ||
114 | byActor: ActorModel, | ||
115 | video: VideoModel, | ||
116 | url: string, | ||
117 | activity: ActivityFollow | ActivityLike | ActivityCreate | ActivityAnnounce, | ||
118 | transaction: Transaction | ||
119 | }) { | ||
120 | const activityBuilder = (audience: ActivityAudience) => { | ||
121 | const undoUrl = getUndoActivityPubUrl(options.url) | ||
122 | |||
123 | return undoActivityData(undoUrl, options.byActor, options.activity, audience) | ||
124 | } | ||
125 | |||
126 | return sendVideoRelatedActivity(activityBuilder, options) | ||
127 | } | ||
diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 605473338..ec46789b7 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts | |||
@@ -7,8 +7,8 @@ import { VideoModel } from '../../../models/video/video' | |||
7 | import { VideoChannelModel } from '../../../models/video/video-channel' | 7 | import { VideoChannelModel } from '../../../models/video/video-channel' |
8 | import { VideoShareModel } from '../../../models/video/video-share' | 8 | import { VideoShareModel } from '../../../models/video/video-share' |
9 | import { getUpdateActivityPubUrl } from '../url' | 9 | import { getUpdateActivityPubUrl } from '../url' |
10 | import { broadcastToFollowers, unicastTo } from './utils' | 10 | import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' |
11 | import { audiencify, getActorsInvolvedInVideo, getAudience, getObjectFollowersAudience } from '../audience' | 11 | import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf } from '../audience' |
12 | import { logger } from '../../../helpers/logger' | 12 | import { logger } from '../../../helpers/logger' |
13 | import { VideoCaptionModel } from '../../../models/video/video-caption' | 13 | import { VideoCaptionModel } from '../../../models/video/video-caption' |
14 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' | 14 | import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' |
@@ -61,16 +61,16 @@ async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelMod | |||
61 | async function sendUpdateCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel) { | 61 | async function sendUpdateCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel) { |
62 | logger.info('Creating job to update cache file %s.', redundancyModel.url) | 62 | logger.info('Creating job to update cache file %s.', redundancyModel.url) |
63 | 63 | ||
64 | const url = getUpdateActivityPubUrl(redundancyModel.url, redundancyModel.updatedAt.toISOString()) | ||
65 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.VideoFile.Video.id) | 64 | const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.VideoFile.Video.id) |
66 | 65 | ||
67 | const redundancyObject = redundancyModel.toActivityPubObject() | 66 | const activityBuilder = (audience: ActivityAudience) => { |
67 | const redundancyObject = redundancyModel.toActivityPubObject() | ||
68 | const url = getUpdateActivityPubUrl(redundancyModel.url, redundancyModel.updatedAt.toISOString()) | ||
68 | 69 | ||
69 | const accountsInvolvedInVideo = await getActorsInvolvedInVideo(video, undefined) | 70 | return buildUpdateActivity(url, byActor, redundancyObject, audience) |
70 | const audience = getObjectFollowersAudience(accountsInvolvedInVideo) | 71 | } |
71 | 72 | ||
72 | const updateActivity = buildUpdateActivity(url, byActor, redundancyObject, audience) | 73 | return sendVideoRelatedActivity(activityBuilder, { byActor, video }) |
73 | return unicastTo(updateActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl) | ||
74 | } | 74 | } |
75 | 75 | ||
76 | // --------------------------------------------------------------------------- | 76 | // --------------------------------------------------------------------------- |
diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts index c20c15633..69706e620 100644 --- a/server/lib/activitypub/send/utils.ts +++ b/server/lib/activitypub/send/utils.ts | |||
@@ -1,13 +1,36 @@ | |||
1 | import { Transaction } from 'sequelize' | 1 | import { Transaction } from 'sequelize' |
2 | import { Activity } from '../../../../shared/models/activitypub' | 2 | import { Activity, ActivityAudience } from '../../../../shared/models/activitypub' |
3 | import { logger } from '../../../helpers/logger' | 3 | import { logger } from '../../../helpers/logger' |
4 | import { ActorModel } from '../../../models/activitypub/actor' | 4 | import { ActorModel } from '../../../models/activitypub/actor' |
5 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' | 5 | import { ActorFollowModel } from '../../../models/activitypub/actor-follow' |
6 | import { JobQueue } from '../../job-queue' | 6 | import { JobQueue } from '../../job-queue' |
7 | import { VideoModel } from '../../../models/video/video' | 7 | import { VideoModel } from '../../../models/video/video' |
8 | import { getActorsInvolvedInVideo } from '../audience' | 8 | import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' |
9 | import { getServerActor } from '../../../helpers/utils' | 9 | import { getServerActor } from '../../../helpers/utils' |
10 | 10 | ||
11 | async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { | ||
12 | byActor: ActorModel, | ||
13 | video: VideoModel, | ||
14 | transaction?: Transaction | ||
15 | }) { | ||
16 | const actorsInvolvedInVideo = await getActorsInvolvedInVideo(options.video, options.transaction) | ||
17 | |||
18 | // Send to origin | ||
19 | if (options.video.isOwned() === false) { | ||
20 | const audience = getRemoteVideoAudience(options.video, actorsInvolvedInVideo) | ||
21 | const activity = activityBuilder(audience) | ||
22 | |||
23 | return unicastTo(activity, options.byActor, options.video.VideoChannel.Account.Actor.sharedInboxUrl) | ||
24 | } | ||
25 | |||
26 | // Send to followers | ||
27 | const audience = getAudienceFromFollowersOf(actorsInvolvedInVideo) | ||
28 | const activity = activityBuilder(audience) | ||
29 | |||
30 | const actorsException = [ options.byActor ] | ||
31 | return broadcastToFollowers(activity, options.byActor, actorsInvolvedInVideo, options.transaction, actorsException) | ||
32 | } | ||
33 | |||
11 | async function forwardVideoRelatedActivity ( | 34 | async function forwardVideoRelatedActivity ( |
12 | activity: Activity, | 35 | activity: Activity, |
13 | t: Transaction, | 36 | t: Transaction, |
@@ -110,7 +133,8 @@ export { | |||
110 | unicastTo, | 133 | unicastTo, |
111 | forwardActivity, | 134 | forwardActivity, |
112 | broadcastToActors, | 135 | broadcastToActors, |
113 | forwardVideoRelatedActivity | 136 | forwardVideoRelatedActivity, |
137 | sendVideoRelatedActivity | ||
114 | } | 138 | } |
115 | 139 | ||
116 | // --------------------------------------------------------------------------- | 140 | // --------------------------------------------------------------------------- |
diff --git a/server/tests/api/server/stats.ts b/server/tests/api/server/stats.ts index d8a3268bb..cb229e876 100644 --- a/server/tests/api/server/stats.ts +++ b/server/tests/api/server/stats.ts | |||
@@ -65,7 +65,6 @@ describe('Test stats (excluding redundancy)', function () { | |||
65 | expect(data.totalVideos).to.equal(1) | 65 | expect(data.totalVideos).to.equal(1) |
66 | expect(data.totalInstanceFollowers).to.equal(2) | 66 | expect(data.totalInstanceFollowers).to.equal(2) |
67 | expect(data.totalInstanceFollowing).to.equal(1) | 67 | expect(data.totalInstanceFollowing).to.equal(1) |
68 | expect(data.videosRedundancy).to.have.lengthOf(0) | ||
69 | }) | 68 | }) |
70 | 69 | ||
71 | it('Should have the correct stats on instance 2', async function () { | 70 | it('Should have the correct stats on instance 2', async function () { |
@@ -80,7 +79,6 @@ describe('Test stats (excluding redundancy)', function () { | |||
80 | expect(data.totalVideos).to.equal(1) | 79 | expect(data.totalVideos).to.equal(1) |
81 | expect(data.totalInstanceFollowers).to.equal(1) | 80 | expect(data.totalInstanceFollowers).to.equal(1) |
82 | expect(data.totalInstanceFollowing).to.equal(1) | 81 | expect(data.totalInstanceFollowing).to.equal(1) |
83 | expect(data.videosRedundancy).to.have.lengthOf(0) | ||
84 | }) | 82 | }) |
85 | 83 | ||
86 | it('Should have the correct stats on instance 3', async function () { | 84 | it('Should have the correct stats on instance 3', async function () { |
@@ -95,7 +93,6 @@ describe('Test stats (excluding redundancy)', function () { | |||
95 | expect(data.totalVideos).to.equal(1) | 93 | expect(data.totalVideos).to.equal(1) |
96 | expect(data.totalInstanceFollowing).to.equal(1) | 94 | expect(data.totalInstanceFollowing).to.equal(1) |
97 | expect(data.totalInstanceFollowers).to.equal(0) | 95 | expect(data.totalInstanceFollowers).to.equal(0) |
98 | expect(data.videosRedundancy).to.have.lengthOf(0) | ||
99 | }) | 96 | }) |
100 | 97 | ||
101 | after(async function () { | 98 | after(async function () { |