1 import { Transaction } from 'sequelize'
2 import { Activity } from '../../../../shared/models/activitypub/activity'
3 import { logger } from '../../../helpers/logger'
4 import { ACTIVITY_PUB, database as db } from '../../../initializers'
5 import { AccountInstance } from '../../../models/account/account-interface'
6 import { VideoChannelInstance } from '../../../models/index'
7 import { VideoInstance } from '../../../models/video/video-interface'
9 activitypubHttpJobScheduler,
10 ActivityPubHttpPayload
11 } from '../../jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler'
13 async function forwardActivity (
16 followersException: AccountInstance[] = []
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 db.Account.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: AccountInstance,
49 toAccountFollowers: AccountInstance[],
51 followersException: AccountInstance[] = []
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: AccountInstance, 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: VideoInstance, accountsInvolvedInVideo: AccountInstance[]) {
84 to: [ video.VideoChannel.Account.url ],
85 cc: accountsInvolvedInVideo.map(a => a.followersUrl)
89 function getOriginVideoChannelAudience (videoChannel: VideoChannelInstance, accountsInvolved: AccountInstance[]) {
91 to: [ videoChannel.Account.url ],
92 cc: accountsInvolved.map(a => a.followersUrl)
96 function getObjectFollowersAudience (accountsInvolvedInObject: AccountInstance[]) {
98 to: accountsInvolvedInObject.map(a => a.followersUrl),
103 async function getAccountsInvolvedInVideo (video: VideoInstance, t: Transaction) {
104 const accountsToForwardView = await db.VideoShare.loadAccountsByShare(video.id, t)
105 accountsToForwardView.push(video.VideoChannel.Account)
107 return accountsToForwardView
110 async function getAccountsInvolvedInVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
111 const accountsToForwardView = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id, t)
112 accountsToForwardView.push(videoChannel.Account)
114 return accountsToForwardView
117 async function getAudience (accountSender: AccountInstance, 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: AccountInstance[], followersException: AccountInstance[], t: Transaction) {
136 const toAccountFollowerIds = toAccountFollower.map(a => a.id)
138 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds, t)
139 const followersSharedInboxException = followersException.map(f => f.sharedInboxUrl)
140 const uris = result.data.filter(sharedInbox => followersSharedInboxException.indexOf(sharedInbox) === -1)
145 // ---------------------------------------------------------------------------
148 broadcastToFollowers,
149 getOriginVideoChannelAudience,
152 getOriginVideoAudience,
153 getAccountsInvolvedInVideo,
154 getAccountsInvolvedInVideoChannel,
155 getObjectFollowersAudience,