mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 09:36:08 +08:00
markdown preview
This commit is contained in:
1 parent
86f67a0ec3
commit
5ca424da0b
15 files changed
+123
-104
No files matched your search
@@ -20,7 +20,6 @@ module.exports = () => {
|
||||
} else {
|
||||
content.content = `${content.content}${line}\n`;
|
||||
}
|
||||
res[pagename].push(content);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
||||
@@ -48,6 +48,7 @@ class DomainCreateHandler extends Handler {
|
||||
async post({ id, name }) {
|
||||
await domain.add(id, this.user._id, name);
|
||||
this.response.body = { domainId: id };
|
||||
this.response.redirect = this.url('homepage', { domainId: id });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
const { PERM_JUDGE, PERM_LOGGEDIN } = require('../permission');
|
||||
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');
|
||||
|
||||
@@ -54,12 +55,21 @@ class SwitchLanguageHandler extends Handler {
|
||||
}
|
||||
}
|
||||
|
||||
class MarkdownHandler extends Handler {
|
||||
async post({ text, safe = true }) {
|
||||
this.response.body = safe
|
||||
? markdown.safe.render(text)
|
||||
: markdown.unsafe.render(text);
|
||||
}
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('file_download', '/fs/:id/:secret', FileDownloadHandler);
|
||||
Route('file_download_with_name', '/fs/:id/:name/:secret', FileDownloadHandler);
|
||||
Route('status', '/status', StatusHandler);
|
||||
Route('status_update', '/status/update', StatusUpdateHandler);
|
||||
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
||||
Route('markdown', '/markdown', MarkdownHandler);
|
||||
}
|
||||
|
||||
apply.updateStatus = function updateStatus(args) {
|
||||
|
||||
+10
-2
@@ -14,7 +14,7 @@ const RecordHandler = contest.ContestHandlerMixin(Handler);
|
||||
|
||||
class RecordListHandler extends RecordHandler {
|
||||
async get({
|
||||
domainId, page = 1, tid, uidOrName,
|
||||
domainId, page = 1, pid, tid, uidOrName,
|
||||
}) {
|
||||
this.response.template = 'record_main.html';
|
||||
const q = { tid };
|
||||
@@ -24,6 +24,7 @@ class RecordListHandler extends RecordHandler {
|
||||
{ _id: parseInt(uidOrName) },
|
||||
];
|
||||
}
|
||||
if (pid) q.pid = pid;
|
||||
const rdocs = await record.getMany(domainId, q, { _id: -1 }, page, await system.get('RECORD_PER_PAGE'));
|
||||
const [udict, pdict] = await Promise.all([
|
||||
user.getList(domainId, rdocs.map((rdoc) => rdoc.uid)),
|
||||
@@ -34,7 +35,14 @@ class RecordListHandler extends RecordHandler {
|
||||
['record_main', null],
|
||||
];
|
||||
this.response.body = {
|
||||
path, page, rdocs, pdict, udict,
|
||||
path,
|
||||
page,
|
||||
rdocs,
|
||||
pdict,
|
||||
udict,
|
||||
fliterPid: pid,
|
||||
fliterTid: tid,
|
||||
fliterUidOrName: uidOrName,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,16 @@ async function _parseDagJson(domainId, dag) {
|
||||
for (const nid of node.requireNids) {
|
||||
assert(ids.has(nid), `required nid ${nid} not found`);
|
||||
}
|
||||
const tasks = [];
|
||||
for (const i in node.pids) {
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
const pdoc = await problem.get(domainId, node.pids[i]); // FIXME no-await-in-loop
|
||||
assert(pdoc, `Problem not found: ${node.pids[i]}`);
|
||||
node.pids[i] = pdoc.docId;
|
||||
tasks.push(problem.get(domainId, node.pids[i]).then((pdoc) => {
|
||||
if (!pdoc) throw new ProblemNotFoundError(domainId, node.pids[i]);
|
||||
node.pids[i] = pdoc.docId;
|
||||
}));
|
||||
}
|
||||
// FIXME no-await-in-loop
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Promise.all(tasks);
|
||||
const newNode = {
|
||||
_id: parseInt(node._id),
|
||||
title: node.title,
|
||||
|
||||
@@ -2,7 +2,7 @@ const { Route, Handler } = require('../service/server');
|
||||
const { NotFoundError } = require('../error');
|
||||
|
||||
class WikiHandler extends Handler {
|
||||
async get({ name: page }) {
|
||||
async get({ page }) {
|
||||
if (!global.Hydro.wiki[page]) throw new NotFoundError(page);
|
||||
const contents = global.Hydro.wiki[page];
|
||||
const path = [
|
||||
|
||||
+12
-12
@@ -3,26 +3,26 @@ const permission = require('../permission');
|
||||
global.Hydro.ui.nav = [];
|
||||
|
||||
const trueChecker = () => true;
|
||||
const Item = (path, name, prefix, perm, checker) => {
|
||||
const Item = (name, args, prefix, perm, checker) => {
|
||||
if (perm && checker) {
|
||||
checker = ((_chk) => (handler) => _chk(handler) && handler.user.hasPerm(perm))(checker);
|
||||
} else if (perm) {
|
||||
checker = (handler) => handler.user.hasPerm(perm);
|
||||
} else if (!checker) checker = trueChecker;
|
||||
global.Hydro.ui.nav.push({
|
||||
path, name, prefix, checker,
|
||||
name, args: args || {}, prefix, checker,
|
||||
});
|
||||
};
|
||||
|
||||
Item('/', 'homepage', 'homepage');
|
||||
Item('/p', 'problem_main', 'problem', permission.PERM_VIEW_PROBLEM);
|
||||
Item('/t', 'training_main', 'training', permission.PERM_VIEW_TRAINING);
|
||||
Item('/homework', 'homework_main', 'homework', permission.PERM_VIEW_HOMEWORK);
|
||||
Item('/discuss', 'discussion_main', 'discussion', permission.PERM_VIEW_DISCUSSION);
|
||||
Item('/c', 'contest_main', 'contest', permission.PERM_VIEW_CONTEST);
|
||||
Item('/record', 'record_main', 'record');
|
||||
Item('/ranking', 'ranking', 'ranking');
|
||||
Item('/domain/dashboard', 'domain_dashboard', 'domain', permission.PERM_MANAGE);
|
||||
Item('/manage/dashboard', 'manage', 'manage', null, (handler) => handler.user.priv === 1);
|
||||
Item('homepage', null, 'homepage');
|
||||
Item('problem_main', null, 'problem', permission.PERM_VIEW_PROBLEM);
|
||||
Item('training_main', null, 'training', permission.PERM_VIEW_TRAINING);
|
||||
Item('homework_main', null, 'homework', permission.PERM_VIEW_HOMEWORK);
|
||||
Item('discussion_main', null, 'discussion', permission.PERM_VIEW_DISCUSSION);
|
||||
Item('contest_main', null, 'contest', permission.PERM_VIEW_CONTEST);
|
||||
Item('record_main', null, 'record');
|
||||
Item('ranking', null, 'ranking');
|
||||
Item('domain_dashboard', null, 'domain', permission.PERM_MANAGE);
|
||||
Item('manage_dashboard', null, 'manage', null, (handler) => handler.user.priv === 1);
|
||||
|
||||
global.Hydro.lib.nav = module.exports = Item;
|
||||
+7
-15
@@ -16,14 +16,6 @@ function ensureDir(dir) {
|
||||
}
|
||||
}
|
||||
|
||||
function superRequire(p) {
|
||||
// eslint-disable-next-line camelcase
|
||||
if (typeof __non_webpack_require__ === 'function') {
|
||||
// eslint-disable-next-line no-undef
|
||||
return __non_webpack_require__(p);
|
||||
} return require(p);
|
||||
}
|
||||
|
||||
let pending = [];
|
||||
const active = [];
|
||||
const fail = [];
|
||||
@@ -35,7 +27,7 @@ async function handler() {
|
||||
try {
|
||||
console.log(`Handler init: ${i}`);
|
||||
console.time(`Handler init: ${i}`);
|
||||
superRequire(p);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Handler init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
@@ -50,7 +42,7 @@ async function locale() {
|
||||
const p = `${os.tmpdir()}/hydro/tmp/${i}/locale.json`;
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
global.Hydro.lib.i18n(superRequire(p));
|
||||
global.Hydro.lib.i18n(eval('require')(p));
|
||||
console.log(`Locale init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
@@ -65,7 +57,7 @@ async function template() {
|
||||
const p = `${os.tmpdir()}/hydro/tmp/${i}/template.json`;
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
Object.assign(global.Hydro.template, superRequire(p));
|
||||
Object.assign(global.Hydro.template, eval('require')(p));
|
||||
console.log(`Template init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
@@ -82,7 +74,7 @@ async function model() {
|
||||
try {
|
||||
console.log(`Model init: ${i}`);
|
||||
console.time(`Model init: ${i}`);
|
||||
superRequire(p);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Model init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
@@ -99,7 +91,7 @@ async function lib() {
|
||||
try {
|
||||
console.log(`Lib init: ${i}`);
|
||||
console.time(`Lib init: ${i}`);
|
||||
superRequire(p);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Lib init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
@@ -116,7 +108,7 @@ async function service() {
|
||||
try {
|
||||
console.log(`Service init: ${i}`);
|
||||
console.time(`Service init: ${i}`);
|
||||
superRequire(p);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Service init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
@@ -133,7 +125,7 @@ async function script() {
|
||||
if (fs.existsSync(p) && !fail.includes(i)) {
|
||||
try {
|
||||
console.time(`Script init: ${i}`);
|
||||
superRequire(p);
|
||||
eval('require')(p);
|
||||
console.timeEnd(`Script init: ${i}`);
|
||||
} catch (e) {
|
||||
fail.push(i);
|
||||
|
||||
+54
-57
@@ -186,14 +186,16 @@ class Handler {
|
||||
|
||||
url(name, kwargs = {}) { // eslint-disable-line class-methods-use-this
|
||||
delete kwargs.__keywords;
|
||||
let res;
|
||||
const { anchor } = kwargs;
|
||||
if (kwargs.query) {
|
||||
const { query } = kwargs;
|
||||
delete kwargs.query;
|
||||
res = router.url(name, kwargs, { query });
|
||||
if (this.args.domainId !== 'system') {
|
||||
name += '_with_domainId';
|
||||
kwargs.domainId = kwargs.domainId || this.args.domainId;
|
||||
}
|
||||
res = router.url(name, kwargs);
|
||||
let res;
|
||||
const { anchor, query } = kwargs;
|
||||
delete kwargs.anchor;
|
||||
delete kwargs.query;
|
||||
if (query) res = router.url(name, kwargs, { query });
|
||||
else res = router.url(name, kwargs);
|
||||
if (anchor) return `${res}#${anchor}`;
|
||||
return res;
|
||||
}
|
||||
@@ -311,60 +313,55 @@ class Handler {
|
||||
}
|
||||
}
|
||||
|
||||
function Route(name, route, RouteHandler, permission = null) {
|
||||
router.all(name, route, async (ctx) => {
|
||||
const h = new RouteHandler(ctx);
|
||||
async function handle(ctx, HandlerClass, permission) {
|
||||
const h = new HandlerClass(ctx);
|
||||
try {
|
||||
const method = ctx.method.toLowerCase();
|
||||
const args = {
|
||||
domainId: 'system', ...ctx.params, ...ctx.query, ...ctx.request.body,
|
||||
};
|
||||
|
||||
if (h.___prepare) await h.___prepare(args);
|
||||
if (permission) h.checkPerm(permission);
|
||||
|
||||
try {
|
||||
const method = ctx.method.toLowerCase();
|
||||
// TODO(masnn) domainId
|
||||
const args = {
|
||||
domainId: 'system', ...ctx.params, ...ctx.query, ...ctx.request.body,
|
||||
};
|
||||
if (h.request.host !== await system.get('server.host')) {
|
||||
try {
|
||||
args.domainId = (h.request.url.split('//')[1] || '')
|
||||
.split(`.${await system.get('server.host')}`)[0] || 'system';
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
for (const key in validate) {
|
||||
if (args[key]) {
|
||||
args[key] = validate[key](args[key], key);
|
||||
}
|
||||
}
|
||||
|
||||
if (h.___prepare) await h.___prepare(args);
|
||||
if (permission) h.checkPerm(permission);
|
||||
|
||||
try {
|
||||
for (const key in validate) {
|
||||
if (args[key]) {
|
||||
args[key] = validate[key](args[key], key);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
if (e instanceof ValidationError) throw e;
|
||||
throw new ValidationError('Argument check failed');
|
||||
}
|
||||
if (h.__prepare) await h.__prepare(args);
|
||||
if (h._prepare) await h._prepare(args);
|
||||
if (h.prepare) await h.prepare(args);
|
||||
|
||||
if (h[`___${method}`]) await h[`___${method}`](args);
|
||||
if (h[`__${method}`]) await h[`__${method}`](args);
|
||||
if (h[`_${method}`]) await h[`_${method}`](args);
|
||||
if (h[method]) await h[method](args);
|
||||
|
||||
if (method === 'post' && ctx.request.body.operation) {
|
||||
const operation = `_${ctx.request.body.operation}`
|
||||
.replace(/_([a-z])/gm, (s) => s[1].toUpperCase());
|
||||
if (h[`${method}${operation}`]) await h[`${method}${operation}`](args);
|
||||
}
|
||||
|
||||
if (h.cleanup) await h.cleanup(args);
|
||||
if (h._cleanup) await h._cleanup(args);
|
||||
if (h.__cleanup) await h.__cleanup(args);
|
||||
if (h.___cleanup) await h.___cleanup(args);
|
||||
} catch (e) {
|
||||
if (h.onerror) await h.onerror(e);
|
||||
if (e instanceof ValidationError) throw e;
|
||||
throw new ValidationError('Argument check failed');
|
||||
}
|
||||
});
|
||||
h.args = args;
|
||||
if (h.__prepare) await h.__prepare(args);
|
||||
if (h._prepare) await h._prepare(args);
|
||||
if (h.prepare) await h.prepare(args);
|
||||
|
||||
if (h[`___${method}`]) await h[`___${method}`](args);
|
||||
if (h[`__${method}`]) await h[`__${method}`](args);
|
||||
if (h[`_${method}`]) await h[`_${method}`](args);
|
||||
if (h[method]) await h[method](args);
|
||||
|
||||
if (method === 'post' && ctx.request.body.operation) {
|
||||
const operation = `_${ctx.request.body.operation}`
|
||||
.replace(/_([a-z])/gm, (s) => s[1].toUpperCase());
|
||||
if (h[`${method}${operation}`]) await h[`${method}${operation}`](args);
|
||||
}
|
||||
|
||||
if (h.cleanup) await h.cleanup(args);
|
||||
if (h._cleanup) await h._cleanup(args);
|
||||
if (h.__cleanup) await h.__cleanup(args);
|
||||
if (h.___cleanup) await h.___cleanup(args);
|
||||
} catch (e) {
|
||||
if (h.onerror) await h.onerror(e);
|
||||
}
|
||||
}
|
||||
|
||||
function Route(name, route, RouteHandler, permission = null) {
|
||||
router.all(name, route, (ctx) => handle(ctx, RouteHandler, permission));
|
||||
router.all(`${name}_with_domainId`, `/d/:domainId${route}`, (ctx) => handle(ctx, RouteHandler, permission));
|
||||
}
|
||||
|
||||
class ConnectionHandler {
|
||||
@@ -461,7 +458,7 @@ function Validate(key, func) {
|
||||
async function start() {
|
||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||
app.use(router.routes()).use(router.allowedMethods());
|
||||
Route('*', Handler);
|
||||
Route('notfound_handler', '*', Handler);
|
||||
if (cluster.worker.id === 1) {
|
||||
const port = await system.get('server.port');
|
||||
server.listen(port);
|
||||
|
||||
@@ -3,6 +3,12 @@ const { PERM_LOGGEDIN } = global.Hydro.permission;
|
||||
const { pastebin } = global.Hydro.model;
|
||||
const { nav } = global.Hydro.lib;
|
||||
|
||||
class PasteMainHandler extends Handler {
|
||||
async get() {
|
||||
this.response.redirect = this.url('paste_creaate');
|
||||
}
|
||||
}
|
||||
|
||||
class PasteShowHandler extends Handler {
|
||||
async get({ docId }) {
|
||||
const doc = await pastebin.get(docId);
|
||||
@@ -42,9 +48,10 @@ class PasteCreateHandler extends Handler {
|
||||
}
|
||||
|
||||
async function apply() {
|
||||
Route('paste', '/paste', PasteMainHandler);
|
||||
Route('paste_create', '/paste/create', PasteCreateHandler);
|
||||
Route('paste_show', '/paste/:docId', PasteShowHandler);
|
||||
nav('/paste/create', 'pastebin', 'pastebin', PERM_LOGGEDIN);
|
||||
nav('paste', null, 'paste', PERM_LOGGEDIN);
|
||||
}
|
||||
|
||||
global.Hydro.handler.pastebin = module.exports = apply;
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.1",
|
||||
"main": "hydro/loader.js",
|
||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||
"author": "masnn",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% macro nav_item(target_page_url, target_page_name, target_page_prefix) %}
|
||||
{% macro nav_item(target_page_name, target_page_args, target_page_prefix) %}
|
||||
<li class="nav__list-item">
|
||||
<a href="{{ target_page_url }}" class="nav__item{% if page_name.startsWith(target_page_prefix) %} nav--active{% endif %}">
|
||||
<a href="{{ url(target_page_name, target_page_args) }}" class="nav__item{% if page_name.startsWith(target_page_prefix) %} nav--active{% endif %}">
|
||||
{{ _(target_page_name) }}
|
||||
</a>
|
||||
</li>
|
||||
@@ -12,7 +12,7 @@
|
||||
<li class="nav__list-item"><a href="/" class="nav__logo"> </a></li>
|
||||
{% for item in Context.nav %}
|
||||
{% if item.checker(handler) %}
|
||||
{{ nav_item(item.path, item.name, item.prefix) }}
|
||||
{{ nav_item(item.name, item.args, item.prefix) }}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</ol>
|
||||
|
||||
@@ -7,7 +7,7 @@ Given two integers x and y, print the sum.
|
||||
# Format
|
||||
|
||||
## Input
|
||||
Two integers x and y, satisfying 0 <= x, y <= 32767.
|
||||
Two integers x and y, satisfying $0\leq x,y\leq 32767$ .
|
||||
|
||||
## Output
|
||||
One integer, the sum of x and y.
|
||||
@@ -15,16 +15,16 @@ One integer, the sum of x and y.
|
||||
# Sample 1
|
||||
|
||||
## Input
|
||||
|
||||
```
|
||||
123 500
|
||||
```
|
||||
|
||||
## Output
|
||||
|
||||
```
|
||||
623
|
||||
```
|
||||
|
||||
# Limitation
|
||||
1s, 1024KiB for each test case.
|
||||
|
||||
```
|
||||
@@ -25,19 +25,19 @@
|
||||
<div class="medium-4 columns">
|
||||
<label class="filter-user">
|
||||
{{ _('By Username / UID') }}
|
||||
<input name="uidOrName" type="text" class="textbox" value="{{ filter_uidOrName }}" autocomplete="off" data-autofocus>
|
||||
<input name="uidOrName" type="text" class="textbox" value="{{ filterUidOrName }}" autocomplete="off" data-autofocus>
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-4 columns">
|
||||
<label>
|
||||
{{ _('By Problem') }}
|
||||
<input name="pid" type="text" class="textbox" value="{{ filter_pid }}">
|
||||
<input name="pid" type="text" class="textbox" value="{{ filterPid }}">
|
||||
</label>
|
||||
</div>
|
||||
<div class="medium-4 columns">
|
||||
<label>
|
||||
{{ _('By Contest') }}
|
||||
<input name="tid" type="text" class="textbox" value="{{ filter_tid }}">
|
||||
<input name="tid" type="text" class="textbox" value="{{ filterTid }}">
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -92,8 +92,9 @@ export default class VjCmEditor extends SimpleMDE {
|
||||
}
|
||||
|
||||
async markdown(text) {
|
||||
// FIXME preview wont update after first toggle
|
||||
const data = await request.ajax({
|
||||
url: '/preview',
|
||||
url: '/markdown',
|
||||
method: 'post',
|
||||
data: $.param({ text }, true),
|
||||
dataType: 'text',
|
||||
|
||||
Reference in new issue
Block a user