From 8b9dbb34234d5b8018a9dca1e39eae98c76a3365 Mon Sep 17 00:00:00 2001 From: Visman Date: Sun, 9 Sep 2018 21:22:18 +0700 Subject: [PATCH] + Delete user(s) --- app/Models/Forum/Delete.php | 61 ++++++--- app/Models/Pages/Admin/Users/Action.php | 66 +++++++--- app/Models/Pages/Profile.php | 2 +- app/Models/Post/Delete.php | 157 ++++++++++++++++-------- app/Models/Post/Model.php | 2 +- app/Models/Search/Delete.php | 87 +++++++++---- app/Models/Topic/Delete.php | 97 +++++++++++---- app/Models/User/Delete.php | 54 ++++++++ app/config/main.dist.php | 1 + 9 files changed, 387 insertions(+), 140 deletions(-) create mode 100644 app/Models/User/Delete.php diff --git a/app/Models/Forum/Delete.php b/app/Models/Forum/Delete.php index ad80144c..43c02fda 100644 --- a/app/Models/Forum/Delete.php +++ b/app/Models/Forum/Delete.php @@ -4,6 +4,7 @@ namespace ForkBB\Models\Forum; use ForkBB\Models\Action; use ForkBB\Models\Forum\Model as Forum; +use ForkBB\Models\User\Model as User; use InvalidArgumentException; use RuntimeException; @@ -20,14 +21,23 @@ class Delete extends Action public function delete(...$args) { if (empty($args)) { - throw new InvalidArgumentException('No arguments, expected forum(s)'); + throw new InvalidArgumentException('No arguments, expected User(s) or Forum(s)'); } - $forums = []; - $all = []; + $users = []; + $forums = []; + $all = []; + $isUser = 0; + $isForum = 0; foreach ($args as $arg) { - if ($arg instanceof Forum) { + if ($arg instanceof User) { + if ($arg->isGuest) { + throw new RuntimeException('Guest can not be deleted'); + } + $users[] = $arg->id; + $isUser = 1; + } elseif ($arg instanceof Forum) { if (! $this->c->forums->get($arg->id) instanceof Forum) { throw new RuntimeException('Forum unavailable'); } @@ -36,32 +46,49 @@ class Delete extends Action foreach (\array_keys($arg->descendants) as $id) { //???? а если не админ? $all[$id] = true; } + $isForum = 1; } else { - throw new InvalidArgumentException('Expected forum(s)'); + throw new InvalidArgumentException('Expected User(s) or Forum(s)'); } } + if ($isUser + $isForum > 1) { + throw new InvalidArgumentException('Expected only User(s) or Forum(s)'); + } + if (\array_diff_key($all, $forums)) { throw new RuntimeException('Descendants should not be or they should be deleted too'); } $this->c->topics->delete(...$args); - //???? подписки, опросы, предупреждения, метки посещения тем + //???? подписки, опросы, предупреждения - foreach ($forums as $forum) { - $this->c->groups->Perm->reset($forum); + if ($users) { + $vars = [ + ':users' => $users, + ]; + $sql = 'DELETE FROM ::mark_of_forum + WHERE uid IN (?ai:users)'; + $this->c->DB->exec($sql, $vars); + + //???? удаление модераторов из разделов } + if ($forums) { + foreach ($forums as $forum) { + $this->c->groups->Perm->reset($forum); + } - $vars = [ - ':forums' => \array_keys($forums), - ]; - $sql = 'DELETE FROM ::mark_of_forum - WHERE fid IN (?ai:forums)'; - $this->c->DB->exec($sql, $vars); + $vars = [ + ':forums' => \array_keys($forums), + ]; + $sql = 'DELETE FROM ::mark_of_forum + WHERE fid IN (?ai:forums)'; + $this->c->DB->exec($sql, $vars); - $sql = 'DELETE FROM ::forums - WHERE id IN (?ai:forums)'; - $this->c->DB->exec($sql, $vars); + $sql = 'DELETE FROM ::forums + WHERE id IN (?ai:forums)'; + $this->c->DB->exec($sql, $vars); + } } } diff --git a/app/Models/Pages/Admin/Users/Action.php b/app/Models/Pages/Admin/Users/Action.php index 7dfb57e4..701ef51c 100644 --- a/app/Models/Pages/Admin/Users/Action.php +++ b/app/Models/Pages/Admin/Users/Action.php @@ -8,6 +8,23 @@ use RuntimeException; class Action extends Users { + /** + * Возвращает список имен пользователей + * + * @param array $users + * + * @return array + */ + protected function nameList(array $users) + { + $result = []; + foreach ($users as $user) { + $result[] = $user->username; + } + \sort($result, \SORT_STRING | \SORT_FLAG_CASE); + return $result; + } + /** * Подготавливает данные для шаблона(ов) действия * @@ -77,7 +94,38 @@ class Action extends Users */ protected function delete(array $args, $method) { + if ('POST' === $method) { + $v = $this->c->Validator->reset() + ->addRules([ + 'token' => 'token:AdminUsersAction', + 'confirm' => 'required|integer|in:0,1', + 'delete_posts' => 'required|integer|in:0,1', + 'delete' => 'string', + ])->addAliases([ + ])->addArguments([ + 'token' => $args, + ]); + if (! $v->validation($_POST) || $v->confirm !== 1) { + return $this->c->Redirect->page('AdminUsers')->message('No confirm redirect'); + } + + if (1 === $v->delete_posts) { + foreach ($this->userList as $user) { + $user->__deleteAllPost = true; + } + } + + $this->c->DB->beginTransaction(); + + $this->c->users->delete(...$this->userList); + + $this->c->DB->commit(); + + $this->c->Cache->delete('stats'); + + return $this->c->Redirect->page('AdminUsers')->message('Users delete redirect'); + } $this->nameTpl = 'admin/form'; $this->classForm = 'delete-users'; @@ -86,24 +134,6 @@ class Action extends Users $this->form = $this->formDelete($args); return $this; - - } - - /** - * Возвращает список имен пользователей - * - * @param array $users - * - * @return array - */ - protected function nameList(array $users) - { - $result = []; - foreach ($users as $user) { - $result[] = $user->username; - } - \sort($result, \SORT_STRING | \SORT_FLAG_CASE); - return $result; } /** diff --git a/app/Models/Pages/Profile.php b/app/Models/Pages/Profile.php index ca080ad5..a43c52b8 100644 --- a/app/Models/Pages/Profile.php +++ b/app/Models/Pages/Profile.php @@ -86,7 +86,7 @@ abstract class Profile extends Page } if ($this->rules->deleteUser) { $btns['delete-user'] = [ - $this->c->Router->link('', ['id' => $this->curUser->id]), + $this->c->Router->link('AdminUsersAction', ['action' => 'delete', 'ids' => $this->curUser->id]), // ???? \ForkBB\__('Delete user'), ]; } diff --git a/app/Models/Post/Delete.php b/app/Models/Post/Delete.php index 9de25b86..a5b379ab 100644 --- a/app/Models/Post/Delete.php +++ b/app/Models/Post/Delete.php @@ -6,6 +6,7 @@ use ForkBB\Models\Action; use ForkBB\Models\Forum\Model as Forum; use ForkBB\Models\Post\Model as Post; use ForkBB\Models\Topic\Model as Topic; +use ForkBB\Models\User\Model as User; use PDO; use InvalidArgumentException; use RuntimeException; @@ -23,84 +24,102 @@ class Delete extends Action public function delete(...$args) { if (empty($args)) { - throw new InvalidArgumentException('No arguments, expected forum, topic or post'); + throw new InvalidArgumentException('No arguments, expected User(s), Forum(s), Topic(s) or Post(s)'); } - $posts = []; - $parents = []; - $topics = []; - $forums = []; + $users = []; + $usersToGuest = []; + $usersDel = []; + $forums = []; + $topics = []; + $posts = []; + $parents = []; + $isUser = 0; + $isForum = 0; + $isTopic = 0; + $isPost = 0; foreach ($args as $arg) { - if ($arg instanceof Post) { - if (! $arg->parent instanceof Topic || ! $arg->parent->parent instanceof Forum) { - throw new RuntimeException('Parents unavailable'); + if ($arg instanceof User) { + if ($arg->isGuest) { + throw new RuntimeException('Guest can not be deleted'); } - $posts[$arg->id] = $arg; - $parents[$arg->topic_id] = $arg->parent; - } elseif ($arg instanceof Topic) { - if (! $arg->parent instanceof Forum) { - throw new RuntimeException('Parent unavailable'); + if (true === $arg->deleteAllPost) { + $usersDel[] = $arg->id; + } else { + $usersToGuest[] = $arg->id; } - $topics[$arg->id] = $arg; + $isUser = 1; } elseif ($arg instanceof Forum) { if (! $this->c->forums->get($arg->id) instanceof Forum) { throw new RuntimeException('Forum unavailable'); } $forums[$arg->id] = $arg; + $isForum = 1; + } elseif ($arg instanceof Topic) { + if (! $arg->parent instanceof Forum) { + throw new RuntimeException('Parent unavailable'); + } + $topics[$arg->id] = $arg; + $isTopic = 1; + } elseif ($arg instanceof Post) { + if (! $arg->parent instanceof Topic || ! $arg->parent->parent instanceof Forum) { + throw new RuntimeException('Parents unavailable'); + } + $posts[$arg->id] = $arg->id; + $parents[$arg->topic_id] = $arg->parent; + $users[$post->poster_id] = $post->poster_id; + $isPost = 1; } else { - throw new InvalidArgumentException('Expected forum, topic or post'); + throw new InvalidArgumentException('Expected User(s), Forum(s), Topic(s) or Post(s)'); } } - if (! empty($posts) + ! empty($topics) + ! empty($forums) > 1) { - throw new InvalidArgumentException('Expected only forum, topic or post'); + if ($isUser + $isForum + $isTopic + $isPost > 1) { + throw new InvalidArgumentException('Expected only User(s), Forum(s), Topic(s) or Post(s)'); } $this->c->search->delete(...$args); - //???? подписки, опросы, предупреждения метки посещения тем - - $users = []; - - if ($posts) { - foreach ($posts as $post) { - $users[$post->poster_id] = true; - } - $users = \array_keys($users); + //???? подписки, опросы, предупреждения + if ($usersToGuest) { $vars = [ - ':posts' => \array_keys($posts), + ':users' => $usersToGuest, ]; - $sql = 'DELETE FROM ::posts - WHERE id IN (?ai:posts)'; + $sql = 'UPDATE ::posts + SET poster_id=1 + WHERE poster_id IN (?ai:users)'; $this->c->DB->exec($sql, $vars); - - $topics = $parents; - $parents = []; - - foreach ($topics as $topic) { - $parents[$topic->forum_id] = $topic->parent; - $this->c->topics->update($topic->calcStat()); - } - - foreach($parents as $forum) { - $this->c->forums->update($forum->calcStat()); - } - } elseif ($topics) { + } + if ($usersDel) { $vars = [ - ':topics' => \array_keys($topics), + ':users' => $usersDel, ]; - $sql = 'SELECT p.poster_id - FROM ::posts AS p - WHERE p.topic_id IN (?ai:topics) - GROUP BY p.poster_id'; - $users = $this->c->DB->query($sql, $vars)->fetchAll(PDO::FETCH_COLUMN); + $sql = 'SELECT p.topic_id + FROM ::posts as p + WHERE p.poster_id IN (?ai:users) + GROUP BY p.topic_id'; + $parents = $this->c->DB->query($sql, $vars)->fetchAll(PDO::FETCH_COLUMN); + + $sql = 'SELECT t.id + FROM ::topics AS t + INNER JOIN ::posts AS p ON t.first_post_id=p.id + WHERE p.poster_id IN (?ai:users)'; + $notUse = $this->c->DB->query($sql, $vars)->fetchAll(PDO::FETCH_COLUMN); + + $parents = \array_diff($parents, $notUse); //???? $sql = 'DELETE FROM ::posts - WHERE topic_id IN (?ai:topics)'; + WHERE poster_id IN (?ai:users)'; $this->c->DB->exec($sql, $vars); - } elseif ($forums) { + + foreach ($parents as &$parent) { + $parent = $this->c->topics->load($parent); //???? ааааАААААААААААААА О_о + } + unset($parent); + } + if ($forums) { $vars = [ ':forums' => \array_keys($forums), ]; @@ -119,7 +138,43 @@ class Delete extends Action )'; $this->c->DB->exec($sql, $vars); } + if ($topics) { + $vars = [ + ':topics' => \array_keys($topics), + ]; + $sql = 'SELECT p.poster_id + FROM ::posts AS p + WHERE p.topic_id IN (?ai:topics) + GROUP BY p.poster_id'; + $users = $this->c->DB->query($sql, $vars)->fetchAll(PDO::FETCH_COLUMN); - $this->c->users->updateCountPosts(...$users); + $sql = 'DELETE FROM ::posts + WHERE topic_id IN (?ai:topics)'; + $this->c->DB->exec($sql, $vars); + } + if ($posts) { + $vars = [ + ':posts' => $posts, + ]; + $sql = 'DELETE FROM ::posts + WHERE id IN (?ai:posts)'; + $this->c->DB->exec($sql, $vars); + } + if ($parents) { + $topics = $parents; + $parents = []; + + foreach ($topics as $topic) { + $parents[$topic->forum_id] = $topic->parent; + $this->c->topics->update($topic->calcStat()); + } + + foreach($parents as $forum) { + $this->c->forums->update($forum->calcStat()); + } + } + if ($users) { + $this->c->users->updateCountPosts(...$users); + } } } diff --git a/app/Models/Post/Model.php b/app/Models/Post/Model.php index c70bd545..91ac1e6f 100644 --- a/app/Models/Post/Model.php +++ b/app/Models/Post/Model.php @@ -46,7 +46,7 @@ class Model extends DataModel $user = $this->c->users->get($this->poster_id); if (! $user instanceof User) { - throw new RuntimeException('No user data'); + throw new RuntimeException('No user data in post number ' . $this->id); } elseif (1 === $this->poster_id) { $user = clone $user; $user->__email = $this->poster_email; diff --git a/app/Models/Search/Delete.php b/app/Models/Search/Delete.php index c011f5a9..61efa219 100644 --- a/app/Models/Search/Delete.php +++ b/app/Models/Search/Delete.php @@ -6,6 +6,7 @@ use ForkBB\Models\Method; use ForkBB\Models\Forum\Model as Forum; use ForkBB\Models\Post\Model as Post; use ForkBB\Models\Topic\Model as Topic; +use ForkBB\Models\User\Model as User; use PDO; use InvalidArgumentException; use RuntimeException; @@ -23,56 +24,68 @@ class Delete extends Method public function delete(...$args) { if (empty($args)) { - throw new InvalidArgumentException('No arguments, expected forum, topic or post'); + throw new InvalidArgumentException('No arguments, expected User(s), Forum(s), Topic(s) or Post(s)'); } - $posts = []; - $parents = []; - $topics = []; + $users = []; $forums = []; - // ????? + $topics = []; + $posts = []; + $isUser = 0; + $isForum = 0; + $isTopic = 0; + $isPost = 0; + foreach ($args as $arg) { - if ($arg instanceof Post) { - if (! $arg->parent instanceof Topic || ! $arg->parent->parent instanceof Forum) { - throw new RuntimeException('Parents unavailable'); + if ($arg instanceof User) { + if ($arg->isGuest) { + throw new RuntimeException('Guest can not be deleted'); } - $posts[$arg->id] = $arg; - } elseif ($arg instanceof Topic) { - if (! $arg->parent instanceof Forum) { - throw new RuntimeException('Parent unavailable'); + if (true === $arg->deleteAllPost) { + $users[] = $arg->id; } - $topics[$arg->id] = $arg; + $isUser = 1; } elseif ($arg instanceof Forum) { if (! $this->c->forums->get($arg->id) instanceof Forum) { throw new RuntimeException('Forum unavailable'); } $forums[$arg->id] = $arg; + $isForum = 1; + } elseif ($arg instanceof Topic) { + if (! $arg->parent instanceof Forum) { + throw new RuntimeException('Parent unavailable'); + } + $topics[$arg->id] = $arg; + $isTopic = 1; + } elseif ($arg instanceof Post) { + if (! $arg->parent instanceof Topic || ! $arg->parent->parent instanceof Forum) { + throw new RuntimeException('Parents unavailable'); + } + $posts[$arg->id] = $arg; + $isPost = 1; } else { - throw new InvalidArgumentException('Expected forum, topic or post'); + throw new InvalidArgumentException('Expected User(s), Forum(s), Topic(s) or Post(s)'); } } - if (! empty($posts) + ! empty($topics) + ! empty($forums) > 1) { - throw new InvalidArgumentException('Expected only forum, topic or post'); + if ($isUser + $isForum + $isTopic + $isPost > 1) { + throw new InvalidArgumentException('Expected only User(s), Forum(s), Topic(s) or Post(s)'); } - if ($posts) { + $sql = null; + + if ($users) { $vars = [ - ':posts' => \array_keys($posts), - ]; - $sql = 'DELETE FROM ::search_matches - WHERE post_id IN (?ai:posts)'; - } elseif ($topics) { - $vars = [ - ':topics' => \array_keys($topics), + ':users' => $users, ]; $sql = 'DELETE FROM ::search_matches WHERE post_id IN ( SELECT p.id FROM ::posts AS p - WHERE p.topic_id IN (?ai:topics) + WHERE p.poster_id IN (?ai:users) )'; - } elseif ($forums) { + } + if ($forums) { $vars = [ ':forums' => \array_keys($forums), ]; @@ -84,6 +97,26 @@ class Delete extends Method WHERE t.forum_id IN (?ai:forums) )'; } - $this->c->DB->exec($sql, $vars); + if ($topics) { + $vars = [ + ':topics' => \array_keys($topics), + ]; + $sql = 'DELETE FROM ::search_matches + WHERE post_id IN ( + SELECT p.id + FROM ::posts AS p + WHERE p.topic_id IN (?ai:topics) + )'; + } + if ($posts) { + $vars = [ + ':posts' => \array_keys($posts), + ]; + $sql = 'DELETE FROM ::search_matches + WHERE post_id IN (?ai:posts)'; + } + if ($sql) { + $this->c->DB->exec($sql, $vars); + } } } diff --git a/app/Models/Topic/Delete.php b/app/Models/Topic/Delete.php index f43805e6..e3bf767c 100644 --- a/app/Models/Topic/Delete.php +++ b/app/Models/Topic/Delete.php @@ -5,6 +5,8 @@ namespace ForkBB\Models\Topic; use ForkBB\Models\Action; use ForkBB\Models\Forum\Model as Forum; use ForkBB\Models\Topic\Model as Topic; +use ForkBB\Models\User\Model as User; +use PDO; use InvalidArgumentException; use RuntimeException; @@ -21,54 +23,83 @@ class Delete extends Action public function delete(...$args) { if (empty($args)) { - throw new InvalidArgumentException('No arguments, expected forum or topic'); + throw new InvalidArgumentException('No arguments, expected User(s), Forum(s) or Topic(s)'); } - $topics = []; - $parents = []; - $forums = []; + $users = []; + $usersDel = []; + $forums = []; + $topics = []; + $parents = []; + $isUser = 0; + $isForum = 0; + $isTopic = 0; foreach ($args as $arg) { - if ($arg instanceof Topic) { - if (! $arg->parent instanceof Forum) { - throw new RuntimeException('Parent unavailable'); + if ($arg instanceof User) { + if ($arg->isGuest) { + throw new RuntimeException('Guest can not be deleted'); } - $topics[$arg->id] = $arg; - $parents[$arg->forum_id] = $arg->parent; + if (true === $arg->deleteAllPost) { + $usersDel[] = $arg->id; + } + $users[] = $arg->id; + $isUser = 1; } elseif ($arg instanceof Forum) { if (! $this->c->forums->get($arg->id) instanceof Forum) { throw new RuntimeException('Forum unavailable'); } $forums[$arg->id] = $arg; + $isForum = 1; + } elseif ($arg instanceof Topic) { + if (! $arg->parent instanceof Forum) { + throw new RuntimeException('Parent unavailable'); + } + $topics[$arg->id] = $arg; + $parents[$arg->forum_id] = $arg->parent; + $isTopic = 1; } else { - throw new InvalidArgumentException('Expected forum or topic'); + throw new InvalidArgumentException('Expected User(s), Forum(s) or Topic(s)'); } } - if (! empty($topics) + ! empty($forums) > 1) { - throw new InvalidArgumentException('Expected only forum or topic'); + if ($isUser + $isForum + $isTopic > 1) { + throw new InvalidArgumentException('Expected only User(s), Forum(s) or Topic(s)'); + } + + if ($usersDel) { + $vars = [ + ':users' => $usersDel, + ]; + $sql = 'SELECT t.id, t.forum_id + FROM ::topics AS t + INNER JOIN ::posts AS p ON t.first_post_id=p.id + WHERE p.poster_id IN (?ai:users)'; + $topics = $this->c->DB->query($sql, $vars)->fetchAll(PDO::FETCH_KEY_PAIR); //???? + + if ($topics) { + foreach ($topics as $value) { // ???? + if (isset($parents[$value])) { + continue; + } + $parents[$value] = $this->c->forums->get($value); + } + } } $this->c->posts->delete(...$args); - //???? подписки, опросы, предупреждения, метки посещения тем + //???? подписки, опросы, предупреждения - if ($topics) { + if ($users) { $vars = [ - ':topics' => \array_keys($topics), + ':users' => $users, ]; $sql = 'DELETE FROM ::mark_of_topic - WHERE tid IN (?ai:topics)'; + WHERE uid IN (?ai:users)'; $this->c->DB->exec($sql, $vars); - - $sql = 'DELETE FROM ::topics - WHERE id IN (?ai:topics)'; - $this->c->DB->exec($sql, $vars); - - foreach($parents as $forum) { - $this->c->forums->update($forum->calcStat()); - } - } elseif ($forums) { + } + if ($forums) { $vars = [ ':forums' => \array_keys($forums), ]; @@ -84,5 +115,21 @@ class Delete extends Action WHERE forum_id IN (?ai:forums)'; $this->c->DB->exec($sql, $vars); } + if ($topics) { + $vars = [ + ':topics' => \array_keys($topics), + ]; + $sql = 'DELETE FROM ::mark_of_topic + WHERE tid IN (?ai:topics)'; + $this->c->DB->exec($sql, $vars); + + $sql = 'DELETE FROM ::topics + WHERE id IN (?ai:topics)'; + $this->c->DB->exec($sql, $vars); + + foreach($parents as $forum) { + $this->c->forums->update($forum->calcStat()); + } + } } } diff --git a/app/Models/User/Delete.php b/app/Models/User/Delete.php new file mode 100644 index 00000000..174c5cd0 --- /dev/null +++ b/app/Models/User/Delete.php @@ -0,0 +1,54 @@ +isGuest) { + throw new RuntimeException('Guest can not be deleted'); + } + $users[] = $arg->id; + } else { + throw new InvalidArgumentException('Expected User'); + } + } + + $this->c->forums->delete(...$args); + + //???? подписки, опросы, предупреждения + + foreach ($args as $user) { + $this->c->Online->delete($user); + } + + $vars = [ + ':users' => $users, + ]; + $sql = 'DELETE FROM ::users + WHERE id IN (?ai:users)'; + $this->c->DB->exec($sql, $vars); + } +} diff --git a/app/config/main.dist.php b/app/config/main.dist.php index 6a16841c..3119d2f1 100644 --- a/app/config/main.dist.php +++ b/app/config/main.dist.php @@ -212,6 +212,7 @@ return [ 'UserManagerUsersNumber' => \ForkBB\Models\User\UsersNumber::class, 'UserManagerPromote' => \ForkBB\Models\User\Promote::class, 'UserManagerFilter' => \ForkBB\Models\User\Filter::class, + 'UserManagerDelete' => \ForkBB\Models\User\Delete::class, 'ForumModel' => \ForkBB\Models\Forum\Model::class, 'ForumModelCalcStat' => \ForkBB\Models\Forum\CalcStat::class,