diff --git a/ServiceAPI/Wall.php b/ServiceAPI/Wall.php index c7a8362c..102c50ce 100644 --- a/ServiceAPI/Wall.php +++ b/ServiceAPI/Wall.php @@ -143,4 +143,30 @@ class Wall implements Handler $resolve($arr); } + + function getIgnoredSources(int $page = 1, callable $resolve, callable $reject) + { + $surses = $this->user->getIgnoredSources($page, 10); + + $arr = [ + "count" => $this->user->getIgnoredSourcesCount(), + "items" => [] + ]; + + foreach($surses as $surs) { + $arr["items"][] = [ + "id" => $surs->getRealId(), + "name" => $surs->getCanonicalName(), + "additional" => (($surs->getRealId() > 0 ? $surs->getStatus() : $surs->getDescription()) ?? "..."), + "avatar" => $surs->getAvatarURL(), + "url" => $surs->getURL(), + ]; + } + + if(rand(0, 200) == 50) { + $arr["fact"] = $this->user->getIgnoresCount(); + } + + $resolve($arr); + } } diff --git a/VKAPI/Handlers/Newsfeed.php b/VKAPI/Handlers/Newsfeed.php index 64ee1862..fc876b5f 100644 --- a/VKAPI/Handlers/Newsfeed.php +++ b/VKAPI/Handlers/Newsfeed.php @@ -1,9 +1,9 @@ requireUser(); @@ -56,12 +56,18 @@ final class Newsfeed extends VKAPIRequestHandler if($this->getUser()->getNsfwTolerance() === User::NSFW_INTOLERANT) $queryBase .= " AND `nsfw` = 0"; + + if(($ignoredCount = $this->getUser()->getIgnoredSourcesCount()) > 0 && $return_banned == 0) { + $sources = implode("', '", $this->getUser()->getIgnoredSources(1, $ignoredCount, true)); + + $queryBase .= " AND `posts`.`wall` NOT IN ('$sources')"; + } $start_from = empty($start_from) ? PHP_INT_MAX : $start_from; $start_time = empty($start_time) ? 0 : $start_time; $end_time = empty($end_time) ? PHP_INT_MAX : $end_time; $posts = DatabaseConnection::i()->getConnection()->query("SELECT `posts`.`id` " . $queryBase . " AND `posts`.`id` <= " . $start_from . " AND " . $start_time . " <= `posts`.`created` AND `posts`.`created` <= " . $end_time . " ORDER BY `created` DESC LIMIT " . $count . " OFFSET " . $offset); - + $rposts = []; $ids = []; foreach($posts as $post) { @@ -74,4 +80,130 @@ final class Newsfeed extends VKAPIRequestHandler return $response; } + + function getBanned(int $extended = 0, string $fields = "", string $name_case = "nom") + { + $this->requireUser(); + + $count = 50; + $offset = 0; + + $banned = array_slice($this->getUser()->getIgnoredSources(1, $count + $offset, true), $offset); + + if($extended == 0) { + $retArr/*d*/ = [ + "groups" => [], + "members" => [] # why + ]; + + foreach($banned as $ban) { + if($ban > 0) { + $retArr["members"][] = $ban; + } else { + $retArr["groups"][] = $ban; + } + } + + return $retArr; + } else { + $retArr = [ + "groups" => [], + "profiles" => [] + ]; + + $usIds = ""; + $clubIds = ""; + + foreach($banned as $ban) { + if($ban > 0) { + $usIds .= $ban . ","; + } else { + $clubIds .= ($ban * -1) . ","; + } + } + + $retArr["profiles"][] = (new Users)->get($usIds, $fields); + $retArr["groups"][] = (new Groups)->getById($clubIds, $fields); + + return $retArr; + } + } + + function addBan(string $user_ids = "", string $group_ids = "") + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + if(empty($user_ids) && empty($group_ids)) + $this->fail(52, "Provide 'user_ids' or 'groups_ids'"); + + $arr = []; + + if(!empty($user_ids)) { + $arr = array_merge($arr, array_map(function($el) { + return (int)$el; + }, explode(",", $user_ids))); + } + + if(!empty($group_ids)) { + $arr = array_merge($arr, array_map(function($el) { + return abs((int)$el) * -1; + }, explode(",", $group_ids))); + } + + $arr = array_unique($arr); + if(sizeof($arr) > 10 || sizeof($arr) < 1) + $this->fail(20, "You can ignore only 10 users/groups at once"); + + $successes = 0; + foreach($arr as $ar) { + $entity = getEntity($ar); + + if(!$entity || $entity->isHideFromGlobalFeedEnabled() || $entity->isIgnoredBy($this->getUser())) continue; + + $entity->toggleIgnore($this->getUser()); + $successes += 1; + } + + return (int)($successes > 0); + } + + function deleteBan(string $user_ids = "", string $group_ids = "") + { + $this->requireUser(); + $this->willExecuteWriteAction(); + + if(empty($user_ids) && empty($group_ids)) + $this->fail(52, "Provide 'user_ids' or 'groups_ids'"); + + $arr = []; + + if(!empty($user_ids)) { + $arr = array_merge($arr, array_map(function($el) { + return (int)$el; + }, explode(",", $user_ids))); + } + + if(!empty($group_ids)) { + $arr = array_merge($arr, array_map(function($el) { + return abs((int)$el) * -1; + }, explode(",", $group_ids))); + } + + $arr = array_unique($arr); + if(sizeof($arr) > 10 || sizeof($arr) < 1) + $this->fail(20, "You can unignore only 10 users/groups at once"); + + $successes = 0; + foreach($arr as $ar) { + $entity = getEntity($ar); + + if(!$entity || $entity->isHideFromGlobalFeedEnabled() || !$entity->isIgnoredBy($this->getUser())) continue; + + $entity->toggleIgnore($this->getUser()); + $successes += 1; + } + + return (int)($successes > 0); + } } diff --git a/Web/Models/Entities/Club.php b/Web/Models/Entities/Club.php index dc1c356e..2bff8995 100644 --- a/Web/Models/Entities/Club.php +++ b/Web/Models/Entities/Club.php @@ -469,4 +469,5 @@ class Club extends RowModel use Traits\TBackDrops; use Traits\TSubscribable; use Traits\TAudioStatuses; + use Traits\TIgnorable; } diff --git a/Web/Models/Entities/Traits/TIgnorable.php b/Web/Models/Entities/Traits/TIgnorable.php new file mode 100644 index 00000000..a3bbc1a1 --- /dev/null +++ b/Web/Models/Entities/Traits/TIgnorable.php @@ -0,0 +1,48 @@ +getContext(); + $data = [ + "owner" => $user->getId(), + "ignored_source" => $this->getRealId(), + ]; + + $sub = $ctx->table("ignored_sources")->where($data); + + if(!$sub->fetch()) { + return false; + } + + return true; + } + + function getIgnoresCount() + { + return sizeof(DatabaseConnection::i()->getContext()->table("ignored_sources")->where("ignored_source", $this->getRealId())); + } + + function toggleIgnore(User $user): bool + { + if($this->isIgnoredBy($user)) { + DatabaseConnection::i()->getContext()->table("ignored_sources")->where([ + "owner" => $user->getId(), + "ignored_source" => $this->getRealId(), + ])->delete(); + + return false; + } else { + DatabaseConnection::i()->getContext()->table("ignored_sources")->insert([ + "owner" => $user->getId(), + "ignored_source" => $this->getRealId(), + ]); + + return true; + } + } +} diff --git a/Web/Models/Entities/User.php b/Web/Models/Entities/User.php index 4f1fbff1..697abdde 100644 --- a/Web/Models/Entities/User.php +++ b/Web/Models/Entities/User.php @@ -1338,7 +1338,37 @@ class User extends RowModel return $res; } + + function getIgnoredSources(int $page = 1, int $perPage = 10, bool $onlyIds = false) + { + $sources = DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())->page($page, $perPage); + $arr = []; + foreach($sources as $source) { + $ignoredSource = (int)$source->ignored_source; + + if($ignoredSource > 0) + $ignoredSourceModel = (new Users)->get($ignoredSource); + else + $ignoredSourceModel = (new Clubs)->get(abs($ignoredSource)); + + if(!$ignoredSourceModel) + continue; + + if(!$onlyIds) + $arr[] = $ignoredSourceModel; + else + $arr[] = $ignoredSourceModel->getRealId(); + } + + return $arr; + } + + function getIgnoredSourcesCount() + { + return sizeof(DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())); + } + function getAudiosCollectionSize() { return (new \openvk\Web\Models\Repositories\Audios)->getUserCollectionSize($this); @@ -1378,7 +1408,13 @@ class User extends RowModel return $returnArr; } + function isHideFromGlobalFeedEnabled(): bool + { + return $this->isClosed(); + } + use Traits\TBackDrops; use Traits\TSubscribable; use Traits\TAudioStatuses; + use Traits\TIgnorable; } diff --git a/Web/Presenters/WallPresenter.php b/Web/Presenters/WallPresenter.php index b29968d0..04cf44ed 100644 --- a/Web/Presenters/WallPresenter.php +++ b/Web/Presenters/WallPresenter.php @@ -197,6 +197,12 @@ final class WallPresenter extends OpenVKPresenter if($this->user->identity->getNsfwTolerance() === User::NSFW_INTOLERANT) $queryBase .= " AND `nsfw` = 0"; + if(($ignoredCount = $this->user->identity->getIgnoredSourcesCount()) > 0) { + $sources = implode("', '", $this->user->identity->getIgnoredSources(1, $ignoredCount, true)); + + $queryBase .= " AND `posts`.`wall` NOT IN ('$sources')"; + } + $posts = DatabaseConnection::i()->getConnection()->query("SELECT `posts`.`id` " . $queryBase . " ORDER BY `created` DESC LIMIT " . $pPage . " OFFSET " . ($page - 1) * $pPage); $count = DatabaseConnection::i()->getConnection()->query("SELECT COUNT(*) " . $queryBase)->fetch()->{"COUNT(*)"}; @@ -650,7 +656,61 @@ final class WallPresenter extends OpenVKPresenter "avatar" => $post->getOwner()->getAvatarUrl() ]]); } + + function renderIgnoreSource() + { + $this->assertUserLoggedIn(); + $this->willExecuteWriteAction(true); + if($_SERVER["REQUEST_METHOD"] !== "POST") + exit(""); + + $owner = $this->user->id; + $ignoredSource = (int)$this->postParam("source"); + + if($this->user->identity->getIgnoredSourcesCount() > 50) + $this->flashFail("err", "Error", tr("max_ignores", 50), null, true); + + if($ignoredSource > 0) { + $ignoredSourceModel = (new Users)->get($ignoredSource); + + if(!$ignoredSourceModel) + $this->flashFail("err", "Error", tr("invalid_user"), null, true); + + if($ignoredSourceModel->getId() == $this->user->id) + $this->flashFail("err", "Error", tr("cant_ignore_self"), null, true); + + if($ignoredSourceModel->isClosed()) + $this->flashFail("err", "Error", tr("no_sense"), null, true); + } else { + $ignoredSourceModel = (new Clubs)->get(abs($ignoredSource)); + + if(!$ignoredSourceModel) + $this->flashFail("err", "Error", tr("invalid_club"), null, true); + + if($ignoredSourceModel->isHideFromGlobalFeedEnabled()) + $this->flashFail("err", "Error", tr("no_sense"), null, true); + } + + if(!$ignoredSourceModel->toggleIgnore($this->user->identity)) { + $tr = ""; + + if($ignoredSource > 0) + $tr = tr("ignore_user"); + else + $tr = tr("ignore_club"); + + $this->returnJson(["success" => true, "act" => "unignored", "text" => $tr]); + } else { + if($ignoredSource > 0) + $tr = tr("unignore_user"); + else + $tr = tr("unignore_club"); + + $this->returnJson(["success" => true, "act" => "ignored", "text" => $tr]); + } + } + function renderAccept() { $this->assertUserLoggedIn(); $this->willExecuteWriteAction(true); diff --git a/Web/Presenters/templates/@layout.xml b/Web/Presenters/templates/@layout.xml index 415f930f..d1bbd5ee 100644 --- a/Web/Presenters/templates/@layout.xml +++ b/Web/Presenters/templates/@layout.xml @@ -401,6 +401,7 @@ {ifset $thisUser} {script "js/al_notifs.js"} + {script "js/al_feed.js"} {/ifset} {if OPENVK_ROOT_CONF['openvk']['preferences']['bellsAndWhistles']['fartscroll']} diff --git a/Web/Presenters/templates/Group/View.xml b/Web/Presenters/templates/Group/View.xml index 91a96119..bc0aa786 100644 --- a/Web/Presenters/templates/Group/View.xml +++ b/Web/Presenters/templates/Group/View.xml @@ -175,6 +175,9 @@ {var $canReport = $thisUser->getId() != $club->getOwner()->getId()} {if $canReport} {_report} + + {if !$club->isIgnoredBy($thisUser)}{_ignore_club}{else}{_unignore_club}{/if} +