学生可在“学籍管理 → 电子成绩单与证明”申请成绩单或学籍证明。
服务端根据登录账号绑定本人档案,不接受学生 ID,无法代他人申请。 成绩单仅包含正式发布成绩;无已发布成绩时明确提示。 同类型、同用途 5 分钟内重复申请复用已有有效凭证。 申请后即时生成 PDF,可在本人凭证列表下载、二维码验真。 管理员的下载记录、失效、重签能力保持不变。
This commit is contained in:
@@ -6,6 +6,7 @@ using Jiaowu.Api.Infrastructure.Auth;
|
||||
using Jiaowu.Api.Infrastructure.Caching;
|
||||
using Jiaowu.Api.Infrastructure.Exams;
|
||||
using Jiaowu.Api.Infrastructure.Middleware;
|
||||
using Jiaowu.Api.Infrastructure.OfficialDocuments;
|
||||
using Jiaowu.Api.Infrastructure.Persistence;
|
||||
using Jiaowu.Api.Infrastructure.Scheduling;
|
||||
using Jiaowu.Api.Infrastructure.Timetables;
|
||||
@@ -66,6 +67,17 @@ var databaseOptions = builder.Configuration
|
||||
var cacheOptions = builder.Configuration
|
||||
.GetSection(AppCacheOptions.SectionName)
|
||||
.Get<AppCacheOptions>() ?? new AppCacheOptions();
|
||||
var officialDocumentOptions = builder.Configuration
|
||||
.GetSection(OfficialDocumentOptions.SectionName)
|
||||
.Get<OfficialDocumentOptions>() ?? new OfficialDocumentOptions();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(officialDocumentOptions.InstitutionName) ||
|
||||
string.IsNullOrWhiteSpace(officialDocumentOptions.IssuingOffice) ||
|
||||
string.IsNullOrWhiteSpace(officialDocumentOptions.DocumentNumberPrefix))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"OfficialDocuments 的 InstitutionName、IssuingOffice 和 DocumentNumberPrefix 不能为空。");
|
||||
}
|
||||
|
||||
if (databaseOptions.Provider.Equals("SQLite", StringComparison.OrdinalIgnoreCase) &&
|
||||
!builder.Environment.IsDevelopment())
|
||||
@@ -109,6 +121,9 @@ if (cacheOptions.ReferenceExpirationMinutes is < 1 or > 1440 ||
|
||||
|
||||
builder.Services.AddSingleton(databaseOptions);
|
||||
builder.Services.AddSingleton(cacheOptions);
|
||||
builder.Services.AddSingleton(officialDocumentOptions);
|
||||
builder.Services.Configure<OfficialDocumentOptions>(
|
||||
builder.Configuration.GetSection(OfficialDocumentOptions.SectionName));
|
||||
builder.Services.AddDbContextPool<AppDbContext>(options =>
|
||||
{
|
||||
if (databaseOptions.Provider.Equals("SQLite", StringComparison.OrdinalIgnoreCase))
|
||||
@@ -215,6 +230,8 @@ builder.Services.AddScoped<MakeupExamArrangementService>();
|
||||
builder.Services.AddSingleton<MakeupExamAutoJobQueue>();
|
||||
builder.Services.AddHostedService<MakeupExamAutoJobWorker>();
|
||||
builder.Services.AddScoped<MakeupExamAutoJobProcessor>();
|
||||
builder.Services.AddSingleton<IOfficialDocumentPdfGenerator, OfficialDocumentPdfGenerator>();
|
||||
builder.Services.AddScoped<OfficialDocumentService>();
|
||||
|
||||
builder.Services
|
||||
.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
@@ -247,6 +264,16 @@ builder.Services.AddRateLimiter(options =>
|
||||
QueueLimit = 0,
|
||||
AutoReplenishment = true
|
||||
}));
|
||||
options.AddPolicy("official-verification", context =>
|
||||
RateLimitPartition.GetFixedWindowLimiter(
|
||||
context.Connection.RemoteIpAddress?.ToString() ?? "unknown",
|
||||
_ => new FixedWindowRateLimiterOptions
|
||||
{
|
||||
PermitLimit = 30,
|
||||
Window = TimeSpan.FromMinutes(1),
|
||||
QueueLimit = 0,
|
||||
AutoReplenishment = true
|
||||
}));
|
||||
});
|
||||
|
||||
builder.Services.AddCors(options =>
|
||||
|
||||
Reference in New Issue
Block a user