Display audit log in settings.
This commit is contained in:
parent
0aaa16e78f
commit
105492154e
7 changed files with 181 additions and 6 deletions
49
assets/less/mio/classes/settings/log.less
Normal file
49
assets/less/mio/classes/settings/log.less
Normal file
|
@ -0,0 +1,49 @@
|
|||
.settings__log {
|
||||
&__country {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
&__entry {
|
||||
display: flex;
|
||||
border: 1px solid #9475b2;
|
||||
justify-content: space-between;
|
||||
padding: 1px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
}
|
||||
|
||||
&__column {
|
||||
flex-grow: 1;
|
||||
margin-left: 5px;
|
||||
margin-right: 1px;
|
||||
|
||||
&--ip,
|
||||
&--date {
|
||||
flex-shrink: 0;
|
||||
|
||||
&:not(:last-child) {
|
||||
flex-grow: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&--action {
|
||||
flex-shrink: 1;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&--ip {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
&--date {
|
||||
min-width: 120px;
|
||||
}
|
||||
|
||||
&__name {
|
||||
font-weight: 700;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -69,6 +69,7 @@ body {
|
|||
@import "classes/settings/account";
|
||||
@import "classes/settings/images";
|
||||
@import "classes/settings/avatar";
|
||||
@import "classes/settings/log";
|
||||
@import "classes/settings/login-history";
|
||||
@import "classes/settings/sessions";
|
||||
|
||||
|
|
20
database/2018_07_23_131728_add_country_to_audit_log.php
Normal file
20
database/2018_07_23_131728_add_country_to_audit_log.php
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
namespace Misuzu\DatabaseMigrations\AddCountryToAuditLog;
|
||||
|
||||
use PDO;
|
||||
|
||||
function migrate_up(PDO $conn): void
|
||||
{
|
||||
$conn->exec('
|
||||
ALTER TABLE `msz_audit_log`
|
||||
ADD COLUMN `log_country` CHAR(2) NOT NULL DEFAULT \'XX\' AFTER `log_ip`;
|
||||
');
|
||||
}
|
||||
|
||||
function migrate_down(PDO $conn): void
|
||||
{
|
||||
$conn->exec('
|
||||
ALTER TABLE `msz_audit_log`
|
||||
DROP COLUMN `log_country`;
|
||||
');
|
||||
}
|
|
@ -28,6 +28,10 @@ $settingsModes = [
|
|||
'title' => 'Login History',
|
||||
'allow' => true,
|
||||
],
|
||||
'log' => [
|
||||
'title' => 'Account Log',
|
||||
'allow' => true,
|
||||
],
|
||||
];
|
||||
$settingsMode = $_GET['m'] ?? null;
|
||||
|
||||
|
@ -426,6 +430,36 @@ switch ($settingsMode) {
|
|||
'login_attempts_count' => $loginAttemptsCount,
|
||||
]);
|
||||
break;
|
||||
|
||||
case 'log':
|
||||
$auditLogCount = audit_log_count($app->getUserId());
|
||||
$auditLog = audit_log_list(
|
||||
$queryOffset,
|
||||
max(20, $queryTake),
|
||||
$app->getUserId()
|
||||
);
|
||||
|
||||
$tpl->vars([
|
||||
'audit_logs' => $auditLog,
|
||||
'audit_log_count' => $auditLogCount,
|
||||
'audit_log_take' => $queryTake,
|
||||
'audit_log_offset' => $queryOffset,
|
||||
'log_strings' => [
|
||||
'PERSONAL_EMAIL_CHANGE' => 'Changed e-mail address to %s.',
|
||||
'PERSONAL_PASSWORD_CHANGE' => 'Changed account password.',
|
||||
'PERSONAL_SESSION_DESTROY' => 'Ended session #%d.',
|
||||
'PASSWORD_RESET' => 'Successfully used the password reset form to change password.',
|
||||
'CHANGELOG_ENTRY_CREATE' => 'Created a new changelog entry #%d.',
|
||||
'CHANGELOG_ENTRY_EDIT' => 'Edited changelog entry #%d.',
|
||||
'CHANGELOG_TAG_ADD' => 'Added tag #%2$d to changelog entry #%1$d.',
|
||||
'CHANGELOG_TAG_REMOVE' => 'Removed tag #%2$d from changelog entry #%1$d.',
|
||||
'CHANGELOG_TAG_CREATE' => 'Created new changelog tag #%d.',
|
||||
'CHANGELOG_TAG_EDIT' => 'Edited changelog tag #%d.',
|
||||
'CHANGELOG_ACTION_CREATE' => 'Created new changelog action #%d.',
|
||||
'CHANGELOG_ACTION_EDITl' => 'Edited changelog action #%d.',
|
||||
],
|
||||
]);
|
||||
break;
|
||||
}
|
||||
|
||||
echo $tpl->render("settings.{$settingsMode}");
|
||||
|
|
|
@ -296,6 +296,7 @@ class Application extends ApplicationBase
|
|||
$this->templatingInstance->addFilter('parse_line');
|
||||
$this->templatingInstance->addFilter('parse_text');
|
||||
$this->templatingInstance->addFilter('asset_url');
|
||||
$this->templatingInstance->addFilter('vsprintf');
|
||||
|
||||
$this->templatingInstance->addFunction('git_commit_hash');
|
||||
$this->templatingInstance->addFunction('git_branch');
|
||||
|
|
|
@ -11,24 +11,40 @@ function audit_log(
|
|||
$ipAddress = $ipAddress ?? IPAddress::remote();
|
||||
|
||||
for ($i = 0; $i < count($params); $i++) {
|
||||
if (preg_match('#(-?[0-9]+)#', $params[$i])) {
|
||||
if (preg_match('#^(-?[0-9]+)$#', $params[$i])) {
|
||||
$params[$i] = (int)$params[$i];
|
||||
}
|
||||
}
|
||||
|
||||
$addLog = Database::prepare('
|
||||
INSERT INTO `msz_audit_log`
|
||||
(`log_action`, `user_id`, `log_params`, `log_ip`)
|
||||
(`log_action`, `user_id`, `log_params`, `log_ip`, `log_country`)
|
||||
VALUES
|
||||
(:action, :user, :params, :log_ip)
|
||||
(:action, :user, :params, :ip, :country)
|
||||
');
|
||||
$addLog->bindValue('action', $action);
|
||||
$addLog->bindValue('user', $userId < 1 ? null : $userId);
|
||||
$addLog->bindValue('params', json_encode($params));
|
||||
$addLog->bindValue('log_ip', $ipAddress->getRaw());
|
||||
$addLog->bindValue('ip', $ipAddress->getRaw());
|
||||
$addLog->bindValue('country', $ipAddress->getCountryCode());
|
||||
$addLog->execute();
|
||||
}
|
||||
|
||||
function audit_log_count($userId = 0): int
|
||||
{
|
||||
$getCount = Database::prepare(sprintf('
|
||||
SELECT COUNT(`log_id`)
|
||||
FROM `msz_audit_log`
|
||||
WHERE %s
|
||||
', $userId < 1 ? '1' : '`user_id` = :user_id'));
|
||||
|
||||
if ($userId >= 1) {
|
||||
$getCount->bindValue('user_id', $userId);
|
||||
}
|
||||
|
||||
return $getCount->execute() ? (int)$getCount->fetchColumn() : 0;
|
||||
}
|
||||
|
||||
function audit_log_list(int $offset, int $take, int $userId = 0): array
|
||||
{
|
||||
$offset = max(0, $offset);
|
||||
|
@ -36,7 +52,7 @@ function audit_log_list(int $offset, int $take, int $userId = 0): array
|
|||
|
||||
$getLogs = Database::prepare(sprintf('
|
||||
SELECT
|
||||
l.`log_id`, l.`log_action`, l.`log_params`, l.`log_created`,
|
||||
l.`log_id`, l.`log_action`, l.`log_params`, l.`log_created`, l.`log_country`,
|
||||
u.`user_id`, u.`username`,
|
||||
INET6_NTOA(l.`log_ip`) as `log_ip`,
|
||||
COALESCE(u.`user_colour`, r.`role_colour`) as `user_colour`
|
||||
|
@ -51,7 +67,7 @@ function audit_log_list(int $offset, int $take, int $userId = 0): array
|
|||
', $userId < 1 ? '1' : 'l.`user_id` = :user_id'));
|
||||
|
||||
if ($userId >= 1) {
|
||||
$getLogs->bindValue('user_id');
|
||||
$getLogs->bindValue('user_id', $userId);
|
||||
}
|
||||
|
||||
$getLogs->bindValue('offset', $offset);
|
||||
|
|
54
views/mio/settings/log.twig
Normal file
54
views/mio/settings/log.twig
Normal file
|
@ -0,0 +1,54 @@
|
|||
{% extends '@mio/settings/master.twig' %}
|
||||
{% from '@mio/macros.twig' import pagination %}
|
||||
|
||||
{% set alpagination = pagination(audit_log_count, audit_log_take, audit_log_offset, '?m=log', 'settings__') %}
|
||||
|
||||
{% block settings_content %}
|
||||
<div class="settings__description">
|
||||
<p>This is a log of all "important" actions that have been done using your account for your review. If you notice anything strange, please alert the staff.</p>
|
||||
</div>
|
||||
|
||||
<div class="settings__log">
|
||||
{{ alpagination }}
|
||||
|
||||
{% for log in audit_logs %}
|
||||
<div class="settings__log__entry" id="log-{{ log.log_id }}">
|
||||
<div class="settings__log__column settings__login-history__column--ip">
|
||||
<div class="settings__log__column__name">
|
||||
IP
|
||||
</div>
|
||||
<div class="settings__log__column__value">
|
||||
{{ log.log_ip }}
|
||||
{% if log.log_country|default('XX') != 'XX' %}
|
||||
<img class="settings__log__country" src="https://static.flash.moe/flags/fff/{{ log.log_country|lower }}.png" alt="{{ log.log_country }}" title="{{ log.log_country|country_name }}">
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings__log__column settings__log__column--date" title="{{ log.log_created|date('r') }}">
|
||||
<div class="settings__log__column__name">
|
||||
Date
|
||||
</div>
|
||||
<time class="settings__log__column__value" datetime="{{ log.log_created|date('c') }}">
|
||||
{{ log.log_created|time_diff }}
|
||||
</time>
|
||||
</div>
|
||||
|
||||
<div class="settings__log__column settings__log__column--action">
|
||||
<div class="settings__log__column__name">
|
||||
Action
|
||||
</div>
|
||||
<div class="settings__log__column__value">
|
||||
{% if log.log_action in log_strings|keys %}
|
||||
{{ log_strings[log.log_action]|vsprintf(log.log_params|json_decode) }}
|
||||
{% else %}
|
||||
{{ log.log_action }}({{ log.log_params }})
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{{ alpagination }}
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in a new issue