Skip to content

Commit f30f12e

Browse files
committed
add filter form
1 parent 39cc430 commit f30f12e

File tree

3 files changed

+114
-33
lines changed

3 files changed

+114
-33
lines changed

packages/hydrooj/src/handler/manage.ts

Lines changed: 101 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,19 @@ import { exec } from 'child_process';
22
import { inspect } from 'util';
33
import * as yaml from 'js-yaml';
44
import { omit } from 'lodash';
5+
import moment from 'moment';
6+
import { Filter, ObjectId } from 'mongodb';
57
import Schema from 'schemastery';
8+
import { Time } from '@hydrooj/utils';
69
import {
7-
CannotEditSuperAdminError, NotLaunchedByPM2Error, UserNotFoundError, ValidationError,
10+
CannotEditSuperAdminError, ContestNotFoundError, NotLaunchedByPM2Error, ProblemNotFoundError, RecordNotFoundError, UserNotFoundError, ValidationError,
811
} from '../error';
12+
import { RecordDoc } from '../interface';
913
import { Logger } from '../logger';
10-
import { PRIV, STATUS } from '../model/builtin';
14+
import { NORMAL_STATUS, PRIV, STATUS } from '../model/builtin';
15+
import * as contest from '../model/contest';
1116
import domain from '../model/domain';
17+
import problem from '../model/problem';
1218
import record from '../model/record';
1319
import * as setting from '../model/setting';
1420
import * as system from '../model/system';
@@ -359,33 +365,99 @@ class SystemUserPrivHandler extends SystemHandler {
359365

360366
class SystemRejudgeHandler extends SystemHandler {
361367
async get() {
362-
const rrdocs = await record.getMultiRejudgeTask({});
363-
this.response.body.rrdocs = rrdocs;
368+
this.response.body = {
369+
rrdocs: await record.getMultiRejudgeTask({}),
370+
apply: true,
371+
status: NORMAL_STATUS.filter((i: STATUS) => ![STATUS.STATUS_COMPILE_ERROR, STATUS.STATUS_ACCEPTED].includes(i)).join(','),
372+
};
364373
this.response.template = 'manage_rejudge.html';
365374
}
366375

367-
@param('domainId', Types.String, true)
368-
@param('pid', Types.Int, true)
369-
@param('uid', Types.Int, true)
370-
@param('contest', Types.String, true)
371-
@param('lang', Types.String, true)
372-
@param('status', Types.Int, true)
376+
@param('uidOrName', Types.UidOrName, true)
377+
@param('pid', Types.ProblemId, true)
378+
@param('tid', Types.ObjectId, true)
379+
@param('langs', Types.CommaSeperatedArray, true)
380+
@param('beginAtDate', Types.Date, true)
381+
@param('beginAtTime', Types.Time, true)
382+
@param('endAtDate', Types.Date, true)
383+
@param('endAtTime', Types.Time, true)
384+
@param('status', Types.CommaSeperatedArray, true)
385+
@param('type', Types.Range(['preview', 'rejudge']))
386+
@param('high_priority', Types.Boolean)
373387
@param('apply', Types.Boolean)
374-
async post(domainId: string, pid: number, uid: number, contest: string, lang: string, status: number, _apply = false) {
388+
async post(
389+
domainId: string, uidOrName?: string, pid?: string | number, tid?: ObjectId,
390+
langs: string[] = [], beginAtDate?: string, beginAtTime?: string, endAtDate?: string,
391+
endAtTime?: string, status: string[] = [], _type = 'rejudge', highPriority = false, _apply = false,
392+
) {
393+
const q: Filter<RecordDoc> = {};
394+
if (uidOrName) {
395+
const udoc = await user.getById(domainId, +uidOrName)
396+
|| await user.getByUname(domainId, uidOrName)
397+
|| await user.getByEmail(domainId, uidOrName);
398+
if (udoc) q.uid = udoc._id;
399+
else throw new UserNotFoundError(uidOrName);
400+
}
401+
if (tid) {
402+
const tdoc = await contest.get(domainId, tid);
403+
if (!tdoc) throw new ContestNotFoundError(domainId, tid);
404+
q.contest = tdoc._id;
405+
}
406+
if (pid) {
407+
const pdoc = await problem.get(domainId, pid);
408+
if (pdoc) q.pid = pdoc.docId;
409+
else throw new ProblemNotFoundError(domainId, pid);
410+
}
411+
if (langs.length) q.lang = { $in: langs.filter((i) => setting.langs[i]) };
412+
let beginAt = null;
413+
let endAt = null;
414+
if (beginAtDate) {
415+
beginAt = moment(`${beginAtDate} ${beginAtTime || '00:00'}`);
416+
if (!beginAt.isValid()) throw new ValidationError('beginAtDate', 'beginAtTime');
417+
q._id ||= {};
418+
q._id = { ...q._id, $gte: Time.getObjectID(beginAt) };
419+
}
420+
if (endAtDate) {
421+
endAt = moment(`${endAtDate} ${endAtTime || '23:59'}`);
422+
if (!endAt.isValid()) throw new ValidationError('endAtDate', 'endAtTime');
423+
q._id ||= {};
424+
q._id = { ...q._id, $lte: Time.getObjectID(endAt) };
425+
}
426+
if (beginAt && endAt && beginAt.isSameOrAfter(endAt)) throw new ValidationError('duration');
427+
const rids = await record.getMulti(domainId, q).project({ _id: 1 }).toArray();
428+
if (_type === 'preview') {
429+
this.response.body = {
430+
uidOrName,
431+
pid,
432+
tid,
433+
langs: langs.join(','),
434+
beginAtDate,
435+
beginAtTime,
436+
endAtDate,
437+
endAtTime,
438+
status: status.join(','),
439+
highPriority,
440+
apply: _apply,
441+
recordLength: rids.length,
442+
rrdocs: await record.getMultiRejudgeTask({}),
443+
};
444+
this.response.template = 'manage_rejudge.html';
445+
return;
446+
}
375447
const rid = await record.add(domainId, -1, this.user._id, '-', 'rejudge', false, {
376448
input: JSON.stringify({
377-
pid, uid, contest, lang, status, apply: _apply,
449+
domainId,
450+
rids: rids.map((i) => i._id.toString()),
451+
highPriority,
452+
apply: _apply,
378453
}),
379454
type: 'rejudge',
380455
});
381456
const args = global.Hydro.script['rejudge'].validate({
382457
rrid: rid.toHexString(),
383458
domainId,
384-
uid,
385-
pid,
386-
contest,
387-
lang,
388-
status,
459+
rids: rids.map((i) => i._id.toString()),
460+
highPriority,
389461
apply: _apply,
390462
});
391463
const report = (data) => judge.next({ domainId, rid, ...data });
@@ -419,7 +491,17 @@ class SystemRejudgeHandler extends SystemHandler {
419491
});
420492
});
421493
this.response.body = { rid };
422-
this.response.redirect = this.url('record_detail', { rid });
494+
this.response.redirect = this.url('manage_rejudge_detail', { rid: rid.toHexString() });
495+
}
496+
}
497+
498+
class SystemRejudgeDetailHandler extends SystemHandler {
499+
@param('rid', Types.ObjectId)
500+
async get(domainId: string, rid: ObjectId) {
501+
const rrdoc = await record.getRejudgeTask(rid);
502+
if (!rrdoc) throw new RecordNotFoundError(domainId, rid);
503+
this.response.body = { rrdoc };
504+
this.response.template = 'manage_rejudge_detail.html';
423505
}
424506
}
425507

@@ -433,5 +515,6 @@ export async function apply(ctx) {
433515
ctx.Route('manage_user_import', '/manage/userimport', SystemUserImportHandler);
434516
ctx.Route('manage_user_priv', '/manage/userpriv', SystemUserPrivHandler);
435517
ctx.Route('manage_rejudge', '/manage/rejudge', SystemRejudgeHandler);
518+
ctx.Route('manage_rejudge_detail', '/manage/rejudge/:rid', SystemRejudgeDetailHandler);
436519
ctx.Connection('manage_check', '/manage/check-conn', SystemCheckConnHandler);
437520
}

packages/ui-default/pages/manage_rejudge.page.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const page = new NamedPage('manage_rejudge', async () => {
1717
{ name: `${i.includes('.') ? `${window.LANGS[i.split('.')[0]].display}/` : ''}${window.LANGS[i].display}`, _id: i }
1818
));
1919
CustomSelectAutoComplete.getOrConstruct($('[name=lang]'), { multi: true, data: langs });
20-
const statuses = Object.values(STATUS_TEXTS).map((i) => ({ name: i, _id: i }));
20+
const statuses = Object.entries(STATUS_TEXTS).map(([i, j]) => ({ name: j, _id: i }));
2121
CustomSelectAutoComplete.getOrConstruct($('[name=status]'), { multi: true, data: statuses });
2222
});
2323

packages/ui-default/templates/manage_rejudge.html

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
<h1 class="section__title">{{ _('Bulk Rejudge') }}</h1>
77
</div>
88
<div class="section__body">
9-
{% if error %}
10-
<p class="typo text-red">{{ error.split('\n')|join('<br>') }}</p>
11-
{% endif %}
12-
<form>
9+
<form method="post">
1310
<div class="row">
1411
<div class="medium-3 columns">
1512
<label class="filter-user">
@@ -38,11 +35,11 @@ <h1 class="section__title">{{ _('Bulk Rejudge') }}</h1>
3835
</div>
3936
<div class="row">
4037
{{ form.form_text({
41-
columns:3,
38+
columns:4,
4239
label:'Begin Date',
4340
name:'beginAtDate',
4441
placeholder:'YYYY-mm-dd',
45-
value:dateBeginText,
42+
value:beginAtDate,
4643
date:true,
4744
row:false
4845
}) }}
@@ -51,16 +48,16 @@ <h1 class="section__title">{{ _('Bulk Rejudge') }}</h1>
5148
label:'Begin Time',
5249
name:'beginAtTime',
5350
placeholder:'HH:MM',
54-
value:timeBeginText,
51+
value:beginAtTime,
5552
time:true,
5653
row:false
5754
}) }}
5855
{{ form.form_text({
59-
columns:3,
56+
columns:4,
6057
label:'End Date',
6158
name:'endAtDate',
6259
placeholder:'YYYY-mm-dd',
63-
value:dateEndText,
60+
value:endAtDate,
6461
date:true,
6562
row:false
6663
}) }}
@@ -69,7 +66,7 @@ <h1 class="section__title">{{ _('Bulk Rejudge') }}</h1>
6966
label:'End Time',
7067
name:'endAtTime',
7168
placeholder:'HH:MM',
72-
value:timeEndText,
69+
value:endAtTime,
7370
time:true,
7471
row:false
7572
}) }}
@@ -95,14 +92,15 @@ <h1 class="section__title">{{ _('Bulk Rejudge') }}</h1>
9592
</label>
9693
</div>
9794
</div>
95+
{% if recordLength %}
96+
<p class="typo">{{ _('Will rejudge {0} records').format(recordLength) }}</p>
97+
{% endif %}
9898
<div class="row">
9999
<div class="medium-3 columns">
100-
<button name="operation" value="preview" class="rounded button">{{ _('Preview') }}</button>
101-
<button name="operation" value="rejudge" class="rounded primary button">{{ _('Rejudge') }}</button>
100+
<button name="type" value="preview" class="rounded button">{{ _('Preview') }}</button>
101+
<button name="type" value="rejudge" class="rounded primary button">{{ _('Rejudge') }}</button>
102102
</div>
103103
</div>
104-
<div class="row"><div class="columns">
105-
</div></div>
106104
</form>
107105
</div>
108106
</div>

0 commit comments

Comments
 (0)