From 0032ebe94aa83fab761c7de3ceb6210ac4532824 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 23 Nov 2017 14:19:55 +0100 Subject: Federate likes/dislikes --- server/lib/activitypub/send/index.ts | 2 + server/lib/activitypub/send/misc.ts | 27 +++++++++++- server/lib/activitypub/send/send-create.ts | 62 +++++++++++++++++++++----- server/lib/activitypub/send/send-like.ts | 60 +++++++++++++++++++++++++ server/lib/activitypub/send/send-undo.ts | 71 +++++++++++++++++++++++++++--- 5 files changed, 204 insertions(+), 18 deletions(-) create mode 100644 server/lib/activitypub/send/send-like.ts (limited to 'server/lib/activitypub/send') diff --git a/server/lib/activitypub/send/index.ts b/server/lib/activitypub/send/index.ts index 5f15dd4b5..ee8f3ad7e 100644 --- a/server/lib/activitypub/send/index.ts +++ b/server/lib/activitypub/send/index.ts @@ -4,4 +4,6 @@ export * from './send-announce' export * from './send-create' export * from './send-delete' export * from './send-follow' +export * from './send-like' +export * from './send-undo' export * from './send-update' diff --git a/server/lib/activitypub/send/misc.ts b/server/lib/activitypub/send/misc.ts index f3dc5c148..41a039b19 100644 --- a/server/lib/activitypub/send/misc.ts +++ b/server/lib/activitypub/send/misc.ts @@ -3,6 +3,7 @@ import { logger } from '../../../helpers/logger' import { ACTIVITY_PUB, database as db } from '../../../initializers' import { AccountInstance } from '../../../models/account/account-interface' import { activitypubHttpJobScheduler } from '../../jobs/activitypub-http-job-scheduler/activitypub-http-job-scheduler' +import { VideoInstance } from '../../../models/video/video-interface' async function broadcastToFollowers ( data: any, @@ -41,6 +42,27 @@ async function unicastTo (data: any, byAccount: AccountInstance, toAccountUrl: s return activitypubHttpJobScheduler.createJob(t, 'activitypubHttpUnicastHandler', jobPayload) } +function getOriginVideoAudience (video: VideoInstance) { + return { + to: [ video.VideoChannel.Account.url ], + cc: [ video.VideoChannel.Account.url + '/followers' ] + } +} + +function getVideoFollowersAudience (video: VideoInstance) { + return { + to: [ video.VideoChannel.Account.url + '/followers' ], + cc: [] + } +} + +async function getAccountsToForwardVideoAction (byAccount: AccountInstance, video: VideoInstance) { + const accountsToForwardView = await db.VideoShare.loadAccountsByShare(video.id) + accountsToForwardView.push(video.VideoChannel.Account) + + return accountsToForwardView +} + async function getAudience (accountSender: AccountInstance, isPublic = true) { const followerInboxUrls = await accountSender.getFollowerSharedInboxUrls() @@ -64,5 +86,8 @@ async function getAudience (accountSender: AccountInstance, isPublic = true) { export { broadcastToFollowers, unicastTo, - getAudience + getAudience, + getOriginVideoAudience, + getAccountsToForwardVideoAction, + getVideoFollowersAudience } diff --git a/server/lib/activitypub/send/send-create.ts b/server/lib/activitypub/send/send-create.ts index e5fb212b7..6afe67ee6 100644 --- a/server/lib/activitypub/send/send-create.ts +++ b/server/lib/activitypub/send/send-create.ts @@ -1,11 +1,17 @@ import { Transaction } from 'sequelize' import { ActivityCreate } from '../../../../shared/models/activitypub/activity' +import { getServerAccount } from '../../../helpers/utils' import { AccountInstance, VideoChannelInstance, VideoInstance } from '../../../models' import { VideoAbuseInstance } from '../../../models/video/video-abuse-interface' -import { broadcastToFollowers, getAudience, unicastTo } from './misc' -import { getVideoAbuseActivityPubUrl, getVideoViewActivityPubUrl } from '../url' -import { getServerAccount } from '../../../helpers/utils' -import { database as db } from '../../../initializers' +import { getVideoAbuseActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoViewActivityPubUrl } from '../url' +import { + broadcastToFollowers, + getAccountsToForwardVideoAction, + getAudience, + getOriginVideoAudience, + getVideoFollowersAudience, + unicastTo +} from './misc' async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Transaction) { const byAccount = videoChannel.Account @@ -29,7 +35,7 @@ async function sendCreateViewToOrigin (byAccount: AccountInstance, video: VideoI const url = getVideoViewActivityPubUrl(byAccount, video) const viewActivity = createViewActivityData(byAccount, video) - const audience = { to: [ video.VideoChannel.Account.url ], cc: [ video.VideoChannel.Account.url + '/followers' ] } + const audience = getOriginVideoAudience(video) const data = await createActivityData(url, byAccount, viewActivity, audience) return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) @@ -39,16 +45,35 @@ async function sendCreateViewToVideoFollowers (byAccount: AccountInstance, video const url = getVideoViewActivityPubUrl(byAccount, video) const viewActivity = createViewActivityData(byAccount, video) - const audience = { to: [ video.VideoChannel.Account.url + '/followers' ], cc: [] } + const audience = getVideoFollowersAudience(video) const data = await createActivityData(url, byAccount, viewActivity, audience) const serverAccount = await getServerAccount() - const accountsToForwardView = await db.VideoShare.loadAccountsByShare(video.id) - accountsToForwardView.push(video.VideoChannel.Account) + const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) + + const followersException = [ byAccount ] + return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) +} + +async function sendCreateDislikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const url = getVideoDislikeActivityPubUrl(byAccount, video) + const dislikeActivity = createDislikeActivityData(byAccount, video) + + const audience = getOriginVideoAudience(video) + const data = await createActivityData(url, byAccount, dislikeActivity, audience) + + return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) +} - // Don't forward view to server that sent it to us - const index = accountsToForwardView.findIndex(a => a.id === byAccount.id) - if (index) accountsToForwardView.splice(index, 1) +async function sendCreateDislikeToVideoFollowers (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const url = getVideoDislikeActivityPubUrl(byAccount, video) + const dislikeActivity = createDislikeActivityData(byAccount, video) + + const audience = getVideoFollowersAudience(video) + const data = await createActivityData(url, byAccount, dislikeActivity, audience) + + const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) + const serverAccount = await getServerAccount() const followersException = [ byAccount ] return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) @@ -71,6 +96,16 @@ async function createActivityData (url: string, byAccount: AccountInstance, obje return activity } +function createDislikeActivityData (byAccount: AccountInstance, video: VideoInstance) { + const obj = { + type: 'Dislike', + actor: byAccount.url, + object: video.url + } + + return obj +} + // --------------------------------------------------------------------------- export { @@ -78,7 +113,10 @@ export { sendVideoAbuse, createActivityData, sendCreateViewToOrigin, - sendCreateViewToVideoFollowers + sendCreateViewToVideoFollowers, + sendCreateDislikeToOrigin, + sendCreateDislikeToVideoFollowers, + createDislikeActivityData } // --------------------------------------------------------------------------- diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts new file mode 100644 index 000000000..70a7d886f --- /dev/null +++ b/server/lib/activitypub/send/send-like.ts @@ -0,0 +1,60 @@ +import { Transaction } from 'sequelize' +import { ActivityLike } from '../../../../shared/models/activitypub/activity' +import { getServerAccount } from '../../../helpers/utils' +import { AccountInstance, VideoInstance } from '../../../models' +import { getVideoLikeActivityPubUrl } from '../url' +import { + broadcastToFollowers, + getAccountsToForwardVideoAction, + getAudience, + getOriginVideoAudience, + getVideoFollowersAudience, + unicastTo +} from './misc' + +async function sendLikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const url = getVideoLikeActivityPubUrl(byAccount, video) + + const audience = getOriginVideoAudience(video) + const data = await likeActivityData(url, byAccount, video, audience) + + return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) +} + +async function sendLikeToVideoFollowers (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const url = getVideoLikeActivityPubUrl(byAccount, video) + + const audience = getVideoFollowersAudience(video) + const data = await likeActivityData(url, byAccount, video, audience) + + const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) + const serverAccount = await getServerAccount() + + const followersException = [ byAccount ] + return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) +} + +async function likeActivityData (url: string, byAccount: AccountInstance, video: VideoInstance, audience?: { to: string[], cc: string[] }) { + if (!audience) { + audience = await getAudience(byAccount) + } + + const activity: ActivityLike = { + type: 'Like', + id: url, + actor: byAccount.url, + to: audience.to, + cc: audience.cc, + object: video.url + } + + return activity +} + +// --------------------------------------------------------------------------- + +export { + sendLikeToOrigin, + sendLikeToVideoFollowers, + likeActivityData +} diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index 77bee6639..53fddd0cb 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts @@ -1,10 +1,14 @@ import { Transaction } from 'sequelize' -import { ActivityFollow, ActivityUndo } from '../../../../shared/models/activitypub/activity' +import { ActivityCreate, ActivityFollow, ActivityLike, ActivityUndo } from '../../../../shared/models/activitypub/activity' import { AccountInstance } from '../../../models' import { AccountFollowInstance } from '../../../models/account/account-follow-interface' -import { unicastTo } from './misc' +import { broadcastToFollowers, getAccountsToForwardVideoAction, unicastTo } from './misc' import { followActivityData } from './send-follow' -import { getAccountFollowActivityPubUrl, getUndoActivityPubUrl } from '../url' +import { getAccountFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' +import { VideoInstance } from '../../../models/video/video-interface' +import { likeActivityData } from './send-like' +import { createActivityData, createDislikeActivityData } from './send-create' +import { getServerAccount } from '../../../helpers/utils' async function sendUndoFollow (accountFollow: AccountFollowInstance, t: Transaction) { const me = accountFollow.AccountFollower @@ -19,15 +23,72 @@ async function sendUndoFollow (accountFollow: AccountFollowInstance, t: Transact return unicastTo(data, me, following.inboxUrl, t) } +async function sendUndoLikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const likeUrl = getVideoLikeActivityPubUrl(byAccount, video) + const undoUrl = getUndoActivityPubUrl(likeUrl) + + const object = await likeActivityData(likeUrl, byAccount, video) + const data = await undoActivityData(undoUrl, byAccount, object) + + return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) +} + +async function sendUndoLikeToVideoFollowers (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const likeUrl = getVideoLikeActivityPubUrl(byAccount, video) + const undoUrl = getUndoActivityPubUrl(likeUrl) + + const object = await likeActivityData(likeUrl, byAccount, video) + const data = await undoActivityData(undoUrl, byAccount, object) + + const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) + const serverAccount = await getServerAccount() + + const followersException = [ byAccount ] + return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) +} + +async function sendUndoDislikeToOrigin (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const dislikeUrl = getVideoDislikeActivityPubUrl(byAccount, video) + const undoUrl = getUndoActivityPubUrl(dislikeUrl) + + const dislikeActivity = createDislikeActivityData(byAccount, video) + const object = await createActivityData(undoUrl, byAccount, dislikeActivity) + + const data = await undoActivityData(undoUrl, byAccount, object) + + return unicastTo(data, byAccount, video.VideoChannel.Account.sharedInboxUrl, t) +} + +async function sendUndoDislikeToVideoFollowers (byAccount: AccountInstance, video: VideoInstance, t: Transaction) { + const dislikeUrl = getVideoDislikeActivityPubUrl(byAccount, video) + const undoUrl = getUndoActivityPubUrl(dislikeUrl) + + const dislikeActivity = createDislikeActivityData(byAccount, video) + const object = await createActivityData(undoUrl, byAccount, dislikeActivity) + + const data = await undoActivityData(undoUrl, byAccount, object) + + const accountsToForwardView = await getAccountsToForwardVideoAction(byAccount, video) + const serverAccount = await getServerAccount() + + const followersException = [ byAccount ] + return broadcastToFollowers(data, serverAccount, accountsToForwardView, t, followersException) +} + + // --------------------------------------------------------------------------- export { - sendUndoFollow + sendUndoFollow, + sendUndoLikeToOrigin, + sendUndoLikeToVideoFollowers, + sendUndoDislikeToOrigin, + sendUndoDislikeToVideoFollowers } // --------------------------------------------------------------------------- -async function undoActivityData (url: string, byAccount: AccountInstance, object: ActivityFollow) { +async function undoActivityData (url: string, byAccount: AccountInstance, object: ActivityFollow | ActivityLike | ActivityCreate) { const activity: ActivityUndo = { type: 'Undo', id: url, -- cgit v1.2.3