feat: comment whispers (#643)

This commit is contained in:
2022-07-20 22:32:45 +08:00
committed by GitHub
parent 62db6c92e6
commit 3bc265dcb8
6 changed files with 105 additions and 8 deletions

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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)
}

View File

@@ -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,
})

View File

@@ -31,6 +31,7 @@ export const generateDefaultConfig: () => IConfig = () => ({
fetchLocationTimeout: 3000,
recordIpLocation: true,
spamKeywords: [],
commentShouldAudit: false,
},
barkOptions: {
enable: false,

View File

@@ -133,6 +133,11 @@ export class CommentOptionsDto {
@JSONSchemaToggleField('禁止非中文评论')
disableNoChinese?: boolean
@IsOptional()
@IsBoolean()
@JSONSchemaToggleField('只展示已读评论')
commentShouldAudit?: boolean
@IsBoolean()
@IsOptional()
@JSONSchemaToggleField('评论公开归属地')