diff --git a/DBEntity.updated.php b/DBEntity.updated.php new file mode 100644 index 00000000..4c039b54 --- /dev/null +++ b/DBEntity.updated.php @@ -0,0 +1,140 @@ +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(); + $user_id = is_null($user) ? (int)OPENVK_ROOT_CONF["openvk"]["preferences"]["support"]["adminAccount"] : $user->getUser()->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 = []; + } + + function getTableName(): string + { + return $this->getTable()->getName(); + } + + 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/User.php b/Web/Models/Entities/User.php index d132e015..db5cf055 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -1016,7 +1016,7 @@ class User extends RowModel { $this->setOnline(time()); $this->setClient_name($platform); - $this->save(); + $this->save(false); return true; } @@ -1034,7 +1034,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..c6cb942b --- /dev/null +++ b/Web/Models/Repositories/CurrentUser.php @@ -0,0 +1,49 @@ +user = $user; + + if ($ip) + $this->ip = $ip; + + if ($useragent) + $this->useragent = $useragent; + } + + public static function get($user, $ip, $useragent) + { + if (self::$instance === null) self::$instance = new self($user, $ip, $useragent); + return self::$instance; + } + + public function getUser(): User + { + 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/Presenters/AdminPresenter.php b/Web/Presenters/AdminPresenter.php index ed1f55eb..bba2ef31 100644 --- a/Web/Presenters/AdminPresenter.php +++ b/Web/Presenters/AdminPresenter.php @@ -1,7 +1,9 @@ gifts = $gifts; $this->bannedLinks = $bannedLinks; $this->chandlerGroups = $chandlerGroups; + $this->logs = DatabaseConnection::i()->getContext()->table("ChandlerLogs"); parent::__construct(); } @@ -551,4 +555,38 @@ 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 = $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; + } + + $this->template->logs = (new Logs)->search($filter); + $this->template->object_types = (new Logs)->getTypes(); + } } diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php index 2f178900..f569dd63 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, $_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"]); $this->redirect("/id" . $user->getId()); + $user->save(); } } diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index 710713e5..b4444bda 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, $_SERVER["REMOTE_ADDR"], $_SERVER["HTTP_USER_AGENT"]); 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 @@
ID | +Пользователь | +Объект | +Тип | +Изменения | +Время | +
---|---|---|---|---|---|
{$log->getId()} | ++ {$log->getUser()} + | ++ + + + + + {$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}
+ |
+ + {=new openvk\Web\Util\DateTime($change["ts"])} + | +