Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(privacy): blacklist v2 #1183

Merged
merged 14 commits into from
Dec 13, 2024
68 changes: 68 additions & 0 deletions VKAPI/Handlers/Account.php
Original file line number Diff line number Diff line change
Expand Up @@ -228,4 +228,72 @@ function sendVotes(int $receiver, int $value, string $message = ""): object

return (object) ['votes' => $this->getUser()->getCoins()];
}

function ban(int $owner_id): int
{
$this->requireUser();
$this->willExecuteWriteAction();

if($owner_id < 0)
return 1;

if($owner_id == $this->getUser()->getId())
$this->fail(15, "Access denied: cannot blacklist yourself");

$config_limit = OPENVK_ROOT_CONF['openvk']['preferences']['blacklists']['limit'] ?? 100;
$user_blocks = $this->getUser()->getBlacklistSize();
if(($user_blocks + 1) > $config_limit)
$this->fail(-7856, "Blacklist limit exceeded");

$entity = get_entity_by_id($owner_id);
if(!$entity || $entity->isDeleted())
return 0;

if($entity->isBlacklistedBy($this->getUser()))
return 1;

$this->getUser()->addToBlacklist($entity);

return 1;
}

function unban(int $owner_id): int
{
$this->requireUser();
$this->willExecuteWriteAction();

if($owner_id < 0)
return 1;

if($owner_id == $this->getUser()->getId())
return 1;

$entity = get_entity_by_id($owner_id);
if(!$entity || $entity->isDeleted())
return 0;

if(!$entity->isBlacklistedBy($this->getUser()))
return 1;

$this->getUser()->removeFromBlacklist($entity);

return 1;
}

function getBanned(int $offset = 0, int $count = 100, string $fields = ""): object
{
$this->requireUser();

$result = (object)[
'count' => $this->getUser()->getBlacklistSize(),
'items' => [],
];
$banned = $this->getUser()->getBlacklist($offset, $count);
foreach($banned as $ban) {
if(!$ban) continue;
$result->items[] = $ban->toVkApiStruct($this->getUser(), $fields);
}

return $result;
}
}
14 changes: 14 additions & 0 deletions VKAPI/Handlers/Users.php
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,20 @@ function get(string $user_ids = "0", string $fields = "", int $offset = 0, int $
case 'nickname':
$response[$i]->nickname = $usr->getPseudo();
break;
case 'blacklisted_by_me':
if(!$authuser) {
continue;
}

$response[$i]->blacklisted_by_me = (int)$usr->isBlacklistedBy($this->getUser());
break;
case 'blacklisted':
if(!$authuser) {
continue;
}

$response[$i]->blacklisted = (int)$this->getUser()->isBlacklistedBy($usr);
break;
}
}

Expand Down
103 changes: 98 additions & 5 deletions Web/Models/Entities/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use openvk\Web\Util\DateTime;
use openvk\Web\Models\RowModel;
use openvk\Web\Models\Entities\{Photo, Message, Correspondence, Gift, Audio};
use openvk\Web\Models\Repositories\{Applications, Bans, Comments, Notes, Posts, Users, Clubs, Albums, Gifts, Notifications, Videos, Photos};
use openvk\Web\Models\Repositories\{Applications, Bans, Comments, Notes, Posts, Users, Clubs, Albums, Gifts, Notifications, Videos, Photos};
use openvk\Web\Models\Exceptions\InvalidUserNameException;
use Nette\Database\Table\ActiveRow;
use Chandler\Database\DatabaseConnection;
Expand Down Expand Up @@ -511,7 +511,7 @@ function getPrivacyPermission(string $permission, ?User $user = NULL): bool
else if($user->getId() === $this->getId())
return true;

if($permission != "messages.write" && !$this->canBeViewedBy($user))
if(/*$permission != "messages.write" && */!$this->canBeViewedBy($user, true))
return false;

switch($permStatus) {
Expand Down Expand Up @@ -1228,11 +1228,16 @@ function isActivated(): bool
return (bool) $this->getRecord()->activated;
}

function isAdmin(): bool
{
return $this->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL);
}

function isDead(): bool
{
return $this->onlineStatus() == 2;
}

function getUnbanTime(): ?string
{
$ban = (new Bans)->get((int) $this->getRecord()->block_reason);
Expand Down Expand Up @@ -1289,17 +1294,21 @@ function getProfileType(): int
return $this->getRecord()->profile_type;
}

function canBeViewedBy(?User $user = NULL): bool
function canBeViewedBy(?User $user = NULL, bool $blacklist_check = true): bool
{
if(!is_null($user)) {
if($this->getId() == $user->getId()) {
return true;
}

if($user->getChandlerUser()->can("access")->model("admin")->whichBelongsTo(NULL)) {
if($user->isAdmin() && !(OPENVK_ROOT_CONF['openvk']['preferences']['blacklists']['applyToAdmins'] ?? true)) {
return true;
}

if($blacklist_check && ($this->isBlacklistedBy($user) || $user->isBlacklistedBy($this))) {
return false;
}

if($this->getProfileType() == 0) {
return true;
} else {
Expand Down Expand Up @@ -1409,6 +1418,20 @@ function toVkApiStruct(?User $user = NULL, string $fields = ''): object
case 'real_id':
$res->real_id = $this->getRealId();
break;
case "blacklisted_by_me":
if(!$user) {
continue;
}

$res->blacklisted_by_me = (int)$this->isBlacklistedBy($user);
break;
case "blacklisted":
if(!$user) {
continue;
}

$res->blacklisted = (int)$user->isBlacklistedBy($this);
break;
}
}

Expand Down Expand Up @@ -1486,6 +1509,76 @@ function getIgnoredSourcesCount()
return DatabaseConnection::i()->getContext()->table("ignored_sources")->where("owner", $this->getId())->count();
}

function isBlacklistedBy(?User $user = NULL): bool
{
if(!$user)
return false;

$ctx = DatabaseConnection::i()->getContext();
$data = [
"author" => $user->getId(),
"target" => $this->getRealId(),
];

$sub = $ctx->table("blacklist_relations")->where($data);
return $sub->count() > 0;
}

function addToBlacklist(?User $user)
{
DatabaseConnection::i()->getContext()->table("blacklist_relations")->insert([
"author" => $this->getRealId(),
"target" => $user->getRealId(),
"created" => time(),
]);

DatabaseConnection::i()->getContext()->table("subscriptions")->where([
"follower" => $user->getId(),
"model" => static::class,
"target" => $this->getId(),
])->delete();

DatabaseConnection::i()->getContext()->table("subscriptions")->where([
"follower" => $this->getId(),
"model" => static::class,
"target" => $user->getId(),
])->delete();

return true;
}

function removeFromBlacklist(?User $user): bool
{
DatabaseConnection::i()->getContext()->table("blacklist_relations")->where([
"author" => $this->getRealId(),
"target" => $user->getRealId(),
])->delete();

return true;
}

function getBlacklist(int $offset = 0, int $limit = 10)
{
$sources = DatabaseConnection::i()->getContext()->table("blacklist_relations")->where("author", $this->getId())->limit($limit, $offset)->order('created ASC');
$output_array = [];

foreach($sources as $source) {
$entity_id = (int)$source->target ;
$entity = (new Users)->get($entity_id);
if(!$entity)
continue;

$output_array[] = $entity;
}

return $output_array;
}

function getBlacklistSize()
{
return DatabaseConnection::i()->getContext()->table("blacklist_relations")->where("author", $this->getId())->count();
}

use Traits\TBackDrops;
use Traits\TSubscribable;
use Traits\TAudioStatuses;
Expand Down
2 changes: 1 addition & 1 deletion Web/Presenters/GroupPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ function renderFollowers(int $id): void
$this->template->paginatorConf = (object) [
"count" => $this->template->count,
"page" => $this->queryParam("p") ?? 1,
"amount" => NULL,
"amount" => 10,
"perPage" => OPENVK_DEFAULT_PER_PAGE,
];
}
Expand Down
3 changes: 3 additions & 0 deletions Web/Presenters/PhotosPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ function renderAlbumList(int $owner): void
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, (int)($this->queryParam("p") ?? 1));
$this->template->count = $this->albums->getUserAlbumsCount($user);
$this->template->owner = $user;
Expand Down Expand Up @@ -161,8 +162,10 @@ function renderPhoto(int $ownerId, int $photoId): void
{
$photo = $this->photos->getByOwnerAndVID($ownerId, $photoId);
if(!$photo || $photo->isDeleted()) $this->notFound();

if(!$photo->canBeViewedBy($this->user->identity))
$this->flashFail("err", tr("forbidden"), tr("forbidden_comment"));

if(!is_null($this->queryParam("from"))) {
if(preg_match("%^album([0-9]++)$%", $this->queryParam("from"), $matches) === 1) {
$album = $this->albums->get((int) $matches[1]);
Expand Down
30 changes: 28 additions & 2 deletions Web/Presenters/UserPresenter.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,29 @@ final class UserPresenter extends OpenVKPresenter
function __construct(Users $users)
{
$this->users = $users;

parent::__construct();
}

function renderView(int $id): void
{
$user = $this->users->get($id);

if(!$user || $user->isDeleted() || !$user->canBeViewedBy($this->user->identity)) {
if(!is_null($user) && $user->isDeactivated()) {
$this->template->_template = "User/deactivated.xml";

$this->template->user = $user;
} else if($this->user->identity->isBlacklistedBy($user)) {
$this->template->_template = "User/blacklisted.xml";

$this->template->blacklist_status = $user->isBlacklistedBy($this->user->identity);
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
$this->template->user = $user;
} else if($user->isBlacklistedBy($this->user->identity)) {
$this->template->_template = "User/blacklisted_pov.xml";

$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
$this->template->user = $user;
} else if(!is_null($user) && !$user->canBeViewedBy($this->user->identity)) {
$this->template->_template = "User/private.xml";
Expand All @@ -57,6 +69,7 @@ function renderView(int $id): void

if($id !== $this->user->id) {
$this->template->ignore_status = $user->isIgnoredBy($this->user->identity);
$this->template->blacklist_status = $user->isBlacklistedBy($this->user->identity);
}
}
}
Expand Down Expand Up @@ -578,7 +591,7 @@ function renderSettings(): void
$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";

Expand All @@ -591,6 +604,19 @@ function renderSettings(): void

$this->template->qrCodeType = substr($qrCode[0], 5);
$this->template->qrCodeData = $qrCode[1];
} else if($this->template->mode === "blacklist") {
$page = (int)($this->queryParam('p') ?? 1);
$count = 10;
$offset = ($page - 1) * $count;

$this->template->blSize = $this->user->identity->getBlacklistSize();
$this->template->blItems = $this->user->identity->getBlacklist($offset, $count);
$this->template->paginatorConf = (object) [
"count" => $this->template->blSize,
"page" => $page,
"amount" => sizeof($this->template->blItems),
"perPage" => OPENVK_DEFAULT_PER_PAGE,
];
}

$this->template->user = $user;
Expand Down
28 changes: 27 additions & 1 deletion Web/Presenters/templates/User/Settings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
{var $isFinance = $mode === 'finance'}
{var $isFinanceTU = $mode === 'finance.top-up'}
{var $isInterface = $mode === 'interface'}
{var $isBl = $mode === 'blacklist'}

<div class="tabs">
<div n:attr="id => ($isMain ? 'activetabs' : 'ki')" class="tab">
Expand All @@ -24,6 +25,9 @@
<div n:attr="id => ($isPrivacy ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($isPrivacy ? 'act_tab_a' : 'ki')" href="/settings?act=privacy">{_privacy}</a>
</div>
<div n:attr="id => ($isBl ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => ($isBl ? 'act_tab_a' : 'ki')" href="/settings?act=blacklist">{_blacklist}</a>
</div>
<div n:if="OPENVK_ROOT_CONF['openvk']['preferences']['commerce']" n:attr="id => (($isFinance || $isFinanceTU) ? 'activetabs' : 'ki')" class="tab">
<a n:attr="id => (($isFinance || $isFinanceTU) ? 'act_tab_a' : 'ki')" href="/settings?act=finance">{_points}</a>
</div>
Expand Down Expand Up @@ -713,7 +717,29 @@
</tbody>
</table>
</form>

{elseif $isBl}
{if $blSize < 1}
{include "../components/error.xml", description => tr("bl_count_zero_desc")}
{else}
<h4 style="margin-bottom: 10px;">{tr("bl_count", $blSize)}.</h4>
<div class='entity_vertical_list mini m_mini scroll_container'>
<div n:foreach="$blItems as $item" class="entity_vertical_list_item scroll_node">
<div class="first_column">
<a href="{$item->getURL()}" class="avatar">
<img src='{$item->getAvatarURL()}'>
</a>
<div class="info">
<b class="noOverflow">
<a href="{$item->getURL()}">
{$item->getCanonicalName()}
</a>
</b>
</div>
</div>
</div>
</div>
{include "../components/paginator.xml", conf => $paginatorConf}
{/if}
{/if}
</div>

Expand Down
Loading
Loading