feat: comment whispers (#643)
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { isUndefined } from 'lodash'
|
||||
import { Document, FilterQuery } from 'mongoose'
|
||||
|
||||
import {
|
||||
Body,
|
||||
@@ -30,6 +31,7 @@ import { MongoIdDto } from '~/shared/dto/id.dto'
|
||||
import { PagerDto } from '~/shared/dto/pager.dto'
|
||||
import { transformDataToPaginate } from '~/transformers/paginate.transformer'
|
||||
|
||||
import { ConfigsService } from '../configs/configs.service'
|
||||
import { UserModel } from '../user/user.model'
|
||||
import {
|
||||
CommentDto,
|
||||
@@ -50,6 +52,7 @@ export class CommentController {
|
||||
constructor(
|
||||
private readonly commentService: CommentService,
|
||||
private readonly eventManager: EventManagerService,
|
||||
private readonly configsService: ConfigsService,
|
||||
) {}
|
||||
|
||||
@Get('/')
|
||||
@@ -63,16 +66,23 @@ export class CommentController {
|
||||
|
||||
@Get('/:id')
|
||||
@ApiOperation({ summary: '根据 comment id 获取评论, 包括子评论' })
|
||||
async getComments(@Param() params: MongoIdDto) {
|
||||
async getComments(
|
||||
@Param() params: MongoIdDto,
|
||||
@IsMaster() isMaster: boolean,
|
||||
) {
|
||||
const { id } = params
|
||||
const data = await this.commentService.model
|
||||
.findOne({
|
||||
_id: id,
|
||||
})
|
||||
.populate('parent')
|
||||
|
||||
if (!data) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
if (data.isWhispers && !isMaster) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -83,19 +93,58 @@ export class CommentController {
|
||||
async getCommentsByRefId(
|
||||
@Param() params: MongoIdDto,
|
||||
@Query() query: PagerDto,
|
||||
@IsMaster() isMaster: boolean,
|
||||
) {
|
||||
const { id } = params
|
||||
const { page = 1, size = 10 } = query
|
||||
const comments = await this.commentService.model.paginate(
|
||||
|
||||
const configs = await this.configsService.get('commentOptions')
|
||||
const { commentShouldAudit } = configs
|
||||
|
||||
const $and: FilterQuery<CommentModel & Document<any, any, any>>[] = [
|
||||
{
|
||||
parent: undefined,
|
||||
ref: id,
|
||||
},
|
||||
{
|
||||
$or: commentShouldAudit
|
||||
? [
|
||||
{
|
||||
state: CommentState.Read,
|
||||
},
|
||||
]
|
||||
: [
|
||||
{
|
||||
state: CommentState.Read,
|
||||
},
|
||||
{ state: CommentState.Unread },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
if (isMaster) {
|
||||
$and.push({
|
||||
$or: [
|
||||
{ isWhispers: true },
|
||||
{ isWhispers: false },
|
||||
{
|
||||
state: CommentState.Read,
|
||||
isWhispers: { $exists: false },
|
||||
},
|
||||
{ state: CommentState.Unread },
|
||||
],
|
||||
})
|
||||
} else {
|
||||
$and.push({
|
||||
$or: [
|
||||
{ isWhispers: false },
|
||||
{
|
||||
isWhispers: { $exists: false },
|
||||
},
|
||||
],
|
||||
})
|
||||
}
|
||||
const comments = await this.commentService.model.paginate(
|
||||
{
|
||||
$and,
|
||||
},
|
||||
{
|
||||
limit: size,
|
||||
@@ -138,6 +187,8 @@ export class CommentController {
|
||||
const comment = await this.commentService.createComment(id, model, ref)
|
||||
|
||||
process.nextTick(async () => {
|
||||
const configs = await this.configsService.get('commentOptions')
|
||||
const { commentShouldAudit } = configs
|
||||
if (await this.commentService.checkSpam(comment)) {
|
||||
comment.state = CommentState.Junk
|
||||
await comment.save()
|
||||
@@ -146,11 +197,27 @@ export class CommentController {
|
||||
this.commentService.sendEmail(comment, ReplyMailType.Owner)
|
||||
}
|
||||
|
||||
if (commentShouldAudit) {
|
||||
await this.eventManager.broadcast(
|
||||
BusinessEvents.COMMENT_CREATE,
|
||||
comment,
|
||||
{
|
||||
scope: EventScope.TO_SYSTEM_ADMIN,
|
||||
},
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
await this.eventManager.broadcast(
|
||||
BusinessEvents.COMMENT_CREATE,
|
||||
comment,
|
||||
{
|
||||
scope: isMaster ? EventScope.TO_SYSTEM_VISITOR : EventScope.ALL,
|
||||
scope: isMaster
|
||||
? EventScope.TO_SYSTEM_VISITOR
|
||||
: comment.isWhispers
|
||||
? EventScope.TO_SYSTEM_ADMIN
|
||||
: EventScope.ALL,
|
||||
},
|
||||
)
|
||||
})
|
||||
@@ -222,6 +289,16 @@ export class CommentController {
|
||||
scope: EventScope.TO_SYSTEM_VISITOR,
|
||||
})
|
||||
} else {
|
||||
const configs = await this.configsService.get('commentOptions')
|
||||
const { commentShouldAudit } = configs
|
||||
|
||||
if (commentShouldAudit) {
|
||||
this.eventManager.broadcast(BusinessEvents.COMMENT_CREATE, comment, {
|
||||
scope: EventScope.TO_SYSTEM_ADMIN,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
this.commentService.sendEmail(comment, ReplyMailType.Owner)
|
||||
this.eventManager.broadcast(BusinessEvents.COMMENT_CREATE, comment, {
|
||||
scope: EventScope.ALL,
|
||||
|
||||
@@ -40,6 +40,10 @@ export class CommentDto {
|
||||
@ApiProperty({ example: 'http://example.com' })
|
||||
@MaxLength(50, { message: '地址不得大于 50 个字符' })
|
||||
url?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
isWhispers?: boolean
|
||||
}
|
||||
|
||||
export class TextOnlyDto {
|
||||
|
||||
@@ -126,6 +126,10 @@ export class CommentModel extends BaseModel {
|
||||
@prop()
|
||||
public location?: string
|
||||
|
||||
// 悄悄话
|
||||
@prop({ default: false })
|
||||
isWhispers?: boolean
|
||||
|
||||
public get avatar() {
|
||||
return getAvatar(this.mail)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import { LeanDocument, Types } from 'mongoose'
|
||||
import { URL } from 'url'
|
||||
|
||||
import { BadRequestException, Injectable, Logger } from '@nestjs/common'
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
Logger,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common'
|
||||
import { DocumentType } from '@typegoose/typegoose'
|
||||
import { BeAnObject, ReturnModelType } from '@typegoose/typegoose/lib/types'
|
||||
|
||||
@@ -24,7 +29,7 @@ import { PostModel } from '../post/post.model'
|
||||
import { ToolService } from '../tool/tool.service'
|
||||
import { UserService } from '../user/user.service'
|
||||
import BlockedKeywords from './block-keywords.json'
|
||||
import { CommentModel, CommentRefTypes } from './comment.model'
|
||||
import { CommentModel, CommentRefTypes, CommentState } from './comment.model'
|
||||
|
||||
@Injectable()
|
||||
export class CommentService {
|
||||
@@ -126,12 +131,13 @@ export class CommentService {
|
||||
type = type_ as any
|
||||
}
|
||||
if (!ref) {
|
||||
throw new CannotFindException()
|
||||
throw new NotFoundException('评论文章不存在')
|
||||
}
|
||||
const commentIndex = ref.commentsIndex || 0
|
||||
doc.key = `#${commentIndex + 1}`
|
||||
const comment = await this.commentModel.create({
|
||||
...doc,
|
||||
state: CommentState.Unread,
|
||||
ref: new Types.ObjectId(id),
|
||||
refType: type,
|
||||
})
|
||||
|
||||
@@ -31,6 +31,7 @@ export const generateDefaultConfig: () => IConfig = () => ({
|
||||
fetchLocationTimeout: 3000,
|
||||
recordIpLocation: true,
|
||||
spamKeywords: [],
|
||||
commentShouldAudit: false,
|
||||
},
|
||||
barkOptions: {
|
||||
enable: false,
|
||||
|
||||
@@ -133,6 +133,11 @@ export class CommentOptionsDto {
|
||||
@JSONSchemaToggleField('禁止非中文评论')
|
||||
disableNoChinese?: boolean
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@JSONSchemaToggleField('只展示已读评论')
|
||||
commentShouldAudit?: boolean
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
@JSONSchemaToggleField('评论公开归属地')
|
||||
|
||||
Reference in New Issue
Block a user