refactor(server): remove Department/UserDepartment entities, CampusScope, and departmentId from all entities
- Delete department.entity.ts, user-department.entity.ts - Remove Department/UserDepartment from entities/index.ts - Remove departmentId column from 18 entities (AttendanceRecord, ArchiveAttachment, Bill, ClassSchedule, Classroom, ClassroomRental, Deposit, DepositInstallment, ExamScore, LearningRecord, Occupancy, PersonalExpense, ResultArchive, Room, RoomExpense, Student, StudentEnrollment, StudentProfile, StudentReport) - Remove departments/ module entirely - Delete campus-scope.ts, campus-scope.middleware.ts (request-utils.ts kept — it's just IP extraction) - Simplify common.module.ts to empty module - Remove CampusScopeMiddleware from app.module.ts - Remove all CampusScope injections and filter calls across all services - Remove departmentId from all DTOs and controllers - Simplify dingtalk/wecom sync to only sync users (no dept table) - Update seed module to remove department seeding - Clean frontend compilation
This commit is contained in:
@@ -1,13 +0,0 @@
|
||||
import { Injectable, NestMiddleware } from '@nestjs/common';
|
||||
import { Request, Response, NextFunction } from 'express';
|
||||
import { CampusScope, CampusRequest } from './campus-scope';
|
||||
|
||||
@Injectable()
|
||||
export class CampusScopeMiddleware implements NestMiddleware {
|
||||
constructor(private readonly scope: CampusScope) {}
|
||||
|
||||
use(req: Request, _res: Response, next: NextFunction): void {
|
||||
(req as CampusRequest).campusScope = this.scope;
|
||||
next();
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
import { Injectable, Scope, Inject } from '@nestjs/common';
|
||||
import { REQUEST } from '@nestjs/core';
|
||||
import { In } from 'typeorm';
|
||||
import { Request } from 'express';
|
||||
import { DepartmentsService } from '../departments/departments.service';
|
||||
|
||||
export interface CampusRequest extends Request {
|
||||
user?: {
|
||||
id: number;
|
||||
isSuperAdmin?: boolean;
|
||||
};
|
||||
campusScope?: CampusScope;
|
||||
}
|
||||
|
||||
@Injectable({ scope: Scope.REQUEST })
|
||||
export class CampusScope {
|
||||
constructor(
|
||||
@Inject(REQUEST) private req: CampusRequest,
|
||||
private departmentsService: DepartmentsService,
|
||||
) {}
|
||||
|
||||
get userId(): number | undefined {
|
||||
return this.req.user?.id;
|
||||
}
|
||||
|
||||
get isSuperAdmin(): boolean {
|
||||
return this.req.user?.isSuperAdmin ?? false;
|
||||
}
|
||||
|
||||
get currentDepartmentId(): number | null {
|
||||
const raw = this.req.headers?.['x-campus-id'];
|
||||
if (raw === undefined) return null;
|
||||
const str = Array.isArray(raw) ? raw[0] : raw;
|
||||
if (!str) return null;
|
||||
const id = parseInt(str, 10);
|
||||
return Number.isNaN(id) ? null : id;
|
||||
}
|
||||
|
||||
/** Appends departmentId filter. No campus selected = no filtering for super admin; empty result for others. */
|
||||
async filter<T extends Record<string, unknown>>(where: T): Promise<T> {
|
||||
if (this.isSuperAdmin && !this.currentDepartmentId) {
|
||||
return where;
|
||||
}
|
||||
|
||||
const ids = await this.getEffectiveScopeIds();
|
||||
if (ids.length === 0) {
|
||||
// Non-super-admin with no scoping → match nothing, never leak unfiltered data
|
||||
if (!this.isSuperAdmin) {
|
||||
return { ...where, departmentId: In([]) };
|
||||
}
|
||||
return where;
|
||||
}
|
||||
|
||||
return { ...where, departmentId: In(ids) };
|
||||
}
|
||||
|
||||
/** Returns department IDs for QueryBuilder .andWhere(). null = no filtering. */
|
||||
async getScopeDepartmentIds(): Promise<number[] | null> {
|
||||
if (this.isSuperAdmin && !this.currentDepartmentId) return null;
|
||||
const ids = await this.getEffectiveScopeIds();
|
||||
return ids.length > 0 ? ids : null;
|
||||
}
|
||||
|
||||
private async getEffectiveScopeIds(): Promise<number[]> {
|
||||
if (this.currentDepartmentId) {
|
||||
return this.departmentsService.getDescendantIds(this.currentDepartmentId);
|
||||
}
|
||||
|
||||
if (!this.userId) return [];
|
||||
|
||||
const userDeptIds = await this.departmentsService.getUserDepartments(this.userId);
|
||||
const allIds = await Promise.all(
|
||||
userDeptIds.map((id) => this.departmentsService.getDescendantIds(id)),
|
||||
);
|
||||
return [...new Set(allIds.flat())];
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,4 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { CampusScope } from './campus-scope';
|
||||
import { CampusScopeMiddleware } from './campus-scope.middleware';
|
||||
import { DepartmentsModule } from '../departments/departments.module';
|
||||
|
||||
@Module({
|
||||
imports: [DepartmentsModule],
|
||||
providers: [CampusScope, CampusScopeMiddleware],
|
||||
exports: [CampusScope, CampusScopeMiddleware, DepartmentsModule],
|
||||
})
|
||||
@Module({})
|
||||
export class CommonModule {}
|
||||
|
||||
Reference in New Issue
Block a user