已完成第十一批迁移:考试维护功能已原生化到 ASP.NET Core 10。
支持考试创建、草稿修改、发布状态切换及不可逆归档。 支持科目、费用、满分和合格线策略校验。 保留已有报名禁止修改科目、待处理成绩复议禁止归档等规则。 数据修改、科目替换与审计日志使用同一数据库事务。 新增 ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED 独立开关。 路由与实现见 [AdminExamManagementService.cs (line 9)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Administration/AdminExamManagementService.cs:9) 和 [NativeAdminReadEndpoints.cs (line 133)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Web/Administration/NativeAdminReadEndpoints.cs:133)。 迁移说明已更新至 [MIGRATION.md (line 57)](C:/Users/BI/Documents/EIS-dotnet/MIGRATION.md:57)。
This commit is contained in:
1 parent
2589305f3c
commit
25501651e1
12 files changed
+688
-11
No files matched your search
@@ -45,6 +45,8 @@ ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED=false
|
||||
ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED=false
|
||||
# 工作流收件箱、同级转交与超级管理员监督调整;必须同时启用管理端基础读取。
|
||||
ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED=false
|
||||
# 考试创建、修改、发布状态及不可逆归档;必须同时启用管理端基础读取。
|
||||
ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED=false
|
||||
|
||||
# 仅在首次创建空数据库时使用。部署前务必修改初始密码。
|
||||
INITIAL_ADMIN_USERNAME=admin
|
||||
|
||||
+4
-3
@@ -12,7 +12,7 @@
|
||||
- [x] 招生公示与 HMAC 文书验真公开接口
|
||||
- [x] 登录、自主注册、Session 与 TOTP(兼容开关默认关闭)
|
||||
- [x] 考生业务
|
||||
- [ ] 管理后台、审批流和考务编排(管理端基础读取、组织维护、批量报名号审批、流程配置、通知公告、考点变更审批、考生/报名/缴费读取、考生账号维护、报名缴费写入及工作流调度已原生化)
|
||||
- [ ] 管理后台、审批流和考务编排(管理端基础读取、组织维护、批量报名号审批、流程配置、通知公告、考点变更审批、考生/报名/缴费读取、考生账号维护、报名缴费写入、工作流调度及考试维护已原生化)
|
||||
- [x] 考生志愿填报与招生录取查询
|
||||
- [ ] Excel、文书和缓存
|
||||
- [ ] 容器入口切换及 Node.js 后端移除
|
||||
@@ -54,7 +54,7 @@ $env:AUTH_NATIVE_ENABLED = 'true'
|
||||
$env:CANDIDATE_NATIVE_ENABLED = 'true'
|
||||
```
|
||||
|
||||
管理后台第一批只读接口(管理上下文、仪表盘、学校、学校组织、管理员和考试列表)已经原生化,并保留超级、校级、班级管理员的权限与数据作用域。第二批覆盖学校、班级和管理员的创建与维护、管理员密码重置及自主注册开关;更新操作与审计日志在同一事务中提交,停用或重置管理员会同步失效其会话。第三批覆盖批量报名号申领的读取、提交和审批,终审会按照当前号码规则原子生成考生账号、初始密码和待补录资料。第四批覆盖报名号规则及审批流程定义的读取与维护,并保留流程层级和批量申领终审约束。第五批覆盖完整通知公告管理:超级管理员可读取手工公告与五类系统公示、创建和编辑手工公告,并控制系统公示是否公开显示;HTML 净化、显隐更新和审计日志均由 ASP.NET Core 原生处理。第六批覆盖考点考场读取、新增与修改申请、重复待审拦截及多级审批;终审会在同一事务中更新流程、审计日志和正式考点考场档案。第七批覆盖考生档案、报名记录和已审核报名的缴费记录读取,并保持三级管理员的数据作用域、证件号脱敏、考试科目及审批流投影与 Node 一致。第八批覆盖校级按班级或年级归档及恢复考生账户、超级管理员重置考生密码、三级管理员按配置流程审核考生资料;账号与流程更新、审计日志在同一事务中提交,归档和密码重置会同步失效相关 ASP.NET Core 会话。第九批覆盖报名审核流程及缴费状态更新:多步报名终审会绑定考生报名号和当前号码规则,缴费确认及撤销会维护确认时间和操作人,所有流程、业务状态与审计日志均在同一事务中提交。第十批覆盖五类业务的工作流收件箱、当前处理人同级转交以及超级管理员指定步骤和处理人的监督调整;重新打开业务时会同步重置业务状态,并阻止已生成账号的批次重复开启。
|
||||
管理后台第一批只读接口(管理上下文、仪表盘、学校、学校组织、管理员和考试列表)已经原生化,并保留超级、校级、班级管理员的权限与数据作用域。第二批覆盖学校、班级和管理员的创建与维护、管理员密码重置及自主注册开关;更新操作与审计日志在同一事务中提交,停用或重置管理员会同步失效其会话。第三批覆盖批量报名号申领的读取、提交和审批,终审会按照当前号码规则原子生成考生账号、初始密码和待补录资料。第四批覆盖报名号规则及审批流程定义的读取与维护,并保留流程层级和批量申领终审约束。第五批覆盖完整通知公告管理:超级管理员可读取手工公告与五类系统公示、创建和编辑手工公告,并控制系统公示是否公开显示;HTML 净化、显隐更新和审计日志均由 ASP.NET Core 原生处理。第六批覆盖考点考场读取、新增与修改申请、重复待审拦截及多级审批;终审会在同一事务中更新流程、审计日志和正式考点考场档案。第七批覆盖考生档案、报名记录和已审核报名的缴费记录读取,并保持三级管理员的数据作用域、证件号脱敏、考试科目及审批流投影与 Node 一致。第八批覆盖校级按班级或年级归档及恢复考生账户、超级管理员重置考生密码、三级管理员按配置流程审核考生资料;账号与流程更新、审计日志在同一事务中提交,归档和密码重置会同步失效相关 ASP.NET Core 会话。第九批覆盖报名审核流程及缴费状态更新:多步报名终审会绑定考生报名号和当前号码规则,缴费确认及撤销会维护确认时间和操作人,所有流程、业务状态与审计日志均在同一事务中提交。第十批覆盖五类业务的工作流收件箱、当前处理人同级转交以及超级管理员指定步骤和处理人的监督调整;重新打开业务时会同步重置业务状态,并阻止已生成账号的批次重复开启。第十一批覆盖超级管理员创建和修改考试、配置科目与合格线、切换发布状态及不可逆归档;考试与科目替换、归档锁定和审计日志在同一事务中提交,并在已有报名或待处理成绩复议时保留原系统的安全拦截。
|
||||
|
||||
其余审批流和考务编排接口仍转发给 Node,因此管理端开关都要求原生认证和共享 Redis;各写入子功能还必须与只读开关一起启用:
|
||||
|
||||
@@ -70,9 +70,10 @@ $env:ADMIN_NATIVE_OPERATIONAL_READS_ENABLED = 'true'
|
||||
$env:ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED = 'true'
|
||||
$env:ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED = 'true'
|
||||
$env:ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED = 'true'
|
||||
$env:ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED = 'true'
|
||||
```
|
||||
|
||||
旧版 `ADMIN_NATIVE_NOTICE_WRITES_ENABLED` 仍可作为兼容别名使用。`GET /health/migration` 的 `administration.nativeReadsEnabled`、`administration.nativeOrganizationWritesEnabled`、`administration.nativeAccountBatchesEnabled`、`administration.nativeConfigurationEnabled`、`administration.nativeNoticeManagementEnabled`、`administration.nativeCentersEnabled`、`administration.nativeOperationalReadsEnabled`、`administration.nativeCandidateManagementEnabled`、`administration.nativeRegistrationPaymentWritesEnabled`、`administration.nativeWorkflowOperationsEnabled` 和 `administration.nativeRoutes` 会报告这些端点是否已切换。
|
||||
旧版 `ADMIN_NATIVE_NOTICE_WRITES_ENABLED` 仍可作为兼容别名使用。`GET /health/migration` 的 `administration.nativeReadsEnabled`、`administration.nativeOrganizationWritesEnabled`、`administration.nativeAccountBatchesEnabled`、`administration.nativeConfigurationEnabled`、`administration.nativeNoticeManagementEnabled`、`administration.nativeCentersEnabled`、`administration.nativeOperationalReadsEnabled`、`administration.nativeCandidateManagementEnabled`、`administration.nativeRegistrationPaymentWritesEnabled`、`administration.nativeWorkflowOperationsEnabled`、`administration.nativeExamManagementEnabled` 和 `administration.nativeRoutes` 会报告这些端点是否已切换。
|
||||
|
||||
完整的宿主、静态资源、JSON 转发和 Session Cookie 冒烟测试:
|
||||
|
||||
|
||||
@@ -446,6 +446,7 @@ try {
|
||||
ADMIN_NATIVE_CANDIDATE_MANAGEMENT_ENABLED = 'true'
|
||||
ADMIN_NATIVE_REGISTRATION_PAYMENT_WRITES_ENABLED = 'true'
|
||||
ADMIN_NATIVE_WORKFLOW_OPERATIONS_ENABLED = 'true'
|
||||
ADMIN_NATIVE_EXAM_MANAGEMENT_ENABLED = 'true'
|
||||
ADMIN_NATIVE_ALLOW_MEMORY = 'true'
|
||||
LegacyNode__Enabled = 'true'
|
||||
LegacyNode__BaseUrl = $legacyBaseUrl
|
||||
@@ -1353,6 +1354,99 @@ try {
|
||||
$restoreSettingBody = @{ enabled = $originalSelfRegistration } | ConvertTo-Json -Compress
|
||||
Invoke-RestMethod -Uri "$nativeAuthBaseUrl/api/admin/settings/self-registration" -Method Put -ContentType 'application/json' -Body $restoreSettingBody -WebSession $nativeSession | Out-Null
|
||||
|
||||
$examCreateForbidden = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams" -Method Post -ContentType 'application/json' -Body '{}' -WebSession $nativeSchoolSession -SkipHttpErrorCheck
|
||||
if ($examCreateForbidden.StatusCode -ne 403 -or $examCreateForbidden.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
|
||||
throw 'Native exam creation did not preserve the super-admin boundary'
|
||||
}
|
||||
$invalidExam = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams" -Method Post -ContentType 'application/json' -Body (@{ name = '缺少日期的考试' } | ConvertTo-Json -Compress) -WebSession $nativeSession -SkipHttpErrorCheck
|
||||
if ($invalidExam.StatusCode -ne 400 -or $invalidExam.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
|
||||
throw 'Native exam creation accepted a request without the required dates'
|
||||
}
|
||||
$invalidExamScoringBody = @{
|
||||
name = '合格线无效的考试'
|
||||
registrationStart = '2035-01-01T00:00:00.000Z'
|
||||
registrationEnd = '2035-01-10T00:00:00.000Z'
|
||||
examStart = '2035-02-01T00:00:00.000Z'
|
||||
examEnd = '2035-02-02T00:00:00.000Z'
|
||||
subjects = @(@{ name = '语文'; fullScore = 100; passRule = 'fixed_score'; passValue = 101 })
|
||||
passPolicy = 'fixed_score'
|
||||
passValue = 60
|
||||
} | ConvertTo-Json -Depth 10 -Compress
|
||||
$invalidExamScoring = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams" -Method Post -ContentType 'application/json' -Body $invalidExamScoringBody -WebSession $nativeSession -SkipHttpErrorCheck
|
||||
if ($invalidExamScoring.StatusCode -ne 400) {
|
||||
throw 'Native exam creation accepted an invalid subject passing score'
|
||||
}
|
||||
$examCode = "NATIVE-$([guid]::NewGuid().ToString('N').Substring(0, 12))"
|
||||
$examCreateBody = @{
|
||||
code = $examCode
|
||||
name = '原生迁移考试'
|
||||
description = '考试维护迁移冒烟验证'
|
||||
registrationStart = '2035-01-01T00:00:00.000Z'
|
||||
registrationEnd = '2035-01-10T00:00:00.000Z'
|
||||
examStart = '2035-02-01T00:00:00.000Z'
|
||||
examEnd = '2035-02-02T00:00:00.000Z'
|
||||
location = '迁移测试考点'
|
||||
passPolicy = 'fixed_score'
|
||||
passValue = 130
|
||||
status = 'draft'
|
||||
subjects = @(
|
||||
@{ name = '语文'; fullScore = 120; passRule = 'fixed_score'; passValue = 72; fee = 30 },
|
||||
@{ name = '英语'; fullScore = 100; passRule = 'rank_percent'; passValue = 30; fee = 25 }
|
||||
)
|
||||
} | ConvertTo-Json -Depth 10 -Compress
|
||||
$examCreateResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams" -Method Post -ContentType 'application/json' -Body $examCreateBody -WebSession $nativeSession
|
||||
$createdExam = ($examCreateResponse.Content | ConvertFrom-Json).exam
|
||||
if ($examCreateResponse.StatusCode -ne 201 -or $examCreateResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or
|
||||
$createdExam.code -ne $examCode -or $createdExam.status -ne 'draft' -or @($createdExam.subjects).Count -ne 2) {
|
||||
throw 'Native exam creation did not persist the requested draft and subjects'
|
||||
}
|
||||
$legacyExamsAfterCreate = Invoke-WebRequest -Uri "$legacyBaseUrl/api/admin/exams" -WebSession $session
|
||||
$nativeExamsAfterCreate = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams" -WebSession $nativeSession
|
||||
Assert-JsonEquivalent -Expected $legacyExamsAfterCreate.Content -Actual $nativeExamsAfterCreate.Content -Label 'Exam creation follow-up'
|
||||
|
||||
$examUpdateBody = @{
|
||||
name = '原生迁移考试(已修改)'
|
||||
location = '迁移测试新考点'
|
||||
passPolicy = 'subject_scores'
|
||||
passValue = 0
|
||||
subjects = @(
|
||||
@{ name = '综合能力'; fullScore = 100; passRule = 'fixed_score'; passValue = 60; fee = 40; start = '13:30'; end = '15:30' }
|
||||
)
|
||||
} | ConvertTo-Json -Depth 10 -Compress
|
||||
$examUpdateResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)" -Method Patch -ContentType 'application/json' -Body $examUpdateBody -WebSession $nativeSession
|
||||
$updatedExam = ($examUpdateResponse.Content | ConvertFrom-Json).exam
|
||||
if ($examUpdateResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or $updatedExam.name -ne '原生迁移考试(已修改)' -or
|
||||
$updatedExam.passPolicy -ne 'subject_scores' -or @($updatedExam.subjects).Count -ne 1 -or $updatedExam.subjects[0].start -ne '13:30') {
|
||||
throw 'Native exam update did not replace the draft configuration'
|
||||
}
|
||||
$examPublishBody = @{ status = 'published' } | ConvertTo-Json -Compress
|
||||
$examPublishResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)" -Method Patch -ContentType 'application/json' -Body $examPublishBody -WebSession $nativeSession
|
||||
if (($examPublishResponse.Content | ConvertFrom-Json).exam.status -ne 'published') {
|
||||
throw 'Native exam update did not publish the draft'
|
||||
}
|
||||
$publishedExamEdit = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)" -Method Patch -ContentType 'application/json' -Body (@{ name = '不应保存的名称' } | ConvertTo-Json -Compress) -WebSession $nativeSession -SkipHttpErrorCheck
|
||||
if ($publishedExamEdit.StatusCode -ne 409) {
|
||||
throw 'Native exam update allowed detail changes while published'
|
||||
}
|
||||
Invoke-RestMethod -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)" -Method Patch -ContentType 'application/json' -Body (@{ status = 'draft' } | ConvertTo-Json -Compress) -WebSession $nativeSession | Out-Null
|
||||
$examArchiveResponse = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)/archive" -Method Post -WebSession $nativeSession
|
||||
$archivedExam = ($examArchiveResponse.Content | ConvertFrom-Json).exam
|
||||
if ($examArchiveResponse.Headers['X-EIS-Implementation'] -ne 'aspnet-core' -or $archivedExam.status -ne 'closed' -or
|
||||
$archivedExam.registrationState -ne 'archived' -or -not $archivedExam.archivedAt -or $archivedExam.totalScore -ne 100) {
|
||||
throw 'Native exam archive did not permanently close the exam'
|
||||
}
|
||||
$duplicateExamArchive = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)/archive" -Method Post -WebSession $nativeSession -SkipHttpErrorCheck
|
||||
if ($duplicateExamArchive.StatusCode -ne 409) {
|
||||
throw 'Native exam archive did not reject a duplicate archive operation'
|
||||
}
|
||||
$archivedExamUpdate = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams/$($createdExam.id)" -Method Patch -ContentType 'application/json' -Body (@{ status = 'draft' } | ConvertTo-Json -Compress) -WebSession $nativeSession -SkipHttpErrorCheck
|
||||
if ($archivedExamUpdate.StatusCode -ne 409) {
|
||||
throw 'Native exam update did not keep archived exams locked'
|
||||
}
|
||||
$legacyExamsAfterArchive = Invoke-WebRequest -Uri "$legacyBaseUrl/api/admin/exams" -WebSession $session
|
||||
$nativeExamsAfterArchive = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/exams" -WebSession $nativeSession
|
||||
Assert-JsonEquivalent -Expected $legacyExamsAfterArchive.Content -Actual $nativeExamsAfterArchive.Content -Label 'Exam archive follow-up'
|
||||
|
||||
$noticeCreateForbidden = Invoke-WebRequest -Uri "$nativeAuthBaseUrl/api/admin/notices" -Method Post -ContentType 'application/json' -Body (@{ title = '越权公告'; content = '<p>无权发布</p>' } | ConvertTo-Json -Compress) -WebSession $nativeSchoolSession -SkipHttpErrorCheck
|
||||
if ($noticeCreateForbidden.StatusCode -ne 403 -or $noticeCreateForbidden.Headers['X-EIS-Implementation'] -ne 'aspnet-core') {
|
||||
throw 'Native notice creation did not preserve the super-admin boundary'
|
||||
@@ -1487,6 +1581,7 @@ try {
|
||||
NativeAdminCandidateManagement = 'passed'
|
||||
NativeAdminRegistrationPaymentWrites = 'passed'
|
||||
NativeAdminWorkflowOperations = 'passed'
|
||||
NativeAdminExamManagement = 'passed'
|
||||
} | Format-List
|
||||
}
|
||||
finally {
|
||||
|
||||
Loaded 3 of 12 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user