mirror of
https://gitcode.com/gh_mirrors/hy/Hydro.git
synced 2026-10-17 17:36:08 +08:00
core: oplog: better logging
This commit is contained in:
1 parent
92c1a41585
commit
ead0d54a55
8 files changed
+74
-60
No files matched your search
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "hydrooj",
|
||||
"version": "3.2.27",
|
||||
"version": "3.2.28",
|
||||
"bin": "bin/hydrooj.js",
|
||||
"main": "src/loader",
|
||||
"module": "src/loader",
|
||||
|
||||
@@ -100,10 +100,10 @@ class BlogEditHandler extends BlogHandler {
|
||||
@param('content', Types.Content)
|
||||
async postUpdate(domainId: string, did: ObjectID, title: string, content: string) {
|
||||
if (!this.user.own(this.ddoc)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||
await blog.edit(did, title, content);
|
||||
await oplog.add({
|
||||
...this.ddoc, operator: this.user._id, type: 'edit',
|
||||
});
|
||||
await Promise.all([
|
||||
blog.edit(did, title, content),
|
||||
oplog.log(this, 'blog.edit', this.ddoc),
|
||||
]);
|
||||
this.response.body = { did };
|
||||
this.response.redirect = this.url('blog_detail', { uid: this.user._id, did });
|
||||
}
|
||||
@@ -111,10 +111,10 @@ class BlogEditHandler extends BlogHandler {
|
||||
@param('did', Types.ObjectID)
|
||||
async postDelete(domainId: string, did: ObjectID) {
|
||||
if (!this.user.own(this.ddoc)) this.checkPriv(PRIV.PRIV_EDIT_SYSTEM);
|
||||
await blog.del(did);
|
||||
await oplog.add({
|
||||
...this.ddoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
|
||||
});
|
||||
await Promise.all([
|
||||
blog.del(did),
|
||||
oplog.log(this, 'blog.delete', this.ddoc),
|
||||
]);
|
||||
this.response.redirect = this.url('blog_main', { uid: this.ddoc.owner });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,10 +251,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
async postEditReply(domainId: string, drid: ObjectID, content: string) {
|
||||
this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
if (!this.user.own(this.drdoc)) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
await discussion.editReply(domainId, drid, content);
|
||||
await oplog.add({
|
||||
...this.drdoc, operator: this.user._id, operateIp: this.request.ip, type: 'edit',
|
||||
});
|
||||
await Promise.all([
|
||||
discussion.editReply(domainId, drid, content),
|
||||
oplog.log(this, 'discussion.reply.edit', this.drdoc),
|
||||
]);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@@ -266,10 +266,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
|
||||
} else this.checkPerm(PERM.PERM_DELETE_DISCUSSION_SELF);
|
||||
}
|
||||
await discussion.delReply(domainId, drid);
|
||||
await oplog.add({
|
||||
...this.drdoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
|
||||
});
|
||||
await Promise.all([
|
||||
discussion.delReply(domainId, drid),
|
||||
oplog.log(this, 'discussion.reply.delete', this.drdoc),
|
||||
]);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@@ -279,11 +279,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
async postEditTailReply(domainId: string, drid: ObjectID, drrid: ObjectID, content: string) {
|
||||
this.checkPerm(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
if (!this.user.own(this.drrdoc)) throw new PermissionError(PERM.PERM_EDIT_DISCUSSION_REPLY_SELF);
|
||||
await discussion.editTailReply(domainId, drid, drrid, content);
|
||||
// TODO: history?
|
||||
await oplog.add({
|
||||
...this.drrdoc, operator: this.user._id, operateIp: this.request.ip, type: 'edit',
|
||||
});
|
||||
await Promise.all([
|
||||
discussion.editTailReply(domainId, drid, drrid, content),
|
||||
oplog.log(this, 'discussion.tailReply.edit', this.drrdoc),
|
||||
]);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@@ -291,10 +290,10 @@ class DiscussionDetailHandler extends DiscussionHandler {
|
||||
@param('drrid', Types.ObjectID)
|
||||
async postDeleteTailReply(domainId: string, drid: ObjectID, drrid: ObjectID) {
|
||||
if (!this.user.own(this.drrdoc)) this.checkPerm(PERM.PERM_DELETE_DISCUSSION_REPLY);
|
||||
await discussion.delTailReply(domainId, drid, drrid);
|
||||
await oplog.add({
|
||||
...this.drrdoc, operator: this.user._id, operateIp: this.request.ip, type: 'delete',
|
||||
});
|
||||
await Promise.all([
|
||||
discussion.delTailReply(domainId, drid, drrid),
|
||||
oplog.log(this, 'discussion.tailReply.delete', this.drrdoc),
|
||||
]);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@@ -346,10 +345,10 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
else this.checkPerm(PERM.PERM_EDIT_DISCUSSION_SELF);
|
||||
if (!this.user.hasPerm(PERM.PERM_HIGHLIGHT_DISCUSSION)) highlight = this.ddoc.highlight;
|
||||
if (!this.user.hasPerm(PERM.PERM_PIN_DISCUSSION)) pin = this.ddoc.pin;
|
||||
await discussion.edit(domainId, did, title, content, highlight, pin);
|
||||
await oplog.add({
|
||||
...this.ddoc, operator: this.user._id, type: 'edit',
|
||||
});
|
||||
await Promise.all([
|
||||
discussion.edit(domainId, did, title, content, highlight, pin),
|
||||
oplog.log(this, 'discussion.edit', this.ddoc),
|
||||
]);
|
||||
this.response.body = { did };
|
||||
this.response.redirect = this.url('discussion_detail', { did });
|
||||
}
|
||||
@@ -358,10 +357,10 @@ class DiscussionEditHandler extends DiscussionHandler {
|
||||
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',
|
||||
});
|
||||
await Promise.all([
|
||||
oplog.log(this, 'discussion.delete', this.ddoc),
|
||||
discussion.del(domainId, did),
|
||||
]);
|
||||
this.response.body = { type: this.ddoc.parentType, parent: this.ddoc.parentId };
|
||||
this.response.redirect = this.url('discussion_node', {
|
||||
type: discussion.typeDisplay[this.ddoc.parentType],
|
||||
|
||||
@@ -11,6 +11,7 @@ import paginate from '../lib/paginate';
|
||||
import { PERM, PERMS_BY_FAMILY, PRIV } from '../model/builtin';
|
||||
import * as discussion from '../model/discussion';
|
||||
import domain from '../model/domain';
|
||||
import * as oplog from '../model/oplog';
|
||||
import { DOMAIN_SETTINGS, DOMAIN_SETTINGS_BY_KEY } from '../model/setting';
|
||||
import * as system from '../model/system';
|
||||
import user from '../model/user';
|
||||
@@ -114,14 +115,20 @@ class DomainUserHandler extends ManageHandler {
|
||||
@post('uid', Types.Int)
|
||||
@post('role', Types.Name)
|
||||
async postSetUser(domainId: string, uid: number, role: string) {
|
||||
await domain.setUserRole(domainId, uid, role);
|
||||
await Promise.all([
|
||||
domain.setUserRole(domainId, uid, role),
|
||||
oplog.log(this, 'domain.setRole', { uid, role }),
|
||||
]);
|
||||
this.back();
|
||||
}
|
||||
|
||||
@param('uid', Types.NumericArray)
|
||||
@param('role', Types.Name)
|
||||
async postSetUsers(domainId: string, uid: number[], role: string) {
|
||||
await domain.setUserRole(domainId, uid, role);
|
||||
await Promise.all([
|
||||
domain.setUserRole(domainId, uid, role),
|
||||
oplog.log(this, 'domain.setRole', { uid, role }),
|
||||
]);
|
||||
this.back();
|
||||
}
|
||||
}
|
||||
@@ -242,7 +249,10 @@ class DomainJoinHandler extends Handler {
|
||||
throw new InvalidJoinInvitationCodeError(this.domain._id);
|
||||
}
|
||||
}
|
||||
await domain.setUserRole(this.domain._id, this.user._id, this.joinSettings.role);
|
||||
await Promise.all([
|
||||
domain.setUserRole(this.domain._id, this.user._id, this.joinSettings.role),
|
||||
oplog.log(this, 'domain.join', {}),
|
||||
]);
|
||||
this.response.redirect = this.url('homepage', { query: { notification: 'Successfully joined domain.' } });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,14 +91,8 @@ export class FSDownloadHandler extends Handler {
|
||||
this.response.addHeader('Cache-Control', 'public');
|
||||
const target = `user/${uid}/${filename}`;
|
||||
const file = await storage.getMeta(target);
|
||||
await oplog.add({
|
||||
type: 'download',
|
||||
time: new Date(),
|
||||
uid: this.user._id,
|
||||
ip: this.request.ip,
|
||||
fileType: 'user',
|
||||
await oplog.log(this, 'download.file.user', {
|
||||
target,
|
||||
referer: this.request.referer,
|
||||
size: file?.size || 0,
|
||||
});
|
||||
if (!file) {
|
||||
|
||||
@@ -514,14 +514,8 @@ export class ProblemFilesHandler extends ProblemDetailHandler {
|
||||
?.filter((i) => files.has(i.name))
|
||||
?.map((i) => i.size),
|
||||
) || 0;
|
||||
await oplog.add({
|
||||
type: 'bulkDownload',
|
||||
time: new Date(),
|
||||
uid: this.user._id,
|
||||
ip: this.request.ip,
|
||||
fileType: 'problem',
|
||||
await oplog.log(this, 'download.problem.bulk', {
|
||||
target: Array.from(files).map((file) => `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${file}`),
|
||||
referer: this.request.referer,
|
||||
size,
|
||||
});
|
||||
for (const file of files) {
|
||||
@@ -618,14 +612,8 @@ export class ProblemFileDownloadHandler extends ProblemDetailHandler {
|
||||
}
|
||||
const target = `problem/${this.pdoc.domainId}/${this.pdoc.docId}/${type}/${filename}`;
|
||||
const file = await storage.getMeta(target);
|
||||
await oplog.add({
|
||||
type: 'download',
|
||||
time: new Date(),
|
||||
uid: this.user._id,
|
||||
ip: this.request.ip,
|
||||
fileType: 'problem',
|
||||
await oplog.log(this, 'download.problem.single', {
|
||||
target,
|
||||
referer: this.request.referer,
|
||||
size: file?.size || 0,
|
||||
});
|
||||
if (!file) {
|
||||
|
||||
@@ -14,6 +14,7 @@ import BlackListModel from '../model/blacklist';
|
||||
import { PERM, PRIV, STATUS } from '../model/builtin';
|
||||
import domain from '../model/domain';
|
||||
import oauth from '../model/oauth';
|
||||
import * as oplog from '../model/oplog';
|
||||
import problem, { ProblemDoc } from '../model/problem';
|
||||
import * as system from '../model/system';
|
||||
import task from '../model/task';
|
||||
@@ -118,7 +119,10 @@ class UserLoginHandler extends Handler {
|
||||
let udoc = await user.getByEmail(domainId, uname);
|
||||
if (!udoc) udoc = await user.getByUname(domainId, uname);
|
||||
if (!udoc) throw new UserNotFoundError(uname);
|
||||
await this.limitRate('user_login', 60, 5);
|
||||
await Promise.all([
|
||||
this.limitRate('user_login', 60, 5),
|
||||
oplog.log(this, 'user.login', { redirect }),
|
||||
]);
|
||||
if (udoc._tfa && !verifyToken(udoc._tfa, tfa)) throw new InvalidTokenError('2FA token invalid.');
|
||||
udoc.checkPassword(password);
|
||||
await user.setById(udoc._id, { loginat: new Date(), loginip: this.request.ip });
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ObjectID } from 'mongodb';
|
||||
import { OplogDoc } from '../interface';
|
||||
import db from '../service/db';
|
||||
import type { Handler } from '../service/server';
|
||||
|
||||
export const coll = db.collection('oplog');
|
||||
|
||||
@@ -14,8 +15,26 @@ export async function add(data: Partial<OplogDoc> & { type: string }): Promise<O
|
||||
return res.insertedId;
|
||||
}
|
||||
|
||||
export async function log<T extends Handler>(handler: T, type: string, data: any) {
|
||||
const res = await coll.insertOne({
|
||||
...data,
|
||||
_id: new ObjectID(),
|
||||
type,
|
||||
time: new Date(),
|
||||
domainId: handler.domainId,
|
||||
ua: handler.request.headers?.['user-agent'],
|
||||
referer: handler.request.headers?.referer,
|
||||
args: handler.args,
|
||||
operator: handler.user?.id,
|
||||
operateIp: handler.request.ip,
|
||||
});
|
||||
return res.insertedId;
|
||||
}
|
||||
|
||||
export async function get(id: ObjectID): Promise<OplogDoc | null> {
|
||||
return await coll.findOne({ _id: id });
|
||||
}
|
||||
|
||||
global.Hydro.model.oplog = { coll, add, get };
|
||||
global.Hydro.model.oplog = {
|
||||
coll, add, get, log,
|
||||
};
|
||||
Reference in new issue
Block a user