1 import { Transaction } from 'sequelize'
2 import { Activity } from '../../../../shared/models/activitypub'
3 import { logger } from '../../../helpers'
4 import { ACTIVITY_PUB } from '../../../initializers'
5 import { AccountModel } from '../../../models/account/account'
6 import { AccountFollowModel } from '../../../models/account/account-follow'
7 import { VideoModel } from '../../../models/video/video'
8 import { VideoChannelModel } from '../../../models/video/video-channel'
9 import { VideoChannelShareModel } from '../../../models/video/video-channel-share'
10 import { VideoShareModel } from '../../../models/video/video-share'
11 import { activitypubHttpJobScheduler, ActivityPubHttpPayload } from '../../jobs/activitypub-http-job-scheduler'
13 async function forwardActivity (
16 followersException: AccountModel[] = []
18 const to = activity.to || []
19 const cc = activity.cc || []
21 const followersUrls: string[] = []
22 for (const dest of to.concat(cc)) {
23 if (dest.endsWith('/followers')) {
24 followersUrls.push(dest)
28 const toAccountFollowers = await AccountModel.listByFollowersUrls(followersUrls, t)
29 const uris = await computeFollowerUris(toAccountFollowers, followersException, t)
31 if (uris.length === 0) {
32 logger.info('0 followers for %s, no forwarding.', toAccountFollowers.map(a => a.id).join(', '))
36 logger.debug('Creating forwarding job.', { uris })
38 const jobPayload: ActivityPubHttpPayload = {
43 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
46 async function broadcastToFollowers (
48 byAccount: AccountModel,
49 toAccountFollowers: AccountModel[],
51 followersException: AccountModel[] = []
53 const uris = await computeFollowerUris(toAccountFollowers, followersException, t)
54 if (uris.length === 0) {
55 logger.info('0 followers for %s, no broadcasting.', toAccountFollowers.map(a => a.id).join(', '))
59 logger.debug('Creating broadcast job.', { uris })
61 const jobPayload: ActivityPubHttpPayload = {
63 signatureAccountId: byAccount.id,
67 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
70 async function unicastTo (data: any, byAccount: AccountModel, toAccountUrl: string, t: Transaction) {
71 logger.debug('Creating unicast job.', { uri: toAccountUrl })
73 const jobPayload: ActivityPubHttpPayload = {
74 uris: [ toAccountUrl ],
75 signatureAccountId: byAccount.id,
79 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
82 function getOriginVideoAudience (video: VideoModel, accountsInvolvedInVideo: AccountModel[]) {
84 to: [ video.VideoChannel.Account.url ],
85 cc: accountsInvolvedInVideo.map(a => a.followersUrl)
89 function getOriginVideoChannelAudience (videoChannel: VideoChannelModel, accountsInvolved: AccountModel[]) {
91 to: [ videoChannel.Account.url ],
92 cc: accountsInvolved.map(a => a.followersUrl)
96 function getObjectFollowersAudience (accountsInvolvedInObject: AccountModel[]) {
98 to: accountsInvolvedInObject.map(a => a.followersUrl),
103 async function getAccountsInvolvedInVideo (video: VideoModel, t: Transaction) {
104 const accountsToForwardView = await VideoShareModel.loadAccountsByShare(video.id, t)
105 accountsToForwardView.push(video.VideoChannel.Account)
107 return accountsToForwardView
110 async function getAccountsInvolvedInVideoChannel (videoChannel: VideoChannelModel, t: Transaction) {
111 const accountsToForwardView = await VideoChannelShareModel.loadAccountsByShare(videoChannel.id, t)
112 accountsToForwardView.push(videoChannel.Account)
114 return accountsToForwardView
117 async function getAudience (accountSender: AccountModel, t: Transaction, isPublic = true) {
118 const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls(t)
120 // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
125 to = [ ACTIVITY_PUB.PUBLIC ]
126 cc = followerInboxUrls
128 to = followerInboxUrls
129 cc = [ ACTIVITY_PUB.PUBLIC ]
135 async function computeFollowerUris (toAccountFollower: AccountModel[], followersException: AccountModel[], t: Transaction) {
136 const toAccountFollowerIds = toAccountFollower.map(a => a.id)
138 const result = await AccountFollowModel.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds, t)
139 const followersSharedInboxException = followersException.map(f => f.sharedInboxUrl)
140 return result.data.filter(sharedInbox => followersSharedInboxException.indexOf(sharedInbox) === -1)
143 // ---------------------------------------------------------------------------
146 broadcastToFollowers,
147 getOriginVideoChannelAudience,
150 getOriginVideoAudience,
151 getAccountsInvolvedInVideo,
152 getAccountsInvolvedInVideoChannel,
153 getObjectFollowersAudience,