Bladeren bron

🔧 refactor(multi-tenant): 统一多租户模块导入和测试配置

- 更新认证模块测试以使用多租户实体
- 修复文件模块路由导入路径
- 统一测试数据工厂使用多租户实体
- 修复用户实体与文件模块的关联关系

🤖 Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
yourname 1 maand geleden
bovenliggende
commit
d940fdd34d

+ 5 - 8
packages/auth-module-mt/tests/integration/auth-tenant-isolation.test.ts

@@ -1,27 +1,24 @@
-import { describe, it, expect, beforeAll, afterAll } from 'vitest';
+import { describe, it, expect, beforeEach } from 'vitest';
 import { OpenAPIHono } from '@hono/zod-openapi';
 import { setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
-import { UserMt } from '@d8d/user-module-mt';
+import { UserEntityMt } from '@d8d/user-module-mt';
+import { FileMt } from '@d8d/file-module-mt';
 import { authRoutes } from '../../src/routes';
 import { AppDataSource } from '@d8d/shared-utils';
 import { UserService } from '@d8d/user-module-mt';
 
 // 设置数据库钩子
-const { setupDatabase, cleanupDatabase } = setupIntegrationDatabaseHooksWithEntities([UserMt]);
+setupIntegrationDatabaseHooksWithEntities([UserEntityMt, FileMt]);
 
 describe('租户认证隔离测试', () => {
   let testApp: OpenAPIHono;
   let userService: UserService;
 
-  beforeAll(async () => {
-    await setupDatabase();
+  beforeEach(async () => {
     testApp = authRoutes;
     userService = new UserService(AppDataSource);
   });
 
-  afterAll(async () => {
-    await cleanupDatabase();
-  });
 
   describe('用户注册和登录', () => {
     it('应该成功注册不同租户的用户', async () => {

+ 5 - 5
packages/auth-module-mt/tests/integration/auth.integration.test.ts

@@ -4,16 +4,16 @@ import {
   IntegrationTestDatabase,
   setupIntegrationDatabaseHooksWithEntities,
 } from '@d8d/shared-test-util';
-import { Role, UserEntity } from '@d8d/user-module';
-import { File } from '@d8d/file-module';
+import { RoleMt, UserEntityMt } from '@d8d/user-module-mt';
+import { FileMt } from '@d8d/file-module-mt';
 import authRoutes from '../../src/routes';
 import { AuthService } from '../../src/services';
-import { UserService } from '@d8d/user-module';
+import { UserService } from '@d8d/user-module-mt';
 import { DisabledStatus } from '@d8d/shared-types';
 import { TestDataFactory } from '../utils/test-data-factory';
 
 // 设置集成测试钩子
-setupIntegrationDatabaseHooksWithEntities([UserEntity, Role, File])
+setupIntegrationDatabaseHooksWithEntities([UserEntityMt, RoleMt, FileMt])
 
 describe('认证API集成测试 (使用hono/testing)', () => {
   let client: ReturnType<typeof testClient<typeof authRoutes>>;
@@ -34,7 +34,7 @@ describe('认证API集成测试 (使用hono/testing)', () => {
     authService = new AuthService(userService);
 
     // 创建测试用户前先删除可能存在的重复用户
-    const userRepository = dataSource.getRepository(UserEntity);
+    const userRepository = dataSource.getRepository(UserEntityMt);
     await userRepository.delete({ username: 'testuser' });
 
     testUser = await TestDataFactory.createTestUser(dataSource, {

+ 3 - 3
packages/auth-module-mt/tests/integration/phone-decrypt.integration.test.ts

@@ -2,9 +2,9 @@ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
 import { testClient } from 'hono/testing';
 import { authRoutes } from '../../src/routes';
 import { IntegrationTestDatabase, setupIntegrationDatabaseHooksWithEntities } from '@d8d/shared-test-util';
-import { Role, UserEntity } from '@d8d/user-module';
+import { RoleMt, UserEntityMt } from '@d8d/user-module-mt';
 import { redisUtil, JWTUtil } from '@d8d/shared-utils';
-import { File } from '@d8d/file-module';
+import { FileMt } from '@d8d/file-module-mt';
 
 // Mock MiniAuthService 的 decryptPhoneNumber 方法
 vi.mock('../../src/services/mini-auth.service', () => ({
@@ -28,7 +28,7 @@ vi.mock('../../src/services/mini-auth.service', () => ({
 }));
 
 // 设置集成测试钩子
-setupIntegrationDatabaseHooksWithEntities([UserEntity, File, Role])
+setupIntegrationDatabaseHooksWithEntities([UserEntityMt, FileMt, RoleMt])
 
 describe('手机号解密API集成测试', () => {
   let client: ReturnType<typeof testClient<typeof authRoutes>>;

+ 8 - 8
packages/auth-module-mt/tests/utils/test-data-factory.ts

@@ -1,6 +1,6 @@
 import { DataSource } from 'typeorm';
-import { UserEntity } from '@d8d/user-module';
-import { Role } from '@d8d/user-module';
+import { UserEntityMt } from '@d8d/user-module-mt';
+import { RoleMt } from '@d8d/user-module-mt';
 
 /**
  * 测试数据工厂类
@@ -9,7 +9,7 @@ export class TestDataFactory {
   /**
    * 创建测试用户数据
    */
-  static createUserData(overrides: Partial<UserEntity> = {}): Partial<UserEntity> {
+  static createUserData(overrides: Partial<UserEntityMt> = {}): Partial<UserEntityMt> {
     const timestamp = Date.now();
     return {
       username: `testuser_${timestamp}`,
@@ -27,7 +27,7 @@ export class TestDataFactory {
   /**
    * 创建测试角色数据
    */
-  static createRoleData(overrides: Partial<Role> = {}): Partial<Role> {
+  static createRoleData(overrides: Partial<RoleMt> = {}): Partial<RoleMt> {
     const timestamp = Date.now();
     return {
       name: `test_role_${timestamp}`,
@@ -39,9 +39,9 @@ export class TestDataFactory {
   /**
    * 在数据库中创建测试用户
    */
-  static async createTestUser(dataSource: DataSource, overrides: Partial<UserEntity> = {}): Promise<UserEntity> {
+  static async createTestUser(dataSource: DataSource, overrides: Partial<UserEntityMt> = {}): Promise<UserEntityMt> {
     const userData = this.createUserData(overrides);
-    const userRepository = dataSource.getRepository(UserEntity);
+    const userRepository = dataSource.getRepository(UserEntityMt);
 
     const user = userRepository.create(userData);
     return await userRepository.save(user);
@@ -50,9 +50,9 @@ export class TestDataFactory {
   /**
    * 在数据库中创建测试角色
    */
-  static async createTestRole(dataSource: DataSource, overrides: Partial<Role> = {}): Promise<Role> {
+  static async createTestRole(dataSource: DataSource, overrides: Partial<RoleMt> = {}): Promise<RoleMt> {
     const roleData = this.createRoleData(overrides);
-    const roleRepository = dataSource.getRepository(Role);
+    const roleRepository = dataSource.getRepository(RoleMt);
 
     const role = roleRepository.create(roleData);
     return await roleRepository.save(role);

+ 1 - 1
packages/file-module-mt/src/index.ts

@@ -8,4 +8,4 @@ export { FileService, MinioService } from './services';
 export * from './schemas';
 
 // 导出路由
-export { default as fileRoutes } from './routes';
+export { default as fileRoutesMt } from './routes';

+ 2 - 2
packages/file-module-mt/src/routes/[id]/delete.mt.ts

@@ -1,9 +1,9 @@
 import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
-import { FileService } from '../../services/file.service';
+import { FileService } from '../../services/index';
 import { ErrorSchema } from '@d8d/shared-utils';
 import { AppDataSource } from '@d8d/shared-utils';
 import { AuthContext } from '@d8d/shared-types';
-import { authMiddleware } from '@d8d/auth-module/middleware';
+import { authMiddleware } from '@d8d/auth-module-mt/middleware';
 
 // 删除文件路由
 const deleteFileRoute = createRoute({

+ 2 - 2
packages/file-module-mt/src/routes/[id]/download.mt.ts

@@ -1,9 +1,9 @@
 import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
-import { FileService } from '../../services/file.service';
+import { FileService } from '../../services/index';
 import { ErrorSchema } from '@d8d/shared-utils';
 import { AppDataSource } from '@d8d/shared-utils';
 import { AuthContext } from '@d8d/shared-types';
-import { authMiddleware } from '@d8d/auth-module/middleware';
+import { authMiddleware } from '@d8d/auth-module-mt/middleware';
 
 // 获取文件下载URL路由
 const downloadFileRoute = createRoute({

+ 2 - 2
packages/file-module-mt/src/routes/[id]/get-url.mt.ts

@@ -1,9 +1,9 @@
 import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
-import { FileService } from '../../services/file.service';
+import { FileService } from '../../services/index';
 import { ErrorSchema } from '@d8d/shared-utils';
 import { AppDataSource } from '@d8d/shared-utils';
 import { AuthContext } from '@d8d/shared-types';
-import { authMiddleware } from '@d8d/auth-module/middleware';
+import { authMiddleware } from '@d8d/auth-module-mt/middleware';
 
 // 获取文件URL路由
 const getFileUrlRoute = createRoute({

+ 1 - 1
packages/file-module-mt/src/routes/index.mt.ts

@@ -10,7 +10,7 @@ import { AuthContext } from '@d8d/shared-types';
 import { createCrudRoutes } from '@d8d/shared-crud';
 import { FileMt } from '../entities/file.entity';
 import { FileSchema, CreateFileDto, UpdateFileDto } from '../schemas/file.schema.mt';
-import { authMiddleware } from '@d8d/auth-module/middleware';
+import { authMiddleware } from '@d8d/auth-module-mt/middleware';
 
 const fileCrudRoutes = createCrudRoutes({
   entity: FileMt,

+ 2 - 1
packages/file-module-mt/src/routes/index.ts

@@ -1,2 +1,3 @@
-export { fileRoutesMt } from './index.mt';
+import { fileRoutesMt } from './index.mt';
+export { fileRoutesMt };
 export default fileRoutesMt;

+ 2 - 2
packages/file-module-mt/src/routes/multipart-complete/post.mt.ts

@@ -1,9 +1,9 @@
 import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
-import { FileService } from '../../services/file.service';
+import { FileService } from '../../services/index';
 import { ErrorSchema } from '@d8d/shared-utils';
 import { AppDataSource } from '@d8d/shared-utils';
 import { AuthContext } from '@d8d/shared-types';
-import { authMiddleware } from '@d8d/auth-module/middleware';
+import { authMiddleware } from '@d8d/auth-module-mt/middleware';
 
 // 完成分片上传请求Schema
 const CompleteMultipartUploadDto = z.object({

+ 2 - 2
packages/file-module-mt/src/routes/multipart-policy/post.mt.ts

@@ -1,9 +1,9 @@
 import { createRoute, OpenAPIHono, z } from '@hono/zod-openapi';
-import { FileService } from '../../services/file.service';
+import { FileService } from '../../services/index';
 import { ErrorSchema } from '@d8d/shared-utils';
 import { AppDataSource } from '@d8d/shared-utils';
 import { AuthContext } from '@d8d/shared-types';
-import { authMiddleware } from '@d8d/auth-module/middleware';
+import { authMiddleware } from '@d8d/auth-module-mt/middleware';
 
 // 创建分片上传策略请求Schema
 const CreateMultipartUploadPolicyDto = z.object({

+ 3 - 3
packages/user-module-mt/src/entities/user.entity.ts

@@ -1,7 +1,7 @@
 import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable, CreateDateColumn, UpdateDateColumn, ManyToOne, JoinColumn } from 'typeorm';
 import { RoleMt } from './role.entity';
 import { DeleteStatus, DisabledStatus } from '@d8d/shared-types';
-import { File } from '@d8d/file-module-mt';
+import { FileMt } from '@d8d/file-module-mt';
 
 @Entity({ name: 'users_mt' })
 export class UserEntityMt {
@@ -32,9 +32,9 @@ export class UserEntityMt {
   @Column({ name: 'avatar_file_id', type: 'int', unsigned: true, nullable: true, comment: '头像文件ID' })
   avatarFileId!: number | null;
 
-  @ManyToOne('File', { nullable: true })
+  @ManyToOne('FileMt', { nullable: true })
   @JoinColumn({ name: 'avatar_file_id', referencedColumnName: 'id' })
-  avatarFile!: File | null;
+  avatarFile!: FileMt | null;
 
   @Column({ name: 'is_disabled', type: 'int', default: DisabledStatus.ENABLED, comment: '是否禁用(0:启用,1:禁用)' })
   isDisabled!: DisabledStatus;