You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Hydro/hydro/handler/misc.ts

170 lines
5.5 KiB
TypeScript

/* eslint-disable camelcase */
import fs from 'fs';
import { ObjectID } from 'mongodb';
import { PRIV } from '../model/builtin';
import * as system from '../model/system';
import * as file from '../model/file';
import * as user from '../model/user';
import * as markdown from '../lib/markdown';
import * as db from '../service/db';
import {
Route, Handler, Types, param,
} from '../service/server';
import { BadRequestError } from '../error';
const coll = db.collection('status');
4 years ago
class FileDownloadHandler extends Handler {
@param('fileId', Types.ObjectID)
@param('secret', Types.String)
@param('name', Types.String, true)
async get(domainId: string, fileId: ObjectID, secret: string, name: string) {
4 years ago
if (name) name = Buffer.from(name, 'base64').toString();
this.response.attachment(name || fileId.toHexString());
this.response.body = await file.getWithSecret(fileId, secret);
4 years ago
}
}
class FileUploadHandler extends Handler {
async getQuota() {
let quota = await system.get('user.quota');
if (this.user.hasPriv(PRIV.PRIV_UNLIMITED_QUOTA)) {
quota = 2 ** 63 - 1;
}
return quota;
}
async get() {
this.response.template = 'fs_upload.html';
this.response.body = { fdoc: null, usage: this.user.usage, quota: await this.getQuota() };
}
@param('title', Types.String)
async post(domainId: string, title: string) {
if (!this.request.files.file) throw new BadRequestError();
const quota = await this.getQuota();
const lfdoc = await fs.promises.stat(this.request.files.file.path);
let ufid: ObjectID;
const udoc = await user.inc(this.user._id, 'usage', lfdoc.size);
try {
ufid = await file.add(this.request.files.file.path, title, this.user._id);
} catch (e) {
await user.inc(this.user._id, 'usage', -lfdoc.size);
throw e;
}
const fdoc = await file.getMeta(ufid);
this.response.template = 'fs_upload.html';
this.response.body = {
fdoc, ufid, usage: udoc.usage, quota,
};
}
}
class StatusHandler extends Handler {
async get() {
const stats = await coll.find().sort({ type: 1, updateAt: -1 }).toArray();
for (const i in stats) {
let desc = '';
const online = new Date(stats[i].updateAt).getTime() > new Date().getTime() - 300000;
if (!online) desc = 'Offline';
desc = desc || 'Online';
4 years ago
stats[i].isOnline = online;
stats[i].status = desc;
}
4 years ago
const path = [
4 years ago
['Hydro', 'homepage'],
['status', null],
4 years ago
];
this.response.body = { stats, path };
this.response.template = 'status.html';
}
}
class StatusUpdateHandler extends Handler {
async post(args) {
this.checkPriv(PRIV.PRIV_JUDGE);
4 years ago
args.type = 'judger';
return coll.updateOne(
{ mid: args.mid, type: 'judger' },
{ $set: args },
{ upsert: true },
);
}
}
class SwitchLanguageHandler extends Handler {
@param('lang', Types.String)
async get(domainId: string, lang: string) {
if (this.user.hasPriv(PRIV.PRIV_USER_PROFILE)) {
await user.setById(this.user._id, { viewLang: lang });
} else this.session.viewLang = lang;
this.back();
}
}
4 years ago
class MarkdownHandler extends Handler {
async post({ text, html = false, inline = false }) {
this.response.body = inline
? markdown.renderInline(text, html)
: markdown.render(text, html);
this.response.type = 'text/html';
4 years ago
}
}
class SockToken extends Handler {
async get() {
this.response.body = { token: this.UIContext.token };
}
}
class UiSettingsHandler extends Handler {
async get() {
const [
header_logo, header_logo_2x,
nav_logo_dark, nav_logo_light,
nav_logo_dark_2x, nav_logo_light_2x,
header_background, header_background_2x,
] = await system.getMany([
'ui.header_logo', 'ui.header_logo_2x',
'ui.nav_logo_dark', 'ui.nav_logo_light',
'ui.nav_logo_dark_2x', 'ui.nav_logo_light_2x',
'ui.header_background', 'ui.header_background2x',
]);
this.response.body = await this.renderHTML('extra.css', {
header_logo,
header_logo_2x,
nav_logo_dark,
nav_logo_light,
nav_logo_dark_2x,
nav_logo_light_2x,
header_background,
header_background_2x,
});
this.response.type = 'text/css';
this.ctx.set('nolog', '1');
}
}
export async function apply() {
Route('file_download', '/fs/:fileId/:secret', FileDownloadHandler);
Route('file_download_with_name', '/fs/:fileId/:name/:secret', FileDownloadHandler);
Route('file_upload', '/fs/upload', FileUploadHandler, PRIV.PRIV_CREATE_FILE);
Route('status', '/status', StatusHandler);
Route('status_update', '/status/update', StatusUpdateHandler);
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
4 years ago
Route('markdown', '/markdown', MarkdownHandler);
Route('token', '/token', SockToken);
Route('ui', '/extra.css', UiSettingsHandler);
}
4 years ago
apply.updateStatus = function updateStatus(args) {
args.type = 'judger';
return coll.updateOne(
{ mid: args.mid, type: 'judger' },
{ $set: args },
{ upsert: true },
);
4 years ago
};
4 years ago
global.Hydro.handler.misc = apply;