Fix announce activities
This commit is contained in:
parent
d6e99e5322
commit
7acee6f18a
|
@ -43,21 +43,18 @@ async function outboxController (req: express.Request, res: express.Response, ne
|
||||||
const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined)
|
const followersMatrix = await ActorModel.getActorsFollowerSharedInboxUrls(actors, undefined)
|
||||||
|
|
||||||
for (const video of data.data) {
|
for (const video of data.data) {
|
||||||
const videoObject = video.toActivityPubObject()
|
|
||||||
|
|
||||||
const byActor = video.VideoChannel.Account.Actor
|
const byActor = video.VideoChannel.Account.Actor
|
||||||
const createActivityAudience = buildAudience(followersMatrix[byActor.id])
|
const createActivityAudience = buildAudience(followersMatrix[byActor.id])
|
||||||
|
|
||||||
// This is a shared video
|
// This is a shared video
|
||||||
if (video.VideoShares !== undefined && video.VideoShares.length !== 0) {
|
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 announceAudience = buildAudience(followersMatrix[actor.id])
|
||||||
const url = getAnnounceActivityPubUrl(video.url, actor)
|
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)
|
activities.push(announceActivity)
|
||||||
} else {
|
} else {
|
||||||
|
const videoObject = video.toActivityPubObject()
|
||||||
const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience)
|
const createActivity = await createActivityData(video.url, byActor, videoObject, undefined, createActivityAudience)
|
||||||
|
|
||||||
activities.push(createActivity)
|
activities.push(createActivity)
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
|
import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
|
||||||
import { isVideoTorrentCreateActivityValid } from './videos'
|
|
||||||
|
|
||||||
function isAnnounceActivityValid (activity: any) {
|
function isAnnounceActivityValid (activity: any) {
|
||||||
return isBaseActivityValid(activity, 'Announce') &&
|
return isBaseActivityValid(activity, 'Announce') &&
|
||||||
(
|
(
|
||||||
isVideoTorrentCreateActivityValid(activity.object) ||
|
isActivityPubUrlValid(activity.object) ||
|
||||||
isActivityPubUrlValid(activity.object)
|
(activity.object && isActivityPubUrlValid(activity.object.id))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { ActivityAnnounce } from '../../../../shared/models/activitypub'
|
import { ActivityAnnounce } from '../../../../shared/models/activitypub'
|
||||||
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
||||||
import { logger } from '../../../helpers/logger'
|
|
||||||
import { sequelizeTypescript } from '../../../initializers'
|
import { sequelizeTypescript } from '../../../initializers'
|
||||||
import { ActorModel } from '../../../models/activitypub/actor'
|
import { ActorModel } from '../../../models/activitypub/actor'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
import { VideoModel } from '../../../models/video/video'
|
||||||
|
@ -8,24 +7,11 @@ import { VideoShareModel } from '../../../models/video/video-share'
|
||||||
import { getOrCreateActorAndServerAndModel } from '../actor'
|
import { getOrCreateActorAndServerAndModel } from '../actor'
|
||||||
import { forwardActivity } from '../send/misc'
|
import { forwardActivity } from '../send/misc'
|
||||||
import { getOrCreateAccountAndVideoAndChannel } from '../videos'
|
import { getOrCreateAccountAndVideoAndChannel } from '../videos'
|
||||||
import { processCreateActivity } from './process-create'
|
|
||||||
|
|
||||||
async function processAnnounceActivity (activity: ActivityAnnounce) {
|
async function processAnnounceActivity (activity: ActivityAnnounce) {
|
||||||
const announcedActivity = activity.object
|
|
||||||
const actorAnnouncer = await getOrCreateActorAndServerAndModel(activity.actor)
|
const actorAnnouncer = await getOrCreateActorAndServerAndModel(activity.actor)
|
||||||
|
|
||||||
if (typeof announcedActivity === 'string') {
|
return processVideoShare(actorAnnouncer, activity)
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
@ -46,15 +32,11 @@ function processVideoShare (actorAnnouncer: ActorModel, activity: ActivityAnnoun
|
||||||
}
|
}
|
||||||
|
|
||||||
async function shareVideo (actorAnnouncer: ActorModel, activity: ActivityAnnounce) {
|
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
|
let video: VideoModel
|
||||||
|
|
||||||
if (typeof announced === 'string') {
|
const res = await getOrCreateAccountAndVideoAndChannel(objectUri)
|
||||||
const res = await getOrCreateAccountAndVideoAndChannel(announced)
|
video = res.video
|
||||||
video = res.video
|
|
||||||
} else {
|
|
||||||
video = await processCreateActivity(announced)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sequelizeTypescript.transaction(async t => {
|
return sequelizeTypescript.transaction(async t => {
|
||||||
// Add share entry
|
// Add share entry
|
||||||
|
|
|
@ -1,20 +1,17 @@
|
||||||
import * as Bluebird from 'bluebird'
|
|
||||||
import { ActivityCreate, VideoTorrentObject } from '../../../../shared'
|
import { ActivityCreate, VideoTorrentObject } from '../../../../shared'
|
||||||
import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects'
|
import { DislikeObject, VideoAbuseObject, ViewObject } from '../../../../shared/models/activitypub/objects'
|
||||||
import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
|
import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
|
||||||
import { VideoRateType } from '../../../../shared/models/videos'
|
|
||||||
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
||||||
import { logger } from '../../../helpers/logger'
|
import { logger } from '../../../helpers/logger'
|
||||||
import { sequelizeTypescript } from '../../../initializers'
|
import { sequelizeTypescript } from '../../../initializers'
|
||||||
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
|
import { AccountVideoRateModel } from '../../../models/account/account-video-rate'
|
||||||
import { ActorModel } from '../../../models/activitypub/actor'
|
import { ActorModel } from '../../../models/activitypub/actor'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
|
||||||
import { VideoAbuseModel } from '../../../models/video/video-abuse'
|
import { VideoAbuseModel } from '../../../models/video/video-abuse'
|
||||||
import { VideoCommentModel } from '../../../models/video/video-comment'
|
import { VideoCommentModel } from '../../../models/video/video-comment'
|
||||||
import { getOrCreateActorAndServerAndModel } from '../actor'
|
import { getOrCreateActorAndServerAndModel } from '../actor'
|
||||||
import { forwardActivity, getActorsInvolvedInVideo } from '../send/misc'
|
import { forwardActivity, getActorsInvolvedInVideo } from '../send/misc'
|
||||||
import { addVideoComments, resolveThread } from '../video-comments'
|
import { resolveThread } from '../video-comments'
|
||||||
import { addVideoShares, getOrCreateAccountAndVideoAndChannel } from '../videos'
|
import { getOrCreateAccountAndVideoAndChannel } from '../videos'
|
||||||
|
|
||||||
async function processCreateActivity (activity: ActivityCreate) {
|
async function processCreateActivity (activity: ActivityCreate) {
|
||||||
const activityObject = activity.object
|
const activityObject = activity.object
|
||||||
|
@ -53,57 +50,9 @@ async function processCreateVideo (
|
||||||
|
|
||||||
const { video } = await getOrCreateAccountAndVideoAndChannel(videoToCreateData, actor)
|
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
|
return video
|
||||||
}
|
}
|
||||||
|
|
||||||
async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) {
|
|
||||||
let rateCounts = 0
|
|
||||||
const tasks: Bluebird<number>[] = []
|
|
||||||
|
|
||||||
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) {
|
async function processCreateDislike (byActor: ActorModel, activity: ActivityCreate) {
|
||||||
const options = {
|
const options = {
|
||||||
arguments: [ byActor, activity ],
|
arguments: [ byActor, activity ],
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Transaction } from 'sequelize'
|
import { Transaction } from 'sequelize'
|
||||||
import { ActivityAnnounce, ActivityAudience, ActivityCreate } from '../../../../shared/models/activitypub'
|
import { ActivityAnnounce, ActivityAudience } from '../../../../shared/models/activitypub'
|
||||||
import { VideoPrivacy } from '../../../../shared/models/videos'
|
|
||||||
import { ActorModel } from '../../../models/activitypub/actor'
|
import { ActorModel } from '../../../models/activitypub/actor'
|
||||||
import { VideoModel } from '../../../models/video/video'
|
import { VideoModel } from '../../../models/video/video'
|
||||||
import { getAnnounceActivityPubUrl } from '../url'
|
import { getAnnounceActivityPubUrl } from '../url'
|
||||||
|
@ -16,14 +15,11 @@ import { createActivityData } from './send-create'
|
||||||
|
|
||||||
async function buildVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) {
|
async function buildVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) {
|
||||||
const url = getAnnounceActivityPubUrl(video.url, byActor)
|
const url = getAnnounceActivityPubUrl(video.url, byActor)
|
||||||
const videoObject = video.toActivityPubObject()
|
const announcedObject = video.url
|
||||||
|
|
||||||
const announcedAudience = await getAudience(byActor, t, video.privacy === VideoPrivacy.PUBLIC)
|
|
||||||
const announcedActivity = await createActivityData(url, video.VideoChannel.Account.Actor, videoObject, t, announcedAudience)
|
|
||||||
|
|
||||||
const accountsToForwardView = await getActorsInvolvedInVideo(video, t)
|
const accountsToForwardView = await getActorsInvolvedInVideo(video, t)
|
||||||
const audience = getObjectFollowersAudience(accountsToForwardView)
|
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) {
|
async function sendVideoAnnounceToFollowers (byActor: ActorModel, video: VideoModel, t: Transaction) {
|
||||||
|
@ -48,7 +44,7 @@ async function sendVideoAnnounceToOrigin (byActor: ActorModel, video: VideoModel
|
||||||
async function announceActivityData (
|
async function announceActivityData (
|
||||||
url: string,
|
url: string,
|
||||||
byActor: ActorModel,
|
byActor: ActorModel,
|
||||||
object: ActivityCreate,
|
object: string,
|
||||||
t: Transaction,
|
t: Transaction,
|
||||||
audience?: ActivityAudience
|
audience?: ActivityAudience
|
||||||
): Promise<ActivityAnnounce> {
|
): Promise<ActivityAnnounce> {
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
|
import * as Bluebird from 'bluebird'
|
||||||
import * as magnetUtil from 'magnet-uri'
|
import * as magnetUtil from 'magnet-uri'
|
||||||
import { join } from 'path'
|
import { join } from 'path'
|
||||||
import * as request from 'request'
|
import * as request from 'request'
|
||||||
import { ActivityIconObject } from '../../../shared/index'
|
import { ActivityIconObject } from '../../../shared/index'
|
||||||
import { VideoTorrentObject } from '../../../shared/models/activitypub/objects'
|
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 { isVideoTorrentObjectValid } from '../../helpers/custom-validators/activitypub/videos'
|
||||||
import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos'
|
import { isVideoFileInfoHashValid } from '../../helpers/custom-validators/videos'
|
||||||
import { retryTransactionWrapper } from '../../helpers/database-utils'
|
import { retryTransactionWrapper } from '../../helpers/database-utils'
|
||||||
import { logger } from '../../helpers/logger'
|
import { logger } from '../../helpers/logger'
|
||||||
import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
|
import { doRequest, doRequestAndSaveToFile } from '../../helpers/requests'
|
||||||
import { ACTIVITY_PUB, CONFIG, REMOTE_SCHEME, sequelizeTypescript, STATIC_PATHS, VIDEO_MIMETYPE_EXT } from '../../initializers'
|
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 { ActorModel } from '../../models/activitypub/actor'
|
||||||
import { TagModel } from '../../models/video/tag'
|
import { TagModel } from '../../models/video/tag'
|
||||||
import { VideoModel } from '../../models/video/video'
|
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 { VideoFileModel } from '../../models/video/video-file'
|
||||||
import { VideoShareModel } from '../../models/video/video-share'
|
import { VideoShareModel } from '../../models/video/video-share'
|
||||||
import { getOrCreateActorAndServerAndModel } from './actor'
|
import { getOrCreateActorAndServerAndModel } from './actor'
|
||||||
|
import { addVideoComments } from './video-comments'
|
||||||
|
|
||||||
function fetchRemoteVideoPreview (video: VideoModel, reject: Function) {
|
function fetchRemoteVideoPreview (video: VideoModel, reject: Function) {
|
||||||
const host = video.VideoChannel.Account.Actor.Server.host
|
const host = video.VideoChannel.Account.Actor.Server.host
|
||||||
|
@ -210,9 +213,57 @@ async function getOrCreateAccountAndVideoAndChannel (videoObject: VideoTorrentOb
|
||||||
|
|
||||||
const video = await retryTransactionWrapper(getOrCreateVideo, options)
|
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 }
|
return { actor, channelActor, video }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function createRates (actorUrls: string[], video: VideoModel, rate: VideoRateType) {
|
||||||
|
let rateCounts = 0
|
||||||
|
const tasks: Bluebird<number>[] = []
|
||||||
|
|
||||||
|
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[]) {
|
async function addVideoShares (instance: VideoModel, shareUrls: string[]) {
|
||||||
for (const shareUrl of shareUrls) {
|
for (const shareUrl of shareUrls) {
|
||||||
// Fetch url
|
// Fetch url
|
||||||
|
|
|
@ -59,7 +59,7 @@ export interface ActivityReject extends BaseActivity {
|
||||||
|
|
||||||
export interface ActivityAnnounce extends BaseActivity {
|
export interface ActivityAnnounce extends BaseActivity {
|
||||||
type: 'Announce'
|
type: 'Announce'
|
||||||
object: ActivityCreate | string
|
object: string | { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActivityUndo extends BaseActivity {
|
export interface ActivityUndo extends BaseActivity {
|
||||||
|
|
Loading…
Reference in New Issue