send-create.ts 6.3 KB

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