Merge branch 'master' into events

This commit is contained in:
undefined committed 2025-06-09 23:22:58 +08:00
commit 067ca3c6bb
57 files changed
+381 -229

No files matched your search

+2 -2
View File
@@ -576,7 +576,7 @@ export class ContestBalloonHandler extends ContestManagementBaseHandler {
const bdocs = await contest.getMultiBalloon(domainId, tid, {
...todo ? { sent: { $exists: false } } : {},
...(!this.tdoc.lockAt || this.user.hasPerm(PERM.PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD))
? {} : { _id: { $lt: this.tdoc.lockAt } },
? {} : { _id: { $lt: Time.getObjectID(this.tdoc.lockAt) } },
}).sort({ _id: -1 }).toArray();
const uids = bdocs.map((i) => i.uid).concat(bdocs.filter((i) => i.sent).map((i) => i.sent));
this.response.body = {
@@ -743,7 +743,7 @@ export async function apply(ctx: Context) {
await Promise.all(tasks);
});
ctx.plugin(ScoreboardService);
ctx.inject(['scoreboard'], ({ Route, scoreboard }) => {
await ctx.inject(['scoreboard'], ({ Route, scoreboard }) => {
Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD);
Route('contest_scoreboard_view', '/contest/:tid/scoreboard/:view', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST_SCOREBOARD);
scoreboard.addView('default', 'Default', { tdoc: 'tdoc', groups: 'groups', realtime: Types.Boolean }, {
+2 -1
View File
@@ -214,6 +214,7 @@ class DomainPermissionHandler extends ManageHandler {
async post({ domainId }) {
const roles = {};
for (const role in this.request.body) {
if (role === 'root') continue; // root role is not editable
const perms = this.request.body[role] instanceof Array
? this.request.body[role]
: [this.request.body[role]];
@@ -460,7 +461,7 @@ export async function apply(ctx: Context) {
ctx.Route('domain_join_applications', '/domain/join_applications', DomainJoinApplicationsHandler);
ctx.Route('domain_join', '/domain/join', DomainJoinHandler, PRIV.PRIV_USER_PROFILE);
ctx.Route('domain_search', '/domain/search', DomainSearchHandler, PRIV.PRIV_USER_PROFILE);
ctx.inject(['api'], ({ api }) => {
await ctx.inject(['api'], ({ api }) => {
api.provide(DomainApi);
});
}
+1 -1
View File
@@ -314,7 +314,7 @@ export async function apply(ctx) {
ctx.Route('homework_edit', '/homework/:tid/edit', HomeworkEditHandler);
ctx.Route('homework_files', '/homework/:tid/file', HomeworkFilesHandler, PERM.PERM_VIEW_HOMEWORK);
ctx.Route('homework_file_download', '/homework/:tid/file/:filename', ContestFileDownloadHandler, PERM.PERM_VIEW_HOMEWORK);
ctx.inject(['scoreboard'], ({ Route }) => {
await ctx.inject(['scoreboard'], ({ Route }) => {
Route('homework_scoreboard', '/homework/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_HOMEWORK_SCOREBOARD);
Route('homework_scoreboard_view', '/homework/:tid/scoreboard/:view', ContestScoreboardHandler, PERM.PERM_VIEW_HOMEWORK_SCOREBOARD);
});
+10 -13
View File
@@ -182,7 +182,7 @@ class SystemConfigHandler extends SystemHandler {
@requireSudo
async get() {
this.response.template = 'manage_config.html';
let value;
let value = this.ctx.setting.configSource;
const processNode = (node: any, schema: Schema<any, any>, parent?: any, accessKey?: string) => {
if (['union', 'intersect'].includes(schema.type)) {
@@ -198,23 +198,20 @@ class SystemConfigHandler extends SystemHandler {
};
try {
try {
value = Schema.intersect(this.ctx.config.settings)(yaml.load(this.ctx.config.configSource));
} catch (e) {
value = yaml.load(this.ctx.config.configSource);
}
for (const schema of this.ctx.config.settings) processNode(value, schema);
const temp = yaml.load(this.ctx.setting.configSource);
for (const schema of this.ctx.setting.settings) processNode(temp, schema);
value = yaml.dump(temp);
} catch (e) { }
this.response.body = {
schema: Schema.intersect(this.ctx.config.settings).toJSON(),
value: yaml.dump(value),
schema: Schema.intersect(this.ctx.setting.settings).toJSON(),
value,
};
}
@requireSudo
@param('value', Types.String)
async post({ }, value: string) {
const oldConfig = yaml.load(this.ctx.config.configSource);
const oldConfig = yaml.load(this.ctx.setting.configSource);
let config;
const processNode = (node: any, old: any, schema: Schema<any, any>, parent?: any, accessKey?: string) => {
if (['union', 'intersect'].includes(schema.type)) {
@@ -231,11 +228,11 @@ class SystemConfigHandler extends SystemHandler {
try {
config = yaml.load(value);
for (const schema of this.ctx.config.settings) processNode(config, oldConfig, schema, null, '');
for (const schema of this.ctx.setting.settings) processNode(config, oldConfig, schema, null, '');
} catch (e) {
throw new ValidationError('value', '', e.message);
}
await this.ctx.config.saveConfig(config);
await this.ctx.setting.saveConfig(config);
}
}
@@ -357,7 +354,7 @@ class SystemUserPrivHandler extends SystemHandler {
}
}
export const inject = ['config', 'check'];
export const inject = ['setting', 'check'];
export async function apply(ctx) {
ctx.Route('manage', '/manage', SystemMainHandler);
ctx.Route('manage_dashboard', '/manage/dashboard', SystemDashboardHandler);
+3 -3
View File
@@ -384,10 +384,10 @@ export class ProblemDetailHandler extends ContestDetailBaseHandler {
if (this.psdoc?.rid) {
this.response.body.rdoc = await record.get(this.args.domainId, this.psdoc.rid);
}
[this.response.body.ctdocs, this.response.body.htdocs] = await Promise.all([
[this.response.body.ctdocs, this.response.body.htdocs] = (await Promise.all([
contest.getRelated(this.args.domainId, this.pdoc.docId),
contest.getRelated(this.args.domainId, this.pdoc.docId, 'homework'),
]);
])).map((tdocs) => tdocs.filter((tdoc) => !tdoc.assign?.length || Set.intersection(tdoc.assign, this.user.group).size));
}
}
@@ -1070,7 +1070,7 @@ export async function apply(ctx: Context) {
ctx.Route('problem_solution_reply_raw', '/p/:pid/solution/:psid/:psrid/raw', ProblemSolutionRawHandler, PERM.PERM_VIEW_PROBLEM);
ctx.Route('problem_statistics', '/p/:pid/stat', ProblemStatisticsHandler, PERM.PERM_VIEW_PROBLEM);
ctx.Route('problem_create', '/problem/create', ProblemCreateHandler, PERM.PERM_CREATE_PROBLEM);
ctx.inject(['api'], ({ api }) => {
await ctx.inject(['api'], ({ api }) => {
api.provide(ProblemApi);
});
}
+1 -1
View File
@@ -625,7 +625,7 @@ export async function apply(ctx: Context) {
throw new NotFoundError();
},
});
ctx.inject(['api'], ({ api }) => {
await ctx.inject(['api'], ({ api }) => {
api.provide(UserApi);
});
}