feat: init configs module

This commit is contained in:
Innei
2021-09-03 15:26:59 +08:00
parent e99d9754af
commit deca66e471
10 changed files with 1055 additions and 2 deletions

View File

@@ -18,8 +18,9 @@ import { AnalyzeMiddleware } from './common/middlewares/analyze.middleware'
import { SkipBrowserDefaultRequestMiddleware } from './common/middlewares/favicon.middleware'
import { SecurityMiddleware } from './common/middlewares/security.middleware'
import { AuthModule } from './modules/auth/auth.module'
// must after post
import { CategoryModule } from './modules/category/category.module'
import { CommentModule } from './modules/comment/comment.module'
import { ConfigsModule } from './modules/configs/configs.module'
import { InitModule } from './modules/init/init.module'
import { PostModule } from './modules/post/post.module'
import { UserModule } from './modules/user/user.module'
@@ -49,6 +50,8 @@ import { HelperModule } from './processors/helper/helper.module'
CategoryModule,
AuthModule,
UserModule,
CommentModule,
ConfigsModule,
GatewayModule,
HelperModule,

View File

@@ -0,0 +1,757 @@
[
"刷单",
"快递代发",
"淘宝",
"代发",
"兼职",
"招聘",
"网络",
"招聘",
"有意者",
"到货",
"本店",
"代购",
"扣扣",
"客服",
"微店",
"兼职",
"兼值",
"淘宝",
"小姐",
"妓女",
"包夜",
"3P",
"LY",
"狼友",
"技师",
"推油",
"胸推",
"BT",
"毒龙",
"口爆",
"兼职",
"楼凤",
"足交",
"口暴",
"口交",
"全套",
"SM",
"桑拿",
"吞精",
"咪咪",
"婊子",
"乳方",
"操逼",
"全职",
"性伴侣",
"网购",
"网络工作",
"代理",
"专业代理",
"帮忙点一下",
"帮忙点下",
"请点击进入",
"详情请进入",
"私人侦探",
"私家侦探",
"针孔摄象",
"调查婚外情",
"信用卡提现",
"无抵押贷款",
"广告代理",
"原音铃声",
"借腹生子",
"找个妈妈",
"找个爸爸",
"代孕妈妈",
"代生孩子",
"代开发票",
"腾讯客服电话",
"销售热线",
"免费订购热线",
"低价出售",
"款到发货",
"回复可见",
"连锁加盟",
"加盟连锁",
"免费二级域名",
"免费使用",
"免费索取",
"蚁力神",
"婴儿汤",
"售肾",
"刻章办",
"买小车",
"套牌车",
"玛雅网",
"电脑传讯",
"视频来源",
"下载速度",
"高清在线",
"全集在线",
"在线播放",
"txt下载",
"六位qq",
"6位qq",
"位的qq",
"个qb",
"送qb",
"用刀横向切腹",
"完全自杀手册",
"四海帮",
"足球投注",
"地下钱庄",
"中国复兴党",
"阿波罗网",
"曾道人",
"六合彩",
"改卷内幕",
"替考试",
"隐形耳机",
"出售答案",
"考中答案",
"答an",
"da案",
"资金周转",
"救市",
"股市圈钱",
"崩盘",
"资金短缺",
"证监会",
"质押贷款",
"小额贷款",
"周小川",
"刘明康",
"尚福林",
"孔丹",
"爱液",
"按摩棒",
"拔出来",
"爆草",
"包二奶",
"暴干",
"暴奸",
"暴乳",
"爆乳",
"暴淫",
"被操",
"被插",
"被干",
"逼奸",
"仓井空",
"插暴",
"操逼",
"操黑",
"操烂",
"肏你",
"肏死",
"操死",
"操我",
"厕奴",
"插比",
"插b",
"插逼",
"插进",
"插你",
"插我",
"插阴",
"潮吹",
"潮喷",
"成人电影",
"成人论坛",
"成人色情",
"成人网站",
"成人文学",
"成人小说",
"艳情小说",
"成人游戏",
"吃精",
"抽插",
"春药",
"大波",
"大力抽送",
"大乳",
"荡妇",
"荡女",
"盗撮",
"发浪",
"放尿",
"肥逼",
"粉穴",
"风月大陆",
"干死你",
"干穴",
"肛交",
"肛门",
"龟头",
"裹本",
"国产av",
"好嫩",
"豪乳",
"黑逼",
"后庭",
"后穴",
"虎骑",
"换妻俱乐部",
"黄片",
"几吧",
"鸡吧",
"鸡巴",
"鸡奸",
"妓女",
"奸情",
"叫床",
"脚交",
"精液",
"就去日",
"巨屌",
"菊花洞",
"菊门",
"巨奶",
"巨乳",
"菊穴",
"开苞",
"口爆",
"口活",
"口交",
"口射",
"口淫",
"裤袜",
"狂操",
"狂插",
"浪逼",
"浪妇",
"浪叫",
"浪女",
"狼友",
"聊性",
"凌辱",
"漏乳",
"露b",
"乱交",
"乱伦",
"轮暴",
"轮操",
"轮奸",
"裸陪",
"买春",
"美逼",
"美少妇",
"美乳",
"美腿",
"美穴",
"美幼",
"秘唇",
"迷奸",
"密穴",
"蜜穴",
"蜜液",
"摸奶",
"摸胸",
"母奸",
"奈美",
"奶子",
"男奴",
"内射",
"嫩逼",
"嫩女",
"嫩穴",
"捏弄",
"女优",
"炮友",
"砲友",
"喷精",
"屁眼",
"前凸后翘",
"强jian",
"强暴",
"强奸处女",
"情趣用品",
"情色",
"拳交",
"全裸",
"群交",
"人妻",
"人兽",
"日逼",
"日烂",
"肉棒",
"肉逼",
"肉唇",
"肉洞",
"肉缝",
"肉棍",
"肉茎",
"肉具",
"揉乳",
"肉穴",
"肉欲",
"乳爆",
"乳房",
"乳沟",
"乳交",
"乳头",
"骚逼",
"骚比",
"骚女",
"骚水",
"骚穴",
"色逼",
"色界",
"色猫",
"色盟",
"色情网站",
"色区",
"色色",
"色诱",
"色欲",
"色b",
"少年阿宾",
"射爽",
"射颜",
"食精",
"释欲",
"兽奸",
"兽交",
"手淫",
"兽欲",
"熟妇",
"熟母",
"熟女",
"爽片",
"双臀",
"死逼",
"丝袜",
"丝诱",
"松岛枫",
"酥痒",
"汤加丽",
"套弄",
"体奸",
"体位",
"舔脚",
"舔阴",
"调教",
"偷欢",
"推油",
"脱内裤",
"文做",
"舞女",
"无修正",
"吸精",
"夏川纯",
"相奸",
"小逼",
"校鸡",
"小穴",
"小xue",
"性感妖娆",
"性感诱惑",
"性虎",
"性饥渴",
"性技巧",
"性交",
"性奴",
"性虐",
"性息",
"性欲",
"胸推",
"穴口",
"穴图",
"亚情",
"颜射",
"阳具",
"杨思敏",
"要射了",
"夜勤病栋",
"一本道",
"一夜欢",
"一夜情",
"一ye情",
"阴部",
"淫虫",
"阴唇",
"淫荡",
"阴道",
"淫电影",
"阴阜",
"淫妇",
"淫河",
"阴核",
"阴户",
"淫贱",
"淫叫",
"淫教师",
"阴茎",
"阴精",
"淫浪",
"淫媚",
"淫糜",
"淫魔",
"淫母",
"淫女",
"淫虐",
"淫妻",
"淫情",
"淫色",
"淫声浪语",
"淫兽学园",
"淫书",
"淫术炼金士",
"淫水",
"淫娃",
"淫威",
"淫亵",
"淫样",
"淫液",
"淫照",
"阴b",
"应召",
"幼交",
"欲火",
"欲女",
"玉乳",
"玉穴",
"援交",
"原味内衣",
"援助交际",
"招鸡",
"招妓",
"抓胸",
"自慰",
"作爱",
"a片",
"fuck",
"gay片",
"g点",
"h动画",
"h动漫",
"失身粉",
"淫荡自慰器",
"习近平",
"平近习",
"xjp",
"习太子",
"习明泽",
"老习",
"温家宝",
"温加宝",
"温x",
"温jia宝",
"温宝宝",
"温加饱",
"温加保",
"张培莉",
"温云松",
"温如春",
"温jb",
"胡温",
"胡x",
"胡jt",
"胡boss",
"胡总",
"胡王八",
"hujintao",
"胡jintao",
"胡j涛",
"胡惊涛",
"胡景涛",
"胡紧掏",
"湖紧掏",
"胡紧套",
"锦涛",
"hjt",
"胡派",
"胡主席",
"刘永清",
"胡海峰",
"胡海清",
"江泽民",
"民泽江",
"江胡",
"江哥",
"江主席",
"江书记",
"江浙闽",
"江沢民",
"江浙民",
"择民",
"则民",
"茳泽民",
"zemin",
"ze民",
"老江",
"老j",
"江core",
"江x",
"江派",
"江zm",
"jzm",
"江戏子",
"江蛤蟆",
"江某某",
"江贼",
"江猪",
"江氏集团",
"江绵恒",
"江绵康",
"王冶坪",
"江泽慧",
"邓小平",
"平小邓",
"xiao平",
"邓xp",
"邓晓平",
"邓朴方",
"邓榕",
"邓质方",
"毛泽东",
"猫泽东",
"猫则东",
"猫贼洞",
"毛zd",
"毛zx",
"z东",
"ze东",
"泽d",
"zedong",
"毛太祖",
"毛相",
"主席画像",
"改革历程",
"朱镕基",
"朱容基",
"朱镕鸡",
"朱容鸡",
"朱云来",
"李鹏",
"李peng",
"里鹏",
"李月月鸟",
"李小鹏",
"李小琳",
"华主席",
"华国",
"国锋",
"国峰",
"锋同志",
"白春礼",
"薄熙来",
"薄一波",
"蔡赴朝",
"蔡武",
"曹刚川",
"常万全",
"陈炳德",
"陈德铭",
"陈建国",
"陈良宇",
"陈绍基",
"陈同海",
"陈至立",
"戴秉国",
"丁一平",
"董建华",
"杜德印",
"杜世成",
"傅锐",
"郭伯雄",
"郭金龙",
"贺国强",
"胡春华",
"耀邦",
"华建敏",
"黄华华",
"黄丽满",
"黄兴国",
"回良玉",
"贾庆林",
"贾廷安",
"靖志远",
"李长春",
"李春城",
"李建国",
"李克强",
"李岚清",
"李沛瑶",
"李荣融",
"李瑞环",
"李铁映",
"李先念",
"李学举",
"李源潮",
"栗智",
"梁光烈",
"廖锡龙",
"林树森",
"林炎志",
"林左鸣",
"令计划",
"柳斌杰",
"刘奇葆",
"刘少奇",
"刘延东",
"刘云山",
"刘志军",
"龙新民",
"路甬祥",
"罗箭",
"吕祖善",
"马飚",
"马恺",
"孟建柱",
"欧广源",
"强卫",
"沈跃跃",
"宋平顺",
"粟戎生",
"苏树林",
"孙家正",
"铁凝",
"屠光绍",
"王东明",
"汪东兴",
"王鸿举",
"王沪宁",
"王乐泉",
"王洛林",
"王岐山",
"王胜俊",
"王太华",
"王学军",
"王兆国",
"王振华",
"吴邦国",
"吴定富",
"吴官正",
"无官正",
"吴胜利",
"吴仪",
"奚国华",
"习仲勋",
"徐才厚",
"许其亮",
"徐绍史",
"杨洁篪",
"叶剑英",
"由喜贵",
"于幼军",
"俞正声",
"袁纯清",
"曾培炎",
"曾庆红",
"曾宪梓",
"曾荫权",
"张德江",
"张定发",
"张高丽",
"张立昌",
"张荣坤",
"张志国",
"赵洪祝",
"紫阳",
"周生贤",
"周永康",
"朱海仑",
"中南海",
"大陆当局",
"中国当局",
"北京当局",
"共产党",
"党产共",
"共贪党",
"阿共",
"产党共",
"公产党",
"工产党",
"共c党",
"共x党",
"共铲",
"供产",
"共惨",
"供铲党",
"供铲谠",
"供铲裆",
"共残党",
"共残主义",
"共产主义的幽灵",
"拱铲",
"老共",
"中共",
"中珙",
"中gong",
"gc党",
"贡挡",
"gong党",
"g产",
"狗产蛋",
"共残裆",
"恶党",
"邪党",
"共产专制",
"共产王朝",
"裆中央",
"土共",
"土g",
"共狗",
"g匪",
"共匪",
"仇共",
"政府",
"症腐",
"政腐",
"政付",
"正府",
"政俯",
"政f",
"zhengfu",
"政zhi",
"挡中央",
"档中央",
"中央领导",
"中国zf",
"中央zf",
"国wu院",
"中华帝国",
"gong和",
"大陆官方",
"北京政权",
"江泽民",
"胡锦涛",
"温家宝",
"习近平",
"习仲勋",
"贺国强",
"贺子珍",
"周永康",
"李长春",
"李德生",
"王岐山",
"姚依林",
"回良玉",
"李源潮",
"李干成",
"戴秉国",
"黄镇",
"刘延东",
"刘瑞龙",
"俞正声",
"黄敬",
"薄熙",
"薄一波",
"周小川",
"周建南",
"温云松",
"徐明",
"江泽慧",
"江绵恒",
"江绵康",
"李小鹏",
"李鹏",
"李小琳",
"朱云来",
"朱容基",
"法轮功",
"李洪志",
"新疆骚乱"
]

View File

@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common'
import { CommentService } from './comment.service'
@Module({
controllers: [],
providers: [CommentService],
exports: [CommentService],
})
export class CommentModule {}

View File

@@ -1,11 +1,23 @@
import { Injectable } from '@nestjs/common'
import { ReturnModelType } from '@typegoose/typegoose'
import { InjectModel } from 'nestjs-typegoose'
import { ConfigsService } from '../configs/configs.service'
import { NoteModel } from '../note/note.model'
import { PageModel } from '../page/page.model'
import { PostModel } from '../post/post.model'
import { CommentModel } from './comment.model'
@Injectable()
export class CommentService {
constructor(
@InjectModel(CommentModel)
private readonly commentModel: MongooseModel<CommentModel>,
@InjectModel(PostModel)
private readonly postModel: ReturnModelType<typeof PostModel>,
@InjectModel(NoteModel)
private readonly noteModel: ReturnModelType<typeof NoteModel>,
@InjectModel(PageModel)
private readonly pageModel: ReturnModelType<typeof PageModel>,
private readonly configs: ConfigsService,
) {}
}

View File

@@ -0,0 +1,131 @@
import { ApiProperty } from '@nestjs/swagger'
import { Transform, Type } from 'class-transformer'
import {
IsBoolean,
IsEmail,
IsInt,
IsNotEmpty,
IsOptional,
IsString,
IsUrl,
ValidateNested,
} from 'class-validator'
export class SEODto {
@IsString({ message: '标题必须是字符串' })
@IsNotEmpty({ message: '不能为空!!' })
@IsOptional()
@ApiProperty({ example: '我的小窝' })
title: string
@IsString({ message: '描述信息必须是字符串' })
@IsNotEmpty({ message: '不能为空!!' })
@IsOptional()
@ApiProperty({ example: '欢迎来到我的小窝' })
description: string
@IsOptional()
@IsUrl({ require_protocol: true }, { message: '站点图标必须为正确的网址' })
icon?: string
@IsString({ message: '关键字必须为一个数组', each: true })
@IsOptional()
@ApiProperty({ example: ['blog', 'mx-space'] })
keywords?: string[]
}
export class UrlDto {
@IsUrl({ require_protocol: true })
@IsOptional()
@ApiProperty({ example: 'http://127.0.0.1:2323' })
webUrl: string
@IsUrl({ require_protocol: true })
@IsOptional()
@ApiProperty({ example: 'http://127.0.0.1:9528' })
adminUrl: string
@IsUrl({ require_protocol: true })
@IsOptional()
@ApiProperty({ example: 'http://127.0.0.1:2333' })
serverUrl: string
@IsUrl()
@IsOptional()
@ApiProperty({ example: 'http://127.0.0.1:8080' })
wsUrl: string
}
class MailOption {
@IsInt()
@Transform(({ value: val }) => parseInt(val))
port: number
@IsUrl({ require_protocol: false })
host: string
}
export class MailOptionsDto {
@IsBoolean()
@IsOptional()
enable: boolean
@IsEmail()
@IsOptional()
user: string
@IsString()
@IsNotEmpty()
@IsOptional()
pass: string
@ValidateNested()
@Type(() => MailOption)
@IsOptional()
options?: MailOption
}
export class CommentOptions {
@IsBoolean()
@IsOptional()
antiSpam: boolean
@IsString({ each: true })
@IsOptional()
spamKeywords?: string[]
@IsString({ each: true })
@IsOptional()
blockIps?: string[]
@IsOptional()
@IsBoolean()
disableNoChinese?: boolean
}
export class BackupOptions {
@IsBoolean()
@IsOptional()
enable: boolean
@IsString()
@IsOptional()
SecretId?: string
@IsOptional()
@IsString()
SecretKey?: string
@IsOptional()
@IsString()
Bucket?: string
@IsString()
@IsOptional()
Region: string
}
export class BaiduSearchOptions {
@IsOptional()
@IsBoolean()
enable?: boolean
@IsOptional()
@IsString()
@IsNotEmpty()
token?: string
}

View File

@@ -0,0 +1,18 @@
import {
BackupOptions,
BaiduSearchOptions,
CommentOptions,
MailOptionsDto,
SEODto,
UrlDto,
} from './configs.dto'
export interface IConfig {
seo: SEODto
url: UrlDto
mailOptions: MailOptionsDto
commentOptions: CommentOptions
backupOptions: BackupOptions
baiduSearchOptions: BaiduSearchOptions
}
export type IConfigKeys = keyof IConfig

View File

@@ -0,0 +1,14 @@
import { modelOptions, prop, Severity } from '@typegoose/typegoose'
import { Schema } from 'mongoose'
@modelOptions({
options: { allowMixed: Severity.ALLOW, customName: 'Option' },
})
export class OptionModel {
@prop({ unique: true, required: true })
name: string
@prop({ type: Schema.Types.Mixed })
value: any
}
export const ConfigModel = OptionModel

View File

@@ -0,0 +1,18 @@
/*
* @Author: Innei
* @Date: 2020-05-08 17:02:08
* @LastEditTime: 2020-09-09 13:36:59
* @LastEditors: Innei
* @FilePath: /mx-server/src/common/global/configs/configs.module.ts
* @Copyright
*/
import { Global, Module } from '@nestjs/common'
import { ConfigsService } from './configs.service'
@Global()
@Module({
providers: [ConfigsService],
exports: [ConfigsService],
})
export class ConfigsModule {}

View File

@@ -0,0 +1,89 @@
import { Injectable, UnprocessableEntityException } from '@nestjs/common'
import { ReturnModelType } from '@typegoose/typegoose'
import { InjectModel } from 'nestjs-typegoose'
import { UserModel } from '../user/user.model'
import { BackupOptions, MailOptionsDto, SEODto, UrlDto } from './configs.dto'
import { IConfig } from './configs.interface'
import { OptionModel } from './configs.model'
@Injectable()
export class ConfigsService {
private config: IConfig = {
seo: {
title: 'mx-space',
description: 'Hello World~',
},
url: {
wsUrl: 'http://localhost:8080', //todo
adminUrl: 'http://localhost:9528',
serverUrl: 'http://localhost:2333',
webUrl: 'http://localhost:2323',
},
mailOptions: {} as MailOptionsDto,
commentOptions: { antiSpam: false },
backupOptions: { enable: false } as BackupOptions,
baiduSearchOptions: { enable: false },
}
constructor(
@InjectModel(OptionModel)
private readonly optionModel: ReturnModelType<typeof OptionModel>,
@InjectModel(UserModel)
private readonly userModel: ReturnModelType<typeof UserModel>,
) {
this.configInit()
}
protected async configInit() {
const configs = await this.optionModel.find().lean()
configs.map((field) => {
const name = field.name as keyof IConfig
const value = field.value
this.config[name] = value
})
}
public get seo() {
return this.config.seo
}
public get url() {
return this.config.url
}
async setSEO(seo: SEODto) {
return await this.patch('seo', seo)
}
async setUrl(url: UrlDto) {
return await this.patch('url', url)
}
public get<T extends keyof IConfig>(key: T): Readonly<IConfig[T]> {
return this.config[key] as Readonly<IConfig[T]>
}
public getConfig(): Readonly<IConfig> {
return this.config
}
public async patch<T extends keyof IConfig>(key: T, data: IConfig[T]) {
await this.optionModel.updateOne(
{ name: key as string },
{ value: { ...this.config[key], ...data } },
{ upsert: true, omitUndefined: true },
)
const newData = (await this.optionModel.findOne({ name: key as string }))
.value
this.config[key] = newData
return this.config[key]
}
public async getMaster() {
const master = await this.userModel.findOne()
if (!master) {
throw new UnprocessableEntityException('未初始化')
}
return master
}
}

View File

@@ -2,6 +2,7 @@ import { Global, Module } from '@nestjs/common'
import { TypegooseModule } from 'nestjs-typegoose'
import { MONGO_DB } from '~/app.config'
import { CommentModel } from '~/modules/comment/comment.model'
import { OptionModel } from '~/modules/configs/configs.model'
import { NoteModel } from '~/modules/note/note.model'
import { PageModel } from '~/modules/page/page.model'
import { CategoryModel } from '../../modules/category/category.model'
@@ -15,6 +16,7 @@ const models = TypegooseModule.forFeature([
CommentModel,
NoteModel,
PageModel,
OptionModel,
])
@Module({
imports: [