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