]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - server/lib/activitypub/process/process-create.ts
Fix lint
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / process / process-create.ts
index 1ddd817dbb9dcfc115d893961fc89f732e5b4e30..32be37e2de534e617c889418cb9d48c8dcd9f71d 100644 (file)
@@ -1,19 +1,22 @@
 import * as Bluebird from 'bluebird'
 import { ActivityCreate, VideoTorrentObject } from '../../../../shared'
 import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects'
+import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
 import { VideoRateType } from '../../../../shared/models/videos'
-import { logger, retryTransactionWrapper } from '../../../helpers'
+import { retryTransactionWrapper } from '../../../helpers/database-utils'
+import { logger } from '../../../helpers/logger'
 import { sequelizeTypescript } from '../../../initializers'
 import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
 import { ActorModel } from '../../../models/activitypub/actor'
 import { TagModel } from '../../../models/video/tag'
 import { VideoModel } from '../../../models/video/video'
 import { VideoAbuseModel } from '../../../models/video/video-abuse'
+import { VideoCommentModel } from '../../../models/video/video-comment'
 import { VideoFileModel } from '../../../models/video/video-file'
 import { getOrCreateActorAndServerAndModel } from '../actor'
-import { forwardActivity } from '../send/misc'
+import { forwardActivity, getActorsInvolvedInVideo } from '../send/misc'
 import { generateThumbnailFromUrl } from '../videos'
-import { addVideoShares, videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc'
+import { addVideoComments, addVideoShares, videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc'
 
 async function processCreateActivity (activity: ActivityCreate) {
   const activityObject = activity.object
@@ -28,6 +31,8 @@ async function processCreateActivity (activity: ActivityCreate) {
     return processCreateVideo(actor, activity)
   } else if (activityType === 'Flag') {
     return processCreateVideoAbuse(actor, activityObject as VideoAbuseObject)
+  } else if (activityType === 'Note') {
+    return processCreateVideoComment(actor, activity)
   }
 
   logger.warn('Unknown activity object type %s when creating activity.', activityType, { activity: activity.id })
@@ -62,17 +67,25 @@ async function processCreateVideo (
 
   // Process outside the transaction because we could fetch remote data
   if (videoToCreateData.likes && Array.isArray(videoToCreateData.likes.orderedItems)) {
+    logger.info('Adding likes of video %s.', video.uuid)
     await createRates(videoToCreateData.likes.orderedItems, video, 'like')
   }
 
   if (videoToCreateData.dislikes && Array.isArray(videoToCreateData.dislikes.orderedItems)) {
+    logger.info('Adding dislikes of video %s.', video.uuid)
     await createRates(videoToCreateData.dislikes.orderedItems, video, 'dislike')
   }
 
   if (videoToCreateData.shares && Array.isArray(videoToCreateData.shares.orderedItems)) {
+    logger.info('Adding shares of video %s.', video.uuid)
     await addVideoShares(video, videoToCreateData.shares.orderedItems)
   }
 
+  if (videoToCreateData.comments && Array.isArray(videoToCreateData.comments.orderedItems)) {
+    logger.info('Adding comments of video %s.', video.uuid)
+    await addVideoComments(video, videoToCreateData.comments.orderedItems)
+  }
+
   return video
 }
 
@@ -184,7 +197,7 @@ function createVideoDislike (byActor: ActorModel, activity: ActivityCreate) {
   })
 }
 
-async function processCreateView (byAccount: ActorModel, activity: ActivityCreate) {
+async function processCreateView (byActor: ActorModel, activity: ActivityCreate) {
   const view = activity.object as ViewObject
 
   const video = await VideoModel.loadByUrlAndPopulateAccount(view.object)
@@ -198,7 +211,7 @@ async function processCreateView (byAccount: ActorModel, activity: ActivityCreat
 
   if (video.isOwned()) {
     // Don't resend the activity to the sender
-    const exceptions = [ byAccount ]
+    const exceptions = [ byActor ]
     await forwardActivity(activity, undefined, exceptions)
   }
 }
@@ -236,3 +249,71 @@ function addRemoteVideoAbuse (actor: ActorModel, videoAbuseToCreateData: VideoAb
     logger.info('Remote abuse for video uuid %s created', videoAbuseToCreateData.object)
   })
 }
+
+function processCreateVideoComment (byActor: ActorModel, activity: ActivityCreate) {
+  const options = {
+    arguments: [ byActor, activity ],
+    errorMessage: 'Cannot create video comment with many retries.'
+  }
+
+  return retryTransactionWrapper(createVideoComment, options)
+}
+
+function createVideoComment (byActor: ActorModel, activity: ActivityCreate) {
+  const comment = activity.object as VideoCommentObject
+  const byAccount = byActor.Account
+
+  if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url)
+
+  return sequelizeTypescript.transaction(async t => {
+    let video = await VideoModel.loadByUrlAndPopulateAccount(comment.inReplyTo, t)
+    let objectToCreate
+
+    // This is a new thread
+    if (video) {
+      objectToCreate = {
+        url: comment.id,
+        text: comment.content,
+        originCommentId: null,
+        inReplyToComment: null,
+        videoId: video.id,
+        accountId: byAccount.id
+      }
+    } else {
+      const inReplyToComment = await VideoCommentModel.loadByUrl(comment.inReplyTo, t)
+      if (!inReplyToComment) throw new Error('Unknown replied comment ' + comment.inReplyTo)
+
+      video = await VideoModel.load(inReplyToComment.videoId)
+
+      const originCommentId = inReplyToComment.originCommentId || inReplyToComment.id
+      objectToCreate = {
+        url: comment.id,
+        text: comment.content,
+        originCommentId,
+        inReplyToCommentId: inReplyToComment.id,
+        videoId: video.id,
+        accountId: byAccount.id
+      }
+    }
+
+    const options = {
+      where: {
+        url: objectToCreate.url
+      },
+      defaults: objectToCreate,
+      transaction: t
+    }
+    const [ ,created ] = await VideoCommentModel.findOrCreate(options)
+
+    if (video.isOwned() && created === true) {
+      // Don't resend the activity to the sender
+      const exceptions = [ byActor ]
+
+      // Mastodon does not add our announces in audience, so we forward to them manually
+      const additionalActors = await getActorsInvolvedInVideo(video, t)
+      const additionalFollowerUrls = additionalActors.map(a => a.followersUrl)
+
+      await forwardActivity(activity, t, exceptions, additionalFollowerUrls)
+    }
+  })
+}