feat(core): 实现文章的发布/取消发布功能 (#2443)
* feat(migration): add isPublished field to posts and notes collections * feat(note, post): add publish status management for notes and posts * build(tsup): 添加 import.meta.url 支持 - 在 tsup 配置中添加 platform: 'node' 设置 - 注入 import.meta.url 兼容层,以支持不同模块格式 * build(core): 修改 mx-server 启动脚本路径 * feat(migration): 添加 v8.4.0 版本迁移脚本至history * feat(core): 修复未认证用户可查看未发布内容的安全问题 - 在 Note 和 Post 模块中添加了对未认证用户的访问限制 * fix(core): 回滚 mx-server 启动脚本路径 * feat(migration): 添加 v8.4.0 数据库脚本以更新 notes 集合字段 * feat(migration): 更新 v8.4.0 修复脚本以重命名 hide 字段并互换其值 * feat(note): 替换 hide 字段为 isPublished,更新相关查询和条件 * feat(note): 将 hide 字段替换为 isPublished,更新相关数据模型 * feat(migration): 添加 v8.4.0 fix2修复脚本以更新 posts 集合中的 isPublished 字段为true
This commit is contained in:
@@ -9,7 +9,7 @@ module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'mx-server',
|
||||
script: 'index.js',
|
||||
script: './index.js',
|
||||
autorestart: true,
|
||||
exec_mode: 'cluster',
|
||||
watch: false,
|
||||
|
||||
@@ -9,6 +9,9 @@ import v5_0_0__1 from './version/v5.0.0-1'
|
||||
import v5_1_1 from './version/v5.1.1'
|
||||
import v5_6_0 from './version/v5.6.0'
|
||||
import v7_2_1 from './version/v7.2.1'
|
||||
import v8_4_0 from './version/v8.4.0'
|
||||
import v8_4_0__1 from './version/v8.4.0.fix1'
|
||||
import v8_4_0__2 from './version/v8.4.0.fix2'
|
||||
|
||||
export default [
|
||||
v200Alpha1,
|
||||
@@ -22,4 +25,7 @@ export default [
|
||||
v5_1_1,
|
||||
v5_6_0,
|
||||
v7_2_1,
|
||||
v8_4_0,
|
||||
v8_4_0__1,
|
||||
v8_4_0__2,
|
||||
]
|
||||
|
||||
39
apps/core/src/migration/version/v8.4.0.fix1.ts
Normal file
39
apps/core/src/migration/version/v8.4.0.fix1.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
//patch for version 8.4.0 v1
|
||||
//移除Note中的isPublished字段,并将hide字段重命名为isPublished
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
export default (async function v0840Fix1(db: Db) {
|
||||
try {
|
||||
const notesCollection = db.collection('notes')
|
||||
|
||||
// 移除 isPublished 字段
|
||||
await notesCollection.updateMany(
|
||||
{},
|
||||
{ $unset: { isPublished: '' } },
|
||||
{ upsert: false },
|
||||
)
|
||||
|
||||
// 将 hide 字段重命名为 isPublished, 同时将true与false互换
|
||||
await notesCollection.updateMany(
|
||||
{},
|
||||
[
|
||||
{
|
||||
$set: {
|
||||
isPublished: {
|
||||
$cond: {
|
||||
if: { $eq: ['$hide', true] },
|
||||
then: false,
|
||||
else: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{ $unset: 'hide' },
|
||||
],
|
||||
{ upsert: false },
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Migration v8.4.0 Fix1 failed:', error)
|
||||
throw error
|
||||
}
|
||||
})
|
||||
19
apps/core/src/migration/version/v8.4.0.fix2.ts
Normal file
19
apps/core/src/migration/version/v8.4.0.fix2.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
// patch for version 8.4.0 v2
|
||||
// 将Posts中的isPublished字段全部设置为true
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
export default (async function v0840Fix2(db: Db) {
|
||||
try {
|
||||
const postsCollection = db.collection('posts')
|
||||
|
||||
// 将 isPublished 字段全部设置为 true
|
||||
await postsCollection.updateMany(
|
||||
{},
|
||||
{ $set: { isPublished: true } },
|
||||
{ upsert: false },
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Migration v8.4.0 Fix2 failed:', error)
|
||||
throw error
|
||||
}
|
||||
})
|
||||
26
apps/core/src/migration/version/v8.4.0.ts
Normal file
26
apps/core/src/migration/version/v8.4.0.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
// patch for version lower than v8.4.0
|
||||
// 本次migration会向posts和notes表中添加一个isPublished字段,默认值为true
|
||||
import type { Db } from 'mongodb'
|
||||
|
||||
export default (async function v0840(db: Db) {
|
||||
try {
|
||||
const postsCollection = db.collection('posts')
|
||||
const notesCollection = db.collection('notes')
|
||||
|
||||
// 添加 isPublished 字段到 posts 集合
|
||||
await postsCollection.updateMany(
|
||||
{},
|
||||
{ $set: { isPublished: true } },
|
||||
{ upsert: false },
|
||||
)
|
||||
|
||||
// 添加 isPublished 字段到 notes 集合
|
||||
await notesCollection.updateMany(
|
||||
{},
|
||||
{ $set: { isPublished: true } },
|
||||
{ upsert: false },
|
||||
)
|
||||
} catch (error) {
|
||||
console.error('Migration to v8.4.0 failed:', error)
|
||||
}
|
||||
})
|
||||
@@ -670,7 +670,7 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy {
|
||||
this.databaseService.db
|
||||
.collection(NOTE_COLLECTION_NAME)
|
||||
.find({
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
})
|
||||
.sort({
|
||||
created: -1,
|
||||
@@ -722,7 +722,7 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy {
|
||||
mood: 1,
|
||||
bookmark: 1,
|
||||
password: 1,
|
||||
hide: 1,
|
||||
isPublished: 1,
|
||||
},
|
||||
)
|
||||
.lean(),
|
||||
@@ -730,11 +730,11 @@ export class ActivityService implements OnModuleInit, OnModuleDestroy {
|
||||
return {
|
||||
posts,
|
||||
notes: notes.map((note) => {
|
||||
if (note.password || note.hide) {
|
||||
if (note.password || !note.isPublished) {
|
||||
note.title = '未公开的日记'
|
||||
}
|
||||
|
||||
return omit(note, 'password', 'hide')
|
||||
return omit(note, 'password', 'isPublished')
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ export class AggregateService {
|
||||
this.noteService.model,
|
||||
!isAuthenticated
|
||||
? {
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
password: undefined,
|
||||
}
|
||||
: {},
|
||||
@@ -111,7 +111,7 @@ export class AggregateService {
|
||||
|
||||
this.findTop(
|
||||
this.postService.model,
|
||||
!isAuthenticated ? { hide: false } : {},
|
||||
!isAuthenticated ? { isPublished: true } : {},
|
||||
size,
|
||||
)
|
||||
.populate('categoryId')
|
||||
@@ -162,7 +162,7 @@ export class AggregateService {
|
||||
this.noteService.model
|
||||
.find(
|
||||
{
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
...addYearCondition(year),
|
||||
},
|
||||
'_id nid title weather mood created modified bookmark',
|
||||
@@ -209,7 +209,7 @@ export class AggregateService {
|
||||
|
||||
this.noteService.model
|
||||
.find({
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
|
||||
$or: [
|
||||
{
|
||||
@@ -258,7 +258,7 @@ export class AggregateService {
|
||||
])
|
||||
|
||||
return combineTasks
|
||||
.flat(1)
|
||||
.flat()
|
||||
.sort((a, b) => -(a.published_at.getTime() - b.published_at.getTime()))
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ export class AggregateService {
|
||||
|
||||
this.noteService.model
|
||||
.find({
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
$and: [
|
||||
{
|
||||
$or: [
|
||||
|
||||
@@ -46,7 +46,7 @@ export class CategoryController {
|
||||
async getCategories(@Query() query: MultiCategoriesQueryDto) {
|
||||
const { ids, joint, type = CategoryType.Category } = query // categories is category's mongo id
|
||||
if (ids) {
|
||||
const ignoreKeys = '-text -summary -hide -images -commentsIndex'
|
||||
const ignoreKeys = '-text -summary -isPublished -images -commentsIndex'
|
||||
if (joint) {
|
||||
const map = new Object()
|
||||
|
||||
|
||||
@@ -94,13 +94,15 @@ export class McpService {
|
||||
*/
|
||||
async getNotes(page = 1, size = 10) {
|
||||
const query = this.noteService.model
|
||||
.find({ hide: false })
|
||||
.find({ isPublished: true })
|
||||
.sort({ created: -1 })
|
||||
.skip((page - 1) * size)
|
||||
.limit(size)
|
||||
|
||||
const notes = await query.exec()
|
||||
const total = await this.noteService.model.countDocuments({ hide: false })
|
||||
const total = await this.noteService.model.countDocuments({
|
||||
isPublished: true,
|
||||
})
|
||||
|
||||
return {
|
||||
data: notes,
|
||||
|
||||
@@ -29,6 +29,7 @@ import {
|
||||
NidType,
|
||||
NotePasswordQueryDto,
|
||||
NoteQueryDto,
|
||||
SetNotePublishStatusDto,
|
||||
} from './note.dto'
|
||||
import { NoteModel, PartialNoteModel } from './note.model'
|
||||
import { NoteService } from './note.service'
|
||||
@@ -68,8 +69,10 @@ export class NoteController {
|
||||
}
|
||||
|
||||
@Get(':id')
|
||||
@Auth()
|
||||
async getOneNote(@Param() params: MongoIdDto) {
|
||||
async getOneNote(
|
||||
@Param() params: MongoIdDto,
|
||||
@IsAuthenticated() isAuthenticated: boolean,
|
||||
) {
|
||||
const { id } = params
|
||||
|
||||
const current = await this.noteService.model
|
||||
@@ -82,6 +85,11 @@ export class NoteController {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
|
||||
// 非认证用户只能查看已发布的手记
|
||||
if (!isAuthenticated && !current.isPublished) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
|
||||
return current
|
||||
}
|
||||
|
||||
@@ -95,9 +103,9 @@ export class NoteController {
|
||||
const half = size >> 1
|
||||
const { id } = params
|
||||
const select = isAuthenticated
|
||||
? 'nid _id title created hide'
|
||||
? 'nid _id title created isPublished'
|
||||
: 'nid _id title created'
|
||||
const condition = isAuthenticated ? {} : { hide: false }
|
||||
const condition = isAuthenticated ? {} : { isPublished: true }
|
||||
|
||||
// 当前文档直接找,不用加条件,反正里面的东西是看不到的
|
||||
const currentDocument = await this.noteService.model
|
||||
@@ -197,7 +205,7 @@ export class NoteController {
|
||||
) {
|
||||
const { nid } = params
|
||||
const { password, single: isSingle } = query
|
||||
const condition = isAuthenticated ? {} : { hide: false }
|
||||
const condition = isAuthenticated ? {} : { isPublished: true }
|
||||
const current: NoteModel | null = await this.noteService.model
|
||||
.findOne({
|
||||
nid,
|
||||
@@ -278,8 +286,8 @@ export class NoteController {
|
||||
sortOrder,
|
||||
} = query
|
||||
const condition: FilterQuery<NoteModel> = isAuthenticated
|
||||
? { $or: [{ hide: false }, { hide: true }] }
|
||||
: { hide: false }
|
||||
? { $or: [{ isPublished: false }, { isPublished: true }] }
|
||||
: { isPublished: true }
|
||||
|
||||
return await this.noteService.getNotePaginationByTopicId(
|
||||
id,
|
||||
@@ -292,4 +300,16 @@ export class NoteController {
|
||||
{ ...condition },
|
||||
)
|
||||
}
|
||||
|
||||
@Patch('/:id/publish')
|
||||
@Auth()
|
||||
async setPublishStatus(
|
||||
@Param() params: MongoIdDto,
|
||||
@Body() body: SetNotePublishStatusDto,
|
||||
) {
|
||||
await this.noteService.updateById(params.id, {
|
||||
isPublished: body.isPublished,
|
||||
})
|
||||
return { success: true }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,3 +57,8 @@ export class NidType {
|
||||
@Transform(({ value: val }) => Number.parseInt(val))
|
||||
nid: number
|
||||
}
|
||||
|
||||
export class SetNotePublishStatusDto {
|
||||
@IsBoolean()
|
||||
isPublished: boolean
|
||||
}
|
||||
|
||||
@@ -45,10 +45,10 @@ export class NoteModel extends WriteBaseModel {
|
||||
@prop({ required: false, unique: true })
|
||||
public nid: number
|
||||
|
||||
@prop({ default: false })
|
||||
@prop({ default: true })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
hide: boolean
|
||||
isPublished?: boolean
|
||||
|
||||
@prop({
|
||||
select: false,
|
||||
|
||||
@@ -40,7 +40,7 @@ export class NoteService {
|
||||
}
|
||||
|
||||
public readonly publicNoteQueryCondition = {
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
$and: [
|
||||
{
|
||||
$or: [
|
||||
@@ -170,7 +170,9 @@ export class NoteService {
|
||||
return note.save()
|
||||
},
|
||||
),
|
||||
note.hide || note.password || this.checkNoteIsSecret(note)
|
||||
note.isPublished === false ||
|
||||
note.password ||
|
||||
this.checkNoteIsSecret(note)
|
||||
? null
|
||||
: this.eventManager.broadcast(
|
||||
BusinessEvents.NOTE_CREATE,
|
||||
@@ -266,7 +268,11 @@ export class NoteService {
|
||||
scope: EventScope.TO_SYSTEM,
|
||||
})
|
||||
|
||||
if (updated.password || updated.hide || updated.publicAt) {
|
||||
if (
|
||||
updated.password ||
|
||||
updated.isPublished === false ||
|
||||
updated.publicAt
|
||||
) {
|
||||
return
|
||||
}
|
||||
this.eventManager.broadcast(
|
||||
|
||||
@@ -16,12 +16,17 @@ import { ApiController } from '~/common/decorators/api-controller.decorator'
|
||||
import { Auth } from '~/common/decorators/auth.decorator'
|
||||
import { HTTPDecorators, Paginator } from '~/common/decorators/http.decorator'
|
||||
import { IpLocation, IpRecord } from '~/common/decorators/ip.decorator'
|
||||
import { IsAuthenticated } from '~/common/decorators/role.decorator'
|
||||
import { CannotFindException } from '~/common/exceptions/cant-find.exception'
|
||||
import { CountingService } from '~/processors/helper/helper.counting.service'
|
||||
import { MongoIdDto } from '~/shared/dto/id.dto'
|
||||
import { addYearCondition } from '~/transformers/db-query.transformer'
|
||||
|
||||
import { CategoryAndSlugDto, PostPagerDto } from './post.dto'
|
||||
import {
|
||||
CategoryAndSlugDto,
|
||||
PostPagerDto,
|
||||
SetPostPublishStatusDto,
|
||||
} from './post.dto'
|
||||
import { PartialPostModel, PostModel } from './post.model'
|
||||
import { PostService } from './post.service'
|
||||
|
||||
@@ -34,7 +39,10 @@ export class PostController {
|
||||
|
||||
@Get('/')
|
||||
@Paginator
|
||||
async getPaginate(@Query() query: PostPagerDto) {
|
||||
async getPaginate(
|
||||
@Query() query: PostPagerDto,
|
||||
@IsAuthenticated() isAuthenticated: boolean,
|
||||
) {
|
||||
const { size, select, page, year, sortBy, sortOrder, truncate } = query
|
||||
|
||||
return this.postService.model
|
||||
@@ -44,6 +52,8 @@ export class PostController {
|
||||
{
|
||||
$match: {
|
||||
...addYearCondition(year),
|
||||
// 非认证用户只能看到已发布的文章
|
||||
...(isAuthenticated ? {} : { isPublished: true }),
|
||||
},
|
||||
},
|
||||
// @see https://stackoverflow.com/questions/54810712/mongodb-sort-by-field-a-if-field-b-null-otherwise-sort-by-field-c
|
||||
@@ -137,8 +147,10 @@ export class PostController {
|
||||
}
|
||||
|
||||
@Get('/:id')
|
||||
@Auth()
|
||||
async getById(@Param() params: MongoIdDto) {
|
||||
async getById(
|
||||
@Param() params: MongoIdDto,
|
||||
@IsAuthenticated() isAuthenticated: boolean,
|
||||
) {
|
||||
const { id } = params
|
||||
const doc = await this.postService.model
|
||||
.findById(id)
|
||||
@@ -151,13 +163,28 @@ export class PostController {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
|
||||
// 非认证用户只能查看已发布的文章
|
||||
if (!isAuthenticated && !doc.isPublished) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
|
||||
return doc
|
||||
}
|
||||
|
||||
@Get('/latest')
|
||||
async getLatest(@IpLocation() ip: IpRecord) {
|
||||
async getLatest(
|
||||
@IpLocation() ip: IpRecord,
|
||||
@IsAuthenticated() isAuthenticated: boolean,
|
||||
) {
|
||||
const query: any = {}
|
||||
|
||||
// 非认证用户只能看到已发布的文章
|
||||
if (!isAuthenticated) {
|
||||
query.isPublished = true
|
||||
}
|
||||
|
||||
const last = await this.postService.model
|
||||
.findOne({})
|
||||
.findOne(query)
|
||||
.sort({ created: -1 })
|
||||
.lean({ getters: true, autopopulate: true })
|
||||
if (!last) {
|
||||
@@ -169,6 +196,7 @@ export class PostController {
|
||||
slug: last.slug,
|
||||
},
|
||||
ip,
|
||||
isAuthenticated,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -176,12 +204,23 @@ export class PostController {
|
||||
async getByCateAndSlug(
|
||||
@Param() params: CategoryAndSlugDto,
|
||||
@IpLocation() { ip }: IpRecord,
|
||||
@IsAuthenticated() isAuthenticated?: boolean,
|
||||
) {
|
||||
const { category, slug } = params
|
||||
const postDocument = await this.postService.getPostBySlug(category, slug)
|
||||
const postDocument = await this.postService.getPostBySlug(
|
||||
category,
|
||||
slug,
|
||||
isAuthenticated,
|
||||
)
|
||||
if (!postDocument) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
|
||||
// 非认证用户只能查看已发布的文章
|
||||
if (!isAuthenticated && !postDocument.isPublished) {
|
||||
throw new CannotFindException()
|
||||
}
|
||||
|
||||
const liked = await this.countingService.getThisRecordIsLiked(
|
||||
postDocument.id,
|
||||
ip,
|
||||
@@ -223,4 +262,16 @@ export class PostController {
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@Patch('/:id/publish')
|
||||
@Auth()
|
||||
async setPublishStatus(
|
||||
@Param() params: MongoIdDto,
|
||||
@Body() body: SetPostPublishStatusDto,
|
||||
) {
|
||||
await this.postService.updateById(params.id, {
|
||||
isPublished: body.isPublished,
|
||||
})
|
||||
return { success: true }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Transform, Type } from 'class-transformer'
|
||||
import { IsInt, IsOptional, IsString } from 'class-validator'
|
||||
import { IsBoolean, IsInt, IsOptional, IsString } from 'class-validator'
|
||||
|
||||
import { PagerDto } from '~/shared/dto/pager.dto'
|
||||
|
||||
@@ -18,3 +18,8 @@ export class PostPagerDto extends PagerDto {
|
||||
@Type(() => Number)
|
||||
truncate?: number
|
||||
}
|
||||
|
||||
export class SetPostPublishStatusDto {
|
||||
@IsBoolean()
|
||||
isPublished: boolean
|
||||
}
|
||||
|
||||
@@ -72,6 +72,11 @@ export class PostModel extends WriteBaseModel {
|
||||
@IsOptional()
|
||||
copyright?: boolean
|
||||
|
||||
@prop({ default: true })
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
isPublished?: boolean
|
||||
|
||||
@prop({
|
||||
type: String,
|
||||
})
|
||||
|
||||
@@ -166,7 +166,11 @@ export class PostService {
|
||||
}
|
||||
}
|
||||
|
||||
async getPostBySlug(categorySlug: string, slug: string) {
|
||||
async getPostBySlug(
|
||||
categorySlug: string,
|
||||
slug: string,
|
||||
isAuthenticated?: boolean,
|
||||
) {
|
||||
const slugTrackerService = this.slugTrackerService
|
||||
const postModel = this.postModel
|
||||
|
||||
@@ -176,14 +180,27 @@ export class PostService {
|
||||
if (!trackedPost) {
|
||||
throw new NotFoundException('该分类未找到 (。•́︿•̀。)')
|
||||
}
|
||||
|
||||
// 检查发布状态
|
||||
if (!isAuthenticated && !trackedPost.isPublished) {
|
||||
throw new NotFoundException('该文章未找到')
|
||||
}
|
||||
|
||||
return trackedPost
|
||||
}
|
||||
|
||||
const queryConditions: any = {
|
||||
slug,
|
||||
categoryId: categoryDocument._id,
|
||||
}
|
||||
|
||||
// 非认证用户只能查看已发布的文章
|
||||
if (!isAuthenticated) {
|
||||
queryConditions.isPublished = true
|
||||
}
|
||||
|
||||
const postDocument = await this.model
|
||||
.findOne({
|
||||
slug,
|
||||
categoryId: categoryDocument._id,
|
||||
})
|
||||
.findOne(queryConditions)
|
||||
.populate('category')
|
||||
.populate({
|
||||
path: 'related',
|
||||
@@ -192,7 +209,15 @@ export class PostService {
|
||||
|
||||
if (postDocument) return postDocument
|
||||
|
||||
return findTrackedPost()
|
||||
const trackedPost = await findTrackedPost()
|
||||
|
||||
// 检查追踪文章的发布状态
|
||||
if (trackedPost && !isAuthenticated && !trackedPost.isPublished) {
|
||||
throw new NotFoundException('该文章未找到')
|
||||
}
|
||||
|
||||
return trackedPost
|
||||
|
||||
async function findTrackedPost() {
|
||||
const tracked = await slugTrackerService.findTrackerBySlug(
|
||||
`/${categorySlug}/${slug}`,
|
||||
|
||||
@@ -62,7 +62,7 @@ export class RenderEjsController {
|
||||
])
|
||||
|
||||
const isPrivateOrEncrypt =
|
||||
('hide' in document && document.hide) ||
|
||||
('isPublished' in document && !document.isPublished) ||
|
||||
('password' in document && !isNil(document.password))
|
||||
|
||||
if (!isAuthenticated && isPrivateOrEncrypt) {
|
||||
|
||||
@@ -61,7 +61,7 @@ export class SearchService {
|
||||
$or: [{ title: { $in: keywordArr } }, { text: { $in: keywordArr } }],
|
||||
$and: [
|
||||
{ password: { $not: null } },
|
||||
{ hide: { $in: showHidden ? [false, true] : [false] } },
|
||||
{ isPublished: { $in: showHidden ? [false, true] : [true] } },
|
||||
{
|
||||
$or: [
|
||||
{ publicAt: { $not: null } },
|
||||
@@ -260,7 +260,7 @@ export class SearchService {
|
||||
this.noteService.model
|
||||
.find(
|
||||
{
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
$or: [
|
||||
{ password: undefined },
|
||||
{ password: null },
|
||||
|
||||
@@ -154,7 +154,8 @@ export class SubscribeService implements OnModuleInit, OnModuleDestroy {
|
||||
const precheck: CoAction<any> = async function (
|
||||
noteOrPost: NoteModel | PostModel,
|
||||
) {
|
||||
if ('hide' in noteOrPost && noteOrPost.hide) return this.abort()
|
||||
if ('isPublished' in noteOrPost && !noteOrPost.isPublished)
|
||||
return this.abort()
|
||||
if ('password' in noteOrPost && !!noteOrPost.password) return this.abort()
|
||||
if (
|
||||
'publicAt' in noteOrPost &&
|
||||
|
||||
@@ -70,8 +70,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-20T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 20,
|
||||
@@ -88,8 +88,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-19T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 19,
|
||||
@@ -106,8 +106,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-18T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 18,
|
||||
@@ -124,8 +124,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-17T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 17,
|
||||
@@ -142,8 +142,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-16T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 16,
|
||||
@@ -160,8 +160,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-15T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 15,
|
||||
@@ -178,8 +178,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-14T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 14,
|
||||
@@ -196,8 +196,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-13T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 13,
|
||||
@@ -214,8 +214,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-12T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 12,
|
||||
@@ -232,8 +232,8 @@ exports[`NoteController (e2e) > GET /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2021-03-11T00:00:00.000Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 11,
|
||||
@@ -264,8 +264,8 @@ exports[`NoteController (e2e) > GET /notes/nid/:nid 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2023-01-17T11:01:57.851Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"liked": true,
|
||||
"modified": null,
|
||||
"mood": "happy",
|
||||
@@ -295,8 +295,8 @@ exports[`NoteController (e2e) > Get patched note 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2023-01-17T11:01:57.851Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"modified": null,
|
||||
"mood": "happy",
|
||||
"nid": 21,
|
||||
@@ -316,8 +316,8 @@ exports[`NoteController (e2e) > POST /notes 1`] = `
|
||||
"read": 0,
|
||||
},
|
||||
"created": "2023-01-17T11:01:57.851Z",
|
||||
"hide": false,
|
||||
"images": [],
|
||||
"is_published": true,
|
||||
"meta": null,
|
||||
"modified": null,
|
||||
"nid": 21,
|
||||
|
||||
@@ -9,7 +9,7 @@ export default Array.from({ length: 20 }).map((_, _i) => {
|
||||
modified: null,
|
||||
allowComment: true,
|
||||
|
||||
hide: false,
|
||||
isPublished: true,
|
||||
commentsIndex: 0,
|
||||
}
|
||||
}) as NoteModel[]
|
||||
|
||||
@@ -103,7 +103,10 @@ export class NoteController<ResponseWrapper> implements IController {
|
||||
*/
|
||||
getMiddleList(id: string, size = 5) {
|
||||
return this.proxy.list(id).get<{
|
||||
data: Pick<NoteModel, 'id' | 'title' | 'nid' | 'created' | 'hide'>[]
|
||||
data: Pick<
|
||||
NoteModel,
|
||||
'id' | 'title' | 'nid' | 'created' | 'isPublished'
|
||||
>[]
|
||||
size: number
|
||||
}>({
|
||||
params: { size },
|
||||
|
||||
@@ -2,7 +2,7 @@ import type { ModelWithLiked, TextBaseModel } from './base'
|
||||
import type { TopicModel } from './topic'
|
||||
|
||||
export interface NoteModel extends TextBaseModel {
|
||||
hide: boolean
|
||||
isPublished: boolean
|
||||
count: {
|
||||
read: number
|
||||
like: number
|
||||
|
||||
@@ -7,4 +7,14 @@ export default defineConfig({
|
||||
dts: true,
|
||||
external: ['mongodb'],
|
||||
format: ['cjs'],
|
||||
platform: 'node',
|
||||
banner: {
|
||||
js: `const __injected_import_meta_url = require("url").pathToFileURL(__filename).href;`,
|
||||
},
|
||||
esbuildOptions(options) {
|
||||
options.define = {
|
||||
...options.define,
|
||||
'import.meta.url': '__injected_import_meta_url',
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -13,11 +13,6 @@ overrides:
|
||||
whatwg-url: 14.1.1
|
||||
zod: 3.25.63
|
||||
|
||||
patchedDependencies:
|
||||
tinyexec@1.0.1:
|
||||
hash: b5c07938d1255875a3a5bceac67c4c8d729351c52498ec9f39dcec351340929c
|
||||
path: patches/tinyexec@1.0.1.patch
|
||||
|
||||
importers:
|
||||
|
||||
.:
|
||||
@@ -7152,7 +7147,7 @@ snapshots:
|
||||
'@antfu/install-pkg@1.1.0':
|
||||
dependencies:
|
||||
package-manager-detector: 1.3.0
|
||||
tinyexec: 1.0.1(patch_hash=b5c07938d1255875a3a5bceac67c4c8d729351c52498ec9f39dcec351340929c)
|
||||
tinyexec: 1.0.1
|
||||
|
||||
'@antfu/utils@8.1.1':
|
||||
optional: true
|
||||
@@ -13238,7 +13233,7 @@ snapshots:
|
||||
|
||||
tinyexec@0.3.2: {}
|
||||
|
||||
tinyexec@1.0.1(patch_hash=b5c07938d1255875a3a5bceac67c4c8d729351c52498ec9f39dcec351340929c): {}
|
||||
tinyexec@1.0.1: {}
|
||||
|
||||
tinyglobby@0.2.13:
|
||||
dependencies:
|
||||
|
||||
Reference in New Issue
Block a user