diff --git a/file/js/be.bastelstu.WCF.Chat.coffee b/file/js/be.bastelstu.WCF.Chat.coffee index 73fea5c..aa95901 100644 --- a/file/js/be.bastelstu.WCF.Chat.coffee +++ b/file/js/be.bastelstu.WCF.Chat.coffee @@ -312,6 +312,13 @@ consoleMock ?= if element[0] console.log '[be.bastelstu.WCF.Chat] Moving User: "' + user.username + '"' element = element.detach() + if user.awayStatus? + element.addClass 'timsChatAway' + element.attr 'title', user.awayStatus + else + element.removeClass 'timsChatAway' + element.removeAttr 'title' + element.data 'tooltip', '' $('#timsChatUserList').append element # Insert the user else @@ -319,6 +326,10 @@ consoleMock ?= li = $ '
' li.attr 'id', id li.addClass 'timsChatUser' + li.addClass 'jsTooltip' + if user.awayStatus? + li.addClass 'timsChatAway' + li.attr 'title', user.awayStatus li.data 'username', user.username a = $ ''+user.username+'' a.click $.proxy (event) -> diff --git a/file/lib/data/chat/message/ChatMessage.class.php b/file/lib/data/chat/message/ChatMessage.class.php index b5d5e52..97b9b47 100755 --- a/file/lib/data/chat/message/ChatMessage.class.php +++ b/file/lib/data/chat/message/ChatMessage.class.php @@ -34,6 +34,7 @@ class ChatMessage extends \wcf\data\DatabaseObject { const TYPE_CLEAR = 9; const TYPE_TEAM = 10; const TYPE_GLOBALMESSAGE = 11; + const TYPE_ERROR = 12; /** * @see \wcf\data\chat\message\ChatMessage::getFormattedMessage() @@ -56,9 +57,12 @@ public function getFormattedMessage($outputType = 'text/html') { $message = WCF::getLanguage()->get('wcf.chat.message.'.$this->type); break; case self::TYPE_NORMAL: + case self::TYPE_ME: + case self::TYPE_WHISPER: if (!$this->enableHTML && $outputType == 'text/html') { $message = \wcf\system\bbcode\SimpleMessageParser::getInstance()->parse($message, true, $this->enableSmilies); } + break; } return $message; } @@ -71,7 +75,7 @@ public function getFormattedMessage($outputType = 'text/html') { public function getFormattedUsername() { $username = $this->getUsername(); - if ($this->type != self::TYPE_INFORMATION) $username = \wcf\util\ChatUtil::gradient($username, $this->color1, $this->color2); + if ($this->type != self::TYPE_INFORMATION && $this->type != self::TYPE_ERROR) $username = \wcf\util\ChatUtil::gradient($username, $this->color1, $this->color2); return ''.$username.''; } @@ -83,6 +87,8 @@ public function getFormattedUsername() { */ public function getUsername() { if ($this->type == self::TYPE_INFORMATION) return WCF::getLanguage()->get('wcf.chat.information'); + if ($this->type == self::TYPE_ERROR) return WCF::getLanguage()->get('wcf.chat.error'); + return $this->username; } @@ -97,6 +103,7 @@ public function jsonify($raw = false) { 'formattedUsername' => $this->getFormattedUsername(), 'formattedMessage' => (string) $this, 'formattedTime' => \wcf\util\DateUtil::format(\wcf\util\DateUtil::getDateTimeByTimestamp($this->time), 'H:i:s'), + 'separator' => ($this->type == self::TYPE_NORMAL) ? ': ' : ' ', 'message' => $this->getFormattedMessage('text/plain'), 'sender' => $this->sender, 'username' => $this->getUsername(), diff --git a/file/lib/data/chat/room/ChatRoom.class.php b/file/lib/data/chat/room/ChatRoom.class.php index 0ad0cbb..578c566 100644 --- a/file/lib/data/chat/room/ChatRoom.class.php +++ b/file/lib/data/chat/room/ChatRoom.class.php @@ -22,7 +22,7 @@ class ChatRoom extends \wcf\data\DatabaseObject implements \wcf\system\request\I * @see \wcf\data\DatabaseObject::$databaseTableIndexName */ protected static $databaseTableIndexName = 'roomID'; - + /** * Caches rooms. * @@ -43,21 +43,18 @@ public function __toString() { * @return integer */ public function countUsers() { - $packageID = \wcf\util\ChatUtil::getPackageID(); - $sql = "SELECT - count(*) as count + COUNT(*) FROM wcf".WCF_N."_user_storage WHERE - field = 'roomID' - AND packageID = ".intval($packageID)." - AND fieldValue = ".intval($this->roomID); + field = ? + AND packageID = ? + AND fieldValue = ?"; $stmt = WCF::getDB()->prepareStatement($sql); - $stmt->execute(); - $row = $stmt->fetchArray(); + $stmt->execute(array('roomID', \wcf\util\ChatUtil::getPackageID(), $this->roomID)); - return $row['count']; + return $stmt->fetchColumn(); } /** @@ -101,32 +98,42 @@ public function getTitle() { */ public function getUsers() { $packageID = \wcf\util\ChatUtil::getPackageID(); - + $sql = "SELECT userID FROM wcf".WCF_N."_user_storage WHERE - field = 'roomID' - AND packageID = ".intval($packageID)." - AND fieldValue = ".intval($this->roomID); + field = ? + AND packageID = ? + AND fieldValue = ?"; $stmt = WCF::getDB()->prepareStatement($sql); - $stmt->execute(); + $stmt->execute(array('roomID', $packageID, $this->roomID)); $userIDs = array(); - while ($row = $stmt->fetchArray()) $userIDs[] = $row['userID']; - - if (!count($userIDs)) return; - + while ($userIDs[] = $stmt->fetchColumn()); + + if (!count($userIDs)) return array(); + $sql = "SELECT - * + u.*, + s.fieldValue AS awayStatus FROM - wcf".WCF_N."_user + wcf".WCF_N."_user u + LEFT JOIN + wcf".WCF_N."_user_storage s + ON ( + u.userID = s.userID + AND s.field = ? + AND s.packageID = ? + ) WHERE - userID IN (".rtrim(str_repeat('?,', count($userIDs)), ',').") + u.userID IN (".rtrim(str_repeat('?,', count($userIDs)), ',').") ORDER BY - username ASC"; + u.username ASC"; $stmt = WCF::getDB()->prepareStatement($sql); + array_unshift($userIDs, 'away', $packageID); $stmt->execute($userIDs); + return $stmt->fetchObjects('\wcf\data\user\User'); } diff --git a/file/lib/form/ChatForm.class.php b/file/lib/form/ChatForm.class.php index 073cbb5..4c53800 100644 --- a/file/lib/form/ChatForm.class.php +++ b/file/lib/form/ChatForm.class.php @@ -32,6 +32,7 @@ class ChatForm extends AbstractForm { public function readData() { $this->userData['color'] = \wcf\util\ChatUtil::readUserData('color'); $this->userData['roomID'] = \wcf\util\ChatUtil::readUserData('roomID'); + $this->userData['away'] = \wcf\util\ChatUtil::readUserData('away'); $this->room = chat\room\ChatRoom::getCache()->search($this->userData['roomID']); if (!$this->room) throw new \wcf\system\exception\IllegalLinkException(); @@ -71,14 +72,63 @@ public function validate() { public function save() { parent::save(); - $commandHandler = new \wcf\system\chat\commands\ChatCommandHandler(); + \wcf\util\ChatUtil::writeUserData(array('away' => null)); + $commandHandler = new \wcf\system\chat\commands\CommandHandler($this->message); + if ($commandHandler->isCommand()) { + try { + $command = $commandHandler->loadCommand(); + + if ($command->enableSmilies != \wcf\system\chat\commands\ICommand::SMILEY_USER) $this->enableSmilies = $command->enableSmilies; + $type = $command->getType(); + $this->message = $command->getMessage(); + $receiver = $command->getReceiver(); + } + catch (\wcf\system\chat\commands\NotFoundException $e) { + $this->message = WCF::getLanguage()->get('wcf.chat.command.error.notFound'); + $type = chat\message\ChatMessage::TYPE_ERROR; + $receiver = WCF::getUser()->userID; + } + catch (\wcf\system\exception\PermissionDeniedException $e) { + $this->message = WCF::getLanguage()->get('wcf.chat.command.error.permissionDenied'); + $type = chat\message\ChatMessage::TYPE_ERROR; + $receiver = WCF::getUser()->userID; + } + catch (\Exception $e) { + $this->message = WCF::getLanguage()->get('wcf.chat.command.error.exception'); + $type = chat\message\ChatMessage::TYPE_ERROR; + $receiver = WCF::getUser()->userID; + } + } + else { + $type = chat\message\ChatMessage::TYPE_NORMAL; + $receiver = null; + } + + // mark user as back + if ($this->userData['away'] !== null) { + $messageAction = new chat\message\ChatMessageAction(array(), 'create', array( + 'data' => array( + 'roomID' => $this->room->roomID, + 'sender' => WCF::getUser()->userID, + 'username' => WCF::getUser()->username, + 'time' => TIME_NOW, + 'type' => chat\message\ChatMessage::TYPE_BACK, + 'message' => '', + 'color1' => $this->userData['color'][1], + 'color2' => $this->userData['color'][2] + ) + )); + $messageAction->executeAction(); + } + $messageAction = new chat\message\ChatMessageAction(array(), 'create', array( 'data' => array( 'roomID' => $this->room->roomID, 'sender' => WCF::getUser()->userID, 'username' => WCF::getUser()->username, + 'receiver' => $receiver, 'time' => TIME_NOW, - 'type' => chat\message\ChatMessage::TYPE_NORMAL, + 'type' => $type, 'message' => $this->message, 'enableSmilies' => $this->enableSmilies, 'color1' => $this->userData['color'][1], @@ -94,7 +144,7 @@ public function save() { * @see \wcf\page\IPage::show() */ public function show() { - header("HTTP/1.0 204 No Content"); + //header("HTTP/1.0 204 No Content"); parent::show(); } } diff --git a/file/lib/page/ChatMessagePage.class.php b/file/lib/page/ChatMessagePage.class.php index ebe5c13..1a9f210 100644 --- a/file/lib/page/ChatMessagePage.class.php +++ b/file/lib/page/ChatMessagePage.class.php @@ -79,7 +79,8 @@ public function show() { foreach ($this->users as $user) { $json['users'][] = array( 'userID' => $user->userID, - 'username' => $user->username + 'username' => $user->username, + 'awayStatus' => $user->awayStatus ); } diff --git a/file/lib/system/chat/commands/AbstractCommand.class.php b/file/lib/system/chat/commands/AbstractCommand.class.php new file mode 100644 index 0000000..8c994ad --- /dev/null +++ b/file/lib/system/chat/commands/AbstractCommand.class.php @@ -0,0 +1,26 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands + */ +abstract class AbstractCommand implements ICommand { + public $commandHandler = null; + + public function __construct(CommandHandler $commandHandler) { + EventHandler::getInstance()->fireAction($this, 'shouldInit'); + $this->commandHandler = $commandHandler; + EventHandler::getInstance()->fireAction($this, 'didInit'); + } + + public function getReceiver() { + return null; + } +} diff --git a/file/lib/system/chat/commands/AbstractRestrictedCommand.class.php b/file/lib/system/chat/commands/AbstractRestrictedCommand.class.php new file mode 100644 index 0000000..6d743a0 --- /dev/null +++ b/file/lib/system/chat/commands/AbstractRestrictedCommand.class.php @@ -0,0 +1,24 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands + */ +abstract class AbstractRestrictedCommand extends AbstractCommand implements IRestrictedCommand { + public function __construct(CommandHandler $commandHandler) { + parent::__construct($commandHandler); + + $this->checkPermission(); + } + + public function checkPermission() { + EventHandler::getInstance()->fireAction($this, 'checkPermission'); + } +} diff --git a/file/lib/system/chat/commands/ChatCommandHandler.class.php b/file/lib/system/chat/commands/ChatCommandHandler.class.php deleted file mode 100644 index 0aaa74b..0000000 --- a/file/lib/system/chat/commands/ChatCommandHandler.class.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @package be.bastelstu.wcf.chat - * @subpackage system.chat.commands - */ -class ChatCommandHandler { - const COMMAND_CHAR = '/'; - - /** - * Checks whether the given text is a command. - * - * @param string $text - * @return boolean - */ - public function isCommand($text) { - return StringUtil::substring($text, 0, StringUtil::length(static::COMMAND_CHAR)) == static::COMMAND_CHAR; - } -} diff --git a/file/lib/system/chat/commands/CommandHandler.class.php b/file/lib/system/chat/commands/CommandHandler.class.php new file mode 100644 index 0000000..23335fa --- /dev/null +++ b/file/lib/system/chat/commands/CommandHandler.class.php @@ -0,0 +1,73 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands + */ +final class CommandHandler { + const COMMAND_CHAR = '/'; + private $text = ''; + + /** + * Initialises the CommandHandler + * + * @param string $text + */ + public function __construct($text) { + $this->text = $text; + } + + /** + * Checks whether the given text is a command. + */ + public function isCommand($text = null) { + if ($text === null) $text = $this->text; + return StringUtil::substring($text, 0, StringUtil::length(static::COMMAND_CHAR)) == static::COMMAND_CHAR; + } + + /** + * Returns the whole message. + * + * @return string + */ + public function getText() { + return $this->text; + } + + /** + * Returns the parameter-string. + * + * @return string + */ + public function getParameters() { + $parts = explode(' ', StringUtil::substring($this->text, StringUtil::length(static::COMMAND_CHAR)), 2); + + if (!isset($parts[1])) return ''; + return $parts[1]; + } + + /** + * Loads the command. + */ + public function loadCommand() { + $parts = explode(' ', StringUtil::substring($this->text, StringUtil::length(static::COMMAND_CHAR)), 2); + + if ($this->isCommand($parts[0])) { + return new commands\Plain($this); + } + + $class = '\wcf\system\chat\commands\commands\\'.ucfirst($parts[0]); + if (!class_exists($class)) { + throw new NotFoundException(); + } + + return new $class($this); + } +} diff --git a/file/lib/system/chat/commands/ICommand.class.php b/file/lib/system/chat/commands/ICommand.class.php new file mode 100644 index 0000000..72e0ae4 --- /dev/null +++ b/file/lib/system/chat/commands/ICommand.class.php @@ -0,0 +1,21 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands + */ +interface ICommand { + const SMILEY_OFF = 0; + const SMILEY_ON = 1; + const SMILEY_USER = 2; + + public function getType(); + public function getMessage(); + public function getReceiver(); +} diff --git a/file/lib/system/chat/commands/IRestrictedCommand.class.php b/file/lib/system/chat/commands/IRestrictedCommand.class.php new file mode 100644 index 0000000..abdb3c2 --- /dev/null +++ b/file/lib/system/chat/commands/IRestrictedCommand.class.php @@ -0,0 +1,15 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands + */ +interface IRestrictedCommand { + protected function checkPermission(); +} diff --git a/file/lib/system/chat/commands/NotFoundException.class.php b/file/lib/system/chat/commands/NotFoundException.class.php new file mode 100644 index 0000000..fe786ec --- /dev/null +++ b/file/lib/system/chat/commands/NotFoundException.class.php @@ -0,0 +1,13 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands + */ +class NotFoundException extends \Exception { } \ No newline at end of file diff --git a/file/lib/system/chat/commands/commands/Away.class.php b/file/lib/system/chat/commands/commands/Away.class.php new file mode 100644 index 0000000..775bc3a --- /dev/null +++ b/file/lib/system/chat/commands/commands/Away.class.php @@ -0,0 +1,43 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands.commands + */ +class Away extends \wcf\system\chat\commands\AbstractCommand { + public $enableSmilies = \wcf\system\chat\commands\ICommand::SMILEY_OFF; + + public function __construct(\wcf\system\chat\commands\CommandHandler $commandHandler) { + parent::__construct($commandHandler); + + \wcf\util\ChatUtil::writeUserData(array('away' => $commandHandler->getParameters())); + } + + /** + * @see \wcf\system\chat\commands\ICommand::getType() + */ + public function getType() { + return \wcf\data\chat\message\ChatMessage::TYPE_AWAY; + } + + /** + * @see \wcf\system\chat\commands\ICommand::getMessage() + */ + public function getMessage() { + return $this->commandHandler->getParameters(); + } + + /** + * @see \wcf\system\chat\commands\ICommand::getReceiver() + */ + public function getReceiver() { + return \wcf\system\WCF::getUser()->userID; + } +} diff --git a/file/lib/system/chat/commands/commands/Color.class.php b/file/lib/system/chat/commands/commands/Color.class.php new file mode 100644 index 0000000..b79ce01 --- /dev/null +++ b/file/lib/system/chat/commands/commands/Color.class.php @@ -0,0 +1,83 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands.commands + */ +class Color extends \wcf\system\chat\commands\AbstractCommand { + public $enableSmilies = \wcf\system\chat\commands\ICommand::SMILEY_OFF; + public static $colors = array( + 'red' => 0xFF0000, + 'blue' => 0x0000FF, + 'green' => 0x00FF00, + 'yellow' => 0xFFFF00, + 'black' => 0x000000, + 'white' => 0xFFFFFF, + 'orange' => 0xFFA500, + 'purple' => 0xA020F0, + 'weed' => 0xF5DEB3, + 'pink' => 0xFFC0CB, + 'grey' => 0xBEBEBE, + 'khaki' => 0xF0E68C, + 'lavender' => 0xE6E6FA, + 'maroon' => 0xB03060, + 'gold' => 0xFFD700, + 'navyblue' => 0x000080, + 'royalblue' => 0x4169E1, + 'aquamarine' => 0x7FFFD4, + 'cyan' => 0x00FFFF, + 'magenta' => 0x00FFFF, + 'oxford' => 0xF02D // looks like green + ); + + public function __construct(\wcf\system\chat\commands\CommandHandler $commandHandler) { + parent::__construct($commandHandler); + try { + list($color[1], $color[2]) = explode(' ', $commandHandler->getParameters()); + } + catch (\wcf\system\exception\SystemException $e) { + $color[1] = $color[2] = $commandHandler->getParameters(); + } + + $regex = new \wcf\system\Regex('^#?([a-f0-9]{3}|[a-f0-9]{6})$', \wcf\system\Regex::CASE_INSENSITIVE); + foreach ($color as $key => $val) { + if (isset(self::$colors[$val])) $color[$key] = self::$colors[$val]; + else { + if (!$regex->match($val)) throw new \wcf\system\chat\commands\NotFoundException(); + $matches = $regex->getMatches(); + $val = $matches[1]; + if (strlen($val) == 3) $val = $val[0].$val[0].$val[1].$val[1].$val[2].$val[2]; + $color[$key] = hexdec($val); + } + } + \wcf\util\ChatUtil::writeUserData(array('color' => $color)); + } + + /** + * @see \wcf\system\chat\commands\ICommand::getType() + */ + public function getType() { + return \wcf\data\chat\message\ChatMessage::TYPE_INFORMATION; + } + + /** + * @see \wcf\system\chat\commands\ICommand::getMessage() + */ + public function getMessage() { + return 'color changed'; + } + + /** + * @see \wcf\system\chat\commands\ICommand::getReceiver() + */ + public function getReceiver() { + return \wcf\system\WCF::getUser()->userID; + } +} diff --git a/file/lib/system/chat/commands/commands/Free.class.php b/file/lib/system/chat/commands/commands/Free.class.php new file mode 100644 index 0000000..2ffdfd8 --- /dev/null +++ b/file/lib/system/chat/commands/commands/Free.class.php @@ -0,0 +1,25 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands.commands + */ +class Free extends Me { + public $enableSmilies = \wcf\system\chat\commands\ICommand::SMILEY_OFF; + + /** + * @see \wcf\system\chat\commands\ICommand::getMessage() + */ + public function getMessage() { + if (\wcf\util\StringUtil::toLowerCase($this->commandHandler->getParameters()) == 'the fish') + return 'freed the fish. OH A NOEZ'; + else + throw new \wcf\system\chat\commands\NotFoundException(); + } +} diff --git a/file/lib/system/chat/commands/commands/Me.class.php b/file/lib/system/chat/commands/commands/Me.class.php new file mode 100644 index 0000000..dbe734e --- /dev/null +++ b/file/lib/system/chat/commands/commands/Me.class.php @@ -0,0 +1,30 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands.commands + */ +class Me extends \wcf\system\chat\commands\AbstractCommand { + public $enableSmilies = \wcf\system\chat\commands\ICommand::SMILEY_USER; + + /** + * @see \wcf\system\chat\commands\ICommand::getType() + */ + public function getType() { + return \wcf\data\chat\message\ChatMessage::TYPE_ME; + } + + /** + * @see \wcf\system\chat\commands\ICommand::getMessage() + */ + public function getMessage() { + return $this->commandHandler->getParameters(); + } +} diff --git a/file/lib/system/chat/commands/commands/Plain.class.php b/file/lib/system/chat/commands/commands/Plain.class.php new file mode 100644 index 0000000..e0d9e53 --- /dev/null +++ b/file/lib/system/chat/commands/commands/Plain.class.php @@ -0,0 +1,36 @@ + + * @package timwolla.wcf.chat + * @subpackage system.chat.commands.commands + */ +class Plain extends \wcf\system\chat\commands\AbstractCommand { + public $enableSmilies = \wcf\system\chat\commands\ICommand::SMILEY_USER; + + /** + * @see \wcf\system\chat\commands\ICommand::getType() + */ + public function getType() { + return \wcf\data\chat\message\ChatMessage::TYPE_NORMAL; + } + + /** + * @see \wcf\system\chat\commands\ICommand::getMessage() + */ + public function getMessage() { + return \wcf\util\StringUtil::substring($this->commandHandler->getText(), 1); + } + + /** + * @see \wcf\system\chat\commands\ICommand::getReceiver() + */ + public function getReceiver() { + return null; + } +} diff --git a/template/chatMessage.tpl b/template/chatMessage.tpl index 5d2de90..7a784e5 100644 --- a/template/chatMessage.tpl +++ b/template/chatMessage.tpl @@ -1 +1 @@ -