From 453e83ea5d81d203ba34bc43cd5c2c750ba40568 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 15 Aug 2019 11:53:26 +0200 Subject: Stronger model typings --- server/lib/activitypub/actor.ts | 75 +++++++---- server/lib/activitypub/audience.ts | 27 ++-- server/lib/activitypub/cache-file.ts | 14 +- server/lib/activitypub/playlist.ts | 19 ++- server/lib/activitypub/process/process-accept.ts | 5 +- server/lib/activitypub/process/process-announce.ts | 7 +- server/lib/activitypub/process/process-create.ts | 14 +- server/lib/activitypub/process/process-delete.ts | 26 ++-- server/lib/activitypub/process/process-dislike.ts | 4 +- server/lib/activitypub/process/process-flag.ts | 6 +- server/lib/activitypub/process/process-follow.ts | 21 +-- server/lib/activitypub/process/process-like.ts | 4 +- server/lib/activitypub/process/process-reject.ts | 4 +- server/lib/activitypub/process/process-undo.ts | 12 +- server/lib/activitypub/process/process-update.ts | 12 +- server/lib/activitypub/process/process-view.ts | 6 +- server/lib/activitypub/process/process.ts | 11 +- server/lib/activitypub/send/send-accept.ts | 7 +- server/lib/activitypub/send/send-announce.ts | 15 +-- server/lib/activitypub/send/send-create.ts | 34 +++-- server/lib/activitypub/send/send-delete.ts | 12 +- server/lib/activitypub/send/send-dislike.ts | 7 +- server/lib/activitypub/send/send-flag.ts | 9 +- server/lib/activitypub/send/send-follow.ts | 6 +- server/lib/activitypub/send/send-like.ts | 7 +- server/lib/activitypub/send/send-reject.ts | 7 +- server/lib/activitypub/send/send-undo.ts | 34 +++-- server/lib/activitypub/send/send-update.ts | 31 +++-- server/lib/activitypub/send/send-view.ts | 6 +- server/lib/activitypub/send/utils.ts | 35 +++-- server/lib/activitypub/share.ts | 21 +-- server/lib/activitypub/url.ts | 60 +++++---- server/lib/activitypub/video-comments.ts | 16 +-- server/lib/activitypub/video-rates.ts | 24 ++-- server/lib/activitypub/videos.ts | 143 ++++++++++++--------- 35 files changed, 412 insertions(+), 329 deletions(-) (limited to 'server/lib/activitypub') diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 9f5d12eb4..7862b0f00 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -22,13 +22,25 @@ import { JobQueue } from '../job-queue' import { getServerActor } from '../../helpers/utils' import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor' import { sequelizeTypescript } from '../../initializers/database' +import { + MAccount, + MActor, + MActorAccountChannelId, + MActorAccountId, + MActorDefault, + MActorFull, + MActorId, + MActorAccountChannelIdActor, + MChannel, + MActorFullActor, MAccountActorDefault, MChannelActorDefault, MChannelActorAccountDefault +} from '../../typings/models' // Set account keys, this could be long so process after the account creation and do not block the client -function setAsyncActorKeys (actor: ActorModel) { +function setAsyncActorKeys (actor: MActor) { return createPrivateAndPublicKeys() .then(({ publicKey, privateKey }) => { - actor.set('publicKey', publicKey) - actor.set('privateKey', privateKey) + actor.publicKey = publicKey + actor.privateKey = privateKey return actor.save() }) .catch(err => { @@ -37,12 +49,26 @@ function setAsyncActorKeys (actor: ActorModel) { }) } +function getOrCreateActorAndServerAndModel ( + activityActor: string | ActivityPubActor, + fetchType: 'all', + recurseIfNeeded?: boolean, + updateCollections?: boolean +): Promise + +function getOrCreateActorAndServerAndModel ( + activityActor: string | ActivityPubActor, + fetchType?: 'association-ids', + recurseIfNeeded?: boolean, + updateCollections?: boolean +): Promise + async function getOrCreateActorAndServerAndModel ( activityActor: string | ActivityPubActor, - fetchType: ActorFetchByUrlType = 'actor-and-association-ids', + fetchType: ActorFetchByUrlType = 'association-ids', recurseIfNeeded = true, updateCollections = false -) { +): Promise { const actorUrl = getAPId(activityActor) let created = false let accountPlaylistsUrl: string @@ -61,7 +87,7 @@ async function getOrCreateActorAndServerAndModel ( // Create the attributed to actor // In PeerTube a video channel is owned by an account - let ownerActor: ActorModel = undefined + let ownerActor: MActorFullActor if (recurseIfNeeded === true && result.actor.type === 'Group') { const accountAttributedTo = result.attributedTo.find(a => a.type === 'Person') if (!accountAttributedTo) throw new Error('Cannot find account attributed to video channel ' + actor.url) @@ -85,8 +111,8 @@ async function getOrCreateActorAndServerAndModel ( accountPlaylistsUrl = result.playlists } - if (actor.Account) actor.Account.Actor = actor - if (actor.VideoChannel) actor.VideoChannel.Actor = actor + if (actor.Account) (actor as MActorAccountChannelIdActor).Account.Actor = actor + if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType) if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.') @@ -140,7 +166,8 @@ async function updateActorInstance (actorInstance: ActorModel, attributes: Activ actorInstance.followingUrl = attributes.following } -async function updateActorAvatarInstance (actor: ActorModel, info: { name: string, onDisk: boolean, fileUrl: string }, t: Transaction) { +type AvatarInfo = { name: string, onDisk: boolean, fileUrl: string } +async function updateActorAvatarInstance (actor: MActorDefault, info: AvatarInfo, t: Transaction) { if (info.name !== undefined) { if (actor.avatarId) { try { @@ -212,14 +239,16 @@ async function addFetchOutboxJob (actor: Pick) { return JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload }) } -async function refreshActorIfNeeded ( - actorArg: ActorModel, +async function refreshActorIfNeeded ( + actorArg: T, fetchedType: ActorFetchByUrlType -): Promise<{ actor: ActorModel, refreshed: boolean }> { +): Promise<{ actor: T | MActorFull, refreshed: boolean }> { if (!actorArg.isOutdated()) return { actor: actorArg, refreshed: false } // We need more attributes - const actor = fetchedType === 'all' ? actorArg : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) + const actor = fetchedType === 'all' + ? actorArg as MActorFull + : await ActorModel.loadByUrlAndPopulateAccountAndChannel(actorArg.url) try { let actorUrl: string @@ -297,9 +326,9 @@ export { function saveActorAndServerAndModelIfNotExist ( result: FetchRemoteActorResult, - ownerActor?: ActorModel, + ownerActor?: MActorFullActor, t?: Transaction -): Bluebird | Promise { +): Bluebird | Promise { let actor = result.actor if (t !== undefined) return save(t) @@ -336,7 +365,7 @@ function saveActorAndServerAndModelIfNotExist ( // Force the actor creation, sometimes Sequelize skips the save() when it thinks the instance already exists // (which could be false in a retried query) - const [ actorCreated ] = await ActorModel.findOrCreate({ + const [ actorCreated ] = await ActorModel.findOrCreate({ defaults: actor.toJSON(), where: { url: actor.url @@ -345,10 +374,10 @@ function saveActorAndServerAndModelIfNotExist ( }) if (actorCreated.type === 'Person' || actorCreated.type === 'Application') { - actorCreated.Account = await saveAccount(actorCreated, result, t) + actorCreated.Account = await saveAccount(actorCreated, result, t) as MAccountActorDefault actorCreated.Account.Actor = actorCreated } else if (actorCreated.type === 'Group') { // Video channel - actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) + actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) as MChannelActorAccountDefault actorCreated.VideoChannel.Actor = actorCreated actorCreated.VideoChannel.Account = ownerActor.Account } @@ -360,7 +389,7 @@ function saveActorAndServerAndModelIfNotExist ( } type FetchRemoteActorResult = { - actor: ActorModel + actor: MActor name: string summary: string support?: string @@ -429,7 +458,7 @@ async function fetchRemoteActor (actorUrl: string): Promise<{ statusCode?: numbe } } -async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t: Transaction) { +async function saveAccount (actor: MActorId, result: FetchRemoteActorResult, t: Transaction) { const [ accountCreated ] = await AccountModel.findOrCreate({ defaults: { name: result.name, @@ -442,10 +471,10 @@ async function saveAccount (actor: ActorModel, result: FetchRemoteActorResult, t transaction: t }) - return accountCreated + return accountCreated as MAccount } -async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResult, ownerActor: ActorModel, t: Transaction) { +async function saveVideoChannel (actor: MActorId, result: FetchRemoteActorResult, ownerActor: MActorAccountId, t: Transaction) { const [ videoChannelCreated ] = await VideoChannelModel.findOrCreate({ defaults: { name: result.name, @@ -460,5 +489,5 @@ async function saveVideoChannel (actor: ActorModel, result: FetchRemoteActorResu transaction: t }) - return videoChannelCreated + return videoChannelCreated as MChannel } diff --git a/server/lib/activitypub/audience.ts b/server/lib/activitypub/audience.ts index 0e3d78590..f2ab54cf7 100644 --- a/server/lib/activitypub/audience.ts +++ b/server/lib/activitypub/audience.ts @@ -3,11 +3,10 @@ import { ActivityAudience } from '../../../shared/models/activitypub' import { ACTIVITY_PUB } from '../../initializers/constants' import { ActorModel } from '../../models/activitypub/actor' import { VideoModel } from '../../models/video/video' -import { VideoCommentModel } from '../../models/video/video-comment' import { VideoShareModel } from '../../models/video/video-share' -import { ActorModelOnly } from '../../typings/models' +import { MActorFollowersUrl, MActorLight, MCommentOwner, MCommentOwnerVideo, MVideo, MVideoAccountLight } from '../../typings/models' -function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: ActorModel[]): ActivityAudience { +function getRemoteVideoAudience (video: MVideoAccountLight, actorsInvolvedInVideo: MActorFollowersUrl[]): ActivityAudience { return { to: [ video.VideoChannel.Account.Actor.url ], cc: actorsInvolvedInVideo.map(a => a.followersUrl) @@ -15,9 +14,9 @@ function getRemoteVideoAudience (video: VideoModel, actorsInvolvedInVideo: Actor } function getVideoCommentAudience ( - videoComment: VideoCommentModel, - threadParentComments: VideoCommentModel[], - actorsInvolvedInVideo: ActorModel[], + videoComment: MCommentOwnerVideo, + threadParentComments: MCommentOwner[], + actorsInvolvedInVideo: MActorFollowersUrl[], isOrigin = false ): ActivityAudience { const to = [ ACTIVITY_PUB.PUBLIC ] @@ -42,26 +41,28 @@ function getVideoCommentAudience ( } } -function getAudienceFromFollowersOf (actorsInvolvedInObject: ActorModel[]): ActivityAudience { +function getAudienceFromFollowersOf (actorsInvolvedInObject: MActorFollowersUrl[]): ActivityAudience { return { to: [ ACTIVITY_PUB.PUBLIC ].concat(actorsInvolvedInObject.map(a => a.followersUrl)), cc: [] } } -async function getActorsInvolvedInVideo (video: VideoModel, t: Transaction) { - const actors = await VideoShareModel.loadActorsByShare(video.id, t) +async function getActorsInvolvedInVideo (video: MVideo, t: Transaction) { + const actors: MActorLight[] = await VideoShareModel.loadActorsByShare(video.id, t) - const videoActor = video.VideoChannel && video.VideoChannel.Account - ? video.VideoChannel.Account.Actor - : await ActorModel.loadAccountActorByVideoId(video.id, t) + const videoAll = video as VideoModel + + const videoActor = videoAll.VideoChannel && videoAll.VideoChannel.Account + ? videoAll.VideoChannel.Account.Actor + : await ActorModel.loadFromAccountByVideoId(video.id, t) actors.push(videoActor) return actors } -function getAudience (actorSender: ActorModelOnly, isPublic = true) { +function getAudience (actorSender: MActorFollowersUrl, isPublic = true) { return buildAudience([ actorSender.followersUrl ], isPublic) } diff --git a/server/lib/activitypub/cache-file.ts b/server/lib/activitypub/cache-file.ts index de5cc54ac..65b2dcb49 100644 --- a/server/lib/activitypub/cache-file.ts +++ b/server/lib/activitypub/cache-file.ts @@ -1,10 +1,10 @@ import { CacheFileObject } from '../../../shared/index' -import { VideoModel } from '../../models/video/video' import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' import { Transaction } from 'sequelize' import { VideoStreamingPlaylistType } from '../../../shared/models/videos/video-streaming-playlist.type' +import { MActorId, MVideoRedundancy, MVideoWithAllFiles } from '@server/typings/models' -function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject, video: VideoModel, byActor: { id?: number }) { +function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId) { if (cacheFileObject.url.mediaType === 'application/x-mpegURL') { const url = cacheFileObject.url @@ -39,7 +39,7 @@ function cacheFileActivityObjectToDBAttributes (cacheFileObject: CacheFileObject } } -async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: VideoModel, byActor: { id?: number }, t: Transaction) { +async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId, t: Transaction) { const redundancyModel = await VideoRedundancyModel.loadByUrl(cacheFileObject.id, t) if (!redundancyModel) { @@ -49,7 +49,7 @@ async function createOrUpdateCacheFile (cacheFileObject: CacheFileObject, video: } } -function createCacheFile (cacheFileObject: CacheFileObject, video: VideoModel, byActor: { id?: number }, t: Transaction) { +function createCacheFile (cacheFileObject: CacheFileObject, video: MVideoWithAllFiles, byActor: MActorId, t: Transaction) { const attributes = cacheFileActivityObjectToDBAttributes(cacheFileObject, video, byActor) return VideoRedundancyModel.create(attributes, { transaction: t }) @@ -57,9 +57,9 @@ function createCacheFile (cacheFileObject: CacheFileObject, video: VideoModel, b function updateCacheFile ( cacheFileObject: CacheFileObject, - redundancyModel: VideoRedundancyModel, - video: VideoModel, - byActor: { id?: number }, + redundancyModel: MVideoRedundancy, + video: MVideoWithAllFiles, + byActor: MActorId, t: Transaction ) { if (redundancyModel.actorId !== byActor.id) { diff --git a/server/lib/activitypub/playlist.ts b/server/lib/activitypub/playlist.ts index c2e2a3283..c52b715ef 100644 --- a/server/lib/activitypub/playlist.ts +++ b/server/lib/activitypub/playlist.ts @@ -1,7 +1,6 @@ import { PlaylistObject } from '../../../shared/models/activitypub/objects/playlist-object' import { crawlCollectionPage } from './crawl' import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' -import { AccountModel } from '../../models/account/account' import { isArray } from '../../helpers/custom-validators/misc' import { getOrCreateActorAndServerAndModel } from './actor' import { logger } from '../../helpers/logger' @@ -13,14 +12,14 @@ import { PlaylistElementObject } from '../../../shared/models/activitypub/object import { getOrCreateVideoAndAccountAndChannel } from './videos' import { isPlaylistElementObjectValid, isPlaylistObjectValid } from '../../helpers/custom-validators/activitypub/playlist' import { VideoPlaylistElementModel } from '../../models/video/video-playlist-element' -import { VideoModel } from '../../models/video/video' import { VideoPlaylistPrivacy } from '../../../shared/models/videos/playlist/video-playlist-privacy.model' import { sequelizeTypescript } from '../../initializers/database' import { createPlaylistMiniatureFromUrl } from '../thumbnail' import { FilteredModelAttributes } from '../../typings/sequelize' -import { AccountModelId } from '../../typings/models' +import { MAccountDefault, MAccountId, MVideoId } from '../../typings/models' +import { MVideoPlaylist, MVideoPlaylistId, MVideoPlaylistOwner } from '../../typings/models/video/video-playlist' -function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) { +function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) { const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPlaylistPrivacy.PUBLIC : VideoPlaylistPrivacy.UNLISTED return { @@ -36,7 +35,7 @@ function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount } } -function playlistElementObjectToDBAttributes (elementObject: PlaylistElementObject, videoPlaylist: VideoPlaylistModel, video: VideoModel) { +function playlistElementObjectToDBAttributes (elementObject: PlaylistElementObject, videoPlaylist: MVideoPlaylistId, video: MVideoId) { return { position: elementObject.position, url: elementObject.id, @@ -47,7 +46,7 @@ function playlistElementObjectToDBAttributes (elementObject: PlaylistElementObje } } -async function createAccountPlaylists (playlistUrls: string[], account: AccountModel) { +async function createAccountPlaylists (playlistUrls: string[], account: MAccountDefault) { await Bluebird.map(playlistUrls, async playlistUrl => { try { const exists = await VideoPlaylistModel.doesPlaylistExist(playlistUrl) @@ -75,7 +74,7 @@ async function createAccountPlaylists (playlistUrls: string[], account: AccountM }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) } -async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: AccountModelId, to: string[]) { +async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) { const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to) if (isArray(playlistObject.attributedTo) && playlistObject.attributedTo.length === 1) { @@ -88,7 +87,7 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc } } - const [ playlist ] = await VideoPlaylistModel.upsert(playlistAttributes, { returning: true }) + const [ playlist ] = await VideoPlaylistModel.upsert(playlistAttributes, { returning: true }) let accItems: string[] = [] await crawlCollectionPage(playlistObject.id, items => { @@ -114,7 +113,7 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc return resetVideoPlaylistElements(accItems, refreshedPlaylist) } -async function refreshVideoPlaylistIfNeeded (videoPlaylist: VideoPlaylistModel): Promise { +async function refreshVideoPlaylistIfNeeded (videoPlaylist: MVideoPlaylistOwner): Promise { if (!videoPlaylist.isOutdated()) return videoPlaylist try { @@ -157,7 +156,7 @@ export { // --------------------------------------------------------------------------- -async function resetVideoPlaylistElements (elementUrls: string[], playlist: VideoPlaylistModel) { +async function resetVideoPlaylistElements (elementUrls: string[], playlist: MVideoPlaylist) { const elementsToCreate: FilteredModelAttributes[] = [] await Bluebird.map(elementUrls, async elementUrl => { diff --git a/server/lib/activitypub/process/process-accept.ts b/server/lib/activitypub/process/process-accept.ts index cf27e6c32..86f7c764d 100644 --- a/server/lib/activitypub/process/process-accept.ts +++ b/server/lib/activitypub/process/process-accept.ts @@ -1,9 +1,8 @@ import { ActivityAccept } from '../../../../shared/models/activitypub' -import { ActorModel } from '../../../models/activitypub/actor' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { addFetchOutboxJob } from '../actor' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorDefault, MActorSignature } from '../../../typings/models' async function processAcceptActivity (options: APProcessorOptions) { const { byActor: targetActor, inboxActor } = options @@ -20,7 +19,7 @@ export { // --------------------------------------------------------------------------- -async function processAccept (actor: ActorModel, targetActor: SignatureActorModel) { +async function processAccept (actor: MActorDefault, targetActor: MActorSignature) { const follow = await ActorFollowModel.loadByActorAndTarget(actor.id, targetActor.id) if (!follow) throw new Error('Cannot find associated follow.') diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index b3cdc4441..91a9ad72c 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -5,10 +5,9 @@ import { VideoShareModel } from '../../../models/video/video-share' import { forwardVideoRelatedActivity } from '../send/utils' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { Notifier } from '../../notifier' -import { VideoModel } from '../../../models/video/video' import { logger } from '../../../helpers/logger' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature, MVideoAccountAllFiles } from '../../../typings/models' async function processAnnounceActivity (options: APProcessorOptions) { const { activity, byActor: actorAnnouncer } = options @@ -26,10 +25,10 @@ export { // --------------------------------------------------------------------------- -async function processVideoShare (actorAnnouncer: SignatureActorModel, activity: ActivityAnnounce, notify: boolean) { +async function processVideoShare (actorAnnouncer: MActorSignature, activity: ActivityAnnounce, notify: boolean) { const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id - let video: VideoModel + let video: MVideoAccountAllFiles let videoCreated: boolean try { diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 6815c6997..c45f09f52 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -10,10 +10,8 @@ import { createOrUpdateCacheFile } from '../cache-file' import { Notifier } from '../../notifier' import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' import { createOrUpdateVideoPlaylist } from '../playlist' -import { VideoModel } from '../../../models/video/video' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { VideoCommentModel } from '../../../models/video/video-comment' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature, MCommentOwnerVideo, MVideoAccountAllFiles } from '../../../typings/models' async function processCreateActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -61,7 +59,7 @@ async function processCreateVideo (activity: ActivityCreate, notify: boolean) { return video } -async function processCreateCacheFile (activity: ActivityCreate, byActor: SignatureActorModel) { +async function processCreateCacheFile (activity: ActivityCreate, byActor: MActorSignature) { const cacheFile = activity.object as CacheFileObject const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFile.object }) @@ -77,15 +75,15 @@ async function processCreateCacheFile (activity: ActivityCreate, byActor: Signat } } -async function processCreateVideoComment (activity: ActivityCreate, byActor: SignatureActorModel, notify: boolean) { +async function processCreateVideoComment (activity: ActivityCreate, byActor: MActorSignature, notify: boolean) { const commentObject = activity.object as VideoCommentObject const byAccount = byActor.Account if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) - let video: VideoModel + let video: MVideoAccountAllFiles let created: boolean - let comment: VideoCommentModel + let comment: MCommentOwnerVideo try { const resolveThreadResult = await resolveThread({ url: commentObject.id, isVideo: false }) video = resolveThreadResult.video @@ -110,7 +108,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: Sig if (created && notify) Notifier.Instance.notifyOnNewComment(comment) } -async function processCreatePlaylist (activity: ActivityCreate, byActor: SignatureActorModel) { +async function processCreatePlaylist (activity: ActivityCreate, byActor: MActorSignature) { const playlistObject = activity.object as PlaylistObject const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index 344d14322..79d0e0d79 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts @@ -2,15 +2,13 @@ import { ActivityDelete } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' import { sequelizeTypescript } from '../../../initializers' -import { AccountModel } from '../../../models/account/account' import { ActorModel } from '../../../models/activitypub/actor' import { VideoModel } from '../../../models/video/video' -import { VideoChannelModel } from '../../../models/video/video-channel' import { VideoCommentModel } from '../../../models/video/video-comment' import { forwardVideoRelatedActivity } from '../send/utils' import { VideoPlaylistModel } from '../../../models/video/video-playlist' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MAccountActor, MActor, MActorSignature, MChannelActor, MChannelActorAccountActor } from '../../../typings/models' async function processDeleteActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -24,13 +22,17 @@ async function processDeleteActivity (options: APProcessorOptions { @@ -84,7 +86,7 @@ async function processDeleteVideo (actor: ActorModel, videoToDelete: VideoModel) logger.info('Remote video with uuid %s removed.', videoToDelete.uuid) } -async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete: VideoPlaylistModel) { +async function processDeleteVideoPlaylist (actor: MActor, playlistToDelete: VideoPlaylistModel) { logger.debug('Removing remote video playlist "%s".', playlistToDelete.uuid) await sequelizeTypescript.transaction(async t => { @@ -98,7 +100,7 @@ async function processDeleteVideoPlaylist (actor: ActorModel, playlistToDelete: logger.info('Remote video playlist with uuid %s removed.', playlistToDelete.uuid) } -async function processDeleteAccount (accountToRemove: AccountModel) { +async function processDeleteAccount (accountToRemove: MAccountActor) { logger.debug('Removing remote account "%s".', accountToRemove.Actor.url) await sequelizeTypescript.transaction(async t => { @@ -108,7 +110,7 @@ async function processDeleteAccount (accountToRemove: AccountModel) { logger.info('Remote account %s removed.', accountToRemove.Actor.url) } -async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelModel) { +async function processDeleteVideoChannel (videoChannelToRemove: MChannelActor) { logger.debug('Removing remote video channel "%s".', videoChannelToRemove.Actor.url) await sequelizeTypescript.transaction(async t => { @@ -118,7 +120,7 @@ async function processDeleteVideoChannel (videoChannelToRemove: VideoChannelMode logger.info('Remote video channel %s removed.', videoChannelToRemove.Actor.url) } -function processDeleteVideoComment (byActor: SignatureActorModel, videoComment: VideoCommentModel, activity: ActivityDelete) { +function processDeleteVideoComment (byActor: MActorSignature, videoComment: VideoCommentModel, activity: ActivityDelete) { logger.debug('Removing remote video comment "%s".', videoComment.url) return sequelizeTypescript.transaction(async t => { diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index 727fcfee0..debd8a67c 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts @@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' import { getVideoDislikeActivityPubUrl } from '../url' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature } from '../../../typings/models' async function processDislikeActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -22,7 +22,7 @@ export { // --------------------------------------------------------------------------- -async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: SignatureActorModel) { +async function processDislike (activity: ActivityCreate | ActivityDislike, byActor: MActorSignature) { const dislikeObject = activity.type === 'Dislike' ? activity.object : (activity.object as DislikeObject).object const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index 1f8a80c14..422386540 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts @@ -8,7 +8,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { Notifier } from '../../notifier' import { getAPId } from '../../../helpers/activitypub' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature, MVideoAbuseVideo } from '../../../typings/models' async function processFlagActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -23,7 +23,7 @@ export { // --------------------------------------------------------------------------- -async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: SignatureActorModel) { +async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, byActor: MActorSignature) { const flag = activity.type === 'Flag' ? activity : (activity.object as VideoAbuseObject) logger.debug('Reporting remote abuse for video %s.', getAPId(flag.object)) @@ -41,7 +41,7 @@ async function processCreateVideoAbuse (activity: ActivityCreate | ActivityFlag, state: VideoAbuseState.PENDING } - const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) + const videoAbuseInstance = await VideoAbuseModel.create(videoAbuseData, { transaction: t }) as MVideoAbuseVideo videoAbuseInstance.Video = video logger.info('Remote abuse for video uuid %s created', flag.object) diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index 240aa5799..bc5660395 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts @@ -10,8 +10,7 @@ import { getAPId } from '../../../helpers/activitypub' import { getServerActor } from '../../../helpers/utils' import { CONFIG } from '../../../initializers/config' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' -import { ActorFollowModelLight } from '../../../typings/models/actor-follow' +import { MAccount, MActorFollowActors, MActorFollowFull, MActorSignature } from '../../../typings/models' async function processFollowActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -28,7 +27,7 @@ export { // --------------------------------------------------------------------------- -async function processFollow (byActor: SignatureActorModel, targetActorURL: string) { +async function processFollow (byActor: MActorSignature, targetActorURL: string) { const { actorFollow, created, isFollowingInstance } = await sequelizeTypescript.transaction(async t => { const targetActor = await ActorModel.loadByUrlAndPopulateAccountAndChannel(targetActorURL, t) @@ -43,10 +42,10 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri await sendReject(byActor, targetActor) - return { actorFollow: undefined } + return { actorFollow: undefined as MActorFollowActors } } - const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ + const [ actorFollow, created ] = await ActorFollowModel.findOrCreate({ where: { actorId: byActor.id, targetActorId: targetActor.id @@ -57,7 +56,7 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri state: CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL ? 'pending' : 'accepted' }, transaction: t - }) as [ ActorFollowModelLight, boolean ] + }) if (actorFollow.state !== 'accepted' && CONFIG.FOLLOWERS.INSTANCE.MANUAL_APPROVAL === false) { actorFollow.state = 'accepted' @@ -77,8 +76,14 @@ async function processFollow (byActor: SignatureActorModel, targetActorURL: stri if (!actorFollow) return if (created) { - if (isFollowingInstance) Notifier.Instance.notifyOfNewInstanceFollow(actorFollow) - else Notifier.Instance.notifyOfNewUserFollow(actorFollow) + if (isFollowingInstance) { + Notifier.Instance.notifyOfNewInstanceFollow(actorFollow) + } else { + const actorFollowFull = actorFollow as MActorFollowFull + actorFollowFull.ActorFollower.Account = await actorFollow.ActorFollower.$get('Account') as MAccount + + Notifier.Instance.notifyOfNewUserFollow(actorFollowFull) + } } logger.info('Actor %s is followed by actor %s.', targetActorURL, byActor.url) diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index cf559af72..62be0de42 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts @@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { getVideoLikeActivityPubUrl } from '../url' import { getAPId } from '../../../helpers/activitypub' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature } from '../../../typings/models' async function processLikeActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -22,7 +22,7 @@ export { // --------------------------------------------------------------------------- -async function processLikeVideo (byActor: SignatureActorModel, activity: ActivityLike) { +async function processLikeVideo (byActor: MActorSignature, activity: ActivityLike) { const videoUrl = getAPId(activity.object) const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-reject.ts b/server/lib/activitypub/process/process-reject.ts index 22e311ceb..00e9afa10 100644 --- a/server/lib/activitypub/process/process-reject.ts +++ b/server/lib/activitypub/process/process-reject.ts @@ -2,7 +2,7 @@ import { ActivityReject } from '../../../../shared/models/activitypub/activity' import { sequelizeTypescript } from '../../../initializers' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { ActorModelOnly } from '../../../typings/models' +import { MActor } from '../../../typings/models' async function processRejectActivity (options: APProcessorOptions) { const { byActor: targetActor, inboxActor } = options @@ -19,7 +19,7 @@ export { // --------------------------------------------------------------------------- -async function processReject (follower: ActorModelOnly, targetActor: ActorModelOnly) { +async function processReject (follower: MActor, targetActor: MActor) { return sequelizeTypescript.transaction(async t => { const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, targetActor.id, t) diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index c37ee38bb..10643b2e9 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts @@ -11,7 +11,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { VideoShareModel } from '../../../models/video/video-share' import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature } from '../../../typings/models' async function processUndoActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -54,7 +54,7 @@ export { // --------------------------------------------------------------------------- -async function processUndoLike (byActor: SignatureActorModel, activity: ActivityUndo) { +async function processUndoLike (byActor: MActorSignature, activity: ActivityUndo) { const likeActivity = activity.object as ActivityLike const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: likeActivity.object }) @@ -77,7 +77,7 @@ async function processUndoLike (byActor: SignatureActorModel, activity: Activity }) } -async function processUndoDislike (byActor: SignatureActorModel, activity: ActivityUndo) { +async function processUndoDislike (byActor: MActorSignature, activity: ActivityUndo) { const dislike = activity.object.type === 'Dislike' ? activity.object : activity.object.object as DislikeObject @@ -102,7 +102,7 @@ async function processUndoDislike (byActor: SignatureActorModel, activity: Activ }) } -async function processUndoCacheFile (byActor: SignatureActorModel, activity: ActivityUndo) { +async function processUndoCacheFile (byActor: MActorSignature, activity: ActivityUndo) { const cacheFileObject = activity.object.object as CacheFileObject const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: cacheFileObject.object }) @@ -127,7 +127,7 @@ async function processUndoCacheFile (byActor: SignatureActorModel, activity: Act }) } -function processUndoFollow (follower: SignatureActorModel, followActivity: ActivityFollow) { +function processUndoFollow (follower: MActorSignature, followActivity: ActivityFollow) { return sequelizeTypescript.transaction(async t => { const following = await ActorModel.loadByUrlAndPopulateAccountAndChannel(followActivity.object, t) const actorFollow = await ActorFollowModel.loadByActorAndTarget(follower.id, following.id, t) @@ -140,7 +140,7 @@ function processUndoFollow (follower: SignatureActorModel, followActivity: Activ }) } -function processUndoAnnounce (byActor: SignatureActorModel, announceActivity: ActivityAnnounce) { +function processUndoAnnounce (byActor: MActorSignature, announceActivity: ActivityAnnounce) { return sequelizeTypescript.transaction(async t => { const share = await VideoShareModel.loadByUrl(announceActivity.id, t) if (!share) throw new Error(`Unknown video share ${announceActivity.id}.`) diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 414f9e375..9f80a0ce9 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts @@ -15,7 +15,7 @@ import { forwardVideoRelatedActivity } from '../send/utils' import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' import { createOrUpdateVideoPlaylist } from '../playlist' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature } from '../../../typings/models' async function processUpdateActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -53,7 +53,7 @@ export { // --------------------------------------------------------------------------- -async function processUpdateVideo (actor: SignatureActorModel, activity: ActivityUpdate) { +async function processUpdateVideo (actor: MActorSignature, activity: ActivityUpdate) { const videoObject = activity.object as VideoTorrentObject if (sanitizeAndCheckVideoTorrentObject(videoObject) === false) { @@ -61,20 +61,20 @@ async function processUpdateVideo (actor: SignatureActorModel, activity: Activit return undefined } - const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false }) + const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false, fetchType: 'all' }) const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) const updateOptions = { video, videoObject, - account: actor.Account, + account: channelActor.VideoChannel.Account, channel: channelActor.VideoChannel, overrideTo: activity.to } return updateVideoFromAP(updateOptions) } -async function processUpdateCacheFile (byActor: SignatureActorModel, activity: ActivityUpdate) { +async function processUpdateCacheFile (byActor: MActorSignature, activity: ActivityUpdate) { const cacheFileObject = activity.object as CacheFileObject if (!isCacheFileObjectValid(cacheFileObject)) { @@ -150,7 +150,7 @@ async function processUpdateActor (actor: ActorModel, activity: ActivityUpdate) } } -async function processUpdatePlaylist (byActor: SignatureActorModel, activity: ActivityUpdate) { +async function processUpdatePlaylist (byActor: MActorSignature, activity: ActivityUpdate) { const playlistObject = activity.object as PlaylistObject const byAccount = byActor.Account diff --git a/server/lib/activitypub/process/process-view.ts b/server/lib/activitypub/process/process-view.ts index e4997b828..df29ee968 100644 --- a/server/lib/activitypub/process/process-view.ts +++ b/server/lib/activitypub/process/process-view.ts @@ -3,7 +3,7 @@ import { forwardVideoRelatedActivity } from '../send/utils' import { Redis } from '../../redis' import { ActivityCreate, ActivityView, ViewObject } from '../../../../shared/models/activitypub' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorSignature } from '../../../typings/models' async function processViewActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -18,11 +18,11 @@ export { // --------------------------------------------------------------------------- -async function processCreateView (activity: ActivityView | ActivityCreate, byActor: SignatureActorModel) { +async function processCreateView (activity: ActivityView | ActivityCreate, byActor: MActorSignature) { const videoObject = activity.type === 'View' ? activity.object : (activity.object as ViewObject).object const options = { - videoObject: videoObject, + videoObject, fetchType: 'only-video' as 'only-video' } const { video } = await getOrCreateVideoAndAccountAndChannel(options) diff --git a/server/lib/activitypub/process/process.ts b/server/lib/activitypub/process/process.ts index d108fe321..c602bf218 100644 --- a/server/lib/activitypub/process/process.ts +++ b/server/lib/activitypub/process/process.ts @@ -1,7 +1,6 @@ import { Activity, ActivityType } from '../../../../shared/models/activitypub' import { checkUrlsSameHost, getAPId } from '../../../helpers/activitypub' import { logger } from '../../../helpers/logger' -import { ActorModel } from '../../../models/activitypub/actor' import { processAcceptActivity } from './process-accept' import { processAnnounceActivity } from './process-announce' import { processCreateActivity } from './process-create' @@ -16,7 +15,7 @@ import { processDislikeActivity } from './process-dislike' import { processFlagActivity } from './process-flag' import { processViewActivity } from './process-view' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { SignatureActorModel } from '../../../typings/models' +import { MActorDefault, MActorSignature } from '../../../typings/models' const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions) => Promise } = { Create: processCreateActivity, @@ -36,15 +35,15 @@ const processActivity: { [ P in ActivityType ]: (options: APProcessorOptions unicastTo(createActivity, byActor, comment.Video.VideoChannel.Account.Actor.sharedInboxUrl)) } -function buildCreateActivity (url: string, byActor: ActorModel, object: any, audience?: ActivityAudience): ActivityCreate { +function buildCreateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityCreate { if (!audience) audience = getAudience(byActor) return audiencify( @@ -122,8 +130,8 @@ export { // --------------------------------------------------------------------------- async function sendVideoRelatedCreateActivity (options: { - byActor: ActorModel, - video: VideoModel, + byActor: MActorLight, + video: MVideoAccountLight, url: string, object: any, transaction?: Transaction diff --git a/server/lib/activitypub/send/send-delete.ts b/server/lib/activitypub/send/send-delete.ts index 6c7fb8449..4b1ff8dc5 100644 --- a/server/lib/activitypub/send/send-delete.ts +++ b/server/lib/activitypub/send/send-delete.ts @@ -1,17 +1,17 @@ import { Transaction } from 'sequelize' import { ActivityAudience, ActivityDelete } from '../../../../shared/models/activitypub' import { ActorModel } from '../../../models/activitypub/actor' -import { VideoModel } from '../../../models/video/video' import { VideoCommentModel } from '../../../models/video/video-comment' import { VideoShareModel } from '../../../models/video/video-share' import { getDeleteActivityPubUrl } from '../url' import { broadcastToActors, broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' import { audiencify, getActorsInvolvedInVideo, getVideoCommentAudience } from '../audience' import { logger } from '../../../helpers/logger' -import { VideoPlaylistModel } from '../../../models/video/video-playlist' import { getServerActor } from '../../../helpers/utils' +import { MCommentOwnerVideoReply, MVideoAccountLight, MVideoPlaylistFullSummary } from '../../../typings/models/video' +import { MActorUrl } from '../../../typings/models' -async function sendDeleteVideo (video: VideoModel, transaction: Transaction) { +async function sendDeleteVideo (video: MVideoAccountLight, transaction: Transaction) { logger.info('Creating job to broadcast delete of video %s.', video.url) const byActor = video.VideoChannel.Account.Actor @@ -42,7 +42,7 @@ async function sendDeleteActor (byActor: ActorModel, t: Transaction) { return broadcastToFollowers(activity, byActor, actorsInvolved, t) } -async function sendDeleteVideoComment (videoComment: VideoCommentModel, t: Transaction) { +async function sendDeleteVideoComment (videoComment: MCommentOwnerVideoReply, t: Transaction) { logger.info('Creating job to send delete of comment %s.', videoComment.url) const isVideoOrigin = videoComment.Video.isOwned() @@ -74,7 +74,7 @@ async function sendDeleteVideoComment (videoComment: VideoCommentModel, t: Trans t.afterCommit(() => unicastTo(activity, byActor, videoComment.Video.VideoChannel.Account.Actor.sharedInboxUrl)) } -async function sendDeleteVideoPlaylist (videoPlaylist: VideoPlaylistModel, t: Transaction) { +async function sendDeleteVideoPlaylist (videoPlaylist: MVideoPlaylistFullSummary, t: Transaction) { logger.info('Creating job to send delete of playlist %s.', videoPlaylist.url) const byActor = videoPlaylist.OwnerAccount.Actor @@ -101,7 +101,7 @@ export { // --------------------------------------------------------------------------- -function buildDeleteActivity (url: string, object: string, byActor: ActorModel, audience?: ActivityAudience): ActivityDelete { +function buildDeleteActivity (url: string, object: string, byActor: MActorUrl, audience?: ActivityAudience): ActivityDelete { const activity = { type: 'Delete' as 'Delete', id: url, diff --git a/server/lib/activitypub/send/send-dislike.ts b/server/lib/activitypub/send/send-dislike.ts index a88436f2c..6e41f241f 100644 --- a/server/lib/activitypub/send/send-dislike.ts +++ b/server/lib/activitypub/send/send-dislike.ts @@ -1,13 +1,12 @@ import { Transaction } from 'sequelize' -import { ActorModel } from '../../../models/activitypub/actor' -import { VideoModel } from '../../../models/video/video' import { getVideoDislikeActivityPubUrl } from '../url' import { logger } from '../../../helpers/logger' import { ActivityAudience, ActivityDislike } from '../../../../shared/models/activitypub' import { sendVideoRelatedActivity } from './utils' import { audiencify, getAudience } from '../audience' +import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' -async function sendDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { +async function sendDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { logger.info('Creating job to dislike %s.', video.url) const activityBuilder = (audience: ActivityAudience) => { @@ -19,7 +18,7 @@ async function sendDislike (byActor: ActorModel, video: VideoModel, t: Transacti return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) } -function buildDislikeActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityDislike { +function buildDislikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityDislike { if (!audience) audience = getAudience(byActor) return audiencify( diff --git a/server/lib/activitypub/send/send-flag.ts b/server/lib/activitypub/send/send-flag.ts index 61ee389a6..5ae1614ab 100644 --- a/server/lib/activitypub/send/send-flag.ts +++ b/server/lib/activitypub/send/send-flag.ts @@ -1,14 +1,13 @@ -import { ActorModel } from '../../../models/activitypub/actor' -import { VideoModel } from '../../../models/video/video' -import { VideoAbuseModel } from '../../../models/video/video-abuse' import { getVideoAbuseActivityPubUrl } from '../url' import { unicastTo } from './utils' import { logger } from '../../../helpers/logger' import { ActivityAudience, ActivityFlag } from '../../../../shared/models/activitypub' import { audiencify, getAudience } from '../audience' import { Transaction } from 'sequelize' +import { MActor, MVideoFullLight } from '../../../typings/models' +import { MVideoAbuseVideo } from '../../../typings/models/video' -async function sendVideoAbuse (byActor: ActorModel, videoAbuse: VideoAbuseModel, video: VideoModel, t: Transaction) { +async function sendVideoAbuse (byActor: MActor, videoAbuse: MVideoAbuseVideo, video: MVideoFullLight, t: Transaction) { if (!video.VideoChannel.Account.Actor.serverId) return // Local user const url = getVideoAbuseActivityPubUrl(videoAbuse) @@ -22,7 +21,7 @@ async function sendVideoAbuse (byActor: ActorModel, videoAbuse: VideoAbuseModel, t.afterCommit(() => unicastTo(flagActivity, byActor, video.VideoChannel.Account.Actor.sharedInboxUrl)) } -function buildFlagActivity (url: string, byActor: ActorModel, videoAbuse: VideoAbuseModel, audience: ActivityAudience): ActivityFlag { +function buildFlagActivity (url: string, byActor: MActor, videoAbuse: MVideoAbuseVideo, audience: ActivityAudience): ActivityFlag { if (!audience) audience = getAudience(byActor) const activity = Object.assign( diff --git a/server/lib/activitypub/send/send-follow.ts b/server/lib/activitypub/send/send-follow.ts index a59ed50cf..6b17b25da 100644 --- a/server/lib/activitypub/send/send-follow.ts +++ b/server/lib/activitypub/send/send-follow.ts @@ -4,9 +4,9 @@ import { getActorFollowActivityPubUrl } from '../url' import { unicastTo } from './utils' import { logger } from '../../../helpers/logger' import { Transaction } from 'sequelize' -import { ActorModelOnly } from '../../../typings/models' +import { MActor, MActorFollowActors } from '../../../typings/models' -function sendFollow (actorFollow: ActorFollowModel, t: Transaction) { +function sendFollow (actorFollow: MActorFollowActors, t: Transaction) { const me = actorFollow.ActorFollower const following = actorFollow.ActorFollowing @@ -21,7 +21,7 @@ function sendFollow (actorFollow: ActorFollowModel, t: Transaction) { t.afterCommit(() => unicastTo(data, me, following.inboxUrl)) } -function buildFollowActivity (url: string, byActor: ActorModelOnly, targetActor: ActorModelOnly): ActivityFollow { +function buildFollowActivity (url: string, byActor: MActor, targetActor: MActor): ActivityFollow { return { type: 'Follow', id: url, diff --git a/server/lib/activitypub/send/send-like.ts b/server/lib/activitypub/send/send-like.ts index 35227887a..e84a6f98b 100644 --- a/server/lib/activitypub/send/send-like.ts +++ b/server/lib/activitypub/send/send-like.ts @@ -1,13 +1,12 @@ import { Transaction } from 'sequelize' import { ActivityAudience, ActivityLike } from '../../../../shared/models/activitypub' -import { ActorModel } from '../../../models/activitypub/actor' -import { VideoModel } from '../../../models/video/video' import { getVideoLikeActivityPubUrl } from '../url' import { sendVideoRelatedActivity } from './utils' import { audiencify, getAudience } from '../audience' import { logger } from '../../../helpers/logger' +import { MActor, MActorAudience, MVideoAccountLight, MVideoUrl } from '../../../typings/models' -async function sendLike (byActor: ActorModel, video: VideoModel, t: Transaction) { +async function sendLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { logger.info('Creating job to like %s.', video.url) const activityBuilder = (audience: ActivityAudience) => { @@ -19,7 +18,7 @@ async function sendLike (byActor: ActorModel, video: VideoModel, t: Transaction) return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) } -function buildLikeActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityLike { +function buildLikeActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityLike { if (!audience) audience = getAudience(byActor) return audiencify( diff --git a/server/lib/activitypub/send/send-reject.ts b/server/lib/activitypub/send/send-reject.ts index 63110b433..4258a3c36 100644 --- a/server/lib/activitypub/send/send-reject.ts +++ b/server/lib/activitypub/send/send-reject.ts @@ -1,12 +1,11 @@ import { ActivityFollow, ActivityReject } from '../../../../shared/models/activitypub' -import { ActorModel } from '../../../models/activitypub/actor' import { getActorFollowActivityPubUrl, getActorFollowRejectActivityPubUrl } from '../url' import { unicastTo } from './utils' import { buildFollowActivity } from './send-follow' import { logger } from '../../../helpers/logger' -import { SignatureActorModel } from '../../../typings/models' +import { MActor } from '../../../typings/models' -async function sendReject (follower: SignatureActorModel, following: ActorModel) { +async function sendReject (follower: MActor, following: MActor) { if (!follower.serverId) { // This should never happen logger.warn('Do not sending reject to local follower.') return @@ -31,7 +30,7 @@ export { // --------------------------------------------------------------------------- -function buildRejectActivity (url: string, byActor: ActorModel, followActivityData: ActivityFollow): ActivityReject { +function buildRejectActivity (url: string, byActor: MActor, followActivityData: ActivityFollow): ActivityReject { return { type: 'Reject', id: url, diff --git a/server/lib/activitypub/send/send-undo.ts b/server/lib/activitypub/send/send-undo.ts index 8fcbbac5c..e9ab5b3c5 100644 --- a/server/lib/activitypub/send/send-undo.ts +++ b/server/lib/activitypub/send/send-undo.ts @@ -2,13 +2,12 @@ import { Transaction } from 'sequelize' import { ActivityAnnounce, ActivityAudience, - ActivityCreate, ActivityDislike, + ActivityCreate, + ActivityDislike, ActivityFollow, ActivityLike, ActivityUndo } from '../../../../shared/models/activitypub' -import { ActorModel } from '../../../models/activitypub/actor' -import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { VideoModel } from '../../../models/video/video' import { getActorFollowActivityPubUrl, getUndoActivityPubUrl, getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from '../url' import { broadcastToFollowers, sendVideoRelatedActivity, unicastTo } from './utils' @@ -16,13 +15,20 @@ import { audiencify, getAudience } from '../audience' import { buildCreateActivity } from './send-create' import { buildFollowActivity } from './send-follow' import { buildLikeActivity } from './send-like' -import { VideoShareModel } from '../../../models/video/video-share' import { buildAnnounceWithVideoAudience } from './send-announce' import { logger } from '../../../helpers/logger' -import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' import { buildDislikeActivity } from './send-dislike' - -async function sendUndoFollow (actorFollow: ActorFollowModel, t: Transaction) { +import { + MActor, MActorAudience, + MActorFollowActors, + MActorLight, + MVideo, + MVideoAccountLight, + MVideoRedundancyVideo, + MVideoShare +} from '../../../typings/models' + +async function sendUndoFollow (actorFollow: MActorFollowActors, t: Transaction) { const me = actorFollow.ActorFollower const following = actorFollow.ActorFollowing @@ -40,7 +46,7 @@ async function sendUndoFollow (actorFollow: ActorFollowModel, t: Transaction) { t.afterCommit(() => unicastTo(undoActivity, me, following.inboxUrl)) } -async function sendUndoAnnounce (byActor: ActorModel, videoShare: VideoShareModel, video: VideoModel, t: Transaction) { +async function sendUndoAnnounce (byActor: MActorLight, videoShare: MVideoShare, video: MVideo, t: Transaction) { logger.info('Creating job to undo announce %s.', videoShare.url) const undoUrl = getUndoActivityPubUrl(videoShare.url) @@ -52,7 +58,7 @@ async function sendUndoAnnounce (byActor: ActorModel, videoShare: VideoShareMode return broadcastToFollowers(undoActivity, byActor, actorsInvolvedInVideo, t, followersException) } -async function sendUndoLike (byActor: ActorModel, video: VideoModel, t: Transaction) { +async function sendUndoLike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { logger.info('Creating job to undo a like of video %s.', video.url) const likeUrl = getVideoLikeActivityPubUrl(byActor, video) @@ -61,7 +67,7 @@ async function sendUndoLike (byActor: ActorModel, video: VideoModel, t: Transact return sendUndoVideoRelatedActivity({ byActor, video, url: likeUrl, activity: likeActivity, transaction: t }) } -async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Transaction) { +async function sendUndoDislike (byActor: MActor, video: MVideoAccountLight, t: Transaction) { logger.info('Creating job to undo a dislike of video %s.', video.url) const dislikeUrl = getVideoDislikeActivityPubUrl(byActor, video) @@ -70,7 +76,7 @@ async function sendUndoDislike (byActor: ActorModel, video: VideoModel, t: Trans return sendUndoVideoRelatedActivity({ byActor, video, url: dislikeUrl, activity: dislikeActivity, transaction: t }) } -async function sendUndoCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel, t: Transaction) { +async function sendUndoCacheFile (byActor: MActor, redundancyModel: MVideoRedundancyVideo, t: Transaction) { logger.info('Creating job to undo cache file %s.', redundancyModel.url) const videoId = redundancyModel.getVideo().id @@ -94,7 +100,7 @@ export { function undoActivityData ( url: string, - byActor: ActorModel, + byActor: MActorAudience, object: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, audience?: ActivityAudience ): ActivityUndo { @@ -112,8 +118,8 @@ function undoActivityData ( } async function sendUndoVideoRelatedActivity (options: { - byActor: ActorModel, - video: VideoModel, + byActor: MActor, + video: MVideoAccountLight, url: string, activity: ActivityFollow | ActivityLike | ActivityDislike | ActivityCreate | ActivityAnnounce, transaction: Transaction diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 5bf092894..3a5cc1853 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts @@ -2,21 +2,29 @@ import { Transaction } from 'sequelize' import { ActivityAudience, ActivityUpdate } from '../../../../shared/models/activitypub' import { VideoPrivacy } from '../../../../shared/models/videos' import { AccountModel } from '../../../models/account/account' -import { ActorModel } from '../../../models/activitypub/actor' import { VideoModel } from '../../../models/video/video' -import { VideoChannelModel } from '../../../models/video/video-channel' import { VideoShareModel } from '../../../models/video/video-share' import { getUpdateActivityPubUrl } from '../url' import { broadcastToFollowers, sendVideoRelatedActivity } from './utils' import { audiencify, getActorsInvolvedInVideo, getAudience } from '../audience' import { logger } from '../../../helpers/logger' import { VideoCaptionModel } from '../../../models/video/video-caption' -import { VideoRedundancyModel } from '../../../models/redundancy/video-redundancy' -import { VideoPlaylistModel } from '../../../models/video/video-playlist' import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' import { getServerActor } from '../../../helpers/utils' +import { + MAccountActor, + MActor, + MActorLight, + MChannelActor, + MVideoAP, + MVideoAPWithoutCaption, + MVideoPlaylistFull, + MVideoRedundancyVideo +} from '../../../typings/models' + +async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction, overrodeByActor?: MActor) { + const video = videoArg as MVideoAP -async function sendUpdateVideo (video: VideoModel, t: Transaction, overrodeByActor?: ActorModel) { if (video.privacy === VideoPrivacy.PRIVATE) return undefined logger.info('Creating job to update video %s.', video.url) @@ -41,7 +49,7 @@ async function sendUpdateVideo (video: VideoModel, t: Transaction, overrodeByAct return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) } -async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelModel, t: Transaction) { +async function sendUpdateActor (accountOrChannel: MAccountActor | MChannelActor, t: Transaction) { const byActor = accountOrChannel.Actor logger.info('Creating job to update actor %s.', byActor.url) @@ -51,7 +59,7 @@ async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelMod const audience = getAudience(byActor) const updateActivity = buildUpdateActivity(url, byActor, accountOrChannelObject, audience) - let actorsInvolved: ActorModel[] + let actorsInvolved: MActor[] if (accountOrChannel instanceof AccountModel) { // Actors that shared my videos are involved too actorsInvolved = await VideoShareModel.loadActorsWhoSharedVideosOf(byActor.id, t) @@ -65,7 +73,7 @@ async function sendUpdateActor (accountOrChannel: AccountModel | VideoChannelMod return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) } -async function sendUpdateCacheFile (byActor: ActorModel, redundancyModel: VideoRedundancyModel) { +async function sendUpdateCacheFile (byActor: MActorLight, redundancyModel: MVideoRedundancyVideo) { logger.info('Creating job to update cache file %s.', redundancyModel.url) const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(redundancyModel.getVideo().id) @@ -80,7 +88,7 @@ async function sendUpdateCacheFile (byActor: ActorModel, redundancyModel: VideoR return sendVideoRelatedActivity(activityBuilder, { byActor, video }) } -async function sendUpdateVideoPlaylist (videoPlaylist: VideoPlaylistModel, t: Transaction) { +async function sendUpdateVideoPlaylist (videoPlaylist: MVideoPlaylistFull, t: Transaction) { if (videoPlaylist.privacy === VideoPlaylistPrivacy.PRIVATE) return undefined const byActor = videoPlaylist.OwnerAccount.Actor @@ -113,7 +121,7 @@ export { // --------------------------------------------------------------------------- -function buildUpdateActivity (url: string, byActor: ActorModel, object: any, audience?: ActivityAudience): ActivityUpdate { +function buildUpdateActivity (url: string, byActor: MActorLight, object: any, audience?: ActivityAudience): ActivityUpdate { if (!audience) audience = getAudience(byActor) return audiencify( @@ -121,8 +129,7 @@ function buildUpdateActivity (url: string, byActor: ActorModel, object: any, aud type: 'Update' as 'Update', id: url, actor: byActor.url, - object: audiencify(object, audience - ) + object: audiencify(object, audience) }, audience ) diff --git a/server/lib/activitypub/send/send-view.ts b/server/lib/activitypub/send/send-view.ts index 8ad126be0..8809417f9 100644 --- a/server/lib/activitypub/send/send-view.ts +++ b/server/lib/activitypub/send/send-view.ts @@ -1,13 +1,13 @@ import { Transaction } from 'sequelize' import { ActivityAudience, ActivityView } from '../../../../shared/models/activitypub' import { ActorModel } from '../../../models/activitypub/actor' -import { VideoModel } from '../../../models/video/video' import { getVideoLikeActivityPubUrl } from '../url' import { sendVideoRelatedActivity } from './utils' import { audiencify, getAudience } from '../audience' import { logger } from '../../../helpers/logger' +import { MActorAudience, MVideoAccountLight, MVideoUrl } from '@server/typings/models' -async function sendView (byActor: ActorModel, video: VideoModel, t: Transaction) { +async function sendView (byActor: ActorModel, video: MVideoAccountLight, t: Transaction) { logger.info('Creating job to send view of %s.', video.url) const activityBuilder = (audience: ActivityAudience) => { @@ -19,7 +19,7 @@ async function sendView (byActor: ActorModel, video: VideoModel, t: Transaction) return sendVideoRelatedActivity(activityBuilder, { byActor, video, transaction: t }) } -function buildViewActivity (url: string, byActor: ActorModel, video: VideoModel, audience?: ActivityAudience): ActivityView { +function buildViewActivity (url: string, byActor: MActorAudience, video: MVideoUrl, audience?: ActivityAudience): ActivityView { if (!audience) audience = getAudience(byActor) return audiencify( diff --git a/server/lib/activitypub/send/utils.ts b/server/lib/activitypub/send/utils.ts index 4f69afb00..8129ab32a 100644 --- a/server/lib/activitypub/send/utils.ts +++ b/server/lib/activitypub/send/utils.ts @@ -4,15 +4,14 @@ import { logger } from '../../../helpers/logger' import { ActorModel } from '../../../models/activitypub/actor' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { JobQueue } from '../../job-queue' -import { VideoModel } from '../../../models/video/video' import { getActorsInvolvedInVideo, getAudienceFromFollowersOf, getRemoteVideoAudience } from '../audience' import { getServerActor } from '../../../helpers/utils' import { afterCommitIfTransaction } from '../../../helpers/database-utils' -import { ActorFollowerException, ActorModelId, ActorModelOnly } from '../../../typings/models' +import { MActorFollowerException, MActor, MActorId, MActorLight, MVideo, MVideoAccountLight } from '../../../typings/models' async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAudience) => Activity, options: { - byActor: ActorModelOnly, - video: VideoModel, + byActor: MActorLight, + video: MVideoAccountLight, transaction?: Transaction }) { const { byActor, video, transaction } = options @@ -41,8 +40,8 @@ async function sendVideoRelatedActivity (activityBuilder: (audience: ActivityAud async function forwardVideoRelatedActivity ( activity: Activity, t: Transaction, - followersException: ActorFollowerException[] = [], - video: VideoModel + followersException: MActorFollowerException[] = [], + video: MVideo ) { // Mastodon does not add our announces in audience, so we forward to them manually const additionalActors = await getActorsInvolvedInVideo(video, t) @@ -54,7 +53,7 @@ async function forwardVideoRelatedActivity ( async function forwardActivity ( activity: Activity, t: Transaction, - followersException: ActorFollowerException[] = [], + followersException: MActorFollowerException[] = [], additionalFollowerUrls: string[] = [] ) { logger.info('Forwarding activity %s.', activity.id) @@ -88,10 +87,10 @@ async function forwardActivity ( async function broadcastToFollowers ( data: any, - byActor: ActorModelId, - toFollowersOf: ActorModelId[], + byActor: MActorId, + toFollowersOf: MActorId[], t: Transaction, - actorsException: ActorFollowerException[] = [] + actorsException: MActorFollowerException[] = [] ) { const uris = await computeFollowerUris(toFollowersOf, actorsException, t) @@ -100,16 +99,16 @@ async function broadcastToFollowers ( async function broadcastToActors ( data: any, - byActor: ActorModelId, - toActors: ActorModelOnly[], + byActor: MActorId, + toActors: MActor[], t?: Transaction, - actorsException: ActorFollowerException[] = [] + actorsException: MActorFollowerException[] = [] ) { const uris = await computeUris(toActors, actorsException) return afterCommitIfTransaction(t, () => broadcastTo(uris, data, byActor)) } -function broadcastTo (uris: string[], data: any, byActor: ActorModelId) { +function broadcastTo (uris: string[], data: any, byActor: MActorId) { if (uris.length === 0) return undefined logger.debug('Creating broadcast job.', { uris }) @@ -123,7 +122,7 @@ function broadcastTo (uris: string[], data: any, byActor: ActorModelId) { return JobQueue.Instance.createJob({ type: 'activitypub-http-broadcast', payload }) } -function unicastTo (data: any, byActor: ActorModelId, toActorUrl: string) { +function unicastTo (data: any, byActor: MActorId, toActorUrl: string) { logger.debug('Creating unicast job.', { uri: toActorUrl }) const payload = { @@ -148,7 +147,7 @@ export { // --------------------------------------------------------------------------- -async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsException: ActorFollowerException[], t: Transaction) { +async function computeFollowerUris (toFollowersOf: MActorId[], actorsException: MActorFollowerException[], t: Transaction) { const toActorFollowerIds = toFollowersOf.map(a => a.id) const result = await ActorFollowModel.listAcceptedFollowerSharedInboxUrls(toActorFollowerIds, t) @@ -157,7 +156,7 @@ async function computeFollowerUris (toFollowersOf: ActorModelId[], actorsExcepti return result.data.filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) } -async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFollowerException[] = []) { +async function computeUris (toActors: MActor[], actorsException: MActorFollowerException[] = []) { const serverActor = await getServerActor() const targetUrls = toActors .filter(a => a.id !== serverActor.id) // Don't send to ourselves @@ -170,7 +169,7 @@ async function computeUris (toActors: ActorModelOnly[], actorsException: ActorFo .filter(sharedInbox => sharedInboxesException.indexOf(sharedInbox) === -1) } -async function buildSharedInboxesException (actorsException: ActorFollowerException[]) { +async function buildSharedInboxesException (actorsException: MActorFollowerException[]) { const serverActor = await getServerActor() return actorsException diff --git a/server/lib/activitypub/share.ts b/server/lib/activitypub/share.ts index 7f38402b6..fdca9bed7 100644 --- a/server/lib/activitypub/share.ts +++ b/server/lib/activitypub/share.ts @@ -1,19 +1,18 @@ import { Transaction } from 'sequelize' import { VideoPrivacy } from '../../../shared/models/videos' import { getServerActor } from '../../helpers/utils' -import { VideoModel } from '../../models/video/video' import { VideoShareModel } from '../../models/video/video-share' import { sendUndoAnnounce, sendVideoAnnounce } from './send' import { getVideoAnnounceActivityPubUrl } from './url' -import { VideoChannelModel } from '../../models/video/video-channel' import * as Bluebird from 'bluebird' import { doRequest } from '../../helpers/requests' import { getOrCreateActorAndServerAndModel } from './actor' import { logger } from '../../helpers/logger' import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' +import { MChannelActor, MChannelActorLight, MVideo, MVideoAccountLight, MVideoId } from '../../typings/models/video' -async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) { +async function shareVideoByServerAndChannel (video: MVideoAccountLight, t: Transaction) { if (video.privacy === VideoPrivacy.PRIVATE) return undefined return Promise.all([ @@ -22,7 +21,11 @@ async function shareVideoByServerAndChannel (video: VideoModel, t: Transaction) ]) } -async function changeVideoChannelShare (video: VideoModel, oldVideoChannel: VideoChannelModel, t: Transaction) { +async function changeVideoChannelShare ( + video: MVideoAccountLight, + oldVideoChannel: MChannelActorLight, + t: Transaction +) { logger.info('Updating video channel of video %s: %s -> %s.', video.uuid, oldVideoChannel.name, video.VideoChannel.name) await undoShareByVideoChannel(video, oldVideoChannel, t) @@ -30,7 +33,7 @@ async function changeVideoChannelShare (video: VideoModel, oldVideoChannel: Vide await shareByVideoChannel(video, t) } -async function addVideoShares (shareUrls: string[], instance: VideoModel) { +async function addVideoShares (shareUrls: string[], video: MVideoId) { await Bluebird.map(shareUrls, async shareUrl => { try { // Fetch url @@ -50,7 +53,7 @@ async function addVideoShares (shareUrls: string[], instance: VideoModel) { const entry = { actorId: actor.id, - videoId: instance.id, + videoId: video.id, url: shareUrl } @@ -69,7 +72,7 @@ export { // --------------------------------------------------------------------------- -async function shareByServer (video: VideoModel, t: Transaction) { +async function shareByServer (video: MVideo, t: Transaction) { const serverActor = await getServerActor() const serverShareUrl = getVideoAnnounceActivityPubUrl(serverActor, video) @@ -88,7 +91,7 @@ async function shareByServer (video: VideoModel, t: Transaction) { return sendVideoAnnounce(serverActor, serverShare, video, t) } -async function shareByVideoChannel (video: VideoModel, t: Transaction) { +async function shareByVideoChannel (video: MVideoAccountLight, t: Transaction) { const videoChannelShareUrl = getVideoAnnounceActivityPubUrl(video.VideoChannel.Actor, video) const [ videoChannelShare ] = await VideoShareModel.findOrCreate({ defaults: { @@ -105,7 +108,7 @@ async function shareByVideoChannel (video: VideoModel, t: Transaction) { return sendVideoAnnounce(video.VideoChannel.Actor, videoChannelShare, video, t) } -async function undoShareByVideoChannel (video: VideoModel, oldVideoChannel: VideoChannelModel, t: Transaction) { +async function undoShareByVideoChannel (video: MVideo, oldVideoChannel: MChannelActorLight, t: Transaction) { // Load old share const oldShare = await VideoShareModel.load(oldVideoChannel.actorId, video.id, t) if (!oldShare) return new Error('Cannot find old video channel share ' + oldVideoChannel.actorId + ' for video ' + video.id) diff --git a/server/lib/activitypub/url.ts b/server/lib/activitypub/url.ts index dfcb3c668..6290af34b 100644 --- a/server/lib/activitypub/url.ts +++ b/server/lib/activitypub/url.ts @@ -1,36 +1,42 @@ import { WEBSERVER } from '../../initializers/constants' -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 { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' -import { VideoPlaylistModel } from '../../models/video/video-playlist' -import { ActorModelOnly, ActorModelUrl } from '../../typings/models' -import { ActorFollowModelLight } from '../../typings/models/actor-follow' - -function getVideoActivityPubUrl (video: VideoModel) { +import { + MActor, + MActorFollowActors, + MActorId, + MActorUrl, + MCommentId, + MVideoAbuseId, + MVideoId, + MVideoUrl, + MVideoUUID +} from '../../typings/models' +import { MVideoPlaylist, MVideoPlaylistUUID } from '../../typings/models/video/video-playlist' +import { MVideoFileVideoUUID } from '../../typings/models/video/video-file' +import { MStreamingPlaylist } from '../../typings/models/video/video-streaming-playlist' + +function getVideoActivityPubUrl (video: MVideoUUID) { return WEBSERVER.URL + '/videos/watch/' + video.uuid } -function getVideoPlaylistActivityPubUrl (videoPlaylist: VideoPlaylistModel) { +function getVideoPlaylistActivityPubUrl (videoPlaylist: MVideoPlaylist) { return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid } -function getVideoPlaylistElementActivityPubUrl (videoPlaylist: VideoPlaylistModel, video: VideoModel) { +function getVideoPlaylistElementActivityPubUrl (videoPlaylist: MVideoPlaylistUUID, video: MVideoUUID) { return WEBSERVER.URL + '/video-playlists/' + videoPlaylist.uuid + '/' + video.uuid } -function getVideoCacheFileActivityPubUrl (videoFile: VideoFileModel) { +function getVideoCacheFileActivityPubUrl (videoFile: MVideoFileVideoUUID) { const suffixFPS = videoFile.fps && videoFile.fps !== -1 ? '-' + videoFile.fps : '' return `${WEBSERVER.URL}/redundancy/videos/${videoFile.Video.uuid}/${videoFile.resolution}${suffixFPS}` } -function getVideoCacheStreamingPlaylistActivityPubUrl (video: VideoModel, playlist: VideoStreamingPlaylistModel) { +function getVideoCacheStreamingPlaylistActivityPubUrl (video: MVideoUUID, playlist: MStreamingPlaylist) { return `${WEBSERVER.URL}/redundancy/streaming-playlists/${playlist.getStringType()}/${video.uuid}` } -function getVideoCommentActivityPubUrl (video: VideoModel, videoComment: VideoCommentModel) { +function getVideoCommentActivityPubUrl (video: MVideoUUID, videoComment: MCommentId) { return WEBSERVER.URL + '/videos/watch/' + video.uuid + '/comments/' + videoComment.id } @@ -42,54 +48,54 @@ function getAccountActivityPubUrl (accountName: string) { return WEBSERVER.URL + '/accounts/' + accountName } -function getVideoAbuseActivityPubUrl (videoAbuse: VideoAbuseModel) { +function getVideoAbuseActivityPubUrl (videoAbuse: MVideoAbuseId) { return WEBSERVER.URL + '/admin/video-abuses/' + videoAbuse.id } -function getVideoViewActivityPubUrl (byActor: ActorModelUrl, video: VideoModel) { +function getVideoViewActivityPubUrl (byActor: MActorUrl, video: MVideoId) { return byActor.url + '/views/videos/' + video.id + '/' + new Date().toISOString() } -function getVideoLikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) { +function getVideoLikeActivityPubUrl (byActor: MActorUrl, video: MVideoId) { return byActor.url + '/likes/' + video.id } -function getVideoDislikeActivityPubUrl (byActor: ActorModelUrl, video: VideoModel | { id: number }) { +function getVideoDislikeActivityPubUrl (byActor: MActorUrl, video: MVideoId) { return byActor.url + '/dislikes/' + video.id } -function getVideoSharesActivityPubUrl (video: VideoModel) { +function getVideoSharesActivityPubUrl (video: MVideoUrl) { return video.url + '/announces' } -function getVideoCommentsActivityPubUrl (video: VideoModel) { +function getVideoCommentsActivityPubUrl (video: MVideoUrl) { return video.url + '/comments' } -function getVideoLikesActivityPubUrl (video: VideoModel) { +function getVideoLikesActivityPubUrl (video: MVideoUrl) { return video.url + '/likes' } -function getVideoDislikesActivityPubUrl (video: VideoModel) { +function getVideoDislikesActivityPubUrl (video: MVideoUrl) { return video.url + '/dislikes' } -function getActorFollowActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) { +function getActorFollowActivityPubUrl (follower: MActor, following: MActorId) { return follower.url + '/follows/' + following.id } -function getActorFollowAcceptActivityPubUrl (actorFollow: ActorFollowModelLight) { +function getActorFollowAcceptActivityPubUrl (actorFollow: MActorFollowActors) { const follower = actorFollow.ActorFollower const me = actorFollow.ActorFollowing return follower.url + '/accepts/follows/' + me.id } -function getActorFollowRejectActivityPubUrl (follower: ActorModelOnly, following: ActorModelOnly) { +function getActorFollowRejectActivityPubUrl (follower: MActorUrl, following: MActorId) { return follower.url + '/rejects/follows/' + following.id } -function getVideoAnnounceActivityPubUrl (byActor: ActorModelOnly, video: VideoModel) { +function getVideoAnnounceActivityPubUrl (byActor: MActorId, video: MVideoUrl) { return video.url + '/announces/' + byActor.id } diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index 8d2c1ade3..375ac0aad 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts @@ -2,20 +2,20 @@ import { sanitizeAndCheckVideoCommentObject } from '../../helpers/custom-validat import { logger } from '../../helpers/logger' import { doRequest } from '../../helpers/requests' import { ACTIVITY_PUB, CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' -import { VideoModel } from '../../models/video/video' import { VideoCommentModel } from '../../models/video/video-comment' import { getOrCreateActorAndServerAndModel } from './actor' import { getOrCreateVideoAndAccountAndChannel } from './videos' import * as Bluebird from 'bluebird' import { checkUrlsSameHost } from '../../helpers/activitypub' +import { MCommentOwner, MCommentOwnerVideo, MVideoAccountAllFiles } from '../../typings/models/video' type ResolveThreadParams = { url: string, - comments?: VideoCommentModel[], + comments?: MCommentOwner[], isVideo?: boolean, commentCreated?: boolean } -type ResolveThreadResult = Promise<{ video: VideoModel, comment: VideoCommentModel, commentCreated: boolean }> +type ResolveThreadResult = Promise<{ video: MVideoAccountAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> async function addVideoComments (commentUrls: string[]) { return Bluebird.map(commentUrls, commentUrl => { @@ -85,9 +85,9 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { const syncParam = { likes: true, dislikes: true, shares: true, comments: false, thumbnail: true, refreshVideo: false } const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: url, syncParam }) - let resultComment: VideoCommentModel + let resultComment: MCommentOwnerVideo if (comments.length !== 0) { - const firstReply = comments[ comments.length - 1 ] + const firstReply = comments[ comments.length - 1 ] as MCommentOwnerVideo firstReply.inReplyToCommentId = null firstReply.originCommentId = null firstReply.videoId = video.id @@ -97,7 +97,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { comments[comments.length - 1] = await firstReply.save() for (let i = comments.length - 2; i >= 0; i--) { - const comment = comments[ i ] + const comment = comments[ i ] as MCommentOwnerVideo comment.originCommentId = firstReply.id comment.inReplyToCommentId = comments[ i + 1 ].id comment.videoId = video.id @@ -107,7 +107,7 @@ async function tryResolveThreadFromVideo (params: ResolveThreadParams) { comments[i] = await comment.save() } - resultComment = comments[0] + resultComment = comments[0] as MCommentOwnerVideo } return { video, comment: resultComment, commentCreated } @@ -151,7 +151,7 @@ async function resolveParentComment (params: ResolveThreadParams) { originCommentId: null, createdAt: new Date(body.published), updatedAt: new Date(body.updated) - }) + }) as MCommentOwner comment.Account = actor.Account return resolveThread({ diff --git a/server/lib/activitypub/video-rates.ts b/server/lib/activitypub/video-rates.ts index cda5b2981..6bd46bb58 100644 --- a/server/lib/activitypub/video-rates.ts +++ b/server/lib/activitypub/video-rates.ts @@ -1,6 +1,4 @@ import { Transaction } from 'sequelize' -import { AccountModel } from '../../models/account/account' -import { VideoModel } from '../../models/video/video' import { sendLike, sendUndoDislike, sendUndoLike } from './send' import { VideoRateType } from '../../../shared/models/videos' import * as Bluebird from 'bluebird' @@ -10,11 +8,11 @@ import { logger } from '../../helpers/logger' import { CRAWL_REQUEST_CONCURRENCY } from '../../initializers/constants' import { doRequest } from '../../helpers/requests' import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' -import { ActorModel } from '../../models/activitypub/actor' import { getVideoDislikeActivityPubUrl, getVideoLikeActivityPubUrl } from './url' import { sendDislike } from './send/send-dislike' +import { MAccountActor, MActorUrl, MVideo, MVideoAccountLight, MVideoId } from '../../typings/models' -async function createRates (ratesUrl: string[], video: VideoModel, rate: VideoRateType) { +async function createRates (ratesUrl: string[], video: MVideo, rate: VideoRateType) { let rateCounts = 0 await Bluebird.map(ratesUrl, async rateUrl => { @@ -64,11 +62,13 @@ async function createRates (ratesUrl: string[], video: VideoModel, rate: VideoRa return } -async function sendVideoRateChange (account: AccountModel, - video: VideoModel, - likes: number, - dislikes: number, - t: Transaction) { +async function sendVideoRateChange ( + account: MAccountActor, + video: MVideoAccountLight, + likes: number, + dislikes: number, + t: Transaction +) { const actor = account.Actor // Keep the order: first we undo and then we create @@ -84,8 +84,10 @@ async function sendVideoRateChange (account: AccountModel, if (dislikes > 0) await sendDislike(actor, video, t) } -function getRateUrl (rateType: VideoRateType, actor: ActorModel, video: VideoModel) { - return rateType === 'like' ? getVideoLikeActivityPubUrl(actor, video) : getVideoDislikeActivityPubUrl(actor, video) +function getRateUrl (rateType: VideoRateType, actor: MActorUrl, video: MVideoId) { + return rateType === 'like' + ? getVideoLikeActivityPubUrl(actor, video) + : getVideoDislikeActivityPubUrl(actor, video) } export { diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 3a8451a32..5c10f9764 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -24,7 +24,6 @@ import { REMOTE_SCHEME, STATIC_PATHS } from '../../initializers/constants' -import { ActorModel } from '../../models/activitypub/actor' import { TagModel } from '../../models/video/tag' import { VideoModel } from '../../models/video/video' import { VideoFileModel } from '../../models/video/video-file' @@ -38,7 +37,6 @@ import { JobQueue } from '../job-queue' import { ActivitypubHttpFetcherPayload } from '../job-queue/handlers/activitypub-http-fetcher' import { createRates } from './video-rates' import { addVideoShares, shareVideoByServerAndChannel } from './share' -import { AccountModel } from '../../models/account/account' import { fetchVideoByUrl, VideoFetchByUrlType } from '../../helpers/video' import { checkUrlsSameHost, getAPId } from '../../helpers/activitypub' import { Notifier } from '../notifier' @@ -49,15 +47,33 @@ import { VideoShareModel } from '../../models/video/video-share' import { VideoCommentModel } from '../../models/video/video-comment' import { sequelizeTypescript } from '../../initializers/database' import { createPlaceholderThumbnail, createVideoMiniatureFromUrl } from '../thumbnail' -import { ThumbnailModel } from '../../models/video/thumbnail' import { ThumbnailType } from '../../../shared/models/videos/thumbnail.type' import { join } from 'path' import { FilteredModelAttributes } from '../../typings/sequelize' import { autoBlacklistVideoIfNeeded } from '../video-blacklist' import { ActorFollowScoreCache } from '../files-cache' -import { AccountModelIdActor, VideoChannelModelId, VideoChannelModelIdActor } from '../../typings/models' +import { + MAccountActor, + MChannelAccountLight, + MChannelDefault, + MChannelId, + MVideo, + MVideoAccountAllFiles, + MVideoAccountLight, + MVideoAP, + MVideoAPWithoutCaption, + MVideoFile, + MVideoFullLight, + MVideoId, + MVideoTag, + MVideoThumbnail, + MVideoWithAllFiles +} from '../../typings/models' +import { MThumbnail } from '../../typings/models/video/thumbnail' + +async function federateVideoIfNeeded (videoArg: MVideoAPWithoutCaption, isNewVideo: boolean, transaction?: sequelize.Transaction) { + const video = videoArg as MVideoAP -async function federateVideoIfNeeded (video: VideoModel, isNewVideo: boolean, transaction?: sequelize.Transaction) { if ( // Check this is not a blacklisted video, or unfederated blacklisted video (video.isBlacklisted() === false || (isNewVideo === false && video.VideoBlacklist.unfederated === false)) && @@ -102,7 +118,7 @@ async function fetchRemoteVideo (videoUrl: string): Promise<{ response: request. return { response, videoObject: body } } -async function fetchRemoteVideoDescription (video: VideoModel) { +async function fetchRemoteVideoDescription (video: MVideoAccountLight) { const host = video.VideoChannel.Account.Actor.Server.host const path = video.getDescriptionAPIPath() const options = { @@ -114,14 +130,14 @@ async function fetchRemoteVideoDescription (video: VideoModel) { return body.description ? body.description : '' } -function fetchRemoteVideoStaticFile (video: VideoModel, path: string, destPath: string) { +function fetchRemoteVideoStaticFile (video: MVideoAccountLight, path: string, destPath: string) { const url = buildRemoteBaseUrl(video, path) // We need to provide a callback, if no we could have an uncaught exception return doRequestAndSaveToFile({ uri: url }, destPath) } -function buildRemoteBaseUrl (video: VideoModel, path: string) { +function buildRemoteBaseUrl (video: MVideoAccountLight, path: string) { const host = video.VideoChannel.Account.Actor.Server.host return REMOTE_SCHEME.HTTP + '://' + host + path @@ -146,7 +162,7 @@ type SyncParam = { thumbnail: boolean refreshVideo?: boolean } -async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: VideoTorrentObject, syncParam: SyncParam) { +async function syncVideoExternalAttributes (video: MVideo, fetchedVideo: VideoTorrentObject, syncParam: SyncParam) { logger.info('Adding likes/dislikes/shares/comments of video %s.', video.uuid) const jobPayloads: ActivitypubHttpFetcherPayload[] = [] @@ -194,12 +210,24 @@ async function syncVideoExternalAttributes (video: VideoModel, fetchedVideo: Vid await Bluebird.map(jobPayloads, payload => JobQueue.Instance.createJob({ type: 'activitypub-http-fetcher', payload })) } +function getOrCreateVideoAndAccountAndChannel (options: { + videoObject: { id: string } | string, + syncParam?: SyncParam, + fetchType?: 'all', + allowRefresh?: boolean +}): Promise<{ video: MVideoAccountAllFiles, created: boolean, autoBlacklisted?: boolean }> +function getOrCreateVideoAndAccountAndChannel (options: { + videoObject: { id: string } | string, + syncParam?: SyncParam, + fetchType?: VideoFetchByUrlType, + allowRefresh?: boolean +}): Promise<{ video: MVideoAccountAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> async function getOrCreateVideoAndAccountAndChannel (options: { videoObject: { id: string } | string, syncParam?: SyncParam, fetchType?: VideoFetchByUrlType, allowRefresh?: boolean // true by default -}) { +}): Promise<{ video: MVideoAccountAllFiles | MVideoThumbnail, created: boolean, autoBlacklisted?: boolean }> { // Default params const syncParam = options.syncParam || { likes: true, dislikes: true, shares: true, comments: true, thumbnail: true, refreshVideo: false } const fetchType = options.fetchType || 'all' @@ -227,8 +255,9 @@ async function getOrCreateVideoAndAccountAndChannel (options: { const { videoObject: fetchedVideo } = await fetchRemoteVideo(videoUrl) if (!fetchedVideo) throw new Error('Cannot fetch remote video with url: ' + videoUrl) - const channelActor = await getOrCreateVideoChannelFromVideoObject(fetchedVideo) - const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(createVideo, fetchedVideo, channelActor, syncParam.thumbnail) + const actor = await getOrCreateVideoChannelFromVideoObject(fetchedVideo) + const videoChannel = actor.VideoChannel + const { autoBlacklisted, videoCreated } = await retryTransactionWrapper(createVideo, fetchedVideo, videoChannel, syncParam.thumbnail) await syncVideoExternalAttributes(videoCreated, fetchedVideo, syncParam) @@ -236,22 +265,22 @@ async function getOrCreateVideoAndAccountAndChannel (options: { } async function updateVideoFromAP (options: { - video: VideoModel, + video: MVideoAccountAllFiles, videoObject: VideoTorrentObject, - account: AccountModelIdActor, - channel: VideoChannelModelIdActor, + account: MAccountActor, + channel: MChannelDefault, overrideTo?: string[] }) { const { video, videoObject, account, channel, overrideTo } = options - logger.debug('Updating remote video "%s".', options.videoObject.uuid) + logger.debug('Updating remote video "%s".', options.videoObject.uuid, { account, channel }) let videoFieldsSave: any const wasPrivateVideo = video.privacy === VideoPrivacy.PRIVATE const wasUnlistedVideo = video.privacy === VideoPrivacy.UNLISTED try { - let thumbnailModel: ThumbnailModel + let thumbnailModel: MThumbnail try { thumbnailModel = await createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) @@ -259,7 +288,7 @@ async function updateVideoFromAP (options: { logger.warn('Cannot generate thumbnail of %s.', videoObject.id, { err }) } - await sequelizeTypescript.transaction(async t => { + const videoUpdated = await sequelizeTypescript.transaction(async t => { const sequelizeOptions = { transaction: t } videoFieldsSave = video.toJSON() @@ -293,21 +322,21 @@ async function updateVideoFromAP (options: { video.channelId = videoData.channelId video.views = videoData.views - await video.save(sequelizeOptions) + const videoUpdated = await video.save(sequelizeOptions) as MVideoFullLight - if (thumbnailModel) await video.addAndSaveThumbnail(thumbnailModel, t) + if (thumbnailModel) await videoUpdated.addAndSaveThumbnail(thumbnailModel, t) // FIXME: use icon URL instead - const previewUrl = buildRemoteBaseUrl(video, join(STATIC_PATHS.PREVIEWS, video.getPreview().filename)) + const previewUrl = buildRemoteBaseUrl(videoUpdated, join(STATIC_PATHS.PREVIEWS, videoUpdated.getPreview().filename)) const previewModel = createPlaceholderThumbnail(previewUrl, video, ThumbnailType.PREVIEW, PREVIEWS_SIZE) - await video.addAndSaveThumbnail(previewModel, t) + await videoUpdated.addAndSaveThumbnail(previewModel, t) { - const videoFileAttributes = videoFileActivityUrlToDBAttributes(video, videoObject) + const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoUpdated, videoObject) const newVideoFiles = videoFileAttributes.map(a => new VideoFileModel(a)) // Remove video files that do not exist anymore - const destroyTasks = video.VideoFiles + const destroyTasks = videoUpdated.VideoFiles .filter(f => !newVideoFiles.find(newFile => newFile.hasSameUniqueKeysThan(f))) .map(f => f.destroy(sequelizeOptions)) await Promise.all(destroyTasks) @@ -318,15 +347,15 @@ async function updateVideoFromAP (options: { .then(([ file ]) => file) }) - video.VideoFiles = await Promise.all(upsertTasks) + videoUpdated.VideoFiles = await Promise.all(upsertTasks) } { - const streamingPlaylistAttributes = streamingPlaylistActivityUrlToDBAttributes(video, videoObject, video.VideoFiles) + const streamingPlaylistAttributes = streamingPlaylistActivityUrlToDBAttributes(videoUpdated, videoObject, videoUpdated.VideoFiles) const newStreamingPlaylists = streamingPlaylistAttributes.map(a => new VideoStreamingPlaylistModel(a)) // Remove video files that do not exist anymore - const destroyTasks = video.VideoStreamingPlaylists + const destroyTasks = videoUpdated.VideoStreamingPlaylists .filter(f => !newStreamingPlaylists.find(newPlaylist => newPlaylist.hasSameUniqueKeysThan(f))) .map(f => f.destroy(sequelizeOptions)) await Promise.all(destroyTasks) @@ -337,38 +366,42 @@ async function updateVideoFromAP (options: { .then(([ streamingPlaylist ]) => streamingPlaylist) }) - video.VideoStreamingPlaylists = await Promise.all(upsertTasks) + videoUpdated.VideoStreamingPlaylists = await Promise.all(upsertTasks) } { // Update Tags const tags = videoObject.tag.map(tag => tag.name) const tagInstances = await TagModel.findOrCreateTags(tags, t) - await video.$set('Tags', tagInstances, sequelizeOptions) + await videoUpdated.$set('Tags', tagInstances, sequelizeOptions) } { // Update captions - await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(video.id, t) + await VideoCaptionModel.deleteAllCaptionsOfRemoteVideo(videoUpdated.id, t) const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { - return VideoCaptionModel.insertOrReplaceLanguage(video.id, c.identifier, t) + return VideoCaptionModel.insertOrReplaceLanguage(videoUpdated.id, c.identifier, t) }) - video.VideoCaptions = await Promise.all(videoCaptionsPromises) + await Promise.all(videoCaptionsPromises) } + + return videoUpdated }) await autoBlacklistVideoIfNeeded({ - video, + video: videoUpdated, user: undefined, isRemote: true, isNew: false, transaction: undefined }) - if (wasPrivateVideo || wasUnlistedVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(video) // Notify our users? + if (wasPrivateVideo || wasUnlistedVideo) Notifier.Instance.notifyOnNewVideoIfNeeded(videoUpdated) // Notify our users? logger.info('Remote video with uuid %s updated', videoObject.uuid) + + return videoUpdated } catch (err) { if (video !== undefined && videoFieldsSave !== undefined) { resetSequelizeInstance(video, videoFieldsSave) @@ -381,15 +414,15 @@ async function updateVideoFromAP (options: { } async function refreshVideoIfNeeded (options: { - video: VideoModel, + video: MVideoThumbnail, fetchedType: VideoFetchByUrlType, syncParam: SyncParam -}): Promise { +}): Promise { if (!options.video.isOutdated()) return options.video // We need more attributes if the argument video was fetched with not enough joints const video = options.fetchedType === 'all' - ? options.video + ? options.video as MVideoAccountAllFiles : await VideoModel.loadByUrlAndPopulateAccount(options.video.url) try { @@ -410,12 +443,11 @@ async function refreshVideoIfNeeded (options: { } const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) - const account = await AccountModel.load(channelActor.VideoChannel.accountId) const updateOptions = { video, videoObject, - account, + account: channelActor.VideoChannel.Account, channel: channelActor.VideoChannel } await retryTransactionWrapper(updateVideoFromAP, updateOptions) @@ -467,15 +499,15 @@ function isAPPlaylistSegmentHashesUrlObject (tag: any): tag is ActivityPlaylistS return tag.name === 'sha256' && tag.type === 'Link' && urlMediaType === 'application/json' } -async function createVideo (videoObject: VideoTorrentObject, channelActor: ActorModel, waitThumbnail = false) { +async function createVideo (videoObject: VideoTorrentObject, channel: MChannelAccountLight, waitThumbnail = false) { logger.debug('Adding remote video %s.', videoObject.id) - const videoData = await videoActivityObjectToDBAttributes(channelActor.VideoChannel, videoObject, videoObject.to) - const video = VideoModel.build(videoData) + const videoData = await videoActivityObjectToDBAttributes(channel, videoObject, videoObject.to) + const video = VideoModel.build(videoData) as MVideoThumbnail const promiseThumbnail = createVideoMiniatureFromUrl(videoObject.icon.url, video, ThumbnailType.MINIATURE) - let thumbnailModel: ThumbnailModel + let thumbnailModel: MThumbnail if (waitThumbnail === true) { thumbnailModel = await promiseThumbnail } @@ -483,8 +515,8 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor const { autoBlacklisted, videoCreated } = await sequelizeTypescript.transaction(async t => { const sequelizeOptions = { transaction: t } - const videoCreated = await video.save(sequelizeOptions) - videoCreated.VideoChannel = channelActor.VideoChannel + const videoCreated = await video.save(sequelizeOptions) as MVideoFullLight + videoCreated.VideoChannel = channel if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t) @@ -517,15 +549,14 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor const videoCaptionsPromises = videoObject.subtitleLanguage.map(c => { return VideoCaptionModel.insertOrReplaceLanguage(videoCreated.id, c.identifier, t) }) - const captions = await Promise.all(videoCaptionsPromises) + await Promise.all(videoCaptionsPromises) - video.VideoFiles = videoFiles - video.VideoStreamingPlaylists = streamingPlaylists - video.Tags = tagInstances - video.VideoCaptions = captions + videoCreated.VideoFiles = videoFiles + videoCreated.VideoStreamingPlaylists = streamingPlaylists + videoCreated.Tags = tagInstances const autoBlacklisted = await autoBlacklistVideoIfNeeded({ - video, + video: videoCreated, user: undefined, isRemote: true, isNew: true, @@ -548,11 +579,7 @@ async function createVideo (videoObject: VideoTorrentObject, channelActor: Actor return { autoBlacklisted, videoCreated } } -async function videoActivityObjectToDBAttributes ( - videoChannel: VideoChannelModelId, - videoObject: VideoTorrentObject, - to: string[] = [] -) { +async function videoActivityObjectToDBAttributes (videoChannel: MChannelId, videoObject: VideoTorrentObject, to: string[] = []) { const privacy = to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1 ? VideoPrivacy.PUBLIC : VideoPrivacy.UNLISTED const duration = videoObject.duration.replace(/[^\d]+/, '') @@ -603,7 +630,7 @@ async function videoActivityObjectToDBAttributes ( } } -function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: VideoTorrentObject) { +function videoFileActivityUrlToDBAttributes (video: MVideo, videoObject: VideoTorrentObject) { const fileUrls = videoObject.url.filter(u => isAPVideoUrlObject(u)) as ActivityVideoUrlObject[] if (fileUrls.length === 0) { @@ -641,7 +668,7 @@ function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: Vid return attributes } -function streamingPlaylistActivityUrlToDBAttributes (video: VideoModel, videoObject: VideoTorrentObject, videoFiles: VideoFileModel[]) { +function streamingPlaylistActivityUrlToDBAttributes (video: MVideoId, videoObject: VideoTorrentObject, videoFiles: MVideoFile[]) { const playlistUrls = videoObject.url.filter(u => isAPStreamingPlaylistUrlObject(u)) as ActivityPlaylistUrlObject[] if (playlistUrls.length === 0) return [] -- cgit v1.2.3