diff options
Diffstat (limited to 'server/models/video/video-comment.ts')
-rw-r--r-- | server/models/video/video-comment.ts | 140 |
1 files changed, 136 insertions, 4 deletions
diff --git a/server/models/video/video-comment.ts b/server/models/video/video-comment.ts index de27b3d87..ed4a345eb 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,98 @@ 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 where: WhereOptions = { | ||
327 | deletedAt: null | ||
328 | } | ||
329 | |||
330 | const whereAccount: WhereOptions = {} | ||
331 | const whereActor: WhereOptions = {} | ||
332 | const whereVideo: WhereOptions = {} | ||
333 | |||
334 | if (isLocal === true) { | ||
335 | Object.assign(whereActor, { | ||
336 | serverId: null | ||
337 | }) | ||
338 | } else if (isLocal === false) { | ||
339 | Object.assign(whereActor, { | ||
340 | serverId: { | ||
341 | [Op.ne]: null | ||
342 | } | ||
343 | }) | ||
344 | } | ||
345 | |||
346 | if (search) { | ||
347 | Object.assign(where, { | ||
348 | [Op.or]: [ | ||
349 | searchAttribute(search, 'text'), | ||
350 | searchAttribute(search, '$Account.Actor.preferredUsername$'), | ||
351 | searchAttribute(search, '$Account.name$'), | ||
352 | searchAttribute(search, '$Video.name$') | ||
353 | ] | ||
354 | }) | ||
355 | } | ||
356 | |||
357 | if (searchAccount) { | ||
358 | Object.assign(whereActor, { | ||
359 | [Op.or]: [ | ||
360 | searchAttribute(searchAccount, '$Account.Actor.preferredUsername$'), | ||
361 | searchAttribute(searchAccount, '$Account.name$') | ||
362 | ] | ||
363 | }) | ||
364 | } | ||
365 | |||
366 | if (searchVideo) { | ||
367 | Object.assign(whereVideo, searchAttribute(searchVideo, 'name')) | ||
368 | } | ||
369 | |||
370 | const query: FindAndCountOptions = { | ||
371 | offset: start, | ||
372 | limit: count, | ||
373 | order: getCommentSort(sort), | ||
374 | where, | ||
375 | include: [ | ||
376 | { | ||
377 | model: AccountModel.unscoped(), | ||
378 | required: true, | ||
379 | where: whereAccount, | ||
380 | include: [ | ||
381 | { | ||
382 | attributes: { | ||
383 | exclude: unusedActorAttributesForAPI | ||
384 | }, | ||
385 | model: ActorModel, // Default scope includes avatar and server | ||
386 | required: true, | ||
387 | where: whereActor | ||
388 | } | ||
389 | ] | ||
390 | }, | ||
391 | { | ||
392 | model: VideoModel.unscoped(), | ||
393 | required: true, | ||
394 | where: whereVideo | ||
395 | } | ||
396 | ] | ||
397 | } | ||
398 | |||
399 | return VideoCommentModel | ||
400 | .findAndCountAll(query) | ||
401 | .then(({ rows, count }) => { | ||
402 | return { total: count, data: rows } | ||
403 | }) | ||
404 | } | ||
405 | |||
306 | static async listThreadsForApi (parameters: { | 406 | static async listThreadsForApi (parameters: { |
307 | videoId: number | 407 | videoId: number |
308 | isVideoOwned: boolean | 408 | isVideoOwned: boolean |
@@ -656,19 +756,51 @@ export class VideoCommentModel extends Model<VideoCommentModel> { | |||
656 | id: this.id, | 756 | id: this.id, |
657 | url: this.url, | 757 | url: this.url, |
658 | text: this.text, | 758 | text: this.text, |
759 | |||
659 | threadId: this.getThreadId(), | 760 | threadId: this.getThreadId(), |
660 | inReplyToCommentId: this.inReplyToCommentId || null, | 761 | inReplyToCommentId: this.inReplyToCommentId || null, |
661 | videoId: this.videoId, | 762 | videoId: this.videoId, |
763 | |||
662 | createdAt: this.createdAt, | 764 | createdAt: this.createdAt, |
663 | updatedAt: this.updatedAt, | 765 | updatedAt: this.updatedAt, |
664 | deletedAt: this.deletedAt, | 766 | deletedAt: this.deletedAt, |
767 | |||
665 | isDeleted: this.isDeleted(), | 768 | isDeleted: this.isDeleted(), |
769 | |||
666 | totalRepliesFromVideoAuthor: this.get('totalRepliesFromVideoAuthor') || 0, | 770 | totalRepliesFromVideoAuthor: this.get('totalRepliesFromVideoAuthor') || 0, |
667 | totalReplies: this.get('totalReplies') || 0, | 771 | totalReplies: this.get('totalReplies') || 0, |
668 | account: this.Account ? this.Account.toFormattedJSON() : null | 772 | |
773 | account: this.Account | ||
774 | ? this.Account.toFormattedJSON() | ||
775 | : null | ||
669 | } as VideoComment | 776 | } as VideoComment |
670 | } | 777 | } |
671 | 778 | ||
779 | toFormattedAdminJSON (this: MCommentAdminFormattable) { | ||
780 | return { | ||
781 | id: this.id, | ||
782 | url: this.url, | ||
783 | text: this.text, | ||
784 | |||
785 | threadId: this.getThreadId(), | ||
786 | inReplyToCommentId: this.inReplyToCommentId || null, | ||
787 | videoId: this.videoId, | ||
788 | |||
789 | createdAt: this.createdAt, | ||
790 | updatedAt: this.updatedAt, | ||
791 | |||
792 | video: { | ||
793 | id: this.Video.id, | ||
794 | uuid: this.Video.uuid, | ||
795 | name: this.Video.name | ||
796 | }, | ||
797 | |||
798 | account: this.Account | ||
799 | ? this.Account.toFormattedJSON() | ||
800 | : null | ||
801 | } as VideoCommentAdmin | ||
802 | } | ||
803 | |||
672 | toActivityPubObject (this: MCommentAP, threadParentComments: MCommentOwner[]): VideoCommentObject | ActivityTombstoneObject { | 804 | toActivityPubObject (this: MCommentAP, threadParentComments: MCommentOwner[]): VideoCommentObject | ActivityTombstoneObject { |
673 | let inReplyTo: string | 805 | let inReplyTo: string |
674 | // New thread, so in AS we reply to the video | 806 | // New thread, so in AS we reply to the video |