mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
讨论置顶功能,修复setup
This commit is contained in:
1 parent
32a6d2de13
commit
d184ca9ea1
20 files changed
+136
-173
No files matched your search
@@ -32,9 +32,9 @@ export async function load(call: Entry) {
|
|||||||
require('../lib/i18n');
|
require('../lib/i18n');
|
||||||
require('../utils');
|
require('../utils');
|
||||||
require('../error');
|
require('../error');
|
||||||
try {
|
const config = require('../options').default();
|
||||||
require('../options').default();
|
if (!config) {
|
||||||
} catch (e) {
|
console.log('Starting setup');
|
||||||
await call({ entry: 'setup', newProcess: true }).catch((err) => {
|
await call({ entry: 'setup', newProcess: true }).catch((err) => {
|
||||||
console.error('Cannot start setup process.', err);
|
console.error('Cannot start setup process.', err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
|
|||||||
@@ -8,14 +8,13 @@ import {
|
|||||||
} from '../error';
|
} from '../error';
|
||||||
import { isContent, isTitle } from '../lib/validator';
|
import { isContent, isTitle } from '../lib/validator';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV, CONSTANT } from '../model/builtin';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as document from '../model/document';
|
import * as document from '../model/document';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as record from '../model/record';
|
import * as record from '../model/record';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as message from '../model/message';
|
import * as message from '../model/message';
|
||||||
import * as system from '../model/system';
|
|
||||||
import {
|
import {
|
||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
@@ -40,7 +39,7 @@ class ContestListHandler extends ContestHandler {
|
|||||||
qs = `rule=${rule}`;
|
qs = `rule=${rule}`;
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
[tdocs, tpcount] = await paginate(tdocs, page, await system.get('CONTEST_PER_PAGE'));
|
[tdocs, tpcount] = await paginate(tdocs, page, CONSTANT.CONTEST_PER_PAGE);
|
||||||
const tids = [];
|
const tids = [];
|
||||||
for (const tdoc of tdocs) tids.push(tdoc.docId);
|
for (const tdoc of tdocs) tids.push(tdoc.docId);
|
||||||
const tsdict = await contest.getListStatus(domainId, this.user._id, tids);
|
const tsdict = await contest.getListStatus(domainId, this.user._id, tids);
|
||||||
|
|||||||
+39
-32
@@ -1,14 +1,15 @@
|
|||||||
import { ObjectID } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { isSafeInteger } from 'lodash';
|
import { isSafeInteger } from 'lodash';
|
||||||
import { DiscussionNotFoundError, DocumentNotFoundError } from '../error';
|
import { DiscussionNotFoundError, DocumentNotFoundError } from '../error';
|
||||||
import { Drdoc, Mdoc } from '../interface';
|
import {
|
||||||
|
Mdoc, Drdoc, Ddoc, Drrdoc,
|
||||||
|
} from '../interface';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
import * as system from '../model/system';
|
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as message from '../model/message';
|
import * as message from '../model/message';
|
||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
import * as document from '../model/document';
|
import * as document from '../model/document';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV, CONSTANT } from '../model/builtin';
|
||||||
import {
|
import {
|
||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
@@ -23,46 +24,45 @@ export const typeMapper = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class DiscussionHandler extends Handler {
|
class DiscussionHandler extends Handler {
|
||||||
ddoc?: any;
|
ddoc?: Ddoc;
|
||||||
|
|
||||||
drdoc?: any;
|
drdoc?: Drdoc;
|
||||||
|
|
||||||
drrdoc?: any;
|
drrdoc?: Drrdoc;
|
||||||
|
|
||||||
vnode?: any;
|
vnode?: any;
|
||||||
|
|
||||||
async _prepare({
|
@param('type', Types.String, true)
|
||||||
domainId, type, name, did, drid, drrid,
|
@param('name', Types.String, true)
|
||||||
}) {
|
@param('did', Types.ObjectID, true)
|
||||||
|
@param('drid', Types.ObjectID, true)
|
||||||
|
@param('drrid', Types.ObjectID, true)
|
||||||
|
async _prepare(
|
||||||
|
domainId: string, type: string, name: string,
|
||||||
|
did: ObjectID, drid: ObjectID, drrid: ObjectID,
|
||||||
|
) {
|
||||||
this.checkPerm(PERM.PERM_VIEW_DISCUSSION);
|
this.checkPerm(PERM.PERM_VIEW_DISCUSSION);
|
||||||
if (did) {
|
if (did) {
|
||||||
did = new ObjectID(did);
|
|
||||||
this.ddoc = await discussion.get(domainId, did);
|
this.ddoc = await discussion.get(domainId, did);
|
||||||
if (!this.ddoc) throw new DiscussionNotFoundError(did);
|
if (!this.ddoc) throw new DiscussionNotFoundError(did);
|
||||||
type = discussion.typeDisplay[this.ddoc.parentType];
|
type = discussion.typeDisplay[this.ddoc.parentType];
|
||||||
name = this.ddoc.parentId;
|
name = this.ddoc.parentId.toString();
|
||||||
if (drid) {
|
if (drrid) {
|
||||||
drid = new ObjectID(drid);
|
[this.drdoc, this.drrdoc] = await discussion.getTailReply(domainId, drid, drrid);
|
||||||
|
if (!this.drrdoc) throw new DiscussionNotFoundError(drrid);
|
||||||
|
} else if (drid) {
|
||||||
this.drdoc = await discussion.getReply(domainId, drid);
|
this.drdoc = await discussion.getReply(domainId, drid);
|
||||||
if (!this.drdoc) throw new DiscussionNotFoundError(drid);
|
if (!this.drdoc) throw new DiscussionNotFoundError(drid);
|
||||||
if (!this.drdoc.parentId.equals(this.ddoc._id)) {
|
if (!this.drdoc.parentId.equals(this.ddoc._id)) {
|
||||||
throw new DocumentNotFoundError(drid);
|
throw new DocumentNotFoundError(drid);
|
||||||
}
|
}
|
||||||
if (drrid) {
|
|
||||||
drrid = new ObjectID(drrid);
|
|
||||||
[, this.drrdoc] = await discussion.getTailReply(domainId, drid, drrid);
|
|
||||||
if (!this.drrdoc) throw new DiscussionNotFoundError(drrid);
|
|
||||||
if (!this.drrdoc.parentId.equals(this.drdoc._id)) {
|
|
||||||
throw new DocumentNotFoundError(drid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(twd2): do more visibility check eg. contest
|
// TODO(twd2): do more visibility check eg. contest
|
||||||
// TODO(twd2): exclude problem/contest discussions?
|
// TODO(twd2): exclude problem/contest discussions?
|
||||||
// TODO(iceboy): continuation based pagination.
|
// TODO(iceboy): continuation based pagination.
|
||||||
if (ObjectID.isValid(name.toString())) name = new ObjectID(name);
|
this.vnode = await discussion.getVnode(domainId, typeMapper[type], name);
|
||||||
this.vnode = await discussion.getVnode(domainId, typeMapper[type], name, this);
|
if (this.vnode.hidden) this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||||
if (this.ddoc) {
|
if (this.ddoc) {
|
||||||
this.ddoc.parentType = this.ddoc.parentType || this.vnode.type;
|
this.ddoc.parentType = this.ddoc.parentType || this.vnode.type;
|
||||||
this.ddoc.parentId = this.ddoc.parentId || this.vnode.id;
|
this.ddoc.parentId = this.ddoc.parentId || this.vnode.id;
|
||||||
@@ -76,7 +76,7 @@ class DiscussionMainHandler extends Handler {
|
|||||||
const [ddocs, dpcount] = await paginate(
|
const [ddocs, dpcount] = await paginate(
|
||||||
discussion.getMulti(domainId),
|
discussion.getMulti(domainId),
|
||||||
page,
|
page,
|
||||||
await system.get('DISCUSSION_PER_PAGE'),
|
CONSTANT.DISCUSSION_PER_PAGE,
|
||||||
);
|
);
|
||||||
const udict = await user.getList(domainId, ddocs.map((ddoc) => ddoc.owner));
|
const udict = await user.getList(domainId, ddocs.map((ddoc) => ddoc.owner));
|
||||||
const path = [
|
const path = [
|
||||||
@@ -84,7 +84,9 @@ class DiscussionMainHandler extends Handler {
|
|||||||
['discussion_main', null],
|
['discussion_main', null],
|
||||||
];
|
];
|
||||||
const [vndict, vnodes] = await Promise.all([
|
const [vndict, vnodes] = await Promise.all([
|
||||||
discussion.getListVnodes(domainId, ddocs, this),
|
discussion.getListVnodes(
|
||||||
|
domainId, ddocs, this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN),
|
||||||
|
),
|
||||||
discussion.getNodes(domainId),
|
discussion.getNodes(domainId),
|
||||||
]);
|
]);
|
||||||
this.response.template = 'discussion_main_or_node.html';
|
this.response.template = 'discussion_main_or_node.html';
|
||||||
@@ -106,7 +108,7 @@ class DiscussionNodeHandler extends DiscussionHandler {
|
|||||||
const [ddocs, dpcount] = await paginate(
|
const [ddocs, dpcount] = await paginate(
|
||||||
discussion.getMulti(domainId, { parentType: typeMapper[type], parentId: name }),
|
discussion.getMulti(domainId, { parentType: typeMapper[type], parentId: name }),
|
||||||
page,
|
page,
|
||||||
await system.get('DISCUSSION_PER_PAGE'),
|
CONSTANT.DISCUSSION_PER_PAGE,
|
||||||
);
|
);
|
||||||
const uids = ddocs.map((ddoc) => ddoc.owner);
|
const uids = ddocs.map((ddoc) => ddoc.owner);
|
||||||
uids.push(this.vnode.owner);
|
uids.push(this.vnode.owner);
|
||||||
@@ -152,9 +154,10 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
|||||||
@param('title', Types.String, isTitle)
|
@param('title', Types.String, isTitle)
|
||||||
@param('content', Types.String, isContent)
|
@param('content', Types.String, isContent)
|
||||||
@param('highlight', Types.Boolean)
|
@param('highlight', Types.Boolean)
|
||||||
|
@param('pin', Types.Boolean)
|
||||||
async post(
|
async post(
|
||||||
domainId: string, type: string, _name: string,
|
domainId: string, type: string, _name: string,
|
||||||
title: string, content: string, highlight = false,
|
title: string, content: string, highlight = false, pin = false,
|
||||||
) {
|
) {
|
||||||
this.limitRate('add_discussion', 3600, 30);
|
this.limitRate('add_discussion', 3600, 30);
|
||||||
let name: ObjectID | string | number;
|
let name: ObjectID | string | number;
|
||||||
@@ -162,9 +165,10 @@ class DiscussionCreateHandler extends DiscussionHandler {
|
|||||||
else if (isSafeInteger(parseInt(_name, 10))) name = parseInt(_name, 10);
|
else if (isSafeInteger(parseInt(_name, 10))) name = parseInt(_name, 10);
|
||||||
else name = _name;
|
else name = _name;
|
||||||
if (highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
|
if (highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
|
||||||
|
if (pin) this.checkPerm(PERM.PERM_PIN_DISCUSSION);
|
||||||
const did = await discussion.add(
|
const did = await discussion.add(
|
||||||
domainId, typeMapper[type], name, this.user._id,
|
domainId, typeMapper[type], name, this.user._id,
|
||||||
title, content, this.request.ip, highlight,
|
title, content, this.request.ip, highlight, pin,
|
||||||
);
|
);
|
||||||
this.response.body = { did };
|
this.response.body = { did };
|
||||||
this.response.redirect = this.url('discussion_detail', { did });
|
this.response.redirect = this.url('discussion_detail', { did });
|
||||||
@@ -181,7 +185,7 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
|||||||
const [drdocs, pcount, drcount] = await paginate(
|
const [drdocs, pcount, drcount] = await paginate(
|
||||||
discussion.getMultiReply(domainId, did),
|
discussion.getMultiReply(domainId, did),
|
||||||
page,
|
page,
|
||||||
await system.get('REPLY_PER_PAGE'),
|
CONSTANT.REPLY_PER_PAGE,
|
||||||
);
|
);
|
||||||
const uids = drdocs.map((drdoc) => drdoc.owner);
|
const uids = drdocs.map((drdoc) => drdoc.owner);
|
||||||
uids.push(this.ddoc.owner);
|
uids.push(this.ddoc.owner);
|
||||||
@@ -327,13 +331,16 @@ class DiscussionEditHandler extends DiscussionHandler {
|
|||||||
@param('title', Types.String, isTitle)
|
@param('title', Types.String, isTitle)
|
||||||
@param('content', Types.String, isContent)
|
@param('content', Types.String, isContent)
|
||||||
@param('highlight', Types.Boolean)
|
@param('highlight', Types.Boolean)
|
||||||
|
@param('pin', Types.Boolean)
|
||||||
async postUpdate(
|
async postUpdate(
|
||||||
domainId: string, did: ObjectID, title: string, content: string, highlight = false,
|
domainId: string, did: ObjectID, title: string, content: string,
|
||||||
|
highlight = false, pin = false,
|
||||||
) {
|
) {
|
||||||
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_DISCUSSION);
|
if (this.ddoc.owner !== this.user._id) this.checkPerm(PERM.PERM_EDIT_DISCUSSION);
|
||||||
else this.checkPerm(PERM.PERM_EDIT_DISCUSSION_SELF);
|
else this.checkPerm(PERM.PERM_EDIT_DISCUSSION_SELF);
|
||||||
if (highlight && !this.ddoc.highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
|
if (highlight !== this.ddoc.highlight) this.checkPerm(PERM.PERM_HIGHLIGHT_DISCUSSION);
|
||||||
await discussion.edit(domainId, did, title, content, highlight);
|
if (pin !== this.ddoc.pin) this.checkPerm(PERM.PERM_PIN_DISCUSSION);
|
||||||
|
await discussion.edit(domainId, did, title, content, highlight, pin);
|
||||||
this.response.body = { did };
|
this.response.body = { did };
|
||||||
this.response.redirect = this.url('discussion_detail', { did });
|
this.response.redirect = this.url('discussion_detail', { did });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import * as domain from '../model/domain';
|
|||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
import * as token from '../model/token';
|
import * as token from '../model/token';
|
||||||
import * as training from '../model/training';
|
import * as training from '../model/training';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV, CONSTANT } from '../model/builtin';
|
||||||
import {
|
import {
|
||||||
isContent, isPassword, isEmail, isTitle,
|
isContent, isPassword, isEmail, isTitle,
|
||||||
} from '../lib/validator';
|
} from '../lib/validator';
|
||||||
@@ -33,7 +33,7 @@ class HomeHandler extends Handler {
|
|||||||
if (this.user.hasPerm(PERM.PERM_VIEW_HOMEWORK)) {
|
if (this.user.hasPerm(PERM.PERM_VIEW_HOMEWORK)) {
|
||||||
const tdocs = await contest.getMulti(domainId, {}, document.TYPE_HOMEWORK)
|
const tdocs = await contest.getMulti(domainId, {}, document.TYPE_HOMEWORK)
|
||||||
.sort('beginAt', -1)
|
.sort('beginAt', -1)
|
||||||
.limit(await system.get('HOMEWORK_ON_MAIN'))
|
.limit(CONSTANT.HOMEWORK_ON_MAIN)
|
||||||
.toArray();
|
.toArray();
|
||||||
const tsdict = await contest.getListStatus(
|
const tsdict = await contest.getListStatus(
|
||||||
domainId, this.user._id,
|
domainId, this.user._id,
|
||||||
@@ -48,7 +48,7 @@ class HomeHandler extends Handler {
|
|||||||
if (this.user.hasPerm(PERM.PERM_VIEW_CONTEST)) {
|
if (this.user.hasPerm(PERM.PERM_VIEW_CONTEST)) {
|
||||||
const tdocs = await contest.getMulti(domainId)
|
const tdocs = await contest.getMulti(domainId)
|
||||||
.sort('beginAt', -1)
|
.sort('beginAt', -1)
|
||||||
.limit(await system.get('CONTEST_ON_MAIN'))
|
.limit(CONSTANT.CONTEST_ON_MAIN)
|
||||||
.toArray();
|
.toArray();
|
||||||
const tsdict = await contest.getListStatus(
|
const tsdict = await contest.getListStatus(
|
||||||
domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId),
|
domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId),
|
||||||
@@ -62,7 +62,7 @@ class HomeHandler extends Handler {
|
|||||||
if (this.user.hasPerm(PERM.PERM_VIEW_TRAINING)) {
|
if (this.user.hasPerm(PERM.PERM_VIEW_TRAINING)) {
|
||||||
const tdocs = await training.getMulti(domainId)
|
const tdocs = await training.getMulti(domainId)
|
||||||
.sort('_id', 1)
|
.sort('_id', 1)
|
||||||
.limit(await system.get('TRAINING_ON_MAIN'))
|
.limit(CONSTANT.TRAINING_ON_MAIN)
|
||||||
.toArray();
|
.toArray();
|
||||||
const tsdict = await training.getListStatus(
|
const tsdict = await training.getListStatus(
|
||||||
domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId),
|
domainId, this.user._id, tdocs.map((tdoc) => tdoc.docId),
|
||||||
@@ -75,9 +75,11 @@ class HomeHandler extends Handler {
|
|||||||
async discussion(domainId: string): Promise<[any[], any]> {
|
async discussion(domainId: string): Promise<[any[], any]> {
|
||||||
if (this.user.hasPerm(PERM.PERM_VIEW_DISCUSSION)) {
|
if (this.user.hasPerm(PERM.PERM_VIEW_DISCUSSION)) {
|
||||||
const ddocs = await discussion.getMulti(domainId)
|
const ddocs = await discussion.getMulti(domainId)
|
||||||
.limit(await system.get('DISCUSSION_ON_MAIN'))
|
.limit(CONSTANT.DISCUSSION_ON_MAIN)
|
||||||
.toArray();
|
.toArray();
|
||||||
const vndict = await discussion.getListVnodes(domainId, ddocs, this);
|
const vndict = await discussion.getListVnodes(
|
||||||
|
domainId, ddocs, this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN),
|
||||||
|
);
|
||||||
return [ddocs, vndict];
|
return [ddocs, vndict];
|
||||||
}
|
}
|
||||||
return [[], {}];
|
return [[], {}];
|
||||||
|
|||||||
@@ -12,8 +12,7 @@ import {
|
|||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import { PERM } from '../model/builtin';
|
import { PERM, CONSTANT } from '../model/builtin';
|
||||||
import * as system from '../model/system';
|
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as discussion from '../model/discussion';
|
import * as discussion from '../model/discussion';
|
||||||
@@ -84,7 +83,7 @@ class HomeworkDetailHandler extends HomeworkHandler {
|
|||||||
const [ddocs, dpcount, dcount] = await paginate(
|
const [ddocs, dpcount, dcount] = await paginate(
|
||||||
discussion.getMulti(domainId, { parentType: tdoc.docType, parentId: tdoc.docId }),
|
discussion.getMulti(domainId, { parentType: tdoc.docType, parentId: tdoc.docId }),
|
||||||
page,
|
page,
|
||||||
await system.get('DISCUSSION_PER_PAGE'),
|
CONSTANT.DISCUSSION_PER_PAGE,
|
||||||
);
|
);
|
||||||
const uids = ddocs.map((ddoc) => ddoc.owner);
|
const uids = ddocs.map((ddoc) => ddoc.owner);
|
||||||
uids.push(tdoc.owner);
|
uids.push(tdoc.owner);
|
||||||
|
|||||||
@@ -102,34 +102,6 @@ class SwitchLanguageHandler extends Handler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class UiSettingsHandler extends Handler {
|
|
||||||
async get() {
|
|
||||||
const [
|
|
||||||
header_logo, header_logo_2x,
|
|
||||||
nav_logo_dark, nav_logo_light,
|
|
||||||
nav_logo_dark_2x, nav_logo_light_2x,
|
|
||||||
header_background, header_background_2x,
|
|
||||||
] = await system.getMany([
|
|
||||||
'ui.header_logo', 'ui.header_logo_2x',
|
|
||||||
'ui.nav_logo_dark', 'ui.nav_logo_light',
|
|
||||||
'ui.nav_logo_dark_2x', 'ui.nav_logo_light_2x',
|
|
||||||
'ui.header_background', 'ui.header_background2x',
|
|
||||||
]);
|
|
||||||
this.response.body = await this.renderHTML('extra.css', {
|
|
||||||
header_logo,
|
|
||||||
header_logo_2x,
|
|
||||||
nav_logo_dark,
|
|
||||||
nav_logo_light,
|
|
||||||
nav_logo_dark_2x,
|
|
||||||
nav_logo_light_2x,
|
|
||||||
header_background,
|
|
||||||
header_background_2x,
|
|
||||||
});
|
|
||||||
this.response.type = 'text/css';
|
|
||||||
this.ctx.set('nolog', '1');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function apply() {
|
export async function apply() {
|
||||||
Route('file_download', '/fs/:fileId/:secret', FileDownloadHandler);
|
Route('file_download', '/fs/:fileId/:secret', FileDownloadHandler);
|
||||||
Route('file_download_with_name', '/fs/:fileId/:name/:secret', FileDownloadHandler);
|
Route('file_download_with_name', '/fs/:fileId/:name/:secret', FileDownloadHandler);
|
||||||
@@ -137,7 +109,6 @@ export async function apply() {
|
|||||||
Route('status', '/status', StatusHandler);
|
Route('status', '/status', StatusHandler);
|
||||||
Route('status_update', '/status/update', StatusUpdateHandler);
|
Route('status_update', '/status/update', StatusUpdateHandler);
|
||||||
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
||||||
Route('ui', '/extra.css', UiSettingsHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.handler.misc = apply;
|
global.Hydro.handler.misc = apply;
|
||||||
@@ -19,8 +19,7 @@ import * as record from '../model/record';
|
|||||||
import * as domain from '../model/domain';
|
import * as domain from '../model/domain';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as solution from '../model/solution';
|
import * as solution from '../model/solution';
|
||||||
import * as system from '../model/system';
|
import { PERM, PRIV, CONSTANT } from '../model/builtin';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
import {
|
import {
|
||||||
Route, Connection, Handler, ConnectionHandler, Types, param, multipart,
|
Route, Connection, Handler, ConnectionHandler, Types, param, multipart,
|
||||||
@@ -78,7 +77,7 @@ class ProblemMainHandler extends ProblemHandler {
|
|||||||
const [pdocs, ppcount, pcount] = await paginate(
|
const [pdocs, ppcount, pcount] = await paginate(
|
||||||
problem.getMulti(domainId, query).sort({ pid: 1 }),
|
problem.getMulti(domainId, query).sort({ pid: 1 }),
|
||||||
page,
|
page,
|
||||||
await system.get('PROBLEM_PER_PAGE'),
|
CONSTANT.PROBLEM_PER_PAGE,
|
||||||
);
|
);
|
||||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||||
psdict = await problem.getListStatus(
|
psdict = await problem.getListStatus(
|
||||||
@@ -122,7 +121,7 @@ class ProblemCategoryHandler extends ProblemHandler {
|
|||||||
const [pdocs, ppcount, pcount] = await paginate(
|
const [pdocs, ppcount, pcount] = await paginate(
|
||||||
problem.getMulti(domainId, q).sort({ pid: 1 }),
|
problem.getMulti(domainId, q).sort({ pid: 1 }),
|
||||||
page,
|
page,
|
||||||
await system.get('PROBLEM_PER_PAGE'),
|
CONSTANT.PROBLEM_PER_PAGE,
|
||||||
);
|
);
|
||||||
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
|
||||||
psdict = await problem.getListStatus(
|
psdict = await problem.getListStatus(
|
||||||
@@ -466,7 +465,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
|||||||
const [psdocs, pcount, pscount] = await paginate(
|
const [psdocs, pcount, pscount] = await paginate(
|
||||||
solution.getMulti(domainId, this.pdoc.docId),
|
solution.getMulti(domainId, this.pdoc.docId),
|
||||||
page,
|
page,
|
||||||
await system.get('SOLUTION_PER_PAGE'),
|
CONSTANT.SOLUTION_PER_PAGE,
|
||||||
);
|
);
|
||||||
const uids = [this.pdoc.owner];
|
const uids = [this.pdoc.owner];
|
||||||
const docids = [];
|
const docids = [];
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { ObjectID } from 'mongodb';
|
import { ObjectID } from 'mongodb';
|
||||||
import { PermissionError, RecordNotFoundError } from '../error';
|
import { PermissionError, RecordNotFoundError } from '../error';
|
||||||
import { PERM } from '../model/builtin';
|
import { PERM, CONSTANT } from '../model/builtin';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as record from '../model/record';
|
import * as record from '../model/record';
|
||||||
import * as contest from '../model/contest';
|
import * as contest from '../model/contest';
|
||||||
import * as system from '../model/system';
|
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
import * as bus from '../service/bus';
|
import * as bus from '../service/bus';
|
||||||
@@ -34,7 +33,7 @@ class RecordListHandler extends RecordHandler {
|
|||||||
const [rdocs] = await paginate(
|
const [rdocs] = await paginate(
|
||||||
record.getMulti(domainId, q).sort('_id', -1),
|
record.getMulti(domainId, q).sort('_id', -1),
|
||||||
page,
|
page,
|
||||||
await system.get('RECORD_PER_PAGE'),
|
CONSTANT.RECORD_PER_PAGE,
|
||||||
);
|
);
|
||||||
const canViewProblemHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
const canViewProblemHidden = this.user.hasPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
||||||
const [udict, pdict] = await Promise.all([
|
const [udict, pdict] = await Promise.all([
|
||||||
|
|||||||
@@ -3,12 +3,11 @@ import { ObjectID } from 'mongodb';
|
|||||||
import { ValidationError, ProblemNotFoundError } from '../error';
|
import { ValidationError, ProblemNotFoundError } from '../error';
|
||||||
import { isTitle, isContent, isDescription } from '../lib/validator';
|
import { isTitle, isContent, isDescription } from '../lib/validator';
|
||||||
import paginate from '../lib/paginate';
|
import paginate from '../lib/paginate';
|
||||||
import { PERM, PRIV } from '../model/builtin';
|
import { PERM, PRIV, CONSTANT } from '../model/builtin';
|
||||||
import * as problem from '../model/problem';
|
import * as problem from '../model/problem';
|
||||||
import * as builtin from '../model/builtin';
|
import * as builtin from '../model/builtin';
|
||||||
import * as training from '../model/training';
|
import * as training from '../model/training';
|
||||||
import * as user from '../model/user';
|
import * as user from '../model/user';
|
||||||
import * as system from '../model/system';
|
|
||||||
import {
|
import {
|
||||||
Route, Handler, Types, param,
|
Route, Handler, Types, param,
|
||||||
} from '../service/server';
|
} from '../service/server';
|
||||||
@@ -58,9 +57,9 @@ class TrainingMainHandler extends Handler {
|
|||||||
@param('page', Types.UnsignedInt, true)
|
@param('page', Types.UnsignedInt, true)
|
||||||
async get(domainId: string, page = 1) {
|
async get(domainId: string, page = 1) {
|
||||||
const [tdocs, tpcount] = await paginate(
|
const [tdocs, tpcount] = await paginate(
|
||||||
training.getMulti(domainId).sort('_id', 1),
|
training.getMulti(domainId),
|
||||||
page,
|
page,
|
||||||
await system.get('TRAINING_PER_PAGE'),
|
CONSTANT.TRAINING_PER_PAGE,
|
||||||
);
|
);
|
||||||
const tids: Set<ObjectID> = new Set();
|
const tids: Set<ObjectID> = new Set();
|
||||||
for (const tdoc of tdocs) tids.add(tdoc.docId);
|
for (const tdoc of tdocs) tids.add(tdoc.docId);
|
||||||
|
|||||||
@@ -231,6 +231,7 @@ export interface DomainDoc extends Dictionary<any> {
|
|||||||
roles: Dictionary<string>,
|
roles: Dictionary<string>,
|
||||||
gravatar: string,
|
gravatar: string,
|
||||||
bulletin: string,
|
bulletin: string,
|
||||||
|
pidCounter: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Message
|
// Message
|
||||||
@@ -262,10 +263,14 @@ export interface Ddoc {
|
|||||||
_id: ObjectID,
|
_id: ObjectID,
|
||||||
docType: number,
|
docType: number,
|
||||||
docId: ObjectID,
|
docId: ObjectID,
|
||||||
|
parentType: number,
|
||||||
|
parentId: ObjectID | number,
|
||||||
owner: number,
|
owner: number,
|
||||||
title: string,
|
title: string,
|
||||||
content: string,
|
content: string,
|
||||||
ip: string,
|
ip: string,
|
||||||
|
pin: boolean,
|
||||||
|
highlight: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discussion reply
|
// Discussion reply
|
||||||
@@ -277,6 +282,7 @@ export interface Drdoc {
|
|||||||
parentId: ObjectID,
|
parentId: ObjectID,
|
||||||
owner: number,
|
owner: number,
|
||||||
ip: string,
|
ip: string,
|
||||||
|
content: string,
|
||||||
reply: Drrdoc[],
|
reply: Drrdoc[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ export const PERM = {
|
|||||||
PERM_VIEW_DISCUSSION: 1n << 27n,
|
PERM_VIEW_DISCUSSION: 1n << 27n,
|
||||||
PERM_CREATE_DISCUSSION: 1n << 28n,
|
PERM_CREATE_DISCUSSION: 1n << 28n,
|
||||||
PERM_HIGHLIGHT_DISCUSSION: 1n << 29n,
|
PERM_HIGHLIGHT_DISCUSSION: 1n << 29n,
|
||||||
|
PERM_PIN_DISCUSSION: 1n << 59n,
|
||||||
PERM_EDIT_DISCUSSION: 1n << 30n,
|
PERM_EDIT_DISCUSSION: 1n << 30n,
|
||||||
PERM_EDIT_DISCUSSION_SELF: 1n << 31n,
|
PERM_EDIT_DISCUSSION_SELF: 1n << 31n,
|
||||||
PERM_DELETE_DISCUSSION: 1n << 32n,
|
PERM_DELETE_DISCUSSION: 1n << 32n,
|
||||||
@@ -603,6 +604,20 @@ export const USER_GENDER_ICONS = {
|
|||||||
[USER_GENDER_OTHER]: '?',
|
[USER_GENDER_OTHER]: '?',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const CONSTANT = {
|
||||||
|
PROBLEM_PER_PAGE: 100,
|
||||||
|
CONTEST_PER_PAGE: 20,
|
||||||
|
DISCUSSION_PER_PAGE: 50,
|
||||||
|
RECORD_PER_PAGE: 100,
|
||||||
|
SOLUTION_PER_PAGE: 20,
|
||||||
|
TRAINING_PER_PAGE: 10,
|
||||||
|
REPLY_PER_PAGE: 50,
|
||||||
|
HOMEWORK_ON_MAIN: 5,
|
||||||
|
DISCUSSION_ON_MAIN: 20,
|
||||||
|
CONTEST_ON_MAIN: 10,
|
||||||
|
TRAINING_ON_MAIN: 10,
|
||||||
|
};
|
||||||
|
|
||||||
global.Hydro.model.builtin = {
|
global.Hydro.model.builtin = {
|
||||||
Permission,
|
Permission,
|
||||||
PERM,
|
PERM,
|
||||||
|
|||||||
+14
-11
@@ -3,7 +3,6 @@ import * as problem from './problem';
|
|||||||
import * as contest from './contest';
|
import * as contest from './contest';
|
||||||
import * as training from './training';
|
import * as training from './training';
|
||||||
import * as document from './document';
|
import * as document from './document';
|
||||||
import { PERM } from './builtin';
|
|
||||||
import { DocumentNotFoundError } from '../error';
|
import { DocumentNotFoundError } from '../error';
|
||||||
import { Ddoc, Drdoc, Drrdoc } from '../interface';
|
import { Ddoc, Drdoc, Drrdoc } from '../interface';
|
||||||
|
|
||||||
@@ -18,7 +17,7 @@ export const typeDisplay = {
|
|||||||
export function add(
|
export function add(
|
||||||
domainId: string, parentType: number, parentId: ObjectID | number | string,
|
domainId: string, parentType: number, parentId: ObjectID | number | string,
|
||||||
owner: number, title: string, content: string,
|
owner: number, title: string, content: string,
|
||||||
ip: string | null = null, highlight: boolean = false,
|
ip: string | null = null, highlight: boolean, pin: boolean,
|
||||||
): Promise<ObjectID> {
|
): Promise<ObjectID> {
|
||||||
return document.add(
|
return document.add(
|
||||||
domainId, content, owner, document.TYPE_DISCUSSION,
|
domainId, content, owner, document.TYPE_DISCUSSION,
|
||||||
@@ -26,8 +25,9 @@ export function add(
|
|||||||
{
|
{
|
||||||
title,
|
title,
|
||||||
ip,
|
ip,
|
||||||
highlight,
|
|
||||||
nReply: 0,
|
nReply: 0,
|
||||||
|
highlight,
|
||||||
|
pin,
|
||||||
updateAt: new Date(),
|
updateAt: new Date(),
|
||||||
views: 0,
|
views: 0,
|
||||||
},
|
},
|
||||||
@@ -40,9 +40,11 @@ export function get(domainId: string, did: ObjectID): Promise<Ddoc | null> {
|
|||||||
|
|
||||||
export function edit(
|
export function edit(
|
||||||
domainId: string, did: ObjectID,
|
domainId: string, did: ObjectID,
|
||||||
title: string, content: string, highlight: boolean,
|
title: string, content: string, highlight: boolean, pin: boolean,
|
||||||
): Promise<Ddoc | null> {
|
): Promise<Ddoc | null> {
|
||||||
return document.set(domainId, document.TYPE_DISCUSSION, did, { title, content, highlight });
|
return document.set(domainId, document.TYPE_DISCUSSION, did, {
|
||||||
|
title, content, highlight, pin,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function del(domainId: string, did: ObjectID) {
|
export function del(domainId: string, did: ObjectID) {
|
||||||
@@ -60,7 +62,8 @@ export function count(domainId: string, query: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getMulti(domainId: string, query: any = {}) {
|
export function getMulti(domainId: string, query: any = {}) {
|
||||||
return document.getMulti(domainId, document.TYPE_DISCUSSION, query).sort('updateAt', -1);
|
return document.getMulti(domainId, document.TYPE_DISCUSSION, query)
|
||||||
|
.sort({ pin: -1, updateAt: -1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function addReply(
|
export async function addReply(
|
||||||
@@ -158,13 +161,12 @@ export function getNode(domainId: string, _id: string) {
|
|||||||
return document.get(domainId, document.TYPE_DISCUSSION_NODE, _id);
|
return document.get(domainId, document.TYPE_DISCUSSION_NODE, _id);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getVnode(domainId: string, type: number, id: string, handler: any) {
|
export async function getVnode(domainId: string, type: number, id: string) {
|
||||||
if (type === document.TYPE_PROBLEM) {
|
if (type === document.TYPE_PROBLEM) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (Number.isSafeInteger(parseInt(id, 10))) id = parseInt(id, 10);
|
if (Number.isSafeInteger(parseInt(id, 10))) id = parseInt(id, 10);
|
||||||
const pdoc = await problem.get(domainId, id);
|
const pdoc = await problem.get(domainId, id);
|
||||||
if (!pdoc) return null;
|
if (!pdoc) return null;
|
||||||
if (pdoc.hidden && handler) handler.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);
|
|
||||||
return { ...pdoc, type, id };
|
return { ...pdoc, type, id };
|
||||||
}
|
}
|
||||||
if (type === document.TYPE_CONTEST) {
|
if (type === document.TYPE_CONTEST) {
|
||||||
@@ -199,12 +201,13 @@ export function getNodes(domainId: string) {
|
|||||||
return document.getMulti(domainId, document.TYPE_DISCUSSION_NODE).toArray();
|
return document.getMulti(domainId, document.TYPE_DISCUSSION_NODE).toArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getListVnodes(domainId: string, ddocs: any, handler: any) {
|
export async function getListVnodes(domainId: string, ddocs: any, getHidden: boolean) {
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
const res = {};
|
const res = {};
|
||||||
async function task(ddoc) {
|
async function task(ddoc: Ddoc) {
|
||||||
const vnode = await getVnode(domainId, ddoc.parentType, ddoc.parentId, handler);
|
const vnode = await getVnode(domainId, ddoc.parentType, ddoc.parentId.toString());
|
||||||
if (!res[ddoc.parentType]) res[ddoc.parentType] = {};
|
if (!res[ddoc.parentType]) res[ddoc.parentType] = {};
|
||||||
|
if (vnode.hidden && !getHidden) return;
|
||||||
res[ddoc.parentType][ddoc.parentId] = vnode;
|
res[ddoc.parentType][ddoc.parentId] = vnode;
|
||||||
}
|
}
|
||||||
for (const ddoc of ddocs) tasks.push(task(ddoc));
|
for (const ddoc of ddocs) tasks.push(task(ddoc));
|
||||||
|
|||||||
+23
-49
@@ -328,66 +328,40 @@ export async function revSetStatus(
|
|||||||
return await collStatus.updateOne(filter, update);
|
return await collStatus.updateOne(filter, update);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable object-curly-newline */
|
||||||
async function ensureIndexes() {
|
async function ensureIndexes() {
|
||||||
await coll.createIndex({ domainId: 1, docType: 1, docId: 1 }, { unique: true });
|
const ic = coll.createIndex.bind(coll);
|
||||||
await coll.createIndex({
|
const is = collStatus.createIndex.bind(coll);
|
||||||
domainId: 1, docType: 1, owner: 1, docId: -1,
|
const u = { unique: true };
|
||||||
});
|
const s = { sparse: true };
|
||||||
|
await ic({ domainId: 1, docType: 1, docId: 1 }, u);
|
||||||
|
await ic({ domainId: 1, docType: 1, owner: 1, docId: -1 });
|
||||||
// For problem
|
// For problem
|
||||||
await coll.createIndex({
|
await ic({ domainId: 1, docType: 1, category: 1, docId: 1 }, s);
|
||||||
domainId: 1, docType: 1, category: 1, docId: 1,
|
await ic({ domainId: 1, docType: 1, hidden: 1, category: 1, docId: 1 }, s);
|
||||||
}, { sparse: true });
|
await ic({ domainId: 1, docType: 1, tag: 1, docId: 1 }, s);
|
||||||
await coll.createIndex({
|
await ic({ domainId: 1, docType: 1, hidden: 1, tag: 1, docId: 1 }, s);
|
||||||
domainId: 1, docType: 1, hidden: 1, category: 1, docId: 1,
|
|
||||||
}, { sparse: true });
|
|
||||||
await coll.createIndex({
|
|
||||||
domainId: 1, docType: 1, tag: 1, docId: 1,
|
|
||||||
}, { sparse: true });
|
|
||||||
await coll.createIndex({
|
|
||||||
domainId: 1, docType: 1, hidden: 1, tag: 1, docId: 1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For problem solution
|
// For problem solution
|
||||||
await coll.createIndex({
|
await ic({ domainId: 1, docType: 1, parentType: 1, parentId: 1, vote: -1, docId: -1 }, s);
|
||||||
domainId: 1, docType: 1, parentType: 1, parentId: 1, vote: -1, docId: -1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For discussion
|
// For discussion
|
||||||
await coll.createIndex({
|
await ic({ domainId: 1, docType: 1, pin: -1, updateAt: -1, docId: -1 }, s);
|
||||||
domainId: 1, docType: 1, updateAt: -1, docId: -1,
|
await ic({ domainId: 1, docType: 1, parentType: 1, parentId: 1, updateAt: -1, docId: -1 }, s);
|
||||||
}, { sparse: true });
|
|
||||||
await coll.createIndex({
|
|
||||||
domainId: 1, docType: 1, parentType: 1, parentId: 1, updateAt: -1, docId: -1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// Hidden doc
|
// Hidden doc
|
||||||
await coll.createIndex({
|
await ic({ domainId: 1, docType: 1, hidden: 1, docId: -1 }, s);
|
||||||
domainId: 1, docType: 1, hidden: 1, docId: -1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For contest
|
// For contest
|
||||||
await coll.createIndex({ domainId: 1, docType: 1, pids: 1 }, { sparse: true });
|
await ic({ domainId: 1, docType: 1, pids: 1 }, s);
|
||||||
await coll.createIndex({
|
await ic({ domainId: 1, docType: 1, rule: 1, docId: -1 }, s);
|
||||||
domainId: 1, docType: 1, rule: 1, docId: -1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For training
|
// For training
|
||||||
await coll.createIndex({ domainId: 1, docType: 1, 'dag.pids': 1 }, { sparse: true });
|
await ic({ domainId: 1, docType: 1, 'dag.pids': 1 }, s);
|
||||||
|
await is({ domainId: 1, docType: 1, uid: 1, docId: 1 }, u);
|
||||||
await collStatus.createIndex({
|
|
||||||
domainId: 1, docType: 1, uid: 1, docId: 1,
|
|
||||||
}, { unique: true });
|
|
||||||
// For rp system
|
// For rp system
|
||||||
await collStatus.createIndex({
|
await is({ domainId: 1, docType: 1, docId: 1, status: 1, rid: 1, rp: 1 }, s);
|
||||||
domainId: 1, docType: 1, docId: 1, status: 1, rid: 1, rp: 1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For contest rule OI
|
// For contest rule OI
|
||||||
await collStatus.createIndex({
|
await is({ domainId: 1, docType: 1, docId: 1, score: -1 }, s);
|
||||||
domainId: 1, docType: 1, docId: 1, score: -1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For contest rule ACM
|
// For contest rule ACM
|
||||||
await collStatus.createIndex({
|
await is({ domainId: 1, docType: 1, docId: 1, accept: -1, time: 1 }, s);
|
||||||
domainId: 1, docType: 1, docId: 1, accept: -1, time: 1,
|
|
||||||
}, { sparse: true });
|
|
||||||
// For training
|
// For training
|
||||||
await collStatus.createIndex({
|
await is({ domainId: 1, docType: 1, uid: 1, enroll: 1, docId: 1 }, s);
|
||||||
domainId: 1, docType: 1, uid: 1, enroll: 1, docId: 1,
|
|
||||||
}, { sparse: true });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.postInit.push(ensureIndexes);
|
global.Hydro.postInit.push(ensureIndexes);
|
||||||
|
|||||||
+11
-10
@@ -7,9 +7,16 @@ const coll = db.collection('domain');
|
|||||||
const collUser = db.collection('domain.user');
|
const collUser = db.collection('domain.user');
|
||||||
|
|
||||||
export async function add(domainId: string, owner: number, name: string, bulletin: string) {
|
export async function add(domainId: string, owner: number, name: string, bulletin: string) {
|
||||||
await coll.insertOne({
|
const ddoc: DomainDoc = {
|
||||||
_id: domainId, owner, name, bulletin, roles: {},
|
_id: domainId,
|
||||||
});
|
owner,
|
||||||
|
name,
|
||||||
|
bulletin,
|
||||||
|
roles: {},
|
||||||
|
gravatar: '',
|
||||||
|
pidCounter: 0,
|
||||||
|
};
|
||||||
|
await coll.insertOne(ddoc);
|
||||||
return domainId;
|
return domainId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,11 +24,6 @@ export function get(domainId: string): Promise<DomainDoc | null> {
|
|||||||
return coll.findOne({ _id: domainId });
|
return coll.findOne({ _id: domainId });
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getMany(query: any, sort: any, page: number, limit: number): Promise<DomainDoc[]> {
|
|
||||||
return coll.find(query).sort(sort).skip((page - 1) * limit).limit(limit)
|
|
||||||
.toArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getMulti(query: any = {}) {
|
export function getMulti(query: any = {}) {
|
||||||
return coll.find(query);
|
return coll.find(query);
|
||||||
}
|
}
|
||||||
@@ -36,7 +38,7 @@ export async function inc(domainId: string, field: string, n: number): Promise<n
|
|||||||
{ $inc: { [field]: n } },
|
{ $inc: { [field]: n } },
|
||||||
{ returnOriginal: false },
|
{ returnOriginal: false },
|
||||||
);
|
);
|
||||||
return res.value.field;
|
return res.value[field];
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getList(domainIds: string[]): Promise<Dictionary<DomainDoc>> {
|
export async function getList(domainIds: string[]): Promise<Dictionary<DomainDoc>> {
|
||||||
@@ -155,7 +157,6 @@ global.Hydro.model.domain = {
|
|||||||
add,
|
add,
|
||||||
inc,
|
inc,
|
||||||
get,
|
get,
|
||||||
getMany,
|
|
||||||
edit,
|
edit,
|
||||||
getMulti,
|
getMulti,
|
||||||
getList,
|
getList,
|
||||||
|
|||||||
@@ -134,17 +134,6 @@ SystemSetting(
|
|||||||
Setting('setting_oauth', 'oauth.googleappid', null, null, 'text', 'Google Oauth ClientID', null),
|
Setting('setting_oauth', 'oauth.googleappid', null, null, 'text', 'Google Oauth ClientID', null),
|
||||||
Setting('setting_oauth', 'oauth.googlesecret', null, null, 'text', 'Google Oauth Secret', null, FLAG_SECRET),
|
Setting('setting_oauth', 'oauth.googlesecret', null, null, 'text', 'Google Oauth Secret', null, FLAG_SECRET),
|
||||||
Setting('setting_proxy', 'proxy', null, null, 'text', 'Proxy Server URL'),
|
Setting('setting_proxy', 'proxy', null, null, 'text', 'Proxy Server URL'),
|
||||||
Setting('setting_storage', 'PROBLEM_PER_PAGE', null, 100, 'number', 'Problems per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'CONTEST_PER_PAGE', null, 20, 'number', 'Contests per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'DISCUSSION_PER_PAGE', null, 50, 'number', 'Discussion per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'RECORD_PER_PAGE', null, 100, 'number', 'Record per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'SOLUTION_PER_PAGE', null, 20, 'number', 'Solutions per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'TRAINING_PER_PAGE', null, 10, 'number', 'Training per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'REPLY_PER_PAGE', null, 50, 'number', 'Reply per Page', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'HOMEWORK_ON_MAIN', null, 5, 'number', 'HOMEWORK_ON_MAIN', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'DISCUSSION_ON_MAIN', null, 20, 'number', 'DISCUSSION_ON_MAIN', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'CONTEST_ON_MAIN', null, 10, 'number', 'CONTEST_ON_MAIN', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'TRAINING_ON_MAIN', null, 10, 'number', 'TRAINING_ON_MAIN', null, FLAG_HIDDEN),
|
|
||||||
Setting('setting_storage', 'db.ver', null, 1, 'number', 'Database version', null, FLAG_DISABLED | FLAG_HIDDEN),
|
Setting('setting_storage', 'db.ver', null, 1, 'number', 'Database version', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||||
Setting('setting_storage', 'user', null, 1, 'number', 'User Counter', null, FLAG_DISABLED | FLAG_HIDDEN),
|
Setting('setting_storage', 'user', null, 1, 'number', 'User Counter', null, FLAG_DISABLED | FLAG_HIDDEN),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ export async function getList(domainId: string, tids: ObjectID[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const getMulti = (domainId: string, query: any = {}) =>
|
export const getMulti = (domainId: string, query: any = {}) =>
|
||||||
document.getMulti(domainId, document.TYPE_TRAINING, query);
|
document.getMulti(domainId, document.TYPE_TRAINING, query).sort('_id', 1);
|
||||||
|
|
||||||
global.Hydro.model.training = {
|
global.Hydro.model.training = {
|
||||||
getPids,
|
getPids,
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export default function load() {
|
|||||||
if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.config', 'hydro', 'config.json');
|
if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.config', 'hydro', 'config.json');
|
||||||
if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.hydro', 'config.json');
|
if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.hydro', 'config.json');
|
||||||
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
|
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
|
||||||
|
if (!fs.existsSync(f)) return null;
|
||||||
let result: any = {};
|
let result: any = {};
|
||||||
try {
|
try {
|
||||||
result = JSON.parse(fs.readFileSync(f).toString());
|
result = JSON.parse(fs.readFileSync(f).toString());
|
||||||
|
|||||||
@@ -745,7 +745,7 @@ export function Connection(
|
|||||||
// TODO use postInit?
|
// TODO use postInit?
|
||||||
export async function start() {
|
export async function start() {
|
||||||
const port = await system.get('server.port');
|
const port = await system.get('server.port');
|
||||||
if (!argv.debug) {
|
if (argv.debug) {
|
||||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms', {
|
app.use(morgan(':method :url :status :res[content-length] - :response-time ms', {
|
||||||
skip: (req, res) => res.hasHeader('nolog'),
|
skip: (req, res) => res.hasHeader('nolog'),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -524,7 +524,6 @@ Problem Solution: 题解列表
|
|||||||
Problem Tags Visibility: 题目标签可见性
|
Problem Tags Visibility: 题目标签可见性
|
||||||
problem_create: 创建题目
|
problem_create: 创建题目
|
||||||
problem_detail: 题目详情
|
problem_detail: 题目详情
|
||||||
problem_detail: 题目详情
|
|
||||||
problem_edit: 编辑题目
|
problem_edit: 编辑题目
|
||||||
problem_import: 导入题目
|
problem_import: 导入题目
|
||||||
problem_main: 题库
|
problem_main: 题库
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydrooj",
|
"name": "hydrooj",
|
||||||
"version": "2.11.9",
|
"version": "2.12.0",
|
||||||
"main": "dist/loader.js",
|
"main": "dist/loader.js",
|
||||||
"bin": "bin/hydrooj.js",
|
"bin": "bin/hydrooj.js",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
|
|||||||
Reference in new issue
Block a user