mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-19 09:38:19 +08:00
Hello Typescript!
This commit is contained in:
1 parent
c9b6412527
commit
ba03d7a7bf
98 files changed
+3186
-2616
No files matched your search
@@ -1,27 +1,19 @@
|
||||
const moment = require('moment-timezone');
|
||||
const { ObjectID } = require('mongodb');
|
||||
const AdmZip = require('adm-zip');
|
||||
const {
|
||||
import moment from 'moment-timezone';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import AdmZip from 'adm-zip';
|
||||
import {
|
||||
ContestNotLiveError, ValidationError, ProblemNotFoundError,
|
||||
ContestNotAttendedError,
|
||||
} = require('../error');
|
||||
const paginate = require('../lib/paginate');
|
||||
const {
|
||||
PERM: {
|
||||
PERM_CREATE_CONTEST, PERM_EDIT_CONTEST, PERM_READ_RECORD_CODE,
|
||||
PERM_VIEW_CONTEST, PERM_EDIT_CONTEST_SELF,
|
||||
},
|
||||
PRIV: {
|
||||
PRIV_READ_RECORD_CODE,
|
||||
},
|
||||
} = require('../model/builtin');
|
||||
const contest = require('../model/contest');
|
||||
const document = require('../model/document');
|
||||
const problem = require('../model/problem');
|
||||
const record = require('../model/record');
|
||||
const user = require('../model/user');
|
||||
const system = require('../model/system');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
} from '../error';
|
||||
import paginate from '../lib/paginate';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import * as contest from '../model/contest';
|
||||
import * as document from '../model/document';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import * as user from '../model/user';
|
||||
import * as system from '../model/system';
|
||||
import { Route, Handler } from '../service/server';
|
||||
|
||||
const ContestHandler = contest.ContestHandlerMixin(Handler);
|
||||
|
||||
@@ -35,7 +27,7 @@ class ContestListHandler extends ContestHandler {
|
||||
tdocs = contest.getMulti(domainId).sort({ beginAt: -1 });
|
||||
qs = '';
|
||||
} else {
|
||||
if (!contest.CONTEST_RULES.includes(rule)) throw new ValidationError('rule');
|
||||
if (!contest.RULES[rule]) throw new ValidationError('rule');
|
||||
tdocs = contest.getMulti(domainId, { rule }).sort({ beginAt: -1 });
|
||||
qs = 'rule={0}'.format(rule);
|
||||
}
|
||||
@@ -127,8 +119,8 @@ class ContestScoreboardDownloadHandler extends ContestDetailHandler {
|
||||
|
||||
class ContestEditHandler extends ContestDetailHandler {
|
||||
async prepare() {
|
||||
if (this.tdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_CONTEST);
|
||||
else this.checkPerm(PERM_EDIT_CONTEST_SELF);
|
||||
if (this.tdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_CONTEST);
|
||||
else this.checkPerm(PERM.PERM_EDIT_CONTEST_SELF);
|
||||
}
|
||||
|
||||
async get() {
|
||||
@@ -160,20 +152,20 @@ class ContestEditHandler extends ContestDetailHandler {
|
||||
async post({
|
||||
domainId, beginAtDate, beginAtTime, duration, title, content, rule, pids, rated = false,
|
||||
}) {
|
||||
let beginAt = moment.tz(`${beginAtDate} ${beginAtTime}`, this.user.timeZone);
|
||||
if (!beginAt.isValid()) {
|
||||
const beginAtMoment = moment.tz(`${beginAtDate} ${beginAtTime}`, this.user.timeZone);
|
||||
if (!beginAtMoment.isValid()) {
|
||||
throw new ValidationError('beginAtDate', 'beginAtTime');
|
||||
}
|
||||
const endAt = beginAt.clone().add(duration, 'hours').toDate();
|
||||
if (beginAt.isSameOrAfter(endAt)) throw new ValidationError('duration');
|
||||
beginAt = beginAt.toDate();
|
||||
const endAt = beginAtMoment.clone().add(duration, 'hours').toDate();
|
||||
if (beginAtMoment.isSameOrAfter(endAt)) throw new ValidationError('duration');
|
||||
const beginAt = beginAtMoment.toDate();
|
||||
pids = await this.verifyProblems(domainId, pids);
|
||||
await contest.edit(domainId, this.tdoc.docId, {
|
||||
title, content, rule, beginAt, endAt, pids, rated,
|
||||
});
|
||||
if (this.tdoc.beginAt !== beginAt || this.tdoc.endAt !== endAt
|
||||
|| Array.isDiff(this.tdoc.pids, pids) || this.tdoc.rule !== rule) {
|
||||
await contest.recalcStatus(this.tdoc.docId);
|
||||
await contest.recalcStatus(domainId, this.tdoc.docId);
|
||||
}
|
||||
this.response.body = { tid: this.tdoc.docId };
|
||||
this.response.redirect = this.url('contest_detail', { tid: this.tdoc.docId });
|
||||
@@ -201,6 +193,7 @@ class ContestProblemHandler extends ContestDetailHandler {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
async get({ tid }) {
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
@@ -272,7 +265,9 @@ class ContestProblemSubmitHandler extends ContestProblemHandler {
|
||||
|
||||
class ContestCodeHandler extends ContestDetailHandler {
|
||||
async get({ domainId, tid }) {
|
||||
if (!this.user.hasPriv(PRIV_READ_RECORD_CODE)) this.checkPerm(PERM_READ_RECORD_CODE);
|
||||
if (!this.user.hasPriv(PRIV.PRIV_READ_RECORD_CODE)) {
|
||||
this.checkPerm(PERM.PERM_READ_RECORD_CODE);
|
||||
}
|
||||
this.limitRate('homework_code', 3600, 60);
|
||||
const [tdoc, tsdocs] = await contest.getAndListStatus(domainId, tid);
|
||||
const rnames = {};
|
||||
@@ -329,23 +324,23 @@ class ContestCreateHandler extends ContestHandler {
|
||||
pids = await this.verifyProblems(domainId, pids);
|
||||
const tid = await contest.add(
|
||||
domainId, title, content,
|
||||
this.user._id, rule, beginAt, endAt, pids, rated,
|
||||
this.user._id, rule, beginAt.toDate(), endAt.toDate(), pids, rated,
|
||||
);
|
||||
this.response.body = { tid };
|
||||
this.response.redirect = this.url('contest_detail', { tid });
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('contest_main', '/contest', ContestListHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_detail', '/contest/:tid', ContestDetailHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_edit', '/contest/:tid/edit', ContestEditHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_scoreboard_download', '/contest/:tid/export/:ext', ContestScoreboardDownloadHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_detail_problem', '/contest/:tid/p/:pid', ContestProblemHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_detail_problem_submit', '/contest/:tid/p/:pid/submit', ContestProblemSubmitHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_code', '/contest/:tid/code', ContestCodeHandler, PERM_VIEW_CONTEST);
|
||||
Route('contest_create', '/contest/create', ContestCreateHandler, PERM_CREATE_CONTEST);
|
||||
export async function apply() {
|
||||
Route('contest_main', '/contest', ContestListHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_detail', '/contest/:tid', ContestDetailHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_edit', '/contest/:tid/edit', ContestEditHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_scoreboard', '/contest/:tid/scoreboard', ContestScoreboardHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_scoreboard_download', '/contest/:tid/export/:ext', ContestScoreboardDownloadHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_detail_problem', '/contest/:tid/p/:pid', ContestProblemHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_detail_problem_submit', '/contest/:tid/p/:pid/submit', ContestProblemSubmitHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_code', '/contest/:tid/code', ContestCodeHandler, PERM.PERM_VIEW_CONTEST);
|
||||
Route('contest_create', '/contest/create', ContestCreateHandler, PERM.PERM_CREATE_CONTEST);
|
||||
}
|
||||
|
||||
global.Hydro.handler.contest = module.exports = apply;
|
||||
global.Hydro.handler.contest = apply;
|
||||
@@ -1,23 +1,14 @@
|
||||
const { ObjectID } = require('mongodb');
|
||||
const paginate = require('../lib/paginate');
|
||||
const system = require('../model/system');
|
||||
const user = require('../model/user');
|
||||
const discussion = require('../model/discussion');
|
||||
const document = require('../model/document');
|
||||
const {
|
||||
PERM: {
|
||||
PERM_VIEW_DISCUSSION, PERM_EDIT_DISCUSSION, PERM_EDIT_DISCUSSION_REPLY,
|
||||
PERM_DELETE_DISCUSSION, PERM_DELETE_DISCUSSION_REPLY, PERM_HIGHLIGHT_DISCUSSION,
|
||||
PERM_CREATE_DISCUSSION, PERM_REPLY_DISCUSSION,
|
||||
},
|
||||
PRIV: {
|
||||
PRIV_USER_PROFILE,
|
||||
},
|
||||
} = require('../model/builtin');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { DiscussionNotFoundError, DocumentNotFoundError } = require('../error');
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { DiscussionNotFoundError, DocumentNotFoundError } from '../error';
|
||||
import paginate from '../lib/paginate';
|
||||
import * as system from '../model/system';
|
||||
import * as user from '../model/user';
|
||||
import * as discussion from '../model/discussion';
|
||||
import * as document from '../model/document';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import { Route, Handler } from '../service/server';
|
||||
|
||||
const typeMapper = {
|
||||
export const typeMapper = {
|
||||
problem: document.TYPE_PROBLEM,
|
||||
contest: document.TYPE_CONTEST,
|
||||
node: document.TYPE_DISCUSSION_NODE,
|
||||
@@ -29,7 +20,7 @@ class DiscussionHandler extends Handler {
|
||||
async _prepare({
|
||||
domainId, type, name, did, drid, drrid,
|
||||
}) {
|
||||
this.checkPerm(PERM_VIEW_DISCUSSION);
|
||||
this.checkPerm(PERM.PERM_VIEW_DISCUSSION);
|
||||
if (did) {
|
||||
this.ddoc = await discussion.get(domainId, did);
|
||||
if (!this.ddoc) throw new DiscussionNotFoundError(did);
|
||||
@@ -124,8 +115,8 @@ class DiscussionNodeHandler extends DiscussionHandler {
|
||||
|
||||
class DiscussionCreateHandler extends DiscussionHandler {
|
||||
async prepare() {
|
||||
this.checkPriv(PRIV_USER_PROFILE);
|
||||
this.checkPerm(PERM_CREATE_DISCUSSION);
|
||||
this.checkPriv(PRIV.PRIV_USER_PROFILE);
|
||||
this.checkPerm(PERM.PERM_CREATE_DISCUSSION);
|
||||
}
|
||||
|
||||
async get({ type, name }) {
|
||||
@@ -144,7 +135,7 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
||||
}) {
|
||||
this.limitRate('add_discussion', 3600, 30);
|
||||
if (ObjectID.isValid(name)) name = new ObjectID(name);
|
||||
if (highlight) this.checkPerm(PERM_HIGHLIGHT_DISCUSSION);
|
||||
if (highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
|
||||
const did = await discussion.add(
|
||||
domainId, typeMapper[type], name, this.user._id,
|
||||
title, content, this.request.ip, highlight,
|
||||
@@ -156,7 +147,7 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
||||
|
||||
class DiscussionDetailHandler extends DiscussionHandler {
|
||||
async get({ domainId, did, page = 1 }) {
|
||||
const dsdoc = this.user.hasPriv(PRIV_USER_PROFILE)
|
||||
const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE)
|
||||
? await discussion.getStatus(domainId, did, this.user._id)
|
||||
: null;
|
||||
const [drdocs, pcount, drcount] = await paginate(
|
||||
@@ -187,31 +178,31 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
}
|
||||
|
||||
async post() {
|
||||
this.checkPriv(PRIV_USER_PROFILE);
|
||||
this.checkPriv(PRIV.PRIV_USER_PROFILE);
|
||||
}
|
||||
|
||||
async postReply({ domainId, did, content }) {
|
||||
this.checkPerm(PERM_REPLY_DISCUSSION);
|
||||
this.checkPerm(PERM.PERM_REPLY_DISCUSSION);
|
||||
this.limitRate('add_discussion', 3600, 30);
|
||||
await discussion.addReply(domainId, did, this.user._id, content, this.request.ip);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postTailReply({ domainId, drid, content }) {
|
||||
this.checkPerm(PERM_REPLY_DISCUSSION);
|
||||
this.checkPerm(PERM.PERM_REPLY_DISCUSSION);
|
||||
this.limitRate('add_discussion', 3600, 30);
|
||||
await discussion.addTailReply(domainId, drid, this.user._id, content, this.request.ip);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postEditReply({ domainId, drid, content }) {
|
||||
if (this.drdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_DISCUSSION_REPLY);
|
||||
if (this.drdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY);
|
||||
await discussion.editReply(domainId, drid, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDeleteReply({ domainId, drid }) {
|
||||
if (this.drdoc.owner !== this.user._id) this.checkPerm(PERM_DELETE_DISCUSSION_REPLY);
|
||||
if (this.drdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
|
||||
await discussion.delReply(domainId, drid);
|
||||
this.back();
|
||||
}
|
||||
@@ -219,13 +210,13 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
async postEditTailReply({
|
||||
domainId, drid, drrid, content,
|
||||
}) {
|
||||
if (this.drdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_DISCUSSION_REPLY);
|
||||
if (this.drdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY);
|
||||
await discussion.editTailReply(domainId, drid, drrid, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDeleteTailReply({ domainId, drid, drrid }) {
|
||||
if (this.drrdoc.owner !== this.user._id) this.checkPerm(PERM_DELETE_DISCUSSION_REPLY);
|
||||
if (this.drrdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
|
||||
await discussion.delTailReply(domainId, drid, drrid);
|
||||
this.back();
|
||||
}
|
||||
@@ -278,15 +269,15 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
async postUpdate({
|
||||
domainId, did, title, content, highlight,
|
||||
}) {
|
||||
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_DISCUSSION);
|
||||
if (highlight && !this.ddoc.highlight) this.checkPerm(PERM_HIGHLIGHT_DISCUSSION);
|
||||
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_DISCUSSION);
|
||||
if (highlight && !this.ddoc.highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
|
||||
await discussion.edit(domainId, did, title, content, highlight);
|
||||
this.response.body = { did };
|
||||
this.response.redirect = this.url('discussion_detail', { did });
|
||||
}
|
||||
|
||||
async postDelete({ domainId, did }) {
|
||||
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM_DELETE_DISCUSSION);
|
||||
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM.PERM_DELETE_DISCUSSION);
|
||||
await discussion.del(domainId, did);
|
||||
this.response.body = { type: this.ddoc.parentType, parent: this.ddoc.parentId };
|
||||
this.response.redirect = this.url('discussion_node', {
|
||||
@@ -296,7 +287,7 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('discussion_main', '/discuss', DiscussionMainHandler);
|
||||
Route('discussion_detail', '/discuss/:did', DiscussionDetailHandler);
|
||||
Route('discussion_edit', '/discuss/:did/edit', DiscussionEditHandler);
|
||||
@@ -307,4 +298,4 @@ async function apply() {
|
||||
Route('discussion_create', '/discuss/:type/:name/create', DiscussionCreateHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.discussion = module.exports = apply;
|
||||
global.Hydro.handler.discussion = apply;
|
||||
@@ -1,11 +1,11 @@
|
||||
const user = require('../model/user');
|
||||
const domain = require('../model/domain');
|
||||
const system = require('../model/system');
|
||||
const { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } = require('../model/setting');
|
||||
const { PERM: { PERM_EDIT_DOMAIN }, PERMS_BY_FAMILY } = require('../model/builtin');
|
||||
const paginate = require('../lib/paginate');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { RoleAlreadyExistError, ValidationError, PermissionError } = require('../error');
|
||||
import { RoleAlreadyExistError, ValidationError, PermissionError } from '../error';
|
||||
import * as user from '../model/user';
|
||||
import * as domain from '../model/domain';
|
||||
import * as system from '../model/system';
|
||||
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
||||
import { PERM, PERMS_BY_FAMILY } from '../model/builtin';
|
||||
import paginate from '../lib/paginate';
|
||||
import { Route, Handler } from '../service/server';
|
||||
|
||||
class DomainRankHandler extends Handler {
|
||||
async get({ domainId, page = 1 }) {
|
||||
@@ -55,7 +55,7 @@ class DomainCreateHandler extends Handler {
|
||||
|
||||
class ManageHandler extends Handler {
|
||||
async prepare({ domainId }) {
|
||||
this.checkPerm(PERM_EDIT_DOMAIN);
|
||||
this.checkPerm(PERM.PERM_EDIT_DOMAIN);
|
||||
this.domain = await domain.get(domainId);
|
||||
}
|
||||
}
|
||||
@@ -178,18 +178,18 @@ class DomainRoleHandler extends ManageHandler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDelete({ roles }) {
|
||||
async postDelete({ domainId, roles }) {
|
||||
for (const role of roles) {
|
||||
if (['root', 'default', 'guest'].includes(role)) {
|
||||
throw new ValidationError('role');
|
||||
}
|
||||
}
|
||||
await user.deleteRoles(roles);
|
||||
await user.deleteRoles(domainId, roles);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('ranking', '/ranking', DomainRankHandler);
|
||||
Route('domain_create', '/domain/create', DomainCreateHandler);
|
||||
Route('domain_dashboard', '/domain/dashboard', DomainDashboardHandler);
|
||||
@@ -199,4 +199,4 @@ async function apply() {
|
||||
Route('domain_role', '/domain/role', DomainRoleHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.domain = module.exports = apply;
|
||||
global.Hydro.handler.domain = apply;
|
||||
@@ -1,40 +1,32 @@
|
||||
const fs = require('fs');
|
||||
const {
|
||||
import fs from 'fs';
|
||||
import {
|
||||
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
||||
NotFoundError,
|
||||
} = require('../error');
|
||||
const bus = require('../service/bus');
|
||||
const {
|
||||
} from '../error';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
Route, Connection, Handler, ConnectionHandler,
|
||||
} = require('../service/server');
|
||||
const misc = require('../lib/misc');
|
||||
const md5 = require('../lib/md5');
|
||||
const contest = require('../model/contest');
|
||||
const message = require('../model/message');
|
||||
const document = require('../model/document');
|
||||
const system = require('../model/system');
|
||||
const user = require('../model/user');
|
||||
const file = require('../model/file');
|
||||
const setting = require('../model/setting');
|
||||
const domain = require('../model/domain');
|
||||
const discussion = require('../model/discussion');
|
||||
const token = require('../model/token');
|
||||
const training = require('../model/training');
|
||||
const {
|
||||
PERM: {
|
||||
PERM_VIEW_TRAINING, PERM_VIEW_CONTEST, PERM_VIEW_DISCUSSION,
|
||||
PERM_VIEW_HOMEWORK,
|
||||
},
|
||||
PRIV: {
|
||||
PRIV_USER_PROFILE, PRIV_DELETE_FILE, PRIV_DELETE_FILE_SELF,
|
||||
},
|
||||
} = require('../model/builtin');
|
||||
} from '../service/server';
|
||||
import * as misc from '../lib/misc';
|
||||
import md5 from '../lib/md5';
|
||||
import * as contest from '../model/contest';
|
||||
import * as message from '../model/message';
|
||||
import * as document from '../model/document';
|
||||
import * as system from '../model/system';
|
||||
import * as user from '../model/user';
|
||||
import * as file from '../model/file';
|
||||
import * as setting from '../model/setting';
|
||||
import * as domain from '../model/domain';
|
||||
import * as discussion from '../model/discussion';
|
||||
import * as token from '../model/token';
|
||||
import * as training from '../model/training';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
|
||||
const { geoip, useragent } = global.Hydro.lib;
|
||||
|
||||
class HomeHandler extends Handler {
|
||||
async homework(domainId) {
|
||||
if (this.user.hasPerm(PERM_VIEW_HOMEWORK)) {
|
||||
if (this.user.hasPerm(PERM.PERM_VIEW_HOMEWORK)) {
|
||||
const tdocs = await contest.getMulti(domainId, {}, document.TYPE_HOMEWORK)
|
||||
.sort('beginAt', -1)
|
||||
.limit(await system.get('HOMEWORK_ON_MAIN'))
|
||||
@@ -49,7 +41,7 @@ class HomeHandler extends Handler {
|
||||
}
|
||||
|
||||
async contest(domainId) {
|
||||
if (this.user.hasPerm(PERM_VIEW_CONTEST)) {
|
||||
if (this.user.hasPerm(PERM.PERM_VIEW_CONTEST)) {
|
||||
const tdocs = await contest.getMulti(domainId)
|
||||
.sort('beginAt', -1)
|
||||
.limit(await system.get('CONTESTS_ON_MAIN'))
|
||||
@@ -63,7 +55,7 @@ class HomeHandler extends Handler {
|
||||
}
|
||||
|
||||
async training(domainId) {
|
||||
if (this.user.hasPerm(PERM_VIEW_TRAINING)) {
|
||||
if (this.user.hasPerm(PERM.PERM_VIEW_TRAINING)) {
|
||||
const tdocs = await training.getMulti(domainId)
|
||||
.sort('_id', 1)
|
||||
.limit(await system.get('TRAININGS_ON_MAIN'))
|
||||
@@ -76,8 +68,8 @@ class HomeHandler extends Handler {
|
||||
return [[], {}];
|
||||
}
|
||||
|
||||
async discussion(domainId) {
|
||||
if (this.user.hasPerm(PERM_VIEW_DISCUSSION)) {
|
||||
async discussion(domainId): Promise<[any[], any]> {
|
||||
if (this.user.hasPerm(PERM.PERM_VIEW_DISCUSSION)) {
|
||||
const ddocs = await discussion.getMulti(domainId)
|
||||
.limit(await system.get('DISCUSSIONS_ON_MAIN'))
|
||||
.toArray();
|
||||
@@ -147,10 +139,10 @@ class HomeSecurityHandler extends Handler {
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postChangeMail({ currentPassword, mail }) {
|
||||
async postChangeMail({ domainId, currentPassword, mail }) {
|
||||
this.limitRate('send_mail', 3600, 30);
|
||||
this.user.checkPassword(currentPassword);
|
||||
const udoc = await user.getByMail(mail);
|
||||
const udoc = await user.getByEmail(domainId, mail, true);
|
||||
if (udoc) throw new UserAlreadyExistError(mail);
|
||||
const [code] = await token.add(
|
||||
token.TYPE_CHANGEMAIL,
|
||||
@@ -216,12 +208,12 @@ class HomeSettingsHandler extends Handler {
|
||||
}
|
||||
|
||||
class UserChangemailWithCodeHandler extends Handler {
|
||||
async get({ code }) {
|
||||
async get({ domainId, code }) {
|
||||
const tdoc = await token.get(code, token.TYPE_CHANGEMAIL);
|
||||
if (!tdoc || tdoc.uid !== this.user._id) {
|
||||
throw new InvalidTokenError(code);
|
||||
}
|
||||
const udoc = await user.getByEmail(tdoc.mail);
|
||||
const udoc = await user.getByEmail(domainId, tdoc.mail, true);
|
||||
if (udoc) throw new UserAlreadyExistError(tdoc.mail);
|
||||
await Promise.all([
|
||||
user.setEmail(this.user._id, tdoc.mail),
|
||||
@@ -271,7 +263,7 @@ class HomeMessagesHandler extends Handler {
|
||||
}
|
||||
|
||||
async postDeleteMessage({ messageId }) {
|
||||
await message.delete(messageId, this.user._id);
|
||||
await message.del(messageId);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
@@ -293,29 +285,29 @@ class HomeMessagesConnectionHandler extends ConnectionHandler {
|
||||
class HomeFileHandler extends Handler {
|
||||
async get() {
|
||||
const ufdocs = await file.getMulti({ owner: this.user._id }).toArray();
|
||||
const fdict = await fs.getMetaDict(ufdocs.map((ufdoc) => ufdoc._id));
|
||||
const fdict = await file.getMetaDict(ufdocs.map((ufdoc) => ufdoc._id));
|
||||
this.response.template = 'home_file.html';
|
||||
this.response.body = { ufdocs, fdict };
|
||||
}
|
||||
|
||||
async postDelete(ufid) {
|
||||
const ufdoc = await file.get(ufid);
|
||||
if (ufdoc.owner !== this.user._id) this.checkPriv(PRIV_DELETE_FILE);
|
||||
else this.checkPriv(PRIV_DELETE_FILE_SELF);
|
||||
const ufdoc = await file.getMeta(ufid);
|
||||
if (ufdoc.owner !== this.user._id) this.checkPriv(PRIV.PRIV_DELETE_FILE);
|
||||
else this.checkPriv(PRIV.PRIV_DELETE_FILE_SELF);
|
||||
const result = await file.del(ufdoc._id);
|
||||
if (result) await file.decUsage(this.user._id, ufdoc.length);
|
||||
if (result) await user.inc(this.user._id, 'usage', ufdoc.length);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('homepage', '/', HomeHandler);
|
||||
Route('home_security', '/home/security', HomeSecurityHandler, PRIV_USER_PROFILE);
|
||||
Route('user_changemail_with_code', '/home/changeMail/:code', UserChangemailWithCodeHandler, PRIV_USER_PROFILE);
|
||||
Route('home_settings', '/home/settings/:category', HomeSettingsHandler, PRIV_USER_PROFILE);
|
||||
Route('home_messages', '/home/messages', HomeMessagesHandler, PRIV_USER_PROFILE);
|
||||
Route('home_file', '/home/file', HomeFileHandler, PRIV_USER_PROFILE);
|
||||
Connection('home_messages_conn', '/home/messages-conn', HomeMessagesConnectionHandler, PRIV_USER_PROFILE);
|
||||
Route('home_security', '/home/security', HomeSecurityHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('user_changemail_with_code', '/home/changeMail/:code', UserChangemailWithCodeHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_settings', '/home/settings/:category', HomeSettingsHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_messages', '/home/messages', HomeMessagesHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('home_file', '/home/file', HomeFileHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Connection('home_messages_conn', '/home/messages-conn', HomeMessagesConnectionHandler, PRIV.PRIV_USER_PROFILE);
|
||||
}
|
||||
|
||||
global.Hydro.handler.home = module.exports = apply;
|
||||
@@ -1,27 +1,21 @@
|
||||
const yaml = require('js-yaml');
|
||||
const moment = require('moment-timezone');
|
||||
const { ObjectID } = require('mongodb');
|
||||
const AdmZip = require('adm-zip');
|
||||
const {
|
||||
import yaml from 'js-yaml';
|
||||
import moment from 'moment-timezone';
|
||||
import { ObjectID } from 'mongodb';
|
||||
import AdmZip from 'adm-zip';
|
||||
import {
|
||||
ValidationError, HomeworkNotLiveError, ProblemNotFoundError,
|
||||
HomeworkNotAttendedError,
|
||||
} = require('../error');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const {
|
||||
PERM_VIEW_HOMEWORK, PERM_ATTEND_HOMEWORK, PERM_VIEW_PROBLEM,
|
||||
PERM_SUBMIT_PROBLEM, PERM_CREATE_HOMEWORK, PERM_EDIT_HOMEWORK,
|
||||
PERM_VIEW_HOMEWORK_SCOREBOARD, PERM_READ_RECORD_CODE,
|
||||
} = require('../model/builtin').PERM;
|
||||
const system = require('../model/system');
|
||||
const user = require('../model/user');
|
||||
const contest = require('../model/contest');
|
||||
const discussion = require('../model/discussion');
|
||||
const problem = require('../model/problem');
|
||||
const record = require('../model/record');
|
||||
const document = require('../model/document');
|
||||
const paginate = require('../lib/paginate');
|
||||
const misc = require('../lib/misc');
|
||||
const ranked = require('../lib/rank');
|
||||
} from '../error';
|
||||
import { Route, Handler } from '../service/server';
|
||||
import { PERM } from '../model/builtin';
|
||||
import * as system from '../model/system';
|
||||
import * as user from '../model/user';
|
||||
import * as contest from '../model/contest';
|
||||
import * as discussion from '../model/discussion';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import * as document from '../model/document';
|
||||
import paginate from '../lib/paginate';
|
||||
|
||||
const HomeworkHandler = contest.ContestHandlerMixin(Handler);
|
||||
|
||||
@@ -31,7 +25,7 @@ class HomeworkMainHandler extends HomeworkHandler {
|
||||
const calendar = [];
|
||||
for (const tdoc of tdocs) {
|
||||
const cal = { ...tdoc, url: `/homework/${tdoc.docId}` };
|
||||
if (contest.isHomeworkExtended(tdoc) || contest.isDone(tdoc)) {
|
||||
if (contest.isExtended(tdoc) || contest.isDone(tdoc)) {
|
||||
cal.endAt = tdoc.endAt;
|
||||
cal.penaltySince = tdoc.penaltySince;
|
||||
} else {
|
||||
@@ -93,7 +87,7 @@ class HomeworkDetailHandler extends HomeworkHandler {
|
||||
}
|
||||
|
||||
async postAttend({ domainId, tid }) {
|
||||
this.checkPerm(PERM_ATTEND_HOMEWORK);
|
||||
this.checkPerm(PERM.PERM_ATTEND_HOMEWORK);
|
||||
const tdoc = await contest.get(domainId, tid, document.TYPE_HOMEWORK);
|
||||
if (contest.isDone(tdoc)) throw new HomeworkNotLiveError(tdoc.docId);
|
||||
await contest.attend(domainId, tdoc.docId, this.user._id, document.TYPE_HOMEWORK);
|
||||
@@ -103,7 +97,7 @@ class HomeworkDetailHandler extends HomeworkHandler {
|
||||
|
||||
class HomeworkDetailProblemHandler extends HomeworkHandler {
|
||||
async prepare({ domainId, tid, pid }) {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM);
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM);
|
||||
[this.tdoc, this.pdoc, this.tsdoc] = await Promise.all([
|
||||
contest.get(domainId, tid, document.TYPE_HOMEWORK),
|
||||
problem.get(domainId, pid, this.user._id),
|
||||
@@ -121,7 +115,7 @@ class HomeworkDetailProblemHandler extends HomeworkHandler {
|
||||
if (!this.tdoc.pids.includes(pid)) throw new ProblemNotFoundError(domainId, pid, tid);
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['homework_main', '/homework'],
|
||||
['homework_main', 'homework_main'],
|
||||
[this.tdoc.title, 'homework_detail', { tid }, true],
|
||||
[this.pdoc.title, null, null, true],
|
||||
];
|
||||
@@ -170,8 +164,8 @@ class HomeworkDetailProblemSubmitHandler extends HomeworkDetailProblemHandler {
|
||||
await contest.updateStatus(domainId, tid, this.user._id,
|
||||
rid, pid, false, 0, document.TYPE_HOMEWORK);
|
||||
this.response.body = { tid, rid };
|
||||
if (this.canShowRecord(this.tdoc)) this.response.redirect = `/record/${rid}`;
|
||||
else this.response.redirect = `/homework/${tid}`;
|
||||
if (this.canShowRecord(this.tdoc)) this.response.redirect = this.url('record_detail', { rid });
|
||||
else this.response.redirect = this.url('homework_detail', { tid });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,7 +224,8 @@ class HomeworkCreateHandler extends HomeworkHandler {
|
||||
class HomeworkEditHandler extends HomeworkHandler {
|
||||
async get({ domainId, tid }) {
|
||||
const tdoc = await contest.get(domainId, tid, document.TYPE_HOMEWORK);
|
||||
if (tdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_HOMEWORK);
|
||||
if (tdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_HOMEWORK);
|
||||
else this.checkPerm(PERM.PERM_EDIT_HOMEWORK_SELF);
|
||||
const extensionDays = Math.round(
|
||||
(tdoc.endAt.getTime() - tdoc.penaltySince.getTime()) / 36000 / 24,
|
||||
) / 100;
|
||||
@@ -262,7 +257,8 @@ class HomeworkEditHandler extends HomeworkHandler {
|
||||
penaltyRules, pids, tid,
|
||||
}) {
|
||||
const tdoc = await contest.get(domainId, tid, document.TYPE_HOMEWORK);
|
||||
if (tdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_HOMEWORK);
|
||||
if (tdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_HOMEWORK);
|
||||
else this.checkPerm(PERM.PERM_EDIT_HOMEWORK_SELF);
|
||||
let beginAt;
|
||||
let penaltySince;
|
||||
try {
|
||||
@@ -288,7 +284,7 @@ class HomeworkEditHandler extends HomeworkHandler {
|
||||
|| tdoc.endAt !== endAt
|
||||
|| tdoc.penaltySince !== penaltySince
|
||||
|| new Set(tdoc.pids) !== new Set(pids)) {
|
||||
await contest.recalcStatus(domainId, document.TYPE_HOMEWORK, tdoc.docId);
|
||||
await contest.recalcStatus(domainId, tdoc.docId, document.TYPE_HOMEWORK);
|
||||
}
|
||||
this.response.body = { tid };
|
||||
this.response.redirect = this.url('homework_detail', { tid });
|
||||
@@ -327,7 +323,7 @@ class HomeworkScoreboardDownloadHandler extends HomeworkHandler {
|
||||
|
||||
class HomeworkCodeHandler extends HomeworkHandler {
|
||||
async get({ domainId, tid }) {
|
||||
this.checkPerm(PERM_READ_RECORD_CODE);
|
||||
this.checkPerm(PERM.PERM_READ_RECORD_CODE);
|
||||
this.limitRate('homework_code', 3600, 60);
|
||||
const [tdoc, tsdocs] = await contest.getAndListStatus(
|
||||
domainId, tid, document.TYPE_HOMEWORK,
|
||||
@@ -352,155 +348,15 @@ class HomeworkCodeHandler extends HomeworkHandler {
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
contest.isHomeworkExtended = (tdoc) => {
|
||||
const now = new Date().getTime();
|
||||
return tdoc.penaltySince.getTime() <= now && now < tdoc.endAt.getTime();
|
||||
};
|
||||
contest.RULES.homework = {
|
||||
TEXT: 'Assignment',
|
||||
check: () => { },
|
||||
stat: (tdoc, journal) => {
|
||||
const effective = {};
|
||||
for (const j of journal) {
|
||||
if (tdoc.pids.includes(j.pid)
|
||||
&& !effective.includes(j.pid)
|
||||
&& effective[j.pid].accept) {
|
||||
effective[j.pid] = j;
|
||||
}
|
||||
}
|
||||
function time(jdoc) {
|
||||
const real = jdoc.rid.generationTime - tdoc.beginAt.getTime() / 1000;
|
||||
return Math.floor(real);
|
||||
}
|
||||
function penaltyScore(jdoc) {
|
||||
const { score } = jdoc;
|
||||
const exceedSeconds = Math.floor(
|
||||
jdoc.rid.generationTime - tdoc.penaltySince.getTime() / 1000,
|
||||
);
|
||||
if (exceedSeconds < 0) return score;
|
||||
let coefficient = 1;
|
||||
const keys = Object.keys(tdoc.penaltyRules)
|
||||
.map((k) => parseFloat(k)).sort((a, b) => a - b);
|
||||
for (const i of keys) {
|
||||
if (i * 3600 <= exceedSeconds) coefficient = tdoc.penaltyRules[i];
|
||||
else break;
|
||||
}
|
||||
return score * coefficient;
|
||||
}
|
||||
const detail = [];
|
||||
for (const j of effective) {
|
||||
detail.push({ ...j, penaltyScore: penaltyScore(j), time: time(j) });
|
||||
}
|
||||
return {
|
||||
score: Math.sum(detail.map((d) => d.score)),
|
||||
penaltyScore: Math.sum(detail.map((d) => d.penaltySince)),
|
||||
time: Math.sum(detail.map((d) => d.time)),
|
||||
detail,
|
||||
};
|
||||
},
|
||||
showScoreboard: () => true,
|
||||
showRecord: () => true,
|
||||
scoreboard(isExport, _, tdoc, rankedTsdocs, udict, pdict) {
|
||||
const columns = [
|
||||
{ type: 'rank', value: _('Rank') },
|
||||
{ type: 'user', value: _('User') },
|
||||
{ type: 'total_score', value: _('Score') },
|
||||
];
|
||||
if (isExport) {
|
||||
columns.push(
|
||||
{ type: 'total_original_score', value: _('Original Score') },
|
||||
{ type: 'total_time', value: _('Total Time (Seconds)') },
|
||||
);
|
||||
}
|
||||
columns.push({ type: 'total_time_str', value: _('Total Time') });
|
||||
for (const index in tdoc.pids) {
|
||||
const pid = tdoc.pids[index];
|
||||
if (isExport) {
|
||||
columns.push(
|
||||
{
|
||||
type: 'problem_score',
|
||||
value: '#{0} {1}'.format(index + 1, pdict[pid].title),
|
||||
},
|
||||
{
|
||||
type: 'problem_original_score',
|
||||
value: '#{0} {1}'.format(index + 1, _('Original Score')),
|
||||
},
|
||||
{
|
||||
type: 'problem_time',
|
||||
value: '#{0} {1}'.format(index + 1, _('Time (Seconds)')),
|
||||
},
|
||||
{
|
||||
type: 'problem_time_str',
|
||||
value: '#{0} {1}'.format(index + 1, _('Time')),
|
||||
},
|
||||
);
|
||||
} else {
|
||||
columns.push({
|
||||
type: 'problem_detail',
|
||||
value: '#{0}'.format(index + 1),
|
||||
raw: pdict[pid],
|
||||
});
|
||||
}
|
||||
}
|
||||
const rows = [columns];
|
||||
for (const [rank, tsdoc] of rankedTsdocs) {
|
||||
const tsddict = {};
|
||||
for (const item of tsdoc.journal || []) {
|
||||
tsddict[item.pid] = item;
|
||||
}
|
||||
const row = [
|
||||
{ type: 'string', value: rank },
|
||||
{
|
||||
type: 'user',
|
||||
value: udict[tsdoc.uid].uname,
|
||||
raw: udict[tsdoc.uid],
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
value: tsdoc.penaltyScore || 0,
|
||||
},
|
||||
];
|
||||
if (isExport) {
|
||||
row.push({ type: 'string', value: tsdoc.score || 0 });
|
||||
row.push({ type: 'string', value: tsdoc.time || 0.0 });
|
||||
}
|
||||
row.push({ type: 'string', value: misc.formatSeconds(tsdoc.time || 0) });
|
||||
for (const pid of tdoc.pids) {
|
||||
const rdoc = (tsddict[pid] || {}).rid;
|
||||
const colScore = (tsddict[pid] || {}).penaltyScore || '-';
|
||||
const colOriginalScore = (tsddict[pid] || {}).score || '-';
|
||||
const colTime = (tsddict[pid] || {}).time || '-';
|
||||
const colTimeStr = colTime !== '-' ? misc.formatSeconds(colTime || 0) : '-';
|
||||
if (isExport) {
|
||||
row.push(
|
||||
{ type: 'string', value: colScore },
|
||||
{ type: 'string', value: colOriginalScore },
|
||||
{ type: 'string', value: colTime },
|
||||
{ type: 'string', value: colTimeStr },
|
||||
);
|
||||
} else {
|
||||
row.push({
|
||||
type: 'record',
|
||||
value: '{0} / {1}\n{2}'.format(colScore, colOriginalScore, colTimeStr),
|
||||
raw: rdoc,
|
||||
});
|
||||
}
|
||||
}
|
||||
rows.push(row);
|
||||
}
|
||||
return rows;
|
||||
},
|
||||
rank: (tsdocs) => ranked(tsdocs, (a, b) => a.score === b.score),
|
||||
};
|
||||
Route('homework_main', '/homework', HomeworkMainHandler, PERM_VIEW_HOMEWORK);
|
||||
Route('homework_create', '/homework/create', HomeworkCreateHandler, PERM_CREATE_HOMEWORK);
|
||||
Route('homework_detail', '/homework/:tid', HomeworkDetailHandler, PERM_VIEW_HOMEWORK);
|
||||
Route('homework_scoreboard', '/homework/:tid/scoreboard', HomeworkScoreboardHandler, PERM_VIEW_HOMEWORK_SCOREBOARD);
|
||||
Route('homework_scoreboard', '/homework/:tid/scoreboard/download/:ext', HomeworkScoreboardDownloadHandler, PERM_VIEW_HOMEWORK_SCOREBOARD);
|
||||
Route('homework_detail_problem', '/homework/:tid/p/:pid', HomeworkDetailProblemHandler, PERM_VIEW_HOMEWORK);
|
||||
Route('homework_detail_problem_submit', '/homework/:tid/p/:pid/submit', HomeworkDetailProblemSubmitHandler, PERM_SUBMIT_PROBLEM);
|
||||
Route('homework_code', '/homework/:tid/code', HomeworkCodeHandler, PERM_VIEW_HOMEWORK);
|
||||
Route('homework_main', '/homework', HomeworkMainHandler, PERM.PERM_VIEW_HOMEWORK);
|
||||
Route('homework_create', '/homework/create', HomeworkCreateHandler, PERM.PERM_CREATE_HOMEWORK);
|
||||
Route('homework_detail', '/homework/:tid', HomeworkDetailHandler, PERM.PERM_VIEW_HOMEWORK);
|
||||
Route('homework_scoreboard', '/homework/:tid/scoreboard', HomeworkScoreboardHandler, PERM.PERM_VIEW_HOMEWORK_SCOREBOARD);
|
||||
Route('homework_scoreboard', '/homework/:tid/scoreboard/download/:ext', HomeworkScoreboardDownloadHandler, PERM.PERM_VIEW_HOMEWORK_SCOREBOARD);
|
||||
Route('homework_detail_problem', '/homework/:tid/p/:pid', HomeworkDetailProblemHandler, PERM.PERM_VIEW_HOMEWORK);
|
||||
Route('homework_detail_problem_submit', '/homework/:tid/p/:pid/submit', HomeworkDetailProblemSubmitHandler, PERM.PERM_SUBMIT_PROBLEM);
|
||||
Route('homework_code', '/homework/:tid/code', HomeworkCodeHandler, PERM.PERM_VIEW_HOMEWORK);
|
||||
Route('homework_edit', '/homework/:tid/edit', HomeworkEditHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.homework = module.exports = apply;
|
||||
global.Hydro.handler.homework = apply;
|
||||
@@ -1,14 +1,14 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const problem = require('../model/problem');
|
||||
const { PERM_CREATE_PROBLEM } = require('../model/builtin').PERM;
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { ValidationError } = require('../error');
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import os from 'os';
|
||||
import { ValidationError } from '../error'
|
||||
import * as problem from '../model/problem';
|
||||
import { PERM } from '../model/builtin';
|
||||
import { Route, Handler } from '../service/server'
|
||||
|
||||
class ProblemImportHandler extends Handler {
|
||||
async prepare() {
|
||||
this.checkPerm(PERM_CREATE_PROBLEM);
|
||||
this.checkPerm(PERM.PERM_CREATE_PROBLEM);
|
||||
}
|
||||
|
||||
async get() {
|
||||
@@ -47,8 +47,8 @@ class ProblemImportHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('problem_import', '/problem/import', ProblemImportHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.import = module.exports = apply;
|
||||
global.Hydro.handler.import = apply;
|
||||
@@ -1,18 +1,18 @@
|
||||
const yaml = require('js-yaml');
|
||||
const { parseTimeMS, parseMemoryMB } = require('../utils');
|
||||
const record = require('../model/record');
|
||||
const problem = require('../model/problem');
|
||||
const builtin = require('../model/builtin');
|
||||
const contest = require('../model/contest');
|
||||
const user = require('../model/user');
|
||||
const task = require('../model/task');
|
||||
const bus = require('../service/bus');
|
||||
const {
|
||||
import yaml from 'js-yaml';
|
||||
import { parseTimeMS, parseMemoryMB } from '../utils';
|
||||
import * as record from '../model/record';
|
||||
import * as problem from '../model/problem';
|
||||
import * as builtin from '../model/builtin';
|
||||
import * as contest from '../model/contest';
|
||||
import * as user from '../model/user';
|
||||
import * as task from '../model/task';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
Route, Handler, Connection, ConnectionHandler,
|
||||
} = require('../service/server');
|
||||
} from '../service/server';
|
||||
|
||||
async function _postJudge(rdoc) {
|
||||
const accept = rdoc.status === builtin.STATUS_ACCEPTED;
|
||||
const accept = rdoc.status === builtin.STATUS.STATUS_ACCEPTED;
|
||||
bus.publish('record_change', rdoc);
|
||||
if (rdoc.type === 'run') return;
|
||||
const tasks = [];
|
||||
@@ -24,7 +24,7 @@ async function _postJudge(rdoc) {
|
||||
),
|
||||
);
|
||||
}
|
||||
if (await problem.updateStatus(rdoc.pid, rdoc.uid, rdoc._id, rdoc.status)) {
|
||||
if (await problem.updateStatus(rdoc.domainId, rdoc.pid, rdoc.uid, rdoc._id, rdoc.status)) {
|
||||
if (accept && !rdoc.rejudged) {
|
||||
tasks.push(
|
||||
problem.inc(rdoc.domainId, rdoc.pid, 'nAccept', 1),
|
||||
@@ -35,12 +35,12 @@ async function _postJudge(rdoc) {
|
||||
await Promise.all(tasks);
|
||||
}
|
||||
|
||||
async function next(body) {
|
||||
export async function next(body) {
|
||||
let rdoc = await record.get(body.domainId, body.rid);
|
||||
const $set = {};
|
||||
const $push = {};
|
||||
const $set: any = {};
|
||||
const $push: any = {};
|
||||
if (body.case) {
|
||||
const c = {};
|
||||
const c: any = {};
|
||||
c.memory = body.case.memory_kb || body.case.memory;
|
||||
c.time = body.case.time_ms || body.case.time;
|
||||
c.judgeText = body.case.judge_text || body.case.judgeText || body.case.message;
|
||||
@@ -65,10 +65,10 @@ async function next(body) {
|
||||
bus.publish('record_change', rdoc);
|
||||
}
|
||||
|
||||
async function end(body) {
|
||||
export async function end(body) {
|
||||
let rdoc = await record.get(body.domainId, body.rid);
|
||||
const $set = {};
|
||||
const $push = {};
|
||||
const $set: any = {};
|
||||
const $push: any = {};
|
||||
const $unset = { progress: '' };
|
||||
if (body.judge_text) {
|
||||
rdoc.judgeTexts.push(body.judge_text);
|
||||
@@ -98,7 +98,7 @@ class PretestHandler extends Handler {
|
||||
if (pid) {
|
||||
const pdoc = await problem.get(domainId, pid);
|
||||
if (pdoc.config) {
|
||||
const config = yaml.safeLoad(pdoc.config);
|
||||
const config: any = yaml.safeLoad(pdoc.config);
|
||||
if (config.time) time = config.time;
|
||||
if (config.memory) memory = config.memory;
|
||||
}
|
||||
@@ -155,19 +155,19 @@ class JudgeConnectionHandler extends ConnectionHandler {
|
||||
|
||||
async cleanup() {
|
||||
if (this.processing) {
|
||||
await record.reset(this.processing);
|
||||
await record.reset(this.processing.domainId, this.processing.rid);
|
||||
task.add(this.processing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('pretest', '/pretest', PretestHandler);
|
||||
Route('judge', '/judge', JudgeHandler, builtin.PERM.PERM_JUDGE);
|
||||
Connection('judge_conn', '/judge/conn', JudgeConnectionHandler, builtin.PERM.PERM_JUDGE);
|
||||
Route('judge', '/judge', JudgeHandler, builtin.PRIV.PRIV_JUDGE);
|
||||
Connection('judge_conn', '/judge/conn', JudgeConnectionHandler, builtin.PRIV.PRIV_JUDGE);
|
||||
}
|
||||
|
||||
apply.next = next;
|
||||
apply.end = end;
|
||||
|
||||
global.Hydro.handler.judge = module.exports = apply;
|
||||
global.Hydro.handler.judge = apply;
|
||||
@@ -1,14 +1,14 @@
|
||||
const setting = require('../model/setting');
|
||||
const system = require('../model/system');
|
||||
const { STATUS, PRIV } = require('../model/builtin');
|
||||
const record = require('../model/record');
|
||||
const judge = require('./judge');
|
||||
const {
|
||||
import * as judge from './judge';
|
||||
import { ValidationError } from '../error';
|
||||
import * as check from '../check';
|
||||
import * as setting from '../model/setting';
|
||||
import * as system from '../model/system';
|
||||
import { STATUS, PRIV } from '../model/builtin';
|
||||
import * as record from '../model/record';
|
||||
import {
|
||||
Route, Connection, Handler, ConnectionHandler,
|
||||
} = require('../service/server');
|
||||
const hpm = require('../lib/hpm');
|
||||
const loader = require('../loader');
|
||||
const check = require('../check');
|
||||
} from '../service/server';
|
||||
import * as hpm from '../lib/hpm';
|
||||
|
||||
function set(key, value) {
|
||||
if (setting.SYSTEM_SETTINGS_BY_KEY[key]) {
|
||||
@@ -81,7 +81,6 @@ class SystemModuleHandler extends SystemHandler {
|
||||
async get() {
|
||||
this.response.body.path.push(['manage_module', null]);
|
||||
this.response.body.installed = await hpm.getDetail();
|
||||
this.response.active = loader.active;
|
||||
this.response.template = 'manage_module.html';
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
const { PRIV_JUDGE, PRIV_USER_PROFILE } = require('../model/builtin').PRIV;
|
||||
const file = require('../model/file');
|
||||
const user = require('../model/user');
|
||||
const markdown = require('../lib/markdown');
|
||||
const db = require('../service/db');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
import { PRIV } from '../model/builtin';
|
||||
import * as file from '../model/file';
|
||||
import * as user from '../model/user';
|
||||
import * as markdown from '../lib/markdown';
|
||||
import * as db from '../service/db';
|
||||
import { Route, Handler } from '../service/server';
|
||||
|
||||
const coll = db.collection('status');
|
||||
|
||||
@@ -11,7 +11,7 @@ class FileDownloadHandler extends Handler {
|
||||
async get({ docId, secret, name }) {
|
||||
if (name) name = Buffer.from(name, 'base64').toString();
|
||||
this.response.attachment(name || docId);
|
||||
this.response.body = await file.get(docId, secret);
|
||||
this.response.body = await file.getWithSecret(docId, secret);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ class StatusHandler extends Handler {
|
||||
|
||||
class StatusUpdateHandler extends Handler {
|
||||
async post(args) {
|
||||
this.checkPerm(PRIV_JUDGE);
|
||||
this.checkPerm(PRIV.PRIV_JUDGE);
|
||||
args.type = 'judger';
|
||||
return coll.updateOne(
|
||||
{ mid: args.mid, type: 'judger' },
|
||||
@@ -49,7 +49,7 @@ class StatusUpdateHandler extends Handler {
|
||||
|
||||
class SwitchLanguageHandler extends Handler {
|
||||
async get({ lang }) {
|
||||
if (this.user.hasPriv(PRIV_USER_PROFILE)) {
|
||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||
await user.setById(this.user._id, { viewLang: lang });
|
||||
} else this.session.viewLang = lang;
|
||||
this.back();
|
||||
@@ -70,7 +70,7 @@ class SockToken extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('file_download', '/fs/:docId/:secret', FileDownloadHandler);
|
||||
Route('file_download_with_name', '/fs/:docId/:name/:secret', FileDownloadHandler);
|
||||
Route('status', '/status', StatusHandler);
|
||||
@@ -89,4 +89,4 @@ apply.updateStatus = function updateStatus(args) {
|
||||
);
|
||||
};
|
||||
|
||||
global.Hydro.handler.misc = module.exports = apply;
|
||||
global.Hydro.handler.misc = apply;
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable no-empty-function */
|
||||
/* eslint-disable class-methods-use-this */
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { NotFoundError } = require('../error');
|
||||
import { NotFoundError } from '../error';
|
||||
import { Route, Handler } from '../service/server';
|
||||
|
||||
class NotFoundHandler extends Handler {
|
||||
async prepare() {
|
||||
@@ -13,8 +13,8 @@ class NotFoundHandler extends Handler {
|
||||
async post() { }
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('notfound', '*', NotFoundHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.notfound = module.exports = apply;
|
||||
global.Hydro.handler.notfound = apply;
|
||||
@@ -1,58 +1,47 @@
|
||||
const paginate = require('../lib/paginate');
|
||||
const validator = require('../lib/validator');
|
||||
const file = require('../model/file');
|
||||
const problem = require('../model/problem');
|
||||
const record = require('../model/record');
|
||||
const user = require('../model/user');
|
||||
const solution = require('../model/solution');
|
||||
const system = require('../model/system');
|
||||
const {
|
||||
PERM: {
|
||||
PERM_VIEW_PROBLEM, PERM_VIEW_PROBLEM_HIDDEN, PERM_SUBMIT_PROBLEM,
|
||||
PERM_CREATE_PROBLEM, PERM_READ_PROBLEM_DATA, PERM_EDIT_PROBLEM,
|
||||
PERM_VIEW_PROBLEM_SOLUTION, PERM_CREATE_PROBLEM_SOLUTION,
|
||||
PERM_EDIT_PROBLEM_SOLUTION, PERM_DELETE_PROBLEM_SOLUTION, PERM_EDIT_PROBLEM_SOLUTION_REPLY,
|
||||
PERM_REPLY_PROBLEM_SOLUTION, PERM_EDIT_PROBLEM_SELF,
|
||||
},
|
||||
PRIV: {
|
||||
PRIV_USER_PROFILE, PRIV_JUDGE,
|
||||
},
|
||||
} = require('../model/builtin');
|
||||
const bus = require('../service/bus');
|
||||
const {
|
||||
import paginate from '../lib/paginate';
|
||||
import * as validator from '../lib/validator';
|
||||
import * as file from '../model/file';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import * as user from '../model/user';
|
||||
import * as solution from '../model/solution';
|
||||
import * as system from '../model/system';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
Route, Connection, Handler, ConnectionHandler,
|
||||
} = require('../service/server');
|
||||
const {
|
||||
} from '../service/server';
|
||||
import {
|
||||
NoProblemError, ProblemDataNotFoundError, BadRequestError,
|
||||
SolutionNotFoundError,
|
||||
} = require('../error');
|
||||
} from '../error';
|
||||
|
||||
class ProblemHandler extends Handler {
|
||||
async _prepare() {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM);
|
||||
async __prepare() {
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM);
|
||||
}
|
||||
|
||||
async get({ domainId, page = 1, q = '' }) {
|
||||
this.response.template = 'problem_main.html';
|
||||
const query = {};
|
||||
const query: any = {};
|
||||
let psdict = {};
|
||||
const path = [
|
||||
const path: any = [
|
||||
['Hydro', 'homepage'],
|
||||
['problem_main', null],
|
||||
];
|
||||
if (q) {
|
||||
q = q.toLowerCase();
|
||||
const $regex = new RegExp(`\\A\\Q${q.replace(/\\E/gmi, /\\E\\E\\Q/gmi)}\\E`, 'gmi');
|
||||
const $regex = new RegExp(`\\A\\Q${q}\\E`, 'gmi');
|
||||
query.title = { $regex };
|
||||
path.push([q, null, null, true]);
|
||||
}
|
||||
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) query.hidden = false;
|
||||
if (!this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) query.hidden = false;
|
||||
const [pdocs, ppcount, pcount] = await paginate(
|
||||
problem.getMulti(domainId, query).sort({ pid: 1 }),
|
||||
page,
|
||||
await system.get('PROBLEM_PER_PAGE'),
|
||||
);
|
||||
if (this.user.hasPriv(PRIV_USER_PROFILE)) {
|
||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||
psdict = await problem.getListStatus(
|
||||
domainId, this.user._id, pdocs.map((pdoc) => pdoc.docId),
|
||||
);
|
||||
@@ -73,7 +62,7 @@ class ProblemHandler extends Handler {
|
||||
}
|
||||
|
||||
async cleanup() {
|
||||
if (this.response.template === 'problem_main.html' && this.preferJson) {
|
||||
if (this.response.template === 'problem_main.html' && this.request.json) {
|
||||
const {
|
||||
path, page, pcount, ppcount, pdocs, psdict, category,
|
||||
} = this.response.body;
|
||||
@@ -98,7 +87,7 @@ class ProblemHandler extends Handler {
|
||||
class ProblemCategoryHandler extends ProblemHandler {
|
||||
async get({ domainId, page = 1, category }) {
|
||||
this.response.template = 'problem_main.html';
|
||||
const q = { $and: [] };
|
||||
const q: any = { $and: [] };
|
||||
for (const name of category) {
|
||||
q.$and.push({
|
||||
$or: [
|
||||
@@ -108,13 +97,13 @@ class ProblemCategoryHandler extends ProblemHandler {
|
||||
});
|
||||
}
|
||||
let psdict = {};
|
||||
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
|
||||
if (!this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
|
||||
const [pdocs, ppcount, pcount] = await paginate(
|
||||
problem.getMulti(domainId, q).sort({ pid: 1 }),
|
||||
page,
|
||||
await system.get('PROBLEM_PER_PAGE'),
|
||||
);
|
||||
if (this.user.hasPriv(PRIV_USER_PROFILE)) {
|
||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||
psdict = await problem.getListStatus(
|
||||
domainId, this.user._id, pdocs.map((pdoc) => pdoc.docId),
|
||||
);
|
||||
@@ -132,7 +121,7 @@ class ProblemCategoryHandler extends ProblemHandler {
|
||||
|
||||
class ProblemRandomHandler extends ProblemHandler {
|
||||
async get({ domainId, category }) {
|
||||
const q = category[0] ? { $and: [] } : {};
|
||||
const q: any = category[0] ? { $and: [] } : {};
|
||||
for (const name of category) {
|
||||
if (name) {
|
||||
q.$and.push({
|
||||
@@ -143,7 +132,7 @@ class ProblemRandomHandler extends ProblemHandler {
|
||||
});
|
||||
}
|
||||
}
|
||||
if (!this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
|
||||
if (!this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) q.hidden = false;
|
||||
const pid = await problem.random(domainId, q);
|
||||
if (!pid) throw new NoProblemError();
|
||||
this.response.body = { pid };
|
||||
@@ -157,7 +146,7 @@ class ProblemDetailHandler extends ProblemHandler {
|
||||
if (pid) {
|
||||
this.pdoc = await problem.get(domainId, pid, this.user._id);
|
||||
if (this.pdoc.hidden && this.pdoc.owner !== this.user._id) {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||
}
|
||||
if (this.pdoc) this.udoc = await user.getById(domainId, this.pdoc.owner);
|
||||
}
|
||||
@@ -168,7 +157,8 @@ class ProblemDetailHandler extends ProblemHandler {
|
||||
};
|
||||
}
|
||||
|
||||
async get() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
async get(args: any) {
|
||||
this.response.body.path = [
|
||||
['Hydro', 'homepage'],
|
||||
['problem_main', 'problem_main'],
|
||||
@@ -260,8 +250,8 @@ class ProblemStatisticsHandler extends ProblemDetailHandler {
|
||||
|
||||
class ProblemManageHandler extends ProblemDetailHandler {
|
||||
async prepare() {
|
||||
if (this.pdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_PROBLEM);
|
||||
else this.checkPerm(PERM_EDIT_PROBLEM_SELF);
|
||||
if (this.pdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_PROBLEM);
|
||||
else this.checkPerm(PERM.PERM_EDIT_PROBLEM_SELF);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,8 +325,10 @@ class ProblemDataUploadHandler extends ProblemManageHandler {
|
||||
|
||||
class ProblemDataDownloadHandler extends ProblemDetailHandler {
|
||||
async get({ pid }) {
|
||||
if (this.user._id !== this.pdoc.owner) {
|
||||
if (!this.user.hasPerm(PERM_READ_PROBLEM_DATA)) this.checkPriv(PRIV_JUDGE);
|
||||
if (!this.user.hasPriv(PRIV.PRIV_JUDGE)) {
|
||||
if (this.user._id !== this.pdoc.owner) {
|
||||
this.checkPerm(PERM.PERM_READ_PROBLEM_DATA);
|
||||
} else this.checkPerm(PERM.PERM_READ_PROBLEM_DATA_SELF);
|
||||
}
|
||||
if (!this.pdoc.data) throw new ProblemDataNotFoundError(pid);
|
||||
else if (typeof this.pdoc.data === 'string') [, this.response.redirect] = this.pdoc.data.split('from:');
|
||||
@@ -347,7 +339,7 @@ class ProblemDataDownloadHandler extends ProblemDetailHandler {
|
||||
class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, page = 1 }) {
|
||||
this.response.template = 'problem_solution.html';
|
||||
this.checkPerm(PERM_VIEW_PROBLEM_SOLUTION);
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const [psdocs, pcount, pscount] = await paginate(
|
||||
solution.getMulti(domainId, this.pdoc.docId),
|
||||
page,
|
||||
@@ -362,7 +354,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
for (const psrdoc of psdoc.reply) uids.push(psrdoc.owner);
|
||||
}
|
||||
}
|
||||
const udict = await user.getList(uids);
|
||||
const udict = await user.getList(domainId, uids);
|
||||
const pssdict = solution.getListStatus(domainId, docids, this.user._id);
|
||||
const path = [
|
||||
['problem_main', 'problem_main'],
|
||||
@@ -379,28 +371,31 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
async postSubmit({ domainId, content }) {
|
||||
this.checkPerm(PERM_CREATE_PROBLEM_SOLUTION);
|
||||
this.checkPerm(PERM.PERM_CREATE_PROBLEM_SOLUTION);
|
||||
await solution.add(domainId, this.pdoc.docId, this.user._id, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postEditSolution({ domainId, content }) {
|
||||
if (this.psdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_PROBLEM_SOLUTION);
|
||||
if (this.psdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION);
|
||||
else this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_SELF);
|
||||
this.psdoc = await solution.edit(domainId, this.psdoc.docId, content);
|
||||
this.ctx.body.psdoc = this.psdoc;
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDeleteSolution({ domainId }) {
|
||||
if (this.psdoc.owner !== this.user._id) this.checkPerm(PERM_DELETE_PROBLEM_SOLUTION);
|
||||
if (this.psdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION);
|
||||
else this.checkPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION_SELF);
|
||||
await solution.del(domainId, this.psdoc.docId);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postReply({ domainId, psid, content }) {
|
||||
this.checkPerm(PERM_REPLY_PROBLEM_SOLUTION);
|
||||
this.checkPerm(PERM.PERM_REPLY_PROBLEM_SOLUTION);
|
||||
const psdoc = await solution.get(domainId, psid);
|
||||
await solution.reply(domainId, psdoc.docId, this.user._id, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postEditReply({
|
||||
@@ -408,14 +403,27 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
}) {
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid);
|
||||
if (psrdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_PROBLEM_SOLUTION_REPLY);
|
||||
if (!(psdoc.owner === this.user._id
|
||||
&& this.user.hasPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_REPLY_SELF_SOLUTION))) {
|
||||
if (!(psrdoc.owner === this.user._id
|
||||
&& this.user.hasPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_REPLY_SELF))) {
|
||||
this.checkPerm(PERM.PERM_EDIT_PROBLEM_SOLUTION_REPLY);
|
||||
}
|
||||
}
|
||||
await solution.editReply(domainId, psid, psrid, content);
|
||||
this.back();
|
||||
}
|
||||
|
||||
async postDeleteReply({ domainId, psid, psrid }) {
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid);
|
||||
if (psrdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_PROBLEM_SOLUTION_REPLY);
|
||||
if (!(psdoc.owner === this.user._id
|
||||
&& this.user.hasPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION_REPLY_SELF_SOLUTION))) {
|
||||
if (!(psrdoc.owner === this.user._id
|
||||
&& this.user.hasPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION_REPLY_SELF))) {
|
||||
this.checkPerm(PERM.PERM_DELETE_PROBLEM_SOLUTION_REPLY);
|
||||
}
|
||||
}
|
||||
await solution.delReply(domainId, psid, psrid);
|
||||
this.back();
|
||||
}
|
||||
@@ -435,7 +443,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
||||
|
||||
class ProblemSolutionRawHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, psid }) {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM_SOLUTION);
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const psdoc = await solution.get(domainId, psid);
|
||||
this.response.type = 'text/markdown';
|
||||
this.response.body = psdoc.content;
|
||||
@@ -443,10 +451,10 @@ class ProblemSolutionRawHandler extends ProblemDetailHandler {
|
||||
}
|
||||
|
||||
class ProblemSolutionReplyRawHandler extends ProblemDetailHandler {
|
||||
async get({ domainId, psid }) {
|
||||
this.checkPerm(PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid);
|
||||
async get({ domainId, psid, psrid }) {
|
||||
this.checkPerm(PERM.PERM_VIEW_PROBLEM_SOLUTION);
|
||||
const [psdoc, psrdoc] = await solution.getReply(domainId, psid, psrid);
|
||||
if ((!psdoc) || psdoc.pid !== this.pdoc.docId) throw new SolutionNotFoundError(psid, psrid);
|
||||
this.response.type = 'text/markdown';
|
||||
this.response.body = psrdoc.content;
|
||||
}
|
||||
@@ -455,7 +463,7 @@ class ProblemSolutionReplyRawHandler extends ProblemDetailHandler {
|
||||
class ProblemCreateHandler extends Handler {
|
||||
async get() {
|
||||
this.response.template = 'problem_edit.html';
|
||||
this.checkPerm(PERM_CREATE_PROBLEM);
|
||||
this.checkPerm(PERM.PERM_CREATE_PROBLEM);
|
||||
this.response.body = {
|
||||
path: [
|
||||
['Hydro', 'homepage'],
|
||||
@@ -477,12 +485,12 @@ class ProblemCreateHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('problem_main', '/p', ProblemHandler);
|
||||
Route('problem_category', '/p/category/:category', ProblemCategoryHandler);
|
||||
Route('problem_random', '/problem/random', ProblemRandomHandler);
|
||||
Route('problem_detail', '/p/:pid', ProblemDetailHandler);
|
||||
Route('problem_submit', '/p/:pid/submit', ProblemSubmitHandler, PERM_SUBMIT_PROBLEM);
|
||||
Route('problem_submit', '/p/:pid/submit', ProblemSubmitHandler, PERM.PERM_SUBMIT_PROBLEM);
|
||||
Route('problem_pretest', '/p/:pid/pretest', ProblemPretestHandler);
|
||||
Route('problem_settings', '/p/:pid/settings', ProblemSettingsHandler);
|
||||
Route('problem_statistics', '/p/:pid/statistics', ProblemStatisticsHandler);
|
||||
@@ -496,4 +504,4 @@ async function apply() {
|
||||
Connection('problem_pretest_conn', '/p/:pid/pretest-conn', ProblemPretestConnectionHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.problem = module.exports = apply;
|
||||
global.Hydro.handler.problem = apply;
|
||||
@@ -1,16 +1,16 @@
|
||||
const { ObjectID } = require('mongodb');
|
||||
const { PermissionError } = require('../error');
|
||||
const { PERM_READ_RECORD_CODE, PERM_REJUDGE, PERM_VIEW_PROBLEM_HIDDEN } = require('../model/builtin').PERM;
|
||||
const problem = require('../model/problem');
|
||||
const record = require('../model/record');
|
||||
const contest = require('../model/contest');
|
||||
const system = require('../model/system');
|
||||
const user = require('../model/user');
|
||||
const paginate = require('../lib/paginate');
|
||||
const bus = require('../service/bus');
|
||||
const {
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { PermissionError } from '../error';
|
||||
import { PERM } from '../model/builtin';
|
||||
import * as problem from '../model/problem';
|
||||
import * as record from '../model/record';
|
||||
import * as contest from '../model/contest';
|
||||
import * as system from '../model/system';
|
||||
import * as user from '../model/user';
|
||||
import paginate from '../lib/paginate';
|
||||
import * as bus from '../service/bus';
|
||||
import {
|
||||
Route, Handler, Connection, ConnectionHandler,
|
||||
} = require('../service/server');
|
||||
} from '../service/server';
|
||||
|
||||
const RecordHandler = contest.ContestHandlerMixin(Handler);
|
||||
|
||||
@@ -19,7 +19,7 @@ class RecordListHandler extends RecordHandler {
|
||||
domainId, page = 1, pid, tid, uidOrName,
|
||||
}) {
|
||||
this.response.template = 'record_main.html';
|
||||
const q = { tid, hidden: false };
|
||||
const q: any = { tid, hidden: false };
|
||||
if (uidOrName) {
|
||||
q.$or = [
|
||||
{ unameLower: uidOrName.toLowerCase() },
|
||||
@@ -61,7 +61,7 @@ class RecordDetailHandler extends RecordHandler {
|
||||
const tdoc = await contest.get(domainId, rdoc.tid, rdoc.ttype);
|
||||
if (!this.canShowRecord(tdoc, true)) throw new PermissionError(rid);
|
||||
}
|
||||
if (rdoc.uid !== this.user.uid && !this.user.hasPerm(PERM_READ_RECORD_CODE)) {
|
||||
if (rdoc.uid !== this.user.uid && !this.user.hasPerm(PERM.PERM_READ_RECORD_CODE)) {
|
||||
rdoc.code = null;
|
||||
}
|
||||
if (rdoc.type !== 'run') rdoc.stdout = rdoc.stderr = '';
|
||||
@@ -85,7 +85,7 @@ class RecordDetailHandler extends RecordHandler {
|
||||
|
||||
class RecordRejudgeHandler extends Handler {
|
||||
async post({ domainId, rid }) {
|
||||
this.checkPerm(PERM_REJUDGE);
|
||||
this.checkPerm(PERM.PERM_REJUDGE);
|
||||
const rdoc = await record.get(domainId, rid);
|
||||
if (rdoc) await record.rejudge(domainId, rid);
|
||||
this.back();
|
||||
@@ -131,7 +131,7 @@ class RecordMainConnectionHandler extends RecordConnectionHandler {
|
||||
user.getById(this.domainId, rdoc.uid),
|
||||
problem.get(this.domainId, rdoc.pid, null, false),
|
||||
]);
|
||||
if (pdoc && pdoc.hidden && !this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)) pdoc = null;
|
||||
if (pdoc && pdoc.hidden && !this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)) pdoc = null;
|
||||
this.send({ html: await this.renderHTML('record_main_tr.html', { rdoc, udoc, pdoc }) });
|
||||
}
|
||||
}
|
||||
@@ -165,7 +165,7 @@ class RecordDetailConnectionHandler extends contest.ContestHandlerMixin(Connecti
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('record_main', '/record', RecordListHandler);
|
||||
Route('record_detail', '/record/:rid', RecordDetailHandler);
|
||||
Route('record_rejudge', '/record/:rid/rejudge', RecordRejudgeHandler);
|
||||
@@ -173,4 +173,4 @@ async function apply() {
|
||||
Connection('record_detail_conn', '/record-detail-conn', RecordDetailConnectionHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.record = module.exports = apply;
|
||||
global.Hydro.handler.record = apply;
|
||||
@@ -1,21 +1,14 @@
|
||||
const assert = require('assert');
|
||||
const { ValidationError, ProblemNotFoundError } = require('../error');
|
||||
const paginate = require('../lib/paginate');
|
||||
const {
|
||||
PERM: {
|
||||
PERM_VIEW_TRAINING, PERM_VIEW_PROBLEM_HIDDEN, PERM_CREATE_TRAINING,
|
||||
PERM_EDIT_TRAINING, PERM_EDIT_TRAINING_SELF,
|
||||
},
|
||||
PRIV: {
|
||||
PRIV_USER_PROFILE,
|
||||
},
|
||||
} = require('../model/builtin');
|
||||
const problem = require('../model/problem');
|
||||
const builtin = require('../model/builtin');
|
||||
const training = require('../model/training');
|
||||
const user = require('../model/user');
|
||||
const system = require('../model/system');
|
||||
const { Route, Handler } = require('../service/server');
|
||||
import assert from 'assert';
|
||||
import { ValidationError, ProblemNotFoundError } from '../error';
|
||||
import paginate from '../lib/paginate';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import * as problem from '../model/problem';
|
||||
import * as builtin from '../model/builtin';
|
||||
import * as training from '../model/training';
|
||||
import * as user from '../model/user';
|
||||
import * as system from '../model/system';
|
||||
import { Route, Handler } from '../service/server';
|
||||
import { ObjectID } from 'mongodb';
|
||||
|
||||
async function _parseDagJson(domainId, dag) {
|
||||
const parsed = [];
|
||||
@@ -65,12 +58,12 @@ class TrainingMainHandler extends Handler {
|
||||
page,
|
||||
await system.get('TRAINING_PER_PAGE'),
|
||||
);
|
||||
const tids = new Set();
|
||||
const tids: Set<ObjectID> = new Set();
|
||||
for (const tdoc of tdocs) tids.add(tdoc.docId);
|
||||
const tsdict = {};
|
||||
let tdict = {};
|
||||
if (this.user.hasPriv(PRIV_USER_PROFILE)) {
|
||||
const enrolledTids = new Set();
|
||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||
const enrolledTids: Set<ObjectID> = new Set();
|
||||
const tsdocs = await training.getMultiStatus(domainId, {
|
||||
uid: this.user._id,
|
||||
$or: [{ docId: { $in: Array.from(tids) } }, { enroll: 1 }],
|
||||
@@ -84,7 +77,7 @@ class TrainingMainHandler extends Handler {
|
||||
tdict = await training.getList(domainId, Array.from(enrolledTids));
|
||||
}
|
||||
}
|
||||
for (const tdoc in tdocs) tdict[tdoc.docId] = tdoc;
|
||||
for (const tdoc of tdocs) tdict[tdoc.docId] = tdoc;
|
||||
const path = [
|
||||
['Hydro', 'homepage'],
|
||||
['training_main', null],
|
||||
@@ -102,7 +95,7 @@ class TrainingDetailHandler extends Handler {
|
||||
const pids = training.getPids(tdoc);
|
||||
const [owner, pdict] = await Promise.all([
|
||||
user.getById(domainId, tdoc.owner),
|
||||
problem.getList(domainId, pids, this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN)),
|
||||
problem.getList(domainId, pids, this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN)),
|
||||
]);
|
||||
const psdict = await problem.getListStatus(domainId, this.user._id, pids);
|
||||
const donePids = new Set();
|
||||
@@ -123,7 +116,7 @@ class TrainingDetailHandler extends Handler {
|
||||
const totalCount = node.pids.length;
|
||||
const doneCount = Set.union(new Set(node.pids), donePids).size;
|
||||
const nsdoc = {
|
||||
progress: totalCount ? parseInt(100 * (doneCount / totalCount), 10) : 100,
|
||||
progress: totalCount ? Math.floor(100 * (doneCount / totalCount)) : 100,
|
||||
isDone: training.isDone(node, doneNids, donePids),
|
||||
isProgress: training.isProgress(node, doneNids, donePids, progPids),
|
||||
isOpen: training.isOpen(node, doneNids, donePids, progPids),
|
||||
@@ -149,7 +142,7 @@ class TrainingDetailHandler extends Handler {
|
||||
}
|
||||
|
||||
async postEnroll({ domainId, tid }) {
|
||||
this.checkPriv(PRIV_USER_PROFILE);
|
||||
this.checkPriv(PRIV.PRIV_USER_PROFILE);
|
||||
const tdoc = await training.get(domainId, tid);
|
||||
await training.enroll(domainId, tdoc.docId, this.user._id);
|
||||
this.back();
|
||||
@@ -186,8 +179,8 @@ class TrainingCreateHandler extends Handler {
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const pdoc in pdocs) {
|
||||
if (pdoc.hidden) this.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||
for (const pdoc of pdocs) {
|
||||
if (pdoc.hidden) this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||
}
|
||||
const tid = await training.add(domainId, title, content, this.user._id, dag, description);
|
||||
this.response.body = { tid };
|
||||
@@ -198,8 +191,8 @@ class TrainingCreateHandler extends Handler {
|
||||
class TrainingEditHandler extends Handler {
|
||||
async prepare({ domainId, tid }) {
|
||||
this.tdoc = await training.get(domainId, tid);
|
||||
if (this.tdoc.owner !== this.user._id) this.checkPerm(PERM_EDIT_TRAINING);
|
||||
else this.checkPerm(PERM_EDIT_TRAINING_SELF);
|
||||
if (this.tdoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_TRAINING);
|
||||
else this.checkPerm(PERM.PERM_EDIT_TRAINING_SELF);
|
||||
}
|
||||
|
||||
async get({ tid }) {
|
||||
@@ -238,8 +231,8 @@ class TrainingEditHandler extends Handler {
|
||||
);
|
||||
}
|
||||
}
|
||||
for (const pdoc in pdocs) {
|
||||
if (pdoc.hidden) this.checkPerm(PERM_VIEW_PROBLEM_HIDDEN);
|
||||
for (const pdoc of pdocs) {
|
||||
if (pdoc.hidden) this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||
}
|
||||
await training.edit(domainId, tid, {
|
||||
title, content, dag, description,
|
||||
@@ -249,11 +242,11 @@ class TrainingEditHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('training_main', '/training', TrainingMainHandler, PERM_VIEW_TRAINING);
|
||||
Route('training_create', '/training/create', TrainingCreateHandler, PERM_CREATE_TRAINING);
|
||||
Route('training_detail', '/training/:tid', TrainingDetailHandler, PERM_VIEW_TRAINING);
|
||||
export async function apply() {
|
||||
Route('training_main', '/training', TrainingMainHandler, PERM.PERM_VIEW_TRAINING);
|
||||
Route('training_create', '/training/create', TrainingCreateHandler, PERM.PERM_CREATE_TRAINING);
|
||||
Route('training_detail', '/training/:tid', TrainingDetailHandler, PERM.PERM_VIEW_TRAINING);
|
||||
Route('training_edit', '/training/:tid/edit', TrainingEditHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.training = module.exports = apply;
|
||||
global.Hydro.handler.training = apply;
|
||||
@@ -1,27 +1,20 @@
|
||||
const superagent = require('superagent');
|
||||
const moment = require('moment-timezone');
|
||||
const { Route, Handler } = require('../service/server.js');
|
||||
const user = require('../model/user');
|
||||
const token = require('../model/token');
|
||||
const record = require('../model/record');
|
||||
const problem = require('../model/problem');
|
||||
const task = require('../model/task');
|
||||
const system = require('../model/system');
|
||||
const { sendMail } = require('../lib/mail');
|
||||
const misc = require('../lib/misc');
|
||||
const {
|
||||
import superagent from 'superagent';
|
||||
import moment from 'moment-timezone';
|
||||
import { Route, Handler } from '../service/server';
|
||||
import * as user from '../model/user';
|
||||
import * as token from '../model/token';
|
||||
import * as record from '../model/record';
|
||||
import * as problem from '../model/problem';
|
||||
import * as task from '../model/task';
|
||||
import * as system from '../model/system';
|
||||
import { PERM, PRIV } from '../model/builtin';
|
||||
import { sendMail } from '../lib/mail';
|
||||
import * as misc from '../lib/misc';
|
||||
import {
|
||||
UserAlreadyExistError, InvalidTokenError, VerifyPasswordError,
|
||||
UserNotFoundError, LoginError, SystemError,
|
||||
BlacklistedError, UserFacingError,
|
||||
} = require('../error');
|
||||
const {
|
||||
PERM: {
|
||||
PERM_VIEW_PROBLEM_HIDDEN,
|
||||
},
|
||||
PRIV: {
|
||||
PRIV_USER_PROFILE, PRIV_REGISTER_USER, PRIV_NONE,
|
||||
},
|
||||
} = require('../model/builtin');
|
||||
} from '../error';
|
||||
|
||||
class UserLoginHandler extends Handler {
|
||||
async get() {
|
||||
@@ -41,7 +34,7 @@ class UserLoginHandler extends Handler {
|
||||
if (!udoc) throw new LoginError(uname);
|
||||
udoc.checkPassword(password);
|
||||
await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip });
|
||||
if (udoc.priv === PRIV_NONE) throw new BlacklistedError(uname);
|
||||
if (udoc.priv === PRIV.PRIV_NONE) throw new BlacklistedError(uname);
|
||||
this.session.uid = udoc._id;
|
||||
this.session.save = rememberme;
|
||||
this.response.redirect = this.request.referer.endsWith('/login') ? '/' : this.request.referer;
|
||||
@@ -116,7 +109,7 @@ class UserLostPassHandler extends Handler {
|
||||
|
||||
async post({ mail }) {
|
||||
if (!await system.get('smtp.user')) throw new SystemError('Cannot send mail');
|
||||
const udoc = await user.getByEmail(mail);
|
||||
const udoc = await user.getByEmail('system', mail);
|
||||
if (!udoc) throw new UserNotFoundError(mail);
|
||||
const [tid] = await token.add(
|
||||
token.TYPE_LOSTPASS,
|
||||
@@ -155,10 +148,14 @@ class UserDetailHandler extends Handler {
|
||||
const rdocs = await record.getByUid(domainId, uid);
|
||||
const pdict = await problem.getList(
|
||||
domainId, rdocs.map((rdoc) => rdoc.pid),
|
||||
this.user.hasPerm(PERM_VIEW_PROBLEM_HIDDEN), false,
|
||||
this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN), false,
|
||||
);
|
||||
// Remove sensitive data
|
||||
if (!isSelfProfile && sdoc) sdoc.createIp = sdoc.updateIp = sdoc._id = '';
|
||||
if (!isSelfProfile && sdoc) {
|
||||
sdoc.createIp = '';
|
||||
sdoc.updateIp = '';
|
||||
sdoc._id = '';
|
||||
}
|
||||
this.response.template = 'user_detail.html';
|
||||
this.response.body = {
|
||||
isSelfProfile, udoc, sdoc, rdocs, pdict,
|
||||
@@ -300,7 +297,7 @@ class OauthCallbackHandler extends Handler {
|
||||
if (udoc) {
|
||||
this.session.uid = udoc._id;
|
||||
} else {
|
||||
this.checkPriv(PRIV_REGISTER_USER);
|
||||
this.checkPriv(PRIV.PRIV_REGISTER_USER);
|
||||
let username = '';
|
||||
r.uname = r.uname || [];
|
||||
r.uname.push(String.random(16));
|
||||
@@ -315,7 +312,7 @@ class OauthCallbackHandler extends Handler {
|
||||
const uid = await user.create({
|
||||
mail: r.email, uname: username, password: String.random(32), regip: this.request.ip,
|
||||
});
|
||||
const $set = {
|
||||
const $set: any = {
|
||||
oauth: args.type,
|
||||
};
|
||||
if (r.bio) $set.bio = r.bio;
|
||||
@@ -326,18 +323,18 @@ class OauthCallbackHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('user_login', '/login', UserLoginHandler);
|
||||
Route('user_oauth', '/oauth/:type', OauthHandler);
|
||||
Route('user_oauth_callback', '/oauth/:type/callback', OauthCallbackHandler);
|
||||
Route('user_register', '/register', UserRegisterHandler, PRIV_REGISTER_USER);
|
||||
Route('user_register_with_code', '/register/:code', UserRegisterWithCodeHandler, PRIV_REGISTER_USER);
|
||||
Route('user_logout', '/logout', UserLogoutHandler, PRIV_USER_PROFILE);
|
||||
Route('user_register', '/register', UserRegisterHandler, PRIV.PRIV_REGISTER_USER);
|
||||
Route('user_register_with_code', '/register/:code', UserRegisterWithCodeHandler, PRIV.PRIV_REGISTER_USER);
|
||||
Route('user_logout', '/logout', UserLogoutHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('user_lostpass', '/lostpass', UserLostPassHandler);
|
||||
Route('user_lostpass_with_code', '/lostpass/:code', UserLostPassWithCodeHandler);
|
||||
Route('user_search', '/user/search', UserSearchHandler);
|
||||
Route('user_delete', '/user/delete', UserDeleteHandler, PRIV_USER_PROFILE);
|
||||
Route('user_delete', '/user/delete', UserDeleteHandler, PRIV.PRIV_USER_PROFILE);
|
||||
Route('user_detail', '/user/:uid', UserDetailHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.user = module.exports = apply;
|
||||
global.Hydro.handler.user = apply;
|
||||
@@ -1,5 +1,5 @@
|
||||
const { Route, Handler } = require('../service/server');
|
||||
const { NotFoundError } = require('../error');
|
||||
import { NotFoundError } from '../error';
|
||||
import { Route, Handler } from '../service/server';
|
||||
|
||||
class WikiHandler extends Handler {
|
||||
async get({ category = 'wiki', page }) {
|
||||
@@ -18,9 +18,9 @@ class WikiHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
export async function apply() {
|
||||
Route('wiki', '/wiki/:page', WikiHandler);
|
||||
Route('wiki_with_category', '/wiki/:category/:page', WikiHandler);
|
||||
}
|
||||
|
||||
global.Hydro.handler.wiki = module.exports = apply;
|
||||
global.Hydro.handler.wiki = apply;
|
||||
Reference in new issue
Block a user