Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions ServiceAPI/Chats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace openvk\ServiceAPI;

use openvk\Web\Models\Entities\User;
use openvk\Web\Models\Repositories\Chats;

class Chats implements Handler
{
protected $user;
protected $chats;

public function __construct(?User $user)
{
$this->user = $user;
$this->chats = new Chats();
}

public function getChat(int $id, callable $resolve, callable $reject): void
{
$chat = $this->chats->get($id);
if (!$chat) {
$reject(53, "No chat with id=$id");
}

$userIds = array_map(fn($u) => $u->getId(), $chat->getUsers());
if (!in_array($this->user->getId(), $userIds)) {
$reject(12, "Access denied");
}

$res = (object) [];
$res->id = $chat->getId();
$res->type = $chat->getRecord()->type;
$res->title = $chat->getRecord()->title;
$res->admin_id = $chat->getRecord()->admin_id;
$res->users = $userIds;
$res->push_settings = $chat->getPushSettings();
$res->photo_50 = $chat->getRecord()->photo_50;
$res->photo_100 = $chat->getRecord()->photo_100;
$res->photo_200 = $chat->getRecord()->photo_200;
$res->left = $chat->isLeft();
$res->kicked = $chat->isKicked();

$resolve($res);
}

public function createChat(string $title, array $userIds, callable $resolve, callable $reject): void
{
if (!$this->user) {
$reject(5, "Authorization required");
}

$users = array_merge([$this->user->getId()], $userIds);
$chat = $this->chats->create('chat', $title, $this->user->getId(), $users);

$resolve((object)['chat_id' => $chat->getId()]);
}
}
85 changes: 84 additions & 1 deletion VKAPI/Handlers/Messages.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
namespace openvk\VKAPI\Handlers;

use openvk\Web\Util\IMBroker;
use openvk\Web\Models\Repositories\{Users as USRRepo, Clubs as ClubRepo};
use openvk\Web\Models\Repositories\{Users as USRRepo, Clubs as ClubRepo, Chats};
use openvk\Web\Models\Entities\{Club as ClubEnt};
use openvk\VKAPI\Handlers\{Users as APIUsers, Groups as APIClubs};

Expand Down Expand Up @@ -813,6 +813,89 @@ public function getMe(int $group_id = 0)
return $this->invoke("im.getMe", [], $group_id);
}

// May be broken lmao
public function getConversationsById(string $peer_ids, int $extended = 0, string $fields = "")
{
$this->requireUser();
$this->willExecuteWriteAction();

$peer_ids = explode(',', $peer_ids);
$result = [];

foreach ($peer_ids as $peer_id) {
$peer_id = (int) $peer_id;

if ($peer_id < 0) {
$club = (new ClubRepo())->get(abs($peer_id));
if (!$club || $club->isBanned()) {
continue;
}

if (!$club->canBeViewedBy($this->getUser())) {
continue;
}
} else {
$user = (new USRRepo())->get($peer_id);
if (!$user || $user->isDeleted() || $user->isBanned()) {
continue;
}

if (!$user->canBeViewedBy($this->getUser())) {
continue;
}
}

$result[] = $this->getConversationById($peer_id, $extended, $fields);
}

return $result;
}

// Chat methods
public function getChat(int $chat_id): object
{
$this->requireUser();

$chats = new Chats();
$chat = $chats->get($chat_id);
if (!$chat) {
$this->fail(100, "One of the parameters specified was missing or invalid: chat not found");
}

$userIds = array_map(fn($u) => $u->getId(), $chat->getUsers());
if (!in_array($this->getUser()->getId(), $userIds)) {
$this->fail(15, "Access denied");
}

return (object) [
'id' => $chat->getId(),
'type' => $chat->getRecord()->type,
'title' => $chat->getRecord()->title,
'admin_id' => $chat->getRecord()->admin_id,
'users' => $userIds,
'push_settings' => $chat->getPushSettings(),
'photo_50' => $chat->getRecord()->photo_50,
'photo_100' => $chat->getRecord()->photo_100,
'photo_200' => $chat->getRecord()->photo_200,
'left' => $chat->isLeft(),
'kicked' => $chat->isKicked(),
];
}

public function createChat(string $title, string $user_ids): object
{
$this->requireUser();
$this->willExecuteWriteAction();

$userIds = array_map('intval', explode(',', $user_ids));
$users = array_merge([$this->getUser()->getId()], $userIds);

$chats = new Chats();
$chat = $chats->create('chat', $title, $this->getUser()->getId(), $users);

return (object) ['chat_id' => $chat->getId()];
}

/*
public function delete(string $message_ids, int $spam = 0, int $delete_for_all = 0): object
{
Expand Down
107 changes: 107 additions & 0 deletions Web/Models/Entities/Chat.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace openvk\Web\Models\Entities;

use openvk\Web\Models\RowModel;
use openvk\Web\Models\Repositories\Users;

/**
* Chat entity for multi-user conversations.
*/
class Chat extends RowModel
{
protected $tableName = "chats";

/**
* Get the admin user of the chat.
*/
public function getAdmin(): ?User
{
return (new Users())->get($this->getRecord()->admin_id);
}

/**
* Get the list of users in the chat.
*
* @return array<User>
*/
public function getUsers(): array
{
$userIds = json_decode($this->getRecord()->users, true) ?? [];
$users = [];
$usersRepo = new Users();
foreach ($userIds as $id) {
$user = $usersRepo->get($id);
if ($user) {
$users[] = $user;
}
}
return $users;
}

/**
* Get push settings.
*
* @return object
*/
public function getPushSettings(): object
{
return json_decode($this->getRecord()->push_settings) ?? (object)['sound' => 1, 'disabled_until' => 0];
}

/**
* Check if the chat is left by the user.
*/
public function isLeft(): bool
{
return (bool) $this->getRecord()->left;
}

/**
* Check if the user is kicked from the chat.
*/
public function isKicked(): bool
{
return (bool) $this->getRecord()->kicked;
}

/**
* Add a user to the chat.
*/
public function addUser(int $userId): bool
{
$users = json_decode($this->getRecord()->users, true) ?? [];
if (!in_array($userId, $users)) {
$users[] = $userId;
$this->stateChanges("users", json_encode($users));
return true;
}
return false;
}

/**
* Remove a user from the chat.
*/
public function removeUser(int $userId): bool
{
$users = json_decode($this->getRecord()->users, true) ?? [];
$key = array_search($userId, $users);
if ($key !== false) {
unset($users[$key]);
$this->stateChanges("users", json_encode(array_values($users)));
return true;
}
return false;
}

/**
* Update push settings.
*/
public function updatePushSettings(int $sound, int $disabledUntil): void
{
$settings = json_encode(['sound' => $sound, 'disabled_until' => $disabledUntil]);
$this->stateChanges("push_settings", $settings);
}
}
75 changes: 75 additions & 0 deletions Web/Models/Repositories/Chats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<?php

declare(strict_types=1);

namespace openvk\Web\Models\Repositories;

use openvk\Web\Models\Entities\Chat;
use Chandler\Database\DatabaseConnection;

class Chats
{
private $context;
private $chats;

public function __construct()
{
$this->context = DatabaseConnection::i()->getContext();
$this->chats = $this->context->table("chats");
}

public function get(int $id): ?Chat
{
$chat = $this->chats->get($id);
if (!$chat) {
return null;
}

return new Chat($chat);
}

public function getByUser(int $userId, int $page = 1, ?int $perPage = null): \Traversable
{
$limit = $perPage ?? OPENVK_DEFAULT_PER_PAGE;
$offset = ($page - 1) * $limit;
$chats = $this->chats->where("JSON_CONTAINS(users, ?)", json_encode($userId))
->order("id DESC")
->limit($limit, $offset);

foreach ($chats as $chat) {
yield new Chat($chat);
}
}

public function create(string $type, string $title, int $adminId, array $users): Chat
{
$data = [
'type' => $type,
'title' => $title,
'admin_id' => $adminId,
'users' => json_encode($users),
'push_settings' => json_encode(['sound' => 1, 'disabled_until' => 0]),
'photo_50' => null,
'photo_100' => null,
'photo_200' => null,
'left' => 0,
'kicked' => 0,
];

$chat = $this->chats->insert($data);
return new Chat($chat);
}

public function findByUsers(array $userIds): ?Chat
{
// For simplicity, assume chats are unique by users, but in reality, might need better logic
$chats = $this->chats->where("JSON_CONTAINS(users, ?)", json_encode($userIds[0]));
foreach ($chats as $chat) {
$chatUsers = json_decode($chat->users, true);
if (count($chatUsers) == count($userIds) && !array_diff($chatUsers, $userIds)) {
return new Chat($chat);
}
}
return null;
}
}
Loading
Loading