import { pageToStartAndCount } from '../../helpers/core-utils'
import { ACTIVITY_PUB } from '../../initializers/constants'
import { announceActivityData, createActivityData } from '../../lib/activitypub/send'
+import { buildAudience } from '../../lib/activitypub/send/misc'
import { getAnnounceActivityPubUrl } from '../../lib/activitypub/url'
import { asyncMiddleware, localAccountValidator } from '../../middlewares'
import { AccountModel } from '../../models/account/account'
+import { ActorModel } from '../../models/activitypub/actor'
import { VideoModel } from '../../models/video/video'
const outboxRouter = express.Router()
const data = await VideoModel.listAllAndSharedByActorForOutbox(actor.id, start, count)
const activities: Activity[] = []
+ // Avoid too many SQL requests
+ const actors = data.data.map(v => v.VideoChannel.Account.Actor)
+ actors.push(actor)
+
+ const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined)
+
for (const video of data.data) {
const videoObject = video.toActivityPubObject()
- const videoChannel = video.VideoChannel
+ const byActor = video.VideoChannel.Account.Actor
+ const createActivityAudience = buildAudience(followersMatrix[byActor.id])
+
// This is a shared video
if (video.VideoShares !== undefined && video.VideoShares.length !== 0) {
- const createActivity = await createActivityData(video.url, videoChannel.Account.Actor, videoObject, undefined)
+ const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience)
+ const announceAudience = buildAudience(followersMatrix[actor.id])
const url = getAnnounceActivityPubUrl(video.url, actor)
- const announceActivity = await announceActivityData(url, actor, createActivity, undefined)
+ const announceActivity = await announceActivityData(url, actor, createActivity, undefined, announceAudience)
activities.push(announceActivity)
} else {
- const createActivity = await createActivityData(video.url, videoChannel.Account.Actor, videoObject, undefined)
+ const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience)
activities.push(createActivity)
}
async function getAudience (actorSender: ActorModel, t: Transaction, isPublic = true) {
const followerInboxUrls = await actorSender.getFollowerSharedInboxUrls(t)
+ return buildAudience(followerInboxUrls, isPublic)
+}
+
+function buildAudience (followerInboxUrls: string[], isPublic = true) {
// Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
let to = []
let cc = []
export {
broadcastToFollowers,
unicastTo,
+ buildAudience,
getAudience,
getOriginVideoAudience,
getActorsInvolvedInVideo,
score: {
[Sequelize.Op.lte]: 0
}
- }
+ },
+ logger: false
}
return ActorFollowModel.findAll(query)
},
onDelete: 'cascade'
})
- AccountFollowing: ActorFollowModel[]
+ ActorFollowing: ActorFollowModel[]
@HasMany(() => ActorFollowModel, {
foreignKey: {
name: 'targetActorId',
allowNull: false
},
- as: 'followers',
+ as: 'ActorFollowers',
onDelete: 'cascade'
})
- AccountFollowers: ActorFollowModel[]
+ ActorFollowers: ActorFollowModel[]
@ForeignKey(() => ServerModel)
@Column
})
}
+ static async getActorsFollowerSharedInboxUrls (actors: ActorModel[], t: Sequelize.Transaction) {
+ const query = {
+ // attribute: [],
+ where: {
+ id: {
+ [Sequelize.Op.in]: actors.map(a => a.id)
+ }
+ },
+ include: [
+ {
+ // attributes: [ ],
+ model: ActorFollowModel.unscoped(),
+ required: true,
+ as: 'ActorFollowers',
+ where: {
+ state: 'accepted'
+ },
+ include: [
+ {
+ attributes: [ 'sharedInboxUrl' ],
+ model: ActorModel.unscoped(),
+ as: 'ActorFollower',
+ required: true
+ }
+ ]
+ }
+ ],
+ transaction: t
+ }
+
+ const hash: { [ id: number ]: string[] } = {}
+ const res = await ActorModel.findAll(query)
+ for (const actor of res) {
+ hash[actor.id] = actor.ActorFollowers.map(follow => follow.ActorFollower.sharedInboxUrl)
+ }
+
+ return hash
+ }
+
toFormattedJSON () {
let avatar: Avatar = null
if (this.Avatar) {
attributes: [ 'sharedInboxUrl' ],
include: [
{
- model: ActorFollowModel,
+ attribute: [],
+ model: ActorFollowModel.unscoped(),
required: true,
- as: 'followers',
+ as: 'ActorFollowers',
where: {
+ state: 'accepted',
targetActorId: this.id
}
}
'$VideoChannel.Account.Actor.serverId$': null
},
{
- '$VideoChannel.Account.Actor.followers.actorId$': actorId
+ '$VideoChannel.Account.Actor.ActorFollowers.actorId$': actorId
},
{
id: {
{
attributes: [ ],
model: ActorFollowModel.unscoped(),
- as: 'followers',
+ as: 'ActorFollowers',
required: false
}
]
import 'mocha'
import { Video, VideoPrivacy } from '../../../../shared/models/videos'
import { VideoComment, VideoCommentThreadTree } from '../../../../shared/models/videos/video-comment.model'
-import { checkVideoFilesWereRemoved, completeVideoCheck, getVideoChannelsList } from '../../utils'
+import { checkVideoFilesWereRemoved, completeVideoCheck } from '../../utils'
import {
flushAndRunMultipleServers, flushTests, getVideosList, killallServers, ServerInfo, setAccessTokensToServers, uploadVideo,
} from '../../utils/index'
import { dateIsValid } from '../../utils/miscs/miscs'
import { follow, getFollowersListPaginationAndSort, getFollowingListPaginationAndSort, unfollow } from '../../utils/server/follows'
-import { expectAccountFollows, getAccountsList } from '../../utils/users/accounts'
+import { expectAccountFollows } from '../../utils/users/accounts'
import { userLogin } from '../../utils/users/login'
import { createUser } from '../../utils/users/users'
import {
let res = await getVideosList(servers[ 0 ].url)
expect(res.body.total).to.equal(1)
- res = await getVideoChannelsList(servers[0].url, 0, 1)
- expect(res.body.total).to.equal(2)
-
- res = await getAccountsList(servers[0].url)
- expect(res.body.total).to.equal(2)
-
await checkVideoFilesWereRemoved(video4.uuid, servers[0].serverNumber)
})