1.0.0-preview

This commit is contained in:
masnn committed 2020-05-13 12:25:18 +08:00
1 parent 90b06d6aa7
commit 8cd84f29e8
18 files changed
+152 -401

No files matched your search

+1 -1
View File
@@ -269,7 +269,7 @@ class ProblemSolutionHandler extends ProblemDetailHandler {
['problem_solution', null],
];
this.response.body = {
path, psdocs, page, pcount, pscount, udict, pssdict,
path, psdocs, page, pcount, pscount, udict, pssdict, pdoc: this.pdoc,
};
}
+13 -17
View File
@@ -1,22 +1,6 @@
const nodemailer = require('nodemailer');
const options = require('../options');
const { SendMailError } = require('../error');
let transporter = null;
try {
transporter = nodemailer.createTransport({
host: options.VJ_SMTP_HOST,
port: options.VJ_DB_PORT,
secure: options.VJ_SMTP_SECURE,
auth: {
user: options.VJ_SMTP_USER,
pass: options.VJ_SMTP_PASSWORD,
},
});
} catch (e) {
console.error(e);
}
module.exports = {
/**
* @param {string} to
@@ -27,9 +11,21 @@ module.exports = {
async sendMail(to, subject, text, html) {
let t;
try {
const system = require('../model/system');
const [host, port, secure, user, pass, from] = await Promise.all([
system.get('smtp.host'),
system.get('smtp.port'),
system.get('smtp.secure'),
system.get('smtp.user'),
system.get('smtp.pass'),
system.get('smtp.from'),
]);
const transporter = nodemailer.createTransport({
host, port, secure, auth: { user, pass },
});
t = await new Promise((resolve, reject) => {
transporter.sendMail({
from: options.VJ_SMTP_FROM,
from,
to,
subject,
text,
+17 -37
View File
@@ -1,3 +1,4 @@
/* eslint-disable import/no-dynamic-require */
/* eslint-disable no-await-in-loop */
/* eslint-disable no-eval */
const fs = require('fs');
@@ -19,6 +20,7 @@ function ensureDir(dir) {
}
const active = [];
const fail = [];
try {
// Let webpack pack builtin module together.
// eslint-disable-next-line import/no-unresolved
@@ -59,7 +61,7 @@ async function preload() {
for (const i of active) {
try {
if (i.os) {
if (!i.os.includes(os.platform())) throw new Error('Unsupported OS');
if (!i.os.includes(os.platform().toLowerCase())) throw new Error('Unsupported OS');
}
if (i.file) {
i.files = {};
@@ -87,6 +89,7 @@ async function handler() {
for (const i of active) {
if (i.handler && !i.fail) {
try {
console.log(`Handler init: ${i.id}`);
console.time(`Handler init: ${i.id}`);
const exports = {};
// eslint-disable-next-line no-unused-vars
@@ -136,6 +139,7 @@ async function model() {
for (const i of active) {
if (i.model && !i.fail) {
try {
console.log(`Model init: ${i.id}`);
console.time(`Model init: ${i.id}`);
const exports = {};
const module = { exports, file: i.files || {} };
@@ -155,6 +159,7 @@ async function lib() {
for (const i of active) {
if (i.lib && !i.fail) {
try {
console.log(`Lib init: ${i.id}`);
console.time(`Lib init: ${i.id}`);
const exports = {};
// eslint-disable-next-line no-unused-vars
@@ -184,44 +189,15 @@ async function service() {
i.fail = true;
fail.push(i.id);
console.error(`Service Load Fail: ${i.id}`);
console.error(e);
}
}
}
}
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);
const setup = require('./service/setup');
await setup.setup();
}
async function load() {
@@ -243,11 +219,12 @@ async function load() {
require('./utils');
require('./error');
require('./permission');
await Promise.all([locale(), template()]);
try {
require('./options');
} catch (e) {
await install();
return;
require('./options');
}
const bus = require('./service/bus');
await new Promise((resolve) => {
@@ -265,7 +242,7 @@ async function load() {
'template', 'validator', 'nav',
];
for (const i of builtinLib) require(`./lib/${i}`);
await Promise.all([lib(), locale(), template()]);
await lib();
require('./service/gridfs');
const server = require('./service/server');
await server.prepare();
@@ -281,7 +258,10 @@ async function load() {
}
const system = require('./model/system');
const dbVer = await system.get('db.ver');
if (dbVer !== 1) await installDb();
if (dbVer !== 1) {
const ins = require('./script/install');
await ins.run();
}
const builtinHandler = [
'home', 'problem', 'record', 'judge', 'user',
'contest', 'training', 'discussion', 'manage', 'import',
@@ -300,4 +280,4 @@ async function load() {
await server.start();
}
module.exports = { load, active };
module.exports = { load, active, fail };
+8 -1
View File
@@ -160,7 +160,13 @@ async function setTestdata(_id, readStream) {
return await edit(_id, { data: f.id }); // eslint-disable-line no-return-await
}
module.exports = {
async function getData(pid) {
const pdoc = await get(pid);
if (!pdoc.data) return null;
return gridfs.openDownloadStream(pdoc.data);
}
global.Hydro.model.problem = module.exports = {
add,
inc,
get,
@@ -175,4 +181,5 @@ module.exports = {
getMultiStatus,
setTestdata,
updateStatus,
getData,
};
+2 -2
View File
@@ -21,7 +21,7 @@ function del(_id) {
async function getFirst(query) {
const res = await coll.find(query).sort('_id', 1).limit(1).toArray();
if (res) {
if (res.length) {
await coll.deleteOne({ _id: res[0]._id });
return res[0];
}
@@ -35,6 +35,6 @@ async function consume(query, cb) {
}, 100);
}
module.exports = {
global.Hydro.model.task = module.exports = {
add, get, del, count, getFirst, consume,
};
+7 -46
View File
@@ -1,59 +1,20 @@
const fs = require('fs');
const os = require('os');
const path = require('path');
const { defaultsDeep } = require('lodash');
const { defaults } = require('lodash');
let options = {
db: {
name: 'hydro',
host: '127.0.0.1',
port: 27017,
username: '',
password: '',
},
template: {
path: path.join(process.cwd(), 'templates'),
},
listen: {
host: '127.0.0.1',
port: 8888,
domain: '',
https: false,
},
smtp: {
from: '',
host: '',
port: 465,
user: '',
pass: '',
secure: false,
},
session: {
keys: ['Hydro'],
secure: false,
domain: '127.0.0.1',
saved_expire_seconds: 3600 * 24,
unsaved_expire_seconds: 600,
registration_token_expire_seconds: 600,
},
constants: {
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,
},
name: 'hydro',
host: '127.0.0.1',
port: 27017,
username: '',
password: '',
};
let f = path.resolve(process.cwd(), 'config.json');
if (!fs.existsSync(f)) f = path.resolve(os.homedir(), '.config', 'hydro', 'config.json');
if (!fs.existsSync(f)) f = path.resolve('/config/config.json');
const t = JSON.parse(fs.readFileSync(f));
options = defaultsDeep(t, options);
options = defaults(t, options);
module.exports = options;
+68 -32
View File
@@ -1,46 +1,82 @@
const { defaults } = require('lodash');
const db = require('../service/db');
const builtin = require('../model/builtin');
const system = require('../model/system');
const pwhash = require('../lib/pwhash');
const { udoc } = require('../interface');
const collUser = db.collection('user');
const collRole = db.collection('role');
const collSystem = db.collection('system');
async function run() {
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),
]);
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,
'smtp.host': '',
'smtp.port': 465,
'smtp.from': '',
'smtp.user': '',
'smtp.pass': '',
'smtp.secure': false,
'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);
try {
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),
]);
} catch (e) {
// Ignore user already exist error
}
await collRole.deleteMany({ _id: { $in: builtin.BUILTIN_ROLES.map((role) => role._id) } });
await collRole.insertMany(builtin.BUILTIN_ROLES);
console.log('Installed');
}
module.exports = { run };
+3 -3
View File
@@ -3,15 +3,15 @@ const bus = require('./bus');
const options = require('../options');
let mongourl = 'mongodb://';
if (options.db.username) mongourl += `${options.db.username}:${options.db.password}@`;
mongourl += `${options.db.host}:${options.db.port}/${options.db.name}`;
if (options.username) mongourl += `${options.username}:${options.password}@`;
mongourl += `${options.host}:${options.port}/${options.name}`;
/**
* @type {import('mongodb').Db}
*/
let db = null;
Mongo.MongoClient.connect(mongourl, { useNewUrlParser: true, useUnifiedTopology: true })
.then((Database) => {
db = Database.db(options.db.name);
db = Database.db(options.name);
db.Db = Database;
bus.publish('system_database_connected', null);
});
+22 -19
View File
@@ -249,27 +249,30 @@ function Route(route, RouteHandler) {
const args = { ...ctx.params, ...ctx.query, ...ctx.request.body };
if (h.___prepare) await h.___prepare(args);
for (const l of check) {
if (args[l]) {
args[l] = new ObjectID(args[l]);
if (!args[l]) throw new ValidationError(l);
try {
for (const l of check) {
if (args[l]) {
args[l] = new ObjectID(args[l]);
if (!args[l]) throw new ValidationError(l);
}
}
if (args.content) validator.checkContent(args.content);
if (args.title) validator.checkContent(args.title);
if (args.uid) args.uid = parseInt(validator.checkUid(args.uid));
if (args.password) validator.checkPassword(args.password);
if (args.mail) validator.checkEmail(args.mail);
if (args.uname) validator.checkUname(args.uname);
if (args.page) args.page = parseInt(args.page);
if (args.duration) args.duration = parseFloat(args.duration);
if (args.pids) args.pids = args.pids.split(',').map((i) => i.trim());
if (args.role) validator.checkRole(args.role);
if (args.roles) {
for (const i of args.roles) validator.checkRole(i);
}
} catch (e) {
if (e instanceof ValidationError) throw e;
throw new ValidationError('Argument check failed');
}
if (args.content) validator.checkContent(args.content);
if (args.title) validator.checkContent(args.title);
if (args.uid) args.uid = parseInt(validator.checkUid(args.uid));
if (args.password) validator.checkPassword(args.password);
if (args.mail) validator.checkEmail(args.mail);
if (args.uname) validator.checkUname(args.uname);
if (args.page) args.page = parseInt(args.page);
if (args.duration) args.duration = parseFloat(args.duration);
if (args.pids) args.pids = args.pids.split(',').map((i) => i.trim());
if (args.role) validator.checkRole(args.role);
if (args.roles) {
for (const i of args.roles) validator.checkRole(i);
}
if (h.__prepare) await h.__prepare(args);
if (h._prepare) await h._prepare(args);
if (h.prepare) await h.prepare(args);
-20
View File
@@ -1,20 +0,0 @@
const Mongo = require('mongodb');
const options = require('./options');
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);
await db.dropDatabase();
console.log('Dropped');
process.exit(0);
}
run().catch((e) => {
console.error(e);
process.exit(1);
});