mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 09:46:28 +08:00
交互式安装
This commit is contained in:
1 parent
6134a16f8c
commit
27cfe81e31
21 files changed
+298
-146
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
config.yaml
|
config.yaml
|
||||||
|
config.json
|
||||||
.build/
|
.build/
|
||||||
*.build
|
*.build
|
||||||
.uibuild/
|
.uibuild/
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ const build = async (type) => {
|
|||||||
mode: type,
|
mode: type,
|
||||||
entry: {
|
entry: {
|
||||||
development: root('hydro/development.js'),
|
development: root('hydro/development.js'),
|
||||||
install: root('hydro/install.js'),
|
|
||||||
uninstall: root('hydro/uninstall.js'),
|
|
||||||
},
|
},
|
||||||
output: {
|
output: {
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
|
|||||||
@@ -3,12 +3,12 @@ const {
|
|||||||
ContestNotAttendedError,
|
ContestNotAttendedError,
|
||||||
} = require('../error');
|
} = require('../error');
|
||||||
const { PERM_CREATE_CONTEST, PERM_EDIT_CONTEST } = require('../permission');
|
const { PERM_CREATE_CONTEST, PERM_EDIT_CONTEST } = require('../permission');
|
||||||
const { constants } = require('../options');
|
|
||||||
const paginate = require('../lib/paginate');
|
const paginate = require('../lib/paginate');
|
||||||
const contest = require('../model/contest');
|
const contest = require('../model/contest');
|
||||||
const problem = require('../model/problem');
|
const problem = require('../model/problem');
|
||||||
const record = require('../model/record');
|
const record = require('../model/record');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
|
const system = require('../model/system');
|
||||||
const { Route, Handler } = require('../service/server');
|
const { Route, Handler } = require('../service/server');
|
||||||
|
|
||||||
const ContestHandler = contest.ContestHandlerMixin(Handler);
|
const ContestHandler = contest.ContestHandlerMixin(Handler);
|
||||||
@@ -27,7 +27,7 @@ class ContestListHandler extends ContestHandler {
|
|||||||
qs = 'rule={0}'.format(rule);
|
qs = 'rule={0}'.format(rule);
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line prefer-const
|
// eslint-disable-next-line prefer-const
|
||||||
[tdocs, tpcount] = await paginate(tdocs, page, constants.CONTEST_PER_PAGE);
|
[tdocs, tpcount] = await paginate(tdocs, page, await system.get('CONTEST_PER_PAGE'));
|
||||||
const tids = [];
|
const tids = [];
|
||||||
for (const tdoc of tdocs) tids.push(tdoc._id);
|
for (const tdoc of tdocs) tids.push(tdoc._id);
|
||||||
const tsdict = await contest.getListStatus(this.user._id, tids);
|
const tsdict = await contest.getListStatus(this.user._id, tids);
|
||||||
@@ -51,12 +51,14 @@ class ContestDetailHandler extends ContestHandler {
|
|||||||
attended;
|
attended;
|
||||||
if (tsdoc) {
|
if (tsdoc) {
|
||||||
attended = tsdoc.attend === 1;
|
attended = tsdoc.attend === 1;
|
||||||
for (const pdetail of tsdoc.journal || []) { psdict[pdetail.pid] = pdetail; }
|
for (const pdetail of tsdoc.journal || []) psdict[pdetail.pid] = pdetail;
|
||||||
if (this.canShowRecord(this.tdoc)) {
|
if (this.canShowRecord(this.tdoc)) {
|
||||||
const q = [];
|
const q = [];
|
||||||
for (const i in psdict) q.push(psdict[i].rid);
|
for (const i in psdict) q.push(psdict[i].rid);
|
||||||
rdict = await record.getList(q);
|
rdict = await record.getList(q);
|
||||||
} else { for (const i in psdict) rdict[psdict[i].rid] = { _id: psdict[i].rid }; }
|
} else {
|
||||||
|
for (const i in psdict) rdict[psdict[i].rid] = { _id: psdict[i].rid };
|
||||||
|
}
|
||||||
} else attended = false;
|
} else attended = false;
|
||||||
const udict = await user.getList([this.tdoc.owner]);
|
const udict = await user.getList([this.tdoc.owner]);
|
||||||
const path = [
|
const path = [
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
const paginate = require('../lib/paginate');
|
const paginate = require('../lib/paginate');
|
||||||
const problem = require('../model/problem');
|
const problem = require('../model/problem');
|
||||||
const contest = require('../model/contest');
|
const contest = require('../model/contest');
|
||||||
|
const system = require('../model/system');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
const discussion = require('../model/discussion');
|
const discussion = require('../model/discussion');
|
||||||
const {
|
const {
|
||||||
@@ -9,7 +10,6 @@ const {
|
|||||||
const {
|
const {
|
||||||
DiscussionNodeNotFoundError, DiscussionNotFoundError, DocumentNotFoundError,
|
DiscussionNodeNotFoundError, DiscussionNotFoundError, DocumentNotFoundError,
|
||||||
} = require('../error');
|
} = require('../error');
|
||||||
const { constants } = require('../options');
|
|
||||||
const {
|
const {
|
||||||
PERM_VIEW_DISCUSSION, PERM_EDIT_DISCUSSION, PERM_EDIT_DISCUSSION_REPLY,
|
PERM_VIEW_DISCUSSION, PERM_EDIT_DISCUSSION, PERM_EDIT_DISCUSSION_REPLY,
|
||||||
PERM_VIEW_PROBLEM_HIDDEN, PERM_DELETE_DISCUSSION, PERM_DELETE_DISCUSSION_REPLY,
|
PERM_VIEW_PROBLEM_HIDDEN, PERM_DELETE_DISCUSSION, PERM_DELETE_DISCUSSION_REPLY,
|
||||||
@@ -65,7 +65,7 @@ class DiscussionMainHandler extends DiscussionHandler {
|
|||||||
const [ddocs, dpcount] = await paginate(
|
const [ddocs, dpcount] = await paginate(
|
||||||
discussion.getMulti(),
|
discussion.getMulti(),
|
||||||
page,
|
page,
|
||||||
constants.DISCUSSION_PER_PAGE,
|
await system.get('DISCUSSION_PER_PAGE'),
|
||||||
);
|
);
|
||||||
const udict = await user.getList(ddocs.map((ddoc) => ddoc.owner));
|
const udict = await user.getList(ddocs.map((ddoc) => ddoc.owner));
|
||||||
const path = [
|
const path = [
|
||||||
@@ -84,7 +84,7 @@ class DiscussionNodeHandler extends DiscussionHandler {
|
|||||||
const [ddocs, dpcount] = await paginate(
|
const [ddocs, dpcount] = await paginate(
|
||||||
discussion.getMulti({ type, docId }),
|
discussion.getMulti({ type, docId }),
|
||||||
page,
|
page,
|
||||||
constants.DISCUSSION_PER_PAGE,
|
await system.get('DISCUSSION_PER_PAGE'),
|
||||||
);
|
);
|
||||||
const udict = await user.getList(ddocs.map((ddoc) => ddoc.owner));
|
const udict = await user.getList(ddocs.map((ddoc) => ddoc.owner));
|
||||||
const path = [
|
const path = [
|
||||||
@@ -142,7 +142,7 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
|||||||
const [drdocs, pcount, drcount] = await paginate(
|
const [drdocs, pcount, drcount] = await paginate(
|
||||||
discussion.getMultiReply(did),
|
discussion.getMultiReply(did),
|
||||||
page,
|
page,
|
||||||
constants.REPLY_PER_PAGE,
|
await system.get('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);
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ const {
|
|||||||
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
VerifyPasswordError, UserAlreadyExistError, InvalidTokenError,
|
||||||
NotFoundError, MessageNotFoundError,
|
NotFoundError, MessageNotFoundError,
|
||||||
} = require('../error');
|
} = require('../error');
|
||||||
const options = require('../options');
|
|
||||||
const bus = require('../service/bus');
|
const bus = require('../service/bus');
|
||||||
const {
|
const {
|
||||||
Route, Connection, Handler, ConnectionHandler,
|
Route, Connection, Handler, ConnectionHandler,
|
||||||
@@ -11,6 +10,7 @@ const misc = require('../lib/misc');
|
|||||||
const md5 = require('../lib/md5');
|
const md5 = require('../lib/md5');
|
||||||
const contest = require('../model/contest');
|
const contest = require('../model/contest');
|
||||||
const message = require('../model/message');
|
const message = require('../model/message');
|
||||||
|
const system = require('../model/system');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
const setting = require('../model/setting');
|
const setting = require('../model/setting');
|
||||||
const discussion = require('../model/discussion');
|
const discussion = require('../model/discussion');
|
||||||
@@ -20,13 +20,12 @@ const {
|
|||||||
PERM_VIEW_TRAINING, PERM_VIEW_CONTEST, PERM_VIEW_DISCUSSION,
|
PERM_VIEW_TRAINING, PERM_VIEW_CONTEST, PERM_VIEW_DISCUSSION,
|
||||||
PERM_LOGGEDIN,
|
PERM_LOGGEDIN,
|
||||||
} = require('../permission');
|
} = require('../permission');
|
||||||
const { CONTESTS_ON_MAIN, TRAININGS_ON_MAIN, DISCUSSIONS_ON_MAIN } = require('../options').constants;
|
|
||||||
|
|
||||||
class HomeHandler extends Handler {
|
class HomeHandler extends Handler {
|
||||||
async contest() {
|
async contest() {
|
||||||
if (this.user.hasPerm(PERM_VIEW_CONTEST)) {
|
if (this.user.hasPerm(PERM_VIEW_CONTEST)) {
|
||||||
const tdocs = await contest.getMulti()
|
const tdocs = await contest.getMulti()
|
||||||
.limit(CONTESTS_ON_MAIN)
|
.limit(await system.get('CONTESTS_ON_MAIN'))
|
||||||
.toArray();
|
.toArray();
|
||||||
const tsdict = await contest.getListStatus(
|
const tsdict = await contest.getListStatus(
|
||||||
this.user._id, tdocs.map((tdoc) => tdoc._id),
|
this.user._id, tdocs.map((tdoc) => tdoc._id),
|
||||||
@@ -40,7 +39,7 @@ class HomeHandler extends Handler {
|
|||||||
if (this.user.hasPerm(PERM_VIEW_TRAINING)) {
|
if (this.user.hasPerm(PERM_VIEW_TRAINING)) {
|
||||||
const tdocs = await training.getMulti()
|
const tdocs = await training.getMulti()
|
||||||
.sort('_id', 1)
|
.sort('_id', 1)
|
||||||
.limit(TRAININGS_ON_MAIN)
|
.limit(await system.get('TRAININGS_ON_MAIN'))
|
||||||
.toArray();
|
.toArray();
|
||||||
const tsdict = await training.getListStatus(
|
const tsdict = await training.getListStatus(
|
||||||
this.user._id, tdocs.map((tdoc) => tdoc._id),
|
this.user._id, tdocs.map((tdoc) => tdoc._id),
|
||||||
@@ -53,7 +52,7 @@ class HomeHandler extends Handler {
|
|||||||
async discussion() {
|
async discussion() {
|
||||||
if (this.user.hasPerm(PERM_VIEW_DISCUSSION)) {
|
if (this.user.hasPerm(PERM_VIEW_DISCUSSION)) {
|
||||||
const ddocs = await discussion.getMulti()
|
const ddocs = await discussion.getMulti()
|
||||||
.limit(DISCUSSIONS_ON_MAIN)
|
.limit(await system.get('DISCUSSIONS_ON_MAIN'))
|
||||||
.toArray();
|
.toArray();
|
||||||
const vndict = await discussion.getListVnodes(ddocs, this);
|
const vndict = await discussion.getListVnodes(ddocs, this);
|
||||||
return [ddocs, vndict];
|
return [ddocs, vndict];
|
||||||
@@ -106,7 +105,7 @@ class HomeSecurityHandler extends Handler {
|
|||||||
if (udoc) throw new UserAlreadyExistError(mail);
|
if (udoc) throw new UserAlreadyExistError(mail);
|
||||||
const [rid] = await token.add(
|
const [rid] = await token.add(
|
||||||
token.TYPE_CHANGEMAIL,
|
token.TYPE_CHANGEMAIL,
|
||||||
options.changemail_token_expire_seconds,
|
await system.get('changemail_token_expire_seconds'),
|
||||||
{ uid: this.udoc._id, mail },
|
{ uid: this.udoc._id, mail },
|
||||||
);
|
);
|
||||||
await mail.sendMail(mail, 'Change Email', 'user_changemail_mail.html', {
|
await mail.sendMail(mail, 'Change Email', 'user_changemail_mail.html', {
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ const {
|
|||||||
NoProblemError, ProblemDataNotFoundError, BadRequestError,
|
NoProblemError, ProblemDataNotFoundError, BadRequestError,
|
||||||
SolutionNotFoundError,
|
SolutionNotFoundError,
|
||||||
} = require('../error');
|
} = require('../error');
|
||||||
const { constants } = require('../options');
|
|
||||||
const {
|
const {
|
||||||
PERM_VIEW_PROBLEM, PERM_VIEW_PROBLEM_HIDDEN, PERM_SUBMIT_PROBLEM,
|
PERM_VIEW_PROBLEM, PERM_VIEW_PROBLEM_HIDDEN, PERM_SUBMIT_PROBLEM,
|
||||||
PERM_CREATE_PROBLEM, PERM_READ_PROBLEM_DATA, PERM_EDIT_PROBLEM,
|
PERM_CREATE_PROBLEM, PERM_READ_PROBLEM_DATA, PERM_EDIT_PROBLEM,
|
||||||
@@ -38,7 +37,7 @@ class ProblemHandler extends Handler {
|
|||||||
const [pdocs, pcount] = await paginate(
|
const [pdocs, pcount] = await paginate(
|
||||||
problem.getMulti(q).sort({ pid: 1 }),
|
problem.getMulti(q).sort({ pid: 1 }),
|
||||||
page,
|
page,
|
||||||
constants.PROBLEM_PER_PAGE,
|
await system.get('PROBLEM_PER_PAGE'),
|
||||||
);
|
);
|
||||||
if (this.user.hasPerm(PERM_LOGGEDIN)) {
|
if (this.user.hasPerm(PERM_LOGGEDIN)) {
|
||||||
psdict = await problem.getListStatus(this.user._id, pdocs.map((pdoc) => pdoc._id));
|
psdict = await problem.getListStatus(this.user._id, pdocs.map((pdoc) => pdoc._id));
|
||||||
@@ -252,7 +251,8 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
|
|||||||
this.checkPerm(PERM_VIEW_PROBLEM_SOLUTION);
|
this.checkPerm(PERM_VIEW_PROBLEM_SOLUTION);
|
||||||
const [psdocs, pcount, pscount] = await paginate(
|
const [psdocs, pcount, pscount] = await paginate(
|
||||||
solution.getMulti(this.pdoc._id),
|
solution.getMulti(this.pdoc._id),
|
||||||
page, constants.SOLUTION_PER_PAGE,
|
page,
|
||||||
|
await system.get('SOLUTION_PER_PAGE'),
|
||||||
);
|
);
|
||||||
const uids = [this.pdoc.owner]; const
|
const uids = [this.pdoc.owner]; const
|
||||||
docids = [];
|
docids = [];
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
const { constants } = require('../options');
|
|
||||||
const {
|
const {
|
||||||
PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD,
|
PERM_READ_RECORD_CODE, PERM_VIEW_CONTEST_HIDDEN_SCOREBOARD,
|
||||||
PERM_REJUDGE, PERM_VIEW_PROBLEM_HIDDEN,
|
PERM_REJUDGE, PERM_VIEW_PROBLEM_HIDDEN,
|
||||||
@@ -6,6 +5,7 @@ const {
|
|||||||
const problem = require('../model/problem');
|
const problem = require('../model/problem');
|
||||||
const record = require('../model/record');
|
const record = require('../model/record');
|
||||||
const contest = require('../model/contest');
|
const contest = require('../model/contest');
|
||||||
|
const system = require('../model/system');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
const bus = require('../service/bus');
|
const bus = require('../service/bus');
|
||||||
const {
|
const {
|
||||||
@@ -16,7 +16,7 @@ class RecordListHandler extends Handler {
|
|||||||
async get({ page = 1 }) {
|
async get({ page = 1 }) {
|
||||||
this.response.template = 'record_main.html';
|
this.response.template = 'record_main.html';
|
||||||
const q = {};
|
const q = {};
|
||||||
const rdocs = await record.getMany(q, { _id: -1 }, page, constants.RECORD_PER_PAGE);
|
const rdocs = await record.getMany(q, { _id: -1 }, page, await system.get('RECORD_PER_PAGE'));
|
||||||
const pdict = {};
|
const pdict = {};
|
||||||
const udict = {};
|
const udict = {};
|
||||||
const ulist = [];
|
const ulist = [];
|
||||||
|
|||||||
@@ -4,12 +4,12 @@ const {
|
|||||||
PERM_LOGGEDIN, PERM_VIEW_TRAINING, PERM_VIEW_PROBLEM_HIDDEN,
|
PERM_LOGGEDIN, PERM_VIEW_TRAINING, PERM_VIEW_PROBLEM_HIDDEN,
|
||||||
PERM_CREATE_TRAINING, PERM_EDIT_TRAINING,
|
PERM_CREATE_TRAINING, PERM_EDIT_TRAINING,
|
||||||
} = require('../permission');
|
} = require('../permission');
|
||||||
const { constants } = require('../options');
|
|
||||||
const paginate = require('../lib/paginate');
|
const paginate = require('../lib/paginate');
|
||||||
const problem = require('../model/problem');
|
const problem = require('../model/problem');
|
||||||
const builtin = require('../model/builtin');
|
const builtin = require('../model/builtin');
|
||||||
const training = require('../model/training');
|
const training = require('../model/training');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
|
const system = require('../model/system');
|
||||||
const { Route, Handler } = require('../service/server');
|
const { Route, Handler } = require('../service/server');
|
||||||
|
|
||||||
async function _parseDagJson(dag) {
|
async function _parseDagJson(dag) {
|
||||||
@@ -60,7 +60,7 @@ class TrainingMainHandler extends TrainingHandler {
|
|||||||
const [tdocs, tpcount] = await paginate(
|
const [tdocs, tpcount] = await paginate(
|
||||||
training.getMulti().sort('_id', 1),
|
training.getMulti().sort('_id', 1),
|
||||||
page,
|
page,
|
||||||
constants.TRAINING_PER_PAGE,
|
await system.get('TRAINING_PER_PAGE'),
|
||||||
);
|
);
|
||||||
const tids = new Set();
|
const tids = new Set();
|
||||||
for (const tdoc of tdocs) tids.add(tdoc._id);
|
for (const tdoc of tdocs) tids.add(tdoc._id);
|
||||||
|
|||||||
+6
-14
@@ -4,7 +4,6 @@ const token = require('../model/token');
|
|||||||
const system = require('../model/system');
|
const system = require('../model/system');
|
||||||
const { sendMail } = require('../lib/mail');
|
const { sendMail } = require('../lib/mail');
|
||||||
const misc = require('../lib/misc');
|
const misc = require('../lib/misc');
|
||||||
const options = require('../options');
|
|
||||||
const { PERM_REGISTER_USER, PERM_LOGGEDIN } = require('../permission');
|
const { PERM_REGISTER_USER, PERM_LOGGEDIN } = require('../permission');
|
||||||
const {
|
const {
|
||||||
UserAlreadyExistError, InvalidTokenError, VerifyPasswordError,
|
UserAlreadyExistError, InvalidTokenError, VerifyPasswordError,
|
||||||
@@ -58,10 +57,10 @@ class UserRegisterHandler extends Handler {
|
|||||||
this.limitRate('send_mail', 3600, 30);
|
this.limitRate('send_mail', 3600, 30);
|
||||||
const t = await token.add(
|
const t = await token.add(
|
||||||
token.TYPE_REGISTRATION,
|
token.TYPE_REGISTRATION,
|
||||||
options.registration_token_expire_seconds,
|
await system.get('registration_token_expire_seconds'),
|
||||||
{ mail },
|
{ mail },
|
||||||
);
|
);
|
||||||
if (options.smtp.user) {
|
if (await system.get('smtp.user')) {
|
||||||
const m = await this.renderHTML('user_register_mail', { url: `/register/${t}` });
|
const m = await this.renderHTML('user_register_mail', { url: `/register/${t}` });
|
||||||
await sendMail(mail, 'Sign Up', 'user_register_mail', m);
|
await sendMail(mail, 'Sign Up', 'user_register_mail', m);
|
||||||
this.response.template = 'user_register_mail_sent.html';
|
this.response.template = 'user_register_mail_sent.html';
|
||||||
@@ -100,21 +99,18 @@ class UserRegisterWithCodeHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UserLostPassHandler extends Handler {
|
class UserLostPassHandler extends Handler {
|
||||||
constructor(ctx) {
|
|
||||||
if (!options.smtp.user) throw new SystemError('Cannot send mail');
|
|
||||||
super(ctx);
|
|
||||||
}
|
|
||||||
|
|
||||||
async get() {
|
async get() {
|
||||||
|
if (!await system.get('smtp.user')) throw new SystemError('Cannot send mail');
|
||||||
this.response.template = 'user_lostpass.html';
|
this.response.template = 'user_lostpass.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
async post({ mail }) {
|
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(mail);
|
||||||
if (!udoc) throw new UserNotFoundError(mail);
|
if (!udoc) throw new UserNotFoundError(mail);
|
||||||
const tid = await token.add(
|
const tid = await token.add(
|
||||||
token.TYPE_LOSTPASS,
|
token.TYPE_LOSTPASS,
|
||||||
options.lostpass_token_expire_seconds,
|
await system.get('lostpass_token_expire_seconds'),
|
||||||
{ uid: udoc._id },
|
{ uid: udoc._id },
|
||||||
);
|
);
|
||||||
const m = await this.renderHTML('user_lostpass_mail', { url: `/lostpass/${tid}`, uname: udoc.uname });
|
const m = await this.renderHTML('user_lostpass_mail', { url: `/lostpass/${tid}`, uname: udoc.uname });
|
||||||
@@ -142,16 +138,12 @@ class UserLostPassWithCodeHandler extends Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UserDetailHandler extends Handler {
|
class UserDetailHandler extends Handler {
|
||||||
constructor(ctx) {
|
|
||||||
super(ctx);
|
|
||||||
this.response.template = 'user_detail.html';
|
|
||||||
}
|
|
||||||
|
|
||||||
async get({ uid }) {
|
async get({ uid }) {
|
||||||
const isSelfProfile = this.user._id === uid;
|
const isSelfProfile = this.user._id === uid;
|
||||||
const udoc = await user.getById(uid);
|
const udoc = await user.getById(uid);
|
||||||
if (!udoc) throw new UserNotFoundError(uid);
|
if (!udoc) throw new UserNotFoundError(uid);
|
||||||
const sdoc = await token.getMostRecentSessionByUid(uid);
|
const sdoc = await token.getMostRecentSessionByUid(uid);
|
||||||
|
this.response.template = 'user_detail.html';
|
||||||
this.response.body = { isSelfProfile, udoc, sdoc };
|
this.response.body = { isSelfProfile, udoc, sdoc };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +0,0 @@
|
|||||||
require('./utils');
|
|
||||||
const Mongo = require('mongodb');
|
|
||||||
const { defaults } = require('lodash');
|
|
||||||
const builtin = require('./model/builtin');
|
|
||||||
const pwhash = require('./lib/pwhash');
|
|
||||||
const options = require('./options');
|
|
||||||
const { udoc } = require('./interface');
|
|
||||||
|
|
||||||
async function run() {
|
|
||||||
let mongourl = 'mongodb://';
|
|
||||||
if (options.db.username) mongourl += `${options.db.username}:${options.db.password}@`;
|
|
||||||
mongourl += `${options.db.host}:${options.db.port}/${options.db.name}`;
|
|
||||||
const Database = await Mongo.MongoClient.connect(
|
|
||||||
mongourl,
|
|
||||||
{ useNewUrlParser: true, useUnifiedTopology: true },
|
|
||||||
);
|
|
||||||
const db = Database.db(options.db.name);
|
|
||||||
const collUser = db.collection('user');
|
|
||||||
const collRole = db.collection('role');
|
|
||||||
const collBlacklist = db.collection('blacklist');
|
|
||||||
const collToken = db.collection('token');
|
|
||||||
async function createUser() {
|
|
||||||
const salt = pwhash.salt();
|
|
||||||
await collUser.insertMany([
|
|
||||||
defaults({
|
|
||||||
_id: 0,
|
|
||||||
uname: 'Hydro',
|
|
||||||
unameLower: 'hydro',
|
|
||||||
mail: 'hydro@hydro',
|
|
||||||
mailLower: 'hydro@hydro',
|
|
||||||
role: 'guest',
|
|
||||||
}, udoc),
|
|
||||||
defaults({
|
|
||||||
_id: 1,
|
|
||||||
mail: 'guest@hydro',
|
|
||||||
mailLower: 'guest@hydro',
|
|
||||||
uname: 'Guest',
|
|
||||||
unameLower: 'guest',
|
|
||||||
role: 'guest',
|
|
||||||
}, udoc),
|
|
||||||
defaults({
|
|
||||||
_id: -1,
|
|
||||||
mail: 'root@hydro',
|
|
||||||
mailLower: 'root@hydro',
|
|
||||||
uname: 'Root',
|
|
||||||
unameLower: 'root',
|
|
||||||
hash: pwhash.hash('rootroot', salt),
|
|
||||||
salt,
|
|
||||||
gravatar: 'root@hydro',
|
|
||||||
role: 'root',
|
|
||||||
}, udoc),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
await collRole.insertMany(builtin.BUILTIN_ROLES);
|
|
||||||
await collBlacklist.createIndex('expireAt', { expireAfterSeconds: 0 });
|
|
||||||
await collToken.createIndex([{ uid: 1 }, { tokenType: 1 }, { updateAt: -1 }], { sparse: true });
|
|
||||||
await collToken.createIndex('expireAt', { expireAfterSeconds: 0 });
|
|
||||||
await createUser();
|
|
||||||
console.log('Installed');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
run().catch((e) => {
|
|
||||||
console.error(e);
|
|
||||||
process.exit(1);
|
|
||||||
});
|
|
||||||
+47
-5
@@ -142,6 +142,41 @@ async function service() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function install() {
|
||||||
|
await Promise.all([lib(), locale(), template()]);
|
||||||
|
require('./service/setup');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function installDb() {
|
||||||
|
const system = require('./model/system');
|
||||||
|
const def = {
|
||||||
|
PROBLEM_PER_PAGE: 100,
|
||||||
|
RECORD_PER_PAGE: 100,
|
||||||
|
SOLUTION_PER_PAGE: 20,
|
||||||
|
CONTEST_PER_PAGE: 20,
|
||||||
|
TRAINING_PER_PAGE: 10,
|
||||||
|
DISCUSSION_PER_PAGE: 50,
|
||||||
|
REPLY_PER_PAGE: 50,
|
||||||
|
CONTESTS_ON_MAIN: 5,
|
||||||
|
TRAININGS_ON_MAIN: 5,
|
||||||
|
DISCUSSIONS_ON_MAIN: 20,
|
||||||
|
'db.ver': 1,
|
||||||
|
'listen.https': false,
|
||||||
|
'listen.port': 8888,
|
||||||
|
'session.keys': ['Hydro'],
|
||||||
|
'session.secure': false,
|
||||||
|
'session.saved_expire_seconds': 3600 * 24,
|
||||||
|
'session.unsaved_expire_seconds': 600,
|
||||||
|
changemail_token_expire_seconds: 3600 * 24,
|
||||||
|
registration_token_expire_seconds: 600,
|
||||||
|
};
|
||||||
|
const tasks = [];
|
||||||
|
for (const key in def) {
|
||||||
|
tasks.push(system.set(key, def[key]));
|
||||||
|
}
|
||||||
|
await Promise.all(tasks);
|
||||||
|
}
|
||||||
|
|
||||||
async function load() {
|
async function load() {
|
||||||
ensureDir(path.resolve(os.tmpdir(), 'hydro'));
|
ensureDir(path.resolve(os.tmpdir(), 'hydro'));
|
||||||
global.Hydro = {
|
global.Hydro = {
|
||||||
@@ -153,12 +188,16 @@ async function load() {
|
|||||||
ui: {},
|
ui: {},
|
||||||
};
|
};
|
||||||
await preload();
|
await preload();
|
||||||
await template();
|
|
||||||
require('./lib/i18n');
|
require('./lib/i18n');
|
||||||
require('./utils');
|
require('./utils');
|
||||||
require('./error');
|
require('./error');
|
||||||
require('./permission');
|
require('./permission');
|
||||||
|
try {
|
||||||
require('./options');
|
require('./options');
|
||||||
|
} catch (e) {
|
||||||
|
await install();
|
||||||
|
return;
|
||||||
|
}
|
||||||
const bus = require('./service/bus');
|
const bus = require('./service/bus');
|
||||||
await new Promise((resolve) => {
|
await new Promise((resolve) => {
|
||||||
const h = () => {
|
const h = () => {
|
||||||
@@ -175,20 +214,23 @@ async function load() {
|
|||||||
'template', 'validator', 'nav',
|
'template', 'validator', 'nav',
|
||||||
];
|
];
|
||||||
for (const i of builtinLib) require(`./lib/${i}`);
|
for (const i of builtinLib) require(`./lib/${i}`);
|
||||||
await lib();
|
await Promise.all([lib(), locale(), template()]);
|
||||||
await locale();
|
|
||||||
require('./service/gridfs');
|
require('./service/gridfs');
|
||||||
const server = require('./service/server');
|
const server = require('./service/server');
|
||||||
|
await server.prepare();
|
||||||
await service();
|
await service();
|
||||||
const builtinModel = [
|
const builtinModel = [
|
||||||
'blacklist', 'builtin', 'contest', 'discussion', 'message',
|
'blacklist', 'builtin', 'contest', 'discussion', 'message',
|
||||||
'opcount', 'problem', 'record', 'setting', 'solution',
|
'opcount', 'problem', 'record', 'setting', 'solution',
|
||||||
'system', 'token', 'training', 'user',
|
'token', 'training', 'user',
|
||||||
];
|
];
|
||||||
for (const i of builtinModel) {
|
for (const i of builtinModel) {
|
||||||
const m = require(`./model/${i}`);
|
const m = require(`./model/${i}`);
|
||||||
if (m.index) await m.index();
|
if (m.index) await m.index();
|
||||||
}
|
}
|
||||||
|
const system = require('./model/system');
|
||||||
|
const dbVer = await system.get('db.ver');
|
||||||
|
if (dbVer !== 1) await installDb();
|
||||||
const builtinHandler = [
|
const builtinHandler = [
|
||||||
'home', 'problem', 'record', 'judge', 'user',
|
'home', 'problem', 'record', 'judge', 'user',
|
||||||
'contest', 'training', 'discussion', 'manage', 'import',
|
'contest', 'training', 'discussion', 'manage', 'import',
|
||||||
@@ -204,7 +246,7 @@ async function load() {
|
|||||||
for (const i in global.Hydro.service) {
|
for (const i in global.Hydro.service) {
|
||||||
if (global.Hydro.service[i].postInit) await global.Hydro.service[i].postInit();
|
if (global.Hydro.service[i].postInit) await global.Hydro.service[i].postInit();
|
||||||
}
|
}
|
||||||
server.start();
|
await server.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { load, active };
|
module.exports = { load, active };
|
||||||
@@ -6,11 +6,19 @@ async function add(ip) {
|
|||||||
const expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000);
|
const expireAt = new Date(new Date().getTime() + 365 * 24 * 60 * 60 * 1000);
|
||||||
return coll.findOneAndUpdate({ _id: ip }, { $set: { expireAt } }, { upsert: true });
|
return coll.findOneAndUpdate({ _id: ip }, { $set: { expireAt } }, { upsert: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
function get(ip) {
|
function get(ip) {
|
||||||
return coll.findOne({ _id: ip });
|
return coll.findOne({ _id: ip });
|
||||||
}
|
}
|
||||||
|
|
||||||
function del(ip) {
|
function del(ip) {
|
||||||
return coll.deleteOne({ _id: ip });
|
return coll.deleteOne({ _id: ip });
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { add, get, del };
|
function index() {
|
||||||
|
return coll.createIndex('expireAt', { expireAfterSeconds: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
add, get, del, index,
|
||||||
|
};
|
||||||
@@ -12,7 +12,7 @@ async function update(_id, operation, config) {
|
|||||||
return get(_id);
|
return get(_id);
|
||||||
}
|
}
|
||||||
async function set(_id, value) {
|
async function set(_id, value) {
|
||||||
await coll.findOneAndUpdate({ _id }, { value }, { upsert: true });
|
await coll.findOneAndUpdate({ _id }, { $set: { value } }, { upsert: true });
|
||||||
return get(_id);
|
return get(_id);
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,12 +3,21 @@ const { ValidationError } = require('../error');
|
|||||||
|
|
||||||
const coll = db.collection('token');
|
const coll = db.collection('token');
|
||||||
|
|
||||||
|
function index() {
|
||||||
|
return Promise.all([
|
||||||
|
coll.createIndex([{ uid: 1 }, { tokenType: 1 }, { updateAt: -1 }], { sparse: true }),
|
||||||
|
coll.createIndex('expireAt', { expireAfterSeconds: 0 }),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
TYPE_SESSION: 0,
|
TYPE_SESSION: 0,
|
||||||
TYPE_CSRF_TOKEN: 1,
|
TYPE_CSRF_TOKEN: 1,
|
||||||
TYPE_REGISTER: 2,
|
TYPE_REGISTER: 2,
|
||||||
TYPE_CHANGEMAIL: 3,
|
TYPE_CHANGEMAIL: 3,
|
||||||
|
|
||||||
|
index,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a token.
|
* Add a token.
|
||||||
* @param {number} tokenType type of the token.
|
* @param {number} tokenType type of the token.
|
||||||
|
|||||||
+5
-9
@@ -51,14 +51,10 @@ let options = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
let f = path.resolve(process.cwd(), 'config.json');
|
||||||
let f = path.resolve(process.cwd(), 'config.yaml');
|
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.yaml');
|
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
|
||||||
if (!fs.existsSync(f)) f = path.resolve('/config/config.yaml');
|
const t = JSON.parse(fs.readFileSync(f));
|
||||||
const t = yaml.safeLoad(fs.readFileSync(f));
|
options = defaultsDeep(t, options);
|
||||||
options = defaultsDeep(t, options);
|
|
||||||
} catch (e) {
|
|
||||||
console.error('Cannot load config');
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = options;
|
module.exports = options;
|
||||||
+4
-12
@@ -4,12 +4,11 @@ const builtin = require('../model/builtin');
|
|||||||
const pwhash = require('../lib/pwhash');
|
const pwhash = require('../lib/pwhash');
|
||||||
const { udoc } = require('../interface');
|
const { udoc } = require('../interface');
|
||||||
|
|
||||||
|
const collUser = db.collection('user');
|
||||||
|
const collRole = db.collection('role');
|
||||||
|
const collSystem = db.collection('system');
|
||||||
|
|
||||||
async function run() {
|
async function run() {
|
||||||
const collUser = db.collection('user');
|
|
||||||
const collRole = db.collection('role');
|
|
||||||
const collBlacklist = db.collection('blacklist');
|
|
||||||
const collToken = db.collection('token');
|
|
||||||
async function createUser() {
|
|
||||||
const salt = pwhash.salt();
|
const salt = pwhash.salt();
|
||||||
await collUser.insertMany([
|
await collUser.insertMany([
|
||||||
defaults({
|
defaults({
|
||||||
@@ -40,14 +39,7 @@ async function run() {
|
|||||||
role: 'root',
|
role: 'root',
|
||||||
}, udoc),
|
}, udoc),
|
||||||
]);
|
]);
|
||||||
}
|
|
||||||
await collUser.createIndex('unameLower', { unique: true });
|
|
||||||
await collUser.createIndex('mailLower', { sparse: true });
|
|
||||||
await collRole.insertMany(builtin.BUILTIN_ROLES);
|
await collRole.insertMany(builtin.BUILTIN_ROLES);
|
||||||
await collBlacklist.createIndex('expireAt', { expireAfterSeconds: 0 });
|
|
||||||
await collToken.createIndex([{ uid: 1 }, { tokenType: 1 }, { updateAt: -1 }], { sparse: true });
|
|
||||||
await collToken.createIndex('expireAt', { expireAfterSeconds: 0 });
|
|
||||||
await createUser();
|
|
||||||
console.log('Installed');
|
console.log('Installed');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,4 +18,5 @@ Mongo.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology:
|
|||||||
|
|
||||||
global.Hydro.service.db = module.exports = {
|
global.Hydro.service.db = module.exports = {
|
||||||
collection: (c) => db.collection(c),
|
collection: (c) => db.collection(c),
|
||||||
|
dropDatabase: () => db.dropDatabase(),
|
||||||
};
|
};
|
||||||
+21
-15
@@ -8,10 +8,10 @@ const cache = require('koa-static-cache');
|
|||||||
const sockjs = require('sockjs');
|
const sockjs = require('sockjs');
|
||||||
const http = require('http');
|
const http = require('http');
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
const options = require('../options');
|
|
||||||
const validator = require('../lib/validator');
|
const validator = require('../lib/validator');
|
||||||
const template = require('../lib/template');
|
const template = require('../lib/template');
|
||||||
const user = require('../model/user');
|
const user = require('../model/user');
|
||||||
|
const system = require('../model/system');
|
||||||
const blacklist = require('../model/blacklist');
|
const blacklist = require('../model/blacklist');
|
||||||
const token = require('../model/token');
|
const token = require('../model/token');
|
||||||
const opcount = require('../model/opcount');
|
const opcount = require('../model/opcount');
|
||||||
@@ -21,18 +21,23 @@ const {
|
|||||||
} = require('../error');
|
} = require('../error');
|
||||||
|
|
||||||
const app = new Koa();
|
const app = new Koa();
|
||||||
const server = (options.listen.https ? https : http).createServer(app.callback());
|
let server;
|
||||||
app.keys = options.session.keys;
|
const router = new Router();
|
||||||
app.use(cache(path.join(process.cwd(), '.uibuild'), {
|
|
||||||
|
async function prepare() {
|
||||||
|
const useHttps = await system.get('listen.https');
|
||||||
|
server = (useHttps ? https : http).createServer(app.callback());
|
||||||
|
app.keys = await system.get('session.keys');
|
||||||
|
app.use(cache(path.join(process.cwd(), '.uibuild'), {
|
||||||
maxAge: 365 * 24 * 60 * 60,
|
maxAge: 365 * 24 * 60 * 60,
|
||||||
}));
|
}));
|
||||||
app.use(Body({
|
app.use(Body({
|
||||||
multipart: true,
|
multipart: true,
|
||||||
formidable: {
|
formidable: {
|
||||||
maxFileSize: 256 * 1024 * 1024,
|
maxFileSize: 256 * 1024 * 1024,
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
const router = new Router();
|
}
|
||||||
|
|
||||||
class Handler {
|
class Handler {
|
||||||
/**
|
/**
|
||||||
@@ -128,8 +133,8 @@ class Handler {
|
|||||||
this.now = new Date();
|
this.now = new Date();
|
||||||
this._handler.sid = this.request.cookies.get('sid');
|
this._handler.sid = this.request.cookies.get('sid');
|
||||||
this._handler.save = this.request.cookies.get('save');
|
this._handler.save = this.request.cookies.get('save');
|
||||||
if (this._handler.save) this._handler.expireSeconds = options.session.saved_expire_seconds;
|
if (this._handler.save) this._handler.expireSeconds = await system.get('session.saved_expire_seconds');
|
||||||
else this._handler.expireSeconds = options.session.unsaved_expire_seconds;
|
else this._handler.expireSeconds = await system.get('session.unsaved_expire_seconds');
|
||||||
this.session = this._handler.sid
|
this.session = this._handler.sid
|
||||||
? await token.update(
|
? await token.update(
|
||||||
this._handler.sid,
|
this._handler.sid,
|
||||||
@@ -213,7 +218,7 @@ class Handler {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const cookie = { secure: options.session.secure };
|
const cookie = { secure: await system.get('session.secure') };
|
||||||
if (this._handler.save) {
|
if (this._handler.save) {
|
||||||
cookie.expires = this.session.expireAt;
|
cookie.expires = this.session.expireAt;
|
||||||
cookie.maxAge = this._handler.expireSeconds;
|
cookie.maxAge = this._handler.expireSeconds;
|
||||||
@@ -354,6 +359,7 @@ class ConnectionHandler {
|
|||||||
if (!this.user) throw new UserNotFoundError(this.session.uid);
|
if (!this.user) throw new UserNotFoundError(this.session.uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function Connection(prefix, RouteConnHandler) {
|
function Connection(prefix, RouteConnHandler) {
|
||||||
const sock = sockjs.createServer({ prefix });
|
const sock = sockjs.createServer({ prefix });
|
||||||
sock.on('connection', async (conn) => {
|
sock.on('connection', async (conn) => {
|
||||||
@@ -389,14 +395,14 @@ function Connection(prefix, RouteConnHandler) {
|
|||||||
sock.installHandlers(server);
|
sock.installHandlers(server);
|
||||||
}
|
}
|
||||||
|
|
||||||
function start() {
|
async function start() {
|
||||||
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||||
app.use(router.routes()).use(router.allowedMethods());
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
Route('*', Handler);
|
Route('*', Handler);
|
||||||
server.listen(options.listen.port);
|
server.listen(await system.get('listen.port'));
|
||||||
console.log('Server listening at: %s', options.listen.port);
|
console.log('Server listening at: %s', await system.get('listen.port'));
|
||||||
}
|
}
|
||||||
|
|
||||||
global.Hydro.service.server = module.exports = {
|
global.Hydro.service.server = module.exports = {
|
||||||
Handler, ConnectionHandler, Route, Connection, start,
|
Handler, ConnectionHandler, Route, Connection, prepare, start,
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const Koa = require('koa');
|
||||||
|
const morgan = require('koa-morgan');
|
||||||
|
const Body = require('koa-body');
|
||||||
|
const Router = require('koa-router');
|
||||||
|
const cache = require('koa-static-cache');
|
||||||
|
const http = require('http');
|
||||||
|
const nunjucks = require('nunjucks');
|
||||||
|
|
||||||
|
function Loader() { }
|
||||||
|
Loader.prototype.getSource = function getSource(name) {
|
||||||
|
if (!global.Hydro.template[name]) throw new Error(`Cannot get template ${name}`);
|
||||||
|
return {
|
||||||
|
src: global.Hydro.template[name],
|
||||||
|
path: name,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
class Nunjucks extends nunjucks.Environment {
|
||||||
|
constructor() {
|
||||||
|
super(new Loader(), { autoescape: true, trimBlocks: true });
|
||||||
|
this.addFilter('json', (self) => JSON.stringify(self), false);
|
||||||
|
this.addFilter('base64_encode', (s) => Buffer.from(s).toString('base64'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const env = new Nunjucks();
|
||||||
|
function render(name) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
env.render(name, {
|
||||||
|
typeof: (o) => typeof o,
|
||||||
|
static_url: (str) => `/${str}`,
|
||||||
|
handler: { renderTitle: (str) => str },
|
||||||
|
_: (str) => str,
|
||||||
|
}, (err, res) => {
|
||||||
|
if (err) reject(err);
|
||||||
|
else resolve(res);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const app = new Koa();
|
||||||
|
const server = http.createServer(app.callback());
|
||||||
|
const router = new Router();
|
||||||
|
app.keys = ['Hydro'];
|
||||||
|
app.use(cache(path.join(process.cwd(), '.uibuild'), {
|
||||||
|
maxAge: 365 * 24 * 60 * 60,
|
||||||
|
}));
|
||||||
|
app.use(Body({
|
||||||
|
multipart: true,
|
||||||
|
formidable: {
|
||||||
|
maxFileSize: 256 * 1024 * 1024,
|
||||||
|
},
|
||||||
|
}));
|
||||||
|
|
||||||
|
router.get('/', async (ctx) => {
|
||||||
|
ctx.body = await render('setup.html');
|
||||||
|
ctx.response.type = 'text/html';
|
||||||
|
});
|
||||||
|
router.post('/', async (ctx) => {
|
||||||
|
const {
|
||||||
|
host, port, name, username, password,
|
||||||
|
} = ctx.request.body;
|
||||||
|
fs.writeFileSync(path.resolve(process.cwd(), 'config.json'), JSON.stringify({
|
||||||
|
host, port, name, username, password,
|
||||||
|
}));
|
||||||
|
ctx.body = await render('setup_done.html');
|
||||||
|
ctx.response.type = 'text/html';
|
||||||
|
});
|
||||||
|
|
||||||
|
app.use(morgan(':method :url :status :res[content-length] - :response-time ms'));
|
||||||
|
app.use(router.routes()).use(router.allowedMethods());
|
||||||
|
server.listen(8888);
|
||||||
|
console.log('Server listening at: 8888');
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-page="setup" data-layout="immersive" class="layout--immersive page--setup nojs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="chrome=1"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
|
<meta name="msapplication-TileColor" content="#579e9a">
|
||||||
|
<meta name="theme-color" content="#56758f">
|
||||||
|
|
||||||
|
<link rel="stylesheet" media="all" href="{{ static_url('vj4.css') }}">
|
||||||
|
<title>{{ _('Setup') }}</title>
|
||||||
|
<script>
|
||||||
|
var _htmlNode = document.documentElement;
|
||||||
|
_htmlNode.className = _htmlNode.className.replace(' nojs', ' hasjs');
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="slideout-panel" id="panel">
|
||||||
|
<div class="main">
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<div class="immersive--content immersive--center">
|
||||||
|
<h1>{{ _('Setup') }}</h1>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<label class="inverse material textbox">
|
||||||
|
{{ _('Database Host') }}
|
||||||
|
<input name="host" type="text" value="127.0.0.1" autofocus>
|
||||||
|
</label>
|
||||||
|
</div></div>
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<label class="inverse material textbox">
|
||||||
|
{{ _('Database Port') }}
|
||||||
|
<input name="port" type="number" value="27017" autofocus>
|
||||||
|
</label>
|
||||||
|
</div></div>
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<label class="inverse material textbox">
|
||||||
|
{{ _('Database Name') }}
|
||||||
|
<input name="name" type="text" value="hydro" autofocus>
|
||||||
|
</label>
|
||||||
|
</div></div>
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<label class="inverse material textbox">
|
||||||
|
{{ _('Database Username') }}
|
||||||
|
<input name="username" type="text" placeholder="{{ _('Leave blank if none') }}" autofocus>
|
||||||
|
</label>
|
||||||
|
</div></div>
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<label class="inverse material textbox">
|
||||||
|
{{ _('Database Password') }}
|
||||||
|
<input name="password" type="password" placeholder="{{ _('Leave blank if none') }}" autofocus>
|
||||||
|
</label>
|
||||||
|
</div></div>
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<div class="text-center">
|
||||||
|
<input type="submit" value="{{ _('Confirm') }}" class="inverse expanded rounded primary button">
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="{{ static_url('vj4.js') }}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html data-page="setup" data-layout="immersive" class="layout--immersive page--setup nojs">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="chrome=1"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||||
|
<meta name="msapplication-TileColor" content="#579e9a">
|
||||||
|
<meta name="theme-color" content="#56758f">
|
||||||
|
<link rel="stylesheet" media="all" href="{{ static_url('vj4.css') }}">
|
||||||
|
<title>{{ _('Setup') }}</title>
|
||||||
|
<script>
|
||||||
|
var _htmlNode = document.documentElement;
|
||||||
|
_htmlNode.className = _htmlNode.className.replace(' nojs', ' hasjs');
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="slideout-panel" id="panel">
|
||||||
|
<div class="main">
|
||||||
|
<div class="row"><div class="columns">
|
||||||
|
<div class="immersive--content immersive--center">
|
||||||
|
<h1>{{ _('Setup') }}</h1>
|
||||||
|
<div class="text-center">
|
||||||
|
{{ _('Done. Please restart the program.') }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/javascript" src="{{ static_url('vj4.js') }}"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Reference in new issue
Block a user