Move to eslint
[oweals/peertube.git] / server / lib / activitypub / send / send-create.ts
1 import { Transaction } from 'sequelize'
2 import { ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub'
3 import { VideoPrivacy } from '../../../../shared/models/videos'
4 import { VideoCommentModel } from '../../../models/video/video-comment'
5 import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils'
6 import { audiencify, getActorsInvolvedInVideo, getAudience, getAudienceFromFollowersOf, getVideoCommentAudience } from '../audience'
7 import { logger } from '../../../helpers/logger'
8 import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model'
9 import { getServerActor } from '../../../helpers/utils'
10 import {
11   MActorLight,
12   MCommentOwnerVideo,
13   MVideoAccountLight,
14   MVideoAP,
15   MVideoPlaylistFull,
16   MVideoRedundancyFileVideo,
17   MVideoRedundancyStreamingPlaylistVideo
18 } from '../../../typings/models'
19
20 async function sendCreateVideo (video: MVideoAP, t: Transaction) {
21   if (!video.hasPrivacyForFederation()) return undefined
22
23   logger.info('Creating job to send video creation of %s.', video.url)
24
25   const byActor = video.VideoChannel.Account.Actor
26   const videoObject = video.toActivityPubObject()
27
28   const audience = getAudience(byActor, video.privacy === VideoPrivacy.PUBLIC)
29   const createActivity = buildCreateActivity(video.url, byActor, videoObject, audience)
30
31   return broadcastToFollowers(createActivity, byActor, [ byActor ], t)
32 }
33
34 async function sendCreateCacheFile (
35   byActor: MActorLight,
36   video: MVideoAccountLight,
37   fileRedundancy: MVideoRedundancyStreamingPlaylistVideo | MVideoRedundancyFileVideo
38 ) {
39   logger.info('Creating job to send file cache of %s.', fileRedundancy.url)
40
41   return sendVideoRelatedCreateActivity({
42     byActor,
43     video,
44     url: fileRedundancy.url,
45     object: fileRedundancy.toActivityPubObject()
46   })
47 }
48
49 async function sendCreateVideoPlaylist (playlist: MVideoPlaylistFull, t: Transaction) {
50   if (playlist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined
51
52   logger.info('Creating job to send create video playlist of %s.', playlist.url)
53
54   const byActor = playlist.OwnerAccount.Actor
55   const audience = getAudience(byActor, playlist.privacy === VideoPlaylistPrivacy.PUBLIC)
56
57   const object = await playlist.toActivityPubObject(null, t)
58   const createActivity = buildCreateActivity(playlist.url, byActor, object, audience)
59
60   const serverActor = await getServerActor()
61   const toFollowersOf = [ byActor, serverActor ]
62
63   if (playlist.VideoChannel) toFollowersOf.push(playlist.VideoChannel.Actor)
64
65   return broadcastToFollowers(createActivity, byActor, toFollowersOf, t)
66 }
67
68 async function sendCreateVideoComment (comment: MCommentOwnerVideo, t: Transaction) {
69   logger.info('Creating job to send comment %s.', comment.url)
70
71   const isOrigin = comment.Video.isOwned()
72
73   const byActor = comment.Account.Actor
74   const threadParentComments = await VideoCommentModel.listThreadParentComments(comment, t)
75   const commentObject = comment.toActivityPubObject(threadParentComments)
76
77   const actorsInvolvedInComment = await getActorsInvolvedInVideo(comment.Video, t)
78   // Add the actor that commented too
79   actorsInvolvedInComment.push(byActor)
80
81   const parentsCommentActors = threadParentComments.map(c => c.Account.Actor)
82
83   let audience: ActivityAudience
84   if (isOrigin) {
85     audience = getVideoCommentAudience(comment, threadParentComments, actorsInvolvedInComment, isOrigin)
86   } else {
87     audience = getAudienceFromFollowersOf(actorsInvolvedInComment.concat(parentsCommentActors))
88   }
89
90   const createActivity = buildCreateActivity(comment.url, byActor, commentObject, audience)
91
92   // This was a reply, send it to the parent actors
93   const actorsException = [ byActor ]
94   await broadcastToActors(createActivity, byActor, parentsCommentActors, t, actorsException)
95
96   // Broadcast to our followers
97   await broadcastToFollowers(createActivity, byActor, [ byActor ], t)
98
99   // Send to actors involved in the comment
100   if (isOrigin) return broadcastToFollowers(createActivity, byActor, actorsInvolvedInComment, t, actorsException)
101
102   // Send to origin
103   t.afterCommit(() => unicastTo(createActivity, byActor, comment.Video.VideoChannel.Account.Actor.getSharedInbox()))
104 }
105
106 function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate {
107   if (!audience) audience = getAudience(byActor)
108
109   return audiencify(
110     {
111       type: 'Create' as 'Create',
112       id: url + '/activity',
113       actor: byActor.url,
114       object: audiencify(object, audience)
115     },
116     audience
117   )
118 }
119
120 // ---------------------------------------------------------------------------
121
122 export {
123   sendCreateVideo,
124   buildCreateActivity,
125   sendCreateVideoComment,
126   sendCreateVideoPlaylist,
127   sendCreateCacheFile
128 }
129
130 // ---------------------------------------------------------------------------
131
132 async function sendVideoRelatedCreateActivity (options: {
133   byActor: MActorLight
134   video: MVideoAccountLight
135   url: string
136   object: any
137   transaction?: Transaction
138 }) {
139   const activityBuilder = (audience: ActivityAudience) => {
140     return buildCreateActivity(options.url, options.byActor, options.object, audience)
141   }
142
143   return sendVideoRelatedActivity(activityBuilder, options)
144 }