Перенос ветки blacklist (#900)

* Blacklist

* Config

* upd

* Added restrictions in the users.get method

* ok

* Update en.strings

* ok 2.0

---------

Co-authored-by: Vladimir Barinov <veselcraft@icloud.com>
This commit is contained in:
n1rwana 2023-06-15 12:36:36 +03:00 committed by GitHub
parent 0d167ac18b
commit 29f482419c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 283 additions and 21 deletions

View file

@ -2,6 +2,7 @@
namespace openvk\VKAPI\Handlers;
use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Repositories\Users as UsersRepo;
use openvk\Web\Models\Repositories\Blacklists;
final class Users extends VKAPIRequestHandler
{
@ -40,12 +41,15 @@ final class Users extends VKAPIRequestHandler
"id" => $usr->getId(),
"first_name" => $usr->getFirstName(),
"last_name" => $usr->getLastName(),
"is_closed" => false,
"can_access_closed" => true,
"is_closed" => (new Blacklists)->isBanned($usr, $authuser),
"can_access_closed" => !(new Blacklists)->isBanned($usr, $authuser),
"blacklisted" => (new Blacklists)->isBanned($usr, $authuser),
"blacklisted_by_me" => (new Blacklists)->isBanned($authuser, $usr)
];
$flds = explode(',', $fields);
if (!(new Blacklists)->isBanned($usr, $authuser))
foreach($flds as $field) {
switch($field) {
case "verified":
@ -157,10 +161,11 @@ final class Users extends VKAPIRequestHandler
}
}
if($usr->getOnline()->timestamp() + 300 > time())
$response[$i]->online = 1;
else
$response[$i]->online = 0;
if (!(new Blacklists)->isBanned($usr, $authuser))
if($usr->getOnline()->timestamp() + 300 > time())
$response[$i]->online = 1;
else
$response[$i]->online = 0;
}
}
}
@ -176,8 +181,14 @@ final class Users extends VKAPIRequestHandler
$users = new UsersRepo;
$this->requireUser();
foreach($users->get($user_id)->getFollowers($offset, $count) as $follower)
$authuser = $this->getUser();
$target = $users->get($user_id);
if ((new Blacklists)->isBanned($target, $authuser))
$this->fail(15, "Access denied: User is blacklisted");
foreach($target->getFollowers($offset, $count) as $follower)
$followers[] = $follower->getId();
$response = $followers;
@ -186,7 +197,7 @@ final class Users extends VKAPIRequestHandler
$response = $this->get(implode(',', $followers), $fields, 0, $count);
return (object) [
"count" => $users->get($user_id)->getFollowersCount(),
"count" => $target->getFollowersCount(),
"items" => $response
];
}

View file

@ -0,0 +1,31 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Entities;
use openvk\Web\Models\RowModel;
use openvk\Web\Util\DateTime;
use openvk\Web\Models\Entities\{User, Manager};
use openvk\Web\Models\Repositories\{Users, Clubs};
class BlacklistItem extends RowModel
{
protected $tableName = "blacklists";
function getId(): int
{
return $this->getRecord()->index;
}
function getAuthor(): ?User
{
return (new Users)->get($this->getRecord()->author);
}
function getTarget(): ?User
{
return (new Users)->get($this->getRecord()->target);
}
function getCreationDate(): DateTime
{
return new DateTime($this->getRecord()->created);
}
}

View file

@ -5,7 +5,7 @@ use openvk\Web\Themes\{Themepack, Themepacks};
use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift};
use openvk\Web\Models\Repositories\{Photos, Users, Clubs, Albums, Gifts, Notifications};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Photos, Gifts, Notifications, Blacklists};
use openvk\Web\Models\Exceptions\InvalidUserNameException;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
@ -440,6 +440,9 @@ class User extends RowModel
return $permStatus === User::PRIVACY_EVERYONE;
else if($user->getId() === $this->getId())
return true;
else if ((new Blacklists)->isBanned($this, $user)) {
return $user->isAdmin() && !OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["blacklists"]["applyToAdmins"];
}
switch($permStatus) {
case User::PRIVACY_ONLY_FRIENDS:
@ -1094,6 +1097,11 @@ class User extends RowModel
return (bool) $this->getRecord()->activated;
}
function isAdmin(): bool
{
return $this->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL);
}
function getUnbanTime(): ?string
{
return !is_null($this->getRecord()->unblock_time) ? date('d.m.Y', $this->getRecord()->unblock_time) : NULL;

View file

@ -0,0 +1,42 @@
<?php declare(strict_types=1);
namespace openvk\Web\Models\Repositories;
use openvk\Web\Models\Entities\{User, BlacklistItem};
use openvk\Web\Models\Repositories\{Clubs, Users};
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection as DB;
class Blacklists
{
private $context;
private $blacklists;
function __construct()
{
$this->context = DB::i()->getContext();
$this->blacklists = $this->context->table("blacklists");
}
function getList(User $user, $page = 1): \Traversable
{
foreach($this->blacklists->where("author", $user->getId())->order("created DESC")->page($page, 10) as $blacklistItem)
yield new BlacklistItem($blacklistItem);
}
function getByAuthorAndTarget(int $author, int $target): ?BlacklistItem
{
return new BlacklistItem($this->blacklists->where(["author" => $author, "target" => $target])->fetch());
}
function getCount(User $user): int
{
return sizeof($this->blacklists->where("author", $user->getId())->fetch());
}
function isBanned(User $author, User $target): bool
{
if (!$author || !$target)
return FALSE;
return !is_null($this->getByAuthorAndTarget($author->getId(), $target->getId()));
}
}

View file

@ -0,0 +1,43 @@
<?php declare(strict_types=1);
namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{BlacklistItem};
use openvk\Web\Models\Repositories\{Blacklists, Users};
use Chandler\Database\DatabaseConnection as DB;
final class BlacklistPresenter extends OpenVKPresenter
{
private $blacklists;
function __construct(Blacklists $blacklists)
{
$this->blacklists = $blacklists;
}
function renderAddToBlacklist(): void
{
$this->willExecuteWriteAction();
$this->assertUserLoggedIn();
$record = new BlacklistItem;
$target = (new Users)->get((int) $this->postParam("id"));
$record->setAuthor($this->user->identity->getId());
$record->setTarget($this->postParam("id"));
$record->setCreated(time());
$record->save();
$this->flashFail("succ", tr("success"), tr("user_blacklisted", $target->getCanonicalName()));
}
function renderRemoveFromBlacklist(): void
{
$this->willExecuteWriteAction();
$this->assertUserLoggedIn();
$record = $this->blacklists->getByAuthorAndTarget($this->user->identity->getId(), $this->postParam("id"));
$name = $record->getTarget()->getCanonicalName();
$record->delete(false);
$this->flashFail("succ", tr("success"), tr("user_removed_from_the_blacklist", $name));
}
}

View file

@ -1,7 +1,7 @@
<?php declare(strict_types=1);
namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\{Club, Photo, Album};
use openvk\Web\Models\Repositories\{Photos, Albums, Users, Clubs};
use openvk\Web\Models\Repositories\{Photos, Albums, Users, Clubs, Blacklists};
use Nette\InvalidStateException as ISE;
final class PhotosPresenter extends OpenVKPresenter
@ -27,6 +27,7 @@ final class PhotosPresenter extends OpenVKPresenter
if(!$user) $this->notFound();
if (!$user->getPrivacyPermission('photos.read', $this->user->identity ?? NULL))
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
$this->template->albums = $this->albums->getUserAlbums($user, $this->queryParam("p") ?? 1);
$this->template->count = $this->albums->getUserAlbumsCount($user);
$this->template->owner = $user;
@ -136,6 +137,11 @@ final class PhotosPresenter extends OpenVKPresenter
if(!$album) $this->notFound();
if($album->getPrettyId() !== $owner . "_" . $id || $album->isDeleted())
$this->notFound();
if ((new Blacklists)->isBanned($album->getOwner(), $this->user->identity)) {
if (!$this->user->identity->isAdmin() OR $this->user->identity->isAdmin() AND OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["blacklists"]["applyToAdmins"])
$this->flashFail("err", tr("forbidden"), tr("user_blacklisted_you"));
}
if($owner > 0 /* bc we currently don't have perms for clubs */) {
$ownerObject = (new Users)->get($owner);
@ -158,7 +164,12 @@ final class PhotosPresenter extends OpenVKPresenter
{
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
if(!$photo || $photo->isDeleted()) $this->notFound();
if ((new Blacklists)->isBanned($photo->getOwner(), $this->user->identity)) {
if (!$this->user->identity->isAdmin() OR $this->user->identity->isAdmin() AND OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["blacklists"]["applyToAdmins"])
$this->flashFail("err", tr("forbidden"), tr("user_blacklisted_you"));
}
if(!is_null($this->queryParam("from"))) {
if(preg_match("%^album([0-9]++)$%", $this->queryParam("from"), $matches) === 1) {
$album = $this->albums->get((int) $matches[1]);

View file

@ -5,7 +5,7 @@ use openvk\Web\Util\Sms;
use openvk\Web\Themes\Themepacks;
use openvk\Web\Models\Entities\{Photo, Post, EmailChangeVerification};
use openvk\Web\Models\Entities\Notifications\{CoinsTransferNotification, RatingUpNotification};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications};
use openvk\Web\Models\Repositories\{Users, Clubs, Albums, Videos, Notes, Vouchers, EmailChangeVerifications, Blacklists};
use openvk\Web\Models\Exceptions\InvalidUserNameException;
use openvk\Web\Util\Validator;
use Chandler\Security\Authenticator;
@ -15,20 +15,34 @@ use Nette\Database\UniqueConstraintViolationException;
final class UserPresenter extends OpenVKPresenter
{
private $users;
public $deactivationTolerant = false;
protected $presenterName = "user";
private $users;
private $blacklists;
function __construct(Users $users)
function __construct(Users $users, Blacklists $blacklists)
{
$this->users = $users;
$this->blacklists = $blacklists;
parent::__construct();
}
function renderView(int $id): void
{
$user = $this->users->get($id);
if ($this->user->identity)
if ($this->blacklists->isBanned($user, $this->user->identity)) {
if ($this->user->identity->isAdmin()) {
if (OPENVK_ROOT_CONF["openvk"]["preferences"]["security"]["blacklists"]["applyToAdmins"]) {
$this->flashFail("err", tr("forbidden"), tr("user_blacklisted_you"));
}
} else {
$this->flashFail("err", tr("forbidden"), tr("user_blacklisted_you"));
}
}
if(!$user || $user->isDeleted()) {
if(!is_null($user) && $user->isDeactivated()) {
$this->template->_template = "User/deactivated.xml";
@ -45,8 +59,11 @@ final class UserPresenter extends OpenVKPresenter
$this->template->videosCount = (new Videos)->getUserVideosCount($user);
$this->template->notes = (new Notes)->getUserNotes($user, 1, 4);
$this->template->notesCount = (new Notes)->getUserNotesCount($user);
$this->template->blacklists = (new Blacklists);
$this->template->user = $user;
$this->template->isBlacklistedThem = $this->template->blacklists->isBanned($this->user->identity, $user);
$this->template->isBlacklistedByThem = $this->template->blacklists->isBanned($user, $this->user->identity);
}
}
@ -498,7 +515,7 @@ final class UserPresenter extends OpenVKPresenter
$this->flash("succ", tr("changes_saved"), tr("changes_saved_comment"));
}
$this->template->mode = in_array($this->queryParam("act"), [
"main", "security", "privacy", "finance", "finance.top-up", "interface"
"main", "security", "privacy", "finance", "finance.top-up", "interface", "blacklist"
]) ? $this->queryParam("act")
: "main";
@ -512,6 +529,11 @@ final class UserPresenter extends OpenVKPresenter
$this->template->qrCodeType = substr($qrCode[0], 5);
$this->template->qrCodeData = $qrCode[1];
}
if($this->template->mode == "blacklist") {
$this->template->items = $this->blacklists->getList($user);
$this->template->count = $this->blacklists->getCount($user);
}
$this->template->user = $user;
$this->template->themes = Themepacks::i()->getThemeList();

View file

@ -1,7 +1,7 @@
<?php declare(strict_types=1);
namespace openvk\Web\Presenters;
use openvk\Web\Models\Entities\Video;
use openvk\Web\Models\Repositories\{Users, Videos};
use openvk\Web\Models\Repositories\{Users, Videos, Blacklists};
use Nette\InvalidStateException as ISE;
final class VideosPresenter extends OpenVKPresenter
@ -40,8 +40,12 @@ final class VideosPresenter extends OpenVKPresenter
{
$user = $this->users->get($owner);
if(!$user) $this->notFound();
if(!$user->getPrivacyPermission('videos.read', $this->user->identity ?? NULL))
if(!$user->getPrivacyPermission('videos.read', $this->user->identity ?? NULL)) {
if ((new Blacklists)->isBanned($user, $this->user->identity))
$this->flashFail("err", tr("forbidden"), tr("user_blacklisted_you"));
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));
}
if($this->videos->getByOwnerAndVID($owner, $vId)->isDeleted()) $this->notFound();

View file

@ -13,6 +13,7 @@
{var $isFinance = $mode === 'finance'}
{var $isFinanceTU = $mode === 'finance.top-up'}
{var $isInterface = $mode === 'interface'}
{var $isBlackList = $mode === 'blacklist'}
<div class="tabs">
<div n:attr="id => ($isMain ? 'activetabs' : 'ki')" class="tab">
@ -30,6 +31,9 @@
<div n:attr="id => ($isInterface ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($isInterface ? 'act_tab_a' : 'ki')" href="/settings?act=interface">{_interface}</a>
</div>
<div n:attr="id => ($isBlackList ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($isBlackList ? 'act_tab_a' : 'ki')" href="/settings?act=blacklist">{_blacklist}</a>
</div>
</div>
<div class="container_gray">
@ -683,7 +687,49 @@
</tbody>
</table>
</form>
{elseif $isBlackList}
{if $count < 1}
{include "../components/nothing.xml"}
{/if}
<div n:foreach="$items as $item" class="content">
<table>
<tbody>
<tr>
<td valign="top">
<a href="/id2">
<img src="{$item->getTarget()->getAvatarURL()}" width="75" alt="Фотография пользователя">
</a>
</td>
<td valign="top" style="width: 100%">
<a href="/id2">
<b>
{$item->getTarget()->getCanonicalName()}
<img n:if="$item->getTarget()->isVerified()" class="name-checkmark" src="/assets/packages/static/openvk/img/checkmark.png">
</b>
</a>
<br>
<table>
<tbody>
<tr>
<td width="120" valign="top"><span class="nobold">Дата добавления:</span></td>
<td>{$item->getCreationDate()}</td>
</tr>
</tbody>
</table>
</td>
<td valign="top" class="action_links" style="width: 150px;">
<form action="/removeFromBl" method="post" class="profile_link_form">
<input type="hidden" name="act" value="rem">
<input type="hidden" name="id" value="{$item->getTarget()->getId()}">
<input type="hidden" name="hash" value="{$csrfToken}">
<input type="submit" class="profile_link" value="удалить из чёрного списка">
</form>
</td>
</tr>
</tbody>
</table>
</div>
{/if}
</div>

View file

@ -165,6 +165,19 @@
{/if}
{/if}
<a style="width: 194px;" n:if="$user->getFollowersCount() > 0" href="/friends{$user->getId()}?act=incoming" class="profile_link">{tr("followers", $user->getFollowersCount())}</a>
{if $isBlacklistedThem}
<form n:if="$thisUser->getId() != $user->getId()" action="/removeFromBl" method="post" class="profile_link_form">
<input type="hidden" name="id" value="{$user->getId()}" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<input type="submit" class="profile_link" value="Удалить из чёрного списка" />
</form>
{else}
<form n:if="$thisUser->getId() != $user->getId()" action="/addToBl" method="post" class="profile_link_form">
<input type="hidden" name="id" value="{$user->getId()}" />
<input type="hidden" name="hash" value="{$csrfToken}" />
<input type="submit" class="profile_link" value="Добавить в чёрный список" />
</form>
{/if}
</div>
<div n:if="isset($thisUser) && !$thisUser->prefersNotToSeeRating()" class="profile-hints">
{var $completeness = $user->getProfileCompletenessReport()}
@ -380,6 +393,11 @@
<div class="right_big_block">
<div class="page_info">
<div n:if="$isBlacklistedByThem AND $thisUser->isAdmin() AND $thisUser->getId() !== $user->getId()" class="user-alert">
<b>{admin_privacy_warning}:</b>
<br/>
{_user_blacklisted_you}
</div>
<div n:if="!is_null($alert = $user->getAlert())" class="user-alert">{strpos($alert, "@") === 0 ? tr(substr($alert, 1)) : $alert}</div>
{var $thatIsThisUser = isset($thisUser) && $user->getId() == $thisUser->getId()}
<div n:if="$thatIsThisUser" class="page_status_popup" id="status_editor" style="display: none;">

View file

@ -23,6 +23,7 @@ services:
- openvk\Web\Presenters\AppsPresenter
- openvk\Web\Presenters\ThemepacksPresenter
- openvk\Web\Presenters\VKAPIPresenter
- openvk\Web\Presenters\BlacklistPresenter
- openvk\Web\Presenters\PollPresenter
- openvk\Web\Presenters\BannedLinkPresenter
- openvk\Web\Models\Repositories\Users
@ -45,6 +46,7 @@ services:
- openvk\Web\Models\Repositories\Topics
- openvk\Web\Models\Repositories\Applications
- openvk\Web\Models\Repositories\ContentSearchRepository
- openvk\Web\Models\Repositories\Blacklists
- openvk\Web\Models\Repositories\Aliases
- openvk\Web\Models\Repositories\BannedLinks
- openvk\Web\Models\Repositories\ChandlerGroups

View file

@ -105,6 +105,10 @@ routes:
handler: "Group->sub"
- url: "/setSub/v4/club"
handler: "Group->attend"
- url: "/removeFromBl"
handler: "Blacklist->removeFromBlacklist"
- url: "/addToBl"
handler: "Blacklist->addToBlacklist"
- url: "/groups/{num}/setNewOwner/{num}"
handler: "Group->changeOwner"
- url: "/comment{num}/like"

View file

@ -1177,6 +1177,8 @@
"admin_commerce_disabled" = "Commerce has been disabled by the system administrator";
"admin_commerce_disabled_desc" = "The voucher and gift settings will be saved, but will have no effect.";
"admin_privacy_warning" = "Be careful with this information";
"admin_banned_links" = "Blocked links";
"admin_banned_link" = "Link";
"admin_banned_domain" = "Domain";
@ -1245,6 +1247,13 @@
"cookies_popup_content" = "All kids love cookie, so this website uses Cookies to identify your session and nothing more. Check <a href='/privacy'>our privacy policy</a> for more information.";
"cookies_popup_agree" = "Accept";
/* Blacklist */
"blacklist" = "Blacklist";
"user_blacklisted_you" = "This user has blacklisted you.";
"user_blacklisted" = "$1 has been blacklisted"
"user_removed_from_the_blacklist" = "$1 has been removed from the blacklist."
/* Away */
"url_is_banned" = "Link is not allowed";

View file

@ -1066,6 +1066,7 @@
"admin_about_instance" = "Инстанция";
"admin_commerce_disabled" = "Коммерция отключена системным администратором";
"admin_commerce_disabled_desc" = "Настройки ваучеров и подарков будут сохранены, но не будут оказывать никакого влияния.";
"admin_privacy_warning" = "Будьте осторожны с этой информацией";
"admin_banned_links" = "Заблокированные ссылки";
"admin_banned_link" = "Ссылка";
"admin_banned_domain" = "Домен";
@ -1123,6 +1124,7 @@
"edit_action" = "Изменить";
"transfer" = "Передать";
"close" = "Закрыть";
"success" = "Успех";
"warning" = "Внимание";
"question_confirm" = "Это действие нельзя отменить. Вы действительно уверены в том что хотите сделать?";
@ -1136,6 +1138,13 @@
"cookies_popup_content" = "Все дети любят печенье, поэтому этот веб-сайт использует Cookies для того, чтобы идентифицировать вашу сессию и ничего более. Ознакомьтесь с нашей <a href='/privacy'>политикой конфиденциальности</a> для получения дополнительной информации.";
"cookies_popup_agree" = "Согласен";
/* Blacklist */
"blacklist" = "Чёрный список";
"user_blacklisted_you" = "Пользователь внёс Вас в чёрный список.";
"user_blacklisted" = "$1 занесён в чёрный список."
"user_removed_from_the_blacklist" = "$1 удалён из чёрного списка."
/* Away */
"url_is_banned" = "Переход невозможен";

View file

@ -38,6 +38,8 @@ openvk:
maxViolations: 50
maxViolationsAge: 120
autoban: true
blacklists:
applyToAdmins: true
registration:
enable: true
disablingReason: ""