fix: repair 5 sites where StudentDingMapping.studentId was misused as User FK

- dingtalk.service.ts syncOneUser: query studentRepo (not userRepo) by mapping.studentId
- sync.service.ts importDingTalkUsers: skip User role lookup for existing mappings
- attendance.service.ts autoMatchDingRecords: use studentId directly, remove second-hop query
- schedule-sync.service.ts syncAll: skip teacher mapping block (deprecated)
- rbac.service.ts getUnboundUsers: return [] (method deleted in Task 4)
This commit is contained in:
2026-07-09 17:00:00 +08:00
parent ef1b46b9f4
commit 86f126671c
5 changed files with 14 additions and 38 deletions

View File

@@ -362,28 +362,16 @@ export class AttendanceService {
if (unmatched.length === 0) return { matched: 0, total: 0 };
// Build dingUserId → userId map from the mapping table
// Build dingUserId → studentId map from the mapping table
const mappings = await this.studentDingMappingRepo.find();
const dingToUserId = new Map<string, number>();
const dingToStudentId = new Map<string, number>();
for (const m of mappings) {
dingToUserId.set(m.dingUserId, m.studentId);
}
// Build userId → studentId map (only students linked to a user)
const students = await this.studentRepo.find({
where: { userId: In([...dingToUserId.values()]) },
select: ['id', 'userId'],
});
const userIdToStudentId = new Map<number, number>();
for (const s of students) {
if (s.userId != null) userIdToStudentId.set(s.userId, s.id);
dingToStudentId.set(m.dingUserId, m.studentId);
}
let matched = 0;
for (const record of unmatched) {
const userId = dingToUserId.get(record.dingUserId);
if (userId == null) continue;
const studentId = userIdToStudentId.get(userId);
const studentId = dingToStudentId.get(record.dingUserId);
if (studentId == null) continue;
record.matchedStudentId = studentId;