|
|
|
/* 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 db from '../service/db';
|
|
|
|
import {
|
|
|
|
Route, Handler, Types, param,
|
|
|
|
} from '../service/server';
|
|
|
|
import { BadRequestError } from '../error';
|
|
|
|
|
|
|
|
const coll = db.collection('status');
|
|
|
|
|
|
|
|
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) {
|
|
|
|
if (name) name = Buffer.from(name, 'base64').toString();
|
|
|
|
const doc = await file.getWithSecret(fileId, secret);
|
|
|
|
this.response.attachment(name || fileId.toHexString(), doc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class FileUploadHandler extends Handler {
|
|
|
|
async getQuota() {
|
|
|
|
let quota = 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)
|
|
|
|
@param('redirect', Types.String, true)
|
|
|
|
async post(domainId: string, title: string, redirect?: 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';
|
|
|
|
if (redirect) {
|
|
|
|
this.response.redirect = redirect.includes('?')
|
|
|
|
? `${redirect}&ufid=${ufid}`
|
|
|
|
: `${redirect}?ufid=${ufid}`;
|
|
|
|
}
|
|
|
|
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';
|
|
|
|
stats[i].isOnline = online;
|
|
|
|
stats[i].status = desc;
|
|
|
|
}
|
|
|
|
const path = [
|
|
|
|
['Hydro', 'homepage'],
|
|
|
|
['status', null],
|
|
|
|
];
|
|
|
|
this.response.body = { stats, path };
|
|
|
|
this.response.template = 'status.html';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class StatusUpdateHandler extends Handler {
|
|
|
|
async post(args) {
|
|
|
|
this.checkPriv(PRIV.PRIV_JUDGE);
|
|
|
|
args.type = 'judger';
|
|
|
|
return coll.updateOne(
|
|
|
|
{ mid: args.mid, type: 'judger' },
|
|
|
|
{ $set: args },
|
|
|
|
{ upsert: true },
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class CheckInHandler extends Handler {
|
|
|
|
async prepare() {
|
|
|
|
const { checkincnt, lastcheckin } = this.user;
|
|
|
|
const today = new Date();
|
|
|
|
today.setHours(0);
|
|
|
|
today.setMinutes(0);
|
|
|
|
today.setSeconds(0);
|
|
|
|
today.setMilliseconds(0);
|
|
|
|
if (lastcheckin === today.getTime()) throw new BadRequestError("You've already checked in today!");
|
|
|
|
this.user.checkincnt++;
|
|
|
|
this.user.lastcheckin = today.getTime();
|
|
|
|
await Promise.all([
|
|
|
|
user.setById(this.user._id, { checkincnt, lastcheckin }),
|
|
|
|
user.inc(this.user._id, 'rpdelta', Math.round(Math.sqrt(checkincnt))),
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
|
|
|
|
async get() {
|
|
|
|
this.response.redirect = '/';
|
|
|
|
}
|
|
|
|
|
|
|
|
async post() {
|
|
|
|
this.response.body = {
|
|
|
|
cnt: this.user.checkincnt,
|
|
|
|
last: this.user.lastcheckin,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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('check_in', '/checkin', CheckInHandler, PRIV.PRIV_USER_PROFILE);
|
|
|
|
Route('switch_language', '/language/:lang', SwitchLanguageHandler);
|
|
|
|
}
|
|
|
|
|
|
|
|
global.Hydro.handler.misc = apply;
|