]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/send/misc.ts
Correctly forward like/dislikes and undo
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / send / misc.ts
CommitLineData
54141398
C
1import { Transaction } from 'sequelize'
2import { logger } from '../../../helpers/logger'
3import { ACTIVITY_PUB, database as db } from '../../../initializers'
4import { AccountInstance } from '../../../models/account/account-interface'
63c93323
C
5import {
6 activitypubHttpJobScheduler,
7 ActivityPubHttpPayload
8} from '../../jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler'
0032ebe9 9import { VideoInstance } from '../../../models/video/video-interface'
63c93323
C
10import { Activity } from '../../../../shared/models/activitypub/activity'
11
12async function forwardActivity (
13 activity: Activity,
14 t: Transaction,
15 followersException: AccountInstance[] = []
16) {
17 const to = activity.to || []
18 const cc = activity.cc || []
19
20 const followersUrls: string[] = []
21 for (const dest of to.concat(cc)) {
22 if (dest.endsWith('/followers')) {
23 followersUrls.push(dest)
24 }
25 }
26
27 const toAccountFollowers = await db.Account.listByFollowersUrls(followersUrls)
28 const uris = await computeFollowerUris(toAccountFollowers, followersException)
29
30 if (uris.length === 0) {
31 logger.info('0 followers for %s, no forwarding.', toAccountFollowers.map(a => a.id).join(', '))
32 return
33 }
34
35 logger.debug('Creating forwarding job.', { uris })
36
37 const jobPayload: ActivityPubHttpPayload = {
38 uris,
39 body: activity
40 }
41
42 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
43}
54141398 44
40ff5707
C
45async function broadcastToFollowers (
46 data: any,
47 byAccount: AccountInstance,
48 toAccountFollowers: AccountInstance[],
49 t: Transaction,
50 followersException: AccountInstance[] = []
51) {
63c93323
C
52 const uris = await computeFollowerUris(toAccountFollowers, followersException)
53 if (uris.length === 0) {
54 logger.info('0 followers for %s, no broadcasting.', toAccountFollowers.map(a => a.id).join(', '))
55 return
54141398
C
56 }
57
63c93323 58 logger.debug('Creating broadcast job.', { uris })
40ff5707 59
63c93323 60 const jobPayload: ActivityPubHttpPayload = {
40ff5707 61 uris,
54141398
C
62 signatureAccountId: byAccount.id,
63 body: data
64 }
65
66 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpBroadcastHandler', jobPayload)
67}
68
69async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: string, t: Transaction) {
63c93323
C
70 logger.debug('Creating unicast job.', { uri: toAccountUrl })
71
72 const jobPayload: ActivityPubHttpPayload = {
54141398
C
73 uris: [ toAccountUrl ],
74 signatureAccountId: byAccount.id,
75 body: data
76 }
77
78 return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload)
79}
80
63c93323 81function getOriginVideoAudience (video: VideoInstance, accountsInvolvedInVideo: AccountInstance[]) {
0032ebe9
C
82 return {
83 to: [ video.VideoChannel.Account.url ],
63c93323 84 cc: accountsInvolvedInVideo.map(a => a.followersUrl)
0032ebe9
C
85 }
86}
87
63c93323 88function getVideoFollowersAudience (accountsInvolvedInVideo: AccountInstance[]) {
0032ebe9 89 return {
63c93323 90 to: accountsInvolvedInVideo.map(a => a.followersUrl),
0032ebe9
C
91 cc: []
92 }
93}
94
63c93323 95async function getAccountsInvolvedInVideo (video: VideoInstance) {
0032ebe9
C
96 const accountsToForwardView = await db.VideoShare.loadAccountsByShare(video.id)
97 accountsToForwardView.push(video.VideoChannel.Account)
98
99 return accountsToForwardView
100}
101
54141398
C
102async function getAudience (accountSender: AccountInstance, isPublic = true) {
103 const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls()
104
105 // Thanks Mastodon: https://github.com/tootsuite/mastodon/blob/master/app/lib/activitypub/tag_manager.rb#L47
106 let to = []
107 let cc = []
108
109 if (isPublic) {
110 to = [ ACTIVITY_PUB.PUBLIC ]
111 cc = followerInboxUrls
112 } else { // Unlisted
113 to = followerInboxUrls
114 cc = [ ACTIVITY_PUB.PUBLIC ]
115 }
116
117 return { to, cc }
118}
119
63c93323
C
120async function computeFollowerUris (toAccountFollower: AccountInstance[], followersException: AccountInstance[]) {
121 const toAccountFollowerIds = toAccountFollower.map(a => a.id)
122
123 const result = await db.AccountFollow.listAcceptedFollowerSharedInboxUrls(toAccountFollowerIds)
124 const followersSharedInboxException = followersException.map(f => f.sharedInboxUrl)
125 const uris = result.data.filter(sharedInbox => followersSharedInboxException.indexOf(sharedInbox) === -1)
126
127 return uris
128}
129
54141398
C
130// ---------------------------------------------------------------------------
131
132export {
133 broadcastToFollowers,
134 unicastTo,
0032ebe9
C
135 getAudience,
136 getOriginVideoAudience,
63c93323
C
137 getAccountsInvolvedInVideo,
138 getVideoFollowersAudience,
139 forwardActivity
54141398 140}