feat: update mongoose to v6

This commit is contained in:
Innei
2022-01-13 14:49:14 +08:00
parent ecbce848fa
commit 409a5e1fac
23 changed files with 738 additions and 804 deletions

View File

@@ -1,9 +1,8 @@
// @ts-check
const inquirer = require('inquirer')
const chalk = require('chalk')
const prompt = inquirer.createPromptModule()
const package = require('../package.json')
const { $ } = require('zx')
const { $, chalk } = require('zx')
const { resolve } = require('path')
const { readdirSync } = require('fs')
const PATCH_DIR = resolve(process.cwd(), './patch')

View File

@@ -7,7 +7,7 @@
"license": "MIT",
"dashboard": {
"repo": "mx-space/admin-next",
"version": "3.11.7"
"version": "3.11.8"
},
"husky": {
"hooks": {
@@ -63,30 +63,29 @@
},
"dependencies": {
"@algolia/client-search": "*",
"@nestjs/common": "8.2.4",
"@nestjs/core": "8.2.4",
"@nestjs/common": "8.2.5",
"@nestjs/core": "8.2.5",
"@nestjs/graphql": "9.1.2",
"@nestjs/jwt": "8.0.0",
"@nestjs/mapped-types": "*",
"@nestjs/passport": "8.0.1",
"@nestjs/platform-fastify": "8.2.4",
"@nestjs/platform-socket.io": "8.2.4",
"@nestjs/platform-fastify": "8.2.5",
"@nestjs/platform-socket.io": "8.2.5",
"@nestjs/schedule": "1.0.2",
"@nestjs/swagger": "5.1.5",
"@nestjs/websockets": "8.2.4",
"@nestjs/websockets": "8.2.5",
"@typegoose/auto-increment": "1.0.0",
"@typegoose/typegoose": "8.3.0",
"algoliasearch": "4.11.0",
"apollo-server-fastify": "3.5.0",
"@typegoose/typegoose": "9.4.0",
"algoliasearch": "4.12.0",
"apollo-server-fastify": "3.6.1",
"axios": "*",
"axios-retry": "3.2.4",
"bcrypt": "5.0.1",
"cache-manager": "3.6.0",
"cache-manager-ioredis": "2.1.0",
"camelcase-keys": "7.0.1",
"chalk": "*",
"class-transformer": "0.5.1",
"class-validator": "0.13.1",
"class-validator": "0.13.2",
"consola": "*",
"cos-nodejs-sdk-v5": "2.11.6",
"dayjs": "1.10.7",
@@ -105,21 +104,20 @@
"marked": "4.0.9",
"mkdirp": "*",
"mongoose": "*",
"mongoose-lean-id": "0.2.0",
"mongoose-lean-id": "0.3.0",
"mongoose-lean-virtuals": "0.9.0",
"mongoose-paginate-v2": "1.4.3",
"mongoose-paginate-v2": "1.5.0",
"nanoid": "3.1.32",
"nestjs-typegoose": "7.1.38",
"node-machine-id": "1.1.12",
"node-vibrant": "3.2.1-alpha.1",
"nodemailer": "6.7.2",
"passport": "0.5.2",
"passport-jwt": "4.0.0",
"pluralize": "*",
"redis": "3.1.2",
"reflect-metadata": "0.1.13",
"rxjs": "7.4.0",
"rxjs": "7.5.2",
"snakecase-keys": "5.1.2",
"ts-morph": "*",
"ua-parser-js": "1.0.2",
"xss": "1.0.10",
"zx": "4.2.0"
@@ -129,12 +127,12 @@
"@innei-util/prettier": "0.1.4",
"@nestjs/cli": "8.1.8",
"@nestjs/schematics": "8.0.5",
"@nestjs/testing": "8.2.4",
"@nestjs/testing": "8.2.5",
"@types/bcrypt": "5.0.0",
"@types/cache-manager": "3.4.2",
"@types/ejs": "3.1.0",
"@types/html-minifier": "4.0.2",
"@types/ioredis": "4.28.5",
"@types/ioredis": "4.28.7",
"@types/jest": "27.4.0",
"@types/js-yaml": "4.0.5",
"@types/lodash": "4.14.178",
@@ -143,13 +141,12 @@
"@types/node": "16.11.19",
"@types/nodemailer": "6.4.4",
"@types/passport-jwt": "3.0.6",
"@types/redis": "2.8.32",
"@types/ua-parser-js": "0.7.36",
"@vercel/ncc": "0.33.1",
"cross-env": "7.0.3",
"eslint": "*",
"husky": "7.0.4",
"ioredis": "*",
"ioredis": "4.28.3",
"jest": "27.4.7",
"lint-staged": "12.1.7",
"mockingoose": "2.15.2",
@@ -167,6 +164,7 @@
"webpack-node-externals": "3.0.0"
},
"resolutions": {
"typescript": "4.5.4"
"typescript": "4.5.4",
"ioredis": "4.28.3"
}
}

1285
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -54,7 +54,7 @@ exports.AXIOS_CONFIG = {
}
exports.SECURITY = {
jwtSecret: argv.jwt_secret || argv.jwtSecret || 'asjhczxiucipoiopiqm2376',
jwtSecret: argv.jwt_secret || argv.jwtSecret,
jwtExpire: '7d',
// 跳过登陆鉴权
skipAuth: isTEST ? true : false,

View File

@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common'
import { ReturnModelType } from '@typegoose/typegoose'
import dayjs from 'dayjs'
import { merge } from 'lodash'
import { PipelineStage } from 'mongoose'
import { InjectModel } from 'nestjs-typegoose'
import { RedisItems, RedisKeys } from '~/constants/cache.constant'
import { CacheService } from '~/processors/cache/cache.service'
@@ -246,7 +247,7 @@ export class AnalyzeService {
from = from ?? new Date(new Date().getTime() - 1000 * 24 * 3600 * 7)
to = to ?? new Date()
const pipeline = [
const pipeline: PipelineStage[] = [
{
$match: {
timestamp: {

View File

@@ -1,13 +1,23 @@
import { Module } from '@nestjs/common'
import { JwtModule } from '@nestjs/jwt'
import { PassportModule } from '@nestjs/passport'
import { machineIdSync } from 'node-machine-id'
import { SECURITY } from '~/app.config'
import { AdminEventsGateway } from '../../processors/gateway/admin/events.gateway'
import { AuthController } from './auth.controller'
import { AuthService } from './auth.service'
import { JwtStrategy } from './jwt.strategy'
export const __secret: any = SECURITY.jwtSecret || 'asjhczxiucipoiopiqm2376'
const getMachineId = () => {
const id = machineIdSync()
consola.log('machine-id: ', id)
return id
}
export const __secret: any =
SECURITY.jwtSecret ||
Buffer.from(getMachineId()).toString('base64').slice(0, 15) ||
'asjhczxiucipoiopiqm2376'
consola.log('JWT Secret start with :', __secret.slice(0, 5))
const jwtModule = JwtModule.registerAsync({
useFactory() {

View File

@@ -11,7 +11,7 @@ import {
ReplyMailType,
} from '~/processors/helper/helper.email.service'
import { WriteBaseModel } from '~/shared/model/base.model'
import { hasChinese, isDev } from '~/utils/index.util'
import { hasChinese } from '~/utils/index.util'
import { ConfigsService } from '../configs/configs.service'
import { UserService } from '../user/user.service'
import BlockedKeywords from './block-keywords.json'
@@ -109,7 +109,7 @@ export class CommentService {
doc.key = `#${commentIndex + 1}`
const comment = await this.commentModel.create({
...doc,
ref: Types.ObjectId(id),
ref: new Types.ObjectId(id),
refType: type,
})
@@ -185,8 +185,6 @@ export class CommentService {
{
path: 'ref',
select: 'title _id slug nid categoryId',
populate: [{ path: 'category', model: 'Category' }],
},
],
sort: { created: -1 },
@@ -196,20 +194,16 @@ export class CommentService {
return queryList
}
async sendEmail(
model: DocumentType<CommentModel>,
type: ReplyMailType,
debug?: true,
) {
async sendEmail(model: DocumentType<CommentModel>, type: ReplyMailType) {
const enable = this.configs.get('mailOptions').enable
if (!enable || (isDev && !debug)) {
if (!enable) {
return
}
this.userService.model.findOne().then(async (master) => {
const refType = model.refType
const refModel = this.getModelByRefType(refType)
const ref = await refModel.findById(model.ref).populate('category')
const refDoc = await refModel.findById(model.ref).lean()
const time = new Date(model.created)
const parent = await this.commentModel.findOne({ _id: model.parent })
@@ -221,11 +215,11 @@ export class CommentService {
to: type === ReplyMailType.Owner ? master.mail : parent.mail,
type,
source: {
title: ref.title,
title: refDoc.title,
text: model.text,
author: type === ReplyMailType.Guest ? parent.author : model.author,
master: master.name,
link: await this.resolveUrlByType(refType, ref),
link: await this.resolveUrlByType(refType, refDoc),
time: parsedTime,
mail: ReplyMailType.Owner === type ? model.mail : master.mail,
ip: model.ip || '',

View File

@@ -122,7 +122,7 @@ export class ConfigsService {
await this.optionModel.updateOne(
{ name: key as string },
{ value: merge(this.config[key], data) },
{ upsert: true, omitUndefined: true },
{ upsert: true },
)
const newData = (await this.optionModel.findOne({ name: key as string }))
.value

View File

@@ -78,7 +78,7 @@ export class MarkdownService {
slug: new Date().getTime(),
text: item.text,
...genDate(item),
categoryId: Types.ObjectId(defaultCategory._id),
categoryId: new Types.ObjectId(defaultCategory._id),
} as any as PostModel)
} else {
const category = await insertOrCreateCategory(

View File

@@ -202,8 +202,7 @@ export class NoteController {
@Put('/:id')
@Auth()
async modify(@Body() body: NoteModel, @Param() params: MongoIdDto) {
await this.noteService.updateById(params.id, body)
return await this.noteService.model.findById(params.id)
return await this.noteService.updateById(params.id, body)
}
@Patch('/:id')

View File

@@ -99,21 +99,25 @@ export class NoteService {
if (['title', 'text'].some((key) => isDefined(doc[key]))) {
doc.modified = new Date()
}
await this.noteModel.updateOne(
const updated = await this.noteModel.findOneAndUpdate(
{
_id: id,
},
{ ...doc },
{ new: true },
)
process.nextTick(async () => {
await Promise.all([
this.cacheService.clearAggregateCache(),
this.imageService.recordImageDimensions(this.noteModel, id),
this.model.findById(id).then((doc) => {
delete doc.password
this.webGateway.broadcast(EventTypes.NOTE_UPDATE, doc)
}),
])
})
return updated
}
async deleteById(id: string) {

View File

@@ -5,7 +5,6 @@ import { InjectModel } from 'nestjs-typegoose'
import { EventTypes } from '~/processors/gateway/events.types'
import { WebEventsGateway } from '~/processors/gateway/web/events.gateway'
import { ImageService } from '~/processors/helper/helper.image.service'
import { PostModel } from '../post/post.model'
import { PageModel } from './page.model'
@Injectable()
@@ -37,7 +36,7 @@ export class PageService {
}
await this.model.updateOne(
{ _id: id },
{ ...omit(doc, PostModel.protectedKeys) },
{ ...omit(doc, PageModel.protectedKeys) },
)
process.nextTick(async () => {
await Promise.all([

View File

@@ -54,7 +54,6 @@ export class PostController {
page,
select,
sort: sortBy ? { [sortBy]: sortOrder || -1 } : { created: -1 },
populate: 'category',
},
)
}
@@ -111,7 +110,7 @@ export class PostController {
@Auth()
@HttpCode(201)
async create(@Body() body: PostModel) {
const _id = Types.ObjectId()
const _id = new Types.ObjectId()
return await this.postService.create({
...body,
@@ -124,8 +123,7 @@ export class PostController {
@Put('/:id')
@Auth()
async update(@Param() params: MongoIdDto, @Body() body: PostModel) {
await this.postService.updateById(params.id, body)
return this.postService.findById(params.id)
return await this.postService.updateById(params.id, body)
}
@Patch('/:id')

View File

@@ -1,7 +1,16 @@
import { Field, ObjectType } from '@nestjs/graphql'
import { PartialType } from '@nestjs/mapped-types'
import { ApiHideProperty, ApiProperty } from '@nestjs/swagger'
import { index, modelOptions, prop, Ref, Severity } from '@typegoose/typegoose'
import {
DocumentType,
index,
modelOptions,
pre,
prop,
Ref,
Severity,
} from '@typegoose/typegoose'
import { BeAnObject } from '@typegoose/typegoose/lib/types'
import {
ArrayUnique,
IsBoolean,
@@ -10,6 +19,7 @@ import {
IsOptional,
IsString,
} from 'class-validator'
import { Query } from 'mongoose'
import {
CountMixed as Count,
Paginator,
@@ -20,6 +30,21 @@ import {
CategoryModel,
} from '../category/category.model'
function autoPopulateCategory(
this: Query<
any,
DocumentType<PostModel, BeAnObject>,
{},
DocumentType<PostModel, BeAnObject>
>,
next: () => void,
) {
this.populate({ path: 'category' })
next()
}
@pre<PostModel>('findOne', autoPopulateCategory)
@pre<PostModel>('find', autoPopulateCategory)
@index({ slug: 1 })
@index({ modified: -1 })
@index({ text: 'text' })

View File

@@ -45,7 +45,6 @@ export class PostResolver {
page,
select,
sort: sortBy ? { [sortBy]: sortOrder || -1 } : { created: -1 },
populate: 'category',
},
)

View File

@@ -8,7 +8,6 @@ import { isDefined } from 'class-validator'
import { omit } from 'lodash'
import { FilterQuery, PaginateOptions } from 'mongoose'
import { InjectModel } from 'nestjs-typegoose'
import { CannotFindException } from '~/common/exceptions/cant-find.exception'
import { CacheService } from '~/processors/cache/cache.service'
import { EventTypes } from '~/processors/gateway/events.types'
import { WebEventsGateway } from '~/processors/gateway/web/events.gateway'
@@ -75,14 +74,6 @@ export class PostService {
return res
}
async findById(id: string) {
const doc = await this.postModel.findById(id).populate('category')
if (!doc) {
throw new CannotFindException()
}
return doc
}
async updateById(id: string, data: Partial<PostModel>) {
const oldDocument = await this.postModel.findById(id).lean()
if (!oldDocument) {
@@ -105,11 +96,12 @@ export class PostService {
data.modified = now
}
await this.postModel.updateOne(
const updated = await this.postModel.findOneAndUpdate(
{
_id: id,
},
omit(data, PostModel.protectedKeys),
{ new: true },
)
process.nextTick(async () => {
// 更新图片信息缓存
@@ -122,6 +114,8 @@ export class PostService {
this.cacheService.clearAggregateCache(),
])
})
return updated
}
async deletePost(id: string) {

View File

@@ -76,7 +76,6 @@ export class SearchService {
limit: size,
page,
select,
populate: 'category',
},
),
)

View File

@@ -108,9 +108,7 @@ export class UserService {
const newCode = nanoid(10)
doc.authCode = newCode
}
return await this.userModel
.updateOne({ _id: user._id }, doc)
.setOptions({ omitUndefined: true })
return await this.userModel.updateOne({ _id: user._id }, doc)
}
/**

View File

@@ -10,16 +10,15 @@ import {
CacheOptionsFactory,
Injectable,
} from '@nestjs/common'
// import redisStore from 'cache-manager-redis-store'
import redisStore from 'cache-manager-ioredis'
import { ClientOpts } from 'redis'
import IORedis from 'ioredis'
import { REDIS } from '~/app.config'
@Injectable()
export class CacheConfigService implements CacheOptionsFactory {
// 缓存配置
public createCacheOptions(): CacheModuleOptions {
const redisOptions: ClientOpts = {
const redisOptions: IORedis.RedisOptions = {
host: REDIS.host as string,
port: REDIS.port as number,
}

View File

@@ -36,10 +36,6 @@ const models = TypegooseModule.forFeature([
TypegooseModule.forRootAsync({
useFactory: () => ({
uri: MONGO_DB.uri,
useCreateIndex: true,
useFindAndModify: false,
useNewUrlParser: true,
useUnifiedTopology: true,
autoIndex: true,
}),
}),

View File

@@ -182,23 +182,38 @@ export class EmailService {
const { user } = mailOptions
const from = `"${seo.title || 'Mx Space'}" <${user}>`
if (type === ReplyMailType.Guest) {
await this.instance.sendMail({
const options = {
from,
...{
subject: `[${seo.title || 'Mx Space'}] 主人给你了新的回复呐`,
to,
html: this.render((await this.readTemplate(type)) as string, source),
},
})
} else
await this.instance.sendMail({
}
if (isDev) {
delete options.html
Object.assign(options, { source })
this.logger.log(options)
return
}
await this.instance.sendMail(options)
} else {
const options = {
from,
...{
subject: `[${seo.title || 'Mx Space'}] 有新回复了耶~`,
to,
html: this.render((await this.readTemplate(type)) as string, source),
},
})
}
if (isDev) {
delete options.html
Object.assign(options, { source })
this.logger.log(options)
return
}
await this.instance.sendMail(options)
}
}
render(template: string, source: EmailTemplateRenderProps) {

View File

@@ -82,7 +82,6 @@ export class ImageService {
{ _id: id },
// 过滤多余的
{ images: result.filter(({ src }) => newImages.includes(src)) },
{ omitUndefined: true },
)
}

View File

@@ -38,6 +38,27 @@ describe.only('test /snippets', () => {
app = await setupE2EApp(ref)
})
beforeEach(() => {
mockingoose(model).toReturn(
{
...mockPayload1,
_id: '61dfc5e1db3c871756fa5f9c',
},
'findOne',
)
mockingoose(model).toReturn(
{
...mockPayload1,
_id: '61dfc5e1db3c871756fa5f9c',
},
'countDocuments',
)
mockTable.set('61dfc5e1db3c871756fa5f9c', {
...mockPayload1,
_id: '121212',
})
})
test('POST /snippets, should 422 with wrong name', async () => {
await app
.inject({
@@ -56,36 +77,28 @@ describe.only('test /snippets', () => {
})
})
test('POST /snippets, should return 201', async () => {
await app
.inject({
method: 'POST',
url: '/snippets',
payload: mockPayload1,
})
.then(async (res) => {
const json = res.json()
expect(res.statusCode).toBe(201)
expect(json).toBeDefined()
expect(json.name).toBe('Snippet_1')
// set mockingoose
mockingoose(model).toReturn(
{
...mockPayload1,
_id: json._id,
},
'findOne',
)
mockingoose(model).toReturn(
{
...mockPayload1,
_id: json._id,
},
'countDocuments',
)
mockTable.set(json._id, json)
})
})
// test('POST /snippets, should return 201', async () => {
// mockingoose(model).toReturn(
// {
// ...mockPayload1,
// },
// 'create',
// )
// await app
// .inject({
// method: 'POST',
// url: '/snippets',
// payload: mockPayload1,
// })
// .then(async (res) => {
// const json = res.json()
// expect(res.statusCode).toBe(201)
// expect(json).toBeDefined()
// expect(json.name).toBe('Snippet_1')
// // set mockingoose
// })
// })
test('POST /snippets, re-create same of name should return 400', async () => {
await app