1 import { Transaction } from 'sequelize'
9 } from '../../../shared/models/activitypub/activity'
10 import { getActivityPubUrl } from '../../helpers/activitypub'
11 import { logger } from '../../helpers/logger'
12 import { database as db } from '../../initializers'
13 import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../models'
14 import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
15 import { activitypubHttpJobScheduler } from '../jobs'
16 import { ACTIVITY_PUB } from '../../initializers/constants'
17 import { VideoPrivacy } from '../../../shared/models/videos/video-privacy.enum'
19 async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
20 const byAccount = videoChannel.Account
22 const videoChannelObject = videoChannel.toActivityPubObject()
23 const data = await createActivityData(videoChannel.url, byAccount, videoChannelObject)
25 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
28 async function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
29 const byAccount = videoChannel.Account
31 const videoChannelObject = videoChannel.toActivityPubObject()
32 const data = await updateActivityData(videoChannel.url, byAccount, videoChannelObject)
34 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id)
35 accountsInvolved.push(byAccount)
37 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
40 async function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) {
41 const byAccount = videoChannel.Account
43 const data = await deleteActivityData(videoChannel.url, byAccount)
45 const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id)
46 accountsInvolved.push(byAccount)
48 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
51 async function sendAddVideo (video: VideoInstance, t: Transaction) {
52 const byAccount = video.VideoChannel.Account
54 const videoObject = video.toActivityPubObject()
55 const data = await addActivityData(video.url, byAccount, video, video.VideoChannel.url, videoObject)
57 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
60 async function sendUpdateVideo (video: VideoInstance, t: Transaction) {
61 const byAccount = video.VideoChannel.Account
63 const videoObject = video.toActivityPubObject()
64 const data = await updateActivityData(video.url, byAccount, videoObject)
66 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id)
67 accountsInvolved.push(byAccount)
69 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
72 async function sendDeleteVideo (video: VideoInstance, t: Transaction) {
73 const byAccount = video.VideoChannel.Account
75 const data = await deleteActivityData(video.url, byAccount)
77 const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id)
78 accountsInvolved.push(byAccount)
80 return broadcastToFollowers(data, byAccount, accountsInvolved, t)
83 async function sendDeleteAccount (account: AccountInstance, t: Transaction) {
84 const data = await deleteActivityData(account.url, account)
86 return broadcastToFollowers(data, account, [ account ], t)
89 async function sendVideoChannelAnnounce (byAccount: AccountInstance, videoChannel: VideoChannelInstance, t: Transaction) {
90 const url = getActivityPubUrl('videoChannel', videoChannel.uuid) + '#announce'
91 const announcedActivity = await createActivityData(url, videoChannel.Account, videoChannel.toActivityPubObject())
93 const data = await announceActivityData(url, byAccount, announcedActivity)
94 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
97 async function sendVideoAnnounce (byAccount: AccountInstance, video: VideoInstance, t: Transaction) {
98 const url = getActivityPubUrl('video', video.uuid) + '#announce'
100 const videoChannel = video.VideoChannel
101 const announcedActivity = await addActivityData(url, videoChannel.Account, video, videoChannel.url, video.toActivityPubObject())
103 const data = await announceActivityData(url, byAccount, announcedActivity)
104 return broadcastToFollowers(data, byAccount, [ byAccount ], t)
107 async function sendVideoAbuse (byAccount: AccountInstance, videoAbuse: VideoAbuseInstance, video: VideoInstance, t: Transaction) {
108 const url = getActivityPubUrl('videoAbuse', videoAbuse.id.toString())
109 const data = await createActivityData(url, byAccount, videoAbuse.toActivityPubObject())
111 return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t)
114 async function sendAccept (byAccount: AccountInstance, toAccount: AccountInstance, t: Transaction) {
115 const data = await acceptActivityData(byAccount)
117 return unicastTo(data, byAccount, toAccount.inboxUrl, t)
120 async function sendFollow (byAccount: AccountInstance, toAccount: AccountInstance, t: Transaction) {
121 const data = await followActivityData(toAccount.url, byAccount)
123 return unicastTo(data, byAccount, toAccount.inboxUrl, t)
126 // ---------------------------------------------------------------------------
129 sendCreateVideoChannel,
130 sendUpdateVideoChannel,
131 sendDeleteVideoChannel,
139 sendVideoChannelAnnounce,
143 // ---------------------------------------------------------------------------
145 async function broadcastToFollowers (data: any, byAccount: AccountInstance, toAccountFollowers: AccountInstance[], t: Transaction) {
146 const toAccountFollowerIds = toAccountFollowers.map(a => a.id)
147 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds)
148 if (result.data.length === 0) {
149 logger.info('Not broadcast because of 0 followers for %s.', toAccountFollowerIds.join(', '))
155 signatureAccountId: byAccount.id,
159 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
162 async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) {
164 uris: [ toAccountUrl ],
165 signatureAccountId: byAccount.id,
169 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
172 async function getAudience (accountSender: AccountInstance, isPublic = true) {
173 const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls()
175 // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
180 to = [ ACTIVITY_PUB.PUBLIC ]
181 cc = followerInboxUrls
183 to = followerInboxUrls
184 cc = [ ACTIVITY_PUB.PUBLIC ]
190 async function createActivityData (url: string, byAccount: AccountInstance, object: any) {
191 const { to, cc } = await getAudience(byAccount)
192 const activity: ActivityCreate = {
195 actor: byAccount.url,
204 async function updateActivityData (url: string, byAccount: AccountInstance, object: any) {
205 const { to, cc } = await getAudience(byAccount)
206 const activity: ActivityUpdate = {
209 actor: byAccount.url,
218 async function deleteActivityData (url: string, byAccount: AccountInstance) {
219 const activity: ActivityDelete = {
228 async function addActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, target: string, object: any) {
229 const videoPublic = video.privacy === VideoPrivacy.PUBLIC
231 const { to, cc } = await getAudience(byAccount, videoPublic)
232 const activity: ActivityAdd = {
235 actor: byAccount.url,
245 async function announceActivityData (url: string, byAccount: AccountInstance, object: any) {
249 actor: byAccount.url,
256 async function followActivityData (url: string, byAccount: AccountInstance) {
257 const activity: ActivityFollow = {
260 actor: byAccount.url,
267 async function acceptActivityData (byAccount: AccountInstance) {
268 const activity: ActivityAccept = {