refactor: 收敛Blog WordPress Asset模块

This commit is contained in:
sunlei 2026-06-15 11:12:57 +08:00
parent cca2f9e1b4
commit ff8e3908f4
41 changed files with 215 additions and 241 deletions

View File

@ -15,7 +15,7 @@
| Domain | Deleted | Merged | Kept | Evidence | | Domain | Deleted | Merged | Kept | Evidence |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| Admin/Auth/Platform Config | `src/admin/example` if no active route evidence; empty old admin subdirectories | auth/user/role/menu/dept/component/dict/notice/system-log/timezone moved into `src/modules/admin/**`; duplicate old imports removed | route paths and public DTO class names kept | `rg '@/admin/' src test` returns no source hits; admin focused Jest passes | | Admin/Auth/Platform Config | `src/admin/example` if no active route evidence; empty old admin subdirectories | auth/user/role/menu/dept/component/dict/notice/system-log/timezone moved into `src/modules/admin/**`; duplicate old imports removed | route paths and public DTO class names kept | `rg '@/admin/' src test` returns no source hits; admin focused Jest passes |
| Blog/WordPress/Asset | none yet | none yet | current files before migration | baseline only | | Blog/WordPress/Asset | old `src/blog`, `src/wordpress`, `src/minio`; legacy module wrappers after local imports replaced | MinIO internal files renamed into Asset module; Blog and WordPress controller/service/entity files moved under target modules | existing route decorators and response DTO behavior | `rg '@/blog/|@/wordpress/|@/minio/' src test` has no hits; Blog/WordPress/Asset focused tests pass |
| Runtime/Common | none yet | none yet | current files before migration | baseline only | | Runtime/Common | none yet | none yet | current files before migration | baseline only |
| QQBot Core/NapCat | none yet | none yet | current files before migration | baseline only | | QQBot Core/NapCat | none yet | none yet | current files before migration | baseline only |
| Plugin Platform/Plugins | none yet | none yet | current files before migration | baseline only | | Plugin Platform/Plugins | none yet | none yet | current files before migration | baseline only |

View File

@ -1,31 +0,0 @@
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
import { CommonModule } from '@/common';
import { WordpressModule } from '@/wordpress/wordpress.module';
import { BlogArticleController } from './blog-article.controller';
import { BlogArticle } from './blog-article.entity';
import { BlogArticleService } from './blog-article.service';
import { BlogThemeConfigController } from './blog-theme-config.controller';
import { BlogThemeConfig } from './blog-theme-config.entity';
import { BlogThemeConfigService } from './blog-theme-config.service';
import { BlogTermController } from './blog-term.controller';
import { BlogTerm } from './blog-term.entity';
import { BlogTermService } from './blog-term.service';
@Module({
imports: [
AdminAuthGuardModule,
CommonModule,
WordpressModule,
TypeOrmModule.forFeature([BlogArticle, BlogTerm, BlogThemeConfig]),
],
controllers: [
BlogArticleController,
BlogTermController,
BlogThemeConfigController,
],
providers: [BlogArticleService, BlogTermService, BlogThemeConfigService],
exports: [BlogArticleService, BlogTermService, BlogThemeConfigService],
})
export class BlogModule {}

View File

@ -1,13 +0,0 @@
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
import { MinioClientController } from './minio.controller';
import { MinioClientService } from './minio.service';
@Module({
imports: [AdminAuthGuardModule, ConfigModule],
controllers: [MinioClientController],
providers: [MinioClientService],
exports: [MinioClientService],
})
export class MinioClientModule {}

View File

@ -17,7 +17,7 @@ import { AdminAuthService } from './admin-auth.service';
import { AdminLoginDto } from './admin-auth.dto'; import { AdminLoginDto } from './admin-auth.dto';
import { AdminPasswordCryptoService } from './admin-password-crypto.service'; import { AdminPasswordCryptoService } from './admin-password-crypto.service';
import { JwtAuthGuard } from './jwt-auth.guard'; import { JwtAuthGuard } from './jwt-auth.guard';
import { WordpressService } from '@/modules/wordpress/wordpress-mirror.service'; import { WordpressService } from '@/modules/wordpress/application/wordpress.service';
@ApiTags('Admin - 认证') @ApiTags('Admin - 认证')
@Controller() @Controller()

View File

@ -5,7 +5,7 @@ import type {
MinioListObjectOptions, MinioListObjectOptions,
MinioObjectResult, MinioObjectResult,
MinioUploadObjectOptions, MinioUploadObjectOptions,
} from './minio.types'; } from '../domain/asset-minio.types';
@Injectable() @Injectable()
export class MinioClientService { export class MinioClientService {

View File

@ -1,7 +1,8 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { MinioClientController } from '@/minio/minio.controller'; import { ConfigModule } from '@nestjs/config';
import { MinioClientModule } from '@/minio/minio.module'; import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
import { MinioClientService } from '@/minio/minio.service'; import { MinioClientService } from './application/asset-minio.service';
import { MinioClientController } from './contract/asset-minio.controller';
export const ASSET_CONTROLLERS = [MinioClientController]; export const ASSET_CONTROLLERS = [MinioClientController];
@ -41,7 +42,9 @@ export const ASSET_DOMAIN_CONTRACT = {
} as const; } as const;
@Module({ @Module({
imports: [MinioClientModule], imports: [AdminAuthGuardModule, ConfigModule],
exports: [MinioClientModule], controllers: ASSET_CONTROLLERS,
providers: ASSET_PROVIDERS,
exports: ASSET_PROVIDERS,
}) })
export class AssetModule {} export class AssetModule {}

View File

@ -21,8 +21,8 @@ import {
ApiTags, ApiTags,
} from '@nestjs/swagger'; } from '@nestjs/swagger';
import { Response } from 'express'; import { Response } from 'express';
import { MinioClientService } from './minio.service'; import { MinioClientService } from '../application/asset-minio.service';
import type { MinioUploadFile } from './minio.types'; import type { MinioUploadFile } from '../domain/asset-minio.types';
import { import {
ApiFileDownloadResponse, ApiFileDownloadResponse,
ApiArrayResponse, ApiArrayResponse,
@ -35,7 +35,7 @@ import {
MinioBucketStatusDto, MinioBucketStatusDto,
MinioObjectDto, MinioObjectDto,
MinioUploadResultDto, MinioUploadResultDto,
} from './minio.dto'; } from './asset-minio.dto';
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard'; import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
const PROXY_RESOURCE_TIMEOUT = 1000 * 15; const PROXY_RESOURCE_TIMEOUT = 1000 * 15;

View File

@ -2,19 +2,19 @@ import { HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { Brackets, Repository } from 'typeorm'; import { Brackets, Repository } from 'typeorm';
import { MarkdownService, throwVbenError, ToolsService } from '@/common'; import { MarkdownService, throwVbenError, ToolsService } from '@/common';
import { WordpressService } from '@/modules/wordpress/application/wordpress.service';
import { import {
BlogArticle, BlogArticle,
type BlogArticleStatus, type BlogArticleStatus,
type BlogArticleTerm, type BlogArticleTerm,
} from './blog-article.entity'; } from '../infrastructure/persistence/blog-article.entity';
import type { import type {
BlogArticleBodyDto, BlogArticleBodyDto,
BlogArticleImportWordpressDto, BlogArticleImportWordpressDto,
BlogArticleListQueryDto, BlogArticleListQueryDto,
BlogArticleTermOptionsQueryDto, BlogArticleTermOptionsQueryDto,
BlogArticleUpdateBodyDto, BlogArticleUpdateBodyDto,
} from './blog-article.dto'; } from '../contract/blog-article.dto';
import { WordpressService } from '@/wordpress/wordpress.service';
import { BlogTermService } from './blog-term.service'; import { BlogTermService } from './blog-term.service';
@Injectable() @Injectable()

View File

@ -5,13 +5,16 @@ import { throwVbenError, ToolsService } from '@/common';
import { import {
BlogArticle, BlogArticle,
type BlogArticleTerm, type BlogArticleTerm,
} from './blog-article.entity'; } from '../infrastructure/persistence/blog-article.entity';
import { BlogTerm, type BlogTermKind } from './blog-term.entity'; import {
BlogTerm,
type BlogTermKind,
} from '../infrastructure/persistence/blog-term.entity';
import type { import type {
BlogTermBodyDto, BlogTermBodyDto,
BlogTermListQueryDto, BlogTermListQueryDto,
BlogTermUpdateBodyDto, BlogTermUpdateBodyDto,
} from './blog-term.dto'; } from '../contract/blog-term.dto';
type CountedBlogTerm = BlogArticleTerm & { type CountedBlogTerm = BlogArticleTerm & {
count: number; count: number;

View File

@ -2,10 +2,10 @@ import { HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm'; import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm'; import { Repository } from 'typeorm';
import { throwVbenError, ToolsService } from '@/common'; import { throwVbenError, ToolsService } from '@/common';
import { WordpressService } from '@/wordpress/wordpress.service'; import { WordpressService } from '@/modules/wordpress/application/wordpress.service';
import type { WordpressArgonThemeConfig } from '@/wordpress/wordpress.types'; import type { WordpressArgonThemeConfig } from '@/modules/wordpress/domain/wordpress.types';
import { BlogThemeConfigBodyDto } from './blog-theme-config.dto'; import { BlogThemeConfigBodyDto } from '../contract/blog-theme-config.dto';
import { BlogThemeConfig } from './blog-theme-config.entity'; import { BlogThemeConfig } from '../infrastructure/persistence/blog-theme-config.entity';
const DEFAULT_THEME_ID = 'argon'; const DEFAULT_THEME_ID = 'argon';

View File

@ -1,11 +1,17 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { BlogArticleController } from '@/blog/blog-article.controller'; import { TypeOrmModule } from '@nestjs/typeorm';
import { BlogArticleService } from '@/blog/blog-article.service'; import { CommonModule } from '@/common';
import { BlogModule } from '@/blog/blog.module'; import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
import { BlogTermController } from '@/blog/blog-term.controller'; import { WordpressMirrorModule } from '@/modules/wordpress/wordpress-mirror.module';
import { BlogTermService } from '@/blog/blog-term.service'; import { BlogArticleService } from './application/blog-article.service';
import { BlogThemeConfigController } from '@/blog/blog-theme-config.controller'; import { BlogTermService } from './application/blog-term.service';
import { BlogThemeConfigService } from '@/blog/blog-theme-config.service'; import { BlogThemeConfigService } from './application/blog-theme-config.service';
import { BlogArticleController } from './contract/blog-article.controller';
import { BlogTermController } from './contract/blog-term.controller';
import { BlogThemeConfigController } from './contract/blog-theme-config.controller';
import { BlogArticle } from './infrastructure/persistence/blog-article.entity';
import { BlogTerm } from './infrastructure/persistence/blog-term.entity';
import { BlogThemeConfig } from './infrastructure/persistence/blog-theme-config.entity';
export const BLOG_CONTENT_CONTROLLERS = [ export const BLOG_CONTENT_CONTROLLERS = [
BlogArticleController, BlogArticleController,
@ -60,7 +66,14 @@ export const BLOG_CONTENT_DOMAIN_CONTRACT = {
} as const; } as const;
@Module({ @Module({
imports: [BlogModule], imports: [
exports: [BlogModule], AdminAuthGuardModule,
CommonModule,
WordpressMirrorModule,
TypeOrmModule.forFeature([BlogArticle, BlogTerm, BlogThemeConfig]),
],
controllers: BLOG_CONTENT_CONTROLLERS,
providers: BLOG_CONTENT_PROVIDERS,
exports: BLOG_CONTENT_PROVIDERS,
}) })
export class BlogContentModule {} export class BlogContentModule {}

View File

@ -19,7 +19,7 @@ import {
BlogArticleTermOptionsQueryDto, BlogArticleTermOptionsQueryDto,
BlogArticleUpdateBodyDto, BlogArticleUpdateBodyDto,
} from './blog-article.dto'; } from './blog-article.dto';
import { BlogArticleService } from './blog-article.service'; import { BlogArticleService } from '../application/blog-article.service';
@ApiTags('Blog - 文章') @ApiTags('Blog - 文章')
@Controller('blog/article') @Controller('blog/article')

View File

@ -1,5 +1,8 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import type { BlogArticleStatus, BlogArticleTerm } from './blog-article.entity'; import type {
BlogArticleStatus,
BlogArticleTerm,
} from '../infrastructure/persistence/blog-article.entity';
export class BlogArticleListQueryDto { export class BlogArticleListQueryDto {
@ApiPropertyOptional({ @ApiPropertyOptional({

View File

@ -12,13 +12,13 @@ import {
import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard'; import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
import { vbenSuccess } from '@/common'; import { vbenSuccess } from '@/common';
import type { BlogTermKind } from './blog-term.entity'; import type { BlogTermKind } from '../infrastructure/persistence/blog-term.entity';
import { import {
BlogTermBodyDto, BlogTermBodyDto,
BlogTermListQueryDto, BlogTermListQueryDto,
BlogTermUpdateBodyDto, BlogTermUpdateBodyDto,
} from './blog-term.dto'; } from './blog-term.dto';
import { BlogTermService } from './blog-term.service'; import { BlogTermService } from '../application/blog-term.service';
@ApiTags('Blog - 分类标签') @ApiTags('Blog - 分类标签')
@Controller('blog') @Controller('blog')

View File

@ -12,7 +12,7 @@ import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard'; import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
import { Public, vbenSuccess } from '@/common'; import { Public, vbenSuccess } from '@/common';
import { BlogThemeConfigBodyDto } from './blog-theme-config.dto'; import { BlogThemeConfigBodyDto } from './blog-theme-config.dto';
import { BlogThemeConfigService } from './blog-theme-config.service'; import { BlogThemeConfigService } from '../application/blog-theme-config.service';
@ApiTags('Blog - 主题') @ApiTags('Blog - 主题')
@Controller('blog/theme') @Controller('blog/theme')

View File

@ -1,5 +1,5 @@
import { ApiPropertyOptional } from '@nestjs/swagger'; import { ApiPropertyOptional } from '@nestjs/swagger';
import type { WordpressArgonThemeConfig } from '@/wordpress/wordpress.types'; import type { WordpressArgonThemeConfig } from '@/modules/wordpress/domain/wordpress.types';
export class BlogThemeConfigBodyDto { export class BlogThemeConfigBodyDto {
@ApiPropertyOptional({ @ApiPropertyOptional({

View File

@ -1,7 +1,7 @@
import { Column, Entity, PrimaryColumn } from 'typeorm'; import { Column, Entity, PrimaryColumn } from 'typeorm';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { KtCreateDateColumn, KtDateTime, KtUpdateDateColumn } from '@/common'; import { KtCreateDateColumn, KtDateTime, KtUpdateDateColumn } from '@/common';
import type { WordpressArgonThemeConfig } from '@/wordpress/wordpress.types'; import type { WordpressArgonThemeConfig } from '@/modules/wordpress/domain/wordpress.types';
@Entity('blog_theme_config') @Entity('blog_theme_config')
export class BlogThemeConfig { export class BlogThemeConfig {

View File

@ -10,7 +10,7 @@ import type {
WordpressArticleListQueryDto, WordpressArticleListQueryDto,
WordpressTermBodyDto, WordpressTermBodyDto,
WordpressTermListQueryDto, WordpressTermListQueryDto,
} from './wordpress.dto'; } from '../contract/wordpress.dto';
import type { import type {
WordpressAuthContext, WordpressAuthContext,
WordpressAvailabilityCache, WordpressAvailabilityCache,
@ -22,7 +22,7 @@ import type {
WordpressResponse, WordpressResponse,
WordpressArgonThemeConfig, WordpressArgonThemeConfig,
WordpressArgonMenuItem, WordpressArgonMenuItem,
} from './wordpress.types'; } from '../domain/wordpress.types';
const WORDPRESS_COOKIE_PREFIXES = [ const WORDPRESS_COOKIE_PREFIXES = [
'wordpress_', 'wordpress_',

View File

@ -19,7 +19,7 @@ import {
WordpressArticleListQueryDto, WordpressArticleListQueryDto,
WordpressArticleUpdateBodyDto, WordpressArticleUpdateBodyDto,
} from './wordpress.dto'; } from './wordpress.dto';
import { WordpressService } from './wordpress.service'; import { WordpressService } from '../application/wordpress.service';
@ApiTags('WordPress - 文章') @ApiTags('WordPress - 文章')
@ApiHeader({ @ApiHeader({

View File

@ -10,7 +10,7 @@ import { ApiHeader, ApiOperation, ApiTags } from '@nestjs/swagger';
import type { Request, Response } from 'express'; import type { Request, Response } from 'express';
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard'; import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
import { Public, vbenSuccess } from '@/common'; import { Public, vbenSuccess } from '@/common';
import { WordpressService } from './wordpress.service'; import { WordpressService } from '../application/wordpress.service';
@ApiTags('WordPress - 认证') @ApiTags('WordPress - 认证')
@ApiHeader({ @ApiHeader({

View File

@ -19,7 +19,7 @@ import {
WordpressTermListQueryDto, WordpressTermListQueryDto,
WordpressTermUpdateBodyDto, WordpressTermUpdateBodyDto,
} from './wordpress.dto'; } from './wordpress.dto';
import { WordpressService } from './wordpress.service'; import { WordpressService } from '../application/wordpress.service';
@ApiTags('WordPress - 分类') @ApiTags('WordPress - 分类')
@ApiHeader({ @ApiHeader({

View File

@ -19,7 +19,7 @@ import {
WordpressTermListQueryDto, WordpressTermListQueryDto,
WordpressTermUpdateBodyDto, WordpressTermUpdateBodyDto,
} from './wordpress.dto'; } from './wordpress.dto';
import { WordpressService } from './wordpress.service'; import { WordpressService } from '../application/wordpress.service';
@ApiTags('WordPress - 标签') @ApiTags('WordPress - 标签')
@ApiHeader({ @ApiHeader({

View File

@ -2,7 +2,7 @@ import { Controller, Get, Res, UseGuards } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger'; import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard'; import { JwtAuthGuard } from '@/modules/admin/identity/auth/jwt-auth.guard';
import { Public, vbenSuccess } from '@/common'; import { Public, vbenSuccess } from '@/common';
import { WordpressService } from './wordpress.service'; import { WordpressService } from '../application/wordpress.service';
@ApiTags('WordPress - 主题') @ApiTags('WordPress - 主题')
@Controller('wordpress/theme') @Controller('wordpress/theme')

View File

@ -1,7 +1,7 @@
import type { import type {
WordpressArticleListQueryDto, WordpressArticleListQueryDto,
WordpressTermListQueryDto, WordpressTermListQueryDto,
} from './wordpress.dto'; } from '../contract/wordpress.dto';
export type WordpressAuthContext = { export type WordpressAuthContext = {
authorization?: string; authorization?: string;

View File

@ -1,11 +1,11 @@
import { Module } from '@nestjs/common'; import { Module } from '@nestjs/common';
import { WordpressArticleController } from '@/wordpress/wordpress-article.controller'; import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
import { WordpressAuthController } from '@/wordpress/wordpress-auth.controller'; import { WordpressService } from './application/wordpress.service';
import { WordpressCategoryController } from '@/wordpress/wordpress-category.controller'; import { WordpressArticleController } from './contract/wordpress-article.controller';
import { WordpressModule } from '@/wordpress/wordpress.module'; import { WordpressAuthController } from './contract/wordpress-auth.controller';
import { WordpressService } from '@/wordpress/wordpress.service'; import { WordpressCategoryController } from './contract/wordpress-category.controller';
import { WordpressTagController } from '@/wordpress/wordpress-tag.controller'; import { WordpressTagController } from './contract/wordpress-tag.controller';
import { WordpressThemeController } from '@/wordpress/wordpress-theme.controller'; import { WordpressThemeController } from './contract/wordpress-theme.controller';
export const WORDPRESS_MIRROR_CONTROLLERS = [ export const WORDPRESS_MIRROR_CONTROLLERS = [
WordpressAuthController, WordpressAuthController,
@ -53,7 +53,9 @@ export const WORDPRESS_MIRROR_DOMAIN_CONTRACT = {
} as const; } as const;
@Module({ @Module({
imports: [WordpressModule], imports: [AdminAuthGuardModule],
exports: [WordpressModule], controllers: WORDPRESS_MIRROR_CONTROLLERS,
providers: WORDPRESS_MIRROR_PROVIDERS,
exports: WORDPRESS_MIRROR_PROVIDERS,
}) })
export class WordpressMirrorModule {} export class WordpressMirrorModule {}

View File

@ -1 +0,0 @@
export { WordpressService } from '@/wordpress/wordpress.service';

View File

@ -1,22 +0,0 @@
import { Module } from '@nestjs/common';
import { AdminAuthGuardModule } from '@/modules/admin/identity/auth/admin-auth-guard.module';
import { WordpressArticleController } from './wordpress-article.controller';
import { WordpressAuthController } from './wordpress-auth.controller';
import { WordpressCategoryController } from './wordpress-category.controller';
import { WordpressService } from './wordpress.service';
import { WordpressTagController } from './wordpress-tag.controller';
import { WordpressThemeController } from './wordpress-theme.controller';
@Module({
imports: [AdminAuthGuardModule],
controllers: [
WordpressAuthController,
WordpressArticleController,
WordpressTagController,
WordpressCategoryController,
WordpressThemeController,
],
providers: [WordpressService],
exports: [WordpressService],
})
export class WordpressModule {}

View File

@ -19,20 +19,20 @@ import {
SaveBodyInterceptor, SaveBodyInterceptor,
ToolsService, ToolsService,
} from '../src/common'; } from '../src/common';
import { BlogArticleController } from '../src/blog/blog-article.controller'; import { BlogArticleService } from '../src/modules/blog/application/blog-article.service';
import { BlogArticleService } from '../src/blog/blog-article.service'; import { BlogTermService } from '../src/modules/blog/application/blog-term.service';
import { BlogThemeConfigController } from '../src/blog/blog-theme-config.controller'; import { BlogThemeConfigService } from '../src/modules/blog/application/blog-theme-config.service';
import { BlogThemeConfigService } from '../src/blog/blog-theme-config.service'; import { BlogArticleController } from '../src/modules/blog/contract/blog-article.controller';
import { BlogTermController } from '../src/blog/blog-term.controller'; import { BlogTermController } from '../src/modules/blog/contract/blog-term.controller';
import { BlogTermService } from '../src/blog/blog-term.service'; import { BlogThemeConfigController } from '../src/modules/blog/contract/blog-theme-config.controller';
import { MinioClientController } from '../src/minio/minio.controller'; import { MinioClientService } from '../src/modules/asset/application/asset-minio.service';
import { MinioClientService } from '../src/minio/minio.service'; import { MinioClientController } from '../src/modules/asset/contract/asset-minio.controller';
import { WordpressArticleController } from '../src/wordpress/wordpress-article.controller'; import { WordpressService } from '../src/modules/wordpress/application/wordpress.service';
import { WordpressAuthController } from '../src/wordpress/wordpress-auth.controller'; import { WordpressArticleController } from '../src/modules/wordpress/contract/wordpress-article.controller';
import { WordpressCategoryController } from '../src/wordpress/wordpress-category.controller'; import { WordpressAuthController } from '../src/modules/wordpress/contract/wordpress-auth.controller';
import { WordpressService } from '../src/wordpress/wordpress.service'; import { WordpressCategoryController } from '../src/modules/wordpress/contract/wordpress-category.controller';
import { WordpressTagController } from '../src/wordpress/wordpress-tag.controller'; import { WordpressTagController } from '../src/modules/wordpress/contract/wordpress-tag.controller';
import { WordpressThemeController } from '../src/wordpress/wordpress-theme.controller'; import { WordpressThemeController } from '../src/modules/wordpress/contract/wordpress-theme.controller';
import { PinoLogger } from 'nestjs-pino'; import { PinoLogger } from 'nestjs-pino';
import { import {
collectControllerRoutes, collectControllerRoutes,

View File

@ -1,10 +1,10 @@
import { getRepositoryToken } from '@nestjs/typeorm'; import { getRepositoryToken } from '@nestjs/typeorm';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { MarkdownService, ToolsService } from '../../src/common'; import { MarkdownService, ToolsService } from '../../src/common';
import { BlogArticle } from '../../src/blog/blog-article.entity'; import { BlogArticleService } from '../../src/modules/blog/application/blog-article.service';
import { BlogArticleService } from '../../src/blog/blog-article.service'; import { BlogTermService } from '../../src/modules/blog/application/blog-term.service';
import { BlogTermService } from '../../src/blog/blog-term.service'; import { BlogArticle } from '../../src/modules/blog/infrastructure/persistence/blog-article.entity';
import { WordpressService } from '../../src/wordpress/wordpress.service'; import { WordpressService } from '../../src/modules/wordpress/application/wordpress.service';
describe('BlogArticleService', () => { describe('BlogArticleService', () => {
let service: BlogArticleService; let service: BlogArticleService;

View File

@ -1,9 +1,9 @@
import { getRepositoryToken } from '@nestjs/typeorm'; import { getRepositoryToken } from '@nestjs/typeorm';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { ToolsService } from '../../src/common'; import { ToolsService } from '../../src/common';
import { BlogArticle } from '../../src/blog/blog-article.entity'; import { BlogTermService } from '../../src/modules/blog/application/blog-term.service';
import { BlogTerm } from '../../src/blog/blog-term.entity'; import { BlogArticle } from '../../src/modules/blog/infrastructure/persistence/blog-article.entity';
import { BlogTermService } from '../../src/blog/blog-term.service'; import { BlogTerm } from '../../src/modules/blog/infrastructure/persistence/blog-term.entity';
describe('BlogTermService', () => { describe('BlogTermService', () => {
let service: BlogTermService; let service: BlogTermService;

View File

@ -1,9 +1,9 @@
import { getRepositoryToken } from '@nestjs/typeorm'; import { getRepositoryToken } from '@nestjs/typeorm';
import { Test } from '@nestjs/testing'; import { Test } from '@nestjs/testing';
import { ToolsService } from '../../src/common'; import { ToolsService } from '../../src/common';
import { BlogThemeConfig } from '../../src/blog/blog-theme-config.entity'; import { BlogThemeConfigService } from '../../src/modules/blog/application/blog-theme-config.service';
import { BlogThemeConfigService } from '../../src/blog/blog-theme-config.service'; import { BlogThemeConfig } from '../../src/modules/blog/infrastructure/persistence/blog-theme-config.entity';
import { WordpressService } from '../../src/wordpress/wordpress.service'; import { WordpressService } from '../../src/modules/wordpress/application/wordpress.service';
describe('BlogThemeConfigService', () => { describe('BlogThemeConfigService', () => {
let service: BlogThemeConfigService; let service: BlogThemeConfigService;

View File

@ -3,16 +3,17 @@ jest.mock('../../../src/modules/qqbot/core/qqbot-core.module', () => ({
})); }));
import { MODULE_METADATA } from '@nestjs/common/constants'; import { MODULE_METADATA } from '@nestjs/common/constants';
import { ConfigModule } from '@nestjs/config';
import { AppModule } from '../../../src/app.module'; import { AppModule } from '../../../src/app.module';
import { MinioClientController } from '../../../src/minio/minio.controller'; import { AdminAuthGuardModule } from '../../../src/modules/admin/identity/auth/admin-auth-guard.module';
import { MinioClientModule } from '../../../src/minio/minio.module';
import { MinioClientService } from '../../../src/minio/minio.service';
import { import {
ASSET_CONTROLLERS, ASSET_CONTROLLERS,
ASSET_DOMAIN_CONTRACT, ASSET_DOMAIN_CONTRACT,
ASSET_PROVIDERS, ASSET_PROVIDERS,
AssetModule, AssetModule,
} from '../../../src/modules/asset/asset.module'; } from '../../../src/modules/asset/asset.module';
import { MinioClientService } from '../../../src/modules/asset/application/asset-minio.service';
import { MinioClientController } from '../../../src/modules/asset/contract/asset-minio.controller';
import { AdminPlatformConfigModule } from '../../../src/modules/admin/platform-config/admin-platform-config.module'; import { AdminPlatformConfigModule } from '../../../src/modules/admin/platform-config/admin-platform-config.module';
import { import {
collectControllerRoutes, collectControllerRoutes,
@ -24,18 +25,13 @@ const getModuleMetadata = <T>(moduleClass: unknown, key: string): T[] => {
return Reflect.getMetadata(key, moduleClass) || []; return Reflect.getMetadata(key, moduleClass) || [];
}; };
const expectControllersNotRegisteredDirectly = ( const expectNoModuleNamed = (modules: unknown[], moduleName: string) => {
moduleClass: unknown, expect(
controllers: unknown[], modules.some(
) => { (moduleRef) =>
const directControllers = getModuleMetadata( typeof moduleRef === 'function' && moduleRef.name === moduleName,
moduleClass, ),
MODULE_METADATA.CONTROLLERS, ).toBe(false);
);
for (const controller of controllers) {
expect(directControllers).not.toContain(controller);
}
}; };
describe('Asset module contract', () => { describe('Asset module contract', () => {
@ -62,30 +58,34 @@ describe('Asset module contract', () => {
expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).toEqual( expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).toEqual(
expect.arrayContaining([AssetModule]), expect.arrayContaining([AssetModule]),
); );
expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).not.toEqual(
expect.arrayContaining([MinioClientModule]),
);
expect( expect(
getModuleMetadata(AdminPlatformConfigModule, MODULE_METADATA.IMPORTS), getModuleMetadata(AdminPlatformConfigModule, MODULE_METADATA.IMPORTS),
).toEqual(expect.arrayContaining([AssetModule])); ).toEqual(expect.arrayContaining([AssetModule]));
expect(
getModuleMetadata(AdminPlatformConfigModule, MODULE_METADATA.IMPORTS),
).not.toEqual(expect.arrayContaining([MinioClientModule]));
expect(getModuleMetadata(AssetModule, MODULE_METADATA.IMPORTS)).toEqual( const appImports = getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS);
expect.arrayContaining([MinioClientModule]), const platformImports = getModuleMetadata(
AdminPlatformConfigModule,
MODULE_METADATA.IMPORTS,
); );
expect(getModuleMetadata(AssetModule, MODULE_METADATA.EXPORTS)).toEqual( const assetImports = getModuleMetadata(AssetModule, MODULE_METADATA.IMPORTS);
expect.arrayContaining([MinioClientModule]), const assetExports = getModuleMetadata(AssetModule, MODULE_METADATA.EXPORTS);
expectNoModuleNamed(appImports, 'MinioClientModule');
expectNoModuleNamed(platformImports, 'MinioClientModule');
expectNoModuleNamed(assetImports, 'MinioClientModule');
expectNoModuleNamed(assetExports, 'MinioClientModule');
expect(assetImports).toEqual(
expect.arrayContaining([AdminAuthGuardModule, ConfigModule]),
); );
expectControllersNotRegisteredDirectly(AssetModule, ASSET_CONTROLLERS);
expect( expect(
getModuleMetadata(MinioClientModule, MODULE_METADATA.CONTROLLERS), getModuleMetadata(AssetModule, MODULE_METADATA.CONTROLLERS),
).toEqual(expect.arrayContaining([MinioClientController])); ).toEqual(expect.arrayContaining([MinioClientController]));
expect( expect(
getModuleMetadata(MinioClientModule, MODULE_METADATA.PROVIDERS), getModuleMetadata(AssetModule, MODULE_METADATA.PROVIDERS),
).toEqual(expect.arrayContaining([MinioClientService])); ).toEqual(expect.arrayContaining([MinioClientService]));
expect(assetExports).toEqual(expect.arrayContaining([MinioClientService]));
expect(ASSET_CONTROLLERS).toEqual( expect(ASSET_CONTROLLERS).toEqual(
expect.arrayContaining([MinioClientController]), expect.arrayContaining([MinioClientController]),
); );

View File

@ -4,19 +4,21 @@ jest.mock('../../../src/modules/qqbot/core/qqbot-core.module', () => ({
import { MODULE_METADATA } from '@nestjs/common/constants'; import { MODULE_METADATA } from '@nestjs/common/constants';
import { AppModule } from '../../../src/app.module'; import { AppModule } from '../../../src/app.module';
import { BlogArticleController } from '../../../src/blog/blog-article.controller'; import { CommonModule } from '../../../src/common';
import { BlogArticleService } from '../../../src/blog/blog-article.service'; import { AdminAuthGuardModule } from '../../../src/modules/admin/identity/auth/admin-auth-guard.module';
import { BlogModule } from '../../../src/blog/blog.module'; import { BlogArticleService } from '../../../src/modules/blog/application/blog-article.service';
import { BlogTermController } from '../../../src/blog/blog-term.controller'; import { BlogTermService } from '../../../src/modules/blog/application/blog-term.service';
import { BlogTermService } from '../../../src/blog/blog-term.service'; import { BlogThemeConfigService } from '../../../src/modules/blog/application/blog-theme-config.service';
import { BlogThemeConfigController } from '../../../src/blog/blog-theme-config.controller'; import { BlogArticleController } from '../../../src/modules/blog/contract/blog-article.controller';
import { BlogThemeConfigService } from '../../../src/blog/blog-theme-config.service'; import { BlogTermController } from '../../../src/modules/blog/contract/blog-term.controller';
import { BlogThemeConfigController } from '../../../src/modules/blog/contract/blog-theme-config.controller';
import { import {
BLOG_CONTENT_CONTROLLERS, BLOG_CONTENT_CONTROLLERS,
BLOG_CONTENT_DOMAIN_CONTRACT, BLOG_CONTENT_DOMAIN_CONTRACT,
BLOG_CONTENT_PROVIDERS, BLOG_CONTENT_PROVIDERS,
BlogContentModule, BlogContentModule,
} from '../../../src/modules/blog/blog-content.module'; } from '../../../src/modules/blog/blog-content.module';
import { WordpressMirrorModule } from '../../../src/modules/wordpress/wordpress-mirror.module';
import { import {
collectControllerRoutes, collectControllerRoutes,
routeKey, routeKey,
@ -27,18 +29,13 @@ const getModuleMetadata = <T>(moduleClass: unknown, key: string): T[] => {
return Reflect.getMetadata(key, moduleClass) || []; return Reflect.getMetadata(key, moduleClass) || [];
}; };
const expectControllersNotRegisteredDirectly = ( const expectNoModuleNamed = (modules: unknown[], moduleName: string) => {
moduleClass: unknown, expect(
controllers: unknown[], modules.some(
) => { (moduleRef) =>
const directControllers = getModuleMetadata( typeof moduleRef === 'function' && moduleRef.name === moduleName,
moduleClass, ),
MODULE_METADATA.CONTROLLERS, ).toBe(false);
);
for (const controller of controllers) {
expect(directControllers).not.toContain(controller);
}
}; };
describe('Blog content module contract', () => { describe('Blog content module contract', () => {
@ -81,29 +78,48 @@ describe('Blog content module contract', () => {
expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).toEqual( expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).toEqual(
expect.arrayContaining([BlogContentModule]), expect.arrayContaining([BlogContentModule]),
); );
expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).not.toEqual(
expect.arrayContaining([BlogModule]),
);
expect( const appImports = getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS);
getModuleMetadata(BlogContentModule, MODULE_METADATA.IMPORTS), const blogImports = getModuleMetadata(
).toEqual(expect.arrayContaining([BlogModule]));
expect(
getModuleMetadata(BlogContentModule, MODULE_METADATA.EXPORTS),
).toEqual(expect.arrayContaining([BlogModule]));
expectControllersNotRegisteredDirectly(
BlogContentModule, BlogContentModule,
BLOG_CONTENT_CONTROLLERS, MODULE_METADATA.IMPORTS,
);
const blogExports = getModuleMetadata(
BlogContentModule,
MODULE_METADATA.EXPORTS,
); );
expect(getModuleMetadata(BlogModule, MODULE_METADATA.CONTROLLERS)).toEqual( expectNoModuleNamed(appImports, 'BlogModule');
expectNoModuleNamed(blogImports, 'BlogModule');
expectNoModuleNamed(blogExports, 'BlogModule');
expect(blogImports).toEqual(
expect.arrayContaining([
AdminAuthGuardModule,
CommonModule,
WordpressMirrorModule,
]),
);
expect(
blogImports.some(
(moduleRef: any) => moduleRef?.module?.name === 'TypeOrmModule',
),
).toBe(true);
expect(getModuleMetadata(BlogContentModule, MODULE_METADATA.CONTROLLERS)).toEqual(
expect.arrayContaining([ expect.arrayContaining([
BlogArticleController, BlogArticleController,
BlogTermController, BlogTermController,
BlogThemeConfigController, BlogThemeConfigController,
]), ]),
); );
expect(getModuleMetadata(BlogModule, MODULE_METADATA.PROVIDERS)).toEqual( expect(getModuleMetadata(BlogContentModule, MODULE_METADATA.PROVIDERS)).toEqual(
expect.arrayContaining([
BlogArticleService,
BlogTermService,
BlogThemeConfigService,
]),
);
expect(blogExports).toEqual(
expect.arrayContaining([ expect.arrayContaining([
BlogArticleService, BlogArticleService,
BlogTermService, BlogTermService,

View File

@ -4,20 +4,20 @@ jest.mock('../../../src/modules/qqbot/core/qqbot-core.module', () => ({
import { MODULE_METADATA } from '@nestjs/common/constants'; import { MODULE_METADATA } from '@nestjs/common/constants';
import { AppModule } from '../../../src/app.module'; import { AppModule } from '../../../src/app.module';
import { AdminAuthGuardModule } from '../../../src/modules/admin/identity/auth/admin-auth-guard.module';
import { AdminIdentityModule } from '../../../src/modules/admin/identity/admin-identity.module'; import { AdminIdentityModule } from '../../../src/modules/admin/identity/admin-identity.module';
import { WordpressService } from '../../../src/modules/wordpress/application/wordpress.service';
import { WordpressArticleController } from '../../../src/modules/wordpress/contract/wordpress-article.controller';
import { WordpressAuthController } from '../../../src/modules/wordpress/contract/wordpress-auth.controller';
import { WordpressCategoryController } from '../../../src/modules/wordpress/contract/wordpress-category.controller';
import { WordpressTagController } from '../../../src/modules/wordpress/contract/wordpress-tag.controller';
import { WordpressThemeController } from '../../../src/modules/wordpress/contract/wordpress-theme.controller';
import { import {
WORDPRESS_MIRROR_CONTROLLERS, WORDPRESS_MIRROR_CONTROLLERS,
WORDPRESS_MIRROR_DOMAIN_CONTRACT, WORDPRESS_MIRROR_DOMAIN_CONTRACT,
WORDPRESS_MIRROR_PROVIDERS, WORDPRESS_MIRROR_PROVIDERS,
WordpressMirrorModule, WordpressMirrorModule,
} from '../../../src/modules/wordpress/wordpress-mirror.module'; } from '../../../src/modules/wordpress/wordpress-mirror.module';
import { WordpressArticleController } from '../../../src/wordpress/wordpress-article.controller';
import { WordpressAuthController } from '../../../src/wordpress/wordpress-auth.controller';
import { WordpressCategoryController } from '../../../src/wordpress/wordpress-category.controller';
import { WordpressModule } from '../../../src/wordpress/wordpress.module';
import { WordpressService } from '../../../src/wordpress/wordpress.service';
import { WordpressTagController } from '../../../src/wordpress/wordpress-tag.controller';
import { WordpressThemeController } from '../../../src/wordpress/wordpress-theme.controller';
import { import {
collectControllerRoutes, collectControllerRoutes,
routeKey, routeKey,
@ -28,18 +28,13 @@ const getModuleMetadata = <T>(moduleClass: unknown, key: string): T[] => {
return Reflect.getMetadata(key, moduleClass) || []; return Reflect.getMetadata(key, moduleClass) || [];
}; };
const expectControllersNotRegisteredDirectly = ( const expectNoModuleNamed = (modules: unknown[], moduleName: string) => {
moduleClass: unknown, expect(
controllers: unknown[], modules.some(
) => { (moduleRef) =>
const directControllers = getModuleMetadata( typeof moduleRef === 'function' && moduleRef.name === moduleName,
moduleClass, ),
MODULE_METADATA.CONTROLLERS, ).toBe(false);
);
for (const controller of controllers) {
expect(directControllers).not.toContain(controller);
}
}; };
describe('WordPress mirror module contract', () => { describe('WordPress mirror module contract', () => {
@ -79,29 +74,34 @@ describe('WordPress mirror module contract', () => {
expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).toEqual( expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).toEqual(
expect.arrayContaining([WordpressMirrorModule]), expect.arrayContaining([WordpressMirrorModule]),
); );
expect(getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS)).not.toEqual(
expect.arrayContaining([WordpressModule]),
);
expect( expect(
getModuleMetadata(AdminIdentityModule, MODULE_METADATA.IMPORTS), getModuleMetadata(AdminIdentityModule, MODULE_METADATA.IMPORTS),
).toEqual(expect.arrayContaining([WordpressMirrorModule])); ).toEqual(expect.arrayContaining([WordpressMirrorModule]));
expect(
getModuleMetadata(AdminIdentityModule, MODULE_METADATA.IMPORTS),
).not.toEqual(expect.arrayContaining([WordpressModule]));
expect( const appImports = getModuleMetadata(AppModule, MODULE_METADATA.IMPORTS);
getModuleMetadata(WordpressMirrorModule, MODULE_METADATA.IMPORTS), const identityImports = getModuleMetadata(
).toEqual(expect.arrayContaining([WordpressModule])); AdminIdentityModule,
expect( MODULE_METADATA.IMPORTS,
getModuleMetadata(WordpressMirrorModule, MODULE_METADATA.EXPORTS), );
).toEqual(expect.arrayContaining([WordpressModule])); const wordpressImports = getModuleMetadata(
expectControllersNotRegisteredDirectly(
WordpressMirrorModule, WordpressMirrorModule,
WORDPRESS_MIRROR_CONTROLLERS, MODULE_METADATA.IMPORTS,
);
const wordpressExports = getModuleMetadata(
WordpressMirrorModule,
MODULE_METADATA.EXPORTS,
); );
expectNoModuleNamed(appImports, 'WordpressModule');
expectNoModuleNamed(identityImports, 'WordpressModule');
expectNoModuleNamed(wordpressImports, 'WordpressModule');
expectNoModuleNamed(wordpressExports, 'WordpressModule');
expect(wordpressImports).toEqual(
expect.arrayContaining([AdminAuthGuardModule]),
);
expect( expect(
getModuleMetadata(WordpressModule, MODULE_METADATA.CONTROLLERS), getModuleMetadata(WordpressMirrorModule, MODULE_METADATA.CONTROLLERS),
).toEqual( ).toEqual(
expect.arrayContaining([ expect.arrayContaining([
WordpressAuthController, WordpressAuthController,
@ -112,8 +112,9 @@ describe('WordPress mirror module contract', () => {
]), ]),
); );
expect( expect(
getModuleMetadata(WordpressModule, MODULE_METADATA.PROVIDERS), getModuleMetadata(WordpressMirrorModule, MODULE_METADATA.PROVIDERS),
).toEqual(expect.arrayContaining([WordpressService])); ).toEqual(expect.arrayContaining([WordpressService]));
expect(wordpressExports).toEqual(expect.arrayContaining([WordpressService]));
expect(WORDPRESS_MIRROR_CONTROLLERS).toEqual( expect(WORDPRESS_MIRROR_CONTROLLERS).toEqual(
expect.arrayContaining([ expect.arrayContaining([
WordpressAuthController, WordpressAuthController,

View File

@ -1,7 +1,7 @@
import { createServer, type Server } from 'node:http'; import { createServer, type Server } from 'node:http';
import { ConfigService } from '@nestjs/config'; import { ConfigService } from '@nestjs/config';
import { MarkdownService, ToolsService } from '../../src/common'; import { MarkdownService, ToolsService } from '../../src/common';
import { WordpressService } from '../../src/wordpress/wordpress.service'; import { WordpressService } from '../../src/modules/wordpress/application/wordpress.service';
describe('WordpressService theme config', () => { describe('WordpressService theme config', () => {
const rootPayload = { const rootPayload = {