1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-04 02:09:37 +02:00

Implement auto tag on comments and videos

* Comments and videos can be automatically tagged using core rules or
   watched word lists
 * These tags can be used to automatically filter videos and comments
 * Introduce a new video comment policy where comments must be approved
   first
 * Comments may have to be approved if the user auto block them using
   core rules or watched word lists
 * Implement FEP-5624 to federate reply control policies
This commit is contained in:
Chocobozzz 2024-03-29 14:25:03 +01:00 committed by Chocobozzz
parent b3e39df59e
commit 29329d6c45
241 changed files with 8090 additions and 1399 deletions

View file

@ -1,30 +1,45 @@
import { pick } from '@peertube/peertube-core-utils'
import { HttpStatusCode, ResultList, VideoComment, VideoCommentThreads, VideoCommentThreadTree } from '@peertube/peertube-models'
import {
HttpStatusCode,
ResultList,
VideoComment,
VideoCommentForAdminOrUser,
VideoCommentThreads,
VideoCommentThreadTree
} from '@peertube/peertube-models'
import { unwrapBody } from '../requests/index.js'
import { AbstractCommand, OverrideCommandOptions } from '../shared/index.js'
type ListForAdminOrAccountCommonOptions = {
start?: number
count?: number
sort?: string
search?: string
searchAccount?: string
searchVideo?: string
videoId?: string | number
videoChannelId?: string | number
autoTagOneOf?: string[]
}
export class CommentsCommand extends AbstractCommand {
private lastVideoId: number | string
private lastThreadId: number
private lastReplyId: number
listForAdmin (options: OverrideCommandOptions & {
start?: number
count?: number
sort?: string
listForAdmin (options: OverrideCommandOptions & ListForAdminOrAccountCommonOptions & {
isLocal?: boolean
onLocalVideo?: boolean
search?: string
searchAccount?: string
searchVideo?: string
} = {}) {
const { sort = '-createdAt' } = options
const path = '/api/v1/videos/comments'
const query = { sort, ...pick(options, [ 'start', 'count', 'isLocal', 'onLocalVideo', 'search', 'searchAccount', 'searchVideo' ]) }
const query = {
...this.buildListForAdminOrAccountQuery(options),
...pick(options, [ 'isLocal', 'onLocalVideo' ])
}
return this.getRequestBody<ResultList<VideoComment>>({
return this.getRequestBody<ResultList<VideoCommentForAdminOrUser>>({
...options,
path,
@ -34,6 +49,35 @@ export class CommentsCommand extends AbstractCommand {
})
}
listCommentsOnMyVideos (options: OverrideCommandOptions & ListForAdminOrAccountCommonOptions & {
isHeldForReview?: boolean
} = {}) {
const path = '/api/v1/users/me/videos/comments'
return this.getRequestBody<ResultList<VideoCommentForAdminOrUser>>({
...options,
path,
query: {
...this.buildListForAdminOrAccountQuery(options),
isHeldForReview: options.isHeldForReview
},
implicitToken: true,
defaultExpectedStatus: HttpStatusCode.OK_200
})
}
private buildListForAdminOrAccountQuery (options: ListForAdminOrAccountCommonOptions) {
return {
sort: '-createdAt',
...pick(options, [ 'start', 'count', 'search', 'searchAccount', 'searchVideo', 'sort', 'videoId', 'videoChannelId', 'autoTagOneOf' ])
}
}
// ---------------------------------------------------------------------------
listThreads (options: OverrideCommandOptions & {
videoId: number | string
videoPassword?: string
@ -71,6 +115,16 @@ export class CommentsCommand extends AbstractCommand {
})
}
async getThreadOf (options: OverrideCommandOptions & {
videoId: number | string
text: string
}) {
const { videoId, text } = options
const threadId = await this.findCommentId({ videoId, text })
return this.getThread({ ...options, videoId, threadId })
}
async createThread (options: OverrideCommandOptions & {
videoId: number | string
text: string
@ -136,11 +190,13 @@ export class CommentsCommand extends AbstractCommand {
text: string
}) {
const { videoId, text } = options
const { data } = await this.listThreads({ videoId, count: 25, sort: '-createdAt' })
const { data } = await this.listForAdmin({ videoId, count: 25, sort: '-createdAt' })
return data.find(c => c.text === text).id
}
// ---------------------------------------------------------------------------
delete (options: OverrideCommandOptions & {
videoId: number | string
commentId: number
@ -156,4 +212,34 @@ export class CommentsCommand extends AbstractCommand {
defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
})
}
async deleteAllComments (options: OverrideCommandOptions & {
videoUUID: string
}) {
const { data } = await this.listForAdmin({ ...options, start: 0, count: 20 })
for (const comment of data) {
if (comment?.video.uuid !== options.videoUUID) continue
await this.delete({ videoId: options.videoUUID, commentId: comment.id, ...options })
}
}
// ---------------------------------------------------------------------------
approve (options: OverrideCommandOptions & {
videoId: number | string
commentId: number
}) {
const { videoId, commentId } = options
const path = '/api/v1/videos/' + videoId + '/comments/' + commentId + '/approve'
return this.postBodyRequest({
...options,
path,
implicitToken: true,
defaultExpectedStatus: HttpStatusCode.NO_CONTENT_204
})
}
}