Tims-Chat/files/lib/data/room/Room.class.php

306 lines
8.8 KiB
PHP

<?php
/*
* Copyright (c) 2010-2022 Tim Düsterhus.
*
* Use of this software is governed by the Business Source License
* included in the LICENSE file.
*
* Change Date: 2026-09-17
*
* On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2
* or later of the General Public License.
*/
namespace chat\data\room;
use chat\page\RoomPage;
use chat\system\cache\runtime\UserRuntimeCache as ChatUserRuntimeCache;
use chat\system\permission\PermissionHandler;
use wcf\data\DatabaseObject;
use wcf\data\ITitledLinkObject;
use wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\request\IRouteController;
use wcf\system\request\LinkHandler;
use wcf\system\WCF;
use wcf\util\StringUtil;
/**
* Represents a chat room.
*
* @property-read integer $roomID
* @property-read string $title
* @property-read string $topic
* @property-read integer $position
* @property-read integer $userLimit
* @property-read integer $isTemporary
* @property-read integer $ownerID
* @property-read integer $topicUseHtml
*/
final class Room extends DatabaseObject implements
IRouteController,
ITitledLinkObject,
\JsonSerializable
{
/**
* @var ?(integer[])
*/
private static $userToRoom;
/**
* @see Room::getTitle()
*/
public function __toString(): string
{
return $this->getTitle();
}
/**
* Returns whether the given user can see at least
* one chat room. If no user is given the current user
* should be assumed
*/
public static function canSeeAny(?UserProfile $user = null): bool
{
$rooms = RoomCache::getInstance()->getRooms();
foreach ($rooms as $room) {
if ($room->canSee($user)) {
return true;
}
}
return false;
}
/**
* Returns whether the given user can see this room.
* If no user is given the current user should be assumed.
*/
public function canSee(?UserProfile $user = null, ?\Exception &$reason = null): bool
{
static $cache = [ ];
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!isset($cache[$this->roomID])) {
$cache[$this->roomID] = [];
}
if (\array_key_exists($user->userID, $cache[$this->roomID])) {
return ($reason = $cache[$this->roomID][$user->userID]) === null;
}
if (!$user->userID) {
$reason = new PermissionDeniedException();
return ($cache[$this->roomID][$user->userID] = $reason) === null;
}
$result = null;
if (!PermissionHandler::get($user)->getPermission($this, 'user.canSee')) {
$result = new PermissionDeniedException();
}
$parameters = [
'user' => $user,
'result' => $result,
];
EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
$reason = $parameters['result'];
if (!($reason === null || $reason instanceof \Throwable)) {
throw new \DomainException('Result of canSee must be a \Throwable or null.');
}
return ($cache[$this->roomID][$user->userID] = $reason) === null;
}
/**
* Returns whether the given user can see the log of this room.
* If no user is given the current user should be assumed.
*/
public function canSeeLog(?UserProfile $user = null, ?\Exception &$reason = null): bool
{
static $cache = [ ];
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!isset($cache[$this->roomID])) {
$cache[$this->roomID] = [];
}
if (\array_key_exists($user->userID, $cache[$this->roomID])) {
return ($reason = $cache[$this->roomID][$user->userID]) === null;
}
$result = null;
if (!PermissionHandler::get($user)->getPermission($this, 'user.canSeeLog')) {
$result = new PermissionDeniedException();
}
$parameters = [
'user' => $user,
'result' => $result,
];
EventHandler::getInstance()->fireAction($this, 'canSeeLog', $parameters);
$reason = $parameters['result'];
if (!($reason === null || $reason instanceof \Throwable)) {
throw new \DomainException('Result of canSeeLog must be a \Throwable or null.');
}
return ($cache[$this->roomID][$user->userID] = $reason) === null;
}
/**
* Returns whether the given user can join this room.
* If no user is given the current user should be assumed.
*/
public function canJoin(?UserProfile $user = null, ?\Exception &$reason = null): bool
{
static $cache = [ ];
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!isset($cache[$this->roomID])) {
$cache[$this->roomID] = [];
}
if (\array_key_exists($user->userID, $cache[$this->roomID])) {
return ($reason = $cache[$this->roomID][$user->userID]) === null;
}
$parameters = [
'user' => $user,
'result' => null,
];
EventHandler::getInstance()->fireAction($this, 'canJoin', $parameters);
$reason = $parameters['result'];
if (!($reason === null || $reason instanceof \Throwable)) {
throw new \DomainException('Result of canJoin must be a \Throwable or null.');
}
return ($cache[$this->roomID][$user->userID] = $reason) === null;
}
/**
* Returns whether the given user can write public messages in this room.
* If no user is given the current user should be assumed.
*/
public function canWritePublicly(?UserProfile $user = null, ?\Exception &$reason = null): bool
{
static $cache = [ ];
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!isset($cache[$this->roomID])) {
$cache[$this->roomID] = [];
}
if (\array_key_exists($user->userID, $cache[$this->roomID])) {
return ($reason = $cache[$this->roomID][$user->userID]) === null;
}
$result = null;
if (!PermissionHandler::get($user)->getPermission($this, 'user.canWrite')) {
$result = new PermissionDeniedException();
}
$parameters = [
'user' => $user,
'result' => $result,
];
EventHandler::getInstance()->fireAction($this, 'canWritePublicly', $parameters);
$reason = $parameters['result'];
if (!($reason === null || $reason instanceof \Throwable)) {
throw new \DomainException('Result of canWritePublicly must be a \Throwable or null.');
}
return ($cache[$this->roomID][$user->userID] = $reason) === null;
}
/**
* @inheritDoc
*/
public function getTitle(): string
{
return WCF::getLanguage()->get($this->title);
}
/**
* @inheritDoc
*/
public function getTopic(): string
{
$topic = StringUtil::trim(WCF::getLanguage()->get($this->topic));
if (!$this->topicUseHtml) {
$topic = StringUtil::encodeHTML($topic);
}
return $topic;
}
/**
* Returns an array of users in this room.
*
* @return \chat\data\user\User[]
*/
public function getUsers()
{
if (self::$userToRoom === null) {
$sql = "SELECT r2u.userID,
r2u.roomID
FROM chat1_room_to_user r2u
INNER JOIN wcf1_user u
ON r2u.userID = u.userID
WHERE r2u.active = ?
ORDER BY u.username ASC";
$statement = WCF::getDB()->prepare($sql);
$statement->execute([ 1 ]);
self::$userToRoom = $statement->fetchMap('roomID', 'userID', false);
if (!empty(self::$userToRoom)) {
ChatUserRuntimeCache::getInstance()->cacheObjectIDs(\array_merge(...self::$userToRoom));
}
}
if (!isset(self::$userToRoom[$this->roomID])) {
return [ ];
}
return ChatUserRuntimeCache::getInstance()->getObjects(self::$userToRoom[$this->roomID]);
}
/**
* @inheritDoc
*/
public function getLink(): string
{
return LinkHandler::getInstance()->getControllerLink(
RoomPage::class,
[
'object' => $this,
'forceFrontend' => true,
]
);
}
/**
* @inheritDoc
*/
public function jsonSerialize()
{
return [
'title' => $this->getTitle(),
'topic' => $this->getTopic(),
'link' => $this->getLink(),
];
}
}