core: blog (draft)

This commit is contained in:
undefined committed 2021-12-18 23:03:09 +08:00
1 parent d40f56e676
commit e935558702
17 files changed
+440 -18

No files matched your search

+132
View File
@@ -0,0 +1,132 @@
import { ObjectID } from 'mongodb';
import { DiscussionNotFoundError } from '../error';
import { BlogDoc } from '../interface';
import paginate from '../lib/paginate';
import * as blog from '../model/blog';
import { PERM, PRIV } from '../model/builtin';
import * as discussion from '../model/discussion';
import * as oplog from '../model/oplog';
import user from '../model/user';
import {
Handler, param, Route, Types,
} from '../service/server';
class BlogHandler extends Handler {
ddoc?: BlogDoc;
@param('did', Types.ObjectID, true)
async _prepare(domainId: string, did: ObjectID) {
this.checkPerm(PERM.PERM_VIEW_DISCUSSION);
if (did) {
this.ddoc = await blog.get(did);
if (!this.ddoc) throw new DiscussionNotFoundError(domainId, did);
}
}
}
class BlogUserHandler extends BlogHandler {
@param('uid', Types.Int)
@param('page', Types.PositiveInt, true)
async get(domainId: string, uid: number, page = 1) {
const [ddocs, dpcount] = await paginate(
blog.getMulti({ owner: uid }),
page,
10,
);
const udoc = await user.getById(domainId, uid);
this.response.template = 'blog_main.html';
this.response.body = {
ddocs,
dpcount,
udoc,
page,
};
}
}
class BlogDetailHandler extends BlogHandler {
@param('did', Types.ObjectID)
async get(domainId: string, did: ObjectID) {
const dsdoc = this.user.hasPriv(PRIV.PRIV_USER_PROFILE)
? await blog.getStatus(did, this.user._id)
: null;
const udoc = await user.getById(domainId, this.ddoc.owner);
if (!dsdoc?.view) {
await Promise.all([
blog.inc(did, 'views', 1),
blog.setStatus(did, this.user._id, { view: true }),
]);
}
this.response.template = 'blog_detail.html';
this.response.body = {
ddoc: this.ddoc, dsdoc, udoc,
};
}
async post() {
this.checkPriv(PRIV.PRIV_USER_PROFILE);
}
@param('did', Types.ObjectID)
async postStar(domainId: string, did: ObjectID) {
await blog.setStar(did, this.user._id, true);
this.back({ star: true });
}
@param('did', Types.ObjectID)
async postUnstar(domainId: string, did: ObjectID) {
await blog.setStar(did, this.user._id, false);
this.back({ star: false });
}
}
class BlogEditHandler extends BlogHandler {
async get() {
this.response.template = 'blog_edit.html';
this.response.body = { ddoc: this.ddoc };
}
@param('title', Types.Title)
@param('content', Types.Content)
async postCreate(domainId: string, title: string, content: string) {
this.checkPerm(PERM.PERM_CREATE_DISCUSSION);
await this.limitRate('add_blog', 3600, 60);
const did = await blog.add(this.user._id, title, content, this.request.ip);
this.response.body = { did };
this.response.redirect = this.url('blog_detail', { uid: this.user._id, did });
}
@param('did', Types.ObjectID)
@param('title', Types.Title)
@param('content', Types.Content)
async postUpdate(domainId: string, did: ObjectID, title: string, content: string) {
if (!this.user.own(this.ddoc)) this.checkPerm(PERM.PERM_EDIT_DISCUSSION);
else this.checkPerm(PERM.PERM_EDIT_DISCUSSION_SELF);
await blog.edit(did, title, content);
await oplog.add({
...this.ddoc, operator: this.user._id, type: 'edit',
});
this.response.body = { did };
this.response.redirect = this.url('blog_detail', { uid: this.user._id, did });
}
@param('did', Types.ObjectID)
async postDelete(domainId: string, did: ObjectID) {
if (!this.user.own(this.ddoc)) this.checkPerm(PERM.PERM_DELETE_DISCUSSION);
else this.checkPerm(PERM.PERM_DELETE_DISCUSSION_SELF);
await discussion.del(domainId, did);
await oplog.add({
...this.ddoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
});
this.response.redirect = this.url('blog_main', { uid: this.ddoc.owner });
}
}
export async function apply() {
Route('blog_main', '/blog/:uid', BlogUserHandler);
Route('blog_create', '/blog/:uid/create', BlogEditHandler);
Route('blog_detail', '/blog/:uid/:did', BlogDetailHandler);
Route('blog_edit', '/blog/:uid/:did/edit', BlogEditHandler);
}
global.Hydro.handler.blog = apply;
+1 -1
View File
@@ -206,7 +206,7 @@ class HomeworkScoreboardDownloadHandler extends Handler {
csv: (rows) => `\uFEFF${rows.map((c) => (c.map((i) => i.value).join(','))).join('\n')}`,
html: (rows) => this.renderHTML('contest_scoreboard_download_html.html', { rows }),
};
if (!getContent[ext]) throw new ValidationError('ext');
if (!getContent[ext]) throw new ValidationError('ext', null, 'Unknown file extension');
const [tdoc, rows] = await contest.getScoreboard.call(this, domainId, tid, true, 0);
this.binary(await getContent[ext](rows), `${tdoc.title}.${ext}`);
}
+7
View File
@@ -66,6 +66,13 @@ export class FilesHandler extends Handler {
this.back();
}
@post('from', Types.String)
@post('to', Types.String)
async postRename(domainId: string, from: string, to: string) {
await storage.rename(`user/${this.user._id}/${from}`, `user/${this.user._id}/${to}`);
this.back();
}
@post('files', Types.Array)
async postDeleteFiles(domainId: string, files: string[]) {
await Promise.all([
+1 -1
View File
@@ -189,7 +189,7 @@ class TrainingCreateHandler extends Handler {
if (pin) this.checkPerm(PERM.PERM_PIN_TRAINING);
const dag = await _parseDagJson(domainId, _dag);
const pids = training.getPids(dag);
assert(pids.length, new ValidationError('dag'));
assert(pids.length, new ValidationError('dag', null, 'Please specify at least one problem'));
const pdocs = await problem.getMulti(domainId, { docId: { $in: pids } }).sort('_id', 1).toArray();
for (const pdoc of pdocs) {
if (pdoc.hidden) this.checkPerm(PERM.PERM_VIEW_PROBLEM_HIDDEN);