From 7acee6f18aac99e359360fc4f2362d5405135a79 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Fri, 26 Jan 2018 12:02:18 +0100 Subject: Fix announce activities --- server/controllers/activitypub/outbox.ts | 7 +-- .../custom-validators/activitypub/announce.ts | 5 +- server/lib/activitypub/process/process-announce.ts | 26 ++-------- server/lib/activitypub/process/process-create.ts | 55 +--------------------- server/lib/activitypub/send/send-announce.ts | 12 ++--- server/lib/activitypub/videos.ts | 53 ++++++++++++++++++++- 6 files changed, 66 insertions(+), 92 deletions(-) (limited to 'server') diff --git a/server/controllers/activitypub/outbox.ts b/server/controllers/activitypub/outbox.ts index ab12a7c4b..41c6ffaeb 100644 --- a/server/controllers/activitypub/outbox.ts +++ b/server/controllers/activitypub/outbox.ts @@ -43,21 +43,18 @@ async function outboxController (req: express.Request, res: express.Response, ne const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined) for (const video of data.data) { - const videoObject = video.toActivityPubObject() - const byActor = video.VideoChannel.Account.Actor const createActivityAudience = buildAudience(followersMatrix[byActor.id]) // This is a shared video if (video.VideoShares !== undefined && video.VideoShares.length !== 0) { - const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience) - const announceAudience = buildAudience(followersMatrix[actor.id]) const url = getAnnounceActivityPubUrl(video.url, actor) - const announceActivity = await announceActivityData(url, actor, createActivity, undefined, announceAudience) + const announceActivity = await announceActivityData(url, actor, video.url, undefined, announceAudience) activities.push(announceActivity) } else { + const videoObject = video.toActivityPubObject() const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience) activities.push(createActivity) diff --git a/server/helpers/custom-validators/activitypub/announce.ts b/server/helpers/custom-validators/activitypub/announce.ts index 7dd1d6988..0519c6026 100644 --- a/server/helpers/custom-validators/activitypub/announce.ts +++ b/server/helpers/custom-validators/activitypub/announce.ts @@ -1,11 +1,10 @@ import { isActivityPubUrlValid, isBaseActivityValid } from './misc' -import { isVideoTorrentCreateActivityValid } from './videos' function isAnnounceActivityValid (activity: any) { return isBaseActivityValid(activity, 'Announce') && ( - isVideoTorrentCreateActivityValid(activity.object) || - isActivityPubUrlValid(activity.object) + isActivityPubUrlValid(activity.object) || + (activity.object && isActivityPubUrlValid(activity.object.id)) ) } diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index bf7d7879d..7dafc0593 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -1,6 +1,5 @@ import { ActivityAnnounce } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' -import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers' import { ActorModel } from '../../../models/activitypub/actor' import { VideoModel } from '../../../models/video/video' @@ -8,24 +7,11 @@ import { VideoShareModel } from '../../../models/video/video-share' import { getOrCreateActorAndServerAndModel } from '../actor' import { forwardActivity } from '../send/misc' import { getOrCreateAccountAndVideoAndChannel } from '../videos' -import { processCreateActivity } from './process-create' async function processAnnounceActivity (activity: ActivityAnnounce) { - const announcedActivity = activity.object const actorAnnouncer = await getOrCreateActorAndServerAndModel(activity.actor) - if (typeof announcedActivity === 'string') { - return processVideoShare(actorAnnouncer, activity) - } else if (announcedActivity.type === 'Create' && announcedActivity.object.type === 'Video') { - return processVideoShare(actorAnnouncer, activity) - } - - logger.warn( - 'Unknown activity object type %s -> %s when announcing activity.', announcedActivity.type, announcedActivity.object.type, - { activity: activity.id } - ) - - return undefined + return processVideoShare(actorAnnouncer, activity) } // --------------------------------------------------------------------------- @@ -46,15 +32,11 @@ function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnoun } async function shareVideo (actorAnnouncer: ActorModel, activity: ActivityAnnounce) { - const announced = activity.object + const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id let video: VideoModel - if (typeof announced === 'string') { - const res = await getOrCreateAccountAndVideoAndChannel(announced) - video = res.video - } else { - video = await processCreateActivity(announced) - } + const res = await getOrCreateAccountAndVideoAndChannel(objectUri) + video = res.video return sequelizeTypescript.transaction(async t => { // Add share entry diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index eff796c1d..ee180b765 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -1,20 +1,17 @@ -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 { 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 { VideoModel } from '../../../models/video/video' import { VideoAbuseModel } from '../../../models/video/video-abuse' import { VideoCommentModel } from '../../../models/video/video-comment' import { getOrCreateActorAndServerAndModel } from '../actor' import { forwardActivity, getActorsInvolvedInVideo } from '../send/misc' -import { addVideoComments, resolveThread } from '../video-comments' -import { addVideoShares, getOrCreateAccountAndVideoAndChannel } from '../videos' +import { resolveThread } from '../video-comments' +import { getOrCreateAccountAndVideoAndChannel } from '../videos' async function processCreateActivity (activity: ActivityCreate) { const activityObject = activity.object @@ -53,57 +50,9 @@ async function processCreateVideo ( const { video } = await getOrCreateAccountAndVideoAndChannel(videoToCreateData, actor) - // 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 } -async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) { - let rateCounts = 0 - const tasks: Bluebird[] = [] - - for (const actorUrl of actorUrls) { - const actor = await getOrCreateActorAndServerAndModel(actorUrl) - const p = AccountVideoRateModel - .create({ - videoId: video.id, - accountId: actor.Account.id, - type: rate - }) - .then(() => rateCounts += 1) - - tasks.push(p) - } - - await Promise.all(tasks) - - logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid) - - // This is "likes" and "dislikes" - await video.increment(rate + 's', { by: rateCounts }) - - return -} - async function processCreateDislike (byActor: ActorModel, activity: ActivityCreate) { const options = { arguments: [ byActor, activity ], diff --git a/server/lib/activitypub/send/send-announce.ts b/server/lib/activitypub/send/send-announce.ts index 93b5668d2..76cb3f80c 100644 --- a/server/lib/activitypub/send/send-announce.ts +++ b/server/lib/activitypub/send/send-announce.ts @@ -1,6 +1,5 @@ import { Transaction } from 'sequelize' -import { ActivityAnnounce, ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub' -import { VideoPrivacy } from '../../../../shared/models/videos' +import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub' import { ActorModel } from '../../../models/activitypub/actor' import { VideoModel } from '../../../models/video/video' import { getAnnounceActivityPubUrl } from '../url' @@ -16,14 +15,11 @@ import { createActivityData } from './send-create' async function buildVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) { const url = getAnnounceActivityPubUrl(video.url, byActor) - const videoObject = video.toActivityPubObject() - - const announcedAudience = await getAudience(byActor, t, video.privacy === VideoPrivacy.PUBLIC) - const announcedActivity = await createActivityData(url, video.VideoChannel.Account.Actor, videoObject, t, announcedAudience) + const announcedObject = video.url const accountsToForwardView = await getActorsInvolvedInVideo(video, t) const audience = getObjectFollowersAudience(accountsToForwardView) - return announceActivityData(url, byActor, announcedActivity, t, audience) + return announceActivityData(url, byActor, announcedObject, t, audience) } async function sendVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) { @@ -48,7 +44,7 @@ async function sendVideoAnnounceToOrigin (byActor: ActorModel, video: VideoModel async function announceActivityData ( url: string, byActor: ActorModel, - object: ActivityCreate, + object: string, t: Transaction, audience?: ActivityAudience ): Promise { diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 50e7e5cde..7d535bb0a 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -1,15 +1,17 @@ +import * as Bluebird from 'bluebird' import * as magnetUtil from 'magnet-uri' import { join } from 'path' import * as request from 'request' import { ActivityIconObject } from '../../../shared/index' import { VideoTorrentObject } from '../../../shared/models/activitypub/objects' -import { VideoPrivacy } from '../../../shared/models/videos' +import { VideoPrivacy, VideoRateType } from '../../../shared/models/videos' import { isVideoTorrentObjectValid } from '../../helpers/custom-validators/activitypub/videos' import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos' import { retryTransactionWrapper } from '../../helpers/database-utils' import { logger } from '../../helpers/logger' import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests' import { ACTIVITY_PUB, CONFIG, REMOTE_SCHEME, sequelizeTypescript, STATIC_PATHS, VIDEO_MIMETYPE_EXT } 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' @@ -17,6 +19,7 @@ import { VideoChannelModel } from '../../models/video/video-channel' import { VideoFileModel } from '../../models/video/video-file' import { VideoShareModel } from '../../models/video/video-share' import { getOrCreateActorAndServerAndModel } from './actor' +import { addVideoComments } from './video-comments' function fetchRemoteVideoPreview (video: VideoModel, reject: Function) { const host = video.VideoChannel.Account.Actor.Server.host @@ -210,9 +213,57 @@ async function getOrCreateAccountAndVideoAndChannel (videoObject: VideoTorrentOb const video = await retryTransactionWrapper(getOrCreateVideo, options) + // Process outside the transaction because we could fetch remote data + if (videoObject.likes && Array.isArray(videoObject.likes.orderedItems)) { + logger.info('Adding likes of video %s.', video.uuid) + await createRates(videoObject.likes.orderedItems, video, 'like') + } + + if (videoObject.dislikes && Array.isArray(videoObject.dislikes.orderedItems)) { + logger.info('Adding dislikes of video %s.', video.uuid) + await createRates(videoObject.dislikes.orderedItems, video, 'dislike') + } + + if (videoObject.shares && Array.isArray(videoObject.shares.orderedItems)) { + logger.info('Adding shares of video %s.', video.uuid) + await addVideoShares(video, videoObject.shares.orderedItems) + } + + if (videoObject.comments && Array.isArray(videoObject.comments.orderedItems)) { + logger.info('Adding comments of video %s.', video.uuid) + await addVideoComments(video, videoObject.comments.orderedItems) + } + return { actor, channelActor, video } } +async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) { + let rateCounts = 0 + const tasks: Bluebird[] = [] + + for (const actorUrl of actorUrls) { + const actor = await getOrCreateActorAndServerAndModel(actorUrl) + const p = AccountVideoRateModel + .create({ + videoId: video.id, + accountId: actor.Account.id, + type: rate + }) + .then(() => rateCounts += 1) + + tasks.push(p) + } + + await Promise.all(tasks) + + logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid) + + // This is "likes" and "dislikes" + await video.increment(rate + 's', { by: rateCounts }) + + return +} + async function addVideoShares (instance: VideoModel, shareUrls: string[]) { for (const shareUrl of shareUrls) { // Fetch url -- cgit v1.2.3