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 ++++++++++++--------- server/lib/avatar.ts | 8 +- server/lib/blocklist.ts | 5 +- server/lib/client-html.ts | 7 +- server/lib/emailer.ts | 36 +++--- server/lib/hls.ts | 6 +- .../lib/job-queue/handlers/activitypub-follow.ts | 9 +- .../job-queue/handlers/activitypub-http-fetcher.ts | 5 +- .../handlers/utils/activitypub-http-utils.ts | 4 +- server/lib/job-queue/handlers/video-file-import.ts | 11 +- server/lib/job-queue/handlers/video-import.ts | 38 +++--- server/lib/job-queue/handlers/video-transcoding.ts | 7 +- server/lib/notifier.ts | 101 ++++++++------- server/lib/oauth-model.ts | 3 +- server/lib/peertube-socket.ts | 4 +- server/lib/redundancy.ts | 3 +- .../lib/schedulers/videos-redundancy-scheduler.ts | 52 +++++--- server/lib/thumbnail.ts | 26 ++-- server/lib/user.ts | 26 ++-- server/lib/video-blacklist.ts | 13 +- server/lib/video-channel.ts | 17 ++- server/lib/video-comment.ts | 11 +- server/lib/video-playlist.ts | 7 +- server/lib/video-transcoding.ts | 16 +-- 58 files changed, 643 insertions(+), 513 deletions(-) (limited to 'server/lib') 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 [] diff --git a/server/lib/avatar.ts b/server/lib/avatar.ts index 1b38e6cb5..9005b3e22 100644 --- a/server/lib/avatar.ts +++ b/server/lib/avatar.ts @@ -3,8 +3,6 @@ import { sendUpdateActor } from './activitypub/send' import { AVATARS_SIZE, LRU_CACHE, QUEUE_CONCURRENCY } from '../initializers/constants' import { updateActorAvatarInstance } from './activitypub' import { processImage } from '../helpers/image-utils' -import { AccountModel } from '../models/account/account' -import { VideoChannelModel } from '../models/video/video-channel' import { extname, join } from 'path' import { retryTransactionWrapper } from '../helpers/database-utils' import * as uuidv4 from 'uuid/v4' @@ -13,8 +11,12 @@ import { sequelizeTypescript } from '../initializers/database' import * as LRUCache from 'lru-cache' import { queue } from 'async' import { downloadImage } from '../helpers/requests' +import { MAccountActorDefault, MChannelActorDefault } from '../typings/models' -async function updateActorAvatarFile (avatarPhysicalFile: Express.Multer.File, accountOrChannel: AccountModel | VideoChannelModel) { +async function updateActorAvatarFile ( + avatarPhysicalFile: Express.Multer.File, + accountOrChannel: MAccountActorDefault | MChannelActorDefault +) { const extension = extname(avatarPhysicalFile.filename) const avatarName = uuidv4() + extension const destination = join(CONFIG.STORAGE.AVATARS_DIR, avatarName) diff --git a/server/lib/blocklist.ts b/server/lib/blocklist.ts index 1633e500c..28c69b46e 100644 --- a/server/lib/blocklist.ts +++ b/server/lib/blocklist.ts @@ -1,6 +1,7 @@ import { sequelizeTypescript } from '../initializers' import { AccountBlocklistModel } from '../models/account/account-blocklist' import { ServerBlocklistModel } from '../models/server/server-blocklist' +import { MAccountBlocklist, MServerBlocklist } from '@server/typings/models' function addAccountInBlocklist (byAccountId: number, targetAccountId: number) { return sequelizeTypescript.transaction(async t => { @@ -20,13 +21,13 @@ function addServerInBlocklist (byAccountId: number, targetServerId: number) { }) } -function removeAccountFromBlocklist (accountBlock: AccountBlocklistModel) { +function removeAccountFromBlocklist (accountBlock: MAccountBlocklist) { return sequelizeTypescript.transaction(async t => { return accountBlock.destroy({ transaction: t }) }) } -function removeServerFromBlocklist (serverBlock: ServerBlocklistModel) { +function removeServerFromBlocklist (serverBlock: MServerBlocklist) { return sequelizeTypescript.transaction(async t => { return serverBlock.destroy({ transaction: t }) }) diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts index 8841dd2ac..a33aef26d 100644 --- a/server/lib/client-html.ts +++ b/server/lib/client-html.ts @@ -13,6 +13,7 @@ import { VideoChannelModel } from '../models/video/video-channel' import * as Bluebird from 'bluebird' import { CONFIG } from '../initializers/config' import { logger } from '../helpers/logger' +import { MAccountActor, MChannelActor, MVideo } from '../typings/models' export class ClientHtml { @@ -65,7 +66,7 @@ export class ClientHtml { } private static async getAccountOrChannelHTMLPage ( - loader: () => Bluebird, + loader: () => Bluebird, req: express.Request, res: express.Response ) { @@ -157,7 +158,7 @@ export class ClientHtml { return htmlStringPage.replace('', linkTag + '') } - private static addVideoOpenGraphAndOEmbedTags (htmlStringPage: string, video: VideoModel) { + private static addVideoOpenGraphAndOEmbedTags (htmlStringPage: string, video: MVideo) { const previewUrl = WEBSERVER.URL + video.getPreviewStaticPath() const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() @@ -236,7 +237,7 @@ export class ClientHtml { return this.addOpenGraphAndOEmbedTags(htmlStringPage, tagsString) } - private static addAccountOrChannelMetaTags (htmlStringPage: string, entity: AccountModel | VideoChannelModel) { + private static addAccountOrChannelMetaTags (htmlStringPage: string, entity: MAccountActor | MChannelActor) { // SEO, use origin account or channel URL const metaTags = `` diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index 73c2bcb1b..fe57a3e4c 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts @@ -3,16 +3,14 @@ import { isTestInstance } from '../helpers/core-utils' import { bunyanLogger, logger } from '../helpers/logger' import { CONFIG } from '../initializers/config' import { UserModel } from '../models/account/user' -import { VideoModel } from '../models/video/video' import { JobQueue } from './job-queue' import { EmailPayload } from './job-queue/handlers/email' import { readFileSync } from 'fs-extra' -import { VideoCommentModel } from '../models/video/video-comment' -import { VideoAbuseModel } from '../models/video/video-abuse' import { VideoBlacklistModel } from '../models/video/video-blacklist' -import { VideoImportModel } from '../models/video/video-import' -import { ActorFollowModel } from '../models/activitypub/actor-follow' import { WEBSERVER } from '../initializers/constants' +import { MCommentOwnerVideo, MVideo, MVideoAbuseVideo, MVideoAccountLight, MVideoBlacklistVideo } from '../typings/models/video' +import { MActorFollowActors, MActorFollowFull, MUser } from '../typings/models' +import { MVideoImport, MVideoImportVideo } from '@server/typings/models/video/video-import' type SendEmailOptions = { to: string[] @@ -90,7 +88,7 @@ class Emailer { } } - addNewVideoFromSubscriberNotification (to: string[], video: VideoModel) { + addNewVideoFromSubscriberNotification (to: string[], video: MVideoAccountLight) { const channelName = video.VideoChannel.getDisplayName() const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() @@ -111,7 +109,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addNewFollowNotification (to: string[], actorFollow: ActorFollowModel, followType: 'account' | 'channel') { + addNewFollowNotification (to: string[], actorFollow: MActorFollowFull, followType: 'account' | 'channel') { const followerName = actorFollow.ActorFollower.Account.getDisplayName() const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() @@ -130,7 +128,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addNewInstanceFollowerNotification (to: string[], actorFollow: ActorFollowModel) { + addNewInstanceFollowerNotification (to: string[], actorFollow: MActorFollowActors) { const awaitingApproval = actorFollow.state === 'pending' ? ' awaiting manual approval.' : '' const text = `Hi dear admin,\n\n` + @@ -148,7 +146,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - myVideoPublishedNotification (to: string[], video: VideoModel) { + myVideoPublishedNotification (to: string[], video: MVideo) { const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() const text = `Hi dear user,\n\n` + @@ -168,7 +166,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - myVideoImportSuccessNotification (to: string[], videoImport: VideoImportModel) { + myVideoImportSuccessNotification (to: string[], videoImport: MVideoImportVideo) { const videoUrl = WEBSERVER.URL + videoImport.Video.getWatchStaticPath() const text = `Hi dear user,\n\n` + @@ -188,7 +186,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - myVideoImportErrorNotification (to: string[], videoImport: VideoImportModel) { + myVideoImportErrorNotification (to: string[], videoImport: MVideoImport) { const importUrl = WEBSERVER.URL + '/my-account/video-imports' const text = `Hi dear user,\n\n` + @@ -208,7 +206,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addNewCommentOnMyVideoNotification (to: string[], comment: VideoCommentModel) { + addNewCommentOnMyVideoNotification (to: string[], comment: MCommentOwnerVideo) { const accountName = comment.Account.getDisplayName() const video = comment.Video const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() @@ -230,7 +228,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addNewCommentMentionNotification (to: string[], comment: VideoCommentModel) { + addNewCommentMentionNotification (to: string[], comment: MCommentOwnerVideo) { const accountName = comment.Account.getDisplayName() const video = comment.Video const commentUrl = WEBSERVER.URL + comment.getCommentStaticPath() @@ -252,7 +250,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addVideoAbuseModeratorsNotification (to: string[], videoAbuse: VideoAbuseModel) { + addVideoAbuseModeratorsNotification (to: string[], videoAbuse: MVideoAbuseVideo) { const videoUrl = WEBSERVER.URL + videoAbuse.Video.getWatchStaticPath() const text = `Hi,\n\n` + @@ -269,7 +267,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addVideoAutoBlacklistModeratorsNotification (to: string[], video: VideoModel) { + addVideoAutoBlacklistModeratorsNotification (to: string[], video: MVideo) { const VIDEO_AUTO_BLACKLIST_URL = WEBSERVER.URL + '/admin/moderation/video-auto-blacklist/list' const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() @@ -292,7 +290,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addNewUserRegistrationNotification (to: string[], user: UserModel) { + addNewUserRegistrationNotification (to: string[], user: MUser) { const text = `Hi,\n\n` + `User ${user.username} just registered on ${WEBSERVER.HOST} PeerTube instance.\n\n` + `Cheers,\n` + @@ -307,7 +305,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addVideoBlacklistNotification (to: string[], videoBlacklist: VideoBlacklistModel) { + addVideoBlacklistNotification (to: string[], videoBlacklist: MVideoBlacklistVideo) { const videoName = videoBlacklist.Video.name const videoUrl = WEBSERVER.URL + videoBlacklist.Video.getWatchStaticPath() @@ -329,7 +327,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addVideoUnblacklistNotification (to: string[], video: VideoModel) { + addVideoUnblacklistNotification (to: string[], video: MVideo) { const videoUrl = WEBSERVER.URL + video.getWatchStaticPath() const text = 'Hi,\n\n' + @@ -381,7 +379,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addUserBlockJob (user: UserModel, blocked: boolean, reason?: string) { + addUserBlockJob (user: MUser, blocked: boolean, reason?: string) { const reasonString = reason ? ` for the following reason: ${reason}` : '' const blockedWord = blocked ? 'blocked' : 'unblocked' const blockedString = `Your account ${user.username} on ${WEBSERVER.HOST} has been ${blockedWord}${reasonString}.` diff --git a/server/lib/hls.ts b/server/lib/hls.ts index 98da4dcd8..05136c21c 100644 --- a/server/lib/hls.ts +++ b/server/lib/hls.ts @@ -1,4 +1,3 @@ -import { VideoModel } from '../models/video/video' import { basename, dirname, join } from 'path' import { HLS_STREAMING_PLAYLIST_DIRECTORY, P2P_MEDIA_LOADER_PEER_VERSION } from '../initializers/constants' import { close, ensureDir, move, open, outputJSON, pathExists, read, readFile, remove, writeFile } from 'fs-extra' @@ -12,6 +11,7 @@ import { flatten, uniq } from 'lodash' import { VideoFileModel } from '../models/video/video-file' import { CONFIG } from '../initializers/config' import { sequelizeTypescript } from '../initializers/database' +import { MVideoWithFile } from '@server/typings/models' async function updateStreamingPlaylistsInfohashesIfNeeded () { const playlistsToUpdate = await VideoStreamingPlaylistModel.listByIncorrectPeerVersion() @@ -28,7 +28,7 @@ async function updateStreamingPlaylistsInfohashesIfNeeded () { } } -async function updateMasterHLSPlaylist (video: VideoModel) { +async function updateMasterHLSPlaylist (video: MVideoWithFile) { const directory = join(HLS_STREAMING_PLAYLIST_DIRECTORY, video.uuid) const masterPlaylists: string[] = [ '#EXTM3U', '#EXT-X-VERSION:3' ] const masterPlaylistPath = join(directory, VideoStreamingPlaylistModel.getMasterHlsPlaylistFilename()) @@ -55,7 +55,7 @@ async function updateMasterHLSPlaylist (video: VideoModel) { await writeFile(masterPlaylistPath, masterPlaylists.join('\n') + '\n') } -async function updateSha256Segments (video: VideoModel) { +async function updateSha256Segments (video: MVideoWithFile) { const json: { [filename: string]: { [range: string]: string } } = {} const playlistDirectory = join(HLS_STREAMING_PLAYLIST_DIRECTORY, video.uuid) diff --git a/server/lib/job-queue/handlers/activitypub-follow.ts b/server/lib/job-queue/handlers/activitypub-follow.ts index 4ae66cd01..741b1ffde 100644 --- a/server/lib/job-queue/handlers/activitypub-follow.ts +++ b/server/lib/job-queue/handlers/activitypub-follow.ts @@ -10,6 +10,7 @@ import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { ActorModel } from '../../../models/activitypub/actor' import { Notifier } from '../../notifier' import { sequelizeTypescript } from '../../../initializers/database' +import { MActorFollowFull, MActorFull } from '../../../typings/models' export type ActivitypubFollowPayload = { followerActorId: number @@ -23,13 +24,13 @@ async function processActivityPubFollow (job: Bull.Job) { logger.info('Processing ActivityPub follow in job %d.', job.id) - let targetActor: ActorModel + let targetActor: MActorFull if (!host || host === WEBSERVER.HOST) { targetActor = await ActorModel.loadLocalByName(payload.name) } else { const sanitizedHost = sanitizeHost(host, REMOTE_SCHEME.HTTP) const actorUrl = await loadActorUrlOrGetFromWebfinger(payload.name + '@' + sanitizedHost) - targetActor = await getOrCreateActorAndServerAndModel(actorUrl) + targetActor = await getOrCreateActorAndServerAndModel(actorUrl, 'all') } const fromActor = await ActorModel.load(payload.followerActorId) @@ -44,7 +45,7 @@ export { // --------------------------------------------------------------------------- -async function follow (fromActor: ActorModel, targetActor: ActorModel) { +async function follow (fromActor: MActorFull, targetActor: MActorFull) { if (fromActor.id === targetActor.id) { throw new Error('Follower is the same than target actor.') } @@ -53,7 +54,7 @@ async function follow (fromActor: ActorModel, targetActor: ActorModel) { const state = !fromActor.serverId && !targetActor.serverId ? 'accepted' : 'pending' const actorFollow = await sequelizeTypescript.transaction(async t => { - const [ actorFollow ] = await ActorFollowModel.findOrCreate({ + const [ actorFollow ] = await ActorFollowModel.findOrCreate({ where: { actorId: fromActor.id, targetActorId: targetActor.id diff --git a/server/lib/job-queue/handlers/activitypub-http-fetcher.ts b/server/lib/job-queue/handlers/activitypub-http-fetcher.ts index c3f59dc77..0182c5169 100644 --- a/server/lib/job-queue/handlers/activitypub-http-fetcher.ts +++ b/server/lib/job-queue/handlers/activitypub-http-fetcher.ts @@ -11,6 +11,7 @@ import { AccountModel } from '../../../models/account/account' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { VideoShareModel } from '../../../models/video/video-share' import { VideoCommentModel } from '../../../models/video/video-comment' +import { MAccountDefault, MVideoFullLight } from '../../../typings/models' type FetchType = 'activity' | 'video-likes' | 'video-dislikes' | 'video-shares' | 'video-comments' | 'account-playlists' @@ -26,10 +27,10 @@ async function processActivityPubHttpFetcher (job: Bull.Job) { const payload = job.data as ActivitypubHttpFetcherPayload - let video: VideoModel + let video: MVideoFullLight if (payload.videoId) video = await VideoModel.loadAndPopulateAccountAndServerAndTags(payload.videoId) - let account: AccountModel + let account: MAccountDefault if (payload.accountId) account = await AccountModel.load(payload.accountId) const fetcherType: { [ id in FetchType ]: (items: any[]) => Promise } = { diff --git a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts index cdee1f6fd..d3bde6e6a 100644 --- a/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts +++ b/server/lib/job-queue/handlers/utils/activitypub-http-utils.ts @@ -3,6 +3,7 @@ import { getServerActor } from '../../../../helpers/utils' import { ActorModel } from '../../../../models/activitypub/actor' import { sha256 } from '../../../../helpers/core-utils' import { HTTP_SIGNATURE } from '../../../../initializers/constants' +import { MActor } from '../../../../typings/models' type Payload = { body: any, signatureActorId?: number } @@ -19,7 +20,8 @@ async function computeBody (payload: Payload) { } async function buildSignedRequestOptions (payload: Payload) { - let actor: ActorModel | null + let actor: MActor | null + if (payload.signatureActorId) { actor = await ActorModel.load(payload.signatureActorId) if (!actor) throw new Error('Unknown signature actor id.') diff --git a/server/lib/job-queue/handlers/video-file-import.ts b/server/lib/job-queue/handlers/video-file-import.ts index 8cacb0ef3..5c5b7dccb 100644 --- a/server/lib/job-queue/handlers/video-file-import.ts +++ b/server/lib/job-queue/handlers/video-file-import.ts @@ -6,6 +6,7 @@ import { getVideoFileFPS, getVideoFileResolution } from '../../../helpers/ffmpeg import { copy, stat } from 'fs-extra' import { VideoFileModel } from '../../../models/video/video-file' import { extname } from 'path' +import { MVideoFile, MVideoWithFile } from '@server/typings/models' export type VideoFileImportPayload = { videoUUID: string, @@ -37,7 +38,7 @@ export { // --------------------------------------------------------------------------- -async function updateVideoFile (video: VideoModel, inputFilePath: string) { +async function updateVideoFile (video: MVideoWithFile, inputFilePath: string) { const { videoFileResolution } = await getVideoFileResolution(inputFilePath) const { size } = await stat(inputFilePath) const fps = await getVideoFileFPS(inputFilePath) @@ -48,7 +49,7 @@ async function updateVideoFile (video: VideoModel, inputFilePath: string) { size, fps, videoId: video.id - }) + }) as MVideoFile const currentVideoFile = video.VideoFiles.find(videoFile => videoFile.resolution === updatedVideoFile.resolution) @@ -60,9 +61,9 @@ async function updateVideoFile (video: VideoModel, inputFilePath: string) { video.VideoFiles = video.VideoFiles.filter(f => f !== currentVideoFile) // Update the database - currentVideoFile.set('extname', updatedVideoFile.extname) - currentVideoFile.set('size', updatedVideoFile.size) - currentVideoFile.set('fps', updatedVideoFile.fps) + currentVideoFile.extname = updatedVideoFile.extname + currentVideoFile.size = updatedVideoFile.size + currentVideoFile.fps = updatedVideoFile.fps updatedVideoFile = currentVideoFile } diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index 13b741180..f9dda79f8 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts @@ -17,9 +17,10 @@ import { move, remove, stat } from 'fs-extra' import { Notifier } from '../../notifier' import { CONFIG } from '../../../initializers/config' import { sequelizeTypescript } from '../../../initializers/database' -import { ThumbnailModel } from '../../../models/video/thumbnail' import { createVideoMiniatureFromUrl, generateVideoMiniature } from '../../thumbnail' import { ThumbnailType } from '../../../../shared/models/videos/thumbnail.type' +import { MThumbnail } from '../../../typings/models/video/thumbnail' +import { MVideoImportDefault, MVideoImportDefaultFiles, MVideoImportVideo } from '@server/typings/models/video/video-import' type VideoImportYoutubeDLPayload = { type: 'youtube-dl' @@ -110,11 +111,13 @@ type ProcessFileOptions = { generateThumbnail: boolean generatePreview: boolean } -async function processFile (downloader: () => Promise, videoImport: VideoImportModel, options: ProcessFileOptions) { +async function processFile (downloader: () => Promise, videoImportArg: MVideoImportDefault, options: ProcessFileOptions) { let tempVideoPath: string let videoDestFile: string let videoFile: VideoFileModel + const videoImport = videoImportArg as MVideoImportDefaultFiles + try { // Download video from youtubeDL tempVideoPath = await downloader() @@ -148,7 +151,7 @@ async function processFile (downloader: () => Promise, videoImport: Vide tempVideoPath = null // This path is not used anymore // Process thumbnail - let thumbnailModel: ThumbnailModel + let thumbnailModel: MThumbnail if (options.downloadThumbnail && options.thumbnailUrl) { thumbnailModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImport.Video, ThumbnailType.MINIATURE) } else if (options.generateThumbnail || options.downloadThumbnail) { @@ -156,7 +159,7 @@ async function processFile (downloader: () => Promise, videoImport: Vide } // Process preview - let previewModel: ThumbnailModel + let previewModel: MThumbnail if (options.downloadPreview && options.thumbnailUrl) { previewModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImport.Video, ThumbnailType.PREVIEW) } else if (options.generatePreview || options.downloadPreview) { @@ -166,14 +169,15 @@ async function processFile (downloader: () => Promise, videoImport: Vide // Create torrent await videoImport.Video.createTorrentAndSetInfoHash(videoFile) - const videoImportUpdated: VideoImportModel = await sequelizeTypescript.transaction(async t => { + const { videoImportUpdated, video } = await sequelizeTypescript.transaction(async t => { + const videoImportToUpdate = videoImport as MVideoImportVideo + // Refresh video - const video = await VideoModel.load(videoImport.videoId, t) - if (!video) throw new Error('Video linked to import ' + videoImport.videoId + ' does not exist anymore.') - videoImport.Video = video + const video = await VideoModel.load(videoImportToUpdate.videoId, t) + if (!video) throw new Error('Video linked to import ' + videoImportToUpdate.videoId + ' does not exist anymore.') const videoFileCreated = await videoFile.save({ transaction: t }) - video.VideoFiles = [ videoFileCreated ] + videoImportToUpdate.Video = Object.assign(video, { VideoFiles: [ videoFileCreated ] }) // Update video DB object video.duration = duration @@ -188,25 +192,25 @@ async function processFile (downloader: () => Promise, videoImport: Vide await federateVideoIfNeeded(videoForFederation, true, t) // Update video import object - videoImport.state = VideoImportState.SUCCESS - const videoImportUpdated = await videoImport.save({ transaction: t }) + videoImportToUpdate.state = VideoImportState.SUCCESS + const videoImportUpdated = await videoImportToUpdate.save({ transaction: t }) as MVideoImportVideo + videoImportUpdated.Video = video logger.info('Video %s imported.', video.uuid) - videoImportUpdated.Video = videoForFederation - return videoImportUpdated + return { videoImportUpdated, video: videoForFederation } }) Notifier.Instance.notifyOnFinishedVideoImport(videoImportUpdated, true) - if (videoImportUpdated.Video.isBlacklisted()) { - Notifier.Instance.notifyOnVideoAutoBlacklist(videoImportUpdated.Video) + if (video.isBlacklisted()) { + Notifier.Instance.notifyOnVideoAutoBlacklist(video) } else { - Notifier.Instance.notifyOnNewVideoIfNeeded(videoImportUpdated.Video) + Notifier.Instance.notifyOnNewVideoIfNeeded(video) } // Create transcoding jobs? - if (videoImportUpdated.Video.state === VideoState.TO_TRANSCODE) { + if (video.state === VideoState.TO_TRANSCODE) { // Put uuid because we don't have id auto incremented for now const dataInput = { type: 'optimize' as 'optimize', diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 981daf9a1..2ebe15bcb 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts @@ -11,6 +11,7 @@ import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' import { generateHlsPlaylist, optimizeVideofile, transcodeOriginalVideofile, mergeAudioVideofile } from '../../video-transcoding' import { Notifier } from '../../notifier' import { CONFIG } from '../../../initializers/config' +import { MVideoUUID, MVideoWithFile } from '@server/typings/models' interface BaseTranscodingPayload { videoUUID: string @@ -73,7 +74,7 @@ async function processVideoTranscoding (job: Bull.Job) { return video } -async function onHlsPlaylistGenerationSuccess (video: VideoModel) { +async function onHlsPlaylistGenerationSuccess (video: MVideoUUID) { if (video === undefined) return undefined await sequelizeTypescript.transaction(async t => { @@ -87,7 +88,7 @@ async function onHlsPlaylistGenerationSuccess (video: VideoModel) { }) } -async function publishNewResolutionIfNeeded (video: VideoModel, payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload) { +async function publishNewResolutionIfNeeded (video: MVideoUUID, payload?: NewResolutionTranscodingPayload | MergeAudioTranscodingPayload) { const { videoDatabase, videoPublished } = await sequelizeTypescript.transaction(async t => { // Maybe the video changed in database, refresh it let videoDatabase = await VideoModel.loadAndPopulateAccountAndServerAndTags(video.uuid, t) @@ -119,7 +120,7 @@ async function publishNewResolutionIfNeeded (video: VideoModel, payload?: NewRes await createHlsJobIfEnabled(payload) } -async function onVideoFileOptimizerSuccess (videoArg: VideoModel, payload: OptimizeTranscodingPayload) { +async function onVideoFileOptimizerSuccess (videoArg: MVideoWithFile, payload: OptimizeTranscodingPayload) { if (videoArg === undefined) return undefined // Outside the transaction (IO on disk) diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index a7dfb0979..f01101b8e 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts @@ -8,13 +8,23 @@ import { UserModel } from '../models/account/user' import { PeerTubeSocket } from './peertube-socket' import { CONFIG } from '../initializers/config' import { VideoPrivacy, VideoState } from '../../shared/models/videos' -import { VideoAbuseModel } from '../models/video/video-abuse' import { VideoBlacklistModel } from '../models/video/video-blacklist' import * as Bluebird from 'bluebird' import { VideoImportModel } from '../models/video/video-import' import { AccountBlocklistModel } from '../models/account/account-blocklist' +import { + MCommentOwnerVideo, + MVideo, + MVideoAbuseVideo, + MVideoAccountLight, + MVideoBlacklistVideo, + MVideoFullLight +} from '../typings/models/video' +import { MUser, MUserAccount, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/typings/models/user' +import { MActorFollowActors, MActorFollowFull } from '../typings/models' import { ActorFollowModel } from '../models/activitypub/actor-follow' -import { AccountModel } from '../models/account/account' +import { MVideoImportVideo } from '@server/typings/models/video/video-import' +import { AccountModel } from '@server/models/account/account' class Notifier { @@ -22,7 +32,7 @@ class Notifier { private constructor () {} - notifyOnNewVideoIfNeeded (video: VideoModel): void { + notifyOnNewVideoIfNeeded (video: MVideoAccountLight): void { // Only notify on public and published videos which are not blacklisted if (video.privacy !== VideoPrivacy.PUBLIC || video.state !== VideoState.PUBLISHED || video.isBlacklisted()) return @@ -30,7 +40,7 @@ class Notifier { .catch(err => logger.error('Cannot notify subscribers of new video %s.', video.url, { err })) } - notifyOnVideoPublishedAfterTranscoding (video: VideoModel): void { + notifyOnVideoPublishedAfterTranscoding (video: MVideoFullLight): void { // don't notify if didn't wait for transcoding or video is still blacklisted/waiting for scheduled update if (!video.waitTranscoding || video.VideoBlacklist || video.ScheduleVideoUpdate) return @@ -38,7 +48,7 @@ class Notifier { .catch(err => logger.error('Cannot notify owner that its video %s has been published after transcoding.', video.url, { err })) } - notifyOnVideoPublishedAfterScheduledUpdate (video: VideoModel): void { + notifyOnVideoPublishedAfterScheduledUpdate (video: MVideoFullLight): void { // don't notify if video is still blacklisted or waiting for transcoding if (video.VideoBlacklist || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return @@ -46,7 +56,7 @@ class Notifier { .catch(err => logger.error('Cannot notify owner that its video %s has been published after scheduled update.', video.url, { err })) } - notifyOnVideoPublishedAfterRemovedFromAutoBlacklist (video: VideoModel): void { + notifyOnVideoPublishedAfterRemovedFromAutoBlacklist (video: MVideoFullLight): void { // don't notify if video is still waiting for transcoding or scheduled update if (video.ScheduleVideoUpdate || (video.waitTranscoding && video.state !== VideoState.PUBLISHED)) return @@ -54,7 +64,7 @@ class Notifier { .catch(err => logger.error('Cannot notify owner that its video %s has been published after removed from auto-blacklist.', video.url, { err })) // tslint:disable-line:max-line-length } - notifyOnNewComment (comment: VideoCommentModel): void { + notifyOnNewComment (comment: MCommentOwnerVideo): void { this.notifyVideoOwnerOfNewComment(comment) .catch(err => logger.error('Cannot notify video owner of new comment %s.', comment.url, { err })) @@ -62,37 +72,37 @@ class Notifier { .catch(err => logger.error('Cannot notify mentions of comment %s.', comment.url, { err })) } - notifyOnNewVideoAbuse (videoAbuse: VideoAbuseModel): void { + notifyOnNewVideoAbuse (videoAbuse: MVideoAbuseVideo): void { this.notifyModeratorsOfNewVideoAbuse(videoAbuse) .catch(err => logger.error('Cannot notify of new video abuse of video %s.', videoAbuse.Video.url, { err })) } - notifyOnVideoAutoBlacklist (video: VideoModel): void { + notifyOnVideoAutoBlacklist (video: MVideo): void { this.notifyModeratorsOfVideoAutoBlacklist(video) .catch(err => logger.error('Cannot notify of auto-blacklist of video %s.', video.url, { err })) } - notifyOnVideoBlacklist (videoBlacklist: VideoBlacklistModel): void { + notifyOnVideoBlacklist (videoBlacklist: MVideoBlacklistVideo): void { this.notifyVideoOwnerOfBlacklist(videoBlacklist) .catch(err => logger.error('Cannot notify video owner of new video blacklist of %s.', videoBlacklist.Video.url, { err })) } - notifyOnVideoUnblacklist (video: VideoModel): void { + notifyOnVideoUnblacklist (video: MVideo): void { this.notifyVideoOwnerOfUnblacklist(video) .catch(err => logger.error('Cannot notify video owner of unblacklist of %s.', video.url, { err })) } - notifyOnFinishedVideoImport (videoImport: VideoImportModel, success: boolean): void { + notifyOnFinishedVideoImport (videoImport: MVideoImportVideo, success: boolean): void { this.notifyOwnerVideoImportIsFinished(videoImport, success) .catch(err => logger.error('Cannot notify owner that its video import %s is finished.', videoImport.getTargetIdentifier(), { err })) } - notifyOnNewUserRegistration (user: UserModel): void { + notifyOnNewUserRegistration (user: MUserAccount): void { this.notifyModeratorsOfNewUserRegistration(user) .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err })) } - notifyOfNewUserFollow (actorFollow: ActorFollowModel): void { + notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { this.notifyUserOfNewActorFollow(actorFollow) .catch(err => { logger.error( @@ -104,14 +114,14 @@ class Notifier { }) } - notifyOfNewInstanceFollow (actorFollow: ActorFollowModel): void { + notifyOfNewInstanceFollow (actorFollow: MActorFollowActors): void { this.notifyAdminsOfNewInstanceFollow(actorFollow) .catch(err => { logger.error('Cannot notify administrators of new follower %s.', actorFollow.ActorFollower.url, { err }) }) } - private async notifySubscribersOfNewVideo (video: VideoModel) { + private async notifySubscribersOfNewVideo (video: MVideoAccountLight) { // List all followers that are users const users = await UserModel.listUserSubscribersOf(video.VideoChannel.actorId) @@ -127,7 +137,7 @@ class Notifier { userId: user.id, videoId: video.id }) - notification.Video = video + notification.Video = video as VideoModel return notification } @@ -139,7 +149,7 @@ class Notifier { return this.notify({ users, settingGetter, notificationCreator, emailSender }) } - private async notifyVideoOwnerOfNewComment (comment: VideoCommentModel) { + private async notifyVideoOwnerOfNewComment (comment: MCommentOwnerVideo) { if (comment.Video.isOwned() === false) return const user = await UserModel.loadByVideoId(comment.videoId) @@ -162,7 +172,7 @@ class Notifier { userId: user.id, commentId: comment.id }) - notification.Comment = comment + notification.Comment = comment as VideoCommentModel return notification } @@ -174,7 +184,7 @@ class Notifier { return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) } - private async notifyOfCommentMention (comment: VideoCommentModel) { + private async notifyOfCommentMention (comment: MCommentOwnerVideo) { const extractedUsernames = comment.extractMentions() logger.debug( 'Extracted %d username from comment %s.', extractedUsernames.length, comment.url, @@ -209,7 +219,7 @@ class Notifier { userId: user.id, commentId: comment.id }) - notification.Comment = comment + notification.Comment = comment as VideoCommentModel return notification } @@ -221,7 +231,7 @@ class Notifier { return this.notify({ users, settingGetter, notificationCreator, emailSender }) } - private async notifyUserOfNewActorFollow (actorFollow: ActorFollowModel) { + private async notifyUserOfNewActorFollow (actorFollow: MActorFollowFull) { if (actorFollow.ActorFollowing.isOwned() === false) return // Account follows one of our account? @@ -236,9 +246,6 @@ class Notifier { if (!user) return - if (!actorFollow.ActorFollower.Account || !actorFollow.ActorFollower.Account.name) { - actorFollow.ActorFollower.Account = await actorFollow.ActorFollower.$get('Account') as AccountModel - } const followerAccount = actorFollow.ActorFollower.Account const accountMuted = await AccountBlocklistModel.isAccountMutedBy(user.Account.id, followerAccount.id) @@ -256,7 +263,7 @@ class Notifier { userId: user.id, actorFollowId: actorFollow.id }) - notification.ActorFollow = actorFollow + notification.ActorFollow = actorFollow as ActorFollowModel return notification } @@ -268,7 +275,7 @@ class Notifier { return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) } - private async notifyAdminsOfNewInstanceFollow (actorFollow: ActorFollowModel) { + private async notifyAdminsOfNewInstanceFollow (actorFollow: MActorFollowActors) { const admins = await UserModel.listWithRight(UserRight.MANAGE_SERVER_FOLLOW) logger.info('Notifying %d administrators of new instance follower: %s.', admins.length, actorFollow.ActorFollower.url) @@ -283,7 +290,7 @@ class Notifier { userId: user.id, actorFollowId: actorFollow.id }) - notification.ActorFollow = actorFollow + notification.ActorFollow = actorFollow as ActorFollowModel return notification } @@ -295,7 +302,7 @@ class Notifier { return this.notify({ users: admins, settingGetter, notificationCreator, emailSender }) } - private async notifyModeratorsOfNewVideoAbuse (videoAbuse: VideoAbuseModel) { + private async notifyModeratorsOfNewVideoAbuse (videoAbuse: MVideoAbuseVideo) { const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_ABUSES) if (moderators.length === 0) return @@ -306,7 +313,7 @@ class Notifier { } async function notificationCreator (user: UserModel) { - const notification = await UserNotificationModel.create({ + const notification: UserNotificationModelForApi = await UserNotificationModel.create({ type: UserNotificationType.NEW_VIDEO_ABUSE_FOR_MODERATORS, userId: user.id, videoAbuseId: videoAbuse.id @@ -323,7 +330,7 @@ class Notifier { return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) } - private async notifyModeratorsOfVideoAutoBlacklist (video: VideoModel) { + private async notifyModeratorsOfVideoAutoBlacklist (video: MVideo) { const moderators = await UserModel.listWithRight(UserRight.MANAGE_VIDEO_BLACKLIST) if (moderators.length === 0) return @@ -339,7 +346,7 @@ class Notifier { userId: user.id, videoId: video.id }) - notification.Video = video + notification.Video = video as VideoModel return notification } @@ -351,7 +358,7 @@ class Notifier { return this.notify({ users: moderators, settingGetter, notificationCreator, emailSender }) } - private async notifyVideoOwnerOfBlacklist (videoBlacklist: VideoBlacklistModel) { + private async notifyVideoOwnerOfBlacklist (videoBlacklist: MVideoBlacklistVideo) { const user = await UserModel.loadByVideoId(videoBlacklist.videoId) if (!user) return @@ -367,7 +374,7 @@ class Notifier { userId: user.id, videoBlacklistId: videoBlacklist.id }) - notification.VideoBlacklist = videoBlacklist + notification.VideoBlacklist = videoBlacklist as VideoBlacklistModel return notification } @@ -379,7 +386,7 @@ class Notifier { return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) } - private async notifyVideoOwnerOfUnblacklist (video: VideoModel) { + private async notifyVideoOwnerOfUnblacklist (video: MVideo) { const user = await UserModel.loadByVideoId(video.id) if (!user) return @@ -395,7 +402,7 @@ class Notifier { userId: user.id, videoId: video.id }) - notification.Video = video + notification.Video = video as VideoModel return notification } @@ -407,7 +414,7 @@ class Notifier { return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) } - private async notifyOwnedVideoHasBeenPublished (video: VideoModel) { + private async notifyOwnedVideoHasBeenPublished (video: MVideoFullLight) { const user = await UserModel.loadByVideoId(video.id) if (!user) return @@ -423,7 +430,7 @@ class Notifier { userId: user.id, videoId: video.id }) - notification.Video = video + notification.Video = video as VideoModel return notification } @@ -435,7 +442,7 @@ class Notifier { return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) } - private async notifyOwnerVideoImportIsFinished (videoImport: VideoImportModel, success: boolean) { + private async notifyOwnerVideoImportIsFinished (videoImport: MVideoImportVideo, success: boolean) { const user = await UserModel.loadByVideoImportId(videoImport.id) if (!user) return @@ -451,7 +458,7 @@ class Notifier { userId: user.id, videoImportId: videoImport.id }) - notification.VideoImport = videoImport + notification.VideoImport = videoImport as VideoImportModel return notification } @@ -465,13 +472,13 @@ class Notifier { return this.notify({ users: [ user ], settingGetter, notificationCreator, emailSender }) } - private async notifyModeratorsOfNewUserRegistration (registeredUser: UserModel) { + private async notifyModeratorsOfNewUserRegistration (registeredUser: MUserAccount) { const moderators = await UserModel.listWithRight(UserRight.MANAGE_USERS) if (moderators.length === 0) return logger.info( 'Notifying %s moderators of new user registration of %s.', - moderators.length, registeredUser.Account.Actor.preferredUsername + moderators.length, registeredUser.username ) function settingGetter (user: UserModel) { @@ -484,7 +491,7 @@ class Notifier { userId: user.id, accountId: registeredUser.Account.id }) - notification.Account = registeredUser.Account + notification.Account = registeredUser.Account as AccountModel return notification } @@ -497,10 +504,10 @@ class Notifier { } private async notify (options: { - users: UserModel[], - notificationCreator: (user: UserModel) => Promise, + users: MUserWithNotificationSetting[], + notificationCreator: (user: MUserWithNotificationSetting) => Promise, emailSender: (emails: string[]) => Promise | Bluebird, - settingGetter: (user: UserModel) => UserNotificationSettingValue + settingGetter: (user: MUserWithNotificationSetting) => UserNotificationSettingValue }) { const emails: string[] = [] @@ -521,7 +528,7 @@ class Notifier { } } - private isEmailEnabled (user: UserModel, value: UserNotificationSettingValue) { + private isEmailEnabled (user: MUser, value: UserNotificationSettingValue) { if (CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION === true && user.emailVerified === false) return false return value & UserNotificationSettingValue.EMAIL diff --git a/server/lib/oauth-model.ts b/server/lib/oauth-model.ts index a1153e88a..086856f41 100644 --- a/server/lib/oauth-model.ts +++ b/server/lib/oauth-model.ts @@ -8,10 +8,11 @@ import { LRU_CACHE } from '../initializers/constants' import { Transaction } from 'sequelize' import { CONFIG } from '../initializers/config' import * as LRUCache from 'lru-cache' +import { MOAuthTokenUser } from '@server/typings/models/oauth/oauth-token' type TokenInfo = { accessToken: string, refreshToken: string, accessTokenExpiresAt: Date, refreshTokenExpiresAt: Date } -const accessTokenCache = new LRUCache({ max: LRU_CACHE.USER_TOKENS.MAX_SIZE }) +const accessTokenCache = new LRUCache({ max: LRU_CACHE.USER_TOKENS.MAX_SIZE }) const userHavingToken = new LRUCache({ max: LRU_CACHE.USER_TOKENS.MAX_SIZE }) // --------------------------------------------------------------------------- diff --git a/server/lib/peertube-socket.ts b/server/lib/peertube-socket.ts index eb84ecd4b..1c7b09175 100644 --- a/server/lib/peertube-socket.ts +++ b/server/lib/peertube-socket.ts @@ -1,8 +1,8 @@ import * as SocketIO from 'socket.io' import { authenticateSocket } from '../middlewares' -import { UserNotificationModel } from '../models/account/user-notification' import { logger } from '../helpers/logger' import { Server } from 'http' +import { UserNotificationModelForApi } from '@server/typings/models/user' class PeerTubeSocket { @@ -32,7 +32,7 @@ class PeerTubeSocket { }) } - sendNotification (userId: number, notification: UserNotificationModel) { + sendNotification (userId: number, notification: UserNotificationModelForApi) { const socket = this.userNotificationSockets[userId] if (!socket) return diff --git a/server/lib/redundancy.ts b/server/lib/redundancy.ts index 04d3ded8f..1b4ecd7c0 100644 --- a/server/lib/redundancy.ts +++ b/server/lib/redundancy.ts @@ -2,8 +2,9 @@ import { VideoRedundancyModel } from '../models/redundancy/video-redundancy' import { sendUndoCacheFile } from './activitypub/send' import { Transaction } from 'sequelize' import { getServerActor } from '../helpers/utils' +import { MVideoRedundancyVideo } from '@server/typings/models' -async function removeVideoRedundancy (videoRedundancy: VideoRedundancyModel, t?: Transaction) { +async function removeVideoRedundancy (videoRedundancy: MVideoRedundancyVideo, t?: Transaction) { const serverActor = await getServerActor() // Local cache, send undo to remote instances diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index 04f601bfb..de8fc075b 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts @@ -3,7 +3,6 @@ import { HLS_REDUNDANCY_DIRECTORY, REDUNDANCY, VIDEO_IMPORT_TIMEOUT, WEBSERVER } import { logger } from '../../helpers/logger' import { VideosRedundancy } from '../../../shared/models/redundancy' import { VideoRedundancyModel } from '../../models/redundancy/video-redundancy' -import { VideoFileModel } from '../../models/video/video-file' import { downloadWebTorrentVideo } from '../../helpers/webtorrent' import { join } from 'path' import { move } from 'fs-extra' @@ -12,16 +11,29 @@ import { sendCreateCacheFile, sendUpdateCacheFile } from '../activitypub/send' import { getVideoCacheFileActivityPubUrl, getVideoCacheStreamingPlaylistActivityPubUrl } from '../activitypub/url' import { removeVideoRedundancy } from '../redundancy' import { getOrCreateVideoAndAccountAndChannel } from '../activitypub' -import { VideoStreamingPlaylistModel } from '../../models/video/video-streaming-playlist' -import { VideoModel } from '../../models/video/video' import { downloadPlaylistSegments } from '../hls' import { CONFIG } from '../../initializers/config' +import { + MStreamingPlaylist, + MStreamingPlaylistVideo, + MVideoAccountLight, + MVideoFile, + MVideoFileVideo, + MVideoRedundancyFileVideo, + MVideoRedundancyStreamingPlaylistVideo, + MVideoRedundancyVideo, + MVideoWithAllFiles +} from '@server/typings/models' type CandidateToDuplicate = { redundancy: VideosRedundancy, - video: VideoModel, - files: VideoFileModel[], - streamingPlaylists: VideoStreamingPlaylistModel[] + video: MVideoWithAllFiles, + files: MVideoFile[], + streamingPlaylists: MStreamingPlaylist[] +} + +function isMVideoRedundancyFileVideo (o: MVideoRedundancyVideo): o is MVideoRedundancyFileVideo { + return !!(o as MVideoRedundancyFileVideo).VideoFile } export class VideosRedundancyScheduler extends AbstractScheduler { @@ -102,7 +114,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { } } - private async extendsRedundancy (redundancyModel: VideoRedundancyModel) { + private async extendsRedundancy (redundancyModel: MVideoRedundancyVideo) { const redundancy = CONFIG.REDUNDANCY.VIDEOS.STRATEGIES.find(s => s.strategy === redundancyModel.strategy) // Redundancy strategy disabled, remove our redundancy instead of extending expiration if (!redundancy) { @@ -172,7 +184,8 @@ export class VideosRedundancyScheduler extends AbstractScheduler { } } - private async createVideoFileRedundancy (redundancy: VideosRedundancy, video: VideoModel, file: VideoFileModel) { + private async createVideoFileRedundancy (redundancy: VideosRedundancy, video: MVideoAccountLight, fileArg: MVideoFile) { + const file = fileArg as MVideoFileVideo file.Video = video const serverActor = await getServerActor() @@ -187,7 +200,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { const destPath = join(CONFIG.STORAGE.REDUNDANCY_DIR, video.getVideoFilename(file)) await move(tmpPath, destPath) - const createdModel = await VideoRedundancyModel.create({ + const createdModel: MVideoRedundancyFileVideo = await VideoRedundancyModel.create({ expiresOn: this.buildNewExpiration(redundancy.minLifetime), url: getVideoCacheFileActivityPubUrl(file), fileUrl: video.getVideoRedundancyUrl(file, WEBSERVER.URL), @@ -203,7 +216,12 @@ export class VideosRedundancyScheduler extends AbstractScheduler { logger.info('Duplicated %s - %d -> %s.', video.url, file.resolution, createdModel.url) } - private async createStreamingPlaylistRedundancy (redundancy: VideosRedundancy, video: VideoModel, playlist: VideoStreamingPlaylistModel) { + private async createStreamingPlaylistRedundancy ( + redundancy: VideosRedundancy, + video: MVideoAccountLight, + playlistArg: MStreamingPlaylist + ) { + const playlist = playlistArg as MStreamingPlaylistVideo playlist.Video = video const serverActor = await getServerActor() @@ -213,7 +231,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { const destDirectory = join(HLS_REDUNDANCY_DIRECTORY, video.uuid) await downloadPlaylistSegments(playlist.playlistUrl, destDirectory, VIDEO_IMPORT_TIMEOUT) - const createdModel = await VideoRedundancyModel.create({ + const createdModel: MVideoRedundancyStreamingPlaylistVideo = await VideoRedundancyModel.create({ expiresOn: this.buildNewExpiration(redundancy.minLifetime), url: getVideoCacheStreamingPlaylistActivityPubUrl(video, playlist), fileUrl: playlist.getVideoRedundancyUrl(WEBSERVER.URL), @@ -229,7 +247,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { logger.info('Duplicated playlist %s -> %s.', playlist.playlistUrl, createdModel.url) } - private async extendsExpirationOf (redundancy: VideoRedundancyModel, expiresAfterMs: number) { + private async extendsExpirationOf (redundancy: MVideoRedundancyVideo, expiresAfterMs: number) { logger.info('Extending expiration of %s.', redundancy.url) const serverActor = await getServerActor() @@ -243,7 +261,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { private async purgeCacheIfNeeded (candidateToDuplicate: CandidateToDuplicate) { while (this.isTooHeavy(candidateToDuplicate)) { const redundancy = candidateToDuplicate.redundancy - const toDelete = await VideoRedundancyModel.loadOldestLocalThatAlreadyExpired(redundancy.strategy, redundancy.minLifetime) + const toDelete = await VideoRedundancyModel.loadOldestLocalExpired(redundancy.strategy, redundancy.minLifetime) if (!toDelete) return await removeVideoRedundancy(toDelete) @@ -263,14 +281,14 @@ export class VideosRedundancyScheduler extends AbstractScheduler { return new Date(Date.now() + expiresAfterMs) } - private buildEntryLogId (object: VideoRedundancyModel) { - if (object.VideoFile) return `${object.VideoFile.Video.url}-${object.VideoFile.resolution}` + private buildEntryLogId (object: MVideoRedundancyFileVideo | MVideoRedundancyStreamingPlaylistVideo) { + if (isMVideoRedundancyFileVideo(object)) return `${object.VideoFile.Video.url}-${object.VideoFile.resolution}` return `${object.VideoStreamingPlaylist.playlistUrl}` } - private getTotalFileSizes (files: VideoFileModel[], playlists: VideoStreamingPlaylistModel[]) { - const fileReducer = (previous: number, current: VideoFileModel) => previous + current.size + private getTotalFileSizes (files: MVideoFile[], playlists: MStreamingPlaylist[]) { + const fileReducer = (previous: number, current: MVideoFile) => previous + current.size const totalSize = files.reduce(fileReducer, 0) if (playlists.length === 0) return totalSize diff --git a/server/lib/thumbnail.ts b/server/lib/thumbnail.ts index a59773f5a..84791955e 100644 --- a/server/lib/thumbnail.ts +++ b/server/lib/thumbnail.ts @@ -1,20 +1,20 @@ -import { VideoFileModel } from '../models/video/video-file' import { generateImageFromVideoFile } from '../helpers/ffmpeg-utils' import { CONFIG } from '../initializers/config' -import { PREVIEWS_SIZE, THUMBNAILS_SIZE, ASSETS_PATH } from '../initializers/constants' -import { VideoModel } from '../models/video/video' +import { ASSETS_PATH, PREVIEWS_SIZE, THUMBNAILS_SIZE } from '../initializers/constants' import { ThumbnailModel } from '../models/video/thumbnail' import { ThumbnailType } from '../../shared/models/videos/thumbnail.type' import { processImage } from '../helpers/image-utils' import { join } from 'path' import { downloadImage } from '../helpers/requests' -import { VideoPlaylistModel } from '../models/video/video-playlist' +import { MVideoPlaylistThumbnail } from '../typings/models/video/video-playlist' +import { MVideoFile, MVideoThumbnail } from '../typings/models' +import { MThumbnail } from '../typings/models/video/thumbnail' type ImageSize = { height: number, width: number } function createPlaylistMiniatureFromExisting ( inputPath: string, - playlist: VideoPlaylistModel, + playlist: MVideoPlaylistThumbnail, automaticallyGenerated: boolean, keepOriginal = false, size?: ImageSize @@ -26,7 +26,7 @@ function createPlaylistMiniatureFromExisting ( return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail }) } -function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: VideoPlaylistModel, size?: ImageSize) { +function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: MVideoPlaylistThumbnail, size?: ImageSize) { const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromPlaylist(playlist, size) const type = ThumbnailType.MINIATURE @@ -34,7 +34,7 @@ function createPlaylistMiniatureFromUrl (fileUrl: string, playlist: VideoPlaylis return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, existingThumbnail, fileUrl }) } -function createVideoMiniatureFromUrl (fileUrl: string, video: VideoModel, type: ThumbnailType, size?: ImageSize) { +function createVideoMiniatureFromUrl (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) { const { filename, basePath, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) const thumbnailCreator = () => downloadImage(fileUrl, basePath, filename, { width, height }) @@ -43,7 +43,7 @@ function createVideoMiniatureFromUrl (fileUrl: string, video: VideoModel, type: function createVideoMiniatureFromExisting ( inputPath: string, - video: VideoModel, + video: MVideoThumbnail, type: ThumbnailType, automaticallyGenerated: boolean, size?: ImageSize @@ -54,7 +54,7 @@ function createVideoMiniatureFromExisting ( return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated, existingThumbnail }) } -function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, type: ThumbnailType) { +function generateVideoMiniature (video: MVideoThumbnail, videoFile: MVideoFile, type: ThumbnailType) { const input = video.getVideoFilePath(videoFile) const { filename, basePath, height, width, existingThumbnail, outputPath } = buildMetadataFromVideo(video, type) @@ -65,7 +65,7 @@ function generateVideoMiniature (video: VideoModel, videoFile: VideoFileModel, t return createThumbnailFromFunction({ thumbnailCreator, filename, height, width, type, automaticallyGenerated: true, existingThumbnail }) } -function createPlaceholderThumbnail (fileUrl: string, video: VideoModel, type: ThumbnailType, size: ImageSize) { +function createPlaceholderThumbnail (fileUrl: string, video: MVideoThumbnail, type: ThumbnailType, size: ImageSize) { const { filename, height, width, existingThumbnail } = buildMetadataFromVideo(video, type, size) const thumbnail = existingThumbnail ? existingThumbnail : new ThumbnailModel() @@ -90,7 +90,7 @@ export { createPlaylistMiniatureFromExisting } -function buildMetadataFromPlaylist (playlist: VideoPlaylistModel, size: ImageSize) { +function buildMetadataFromPlaylist (playlist: MVideoPlaylistThumbnail, size: ImageSize) { const filename = playlist.generateThumbnailName() const basePath = CONFIG.STORAGE.THUMBNAILS_DIR @@ -104,7 +104,7 @@ function buildMetadataFromPlaylist (playlist: VideoPlaylistModel, size: ImageSiz } } -function buildMetadataFromVideo (video: VideoModel, type: ThumbnailType, size?: ImageSize) { +function buildMetadataFromVideo (video: MVideoThumbnail, type: ThumbnailType, size?: ImageSize) { const existingThumbnail = Array.isArray(video.Thumbnails) ? video.Thumbnails.find(t => t.type === type) : undefined @@ -148,7 +148,7 @@ async function createThumbnailFromFunction (parameters: { type: ThumbnailType, automaticallyGenerated?: boolean, fileUrl?: string, - existingThumbnail?: ThumbnailModel + existingThumbnail?: MThumbnail }) { const { thumbnailCreator, filename, width, height, type, existingThumbnail, automaticallyGenerated = null, fileUrl = null } = parameters diff --git a/server/lib/user.ts b/server/lib/user.ts index 0e4007770..266974cac 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts @@ -5,7 +5,6 @@ import { AccountModel } from '../models/account/account' import { UserModel } from '../models/account/user' import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' import { createVideoChannel } from './video-channel' -import { VideoChannelModel } from '../models/video/video-channel' import { ActorModel } from '../models/activitypub/actor' import { UserNotificationSettingModel } from '../models/account/user-notification-setting' import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' @@ -14,14 +13,17 @@ import { sequelizeTypescript } from '../initializers/database' import { Transaction } from 'sequelize/types' import { Redis } from './redis' import { Emailer } from './emailer' +import { MAccountActor, MActor, MChannelActor } from '../typings/models' +import { MUser, MUserId, MUserNotifSettingAccount } from '../typings/models/user' type ChannelNames = { name: string, displayName: string } + async function createUserAccountAndChannelAndPlaylist (parameters: { userToCreate: UserModel, userDisplayName?: string, channelNames?: ChannelNames, validateUser?: boolean -}) { +}): Promise<{ user: MUserNotifSettingAccount, account: MAccountActor, videoChannel: MChannelActor }> { const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { @@ -30,7 +32,7 @@ async function createUserAccountAndChannelAndPlaylist (parameters: { validate: validateUser } - const userCreated = await userToCreate.save(userOptions) + const userCreated: MUserNotifSettingAccount = await userToCreate.save(userOptions) userCreated.NotificationSetting = await createDefaultUserNotificationSettings(userCreated, t) const accountCreated = await createLocalAccountWithoutKeys({ @@ -50,15 +52,15 @@ async function createUserAccountAndChannelAndPlaylist (parameters: { return { user: userCreated, account: accountCreated, videoChannel, videoPlaylist } }) - const [ accountKeys, channelKeys ] = await Promise.all([ + const [ accountActorWithKeys, channelActorWithKeys ] = await Promise.all([ setAsyncActorKeys(account.Actor), setAsyncActorKeys(videoChannel.Actor) ]) - account.Actor = accountKeys - videoChannel.Actor = channelKeys + account.Actor = accountActorWithKeys + videoChannel.Actor = channelActorWithKeys - return { user, account, videoChannel } as { user: UserModel, account: AccountModel, videoChannel: VideoChannelModel } + return { user, account, videoChannel } } async function createLocalAccountWithoutKeys (parameters: { @@ -73,7 +75,7 @@ async function createLocalAccountWithoutKeys (parameters: { const url = getAccountActivityPubUrl(name) const actorInstance = buildActorInstance(type, url, name) - const actorInstanceCreated = await actorInstance.save({ transaction: t }) + const actorInstanceCreated: MActor = await actorInstance.save({ transaction: t }) const accountInstance = new AccountModel({ name: displayName || name, @@ -82,7 +84,7 @@ async function createLocalAccountWithoutKeys (parameters: { actorId: actorInstanceCreated.id }) - const accountInstanceCreated = await accountInstance.save({ transaction: t }) + const accountInstanceCreated: MAccountActor = await accountInstance.save({ transaction: t }) accountInstanceCreated.Actor = actorInstanceCreated return accountInstanceCreated @@ -102,7 +104,7 @@ async function createApplicationActor (applicationId: number) { return accountCreated } -async function sendVerifyUserEmail (user: UserModel, isPendingEmail = false) { +async function sendVerifyUserEmail (user: MUser, isPendingEmail = false) { const verificationString = await Redis.Instance.setVerifyEmailVerificationString(user.id) let url = WEBSERVER.URL + '/verify-account/email?userId=' + user.id + '&verificationString=' + verificationString @@ -124,7 +126,7 @@ export { // --------------------------------------------------------------------------- -function createDefaultUserNotificationSettings (user: UserModel, t: Transaction | undefined) { +function createDefaultUserNotificationSettings (user: MUserId, t: Transaction | undefined) { const values: UserNotificationSetting & { userId: number } = { userId: user.id, newVideoFromSubscription: UserNotificationSettingValue.WEB, @@ -143,7 +145,7 @@ function createDefaultUserNotificationSettings (user: UserModel, t: Transaction return UserNotificationSettingModel.create(values, { transaction: t }) } -async function buildChannelAttributes (user: UserModel, channelNames?: ChannelNames) { +async function buildChannelAttributes (user: MUser, channelNames?: ChannelNames) { if (channelNames) return channelNames let channelName = user.username + '_channel' diff --git a/server/lib/video-blacklist.ts b/server/lib/video-blacklist.ts index bdaecd8e2..a0fc26e84 100644 --- a/server/lib/video-blacklist.ts +++ b/server/lib/video-blacklist.ts @@ -2,16 +2,15 @@ import { Transaction } from 'sequelize' import { CONFIG } from '../initializers/config' import { UserRight, VideoBlacklistType } from '../../shared/models' import { VideoBlacklistModel } from '../models/video/video-blacklist' -import { UserModel } from '../models/account/user' -import { VideoModel } from '../models/video/video' import { logger } from '../helpers/logger' import { UserAdminFlag } from '../../shared/models/users/user-flag.model' import { Hooks } from './plugins/hooks' import { Notifier } from './notifier' +import { MUser, MVideoBlacklist, MVideoWithBlacklistLight } from '@server/typings/models' async function autoBlacklistVideoIfNeeded (parameters: { - video: VideoModel, - user?: UserModel, + video: MVideoWithBlacklistLight, + user?: MUser, isRemote: boolean, isNew: boolean, notify?: boolean, @@ -32,7 +31,7 @@ async function autoBlacklistVideoIfNeeded (parameters: { reason: 'Auto-blacklisted. Moderator review required.', type: VideoBlacklistType.AUTO_BEFORE_PUBLISHED } - const [ videoBlacklist ] = await VideoBlacklistModel.findOrCreate({ + const [ videoBlacklist ] = await VideoBlacklistModel.findOrCreate({ where: { videoId: video.id }, @@ -49,10 +48,10 @@ async function autoBlacklistVideoIfNeeded (parameters: { } async function autoBlacklistNeeded (parameters: { - video: VideoModel, + video: MVideoWithBlacklistLight, isRemote: boolean, isNew: boolean, - user?: UserModel + user?: MUser }) { const { user, video, isRemote, isNew } = parameters diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index ee0482c36..ee8eb6568 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts @@ -1,12 +1,19 @@ import * as Sequelize from 'sequelize' import * as uuidv4 from 'uuid/v4' import { VideoChannelCreate } from '../../shared/models' -import { AccountModel } from '../models/account/account' import { VideoChannelModel } from '../models/video/video-channel' import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub' import { VideoModel } from '../models/video/video' +import { MAccountId, MChannelActor, MChannelId } from '../typings/models' -async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account: AccountModel, t: Sequelize.Transaction) { +type CustomVideoChannelModelAccount = MChannelActor & + { Account?: T } + +async function createVideoChannel ( + videoChannelInfo: VideoChannelCreate, + account: T, + t: Sequelize.Transaction +): Promise> { const uuid = uuidv4() const url = getVideoChannelActivityPubUrl(videoChannelInfo.name) const actorInstance = buildActorInstance('Group', url, videoChannelInfo.name, uuid) @@ -21,10 +28,10 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account actorId: actorInstanceCreated.id } - const videoChannel = VideoChannelModel.build(videoChannelData) + const videoChannel = new VideoChannelModel(videoChannelData) const options = { transaction: t } - const videoChannelCreated = await videoChannel.save(options) + const videoChannelCreated: CustomVideoChannelModelAccount = await videoChannel.save(options) as MChannelActor // Do not forget to add Account/Actor information to the created video channel videoChannelCreated.Account = account @@ -34,7 +41,7 @@ async function createVideoChannel (videoChannelInfo: VideoChannelCreate, account return videoChannelCreated } -async function federateAllVideosOfChannel (videoChannel: VideoChannelModel) { +async function federateAllVideosOfChannel (videoChannel: MChannelId) { const videoIds = await VideoModel.getAllIdsFromChannel(videoChannel) for (const videoId of videoIds) { diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts index 449aa74cb..bb811bd2c 100644 --- a/server/lib/video-comment.ts +++ b/server/lib/video-comment.ts @@ -1,17 +1,16 @@ import * as Sequelize from 'sequelize' import { ResultList } from '../../shared/models' import { VideoCommentThreadTree } from '../../shared/models/videos/video-comment.model' -import { AccountModel } from '../models/account/account' -import { VideoModel } from '../models/video/video' import { VideoCommentModel } from '../models/video/video-comment' import { getVideoCommentActivityPubUrl } from './activitypub' import { sendCreateVideoComment } from './activitypub/send' +import { MAccountDefault, MComment, MCommentOwnerVideoReply, MVideoFullLight } from '../typings/models' async function createVideoComment (obj: { text: string, - inReplyToComment: VideoCommentModel | null, - video: VideoModel - account: AccountModel + inReplyToComment: MComment | null, + video: MVideoFullLight, + account: MAccountDefault }, t: Sequelize.Transaction) { let originCommentId: number | null = null let inReplyToCommentId: number | null = null @@ -32,7 +31,7 @@ async function createVideoComment (obj: { comment.url = getVideoCommentActivityPubUrl(obj.video, comment) - const savedComment = await comment.save({ transaction: t }) + const savedComment: MCommentOwnerVideoReply = await comment.save({ transaction: t }) savedComment.InReplyToVideoComment = obj.inReplyToComment savedComment.Video = obj.video savedComment.Account = obj.account diff --git a/server/lib/video-playlist.ts b/server/lib/video-playlist.ts index 6e214e60f..29b70cfda 100644 --- a/server/lib/video-playlist.ts +++ b/server/lib/video-playlist.ts @@ -1,12 +1,13 @@ import * as Sequelize from 'sequelize' -import { AccountModel } from '../models/account/account' import { VideoPlaylistModel } from '../models/video/video-playlist' import { VideoPlaylistPrivacy } from '../../shared/models/videos/playlist/video-playlist-privacy.model' import { getVideoPlaylistActivityPubUrl } from './activitypub' import { VideoPlaylistType } from '../../shared/models/videos/playlist/video-playlist-type.model' +import { MAccount } from '../typings/models' +import { MVideoPlaylistOwner } from '../typings/models/video/video-playlist' -async function createWatchLaterPlaylist (account: AccountModel, t: Sequelize.Transaction) { - const videoPlaylist = new VideoPlaylistModel({ +async function createWatchLaterPlaylist (account: MAccount, t: Sequelize.Transaction) { + const videoPlaylist: MVideoPlaylistOwner = new VideoPlaylistModel({ name: 'Watch later', privacy: VideoPlaylistPrivacy.PRIVATE, type: VideoPlaylistType.WATCH_LATER, diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts index ba6b29163..a204c0c63 100644 --- a/server/lib/video-transcoding.ts +++ b/server/lib/video-transcoding.ts @@ -5,16 +5,16 @@ import { ensureDir, move, remove, stat } from 'fs-extra' import { logger } from '../helpers/logger' import { VideoResolution } from '../../shared/models/videos' import { VideoFileModel } from '../models/video/video-file' -import { VideoModel } from '../models/video/video' import { updateMasterHLSPlaylist, updateSha256Segments } from './hls' import { VideoStreamingPlaylistModel } from '../models/video/video-streaming-playlist' import { VideoStreamingPlaylistType } from '../../shared/models/videos/video-streaming-playlist.type' import { CONFIG } from '../initializers/config' +import { MVideoFile, MVideoWithFile, MVideoWithFileThumbnail } from '@server/typings/models' /** * Optimize the original video file and replace it. The resolution is not changed. */ -async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) { +async function optimizeVideofile (video: MVideoWithFile, inputVideoFileArg?: MVideoFile) { const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR const transcodeDirectory = CONFIG.STORAGE.TMP_DIR const newExtname = '.mp4' @@ -57,7 +57,7 @@ async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFi /** * Transcode the original video file to a lower resolution. */ -async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoResolution, isPortrait: boolean) { +async function transcodeOriginalVideofile (video: MVideoWithFile, resolution: VideoResolution, isPortrait: boolean) { const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR const transcodeDirectory = CONFIG.STORAGE.TMP_DIR const extname = '.mp4' @@ -87,7 +87,7 @@ async function transcodeOriginalVideofile (video: VideoModel, resolution: VideoR return onVideoFileTranscoding(video, newVideoFile, videoTranscodedPath, videoOutputPath) } -async function mergeAudioVideofile (video: VideoModel, resolution: VideoResolution) { +async function mergeAudioVideofile (video: MVideoWithFileThumbnail, resolution: VideoResolution) { const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR const transcodeDirectory = CONFIG.STORAGE.TMP_DIR const newExtname = '.mp4' @@ -117,7 +117,7 @@ async function mergeAudioVideofile (video: VideoModel, resolution: VideoResoluti return onVideoFileTranscoding(video, inputVideoFile, videoTranscodedPath, videoOutputPath) } -async function generateHlsPlaylist (video: VideoModel, resolution: VideoResolution, isPortraitMode: boolean) { +async function generateHlsPlaylist (video: MVideoWithFile, resolution: VideoResolution, isPortraitMode: boolean) { const baseHlsDirectory = join(HLS_STREAMING_PLAYLIST_DIRECTORY, video.uuid) await ensureDir(join(HLS_STREAMING_PLAYLIST_DIRECTORY, video.uuid)) @@ -165,14 +165,14 @@ export { // --------------------------------------------------------------------------- -async function onVideoFileTranscoding (video: VideoModel, videoFile: VideoFileModel, transcodingPath: string, outputPath: string) { +async function onVideoFileTranscoding (video: MVideoWithFile, videoFile: MVideoFile, transcodingPath: string, outputPath: string) { const stats = await stat(transcodingPath) const fps = await getVideoFileFPS(transcodingPath) await move(transcodingPath, outputPath) - videoFile.set('size', stats.size) - videoFile.set('fps', fps) + videoFile.size = stats.size + videoFile.fps = fps await video.createTorrentAndSetInfoHash(videoFile) -- cgit v1.2.3 From 96ca24f00e5ae5471dee9ee596489fe50af2b46f Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 20 Aug 2019 10:22:05 +0200 Subject: Fix tests --- server/lib/activitypub/videos.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 5c10f9764..035994da8 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -65,9 +65,7 @@ import { MVideoFile, MVideoFullLight, MVideoId, - MVideoTag, - MVideoThumbnail, - MVideoWithAllFiles + MVideoThumbnail } from '../../typings/models' import { MThumbnail } from '../../typings/models/video/thumbnail' -- cgit v1.2.3 From 0283eaac2a8e73006c66df3cf5bb9012e37450e5 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 20 Aug 2019 13:52:49 +0200 Subject: Cleanup model types --- server/lib/activitypub/actor.ts | 13 +++++++------ server/lib/activitypub/process/process-announce.ts | 4 ++-- server/lib/activitypub/process/process-create.ts | 4 ++-- server/lib/activitypub/video-comments.ts | 4 ++-- server/lib/activitypub/videos.ts | 12 ++++++------ server/lib/avatar.ts | 4 ++-- server/lib/emailer.ts | 6 ++---- .../lib/job-queue/handlers/activitypub-follow.ts | 17 +++++++++++++---- server/lib/job-queue/handlers/video-import.ts | 22 +++++++++++----------- server/lib/notifier.ts | 6 +++--- .../lib/schedulers/videos-redundancy-scheduler.ts | 4 +++- 11 files changed, 53 insertions(+), 43 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 7862b0f00..5201bdeef 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -24,15 +24,17 @@ import { ActorFetchByUrlType, fetchActorByUrl } from '../../helpers/actor' import { sequelizeTypescript } from '../../initializers/database' import { MAccount, + MAccountDefault, MActor, MActorAccountChannelId, + MActorAccountChannelIdActor, MActorAccountId, MActorDefault, MActorFull, + MActorFullActor, MActorId, - MActorAccountChannelIdActor, MChannel, - MActorFullActor, MAccountActorDefault, MChannelActorDefault, MChannelActorAccountDefault + MChannelAccountDefault } from '../../typings/models' // Set account keys, this could be long so process after the account creation and do not block the client @@ -374,12 +376,11 @@ function saveActorAndServerAndModelIfNotExist ( }) if (actorCreated.type === 'Person' || actorCreated.type === 'Application') { - actorCreated.Account = await saveAccount(actorCreated, result, t) as MAccountActorDefault + actorCreated.Account = await saveAccount(actorCreated, result, t) as MAccountDefault actorCreated.Account.Actor = actorCreated } else if (actorCreated.type === 'Group') { // Video channel - actorCreated.VideoChannel = await saveVideoChannel(actorCreated, result, ownerActor, t) as MChannelActorAccountDefault - actorCreated.VideoChannel.Actor = actorCreated - actorCreated.VideoChannel.Account = ownerActor.Account + const channel = await saveVideoChannel(actorCreated, result, ownerActor, t) + actorCreated.VideoChannel = Object.assign(channel, { Actor: actorCreated, Account: ownerActor.Account }) } actorCreated.Server = server diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index 91a9ad72c..7e22125d5 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -7,7 +7,7 @@ import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { Notifier } from '../../notifier' import { logger } from '../../../helpers/logger' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { MActorSignature, MVideoAccountAllFiles } from '../../../typings/models' +import { MActorSignature, MVideoAccountLightBlacklistAllFiles } from '../../../typings/models' async function processAnnounceActivity (options: APProcessorOptions) { const { activity, byActor: actorAnnouncer } = options @@ -28,7 +28,7 @@ export { async function processVideoShare (actorAnnouncer: MActorSignature, activity: ActivityAnnounce, notify: boolean) { const objectUri = typeof activity.object === 'string' ? activity.object : activity.object.id - let video: MVideoAccountAllFiles + let video: MVideoAccountLightBlacklistAllFiles let videoCreated: boolean try { diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index c45f09f52..bee853721 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -11,7 +11,7 @@ import { Notifier } from '../../notifier' import { PlaylistObject } from '../../../../shared/models/activitypub/objects/playlist-object' import { createOrUpdateVideoPlaylist } from '../playlist' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' -import { MActorSignature, MCommentOwnerVideo, MVideoAccountAllFiles } from '../../../typings/models' +import { MActorSignature, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../../typings/models' async function processCreateActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -81,7 +81,7 @@ async function processCreateVideoComment (activity: ActivityCreate, byActor: MAc if (!byAccount) throw new Error('Cannot create video comment with the non account actor ' + byActor.url) - let video: MVideoAccountAllFiles + let video: MVideoAccountLightBlacklistAllFiles let created: boolean let comment: MCommentOwnerVideo try { diff --git a/server/lib/activitypub/video-comments.ts b/server/lib/activitypub/video-comments.ts index 375ac0aad..3e8306fa4 100644 --- a/server/lib/activitypub/video-comments.ts +++ b/server/lib/activitypub/video-comments.ts @@ -7,7 +7,7 @@ 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' +import { MCommentOwner, MCommentOwnerVideo, MVideoAccountLightBlacklistAllFiles } from '../../typings/models/video' type ResolveThreadParams = { url: string, @@ -15,7 +15,7 @@ type ResolveThreadParams = { isVideo?: boolean, commentCreated?: boolean } -type ResolveThreadResult = Promise<{ video: MVideoAccountAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> +type ResolveThreadResult = Promise<{ video: MVideoAccountLightBlacklistAllFiles, comment: MCommentOwnerVideo, commentCreated: boolean }> async function addVideoComments (commentUrls: string[]) { return Bluebird.map(commentUrls, commentUrl => { diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 035994da8..970a953fc 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -58,7 +58,7 @@ import { MChannelDefault, MChannelId, MVideo, - MVideoAccountAllFiles, + MVideoAccountLightBlacklistAllFiles, MVideoAccountLight, MVideoAP, MVideoAPWithoutCaption, @@ -213,19 +213,19 @@ function getOrCreateVideoAndAccountAndChannel (options: { syncParam?: SyncParam, fetchType?: 'all', allowRefresh?: boolean -}): Promise<{ video: MVideoAccountAllFiles, created: boolean, autoBlacklisted?: boolean }> +}): Promise<{ video: MVideoAccountLightBlacklistAllFiles, 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 }> +}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | 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 }> { +}): Promise<{ video: MVideoAccountLightBlacklistAllFiles | 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' @@ -263,7 +263,7 @@ async function getOrCreateVideoAndAccountAndChannel (options: { } async function updateVideoFromAP (options: { - video: MVideoAccountAllFiles, + video: MVideoAccountLightBlacklistAllFiles, videoObject: VideoTorrentObject, account: MAccountActor, channel: MChannelDefault, @@ -420,7 +420,7 @@ async function refreshVideoIfNeeded (options: { // We need more attributes if the argument video was fetched with not enough joints const video = options.fetchedType === 'all' - ? options.video as MVideoAccountAllFiles + ? options.video as MVideoAccountLightBlacklistAllFiles : await VideoModel.loadByUrlAndPopulateAccount(options.video.url) try { diff --git a/server/lib/avatar.ts b/server/lib/avatar.ts index 9005b3e22..ad4cdd3ab 100644 --- a/server/lib/avatar.ts +++ b/server/lib/avatar.ts @@ -11,11 +11,11 @@ import { sequelizeTypescript } from '../initializers/database' import * as LRUCache from 'lru-cache' import { queue } from 'async' import { downloadImage } from '../helpers/requests' -import { MAccountActorDefault, MChannelActorDefault } from '../typings/models' +import { MAccountDefault, MChannelDefault } from '../typings/models' async function updateActorAvatarFile ( avatarPhysicalFile: Express.Multer.File, - accountOrChannel: MAccountActorDefault | MChannelActorDefault + accountOrChannel: MAccountDefault | MChannelDefault ) { const extension = extname(avatarPhysicalFile.filename) const avatarName = uuidv4() + extension diff --git a/server/lib/emailer.ts b/server/lib/emailer.ts index fe57a3e4c..a888b7a72 100644 --- a/server/lib/emailer.ts +++ b/server/lib/emailer.ts @@ -2,14 +2,12 @@ import { createTransport, Transporter } from 'nodemailer' import { isTestInstance } from '../helpers/core-utils' import { bunyanLogger, logger } from '../helpers/logger' import { CONFIG } from '../initializers/config' -import { UserModel } from '../models/account/user' import { JobQueue } from './job-queue' import { EmailPayload } from './job-queue/handlers/email' import { readFileSync } from 'fs-extra' -import { VideoBlacklistModel } from '../models/video/video-blacklist' import { WEBSERVER } from '../initializers/constants' import { MCommentOwnerVideo, MVideo, MVideoAbuseVideo, MVideoAccountLight, MVideoBlacklistVideo } from '../typings/models/video' -import { MActorFollowActors, MActorFollowFull, MUser } from '../typings/models' +import { MActorFollowActors, MActorFollowFollowingFullFollowerAccount, MUser } from '../typings/models' import { MVideoImport, MVideoImportVideo } from '@server/typings/models/video/video-import' type SendEmailOptions = { @@ -109,7 +107,7 @@ class Emailer { return JobQueue.Instance.createJob({ type: 'email', payload: emailPayload }) } - addNewFollowNotification (to: string[], actorFollow: MActorFollowFull, followType: 'account' | 'channel') { + addNewFollowNotification (to: string[], actorFollow: MActorFollowFollowingFullFollowerAccount, followType: 'account' | 'channel') { const followerName = actorFollow.ActorFollower.Account.getDisplayName() const followingName = (actorFollow.ActorFollowing.VideoChannel || actorFollow.ActorFollowing.Account).getDisplayName() diff --git a/server/lib/job-queue/handlers/activitypub-follow.ts b/server/lib/job-queue/handlers/activitypub-follow.ts index 741b1ffde..5cb55cad6 100644 --- a/server/lib/job-queue/handlers/activitypub-follow.ts +++ b/server/lib/job-queue/handlers/activitypub-follow.ts @@ -10,7 +10,7 @@ import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { ActorModel } from '../../../models/activitypub/actor' import { Notifier } from '../../notifier' import { sequelizeTypescript } from '../../../initializers/database' -import { MActorFollowFull, MActorFull } from '../../../typings/models' +import { MAccount, MActor, MActorFollowActors, MActorFollowFull, MActorFull } from '../../../typings/models' export type ActivitypubFollowPayload = { followerActorId: number @@ -45,7 +45,7 @@ export { // --------------------------------------------------------------------------- -async function follow (fromActor: MActorFull, targetActor: MActorFull) { +async function follow (fromActor: MActor, targetActor: MActorFull) { if (fromActor.id === targetActor.id) { throw new Error('Follower is the same than target actor.') } @@ -54,7 +54,7 @@ async function follow (fromActor: MActorFull, targetActor: MActorFull) { const state = !fromActor.serverId && !targetActor.serverId ? 'accepted' : 'pending' const actorFollow = await sequelizeTypescript.transaction(async t => { - const [ actorFollow ] = await ActorFollowModel.findOrCreate({ + const [ actorFollow ] = await ActorFollowModel.findOrCreate({ where: { actorId: fromActor.id, targetActorId: targetActor.id @@ -75,5 +75,14 @@ async function follow (fromActor: MActorFull, targetActor: MActorFull) { return actorFollow }) - if (actorFollow.state === 'accepted') Notifier.Instance.notifyOfNewUserFollow(actorFollow) + if (actorFollow.state === 'accepted') { + const followerFull = Object.assign(fromActor, { Account: await actorFollow.ActorFollower.$get('Account') as MAccount }) + + const actorFollowFull = Object.assign(actorFollow, { + ActorFollowing: targetActor, + ActorFollower: followerFull + }) + + Notifier.Instance.notifyOfNewUserFollow(actorFollowFull) + } } diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts index f9dda79f8..ff8c93328 100644 --- a/server/lib/job-queue/handlers/video-import.ts +++ b/server/lib/job-queue/handlers/video-import.ts @@ -111,13 +111,11 @@ type ProcessFileOptions = { generateThumbnail: boolean generatePreview: boolean } -async function processFile (downloader: () => Promise, videoImportArg: MVideoImportDefault, options: ProcessFileOptions) { +async function processFile (downloader: () => Promise, videoImport: MVideoImportDefault, options: ProcessFileOptions) { let tempVideoPath: string let videoDestFile: string let videoFile: VideoFileModel - const videoImport = videoImportArg as MVideoImportDefaultFiles - try { // Download video from youtubeDL tempVideoPath = await downloader() @@ -142,35 +140,37 @@ async function processFile (downloader: () => Promise, videoImportArg: M videoId: videoImport.videoId } videoFile = new VideoFileModel(videoFileData) + + const videoWithFiles = Object.assign(videoImport.Video, { VideoFiles: [ videoFile ] }) // To clean files if the import fails - videoImport.Video.VideoFiles = [ videoFile ] + const videoImportWithFiles: MVideoImportDefaultFiles = Object.assign(videoImport, { Video: videoWithFiles }) // Move file - videoDestFile = join(CONFIG.STORAGE.VIDEOS_DIR, videoImport.Video.getVideoFilename(videoFile)) + videoDestFile = join(CONFIG.STORAGE.VIDEOS_DIR, videoImportWithFiles.Video.getVideoFilename(videoFile)) await move(tempVideoPath, videoDestFile) tempVideoPath = null // This path is not used anymore // Process thumbnail let thumbnailModel: MThumbnail if (options.downloadThumbnail && options.thumbnailUrl) { - thumbnailModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImport.Video, ThumbnailType.MINIATURE) + thumbnailModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImportWithFiles.Video, ThumbnailType.MINIATURE) } else if (options.generateThumbnail || options.downloadThumbnail) { - thumbnailModel = await generateVideoMiniature(videoImport.Video, videoFile, ThumbnailType.MINIATURE) + thumbnailModel = await generateVideoMiniature(videoImportWithFiles.Video, videoFile, ThumbnailType.MINIATURE) } // Process preview let previewModel: MThumbnail if (options.downloadPreview && options.thumbnailUrl) { - previewModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImport.Video, ThumbnailType.PREVIEW) + previewModel = await createVideoMiniatureFromUrl(options.thumbnailUrl, videoImportWithFiles.Video, ThumbnailType.PREVIEW) } else if (options.generatePreview || options.downloadPreview) { - previewModel = await generateVideoMiniature(videoImport.Video, videoFile, ThumbnailType.PREVIEW) + previewModel = await generateVideoMiniature(videoImportWithFiles.Video, videoFile, ThumbnailType.PREVIEW) } // Create torrent - await videoImport.Video.createTorrentAndSetInfoHash(videoFile) + await videoImportWithFiles.Video.createTorrentAndSetInfoHash(videoFile) const { videoImportUpdated, video } = await sequelizeTypescript.transaction(async t => { - const videoImportToUpdate = videoImport as MVideoImportVideo + const videoImportToUpdate = videoImportWithFiles as MVideoImportVideo // Refresh video const video = await VideoModel.load(videoImportToUpdate.videoId, t) diff --git a/server/lib/notifier.ts b/server/lib/notifier.ts index f01101b8e..23f76a21a 100644 --- a/server/lib/notifier.ts +++ b/server/lib/notifier.ts @@ -21,7 +21,7 @@ import { MVideoFullLight } from '../typings/models/video' import { MUser, MUserAccount, MUserWithNotificationSetting, UserNotificationModelForApi } from '@server/typings/models/user' -import { MActorFollowActors, MActorFollowFull } from '../typings/models' +import { MActorFollowActors, MActorFollowFull, MActorFollowFollowingFullFollowerAccount } from '../typings/models' import { ActorFollowModel } from '../models/activitypub/actor-follow' import { MVideoImportVideo } from '@server/typings/models/video/video-import' import { AccountModel } from '@server/models/account/account' @@ -102,7 +102,7 @@ class Notifier { .catch(err => logger.error('Cannot notify moderators of new user registration (%s).', user.username, { err })) } - notifyOfNewUserFollow (actorFollow: MActorFollowFull): void { + notifyOfNewUserFollow (actorFollow: MActorFollowFollowingFullFollowerAccount): void { this.notifyUserOfNewActorFollow(actorFollow) .catch(err => { logger.error( @@ -231,7 +231,7 @@ class Notifier { return this.notify({ users, settingGetter, notificationCreator, emailSender }) } - private async notifyUserOfNewActorFollow (actorFollow: MActorFollowFull) { + private async notifyUserOfNewActorFollow (actorFollow: MActorFollowFollowingFullFollowerAccount) { if (actorFollow.ActorFollowing.isOwned() === false) return // Account follows one of our account? diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index de8fc075b..d9018e606 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts @@ -32,7 +32,9 @@ type CandidateToDuplicate = { streamingPlaylists: MStreamingPlaylist[] } -function isMVideoRedundancyFileVideo (o: MVideoRedundancyVideo): o is MVideoRedundancyFileVideo { +function isMVideoRedundancyFileVideo ( + o: MVideoRedundancyFileVideo | MVideoRedundancyStreamingPlaylistVideo +): o is MVideoRedundancyFileVideo { return !!(o as MVideoRedundancyFileVideo).VideoFile } -- cgit v1.2.3 From 1ca9f7c3f7afac2af4c4c25b98426731f7e789c6 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Tue, 20 Aug 2019 19:05:31 +0200 Subject: Type toFormattedJSON --- server/lib/activitypub/actor.ts | 4 ++-- server/lib/user.ts | 19 +++++++++---------- server/lib/video-channel.ts | 10 +++++----- 3 files changed, 16 insertions(+), 17 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index 5201bdeef..13b73077e 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts @@ -38,7 +38,7 @@ import { } 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: MActor) { +function setAsyncActorKeys (actor: T) { return createPrivateAndPublicKeys() .then(({ publicKey, privateKey }) => { actor.publicKey = publicKey @@ -148,7 +148,7 @@ function buildActorInstance (type: ActivityPubActorType, url: string, preferredU sharedInboxUrl: WEBSERVER.URL + '/inbox', followersUrl: url + '/followers', followingUrl: url + '/following' - }) + }) as MActor } async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) { diff --git a/server/lib/user.ts b/server/lib/user.ts index 266974cac..d84aff464 100644 --- a/server/lib/user.ts +++ b/server/lib/user.ts @@ -2,9 +2,8 @@ import * as uuidv4 from 'uuid/v4' import { ActivityPubActorType } from '../../shared/models/activitypub' import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants' import { AccountModel } from '../models/account/account' -import { UserModel } from '../models/account/user' import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub' -import { createVideoChannel } from './video-channel' +import { createLocalVideoChannel } from './video-channel' import { ActorModel } from '../models/activitypub/actor' import { UserNotificationSettingModel } from '../models/account/user-notification-setting' import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users' @@ -13,17 +12,17 @@ import { sequelizeTypescript } from '../initializers/database' import { Transaction } from 'sequelize/types' import { Redis } from './redis' import { Emailer } from './emailer' -import { MAccountActor, MActor, MChannelActor } from '../typings/models' -import { MUser, MUserId, MUserNotifSettingAccount } from '../typings/models/user' +import { MAccountDefault, MActorDefault, MChannelActor } from '../typings/models' +import { MUser, MUserDefault, MUserId } from '../typings/models/user' type ChannelNames = { name: string, displayName: string } async function createUserAccountAndChannelAndPlaylist (parameters: { - userToCreate: UserModel, + userToCreate: MUser, userDisplayName?: string, channelNames?: ChannelNames, validateUser?: boolean -}): Promise<{ user: MUserNotifSettingAccount, account: MAccountActor, videoChannel: MChannelActor }> { +}): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> { const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => { @@ -32,7 +31,7 @@ async function createUserAccountAndChannelAndPlaylist (parameters: { validate: validateUser } - const userCreated: MUserNotifSettingAccount = await userToCreate.save(userOptions) + const userCreated: MUserDefault = await userToCreate.save(userOptions) userCreated.NotificationSetting = await createDefaultUserNotificationSettings(userCreated, t) const accountCreated = await createLocalAccountWithoutKeys({ @@ -45,7 +44,7 @@ async function createUserAccountAndChannelAndPlaylist (parameters: { userCreated.Account = accountCreated const channelAttributes = await buildChannelAttributes(userCreated, channelNames) - const videoChannel = await createVideoChannel(channelAttributes, accountCreated, t) + const videoChannel = await createLocalVideoChannel(channelAttributes, accountCreated, t) const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t) @@ -75,7 +74,7 @@ async function createLocalAccountWithoutKeys (parameters: { const url = getAccountActivityPubUrl(name) const actorInstance = buildActorInstance(type, url, name) - const actorInstanceCreated: MActor = await actorInstance.save({ transaction: t }) + const actorInstanceCreated: MActorDefault = await actorInstance.save({ transaction: t }) const accountInstance = new AccountModel({ name: displayName || name, @@ -84,7 +83,7 @@ async function createLocalAccountWithoutKeys (parameters: { actorId: actorInstanceCreated.id }) - const accountInstanceCreated: MAccountActor = await accountInstance.save({ transaction: t }) + const accountInstanceCreated: MAccountDefault = await accountInstance.save({ transaction: t }) accountInstanceCreated.Actor = actorInstanceCreated return accountInstanceCreated diff --git a/server/lib/video-channel.ts b/server/lib/video-channel.ts index ee8eb6568..41eab456b 100644 --- a/server/lib/video-channel.ts +++ b/server/lib/video-channel.ts @@ -4,12 +4,12 @@ import { VideoChannelCreate } from '../../shared/models' import { VideoChannelModel } from '../models/video/video-channel' import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub' import { VideoModel } from '../models/video/video' -import { MAccountId, MChannelActor, MChannelId } from '../typings/models' +import { MAccountId, MChannelDefault, MChannelId } from '../typings/models' -type CustomVideoChannelModelAccount = MChannelActor & +type CustomVideoChannelModelAccount = MChannelDefault & { Account?: T } -async function createVideoChannel ( +async function createLocalVideoChannel ( videoChannelInfo: VideoChannelCreate, account: T, t: Sequelize.Transaction @@ -31,7 +31,7 @@ async function createVideoChannel ( const videoChannel = new VideoChannelModel(videoChannelData) const options = { transaction: t } - const videoChannelCreated: CustomVideoChannelModelAccount = await videoChannel.save(options) as MChannelActor + const videoChannelCreated: CustomVideoChannelModelAccount = await videoChannel.save(options) as MChannelDefault // Do not forget to add Account/Actor information to the created video channel videoChannelCreated.Account = account @@ -54,6 +54,6 @@ async function federateAllVideosOfChannel (videoChannel: MChannelId) { // --------------------------------------------------------------------------- export { - createVideoChannel, + createLocalVideoChannel, federateAllVideosOfChannel } -- cgit v1.2.3 From f92e7f76d43cbad173be87f47105b9a02032318a Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 21 Aug 2019 08:57:00 +0200 Subject: Fix ownership change --- server/lib/activitypub/process/process-update.ts | 7 +++++-- server/lib/activitypub/videos.ts | 6 +++--- 2 files changed, 8 insertions(+), 5 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 9f80a0ce9..a47d605d8 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 { MActorSignature } from '../../../typings/models' +import { MActorSignature, MAccountIdActor } from '../../../typings/models' async function processUpdateActivity (options: APProcessorOptions) { const { activity, byActor } = options @@ -64,10 +64,13 @@ async function processUpdateVideo (actor: MActorSignature, activity: ActivityUpd const { video } = await getOrCreateVideoAndAccountAndChannel({ videoObject: videoObject.id, allowRefresh: false, fetchType: 'all' }) const channelActor = await getOrCreateVideoChannelFromVideoObject(videoObject) + const account = actor.Account as MAccountIdActor + account.Actor = actor + const updateOptions = { video, videoObject, - account: channelActor.VideoChannel.Account, + account, channel: channelActor.VideoChannel, overrideTo: activity.to } diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index 970a953fc..c318978fd 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts @@ -53,13 +53,13 @@ import { FilteredModelAttributes } from '../../typings/sequelize' import { autoBlacklistVideoIfNeeded } from '../video-blacklist' import { ActorFollowScoreCache } from '../files-cache' import { - MAccountActor, + MAccountIdActor, MChannelAccountLight, MChannelDefault, MChannelId, MVideo, - MVideoAccountLightBlacklistAllFiles, MVideoAccountLight, + MVideoAccountLightBlacklistAllFiles, MVideoAP, MVideoAPWithoutCaption, MVideoFile, @@ -265,7 +265,7 @@ async function getOrCreateVideoAndAccountAndChannel (options: { async function updateVideoFromAP (options: { video: MVideoAccountLightBlacklistAllFiles, videoObject: VideoTorrentObject, - account: MAccountActor, + account: MAccountIdActor, channel: MChannelDefault, overrideTo?: string[] }) { -- cgit v1.2.3 From b5fecbf44192144d1ca27c23a0b53922de288c10 Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Wed, 21 Aug 2019 14:31:57 +0200 Subject: Type toActivityPubObject functions --- server/lib/activitypub/send/send-update.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/send/send-update.ts b/server/lib/activitypub/send/send-update.ts index 3a5cc1853..37517c2be 100644 --- a/server/lib/activitypub/send/send-update.ts +++ b/server/lib/activitypub/send/send-update.ts @@ -12,10 +12,10 @@ import { VideoCaptionModel } from '../../../models/video/video-caption' import { VideoPlaylistPrivacy } from '../../../../shared/models/videos/playlist/video-playlist-privacy.model' import { getServerActor } from '../../../helpers/utils' import { - MAccountActor, + MAccountDefault, MActor, MActorLight, - MChannelActor, + MChannelDefault, MVideoAP, MVideoAPWithoutCaption, MVideoPlaylistFull, @@ -49,7 +49,7 @@ async function sendUpdateVideo (videoArg: MVideoAPWithoutCaption, t: Transaction return broadcastToFollowers(updateActivity, byActor, actorsInvolved, t) } -async function sendUpdateActor (accountOrChannel: MAccountActor | MChannelActor, t: Transaction) { +async function sendUpdateActor (accountOrChannel: MChannelDefault | MAccountDefault, t: Transaction) { const byActor = accountOrChannel.Actor logger.info('Creating job to update actor %s.', byActor.url) -- cgit v1.2.3