From 80fdaf064562aff968f4c9cea1cf220bc12a70da Mon Sep 17 00:00:00 2001 From: Chocobozzz Date: Thu, 7 May 2020 14:58:24 +0200 Subject: Add moderation helpers to plugins --- server/lib/activitypub/process/process-announce.ts | 2 +- server/lib/activitypub/process/process-create.ts | 2 +- server/lib/activitypub/process/process-delete.ts | 2 +- server/lib/activitypub/process/process-dislike.ts | 2 +- server/lib/activitypub/process/process-flag.ts | 2 +- server/lib/activitypub/process/process-follow.ts | 2 +- server/lib/activitypub/process/process-like.ts | 2 +- server/lib/activitypub/process/process-reject.ts | 2 +- server/lib/activitypub/process/process-undo.ts | 2 +- server/lib/activitypub/process/process-update.ts | 2 +- server/lib/blocklist.ts | 4 +- server/lib/job-queue/handlers/video-transcoding.ts | 2 +- server/lib/plugins/plugin-helpers.ts | 78 ++++++++++++++++++++- server/lib/video-blacklist.ts | 80 +++++++++++++++++++--- 14 files changed, 159 insertions(+), 25 deletions(-) (limited to 'server/lib') diff --git a/server/lib/activitypub/process/process-announce.ts b/server/lib/activitypub/process/process-announce.ts index 7e22125d5..26427aaa1 100644 --- a/server/lib/activitypub/process/process-announce.ts +++ b/server/lib/activitypub/process/process-announce.ts @@ -1,6 +1,6 @@ import { ActivityAnnounce } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { VideoShareModel } from '../../../models/video/video-share' import { forwardVideoRelatedActivity } from '../send/utils' import { getOrCreateVideoAndAccountAndChannel } from '../videos' diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index d375e29e3..566bf6992 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts @@ -2,7 +2,7 @@ import { ActivityCreate, CacheFileObject, VideoTorrentObject } from '../../../.. import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { resolveThread } from '../video-comments' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' diff --git a/server/lib/activitypub/process/process-delete.ts b/server/lib/activitypub/process/process-delete.ts index e76132f91..7c8dc83e8 100644 --- a/server/lib/activitypub/process/process-delete.ts +++ b/server/lib/activitypub/process/process-delete.ts @@ -1,7 +1,7 @@ import { ActivityDelete } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { ActorModel } from '../../../models/activitypub/actor' import { VideoModel } from '../../../models/video/video' import { VideoCommentModel } from '../../../models/video/video-comment' diff --git a/server/lib/activitypub/process/process-dislike.ts b/server/lib/activitypub/process/process-dislike.ts index debd8a67c..fcdd0b86e 100644 --- a/server/lib/activitypub/process/process-dislike.ts +++ b/server/lib/activitypub/process/process-dislike.ts @@ -1,7 +1,7 @@ import { ActivityCreate, ActivityDislike } from '../../../../shared' import { DislikeObject } from '../../../../shared/models/activitypub/objects' import { retryTransactionWrapper } from '../../../helpers/database-utils' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { forwardVideoRelatedActivity } from '../send/utils' diff --git a/server/lib/activitypub/process/process-flag.ts b/server/lib/activitypub/process/process-flag.ts index e6e9084de..9a488a473 100644 --- a/server/lib/activitypub/process/process-flag.ts +++ b/server/lib/activitypub/process/process-flag.ts @@ -2,7 +2,7 @@ import { ActivityCreate, ActivityFlag, VideoAbuseState } from '../../../../share import { VideoAbuseObject } from '../../../../shared/models/activitypub/objects' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { VideoAbuseModel } from '../../../models/video/video-abuse' import { getOrCreateVideoAndAccountAndChannel } from '../videos' import { Notifier } from '../../notifier' diff --git a/server/lib/activitypub/process/process-follow.ts b/server/lib/activitypub/process/process-follow.ts index 8f7828e41..950d421dd 100644 --- a/server/lib/activitypub/process/process-follow.ts +++ b/server/lib/activitypub/process/process-follow.ts @@ -1,7 +1,7 @@ import { ActivityFollow } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { ActorModel } from '../../../models/activitypub/actor' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { sendAccept, sendReject } from '../send' diff --git a/server/lib/activitypub/process/process-like.ts b/server/lib/activitypub/process/process-like.ts index 62be0de42..fba3c76a4 100644 --- a/server/lib/activitypub/process/process-like.ts +++ b/server/lib/activitypub/process/process-like.ts @@ -1,6 +1,6 @@ import { ActivityLike } from '../../../../shared/models/activitypub' import { retryTransactionWrapper } from '../../../helpers/database-utils' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { forwardVideoRelatedActivity } from '../send/utils' import { getOrCreateVideoAndAccountAndChannel } from '../videos' diff --git a/server/lib/activitypub/process/process-reject.ts b/server/lib/activitypub/process/process-reject.ts index 00e9afa10..9804436a2 100644 --- a/server/lib/activitypub/process/process-reject.ts +++ b/server/lib/activitypub/process/process-reject.ts @@ -1,5 +1,5 @@ import { ActivityReject } from '../../../../shared/models/activitypub/activity' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' import { APProcessorOptions } from '../../../typings/activitypub-processor.model' import { MActor } from '../../../typings/models' diff --git a/server/lib/activitypub/process/process-undo.ts b/server/lib/activitypub/process/process-undo.ts index 10643b2e9..9ef6a8a97 100644 --- a/server/lib/activitypub/process/process-undo.ts +++ b/server/lib/activitypub/process/process-undo.ts @@ -2,7 +2,7 @@ import { ActivityAnnounce, ActivityFollow, ActivityLike, ActivityUndo, CacheFile import { DislikeObject } from '../../../../shared/models/activitypub/objects' import { retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { AccountVideoRateModel } from '../../../models/account/account-video-rate' import { ActorModel } from '../../../models/activitypub/actor' import { ActorFollowModel } from '../../../models/activitypub/actor-follow' diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 9579512b7..98ab0f83d 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts @@ -2,7 +2,7 @@ import { ActivityUpdate, CacheFileObject, VideoTorrentObject } from '../../../.. import { ActivityPubActor } from '../../../../shared/models/activitypub/activitypub-actor' import { resetSequelizeInstance, retryTransactionWrapper } from '../../../helpers/database-utils' import { logger } from '../../../helpers/logger' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { AccountModel } from '../../../models/account/account' import { ActorModel } from '../../../models/activitypub/actor' import { VideoChannelModel } from '../../../models/video/video-channel' diff --git a/server/lib/blocklist.ts b/server/lib/blocklist.ts index 28c69b46e..842eecb5b 100644 --- a/server/lib/blocklist.ts +++ b/server/lib/blocklist.ts @@ -1,7 +1,7 @@ -import { sequelizeTypescript } from '../initializers' +import { sequelizeTypescript } from '@server/initializers/database' +import { MAccountBlocklist, MServerBlocklist } from '@server/typings/models' 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 => { diff --git a/server/lib/job-queue/handlers/video-transcoding.ts b/server/lib/job-queue/handlers/video-transcoding.ts index 04aac515f..46d52e1cf 100644 --- a/server/lib/job-queue/handlers/video-transcoding.ts +++ b/server/lib/job-queue/handlers/video-transcoding.ts @@ -10,7 +10,7 @@ import { VideoModel } from '../../../models/video/video' import { JobQueue } from '../job-queue' import { federateVideoIfNeeded } from '../../activitypub/videos' import { retryTransactionWrapper } from '../../../helpers/database-utils' -import { sequelizeTypescript } from '../../../initializers' +import { sequelizeTypescript } from '../../../initializers/database' import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' import { generateHlsPlaylist, mergeAudioVideofile, optimizeOriginalVideofile, transcodeNewResolution } from '../../video-transcoding' import { Notifier } from '../../notifier' diff --git a/server/lib/plugins/plugin-helpers.ts b/server/lib/plugins/plugin-helpers.ts index 608207e05..de82b4918 100644 --- a/server/lib/plugins/plugin-helpers.ts +++ b/server/lib/plugins/plugin-helpers.ts @@ -3,6 +3,15 @@ import { sequelizeTypescript } from '@server/initializers/database' import { buildLogger } from '@server/helpers/logger' import { VideoModel } from '@server/models/video/video' import { WEBSERVER } from '@server/initializers/constants' +import { ServerModel } from '@server/models/server/server' +import { getServerActor } from '@server/models/application/application' +import { addServerInBlocklist, removeServerFromBlocklist, addAccountInBlocklist, removeAccountFromBlocklist } from '../blocklist' +import { ServerBlocklistModel } from '@server/models/server/server-blocklist' +import { AccountModel } from '@server/models/account/account' +import { VideoBlacklistCreate } from '@shared/models' +import { blacklistVideo, unblacklistVideo } from '../video-blacklist' +import { VideoBlacklistModel } from '@server/models/video/video-blacklist' +import { AccountBlocklistModel } from '@server/models/account/account-blocklist' function buildPluginHelpers (npmName: string): PeerTubeHelpers { const logger = buildPluginLogger(npmName) @@ -12,11 +21,17 @@ function buildPluginHelpers (npmName: string): PeerTubeHelpers { const config = buildConfigHelpers() + const server = buildServerHelpers() + + const moderation = buildModerationHelpers() + return { logger, database, videos, - config + config, + moderation, + server } } @@ -36,8 +51,18 @@ function buildDatabaseHelpers () { } } +function buildServerHelpers () { + return { + getServerActor: () => getServerActor() + } +} + function buildVideosHelpers () { return { + loadByUrl: (url: string) => { + return VideoModel.loadByUrl(url) + }, + removeVideo: (id: number) => { return sequelizeTypescript.transaction(async t => { const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(id, t) @@ -48,6 +73,57 @@ function buildVideosHelpers () { } } +function buildModerationHelpers () { + return { + blockServer: async (options: { byAccountId: number, hostToBlock: string }) => { + const serverToBlock = await ServerModel.loadOrCreateByHost(options.hostToBlock) + + await addServerInBlocklist(options.byAccountId, serverToBlock.id) + }, + + unblockServer: async (options: { byAccountId: number, hostToUnblock: string }) => { + const serverBlock = await ServerBlocklistModel.loadByAccountAndHost(options.byAccountId, options.hostToUnblock) + if (!serverBlock) return + + await removeServerFromBlocklist(serverBlock) + }, + + blockAccount: async (options: { byAccountId: number, handleToBlock: string }) => { + const accountToBlock = await AccountModel.loadByNameWithHost(options.handleToBlock) + if (!accountToBlock) return + + await addAccountInBlocklist(options.byAccountId, accountToBlock.id) + }, + + unblockAccount: async (options: { byAccountId: number, handleToUnblock: string }) => { + const targetAccount = await AccountModel.loadByNameWithHost(options.handleToUnblock) + if (!targetAccount) return + + const accountBlock = await AccountBlocklistModel.loadByAccountAndTarget(options.byAccountId, targetAccount.id) + if (!accountBlock) return + + await removeAccountFromBlocklist(accountBlock) + }, + + blacklistVideo: async (options: { videoIdOrUUID: number | string, createOptions: VideoBlacklistCreate }) => { + const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(options.videoIdOrUUID) + if (!video) return + + await blacklistVideo(video, options.createOptions) + }, + + unblacklistVideo: async (options: { videoIdOrUUID: number | string }) => { + const video = await VideoModel.loadAndPopulateAccountAndServerAndTags(options.videoIdOrUUID) + if (!video) return + + const videoBlacklist = await VideoBlacklistModel.loadByVideoId(video.id) + if (!videoBlacklist) return + + await unblacklistVideo(videoBlacklist, video) + } + } +} + function buildConfigHelpers () { return { getWebserverUrl () { diff --git a/server/lib/video-blacklist.ts b/server/lib/video-blacklist.ts index 3b90b1b94..bd60c6201 100644 --- a/server/lib/video-blacklist.ts +++ b/server/lib/video-blacklist.ts @@ -1,12 +1,22 @@ import { Transaction } from 'sequelize' +import { sequelizeTypescript } from '@server/initializers/database' +import { + MUser, + MVideoAccountLight, + MVideoBlacklist, + MVideoBlacklistVideo, + MVideoFullLight, + MVideoWithBlacklistLight +} from '@server/typings/models' +import { UserRight, VideoBlacklistCreate, VideoBlacklistType } from '../../shared/models' +import { UserAdminFlag } from '../../shared/models/users/user-flag.model' +import { logger } from '../helpers/logger' import { CONFIG } from '../initializers/config' -import { UserRight, VideoBlacklistType } from '../../shared/models' import { VideoBlacklistModel } from '../models/video/video-blacklist' -import { logger } from '../helpers/logger' -import { UserAdminFlag } from '../../shared/models/users/user-flag.model' -import { Hooks } from './plugins/hooks' +import { sendDeleteVideo } from './activitypub/send' +import { federateVideoIfNeeded } from './activitypub/videos' import { Notifier } from './notifier' -import { MUser, MVideoBlacklistVideo, MVideoWithBlacklistLight } from '@server/typings/models' +import { Hooks } from './plugins/hooks' async function autoBlacklistVideoIfNeeded (parameters: { video: MVideoWithBlacklistLight @@ -49,6 +59,60 @@ async function autoBlacklistVideoIfNeeded (parameters: { return true } +async function blacklistVideo (videoInstance: MVideoAccountLight, options: VideoBlacklistCreate) { + const blacklist: MVideoBlacklistVideo = await VideoBlacklistModel.create({ + videoId: videoInstance.id, + unfederated: options.unfederate === true, + reason: options.reason, + type: VideoBlacklistType.MANUAL + } + ) + blacklist.Video = videoInstance + + if (options.unfederate === true) { + await sendDeleteVideo(videoInstance, undefined) + } + + Notifier.Instance.notifyOnVideoBlacklist(blacklist) +} + +async function unblacklistVideo (videoBlacklist: MVideoBlacklist, video: MVideoFullLight) { + const videoBlacklistType = await sequelizeTypescript.transaction(async t => { + const unfederated = videoBlacklist.unfederated + const videoBlacklistType = videoBlacklist.type + + await videoBlacklist.destroy({ transaction: t }) + video.VideoBlacklist = undefined + + // Re federate the video + if (unfederated === true) { + await federateVideoIfNeeded(video, true, t) + } + + return videoBlacklistType + }) + + Notifier.Instance.notifyOnVideoUnblacklist(video) + + if (videoBlacklistType === VideoBlacklistType.AUTO_BEFORE_PUBLISHED) { + Notifier.Instance.notifyOnVideoPublishedAfterRemovedFromAutoBlacklist(video) + + // Delete on object so new video notifications will send + delete video.VideoBlacklist + Notifier.Instance.notifyOnNewVideoIfNeeded(video) + } +} + +// --------------------------------------------------------------------------- + +export { + autoBlacklistVideoIfNeeded, + blacklistVideo, + unblacklistVideo +} + +// --------------------------------------------------------------------------- + function autoBlacklistNeeded (parameters: { video: MVideoWithBlacklistLight isRemote: boolean @@ -66,9 +130,3 @@ function autoBlacklistNeeded (parameters: { return true } - -// --------------------------------------------------------------------------- - -export { - autoBlacklistVideoIfNeeded -} -- cgit v1.2.3