mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-20 01:38:19 +08:00
优化rating计算速度
This commit is contained in:
1 parent
45f1184d68
commit
55912b087d
22 files changed
+200
-69
No files matched your search
@@ -28,6 +28,10 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: full.js
|
name: full.js
|
||||||
path: .build/full.js
|
path: .build/full.js
|
||||||
|
- uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: install.js
|
||||||
|
path: .build/install.js
|
||||||
- uses: actions/upload-artifact@v1
|
- uses: actions/upload-artifact@v1
|
||||||
with:
|
with:
|
||||||
name: module
|
name: module
|
||||||
|
|||||||
@@ -282,7 +282,7 @@ class ContestCreateHandler extends ContestHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async post({
|
async post({
|
||||||
domainId, title, content, rule, beginAtDate, beginAtTime, duration, pids,
|
domainId, title, content, rule, beginAtDate, beginAtTime, duration, pids, rated = false,
|
||||||
}) {
|
}) {
|
||||||
let beginAt;
|
let beginAt;
|
||||||
try {
|
try {
|
||||||
@@ -294,7 +294,7 @@ class ContestCreateHandler extends ContestHandler {
|
|||||||
pids = await this.verifyProblems(domainId, pids);
|
pids = await this.verifyProblems(domainId, pids);
|
||||||
const tid = await contest.add(
|
const tid = await contest.add(
|
||||||
domainId, title, content,
|
domainId, title, content,
|
||||||
this.user._id, rule, beginAt, endAt, pids,
|
this.user._id, rule, beginAt, endAt, pids, rated,
|
||||||
);
|
);
|
||||||
this.response.body = { tid };
|
this.response.body = { tid };
|
||||||
this.response.redirect = `/c/${tid}`;
|
this.response.redirect = `/c/${tid}`;
|
||||||
|
|||||||
@@ -95,7 +95,12 @@ class DomainUserHandler extends ManageHandler {
|
|||||||
const uids = [];
|
const uids = [];
|
||||||
const rudocs = {};
|
const rudocs = {};
|
||||||
const [udocs, roles] = await Promise.all([
|
const [udocs, roles] = await Promise.all([
|
||||||
user.getInDomain(domainId),
|
user.getMultiInDomain(domainId, {
|
||||||
|
$and: [
|
||||||
|
{ role: { $ne: 'default' } },
|
||||||
|
{ role: { $ne: null } },
|
||||||
|
],
|
||||||
|
}).toArray(),
|
||||||
user.getRoles(domainId),
|
user.getRoles(domainId),
|
||||||
]);
|
]);
|
||||||
for (const role of roles) rudocs[role._id] = [];
|
for (const role of roles) rudocs[role._id] = [];
|
||||||
@@ -104,7 +109,7 @@ class DomainUserHandler extends ManageHandler {
|
|||||||
// TODO Improve here
|
// TODO Improve here
|
||||||
// eslint-disable-next-line no-await-in-loop
|
// eslint-disable-next-line no-await-in-loop
|
||||||
const ud = await user.getById(domainId, udoc.uid);
|
const ud = await user.getById(domainId, udoc.uid);
|
||||||
rudocs[udoc.role].push({ ...ud, role: udoc.role });
|
rudocs[ud.role].push(ud);
|
||||||
}
|
}
|
||||||
const rolesSelect = roles.map((role) => [role._id, role._id]);
|
const rolesSelect = roles.map((role) => [role._id, role._id]);
|
||||||
const udict = await user.getList(domainId, uids);
|
const udict = await user.getList(domainId, uids);
|
||||||
|
|||||||
@@ -197,7 +197,7 @@ class HomeworkCreateHandler extends HomeworkHandler {
|
|||||||
async post({
|
async post({
|
||||||
domainId, title, content, beginAtDate, beginAtTime,
|
domainId, title, content, beginAtDate, beginAtTime,
|
||||||
penaltySinceDate, penaltySinceTime, extensionDays,
|
penaltySinceDate, penaltySinceTime, extensionDays,
|
||||||
penaltyRules, pids,
|
penaltyRules, pids, rated = false,
|
||||||
}) {
|
}) {
|
||||||
let beginAt;
|
let beginAt;
|
||||||
let penaltySince;
|
let penaltySince;
|
||||||
@@ -216,7 +216,7 @@ class HomeworkCreateHandler extends HomeworkHandler {
|
|||||||
if (penaltySince > endAt) throw new ValidationError('extensionDays');
|
if (penaltySince > endAt) throw new ValidationError('extensionDays');
|
||||||
await this.verifyProblems(domainId, pids);
|
await this.verifyProblems(domainId, pids);
|
||||||
const tid = await contest.add(domainId, title, content, this.user._id,
|
const tid = await contest.add(domainId, title, content, this.user._id,
|
||||||
'homework', beginAt, endAt, pids, { penaltySince, penaltyRules }, document.TYPE_HOMEWORK);
|
'homework', beginAt, endAt, pids, rated, { penaltySince, penaltyRules }, document.TYPE_HOMEWORK);
|
||||||
this.response.body = { tid };
|
this.response.body = { tid };
|
||||||
this.response.redirect = `/homework/${tid}`;
|
this.response.redirect = `/homework/${tid}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const { PermissionError } = require('../error');
|
|||||||
class SystemHandler extends Handler {
|
class SystemHandler extends Handler {
|
||||||
async prepare() {
|
async prepare() {
|
||||||
if (!this.user.priv) throw new PermissionError('???');
|
if (!this.user.priv) throw new PermissionError('???');
|
||||||
this.body = {
|
this.response.body = {
|
||||||
path: [
|
path: [
|
||||||
['Hydro', '/'],
|
['Hydro', '/'],
|
||||||
['manage_main', '/manage'],
|
['manage_main', '/manage'],
|
||||||
@@ -58,7 +58,7 @@ class SystemScriptHandler extends SystemHandler {
|
|||||||
|
|
||||||
async post({ id, args }) {
|
async post({ id, args }) {
|
||||||
// TODO Do not use console.log
|
// TODO Do not use console.log
|
||||||
await global.Hydro.script[id].run(args, console.log);
|
await global.Hydro.script[id].run(JSON.parse(args), console.log);
|
||||||
this.back();
|
this.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@ class ProblemSubmitHandler extends ProblemDetailHandler {
|
|||||||
});
|
});
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
record.judge(domainId, rid),
|
record.judge(domainId, rid),
|
||||||
user.inc(this.user._id, 'nSubmit'),
|
user.incDomain(domainId, this.user._id, 'nSubmit'),
|
||||||
]);
|
]);
|
||||||
this.response.body = { rid };
|
this.response.body = { rid };
|
||||||
this.response.redirect = `/r/${rid}`;
|
this.response.redirect = `/r/${rid}`;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
const crypto = require('crypto');
|
||||||
|
/**
|
||||||
|
* @param {any} content
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
global.Hydro.lib.sha1 = module.exports = (content) => {
|
||||||
|
const hash = crypto.createHash('sha1');
|
||||||
|
hash.update(content);
|
||||||
|
return hash.digest('hex');
|
||||||
|
};
|
||||||
+2
-2
@@ -216,7 +216,7 @@ const builtinHandler = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
const builtinScript = [
|
const builtinScript = [
|
||||||
'install', 'uninstall', 'rating', 'recalcRating',
|
'install', 'uninstall', 'rating', 'recalcRating', 'register',
|
||||||
];
|
];
|
||||||
|
|
||||||
async function loadAsMaster() {
|
async function loadAsMaster() {
|
||||||
@@ -385,7 +385,7 @@ async function load() {
|
|||||||
cluster.on('online', (worker) => {
|
cluster.on('online', (worker) => {
|
||||||
console.log(`Worker ${worker.process.pid} is online`);
|
console.log(`Worker ${worker.process.pid} is online`);
|
||||||
});
|
});
|
||||||
for (let i = 0; i < numCPUs; i++) {
|
for (let i = 1; i < numCPUs; i++) {
|
||||||
cluster.fork();
|
cluster.fork();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -207,7 +207,8 @@ const RULES = {
|
|||||||
* @returns {ObjectID} tid
|
* @returns {ObjectID} tid
|
||||||
*/
|
*/
|
||||||
function add(domainId, title, content, owner, rule,
|
function add(domainId, title, content, owner, rule,
|
||||||
beginAt = new Date(), endAt = new Date(), pids = [], data = {}, type = document.TYPE_CONTEST) {
|
beginAt = new Date(), endAt = new Date(), pids = [], rated = false,
|
||||||
|
data = {}, type = document.TYPE_CONTEST) {
|
||||||
validator.checkTitle(title);
|
validator.checkTitle(title);
|
||||||
validator.checkContent(content);
|
validator.checkContent(content);
|
||||||
if (!this.RULES[rule]) throw new ValidationError('rule');
|
if (!this.RULES[rule]) throw new ValidationError('rule');
|
||||||
@@ -217,7 +218,7 @@ function add(domainId, title, content, owner, rule,
|
|||||||
});
|
});
|
||||||
this.RULES[rule].check(data);
|
this.RULES[rule].check(data);
|
||||||
return document.add(domainId, content, owner, type, null, null, null, {
|
return document.add(domainId, content, owner, type, null, null, null, {
|
||||||
...data, title, rule, beginAt, endAt, pids, attend: 0,
|
...data, title, rule, beginAt, endAt, pids, attend: 0, rated,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-8
@@ -29,7 +29,7 @@ class USER {
|
|||||||
this.nSubmit = dudoc.nSubmit || 0;
|
this.nSubmit = dudoc.nSubmit || 0;
|
||||||
this.rating = dudoc.rating || 1500;
|
this.rating = dudoc.rating || 1500;
|
||||||
this.perm = dudoc.perm;
|
this.perm = dudoc.perm;
|
||||||
this.role = dudoc.role;
|
this.role = dudoc.role || 'default';
|
||||||
}
|
}
|
||||||
|
|
||||||
hasPerm(p) {
|
hasPerm(p) {
|
||||||
@@ -39,7 +39,7 @@ class USER {
|
|||||||
checkPassword(password) {
|
checkPassword(password) {
|
||||||
const h = global.Hydro.lib[`hash.${this.hashType || 'hydro'}`];
|
const h = global.Hydro.lib[`hash.${this.hashType || 'hydro'}`];
|
||||||
if (!h) throw new Error('Unknown hash method');
|
if (!h) throw new Error('Unknown hash method');
|
||||||
return h.check(password, this.salt(), this.hash());
|
return h.check(password, this.salt(), this.hash(), this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +120,17 @@ async function inc(_id, field, n = 1) {
|
|||||||
return udoc;
|
return udoc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setInDomain(domainId, uid, params) {
|
||||||
|
return document.setStatus(domainId, document.TYPE_DOMAIN_USER, 0, uid, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function incDomain(domainId, uid, field, n = 1) {
|
||||||
|
const dudoc = await getInDomain(domainId, { _id: uid });
|
||||||
|
dudoc[field] = dudoc[field] + n || n;
|
||||||
|
await setInDomain(domainId, uid, { [field]: dudoc[field] });
|
||||||
|
return dudoc;
|
||||||
|
}
|
||||||
|
|
||||||
async function create({
|
async function create({
|
||||||
uid, mail, uname, password, regip = '127.0.0.1', priv = perm.PRIV_NONE,
|
uid, mail, uname, password, regip = '127.0.0.1', priv = perm.PRIV_NONE,
|
||||||
}) {
|
}) {
|
||||||
@@ -151,10 +162,6 @@ function getMulti(params) {
|
|||||||
return coll.find(params);
|
return coll.find(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setInDomain(domainId, uid, params) {
|
|
||||||
return document.setStatus(domainId, document.TYPE_DOMAIN_USER, 0, uid, params);
|
|
||||||
}
|
|
||||||
|
|
||||||
function setMultiInDomain(domainId, query, params) {
|
function setMultiInDomain(domainId, query, params) {
|
||||||
return document.setMultiStatus(domainId, document.TYPE_DOMAIN_USER, query, params);
|
return document.setMultiStatus(domainId, document.TYPE_DOMAIN_USER, query, params);
|
||||||
}
|
}
|
||||||
@@ -193,8 +200,8 @@ function getRole(domainId, name) {
|
|||||||
return document.get(domainId, document.TYPE_DOMAIN_USER, name);
|
return document.get(domainId, document.TYPE_DOMAIN_USER, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMultiInDomain(domainId) {
|
function getMultiInDomain(domainId, query) {
|
||||||
return document.getMultiStatus(domainId, document.TYPE_DOMAIN_USER);
|
return document.getMultiStatus(domainId, document.TYPE_DOMAIN_USER, query);
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRole(domainId, name, permission) {
|
function addRole(domainId, name, permission) {
|
||||||
@@ -223,6 +230,7 @@ global.Hydro.model.user = module.exports = {
|
|||||||
getByUname,
|
getByUname,
|
||||||
getMulti,
|
getMulti,
|
||||||
inc,
|
inc,
|
||||||
|
incDomain,
|
||||||
setById,
|
setById,
|
||||||
setEmail,
|
setEmail,
|
||||||
setPassword,
|
setPassword,
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ async function run({ username, password } = {}) {
|
|||||||
}
|
}
|
||||||
await Promise.all(tasks);
|
await Promise.all(tasks);
|
||||||
tasks = [
|
tasks = [
|
||||||
allowFail(domain.add, 'system', 0),
|
domain.add('system', 0, 'Hydro').catch(() => domain.edit('system', { owner: 0, name: 'Hydro' })),
|
||||||
collUser.updateOne({ _id: 0 }, {
|
collUser.updateOne({ _id: 0 }, {
|
||||||
$set: defaults({
|
$set: defaults({
|
||||||
_id: 0,
|
_id: 0,
|
||||||
|
|||||||
@@ -14,28 +14,30 @@ async function run({ domainId, isSub = false }, report) {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const contests = await contest.getMulti(domainId).sort('endAt', -1).toArray();
|
const contests = await contest.getMulti(domainId, { rated: true }).sort('endAt', -1).toArray();
|
||||||
await report({ total: contests.length });
|
await report({ total: contests.length });
|
||||||
await user.setMultiInDomain(domainId, {}, { rating: 1500 });
|
const udict = {};
|
||||||
for (const i in contests) {
|
for (const i in contests) {
|
||||||
const tdoc = contests[i];
|
const tdoc = contests[i];
|
||||||
const tsdocs = await contest.getMultiStatus(domainId, { docId: tdoc.docId })
|
const tsdocs = await contest.getMultiStatus(domainId, { docId: tdoc.docId })
|
||||||
.sort(contest.RULES[tdoc.rule].statusSort).toArray();
|
.sort(contest.RULES[tdoc.rule].statusSort).toArray();
|
||||||
const udict = await user.getList(domainId, tsdocs.map((tsdoc) => tsdoc.uid));
|
|
||||||
const rankedTsdocs = contest.RULES[tdoc.rule].rank(tsdocs);
|
const rankedTsdocs = contest.RULES[tdoc.rule].rank(tsdocs);
|
||||||
const users = [];
|
const users = [];
|
||||||
for (const result of rankedTsdocs) {
|
for (const result of rankedTsdocs) {
|
||||||
users.push({ ...result[1], rank: result[0], old: udict[result[1].uid].rating || 1500 });
|
users.push({ ...result[1], rank: result[0], old: udict[result[1].uid] || 1500 });
|
||||||
}
|
}
|
||||||
const rated = rating(users);
|
const rated = rating(users);
|
||||||
const tasks = [];
|
|
||||||
for (const udoc of rated) {
|
for (const udoc of rated) {
|
||||||
tasks.push(user.setInDomain(domainId, udoc.uid, { rating: udoc.new }));
|
udict[udoc.uid] = udoc.new;
|
||||||
}
|
}
|
||||||
await Promise.all(tasks);
|
|
||||||
if (isSub) await report({ subProgress: (i + 1) / contests.length });
|
if (isSub) await report({ subProgress: (i + 1) / contests.length });
|
||||||
else await report({ current: parseInt(i) + 1 });
|
else await report({ current: parseInt(i) + 1 });
|
||||||
}
|
}
|
||||||
|
const tasks = [];
|
||||||
|
for (const uid in udict) {
|
||||||
|
tasks.push(user.setInDomain(domainId, uid, { rating: udict[uid] }));
|
||||||
|
}
|
||||||
|
await Promise.all(tasks);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const user = require('../model/user');
|
||||||
|
const system = require('../model/system');
|
||||||
|
|
||||||
|
async function run({
|
||||||
|
uname, password, mail, uid,
|
||||||
|
}) {
|
||||||
|
if (!uid) uid = await system.inc('user');
|
||||||
|
await user.create({
|
||||||
|
uid, uname, password, mail, regip: '127.0.0.1',
|
||||||
|
});
|
||||||
|
return uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
global.Hydro.script.register = module.exports = { run };
|
||||||
@@ -302,7 +302,7 @@ function Route(route, RouteHandler, permission = null) {
|
|||||||
const method = ctx.method.toLowerCase();
|
const method = ctx.method.toLowerCase();
|
||||||
// TODO(masnn) domainId
|
// TODO(masnn) domainId
|
||||||
const args = {
|
const args = {
|
||||||
...ctx.params, ...ctx.query, ...ctx.request.body, domainId: 'system',
|
domainId: 'system', ...ctx.params, ...ctx.query, ...ctx.request.body,
|
||||||
};
|
};
|
||||||
if (h.request.host !== await system.get('server.host')) {
|
if (h.request.host !== await system.get('server.host')) {
|
||||||
args.domainId = h.request.url.split('//')[1].split(`.${await system.get('server.host')}`)[0] || '';
|
args.domainId = h.request.url.split('//')[1].split(`.${await system.get('server.host')}`)[0] || '';
|
||||||
@@ -399,7 +399,7 @@ function Connection(prefix, RouteConnHandler) {
|
|||||||
sock.on('connection', async (conn) => {
|
sock.on('connection', async (conn) => {
|
||||||
const h = new RouteConnHandler(conn);
|
const h = new RouteConnHandler(conn);
|
||||||
try {
|
try {
|
||||||
const args = { ...h.request.params, domainId: 'system' };
|
const args = { domainId: 'system', ...h.request.params };
|
||||||
|
|
||||||
if (args.uid) args.uid = parseInt(validator.checkUid(args.uid));
|
if (args.uid) args.uid = parseInt(validator.checkUid(args.uid));
|
||||||
if (args.page) args.page = parseInt(args.page);
|
if (args.page) args.page = parseInt(args.page);
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
const { md5, sha1 } = global.Hydro.lib;
|
||||||
|
|
||||||
|
global.Hydro.lib['hash.vj2'] = module.exports = {
|
||||||
|
/**
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} salt
|
||||||
|
* @param {string} hash
|
||||||
|
*/
|
||||||
|
check(password, salt, hash, udoc) {
|
||||||
|
return hash === this.hash(password, salt, udoc);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* @param {string} password
|
||||||
|
* @param {string} salt
|
||||||
|
*/
|
||||||
|
hash(password, salt, udoc) {
|
||||||
|
const { uname, unameLower } = udoc;
|
||||||
|
const pmd5 = md5(password);
|
||||||
|
const mixedSha1 = sha1(md5(unameLower + pmd5) + salt + sha1(pmd5 + salt));
|
||||||
|
return `${Buffer.from(uname).toString('base64')}|${mixedSha1}`;
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -34,9 +34,7 @@ const tasks = {
|
|||||||
gender: doc.gender,
|
gender: doc.gender,
|
||||||
qq: doc.qq,
|
qq: doc.qq,
|
||||||
}),
|
}),
|
||||||
document: async (doc) => {
|
document: {
|
||||||
const res = {};
|
|
||||||
const mapper = {
|
|
||||||
_id: '_id',
|
_id: '_id',
|
||||||
doc_id: 'docId',
|
doc_id: 'docId',
|
||||||
doc_type: 'docType',
|
doc_type: 'docType',
|
||||||
@@ -107,23 +105,8 @@ const tasks = {
|
|||||||
return r;
|
return r;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
|
||||||
for (const key in doc) {
|
|
||||||
if (typeof mapper[key] === 'string') {
|
|
||||||
res[mapper[key]] = doc[key];
|
|
||||||
} else if (typeof mapper[key] === 'object') {
|
|
||||||
res[mapper[key].field] = mapper[key].processer(doc[key]);
|
|
||||||
} else if (mapper[key] === null) {
|
|
||||||
// Ignore this key
|
|
||||||
} else {
|
|
||||||
console.log('Unknown key:', key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
},
|
},
|
||||||
'document.status': async (doc) => {
|
'document.status': {
|
||||||
const res = {};
|
|
||||||
const mapper = {
|
|
||||||
_id: '_id',
|
_id: '_id',
|
||||||
doc_id: 'docId',
|
doc_id: 'docId',
|
||||||
doc_type: 'docType',
|
doc_type: 'docType',
|
||||||
@@ -168,17 +151,6 @@ const tasks = {
|
|||||||
field: 'donePids',
|
field: 'donePids',
|
||||||
processer: (pids) => pids.map((id) => pid(id)),
|
processer: (pids) => pids.map((id) => pid(id)),
|
||||||
},
|
},
|
||||||
};
|
|
||||||
for (const key in doc) {
|
|
||||||
if (typeof mapper[key] === 'string') {
|
|
||||||
res[mapper[key]] = doc[key];
|
|
||||||
} else if (typeof mapper[key] === 'object') {
|
|
||||||
res[mapper[key].field] = mapper[key].processer(doc[key]);
|
|
||||||
} else {
|
|
||||||
console.log('Unknown key:', key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
},
|
},
|
||||||
record: async (doc) => {
|
record: async (doc) => {
|
||||||
const testCases = [];
|
const testCases = [];
|
||||||
@@ -211,6 +183,16 @@ const tasks = {
|
|||||||
testCases,
|
testCases,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
domain: {
|
||||||
|
_id: '_id',
|
||||||
|
doc_id: 'docId',
|
||||||
|
doc_type: 'docType',
|
||||||
|
owner_uid: 'owner',
|
||||||
|
name: 'name',
|
||||||
|
gravatar: 'gravatar',
|
||||||
|
bulletin: 'bulletin',
|
||||||
|
pid_counter: 'pidCounter',
|
||||||
|
},
|
||||||
'fs.files': async (doc) => doc,
|
'fs.files': async (doc) => doc,
|
||||||
'fs.chunks': async (doc) => doc,
|
'fs.chunks': async (doc) => doc,
|
||||||
file: async (doc) => ({
|
file: async (doc) => ({
|
||||||
@@ -227,6 +209,7 @@ const cursor = {
|
|||||||
document: (s) => s.collection('document').find({ doc_type: { $ne: 20 } }),
|
document: (s) => s.collection('document').find({ doc_type: { $ne: 20 } }),
|
||||||
'document.status': (s) => s.collection('document.status').find(),
|
'document.status': (s) => s.collection('document.status').find(),
|
||||||
record: (s) => s.collection('record').find(),
|
record: (s) => s.collection('record').find(),
|
||||||
|
domain: (s) => s.collection('domain').find(),
|
||||||
'fs.files': (s) => s.collection('fs.files').find(),
|
'fs.files': (s) => s.collection('fs.files').find(),
|
||||||
'fs.chunks': (s) => s.collection('fs.chunks').find(),
|
'fs.chunks': (s) => s.collection('fs.chunks').find(),
|
||||||
file: (s) => s.collection('fs.files').find(),
|
file: (s) => s.collection('fs.files').find(),
|
||||||
@@ -255,6 +238,59 @@ async function discussionNode(src, report) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function domainUser(src, report) {
|
||||||
|
const count = await src.collection('domain.user').find().count();
|
||||||
|
await report({ progress: 1, message: `domain.user: ${count}` });
|
||||||
|
const total = Math.floor(count / 50);
|
||||||
|
for (let i = 0; i <= total; i++) {
|
||||||
|
const docs = await src.collection('domain.user')
|
||||||
|
.find().skip(i * 50).limit(50)
|
||||||
|
.toArray();
|
||||||
|
for (const doc of docs) {
|
||||||
|
const mapper = {
|
||||||
|
_id: '_id',
|
||||||
|
uid: 'uid',
|
||||||
|
join_at: 'joinAt',
|
||||||
|
role: 'role',
|
||||||
|
num_liked: 'nLike',
|
||||||
|
num_submit: 'nSubmit',
|
||||||
|
num_accept: 'nAccept',
|
||||||
|
num_problems: 'nProblems',
|
||||||
|
domain_id: 'domainId',
|
||||||
|
level: 'level',
|
||||||
|
};
|
||||||
|
const d = {};
|
||||||
|
for (const key in doc) {
|
||||||
|
if (typeof mapper[key] === 'string') {
|
||||||
|
d[mapper[key]] = doc[key];
|
||||||
|
} else if (typeof mapper[key] === 'object') {
|
||||||
|
d[mapper[key].field] = mapper[key].processer(doc[key]);
|
||||||
|
} else if (mapper[key] === null) {
|
||||||
|
// Ignore this key
|
||||||
|
} else {
|
||||||
|
console.log('Unknown key:', key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const docWithoutId = {};
|
||||||
|
for (const key in d) {
|
||||||
|
if (key !== '_id') {
|
||||||
|
docWithoutId[key] = d[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
d.push(dst.collection('document').updateOne(
|
||||||
|
{ _id: d._id },
|
||||||
|
{
|
||||||
|
$set: {
|
||||||
|
...docWithoutId, docType: 0, docId: 1, role: docWithoutId.role || 'default',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ upsert: true },
|
||||||
|
));
|
||||||
|
}
|
||||||
|
await report({ progress: Math.round(100 * ((i + 1) / (total + 1))) });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function fixPid(report) {
|
async function fixPid(report) {
|
||||||
const count = await dst.collection('document').find({ docType: 10 }).count();
|
const count = await dst.collection('document').find({ docType: 10 }).count();
|
||||||
await report({ progress: 1, message: `Fix pid: ${count}` });
|
await report({ progress: 1, message: `Fix pid: ${count}` });
|
||||||
@@ -298,8 +334,25 @@ async function task(name, src, report) {
|
|||||||
const docs = await cursor[name](src).skip(i * 50).limit(50).toArray();
|
const docs = await cursor[name](src).skip(i * 50).limit(50).toArray();
|
||||||
const res = [];
|
const res = [];
|
||||||
for (const doc of docs) {
|
for (const doc of docs) {
|
||||||
const d = await tasks[name](doc);
|
let d = {};
|
||||||
|
if (typeof tasks[name].call === 'function') {
|
||||||
|
d = await tasks[name](doc);
|
||||||
|
} else {
|
||||||
|
const mapper = tasks[name];
|
||||||
|
for (const key in doc) {
|
||||||
|
if (typeof mapper[key] === 'string') {
|
||||||
|
res[mapper[key]] = doc[key];
|
||||||
|
} else if (typeof mapper[key] === 'object') {
|
||||||
|
res[mapper[key].field] = mapper[key].processer(doc[key]);
|
||||||
|
} else if (mapper[key] === null) {
|
||||||
|
// Ignore this key
|
||||||
|
} else {
|
||||||
|
console.log('Unknown key:', key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (d) {
|
if (d) {
|
||||||
|
if (d.rule) d.rated = true; // Hack contest rated field
|
||||||
const docWithoutId = {};
|
const docWithoutId = {};
|
||||||
const docWithoutDid = {};
|
const docWithoutDid = {};
|
||||||
for (const key in d) {
|
for (const key in d) {
|
||||||
@@ -380,6 +433,7 @@ async function migrateVijos({
|
|||||||
for (const i of d) await task(i, src, report);
|
for (const i of d) await task(i, src, report);
|
||||||
await fixPid(report);
|
await fixPid(report);
|
||||||
await discussionNode(src, report);
|
await discussionNode(src, report);
|
||||||
|
await domainUser(src, report);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hydro",
|
"name": "hydro",
|
||||||
"version": "2.0.0",
|
"version": "2.0.1",
|
||||||
"main": "hydro/development.js",
|
"main": "hydro/development.js",
|
||||||
"repository": "https://github.com/hydro-dev/Hydro.git",
|
"repository": "https://github.com/hydro-dev/Hydro.git",
|
||||||
"author": "masnn",
|
"author": "masnn",
|
||||||
@@ -35,8 +35,10 @@
|
|||||||
"build": "node build/index.js",
|
"build": "node build/index.js",
|
||||||
"build:development": "node build/development.js",
|
"build:development": "node build/development.js",
|
||||||
"build:production": "node build/production.js",
|
"build:production": "node build/production.js",
|
||||||
|
"build:all": "cd ui && yarn && yarn build:production && cd .. && yarn && yarn build:production",
|
||||||
|
"start": "node hydro/loader.js",
|
||||||
"pack": "pkg .",
|
"pack": "pkg .",
|
||||||
"lint": "eslint build hydro module --fix"
|
"lint": "eslint build hydro module tool --fix"
|
||||||
},
|
},
|
||||||
"pkg": {
|
"pkg": {
|
||||||
"scripts": [
|
"scripts": [
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
row:false
|
row:false
|
||||||
}) }}
|
}) }}
|
||||||
{{ form.form_text({
|
{{ form.form_text({
|
||||||
columns:8,
|
columns:4,
|
||||||
label:'Title',
|
label:'Title',
|
||||||
name:'title',
|
name:'title',
|
||||||
placeholder:_('title'),
|
placeholder:_('title'),
|
||||||
@@ -23,6 +23,14 @@
|
|||||||
autofocus:true,
|
autofocus:true,
|
||||||
row:false
|
row:false
|
||||||
}) }}
|
}) }}
|
||||||
|
{{ form.form_checkbox({
|
||||||
|
columns:4,
|
||||||
|
label:'Rated',
|
||||||
|
name:'rated',
|
||||||
|
placeholder:_('rated'),
|
||||||
|
value:true,
|
||||||
|
row:false
|
||||||
|
}) }}
|
||||||
</div><div class="row">
|
</div><div class="row">
|
||||||
{{ form.form_text({
|
{{ form.form_text({
|
||||||
columns:4,
|
columns:4,
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th class="col--description">{{ _('Permissions') }}</th>
|
<th class="col--description">{{ _('Permissions') }}</th>
|
||||||
{% for role in roles %}
|
{% for role in roles %}
|
||||||
<th class="col--p"><span data-tooltip="{{ role }}">{{ role._id }}</span></th>
|
<th class="col--p"><span data-tooltip="{{ role._id }}">{{ role._id }}</span></th>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.page--manage_permission
|
.page--domain_permission
|
||||||
.col--p
|
.col--p
|
||||||
width: 80px
|
width: 80px
|
||||||
text-align: center
|
text-align: center
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.page--manage_role
|
.page--domain_role
|
||||||
.col--checkbox
|
.col--checkbox
|
||||||
width: 60px
|
width: 60px
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.page--manage_user
|
.page--domain_user
|
||||||
.col--checkbox
|
.col--checkbox
|
||||||
width: 60px
|
width: 60px
|
||||||
|
|
||||||
|
|||||||
Reference in new issue
Block a user