-import * as Bluebird from 'bluebird'
import { uniq } from 'lodash'
-import { FindAndCountOptions, FindOptions, Op, Order, ScopeOptions, Sequelize, Transaction, WhereOptions } from 'sequelize'
+import { FindAndCountOptions, FindOptions, Op, Order, QueryTypes, ScopeOptions, Sequelize, Transaction, WhereOptions } from 'sequelize'
import {
AllowNull,
BelongsTo,
}
]
})
-export class VideoCommentModel extends Model<VideoCommentModel> {
+export class VideoCommentModel extends Model {
@CreatedAt
createdAt: Date
})
CommentAbuses: VideoCommentAbuseModel[]
- static loadById (id: number, t?: Transaction): Bluebird<MComment> {
+ static loadById (id: number, t?: Transaction): Promise<MComment> {
const query: FindOptions = {
where: {
id
return VideoCommentModel.findOne(query)
}
- static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction): Bluebird<MCommentOwnerVideoReply> {
+ static loadByIdAndPopulateVideoAndAccountAndReply (id: number, t?: Transaction): Promise<MCommentOwnerVideoReply> {
const query: FindOptions = {
where: {
id
.findOne(query)
}
- static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction): Bluebird<MCommentOwnerVideo> {
+ static loadByUrlAndPopulateAccountAndVideo (url: string, t?: Transaction): Promise<MCommentOwnerVideo> {
const query: FindOptions = {
where: {
url
return VideoCommentModel.scope([ ScopeNames.WITH_ACCOUNT, ScopeNames.WITH_VIDEO ]).findOne(query)
}
- static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction): Bluebird<MCommentOwnerReplyVideoLight> {
+ static loadByUrlAndPopulateReplyAndVideoUrlAndAccount (url: string, t?: Transaction): Promise<MCommentOwnerReplyVideoLight> {
const query: FindOptions = {
where: {
url
}) {
const { start, count, sort, isLocal, search, searchAccount, searchVideo } = parameters
- const query: FindAndCountOptions = {
- offset: start,
- limit: count,
- order: getCommentSort(sort)
- }
-
const where: WhereOptions = {
- isDeleted: false
+ deletedAt: null
}
const whereAccount: WhereOptions = {}
const whereVideo: WhereOptions = {}
if (isLocal === true) {
- Object.assign(where, {
+ Object.assign(whereActor, {
serverId: null
})
} else if (isLocal === false) {
- Object.assign(where, {
+ Object.assign(whereActor, {
serverId: {
[Op.ne]: null
}
}
if (search) {
- Object.assign(where, searchAttribute(search, 'text'))
- Object.assign(whereActor, searchAttribute(search, 'preferredUsername'))
- Object.assign(whereAccount, searchAttribute(search, 'name'))
- Object.assign(whereVideo, searchAttribute(search, 'name'))
+ Object.assign(where, {
+ [Op.or]: [
+ searchAttribute(search, 'text'),
+ searchAttribute(search, '$Account.Actor.preferredUsername$'),
+ searchAttribute(search, '$Account.name$'),
+ searchAttribute(search, '$Video.name$')
+ ]
+ })
}
if (searchAccount) {
- Object.assign(whereActor, searchAttribute(search, 'preferredUsername'))
- Object.assign(whereAccount, searchAttribute(search, 'name'))
+ Object.assign(whereActor, {
+ [Op.or]: [
+ searchAttribute(searchAccount, '$Account.Actor.preferredUsername$'),
+ searchAttribute(searchAccount, '$Account.name$')
+ ]
+ })
}
if (searchVideo) {
- Object.assign(whereVideo, searchAttribute(search, 'name'))
+ Object.assign(whereVideo, searchAttribute(searchVideo, 'name'))
}
- query.include = [
- {
- model: AccountModel.unscoped(),
- required: !!searchAccount,
- where: whereAccount,
- include: [
- {
- attributes: {
- exclude: unusedActorAttributesForAPI
- },
- model: ActorModel, // Default scope includes avatar and server
- required: true,
- where: whereActor
- }
- ]
- },
- {
- model: VideoModel.unscoped(),
- required: true,
- where: whereVideo
- }
- ]
+ const query: FindAndCountOptions = {
+ offset: start,
+ limit: count,
+ order: getCommentSort(sort),
+ where,
+ include: [
+ {
+ model: AccountModel.unscoped(),
+ required: true,
+ where: whereAccount,
+ include: [
+ {
+ attributes: {
+ exclude: unusedActorAttributesForAPI
+ },
+ model: ActorModel, // Default scope includes avatar and server
+ required: true,
+ where: whereActor
+ }
+ ]
+ },
+ {
+ model: VideoModel.unscoped(),
+ required: true,
+ where: whereVideo
+ }
+ ]
+ }
return VideoCommentModel
.findAndCountAll(query)
const blockerAccountIds = await VideoCommentModel.buildBlockerAccountIds({ videoId, user, isVideoOwned })
- const query = {
+ const accountBlockedWhere = {
+ accountId: {
+ [Op.notIn]: Sequelize.literal(
+ '(' + buildBlockedAccountSQL(blockerAccountIds) + ')'
+ )
+ }
+ }
+
+ const queryList = {
offset: start,
limit: count,
order: getCommentSort(sort),
},
{
[Op.or]: [
- {
- accountId: {
- [Op.notIn]: Sequelize.literal(
- '(' + buildBlockedAccountSQL(blockerAccountIds) + ')'
- )
- }
- },
+ accountBlockedWhere,
{
accountId: null
}
}
}
- const scopes: (string | ScopeOptions)[] = [
+ const scopesList: (string | ScopeOptions)[] = [
ScopeNames.WITH_ACCOUNT_FOR_API,
{
method: [ ScopeNames.ATTRIBUTES_FOR_API, blockerAccountIds ]
}
]
- return VideoCommentModel
- .scope(scopes)
- .findAndCountAll(query)
- .then(({ rows, count }) => {
- return { total: count, data: rows }
- })
+ const queryCount = {
+ where: {
+ videoId,
+ deletedAt: null,
+ ...accountBlockedWhere
+ }
+ }
+
+ return Promise.all([
+ VideoCommentModel.scope(scopesList).findAndCountAll(queryList),
+ VideoCommentModel.count(queryCount)
+ ]).then(([ { rows, count }, totalNotDeletedComments ]) => {
+ return { total: count, data: rows, totalNotDeletedComments }
+ })
}
static async listThreadCommentsForApi (parameters: {
order: [ [ 'createdAt', 'ASC' ], [ 'updatedAt', 'ASC' ] ] as Order,
where: {
videoId,
- [Op.or]: [
- { id: threadId },
- { originCommentId: threadId }
- ],
- accountId: {
- [Op.notIn]: Sequelize.literal(
- '(' + buildBlockedAccountSQL(blockerAccountIds) + ')'
- )
- }
+ [Op.and]: [
+ {
+ [Op.or]: [
+ { id: threadId },
+ { originCommentId: threadId }
+ ]
+ },
+ {
+ [Op.or]: [
+ {
+ accountId: {
+ [Op.notIn]: Sequelize.literal(
+ '(' + buildBlockedAccountSQL(blockerAccountIds) + ')'
+ )
+ }
+ },
+ {
+ accountId: null
+ }
+ ]
+ }
+ ]
}
}
}
]
- return VideoCommentModel
- .scope(scopes)
+ return VideoCommentModel.scope(scopes)
.findAndCountAll(query)
.then(({ rows, count }) => {
return { total: count, data: rows }
})
}
- static listThreadParentComments (comment: MCommentId, t: Transaction, order: 'ASC' | 'DESC' = 'ASC'): Bluebird<MCommentOwner[]> {
+ static listThreadParentComments (comment: MCommentId, t: Transaction, order: 'ASC' | 'DESC' = 'ASC'): Promise<MCommentOwner[]> {
const query = {
order: [ [ 'createdAt', order ] ] as Order,
where: {
}
}
+ static listRemoteCommentUrlsOfLocalVideos () {
+ const query = `SELECT "videoComment".url FROM "videoComment" ` +
+ `INNER JOIN account ON account.id = "videoComment"."accountId" ` +
+ `INNER JOIN actor ON actor.id = "account"."actorId" AND actor."serverId" IS NOT NULL ` +
+ `INNER JOIN video ON video.id = "videoComment"."videoId" AND video.remote IS FALSE`
+
+ return VideoCommentModel.sequelize.query<{ url: string }>(query, {
+ type: QueryTypes.SELECT,
+ raw: true
+ }).then(rows => rows.map(r => r.url))
+ }
+
static cleanOldCommentsOf (videoId: number, beforeUpdatedAt: Date) {
const query = {
where: {