aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--server/controllers/activitypub/outbox.ts19
-rw-r--r--server/lib/activitypub/send/misc.ts5
-rw-r--r--server/models/activitypub/actor-follow.ts3
-rw-r--r--server/models/activitypub/actor.ts51
-rw-r--r--server/models/video/video.ts4
-rw-r--r--server/tests/api/server/follows.ts10
6 files changed, 72 insertions, 20 deletions
diff --git a/server/controllers/activitypub/outbox.ts b/server/controllers/activitypub/outbox.ts
index 620f9ee83..ab12a7c4b 100644
--- a/server/controllers/activitypub/outbox.ts
+++ b/server/controllers/activitypub/outbox.ts
@@ -4,9 +4,11 @@ import { activityPubCollectionPagination } from '../../helpers/activitypub'
4import { pageToStartAndCount } from '../../helpers/core-utils' 4import { pageToStartAndCount } from '../../helpers/core-utils'
5import { ACTIVITY_PUB } from '../../initializers/constants' 5import { ACTIVITY_PUB } from '../../initializers/constants'
6import { announceActivityData, createActivityData } from '../../lib/activitypub/send' 6import { announceActivityData, createActivityData } from '../../lib/activitypub/send'
7import { buildAudience } from '../../lib/activitypub/send/misc'
7import { getAnnounceActivityPubUrl } from '../../lib/activitypub/url' 8import { getAnnounceActivityPubUrl } from '../../lib/activitypub/url'
8import { asyncMiddleware, localAccountValidator } from '../../middlewares' 9import { asyncMiddleware, localAccountValidator } from '../../middlewares'
9import { AccountModel } from '../../models/account/account' 10import { AccountModel } from '../../models/account/account'
11import { ActorModel } from '../../models/activitypub/actor'
10import { VideoModel } from '../../models/video/video' 12import { VideoModel } from '../../models/video/video'
11 13
12const outboxRouter = express.Router() 14const outboxRouter = express.Router()
@@ -34,20 +36,29 @@ async function outboxController (req: express.Request, res: express.Response, ne
34 const data = await VideoModel.listAllAndSharedByActorForOutbox(actor.id, start, count) 36 const data = await VideoModel.listAllAndSharedByActorForOutbox(actor.id, start, count)
35 const activities: Activity[] = [] 37 const activities: Activity[] = []
36 38
39 // Avoid too many SQL requests
40 const actors = data.data.map(v => v.VideoChannel.Account.Actor)
41 actors.push(actor)
42
43 const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined)
44
37 for (const video of data.data) { 45 for (const video of data.data) {
38 const videoObject = video.toActivityPubObject() 46 const videoObject = video.toActivityPubObject()
39 47
40 const videoChannel = video.VideoChannel 48 const byActor = video.VideoChannel.Account.Actor
49 const createActivityAudience = buildAudience(followersMatrix[byActor.id])
50
41 // This is a shared video 51 // This is a shared video
42 if (video.VideoShares !== undefined && video.VideoShares.length !== 0) { 52 if (video.VideoShares !== undefined && video.VideoShares.length !== 0) {
43 const createActivity = await createActivityData(video.url, videoChannel.Account.Actor, videoObject, undefined) 53 const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience)
44 54
55 const announceAudience = buildAudience(followersMatrix[actor.id])
45 const url = getAnnounceActivityPubUrl(video.url, actor) 56 const url = getAnnounceActivityPubUrl(video.url, actor)
46 const announceActivity = await announceActivityData(url, actor, createActivity, undefined) 57 const announceActivity = await announceActivityData(url, actor, createActivity, undefined, announceAudience)
47 58
48 activities.push(announceActivity) 59 activities.push(announceActivity)
49 } else { 60 } else {
50 const createActivity = await createActivityData(video.url, videoChannel.Account.Actor, videoObject, undefined) 61 const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience)
51 62
52 activities.push(createActivity) 63 activities.push(createActivity)
53 } 64 }
diff --git a/server/lib/activitypub/send/misc.ts b/server/lib/activitypub/send/misc.ts
index 261586ae4..dc0d3de57 100644
--- a/server/lib/activitypub/send/misc.ts
+++ b/server/lib/activitypub/send/misc.ts
@@ -143,6 +143,10 @@ async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) {
143async function getAudience (actorSender: ActorModel, t: Transaction, isPublic = true) { 143async function getAudience (actorSender: ActorModel, t: Transaction, isPublic = true) {
144 const followerInboxUrls = await actorSender.getFollowerSharedInboxUrls(t) 144 const followerInboxUrls = await actorSender.getFollowerSharedInboxUrls(t)
145 145
146 return buildAudience(followerInboxUrls, isPublic)
147}
148
149function buildAudience (followerInboxUrls: string[], isPublic = true) {
146 // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47 150 // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
147 let to = [] 151 let to = []
148 let cc = [] 152 let cc = []
@@ -183,6 +187,7 @@ async function computeUris (toActors: ActorModel[], actorsException: ActorModel[
183export { 187export {
184 broadcastToFollowers, 188 broadcastToFollowers,
185 unicastTo, 189 unicastTo,
190 buildAudience,
186 getAudience, 191 getAudience,
187 getOriginVideoAudience, 192 getOriginVideoAudience,
188 getActorsInvolvedInVideo, 193 getActorsInvolvedInVideo,
diff --git a/server/models/activitypub/actor-follow.ts b/server/models/activitypub/actor-follow.ts
index ced481547..416496607 100644
--- a/server/models/activitypub/actor-follow.ts
+++ b/server/models/activitypub/actor-follow.ts
@@ -375,7 +375,8 @@ export class ActorFollowModel extends Model<ActorFollowModel> {
375 score: { 375 score: {
376 [Sequelize.Op.lte]: 0 376 [Sequelize.Op.lte]: 0
377 } 377 }
378 } 378 },
379 logger: false
379 } 380 }
380 381
381 return ActorFollowModel.findAll(query) 382 return ActorFollowModel.findAll(query)
diff --git a/server/models/activitypub/actor.ts b/server/models/activitypub/actor.ts
index 408d4df23..269149a31 100644
--- a/server/models/activitypub/actor.ts
+++ b/server/models/activitypub/actor.ts
@@ -167,17 +167,17 @@ export class ActorModel extends Model<ActorModel> {
167 }, 167 },
168 onDelete: 'cascade' 168 onDelete: 'cascade'
169 }) 169 })
170 AccountFollowing: ActorFollowModel[] 170 ActorFollowing: ActorFollowModel[]
171 171
172 @HasMany(() => ActorFollowModel, { 172 @HasMany(() => ActorFollowModel, {
173 foreignKey: { 173 foreignKey: {
174 name: 'targetActorId', 174 name: 'targetActorId',
175 allowNull: false 175 allowNull: false
176 }, 176 },
177 as: 'followers', 177 as: 'ActorFollowers',
178 onDelete: 'cascade' 178 onDelete: 'cascade'
179 }) 179 })
180 AccountFollowers: ActorFollowModel[] 180 ActorFollowers: ActorFollowModel[]
181 181
182 @ForeignKey(() => ServerModel) 182 @ForeignKey(() => ServerModel)
183 @Column 183 @Column
@@ -277,6 +277,45 @@ export class ActorModel extends Model<ActorModel> {
277 }) 277 })
278 } 278 }
279 279
280 static async getActorsFollowerSharedInboxUrls (actors: ActorModel[], t: Sequelize.Transaction) {
281 const query = {
282 // attribute: [],
283 where: {
284 id: {
285 [Sequelize.Op.in]: actors.map(a => a.id)
286 }
287 },
288 include: [
289 {
290 // attributes: [ ],
291 model: ActorFollowModel.unscoped(),
292 required: true,
293 as: 'ActorFollowers',
294 where: {
295 state: 'accepted'
296 },
297 include: [
298 {
299 attributes: [ 'sharedInboxUrl' ],
300 model: ActorModel.unscoped(),
301 as: 'ActorFollower',
302 required: true
303 }
304 ]
305 }
306 ],
307 transaction: t
308 }
309
310 const hash: { [ id: number ]: string[] } = {}
311 const res = await ActorModel.findAll(query)
312 for (const actor of res) {
313 hash[actor.id] = actor.ActorFollowers.map(follow => follow.ActorFollower.sharedInboxUrl)
314 }
315
316 return hash
317 }
318
280 toFormattedJSON () { 319 toFormattedJSON () {
281 let avatar: Avatar = null 320 let avatar: Avatar = null
282 if (this.Avatar) { 321 if (this.Avatar) {
@@ -347,10 +386,12 @@ export class ActorModel extends Model<ActorModel> {
347 attributes: [ 'sharedInboxUrl' ], 386 attributes: [ 'sharedInboxUrl' ],
348 include: [ 387 include: [
349 { 388 {
350 model: ActorFollowModel, 389 attribute: [],
390 model: ActorFollowModel.unscoped(),
351 required: true, 391 required: true,
352 as: 'followers', 392 as: 'ActorFollowers',
353 where: { 393 where: {
394 state: 'accepted',
354 targetActorId: this.id 395 targetActorId: this.id
355 } 396 }
356 } 397 }
diff --git a/server/models/video/video.ts b/server/models/video/video.ts
index 514edfd9c..0d115367f 100644
--- a/server/models/video/video.ts
+++ b/server/models/video/video.ts
@@ -67,7 +67,7 @@ enum ScopeNames {
67 '$VideoChannel.Account.Actor.serverId$': null 67 '$VideoChannel.Account.Actor.serverId$': null
68 }, 68 },
69 { 69 {
70 '$VideoChannel.Account.Actor.followers.actorId$': actorId 70 '$VideoChannel.Account.Actor.ActorFollowers.actorId$': actorId
71 }, 71 },
72 { 72 {
73 id: { 73 id: {
@@ -106,7 +106,7 @@ enum ScopeNames {
106 { 106 {
107 attributes: [ ], 107 attributes: [ ],
108 model: ActorFollowModel.unscoped(), 108 model: ActorFollowModel.unscoped(),
109 as: 'followers', 109 as: 'ActorFollowers',
110 required: false 110 required: false
111 } 111 }
112 ] 112 ]
diff --git a/server/tests/api/server/follows.ts b/server/tests/api/server/follows.ts
index ac614d605..c0115e534 100644
--- a/server/tests/api/server/follows.ts
+++ b/server/tests/api/server/follows.ts
@@ -4,7 +4,7 @@ import * as chai from 'chai'
4import 'mocha' 4import 'mocha'
5import { Video, VideoPrivacy } from '../../../../shared/models/videos' 5import { Video, VideoPrivacy } from '../../../../shared/models/videos'
6import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model' 6import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
7import { checkVideoFilesWereRemoved, completeVideoCheck, getVideoChannelsList } from '../../utils' 7import { checkVideoFilesWereRemoved, completeVideoCheck } from '../../utils'
8 8
9import { 9import {
10 flushAndRunMultipleServers, flushTests, getVideosList, killallServers, ServerInfo, setAccessTokensToServers, uploadVideo, 10 flushAndRunMultipleServers, flushTests, getVideosList, killallServers, ServerInfo, setAccessTokensToServers, uploadVideo,
@@ -12,7 +12,7 @@ import {
12} from '../../utils/index' 12} from '../../utils/index'
13import { dateIsValid } from '../../utils/miscs/miscs' 13import { dateIsValid } from '../../utils/miscs/miscs'
14import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../../utils/server/follows' 14import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../../utils/server/follows'
15import { expectAccountFollows, getAccountsList } from '../../utils/users/accounts' 15import { expectAccountFollows } from '../../utils/users/accounts'
16import { userLogin } from '../../utils/users/login' 16import { userLogin } from '../../utils/users/login'
17import { createUser } from '../../utils/users/users' 17import { createUser } from '../../utils/users/users'
18import { 18import {
@@ -354,12 +354,6 @@ describe('Test follows', function () {
354 let res = await getVideosList(servers[ 0 ].url) 354 let res = await getVideosList(servers[ 0 ].url)
355 expect(res.body.total).to.equal(1) 355 expect(res.body.total).to.equal(1)
356 356
357 res = await getVideoChannelsList(servers[0].url, 0, 1)
358 expect(res.body.total).to.equal(2)
359
360 res = await getAccountsList(servers[0].url)
361 expect(res.body.total).to.equal(2)
362
363 await checkVideoFilesWereRemoved(video4.uuid, servers[0].serverNumber) 357 await checkVideoFilesWereRemoved(video4.uuid, servers[0].serverNumber)
364 }) 358 })
365 359