1
0
mirror of https://github.com/wbbaddons/Tims-Chat.git synced 2024-10-31 14:10:08 +00:00

Compare commits

..

No commits in common. "master" and "v4.1.0-rc.7" have entirely different histories.

233 changed files with 8171 additions and 9555 deletions

View File

@ -3,9 +3,9 @@
, "last 2 chromeandroid versions" , "last 2 chromeandroid versions"
, "firefox esr" , "firefox esr"
, "last 2 firefox versions" , "last 2 firefox versions"
, "last 2 edge versions" , "edge >= 17"
, "safari >= 15" , "safari >= 12"
, "ios >= 15" , "ios >= 12"
] ]
} }
, "debug": true , "debug": true

3
.gitattributes vendored
View File

@ -1,3 +0,0 @@
*.php diff=php
*.css diff=css
*.scss diff=css

View File

@ -1,8 +0,0 @@
{
"editor.rulers": [
{
"column": 120,
"color": "#ff00ff40"
}
]
}

View File

@ -4,13 +4,13 @@ License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
Parameters Parameters
Licensor: Tim Düsterhus Licensor: Tim Düsterhus
Licensed Work: Tims Chat 4.3 Licensed Work: Tims Chat 4.1
The Licensed Work is (c) 2010-2024 Tim Düsterhus The Licensed Work is (c) 2010-2021 Tim Düsterhus
Additional Use Grant: You may use the Licensed Work when your application Additional Use Grant: You may use the Licensed Work when your application
uses the Licensed Work for a purpose that does neither uses the Licensed Work for a purpose that does neither
directly or indirectly generate revenue. directly or indirectly generate revenue.
Change Date: 2028-06-15 Change Date: 2025-03-05
Change License: Version 2 or later of the GNU General Public License as Change License: Version 2 or later of the GNU General Public License as
published by the Free Software Foundation. published by the Free Software Foundation.

View File

@ -16,7 +16,7 @@
<controller>chat\acp\form\RoomAddForm</controller> <controller>chat\acp\form\RoomAddForm</controller>
<parent>chat.acp.menu.link.room.list</parent> <parent>chat.acp.menu.link.room.list</parent>
<permissions>admin.chat.canManageRoom</permissions> <permissions>admin.chat.canManageRoom</permissions>
<icon>plus</icon> <icon>fa-plus</icon>
</acpmenuitem> </acpmenuitem>
<acpmenuitem name="chat.acp.menu.link.command.trigger.list"> <acpmenuitem name="chat.acp.menu.link.command.trigger.list">
@ -29,7 +29,7 @@
<controller>chat\acp\form\CommandTriggerAddForm</controller> <controller>chat\acp\form\CommandTriggerAddForm</controller>
<parent>chat.acp.menu.link.command.trigger.list</parent> <parent>chat.acp.menu.link.command.trigger.list</parent>
<permissions>admin.chat.canManageTriggers</permissions> <permissions>admin.chat.canManageTriggers</permissions>
<icon>plus</icon> <icon>fa-plus</icon>
</acpmenuitem> </acpmenuitem>
<acpmenuitem name="chat.acp.menu.link.suspension.list"> <acpmenuitem name="chat.acp.menu.link.suspension.list">

View File

@ -0,0 +1,5 @@
<dl>
<dt>{lang}chat.acp.index.system.software.chatVersion{/lang}</dt>
<dd>{$__chat->getPackage()->packageVersion}</dd>
</dl>

View File

@ -7,14 +7,18 @@
<nav class="contentHeaderNavigation"> <nav class="contentHeaderNavigation">
<ul> <ul>
<li><a href="{link application='chat' controller='CommandTriggerList'}{/link}" class="button">{icon name='list'} <span>{lang}chat.acp.command.trigger.list{/lang}</span></a></li> <li><a href="{link application='chat' controller='CommandTriggerList'}{/link}" class="button"><span class="icon icon16 fa-list"></span> <span>{lang}chat.acp.command.trigger.list{/lang}</span></a></li>
{event name='contentHeaderNavigation'} {event name='contentHeaderNavigation'}
</ul> </ul>
</nav> </nav>
</header> </header>
{include file='formNotice'} {include file='formError'}
{if $success|isset}
<p class="success">{lang}wcf.global.success.{$action}{/lang}</p>
{/if}
<form method="post" action="{if $action == 'add'}{link application='chat' controller='CommandTriggerAdd'}{/link}{else}{link application='chat' controller='CommandTriggerEdit' id=$triggerID}{/link}{/if}"> <form method="post" action="{if $action == 'add'}{link application='chat' controller='CommandTriggerAdd'}{/link}{else}{link application='chat' controller='CommandTriggerEdit' id=$triggerID}{/link}{/if}">
<div class="section"> <div class="section">
@ -60,7 +64,7 @@
<div class="formSubmit"> <div class="formSubmit">
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s"> <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
{csrfToken} {@SECURITY_TOKEN_INPUT_TAG}
</div> </div>
</form> </form>

View File

@ -14,7 +14,7 @@
<nav class="contentHeaderNavigation"> <nav class="contentHeaderNavigation">
<ul> <ul>
<li><a href="{link controller='CommandTriggerAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.command.trigger.add{/lang}</span></a></li> <li><a href="{link controller='CommandTriggerAdd' application='chat'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}chat.acp.command.trigger.add{/lang}</span></a></li>
{event name='contentHeaderNavigation'} {event name='contentHeaderNavigation'}
</ul> </ul>
@ -45,8 +45,8 @@
{foreach from=$objects item=trigger} {foreach from=$objects item=trigger}
<tr class="jsTriggerRow"> <tr class="jsTriggerRow">
<td class="columnIcon"> <td class="columnIcon">
<a href="{link controller='CommandTriggerEdit' object=$trigger application='chat'}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a> <a href="{link controller='CommandTriggerEdit' object=$trigger application='chat'}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
<span class="jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{$trigger->triggerID}" data-confirm-message-html="{lang __encode=true}chat.acp.command.trigger.delete.sure{/lang}">{icon name='xmark'}</span> <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$trigger->triggerID}" data-confirm-message-html="{lang __encode=true}chat.acp.command.trigger.delete.sure{/lang}"></span>
{event name='rowButtons'} {event name='rowButtons'}
</td> </td>
@ -75,7 +75,7 @@
<nav class="contentFooterNavigation"> <nav class="contentFooterNavigation">
<ul> <ul>
<li><a href="{link controller='CommandTriggerAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.command.trigger.add{/lang}</span></a></li> <li><a href="{link controller='CommandTriggerAdd' application='chat'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}chat.acp.command.trigger.add{/lang}</span></a></li>
{event name='contentFooterNavigation'} {event name='contentFooterNavigation'}
</ul> </ul>

View File

@ -19,14 +19,18 @@
<nav class="contentHeaderNavigation"> <nav class="contentHeaderNavigation">
<ul> <ul>
<li><a href="{link application='chat' controller='RoomList'}{/link}" class="button">{icon name='list'} <span>{lang}chat.acp.room.list{/lang}</span></a></li> <li><a href="{link application='chat' controller='RoomList'}{/link}" class="button"><span class="icon icon16 fa-list"></span> <span>{lang}chat.acp.room.list{/lang}</span></a></li>
{event name='contentHeaderNavigation'} {event name='contentHeaderNavigation'}
</ul> </ul>
</nav> </nav>
</header> </header>
{include file='formNotice'} {include file='formError'}
{if $success|isset}
<p class="success">{lang}wcf.global.success.{$action}{/lang}</p>
{/if}
<form method="post" action="{if $action == 'add'}{link application='chat' controller='RoomAdd'}{/link}{else}{link application='chat' controller='RoomEdit' id=$roomID}{/link}{/if}"> <form method="post" action="{if $action == 'add'}{link application='chat' controller='RoomAdd'}{/link}{else}{link application='chat' controller='RoomEdit' id=$roomID}{/link}{/if}">
<div class="section"> <div class="section">
@ -101,7 +105,7 @@
<div class="formSubmit"> <div class="formSubmit">
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s"> <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
{csrfToken} {@SECURITY_TOKEN_INPUT_TAG}
</div> </div>
</form> </form>

View File

@ -19,7 +19,7 @@
<nav class="contentHeaderNavigation"> <nav class="contentHeaderNavigation">
<ul> <ul>
<li><a href="{link controller='RoomAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.room.add{/lang}</span></a></li> <li><a href="{link controller='RoomAdd' application='chat'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}chat.acp.room.add{/lang}</span></a></li>
{event name='contentHeaderNavigation'} {event name='contentHeaderNavigation'}
</ul> </ul>
@ -37,14 +37,14 @@
<ol id="roomContainer0" class="sortableList" data-object-id="0"> <ol id="roomContainer0" class="sortableList" data-object-id="0">
{content} {content}
{foreach from=$objects item=room} {foreach from=$objects item=room}
<li class="sortableNode sortableNoNesting" data-object-id="{$room->roomID}"> <li class="sortableNode sortableNoNesting" data-object-id="{@$room->roomID}">
<span class="sortableNodeLabel"> <span class="sortableNodeLabel">
<a href="{link controller='RoomEdit' application='chat' object=$room}{/link}">{$room}</a> <a href="{link controller='RoomEdit' application='chat' object=$room}{/link}">{$room}</a>
<span class="statusDisplay sortableButtonContainer"> <span class="statusDisplay sortableButtonContainer">
<span class="sortableNodeHandle">{icon name='up-down-left-right'}</span> <span class="icon icon16 fa-arrows sortableNodeHandle"></span>
<a href="{link controller='RoomEdit' application='chat' object=$room}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip">{icon name='pencil'}</a> <a href="{link controller='RoomEdit' application='chat' object=$room}{/link}" title="{lang}wcf.global.button.edit{/lang}" class="jsTooltip"><span class="icon icon16 fa-pencil"></span></a>
<span class="jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{$room->roomID}" data-confirm-message-html="{lang __encode=true}chat.acp.room.delete.sure{/lang}">{icon name='xmark'}</span> <span class="icon icon16 fa-times jsDeleteButton jsTooltip pointer" title="{lang}wcf.global.button.delete{/lang}" data-object-id="{@$room->roomID}" data-confirm-message-html="{lang __encode=true}chat.acp.room.delete.sure{/lang}"></span>
{event name='itemButtons'} {event name='itemButtons'}
</span> </span>
</span> </span>
@ -70,7 +70,7 @@
<nav class="contentFooterNavigation"> <nav class="contentFooterNavigation">
<ul> <ul>
<li><a href="{link controller='RoomAdd' application='chat'}{/link}" class="button">{icon name='plus'} <span>{lang}chat.acp.room.add{/lang}</span></a></li> <li><a href="{link controller='RoomAdd' application='chat'}{/link}" class="button"><span class="icon icon16 fa-plus"></span> <span>{lang}chat.acp.room.add{/lang}</span></a></li>
{event name='contentFooterNavigation'} {event name='contentFooterNavigation'}
</ul> </ul>

View File

@ -99,7 +99,7 @@ require([ 'Bastelstu.be/PromiseWrap/Ajax', 'Bastelstu.be/PromiseWrap/Ui/Confirma
<div class="formSubmit"> <div class="formSubmit">
<input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s"> <input type="submit" value="{lang}wcf.global.button.submit{/lang}" accesskey="s">
{csrfToken} {@SECURITY_TOKEN_INPUT_TAG}
</div> </div>
</section> </section>
</form> </form>
@ -141,7 +141,7 @@ require([ 'Bastelstu.be/PromiseWrap/Ajax', 'Bastelstu.be/PromiseWrap/Ui/Confirma
{foreach from=$objects item=suspension} {foreach from=$objects item=suspension}
<tr class="jsSuspensionRow" data-object-id="{$suspension->suspensionID}"> <tr class="jsSuspensionRow" data-object-id="{$suspension->suspensionID}">
<td class="columnIcon"> <td class="columnIcon">
<span class="jsRevokeButton{if !$suspension->isActive()} disabled{else} pointer{/if}" title="{lang}chat.acp.suspension.revoke{/lang}" data-confirm-message-html="{lang}chat.acp.suspension.revoke.sure{/lang}">{icon name='arrow-rotate-left'}</span> <span class="icon icon16 fa-undo{if !$suspension->isActive()} disabled{else} pointer{/if} jsRevokeButton" title="{lang}chat.acp.suspension.revoke{/lang}" data-confirm-message-html="{lang}chat.acp.suspension.revoke.sure{/lang}"></span>
{event name='rowButtons'} {event name='rowButtons'}
</td> </td>

View File

@ -1,25 +1,21 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
* or later of the General Public License. * or later of the General Public License.
*/ */
use wcf\system\box\BoxHandler; use \wcf\system\box\BoxHandler;
BoxHandler::getInstance()->createBoxCondition( BoxHandler::getInstance()->createBoxCondition( 'be.bastelstu.chat.roomListDashboard'
'be.bastelstu.chat.roomListDashboard', , 'be.bastelstu.chat.box.roomList.condition'
'be.bastelstu.chat.box.roomList.condition', , 'be.bastelstu.chat.roomFilled'
'be.bastelstu.chat.roomFilled', , [ 'chatRoomIsFilled' => 1 ]
[ );
'chatRoomIsFilled' => 1,
]
);

View File

@ -1,44 +1,35 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
* or later of the General Public License. * or later of the General Public License.
*/ */
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use wcf\data\object\type\ObjectTypeCache;
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( $objectTypeID = \wcf\data\object\type\ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', 'be.bastelstu.chat.messageType.chatUpdate');
'be.bastelstu.chat.messageType',
'be.bastelstu.chat.messageType.chatUpdate'
);
if ($objectTypeID) { if ($objectTypeID) {
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => null
[ ], , 'userID' => null
'create', , 'username' => ''
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => null, , 'payload' => serialize([ ])
'userID' => null, ]
'username' => '', ]
'time' => TIME_NOW, )
'objectTypeID' => $objectTypeID, )->executeAction();
'payload' => \serialize([ ]),
],
]
))->executeAction();
} }
$CHATCore = \file_get_contents(__DIR__ . '/../lib/system/CHATCore.class.php'); $CHATCore = file_get_contents(__DIR__.'/../lib/system/CHATCore.class.php');
if (\strpos($CHATCore, 'chat.phar.php') === false) { if (strpos($CHATCore, 'chat.phar.php') === false) {
@\unlink(__DIR__ . '/../chat.phar.php'); @unlink(__DIR__.'/../chat.phar.php');
} }

View File

@ -1,41 +0,0 @@
<?php
/**
* Deletes orphaned attachments.
*
* @author Tim Duesterhus
* @copyright 2001-2022 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @package WoltLabSuite\Core
* @see https://github.com/WoltLab/com.woltlab.wcf.conversation/blob/f0d4964a0b8042c440d5a3f759078429dc43c5b8/files/acp/update_com.woltlab.wcf.conversation_5.5_cleanup_orphaned_attachments.php
*/
use wcf\data\attachment\AttachmentAction;
use wcf\data\object\type\ObjectTypeCache;
use wcf\system\package\SplitNodeException;
use wcf\system\WCF;
$objectType = ObjectTypeCache::getInstance()
->getObjectTypeByName('com.woltlab.wcf.attachment.objectType', 'be.bastelstu.chat.message');
$sql = "SELECT attachmentID
FROM wcf1_attachment
WHERE objectTypeID = ?
AND objectID NOT IN (
SELECT messageID
FROM chat1_message
)";
$statement = WCF::getDB()->prepare($sql, 100);
$statement->execute([$objectType->objectTypeID]);
$attachmentIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
if (empty($attachmentIDs)) {
return;
}
(new AttachmentAction($attachmentIDs, 'delete'))->executeAction();
// If we reached this location we processed at least one attachment.
// If this was the final attachment the next iteration will abort this
// script early, thus not splitting the node.
throw new SplitNodeException();

View File

@ -1,19 +1,18 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
* or later of the General Public License. * or later of the General Public License.
*/ */
\define('RELATIVE_CHAT_DIR', '../'); define('RELATIVE_CHAT_DIR', '../');
require_once(RELATIVE_CHAT_DIR . '/app.config.inc.php'); require_once(RELATIVE_CHAT_DIR.'/config.inc.php');
require_once(RELATIVE_WCF_DIR . 'acp/global.php'); require_once(RELATIVE_WCF_DIR.'acp/global.php');

View File

@ -1,20 +1,16 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
* or later of the General Public License. * or later of the General Public License.
*/ */
use wcf\system\request\RequestHandler;
require('./global.php'); require('./global.php');
\wcf\system\request\RequestHandler::getInstance()->handle('chat', true);
RequestHandler::getInstance()->handle('chat', true);

View File

@ -1,17 +1,16 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
* or later of the General Public License. * or later of the General Public License.
*/ */
require_once(__DIR__ . '/app.config.inc.php'); require_once(dirname(__FILE__).'/config.inc.php');
require_once(RELATIVE_WCF_DIR . 'global.php'); require_once(RELATIVE_WCF_DIR.'global.php');

View File

@ -1,20 +1,16 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
* or later of the General Public License. * or later of the General Public License.
*/ */
use wcf\system\request\RequestHandler;
require('./global.php'); require('./global.php');
\wcf\system\request\RequestHandler::getInstance()->handle('chat');
RequestHandler::getInstance()->handle('chat');

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,173 +14,146 @@
namespace chat\acp\form; namespace chat\acp\form;
use chat\data\command\CommandList; use \chat\data\command\CommandCache;
use chat\data\command\CommandTrigger; use \chat\data\command\CommandTrigger;
use chat\data\command\CommandTriggerAction; use \chat\data\command\CommandTriggerAction;
use wcf\form\AbstractForm; use \chat\data\command\CommandTriggerEditor;
use wcf\system\exception\UserInputException; use \wcf\system\exception\UserInputException;
use wcf\system\WCF; use \wcf\system\WCF;
use wcf\util\StringUtil;
/** /**
* Shows the command trigger add form. * Shows the command trigger add form.
*/ */
class CommandTriggerAddForm extends AbstractForm class CommandTriggerAddForm extends \wcf\form\AbstractForm {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.command.trigger.add';
public $activeMenuItem = 'chat.acp.menu.link.command.trigger.add';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $neededPermissions = [ public $neededPermissions = [ 'admin.chat.canManageTriggers' ];
'admin.chat.canManageTriggers',
];
/** /**
* The new trigger for the specified command * The new trigger for the specified command
* @var string * @var string
*/ */
public $commandTrigger = ''; public $commandTrigger = '';
/** /**
* List of currently known commands * List of currently known commands
* @var array * @var array
*/ */
public $commands = [ ]; public $commands = [ ];
/** /**
* The selected command. * The selected command.
* *
* @param Command * @param Command
*/ */
public $command; public $command = null;
/** /**
* The fully qualified name of the command * The fully qualified name of the command
* @var string * @var string
*/ */
public $className = ''; public $className = '';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ $commandList = new \chat\data\command\CommandList();
$commandList = new CommandList(); $commandList->sqlOrderBy = 'command.className';
$commandList->sqlOrderBy = 'command.className'; $commandList->readObjects();
$commandList->readObjects();
$this->commands = $commandList->getObjects(); $this->commands = $commandList->getObjects();
parent::readData(); parent::readData();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readFormParameters() public function readFormParameters() {
{ parent::readFormParameters();
parent::readFormParameters();
if (isset($_POST['commandTrigger'])) { if (isset($_POST['commandTrigger'])) $this->commandTrigger = \wcf\util\StringUtil::trim($_POST['commandTrigger']);
$this->commandTrigger = StringUtil::trim($_POST['commandTrigger']); if (isset($_POST['className'])) $this->className = \wcf\util\StringUtil::trim($_POST['className']);
} }
if (isset($_POST['className'])) {
$this->className = StringUtil::trim($_POST['className']);
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate() public function validate() {
{ parent::validate();
parent::validate();
if ($this->commandTrigger === '') { if (empty($this->commandTrigger)) {
throw new UserInputException('commandTrigger', 'empty'); throw new UserInputException('commandTrigger', 'empty');
} }
// Triggers must not contain whitespace // Triggers must not contain whitespace
if (\preg_match('~\s~', $this->commandTrigger)) { if (preg_match('~\s~', $this->commandTrigger)) {
throw new UserInputException('commandTrigger', 'invalid'); throw new UserInputException('commandTrigger', 'invalid');
} }
// Check for duplicates // Check for duplicates
$trigger = CommandTrigger::getTriggerByName($this->commandTrigger); $trigger = CommandTrigger::getTriggerByName($this->commandTrigger);
if ( if ((!isset($this->trigger) && $trigger->triggerID) || (isset($this->trigger) && $trigger->triggerID != $this->trigger->triggerID)) {
(!isset($this->trigger) && $trigger->triggerID) throw new UserInputException('commandTrigger', 'duplicate');
|| (isset($this->trigger) && $trigger->triggerID != $this->trigger->triggerID) }
) {
throw new UserInputException('commandTrigger', 'duplicate');
}
if ($this->className === '') { if (empty($this->className)) {
throw new UserInputException('className', 'empty'); throw new UserInputException('className', 'empty');
} }
// Check if the command is registered // Check if the command is registered
foreach ($this->commands as $command) { foreach ($this->commands as $command) {
if ($command->className === $this->className) { if ($command->className === $this->className) {
$this->command = $command; $this->command = $command;
break; break;
} }
} }
if (!$this->command) { if (!$this->command) {
throw new UserInputException('className', 'notFound'); throw new UserInputException('className', 'notFound');
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function save() public function save() {
{ parent::save();
parent::save();
$fields = [ $fields = [ 'commandTrigger' => $this->commandTrigger
'commandTrigger' => $this->commandTrigger, , 'commandID' => $this->command->commandID
'commandID' => $this->command->commandID, ];
];
// create room // create room
$this->objectAction = new CommandTriggerAction( $this->objectAction = new \chat\data\command\CommandTriggerAction([ ], 'create', [ 'data' => array_merge($this->additionalFields, $fields) ]);
[ ], $this->objectAction->executeAction();
'create',
[
'data' => \array_merge(
$this->additionalFields,
$fields
),
]
);
$this->objectAction->executeAction();
$this->saved(); $this->saved();
// reset values // reset values
$this->commandTrigger = $this->className = ''; $this->commandTrigger = $this->className = '';
// show success message // show success message
WCF::getTPL()->assign('success', true); WCF::getTPL()->assign('success', true);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'action' => 'add'
'action' => 'add', , 'commandTrigger' => $this->commandTrigger
'commandTrigger' => $this->commandTrigger, , 'className' => $this->className
'className' => $this->className, , 'availableCommands' => $this->commands
'availableCommands' => $this->commands, ]);
]); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,119 +14,99 @@
namespace chat\acp\form; namespace chat\acp\form;
use chat\data\command\CommandList; use \chat\data\command\CommandTrigger;
use chat\data\command\CommandTrigger; use \chat\data\command\CommandTriggerAction;
use chat\data\command\CommandTriggerAction; use \chat\data\command\CommandTriggerEditor;
use wcf\form\AbstractForm; use \wcf\system\exception\IllegalLinkException;
use wcf\system\exception\IllegalLinkException; use \wcf\system\exception\UserInputException;
use wcf\system\WCF; use \wcf\system\WCF;
/** /**
* Shows the command trigger edit form. * Shows the command trigger edit form.
*/ */
class CommandTriggerEditForm extends CommandTriggerAddForm class CommandTriggerEditForm extends CommandTriggerAddForm {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.command.trigger.list';
public $activeMenuItem = 'chat.acp.menu.link.command.trigger.list';
/** /**
* The requested command trigger ID. * The requested command trigger ID.
* *
* @param int * @param int
*/ */
public $triggerID = 0; public $triggerID = 0;
/** /**
* The requested command trigger. * The requested command trigger.
* *
* @param CommandTrigger * @param CommandTrigger
*/ */
public $trigger; public $trigger = null;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readParameters() public function readParameters() {
{ if (isset($_REQUEST['id'])) $this->triggerID = intval($_REQUEST['id']);
if (isset($_REQUEST['id'])) { $this->trigger = new CommandTrigger($this->triggerID);
$this->triggerID = \intval($_REQUEST['id']);
}
$this->trigger = new CommandTrigger($this->triggerID);
if (!$this->trigger) { if (!$this->trigger) {
throw new IllegalLinkException(); throw new IllegalLinkException();
} }
parent::readParameters(); parent::readParameters();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ parent::readData();
parent::readData();
if (empty($_POST)) { if (empty($_POST)) {
$commandList = new CommandList(); $commandList = new \chat\data\command\CommandList();
$commandList->getConditionBuilder()->add('command.commandID = ?', [ $this->trigger->commandID ]); $commandList->getConditionBuilder()->add('command.commandID = ?', [ $this->trigger->commandID ]);
$commandList->readObjects(); $commandList->readObjects();
$commands = $commandList->getObjects(); $commands = $commandList->getObjects();
if (!\count($commands)) { if (!count($commands)) {
throw new IllegalLinkException(); throw new IllegalLinkException();
} }
$this->commandTrigger = $this->trigger->commandTrigger; $this->commandTrigger = $this->trigger->commandTrigger;
$this->className = $commands[$this->trigger->commandID]->className; $this->className = $commands[$this->trigger->commandID]->className;
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function save() public function save() {
{ \wcf\form\AbstractForm::save();
AbstractForm::save();
$fields = [ $fields = [ 'commandTrigger' => $this->commandTrigger
'commandTrigger' => $this->commandTrigger, , 'commandID' => $this->command->commandID
'commandID' => $this->command->commandID, ];
];
// update trigger // update trigger
$this->objectAction = new CommandTriggerAction( $this->objectAction = new CommandTriggerAction([ $this->trigger ], 'update', [ 'data' => array_merge($this->additionalFields, $fields) ]);
[ $this->objectAction->executeAction();
$this->trigger,
],
'update',
[
'data' => \array_merge(
$this->additionalFields,
$fields
),
]
);
$this->objectAction->executeAction();
$this->saved(); $this->saved();
// show success message // show success message
WCF::getTPL()->assign('success', true); WCF::getTPL()->assign('success', true);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'action' => 'edit'
'action' => 'edit', , 'triggerID' => $this->trigger->triggerID
'triggerID' => $this->trigger->triggerID, ]);
]); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,236 +14,202 @@
namespace chat\acp\form; namespace chat\acp\form;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomAction; use \chat\data\room\RoomAction;
use chat\data\room\RoomEditor; use \chat\data\room\RoomEditor;
use wcf\data\package\PackageCache; use \wcf\system\acl\ACLHandler;
use wcf\form\AbstractForm; use \wcf\system\exception\UserInputException;
use wcf\system\acl\ACLHandler; use \wcf\system\language\I18nHandler;
use wcf\system\exception\UserInputException; use \wcf\system\WCF;
use wcf\system\language\I18nHandler;
use wcf\system\WCF;
/** /**
* Shows the room add form. * Shows the room add form.
*/ */
class RoomAddForm extends AbstractForm class RoomAddForm extends \wcf\form\AbstractForm {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.room.add';
public $activeMenuItem = 'chat.acp.menu.link.room.add';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $neededPermissions = [ public $neededPermissions = [ 'admin.chat.canManageRoom' ];
'admin.chat.canManageRoom',
];
/** /**
* Object type ID of the ACL object type for rooms. * Object type ID of the ACL object type for rooms.
* @var int * @var int
*/ */
public $aclObjectTypeID = 0; public $aclObjectTypeID = 0;
/** /**
* Chat room title. * Chat room title.
* @var string * @var string
*/ */
public $title = ''; public $title = '';
/** /**
* Chat room topic. * Chat room topic.
* @var string * @var string
*/ */
public $topic = ''; public $topic = '';
/** /**
* Whether HTML should be interpreted in the room's topic. * Whether HTML should be interpreted in the room's topic.
* @var boolean * @var boolean
*/ */
public $topicUseHtml = false; public $topicUseHtml = false;
/** /**
* Chat room user limit. * Chat room user limit.
* @var int * @var int
*/ */
public $userLimit = 0; public $userLimit = 0;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readParameters() public function readParameters() {
{ parent::readParameters();
parent::readParameters();
I18nHandler::getInstance()->register('title'); I18nHandler::getInstance()->register('title');
I18nHandler::getInstance()->register('topic'); I18nHandler::getInstance()->register('topic');
$this->aclObjectTypeID = ACLHandler::getInstance()->getObjectTypeID('be.bastelstu.chat.room'); $this->aclObjectTypeID = ACLHandler::getInstance()->getObjectTypeID('be.bastelstu.chat.room');
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readFormParameters() public function readFormParameters() {
{ parent::readFormParameters();
parent::readFormParameters();
// read i18n values // read i18n values
I18nHandler::getInstance()->readValues(); I18nHandler::getInstance()->readValues();
// handle i18n plain input // handle i18n plain input
if (I18nHandler::getInstance()->isPlainValue('title')) { if (I18nHandler::getInstance()->isPlainValue('title')) $this->title = I18nHandler::getInstance()->getValue('title');
$this->title = I18nHandler::getInstance()->getValue('title'); if (I18nHandler::getInstance()->isPlainValue('topic')) $this->topic = I18nHandler::getInstance()->getValue('topic');
} if (isset($_POST['userLimit'])) $this->userLimit = intval($_POST['userLimit']);
if (I18nHandler::getInstance()->isPlainValue('topic')) { if (isset($_POST['topicUseHtml'])) $this->topicUseHtml = true;
$this->topic = I18nHandler::getInstance()->getValue('topic'); }
}
if (isset($_POST['userLimit'])) {
$this->userLimit = \intval($_POST['userLimit']);
}
if (isset($_POST['topicUseHtml'])) {
$this->topicUseHtml = true;
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate() public function validate() {
{ parent::validate();
parent::validate();
// validate title // validate title
if (!I18nHandler::getInstance()->validateValue('title')) { if (!I18nHandler::getInstance()->validateValue('title')) {
if (I18nHandler::getInstance()->isPlainValue('title')) { if (I18nHandler::getInstance()->isPlainValue('title')) {
throw new UserInputException('title'); throw new UserInputException('title');
} else { }
throw new UserInputException('title', 'multilingual'); else {
} throw new UserInputException('title', 'multilingual');
} }
}
// validate topic // validate topic
if (!I18nHandler::getInstance()->validateValue('topic', false, true)) { if (!I18nHandler::getInstance()->validateValue('topic', false, true)) {
throw new UserInputException('topic'); throw new UserInputException('topic');
} }
if (\mb_strlen($this->topic) > 10000) { if (mb_strlen($this->topic) > 10000) {
throw new UserInputException('topic', 'tooLong'); throw new UserInputException('topic', 'tooLong');
} }
if ($this->userLimit < 0) { if ($this->userLimit < 0) {
throw new UserInputException('userLimit', 'negative'); throw new UserInputException('userLimit', 'negative');
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function save() public function save() {
{ parent::save();
parent::save();
$fields = [ $fields = [ 'title' => $this->title
'title' => $this->title, , 'topic' => $this->topic
'topic' => $this->topic, , 'topicUseHtml' => (int) $this->topicUseHtml
'topicUseHtml' => (int)$this->topicUseHtml, , 'userLimit' => $this->userLimit
'userLimit' => $this->userLimit, , 'position' => 0 // TODO
'position' => 0, // TODO ];
];
// create room // create room
$this->objectAction = new RoomAction( $this->objectAction = new \chat\data\room\RoomAction([], 'create', [ 'data' => array_merge($this->additionalFields, $fields) ]);
[ ], $returnValues = $this->objectAction->executeAction();
'create',
[
'data' => \array_merge(
$this->additionalFields,
$fields
),
]
);
$returnValues = $this->objectAction->executeAction();
// save i18n values // save i18n values
$this->saveI18nValue( $this->saveI18nValue($returnValues['returnValues'], [ 'title', 'topic' ]);
$returnValues['returnValues'],
[
'title',
'topic',
]
);
// save ACL // save ACL
ACLHandler::getInstance()->save($returnValues['returnValues']->roomID, $this->aclObjectTypeID); ACLHandler::getInstance()->save($returnValues['returnValues']->roomID, $this->aclObjectTypeID);
$this->saved(); $this->saved();
// reset values // reset values
$this->title = $this->topic = ''; $this->title = $this->topic = '';
$this->userLimit = 0; $this->userLimit = 0;
$this->topicUseHtml = false; $this->topicUseHtml = false;
I18nHandler::getInstance()->reset(); I18nHandler::getInstance()->reset();
ACLHandler::getInstance()->disableAssignVariables(); ACLHandler::getInstance()->disableAssignVariables();
// show success message // show success message
WCF::getTPL()->assign('success', true); WCF::getTPL()->assign('success', true);
} }
/** /**
* Saves i18n values. * Saves i18n values.
* *
* @param Room $room * @param Room $room
* @param string[] $columns * @param string[] $columns
*/ */
public function saveI18nValue(Room $room, $columns) public function saveI18nValue(Room $room, $columns) {
{ $data = [ ];
$data = [ ];
foreach ($columns as $columnName) { foreach ($columns as $columnName) {
$languageItem = 'chat.room.room' . $room->roomID . '.' . $columnName; $languageItem = 'chat.room.room'.$room->roomID.'.'.$columnName;
if (I18nHandler::getInstance()->isPlainValue($columnName)) { if (I18nHandler::getInstance()->isPlainValue($columnName)) {
if ($room->{$columnName} === $languageItem) { if ($room->$columnName === $languageItem) {
I18nHandler::getInstance()->remove($languageItem); I18nHandler::getInstance()->remove($languageItem);
} }
} else { }
$packageID = PackageCache::getInstance()->getPackageID('be.bastelstu.chat'); else {
$packageID = \wcf\data\package\PackageCache::getInstance()->getPackageID('be.bastelstu.chat');
I18nHandler::getInstance()->save( I18nHandler::getInstance()->save( $columnName
$columnName, , $languageItem
$languageItem, , 'chat.room'
'chat.room', , $packageID
$packageID );
);
$data[$columnName] = $languageItem; $data[$columnName] = $languageItem;
} }
} }
if ($data !== []) { if (!empty($data)) {
(new RoomEditor($room))->update($data); (new RoomEditor($room))->update($data);
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
ACLHandler::getInstance()->assignVariables($this->aclObjectTypeID); ACLHandler::getInstance()->assignVariables($this->aclObjectTypeID);
I18nHandler::getInstance()->assignVariables(); I18nHandler::getInstance()->assignVariables();
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'action' => 'add'
'action' => 'add', , 'aclObjectTypeID' => $this->aclObjectTypeID
'aclObjectTypeID' => $this->aclObjectTypeID, , 'userLimit' => $this->userLimit
'userLimit' => $this->userLimit, , 'topicUseHtml' => $this->topicUseHtml
'topicUseHtml' => $this->topicUseHtml, ]);
]); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,144 +14,104 @@
namespace chat\acp\form; namespace chat\acp\form;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomAction; use \chat\data\room\RoomAction;
use wcf\data\package\PackageCache; use \wcf\system\acl\ACLHandler;
use wcf\form\AbstractForm; use \wcf\system\language\I18nHandler;
use wcf\system\acl\ACLHandler; use \wcf\system\WCF;
use wcf\system\exception\IllegalLinkException;
use wcf\system\language\I18nHandler;
use wcf\system\WCF;
/** /**
* Shows the room edit form. * Shows the room edit form.
*/ */
class RoomEditForm extends RoomAddForm class RoomEditForm extends RoomAddForm {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.room.list';
public $activeMenuItem = 'chat.acp.menu.link.room.list';
/** /**
* The requested chat room ID. * The requested chat room ID.
* *
* @param int * @param int
*/ */
public $roomID = 0; public $roomID = 0;
/** /**
* The requested chat room. * The requested chat room.
* *
* @param Room * @param Room
*/ */
public $room; public $room = null;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readParameters() public function readParameters() {
{ if (isset($_REQUEST['id'])) $this->roomID = intval($_REQUEST['id']);
if (isset($_REQUEST['id'])) { $this->room = new Room($this->roomID);
$this->roomID = \intval($_REQUEST['id']);
}
$this->room = new Room($this->roomID);
if (!$this->room) { if (!$this->room) {
throw new IllegalLinkException(); throw new IllegalLinkException();
} }
parent::readParameters(); parent::readParameters();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ parent::readData();
parent::readData();
if (empty($_POST)) { if (empty($_POST)) {
$packageID = PackageCache::getInstance()->getPackageID('be.bastelstu.chat'); $packageID = \wcf\data\package\PackageCache::getInstance()->getPackageID('be.bastelstu.chat');
I18nHandler::getInstance()->setOptions( I18nHandler::getInstance()->setOptions('title', $packageID, $this->room->title, 'chat.room.room\d+.title');
'title', I18nHandler::getInstance()->setOptions('topic', $packageID, $this->room->topic, 'chat.room.room\d+.topic');
$packageID, $this->userLimit = $this->room->userLimit;
$this->room->title, $this->topicUseHtml = $this->room->topicUseHtml;
'chat.room.room\d+.title' }
); }
I18nHandler::getInstance()->setOptions(
'topic',
$packageID,
$this->room->topic,
'chat.room.room\d+.topic'
);
$this->userLimit = $this->room->userLimit;
$this->topicUseHtml = $this->room->topicUseHtml;
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function save() public function save() {
{ \wcf\form\AbstractForm::save();
AbstractForm::save();
$fields = [ $fields = [ 'title' => $this->title
'title' => $this->title, , 'topic' => $this->topic
'topic' => $this->topic, , 'topicUseHtml' => (int) $this->topicUseHtml
'topicUseHtml' => (int)$this->topicUseHtml, , 'userLimit' => $this->userLimit
'userLimit' => $this->userLimit, , 'position' => 0 // TODO
'position' => 0, // TODO ];
];
// update room // update room
$this->objectAction = new RoomAction( $this->objectAction = new RoomAction([ $this->room ], 'update', [ 'data' => array_merge($this->additionalFields, $fields) ]);
[ $this->room ], $returnValues = $this->objectAction->executeAction();
'update',
[
'data' => \array_merge(
$this->additionalFields,
$fields
),
]
);
$returnValues = $this->objectAction->executeAction();
// save i18n values // save i18n values
$this->saveI18nValue( $this->saveI18nValue($this->room, [ 'title', 'topic' ]);
$this->room,
[
'title',
'topic',
]
);
// save ACL // save ACL
ACLHandler::getInstance()->save( ACLHandler::getInstance()->save($this->room->roomID, $this->aclObjectTypeID);
$this->room->roomID,
$this->aclObjectTypeID
);
$this->saved(); $this->saved();
// show success message // show success message
WCF::getTPL()->assign('success', true); WCF::getTPL()->assign('success', true);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
I18nHandler::getInstance()->assignVariables(!empty($_POST)); I18nHandler::getInstance()->assignVariables(!empty($_POST));
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'action' => 'edit'
'action' => 'edit', , 'roomID' => $this->room->roomID
'roomID' => $this->room->roomID, , 'room' => $this->room
'room' => $this->room, ]);
]); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,53 +14,42 @@
namespace chat\acp\page; namespace chat\acp\page;
use chat\data\command\CommandTriggerList;
use wcf\page\SortablePage;
/** /**
* Shows the command trigger list. * Shows the command trigger list.
*/ */
final class CommandTriggerListPage extends SortablePage class CommandTriggerListPage extends \wcf\page\SortablePage {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.command.trigger.list';
public $activeMenuItem = 'chat.acp.menu.link.command.trigger.list';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $neededPermissions = [ public $neededPermissions = [ 'admin.chat.canManageTriggers' ];
'admin.chat.canManageTriggers',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $objectListClassName = CommandTriggerList::class; public $objectListClassName = \chat\data\command\CommandTriggerList::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $validSortFields = [ public $validSortFields = [ 'triggerID', 'commandTrigger', 'className' ];
'triggerID',
'commandTrigger',
'className',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $defaultSortField = 'commandTrigger'; public $defaultSortField = 'commandTrigger';
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function initObjectList() protected function initObjectList() {
{ parent::initObjectList();
parent::initObjectList();
$this->objectList->sqlSelects = 'command.className'; $this->objectList->sqlSelects = 'command.className';
$this->objectList->sqlJoins = 'LEFT JOIN chat' . WCF_N . '_command command ON (command.commandID = command_trigger.commandID)'; $this->objectList->sqlJoins = 'LEFT JOIN chat'.WCF_N.'_command command ON (command.commandID = command_trigger.commandID)';
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,41 +14,32 @@
namespace chat\acp\page; namespace chat\acp\page;
use chat\data\room\RoomList;
use wcf\page\SortablePage;
/** /**
* Shows the room list. * Shows the room list.
*/ */
final class RoomListPage extends SortablePage class RoomListPage extends \wcf\page\SortablePage {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.room.list';
public $activeMenuItem = 'chat.acp.menu.link.room.list';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $neededPermissions = [ public $neededPermissions = [ 'admin.chat.canManageRoom' ];
'admin.chat.canManageRoom',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $objectListClassName = RoomList::class; public $objectListClassName = \chat\data\room\RoomList::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $validSortFields = [ public $validSortFields = [ 'roomID', 'title' ];
'roomID',
'title',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $defaultSortField = 'position'; public $defaultSortField = 'position';
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,236 +14,212 @@
namespace chat\acp\page; namespace chat\acp\page;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomList; use \chat\data\suspension\Suspension;
use chat\data\suspension\Suspension; use \wcf\data\user\User;
use chat\data\suspension\SuspensionList; use \wcf\system\WCF;
use wcf\data\object\type\ObjectTypeCache; use \wcf\util\StringUtil;
use wcf\data\user\User;
use wcf\page\SortablePage;
use wcf\system\cache\runtime\UserRuntimeCache;
use wcf\system\WCF;
use wcf\util\StringUtil;
/** /**
* Shows the suspension list. * Shows the suspension list.
*/ */
final class SuspensionListPage extends SortablePage class SuspensionListPage extends \wcf\page\SortablePage {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $activeMenuItem = 'chat.acp.menu.link.suspension.list';
public $activeMenuItem = 'chat.acp.menu.link.suspension.list';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $neededPermissions = [ public $neededPermissions = [ 'admin.chat.canManageSuspensions' ];
'admin.chat.canManageSuspensions',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $objectListClassName = SuspensionList::class; public $objectListClassName = \chat\data\suspension\SuspensionList::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $validSortFields = [ public $validSortFields = [ 'suspensionID', 'time', 'expires', 'revoked' ];
'suspensionID',
'time',
'expires',
'revoked',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $defaultSortField = 'expiresSort'; public $defaultSortField = 'expiresSort';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $defaultSortOrder = 'DESC'; public $defaultSortOrder = 'DESC';
/** /**
* userID filter * userID filter
* @var int * @var int
*/ */
public $userID; public $userID = null;
/** /**
* roomID filter * roomID filter
* @var int * @var int
*/ */
public $roomID; public $roomID = null;
/** /**
* objectTypeID filter * objectTypeID filter
* @var int * @var int
*/ */
public $objectTypeID; public $objectTypeID = null;
/** /**
* judgeID filter * judgeID filter
* @var int * @var int
*/ */
public $judgeID; public $judgeID = null;
/** /**
* Whether to show expired entries * Whether to show expired entries
* @var boolean * @var boolean
*/ */
public $showExpired = true; public $showExpired = true;
/** /**
* username filter * username filter
* @var string * @var string
*/ */
public $searchUsername; public $searchUsername = null;
/** /**
* judge's username filter * judge's username filter
* @var string * @var string
*/ */
public $searchJudge; public $searchJudge = null;
/** /**
* Array of available suspension object types * Array of available suspension object types
* @var array * @var array
*/ */
public $availableObjectTypes = [ ]; public $availableObjectTypes = [ ];
/** /**
* Array of available chat rooms * Array of available chat rooms
* @var array * @var array
*/ */
public $availableRooms = [ ]; public $availableRooms = [ ];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readParameters() public function readParameters() {
{ parent::readParameters();
parent::readParameters();
if (isset($_REQUEST['roomID']) && $_REQUEST['roomID'] !== '') { if (isset($_REQUEST['roomID']) && $_REQUEST['roomID'] !== '') $this->roomID = intval($_REQUEST['roomID']);
$this->roomID = \intval($_REQUEST['roomID']); if (isset($_REQUEST['userID']) && $_REQUEST['userID'] !== '') $this->userID = intval($_REQUEST['userID']);
} if (isset($_REQUEST['judgeID']) && $_REQUEST['judgeID'] !== '') $this->judgeID = intval($_REQUEST['judgeID']);
if (isset($_REQUEST['userID']) && $_REQUEST['userID'] !== '') { if (isset($_REQUEST['objectTypeID']) && $_REQUEST['objectTypeID'] !== '') $this->objectTypeID = intval($_REQUEST['objectTypeID']);
$this->userID = \intval($_REQUEST['userID']); // Checkboxes need special handling
} if (!empty($_POST) && !isset($_POST['showExpired'])) $this->showExpired = false;
if (isset($_REQUEST['judgeID']) && $_REQUEST['judgeID'] !== '') {
$this->judgeID = \intval($_REQUEST['judgeID']);
}
if (isset($_REQUEST['objectTypeID']) && $_REQUEST['objectTypeID'] !== '') {
$this->objectTypeID = \intval($_REQUEST['objectTypeID']);
}
// Checkboxes need special handling
if (!empty($_POST) && !isset($_POST['showExpired'])) {
$this->showExpired = false;
}
if (isset($_POST['searchUsername'])) { if (isset($_POST['searchUsername'])) {
$this->searchUsername = StringUtil::trim($_POST['searchUsername']); $this->searchUsername = StringUtil::trim($_POST['searchUsername']);
if ($this->searchUsername !== '') { if (!empty($this->searchUsername)) {
$this->userID = User::getUserByUsername($this->searchUsername)->userID; $this->userID = User::getUserByUsername($this->searchUsername)->userID;
} }
} elseif ($this->userID !== null) { }
$this->searchUsername = (new User($this->userID))->username; else if ($this->userID !== null) {
} $this->searchUsername = (new User($this->userID))->username;
}
if (isset($_POST['searchJudge'])) { if (isset($_POST['searchJudge'])) {
$this->searchJudge = StringUtil::trim($_POST['searchJudge']); $this->searchJudge = StringUtil::trim($_POST['searchJudge']);
if ($this->searchJudge !== '') { if (!empty($this->searchJudge)) {
$this->judgeID = User::getUserByUsername($this->searchJudge)->userID; $this->judgeID = User::getUserByUsername($this->searchJudge)->userID;
} }
} elseif ($this->judgeID !== null) { }
$this->searchJudge = (new User($this->judgeID))->username; else if ($this->judgeID !== null) {
} $this->searchJudge = (new User($this->judgeID))->username;
} }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ $this->availableObjectTypes = \wcf\data\object\type\ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.suspension');
$this->availableObjectTypes = ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.suspension');
$roomList = new RoomList(); $roomList = new \chat\data\room\RoomList();
$roomList->sqlOrderBy = "room.position"; $roomList->sqlOrderBy = "room.position";
$roomList->readObjects(); $roomList->readObjects();
$this->availableRooms = $roomList->getObjects(); $this->availableRooms = $roomList->getObjects();
parent::readData(); parent::readData();
UserRuntimeCache::getInstance()->cacheObjectIDs(\array_map(static function (Suspension $s) { \wcf\system\cache\runtime\UserRuntimeCache::getInstance()->cacheObjectIDs(array_map(function (Suspension $s) {
return $s->userID; return $s->userID;
}, $this->objectList->getObjects())); }, $this->objectList->getObjects()));
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function initObjectList() protected function initObjectList() {
{ parent::initObjectList();
parent::initObjectList();
$this->objectList->sqlSelects .= 'COALESCE(suspension.revoked, suspension.expires, 2147483647) AS expiresSort'; $this->objectList->sqlSelects .= 'COALESCE(suspension.revoked, suspension.expires, 2147483647) AS expiresSort';
if (!empty($this->availableRooms)) { if (!empty($this->availableRooms)) {
$this->objectList->getConditionBuilder()->add('(roomID IN (?) OR roomID IS NULL)', [ \array_map(static function (Room $room) { $this->objectList->getConditionBuilder()->add('(roomID IN (?) OR roomID IS NULL)', [ array_map(function (Room $room) {
return $room->roomID; return $room->roomID;
}, $this->availableRooms) ]); }, $this->availableRooms) ]);
} else { }
$this->objectList->getConditionBuilder()->add('1 = 0'); else {
} $this->objectList->getConditionBuilder()->add('1 = 0');
}
if ($this->userID !== null) { if ($this->userID !== null) {
$this->objectList->getConditionBuilder()->add('userID = ?', [ $this->userID ]); $this->objectList->getConditionBuilder()->add('userID = ?', [ $this->userID ]);
} }
if ($this->roomID !== null) { if ($this->roomID !== null) {
if ($this->roomID === 0) { if ($this->roomID === 0) {
$this->objectList->getConditionBuilder()->add('roomID IS NULL'); $this->objectList->getConditionBuilder()->add('roomID IS NULL');
} else { }
$this->objectList->getConditionBuilder()->add('roomID = ?', [ $this->roomID ]); else {
} $this->objectList->getConditionBuilder()->add('roomID = ?', [ $this->roomID ]);
} }
}
if ($this->objectTypeID !== null) { if ($this->objectTypeID !== null) {
$this->objectList->getConditionBuilder()->add('objectTypeID = ?', [ $this->objectTypeID ]); $this->objectList->getConditionBuilder()->add('objectTypeID = ?', [ $this->objectTypeID ]);
} }
if ($this->judgeID !== null) { if ($this->judgeID !== null) {
$this->objectList->getConditionBuilder()->add('judgeID = ?', [ $this->judgeID ]); $this->objectList->getConditionBuilder()->add('judgeID = ?', [ $this->judgeID ]);
} }
if ($this->showExpired === false) { if ($this->showExpired === false) {
$this->objectList->getConditionBuilder()->add('expires >= ?', [ TIME_NOW ]); $this->objectList->getConditionBuilder()->add('expires >= ?', [ TIME_NOW ]);
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'userID' => $this->userID
'userID' => $this->userID, , 'roomID' => $this->roomID
'roomID' => $this->roomID, , 'objectTypeID' => $this->objectTypeID
'objectTypeID' => $this->objectTypeID, , 'judgeID' => $this->judgeID
'judgeID' => $this->judgeID, , 'availableRooms' => $this->availableRooms
'availableRooms' => $this->availableRooms, , 'availableObjectTypes' => $this->availableObjectTypes
'availableObjectTypes' => $this->availableObjectTypes, , 'searchUsername' => $this->searchUsername
'searchUsername' => $this->searchUsername, , 'searchJudge' => $this->searchJudge
'searchJudge' => $this->searchJudge, , 'showExpired' => $this->showExpired
'showExpired' => $this->showExpired, ]);
]); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,46 +14,38 @@
namespace chat\data\command; namespace chat\data\command;
use chat\system\command\ICommand; use \wcf\system\WCF;
use wcf\data\package\PackageCache;
use wcf\data\ProcessibleDatabaseObject;
use wcf\system\WCF;
/** /**
* Represents a chat command. * Represents a chat command.
*/ */
class Command extends ProcessibleDatabaseObject class Command extends \wcf\data\ProcessibleDatabaseObject {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $processorInterface = \chat\system\command\ICommand::class;
protected static $processorInterface = ICommand::class;
/** /**
* Returns whether this command has at least one trigger assigned. * Returns whether this command has at least one trigger assigned.
* *
* The default PlainCommand implicitely has one. * The default PlainCommand implicitely has one.
*/ */
public function hasTriggers(): bool public function hasTriggers() {
{ static $chatPackageID = null;
static $chatPackageID = null;
if ($chatPackageID === null) { if ($chatPackageID === null) {
$chatPackageID = PackageCache::getInstance()->getPackageID('be.bastelstu.chat'); $chatPackageID = \wcf\data\package\PackageCache::getInstance()->getPackageID('be.bastelstu.chat');
} }
if ($this->packageID === $chatPackageID && $this->identifier === 'plain') { if ($this->packageID === $chatPackageID && $this->identifier === 'plain') {
return true; return true;
} }
$sql = "SELECT COUNT(*) $sql = "SELECT COUNT(*)
FROM chat1_command_trigger FROM chat".WCF_N."_command_trigger
WHERE commandID = ?"; WHERE commandID = ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ $statement->execute([ $this->commandID ]);
$this->commandID, return $statement->fetchSingleColumn() > 0;
]); }
return $statement->fetchSingleColumn() > 0;
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,98 +14,97 @@
namespace chat\data\command; namespace chat\data\command;
use chat\system\cache\builder\CommandCacheBuilder;
use wcf\data\package\Package;
use wcf\system\SingletonFactory;
/** /**
* Manages the command cache. * Manages the command cache.
*/ */
final class CommandCache extends SingletonFactory class CommandCache extends \wcf\system\SingletonFactory {
{ /**
/** * list of cached commands
* list of cached commands * @var Command[]
* @var Command[] */
*/ protected $commands = [ ];
protected $commands = [ ];
/** /**
* list of cached commands by package * list of cached commands by package
* @var Command[][] * @var Command[][]
*/ */
protected $packages = [ ]; protected $packages = [ ];
/** /**
* list of cached triggers * list of cached triggers
* @var int[] * @var int[]
*/ */
protected $triggers = [ ]; protected $triggers = [ ];
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function init() protected function init() {
{ $data = \chat\system\cache\builder\CommandCacheBuilder::getInstance()->getData();
$data = CommandCacheBuilder::getInstance()->getData();
$this->commands = $data['commands']; $this->commands = $data['commands'];
$this->packages = $data['packages']; $this->packages = $data['packages'];
$this->triggers = $data['triggers']; $this->triggers = $data['triggers'];
} }
/** /**
* Returns a specific command. * Returns a specific command.
*/ *
public function getCommand(int $commandID): ?Command * @param integer $commandID
{ * @return Command
if (isset($this->commands[$commandID])) { */
return $this->commands[$commandID]; public function getCommand($commandID) {
} if (isset($this->commands[$commandID])) {
return $this->commands[$commandID];
}
return null; return null;
} }
/** /**
* Returns a specific command defined by a trigger. * Returns a specific command defined by a trigger.
*/ *
public function getCommandByTrigger(string $trigger): ?Command * @param string $trigger
{ * @return Command
if (isset($this->triggers[$trigger])) { */
return $this->commands[$this->triggers[$trigger]]; public function getCommandByTrigger($trigger) {
} if (isset($this->triggers[$trigger])) {
return $this->commands[$this->triggers[$trigger]];
}
return null; return null;
} }
/** /**
* Returns the command defined by the given package and identifier. * Returns the command defined by the given package and identifier.
*/ *
public function getCommandByPackageAndIdentifier(Package $package, string $identifier): ?Command * @param \wcf\data\package\Package $package
{ * @param string $identifier
if (isset($this->packages[$package->packageID][$identifier])) { * @return Command
return $this->packages[$package->packageID][$identifier]; */
} public function getCommandByPackageAndIdentifier(\wcf\data\package\Package $package, $identifier) {
if (isset($this->packages[$package->packageID][$identifier])) {
return $this->packages[$package->packageID][$identifier];
}
return null; return null;
} }
/** /**
* Returns all commands. * Returns all commands.
* *
* @return Command[] * @return Command[]
*/ */
public function getCommands() public function getCommands() {
{ return $this->commands;
return $this->commands; }
}
/** /**
* Returns all triggers. * Returns all triggers.
* *
* @return int[] * @return int[]
*/ */
public function getTriggers() public function getTriggers() {
{ return $this->triggers;
return $this->triggers; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,15 +14,12 @@
namespace chat\data\command; namespace chat\data\command;
use wcf\data\DatabaseObjectEditor;
/** /**
* Represents a chat command editor. * Represents a chat command editor.
*/ */
class CommandEditor extends DatabaseObjectEditor class CommandEditor extends \wcf\data\DatabaseObjectEditor {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $baseClass = Command::class;
protected static $baseClass = Command::class;
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,17 +14,8 @@
namespace chat\data\command; namespace chat\data\command;
use wcf\data\DatabaseObjectList;
/** /**
* Represents a list of chat commands. * Represents a list of chat commands.
*
* @method Command current()
* @method Command[] getObjects()
* @method Command|null getSingleObject()
* @method Command|null search($objectID)
* @property Command[] $objects
*/ */
class CommandList extends DatabaseObjectList class CommandList extends \wcf\data\DatabaseObjectList {
{
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,48 +14,41 @@
namespace chat\data\command; namespace chat\data\command;
use wcf\data\DatabaseObject; use \wcf\system\WCF;
use wcf\system\request\IRouteController;
use wcf\system\WCF;
/** /**
* Represents a chat command trigger. * Represents a chat command trugger.
*/ */
class CommandTrigger extends DatabaseObject implements IRouteController class CommandTrigger extends \wcf\data\DatabaseObject implements \wcf\system\request\IRouteController {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getTitle() {
public function getTitle(): string return $this->commandTrigger;
{ }
return $this->commandTrigger;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getObjectID() public function getObjectID() {
{ return $this->triggerID;
return $this->triggerID; }
}
/** /**
* Returns the trigger specified by its commandTrigger value * Returns the trigger specified by its commandTrigger value
* *
* @return CommandTrigger * @param string $name
*/ * @return CommandTrigger
public static function getTriggerByName(string $name) */
{ public static function getTriggerByName($name) {
$sql = "SELECT * $sql = "SELECT *
FROM chat1_command_trigger FROM chat".WCF_N."_command_trigger
WHERE commandTrigger = ?"; WHERE commandTrigger = ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ $name ]); $statement->execute([ $name ]);
$row = $statement->fetchArray(); $row = $statement->fetchArray();
if (!$row) { if (!$row) $row = [];
$row = [];
}
return new self(null, $row); return new self(null, $row);
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,24 +14,17 @@
namespace chat\data\command; namespace chat\data\command;
use wcf\data\AbstractDatabaseObjectAction;
/** /**
* Executes command trigger-related actions. * Executes command trigger-related actions.
*/ */
class CommandTriggerAction extends AbstractDatabaseObjectAction class CommandTriggerAction extends \wcf\data\AbstractDatabaseObjectAction {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected $permissionsDelete = [ 'admin.chat.canManageTriggers' ];
protected $permissionsDelete = [
'admin.chat.canManageTriggers',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $permissionsUpdate = [ protected $permissionsUpdate = [ 'admin.chat.canManageTriggers' ];
'admin.chat.canManageTriggers',
];
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,25 +14,19 @@
namespace chat\data\command; namespace chat\data\command;
use chat\system\cache\builder\CommandCacheBuilder;
use wcf\data\DatabaseObjectEditor;
use wcf\data\IEditableCachedObject;
/** /**
* Represents a command trigger editor. * Represents a command trigger editor.
*/ */
class CommandTriggerEditor extends DatabaseObjectEditor implements IEditableCachedObject class CommandTriggerEditor extends \wcf\data\DatabaseObjectEditor implements \wcf\data\IEditableCachedObject {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $baseClass = CommandTrigger::class;
protected static $baseClass = CommandTrigger::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function resetCache() public static function resetCache() {
{ \chat\system\cache\builder\CommandCacheBuilder::getInstance()->reset();
CommandCacheBuilder::getInstance()->reset(); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,17 +14,7 @@
namespace chat\data\command; namespace chat\data\command;
use wcf\data\DatabaseObjectList;
/** /**
* Represents a list command triggers. * Represents a list command triggers.
*
* @method CommandTrigger current()
* @method CommandTrigger[] getObjects()
* @method CommandTrigger|null getSingleObject()
* @method CommandTrigger|null search($objectID)
* @property CommandTrigger[] $objects
*/ */
class CommandTriggerList extends DatabaseObjectList class CommandTriggerList extends \wcf\data\DatabaseObjectList { }
{
}

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,61 +14,54 @@
namespace chat\data\message; namespace chat\data\message;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomCache; use \wcf\data\object\type\ObjectType;
use wcf\data\DatabaseObject; use \wcf\data\object\type\ObjectTypeCache;
use wcf\data\object\type\ObjectType;
use wcf\data\object\type\ObjectTypeCache;
/** /**
* Represents a chat message. * Represents a chat message.
* *
* @property-read integer $messageID * @property-read integer $messageID
* @property-read integer $time * @property-read integer $time
* @property-read integer $roomID * @property-read integer $roomID
* @property-read integer $userID * @property-read integer $userID
* @property-read string $username * @property-read string $username
* @property-read integer $objectTypeID * @property-read integer $objectTypeID
* @property-read mixed $payload * @property-read mixed $payload
* @property-read integer $hasEmbeddedObjects * @property-read integer $hasEmbeddedObjects
* @property-read integer $isDeleted * @property-read integer $isDeleted
*/ */
class Message extends DatabaseObject class Message extends \wcf\data\DatabaseObject {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected function handleData($data) {
protected function handleData($data) parent::handleData($data);
{
parent::handleData($data);
$this->data['payload'] = @\unserialize($this->data['payload']); $this->data['payload'] = @unserialize($this->data['payload']);
if (!\is_array($this->data['payload'])) { if (!is_array($this->data['payload'])) {
$this->data['payload'] = [ ]; $this->data['payload'] = [ ];
} }
} }
/** /**
* Returns whether this message already is inside the log. * Returns whether this message already is inside the log.
*/ */
public function isInLog(): bool public function isInLog(): bool {
{ return $this->time < (TIME_NOW - CHAT_ARCHIVE_AFTER);
return $this->time < (TIME_NOW - CHAT_ARCHIVE_AFTER); }
}
/** /**
* Returns the message type object of this message. * Returns the message type object of this message.
*/ */
public function getMessageType(): ObjectType public function getMessageType(): ObjectType {
{ return ObjectTypeCache::getInstance()->getObjectType($this->objectTypeID);
return ObjectTypeCache::getInstance()->getObjectType($this->objectTypeID); }
}
/** /**
* Returns the chat room that contains this message. * Returns the chat room that contains this message.
*/ */
public function getRoom(): Room public function getRoom(): Room {
{ return \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
return RoomCache::getInstance()->getRoom($this->roomID); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,478 +14,359 @@
namespace chat\data\message; namespace chat\data\message;
use chat\data\command\CommandCache; use \chat\data\command\CommandCache;
use chat\data\room\RoomCache; use \chat\data\room\RoomCache;
use chat\data\user\User as ChatUser; use \wcf\data\object\type\ObjectTypeCache;
use chat\data\user\UserAction as ChatUserAction; use \wcf\system\attachment\AttachmentHandler;
use chat\system\message\type\IDeletableMessageType; use \wcf\system\exception\PermissionDeniedException;
use wcf\data\AbstractDatabaseObjectAction; use \wcf\system\exception\UserInputException;
use wcf\data\object\type\ObjectTypeCache; use \wcf\system\user\activity\point\UserActivityPointHandler;
use wcf\system\attachment\AttachmentHandler; use \wcf\system\WCF;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
use wcf\system\html\input\HtmlInputProcessor;
use wcf\system\message\embedded\object\MessageEmbeddedObjectManager;
use wcf\system\push\PushHandler;
use wcf\system\user\activity\point\UserActivityPointHandler;
use wcf\system\WCF;
/** /**
* Executes chat user-related actions. * Executes chat user-related actions.
*/ */
class MessageAction extends AbstractDatabaseObjectAction class MessageAction extends \wcf\data\AbstractDatabaseObjectAction {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function create() {
public function create() $message = parent::create();
{
$message = parent::create();
\assert($message instanceof Message);
if (isset($this->parameters['updateTimestamp']) && $this->parameters['updateTimestamp']) { if (isset($this->parameters['updateTimestamp']) && $this->parameters['updateTimestamp']) {
$sql = "UPDATE chat1_room_to_user $sql = "UPDATE chat".WCF_N."_room_to_user SET lastPush = ? WHERE roomID = ? AND userID = ?";
SET lastPush = ? $statement = WCF::getDB()->prepareStatement($sql);
WHERE roomID = ? $statement->execute([ TIME_NOW, $message->roomID, $message->userID ]);
AND userID = ?"; }
$statement = WCF::getDB()->prepare($sql); if (isset($this->parameters['grantPoints']) && $this->parameters['grantPoints']) {
$statement->execute([ UserActivityPointHandler::getInstance()->fireEvent('be.bastelstu.chat.activityPointEvent.message', $message->messageID, $message->userID);
TIME_NOW, }
$message->roomID,
$message->userID,
]);
}
if (isset($this->parameters['grantPoints']) && $this->parameters['grantPoints']) {
UserActivityPointHandler::getInstance()->fireEvent(
'be.bastelstu.chat.activityPointEvent.message',
$message->messageID,
$message->userID
);
}
$pushHandler = PushHandler::getInstance(); $pushHandler = \wcf\system\push\PushHandler::getInstance();
if ($pushHandler->isEnabled() && \in_array('target:channels', $pushHandler->getFeatureFlags())) { if ($pushHandler->isEnabled() && in_array('target:channels', $pushHandler->getFeatureFlags())) {
$fastSelect = $message->getMessageType()->getProcessor()->supportsFastSelect(); $fastSelect = $message->getMessageType()->getProcessor()->supportsFastSelect();
if ($fastSelect) { if ($fastSelect) {
$target = [ $target = [ 'channels' => [ 'be.bastelstu.chat.room-'.$message->roomID ] ];
'channels' => [ }
'be.bastelstu.chat.room-' . $message->roomID, else {
], $target = [ 'channels' => [ 'be.bastelstu.chat' ] ];
]; }
} else { $pushHandler->sendMessage([ 'message' => 'be.bastelstu.chat.message'
$target = [ , 'target' => $target
'channels' => [ ]);
'be.bastelstu.chat', }
],
];
}
$pushHandler->sendMessage([
'message' => 'be.bastelstu.chat.message',
'target' => $target,
]);
}
return $message; return $message;
} }
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validateTrash() public function validateTrash() {
{ // read objects
// read objects if (empty($this->objects)) {
if (empty($this->objects)) { $this->readObjects();
$this->readObjects();
if (empty($this->objects)) { if (empty($this->objects)) {
throw new UserInputException('objectIDs'); throw new UserInputException('objectIDs');
} }
} }
foreach ($this->getObjects() as $message) { foreach ($this->getObjects() as $message) {
if ($message->isDeleted) { if ($message->isDeleted) continue;
continue;
}
$messageType = $message->getMessageType()->getProcessor(); $messageType = $message->getMessageType()->getProcessor();
if ( if (!($messageType instanceof \chat\system\message\type\IDeletableMessageType) || !$messageType->canDelete($message->getDecoratedObject())) {
!($messageType instanceof IDeletableMessageType) throw new PermissionDeniedException();
|| !$messageType->canDelete($message->getDecoratedObject()) }
) { }
throw new PermissionDeniedException(); }
}
}
}
/** /**
* Marks this message as deleted and creates a tombstone message. * Marks this message as deleted and creates a tombstone message.
* *
* Note: Contrary to other applications there is no way to undelete a message. * Note: Contrary to other applications there is no way to undelete a message.
*/ */
public function trash() public function trash() {
{ if (empty($this->objects)) {
if (empty($this->objects)) { $this->readObjects();
$this->readObjects(); }
}
$data = [ $data = [ 'isDeleted' => 1
'isDeleted' => 1, ];
];
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', 'be.bastelstu.chat.messageType.tombstone');
'be.bastelstu.chat.messageType', if (!$objectTypeID) {
'be.bastelstu.chat.messageType.tombstone' throw new \LogicException('Missing object type');
); }
if (!$objectTypeID) {
throw new \LogicException('Missing object type');
}
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$objectAction = new static( $objectAction = new static($this->getObjects(), 'update', [ 'data' => $data ]);
$this->getObjects(), $objectAction->executeAction();
'update', foreach ($this->getObjects() as $message) {
[ if ($message->isDeleted) continue;
'data' => $data,
]
);
$objectAction->executeAction();
foreach ($this->getObjects() as $message) {
if ($message->isDeleted) {
continue;
}
(new self( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $message->roomID
[ ], , 'userID' => null
'create', , 'username' => ''
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $message->roomID, , 'payload' => serialize([ 'messageID' => $message->messageID ])
'userID' => null, ]
'username' => '', ]
'time' => TIME_NOW, )
'objectTypeID' => $objectTypeID, )->executeAction();
'payload' => \serialize([ }
'messageID' => $message->messageID, WCF::getDB()->commitTransaction();
]), }
],
]
))->executeAction();
}
WCF::getDB()->commitTransaction();
}
/** /**
* Prunes chat messages older than chat_log_archivetime days. * Prunes chat messages older than chat_log_archivetime days.
*/ */
public function prune() public function prune() {
{ // Check whether pruning is disabled.
// Check whether pruning is disabled. if (!CHAT_LOG_ARCHIVETIME) return;
if (!CHAT_LOG_ARCHIVETIME) {
return;
}
$sql = "SELECT messageID $sql = "SELECT messageID
FROM chat1_message FROM chat".WCF_N."_message
WHERE time < ?"; WHERE time < ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ TIME_NOW - CHAT_LOG_ARCHIVETIME * 86400 ]); $statement->execute([ TIME_NOW - CHAT_LOG_ARCHIVETIME * 86400 ]);
$messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); $messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
return \call_user_func( return call_user_func([$this->className, 'deleteAll'], $messageIDs);
[$this->className, 'deleteAll'], }
$messageIDs
);
}
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validatePull() public function validatePull() {
{ $this->readString('sessionID', true);
$this->readString('sessionID', true); if ($this->parameters['sessionID']) {
if ($this->parameters['sessionID']) { $this->parameters['sessionID'] = pack('H*', str_replace('-', '', $this->parameters['sessionID']));
$this->parameters['sessionID'] = \pack( }
'H*',
\str_replace('-', '', $this->parameters['sessionID'])
);
}
$this->readInteger('roomID'); $this->readInteger('roomID');
$this->readBoolean('inLog', true); $this->readBoolean('inLog', true);
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID'); if (!$room->canSee($user = null, $reason)) throw $reason;
} $user = new \chat\data\user\User(WCF::getUser());
if (!$room->canSee($user = null, $reason)) { if (!$this->parameters['inLog'] && !$user->isInRoom($room)) throw new PermissionDeniedException();
throw $reason; if ($this->parameters['inLog'] && !$room->canSeeLog(null, $reason)) throw $reason;
}
$user = new ChatUser(WCF::getUser());
if (!$this->parameters['inLog'] && !$user->isInRoom($room)) {
throw new PermissionDeniedException();
}
if ($this->parameters['inLog'] && !$room->canSeeLog(null, $reason)) {
throw $reason;
}
$this->readInteger('from', true); $this->readInteger('from', true);
$this->readInteger('to', true); $this->readInteger('to', true);
// One may not pass both 'from' and 'to' // One may not pass both 'from' and 'to'
if ($this->parameters['from'] && $this->parameters['to']) { if ($this->parameters['from'] && $this->parameters['to']) {
throw new UserInputException(); throw new UserInputException();
} }
} }
/** /**
* Pulls messages for the given room. * Pulls messages for the given room.
*/ */
public function pull() public function pull() {
{ $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); if ($room === null) throw new UserInputException('roomID');
if ($room === null) {
throw new UserInputException('roomID');
}
if (($sessionID = $this->parameters['sessionID'])) { if (($sessionID = $this->parameters['sessionID'])) {
if (\strlen($sessionID) !== 16) { if (strlen($sessionID) !== 16) throw new UserInputException('sessionID');
throw new UserInputException('sessionID');
}
(new ChatUserAction([], 'clearDeadSessions'))->executeAction(); (new \chat\data\user\UserAction([], 'clearDeadSessions'))->executeAction();
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
// update timestamp // update timestamp
$sql = "UPDATE chat1_room_to_user $sql = "UPDATE chat".WCF_N."_room_to_user
SET lastPull = ? SET lastPull = ?
WHERE roomID = ? WHERE roomID = ?
AND userID = ?"; AND userID = ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ TIME_NOW, $statement->execute([ TIME_NOW
$room->roomID, , $room->roomID
WCF::getUser()->userID, , WCF::getUser()->userID
]); ]);
$sql = "UPDATE chat1_session $sql = "UPDATE chat".WCF_N."_session
SET lastRequest = ? SET lastRequest = ?
WHERE roomID = ? WHERE roomID = ?
AND userID = ? AND userID = ?
AND sessionID = ?"; AND sessionID = ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ TIME_NOW, $statement->execute([ TIME_NOW
$room->roomID, , $room->roomID
WCF::getUser()->userID, , WCF::getUser()->userID
$sessionID, , $sessionID
]); ]);
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
} }
// Determine message types supporting fast select // Determine message types supporting fast select
$objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType'); $objectTypes = \wcf\data\object\type\ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType');
$fastSelect = \array_map(static function ($item) { $fastSelect = array_map(function ($item) {
return $item->objectTypeID; return $item->objectTypeID;
}, \array_filter($objectTypes, static function ($item) { }, array_filter($objectTypes, function ($item) {
return $item->getProcessor()->supportsFastSelect(); return $item->getProcessor()->supportsFastSelect();
})); }));
// Build fast select filter // Build fast select filter
$condition = new PreparedStatementConditionBuilder(); $condition = new \wcf\system\database\util\PreparedStatementConditionBuilder();
$condition->add('((roomID = ? AND objectTypeID IN (?)) OR objectTypeID NOT IN (?))', [ $room->roomID, $fastSelect, $fastSelect ]); $condition->add('((roomID = ? AND objectTypeID IN (?)) OR objectTypeID NOT IN (?))', [ $room->roomID, $fastSelect, $fastSelect ]);
$sortOrder = 'DESC'; $sortOrder = 'DESC';
// Add offset // Add offset
if ($this->parameters['from']) { if ($this->parameters['from']) {
$condition->add('messageID >= ?', [ $this->parameters['from'] ]); $condition->add('messageID >= ?', [ $this->parameters['from'] ]);
$sortOrder = 'ASC'; $sortOrder = 'ASC';
} }
if ($this->parameters['to']) { if ($this->parameters['to']) {
$condition->add('messageID <= ?', [ $this->parameters['to'] ]); $condition->add('messageID <= ?', [ $this->parameters['to'] ]);
} }
$sql = "SELECT messageID $sql = "SELECT messageID
FROM chat1_message FROM chat".WCF_N."_message
" . $condition . " ".$condition."
ORDER BY messageID " . $sortOrder; ORDER BY messageID ".$sortOrder;
$statement = WCF::getDB()->prepare($sql, 20); $statement = WCF::getDB()->prepareStatement($sql, 20);
$statement->execute($condition->getParameters()); $statement->execute($condition->getParameters());
$messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); $messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
$objectList = new MessageList(); $objectList = new MessageList();
$objectList->setObjectIDs($messageIDs); $objectList->setObjectIDs($messageIDs);
$objectList->readObjects(); $objectList->readObjects();
$objects = $objectList->getObjects(); $objects = $objectList->getObjects();
$canSeeLog = $room->canSeeLog(); $canSeeLog = $room->canSeeLog();
$messages = \array_map(static function (Message $item) use ($room) { $messages = array_map(function (Message $item) use ($room) {
return new ViewableMessage($item, $room); return new ViewableMessage($item, $room);
}, \array_filter($objects, function (Message $message) use ($canSeeLog, $room) { }, array_filter($objects, function (Message $message) use ($canSeeLog, $room) {
if ($this->parameters['inLog'] || $message->isInLog()) { if ($this->parameters['inLog'] || $message->isInLog()) {
return $canSeeLog && $message->getMessageType()->getProcessor()->canSeeInLog($message, $room); return $canSeeLog && $message->getMessageType()->getProcessor()->canSeeInLog($message, $room);
} else { }
return $message->getMessageType()->getProcessor()->canSee($message, $room); else {
} return $message->getMessageType()->getProcessor()->canSee($message, $room);
})); }
}));
$embeddedObjectMessageIDs = \array_map(static function ($message) { $embeddedObjectMessageIDs = array_map(function ($message) {
return $message->messageID; return $message->messageID;
}, \array_filter($messages, static function ($message) { }, array_filter($messages, function ($message) {
return $message->hasEmbeddedObjects; return $message->hasEmbeddedObjects;
})); }));
if ($embeddedObjectMessageIDs !== []) { if (!empty($embeddedObjectMessageIDs)) {
// load embedded objects // load embedded objects
MessageEmbeddedObjectManager::getInstance()->loadObjects('be.bastelstu.chat.message', $embeddedObjectMessageIDs); \wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->loadObjects('be.bastelstu.chat.message', $embeddedObjectMessageIDs);
} }
return [ return [ 'messages' => $messages
'messages' => $messages, , 'from' => $this->parameters['from'] ?: (!empty($objects) ? reset($objects)->messageID : $this->parameters['to'] + 1)
'from' => $this->parameters['from'] ?: (!empty($objects) ? \reset($objects)->messageID : $this->parameters['to'] + 1), , 'to' => $this->parameters['to'] ?: (!empty($objects) ? end($objects)->messageID : $this->parameters['from'] - 1)
'to' => $this->parameters['to'] ?: (!empty($objects) ? \end($objects)->messageID : $this->parameters['from'] - 1), ];
]; }
}
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validatePush() public function validatePush() {
{ $this->readInteger('roomID');
$this->readInteger('roomID');
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID'); if (!$room->canSee($user = null, $reason)) throw $reason;
} $user = new \chat\data\user\User(WCF::getUser());
if (!$room->canSee($user = null, $reason)) { if (!$user->isInRoom($room)) throw new PermissionDeniedException();
throw $reason;
}
$user = new ChatUser(WCF::getUser());
if (!$user->isInRoom($room)) {
throw new PermissionDeniedException();
}
$this->readInteger('commandID'); $this->readInteger('commandID');
$command = CommandCache::getInstance()->getCommand($this->parameters['commandID']); $command = CommandCache::getInstance()->getCommand($this->parameters['commandID']);
if ($command === null) { if ($command === null) throw new UserInputException('commandID');
throw new UserInputException('commandID'); if (!$command->hasTriggers()) {
} if (!$command->getProcessor()->allowWithoutTrigger()) {
if (!$command->hasTriggers()) { throw new UserInputException('commandID');
if (!$command->getProcessor()->allowWithoutTrigger()) { }
throw new UserInputException('commandID'); }
}
}
$this->readJSON('parameters', true); $this->readJSON('parameters', true);
} }
/** /**
* Pushes a new message into the given room. * Pushes a new message into the given room.
*/ */
public function push() public function push() {
{ $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); if ($room === null) throw new UserInputException('roomID');
if ($room === null) {
throw new UserInputException('roomID');
}
$command = CommandCache::getInstance()->getCommand($this->parameters['commandID']); $command = CommandCache::getInstance()->getCommand($this->parameters['commandID']);
if ($command === null) { if ($command === null) throw new UserInputException('commandID');
throw new UserInputException('commandID');
}
$processor = $command->getProcessor(); $processor = $command->getProcessor();
$processor->validate($this->parameters['parameters'], $room); $processor->validate($this->parameters['parameters'], $room);
$processor->execute($this->parameters['parameters'], $room); $processor->execute($this->parameters['parameters'], $room);
} }
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validatePushAttachment() public function validatePushAttachment() {
{ $this->readInteger('roomID');
$this->readInteger('roomID');
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID'); if (!$room->canSee($user = null, $reason)) throw $reason;
} $user = new \chat\data\user\User(WCF::getUser());
if (!$room->canSee($user = null, $reason)) { if (!$user->isInRoom($room)) throw new PermissionDeniedException();
throw $reason;
}
$user = new ChatUser(WCF::getUser());
if (!$user->isInRoom($room)) {
throw new PermissionDeniedException();
}
if (!$room->canWritePublicly(null, $reason)) { if (!$room->canWritePublicly(null, $reason)) throw $reason;
throw $reason;
}
$this->readString('tmpHash'); $this->readString('tmpHash');
} }
/** /**
* Pushes a new attachment into the given room. * Pushes a new attachment into the given room.
*/ */
public function pushAttachment() public function pushAttachment() {
{ $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', 'be.bastelstu.chat.messageType.attachment');
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( if (!$objectTypeID) throw new \LogicException('Missing object type');
'be.bastelstu.chat.messageType',
'be.bastelstu.chat.messageType.attachment'
);
if (!$objectTypeID) {
throw new \LogicException('Missing object type');
}
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID');
}
$attachmentHandler = new AttachmentHandler( $attachmentHandler = new AttachmentHandler('be.bastelstu.chat.message', 0, $this->parameters['tmpHash'], $room->roomID);
'be.bastelstu.chat.message', $attachments = $attachmentHandler->getAttachmentList();
0, $attachmentIDs = [];
$this->parameters['tmpHash'], foreach ($attachments as $attachment) {
$room->roomID $attachmentIDs[] = $attachment->attachmentID;
); }
$attachments = $attachmentHandler->getAttachmentList();
$attachmentIDs = [];
foreach ($attachments as $attachment) {
$attachmentIDs[] = $attachment->attachmentID;
}
$processor = new HtmlInputProcessor(); $processor = new \wcf\system\html\input\HtmlInputProcessor();
$processor->process(\implode(' ', \array_map(static function ($attachmentID) { $processor->process(implode(' ', array_map(function ($attachmentID) {
return '[attach=' . $attachmentID . ',none,true][/attach]'; return '[attach='.$attachmentID.',none,true][/attach]';
}, $attachmentIDs)), 'be.bastelstu.chat.message', 0); }, $attachmentIDs)), 'be.bastelstu.chat.message', 0);
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
/** @var Message $message */ /** @var Message $message */
$message = (new self( $message = (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => WCF::getUser()->userID
'create', , 'username' => WCF::getUser()->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'attachmentIDs' => $attachmentIDs
'userID' => WCF::getUser()->userID, , 'message' => $processor->getHtml()
'username' => WCF::getUser()->username, ])
'time' => TIME_NOW, ]
'objectTypeID' => $objectTypeID, ]
'payload' => \serialize([ )
'attachmentIDs' => $attachmentIDs, )->executeAction()['returnValues'];
'message' => $processor->getHtml(),
]),
],
]
))->executeAction()['returnValues'];
$attachmentHandler->updateObjectID($message->messageID); $attachmentHandler->updateObjectID($message->messageID);
$processor->setObjectID($message->messageID); $processor->setObjectID($message->messageID);
if (MessageEmbeddedObjectManager::getInstance()->registerObjects($processor)) { if (\wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->registerObjects($processor)) {
(new MessageEditor($message))->update([ (new MessageEditor($message))->update([
'hasEmbeddedObjects' => 1, 'hasEmbeddedObjects' => 1
]); ]);
} }
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,34 +14,31 @@
namespace chat\data\message; namespace chat\data\message;
use wcf\data\DatabaseObjectEditor; use \wcf\system\attachment\AttachmentHandler;
use wcf\system\attachment\AttachmentHandler; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* Represents a chat message editor. * Represents a chat message editor.
*/ */
class MessageEditor extends DatabaseObjectEditor class MessageEditor extends \wcf\data\DatabaseObjectEditor {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $baseClass = Message::class;
protected static $baseClass = Message::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function deleteAll(array $messageIDs = []) public static function deleteAll(array $messageIDs = []) {
{ WCF::getDB()->beginTransaction();
WCF::getDB()->beginTransaction();
$result = parent::deleteAll($messageIDs); $result = parent::deleteAll($messageIDs);
if ($messageIDs !== []) { if (!empty($messageIDs)) {
AttachmentHandler::removeAttachments('be.bastelstu.chat.message', $messageIDs); AttachmentHandler::removeAttachments('be.bastelstu.chat.message', $messageIDs);
} }
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
return $result; return $result;
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,17 +14,8 @@
namespace chat\data\message; namespace chat\data\message;
use wcf\data\DatabaseObjectList;
/** /**
* Represents a list of chat messages. * Represents a list of chat messages.
*
* @method Message current()
* @method Message[] getObjects()
* @method Message|null getSingleObject()
* @method Message|null search($objectID)
* @property Message[] $objects
*/ */
class MessageList extends DatabaseObjectList class MessageList extends \wcf\data\DatabaseObjectList {
{
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,59 +14,50 @@
namespace chat\data\message; namespace chat\data\message;
use chat\data\room\Room; use \wcf\system\request\LinkHandler;
use chat\page\LogPage; use \wcf\system\WCF;
use wcf\data\DatabaseObjectDecorator;
use wcf\system\request\LinkHandler;
use wcf\system\WCF;
/** /**
* Represents a chat message. * Represents a chat message.
*/ */
class ViewableMessage extends DatabaseObjectDecorator implements \JsonSerializable class ViewableMessage extends \wcf\data\DatabaseObjectDecorator implements \JsonSerializable {
{ protected static $baseClass = Message::class;
protected static $baseClass = Message::class;
protected $room; protected $room = null;
public function __construct(Message $message, Room $room) public function __construct(Message $message, \chat\data\room\Room $room) {
{ parent::__construct($message);
parent::__construct($message);
$this->room = $room; $this->room = $room;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function jsonSerialize(): array public function jsonSerialize() {
{ $link = LinkHandler::getInstance()->getLink('Log', [ 'application' => 'chat'
$link = LinkHandler::getInstance()->getControllerLink( , 'messageid' => $this->messageID
LogPage::class, , 'object' => $this->room
[ ]);
'messageid' => $this->messageID,
'object' => $this->room,
]
);
if ($this->isDeleted) { if ($this->isDeleted) {
$payload = false; $payload = false;
$objectType = 'be.bastelstu.chat.messageType.tombstone'; $objectType = 'be.bastelstu.chat.messageType.tombstone';
} else { }
$payload = $this->getMessageType()->getProcessor()->getPayload($this->getDecoratedObject()); else {
$objectType = $this->getMessageType()->objectType; $payload = $this->getMessageType()->getProcessor()->getPayload($this->getDecoratedObject());
} $objectType = $this->getMessageType()->objectType;
}
return [ return [ 'messageID' => $this->messageID
'messageID' => $this->messageID, , 'userID' => $this->userID
'userID' => $this->userID, , 'username' => $this->username
'username' => $this->username, , 'time' => $this->time
'time' => $this->time, , 'payload' => $payload
'payload' => $payload, , 'objectType' => $objectType
'objectType' => $objectType, , 'link' => $link
'link' => $link, , 'isIgnored' => WCF::getUserProfileHandler()->isIgnoredUser($this->userID)
'isIgnored' => WCF::getUserProfileHandler()->isIgnoredUser($this->userID), , 'isDeleted' => (bool) $this->isDeleted
'isDeleted' => (bool)$this->isDeleted, ];
]; }
}
} }

View File

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

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,478 +14,363 @@
namespace chat\data\room; namespace chat\data\room;
use chat\data\command\CommandCache; use \chat\data\user\User as ChatUser;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\user\User as ChatUser; use \wcf\data\object\type\ObjectTypeCache;
use chat\data\user\UserAction as ChatUserAction; use \wcf\system\cache\runtime\UserProfileRuntimeCache;
use chat\system\box\RoomListBoxController; use \wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\data\AbstractDatabaseObjectAction; use \wcf\system\exception\PermissionDeniedException;
use wcf\data\box\Box; use \wcf\system\exception\UserInputException;
use wcf\data\ISortableAction; use \wcf\system\user\activity\point\UserActivityPointHandler;
use wcf\data\object\type\ObjectTypeCache; use \wcf\system\WCF;
use wcf\data\package\PackageCache;
use wcf\data\user\UserProfile;
use wcf\system\cache\runtime\UserProfileRuntimeCache;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\event\EventHandler;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
use wcf\system\push\PushHandler;
use wcf\system\user\activity\point\UserActivityPointHandler;
use wcf\system\WCF;
/** /**
* Executes chat room-related actions. * Executes chat room-related actions.
*/ */
class RoomAction extends AbstractDatabaseObjectAction implements ISortableAction class RoomAction extends \wcf\data\AbstractDatabaseObjectAction implements \wcf\data\ISortableAction {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected $permissionsDelete = [ 'admin.chat.canManageRoom' ];
protected $permissionsDelete = [
'admin.chat.canManageRoom',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $permissionsUpdate = [ protected $permissionsUpdate = [ 'admin.chat.canManageRoom' ];
'admin.chat.canManageRoom',
];
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validateJoin() public function validateJoin() {
{ unset($this->parameters['user']);
unset($this->parameters['user']);
$this->readString('sessionID'); $this->readString('sessionID');
$this->parameters['sessionID'] = \pack( $this->parameters['sessionID'] = pack('H*', str_replace('-', '', $this->parameters['sessionID']));
'H*',
\str_replace('-', '', $this->parameters['sessionID'])
);
$this->readInteger('roomID'); $this->readInteger('roomID');
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID'); if (!$room->canSee($user = null, $reason)) throw $reason;
} if (!$room->canJoin($user = null, $reason)) throw $reason;
if (!$room->canSee($user = null, $reason)) { }
throw $reason;
}
if (!$room->canJoin($user = null, $reason)) {
throw $reason;
}
}
/** /**
* Makes the given user join the current chat room. * Makes the given user join the current chat room.
*/ */
public function join() public function join() {
{ $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', 'be.bastelstu.chat.messageType.join');
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( if (!$objectTypeID) throw new \LogicException('Missing object type');
'be.bastelstu.chat.messageType', // User cannot be set during an AJAX request, but may be set by Tims Chat itself.
'be.bastelstu.chat.messageType.join' if (!isset($this->parameters['user'])) $this->parameters['user'] = WCF::getUser();
); $user = new ChatUser($this->parameters['user']);
if (!$objectTypeID) {
throw new \LogicException('Missing object type');
}
// User cannot be set during an AJAX request, but may be set by Tims Chat itself.
if (!isset($this->parameters['user'])) {
$this->parameters['user'] = WCF::getUser();
}
$user = new ChatUser($this->parameters['user']);
// Check parameters // Check parameters
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID'); $sessionID = $this->parameters['sessionID'];
} if (strlen($sessionID) !== 16) throw new UserInputException('sessionID');
$sessionID = $this->parameters['sessionID'];
if (\strlen($sessionID) !== 16) {
throw new UserInputException('sessionID');
}
try { try {
// Create room_to_user mapping. // Create room_to_user mapping.
$sql = "INSERT INTO chat1_room_to_user $sql = "INSERT INTO chat".WCF_N."_room_to_user (active, roomID, userID) VALUES (?, ?, ?)";
(active, roomID, userID) $statement = WCF::getDB()->prepareStatement($sql);
VALUES (?, ?, ?)"; $statement->execute([ 0, $room->roomID, $user->userID ]);
$statement = WCF::getDB()->prepare($sql); }
$statement->execute([ 0, $room->roomID, $user->userID ]); catch (\wcf\system\database\exception\DatabaseException $e) {
} catch (\wcf\system\database\exception\DatabaseException $e) { // Ignore if there already is a mapping.
// Ignore if there already is a mapping. if ((string) $e->getCode() !== '23000') throw $e;
if ((string)$e->getCode() !== '23000') { }
throw $e;
}
}
try { try {
$sql = "INSERT INTO chat1_session $sql = "INSERT INTO chat".WCF_N."_session (roomID, userID, sessionID, lastRequest) VALUES (?, ?, ?, ?)";
(roomID, userID, sessionID, lastRequest) $statement = WCF::getDB()->prepareStatement($sql);
VALUES (?, ?, ?, ?)"; $statement->execute([ $room->roomID, $user->userID, $sessionID, TIME_NOW ]);
$statement = WCF::getDB()->prepare($sql); }
$statement->execute([ catch (\wcf\system\database\exception\DatabaseException $e) {
$room->roomID, if ((string) $e->getCode() !== '23000') throw $e;
$user->userID,
$sessionID,
TIME_NOW,
]);
} catch (\wcf\system\database\exception\DatabaseException $e) {
if ((string)$e->getCode() !== '23000') {
throw $e;
}
throw new UserInputException('sessionID'); throw new UserInputException('sessionID');
} }
$markAsBack = static function () use ($user, $room) { $markAsBack = function () use ($user, $room) {
$userProfile = new UserProfile($user->getDecoratedObject()); $userProfile = new \wcf\data\user\UserProfile($user->getDecoratedObject());
$package = PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat'); $package = \wcf\data\package\PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat');
$command = CommandCache::getInstance()->getCommandByPackageAndIdentifier($package, 'back'); $command = \chat\data\command\CommandCache::getInstance()->getCommandByPackageAndIdentifier($package, 'back');
$processor = $command->getProcessor(); $processor = $command->getProcessor();
$processor->execute([ ], $room, $userProfile); $processor->execute([ ], $room, $userProfile);
}; };
if ($user->chatAway !== null) { if ($user->chatAway !== null) {
$markAsBack(); $markAsBack();
} }
// Attempt to mark the user as active in the room. // Attempt to mark the user as active in the room.
$sql = "UPDATE chat1_room_to_user $sql = "UPDATE chat".WCF_N."_room_to_user SET active = ? WHERE roomID = ? AND userID = ?";
SET active = ? $statement = WCF::getDB()->prepareStatement($sql);
WHERE roomID = ? $statement->execute([ 1, $room->roomID, $user->userID ]);
AND userID = ?"; if ($statement->getAffectedRows() === 0) {
$statement = WCF::getDB()->prepare($sql); // The User already is inside the room: Nothing to do here.
$statement->execute([ 1, $room->roomID, $user->userID ]); return;
if ($statement->getAffectedRows() === 0) { }
// The User already is inside the room: Nothing to do here.
return;
}
// Update lastPull. This must not be merged into the above query, because of the 'getAffectedRows' check. // Update lastPull. This must not be merged into the above query, because of the 'getAffectedRows' check.
$sql = "UPDATE chat1_room_to_user $sql = "UPDATE chat".WCF_N."_room_to_user SET lastPull = ? WHERE roomID = ? AND userID = ?";
SET lastPull = ? $statement = WCF::getDB()->prepareStatement($sql);
WHERE roomID = ? $statement->execute([ TIME_NOW, $room->roomID, $user->userID ]);
AND userID = ?";
$statement = WCF::getDB()->prepare($sql);
$statement->execute([ TIME_NOW, $room->roomID, $user->userID ]);
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ ])
'userID' => $user->userID, ]
'username' => $user->username, ]
'time' => TIME_NOW, )
'objectTypeID' => $objectTypeID, )->executeAction();
'payload' => \serialize([ ]),
],
]
))->executeAction();
UserActivityPointHandler::getInstance()->fireEvent( UserActivityPointHandler::getInstance()->fireEvent('be.bastelstu.chat.activityPointEvent.join', 0, $user->userID);
'be.bastelstu.chat.activityPointEvent.join', $pushHandler = \wcf\system\push\PushHandler::getInstance();
0, $pushHandler->sendMessage([ 'message' => 'be.bastelstu.chat.join'
$user->userID , 'target' => 'registered'
); ]);
$pushHandler = PushHandler::getInstance(); }
$pushHandler->sendMessage([
'message' => 'be.bastelstu.chat.join',
'target' => 'registered',
]);
}
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validateLeave() public function validateLeave() {
{ unset($this->parameters['user']);
unset($this->parameters['user']);
$this->readString('sessionID'); $this->readString('sessionID');
$this->parameters['sessionID'] = \pack( $this->parameters['sessionID'] = pack('H*', str_replace('-', '', $this->parameters['sessionID']));
'H*',
\str_replace('-', '', $this->parameters['sessionID'])
);
$this->readInteger('roomID'); $this->readInteger('roomID');
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID'); // Do not check permissions: If the user is not inside the room nothing happens, if he is it
} // may lead to a faster eviction of the user.
// Do not check permissions: If the user is not inside the room nothing happens, if he is it }
// may lead to a faster eviction of the user.
}
/** /**
* Makes the given user leave the current chat room. * Makes the given user leave the current chat room.
*/ */
public function leave() public function leave() {
{ $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', 'be.bastelstu.chat.messageType.leave');
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( if ($objectTypeID) {
'be.bastelstu.chat.messageType', // User cannot be set during an AJAX request, but may be set by Tims Chat itself.
'be.bastelstu.chat.messageType.leave' if (!isset($this->parameters['user'])) $this->parameters['user'] = WCF::getUser();
); $user = new ChatUser($this->parameters['user']);
if ($objectTypeID) {
// User cannot be set during an AJAX request, but may be set by Tims Chat itself.
if (!isset($this->parameters['user'])) {
$this->parameters['user'] = WCF::getUser();
}
$user = new ChatUser($this->parameters['user']);
$room = RoomCache::getInstance()->getRoom($this->parameters['roomID']); $room = RoomCache::getInstance()->getRoom($this->parameters['roomID']);
if ($room === null) { if ($room === null) throw new UserInputException('roomID');
throw new UserInputException('roomID');
}
$sessionID = null; $sessionID = null;
if (isset($this->parameters['sessionID'])) { if (isset($this->parameters['sessionID'])) {
$sessionID = $this->parameters['sessionID']; $sessionID = $this->parameters['sessionID'];
if (\strlen($sessionID) !== 16) { if (strlen($sessionID) !== 16) throw new UserInputException('sessionID');
throw new UserInputException('sessionID'); }
}
}
// Delete session. // Delete session.
$condition = new PreparedStatementConditionBuilder(); $condition = new \wcf\system\database\util\PreparedStatementConditionBuilder();
$condition->add('roomID = ?', [ $room->roomID ]); $condition->add('roomID = ?', [ $room->roomID ]);
$condition->add('userID = ?', [ $user->userID ]); $condition->add('userID = ?', [ $user->userID ]);
if ($sessionID !== null) { if ($sessionID !== null) {
$condition->add('sessionID = ?', [ $sessionID ]); $condition->add('sessionID = ?', [ $sessionID ]);
} }
$sql = "DELETE FROM chat1_session $sql = "DELETE FROM chat".WCF_N."_session
{$condition}"; ".$condition;
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute($condition->getParameters()); $statement->execute($condition->getParameters());
if ($statement->getAffectedRows() === 0) { if ($statement->getAffectedRows() === 0) {
throw new UserInputException('sessionID'); throw new UserInputException('sessionID');
} }
try { try {
$commited = false; $commited = false;
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
// Check whether we deleted the last session. // Check whether we deleted the last session.
$sql = "SELECT COUNT(*) $sql = "SELECT COUNT(*)
FROM chat1_session FROM chat".WCF_N."_session
WHERE roomID = ? WHERE roomID = ?
AND userID = ?"; AND userID = ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ $room->roomID, $user->userID ]); $statement->execute([ $room->roomID, $user->userID ]);
// We did not: Nothing to do here. // We did not: Nothing to do here.
if ($statement->fetchColumn()) { if ($statement->fetchColumn()) return;
return;
}
// Mark the user as inactive. // Mark the user as inactive.
$sql = "UPDATE chat1_room_to_user $sql = "UPDATE chat".WCF_N."_room_to_user SET active = ? WHERE roomID = ? AND userID = ?";
SET active = ? $statement = WCF::getDB()->prepareStatement($sql);
WHERE roomID = ? $statement->execute([ 0, $room->roomID, $user->userID ]);
AND userID = ?"; if ($statement->getAffectedRows() === 0) throw new \LogicException('Unreachable');
$statement = WCF::getDB()->prepare($sql);
$statement->execute([ 0, $room->roomID, $user->userID ]);
\assert($statement->getAffectedRows() > 0);
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
$commited = true; $commited = true;
} finally { }
if (!$commited) { finally {
WCF::getDB()->rollBackTransaction(); if (!$commited) WCF::getDB()->rollBackTransaction();
} }
}
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ ])
'userID' => $user->userID, ]
'username' => $user->username, ]
'time' => TIME_NOW, )
'objectTypeID' => $objectTypeID, )->executeAction();
'payload' => \serialize([ ]),
],
]
))->executeAction();
$pushHandler = PushHandler::getInstance(); $pushHandler = \wcf\system\push\PushHandler::getInstance();
$pushHandler->sendMessage([ $pushHandler->sendMessage([ 'message' => 'be.bastelstu.chat.leave'
'message' => 'be.bastelstu.chat.leave', , 'target' => 'registered'
'target' => 'registered', ]);
]); }
} else { else {
throw new \LogicException('Missing object type'); throw new \LogicException('Missing object type');
} }
} }
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validateGetUsers() public function validateGetUsers() {
{ if (empty($this->getObjects())) {
if (empty($this->getObjects())) { $this->readObjects();
$this->readObjects(); }
} if (count($this->getObjects()) !== 1) {
if (\count($this->getObjects()) !== 1) { throw new UserInputException('objectIDs');
throw new UserInputException('objectIDs'); }
}
$room = $this->getObjects()[0]; $room = $this->getObjects()[0];
$user = new ChatUser(WCF::getUser()); $user = new ChatUser(WCF::getUser());
if (!$user->isInRoom($room->getDecoratedObject())) { if (!$user->isInRoom($room->getDecoratedObject())) throw new PermissionDeniedException();
throw new PermissionDeniedException(); }
}
}
/** /**
* Returns the userIDs of the users in this room. * Returns the userIDs of the users in this room.
*/ */
public function getUsers() public function getUsers() {
{ if (empty($this->getObjects())) {
if (empty($this->getObjects())) { $this->readObjects();
$this->readObjects(); }
} if (count($this->getObjects()) !== 1) {
if (\count($this->getObjects()) !== 1) { throw new UserInputException('objectIDs');
throw new UserInputException('objectIDs'); }
}
$room = $this->getObjects()[0]; $room = $this->getObjects()[0];
$users = (new ChatUserAction( $users = (new \chat\data\user\UserAction([ ], 'getUsersByID', [
[ ], 'userIDs' => array_keys($room->getUsers())
'getUsersByID', ]))->executeAction()['returnValues'];
[
'userIDs' => \array_keys($room->getUsers()),
]
))->executeAction()['returnValues'];
$users = \array_map(static function (array $user) use ($room) { $users = array_map(function (array $user) use ($room) {
$userProfile = UserProfileRuntimeCache::getInstance()->getObject($user['userID']); $userProfile = UserProfileRuntimeCache::getInstance()->getObject($user['userID']);
if (!isset($user['permissions'])) { if (!isset($user['permissions'])) $user['permissions'] = [];
$user['permissions'] = []; $user['permissions']['canWritePublicly'] = $room->canWritePublicly($userProfile);
}
$user['permissions']['canWritePublicly'] = $room->canWritePublicly($userProfile);
return $user; return $user;
}, $users); }, $users);
EventHandler::getInstance()->fireAction($this, 'getUsers', $users); \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'getUsers', $users);
return $users; return $users;
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validateUpdatePosition() public function validateUpdatePosition() {
{ // validate permissions
// validate permissions if (is_array($this->permissionsUpdate) && !empty($this->permissionsUpdate)) {
if (\is_array($this->permissionsUpdate) && !empty($this->permissionsUpdate)) { WCF::getSession()->checkPermissions($this->permissionsUpdate);
WCF::getSession()->checkPermissions($this->permissionsUpdate); }
} else { else {
throw new PermissionDeniedException(); throw new PermissionDeniedException();
} }
$this->readIntegerArray('structure', false, 'data'); $this->readIntegerArray('structure', false, 'data');
$roomList = new RoomList(); $roomList = new RoomList();
$roomList->readObjects(); $roomList->readObjects();
foreach ($this->parameters['data']['structure'][0] as $roomID) { foreach ($this->parameters['data']['structure'][0] as $roomID) {
$room = $roomList->search($roomID); $room = $roomList->search($roomID);
if ($room === null) { if ($room === null) throw new UserInputException('structure');
throw new UserInputException('structure'); }
} }
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function updatePosition() public function updatePosition() {
{ $roomList = new RoomList();
$roomList = new RoomList(); $roomList->readObjects();
$roomList->readObjects();
$i = 0; $i = 0;
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
foreach ($this->parameters['data']['structure'][0] as $roomID) { foreach ($this->parameters['data']['structure'][0] as $roomID) {
$room = $roomList->search($roomID); $room = $roomList->search($roomID);
if ($room === null) { if ($room === null) continue;
continue;
}
$editor = new RoomEditor($room); $editor = new RoomEditor($room);
$editor->update([ $editor->update([ 'position' => $i++ ]);
'position' => $i++, }
]); WCF::getDB()->commitTransaction();
} }
WCF::getDB()->commitTransaction();
}
/** /**
* Validates permissions. * Validates permissions.
*/ */
public function validateGetBoxRoomList() public function validateGetBoxRoomList() {
{ if (!\chat\data\room\Room::canSeeAny()) throw new \wcf\system\exception\PermissionDeniedException();
if (!Room::canSeeAny()) {
throw new PermissionDeniedException();
}
$this->readBoolean('isSidebar', true); $this->readBoolean('isSidebar', true);
$this->readBoolean('skipEmptyRooms', true); $this->readBoolean('skipEmptyRooms', true);
$this->readInteger('activeRoomID', true); $this->readInteger('activeRoomID', true);
unset($this->parameters['boxController']); unset($this->parameters['boxController']);
$this->readInteger('boxID', true); $this->readInteger('boxID', true);
if ($this->parameters['boxID']) { if ($this->parameters['boxID']) {
$box = new Box($this->parameters['boxID']); $box = new \wcf\data\box\Box($this->parameters['boxID']);
if ($box->boxID) { if ($box->boxID) {
$this->parameters['boxController'] = $box->getController(); $this->parameters['boxController'] = $box->getController();
if ($this->parameters['boxController'] instanceof RoomListBoxController) { if ($this->parameters['boxController'] instanceof \chat\system\box\RoomListBoxController) {
// all checks passed, end validation; otherwise throw the exception below // all checks passed, end validation; otherwise throw the exception below
return; return;
} }
} }
throw new UserInputException('boxID'); throw new UserInputException('boxID');
} }
} }
/** /**
* Returns dashboard roomlist. * Returns dashboard roomlist.
*/ */
public function getBoxRoomList() public function getBoxRoomList() {
{ if (isset($this->parameters['boxController'])) {
if (isset($this->parameters['boxController'])) { $this->parameters['boxController']->setActiveRoomID($this->parameters['activeRoomID']);
$this->parameters['boxController']->setActiveRoomID($this->parameters['activeRoomID']);
return [ return [ 'template' => $this->parameters['boxController']->getContent() ];
'template' => $this->parameters['boxController']->getContent(), }
];
}
// Fetch all rooms, the templates have filtering in place // Fetch all rooms, the templates have filtering in place
$rooms = RoomCache::getInstance()->getRooms(); $rooms = RoomCache::getInstance()->getRooms();
$template = 'boxRoomList' . ($this->parameters['isSidebar'] ? 'Sidebar' : ''); $template = 'boxRoomList'.($this->parameters['isSidebar'] ? 'Sidebar' : '');
WCF::getTPL()->assign([ \wcf\system\WCF::getTPL()->assign([ 'boxRoomList' => $rooms
'boxRoomList' => $rooms, , 'skipEmptyRooms' => $this->parameters['skipEmptyRooms']
'skipEmptyRooms' => $this->parameters['skipEmptyRooms'], , 'activeRoomID' => $this->parameters['activeRoomID']
'activeRoomID' => $this->parameters['activeRoomID'], ]);
]);
return [ return [ 'template' => \wcf\system\WCF::getTPL()->fetch($template, 'chat') ];
'template' => WCF::getTPL()->fetch($template, 'chat'), }
];
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,55 +14,53 @@
namespace chat\data\room; namespace chat\data\room;
use chat\system\cache\builder\RoomCacheBuilder; use \wcf\system\WCF;
use wcf\system\SingletonFactory;
/** /**
* Manages the room cache. * Manages the room cache.
*/ */
final class RoomCache extends SingletonFactory class RoomCache extends \wcf\system\SingletonFactory {
{ /**
/** * List of cached rooms.
* List of cached rooms. *
* * @var Room[]
* @var Room[] */
*/ protected $rooms = [ ];
protected $rooms = [ ];
/** /**
* Cached user counts for the rooms. * Cached user counts for the rooms.
* *
* @var int[] * @var int[]
*/ */
protected $userCount = [ ]; protected $userCount = [ ];
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function init() protected function init() {
{ $this->rooms = \chat\system\cache\builder\RoomCacheBuilder::getInstance()->getData();
$this->rooms = RoomCacheBuilder::getInstance()->getData(); }
}
/** /**
* Returns a specific room. * Returns a specific room.
*/ *
public function getRoom(int $roomID): ?Room * @param integer $roomID
{ * @return Room
if (isset($this->rooms[$roomID])) { */
return $this->rooms[$roomID]; public function getRoom($roomID) {
} if (isset($this->rooms[$roomID])) {
return $this->rooms[$roomID];
}
return null; return null;
} }
/** /**
* Returns all rooms. * Returns all rooms.
* *
* @return Room[] * @return Room[]
*/ */
public function getRooms() public function getRooms() {
{ return $this->rooms;
return $this->rooms; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,27 +14,20 @@
namespace chat\data\room; namespace chat\data\room;
use chat\system\cache\builder\RoomCacheBuilder;
use chat\system\permission\PermissionHandler;
use wcf\data\DatabaseObjectEditor;
use wcf\data\IEditableCachedObject;
/** /**
* Represents a chat room editor. * Represents a chat room editor.
*/ */
class RoomEditor extends DatabaseObjectEditor implements IEditableCachedObject class RoomEditor extends \wcf\data\DatabaseObjectEditor implements \wcf\data\IEditableCachedObject {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $baseClass = Room::class;
protected static $baseClass = Room::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public static function resetCache() public static function resetCache() {
{ \chat\system\cache\builder\RoomCacheBuilder::getInstance()->reset();
RoomCacheBuilder::getInstance()->reset(); \chat\system\permission\PermissionHandler::resetCache();
PermissionHandler::resetCache(); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,21 +14,12 @@
namespace chat\data\room; namespace chat\data\room;
use wcf\data\DatabaseObjectList;
/** /**
* Represents a list of chat rooms. * Represents a list of chat rooms.
*
* @method Room current()
* @method Room[] getObjects()
* @method Room|null getSingleObject()
* @method Room|null search($objectID)
* @property Room[] $objects
*/ */
class RoomList extends DatabaseObjectList class RoomList extends \wcf\data\DatabaseObjectList {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $sqlOrderBy = 'position';
public $sqlOrderBy = 'position';
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,105 +14,98 @@
namespace chat\data\suspension; namespace chat\data\suspension;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomCache; use \wcf\data\user\User;
use wcf\data\DatabaseObject; use \wcf\system\WCF;
use wcf\data\object\type\ObjectType;
use wcf\data\object\type\ObjectTypeCache;
use wcf\data\user\User;
use wcf\system\cache\runtime\UserRuntimeCache;
/** /**
* Represents a chat suspension. * Represents a chat suspension.
*/ */
class Suspension extends DatabaseObject implements \JsonSerializable class Suspension extends \wcf\data\DatabaseObject implements \JsonSerializable {
{ /**
/** * Returns the active suspensions for the given (objectTypeID, Room, User)
* Returns the active suspensions for the given (objectTypeID, Room, User) * triple.
* triple. *
* * @param int $objectTypeID
* @return \chat\data\suspension\Suspension[] * @param \wcf\data\user\User $user
*/ * @param \chat\data\room\Room $room
public static function getActiveSuspensionsByTriple(int $objectTypeID, User $user, Room $room) * @return \chat\data\suspension\Suspension[]
{ */
$suspensionList = new SuspensionList(); public static function getActiveSuspensionsByTriple($objectTypeID, User $user, Room $room) {
$suspensionList = new SuspensionList();
$suspensionList->getConditionBuilder()->add('(expires IS NULL OR expires > ?)', [ TIME_NOW ]); $suspensionList->getConditionBuilder()->add('(expires IS NULL OR expires > ?)', [ TIME_NOW ]);
$suspensionList->getConditionBuilder()->add('revoked IS NULL'); $suspensionList->getConditionBuilder()->add('revoked IS NULL');
$suspensionList->getConditionBuilder()->add('userID = ?', [ $user->userID ]); $suspensionList->getConditionBuilder()->add('userID = ?', [ $user->userID ]);
$suspensionList->getConditionBuilder()->add('objectTypeID = ?', [ $objectTypeID ]); $suspensionList->getConditionBuilder()->add('objectTypeID = ?', [ $objectTypeID ]);
$suspensionList->getConditionBuilder()->add('(roomID IS NULL OR roomID = ?)', [ $room->roomID ]); $suspensionList->getConditionBuilder()->add('(roomID IS NULL OR roomID = ?)', [ $room->roomID ]);
$suspensionList->readObjects(); $suspensionList->readObjects();
return \array_filter($suspensionList->getObjects(), static function (self $suspension) { return array_filter($suspensionList->getObjects(), function (Suspension $suspension) {
return $suspension->isActive(); return $suspension->isActive();
}); });
} }
/** /**
* Returns the suspension object type of this message. * Returns the suspension object type of this message.
*/ *
public function getSuspensionType(): ObjectType * @return \wcf\data\object\type\ObjectType
{ */
return ObjectTypeCache::getInstance()->getObjectType($this->objectTypeID); public function getSuspensionType() {
} return \wcf\data\object\type\ObjectTypeCache::getInstance()->getObjectType($this->objectTypeID);
}
/** /**
* Returns whether this suspension still is in effect. * Returns whether this suspension still is in effect.
*/ *
public function isActive(): bool * @return boolean
{ */
if ($this->revoked !== null) { public function isActive() {
return false; if ($this->revoked !== null) return false;
} if (!$this->getSuspensionType()->getProcessor()->hasEffect($this)) return false;
if (!$this->getSuspensionType()->getProcessor()->hasEffect($this)) {
return false;
}
if ($this->expires === null) { if ($this->expires === null) return true;
return true;
}
return $this->expires > TIME_NOW; return $this->expires > TIME_NOW;
} }
/** /**
* Returns the chat room this suspension is in effect. * Returns the chat room this suspension is in effect.
* Returns null if this is a global suspension. * Returns null if this is a global suspension.
*/ *
public function getRoom(): ?Room * @return \chat\data\room\Room
{ */
if ($this->roomID === null) { public function getRoom() {
return null; if ($this->roomID === null) {
} return null;
}
return RoomCache::getInstance()->getRoom($this->roomID); return \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
} }
/** /**
* Returns the user that is affected by this suspension. * Returns the user that is affected by this suspension.
*/ *
public function getUser(): User * @return \wcf\data\user\User
{ */
return UserRuntimeCache::getInstance()->getObject($this->userID); public function getUser() {
} return \wcf\system\cache\runtime\UserRuntimeCache::getInstance()->getObject($this->userID);
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function jsonSerialize(): array public function jsonSerialize() {
{ return [ 'userID' => $this->userID
return [ , 'username' => $this->getUser()->username
'userID' => $this->userID, , 'roomID' => $this->roomID
'username' => $this->getUser()->username, , 'time' => $this->time
'roomID' => $this->roomID, , 'expires' => $this->expires
'time' => $this->time, , 'reason' => $this->reason
'expires' => $this->expires, , 'objectType' => $this->getSuspensionType()->objectType
'reason' => $this->reason, , 'judgeID' => $this->judgeID
'objectType' => $this->getSuspensionType()->objectType, , 'judge' => $this->judge
'judgeID' => $this->judgeID, ];
'judge' => $this->judge, }
];
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,75 +14,55 @@
namespace chat\data\suspension; namespace chat\data\suspension;
use wcf\data\AbstractDatabaseObjectAction; use \wcf\system\WCF;
use wcf\system\exception\UserInputException;
use wcf\system\WCF;
/** /**
* Executes suspension-related actions. * Executes suspension-related actions.
*/ */
class SuspensionAction extends AbstractDatabaseObjectAction class SuspensionAction extends \wcf\data\AbstractDatabaseObjectAction {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected $requireACP = [ 'revoke' ];
protected $requireACP = [
'revoke',
];
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validateRevoke() public function validateRevoke() {
{ if (empty($this->objects)) {
if (empty($this->objects)) { $this->readObjects();
$this->readObjects();
if (empty($this->objects)) { if (empty($this->objects)) {
throw new UserInputException('objectIDs'); throw new UserInputException('objectIDs');
} }
} }
unset($this->parameters['revoker']); unset($this->parameters['revoker']);
WCF::getSession()->checkPermissions([ WCF::getSession()->checkPermissions([ 'admin.chat.canManageSuspensions' ]);
'admin.chat.canManageSuspensions',
]);
foreach ($this->getObjects() as $object) { foreach ($this->getObjects() as $object) {
if (!$object->isActive()) { if (!$object->isActive()) throw new UserInputException('objectIDs', 'nonActive');
throw new UserInputException('objectIDs', 'nonActive'); }
} }
}
}
/** /**
* Revokes the suspensions * Revokes the suspensions
*/ */
public function revoke() public function revoke() {
{ if (empty($this->objects)) {
if (empty($this->objects)) { $this->readObjects();
$this->readObjects(); }
}
// User cannot be set during an AJAX request, but may be set by Tims Chat itself. // User cannot be set during an AJAX request, but may be set by Tims Chat itself.
if (!isset($this->parameters['revoker'])) { if (!isset($this->parameters['revoker'])) $this->parameters['revoker'] = WCF::getUser();
$this->parameters['revoker'] = WCF::getUser();
}
$data = [ $data = [ 'revoked' => TIME_NOW
'revoked' => TIME_NOW, , 'revokerID' => $this->parameters['revoker']->userID
'revokerID' => $this->parameters['revoker']->userID, , 'revoker' => $this->parameters['revoker']->username
'revoker' => $this->parameters['revoker']->username, ];
];
$objectAction = new static( $objectAction = new static($this->getObjects(), 'update', [ 'data' => $data ]);
$this->getObjects(), $objectAction->executeAction();
'update', }
[
'data' => $data,
]
);
$objectAction->executeAction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,15 +14,12 @@
namespace chat\data\suspension; namespace chat\data\suspension;
use wcf\data\DatabaseObjectEditor;
/** /**
* Represents a chat suspension editor. * Represents a chat suspension editor.
*/ */
class SuspensionEditor extends DatabaseObjectEditor class SuspensionEditor extends \wcf\data\DatabaseObjectEditor {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $baseClass = Suspension::class;
protected static $baseClass = Suspension::class;
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,17 +14,9 @@
namespace chat\data\suspension; namespace chat\data\suspension;
use wcf\data\DatabaseObjectList;
/** /**
* Represents a list of chat suspensions. * Represents a list of chat suspensions.
*
* @method Suspension current()
* @method Suspension[] getObjects()
* @method Suspension|null getSingleObject()
* @method Suspension|null search($objectID)
* @property Suspension[] $objects
*/ */
class SuspensionList extends DatabaseObjectList class SuspensionList extends \wcf\data\DatabaseObjectList {
{
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,107 +14,93 @@
namespace chat\data\user; namespace chat\data\user;
use chat\data\room\Room; use \wcf\system\WCF;
use chat\data\room\RoomCache;
use wcf\data\DatabaseObjectDecorator;
use wcf\system\WCF;
/** /**
* Decorates the User object to make it useful in context of Tims Chat. * Decorates the User object to make it useful in context of Tims Chat.
*/ */
class User extends DatabaseObjectDecorator implements \JsonSerializable class User extends \wcf\data\DatabaseObjectDecorator implements \JsonSerializable {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $baseClass = \wcf\data\user\User::class;
protected static $baseClass = \wcf\data\user\User::class;
/** /**
* array of room_to_user rows * array of room_to_user rows
* *
* @var int[][] * @var int[][]
*/ */
protected $roomToUser; protected $roomToUser = null;
/** /**
* Returns an array of the room_to_user arrays for this user. * Returns an array of the room_to_user arrays for this user.
* *
* @return mixed[] * @return mixed[]
*/ */
public function getRoomAssociations($skipCache = false) public function getRoomAssociations($skipCache = false) {
{ if ($this->roomToUser === null || $skipCache) {
if ($this->roomToUser === null || $skipCache) { $sql = "SELECT *
$sql = "SELECT * FROM chat".WCF_N."_room_to_user
FROM chat1_room_to_user WHERE userID = ?";
WHERE userID = ?"; $statement = WCF::getDB()->prepareStatement($sql);
$statement = WCF::getDB()->prepare($sql); $statement->execute([ $this->userID ]);
$statement->execute([ $this->userID ]); $this->roomToUser = [ ];
$this->roomToUser = [ ]; while (($row = $statement->fetchArray())) {
while (($row = $statement->fetchArray())) { $this->roomToUser[$row['roomID']] = $row;
$this->roomToUser[$row['roomID']] = $row; }
} }
}
return $this->roomToUser; return $this->roomToUser;
} }
/** /**
* Returns an array of Rooms this user is part of. * Returns an array of Rooms this user is part of.
* *
* @return \chat\data\room\Room[] * @return \chat\data\room\Room[]
*/ */
public function getRooms($skipCache = false) public function getRooms($skipCache = false) {
{ return array_map(function ($assoc) {
return \array_map(static function ($assoc) { return \chat\data\room\RoomCache::getInstance()->getRoom($assoc['roomID']);
return RoomCache::getInstance()->getRoom($assoc['roomID']); }, array_filter($this->getRoomAssociations($skipCache), function ($assoc) {
}, \array_filter($this->getRoomAssociations($skipCache), static function ($assoc) { return $assoc['active'] === 1;
return $assoc['active'] === 1; }));
})); }
}
/** /**
* Returns whether the user is in the given room. * Returns whether the user is in the given room.
*/ *
public function isInRoom(Room $room, $skipCache = false): bool * @param \chat\data\room\Room $room
{ * @return boolean
$assoc = $this->getRoomAssociations($skipCache); */
public function isInRoom(\chat\data\room\Room $room, $skipCache = false) {
$assoc = $this->getRoomAssociations($skipCache);
if (!isset($assoc[$room->roomID])) { if (!isset($assoc[$room->roomID])) return false;
return false; return $assoc[$room->roomID]['active'] === 1;
} }
return $assoc[$room->roomID]['active'] === 1; /**
} * Returns (userID, roomID, sessionID) triples where the client died.
*
* @return mixed[][]
*/
public static function getDeadSessions() {
$sql = "SELECT userID, roomID, sessionID
FROM chat".WCF_N."_session
WHERE lastRequest < ?";
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ TIME_NOW - 60 * 3 ]);
/** return $statement->fetchAll(\PDO::FETCH_ASSOC);
* Returns (userID, roomID, sessionID) triples where the client died. }
*
* @return mixed[][]
*/
public static function getDeadSessions()
{
$sql = "SELECT userID,
roomID,
sessionID
FROM chat1_session
WHERE lastRequest < ?";
$statement = WCF::getDB()->prepare($sql);
$statement->execute([
TIME_NOW - 60 * 3,
]);
return $statement->fetchAll(\PDO::FETCH_ASSOC); /**
} * @inheritDoc
*/
/** public function jsonSerialize() {
* @inheritDoc return [ 'userID' => $this->userID
*/ , 'username' => $this->username
public function jsonSerialize(): array , 'link' => $this->getLink()
{ ];
return [ }
'userID' => $this->userID,
'username' => $this->username,
'link' => $this->getLink(),
];
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,126 +14,105 @@
namespace chat\data\user; namespace chat\data\user;
use chat\data\room\Room; use \chat\data\room\RoomCache;
use chat\data\room\RoomAction; use \wcf\system\cache\runtime\UserProfileRuntimeCache;
use wcf\data\AbstractDatabaseObjectAction; use \wcf\system\cache\runtime\UserRuntimeCache;
use wcf\system\cache\runtime\UserProfileRuntimeCache; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\cache\runtime\UserRuntimeCache; use \wcf\system\exception\UserInputException;
use wcf\system\event\EventHandler; use \wcf\system\WCF;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException;
/** /**
* Executes chat user-related actions. * Executes chat user-related actions.
*/ */
class UserAction extends AbstractDatabaseObjectAction class UserAction extends \wcf\data\AbstractDatabaseObjectAction {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected $className = User::class;
protected $className = User::class;
/** /**
* Validates parameters and permissions. * Validates parameters and permissions.
*/ */
public function validateGetUsersByID() public function validateGetUsersByID() {
{ if (!\chat\data\room\Room::canSeeAny()) throw new PermissionDeniedException();
if (!Room::canSeeAny()) {
throw new PermissionDeniedException();
}
$this->readIntegerArray('userIDs'); $this->readIntegerArray('userIDs');
} }
/** /**
* Returns information about the users identified by the given userIDs. * Returns information about the users identified by the given userIDs.
*/ */
public function getUsersByID() public function getUsersByID() {
{ $userList = UserProfileRuntimeCache::getInstance()->getObjects($this->parameters['userIDs']);
$userList = UserProfileRuntimeCache::getInstance()->getObjects($this->parameters['userIDs']);
return \array_map(function ($user) { return array_map(function ($user) {
if (!$user) { if (!$user) return null;
return null;
}
$payload = [ $payload = [ 'image16' => $user->getAvatar()->getImageTag(16)
'image16' => $user->getAvatar()->getImageTag(16), , 'image24' => $user->getAvatar()->getImageTag(24)
'image24' => $user->getAvatar()->getImageTag(24), , 'image32' => $user->getAvatar()->getImageTag(32)
'image32' => $user->getAvatar()->getImageTag(32), , 'image48' => $user->getAvatar()->getImageTag(48)
'image48' => $user->getAvatar()->getImageTag(48), , 'imageUrl' => $user->getAvatar()->getURL()
'imageUrl' => $user->getAvatar()->getURL(), , 'link' => $user->getLink()
'link' => $user->getLink(), , 'anchor' => $user->getAnchorTag()
'anchor' => $user->getAnchorTag(), , 'userID' => $user->userID
'userID' => $user->userID, , 'username' => $user->username
'username' => $user->username, , 'userTitle' => $user->getUserTitle()
'userTitle' => $user->getUserTitle(), , 'userRankClass' => $user->getRank() ? $user->getRank()->cssClassName : null
'userRankClass' => $user->getRank() ? $user->getRank()->cssClassName : null, , 'formattedUsername' => $user->getFormattedUsername()
'formattedUsername' => $user->getFormattedUsername(), , 'away' => $user->chatAway
'away' => $user->chatAway, , 'color1' => $user->chatColor1
'color1' => $user->chatColor1, , 'color2' => $user->chatColor2
'color2' => $user->chatColor2, ];
];
EventHandler::getInstance()->fireAction($this, 'getUsersByID', $payload); \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'getUsersByID', $payload);
return $payload; return $payload;
}, $userList); }, $userList);
} }
/** /**
* Clears dead clients. * Clears dead clients.
*/ */
public function clearDeadSessions() public function clearDeadSessions() {
{ $sessions = User::getDeadSessions();
$sessions = User::getDeadSessions(); if (empty($sessions)) return;
if ($sessions === []) { $userIDs = array_map(function ($item) {
return; return $item['userID'];
} }, $sessions);
$userIDs = \array_map(static function ($item) { $users = UserRuntimeCache::getInstance()->getObjects($userIDs);
return $item['userID']; foreach ($sessions as $session) {
}, $sessions); $parameters = [ 'user' => $users[$session['userID']]
$users = UserRuntimeCache::getInstance()->getObjects($userIDs); , 'roomID' => $session['roomID']
foreach ($sessions as $session) { , 'sessionID' => $session['sessionID']
$parameters = [ ];
'user' => $users[$session['userID']], try {
'roomID' => $session['roomID'], (new \chat\data\room\RoomAction([ ], 'leave', $parameters))->executeAction();
'sessionID' => $session['sessionID'], }
]; catch (UserInputException $e) {
// Probably some other request has been faster to remove this session, ignore
}
}
}
try { /**
(new RoomAction( * @inheritDoc
[ ], */
'leave', public function create() {
$parameters throw new \BadMethodCallException();
))->executeAction(); }
} catch (UserInputException $e) {
// Probably some other request has been faster to remove this session, ignore
}
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function create() public function update() {
{ throw new \BadMethodCallException();
throw new \BadMethodCallException(); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function update() public function delete() {
{ throw new \BadMethodCallException();
throw new \BadMethodCallException(); }
}
/**
* @inheritDoc
*/
public function delete()
{
throw new \BadMethodCallException();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -18,10 +17,9 @@
/** /**
* Represents a list of chat users. * Represents a list of chat users.
*/ */
class UserList extends \wcf\data\user\UserList class UserList extends \wcf\data\user\UserList {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $decoratorClassName = User::class;
public $decoratorClassName = User::class;
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,187 +14,157 @@
namespace chat\page; namespace chat\page;
use chat\data\message\Message; use \chat\data\message\MessageList;
use chat\data\message\MessageList; use \wcf\system\exception\IllegalLinkException;
use chat\data\room\RoomCache; use \wcf\system\exception\PermissionDeniedException;
use wcf\data\object\type\ObjectTypeCache; use \wcf\system\page\PageLocationManager;
use wcf\page\AbstractPage; use \wcf\system\WCF;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\page\PageLocationManager;
use wcf\system\request\LinkHandler;
use wcf\system\WCF;
use wcf\util\HeaderUtil;
/** /**
* Shows the log of a specific chat room. * Shows the log of a specific chat room.
*/ */
final class LogPage extends AbstractPage class LogPage extends \wcf\page\AbstractPage {
{ use TConfiguredPage;
use TConfiguredPage;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $loginRequired = true; public $loginRequired = true;
/** /**
* The requested chat room ID. * The requested chat room ID.
* @var int * @var int
*/ */
public $roomID = 0; public $roomID = 0;
/** /**
* The requested chat room. * The requested chat room.
* @var \chat\data\room\Room * @var \chat\data\room\Room
*/ */
public $room; public $room = null;
/** /**
* The requested message ID. * The requested message ID.
* @var int * @var int
*/ */
public $messageID = 0; public $messageID = 0;
/** /**
* The requested message. * The requested message.
* @var \chat\data\message\Message * @var \chat\data\message\Message
*/ */
public $message; public $message = null;
/** /**
* The requested time. * The requested time.
* @var int * @var int
*/ */
public $datetime = 0; public $datetime = 0;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readParameters() public function readParameters() {
{ parent::readParameters();
parent::readParameters();
if (isset($_GET['id'])) { if (isset($_GET['id'])) $this->roomID = intval($_GET['id']);
$this->roomID = \intval($_GET['id']); $this->room = \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
}
$this->room = RoomCache::getInstance()->getRoom($this->roomID);
if ($this->room === null) { if ($this->room === null) throw new IllegalLinkException();
throw new IllegalLinkException(); if (!$this->room->canSee($user = null, $reason)) throw $reason;
} if (!$this->room->canSeeLog($user = null, $reason)) throw $reason;
if (!$this->room->canSee($user = null, $reason)) {
throw $reason;
}
if (!$this->room->canSeeLog($user = null, $reason)) {
throw $reason;
}
if (isset($_GET['messageid'])) { if (isset($_GET['messageid'])) $this->messageID = intval($_GET['messageid']);
$this->messageID = \intval($_GET['messageid']); if ($this->messageID) {
} $this->message = new \chat\data\message\Message($this->messageID);
if ($this->messageID) { if (!$this->message->getMessageType()->getProcessor()->canSeeInLog($this->message, $this->room)) {
$this->message = new Message($this->messageID); throw new PermissionDeniedException();
if (!$this->message->getMessageType()->getProcessor()->canSeeInLog($this->message, $this->room)) { }
throw new PermissionDeniedException(); }
}
}
if (isset($_REQUEST['datetime'])) { if (isset($_REQUEST['datetime'])) $this->datetime = strtotime($_REQUEST['datetime']);
$this->datetime = \strtotime($_REQUEST['datetime']); }
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ parent::readData();
parent::readData();
if ($this->datetime) { if ($this->datetime) {
// Determine message types supporting fast select // Determine message types supporting fast select
$objectTypes = ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType'); $objectTypes = \wcf\data\object\type\ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType');
$fastSelect = \array_map(static function ($item) { $fastSelect = array_map(function ($item) {
return $item->objectTypeID; return $item->objectTypeID;
}, \array_filter($objectTypes, static function ($item) { }, array_filter($objectTypes, function ($item) {
// TODO: Consider a method couldAppearInLog(): bool // TODO: Consider a method couldAppearInLog(): bool
return $item->getProcessor()->supportsFastSelect(); return $item->getProcessor()->supportsFastSelect();
})); }));
$minimum = 0; $minimum = 0;
$loops = 0; $loops = 0;
do { do {
// Build fast select filter // Build fast select filter
$condition = new PreparedStatementConditionBuilder(); $condition = new \wcf\system\database\util\PreparedStatementConditionBuilder();
$condition->add('((roomID = ? AND objectTypeID IN (?)) OR objectTypeID NOT IN (?))', [ $this->room->roomID, $fastSelect, $fastSelect ]); $condition->add('((roomID = ? AND objectTypeID IN (?)) OR objectTypeID NOT IN (?))', [ $this->room->roomID, $fastSelect, $fastSelect ]);
$condition->add('time >= ?', [ $this->datetime ]); $condition->add('time >= ?', [ $this->datetime ]);
if ($minimum) { if ($minimum) {
$condition->add('messageID > ?', [ $minimum ]); $condition->add('messageID > ?', [ $minimum ]);
} }
$sql = "SELECT messageID $sql = "SELECT messageID
FROM chat1_message FROM chat".WCF_N."_message
{$condition} ".$condition."
ORDER BY messageID ASC"; ORDER BY messageID ASC";
$statement = WCF::getDB()->prepare($sql, 20); $statement = WCF::getDB()->prepareStatement($sql, 20);
$statement->execute($condition->getParameters()); $statement->execute($condition->getParameters());
$messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN); $messageIDs = $statement->fetchAll(\PDO::FETCH_COLUMN);
$objectList = new MessageList(); $objectList = new MessageList();
$objectList->setObjectIDs($messageIDs); $objectList->setObjectIDs($messageIDs);
$objectList->readObjects(); $objectList->readObjects();
$objects = $objectList->getObjects(); $objects = $objectList->getObjects();
if (empty($objects)) { if (empty($objects)) {
// TODO: UserInputException? // TODO: UserInputException?
throw new IllegalLinkException(); throw new IllegalLinkException();
} }
foreach ($objects as $message) { foreach ($objects as $message) {
if ($message->getMessageType()->getProcessor()->canSeeInLog($message, $this->room)) { if ($message->getMessageType()->getProcessor()->canSeeInLog($message, $this->room)) {
$parameters = [ $parameters = [ 'application' => 'chat'
'messageid' => $message->messageID, , 'messageid' => $message->messageID
'object' => $this->room, , 'object' => $this->room
]; ];
HeaderUtil::redirect(LinkHandler::getInstance()->getControllerLink(self::class, $parameters)); \wcf\util\HeaderUtil::redirect(\wcf\system\request\LinkHandler::getInstance()->getLink('Log', $parameters));
exit;
}
$minimum = $message->messageID;
}
}
while (++$loops <= 3);
exit; // Do a best guess redirect to an ID that is as near as possible
} $parameters = [ 'application' => 'chat'
$minimum = $message->messageID; , 'messageid' => $minimum
} , 'object' => $this->room
} while (++$loops <= 3); ];
\wcf\util\HeaderUtil::redirect(\wcf\system\request\LinkHandler::getInstance()->getLink('Log', $parameters));
exit;
}
}
// Do a best guess redirect to an ID that is as near as possible /**
$parameters = [ * @inheritDoc
'application' => 'chat', */
'messageid' => $minimum, public function assignVariables() {
'object' => $this->room, parent::assignVariables();
];
HeaderUtil::redirect(LinkHandler::getInstance()->getControllerLink(self::class, $parameters));
exit; PageLocationManager::getInstance()->addParentLocation('be.bastelstu.chat.Room', $this->room->roomID, $this->room);
} WCF::getTPL()->assign([ 'room' => $this->room
} , 'roomList' => \chat\data\room\RoomCache::getInstance()->getRooms()
, 'messageID' => $this->messageID
/** , 'message' => $this->message
* @inheritDoc , 'config' => $this->getConfig()
*/ ]);
public function assignVariables() }
{
parent::assignVariables();
PageLocationManager::getInstance()->addParentLocation(
'be.bastelstu.chat.Room',
$this->room->roomID,
$this->room
);
WCF::getTPL()->assign([
'room' => $this->room,
'roomList' => RoomCache::getInstance()->getRooms(),
'messageID' => $this->messageID,
'message' => $this->message,
'config' => $this->getConfig(),
]);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,60 +14,48 @@
namespace chat\page; namespace chat\page;
use chat\data\room\Room; use \wcf\system\WCF;
use chat\data\room\RoomCache;
use wcf\page\AbstractPage;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\WCF;
/** /**
* Shows the list of available chat rooms. * Shows the list of available chat rooms.
*/ */
final class RoomListPage extends AbstractPage class RoomListPage extends \wcf\page\AbstractPage {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public $loginRequired = true;
public $loginRequired = true;
/** /**
* List of rooms. * List of rooms.
* *
* @var \chat\data\room\Room[] * @var \chat\data\room\Room[]
*/ */
public $rooms = [ ]; public $rooms = [ ];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function checkPermissions() public function checkPermissions() {
{ parent::checkPermissions();
parent::checkPermissions();
if (!Room::canSeeAny()) { if (!\chat\data\room\Room::canSeeAny()) throw new \wcf\system\exception\PermissionDeniedException();
throw new PermissionDeniedException(); }
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ parent::readData();
parent::readData();
$this->rooms = RoomCache::getInstance()->getRooms(); $this->rooms = \chat\data\room\RoomCache::getInstance()->getRooms();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'rooms' => $this->rooms ]);
'rooms' => $this->rooms, }
]);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,131 +14,107 @@
namespace chat\page; namespace chat\page;
use chat\data\room\RoomCache; use \wcf\system\exception\IllegalLinkException;
use wcf\data\package\PackageCache; use \wcf\system\exception\NamedUserException;
use wcf\page\AbstractPage; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\attachment\AttachmentHandler; use \wcf\system\WCF;
use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\NamedUserException;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\push\PushHandler;
use wcf\system\WCF;
/** /**
* Shows a specific chat room. * Shows a specific chat room.
*/ */
final class RoomPage extends AbstractPage class RoomPage extends \wcf\page\AbstractPage {
{ use TConfiguredPage;
use TConfiguredPage;
/** /**
* Almost dummy attachment handler (used in language variable) * Almost dummy attachment handler (used in language variable)
* *
* @var \wcf\system\attachment\AttachmentHandler * @var \wcf\system\attachment\AttachmentHandler
*/ */
public $attachmentHandler; public $attachmentHandler;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public $loginRequired = true; public $loginRequired = true;
/** /**
* The requested chat room ID. * The requested chat room ID.
* *
* @var int * @param int
*/ */
public $roomID = 0; public $roomID = 0;
/** /**
* The requested chat room. * The requested chat room.
* *
* @var \chat\data\room\Room * @param \chat\data\room\Room
*/ */
public $room; public $room = null;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readParameters() public function readParameters() {
{ parent::readParameters();
parent::readParameters();
if (isset($_GET['id'])) { if (isset($_GET['id'])) $this->roomID = intval($_GET['id']);
$this->roomID = \intval($_GET['id']); $this->room = \chat\data\room\RoomCache::getInstance()->getRoom($this->roomID);
}
$this->room = RoomCache::getInstance()->getRoom($this->roomID);
if ($this->room === null) { if ($this->room === null) throw new IllegalLinkException();
throw new IllegalLinkException(); if (!$this->room->canSee($user = null, $reason)) throw $reason;
} if (!$this->room->canJoin($user = null, $reason)) throw $reason;
if (!$this->room->canSee($user = null, $reason)) {
throw $reason;
}
if (!$this->room->canJoin($user = null, $reason)) {
throw $reason;
}
$this->canonicalURL = $this->room->getLink(); $this->canonicalURL = $this->room->getLink();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function checkPermissions() public function checkPermissions() {
{ parent::checkPermissions();
parent::checkPermissions();
$package = PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat'); $package = \wcf\data\package\PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat');
if (\stripos($package->packageVersion, 'Alpha') !== false) { if (stripos($package->packageVersion, 'Alpha') !== false) {
$sql = "SELECT COUNT(*) FROM wcf1_user"; $sql = "SELECT COUNT(*) FROM wcf".WCF_N."_user";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute(); $statement->execute();
$userCount = $statement->fetchSingleColumn(); $userCount = $statement->fetchSingleColumn();
if ((($userCount > 5 && !OFFLINE) || ($userCount > 30 && OFFLINE)) && \sha1(WCF_UUID) !== '643a6b3af2a6ea3d393c4d8371e75d7d1b66e0d0') { if ((($userCount > 5 && !OFFLINE) || ($userCount > 30 && OFFLINE)) && sha1(WCF_UUID) !== '643a6b3af2a6ea3d393c4d8371e75d7d1b66e0d0') {
throw new PermissionDeniedException("Do not use alpha versions of Tims Chat in production communities!"); throw new PermissionDeniedException("Do not use alpha versions of Tims Chat in production communities!");
} }
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function readData() public function readData() {
{ $sql = "SELECT 1";
$sql = "SELECT 1"; $statement = WCF::getDB()->prepareStatement($sql);
$statement = WCF::getDB()->prepare($sql); $statement->execute();
$statement->execute(); if ($statement->fetchSingleColumn() !== 1) {
if ($statement->fetchSingleColumn() !== 1) { throw new NamedUserException('PHP must be configured to use the MySQLnd driver, instead of libmysqlclient.');
throw new NamedUserException('PHP must be configured to use the MySQLnd driver, instead of libmysqlclient.'); }
}
parent::readData(); parent::readData();
// This attachment handler gets only used for the language variable `wcf.attachment.upload.limits`! // This attachment handler gets only used for the language variable `wcf.attachment.upload.limits`!
$this->attachmentHandler = new AttachmentHandler( $this->attachmentHandler = new \wcf\system\attachment\AttachmentHandler('be.bastelstu.chat.message', 0, 'DEADC0DE00000000DEADC0DE00000000DEADC0DE', $this->room->roomID);
'be.bastelstu.chat.message',
0,
'DEADC0DE00000000DEADC0DE00000000DEADC0DE',
$this->room->roomID
);
$pushHandler = PushHandler::getInstance(); $pushHandler = \wcf\system\push\PushHandler::getInstance();
$pushHandler->joinChannel('be.bastelstu.chat'); $pushHandler->joinChannel('be.bastelstu.chat');
$pushHandler->joinChannel('be.bastelstu.chat.room-' . $this->room->roomID); $pushHandler->joinChannel('be.bastelstu.chat.room-'.$this->room->roomID);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function assignVariables() public function assignVariables() {
{ parent::assignVariables();
parent::assignVariables();
WCF::getTPL()->assign([ WCF::getTPL()->assign([ 'room' => $this->room
'room' => $this->room, , 'config' => $this->getConfig()
'config' => $this->getConfig(), , 'attachmentHandler' => $this->attachmentHandler
'attachmentHandler' => $this->attachmentHandler, ]);
]); }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,55 +14,47 @@
namespace chat\page; namespace chat\page;
use chat\data\command\Command; use \chat\data\command\Command;
use chat\data\command\CommandCache; use \chat\data\command\CommandCache;
use wcf\data\object\type\ObjectTypeCache; use \wcf\data\object\type\ObjectTypeCache;
use wcf\data\package\PackageCache; use \wcf\data\package\PackageCache;
use wcf\system\event\EventHandler;
use wcf\util\JSON;
/** /**
* Provides a getConfig() method, returning the JSON configuration * Provides a getConfig() method, returning the JSON configuration
* for the chat's JavaSCript. * for the chat's JavaSCript.
*/ */
trait TConfiguredPage trait TConfiguredPage {
{ /**
/** * Returns the configuration for the chat's JavaScript.
* Returns the configuration for the chat's JavaScript. */
*/ public function getConfig() {
public function getConfig() $triggers = CommandCache::getInstance()->getTriggers();
{
$triggers = CommandCache::getInstance()->getTriggers();
$commands = \array_map(function (Command $item) { $commands = array_map(function (Command $item) {
$package = PackageCache::getInstance()->getPackage($item->packageID)->package; $package = PackageCache::getInstance()->getPackage($item->packageID)->package;
return [ 'package' => $package
, 'identifier' => $item->identifier
, 'commandID' => $item->commandID
, 'module' => $item->getProcessor()->getJavaScriptModuleName()
, 'isAvailable' => $item->getProcessor()->isAvailable($this->room) && ($item->hasTriggers() || $item->getProcessor()->allowWithoutTrigger())
];
}, CommandCache::getInstance()->getCommands());
return [ $messageTypes = array_map(function ($item) {
'package' => $package, return [ 'module' => $item->getProcessor()->getJavaScriptModuleName()
'identifier' => $item->identifier, ];
'commandID' => $item->commandID, }, ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType'));
'module' => $item->getProcessor()->getJavaScriptModuleName(),
'isAvailable' => $item->getProcessor()->isAvailable($this->room) && ($item->hasTriggers() || $item->getProcessor()->allowWithoutTrigger()),
];
}, CommandCache::getInstance()->getCommands());
$messageTypes = \array_map(static function ($item) { $config = [ 'clientVersion' => 1
return [ , 'reloadTime' => (int) CHAT_RELOADTIME
'module' => $item->getProcessor()->getJavaScriptModuleName(), , 'autoAwayTime' => (int) CHAT_AUTOAWAYTIME
]; , 'commands' => $commands
}, ObjectTypeCache::getInstance()->getObjectTypes('be.bastelstu.chat.messageType')); , 'triggers' => $triggers
, 'messageTypes' => $messageTypes
];
$config = [ \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'config', $config);
'clientVersion' => 1,
'reloadTime' => (int)CHAT_RELOADTIME,
'autoAwayTime' => (int)CHAT_AUTOAWAYTIME,
'commands' => $commands,
'triggers' => $triggers,
'messageTypes' => $messageTypes,
];
EventHandler::getInstance()->fireAction($this, 'config', $config); return \wcf\util\JSON::encode($config);
}
return JSON::encode($config);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,33 +14,25 @@
namespace chat\system; namespace chat\system;
use chat\page\RoomListPage; class CHATCore extends \wcf\system\application\AbstractApplication {
use wcf\system\application\AbstractApplication; /**
use wcf\system\request\route\StaticRequestRoute; * @inheritDoc
use wcf\system\request\RouteHandler; */
protected $primaryController = \chat\page\RoomListPage::class;
final class CHATCore extends AbstractApplication /**
{ * @inheritDoc
/** */
* @inheritDoc public function __run() {
*/ $route = new \wcf\system\request\route\StaticRequestRoute();
protected $primaryController = RoomListPage::class; $route->setStaticController('chat', 'Log');
$route->setBuildSchema('/{controller}/{id}-{title}/{messageid}');
$route->setPattern('~^/?(?P<controller>[^/]+)/(?P<id>\d+)(?:-(?P<title>[^/]+))?/(?P<messageid>\d+)~x');
$route->setRequiredComponents([ 'id' => '~^\d+$~'
, 'messageid' => '~^\d+$~'
]);
$route->setMatchController(true);
/** \wcf\system\request\RouteHandler::getInstance()->addRoute($route);
* @inheritDoc }
*/
public function __run()
{
$route = new StaticRequestRoute();
$route->setStaticController('chat', 'Log');
$route->setBuildSchema('/{controller}/{id}-{title}/{messageid}');
$route->setPattern('~^/?(?P<controller>[^/]+)/(?P<id>\d+)(?:-(?P<title>[^/]+))?/(?P<messageid>\d+)~x');
$route->setRequiredComponents([
'id' => '~^\d+$~',
'messageid' => '~^\d+$~',
]);
$route->setMatchController(true);
RouteHandler::getInstance()->addRoute($route);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,110 +14,95 @@
namespace chat\system\attachment; namespace chat\system\attachment;
use chat\data\message\Message; use \chat\data\message\Message;
use chat\data\message\MessageList; use \chat\data\message\MessageList;
use chat\data\room\RoomCache; use \chat\data\room\RoomCache;
use wcf\system\attachment\AbstractAttachmentObjectType; use \wcf\system\WCF;
use wcf\system\WCF;
use wcf\util\ArrayUtil;
/** /**
* Attachment object type implementation for messages. * Attachment object type implementation for messages.
*/ */
final class MessageAttachmentObjectType extends AbstractAttachmentObjectType class MessageAttachmentObjectType extends \wcf\system\attachment\AbstractAttachmentObjectType {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function canDownload($objectID) {
public function canDownload($objectID): bool if ($objectID) {
{ $message = new Message($objectID);
if ($objectID) {
$message = new Message($objectID);
if (!$message->messageID) { if ($message->getMessageType()->objectType !== 'be.bastelstu.chat.messageType.attachment') {
return false; throw new \LogicException('Unreachable');
} }
$room = $message->getRoom();
\assert($message->getMessageType()->objectType === 'be.bastelstu.chat.messageType.attachment'); return $room->canSee();
$room = $message->getRoom(); }
return $room->canSee(); return false;
} }
return false; /**
} * @inheritDoc
*/
public function canUpload($objectID, $parentObjectID = 0) {
if ($objectID) {
return false;
}
/** if (!WCF::getSession()->getPermission('user.chat.canAttach')) {
* @inheritDoc return false;
*/ }
public function canUpload($objectID, $parentObjectID = 0): bool
{
if ($objectID) {
return false;
}
if (!WCF::getSession()->getPermission('user.chat.canAttach')) { $room = null;
return false; if ($parentObjectID) {
} $room = RoomCache::getInstance()->getRoom($parentObjectID);
}
$room = null; if ($room !== null) {
if ($parentObjectID) { return $room->canSee();
$room = RoomCache::getInstance()->getRoom($parentObjectID); }
}
if ($room !== null) { return false;
return $room->canSee(); }
}
return false; /**
} * @inheritDoc
*/
public function canDelete($objectID) {
return false;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function canDelete($objectID): bool public function getMaxCount() {
{ return 1;
return false; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getMaxCount(): int public function getMaxSize() {
{ return WCF::getSession()->getPermission('user.chat.attachment.maxSize');
return 1; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getMaxSize(): int public function getAllowedExtensions() {
{ return \wcf\util\ArrayUtil::trim(\explode("\n", WCF::getSession()->getPermission('user.chat.attachment.allowedExtensions')));
return (int)WCF::getSession()->getPermission('user.chat.attachment.maxSize'); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getAllowedExtensions() public function cacheObjects(array $objectIDs) {
{ $messageList = new MessageList();
return ArrayUtil::trim(\explode( $messageList->setObjectIDs($objectIDs);
"\n", $messageList->readObjects();
WCF::getSession()->getPermission('user.chat.attachment.allowedExtensions')
));
}
/** foreach ($messageList->getObjects() as $objectID => $object) {
* @inheritDoc $this->cachedObjects[$objectID] = $object;
*/ }
public function cacheObjects(array $objectIDs) }
{
$messageList = new MessageList();
$messageList->setObjectIDs($objectIDs);
$messageList->readObjects();
foreach ($messageList->getObjects() as $objectID => $object) {
$this->cachedObjects[$objectID] = $object;
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,129 +14,107 @@
namespace chat\system\box; namespace chat\system\box;
use chat\data\room\Room; use \wcf\system\request\RequestHandler;
use chat\data\room\RoomList; use \wcf\system\WCF;
use chat\page\RoomListPage;
use chat\page\RoomPage;
use wcf\system\box\AbstractDatabaseObjectListBoxController;
use wcf\system\request\LinkHandler;
use wcf\system\request\RequestHandler;
use wcf\system\WCF;
/** /**
* Dynamic box controller implementation for a list of rooms. * Dynamic box controller implementation for a list of rooms.
*/ */
final class RoomListBoxController extends AbstractDatabaseObjectListBoxController class RoomListBoxController extends \wcf\system\box\AbstractDatabaseObjectListBoxController {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected static $supportedPositions = [ 'contentBottom', 'contentTop', 'sidebarLeft', 'sidebarRight' ];
protected static $supportedPositions = [
'contentBottom',
'contentTop',
'sidebarLeft',
'sidebarRight',
];
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $conditionDefinition = 'be.bastelstu.chat.box.roomList.condition'; protected $conditionDefinition = 'be.bastelstu.chat.box.roomList.condition';
/** /**
* @var int * @var int
*/ */
protected $activeRoomID; protected $activeRoomID = null;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function __construct() public function __construct() {
{ parent::__construct();
parent::__construct();
$activeRequest = RequestHandler::getInstance()->getActiveRequest(); $activeRequest = RequestHandler::getInstance()->getActiveRequest();
if ($activeRequest && $activeRequest->getRequestObject() instanceof RoomPage) { if ($activeRequest && $activeRequest->getRequestObject() instanceof \chat\page\RoomPage) {
$this->activeRoomID = $activeRequest->getRequestObject()->room->roomID; $this->activeRoomID = $activeRequest->getRequestObject()->room->roomID;
} }
} }
/** /**
* Sets the active room ID. * Sets the active room ID.
*/ */
public function setActiveRoomID($activeRoomID) public function setActiveRoomID($activeRoomID) {
{ $this->activeRoomID = $activeRoomID;
$this->activeRoomID = $activeRoomID; }
}
/** /**
* Returns the active room ID. * Returns the active room ID.
* *
* @return int * @return int
*/ */
public function getActiveRoomID() public function getActiveRoomID() {
{ return $this->activeRoomID;
return $this->activeRoomID; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function hasLink() public function hasLink() {
{ return true;
return true; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getLink(): string public function getLink() {
{ return \wcf\system\request\LinkHandler::getInstance()->getLink('RoomList', [ 'application' => 'chat' ]);
return LinkHandler::getInstance()->getControllerLink(RoomListPage::class); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function getObjectList() protected function getObjectList() {
{ return new \chat\data\room\RoomList();
return new RoomList(); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected function getTemplate() protected function getTemplate() {
{ $templateName = 'boxRoomList';
$templateName = 'boxRoomList'; if ($this->box->position === 'sidebarLeft' || $this->box->position === 'sidebarRight') {
if ($this->box->position === 'sidebarLeft' || $this->box->position === 'sidebarRight') { $templateName = 'boxRoomListSidebar';
$templateName = 'boxRoomListSidebar'; }
}
return WCF::getTPL()->fetch($templateName, 'chat', [ return WCF::getTPL()->fetch($templateName, 'chat', [ 'boxRoomList' => $this->objectList
'boxRoomList' => $this->objectList, , 'boxID' => $this->getBox()->boxID
'boxID' => $this->getBox()->boxID, , 'activeRoomID' => $this->activeRoomID ?: 0
'activeRoomID' => $this->activeRoomID ?: 0, ], true);
], true); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function hasContent() public function hasContent() {
{ if ($this->box->position === 'sidebarLeft' || $this->box->position === 'sidebarRight') {
if ($this->box->position === 'sidebarLeft' || $this->box->position === 'sidebarRight') { parent::hasContent();
parent::hasContent();
foreach ($this->objectList as $room) { foreach ($this->objectList as $room) {
if ($room->canSee()) { if ($room->canSee()) return true;
return true; }
}
}
return false; return false;
} else { }
return Room::canSeeAny(); else {
} return \chat\data\room\Room::canSeeAny();
} }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,46 +14,39 @@
namespace chat\system\cache\builder; namespace chat\system\cache\builder;
use chat\data\command\CommandList; use \wcf\system\WCF;
use wcf\system\cache\builder\AbstractCacheBuilder;
use wcf\system\WCF;
/** /**
* Caches all chat commands. * Caches all chat commands.
*/ */
final class CommandCacheBuilder extends AbstractCacheBuilder class CommandCacheBuilder extends \wcf\system\cache\builder\AbstractCacheBuilder {
{ /**
/** * @see \wcf\system\cache\AbstractCacheBuilder::rebuild()
* @inheritDoc */
*/ public function rebuild(array $parameters) {
public function rebuild(array $parameters) $data = [ 'commands' => [ ]
{ , 'triggers' => [ ]
$data = [ , 'packages' => [ ]
'commands' => [ ], ];
'triggers' => [ ],
'packages' => [ ],
];
$commandList = new CommandList(); $commandList = new \chat\data\command\CommandList();
$commandList->sqlOrderBy = 'command.commandID'; $commandList->sqlOrderBy = 'command.commandID';
$commandList->readObjects(); $commandList->readObjects();
$data['commands'] = $commandList->getObjects(); $data['commands'] = $commandList->getObjects();
foreach ($data['commands'] as $command) { foreach ($data['commands'] as $command) {
if (!isset($data['packages'][$command->packageID])) { if (!isset($data['packages'][$command->packageID])) $data['packages'][$command->packageID] = [ ];
$data['packages'][$command->packageID] = [ ]; $data['packages'][$command->packageID][$command->identifier] = $command;
} }
$data['packages'][$command->packageID][$command->identifier] = $command;
}
$sql = "SELECT * $sql = "SELECT *
FROM chat1_command_trigger"; FROM chat".WCF_N."_command_trigger";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute(); $statement->execute();
$data['triggers'] = $statement->fetchMap('commandTrigger', 'commandID'); $data['triggers'] = $statement->fetchMap('commandTrigger', 'commandID');
return $data; return $data;
} }
} }

View File

@ -1,8 +1,7 @@
<?php <?php
/** /**
* Copyright (C) 2010-2024 Tim Düsterhus * Copyright (C) 2010-2021 Tim Düsterhus
* Copyright (C) 2010-2024 Woltlab GmbH * Copyright (C) 2010-2021 Woltlab GmbH
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -21,45 +20,42 @@
namespace chat\system\cache\builder; namespace chat\system\cache\builder;
use wcf\system\acl\ACLHandler; use \wcf\system\acl\ACLHandler;
use wcf\system\cache\builder\AbstractCacheBuilder; use \wcf\system\WCF;
use wcf\system\database\util\PreparedStatementConditionBuilder;
use wcf\system\WCF;
/** /**
* Caches the chat permissions for a combination of user groups. * Caches the chat permissions for a combination of user groups.
*/ */
final class PermissionCacheBuilder extends AbstractCacheBuilder class PermissionCacheBuilder extends \wcf\system\cache\builder\AbstractCacheBuilder {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function rebuild(array $parameters) {
public function rebuild(array $parameters) $data = [ ];
{
$data = [ ];
if (!empty($parameters)) { if (!empty($parameters)) {
$conditionBuilder = new PreparedStatementConditionBuilder(); $conditionBuilder = new \wcf\system\database\util\PreparedStatementConditionBuilder();
$conditionBuilder->add('acl_option.objectTypeID = ?', [ ACLHandler::getInstance()->getObjectTypeID('be.bastelstu.chat.room') ]); $conditionBuilder->add('acl_option.objectTypeID = ?', [ ACLHandler::getInstance()->getObjectTypeID('be.bastelstu.chat.room') ]);
$conditionBuilder->add('option_to_group.groupID IN (?)', [ $parameters ]); $conditionBuilder->add('option_to_group.groupID IN (?)', [ $parameters ]);
$sql = "SELECT option_to_group.objectID AS roomID, $sql = "SELECT option_to_group.objectID AS roomID,
option_to_group.optionValue, option_to_group.optionValue,
acl_option.optionName AS permission acl_option.optionName AS permission
FROM wcf1_acl_option acl_option FROM wcf".WCF_N."_acl_option acl_option
INNER JOIN wcf1_acl_option_to_group option_to_group INNER JOIN wcf".WCF_N."_acl_option_to_group option_to_group
ON option_to_group.optionID = acl_option.optionID ON option_to_group.optionID = acl_option.optionID
{$conditionBuilder}"; ".$conditionBuilder;
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute($conditionBuilder->getParameters()); $statement->execute($conditionBuilder->getParameters());
while (($row = $statement->fetchArray())) { while (($row = $statement->fetchArray())) {
if (!isset($data[$row['roomID']][$row['permission']])) { if (!isset($data[$row['roomID']][$row['permission']])) {
$data[$row['roomID']][$row['permission']] = $row['optionValue']; $data[$row['roomID']][$row['permission']] = $row['optionValue'];
} else { }
$data[$row['roomID']][$row['permission']] = $row['optionValue'] || $data[$row['roomID']][$row['permission']]; else {
} $data[$row['roomID']][$row['permission']] = $row['optionValue'] || $data[$row['roomID']][$row['permission']];
} }
} }
}
return $data; return $data;
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,23 +14,18 @@
namespace chat\system\cache\builder; namespace chat\system\cache\builder;
use chat\data\room\RoomList;
use wcf\system\cache\builder\AbstractCacheBuilder;
/** /**
* Caches all chat rooms. * Caches all chat rooms.
*/ */
final class RoomCacheBuilder extends AbstractCacheBuilder class RoomCacheBuilder extends \wcf\system\cache\builder\AbstractCacheBuilder {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function rebuild(array $parameters) {
public function rebuild(array $parameters) $roomList = new \chat\data\room\RoomList();
{ $roomList->sqlOrderBy = "room.position";
$roomList = new RoomList(); $roomList->readObjects();
$roomList->sqlOrderBy = "room.position";
$roomList->readObjects();
return $roomList->getObjects(); return $roomList->getObjects();
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,16 +14,12 @@
namespace chat\system\cache\runtime; namespace chat\system\cache\runtime;
use chat\data\user\UserList as ChatUserList;
use wcf\system\cache\runtime\AbstractRuntimeCache;
/** /**
* Runtime cache implementation for chat users. * Runtime cache implementation for chat users.
*/ */
class UserRuntimeCache extends AbstractRuntimeCache class UserRuntimeCache extends \wcf\system\cache\runtime\AbstractRuntimeCache {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected $listClassName = \chat\data\user\UserList::class;
protected $listClassName = ChatUserList::class;
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,76 +14,64 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\command\Command; use \chat\data\room\Room;
use chat\data\room\Room; use \wcf\data\object\type\ObjectTypeCache;
use wcf\data\DatabaseObjectDecorator; use \wcf\data\user\UserProfile;
use wcf\data\IDatabaseObjectProcessor; use \wcf\system\exception\UserInputException;
use wcf\data\object\type\ObjectTypeCache;
use wcf\data\user\UserProfile;
use wcf\system\exception\UserInputException;
/** /**
* Default implemention for command processors. * Default implemention for command processors.
*/ */
abstract class AbstractCommand extends DatabaseObjectDecorator implements abstract class AbstractCommand extends \wcf\data\DatabaseObjectDecorator implements ICommand
ICommand, , \wcf\data\IDatabaseObjectProcessor {
IDatabaseObjectProcessor /**
{ * @inheritDoc
/** */
* @inheritDoc protected static $baseClass = \chat\data\command\Command::class;
*/
protected static $baseClass = Command::class;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ return true;
return true; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function allowWithoutTrigger() public function allowWithoutTrigger() {
{ return false;
return false; }
}
/** /**
* Returns the object type ID for the given message type. * Returns the object type ID for the given message type.
* *
* @param string * @param string
* @return int * @return int
*/ */
public function getMessageObjectTypeID($objectType) public function getMessageObjectTypeID($objectType) {
{ $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.messageType', $objectType);
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName(
'be.bastelstu.chat.messageType',
$objectType
);
if (!$objectType) { if (!$objectType) {
throw new \LogicException('Missing object type'); throw new \LogicException('Missing object type');
} }
return $objectTypeID; return $objectTypeID;
} }
/** /**
* Ensures that the given parameter exists in the parameter array and * Ensures that the given parameter exists in the parameter array and
* throws otherwise. * throws otherwise.
* *
* @param array $parameters * @param array $parameters
* @param string $key * @param string $key
* @return mixed The value. * @return mixed The value.
*/ */
public function assertParameter($parameters, $key) public function assertParameter($parameters, $key) {
{ if (array_key_exists($key, $parameters)) {
if (\array_key_exists($key, $parameters)) { return $parameters[$key];
return $parameters[$key]; }
}
throw new UserInputException('message'); throw new UserInputException('message');
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,114 +14,71 @@
namespace chat\system\command; namespace chat\system\command;
use wcf\data\DatabaseObject; use \wcf\system\exception\UserInputException;
use wcf\system\bbcode\BBCodeHandler; use \wcf\system\bbcode\BBCodeHandler;
use wcf\system\exception\UserInputException; use \wcf\system\message\censorship\Censorship;
use wcf\system\html\input\HtmlInputProcessor; use \wcf\system\WCF;
use wcf\system\message\censorship\Censorship;
use wcf\system\WCF;
/** /**
* Represents a command that processes the input using HtmlInputProcessor. * Represents a command that processes the input using HtmlInputProcessor.
*/ */
abstract class AbstractInputProcessedCommand extends AbstractCommand abstract class AbstractInputProcessedCommand extends AbstractCommand {
{ /**
/** * HtmlInputProcessor to use.
* HtmlInputProcessor to use. * @var \wcf\system\html\input\HtmlInputProcessor
* @var \wcf\system\html\input\HtmlInputProcessor */
*/ protected $processor = null;
protected $processor;
/** /**
* The text processed last. * The text processed last.
* @var string * @var string
*/ */
private $text; private $text = null;
public function __construct(DatabaseObject $object) public function __construct(\wcf\data\DatabaseObject $object) {
{ parent::__construct($object);
parent::__construct($object);
$this->processor = new HtmlInputProcessor(); $this->processor = new \wcf\system\html\input\HtmlInputProcessor();
$this->setDisallowedBBCodes(); $this->setDisallowedBBCodes();
} }
private function setDisallowedBBCodes() private function setDisallowedBBCodes() {
{ BBCodeHandler::getInstance()->setDisallowedBBCodes(explode(',', WCF::getSession()->getPermission('user.chat.disallowedBBCodes')));
BBCodeHandler::getInstance()->setDisallowedBBCodes(\explode( }
',',
WCF::getSession()->getPermission('user.chat.disallowedBBCodes')
));
}
public function setText($text) public function setText($text) {
{ if ($this->text === $text) return;
if ($this->text === $text) {
return;
}
$this->text = $text; $this->text = $text;
$this->setDisallowedBBCodes(); $this->setDisallowedBBCodes();
$this->processor->process( $this->processor->process($text, 'be.bastelstu.chat.message', 0);
$text, }
'be.bastelstu.chat.message',
0
);
}
public function validateText() public function validateText() {
{ if ($this->processor->appearsToBeEmpty()) {
if ($this->processor->appearsToBeEmpty()) { throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.global.form.error.empty'));
throw new UserInputException( }
'message',
WCF::getLanguage()->getDynamicVariable('wcf.global.form.error.empty')
);
}
$message = $this->processor->getTextContent(); $message = $this->processor->getTextContent();
// validate message length // validate message length
if (\mb_strlen($message) > CHAT_MAX_LENGTH) { if (mb_strlen($message) > CHAT_MAX_LENGTH) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', [ 'maxTextLength' => CHAT_MAX_LENGTH ]));
'message', }
WCF::getLanguage()->getDynamicVariable(
'wcf.message.error.tooLong',
[
'maxTextLength' => CHAT_MAX_LENGTH,
]
)
);
}
// search for disallowed bbcodes // search for disallowed bbcodes
$this->setDisallowedBBCodes(); $this->setDisallowedBBCodes();
$disallowedBBCodes = $this->processor->validate(); $disallowedBBCodes = $this->processor->validate();
if (!empty($disallowedBBCodes)) { if (!empty($disallowedBBCodes)) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.disallowedBBCodes', [ 'disallowedBBCodes' => $disallowedBBCodes ]));
'message', }
WCF::getLanguage()->getDynamicVariable(
'wcf.message.error.disallowedBBCodes',
[
'disallowedBBCodes' => $disallowedBBCodes,
]
)
);
}
// search for censored words // search for censored words
if (ENABLE_CENSORSHIP) { if (ENABLE_CENSORSHIP) {
$result = Censorship::getInstance()->test($message); $result = Censorship::getInstance()->test($message);
if ($result) { if ($result) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', [ 'censoredWords' => $result ]));
'message', }
WCF::getLanguage()->getDynamicVariable( }
'wcf.message.error.censoredWordsFound', }
[
'censoredWords' => $result,
]
)
);
}
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,192 +14,157 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\suspension\Suspension; use \chat\data\suspension\Suspension;
use chat\data\suspension\SuspensionAction; use \chat\data\suspension\SuspensionAction;
use chat\data\user\User as ChatUser; use \wcf\data\object\type\ObjectTypeCache;
use wcf\data\object\type\ObjectTypeCache; use \wcf\data\user\UserProfile;
use wcf\data\user\UserProfile; use \wcf\system\exception\UserInputException;
use wcf\system\exception\UserInputException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* Represents a command that creates suspensions * Represents a command that creates suspensions
*/ */
abstract class AbstractSuspensionCommand extends AbstractCommand abstract class AbstractSuspensionCommand extends AbstractCommand {
{ use TNeedsUser;
use TNeedsUser;
/** /**
* Returns the name of the object type for this suspension. * Returns the name of the object type for this suspension.
* *
* @return string * @return string
*/ */
abstract public function getObjectTypeName(); abstract public function getObjectTypeName();
/** /**
* Checks the permissions to execute this command. * Checks the permissions to execute this command.
* Throws if necessary. * Throws if necessary.
* *
* @see \chat\system\command\ICommand::validate() * @see \chat\system\command\ICommand::validate()
*/ */
abstract protected function checkPermissions($parameters, Room $room, UserProfile $user); abstract protected function checkPermissions($parameters, Room $room, UserProfile $user);
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$this->assertParameter($parameters, 'username'); $this->assertParameter($parameters, 'username');
$this->assertParameter($parameters, 'globally'); $this->assertParameter($parameters, 'globally');
$this->assertParameter($parameters, 'duration'); $this->assertParameter($parameters, 'duration');
$this->assertParameter($parameters, 'reason'); $this->assertParameter($parameters, 'reason');
$this->assertUser($parameters['username']); $this->assertUser($parameters['username']);
if ($parameters['duration'] !== null && $parameters['duration'] < TIME_NOW) { if ($parameters['duration'] !== null && $parameters['duration'] < TIME_NOW) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.datePast'));
'message', }
WCF::getLanguage()->getDynamicVariable('chat.error.datePast') if (!empty($parameters['reason']) && mb_strlen($parameters['reason']) > 100) {
); throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', [ 'maxTextLength' => 250 ]));
} }
if (!empty($parameters['reason']) && \mb_strlen($parameters['reason']) > 100) { $this->checkPermissions($parameters, $room, $user);
throw new UserInputException(
'message',
WCF::getLanguage()->getDynamicVariable(
'wcf.message.error.tooLong',
[
'maxTextLength' => 250,
]
)
);
}
$this->checkPermissions($parameters, $room, $user);
$test = new Suspension(null, $this->getSuspensionData($parameters, $room, $user)); $test = new Suspension(null, $this->getSuspensionData($parameters, $room, $user));
if (!$test->isActive()) { if (!$test->isActive()) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.suspension.noEffect'));
'message', }
WCF::getLanguage()->getDynamicVariable('chat.error.suspension.noEffect') }
);
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$data = $this->getSuspensionData($parameters, $room, $user); $data = $this->getSuspensionData($parameters, $room, $user);
$test = new Suspension(null, $data); $test = new Suspension(null, $data);
if (!$test->isActive()) { if (!$test->isActive()) {
return; return;
} }
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$suspension = (new SuspensionAction( $suspension = (new SuspensionAction([ ], 'create', [ 'data' => $data ]))->executeAction()['returnValues'];
[ ],
'create',
[
'data' => $data,
]
))->executeAction()['returnValues'];
$this->afterCreate($suspension, $parameters, $room, $user); $this->afterCreate($suspension, $parameters, $room, $user);
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
} }
/** /**
* Creates chat messages informing about the suspension. * Creates chat messages informing about the suspension.
* *
* @param mixed[] $parameters * @param \chat\data\suspension\Suspension $suspension
*/ * @param mixed[] $parameters
protected function afterCreate(Suspension $suspension, $parameters, Room $room, UserProfile $user) * @param \chat\data\room\Room $room
{ * @param \wcf\data\user\UserProfile $user
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.suspend'); */
$target = $suspension->getUser(); protected function afterCreate(Suspension $suspension, $parameters, Room $room, UserProfile $user) {
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.suspend');
$target = $suspension->getUser();
if ($suspension->getRoom() === null) { if ($suspension->getRoom() === null) {
$roomIDs = \array_map(static function (Room $room) { $roomIDs = array_map(function (Room $room) use ($user) {
return $room->roomID; return $room->roomID;
}, (new ChatUser($target))->getRooms()); }, (new \chat\data\user\User($target))->getRooms());
$roomIDs[] = $room->roomID; $roomIDs[] = $room->roomID;
} else { }
$roomIDs = [ $suspension->getRoom()->roomID ]; else {
} $roomIDs = [ $suspension->getRoom()->roomID ];
}
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'suspension' => $suspension
'userID' => $user->userID, , 'roomIDs' => $roomIDs
'username' => $user->username, , 'globally' => $this->isGlobally($parameters)
'time' => TIME_NOW, , 'target' => [ 'userID' => $target->userID
'objectTypeID' => $objectTypeID, , 'username' => $target->username
'payload' => \serialize([ ]
'suspension' => $suspension, ])
'roomIDs' => $roomIDs, ]
'globally' => $this->isGlobally($parameters), , 'updateTimestamp' => true
'target' => [ ]
'userID' => $target->userID, )
'username' => $target->username, )->executeAction();
], }
]),
],
'updateTimestamp' => true,
]
))->executeAction();
}
/** /**
* Returns the database fields. * Returns the database fields.
* *
* @param mixed[] $parameters * @param mixed[] $parameters
* @return mixed[] * @param \chat\data\room\Room $room
*/ * @param \wcf\data\user\UserProfile $user
protected function getSuspensionData($parameters, Room $room, ?UserProfile $user = null) * @return mixed[]
{ */
$target = $this->getUser($parameters['username']); protected function getSuspensionData($parameters, Room $room, UserProfile $user = null) {
$globally = $this->isGlobally($parameters); $target = $this->getUser($parameters['username']);
$expires = $parameters['duration']; $globally = $this->isGlobally($parameters);
$reason = $parameters['reason'] ?: ''; $expires = $parameters['duration'];
$reason = $parameters['reason'] ?: '';
$roomID = $globally ? null : $room->roomID; $roomID = $globally ? null : $room->roomID;
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.suspension', $this->getObjectTypeName());
'be.bastelstu.chat.suspension',
$this->getObjectTypeName()
);
return [ return [ 'time' => TIME_NOW
'time' => TIME_NOW, , 'expires' => $expires
'expires' => $expires, , 'roomID' => $roomID
'roomID' => $roomID, , 'userID' => $target->userID
'userID' => $target->userID, , 'objectTypeID' => $objectTypeID
'objectTypeID' => $objectTypeID, , 'reason' => $reason
'reason' => $reason, , 'judgeID' => $user->userID
'judgeID' => $user->userID, , 'judge' => $user->username
'judge' => $user->username, ];
]; }
}
/** /**
* Returns whether a global suspension was requested. * Returns whether a global suspension was requested.
* *
* @param mixed[] $parameters * @param mixed[] $parameters
* @return boolean * @return boolean
*/ */
protected function isGlobally($parameters) protected function isGlobally($parameters) {
{ return $parameters['globally'] === true;
return $parameters['globally'] === true; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,172 +14,149 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\suspension\Suspension; use \chat\data\suspension\Suspension;
use chat\data\suspension\SuspensionAction; use \chat\data\suspension\SuspensionAction;
use chat\data\suspension\SuspensionList; use \chat\data\suspension\SuspensionList;
use chat\data\user\User as ChatUser; use \wcf\data\object\type\ObjectTypeCache;
use wcf\data\object\type\ObjectTypeCache; use \wcf\data\user\UserProfile;
use wcf\data\user\UserProfile; use \wcf\system\exception\UserInputException;
use wcf\system\exception\UserInputException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* Represents a command that revokes suspensions * Represents a command that revokes suspensions
*/ */
abstract class AbstractUnsuspensionCommand extends AbstractCommand abstract class AbstractUnsuspensionCommand extends AbstractCommand {
{ use TNeedsUser;
use TNeedsUser;
/** /**
* Returns the name of the object type for this suspension. * Returns the name of the object type for this suspension.
* *
* @return string * @return string
*/ */
abstract public function getObjectTypeName(); abstract public function getObjectTypeName();
/** /**
* Checks the permissions to execute this command. * Checks the permissions to execute this command.
* Throws if necessary. * Throws if necessary.
* *
* @see \chat\system\command\ICommand::validate() * @see \chat\system\command\ICommand::validate()
*/ */
abstract protected function checkPermissions($parameters, Room $room, UserProfile $user); abstract protected function checkPermissions($parameters, Room $room, UserProfile $user);
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$this->assertParameter($parameters, 'username'); $this->assertParameter($parameters, 'username');
$this->assertParameter($parameters, 'globally'); $this->assertParameter($parameters, 'globally');
$this->assertUser($parameters['username']); $this->assertUser($parameters['username']);
$suspensions = $this->getSuspensionData($parameters, $room, $user); $suspensions = $this->getSuspensionData($parameters, $room, $user);
if (empty($suspensions)) { if (empty($suspensions)) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.suspension.remove.empty'));
'message', }
WCF::getLanguage()->getDynamicVariable('chat.error.suspension.remove.empty') }
);
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$suspensions = $this->getSuspensionData($parameters, $room, $user); $suspensions = $this->getSuspensionData($parameters, $room, $user);
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
(new SuspensionAction( (new SuspensionAction($suspensions, 'revoke', [ ]))->executeAction();
$suspensions, $this->afterCreate($suspensions, $parameters, $room, $user);
'revoke', WCF::getDB()->commitTransaction();
[ ] }
))->executeAction();
$this->afterCreate($suspensions, $parameters, $room, $user);
WCF::getDB()->commitTransaction();
}
/** /**
* Creates chat messages informing about the removed suspensions. * Creates chat messages informing about the removed suspensions.
* *
* @param \chat\data\suspension\Suspension[] $suspension * @param \chat\data\suspension\Suspension[] $suspension
* @param mixed[] $parameters * @param mixed[] $parameters
*/ * @param \chat\data\room\Room $room
protected function afterCreate($suspensions, $parameters, Room $room, UserProfile $user) * @param \wcf\data\user\UserProfile $user
{ */
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.unsuspend'); protected function afterCreate($suspensions, $parameters, Room $room, UserProfile $user) {
$target = $this->getUser($parameters['username']); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.unsuspend');
if ($this->isGlobally($parameters)) { $target = $this->getUser($parameters['username']);
$roomIDs = \array_map(static function (Room $room) { if ($this->isGlobally($parameters)) {
return $room->roomID; $roomIDs = array_map(function (Room $room) use ($user) {
}, (new ChatUser($target))->getRooms()); return $room->roomID;
$roomIDs[] = $room->roomID; }, (new \chat\data\user\User($target))->getRooms());
} else { $roomIDs[] = $room->roomID;
$roomIDs = [ }
$room->roomID, else {
]; $roomIDs = [ $room->roomID ];
} }
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'objectType' => $this->getObjectTypeName()
'userID' => $user->userID, , 'roomIDs' => $roomIDs
'username' => $user->username, , 'globally' => $this->isGlobally($parameters)
'time' => TIME_NOW, , 'target' => [ 'userID' => $target->userID
'objectTypeID' => $objectTypeID, , 'username' => $target->username
'payload' => \serialize([ ]
'objectType' => $this->getObjectTypeName(), ])
'roomIDs' => $roomIDs, ]
'globally' => $this->isGlobally($parameters), , 'updateTimestamp' => true
'target' => [ ]
'userID' => $target->userID, )
'username' => $target->username, )->executeAction();
], }
]),
],
'updateTimestamp' => true,
]
))->executeAction();
}
/** /**
* Returns the active suspensions. * Returns the active suspensions.
* *
* @param mixed[] $parameters * @param mixed[] $parameters
* @return mixed[] * @param \chat\data\room\Room $room
*/ * @param \wcf\data\user\UserProfile $user
protected function getSuspensionData($parameters, Room $room, ?UserProfile $user = null) * @return mixed[]
{ */
$target = $this->getUser($parameters['username']); protected function getSuspensionData($parameters, Room $room, UserProfile $user = null) {
$target = $this->getUser($parameters['username']);
$roomID = $this->isGlobally($parameters) ? null : $room->roomID; $roomID = $this->isGlobally($parameters) ? null : $room->roomID;
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName( $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.suspension', $this->getObjectTypeName());
'be.bastelstu.chat.suspension',
$this->getObjectTypeName()
);
$suspensionList = new SuspensionList(); $suspensionList = new SuspensionList();
$suspensionList->getConditionBuilder()->add('(expires IS NULL OR expires > ?)', [ TIME_NOW ]); $suspensionList->getConditionBuilder()->add('(expires IS NULL OR expires > ?)', [ TIME_NOW ]);
$suspensionList->getConditionBuilder()->add('revoked IS NULL'); $suspensionList->getConditionBuilder()->add('revoked IS NULL');
$suspensionList->getConditionBuilder()->add('userID = ?', [ $target->userID ]); $suspensionList->getConditionBuilder()->add('userID = ?', [ $target->userID ]);
$suspensionList->getConditionBuilder()->add('objectTypeID = ?', [ $objectTypeID ]); $suspensionList->getConditionBuilder()->add('objectTypeID = ?', [ $objectTypeID ]);
if ($roomID === null) { if ($roomID === null) {
$suspensionList->getConditionBuilder()->add('roomID IS NULL'); $suspensionList->getConditionBuilder()->add('roomID IS NULL');
} else { }
$suspensionList->getConditionBuilder()->add('roomID = ?', [ $room->roomID ]); else {
} $suspensionList->getConditionBuilder()->add('roomID = ?', [ $room->roomID ]);
}
$suspensionList->readObjects(); $suspensionList->readObjects();
return \array_filter($suspensionList->getObjects(), static function (Suspension $suspension) { return array_filter($suspensionList->getObjects(), function (Suspension $suspension) {
return $suspension->isActive(); return $suspension->isActive();
}); });
} }
/** /**
* Returns whether a global suspension removal was requested. * Returns whether a global suspension removal was requested.
* *
* @param mixed[] $parameters * @param mixed[] $parameters
* @return boolean * @return boolean
*/ */
protected function isGlobally($parameters) protected function isGlobally($parameters) {
{ return $parameters['globally'] === true;
return $parameters['globally'] === true; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,99 +14,74 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\user\User as ChatUser; use \wcf\data\user\UserProfile;
use wcf\data\user\UserEditor; use \wcf\system\exception\PermissionDeniedException;
use wcf\data\user\UserProfile; use \wcf\system\exception\UserInputException;
use wcf\system\exception\UserInputException; use \wcf\system\message\censorship\Censorship;
use wcf\system\message\censorship\Censorship; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* The away command marks the user as being away. * The away command marks the user as being away.
*/ */
final class AwayCommand extends AbstractCommand implements ICommand class AwayCommand extends AbstractCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Away';
{ }
return 'Bastelstu.be/Chat/Command/Away';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$reason = $this->assertParameter($parameters, 'reason'); $reason = $this->assertParameter($parameters, 'reason');
// search for censored words // search for censored words
if (ENABLE_CENSORSHIP) { if (ENABLE_CENSORSHIP) {
$result = Censorship::getInstance()->test($reason); $result = Censorship::getInstance()->test($reason);
if ($result) { if ($result) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', [ 'censoredWords' => $result ]));
'message', }
WCF::getLanguage()->getDynamicVariable( }
'wcf.message.error.censoredWordsFound', }
[
'censoredWords' => $result,
]
)
);
}
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$reason = $this->assertParameter($parameters, 'reason'); $reason = $this->assertParameter($parameters, 'reason');
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.away'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.away');
$rooms = \array_map(static function (Room $room) use ($user) { $rooms = array_map(function (Room $room) use ($user) {
return [ return [ 'roomID' => $room->roomID
'roomID' => $room->roomID, , 'isSilent' => !$room->canWritePublicly($user)
'isSilent' => !$room->canWritePublicly($user), ];
]; }, (new \chat\data\user\User($user->getDecoratedObject()))->getRooms());
}, (new ChatUser($user->getDecoratedObject()))->getRooms());
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$editor = new UserEditor($user->getDecoratedObject()); $editor = new \wcf\data\user\UserEditor($user->getDecoratedObject());
$editor->update([ $editor->update([ 'chatAway' => $reason ]);
'chatAway' => $reason,
]);
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'message' => $reason
'userID' => $user->userID, , 'rooms' => array_values($rooms)
'username' => $user->username, ])
'time' => TIME_NOW, ]
'objectTypeID' => $objectTypeID, , 'updateTimestamp' => true
'payload' => \serialize([ ]
'message' => $reason, )
'rooms' => \array_values($rooms), )->executeAction();
]), WCF::getDB()->commitTransaction();
], }
'updateTimestamp' => true,
]
))->executeAction();
WCF::getDB()->commitTransaction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,89 +14,67 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\user\User as ChatUser; use \wcf\data\user\UserProfile;
use wcf\data\user\UserEditor; use \wcf\system\exception\PermissionDeniedException;
use wcf\data\user\UserProfile; use \wcf\system\WCF;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\WCF;
/** /**
* The back command marks the user as being back. * The back command marks the user as being back.
*/ */
final class BackCommand extends AbstractCommand implements ICommand class BackCommand extends AbstractCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function allowWithoutTrigger() {
public function allowWithoutTrigger() return true;
{ }
return true;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName() public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/Command/Back';
return 'Bastelstu.be/Chat/Command/Back'; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if ($user->chatAway === null) { if ($user->chatAway === null) throw new PermissionDeniedException();
throw new PermissionDeniedException(); }
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.back'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.back');
$rooms = \array_map(static function (Room $room) use ($user) { $rooms = array_map(function (Room $room) use ($user) {
return [ return [ 'roomID' => $room->roomID
'roomID' => $room->roomID, , 'isSilent' => !$room->canWritePublicly($user)
'isSilent' => !$room->canWritePublicly($user), ];
]; }, (new \chat\data\user\User($user->getDecoratedObject()))->getRooms());
}, (new ChatUser($user->getDecoratedObject()))->getRooms());
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$editor = new UserEditor($user->getDecoratedObject()); $editor = new \wcf\data\user\UserEditor($user->getDecoratedObject());
$editor->update([ $editor->update([ 'chatAway' => null ]);
'chatAway' => null,
]);
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'rooms' => array_values($rooms) ])
'userID' => $user->userID, ]
'username' => $user->username, , 'updateTimestamp' => true
'time' => TIME_NOW, ]
'objectTypeID' => $objectTypeID, )
'payload' => \serialize([ )->executeAction();
'rooms' => \array_values($rooms), WCF::getDB()->commitTransaction();
]), }
],
'updateTimestamp' => true,
]
))->executeAction();
WCF::getDB()->commitTransaction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,98 +14,81 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomAction; use \chat\data\suspension\Suspension;
use chat\data\suspension\Suspension; use \chat\data\suspension\SuspensionAction;
use chat\data\user\User as ChatUser; use \chat\system\permission\PermissionHandler;
use chat\system\permission\PermissionHandler; use \wcf\data\object\type\ObjectTypeCache;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* The ban command creates a new be.bastelstu.chat.suspension.ban suspension. * The ban command creates a new be.bastelstu.chat.suspension.ban suspension.
*/ */
final class BanCommand extends AbstractSuspensionCommand implements ICommand class BanCommand extends AbstractSuspensionCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Ban';
{ }
return 'Bastelstu.be/Chat/Command/Ban';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) { return $user->getPermission('mod.chat.canBan') || PermissionHandler::get($user)->getPermission($room, 'mod.canBan');
$user = new UserProfile(WCF::getUser()); }
}
return $user->getPermission('mod.chat.canBan') || PermissionHandler::get($user)->getPermission($room, 'mod.canBan'); /**
} * @inheritDoc
*/
public function getObjectTypeName() {
return 'be.bastelstu.chat.suspension.ban';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getObjectTypeName() protected function checkPermissions($parameters, Room $room, UserProfile $user) {
{ $permission = $user->getPermission('mod.chat.canBan');
return 'be.bastelstu.chat.suspension.ban';
}
/** if (!$this->isGlobally($parameters)) {
* @inheritDoc $permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canBan');
*/ }
protected function checkPermissions($parameters, Room $room, UserProfile $user)
{
$permission = $user->getPermission('mod.chat.canBan');
if (!$this->isGlobally($parameters)) { if (!$permission) throw new PermissionDeniedException();
$permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canBan'); }
}
if (!$permission) { /**
throw new PermissionDeniedException(); * @inheritDoc
} */
} protected function afterCreate(Suspension $suspension, $parameters, Room $room, UserProfile $user) {
parent::afterCreate($suspension, $parameters, $room, $user);
/** $user = new \chat\data\user\User($suspension->getUser());
* @inheritDoc $rooms = [ ];
*/ if ($suspension->getRoom() === null) {
protected function afterCreate(Suspension $suspension, $parameters, Room $room, UserProfile $user) $rooms = $user->getRooms();
{ }
parent::afterCreate($suspension, $parameters, $room, $user); else {
if ($user->isInRoom($suspension->getRoom())) {
$rooms = [ $suspension->getRoom() ];
}
}
$user = new ChatUser($suspension->getUser()); foreach ($rooms as $room) {
$rooms = [ ]; $parameters = [ 'user' => $suspension->getUser()
if ($suspension->getRoom() === null) { , 'roomID' => $room->roomID
$rooms = $user->getRooms(); ];
} else { try {
if ($user->isInRoom($suspension->getRoom())) { (new \chat\data\room\RoomAction([ ], 'leave', $parameters))->executeAction();
$rooms = [ }
$suspension->getRoom(), catch (UserInputException $e) {
]; // User already left
} }
} }
}
foreach ($rooms as $room) {
$parameters = [
'user' => $suspension->getUser(),
'roomID' => $room->roomID,
];
try {
(new RoomAction(
[ ],
'leave',
$parameters
))->executeAction();
} catch (UserInputException $e) {
// User already left
}
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,94 +14,72 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\message\MessageEditor; use \chat\data\message\MessageEditor;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* BroadcastCommand sends a broadcast into all channels. * BroadcastCommand sends a broadcast into all channels.
*/ */
final class BroadcastCommand extends AbstractInputProcessedCommand implements ICommand class BroadcastCommand extends AbstractInputProcessedCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Broadcast';
{ }
return 'Bastelstu.be/Chat/Command/Broadcast';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) { return $user->getPermission('mod.chat.canBroadcast');
$user = new UserProfile(WCF::getUser()); }
}
return $user->getPermission('mod.chat.canBroadcast'); /**
} * @inheritDoc
*/
public function validate($parameters, Room $room, UserProfile $user = null) {
if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
/** if (!$user->getPermission('mod.chat.canBroadcast')) throw new PermissionDeniedException();
* @inheritDoc
*/
public function validate($parameters, Room $room, ?UserProfile $user = null)
{
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!$user->getPermission('mod.chat.canBroadcast')) { $this->setText($this->assertParameter($parameters, 'text'));
throw new PermissionDeniedException(); $this->validateText();
} }
$this->setText($this->assertParameter($parameters, 'text')); /**
$this->validateText(); * @inheritDoc
} */
public function execute($parameters, Room $room, UserProfile $user = null) {
if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
/** $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.broadcast');
* @inheritDoc $this->setText($this->assertParameter($parameters, 'text'));
*/
public function execute($parameters, Room $room, ?UserProfile $user = null)
{
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.broadcast'); WCF::getDB()->beginTransaction();
$this->setText($this->assertParameter($parameters, 'text')); $message = (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
, 'userID' => $user->userID
, 'username' => $user->username
, 'time' => TIME_NOW
, 'objectTypeID' => $objectTypeID
, 'payload' => serialize([ 'message' => $this->processor->getHtml() ])
]
, 'updateTimestamp' => true
]
)
)->executeAction()['returnValues'];
WCF::getDB()->beginTransaction(); $this->processor->setObjectID($message->messageID);
$message = (new MessageAction( if (\wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) {
[ ], (new MessageEditor($message))->update([
'create', 'hasEmbeddedObjects' => 1
[ ]);
'data' => [ }
'roomID' => $room->roomID, WCF::getDB()->commitTransaction();
'userID' => $user->userID, }
'username' => $user->username,
'time' => TIME_NOW,
'objectTypeID' => $objectTypeID,
'payload' => \serialize([
'message' => $this->processor->getHtml(),
]),
],
'updateTimestamp' => true,
]
)
)->executeAction()['returnValues'];
$this->processor->setObjectID($message->messageID);
if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) {
(new MessageEditor($message))->update([
'hasEmbeddedObjects' => 1,
]);
}
WCF::getDB()->commitTransaction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,312 +14,272 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\DatabaseObject; use \wcf\data\user\UserProfile;
use wcf\data\user\UserEditor; use \wcf\system\exception\PermissionDeniedException;
use wcf\data\user\UserProfile; use \wcf\system\exception\UserInputException;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\WCF;
use wcf\system\exception\UserInputException; use \wcf\util\StringUtil;
use wcf\system\Regex;
use wcf\system\WCF;
use wcf\util\StringUtil;
/** /**
* The color command allows a user to set a color for their username * The color command allows a user to set a color for their username
*/ */
final class ColorCommand extends AbstractCommand implements ICommand class ColorCommand extends AbstractCommand implements ICommand {
{ /**
/** * Regular expression matching RGB values in hexadecimal notation
* Regular expression matching RGB values in hexadecimal notation * @var \wcf\system\Regex
* @var \wcf\system\Regex */
*/ protected $colorRegex = null;
protected $colorRegex;
public function __construct(DatabaseObject $object) public function __construct(\wcf\data\DatabaseObject $object) {
{ parent::__construct($object);
parent::__construct($object);
$this->colorRegex = new Regex('^#?([a-f0-9]{6})$', Regex::CASE_INSENSITIVE); $this->colorRegex = new \wcf\system\Regex('^#?([a-f0-9]{6})$', \wcf\system\Regex::CASE_INSENSITIVE);
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName() public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/Command/Color';
return 'Bastelstu.be/Chat/Command/Color'; }
}
/** /**
* Map CSS color names to hexcodes. * Map CSS color names to hexcodes.
* See: https://www.w3.org/TR/css3-color/#svg-color * See: https://www.w3.org/TR/css3-color/#svg-color
* *
* @var int[] * @var int[]
*/ */
public static $colors = [ public static $colors = [
'aliceblue' => 0xF0F8FF, 'aliceblue' => 0xF0F8FF,
'antiquewhite' => 0xFAEBD7, 'antiquewhite' => 0xFAEBD7,
'aqua' => 0x00FFFF, 'aqua' => 0x00FFFF,
'aquamarine' => 0x7FFFD4, 'aquamarine' => 0x7FFFD4,
'azure' => 0xF0FFFF, 'azure' => 0xF0FFFF,
'beige' => 0xF5F5DC, 'beige' => 0xF5F5DC,
'bisque' => 0xFFE4C4, 'bisque' => 0xFFE4C4,
'black' => 0x000000, 'black' => 0x000000,
'blanchedalmond' => 0xFFEBCD, 'blanchedalmond' => 0xFFEBCD,
'blue' => 0x0000FF, 'blue' => 0x0000FF,
'bluescreenblue' => 0x0000AA, 'bluescreenblue' => 0x0000AA,
'blueviolet' => 0x8A2BE2, 'blueviolet' => 0x8A2BE2,
'brown' => 0xA52A2A, 'brown' => 0xA52A2A,
'burlywood' => 0xDEB887, 'burlywood' => 0xDEB887,
'cadetblue' => 0x5F9EA0, 'cadetblue' => 0x5F9EA0,
'chartreuse' => 0x7FFF00, 'chartreuse' => 0x7FFF00,
'chocolate' => 0xD2691E, 'chocolate' => 0xD2691E,
'coral' => 0xFF7F50, 'coral' => 0xFF7F50,
'cornflowerblue' => 0x6495ED, 'cornflowerblue' => 0x6495ED,
'cornsilk' => 0xFFF8DC, 'cornsilk' => 0xFFF8DC,
'crimson' => 0xDC143C, 'crimson' => 0xDC143C,
'cyan' => 0x00FFFF, 'cyan' => 0x00FFFF,
'darkblue' => 0x00008B, 'darkblue' => 0x00008B,
'darkcyan' => 0x008B8B, 'darkcyan' => 0x008B8B,
'darkgoldenrod' => 0xB8860B, 'darkgoldenrod' => 0xB8860B,
'darkgray' => 0xA9A9A9, 'darkgray' => 0xA9A9A9,
'darkgrey' => 0xA9A9A9, 'darkgrey' => 0xA9A9A9,
'darkgreen' => 0x006400, 'darkgreen' => 0x006400,
'darkkhaki' => 0xBDB76B, 'darkkhaki' => 0xBDB76B,
'darkmagenta' => 0x8B008B, 'darkmagenta' => 0x8B008B,
'darkolivegreen' => 0x556B2F, 'darkolivegreen' => 0x556B2F,
'darkorange' => 0xFF8C00, 'darkorange' => 0xFF8C00,
'darkorchid' => 0x9932CC, 'darkorchid' => 0x9932CC,
'darkred' => 0x8B0000, 'darkred' => 0x8B0000,
'darksalmon' => 0xE9967A, 'darksalmon' => 0xE9967A,
'darkseagreen' => 0x8FBC8F, 'darkseagreen' => 0x8FBC8F,
'darkslateblue' => 0x483D8B, 'darkslateblue' => 0x483D8B,
'darkslategray' => 0x2F4F4F, 'darkslategray' => 0x2F4F4F,
'darkslategrey' => 0x2F4F4F, 'darkslategrey' => 0x2F4F4F,
'darkturquoise' => 0x00CED1, 'darkturquoise' => 0x00CED1,
'darkviolet' => 0x9400D3, 'darkviolet' => 0x9400D3,
'deeppink' => 0xFF1493, 'deeppink' => 0xFF1493,
'deepskyblue' => 0x00BFFF, 'deepskyblue' => 0x00BFFF,
'dimgray' => 0x696969, 'dimgray' => 0x696969,
'dimgrey' => 0x696969, 'dimgrey' => 0x696969,
'dodgerblue' => 0x1E90FF, 'dodgerblue' => 0x1E90FF,
'firebrick' => 0xB22222, 'firebrick' => 0xB22222,
'floralwhite' => 0xFFFAF0, 'floralwhite' => 0xFFFAF0,
'forestgreen' => 0x228B22, 'forestgreen' => 0x228B22,
'fuchsia' => 0xFF00FF, 'fuchsia' => 0xFF00FF,
'gainsboro' => 0xDCDCDC, 'gainsboro' => 0xDCDCDC,
'ghostwhite' => 0xF8F8FF, 'ghostwhite' => 0xF8F8FF,
'gold' => 0xFFD700, 'gold' => 0xFFD700,
'goldenrod' => 0xDAA520, 'goldenrod' => 0xDAA520,
'gray' => 0x808080, 'gray' => 0x808080,
'grey' => 0x808080, 'grey' => 0x808080,
'green' => 0x008000, 'green' => 0x008000,
'greenyellow' => 0xADFF2F, 'greenyellow' => 0xADFF2F,
'honeydew' => 0xF0FFF0, 'honeydew' => 0xF0FFF0,
'hotpink' => 0xFF69B4, 'hotpink' => 0xFF69B4,
'indianred' => 0xCD5C5C, 'indianred' => 0xCD5C5C,
'indigo' => 0x4B0082, 'indigo' => 0x4B0082,
'ivory' => 0xFFFFF0, 'ivory' => 0xFFFFF0,
'khaki' => 0xF0E68C, 'khaki' => 0xF0E68C,
'lavender' => 0xE6E6FA, 'lavender' => 0xE6E6FA,
'lavenderblush' => 0xFFF0F5, 'lavenderblush' => 0xFFF0F5,
'lawngreen' => 0x7CFC00, 'lawngreen' => 0x7CFC00,
'lemonchiffon' => 0xFFFACD, 'lemonchiffon' => 0xFFFACD,
'lightblue' => 0xADD8E6, 'lightblue' => 0xADD8E6,
'lightcoral' => 0xF08080, 'lightcoral' => 0xF08080,
'lightcyan' => 0xE0FFFF, 'lightcyan' => 0xE0FFFF,
'lightgoldenrodyellow' => 0xFAFAD2, 'lightgoldenrodyellow' => 0xFAFAD2,
'lightgray' => 0xD3D3D3, 'lightgray' => 0xD3D3D3,
'lightgrey' => 0xD3D3D3, 'lightgrey' => 0xD3D3D3,
'lightgreen' => 0x90EE90, 'lightgreen' => 0x90EE90,
'lightpink' => 0xFFB6C1, 'lightpink' => 0xFFB6C1,
'lightsalmon' => 0xFFA07A, 'lightsalmon' => 0xFFA07A,
'lightseagreen' => 0x20B2AA, 'lightseagreen' => 0x20B2AA,
'lightskyblue' => 0x87CEFA, 'lightskyblue' => 0x87CEFA,
'lightslategray' => 0x778899, 'lightslategray' => 0x778899,
'lightslategrey' => 0x778899, 'lightslategrey' => 0x778899,
'lightsteelblue' => 0xB0C4DE, 'lightsteelblue' => 0xB0C4DE,
'lightyellow' => 0xFFFFE0, 'lightyellow' => 0xFFFFE0,
'lime' => 0x00FF00, 'lime' => 0x00FF00,
'limegreen' => 0x32CD32, 'limegreen' => 0x32CD32,
'linen' => 0xFAF0E6, 'linen' => 0xFAF0E6,
'magenta' => 0xFF00FF, 'magenta' => 0xFF00FF,
'maroon' => 0x800000, 'maroon' => 0x800000,
'mediumaquamarine' => 0x66CDAA, 'mediumaquamarine' => 0x66CDAA,
'mediumblue' => 0x0000CD, 'mediumblue' => 0x0000CD,
'mediumorchid' => 0xBA55D3, 'mediumorchid' => 0xBA55D3,
'mediumpurple' => 0x9370D8, 'mediumpurple' => 0x9370D8,
'mediumseagreen' => 0x3CB371, 'mediumseagreen' => 0x3CB371,
'mediumslateblue' => 0x7B68EE, 'mediumslateblue' => 0x7B68EE,
'mediumspringgreen' => 0x00FA9A, 'mediumspringgreen' => 0x00FA9A,
'mediumturquoise' => 0x48D1CC, 'mediumturquoise' => 0x48D1CC,
'mediumvioletred' => 0xC71585, 'mediumvioletred' => 0xC71585,
'midnightblue' => 0x191970, 'midnightblue' => 0x191970,
'mintcream' => 0xF5FFFA, 'mintcream' => 0xF5FFFA,
'mistyrose' => 0xFFE4E1, 'mistyrose' => 0xFFE4E1,
'moccasin' => 0xFFE4B5, 'moccasin' => 0xFFE4B5,
'navajowhite' => 0xFFDEAD, 'navajowhite' => 0xFFDEAD,
'navy' => 0x000080, 'navy' => 0x000080,
'oldlace' => 0xFDF5E6, 'oldlace' => 0xFDF5E6,
'olive' => 0x808000, 'olive' => 0x808000,
'olivedrab' => 0x6B8E23, 'olivedrab' => 0x6B8E23,
'orange' => 0xFFA500, 'orange' => 0xFFA500,
'orangered' => 0xFF4500, 'orangered' => 0xFF4500,
'orchid' => 0xDA70D6, 'orchid' => 0xDA70D6,
'oxford' => 0xF02D, // looks like green 'oxford' => 0xF02D, // looks like green
'palegoldenrod' => 0xEEE8AA, 'palegoldenrod' => 0xEEE8AA,
'palegreen' => 0x98FB98, 'palegreen' => 0x98FB98,
'paleturquoise' => 0xAFEEEE, 'paleturquoise' => 0xAFEEEE,
'palevioletred' => 0xD87093, 'palevioletred' => 0xD87093,
'papayawhip' => 0xFFEFD5, 'papayawhip' => 0xFFEFD5,
'peachpuff' => 0xFFDAB9, 'peachpuff' => 0xFFDAB9,
'peru' => 0xCD853F, 'peru' => 0xCD853F,
'pink' => 0xFFC0CB, 'pink' => 0xFFC0CB,
'plum' => 0xDDA0DD, 'plum' => 0xDDA0DD,
'powderblue' => 0xB0E0E6, 'powderblue' => 0xB0E0E6,
'purple' => 0x800080, 'purple' => 0x800080,
'red' => 0xFF0000, 'red' => 0xFF0000,
'rosybrown' => 0xBC8F8F, 'rosybrown' => 0xBC8F8F,
'royalblue' => 0x4169E1, 'royalblue' => 0x4169E1,
'saddlebrown' => 0x8B4513, 'saddlebrown' => 0x8B4513,
'sadwin' => 0x2067B2, 'sadwin' => 0x2067B2,
'salmon' => 0xFA8072, 'salmon' => 0xFA8072,
'sandybrown' => 0xF4A460, 'sandybrown' => 0xF4A460,
'seagreen' => 0x2E8B57, 'seagreen' => 0x2E8B57,
'seashell' => 0xFFF5EE, 'seashell' => 0xFFF5EE,
'sienna' => 0xA0522D, 'sienna' => 0xA0522D,
'silver' => 0xC0C0C0, 'silver' => 0xC0C0C0,
'skyblue' => 0x87CEEB, 'skyblue' => 0x87CEEB,
'slateblue' => 0x6A5ACD, 'slateblue' => 0x6A5ACD,
'slategray' => 0x708090, 'slategray' => 0x708090,
'slategrey' => 0x708090, 'slategrey' => 0x708090,
'snow' => 0xFFFAFA, 'snow' => 0xFFFAFA,
'springgreen' => 0x00FF7F, 'springgreen' => 0x00FF7F,
'steelblue' => 0x4682B4, 'steelblue' => 0x4682B4,
'tan' => 0xD2B48C, 'tan' => 0xD2B48C,
'teal' => 0x008080, 'teal' => 0x008080,
'thistle' => 0xD8BFD8, 'thistle' => 0xD8BFD8,
'tomato' => 0xFF6347, 'tomato' => 0xFF6347,
'turquoise' => 0x40E0D0, 'turquoise' => 0x40E0D0,
'violet' => 0xEE82EE, 'violet' => 0xEE82EE,
'wheat' => 0xF5DEB3, 'wheat' => 0xF5DEB3,
'white' => 0xFFFFFF, 'white' => 0xFFFFFF,
'whitesmoke' => 0xF5F5F5, 'whitesmoke' => 0xF5F5F5,
'yellow' => 0xFFFF00, 'yellow' => 0xFFFF00,
'yellowgreen' => 0x9ACD32, 'yellowgreen' => 0x9ACD32
]; ];
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!$user->getPermission('user.chat.canSetColor')) { if (!$user->getPermission('user.chat.canSetColor')) throw new PermissionDeniedException();
throw new PermissionDeniedException();
}
foreach ($parameters as $parameter) { foreach ($parameters as $parameter) {
$value = StringUtil::trim($this->assertParameter($parameter, 'value')); $value = StringUtil::trim($this->assertParameter($parameter, 'value'));
$valid = true; $valid = true;
switch ($this->assertParameter($parameter, 'type')) { switch ($this->assertParameter($parameter, 'type')) {
case 'hex': case 'hex':
if (!$this->colorRegex->match($value)) { if (!$this->colorRegex->match($value)) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.invalidColor', [ 'color' => $value ]));
'message', }
WCF::getLanguage()->getDynamicVariable( break;
'chat.error.invalidColor', case 'word':
[ if (!isset(self::$colors[$value])) {
'color' => $value, throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.invalidColor', [ 'color' => $value ]));
] }
) break;
);
}
break;
case 'word':
if (!isset(self::$colors[$value])) {
throw new UserInputException(
'message',
WCF::getLanguage()->getDynamicVariable(
'chat.error.invalidColor',
[
'color' => $value,
]
)
);
}
break;
default: default:
throw new UserInputException('message'); throw new UserInputException('message');
} }
} }
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.color'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.color');
$colors = [ ]; $colors = [ ];
if (!isset($parameters[1])) { if (!isset($parameters[1])) $parameters[1] = $parameters[0];
$parameters[1] = $parameters[0];
}
foreach ($parameters as $key => $parameter) { foreach ($parameters as $key => $parameter) {
$value = StringUtil::trim($this->assertParameter($parameter, 'value')); $value = StringUtil::trim($this->assertParameter($parameter, 'value'));
switch ($this->assertParameter($parameter, 'type')) { switch ($this->assertParameter($parameter, 'type')) {
case 'hex': case 'hex':
$colors[$key] = \hexdec($value); $colors[$key] = hexdec($value);
break; break;
case 'word': case 'word':
if (!isset(self::$colors[$value])) { if (!isset(self::$colors[$value])) throw new UserInputException('message');
throw new UserInputException('message'); $colors[$key] = self::$colors[$value];
} break;
$colors[$key] = self::$colors[$value]; default:
break; throw new UserInputException('message');
default: }
throw new UserInputException('message'); }
}
}
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$editor = new UserEditor($user->getDecoratedObject()); $editor = new \wcf\data\user\UserEditor($user->getDecoratedObject());
$editor->update([ $editor->update([ 'chatColor1' => $colors[0]
'chatColor1' => $colors[0], , 'chatColor2' => $colors[1]
'chatColor2' => $colors[1], ]);
]);
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'color1' => $colors[0]
'userID' => $user->userID, , 'color2' => $colors[1]
'username' => $user->username, ])
'time' => TIME_NOW, ]
'objectTypeID' => $objectTypeID, , 'updateTimestamp' => true
'payload' => \serialize([ ]
'color1' => $colors[0], )
'color2' => $colors[1], )->executeAction();
]), WCF::getDB()->commitTransaction();
], }
'updateTimestamp' => true,
]
))->executeAction();
WCF::getDB()->commitTransaction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,64 +14,63 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
/** /**
* Interface for Command processors. * Interface for Command processors.
*/ */
interface ICommand interface ICommand {
{ /**
/** * Returns whether the command can be used even when
* Returns whether the command can be used even when * no trigger is configured for it.
* no trigger is configured for it. *
* * @return boolean
* @return boolean */
*/ public function allowWithoutTrigger();
public function allowWithoutTrigger();
/** /**
* Returns the name of the JavaScript module. * Returns the name of the JavaScript module.
* *
* @return string * @return string
*/ */
public function getJavaScriptModuleName(); public function getJavaScriptModuleName();
/** /**
* Returns whether this command theoretically is available * Returns whether this command theoretically is available
* in the given room, for the given user. * in the given room, for the given user.
* If no user is given the active user should be assumed. * If no user is given the active user should be assumed.
* *
* The return value sets a flag for the JavaScript to * The return value sets a flag for the JavaScript to
* consume. You still need to validate() this as well! * consume. You still need to validate() this as well!
* *
* @param Room $room * @param Room $room
* @param UserProfile $user * @param UserProfile $user
* @return boolean * @return boolean
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null); public function isAvailable(Room $room, UserProfile $user = null);
/** /**
* Validates the execution of the command with the given parameters * Validates the execution of the command with the given parameters
* in the given room for the given user. * in the given room for the given user.
* If no user is given the active user should be assumed. * If no user is given the active user should be assumed.
* This method must throw if the command may not be executed in this form. * This method must throw if the command may not be executed in this form.
* *
* @param mixed $parameters * @param mixed $parameters
* @param Room $room * @param Room $room
* @param UserProfile $user * @param UserProfile $user
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null); public function validate($parameters, Room $room, UserProfile $user = null);
/** /**
* Executes the command with the given parameters in the given room in * Executes the command with the given parameters in the given room in
* the context of the given user. * the context of the given user.
* If no user is given the active user should be assumed. * If no user is given the active user should be assumed.
* This method must throw if the command may not be executed in this form. * This method must throw if the command may not be executed in this form.
* *
* @param mixed $parameters * @param mixed $parameters
* @param Room $room * @param Room $room
* @param UserProfile $user * @param UserProfile $user
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null); public function execute($parameters, Room $room, UserProfile $user = null);
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,91 +14,75 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomCache; use \chat\data\room\RoomCache;
use chat\data\user\User as ChatUser; use \wcf\data\user\User;
use wcf\data\user\User; use \wcf\data\user\UserProfile;
use wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\WCF;
/** /**
* The info command shows information about a single user. * The info command shows information about a single user.
*/ */
final class InfoCommand extends AbstractCommand implements ICommand class InfoCommand extends AbstractCommand implements ICommand {
{ use TNeedsUser;
use TNeedsUser;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName() public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/Command/Info';
return 'Bastelstu.be/Chat/Command/Info'; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$this->assertUser($this->assertParameter($parameters, 'username')); $this->assertUser($this->assertParameter($parameters, 'username'));
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.info'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.info');
$target = new ChatUser($this->getUser($this->assertParameter($parameters, 'username'))); $target = new \chat\data\user\User($this->getUser($this->assertParameter($parameters, 'username')));
$rooms = \array_values(\array_map(static function ($assoc) { $rooms = array_values(array_map(function ($assoc) {
$room = RoomCache::getInstance()->getRoom($assoc['roomID']); $room = RoomCache::getInstance()->getRoom($assoc['roomID']);
return [ return [ 'title' => (string) $room
'title' => (string)$room, , 'roomID' => $assoc['roomID']
'roomID' => $assoc['roomID'], , 'lastPush' => $assoc['lastPush']
'lastPush' => $assoc['lastPush'], , 'lastPull' => $assoc['lastPull']
'lastPull' => $assoc['lastPull'], , 'active' => $assoc['active']
'active' => $assoc['active'], , 'link' => $room->getLink()
'link' => $room->getLink(), ];
]; }, array_filter($target->getRoomAssociations(), function ($assoc) {
}, \array_filter($target->getRoomAssociations(), static function ($assoc) { return RoomCache::getInstance()->getRoom($assoc['roomID'])->canSee();
return RoomCache::getInstance()->getRoom($assoc['roomID'])->canSee(); })));
})));
$payload = [ $payload = [ 'data' => [ 'rooms' => $rooms
'data' => [ , 'away' => $target->chatAway
'rooms' => $rooms, , 'user' => $target
'away' => $target->chatAway, ]
'user' => $target, , 'caller' => $user
], 'caller' => $user, ];
];
EventHandler::getInstance()->fireAction($this, 'execute', $payload); \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'execute', $payload);
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize($payload['data'])
'userID' => $user->userID, ]
'username' => $user->username, , 'updateTimestamp' => true
'time' => TIME_NOW, ]
'objectTypeID' => $objectTypeID, )
'payload' => \serialize($payload['data']), )->executeAction();
], 'updateTimestamp' => true, }
]
))->executeAction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,106 +14,71 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\UserInputException; use \wcf\system\exception\UserInputException;
use wcf\system\message\censorship\Censorship; use \wcf\system\message\censorship\Censorship;
use wcf\system\WCF; use \wcf\system\WCF;
/** /**
* MeCommand represents an action message. * MeCommand represents an action message.
*/ */
final class MeCommand extends AbstractCommand implements ICommand class MeCommand extends AbstractCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Me';
{ }
return 'Bastelstu.be/Chat/Command/Me';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!$room->canWritePublicly($user)) { if (!$room->canWritePublicly($user)) throw new PermissionDeniedException();
throw new PermissionDeniedException();
}
$text = $this->assertParameter($parameters, 'text'); $text = $this->assertParameter($parameters, 'text');
if (\mb_strlen($text) === 0) { if (mb_strlen($text) === 0) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.global.form.error.empty'));
'message', }
WCF::getLanguage()->getDynamicVariable('wcf.global.form.error.empty')
);
}
// validate message length // validate message length
if (\mb_strlen($text) > CHAT_MAX_LENGTH) { if (mb_strlen($text) > CHAT_MAX_LENGTH) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.tooLong', [ 'maxTextLength' => CHAT_MAX_LENGTH ]));
'message', }
WCF::getLanguage()->getDynamicVariable(
'wcf.message.error.tooLong',
[
'maxTextLength' => CHAT_MAX_LENGTH,
]
)
);
}
// search for censored words // search for censored words
if (ENABLE_CENSORSHIP) { if (ENABLE_CENSORSHIP) {
$result = Censorship::getInstance()->test($text); $result = Censorship::getInstance()->test($text);
if ($result) { if ($result) {
throw new UserInputException( throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('wcf.message.error.censoredWordsFound', [ 'censoredWords' => $result ]));
'message', }
WCF::getLanguage()->getDynamicVariable( }
'wcf.message.error.censoredWordsFound', }
[
'censoredWords' => $result,
]
)
);
}
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.me'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.me');
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'message' => $this->assertParameter($parameters, 'text') ])
'userID' => $user->userID, ]
'username' => $user->username, , 'updateTimestamp' => true
'time' => TIME_NOW, , 'grantPoints' => true
'objectTypeID' => $objectTypeID, ]
'payload' => \serialize([ )
'message' => $this->assertParameter($parameters, 'text'), )->executeAction();
]), }
],
'updateTimestamp' => true,
'grantPoints' => true,
]
))->executeAction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,58 +14,50 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\system\permission\PermissionHandler; use \chat\data\suspension\SuspensionAction;
use wcf\data\user\UserProfile; use \chat\system\permission\PermissionHandler;
use wcf\system\exception\PermissionDeniedException; use \wcf\data\object\type\ObjectTypeCache;
use wcf\system\WCF; use \wcf\data\user\UserProfile;
use \wcf\system\exception\PermissionDeniedException;
use \wcf\system\WCF;
/** /**
* The mute command creates a new be.bastelstu.chat.suspension.mute suspension. * The mute command creates a new be.bastelstu.chat.suspension.mute suspension.
*/ */
final class MuteCommand extends AbstractSuspensionCommand implements ICommand class MuteCommand extends AbstractSuspensionCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Mute';
{ }
return 'Bastelstu.be/Chat/Command/Mute';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) { return $user->getPermission('mod.chat.canMute') || PermissionHandler::get($user)->getPermission($room, 'mod.canMute');
$user = new UserProfile(WCF::getUser()); }
}
return $user->getPermission('mod.chat.canMute') || PermissionHandler::get($user)->getPermission($room, 'mod.canMute'); /**
} * @inheritDoc
*/
public function getObjectTypeName() {
return 'be.bastelstu.chat.suspension.mute';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getObjectTypeName() protected function checkPermissions($parameters, Room $room, UserProfile $user) {
{ $permission = $user->getPermission('mod.chat.canMute');
return 'be.bastelstu.chat.suspension.mute';
}
/** if (!$this->isGlobally($parameters)) {
* @inheritDoc $permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canMute');
*/ }
protected function checkPermissions($parameters, Room $room, UserProfile $user)
{
$permission = $user->getPermission('mod.chat.canMute');
if (!$this->isGlobally($parameters)) { if (!$permission) throw new PermissionDeniedException();
$permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canMute'); }
}
if (!$permission) {
throw new PermissionDeniedException();
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,90 +14,72 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\message\MessageEditor; use \chat\data\message\MessageEditor;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* The plain command creates a normal chat message * The plain command creates a normal chat message
*/ */
final class PlainCommand extends AbstractInputProcessedCommand implements ICommand class PlainCommand extends AbstractInputProcessedCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function allowWithoutTrigger() {
public function allowWithoutTrigger() return true;
{ }
return true;
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName() public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/Command/Plain';
return 'Bastelstu.be/Chat/Command/Plain'; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!$room->canWritePublicly($user)) { if (!$room->canWritePublicly($user)) throw new PermissionDeniedException();
throw new PermissionDeniedException();
}
$this->setText($this->assertParameter($parameters, 'text')); $this->setText($this->assertParameter($parameters, 'text'));
$this->validateText(); $this->validateText();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.plain'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.plain');
$this->setText($this->assertParameter($parameters, 'text')); $this->setText($this->assertParameter($parameters, 'text'));
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$message = (new MessageAction( $message = (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'message' => $this->processor->getHtml() ])
'userID' => $user->userID, ]
'username' => $user->username, , 'updateTimestamp' => true
'time' => TIME_NOW, , 'grantPoints' => true
'objectTypeID' => $objectTypeID, ]
'payload' => \serialize([ )
'message' => $this->processor->getHtml(), )->executeAction()['returnValues'];
]),
],
'updateTimestamp' => true,
'grantPoints' => true,
]
))->executeAction()['returnValues'];
$this->processor->setObjectID($message->messageID); $this->processor->setObjectID($message->messageID);
if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) { if (\wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) {
(new MessageEditor($message))->update([ (new MessageEditor($message))->update([
'hasEmbeddedObjects' => 1, 'hasEmbeddedObjects' => 1
]); ]);
} }
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,47 +14,40 @@
namespace chat\system\command; namespace chat\system\command;
use wcf\data\user\User; use \wcf\data\user\User;
use wcf\system\exception\UserInputException; use \wcf\system\exception\UserInputException;
use wcf\system\WCF; use \wcf\system\WCF;
/** /**
* Adds helpful functions for commands that operate on a user. * Adds helpful functions for commands that operate on a user.
*/ */
trait TNeedsUser trait TNeedsUser {
{ /**
/** * Returns the user with the given username.
* Returns the user with the given username. *
*/ * @param string $username
protected function getUser(string $username): User * @return \wcf\data\user\User
{ */
static $cache = [ ]; protected function getUser($username) {
if (!isset($cache[$username])) { static $cache = [ ];
$cache[$username] = User::getUserByUsername($username); if (!isset($cache[$username])) {
} $cache[$username] = User::getUserByUsername($username);
}
return $cache[$username]; return $cache[$username];
} }
/** /**
* Checks whether the given username is valid and throws otherwise. * Checks whether the given username is valid and throws otherwise.
*/ *
protected function assertUser(string $username): User * @param string $username
{ * @return \wcf\data\user\User
$user = $this->getUser($username); */
protected function assertUser($username) {
$user = $this->getUser($username);
if (!$user->userID) { if (!$user->userID) throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.userNotFound', [ 'username' => $username ]));
throw new UserInputException(
'message',
WCF::getLanguage()->getDynamicVariable(
'chat.error.userNotFound',
[
'username' => $username,
]
)
);
}
return $user; return $user;
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,92 +14,73 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\message\MessageEditor; use \chat\data\message\MessageEditor;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; use \wcf\system\exception\UserInputException;
use wcf\system\WCF; use \wcf\system\WCF;
/** /**
* TeamCommand sends a broadcast to all team members. * TeamCommand sends a broadcast to all team members.
*/ */
final class TeamCommand extends AbstractInputProcessedCommand implements ICommand class TeamCommand extends AbstractInputProcessedCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Team';
{ }
return 'Bastelstu.be/Chat/Command/Team';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) { return $user->getPermission('mod.chat.canTeam');
$user = new UserProfile(WCF::getUser()); }
}
return $user->getPermission('mod.chat.canTeam'); /**
} * @inheritDoc
*/
public function validate($parameters, Room $room, UserProfile $user = null) {
if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
/** if (!$user->getPermission('mod.chat.canTeam')) throw new PermissionDeniedException();
* @inheritDoc
*/
public function validate($parameters, Room $room, ?UserProfile $user = null)
{
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
if (!$user->getPermission('mod.chat.canTeam')) { $this->setText($this->assertParameter($parameters, 'text'));
throw new PermissionDeniedException(); $this->validateText();
} }
$this->setText($this->assertParameter($parameters, 'text')); /**
$this->validateText(); * @inheritDoc
} */
public function execute($parameters, Room $room, UserProfile $user = null) {
if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
/** $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.team');
* @inheritDoc $this->setText($this->assertParameter($parameters, 'text'));
*/
public function execute($parameters, Room $room, ?UserProfile $user = null)
{
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.team'); WCF::getDB()->beginTransaction();
$this->setText($this->assertParameter($parameters, 'text')); $message = (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
, 'userID' => $user->userID
, 'username' => $user->username
, 'time' => TIME_NOW
, 'objectTypeID' => $objectTypeID
, 'payload' => serialize([ 'message' => $this->processor->getHtml() ])
]
, 'updateTimestamp' => true
]
)
)->executeAction()['returnValues'];
WCF::getDB()->beginTransaction(); $this->processor->setObjectID($message->messageID);
$message = (new MessageAction( if (\wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) {
[ ], (new MessageEditor($message))->update([
'create', 'hasEmbeddedObjects' => 1
[ ]);
'data' => [ }
'roomID' => $room->roomID, WCF::getDB()->commitTransaction();
'userID' => $user->userID, }
'username' => $user->username,
'time' => TIME_NOW,
'objectTypeID' => $objectTypeID,
'payload' => \serialize([
'message' => $this->processor->getHtml(),
]),
], 'updateTimestamp' => true,
]
))->executeAction()['returnValues'];
$this->processor->setObjectID($message->messageID);
if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) {
(new MessageEditor($message))->update([
'hasEmbeddedObjects' => 1,
]);
}
WCF::getDB()->commitTransaction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,187 +14,123 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomAction; use \wcf\data\user\UserProfile;
use wcf\data\user\UserProfile; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\exception\UserInputException;
use wcf\system\exception\UserInputException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* The temproom command allows a user to manage temporary rooms. * The temproom command allows a user to manage temporary rooms.
*/ */
final class TemproomCommand extends AbstractCommand implements ICommand class TemproomCommand extends AbstractCommand implements ICommand {
{ use TNeedsUser;
use TNeedsUser;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName() public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/Command/Temproom';
return 'Bastelstu.be/Chat/Command/Temproom'; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
switch ($this->assertParameter($parameters, 'type')) { switch ($this->assertParameter($parameters, 'type')) {
case 'create': case 'create':
if (!$user->getPermission('user.chat.canTemproom')) { if (!$user->getPermission('user.chat.canTemproom')) throw new PermissionDeniedException();
throw new PermissionDeniedException(); break;
} case 'invite':
break; if (!$room->isTemporary) throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.notInTemproom'));
case 'invite': if ($room->ownerID !== $user->userID) throw new PermissionDeniedException();
if (!$room->isTemporary) {
throw new UserInputException(
'message',
WCF::getLanguage()->getDynamicVariable('chat.error.notInTemproom')
);
}
if ($room->ownerID !== $user->userID) {
throw new PermissionDeniedException();
}
$recipient = new UserProfile($this->assertUser($this->assertParameter($parameters, 'username'))); $recipient = new UserProfile($this->assertUser($this->assertParameter($parameters, 'username')));
if ($recipient->isIgnoredUser($user->userID)) { if ($recipient->isIgnoredUser($user->userID)) throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.userIgnoresYou', [ 'user' => $recipient ]));
throw new UserInputException( break;
'message', case 'delete':
WCF::getLanguage()->getDynamicVariable( if (!$room->isTemporary) throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.notInTemproom'));
'chat.error.userIgnoresYou', if ($room->ownerID !== $user->userID) throw new PermissionDeniedException();
[ break;
'user' => $recipient, default:
] throw new UserInputException('message');
) }
); }
}
break;
case 'delete':
if (!$room->isTemporary) {
throw new UserInputException(
'message',
WCF::getLanguage()->getDynamicVariable(
'chat.error.notInTemproom'
)
);
}
if ($room->ownerID !== $user->userID) {
throw new PermissionDeniedException();
}
break;
default:
throw new UserInputException('message');
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
switch ($this->assertParameter($parameters, 'type')) { switch ($this->assertParameter($parameters, 'type')) {
case 'create': case 'create':
$fields = [ $fields = [ 'title' => WCF::getLanguage()->getDynamicVariable('chat.room.temporary.blueprint', [ 'user' => $user ])
'title' => WCF::getLanguage()->getDynamicVariable( , 'topic' => ''
'chat.room.temporary.blueprint', , 'position' => 999
[ , 'isTemporary' => true
'user' => $user, , 'ownerID' => $user->userID
] ];
),
'topic' => '',
'position' => 999,
'isTemporary' => true,
'ownerID' => $user->userID,
];
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
// create room // create room
$tempRoom = (new RoomAction([], 'create', [ $tempRoom = (new \chat\data\room\RoomAction([], 'create', [ 'data' => $fields ]))->executeAction()['returnValues'];
'data' => $fields, $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.temproomCreated');
]))->executeAction()['returnValues']; (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.temproomCreated'); , 'userID' => $user->userID
(new MessageAction( , 'username' => $user->username
[ ], , 'time' => TIME_NOW
'create', , 'objectTypeID' => $objectTypeID
[ , 'payload' => serialize([ 'room' => $tempRoom ])
'data' => [ ]
'roomID' => $room->roomID, , 'updateTimestamp' => true
'userID' => $user->userID, ]
'username' => $user->username, )
'time' => TIME_NOW, )->executeAction();
'objectTypeID' => $objectTypeID, WCF::getDB()->commitTransaction();
'payload' => \serialize([ return;
'room' => $tempRoom, case 'invite':
]), $recipient = $this->getUser($this->assertParameter($parameters, 'username'));
], 'updateTimestamp' => true, WCF::getDB()->beginTransaction();
] try {
))->executeAction(); $sql = "INSERT INTO chat".WCF_N."_room_temporary_invite
WCF::getDB()->commitTransaction(); (userID, roomID)
VALUES (?, ?)";
$statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ $recipient->userID, $room->roomID ]);
}
catch (\wcf\system\database\DatabaseException $e) {
WCF::getDB()->rollBackTransaction();
// Duplicate key errors don't cause harm.
if ((string) $e->getCode() !== '23000') throw $e;
return;
}
return; $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.temproomInvited');
case 'invite': (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
$recipient = $this->getUser($this->assertParameter($parameters, 'username')); , 'userID' => $user->userID
WCF::getDB()->beginTransaction(); , 'username' => $user->username
try { , 'time' => TIME_NOW
$sql = "INSERT INTO chat1_room_temporary_invite , 'objectTypeID' => $objectTypeID
(userID, roomID) , 'payload' => serialize([ 'recipient' => $recipient->userID
VALUES (?, ?)"; , 'recipientName' => $recipient->username
$statement = WCF::getDB()->prepare($sql); ])
$statement->execute([ $recipient->userID, $room->roomID ]); ]
} catch (\wcf\system\database\DatabaseException $e) { , 'updateTimestamp' => true
WCF::getDB()->rollBackTransaction(); ]
// Duplicate key errors don't cause harm. )
if ((string)$e->getCode() !== '23000') { )->executeAction();
throw $e; WCF::getDB()->commitTransaction();
}
return; return;
} case 'delete':
(new \chat\data\room\RoomAction([ $room ], 'delete'))->executeAction();
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.temproomInvited'); return;
(new MessageAction( default:
[ ], throw new UserInputException('message');
'create', }
[ }
'data' => [
'roomID' => $room->roomID,
'userID' => $user->userID,
'username' => $user->username,
'time' => TIME_NOW,
'objectTypeID' => $objectTypeID,
'payload' => \serialize([
'recipient' => $recipient->userID,
'recipientName' => $recipient->username,
]),
],
'updateTimestamp' => true,
]
))->executeAction();
WCF::getDB()->commitTransaction();
return;
case 'delete':
(new RoomAction(
[
$room,
],
'delete'
))->executeAction();
return;
default:
throw new UserInputException('message');
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,59 +14,51 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\suspension\Suspension; use \chat\data\suspension\Suspension;
use chat\system\permission\PermissionHandler; use \chat\data\suspension\SuspensionAction;
use wcf\data\user\UserProfile; use \chat\system\permission\PermissionHandler;
use wcf\system\exception\PermissionDeniedException; use \wcf\data\object\type\ObjectTypeCache;
use wcf\system\WCF; use \wcf\data\user\UserProfile;
use \wcf\system\exception\PermissionDeniedException;
use \wcf\system\WCF;
/** /**
* The unban command revokes a new be.bastelstu.chat.suspension.ban suspension. * The unban command revokes a new be.bastelstu.chat.suspension.ban suspension.
*/ */
final class UnbanCommand extends AbstractUnsuspensionCommand implements ICommand class UnbanCommand extends AbstractUnsuspensionCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Unban';
{ }
return 'Bastelstu.be/Chat/Command/Unban';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) { return $user->getPermission('mod.chat.canBan') || PermissionHandler::get($user)->getPermission($room, 'mod.canBan');
$user = new UserProfile(WCF::getUser()); }
}
return $user->getPermission('mod.chat.canBan') || PermissionHandler::get($user)->getPermission($room, 'mod.canBan'); /**
} * @inheritDoc
*/
public function getObjectTypeName() {
return 'be.bastelstu.chat.suspension.ban';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getObjectTypeName() protected function checkPermissions($parameters, Room $room, UserProfile $user) {
{ $permission = $user->getPermission('mod.chat.canBan');
return 'be.bastelstu.chat.suspension.ban';
}
/** if (!$this->isGlobally($parameters)) {
* @inheritDoc $permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canBan');
*/ }
protected function checkPermissions($parameters, Room $room, UserProfile $user)
{
$permission = $user->getPermission('mod.chat.canBan');
if (!$this->isGlobally($parameters)) { if (!$permission) throw new PermissionDeniedException();
$permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canBan'); }
}
if (!$permission) {
throw new PermissionDeniedException();
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,58 +14,50 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\system\permission\PermissionHandler; use \chat\data\suspension\SuspensionAction;
use wcf\data\user\UserProfile; use \chat\system\permission\PermissionHandler;
use wcf\system\exception\PermissionDeniedException; use \wcf\data\object\type\ObjectTypeCache;
use wcf\system\WCF; use \wcf\data\user\UserProfile;
use \wcf\system\exception\PermissionDeniedException;
use \wcf\system\WCF;
/** /**
* The unmute command revokes a new be.bastelstu.chat.suspension.mute suspension. * The unmute command revokes a new be.bastelstu.chat.suspension.mute suspension.
*/ */
final class UnmuteCommand extends AbstractUnsuspensionCommand implements ICommand class UnmuteCommand extends AbstractUnsuspensionCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Unmute';
{ }
return 'Bastelstu.be/Chat/Command/Unmute';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function isAvailable(Room $room, ?UserProfile $user = null) public function isAvailable(Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(WCF::getUser());
if ($user === null) { return $user->getPermission('mod.chat.canMute') || PermissionHandler::get($user)->getPermission($room, 'mod.canMute');
$user = new UserProfile(WCF::getUser()); }
}
return $user->getPermission('mod.chat.canMute') || PermissionHandler::get($user)->getPermission($room, 'mod.canMute'); /**
} * @inheritDoc
*/
public function getObjectTypeName() {
return 'be.bastelstu.chat.suspension.mute';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getObjectTypeName() protected function checkPermissions($parameters, Room $room, UserProfile $user) {
{ $permission = $user->getPermission('mod.chat.canMute');
return 'be.bastelstu.chat.suspension.mute';
}
/** if (!$this->isGlobally($parameters)) {
* @inheritDoc $permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canMute');
*/ }
protected function checkPermissions($parameters, Room $room, UserProfile $user)
{
$permission = $user->getPermission('mod.chat.canMute');
if (!$this->isGlobally($parameters)) { if (!$permission) throw new PermissionDeniedException();
$permission = $permission || PermissionHandler::get($user)->getPermission($room, 'mod.canMute'); }
}
if (!$permission) {
throw new PermissionDeniedException();
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,75 +14,61 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\room\Room; use \chat\data\room\Room;
use chat\data\room\RoomList; use \wcf\data\user\User;
use chat\data\user\User as ChatUser; use \wcf\data\user\UserProfile;
use wcf\data\user\UserProfile;
use wcf\system\WCF;
/** /**
* The where command shows the distribution of users among * The where command shows the distribution of users among
* the different chat rooms. * the different chat rooms.
*/ */
final class WhereCommand extends AbstractCommand implements ICommand class WhereCommand extends AbstractCommand implements ICommand {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ public function getJavaScriptModuleName() {
public function getJavaScriptModuleName() return 'Bastelstu.be/Chat/Command/Where';
{ }
return 'Bastelstu.be/Chat/Command/Where';
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) { }
$user = new UserProfile(WCF::getUser());
}
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.where'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.where');
$roomList = new RoomList(); $roomList = new \chat\data\room\RoomList();
$roomList->readObjects(); $roomList->readObjects();
$rooms = \array_map(static function (Room $room) { $rooms = array_map(function (Room $room) {
$users = \array_map(static function (ChatUser $user) { $users = array_map(function (\chat\data\user\User $user) {
return $user->jsonSerialize(); return $user->jsonSerialize();
}, $room->getUsers()); }, $room->getUsers());
return [ return [ 'roomID' => $room->roomID
'roomID' => $room->roomID, , 'users' => array_values($users)
'users' => \array_values($users), ];
]; }, array_filter($roomList->getObjects(), function (Room $room) {
}, \array_filter($roomList->getObjects(), static function (Room $room) { return $room->canSee();
return $room->canSee(); }));
}));
(new MessageAction( (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize($rooms)
'userID' => $user->userID, ]
'username' => $user->username, , 'updateTimestamp' => true
'time' => TIME_NOW, ]
'objectTypeID' => $objectTypeID, )
'payload' => \serialize($rooms), )->executeAction();
], 'updateTimestamp' => true, }
]
))->executeAction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,96 +14,72 @@
namespace chat\system\command; namespace chat\system\command;
use chat\data\message\MessageAction; use \chat\data\message\MessageAction;
use chat\data\message\MessageEditor; use \chat\data\message\MessageEditor;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\exception\UserInputException; use \wcf\system\exception\UserInputException;
use wcf\system\message\embedded\object\MessageEmbeddedObjectManager; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* The whisper command creates a private message * The whisper command creates a private message
* between two chat users. * between two chat users.
*/ */
final class WhisperCommand extends AbstractInputProcessedCommand implements ICommand class WhisperCommand extends AbstractInputProcessedCommand implements ICommand {
{ use TNeedsUser;
use TNeedsUser;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName() public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/Command/Whisper';
return 'Bastelstu.be/Chat/Command/Whisper'; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function validate($parameters, Room $room, ?UserProfile $user = null) public function validate($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$recipient = new UserProfile($this->assertUser($this->assertParameter($parameters, 'username'))); $recipient = new UserProfile($this->assertUser($this->assertParameter($parameters, 'username')));
if ($recipient->isIgnoredUser($user->userID)) { if ($recipient->isIgnoredUser($user->userID)) throw new UserInputException('message', WCF::getLanguage()->getDynamicVariable('chat.error.userIgnoresYou', [ 'user' => $recipient ]));
throw new UserInputException(
'message',
WCF::getLanguage()->getDynamicVariable(
'chat.error.userIgnoresYou',
[
'user' => $recipient,
]
)
);
}
$this->setText($this->assertParameter($parameters, 'text')); $this->setText($this->assertParameter($parameters, 'text'));
$this->validateText(); $this->validateText();
} }
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function execute($parameters, Room $room, ?UserProfile $user = null) public function execute($parameters, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.whisper'); $objectTypeID = $this->getMessageObjectTypeID('be.bastelstu.chat.messageType.whisper');
$recipient = $this->assertUser($this->assertParameter($parameters, 'username')); $recipient = $this->assertUser($this->assertParameter($parameters, 'username'));
$this->setText($this->assertParameter($parameters, 'text')); $this->setText($this->assertParameter($parameters, 'text'));
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
$message = (new MessageAction( $message = (new MessageAction([ ], 'create', [ 'data' => [ 'roomID' => $room->roomID
[ ], , 'userID' => $user->userID
'create', , 'username' => $user->username
[ , 'time' => TIME_NOW
'data' => [ , 'objectTypeID' => $objectTypeID
'roomID' => $room->roomID, , 'payload' => serialize([ 'message' => $this->processor->getHtml()
'userID' => $user->userID, , 'recipient' => $recipient->userID
'username' => $user->username, , 'recipientName' => $recipient->username
'time' => TIME_NOW, ])
'objectTypeID' => $objectTypeID, ]
'payload' => \serialize([ , 'updateTimestamp' => true
'message' => $this->processor->getHtml(), ]
'recipient' => $recipient->userID, )
'recipientName' => $recipient->username, )->executeAction()['returnValues'];
]),
],
'updateTimestamp' => true,
]
))->executeAction()['returnValues'];
$this->processor->setObjectID($message->messageID); $this->processor->setObjectID($message->messageID);
if (MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) { if (\wcf\system\message\embedded\object\MessageEmbeddedObjectManager::getInstance()->registerObjects($this->processor)) {
(new MessageEditor($message))->update([ (new MessageEditor($message))->update([
'hasEmbeddedObjects' => 1, 'hasEmbeddedObjects' => 1
]); ]);
} }
WCF::getDB()->commitTransaction(); WCF::getDB()->commitTransaction();
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,45 +14,33 @@
namespace chat\system\condition\room; namespace chat\system\condition\room;
use chat\data\room\RoomList; use \chat\data\room\RoomList;
use wcf\data\DatabaseObjectList; use \wcf\data\DatabaseObject;
use wcf\system\condition\AbstractCheckboxCondition; use \wcf\data\DatabaseObjectList;
use wcf\system\condition\IObjectListCondition; use \wcf\system\exception\SystemException;
use wcf\system\exception\ParentClassException;
/** /**
* Condition implementation for rooms to only include non-empty rooms in lists. * Condition implementation for rooms to only include non-empty rooms in lists.
*/ */
final class RoomFilledCondition extends AbstractCheckboxCondition implements IObjectListCondition class RoomFilledCondition extends \wcf\system\condition\AbstractCheckboxCondition implements \wcf\system\condition\IObjectListCondition {
{ /**
/** * @inheritDoc
* @inheritDoc */
*/ protected $fieldName = 'chatRoomIsFilled';
protected $fieldName = 'chatRoomIsFilled';
/** /**
* @inheritDoc * @inheritDoc
*/ */
protected $label = 'chat.room.condition.isFilled'; protected $label = 'chat.room.condition.isFilled';
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) public function addObjectListCondition(DatabaseObjectList $objectList, array $conditionData) {
{ if (!($objectList instanceof RoomList)) {
if (!($objectList instanceof RoomList)) { throw new \wcf\system\exception\ParentClassException(get_class($objectList), RoomList::class);
throw new ParentClassException(\get_class($objectList), RoomList::class); }
}
$objectList->getConditionBuilder()->add( $objectList->getConditionBuilder()->add("EXISTS (SELECT 1 FROM chat".WCF_N."_room_to_user r2u WHERE r2u.roomID = room.roomID AND active = ?)", [ 1 ]);
" }
EXISTS (
SELECT 1
FROM chat" . WCF_N . "_room_to_user r2u
WHERE r2u.roomID = room.roomID
AND active = ?
)",
[ 1 ]
);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,35 +14,27 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\message\MessageAction; use \wcf\system\WCF;
use chat\data\user\UserAction as ChatUserAction;
use wcf\system\event\listener\IParameterizedEventListener;
use wcf\system\WCF;
/** /**
* Vaporizes unneeded data. * Vaporizes unneeded data.
*/ */
final class HourlyCleanUpCronjobExecuteChatCleanUpListener implements IParameterizedEventListener class HourlyCleanUpCronjobExecuteChatCleanUpListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) (new \chat\data\message\MessageAction([ ], 'prune'))->executeAction();
{ (new \chat\data\user\UserAction([], 'clearDeadSessions'))->executeAction();
(new MessageAction([ ], 'prune'))->executeAction();
(new ChatUserAction([ ], 'clearDeadSessions'))->executeAction();
$sql = "UPDATE chat1_room_to_user $sql = "UPDATE chat".WCF_N."_room_to_user
SET active = ? SET active = ?
WHERE (roomID, userID) NOT IN ( WHERE (roomID, userID) NOT IN (SELECT roomID, userID FROM chat".WCF_N."_session)
SELECT roomID, userID AND active = ?";
FROM chat1_session $statement = WCF::getDB()->prepareStatement($sql);
) $statement->execute([ 0, 1 ]);
AND active = ?"; if ($statement->getAffectedRows()) {
$statement = WCF::getDB()->prepare($sql); \wcf\functions\exception\logThrowable(new \Exception('Unreachable'));
$statement->execute([ 0, 1 ]); }
if ($statement->getAffectedRows()) { }
\wcf\functions\exception\logThrowable(new \Exception('Unreachable'));
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,38 +14,30 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\room\RoomAction; use \wcf\system\WCF;
use chat\data\room\RoomList;
use wcf\system\event\listener\IParameterizedEventListener;
use wcf\system\WCF;
/** /**
* Removes empty temporary rooms. * Removes empty temporary rooms.
*/ */
final class HourlyCleanUpCronjobExecuteTemproomListener implements IParameterizedEventListener class HourlyCleanUpCronjobExecuteTemproomListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) $roomList = new \chat\data\room\RoomList();
{ $roomList->getConditionBuilder()->add('isTemporary = ?', [ 1 ]);
$roomList = new RoomList(); $roomList->readObjects();
$roomList->getConditionBuilder()->add('isTemporary = ?', [ 1 ]);
$roomList->readObjects();
$toDelete = [ ]; $toDelete = [ ];
WCF::getDB()->beginTransaction(); WCF::getDB()->beginTransaction();
foreach ($roomList as $room) { foreach ($roomList as $room) {
if (\count($room->getUsers()) === 0) { if (count($room->getUsers()) === 0) {
$toDelete[] = $room; $toDelete[] = $room;
} }
} }
if ($toDelete !== []) { if (!empty($toDelete)) {
(new RoomAction( (new \chat\data\room\RoomAction($toDelete, 'delete'))->executeAction();
$toDelete, }
'delete' WCF::getDB()->commitTransaction();
))->executeAction(); }
}
WCF::getDB()->commitTransaction();
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,52 +14,48 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\room\RoomCache; use \chat\data\suspension\Suspension;
use chat\data\suspension\Suspension; use \wcf\data\object\type\ObjectTypeCache;
use chat\data\suspension\SuspensionList; use \wcf\system\WCF;
use wcf\system\event\listener\IParameterizedEventListener;
/** /**
* Fetches information about the users suspensions * Fetches information about the users suspensions
*/ */
final class InfoCommandSuspensionsListener implements IParameterizedEventListener class InfoCommandSuspensionsListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) if (!$parameters['caller']->getPermission('admin.chat.canManageSuspensions')) {
{ return;
if (!$parameters['caller']->getPermission('admin.chat.canManageSuspensions')) { }
return;
}
$target = $parameters['data']['user']; $target = $parameters['data']['user'];
$parameters['data']['suspensions'] = [ ]; $parameters['data']['suspensions'] = [ ];
$suspensionList = new SuspensionList(); $suspensionList = new \chat\data\suspension\SuspensionList();
$suspensionList->getConditionBuilder()->add('(expires IS NULL OR expires > ?)', [ TIME_NOW ]); $suspensionList->getConditionBuilder()->add('(expires IS NULL OR expires > ?)', [ TIME_NOW ]);
$suspensionList->getConditionBuilder()->add('revoked IS NULL'); $suspensionList->getConditionBuilder()->add('revoked IS NULL');
$suspensionList->getConditionBuilder()->add('userID = ?', [ $target->userID ]); $suspensionList->getConditionBuilder()->add('userID = ?', [ $target->userID ]);
$suspensionList->sqlOrderBy = 'expires ASC, time ASC'; $suspensionList->sqlOrderBy = 'expires ASC, time ASC';
$suspensionList->readObjects(); $suspensionList->readObjects();
$suspensions = \array_filter($suspensionList->getObjects(), static function (Suspension $suspension) { $suspensions = array_filter($suspensionList->getObjects(), function (Suspension $suspension) {
return $suspension->isActive(); return $suspension->isActive();
}); });
$parameters['data']['suspensions'] = \array_values(\array_map(static function ($suspension) { $parameters['data']['suspensions'] = array_values(array_map(function ($suspension) {
$room = RoomCache::getInstance()->getRoom($suspension->roomID); $room = \chat\data\room\RoomCache::getInstance()->getRoom($suspension->roomID);
$suspension = $suspension->jsonSerialize(); $suspension = $suspension->jsonSerialize();
if ($room) { if ($room) {
$suspension['room'] = [ $suspension['room'] = [ 'title' => $room->getTitle()
'title' => $room->getTitle(), , 'link' => $room->getLink()
'link' => $room->getLink(), ];
]; }
}
return $suspension; return $suspension;
}, $suspensions)); }, $suspensions));
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,37 +14,31 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\command\CommandCache; use \chat\data\command\CommandCache;
use wcf\data\package\PackageCache; use \wcf\system\cache\runtime\UserProfileRuntimeCache;
use wcf\system\cache\runtime\UserProfileRuntimeCache;
use wcf\system\event\listener\IParameterizedEventListener;
/** /**
* Adds moderator permissions to the user object. * Adds moderator permissiosn to the user object.
*/ */
final class RoomActionGetUsersModeratorListener implements IParameterizedEventListener class RoomActionGetUsersModeratorListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$users) {
public function execute($eventObj, $className, $eventName, array &$users) $room = $eventObj->getObjects()[0]->getDecoratedObject();
{
$room = $eventObj->getObjects()[0]->getDecoratedObject();
$package = PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat'); $package = \wcf\data\package\PackageCache::getInstance()->getPackageByIdentifier('be.bastelstu.chat');
$muteCommand = CommandCache::getInstance()->getCommandByPackageAndIdentifier($package, 'mute')->getProcessor(); $muteCommand = CommandCache::getInstance()->getCommandByPackageAndIdentifier($package, 'mute')->getProcessor();
$banCommand = CommandCache::getInstance()->getCommandByPackageAndIdentifier($package, 'ban')->getProcessor(); $banCommand = CommandCache::getInstance()->getCommandByPackageAndIdentifier($package, 'ban')->getProcessor();
$users = \array_map(static function (array $user) use ($room, $muteCommand, $banCommand) { $users = array_map(function (array $user) use ($room, $muteCommand, $banCommand) {
$userProfile = UserProfileRuntimeCache::getInstance()->getObject($user['userID']); $userProfile = UserProfileRuntimeCache::getInstance()->getObject($user['userID']);
if (!isset($user['permissions'])) { if (!isset($user['permissions'])) $user['permissions'] = [];
$user['permissions'] = [];
}
$user['permissions']['canMute'] = $muteCommand->isAvailable($room, $userProfile); $user['permissions']['canMute'] = $muteCommand->isAvailable($room, $userProfile);
$user['permissions']['canBan'] = $banCommand->isAvailable($room, $userProfile); $user['permissions']['canBan'] = $banCommand->isAvailable($room, $userProfile);
return $user; return $user;
}, $users); }, $users);
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,37 +14,25 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\suspension\Suspension; use \chat\data\suspension\Suspension;
use wcf\data\object\type\ObjectTypeCache; use \wcf\data\object\type\ObjectTypeCache;
use wcf\system\event\listener\IParameterizedEventListener; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* Denies access to banned users. * Denies access to banned users.
*/ */
final class RoomCanJoinBanListener implements IParameterizedEventListener class RoomCanJoinBanListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.suspension', 'be.bastelstu.chat.suspension.ban');
{ if (!$objectTypeID) throw new \LogicException('Unreachable');
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName(
'be.bastelstu.chat.suspension',
'be.bastelstu.chat.suspension.ban'
);
\assert($objectTypeID !== null);
$suspensions = Suspension::getActiveSuspensionsByTriple( $suspensions = Suspension::getActiveSuspensionsByTriple($objectTypeID, $parameters['user']->getDecoratedObject(), $eventObj);
$objectTypeID, if (!empty($suspensions)) {
$parameters['user']->getDecoratedObject(), $parameters['result'] = new PermissionDeniedException(WCF::getLanguage()->getDynamicVariable('chat.suspension.info.be.bastelstu.chat.suspension.ban'));
$eventObj }
); }
if ($suspensions !== []) {
$parameters['result'] = new PermissionDeniedException(
WCF::getLanguage()->getDynamicVariable('chat.suspension.info.be.bastelstu.chat.suspension.ban')
);
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,43 +14,29 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\user\User as ChatUser; use \chat\system\permission\PermissionHandler;
use chat\system\permission\PermissionHandler; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\event\listener\IParameterizedEventListener; use \wcf\system\WCF;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\WCF;
/** /**
* Denies access when room is full. * Denies access when room is full.
*/ */
final class RoomCanJoinUserLimitListener implements IParameterizedEventListener class RoomCanJoinUserLimitListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) if ($eventObj->userLimit === 0) return;
{
if ($eventObj->userLimit === 0) {
return;
}
$users = $eventObj->getUsers(); $users = $eventObj->getUsers();
if (\count($users) < $eventObj->userLimit) { if (count($users) < $eventObj->userLimit) return;
return;
}
$user = new ChatUser($parameters['user']->getDecoratedObject()); $user = new \chat\data\user\User($parameters['user']->getDecoratedObject());
if ($user->isInRoom($eventObj)) { if ($user->isInRoom($eventObj)) return;
return;
}
$canIgnoreLimit = PermissionHandler::get($parameters['user'])->getPermission($eventObj, 'mod.canIgnoreUserLimit'); $canIgnoreLimit = PermissionHandler::get($parameters['user'])->getPermission($eventObj, 'mod.canIgnoreUserLimit');
if ($canIgnoreLimit) { if ($canIgnoreLimit) return;
return;
}
$parameters['result'] = new PermissionDeniedException( $parameters['result'] = new PermissionDeniedException(WCF::getLanguage()->get('chat.error.roomFull'));
WCF::getLanguage()->get('chat.error.roomFull') }
);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,43 +14,31 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\user\User as ChatUser; use \chat\system\permission\PermissionHandler;
use wcf\system\event\listener\IParameterizedEventListener; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* Denies access to temporary rooms, unless invited. * Denies access to temporary rooms, unless invited.
*/ */
final class RoomCanSeeTemproomListener implements IParameterizedEventListener class RoomCanSeeTemproomListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) if (!$eventObj->isTemporary) return;
{
if (!$eventObj->isTemporary) {
return;
}
$user = new ChatUser($parameters['user']->getDecoratedObject()); $user = new \chat\data\user\User($parameters['user']->getDecoratedObject());
if ($eventObj->ownerID === $user->userID) { if ($eventObj->ownerID === $user->userID) return;
return;
}
$sql = "SELECT COUNT(*) $sql = "SELECT COUNT(*)
FROM chat1_room_temporary_invite FROM chat".WCF_N."_room_temporary_invite
WHERE userID = ? WHERE userID = ?
AND roomID = ?"; AND roomID = ?";
$statement = WCF::getDB()->prepare($sql); $statement = WCF::getDB()->prepareStatement($sql);
$statement->execute([ $statement->execute([ $user->userID, $eventObj->roomID ]);
$user->userID, if ($statement->fetchSingleColumn() > 0) return;
$eventObj->roomID,
]);
if ($statement->fetchSingleColumn() > 0) {
return;
}
$parameters['result'] = new PermissionDeniedException(); $parameters['result'] = new PermissionDeniedException();
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,37 +14,25 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\suspension\Suspension; use \chat\data\suspension\Suspension;
use wcf\data\object\type\ObjectTypeCache; use \wcf\data\object\type\ObjectTypeCache;
use wcf\system\event\listener\IParameterizedEventListener; use \wcf\system\exception\PermissionDeniedException;
use wcf\system\exception\PermissionDeniedException; use \wcf\system\WCF;
use wcf\system\WCF;
/** /**
* Denies access to muted users. * Denies access to muted users.
*/ */
final class RoomCanWritePubliclyMuteListener implements IParameterizedEventListener class RoomCanWritePubliclyMuteListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) $objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName('be.bastelstu.chat.suspension', 'be.bastelstu.chat.suspension.mute');
{ if (!$objectTypeID) throw new \LogicException('Unreachable');
$objectTypeID = ObjectTypeCache::getInstance()->getObjectTypeIDByName(
'be.bastelstu.chat.suspension',
'be.bastelstu.chat.suspension.mute'
);
\assert($objectTypeID !== null);
$suspensions = Suspension::getActiveSuspensionsByTriple( $suspensions = Suspension::getActiveSuspensionsByTriple($objectTypeID, $parameters['user']->getDecoratedObject(), $eventObj);
$objectTypeID, if (!empty($suspensions)) {
$parameters['user']->getDecoratedObject(), $parameters['result'] = new PermissionDeniedException(WCF::getLanguage()->getDynamicVariable('chat.suspension.info.be.bastelstu.chat.suspension.mute'));
$eventObj }
); }
if ($suspensions !== []) {
$parameters['result'] = new PermissionDeniedException(
WCF::getLanguage()->getDynamicVariable('chat.suspension.info.be.bastelstu.chat.suspension.mute')
);
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,21 +14,16 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use wcf\system\event\listener\IParameterizedEventListener;
use wcf\system\exception\PermissionDeniedException;
/** /**
* Disallow editing of temprooms in ACP. * Disallow editing of temprooms in ACP.
*/ */
final class RoomEditFormTemproomListener implements IParameterizedEventListener class RoomEditFormTemproomListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) if ($eventObj->room->isTemporary) {
{ throw new \wcf\system\exception\PermissionDeniedException();
if ($eventObj->room->isTemporary) { }
throw new PermissionDeniedException(); }
}
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,18 +14,14 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use wcf\system\event\listener\IParameterizedEventListener;
/** /**
* Hides temprooms in ACP. * Hides temprooms in ACP.
*/ */
final class RoomListPageTemproomListener implements IParameterizedEventListener class RoomListPageTemproomListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) $eventObj->objectList->getConditionBuilder()->add('isTemporary = ?', [ 0 ]);
{ }
$eventObj->objectList->getConditionBuilder()->add('isTemporary = ?', [ 0 ]);
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 3 * License, use of this software will be governed by version 3
@ -15,21 +14,18 @@
namespace chat\system\event\listener; namespace chat\system\event\listener;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\system\event\listener\IParameterizedEventListener;
/** /**
* Hides temprooms in ACP. * Hides temprooms in ACP.
*/ */
final class SuspensionListPageTemproomListener implements IParameterizedEventListener class SuspensionListPageTemproomListener implements \wcf\system\event\listener\IParameterizedEventListener {
{ /**
/** * @see \wcf\system\event\listener\IParameterizedEventListener::execute()
* @inheritDoc */
*/ public function execute($eventObj, $className, $eventName, array &$parameters) {
public function execute($eventObj, $className, $eventName, array &$parameters) $eventObj->availableRooms = array_filter($eventObj->availableRooms, function (Room $room) {
{ return !$room->isTemporary;
$eventObj->availableRooms = \array_filter($eventObj->availableRooms, static function (Room $room) { });
return !$room->isTemporary; }
});
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,89 +14,65 @@
namespace chat\system\message\type; namespace chat\system\message\type;
use chat\data\message\Message;
use wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\html\output\HtmlOutputProcessor;
use wcf\system\WCF;
/** /**
* AttachmentMessageType represents a message with an attached file. * AttachmentMessageType represents a message with an attached file.
*/ */
final class AttachmentMessageType implements IMessageType, IDeletableMessageType class AttachmentMessageType implements IMessageType, IDeletableMessageType {
{ use TCanSeeInSameRoom;
use TCanSeeInSameRoom;
/** /**
* HtmlOutputProcessor to use. * HtmlOutputProcessor to use.
* @var \wcf\system\html\output\HtmlOutputProcessor * @var \wcf\system\html\output\HtmlOutputProcessor
*/ */
protected $processor; protected $processor = null;
public function __construct() public function __construct() {
{ $this->processor = new \wcf\system\html\output\HtmlOutputProcessor();
$this->processor = new HtmlOutputProcessor(); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName(): string public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/MessageType/Plain';
return 'Bastelstu.be/Chat/MessageType/Plain'; }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function canDelete(Message $message, ?UserProfile $user = null): bool public function canDelete(\chat\data\message\Message $message, \wcf\data\user\UserProfile $user = null) {
{ if ($user === null) $user = new \wcf\data\user\UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
return !!$user->getPermission('mod.chat.canDelete'); return $user->getPermission('mod.chat.canDelete');
} }
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::getPayload()
*/ */
public function getPayload(Message $message, ?UserProfile $user = null) public function getPayload(\chat\data\message\Message $message, \wcf\data\user\UserProfile $user = null) {
{ if ($user === null) $user = new \wcf\data\user\UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$payload = $message->payload; $payload = $message->payload;
$payload['formattedMessage'] = null; $payload['formattedMessage'] = null;
$payload['plaintextMessage'] = null; $payload['plaintextMessage'] = null;
$parameters = [ $parameters = [ 'message' => $message
'message' => $message, , 'user' => $user
'user' => $user, , 'payload' => $payload
'payload' => $payload, ];
]; \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'getPayload', $parameters);
EventHandler::getInstance()->fireAction($this, 'getPayload', $parameters);
if ($parameters['payload']['formattedMessage'] === null) { if ($parameters['payload']['formattedMessage'] === null) {
$this->processor->setOutputType('text/html'); $this->processor->setOutputType('text/html');
$this->processor->process( $this->processor->process($parameters['payload']['message'], 'be.bastelstu.chat.message', $message->messageID);
$parameters['payload']['message'], $parameters['payload']['formattedMessage'] = $this->processor->getHtml();
'be.bastelstu.chat.message', }
$message->messageID if ($parameters['payload']['plaintextMessage'] === null) {
); $this->processor->setOutputType('text/plain');
$parameters['payload']['formattedMessage'] = $this->processor->getHtml(); $this->processor->process($parameters['payload']['message'], 'be.bastelstu.chat.message', $message->messageID);
} $parameters['payload']['plaintextMessage'] = $this->processor->getHtml();
if ($parameters['payload']['plaintextMessage'] === null) { }
$this->processor->setOutputType('text/plain');
$this->processor->process(
$parameters['payload']['message'],
'be.bastelstu.chat.message',
$message->messageID
);
$parameters['payload']['plaintextMessage'] = $this->processor->getHtml();
}
return $parameters['payload']; return $parameters['payload'];
} }
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,80 +14,67 @@
namespace chat\system\message\type; namespace chat\system\message\type;
use chat\data\message\Message; use \chat\data\message\Message;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\WCF;
/** /**
* AwayMessageType represents a notice that a user now is away from chat. * AwayMessageType represents a notice that a user now is away from chat.
*/ */
final class AwayMessageType implements IMessageType class AwayMessageType implements IMessageType {
{ use TDefaultPayload;
use TDefaultPayload;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName(): string public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/MessageType/Away';
return 'Bastelstu.be/Chat/MessageType/Away'; }
}
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSee()
*/ */
public function canSee(Message $message, Room $room, ?UserProfile $user = null): bool public function canSee(Message $message, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$roomIDs = \array_map(static function ($item) { $roomIDs = array_map(function ($item) {
return $item['roomID']; return $item['roomID'];
}, $message->payload['rooms']); }, $message->payload['rooms']);
$parameters = [ $parameters = [ 'message' => $message
'message' => $message, , 'room' => $room
'room' => $room, , 'user' => $user
'user' => $user, , 'canSee' => in_array($room->roomID, $roomIDs, true)
'canSee' => \in_array($room->roomID, $roomIDs, true), ];
]; \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
return $parameters['canSee']; return $parameters['canSee'];
} }
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSeeInLog()
*/ */
public function canSeeInLog(Message $message, Room $room, ?UserProfile $user = null): bool public function canSeeInLog(Message $message, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$roomIDs = \array_map(static function ($item) { $roomIDs = array_map(function ($item) {
return $item['roomID']; return $item['roomID'];
}, $message->payload['rooms']); }, $message->payload['rooms']);
$parameters = [ $parameters = [ 'message' => $message
'message' => $message, , 'room' => $room
'room' => $room, , 'user' => $user
'user' => $user, , 'canSee' => in_array($room->roomID, $roomIDs, true)
'canSee' => \in_array($room->roomID, $roomIDs, true), ];
]; \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSeeInLog', $parameters);
EventHandler::getInstance()->fireAction($this, 'canSeeInLog', $parameters);
return $parameters['canSee']; return $parameters['canSee'];
} }
/** /**
* @inheritDoc * @see»\chat\system\message\type\IMessageType::supportsFastSelect()
*/ */
public function supportsFastSelect(): bool public function supportsFastSelect() {
{ return false;
return false; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,80 +14,67 @@
namespace chat\system\message\type; namespace chat\system\message\type;
use chat\data\message\Message; use \chat\data\message\Message;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\WCF;
/** /**
* BackMessageType represents a notice that a user now is now back. * BackMessageType represents a notice that a user now is now back.
*/ */
final class BackMessageType implements IMessageType class BackMessageType implements IMessageType {
{ use TDefaultPayload;
use TDefaultPayload;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName(): string public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/MessageType/Back';
return 'Bastelstu.be/Chat/MessageType/Back'; }
}
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSee()
*/ */
public function canSee(Message $message, Room $room, ?UserProfile $user = null): bool public function canSee(Message $message, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$roomIDs = \array_map(static function ($item) { $roomIDs = array_map(function ($item) {
return $item['roomID']; return $item['roomID'];
}, $message->payload['rooms']); }, $message->payload['rooms']);
$parameters = [ $parameters = [ 'message' => $message
'message' => $message, , 'room' => $room
'room' => $room, , 'user' => $user
'user' => $user, , 'canSee' => in_array($room->roomID, $roomIDs, true)
'canSee' => \in_array($room->roomID, $roomIDs, true), ];
]; \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
return $parameters['canSee']; return $parameters['canSee'];
} }
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSeeInLog()
*/ */
public function canSeeInLog(Message $message, Room $room, ?UserProfile $user = null): bool public function canSeeInLog(Message $message, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$roomIDs = \array_map(static function ($item) { $roomIDs = array_map(function ($item) {
return $item['roomID']; return $item['roomID'];
}, $message->payload['rooms']); }, $message->payload['rooms']);
$parameters = [ $parameters = [ 'message' => $message
'message' => $message, , 'room' => $room
'room' => $room, , 'user' => $user
'user' => $user, , 'canSee' => in_array($room->roomID, $roomIDs, true)
'canSee' => \in_array($room->roomID, $roomIDs, true), ];
]; \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSeeInLog', $parameters);
EventHandler::getInstance()->fireAction($this, 'canSeeInLog', $parameters);
return $parameters['canSee']; return $parameters['canSee'];
} }
/** /**
* @inheritDoc * @see»\chat\system\message\type\IMessageType::supportsFastSelect()
*/ */
public function supportsFastSelect(): bool public function supportsFastSelect() {
{ return false;
return false; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,100 +14,76 @@
namespace chat\system\message\type; namespace chat\system\message\type;
use chat\data\message\Message; use \chat\data\message\Message;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\WCF;
/** /**
* BroadcastMessageType represents a broadcasted message. * BroadcastMessageType represents a broadcasted message.
*/ */
final class BroadcastMessageType implements IMessageType, IDeletableMessageType class BroadcastMessageType extends PlainMessageType {
{ /**
/** * HtmlOutputProcessor to use.
* @var PlainMessageType * @var \wcf\system\html\output\HtmlOutputProcessor
*/ */
protected $plainMessageType; protected $processor = null;
public function __construct() public function __construct() {
{ $this->processor = new \wcf\system\html\output\HtmlOutputProcessor();
$this->plainMessageType = new PlainMessageType(); }
}
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName(): string public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/MessageType/Broadcast';
return 'Bastelstu.be/Chat/MessageType/Broadcast'; }
}
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSee()
*/ */
public function getPayload(Message $message, ?UserProfile $user = null) public function canSee(Message $message, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
return $this->plainMessageType->getPayload($message, $user);
}
/** $parameters = [ 'message' => $message
* @inheritDoc , 'room' => $room
*/ , 'user' => $user
public function canSee(Message $message, Room $room, ?UserProfile $user = null): bool , 'canSee' => true
{ ];
if ($user === null) { \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
$user = new UserProfile(WCF::getUser());
}
$parameters = [ return $parameters['canSee'];
'message' => $message, }
'room' => $room,
'user' => $user,
'canSee' => true,
];
EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
return $parameters['canSee']; /**
} * @see \chat\system\message\type\IMessageType::canSeeInLog()
*/
public function canSeeInLog(Message $message, Room $room, UserProfile $user = null) {
if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
/** $parameters = [ 'message' => $message
* @inheritDoc , 'room' => $room
*/ , 'user' => $user
public function canSeeInLog(Message $message, Room $room, ?UserProfile $user = null): bool , 'canSee' => true
{ ];
if ($user === null) { \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSeeInLog', $parameters);
$user = new UserProfile(WCF::getUser());
}
$parameters = [ return $parameters['canSee'];
'message' => $message, }
'room' => $room,
'user' => $user,
'canSee' => true,
];
EventHandler::getInstance()->fireAction($this, 'canSeeInLog', $parameters);
return $parameters['canSee']; /**
} * @inheritDoc
*/
public function canDelete(\chat\data\message\Message $message, \wcf\data\user\UserProfile $user = null) {
if ($user === null) $user = new \wcf\data\user\UserProfile(\wcf\system\WCF::getUser());
/** return $user->getPermission('mod.chat.canDelete');
* @inheritDoc }
*/
public function canDelete(Message $message, ?UserProfile $user = null): bool
{
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
return !!$user->getPermission('mod.chat.canDelete'); /**
} * @see»\chat\system\message\type\IMessageType::supportsFastSelect()
*/
/** public function supportsFastSelect() {
* @inheritDoc return false;
*/ }
public function supportsFastSelect(): bool
{
return false;
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,46 +14,41 @@
namespace chat\system\message\type; namespace chat\system\message\type;
use chat\data\message\Message; use \chat\data\message\Message;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
/** /**
* ChatUpdateMessageType informs the chat about a back end update. * ChatUpdateMessageType informs the chat about a back end update.
*/ */
final class ChatUpdateMessageType implements IMessageType class ChatUpdateMessageType implements IMessageType {
{ use TDefaultPayload;
use TDefaultPayload;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName(): string public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/MessageType/ChatUpdate';
return 'Bastelstu.be/Chat/MessageType/ChatUpdate'; }
}
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSee()
*/ */
public function canSee(Message $message, Room $room, ?UserProfile $user = null): bool public function canSee(Message $message, Room $room, UserProfile $user = null) {
{ return true;
return true; }
}
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSeeInLog()
*/ */
public function canSeeInLog(Message $message, Room $room, ?UserProfile $user = null): bool public function canSeeInLog(Message $message, Room $room, UserProfile $user = null) {
{ return true;
return true; }
}
/** /**
* @inheritDoc * @see»\chat\system\message\type\IMessageType::supportsFastSelect()
*/ */
public function supportsFastSelect(): bool public function supportsFastSelect() {
{ return false;
return false; }
}
} }

View File

@ -1,12 +1,11 @@
<?php <?php
/* /*
* Copyright (c) 2010-2024 Tim Düsterhus. * Copyright (c) 2010-2021 Tim Düsterhus.
* *
* Use of this software is governed by the Business Source License * Use of this software is governed by the Business Source License
* included in the LICENSE file. * included in the LICENSE file.
* *
* Change Date: 2028-06-15 * Change Date: 2025-03-05
* *
* On the date above, in accordance with the Business Source * On the date above, in accordance with the Business Source
* License, use of this software will be governed by version 2 * License, use of this software will be governed by version 2
@ -15,60 +14,50 @@
namespace chat\system\message\type; namespace chat\system\message\type;
use chat\data\message\Message; use \chat\data\message\Message;
use chat\data\room\Room; use \chat\data\room\Room;
use wcf\data\user\UserProfile; use \wcf\data\user\UserProfile;
use wcf\system\event\EventHandler;
use wcf\system\WCF;
/** /**
* ColorMessageType represents a color message. * ColorMessageType represents a color message.
*/ */
final class ColorMessageType implements IMessageType class ColorMessageType implements IMessageType {
{ use TDefaultPayload;
use TDefaultPayload;
/** /**
* @inheritDoc * @inheritDoc
*/ */
public function getJavaScriptModuleName(): string public function getJavaScriptModuleName() {
{ return 'Bastelstu.be/Chat/MessageType/Color';
return 'Bastelstu.be/Chat/MessageType/Color'; }
}
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSee()
*/ */
public function canSee(Message $message, Room $room, ?UserProfile $user = null): bool public function canSee(Message $message, Room $room, UserProfile $user = null) {
{ if ($user === null) $user = new UserProfile(\wcf\system\WCF::getUser());
if ($user === null) {
$user = new UserProfile(WCF::getUser());
}
$parameters = [ $parameters = [ 'message' => $message
'message' => $message, , 'room' => $room
'room' => $room, , 'user' => $user
'user' => $user, , 'canSee' => true
'canSee' => true, ];
]; \wcf\system\event\EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
EventHandler::getInstance()->fireAction($this, 'canSee', $parameters);
return $parameters['canSee']; return $parameters['canSee'];
} }
/** /**
* @inheritDoc * @see \chat\system\message\type\IMessageType::canSeeInLog()
*/ */
public function canSeeInLog(Message $message, Room $room, ?UserProfile $user = null): bool public function canSeeInLog(Message $message, Room $room, UserProfile $user = null) {
{ return false;
return false; }
}
/** /**
* @inheritDoc * @see»\chat\system\message\type\IMessageType::supportsFastSelect()
*/ */
public function supportsFastSelect(): bool public function supportsFastSelect() {
{ return false;
return false; }
}
} }

Some files were not shown because too many files have changed in this diff Show More