修复1
This commit is contained in:
@@ -1,4 +1,9 @@
|
|||||||
export function createSessionManager({ sessions, readDb, sendError }) {
|
export function createSessionManager({ sessions, readDb, sendError }) {
|
||||||
|
function normalizeUser(user) {
|
||||||
|
if (user?.role === 'admin' && !user.adminLevel) return { ...user, adminLevel: 'super' };
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
function parseCookies(request) {
|
function parseCookies(request) {
|
||||||
return Object.fromEntries(String(request.headers.cookie || '').split(';').map(part => part.trim()).filter(Boolean).map(part => {
|
return Object.fromEntries(String(request.headers.cookie || '').split(';').map(part => part.trim()).filter(Boolean).map(part => {
|
||||||
const index = part.indexOf('=');
|
const index = part.indexOf('=');
|
||||||
@@ -15,7 +20,7 @@ export function createSessionManager({ sessions, readDb, sendError }) {
|
|||||||
}
|
}
|
||||||
const db = await readDb();
|
const db = await readDb();
|
||||||
const user = db.users.find(item => item.id === session.userId) || null;
|
const user = db.users.find(item => item.id === session.userId) || null;
|
||||||
return user?.active === false || user?.archivedAt ? null : user;
|
return user?.active === false || user?.archivedAt ? null : normalizeUser(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
function safeUser(user) {
|
function safeUser(user) {
|
||||||
@@ -23,7 +28,7 @@ export function createSessionManager({ sessions, readDb, sendError }) {
|
|||||||
id: user.id,
|
id: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
role: user.role,
|
role: user.role,
|
||||||
adminLevel: user.adminLevel || null,
|
adminLevel: user.role === 'admin' ? user.adminLevel || 'super' : null,
|
||||||
schoolId: user.schoolId || null,
|
schoolId: user.schoolId || null,
|
||||||
classId: user.classId || null,
|
classId: user.classId || null,
|
||||||
displayName: user.displayName,
|
displayName: user.displayName,
|
||||||
|
|||||||
+23
-1
@@ -72,7 +72,18 @@ process.env.DATABASE_CLIENT = 'sqlite';
|
|||||||
process.env.SQLITE_PATH = testDb;
|
process.env.SQLITE_PATH = testDb;
|
||||||
const seededTestDatabase = await createDatabase({
|
const seededTestDatabase = await createDatabase({
|
||||||
root,
|
root,
|
||||||
seed: () => createSeedDatabase({ nowIso: () => new Date().toISOString(), hashPassword })
|
seed: () => {
|
||||||
|
const state = createSeedDatabase({ nowIso: () => new Date().toISOString(), hashPassword });
|
||||||
|
const currentSuperAdmin = state.users.find(user => user.role === 'admin' && user.adminLevel === 'super');
|
||||||
|
state.users.push({
|
||||||
|
...currentSuperAdmin,
|
||||||
|
id: 'admin_legacy_super',
|
||||||
|
username: 'legacy_super',
|
||||||
|
adminLevel: null,
|
||||||
|
displayName: '旧版超级管理员'
|
||||||
|
});
|
||||||
|
return state;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
await seededTestDatabase.close();
|
await seededTestDatabase.close();
|
||||||
|
|
||||||
@@ -116,6 +127,7 @@ function createClient() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const admin = createClient();
|
const admin = createClient();
|
||||||
|
const legacyAdmin = createClient();
|
||||||
const schoolAdmin = createClient();
|
const schoolAdmin = createClient();
|
||||||
const schoolAdmin2 = createClient();
|
const schoolAdmin2 = createClient();
|
||||||
const classAdmin = createClient();
|
const classAdmin = createClient();
|
||||||
@@ -210,6 +222,8 @@ try {
|
|||||||
const loginAdmin = await admin.request('/api/auth/login', { method: 'POST', body: { username: 'admin', password: '12345678' } });
|
const loginAdmin = await admin.request('/api/auth/login', { method: 'POST', body: { username: 'admin', password: '12345678' } });
|
||||||
assert.equal(loginAdmin.data.user.role, 'admin');
|
assert.equal(loginAdmin.data.user.role, 'admin');
|
||||||
assert.equal(loginAdmin.data.user.adminLevel, 'super', '默认管理员应为超级管理员');
|
assert.equal(loginAdmin.data.user.adminLevel, 'super', '默认管理员应为超级管理员');
|
||||||
|
const loginLegacyAdmin = await legacyAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'legacy_super', password: '12345678' } });
|
||||||
|
assert.equal(loginLegacyAdmin.data.user.adminLevel, 'super', '未保存层级的旧版管理员登录后应规范化为超级管理员');
|
||||||
assert.equal((await schoolAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'school_admin', password: '12345678' } })).data.user.adminLevel, 'school');
|
assert.equal((await schoolAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'school_admin', password: '12345678' } })).data.user.adminLevel, 'school');
|
||||||
assert.equal((await schoolAdmin2.request('/api/auth/login', { method: 'POST', body: { username: 'school_admin_2', password: '12345678' } })).data.user.adminLevel, 'school');
|
assert.equal((await schoolAdmin2.request('/api/auth/login', { method: 'POST', body: { username: 'school_admin_2', password: '12345678' } })).data.user.adminLevel, 'school');
|
||||||
assert.equal((await classAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'class_admin', password: '12345678' } })).data.user.adminLevel, 'class');
|
assert.equal((await classAdmin.request('/api/auth/login', { method: 'POST', body: { username: 'class_admin', password: '12345678' } })).data.user.adminLevel, 'class');
|
||||||
@@ -258,6 +272,9 @@ try {
|
|||||||
assert.ok(adminDirectory.data.admins.filter(item => item.adminLevel === 'school' && item.schoolId === 'school_hz1').length >= 2, '同一学校应支持多个同级管理员');
|
assert.ok(adminDirectory.data.admins.filter(item => item.adminLevel === 'school' && item.schoolId === 'school_hz1').length >= 2, '同一学校应支持多个同级管理员');
|
||||||
const schoolCenters = await schoolAdmin.request('/api/admin/centers');
|
const schoolCenters = await schoolAdmin.request('/api/admin/centers');
|
||||||
assert.ok(schoolCenters.data.centers.every(item => item.schoolId === 'school_hz1'), '校级管理员只能读取本校考点');
|
assert.ok(schoolCenters.data.centers.every(item => item.schoolId === 'school_hz1'), '校级管理员只能读取本校考点');
|
||||||
|
const legacySuperCenters = await legacyAdmin.request('/api/admin/centers');
|
||||||
|
assert.ok(legacySuperCenters.data.centers.some(item => item.schoolId === 'school_hz3'), '旧版超级管理员应能跨校读取学校维护的正式考点');
|
||||||
|
assert.ok(legacySuperCenters.data.centers.flatMap(item => item.rooms).some(item => item.centerId === 'center_hz3'), '旧版超级管理员应能读取其他学校维护的结构化考场');
|
||||||
const newCenter = await schoolAdmin.request('/api/admin/centers', { method: 'POST', body: {
|
const newCenter = await schoolAdmin.request('/api/admin/centers', { method: 'POST', body: {
|
||||||
code: 'HZ01-EAST', name: '海州市第一中学东区考点', provinceCode: '320000', cityCode: '320700', districtCode: '320706', address: '测试路 8 号', contact: '0518-12345678',
|
code: 'HZ01-EAST', name: '海州市第一中学东区考点', provinceCode: '320000', cityCode: '320700', districtCode: '320706', address: '测试路 8 号', contact: '0518-12345678',
|
||||||
managerName: '测试负责人', managerPhone: '13800001234', emergencyPhone: '0518-120', gateOpenTime: '07:00', transport: '东门入场', status: 'active', notes: '自动化测试档案',
|
managerName: '测试负责人', managerPhone: '13800001234', emergencyPhone: '0518-120', gateOpenTime: '07:00', transport: '东门入场', status: 'active', notes: '自动化测试档案',
|
||||||
@@ -265,6 +282,9 @@ try {
|
|||||||
} });
|
} });
|
||||||
assert.equal(newCenter.response.status, 202, '新增考点应创建审批申请而不是直接落库');
|
assert.equal(newCenter.response.status, 202, '新增考点应创建审批申请而不是直接落库');
|
||||||
assert.equal(newCenter.data.changeRequest.schoolId, 'school_hz1', '校级管理员新增考点必须自动归属本校');
|
assert.equal(newCenter.data.changeRequest.schoolId, 'school_hz1', '校级管理员新增考点必须自动归属本校');
|
||||||
|
const legacyPendingCenters = await legacyAdmin.request('/api/admin/centers');
|
||||||
|
const legacyPendingCenter = legacyPendingCenters.data.changeRequests.find(item => item.id === newCenter.data.changeRequest.id);
|
||||||
|
assert.equal(legacyPendingCenter?.rooms[0]?.code, 'E001', '旧版超级管理员应能读取学校提交的待审批考点与考场快照');
|
||||||
const beforeCenterApproval = await schoolAdmin.request('/api/admin/centers');
|
const beforeCenterApproval = await schoolAdmin.request('/api/admin/centers');
|
||||||
assert.ok(!beforeCenterApproval.data.centers.some(item => item.code === 'HZ01-EAST'), '考点审批通过前不得进入正式档案');
|
assert.ok(!beforeCenterApproval.data.centers.some(item => item.code === 'HZ01-EAST'), '考点审批通过前不得进入正式档案');
|
||||||
const approveCenter = await admin.request(`/api/admin/center-change-requests/${newCenter.data.changeRequest.id}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '考务条件核验通过' } });
|
const approveCenter = await admin.request(`/api/admin/center-change-requests/${newCenter.data.changeRequest.id}`, { method: 'PATCH', body: { status: 'approved', reviewNote: '考务条件核验通过' } });
|
||||||
@@ -273,6 +293,8 @@ try {
|
|||||||
const createdCenter = afterCenterApproval.data.centers.find(item => item.code === 'HZ01-EAST');
|
const createdCenter = afterCenterApproval.data.centers.find(item => item.code === 'HZ01-EAST');
|
||||||
assert.equal(createdCenter.rooms.length, 1, '审批通过后应同时写入结构化考场');
|
assert.equal(createdCenter.rooms.length, 1, '审批通过后应同时写入结构化考场');
|
||||||
assert.equal(createdCenter.totalCapacity, 30, '考场容量应汇总到考点档案');
|
assert.equal(createdCenter.totalCapacity, 30, '考场容量应汇总到考点档案');
|
||||||
|
const legacyApprovedCenter = (await legacyAdmin.request('/api/admin/centers')).data.centers.find(item => item.code === 'HZ01-EAST');
|
||||||
|
assert.equal(legacyApprovedCenter?.rooms[0]?.code, 'E001', '旧版超级管理员应能读取学校维护并审批生效的考点与考场');
|
||||||
const centerUpdate = await schoolAdmin.request(`/api/admin/centers/${createdCenter.id}`, { method: 'PATCH', body: {
|
const centerUpdate = await schoolAdmin.request(`/api/admin/centers/${createdCenter.id}`, { method: 'PATCH', body: {
|
||||||
...createdCenter, managerName: '变更后负责人', rooms: [
|
...createdCenter, managerName: '变更后负责人', rooms: [
|
||||||
...createdCenter.rooms,
|
...createdCenter.rooms,
|
||||||
|
|||||||
Reference in New Issue
Block a user