From fab54f37c8ec98da78ba1d14cc441d0beca94816 Mon Sep 17 00:00:00 2001 From: n1rwana Date: Wed, 2 Aug 2023 16:56:07 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=9B=D0=BE=D0=B3=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DBEntity.updated.php | 135 +++++++++++++++ Web/Models/Entities/Comment.php | 5 + Web/Models/Entities/IP.php | 6 +- Web/Models/Entities/Log.php | 190 +++++++++++++++++++++ Web/Models/Entities/User.php | 4 +- Web/Models/Repositories/CurrentUser.php | 31 ++++ Web/Models/Repositories/Logs.php | 94 ++++++++++ Web/Presenters/AdminPresenter.php | 45 ++++- Web/Presenters/AuthPresenter.php | 6 +- Web/Presenters/OpenVKPresenter.php | 5 +- Web/Presenters/templates/Admin/@layout.xml | 3 + Web/Presenters/templates/Admin/Logs.xml | 99 +++++++++++ Web/Presenters/templates/Group/View.xml | 1 + Web/Presenters/templates/User/View.xml | 3 + Web/di.yml | 1 + Web/routes.yml | 2 + install/00038-logs.sql | 19 +++ openvk-example.yml | 1 + 18 files changed, 639 insertions(+), 11 deletions(-) create mode 100644 DBEntity.updated.php create mode 100644 Web/Models/Entities/Log.php create mode 100644 Web/Models/Repositories/CurrentUser.php create mode 100644 Web/Models/Repositories/Logs.php create mode 100644 Web/Presenters/templates/Admin/Logs.xml create mode 100644 install/00038-logs.sql diff --git a/DBEntity.updated.php b/DBEntity.updated.php new file mode 100644 index 00000000..52e17043 --- /dev/null +++ b/DBEntity.updated.php @@ -0,0 +1,135 @@ +getTable()->getName(); + if($_table !== $this->tableName) + throw new ISE("Invalid data supplied for model: table $_table is not compatible with table" . $this->tableName); + + $this->record = $row; + } + + function __call(string $fName, array $args) + { + if(substr($fName, 0, 3) === "set") { + $field = mb_strtolower(substr($fName, 3)); + $this->stateChanges($field, $args[0]); + } else { + throw new \Error("Call to undefined method " . get_class($this) . "::$fName"); + } + } + + private function getTable(): Selection + { + return DatabaseConnection::i()->getContext()->table($this->tableName); + } + + protected function getRecord(): ?ActiveRow + { + return $this->record; + } + + protected function stateChanges(string $column, $value): void + { + if(!is_null($this->record)) + $t = $this->record->{$column}; #Test if column exists + + $this->changes[$column] = $value; + } + + function getId() + { + return $this->getRecord()->id; + } + + function isDeleted(): bool + { + return (bool) $this->getRecord()->deleted; + } + + function unwrap(): object + { + return (object) $this->getRecord()->toArray(); + } + + function delete(bool $softly = true): void + { + $user = CurrentUser::i()->getUser(); + $user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId(); + + if(is_null($this->record)) + throw new ISE("Can't delete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?"); + + (new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 2, $this->record->toArray(), $this->changes); + + if($softly) { + $this->record = $this->getTable()->where("id", $this->record->id)->update(["deleted" => true]); + } else { + $this->record->delete(); + $this->deleted = true; + } + } + + function undelete(): void + { + if(is_null($this->record)) + throw new ISE("Can't undelete a model, that hasn't been flushed to DB. Have you forgotten to call save() first?"); + + $user = CurrentUser::i()->getUser(); + $user_id = is_null($user) ? (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId(); + + (new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 3, $this->record->toArray(), ["deleted" => false]); + + $this->getTable()->where("id", $this->record->id)->update(["deleted" => false]); + } + + function save(?bool $log = true): void + { + if ($log) { + $user = CurrentUser::i()->getUser(); + $user_id = is_null($user) ? (int)OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId(); + } + + if(is_null($this->record)) { + $this->record = $this->getTable()->insert($this->changes); + + if ($log && $this->getTable()->getName() !== "logs") { + (new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 0, $this->record->toArray(), $this->changes); + } + } else { + if ($log && $this->getTable()->getName() !== "logs") { + (new Logs)->create($user_id, $this->getTable()->getName(), get_class($this), 1, $this->record->toArray(), $this->changes); + } + + if ($this->deleted) { + $this->record = $this->getTable()->insert((array)$this->record); + } else { + $this->getTable()->get($this->record->id)->update($this->changes); + $this->record = $this->getTable()->get($this->record->id); + } + } + + $this->changes = []; + } + + use \Nette\SmartObject; +} diff --git a/Web/Models/Entities/Comment.php b/Web/Models/Entities/Comment.php index 7c6222e4..d813d6be 100644 --- a/Web/Models/Entities/Comment.php +++ b/Web/Models/Entities/Comment.php @@ -85,4 +85,9 @@ class Comment extends Post } return $res; } + + function getURL(): string + { + return "/wall" . $this->getTarget()->getPrettyId() . "#_comment" . $this->getId(); + } } diff --git a/Web/Models/Entities/IP.php b/Web/Models/Entities/IP.php index ecea92ca..df2c9787 100644 --- a/Web/Models/Entities/IP.php +++ b/Web/Models/Entities/IP.php @@ -92,7 +92,7 @@ class IP extends RowModel $this->stateChanges("rate_limit_counter", $aCounter); $this->stateChanges("rate_limit_violation_counter_start", $vCounterSessionStart); $this->stateChanges("rate_limit_violation_counter", $vCounter); - $this->save(); + $this->save(false); } } @@ -105,11 +105,11 @@ class IP extends RowModel $this->stateChanges("ip", $ip); } - function save(): void + function save($log): void { if(is_null($this->getRecord())) $this->stateChanges("first_seen", time()); - parent::save(); + parent::save($log); } } diff --git a/Web/Models/Entities/Log.php b/Web/Models/Entities/Log.php new file mode 100644 index 00000000..eabfd36f --- /dev/null +++ b/Web/Models/Entities/Log.php @@ -0,0 +1,190 @@ +getRecord()->id; + } + + function getUser(): ?User + { + return (new Users)->get((int) $this->getRecord()->user); + } + + function getObjectTable(): string + { + return $this->getRecord()->object_table; + } + + function getObjectId(): int + { + return $this->getRecord()->object_id; + } + + function getObject() + { + $model = $this->getRecord()->object_model; + return new $model(DatabaseConnection::i()->getContext()->table($this->getObjectTable())->get($this->getObjectId())); + } + + function getTypeRaw(): int + { + return $this->getRecord()->type; + } + + function getType(): string + { + return ["добавил", "отредактировал", "удалил", "восстановил"][$this->getTypeRaw()]; + } + + function getTypeNom(): string + { + return ["Создание", "Редактирование", "Удаление", "Восстановление"][$this->getTypeRaw()]; + } + + function getObjectType(): string + { + return [ + "albums" => "Альбом", + "groups" => "Сообщество", + "profiles" => "Профиль", + "comments" => "Комментарий", + "ip" => "IP-адрес", + "posts" => "Запись", + "tickets" => "Вопрос", + "tickets_comments" => "Комментарий к тикету", + ][$this->getRecord()->object_table] ?? $this->getRecord()->object_model; + } + + function getObjectName(): string + { + $object = $this->getObject(); + if (method_exists($object, 'getCanonicalName')) + return $object->getCanonicalName(); + else return "[#" . $this->getObjectId() . "] " . $this->getObjectType(); + } + + function getLogsText(): string + { + return $this->getRecord()->logs_text; + } + + function getObjectURL(): string + { + $object = $this->getObject(); + if (method_exists($object, "getURL") && $this->getObjectTable() !== "videos") + return $this->getObject()->getURL(); + else + return "#"; + } + + function getObjectAvatar(): ?string + { + $object = $this->getObject(); + if (method_exists($object, 'getAvatarURL')) + return $object->getAvatarURL("normal"); + else return NULL; + } + + function getOldValue(): ?array + { + return (array) json_decode($this->getRecord()->xdiff_old, true, JSON_UNESCAPED_UNICODE) ?? null; + } + + function getNewValue(): ?array + { + return (array) json_decode($this->getRecord()->xdiff_new, true, JSON_UNESCAPED_UNICODE) ?? null; + } + + function getTime(): DateTime + { + return new DateTime($this->getRecord()->ts); + } + + function diff($old, $new): array + { + $matrix = array(); + $maxlen = 0; + foreach ($old as $oindex => $ovalue) { + $nkeys = array_keys($new, $ovalue); + foreach ($nkeys as $nindex) { + $matrix[$oindex][$nindex] = isset($matrix[$oindex - 1][$nindex - 1]) ? + $matrix[$oindex - 1][$nindex - 1] + 1 : 1; + if ($matrix[$oindex][$nindex] > $maxlen) { + $maxlen = $matrix[$oindex][$nindex]; + $omax = $oindex + 1 - $maxlen; + $nmax = $nindex + 1 - $maxlen; + } + } + } + if ($maxlen == 0) return array(array('d' => $old, 'i' => $new)); + return array_merge( + $this->diff(array_slice($old, 0, $omax), array_slice($new, 0, $nmax)), + array_slice($new, $nmax, $maxlen), + $this->diff(array_slice($old, $omax + $maxlen), array_slice($new, $nmax + $maxlen))); + } + + function htmlDiff($old, $new): string + { + $ret = ''; + $diff = $this->diff(preg_split("/[\s]+/", $old), preg_split("/[\s]+/", $new)); + foreach ($diff as $k) { + if (is_array($k)) + $ret .= (!empty($k['d']) ? "" . implode(' ', $k['d']) . " " : '') . + (!empty($k['i']) ? "" . implode(' ', $k['i']) . " " : ''); + else $ret .= $k . ' '; + } + return $ret; + } + + function getChanges(): array + { + $result = $this->getOldValue(); + $_changes = []; + + if ($this->getTypeRaw() === 1) { // edit + $changes = $this->getNewValue(); + + foreach ($changes as $field => $value) { + $new_value = xdiff_string_patch((string) $result[$field], (string) $value); + $_changes[$field] = [ + "field" => $field, + "old_value" => $result[$field], + "new_value" => strlen($new_value) > 0 ? $new_value : "(empty)", + "ts" => $this->getTime(), + "diff" => $this->htmlDiff((string) $result[$field], (string) $new_value) + ]; + } + } else if ($this->getTypeRaw() === 0) { // create + foreach ($result as $field => $value) { + $_changes[$field] = [ + "field" => $field, + "old_value" => $value, + "ts" => $this->getTime() + ]; + } + } else if ($this->getTypeRaw() === 2) { // delete + $_changes[] = [ + "field" => "deleted", + "old_value" => 0, + "new_value" => 1, + "ts" => $this->getTime(), + "diff" => $this->htmlDiff("0", "1") + ]; + } + + return $_changes; + } +} diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php index 348631e4..66bb5696 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -1013,7 +1013,7 @@ class User extends RowModel { $this->setOnline(time()); $this->setClient_name($platform); - $this->save(); + $this->save(false); return true; } @@ -1031,7 +1031,7 @@ class User extends RowModel function adminNotify(string $message): bool { - $admId = OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"]; + $admId = (int) OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"]; if(!$admId) return false; else if(is_null($admin = (new Users)->get($admId))) diff --git a/Web/Models/Repositories/CurrentUser.php b/Web/Models/Repositories/CurrentUser.php new file mode 100644 index 00000000..c71a5ac7 --- /dev/null +++ b/Web/Models/Repositories/CurrentUser.php @@ -0,0 +1,31 @@ +user = $user; + } + + public static function get($user) + { + if (self::$instance === null) self::$instance = new self($user); + return self::$instance; + } + + public function getUser(): User + { + return $this->user; + } + + public static function i() + { + return self::$instance; + } +} diff --git a/Web/Models/Repositories/Logs.php b/Web/Models/Repositories/Logs.php new file mode 100644 index 00000000..96ceba0a --- /dev/null +++ b/Web/Models/Repositories/Logs.php @@ -0,0 +1,94 @@ +context = DatabaseConnection::i()->getContext(); + $this->logs = $this->context->table("logs"); + } + + private function toLog(?ActiveRow $ar): ?Log + { + return is_null($ar) ? NULL : new Log($ar); + } + + function get(int $id): ?Log + { + return $this->toLog($this->logs->get($id)); + } + + function create(int $user, string $table, string $model, int $type, $object, $changes): void + { + if (OPENVK_ROOT_CONF["openvk"]["preferences"]["logs"] === true) { + $fobject = (is_array($object) ? $object : $object->unwrap()); + $nobject = []; + $_changes = []; + + if ($type === 1) { + foreach ($changes as $field => $value) { + $nobject[$field] = $fobject[$field]; + } + + foreach (array_diff_assoc($nobject, $changes) as $field => $value) { + if (str_starts_with($field, "rate_limit")) continue; + if ($field === "online") continue; + $_changes[$field] = xdiff_string_diff((string)$nobject[$field], (string)$changes[$field]); + } + + if (count($_changes) === 0) return; + } else if ($type === 0) { // if new + $nobject = $fobject; + foreach ($fobject as $field => $value) { + $_changes[$field] = xdiff_string_diff("", (string)$value); + } + } else if ($type === 2 || $type === 3) { // if deleting or restoring + $_changes["deleted"] = (int)($type === 2); + } + + $log = new Log; + $log->setUser($user); + $log->setType($type); + $log->setObject_Table($table); + $log->setObject_Model($model); + $log->setObject_Id(is_array($object) ? $object["id"] : $object->getId()); + $log->setXdiff_Old(json_encode($nobject)); + $log->setXdiff_New(json_encode($_changes)); + $log->setTs(time()); + $log->save(false); + } + } + + function find(string $query, array $pars = [], string $sort = "id DESC", int $page = 1, ?int $perPage = NULL): \Traversable + { + $query = "%$query%"; + $result = $this->logs->where("id LIKE ? OR object_table LIKE ?", $query, $query); + + return new Util\EntityStream("Log", $result->order($sort)); + } + + function search($filter): \Traversable + { + foreach ($this->logs->where($filter)->order("id DESC") as $log) + yield new Log($log); + } + + function getTypes(): array + { + $types = []; + foreach ($this->context->query("SELECT DISTINCT(`object_model`) AS `object_model` FROM `logs`")->fetchAll() as $type) + $types[] = str_replace("openvk\\Web\\Models\\Entities\\", "", $type->object_model); + + return $types; + } +} diff --git a/Web/Presenters/AdminPresenter.php b/Web/Presenters/AdminPresenter.php index ff21612b..a8432bcd 100644 --- a/Web/Presenters/AdminPresenter.php +++ b/Web/Presenters/AdminPresenter.php @@ -1,7 +1,7 @@ users = $users; $this->clubs = $clubs; @@ -21,6 +22,7 @@ final class AdminPresenter extends OpenVKPresenter $this->gifts = $gifts; $this->bannedLinks = $bannedLinks; $this->chandlerGroups = $chandlerGroups; + $this->logs = $logs; parent::__construct(); } @@ -550,4 +552,43 @@ final class AdminPresenter extends OpenVKPresenter $this->redirect("/admin/users/id" . $user->getId()); } + + function renderLogs(): void + { + $filter = []; + + if ($this->queryParam("id")) { + $id = (int) $this->queryParam("id"); + $filter["id"] = $id; + $this->template->id = $id; + } + if ($this->queryParam("type") !== NULL && $this->queryParam("type") !== "any") { + $type = in_array($this->queryParam("type"), [0, 1, 2, 3]) ? (int) $this->queryParam("type") : 0; + $filter["type"] = $type; + $this->template->type = $type; + } + if ($this->queryParam("uid")) { + $user = (int) $this->queryParam("uid"); + $filter["user"] = $user; + $this->template->user = $user; + } + if ($this->queryParam("obj_id")) { + $obj_id = (int) $this->queryParam("obj_id"); + $filter["object_id"] = $obj_id; + $this->template->obj_id = $obj_id; + } + if ($this->queryParam("obj_type") !== NULL && $this->queryParam("obj_type") !== "any") { + $obj_type = "openvk\\Web\\Models\\Entities\\" . $this->queryParam("obj_type"); + $filter["object_model"] = $obj_type; + $this->template->obj_type = $obj_type; + } + + if (count($filter) === 0) { + $this->template->logs = $this->searchResults($this->logs, $this->template->count); + } else { + $this->template->logs = $this->logs->search($filter); + } + + $this->template->object_types = (new Logs)->getTypes(); + } } diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php index 2f178900..4bca557a 100644 --- a/Web/Presenters/AuthPresenter.php +++ b/Web/Presenters/AuthPresenter.php @@ -1,7 +1,7 @@ flashFail("err", tr("failed_to_register"), tr("user_already_exists")); $user->setUser($chUser->getId()); - $user->save(); + $user->save(false); if(!is_null($referer)) { $user->toggleSubscription($referer); @@ -130,7 +130,9 @@ final class AuthPresenter extends OpenVKPresenter } $this->authenticator->authenticate($chUser->getId()); + (new Logs)->create($user->getId(), "profiles", "openvk\\Web\\Models\\Entities\\User", 0, $user, $user); $this->redirect("/id" . $user->getId()); + $user->save(); } } diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index 710713e5..0cf67444 100755 --- a/Web/Presenters/OpenVKPresenter.php +++ b/Web/Presenters/OpenVKPresenter.php @@ -7,7 +7,7 @@ use Chandler\Security\Authenticator; use Latte\Engine as TemplatingEngine; use openvk\Web\Models\Entities\IP; use openvk\Web\Themes\Themepacks; -use openvk\Web\Models\Repositories\{IPs, Users, APITokens, Tickets}; +use openvk\Web\Models\Repositories\{CurrentUser, IPs, Users, APITokens, Tickets}; use WhichBrowser; abstract class OpenVKPresenter extends SimplePresenter @@ -211,6 +211,7 @@ abstract class OpenVKPresenter extends SimplePresenter $this->user->id = $this->user->identity->getId(); $this->template->thisUser = $this->user->identity; $this->template->userTainted = $user->isTainted(); + CurrentUser::get($this->user->identity); if($this->user->identity->isDeleted() && !$this->deactivationTolerant) { if($this->user->identity->isDeactivated()) { @@ -255,7 +256,7 @@ abstract class OpenVKPresenter extends SimplePresenter if($this->user->identity->onlineStatus() == 0 && !($this->user->identity->isDeleted() || $this->user->identity->isBanned())) { $this->user->identity->setOnline(time()); $this->user->identity->setClient_name(NULL); - $this->user->identity->save(); + $this->user->identity->save(false); } $this->template->ticketAnsweredCount = (new Tickets)->getTicketsCountByUserId($this->user->id, 1); diff --git a/Web/Presenters/templates/Admin/@layout.xml b/Web/Presenters/templates/Admin/@layout.xml index 7b1a30f3..f254dd9a 100644 --- a/Web/Presenters/templates/Admin/@layout.xml +++ b/Web/Presenters/templates/Admin/@layout.xml @@ -124,6 +124,9 @@
  • {_admin_settings_tuning}
  • +
  • + Логи +
  • {_admin_settings_appearance}
  • diff --git a/Web/Presenters/templates/Admin/Logs.xml b/Web/Presenters/templates/Admin/Logs.xml new file mode 100644 index 00000000..e30df251 --- /dev/null +++ b/Web/Presenters/templates/Admin/Logs.xml @@ -0,0 +1,99 @@ +{extends "@layout.xml"} + +{block title} + Логи +{/block} + +{block heading} + Логи +{/block} + +{block content} + {var $logs = iterator_to_array($logs)} + {var $amount = sizeof($logs)} + + +
    +
    + + + +
    +
    +
    + + + +
    + + + + + + + + + + + + + + + + + + + + + + + +
    IDПользовательОбъектТипИзмененияВремя
    {$log->getId()} + + + {$log->getUser()->getCanonicalName()} + + + {$log->getUser()->getCanonicalName()} + + + + {$log->getObjectName()} + + + {$log->getObjectName()} + {$log->getTypeNom()} + {foreach $log->getChanges() as $change} +
    + {$change["field"]}: + {if array_key_exists('diff', $change)} + {$change["diff"]|noescape} + {else} + {$change["old_value"]} + {/if} +
    + {/foreach} +
    + {$change["ts"]} +
    +
    +
    + {var $isLast = ((20 * (($_GET['p'] ?? 1) - 1)) + $amount) < $count} + + « + » +
    +{/block} diff --git a/Web/Presenters/templates/Group/View.xml b/Web/Presenters/templates/Group/View.xml index bf392a9f..10d1f0dd 100644 --- a/Web/Presenters/templates/Group/View.xml +++ b/Web/Presenters/templates/Group/View.xml @@ -124,6 +124,7 @@ {/if} {if $thisUser->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)} {_manage_group_action} + Последние действия {/if} {if $club->getSubscriptionStatus($thisUser) == false}
    diff --git a/Web/Presenters/templates/User/View.xml b/Web/Presenters/templates/User/View.xml index 1fa71026..bc197310 100644 --- a/Web/Presenters/templates/User/View.xml +++ b/Web/Presenters/templates/User/View.xml @@ -118,6 +118,9 @@ {_warn_user_action} + + Последние действия + {/if} {if $thisUser->getChandlerUser()->can('write')->model('openvk\Web\Models\Entities\TicketReply')->whichBelongsTo(0)} diff --git a/Web/di.yml b/Web/di.yml index 3363c5de..1e7532f2 100644 --- a/Web/di.yml +++ b/Web/di.yml @@ -49,3 +49,4 @@ services: - openvk\Web\Models\Repositories\BannedLinks - openvk\Web\Models\Repositories\ChandlerGroups - openvk\Web\Presenters\MaintenancePresenter + - openvk\Web\Models\Repositories\Logs diff --git a/Web/routes.yml b/Web/routes.yml index d1a0e7ae..0d5fc2ce 100644 --- a/Web/routes.yml +++ b/Web/routes.yml @@ -339,6 +339,8 @@ routes: handler: "Admin->chandlerGroup" - url: "/admin/chandler/users/{slug}" handler: "Admin->chandlerUser" + - url: "/admin/logs" + handler: "Admin->logs" - url: "/internal/wall{num}" handler: "Wall->wallEmbedded" - url: "/robots.txt" diff --git a/install/00038-logs.sql b/install/00038-logs.sql new file mode 100644 index 00000000..3943f629 --- /dev/null +++ b/install/00038-logs.sql @@ -0,0 +1,19 @@ +CREATE TABLE `logs` +( + `id` bigint(20) UNSIGNED NOT NULL, + `user` bigint(20) UNSIGNED NOT NULL, + `type` int(11) NOT NULL, + `object_table` tinytext COLLATE utf8mb4_unicode_ci NOT NULL, + `object_model` mediumtext COLLATE utf8mb4_unicode_ci NOT NULL, + `object_id` bigint(20) UNSIGNED NOT NULL, + `xdiff_old` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `xdiff_new` longtext COLLATE utf8mb4_unicode_ci NOT NULL, + `ts` bigint(20) NOT NULL +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +ALTER TABLE `logs` + ADD PRIMARY KEY (`id`); + +ALTER TABLE `logs` + MODIFY `id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT; +COMMIT; diff --git a/openvk-example.yml b/openvk-example.yml index e3fd1c3a..4b45e7ba 100644 --- a/openvk-example.yml +++ b/openvk-example.yml @@ -102,6 +102,7 @@ openvk: fartscroll: false testLabel: false defaultMobileTheme: "" + logs: true telemetry: plausible: From 6b8477ed01132791ddabaf9865eb4f3d97ed389e Mon Sep 17 00:00:00 2001 From: n1rwana Date: Thu, 3 Aug 2023 17:15:07 +0300 Subject: [PATCH 2/3] Update DBEntity.updated.php --- DBEntity.updated.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DBEntity.updated.php b/DBEntity.updated.php index 52e17043..5414a2e9 100644 --- a/DBEntity.updated.php +++ b/DBEntity.updated.php @@ -105,8 +105,8 @@ abstract class DBEntity function save(?bool $log = true): void { if ($log) { - $user = CurrentUser::i()->getUser(); - $user_id = is_null($user) ? (int)OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getId(); + $user = CurrentUser::i(); + $user_id = is_null($user) ? (int)OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getUser()->getId(); } if(is_null($this->record)) { From 0997ee1ca9ccfff8438134e5574dd20cfd54f598 Mon Sep 17 00:00:00 2001 From: n1rwana Date: Tue, 8 Aug 2023 21:14:43 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A1=D0=B1=D0=BE=D1=80=20IP=20=D0=B8=20Us?= =?UTF-8?q?erAgent=20+=20=D1=84=D0=B8=D0=BA=D1=81=20=D0=BB=D0=BE=D0=B3?= =?UTF-8?q?=D0=B8=D1=80=D0=BE=D0=B2=D0=B0=D0=BD=D0=B8=D1=8F=20=D0=B2=20IPs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Web/Models/Repositories/CurrentUser.php | 24 +++++++++++++++++++++--- Web/Models/Repositories/IPs.php | 2 +- Web/Models/Repositories/Logs.php | 4 +++- Web/Presenters/OpenVKPresenter.php | 2 +- install/{ => sqls}/00038-logs.sql | 4 +++- 5 files changed, 29 insertions(+), 7 deletions(-) rename install/{ => sqls}/00038-logs.sql (79%) diff --git a/Web/Models/Repositories/CurrentUser.php b/Web/Models/Repositories/CurrentUser.php index c71a5ac7..c6cb942b 100644 --- a/Web/Models/Repositories/CurrentUser.php +++ b/Web/Models/Repositories/CurrentUser.php @@ -6,16 +6,24 @@ class CurrentUser { private static $instance = null; private $user; + private $ip; + private $useragent; - public function __construct(?User $user = NULL) + public function __construct(?User $user = NULL, ?string $ip = NULL, ?string $useragent = NULL) { if ($user) $this->user = $user; + + if ($ip) + $this->ip = $ip; + + if ($useragent) + $this->useragent = $useragent; } - public static function get($user) + public static function get($user, $ip, $useragent) { - if (self::$instance === null) self::$instance = new self($user); + if (self::$instance === null) self::$instance = new self($user, $ip, $useragent); return self::$instance; } @@ -24,6 +32,16 @@ class CurrentUser return $this->user; } + public function getIP(): string + { + return $this->ip; + } + + public function getUserAgent(): string + { + return $this->useragent; + } + public static function i() { return self::$instance; diff --git a/Web/Models/Repositories/IPs.php b/Web/Models/Repositories/IPs.php index c4485b73..59fc6570 100644 --- a/Web/Models/Repositories/IPs.php +++ b/Web/Models/Repositories/IPs.php @@ -24,7 +24,7 @@ class IPs if(!$res) { $res = new IP; $res->setIp($ip); - $res->save(); + $res->save(false); return $res; } diff --git a/Web/Models/Repositories/Logs.php b/Web/Models/Repositories/Logs.php index 96ceba0a..6f7d3937 100644 --- a/Web/Models/Repositories/Logs.php +++ b/Web/Models/Repositories/Logs.php @@ -65,7 +65,9 @@ class Logs $log->setXdiff_Old(json_encode($nobject)); $log->setXdiff_New(json_encode($_changes)); $log->setTs(time()); - $log->save(false); + $log->setIp(CurrentUser::i()->getIP()); + $log->setUserAgent(CurrentUser::i()->getUserAgent()); + $log->save(); } } diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index 0cf67444..b4444bda 100755 --- a/Web/Presenters/OpenVKPresenter.php +++ b/Web/Presenters/OpenVKPresenter.php @@ -211,7 +211,7 @@ abstract class OpenVKPresenter extends SimplePresenter $this->user->id = $this->user->identity->getId(); $this->template->thisUser = $this->user->identity; $this->template->userTainted = $user->isTainted(); - CurrentUser::get($this->user->identity); + CurrentUser::get($this->user->identity, $_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"]); if($this->user->identity->isDeleted() && !$this->deactivationTolerant) { if($this->user->identity->isDeactivated()) { diff --git a/install/00038-logs.sql b/install/sqls/00038-logs.sql similarity index 79% rename from install/00038-logs.sql rename to install/sqls/00038-logs.sql index 3943f629..e136c83f 100644 --- a/install/00038-logs.sql +++ b/install/sqls/00038-logs.sql @@ -8,7 +8,9 @@ CREATE TABLE `logs` `object_id` bigint(20) UNSIGNED NOT NULL, `xdiff_old` longtext COLLATE utf8mb4_unicode_ci NOT NULL, `xdiff_new` longtext COLLATE utf8mb4_unicode_ci NOT NULL, - `ts` bigint(20) NOT NULL + `ts` bigint(20) NOT NULL, + `ip` tinytext NOT NULL, + `useragent` longtext NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; ALTER TABLE `logs`