]>
Commit | Line | Data |
---|---|---|
afffe988 | 1 | import { Transaction } from 'sequelize' |
e4f97bab | 2 | import { |
afffe988 C |
3 | ActivityAccept, |
4 | ActivityAdd, | |
5 | ActivityCreate, | |
6 | ActivityDelete, | |
7 | ActivityFollow, | |
8 | ActivityUpdate | |
9 | } from '../../../shared/models/activitypub/activity' | |
8e13fa7d | 10 | import { getActivityPubUrl } from '../../helpers/activitypub' |
8e10cf1a | 11 | import { logger } from '../../helpers/logger' |
afffe988 C |
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' | |
9a27cdc2 C |
16 | import { ACTIVITY_PUB } from '../../initializers/constants' |
17 | import { VideoPrivacy } from '../../../shared/models/videos/video-privacy.enum' | |
afffe988 C |
18 | |
19 | async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) { | |
20 | const byAccount = videoChannel.Account | |
e4f97bab | 21 | |
e4f97bab | 22 | const videoChannelObject = videoChannel.toActivityPubObject() |
afffe988 | 23 | const data = await createActivityData(videoChannel.url, byAccount, videoChannelObject) |
e4f97bab | 24 | |
afffe988 | 25 | return broadcastToFollowers(data, byAccount, [ byAccount ], t) |
e4f97bab C |
26 | } |
27 | ||
afffe988 C |
28 | async function sendUpdateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) { |
29 | const byAccount = videoChannel.Account | |
30 | ||
e4f97bab | 31 | const videoChannelObject = videoChannel.toActivityPubObject() |
afffe988 | 32 | const data = await updateActivityData(videoChannel.url, byAccount, videoChannelObject) |
e4f97bab | 33 | |
d7d5611c | 34 | const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id) |
afffe988 | 35 | accountsInvolved.push(byAccount) |
d7d5611c | 36 | |
afffe988 | 37 | return broadcastToFollowers(data, byAccount, accountsInvolved, t) |
e4f97bab C |
38 | } |
39 | ||
afffe988 C |
40 | async function sendDeleteVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) { |
41 | const byAccount = videoChannel.Account | |
42 | ||
43 | const data = await deleteActivityData(videoChannel.url, byAccount) | |
e4f97bab | 44 | |
d7d5611c | 45 | const accountsInvolved = await db.VideoChannelShare.loadAccountsByShare(videoChannel.id) |
afffe988 | 46 | accountsInvolved.push(byAccount) |
d7d5611c | 47 | |
afffe988 | 48 | return broadcastToFollowers(data, byAccount, accountsInvolved, t) |
e4f97bab C |
49 | } |
50 | ||
afffe988 C |
51 | async function sendAddVideo (video: VideoInstance, t: Transaction) { |
52 | const byAccount = video.VideoChannel.Account | |
53 | ||
e4f97bab | 54 | const videoObject = video.toActivityPubObject() |
9a27cdc2 | 55 | const data = await addActivityData(video.url, byAccount, video, video.VideoChannel.url, videoObject) |
e4f97bab | 56 | |
afffe988 | 57 | return broadcastToFollowers(data, byAccount, [ byAccount ], t) |
e4f97bab C |
58 | } |
59 | ||
afffe988 C |
60 | async function sendUpdateVideo (video: VideoInstance, t: Transaction) { |
61 | const byAccount = video.VideoChannel.Account | |
62 | ||
e4f97bab | 63 | const videoObject = video.toActivityPubObject() |
afffe988 | 64 | const data = await updateActivityData(video.url, byAccount, videoObject) |
e4f97bab | 65 | |
d7d5611c | 66 | const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id) |
afffe988 | 67 | accountsInvolved.push(byAccount) |
d7d5611c | 68 | |
afffe988 | 69 | return broadcastToFollowers(data, byAccount, accountsInvolved, t) |
e4f97bab C |
70 | } |
71 | ||
afffe988 C |
72 | async function sendDeleteVideo (video: VideoInstance, t: Transaction) { |
73 | const byAccount = video.VideoChannel.Account | |
74 | ||
75 | const data = await deleteActivityData(video.url, byAccount) | |
e4f97bab | 76 | |
d7d5611c | 77 | const accountsInvolved = await db.VideoShare.loadAccountsByShare(video.id) |
afffe988 | 78 | accountsInvolved.push(byAccount) |
d7d5611c | 79 | |
afffe988 | 80 | return broadcastToFollowers(data, byAccount, accountsInvolved, t) |
e4f97bab C |
81 | } |
82 | ||
afffe988 | 83 | async function sendDeleteAccount (account: AccountInstance, t: Transaction) { |
350e31d6 | 84 | const data = await deleteActivityData(account.url, account) |
7a7724e6 | 85 | |
afffe988 | 86 | return broadcastToFollowers(data, account, [ account ], t) |
efc32059 C |
87 | } |
88 | ||
afffe988 | 89 | async function sendVideoChannelAnnounce (byAccount: AccountInstance, videoChannel: VideoChannelInstance, t: Transaction) { |
20494f12 | 90 | const url = getActivityPubUrl('videoChannel', videoChannel.uuid) + '#announce' |
afffe988 | 91 | const announcedActivity = await createActivityData(url, videoChannel.Account, videoChannel.toActivityPubObject()) |
20494f12 C |
92 | |
93 | const data = await announceActivityData(url, byAccount, announcedActivity) | |
afffe988 | 94 | return broadcastToFollowers(data, byAccount, [ byAccount ], t) |
20494f12 | 95 | } |
efc32059 | 96 | |
afffe988 | 97 | async function sendVideoAnnounce (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { |
20494f12 | 98 | const url = getActivityPubUrl('video', video.uuid) + '#announce' |
efc32059 | 99 | |
20494f12 | 100 | const videoChannel = video.VideoChannel |
9a27cdc2 | 101 | const announcedActivity = await addActivityData(url, videoChannel.Account, video, videoChannel.url, video.toActivityPubObject()) |
20494f12 C |
102 | |
103 | const data = await announceActivityData(url, byAccount, announcedActivity) | |
afffe988 | 104 | return broadcastToFollowers(data, byAccount, [ byAccount ], t) |
7a7724e6 C |
105 | } |
106 | ||
afffe988 | 107 | async function sendVideoAbuse (byAccount: AccountInstance, videoAbuse: VideoAbuseInstance, video: VideoInstance, t: Transaction) { |
8e13fa7d | 108 | const url = getActivityPubUrl('videoAbuse', videoAbuse.id.toString()) |
afffe988 | 109 | const data = await createActivityData(url, byAccount, videoAbuse.toActivityPubObject()) |
8e13fa7d | 110 | |
afffe988 | 111 | return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) |
8e13fa7d C |
112 | } |
113 | ||
afffe988 C |
114 | async function sendAccept (byAccount: AccountInstance, toAccount: AccountInstance, t: Transaction) { |
115 | const data = await acceptActivityData(byAccount) | |
ce548a10 | 116 | |
afffe988 | 117 | return unicastTo(data, byAccount, toAccount.inboxUrl, t) |
ce548a10 C |
118 | } |
119 | ||
afffe988 C |
120 | async function sendFollow (byAccount: AccountInstance, toAccount: AccountInstance, t: Transaction) { |
121 | const data = await followActivityData(toAccount.url, byAccount) | |
ce548a10 | 122 | |
afffe988 | 123 | return unicastTo(data, byAccount, toAccount.inboxUrl, t) |
ce548a10 C |
124 | } |
125 | ||
e4f97bab C |
126 | // --------------------------------------------------------------------------- |
127 | ||
128 | export { | |
571389d4 C |
129 | sendCreateVideoChannel, |
130 | sendUpdateVideoChannel, | |
131 | sendDeleteVideoChannel, | |
132 | sendAddVideo, | |
133 | sendUpdateVideo, | |
7a7724e6 | 134 | sendDeleteVideo, |
ce548a10 C |
135 | sendDeleteAccount, |
136 | sendAccept, | |
8e13fa7d | 137 | sendFollow, |
efc32059 | 138 | sendVideoAbuse, |
20494f12 C |
139 | sendVideoChannelAnnounce, |
140 | sendVideoAnnounce | |
e4f97bab C |
141 | } |
142 | ||
143 | // --------------------------------------------------------------------------- | |
144 | ||
afffe988 | 145 | async function broadcastToFollowers (data: any, byAccount: AccountInstance, toAccountFollowers: AccountInstance[], t: Transaction) { |
efc32059 C |
146 | const toAccountFollowerIds = toAccountFollowers.map(a => a.id) |
147 | const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds) | |
8e10cf1a | 148 | if (result.data.length === 0) { |
efc32059 | 149 | logger.info('Not broadcast because of 0 followers for %s.', toAccountFollowerIds.join(', ')) |
8e10cf1a C |
150 | return |
151 | } | |
571389d4 C |
152 | |
153 | const jobPayload = { | |
154 | uris: result.data, | |
afffe988 | 155 | signatureAccountId: byAccount.id, |
571389d4 C |
156 | body: data |
157 | } | |
158 | ||
afffe988 | 159 | return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload) |
e4f97bab C |
160 | } |
161 | ||
afffe988 | 162 | async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) { |
ce548a10 | 163 | const jobPayload = { |
8e13fa7d | 164 | uris: [ toAccountUrl ], |
afffe988 | 165 | signatureAccountId: byAccount.id, |
ce548a10 C |
166 | body: data |
167 | } | |
168 | ||
afffe988 | 169 | return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload) |
e4f97bab C |
170 | } |
171 | ||
9a27cdc2 C |
172 | async function getAudience (accountSender: AccountInstance, isPublic = true) { |
173 | const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls() | |
e4f97bab | 174 | |
9a27cdc2 C |
175 | // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47 |
176 | let to = [] | |
177 | let cc = [] | |
178 | ||
179 | if (isPublic) { | |
180 | to = [ ACTIVITY_PUB.PUBLIC ] | |
181 | cc = followerInboxUrls | |
182 | } else { // Unlisted | |
183 | to = followerInboxUrls | |
184 | cc = [ ACTIVITY_PUB.PUBLIC ] | |
185 | } | |
186 | ||
187 | return { to, cc } | |
e4f97bab C |
188 | } |
189 | ||
afffe988 | 190 | async function createActivityData (url: string, byAccount: AccountInstance, object: any) { |
9a27cdc2 | 191 | const { to, cc } = await getAudience(byAccount) |
afffe988 | 192 | const activity: ActivityCreate = { |
e4f97bab C |
193 | type: 'Create', |
194 | id: url, | |
195 | actor: byAccount.url, | |
196 | to, | |
9a27cdc2 | 197 | cc, |
e4f97bab C |
198 | object |
199 | } | |
200 | ||
afffe988 | 201 | return activity |
e4f97bab C |
202 | } |
203 | ||
204 | async function updateActivityData (url: string, byAccount: AccountInstance, object: any) { | |
9a27cdc2 | 205 | const { to, cc } = await getAudience(byAccount) |
afffe988 | 206 | const activity: ActivityUpdate = { |
e4f97bab C |
207 | type: 'Update', |
208 | id: url, | |
209 | actor: byAccount.url, | |
210 | to, | |
9a27cdc2 | 211 | cc, |
e4f97bab C |
212 | object |
213 | } | |
214 | ||
afffe988 | 215 | return activity |
e4f97bab C |
216 | } |
217 | ||
7a7724e6 | 218 | async function deleteActivityData (url: string, byAccount: AccountInstance) { |
afffe988 | 219 | const activity: ActivityDelete = { |
7a7724e6 | 220 | type: 'Delete', |
e4f97bab | 221 | id: url, |
7a7724e6 | 222 | actor: byAccount.url |
e4f97bab C |
223 | } |
224 | ||
afffe988 | 225 | return activity |
e4f97bab C |
226 | } |
227 | ||
9a27cdc2 C |
228 | async function addActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, target: string, object: any) { |
229 | const videoPublic = video.privacy === VideoPrivacy.PUBLIC | |
230 | ||
231 | const { to, cc } = await getAudience(byAccount, videoPublic) | |
afffe988 | 232 | const activity: ActivityAdd = { |
e4f97bab C |
233 | type: 'Add', |
234 | id: url, | |
235 | actor: byAccount.url, | |
236 | to, | |
9a27cdc2 | 237 | cc, |
e4f97bab C |
238 | object, |
239 | target | |
240 | } | |
241 | ||
afffe988 | 242 | return activity |
e4f97bab | 243 | } |
ce548a10 | 244 | |
efc32059 | 245 | async function announceActivityData (url: string, byAccount: AccountInstance, object: any) { |
afffe988 | 246 | const activity = { |
efc32059 C |
247 | type: 'Announce', |
248 | id: url, | |
249 | actor: byAccount.url, | |
250 | object | |
251 | } | |
252 | ||
afffe988 | 253 | return activity |
efc32059 C |
254 | } |
255 | ||
ce548a10 | 256 | async function followActivityData (url: string, byAccount: AccountInstance) { |
afffe988 | 257 | const activity: ActivityFollow = { |
ce548a10 C |
258 | type: 'Follow', |
259 | id: byAccount.url, | |
260 | actor: byAccount.url, | |
261 | object: url | |
262 | } | |
263 | ||
afffe988 | 264 | return activity |
ce548a10 C |
265 | } |
266 | ||
267 | async function acceptActivityData (byAccount: AccountInstance) { | |
afffe988 | 268 | const activity: ActivityAccept = { |
ce548a10 C |
269 | type: 'Accept', |
270 | id: byAccount.url, | |
271 | actor: byAccount.url | |
272 | } | |
273 | ||
afffe988 | 274 | return activity |
ce548a10 | 275 | } |