|
|
|
@ -256,12 +256,13 @@ export class ContestProblemListHandler extends ContestDetailBaseHandler {
|
|
|
|
|
async get(domainId: string, tid: ObjectId) {
|
|
|
|
|
if (contest.isNotStarted(this.tdoc)) throw new ContestNotLiveError(domainId, tid);
|
|
|
|
|
if (!this.tsdoc?.attend && !contest.isDone(this.tdoc)) throw new ContestNotAttendedError(domainId, tid);
|
|
|
|
|
const [pdict, udict] = await Promise.all([
|
|
|
|
|
const [pdict, udict, tcdocs] = await Promise.all([
|
|
|
|
|
problem.getList(domainId, this.tdoc.pids, true, true, problem.PROJECTION_CONTEST_LIST),
|
|
|
|
|
user.getList(domainId, [this.tdoc.owner, this.user._id]),
|
|
|
|
|
contest.getMultiClarification(domainId, tid, this.user._id),
|
|
|
|
|
]);
|
|
|
|
|
this.response.body = {
|
|
|
|
|
pdict, psdict: {}, udict, rdict: {}, tdoc: this.tdoc, tsdoc: this.tsdoc,
|
|
|
|
|
pdict, psdict: {}, udict, rdict: {}, tdoc: this.tdoc, tsdoc: this.tsdoc, tcdocs,
|
|
|
|
|
};
|
|
|
|
|
this.response.template = 'contest_problemlist.html';
|
|
|
|
|
if (!this.tsdoc) return;
|
|
|
|
@ -282,6 +283,24 @@ export class ContestProblemListHandler extends ContestDetailBaseHandler {
|
|
|
|
|
for (const i of psdocs) this.response.body.rdict[i.rid] = { _id: i.rid };
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@param('tid', Types.ObjectId)
|
|
|
|
|
@param('content', Types.Content)
|
|
|
|
|
@param('subject', Types.Int)
|
|
|
|
|
async postClarification(domainId: string, tid: ObjectId, content: string, subject: number) {
|
|
|
|
|
if (!this.tsdoc?.attend) throw new ContestNotAttendedError(domainId, tid);
|
|
|
|
|
if (!contest.isOngoing(this.tdoc)) throw new ContestNotLiveError(domainId, tid);
|
|
|
|
|
await this.limitRate('add_discussion', 3600, 60);
|
|
|
|
|
await contest.addClarification(domainId, tid, this.user._id, content, this.request.ip, subject);
|
|
|
|
|
if (!this.user.own(this.tdoc)) {
|
|
|
|
|
await Promise.all([this.tdoc.owner, ...this.tdoc.maintainer].map((uid) => message.send(1, uid, JSON.stringify({
|
|
|
|
|
message: 'Contest {0} has a new clarification about {1}, please go to contest management to reply.',
|
|
|
|
|
params: [this.tdoc.title, subject > 0 ? `#${this.tdoc.pids.indexOf(subject) + 1}` : 'the contest'],
|
|
|
|
|
url: this.url('contest_manage', { tid }),
|
|
|
|
|
}), message.FLAG_I18N | message.FLAG_UNREAD)));
|
|
|
|
|
}
|
|
|
|
|
this.back();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class ContestScoreboardHandler extends ContestDetailBaseHandler {
|
|
|
|
@ -558,12 +577,15 @@ export class ContestCodeHandler extends Handler {
|
|
|
|
|
export class ContestManagementHandler extends ContestManagementBaseHandler {
|
|
|
|
|
@param('tid', Types.ObjectId)
|
|
|
|
|
async get(domainId: string, tid: ObjectId) {
|
|
|
|
|
const tcdocs = await contest.getMultiClarification(domainId, tid);
|
|
|
|
|
this.response.body = {
|
|
|
|
|
tdoc: this.tdoc,
|
|
|
|
|
tsdoc: this.tsdoc,
|
|
|
|
|
owner_udoc: await user.getById(domainId, this.tdoc.owner),
|
|
|
|
|
pdict: await problem.getList(domainId, this.tdoc.pids, true, true, problem.PROJECTION_CONTEST_LIST),
|
|
|
|
|
files: sortFiles(this.tdoc.files || []),
|
|
|
|
|
udict: await user.getListForRender(domainId, tcdocs.map((i) => i.owner)),
|
|
|
|
|
tcdocs,
|
|
|
|
|
urlForFile: (filename: string) => this.url('contest_file_download', { tid, filename }),
|
|
|
|
|
};
|
|
|
|
|
this.response.pjax = 'partials/files.html';
|
|
|
|
@ -572,11 +594,28 @@ export class ContestManagementHandler extends ContestManagementBaseHandler {
|
|
|
|
|
|
|
|
|
|
@param('tid', Types.ObjectId)
|
|
|
|
|
@param('content', Types.Content)
|
|
|
|
|
async postBroadcast(domainId: string, tid: ObjectId, content: string) {
|
|
|
|
|
@param('did', Types.ObjectId, true)
|
|
|
|
|
@param('subject', Types.Int, true)
|
|
|
|
|
async postClarification(domainId: string, tid: ObjectId, content: string, did: ObjectId, subject = 0) {
|
|
|
|
|
if (did) {
|
|
|
|
|
const tcdoc = await contest.getClarification(domainId, did);
|
|
|
|
|
await Promise.all([
|
|
|
|
|
contest.addClarificationReply(domainId, did, 0, content, this.request.ip),
|
|
|
|
|
message.send(1, tcdoc.owner, JSON.stringify({
|
|
|
|
|
message: 'Contest {0} jury replied to your clarification, please go to contest page to view.',
|
|
|
|
|
params: [this.tdoc.title],
|
|
|
|
|
url: this.url('contest_problemlist', { tid }),
|
|
|
|
|
}), message.FLAG_I18N | message.FLAG_ALERT),
|
|
|
|
|
]);
|
|
|
|
|
} else {
|
|
|
|
|
const tsdocs = await contest.getMultiStatus(domainId, { docId: tid }).toArray();
|
|
|
|
|
const uids = Array.from<number>(new Set(tsdocs.map((tsdoc) => tsdoc.uid)));
|
|
|
|
|
const flag = contest.isOngoing(this.tdoc) ? message.FLAG_ALERT : message.FLAG_UNREAD;
|
|
|
|
|
await Promise.all(uids.map((uid) => message.send(this.user._id, uid, content, flag)));
|
|
|
|
|
await Promise.all([
|
|
|
|
|
contest.addClarification(domainId, tid, 0, content, this.request.ip, subject),
|
|
|
|
|
...uids.map((uid) => message.send(1, uid, content, flag)),
|
|
|
|
|
]);
|
|
|
|
|
}
|
|
|
|
|
this.back();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|