core: problem.del, ignore upgrade on fresh install

This commit is contained in:
undefined committed 2021-01-12 23:24:54 +08:00
1 parent 1543a374e3
commit 1d3bdacde9
12 files changed
+66 -119

No files matched your search

+1
View File
@@ -1,3 +1,4 @@
__id: en
__langname: English __langname: English
Can be Extended For: Extension Can be Extended For: Extension
contest_create: Contest Create contest_create: Contest Create
+1
View File
@@ -1,3 +1,4 @@
__id: ko
__langname: 한국어 __langname: 한국어
'"{data}" copied to clipboard!': “{data}”복사 완료 '"{data}" copied to clipboard!': “{data}”복사 완료
'{} is a moderator of this domain.': '{}가 그룹의 관리자입니다.' '{} is a moderator of this domain.': '{}가 그룹의 관리자입니다.'
+1
View File
@@ -1,3 +1,4 @@
__id: zh
__langname: 简体中文 __langname: 简体中文
'"{data}" copied to clipboard!': “{data}”已复制到剪贴板! '"{data}" copied to clipboard!': “{data}”已复制到剪贴板!
'{} is a moderator of this domain.': '{}是这个域的管理者之一。' '{} is a moderator of this domain.': '{}是这个域的管理者之一。'
+1
View File
@@ -1,3 +1,4 @@
__id: zh_TW
__langname: 正體中文 __langname: 正體中文
'{0} comments': '{0} 條評論' '{0} comments': '{0} 條評論'
'{0} discussions': '{0} 條討論' '{0} discussions': '{0} 條討論'
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "hydrooj", "name": "hydrooj",
"version": "2.15.17", "version": "2.15.18",
"bin": "bin/hydrooj.js", "bin": "bin/hydrooj.js",
"main": "dist/loader.js", "main": "dist/loader.js",
"typings": "dist/loader.d.ts", "typings": "dist/loader.d.ts",
+5
View File
@@ -69,9 +69,14 @@ export async function load(call: Entry) {
for (const i of builtinModel) require(`../model/${i}`); for (const i of builtinModel) require(`../model/${i}`);
const scripts = require('../upgrade'); const scripts = require('../upgrade');
let dbVer = (await modelSystem.get('db.ver')) ?? 0; let dbVer = (await modelSystem.get('db.ver')) ?? 0;
const isFresh = !dbVer;
const expected = scripts.length; const expected = scripts.length;
while (dbVer < expected) { while (dbVer < expected) {
logger.info('Upgrading database: from %d to %d', dbVer, expected); logger.info('Upgrading database: from %d to %d', dbVer, expected);
if (isFresh) {
const func = scripts[dbVer].toString();
if (func.includes('_FRESH_INSTALL_IGNORE')) continue;
}
const result = await scripts[dbVer](); const result = await scripts[dbVer]();
if (!result) break; if (!result) break;
dbVer++; dbVer++;
+1
View File
@@ -329,6 +329,7 @@ export interface DomainDoc extends Dictionary<any> {
bulletin: string, bulletin: string,
pidCounter: number, pidCounter: number,
join?: any, join?: any,
hostname?: string,
} }
// Message // Message
+2 -6
View File
@@ -46,12 +46,8 @@ String.prototype.translate = function translate(...languages: string[]) {
languages.push(global.Hydro.model.system.get('server.language')); languages.push(global.Hydro.model.system.get('server.language'));
for (const language of languages) { for (const language of languages) {
if (!language) continue; if (!language) continue;
if (locales[language]) { const curr = (locales[language] || {})[this] || (locales[language.split('_')[0]] || {})[this];
if (locales[language][this] !== undefined) return locales[language][this]; if (curr) return curr;
}
if (locales[language.split('_')[0]]) {
if (locales[language.split('_')[0]][this] !== undefined) return locales[language.split('_')[0]][this];
}
} }
return this; return this;
}; };
+9 -5
View File
@@ -137,6 +137,14 @@ export function count(domainId: string, query: FilterQuery<Pdoc>) {
return document.count(domainId, document.TYPE_PROBLEM, query); return document.count(domainId, document.TYPE_PROBLEM, query);
} }
export function del(domainId: string, docId: number) {
return Promise.all([
document.deleteOne(domainId, document.TYPE_PROBLEM, docId),
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM, { docId }),
bus.parallel('problem/delete', domainId, docId),
]);
}
export async function addTestdata(domainId: string, pid: number, name: string, f: Readable | Buffer | string) { export async function addTestdata(domainId: string, pid: number, name: string, f: Readable | Buffer | string) {
await storage.put(`problem/${domainId}/${pid}/testdata/${name}`, f); await storage.put(`problem/${domainId}/${pid}/testdata/${name}`, f);
const meta = await storage.getMeta(`problem/${domainId}/${pid}/testdata/${name}`); const meta = await storage.getMeta(`problem/${domainId}/${pid}/testdata/${name}`);
@@ -208,11 +216,6 @@ export function setStar(domainId: string, pid: number, uid: number, star: boolea
return document.setStatus(domainId, document.TYPE_PROBLEM, pid, uid, { star }); return document.setStatus(domainId, document.TYPE_PROBLEM, pid, uid, { star });
} }
bus.on('problem/delete', (domainId, docId) => Promise.all([
document.deleteOne(domainId, document.TYPE_PROBLEM, docId),
document.deleteMultiStatus(domainId, document.TYPE_PROBLEM, { docId }),
]));
global.Hydro.model.problem = { global.Hydro.model.problem = {
Pdoc, Pdoc,
@@ -227,6 +230,7 @@ global.Hydro.model.problem = {
add, add,
inc, inc,
get, get,
del,
edit, edit,
count, count,
push, push,
+37 -106
View File
@@ -194,69 +194,17 @@ function _descriptor(v: ParamOption) {
}; };
} }
export function get( type DescriptorBuilder =
name: string, type: Type, validate: null, convert: Converter ((name: string, type: Type) => MethodDecorator)
): MethodDecorator; & ((name: string, type: Type, validate: null, convert: Converter) => MethodDecorator)
export function get( & ((name: string, type: Type, validate?: Validator, convert?: Converter) => MethodDecorator)
name: string, type: Type, validate?: Validator, convert?: Converter, & ((name: string, type?: Type, isOptional?: boolean, validate?: Validator, convert?: Converter) => MethodDecorator)
): MethodDecorator; & ((name: string, ...args: Array<Type | boolean | Validator | Converter>) => MethodDecorator)
export function get(
name: string, type?: Type, isOptional?: boolean, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function get(
name: string, ...args: Array<Type | boolean | Validator | Converter>
): MethodDecorator;
export function get(name: string, ...args: any): MethodDecorator {
return _descriptor(_buildParam(name, 'get', ...args));
}
export function post( export const get: DescriptorBuilder = (name, ...args) => _descriptor(_buildParam(name, 'get', ...args));
name: string, type: Type, validate: null, convert: Converter export const post: DescriptorBuilder = (name, ...args) => _descriptor(_buildParam(name, 'post', ...args));
): MethodDecorator; export const route: DescriptorBuilder = (name, ...args) => _descriptor(_buildParam(name, 'route', ...args));
export function post( export const param: DescriptorBuilder = (name, ...args) => _descriptor(_buildParam(name, 'all', ...args));
name: string, type?: Type, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function post(
name: string, type?: Type, isOptional?: boolean, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function post(
name: string, ...args: Array<Type | boolean | Converter | Validator>
): MethodDecorator;
export function post(name: string, ...args: any): MethodDecorator {
return _descriptor(_buildParam(name, 'post', ...args));
}
export function route(
name: string, type: Type, validate: null, convert: Converter
): MethodDecorator;
export function route(
name: string, type?: Type, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function route(
name: string, type?: Type, isOptional?: boolean, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function route(
name: string, ...args: Array<Type | boolean | Converter | Validator>
): MethodDecorator;
export function route(name: string, ...args: any): MethodDecorator {
return _descriptor(_buildParam(name, 'route', ...args));
}
export function param(
name: string, type: Type, validate: null, convert: Converter
): MethodDecorator;
export function param(
name: string, type?: Type, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function param(
name: string, type?: Type, isOptional?: boolean, validate?: Validator, convert?: Converter,
): MethodDecorator;
export function param(
name: string, ...args: Array<Type | boolean | Converter | Validator>
): MethodDecorator;
export function param(name: string, ...args: any): MethodDecorator {
return _descriptor(_buildParam(name, 'all', ...args));
}
export function requireCsrfToken(target: any, funcName: string, obj: any) { export function requireCsrfToken(target: any, funcName: string, obj: any) {
const originalMethod = obj.value; const originalMethod = obj.value;
@@ -323,6 +271,24 @@ export class HandlerCommon {
if (!this.user.hasPriv(...args)) throw new PrivilegeError(...args); if (!this.user.hasPriv(...args)) throw new PrivilegeError(...args);
} }
async renderHTML(name: string, context: any): Promise<string> {
const UserContext: any = {
...this.user,
gravatar: misc.gravatar(this.user.gravatar || '', 128),
perm: this.user.perm.toString(),
};
UserContext.viewLang = this.translate('__id');
if (!global.Hydro.lib.template) return JSON.stringify(context);
const res = await global.Hydro.lib.template.render(name, {
handler: this,
UserContext,
url: this.url.bind(this),
_: this.translate.bind(this),
...context,
});
return res;
}
url(name: string, kwargs: any = {}) { url(name: string, kwargs: any = {}) {
let res = '#'; let res = '#';
const args: any = {}; const args: any = {};
@@ -395,9 +361,7 @@ export class Handler extends HandlerCommon {
ip: ctx.request.ip, ip: ctx.request.ip,
headers: ctx.request.headers, headers: ctx.request.headers,
cookies: ctx.cookies, cookies: ctx.cookies,
// @ts-ignore
body: ctx.request.body, body: ctx.request.body,
// @ts-ignore
files: ctx.request.files, files: ctx.request.files,
query: ctx.query, query: ctx.query,
path: ctx.path, path: ctx.path,
@@ -428,6 +392,8 @@ export class Handler extends HandlerCommon {
url_prefix: '/', url_prefix: '/',
}; };
this.session = {}; this.session = {};
const xff = system.get('server.xff');
if (xff) this.request.ip = this.request.headers[xff.toLowerCase()] || this.request.ip;
} }
@lrucache @lrucache
@@ -436,23 +402,6 @@ export class Handler extends HandlerCommon {
return hash('csrf_token', id); return hash('csrf_token', id);
} }
async renderHTML(name: string, context: any): Promise<string> {
const UserContext = {
...this.user,
gravatar: misc.gravatar(this.user.gravatar || '', 128),
perm: this.user.perm.toString(),
};
if (!global.Hydro.lib.template) return JSON.stringify(context);
const res = await global.Hydro.lib.template.render(name, {
handler: this,
UserContext,
url: this.url.bind(this),
_: this.translate.bind(this),
...context,
});
return res;
}
async render(name: string, context: any) { async render(name: string, context: any) {
this.response.body = await this.renderHTML(name, context); this.response.body = await this.renderHTML(name, context);
this.response.type = 'text/html'; this.response.type = 'text/html';
@@ -482,10 +431,9 @@ export class Handler extends HandlerCommon {
} }
async init({ domainId }) { async init({ domainId }) {
const xff = system.get('server.xff') as string;
if (xff) this.request.ip = this.request.headers[xff.toLowerCase()];
[this.domain] = await Promise.all([ [this.domain] = await Promise.all([
domain.get(domainId), domain.get(domainId),
this.limitRate('global', 10, 100),
this.getSession(), this.getSession(),
this.getBdoc(), this.getBdoc(),
]); ]);
@@ -733,15 +681,6 @@ export class ConnectionHandler extends HandlerCommon {
for (const i in p) this.request.params[p[i][0]] = decodeURIComponent(p[i][1]); for (const i in p) this.request.params[p[i][0]] = decodeURIComponent(p[i][1]);
} }
async renderHTML(name: string, context: any): Promise<string> {
const res = await global.Hydro.lib.template.render(name, Object.assign(context, {
handler: this,
url: this.url.bind(this),
_: this.translate.bind(this),
}));
return res;
}
send(data: any) { send(data: any) {
this.conn.write(JSON.stringify(data)); this.conn.write(JSON.stringify(data));
} }
@@ -782,10 +721,13 @@ export class ConnectionHandler extends HandlerCommon {
domain.get(domainId), domain.get(domainId),
this.getSession(cookie), this.getSession(cookie),
]); ]);
const bdoc = await blacklist.get(this.request.ip); const [bdoc, udoc] = await Promise.all([
blacklist.get(this.request.ip),
user.getById(domainId, this.session.uid, this.session.scope),
]);
if (bdoc) throw new BlacklistedError(this.request.ip); if (bdoc) throw new BlacklistedError(this.request.ip);
this.user = await user.getById(domainId, this.session.uid, this.session.scope); if (!udoc) throw new UserNotFoundError(this.session.uid);
if (!this.user) throw new UserNotFoundError(this.session.uid); this.user = udoc;
if (this.user._id === 0 && this.session.viewLang) this.user.viewLang = this.session.viewLang; if (this.user._id === 0 && this.session.viewLang) this.user.viewLang = this.session.viewLang;
} }
} }
@@ -844,17 +786,6 @@ export function start() {
logger.debug(`${ctx.request.method} ${ctx.request.path} ${ctx.response.status} ${endTime - startTime}ms ${ctx.response.length}`); logger.debug(`${ctx.request.method} ${ctx.request.path} ${ctx.response.status} ${endTime - startTime}ms ${ctx.response.length}`);
}); });
} }
app.use(async (ctx, next) => {
const xff = system.get('server.xff');
const ip = xff ? ctx.request.headers[xff] : ctx.request.ip;
try {
await opcount.inc('global', ip, 10, 100);
} catch (e) {
ctx.status = 429;
return null;
}
return await next();
});
app.use(router.routes()).use(router.allowedMethods()); app.use(router.routes()).use(router.allowedMethods());
server.listen(argv.port || port); server.listen(argv.port || port);
logger.success('Server listening at: %d', argv.port || port); logger.success('Server listening at: %d', argv.port || port);
+1 -1
View File
@@ -13,7 +13,7 @@ declare module 'terminal-kit/Terminal' {
} }
} }
const useTerminal = cluster.isMaster && process.stdout.isTTY && !argv.legacy; const useTerminal = cluster.isMaster && process.stdout.isTTY && !argv.legacy && !argv._.length;
export namespace Progress { export namespace Progress {
export class Progress { export class Progress {
+6
View File
@@ -1,3 +1,4 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable no-await-in-loop */ /* eslint-disable no-await-in-loop */
import { ObjectID, Collection } from 'mongodb'; import { ObjectID, Collection } from 'mongodb';
import AdmZip from 'adm-zip'; import AdmZip from 'adm-zip';
@@ -28,6 +29,7 @@ const scripts: UpgradeScript[] = [
}, },
// Add history column to ddoc,drdoc,psdoc // Add history column to ddoc,drdoc,psdoc
async function _1_2() { async function _1_2() {
const _FRESH_INSTALL_IGNORE = 1;
const domains = await domain.getMulti().project({ _id: 1 }).toArray(); const domains = await domain.getMulti().project({ _id: 1 }).toArray();
for (const d of domains) { for (const d of domains) {
const bulk = document.coll.initializeUnorderedBulkOp(); const bulk = document.coll.initializeUnorderedBulkOp();
@@ -46,10 +48,12 @@ const scripts: UpgradeScript[] = [
return true; return true;
}, },
async function _2_3() { async function _2_3() {
const _FRESH_INSTALL_IGNORE = 1;
await db.collection('document').updateMany({ pid: /^\d+$/i }, { $unset: { pid: '' } }); await db.collection('document').updateMany({ pid: /^\d+$/i }, { $unset: { pid: '' } });
return true; return true;
}, },
async function _3_4() { async function _3_4() {
const _FRESH_INSTALL_IGNORE = 1;
if (storage.error) { if (storage.error) {
logger.error('Cannot upgrade. Please change storage config.'); logger.error('Cannot upgrade. Please change storage config.');
return false; return false;
@@ -133,6 +137,7 @@ const scripts: UpgradeScript[] = [
return true; return true;
}, },
async function _4_5() { async function _4_5() {
const _FRESH_INSTALL_IGNORE = 1;
const domains = await domain.getMulti().project({ _id: 1 }).toArray(); const domains = await domain.getMulti().project({ _id: 1 }).toArray();
for (const d of domains) { for (const d of domains) {
const bulk = document.coll.initializeUnorderedBulkOp(); const bulk = document.coll.initializeUnorderedBulkOp();
@@ -147,6 +152,7 @@ const scripts: UpgradeScript[] = [
}, },
async function _5_6() { async function _5_6() {
// Issue #58 // Issue #58
const _FRESH_INSTALL_IGNORE = 1;
await domain.edit('system', { owner: 1 }); await domain.edit('system', { owner: 1 });
}, },
]; ];