diff --git a/Web/Models/Entities/Post.php b/Web/Models/Entities/Post.php index 695dde87..4afb4baa 100644 --- a/Web/Models/Entities/Post.php +++ b/Web/Models/Entities/Post.php @@ -84,6 +84,11 @@ class Post extends Postable { return ($this->getRecord()->flags & 0b01000000) > 0; } + + function isDeactivationMessage(): bool + { + return ($this->getRecord()->flags & 0b00100000) > 0; + } function isExplicit(): bool { diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php index 2e0d0ce5..f7ace42b 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -147,7 +147,7 @@ class User extends RowModel function getFirstName(bool $pristine = false): string { - $name = $this->getRecord()->deleted ? "DELETED" : mb_convert_case($this->getRecord()->first_name, MB_CASE_TITLE); + $name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->first_name, MB_CASE_TITLE)); if((($ts = tr("__transNames")) !== "@__transNames") && !$pristine) return mb_convert_case(transliterator_transliterate($ts, $name), MB_CASE_TITLE); else @@ -156,7 +156,7 @@ class User extends RowModel function getLastName(bool $pristine = false): string { - $name = $this->getRecord()->deleted ? "DELETED" : mb_convert_case($this->getRecord()->last_name, MB_CASE_TITLE); + $name = ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : mb_convert_case($this->getRecord()->last_name, MB_CASE_TITLE)); if((($ts = tr("__transNames")) !== "@__transNames") && !$pristine) return mb_convert_case(transliterator_transliterate($ts, $name), MB_CASE_TITLE); else @@ -165,12 +165,12 @@ class User extends RowModel function getPseudo(): ?string { - return $this->getRecord()->deleted ? "DELETED" : $this->getRecord()->pseudo; + return ($this->isDeleted() && !$this->isDeactivated() ? "DELETED" : $this->getRecord()->pseudo); } function getFullName(): string { - if($this->getRecord()->deleted) + if($this->isDeleted() && !$this->isDeactivated()) return "DELETED"; $pseudo = $this->getPseudo(); @@ -195,7 +195,7 @@ class User extends RowModel function getCanonicalName(): string { - if($this->getRecord()->deleted) + if($this->isDeleted() && !$this->isDeactivated()) return "DELETED"; else return $this->getFirstName() . " " . $this->getLastName(); @@ -785,6 +785,27 @@ class User extends RowModel $this->save(); } + function deactivate(?string $reason): void + { + $this->setDeleted(1); + $this->setDeact_Date(time() + (MONTH * 7)); + $this->setDeact_Reason($reason); + $this->save(); + } + + function reactivate(): void + { + $this->setDeleted(0); + $this->setDeact_Date(0); + $this->setDeact_Reason(""); + $this->save(); + } + + function getDeactivationDate(): DateTime + { + return new DateTime($this->getRecord()->deact_date); + } + function verifyNumber(string $code): bool { $ver = $this->getPendingPhoneVerification(); @@ -956,6 +977,14 @@ class User extends RowModel return FALSE; } + function isDeactivated(): bool + { + if ($this->getDeactivationDate()->timestamp() > time()) + return TRUE; + else + return FALSE; + } + /** * 0 - Default status * 1 - Incognito online status diff --git a/Web/Presenters/AboutPresenter.php b/Web/Presenters/AboutPresenter.php index 3caa007d..6b21ca1a 100644 --- a/Web/Presenters/AboutPresenter.php +++ b/Web/Presenters/AboutPresenter.php @@ -9,6 +9,7 @@ final class AboutPresenter extends OpenVKPresenter { protected $banTolerant = true; protected $activationTolerant = true; + protected $deactivationTolerant = true; function renderIndex(): void { diff --git a/Web/Presenters/AuthPresenter.php b/Web/Presenters/AuthPresenter.php index ad0db0c7..b3a8e8c2 100644 --- a/Web/Presenters/AuthPresenter.php +++ b/Web/Presenters/AuthPresenter.php @@ -20,6 +20,7 @@ final class AuthPresenter extends OpenVKPresenter { protected $banTolerant = true; protected $activationTolerant = true; + protected $deactivationTolerant = true; private $authenticator; private $db; @@ -151,7 +152,7 @@ final class AuthPresenter extends OpenVKPresenter $this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password")); $ovkUser = new User($user->related("profiles.user")->fetch()); - if($ovkUser->isDeleted()) + if($ovkUser->isDeleted() && !$ovkUser->isDeactivated()) $this->flashFail("err", tr("login_failed"), tr("invalid_username_or_password")); $secret = $user->related("profiles.user")->fetch()["2fa_secret"]; @@ -321,4 +322,15 @@ final class AuthPresenter extends OpenVKPresenter $this->redirect("/"); } } + + function renderReactivatePage(): void + { + $this->assertUserLoggedIn(); + $this->willExecuteWriteAction(); + + $this->user->identity->reactivate(); + + $this->redirect("/", 2); + exit; + } } diff --git a/Web/Presenters/OpenVKPresenter.php b/Web/Presenters/OpenVKPresenter.php index 5c7f95c3..38f301f8 100755 --- a/Web/Presenters/OpenVKPresenter.php +++ b/Web/Presenters/OpenVKPresenter.php @@ -14,6 +14,7 @@ abstract class OpenVKPresenter extends SimplePresenter { protected $banTolerant = false; protected $activationTolerant = false; + protected $deactivationTolerant = false; protected $errorTemplate = "@error"; protected $user = NULL; @@ -214,39 +215,28 @@ abstract class OpenVKPresenter extends SimplePresenter $this->template->thisUser = $this->user->identity; $this->template->userTainted = $user->isTainted(); - if($this->user->identity->isDeleted()) { - /* - ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣴⠶⠶⣶⠶⠶⠶⠶⠶⠶⠶⠶⠶⢶⠶⠶⠶⠤⠤⠤⠤⣄⣀⣀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠀⣠⡾⠋⠀⠀⠊⠀⠀⠀⠀⠀⠀⠀⠀⠒⠒⠒⠀⠀⠀⠀⠤⢤⣤⣄⠉⠉⠛⠛⠷⣦⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⣰⠟⠀⠀⠀⠀⠀⠐⠋⢑⣤⣶⣶⣤⡢⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣄⡂⠀⠀⠶⢄⠙⢷⣤⠀⠀⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⣸⡿⠚⠉⡀⠀⠀⠀⠀⢰⣿⣿⣿⣿⣿⣿⡄⠀⠀⠀⢢⠀⠀⡀⣰⣿⣿⣿⣿⣦⡀⠀⠀⠡⡀⢹⡆⠀⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⢀⣴⠏⠀⣀⣀⣀⡤⢤⣄⣠⣿⣿⣿⣿⣻⣿⣿⣷⠀⢋⣾⠈⠙⣶⠒⢿⣿⣿⣿⣿⡿⠟⠃⠀⡀⠡⠼⣧⡀⠀⠀⠀⠀⠀⠀ - ⠀⠀⢀⣴⣿⢃⡴⢊⢽⣶⣤⣀⠀⠊⠉⠉⡛⢿⣿⣿⣿⠿⠋⢀⡀⠁⠀⠀⢸⣁⣀⣉⣉⣉⡉⠀⠩⡡⠀⣩⣦⠀⠈⠻⣦⡀⠀⠀⠀⠀ - ⠀⢠⡟⢡⠇⡞⢀⠆⠀⢻⣿⣿⣷⣄⠀⢀⠈⠂⠈⢁⡤⠚⡟⠉⠀⣀⣀⠀⠈⠳⣍⠓⢆⢀⡠⢀⣨⣴⣿⣿⡏⢀⡆⠀⢸⡇⠀⠀⠀⠀ - ⠀⣾⠁⢸⠀⠀⢸⠀⠀⠀⠹⣿⣿⣿⣿⣶⣬⣦⣤⡈⠀⠀⠇⠀⠛⠉⣩⣤⣤⣤⣿⣤⣤⣴⣾⣿⣿⣿⣿⣿⣧⠞⠀⠀⢸⡇⠀⠀⠀⠀ - ⠀⢹⣆⠸⠀⠀⢸⠀⠀⠀⠀⠘⢿⣿⣿⣿⣿⣿⣿⣟⣛⠛⠛⣛⡛⠛⠛⣛⣋⡉⠉⣡⠶⢾⣿⣿⣿⣿⣿⣿⡇⠀⠀⢀⣾⠃⠀⠀⠀⠀ - ⠀⠀⠻⣆⡀⠀⠈⢂⠀⠀⠀⠠⡈⢻⣿⣿⣿⣿⡟⠁⠈⢧⡼⠉⠙⣆⡞⠁⠈⢹⣴⠃⠀⢸⣿⣿⣿⣿⣿⣿⠃⠀⡆⣾⠃⠀⠀⠀⠀⠀ - ⠀⠀⠀⠈⢻⣇⠀⠀⠀⠀⠀⠀⢡⠀⠹⣿⣿⣿⣷⡀⠀⣸⡇⠀⠀⣿⠁⠀⠀⠘⣿⠀⠀⠘⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠹⣇⠀⠠⠀⠀⠀⠀⠡⠐⢬⡻⣿⣿⣿⣿⣿⣷⣶⣶⣿⣦⣤⣤⣤⣿⣦⣶⣿⣿⣿⣿⣿⣿⣿⠀⠀⣿⡇⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠹⣧⡀⠡⡀⠀⠀⠀⠑⠄⠙⢎⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⠀⢿⡇⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠈⠳⣤⡐⡄⠀⠀⠀⠈⠂⠀⠱⣌⠻⣿⣿⣿⣿⣿⣿⣿⠿⣿⠟⢻⡏⢻⣿⣿⣿⣿⣿⣿⣿⠀⢸⡇⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠻⢮⣦⡀⠂⠀⢀⠀⠀⠈⠳⣈⠻⣿⣿⣿⡇⠘⡄⢸⠀⠀⣇⠀⣻⣿⣿⣿⣿⣿⡏⠀⠸⡇⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⢶⣤⣄⡑⠄⠀⠀⠈⠑⠢⠙⠻⢷⣶⣵⣞⣑⣒⣋⣉⣁⣻⣿⠿⠟⠱⠃⡸⠀⣧⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠻⣷⣄⡀⠐⠢⣄⣀⡀⠀⠉⠉⠉⠉⠛⠙⠭⠭⠄⠒⠈⠀⠐⠁⢀⣿⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠷⢦⣤⣤⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣒⡠⠄⣠⡾⠃⠀⠀⠀⠀⠀⠀ - ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠙⠛⠷⠶⣦⣤⣭⣤⣬⣭⣭⣴⠶⠛⠉⠀⠀⠀⠀⠀⠀⠀⠀ - */ - Authenticator::i()->logout(); - Session::i()->set("_su", NULL); - $this->flashFail("err", tr("error"), tr("profile_not_found")); - $this->redirect("/", static::REDIRECT_TEMPORARY); + if($this->user->identity->isDeleted() && !$this->deactivationTolerant) { + if($this->user->identity->isDeactivated()) { + header("HTTP/1.1 403 Forbidden"); + $this->getTemplatingEngine()->render(__DIR__ . "/templates/@deactivated.xml", [ + "thisUser" => $this->user->identity, + "csrfToken" => $GLOBALS["csrfToken"], + "isTimezoned" => Session::i()->get("_timezoneOffset"), + ]); + } else { + Authenticator::i()->logout(); + Session::i()->set("_su", NULL); + $this->flashFail("err", tr("error"), tr("profile_not_found")); + $this->redirect("/", static::REDIRECT_TEMPORARY); + } + exit; } if($this->user->identity->isBanned() && !$this->banTolerant) { header("HTTP/1.1 403 Forbidden"); $this->getTemplatingEngine()->render(__DIR__ . "/templates/@banned.xml", [ - "thisUser" => $this->user->identity, - "csrfToken" => $GLOBALS["csrfToken"], + "thisUser" => $this->user->identity, + "csrfToken" => $GLOBALS["csrfToken"], "isTimezoned" => Session::i()->get("_timezoneOffset"), ]); exit; @@ -256,8 +246,8 @@ abstract class OpenVKPresenter extends SimplePresenter if(!$this->user->identity->isActivated() && !$this->activationTolerant) { header("HTTP/1.1 403 Forbidden"); $this->getTemplatingEngine()->render(__DIR__ . "/templates/@email.xml", [ - "thisUser" => $this->user->identity, - "csrfToken" => $GLOBALS["csrfToken"], + "thisUser" => $this->user->identity, + "csrfToken" => $GLOBALS["csrfToken"], "isTimezoned" => Session::i()->get("_timezoneOffset"), ]); exit; diff --git a/Web/Presenters/SupportPresenter.php b/Web/Presenters/SupportPresenter.php index 92859bb6..b9af87ac 100644 --- a/Web/Presenters/SupportPresenter.php +++ b/Web/Presenters/SupportPresenter.php @@ -12,6 +12,7 @@ use Parsedown; final class SupportPresenter extends OpenVKPresenter { protected $banTolerant = true; + protected $deactivationTolerant = true; private $tickets; private $comments; diff --git a/Web/Presenters/UserPresenter.php b/Web/Presenters/UserPresenter.php index 667274ab..3ef4b9da 100644 --- a/Web/Presenters/UserPresenter.php +++ b/Web/Presenters/UserPresenter.php @@ -3,6 +3,7 @@ namespace openvk\Web\Presenters; use openvk\Web\Util\Sms; use openvk\Web\Themes\Themepacks; use openvk\Web\Models\Entities\Photo; +use openvk\Web\Models\Entities\Post; use openvk\Web\Models\Repositories\Users; use openvk\Web\Models\Repositories\Clubs; use openvk\Web\Models\Repositories\Albums; @@ -22,6 +23,8 @@ use Nette\Database\UniqueConstraintViolationException; final class UserPresenter extends OpenVKPresenter { private $users; + + public $deactivationTolerant = false; function __construct(Users $users) { @@ -34,7 +37,13 @@ final class UserPresenter extends OpenVKPresenter { $user = $this->users->get($id); if(!$user || $user->isDeleted()) { - $this->template->_template = "User/deleted.xml"; + if($user->isDeactivated()) { + $this->template->_template = "User/deactivated.xml"; + + $this->template->user = $user; + } else { + $this->template->_template = "User/deleted.xml"; + } } else { $this->template->albums = (new Albums)->getUserAlbums($user); $this->template->albumsCount = (new Albums)->getUserAlbumsCount($user); @@ -272,8 +281,7 @@ final class UserPresenter extends OpenVKPresenter $user->toggleSubscription($this->user->identity); - header("HTTP/1.1 302 Found"); - header("Location: /id" . $user->getId()); + $this->redirect("/id" . $user->getId()); exit; } @@ -474,6 +482,33 @@ final class UserPresenter extends OpenVKPresenter $this->template->themes = Themepacks::i()->getThemeList(); } + function renderDeactivate(): void + { + $this->assertUserLoggedIn(); + $this->willExecuteWriteAction(); + + $flags = 0; + $reason = $this->postParam("deactivate_reason"); + $share = $this->postParam("deactivate_share"); + + if($share) { + $flags |= 0b00100000; + + $post = new Post; + $post->setOwner($this->user->id); + $post->setWall($this->user->id); + $post->setCreated(time()); + $post->setContent($reason); + $post->setFlags($flags); + $post->save(); + } + + $this->user->identity->deactivate($reason); + + $this->redirect("/"); + exit; + } + function renderTwoFactorAuthSettings(): void { $this->assertUserLoggedIn(); diff --git a/Web/Presenters/templates/@deactivated.xml b/Web/Presenters/templates/@deactivated.xml new file mode 100644 index 00000000..1780abf1 --- /dev/null +++ b/Web/Presenters/templates/@deactivated.xml @@ -0,0 +1,34 @@ +{extends "@layout.xml"} +{block title}{$thisUser->getCanonicalName()}{/block} + +{block header} + {$thisUser->getCanonicalName()} +{/block} + +{block content} +
+ {tr("profile_deactivated_msg", $thisUser->getDeactivationDate()->format("%e %B %G" . tr("time_at_sp") . "%R"))|noescape} +
+ +
+
+ {$thisUser->getCanonicalName()} +
+
+ +
+
+
+
+

{$thisUser->getFullName()}

+
{_profile_deactivated_status}
+
+
+
+ {_profile_deactivated_info|noescape} +
+
+
+{/block} \ No newline at end of file diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml index 07c9380a..52a7e355 100644 --- a/Web/Presenters/templates/@layout.xml +++ b/Web/Presenters/templates/@layout.xml @@ -102,29 +102,35 @@ {if $instance_name != OPENVK_DEFAULT_INSTANCE_NAME}{$instance_name}{/if}
{ifset $thisUser} - - - - - - - + {if $thisUser->isDeactivated()} + + {else} + + + + + + + + {/if} {else}