diff options
Diffstat (limited to 'server/models/video/video-comment.ts')
-rw-r--r-- | server/models/video/video-comment.ts | 132 |
1 files changed, 128 insertions, 4 deletions
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index de27b3d87..70aed75d6 100644 --- a/server/models/video/video-comment.ts +++ b/server/models/video/video-comment.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import * as Bluebird from 'bluebird' | 1 | import * as Bluebird from 'bluebird' |
2 | import { uniq } from 'lodash' | 2 | import { uniq } from 'lodash' |
3 | import { FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction, WhereOptions } from 'sequelize' | 3 | import { FindAndCountOptions, FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction, WhereOptions } from 'sequelize' |
4 | import { | 4 | import { |
5 | AllowNull, | 5 | AllowNull, |
6 | BelongsTo, | 6 | BelongsTo, |
@@ -20,13 +20,14 @@ import { MAccount, MAccountId, MUserAccountId } from '@server/types/models' | |||
20 | import { VideoPrivacy } from '@shared/models' | 20 | import { VideoPrivacy } from '@shared/models' |
21 | import { ActivityTagObject, ActivityTombstoneObject } from '../../../shared/models/activitypub/objects/common-objects' | 21 | import { ActivityTagObject, ActivityTombstoneObject } from '../../../shared/models/activitypub/objects/common-objects' |
22 | import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' | 22 | import { VideoCommentObject } from '../../../shared/models/activitypub/objects/video-comment-object' |
23 | import { VideoComment } from '../../../shared/models/videos/video-comment.model' | 23 | import { VideoComment, VideoCommentAdmin } from '../../../shared/models/videos/video-comment.model' |
24 | import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' | 24 | import { actorNameAlphabet } from '../../helpers/custom-validators/activitypub/actor' |
25 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' | 25 | import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc' |
26 | import { regexpCapture } from '../../helpers/regexp' | 26 | import { regexpCapture } from '../../helpers/regexp' |
27 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' | 27 | import { CONSTRAINTS_FIELDS, WEBSERVER } from '../../initializers/constants' |
28 | import { | 28 | import { |
29 | MComment, | 29 | MComment, |
30 | MCommentAdminFormattable, | ||
30 | MCommentAP, | 31 | MCommentAP, |
31 | MCommentFormattable, | 32 | MCommentFormattable, |
32 | MCommentId, | 33 | MCommentId, |
@@ -40,7 +41,14 @@ import { | |||
40 | import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' | 41 | import { VideoCommentAbuseModel } from '../abuse/video-comment-abuse' |
41 | import { AccountModel } from '../account/account' | 42 | import { AccountModel } from '../account/account' |
42 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' | 43 | import { ActorModel, unusedActorAttributesForAPI } from '../activitypub/actor' |
43 | import { buildBlockedAccountSQL, buildBlockedAccountSQLOptimized, buildLocalAccountIdsIn, getCommentSort, throwIfNotValid } from '../utils' | 44 | import { |
45 | buildBlockedAccountSQL, | ||
46 | buildBlockedAccountSQLOptimized, | ||
47 | buildLocalAccountIdsIn, | ||
48 | getCommentSort, | ||
49 | searchAttribute, | ||
50 | throwIfNotValid | ||
51 | } from '../utils' | ||
44 | import { VideoModel } from './video' | 52 | import { VideoModel } from './video' |
45 | import { VideoChannelModel } from './video-channel' | 53 | import { VideoChannelModel } from './video-channel' |
46 | 54 | ||
@@ -303,6 +311,90 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
303 | return VideoCommentModel.scope([ ScopeNames.WITH_IN_REPLY_TO, ScopeNames.WITH_ACCOUNT ]).findOne(query) | 311 | return VideoCommentModel.scope([ ScopeNames.WITH_IN_REPLY_TO, ScopeNames.WITH_ACCOUNT ]).findOne(query) |
304 | } | 312 | } |
305 | 313 | ||
314 | static listCommentsForApi (parameters: { | ||
315 | start: number | ||
316 | count: number | ||
317 | sort: string | ||
318 | |||
319 | isLocal?: boolean | ||
320 | search?: string | ||
321 | searchAccount?: string | ||
322 | searchVideo?: string | ||
323 | }) { | ||
324 | const { start, count, sort, isLocal, search, searchAccount, searchVideo } = parameters | ||
325 | |||
326 | const query: FindAndCountOptions = { | ||
327 | offset: start, | ||
328 | limit: count, | ||
329 | order: getCommentSort(sort) | ||
330 | } | ||
331 | |||
332 | const where: WhereOptions = { | ||
333 | isDeleted: false | ||
334 | } | ||
335 | |||
336 | const whereAccount: WhereOptions = {} | ||
337 | const whereActor: WhereOptions = {} | ||
338 | const whereVideo: WhereOptions = {} | ||
339 | |||
340 | if (isLocal === true) { | ||
341 | Object.assign(where, { | ||
342 | serverId: null | ||
343 | }) | ||
344 | } else if (isLocal === false) { | ||
345 | Object.assign(where, { | ||
346 | serverId: { | ||
347 | [Op.ne]: null | ||
348 | } | ||
349 | }) | ||
350 | } | ||
351 | |||
352 | if (search) { | ||
353 | Object.assign(where, searchAttribute(search, 'text')) | ||
354 | Object.assign(whereActor, searchAttribute(search, 'preferredUsername')) | ||
355 | Object.assign(whereAccount, searchAttribute(search, 'name')) | ||
356 | Object.assign(whereVideo, searchAttribute(search, 'name')) | ||
357 | } | ||
358 | |||
359 | if (searchAccount) { | ||
360 | Object.assign(whereActor, searchAttribute(search, 'preferredUsername')) | ||
361 | Object.assign(whereAccount, searchAttribute(search, 'name')) | ||
362 | } | ||
363 | |||
364 | if (searchVideo) { | ||
365 | Object.assign(whereVideo, searchAttribute(search, 'name')) | ||
366 | } | ||
367 | |||
368 | query.include = [ | ||
369 | { | ||
370 | model: AccountModel.unscoped(), | ||
371 | required: !!searchAccount, | ||
372 | where: whereAccount, | ||
373 | include: [ | ||
374 | { | ||
375 | attributes: { | ||
376 | exclude: unusedActorAttributesForAPI | ||
377 | }, | ||
378 | model: ActorModel, // Default scope includes avatar and server | ||
379 | required: true, | ||
380 | where: whereActor | ||
381 | } | ||
382 | ] | ||
383 | }, | ||
384 | { | ||
385 | model: VideoModel.unscoped(), | ||
386 | required: true, | ||
387 | where: whereVideo | ||
388 | } | ||
389 | ] | ||
390 | |||
391 | return VideoCommentModel | ||
392 | .findAndCountAll(query) | ||
393 | .then(({ rows, count }) => { | ||
394 | return { total: count, data: rows } | ||
395 | }) | ||
396 | } | ||
397 | |||
306 | static async listThreadsForApi (parameters: { | 398 | static async listThreadsForApi (parameters: { |
307 | videoId: number | 399 | videoId: number |
308 | isVideoOwned: boolean | 400 | isVideoOwned: boolean |
@@ -656,19 +748,51 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
656 | id: this.id, | 748 | id: this.id, |
657 | url: this.url, | 749 | url: this.url, |
658 | text: this.text, | 750 | text: this.text, |
751 | |||
659 | threadId: this.getThreadId(), | 752 | threadId: this.getThreadId(), |
660 | inReplyToCommentId: this.inReplyToCommentId || null, | 753 | inReplyToCommentId: this.inReplyToCommentId || null, |
661 | videoId: this.videoId, | 754 | videoId: this.videoId, |
755 | |||
662 | createdAt: this.createdAt, | 756 | createdAt: this.createdAt, |
663 | updatedAt: this.updatedAt, | 757 | updatedAt: this.updatedAt, |
664 | deletedAt: this.deletedAt, | 758 | deletedAt: this.deletedAt, |
759 | |||
665 | isDeleted: this.isDeleted(), | 760 | isDeleted: this.isDeleted(), |
761 | |||
666 | totalRepliesFromVideoAuthor: this.get('totalRepliesFromVideoAuthor') || 0, | 762 | totalRepliesFromVideoAuthor: this.get('totalRepliesFromVideoAuthor') || 0, |
667 | totalReplies: this.get('totalReplies') || 0, | 763 | totalReplies: this.get('totalReplies') || 0, |
668 | account: this.Account ? this.Account.toFormattedJSON() : null | 764 | |
765 | account: this.Account | ||
766 | ? this.Account.toFormattedJSON() | ||
767 | : null | ||
669 | } as VideoComment | 768 | } as VideoComment |
670 | } | 769 | } |
671 | 770 | ||
771 | toFormattedAdminJSON (this: MCommentAdminFormattable) { | ||
772 | return { | ||
773 | id: this.id, | ||
774 | url: this.url, | ||
775 | text: this.text, | ||
776 | |||
777 | threadId: this.getThreadId(), | ||
778 | inReplyToCommentId: this.inReplyToCommentId || null, | ||
779 | videoId: this.videoId, | ||
780 | |||
781 | createdAt: this.createdAt, | ||
782 | updatedAt: this.updatedAt, | ||
783 | |||
784 | video: { | ||
785 | id: this.Video.id, | ||
786 | uuid: this.Video.uuid, | ||
787 | name: this.Video.name | ||
788 | }, | ||
789 | |||
790 | account: this.Account | ||
791 | ? this.Account.toFormattedJSON() | ||
792 | : null | ||
793 | } as VideoCommentAdmin | ||
794 | } | ||
795 | |||
672 | toActivityPubObject (this: MCommentAP, threadParentComments: MCommentOwner[]): VideoCommentObject | ActivityTombstoneObject { | 796 | toActivityPubObject (this: MCommentAP, threadParentComments: MCommentOwner[]): VideoCommentObject | ActivityTombstoneObject { |
673 | let inReplyTo: string | 797 | let inReplyTo: string |
674 | // New thread, so in AS we reply to the video | 798 | // New thread, so in AS we reply to the video |