From 4e50b6a1c9a3eb261e04ede73241648e6edf21d6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Mon, 27 Nov 2017 14:44:51 +0100 Subject: Add shares forward and collection on videos/video channels --- server/lib/activitypub/process/misc.ts | 57 +++++++++++- server/lib/activitypub/process/process-add.ts | 16 ++-- server/lib/activitypub/process/process-announce.ts | 100 +++++++++++++++++---- server/lib/activitypub/process/process-create.ts | 12 ++- 4 files changed, 155 insertions(+), 30 deletions(-) (limited to 'server/lib/activitypub/process') diff --git a/server/lib/activitypub/process/misc.ts b/server/lib/activitypub/process/misc.ts index eefbe2884..f20e588ab 100644 --- a/server/lib/activitypub/process/misc.ts +++ b/server/lib/activitypub/process/misc.ts @@ -1,13 +1,16 @@ import * as magnetUtil from 'magnet-uri' import { VideoTorrentObject } from '../../../../shared' import { VideoChannelObject } from '../../../../shared/models/activitypub/objects/video-channel-object' +import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' import { isVideoFileInfoHashValid } from '../../../helpers/custom-validators/videos' +import { doRequest } from '../../../helpers/requests' +import { database as db } from '../../../initializers' import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../../initializers/constants' import { AccountInstance } from '../../../models/account/account-interface' import { VideoChannelInstance } from '../../../models/video/video-channel-interface' import { VideoFileAttributes } from '../../../models/video/video-file-interface' import { VideoAttributes, VideoInstance } from '../../../models/video/video-interface' -import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum' +import { getOrCreateAccountAndServer } from '../account' function videoChannelActivityObjectToDBAttributes (videoChannelObject: VideoChannelObject, account: AccountInstance) { return { @@ -97,10 +100,60 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoInstance, videoO return attributes } +async function addVideoShares (instance: VideoInstance, shares: string[]) { + for (const share of shares) { + // Fetch url + const json = await doRequest({ + uri: share, + json: true + }) + const actor = json['actor'] + if (!actor) continue + + const account = await getOrCreateAccountAndServer(actor) + + const entry = { + accountId: account.id, + videoId: instance.id + } + + await db.VideoShare.findOrCreate({ + where: entry, + defaults: entry + }) + } +} + +async function addVideoChannelShares (instance: VideoChannelInstance, shares: string[]) { + for (const share of shares) { + // Fetch url + const json = await doRequest({ + uri: share, + json: true + }) + const actor = json['actor'] + if (!actor) continue + + const account = await getOrCreateAccountAndServer(actor) + + const entry = { + accountId: account.id, + videoChannelId: instance.id + } + + await db.VideoChannelShare.findOrCreate({ + where: entry, + defaults: entry + }) + } +} + // --------------------------------------------------------------------------- export { videoFileActivityUrlToDBAttributes, videoActivityObjectToDBAttributes, - videoChannelActivityObjectToDBAttributes + videoChannelActivityObjectToDBAttributes, + addVideoChannelShares, + addVideoShares } diff --git a/server/lib/activitypub/process/process-add.ts b/server/lib/activitypub/process/process-add.ts index 98280b9f0..e6bf63eb2 100644 --- a/server/lib/activitypub/process/process-add.ts +++ b/server/lib/activitypub/process/process-add.ts @@ -11,7 +11,7 @@ import { VideoInstance } from '../../../models/video/video-interface' import { getOrCreateAccountAndServer } from '../account' import { getOrCreateVideoChannel } from '../video-channels' import { generateThumbnailFromUrl } from '../videos' -import { videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' +import { addVideoShares, videoActivityObjectToDBAttributes, videoFileActivityUrlToDBAttributes } from './misc' async function processAddActivity (activity: ActivityAdd) { const activityObject = activity.object @@ -37,12 +37,10 @@ export { // --------------------------------------------------------------------------- -async function processAddVideo ( - account: AccountInstance, - activity: ActivityAdd, - videoChannel: VideoChannelInstance, - videoToCreateData: VideoTorrentObject -) { +async function processAddVideo (account: AccountInstance, + activity: ActivityAdd, + videoChannel: VideoChannelInstance, + videoToCreateData: VideoTorrentObject) { const options = { arguments: [ account, activity, videoChannel, videoToCreateData ], errorMessage: 'Cannot insert the remote video with many retries.' @@ -59,6 +57,10 @@ async function processAddVideo ( await createRates(videoToCreateData.dislikes.orderedItems, video, 'dislike') } + if (videoToCreateData.shares && Array.isArray(videoToCreateData.shares.orderedItems)) { + await addVideoShares(video, videoToCreateData.shares.orderedItems) + } + return video } diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index d8532d3a1..2aa9ad5c7 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -1,34 +1,23 @@ -import { ActivityAnnounce } from '../../../../shared/models/activitypub/activity' +import { ActivityAdd, ActivityAnnounce, ActivityCreate } from '../../../../shared/models/activitypub/activity' +import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { database as db } from '../../../initializers/index' +import { AccountInstance } from '../../../models/account/account-interface' import { VideoInstance } from '../../../models/index' import { VideoChannelInstance } from '../../../models/video/video-channel-interface' +import { getOrCreateAccountAndServer } from '../account' +import { forwardActivity } from '../send/misc' import { processAddActivity } from './process-add' import { processCreateActivity } from './process-create' -import { getOrCreateAccountAndServer } from '../account' async function processAnnounceActivity (activity: ActivityAnnounce) { const announcedActivity = activity.object const accountAnnouncer = await getOrCreateAccountAndServer(activity.actor) if (announcedActivity.type === 'Create' && announcedActivity.object.type === 'VideoChannel') { - // Add share entry - const videoChannel: VideoChannelInstance = await processCreateActivity(announcedActivity) - await db.VideoChannelShare.create({ - accountId: accountAnnouncer.id, - videoChannelId: videoChannel.id - }) - - return undefined + return processVideoChannelShare(accountAnnouncer, activity) } else if (announcedActivity.type === 'Add' && announcedActivity.object.type === 'Video') { - // Add share entry - const video: VideoInstance = await processAddActivity(announcedActivity) - await db.VideoShare.create({ - accountId: accountAnnouncer.id, - videoId: video.id - }) - - return undefined + return processVideoShare(accountAnnouncer, activity) } logger.warn( @@ -44,3 +33,78 @@ async function processAnnounceActivity (activity: ActivityAnnounce) { export { processAnnounceActivity } + +// --------------------------------------------------------------------------- + +function processVideoChannelShare (accountAnnouncer: AccountInstance, activity: ActivityAnnounce) { + const options = { + arguments: [ accountAnnouncer, activity ], + errorMessage: 'Cannot share the video channel with many retries.' + } + + return retryTransactionWrapper(shareVideoChannel, options) +} + +async function shareVideoChannel (accountAnnouncer: AccountInstance, activity: ActivityAnnounce) { + const announcedActivity = activity.object as ActivityCreate + + return db.sequelize.transaction(async t => { + // Add share entry + const videoChannel: VideoChannelInstance = await processCreateActivity(announcedActivity) + const share = { + accountId: accountAnnouncer.id, + videoChannelId: videoChannel.id + } + + const [ , created ] = await db.VideoChannelShare.findOrCreate({ + where: share, + defaults: share, + transaction: t + }) + + if (videoChannel.isOwned() && created === true) { + // Don't resend the activity to the sender + const exceptions = [ accountAnnouncer ] + await forwardActivity(activity, t, exceptions) + } + + return undefined + }) +} + +function processVideoShare (accountAnnouncer: AccountInstance, activity: ActivityAnnounce) { + const options = { + arguments: [ accountAnnouncer, activity ], + errorMessage: 'Cannot share the video with many retries.' + } + + return retryTransactionWrapper(shareVideo, options) +} + +function shareVideo (accountAnnouncer: AccountInstance, activity: ActivityAnnounce) { + const announcedActivity = activity.object as ActivityAdd + + return db.sequelize.transaction(async t => { + // Add share entry + const video: VideoInstance = await processAddActivity(announcedActivity) + + const share = { + accountId: accountAnnouncer.id, + videoId: video.id + } + + const [ , created ] = await db.VideoShare.findOrCreate({ + where: share, + defaults: share, + transaction: t + }) + + if (video.isOwned() && created === true) { + // Don't resend the activity to the sender + const exceptions = [ accountAnnouncer ] + await forwardActivity(activity, t, exceptions) + } + + return undefined + }) +} diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 1f982598b..c88082bbf 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -8,7 +8,7 @@ import { AccountInstance } from '../../../models/account/account-interface' import { getOrCreateAccountAndServer } from '../account' import { forwardActivity } from '../send/misc' import { getVideoChannelActivityPubUrl } from '../url' -import { videoChannelActivityObjectToDBAttributes } from './misc' +import { addVideoChannelShares, videoChannelActivityObjectToDBAttributes } from './misc' async function processCreateActivity (activity: ActivityCreate) { const activityObject = activity.object @@ -92,13 +92,19 @@ async function processCreateView (byAccount: AccountInstance, activity: Activity } } -function processCreateVideoChannel (account: AccountInstance, videoChannelToCreateData: VideoChannelObject) { +async function processCreateVideoChannel (account: AccountInstance, videoChannelToCreateData: VideoChannelObject) { const options = { arguments: [ account, videoChannelToCreateData ], errorMessage: 'Cannot insert the remote video channel with many retries.' } - return retryTransactionWrapper(addRemoteVideoChannel, options) + const videoChannel = await retryTransactionWrapper(addRemoteVideoChannel, options) + + if (videoChannelToCreateData.shares && Array.isArray(videoChannelToCreateData.shares.orderedItems)) { + await addVideoChannelShares(videoChannel, videoChannelToCreateData.shares.orderedItems) + } + + return videoChannel } function addRemoteVideoChannel (account: AccountInstance, videoChannelToCreateData: VideoChannelObject) { -- cgit v1.2.3