diff --git a/src/messenger/tests/server_side/webim/libs/classes/ThreadTest.php b/src/messenger/tests/server_side/webim/libs/classes/ThreadTest.php index 08f59f56..9cab8d5e 100644 --- a/src/messenger/tests/server_side/webim/libs/classes/ThreadTest.php +++ b/src/messenger/tests/server_side/webim/libs/classes/ThreadTest.php @@ -202,6 +202,7 @@ class ThreadTest extends PHPUnit_Framework_TestCase { 'lrevision' => 189, 'istate' => Thread::STATE_QUEUE, + 'invitationstate' => Thread::INVITATION_NOT_INVITED, 'ltoken' => 19908, 'nextagent' => 0, @@ -574,15 +575,19 @@ class ThreadTest extends PHPUnit_Framework_TestCase { 'agentId' => 12, 'tmessage' => 'New message text', 'dtmcreated' => time(), - 'tname' => 'Sender name' + 'tname' => 'Sender name', + 'plugin' => '', + 'data' => array() ); $message['messageid'] = $thread->postMessage( $message['ikind'], $message['tmessage'], - $message['tname'], - $message['agentId'], - $message['dtmcreated'] + array( + 'name' => $message['tname'], + 'operator_id' => $message['agentId'], + 'created' => $message['dtmcreated'] + ) ); // Load message info from database $msg_info = $db->query( @@ -590,6 +595,8 @@ class ThreadTest extends PHPUnit_Framework_TestCase { array($message['messageid']), array('return_rows' => Database::RETURN_ONE_ROW) ); + $msg_info['data'] = unserialize($msg_info['data']); + // Check values $this->assertEquals($message, $msg_info); @@ -613,21 +620,27 @@ class ThreadTest extends PHPUnit_Framework_TestCase { 'kind' => Thread::KIND_USER, 'message' => 'The first message', 'created' => time(), - 'name' => 'System message only for agent' + 'name' => 'System message only for agent', + 'plugin' => 'f_test_plg', + 'data' => array('msg_num' => 1) ); // The second $second_message = array( 'kind' => Thread::KIND_AGENT, 'message' => 'The second message', 'created' => time(), - 'name' => 'User' + 'name' => 'User', + 'plugin' => 'f_test_plg', + 'data' => array('msg_num' => 1) ); // The third $third_message = array( 'kind' => Thread::KIND_FOR_AGENT, 'message' => 'The third message', 'created' => time(), - 'name' => 'Agent' + 'name' => 'Agent', + 'plugin' => 'f_test_plg', + 'data' => array('msg_num' => 1) ); // Send messages @@ -635,25 +648,37 @@ class ThreadTest extends PHPUnit_Framework_TestCase { $first_message['id'] = $thread->postMessage( $first_message['kind'], $first_message['message'], - $first_message['name'], - 12, - $first_message['created'] + array( + 'name' => $first_message['name'], + 'operator_id' => 12, + 'created' => $first_message['created'], + 'plugin' => $second_message['plugin'], + 'data' => $second_message['data'] + ) ); // The second $second_message['id'] = $thread->postMessage( $second_message['kind'], $second_message['message'], - $second_message['name'], - 14, - $second_message['created'] + array( + 'name' => $second_message['name'], + 'operator_id' => 14, + 'created' => $second_message['created'], + 'plugin' => $second_message['plugin'], + 'data' => $second_message['data'] + ) ); // The third $third_message['id'] = $thread->postMessage( $third_message['kind'], $third_message['message'], - $third_message['name'], - 16, - $third_message['created'] + array( + 'name' => $third_message['name'], + 'operator_id' => 16, + 'created' => $third_message['created'], + 'plugin' => $second_message['plugin'], + 'data' => $second_message['data'] + ) ); // Check messages for agent with ids starts from $msg_id diff --git a/src/messenger/webim/install/dbinfo.php b/src/messenger/webim/install/dbinfo.php index be0d1f22..df15d2b9 100644 --- a/src/messenger/webim/install/dbinfo.php +++ b/src/messenger/webim/install/dbinfo.php @@ -127,6 +127,11 @@ $dbtables = array( "agentId" => "int NOT NULL DEFAULT 0", // Message text body. "tmessage" => "text NOT NULL", + // Name of the plugin which sent the message. If message was not sent by + // a plugin this field equals to an empty string. + "plugin" => "varchar(256) NOT NULL DEFAULT ''", + // Arbitrary serialized data related with message. + "data" => "text", // Unix timestamp when message was created. "dtmcreated" => "int NOT NULL DEFAULT 0", // Name of the message sender. @@ -266,7 +271,7 @@ $dbtables_can_update = array( "${mysqlprefix}chatthread" => array("agentId", "userTyping", "agentTyping", "messageCount", "nextagent", "shownmessageid", "userid", "userAgent", "groupid", "dtmchatstarted", "invitationstate"), "${mysqlprefix}chatthreadstatistics" => array("missedthreads", "sentinvitations", "acceptedinvitations", "rejectedinvitations", "ignoredinvitations"), "${mysqlprefix}requestbuffer" => array("requestid", "requestkey", "request"), - "${mysqlprefix}chatmessage" => array("agentId"), + "${mysqlprefix}chatmessage" => array("agentId", "plugin", "data"), "${mysqlprefix}chatoperator" => array("vcavatar", "vcjabbername", "iperm", "istatus", "idisabled", "vcemail", "dtmrestore", "vcrestoretoken", "code"), "${mysqlprefix}chatoperatorstatistics" => array("sentinvitations", "acceptedinvitations", "rejectedinvitations", "ignoredinvitations"), "${mysqlprefix}chatban" => array(), diff --git a/src/messenger/webim/install/dbperform.php b/src/messenger/webim/install/dbperform.php index 5aa1e8d8..9262ecb4 100644 --- a/src/messenger/webim/install/dbperform.php +++ b/src/messenger/webim/install/dbperform.php @@ -91,6 +91,14 @@ if ($act == "silentcreateall") { runsql("update ${mysqlprefix}chatmessage, ${mysqlprefix}chatoperator set agentId = operatorid where agentId = 0 AND ikind = 2 AND (vclocalename = tname OR vccommonname = tname)", $link); } + if (in_array("${mysqlprefix}chatmessage.plugin", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatmessage ADD plugin varchar(256) NOT NULL DEFAULT '' AFTER tmessage", $link); + } + + if (in_array("${mysqlprefix}chatmessage.data", $absent_columns)) { + runsql("ALTER TABLE ${mysqlprefix}chatmessage ADD data text AFTER plugin", $link); + } + if (in_array("${mysqlprefix}chatthread.agentId", $absent_columns)) { runsql("ALTER TABLE ${mysqlprefix}chatthread ADD agentId int NOT NULL DEFAULT 0 AFTER agentName", $link); runsql("update ${mysqlprefix}chatthread, ${mysqlprefix}chatoperator set agentId = operatorid where agentId = 0 AND (vclocalename = agentName OR vccommonname = agentName)", $link); diff --git a/src/messenger/webim/js/compiled/chat/collections/messages.js b/src/messenger/webim/js/compiled/chat/collections/messages.js index 5c2e87c7..cc94e1bd 100644 --- a/src/messenger/webim/js/compiled/chat/collections/messages.js +++ b/src/messenger/webim/js/compiled/chat/collections/messages.js @@ -6,5 +6,5 @@ http://www.apache.org/licenses/LICENSE-2.0 */ (function(b,d,j){b.Collections.Messages=d.Collection.extend({model:b.Models.Message,initialize:function(){this.periodicallyCalled=[];this.periodicallyCalled.push(b.Objects.server.callFunctionsPeriodically(j.bind(this.updateMessagesFunctionBuilder,this),j.bind(this.updateMessages,this)))},finalize:function(){for(var a=0;a:plugin:message' and // 'process:plugin:message' otherwise. - pluginName = messageData.message.plugin || false; + pluginName = messageData.plugin || false; eventName = 'process:' + ((pluginName !== false) ? pluginName + ':' : '') + 'plugin:message'; diff --git a/src/messenger/webim/js/source/default/models/message.js b/src/messenger/webim/js/source/default/models/message.js index 259ac713..19106ecc 100644 --- a/src/messenger/webim/js/source/default/models/message.js +++ b/src/messenger/webim/js/source/default/models/message.js @@ -40,7 +40,20 @@ * Text of the message * @type String */ - message: '' + message: '', + + /** + * Name of the plugin which sent the message. If message was not + * sent by a plugin it equals to an empty string. + * @type String + */ + plugin: '', + + /** + * Set of arbitrary data attached to the message. + * @type Object + */ + data: {} }, /** Message kind constants */ diff --git a/src/messenger/webim/js/source/thread_log/app.js b/src/messenger/webim/js/source/thread_log/app.js index fae4515b..bd3f972e 100644 --- a/src/messenger/webim/js/source/thread_log/app.js +++ b/src/messenger/webim/js/source/thread_log/app.js @@ -18,8 +18,16 @@ // Initialize application App.addInitializer(function(options){ + // Create new empty messages collection and store it + var messages = new Mibew.Collections.Messages(); + Mibew.Objects.Collections.messages = messages; + + // Update messages in the collection + messages.updateMessages(options.messages); + + // Dispaly collection App.messagesRegion.show(new Mibew.Views.MessagesCollection({ - collection: new Mibew.Collections.Messages(options.messages) + collection: messages })); }); diff --git a/src/messenger/webim/js/source/thread_log/collections/messages.js b/src/messenger/webim/js/source/thread_log/collections/messages.js index 9efed02c..bf5ec41f 100644 --- a/src/messenger/webim/js/source/thread_log/collections/messages.js +++ b/src/messenger/webim/js/source/thread_log/collections/messages.js @@ -18,7 +18,29 @@ * Default contructor for model * @type Function */ - model: Mibew.Models.Message + model: Mibew.Models.Message, + + /** + * Update messages in collection. + * + * Skip messages with empty text body. + * @param rawMessages {Array} Array of row message models data. + */ + updateMessages: function(rawMessages) { + // Reject all messages with empty text body + var newMessages = []; + for(var i = 0; i < rawMessages.length; i++) { + if (! rawMessages[i].message) { + continue; + } + newMessages.push(rawMessages[i]); + } + + // Add new messages to the collection + if (newMessages.length > 0) { + this.add(newMessages); + } + } } ); diff --git a/src/messenger/webim/libs/classes/thread.php b/src/messenger/webim/libs/classes/thread.php index 91a5e04c..ecb300f2 100644 --- a/src/messenger/webim/libs/classes/thread.php +++ b/src/messenger/webim/libs/classes/thread.php @@ -563,9 +563,10 @@ Class Thread { $this->postMessage( self::KIND_CONN, $message_to_post, - null, - null, - $last_ping_other_side + self::CONNECTION_TIMEOUT + array( + 'created' => $last_ping_other_side + + self::CONNECTION_TIMEOUT + ) ); // And update thread @@ -582,9 +583,10 @@ Class Thread { $this->postMessage( self::KIND_FOR_AGENT, $message_to_post, - null, - null, - $last_ping_other_side + self::CONNECTION_TIMEOUT + array( + 'created' => $last_ping_other_side + + self::CONNECTION_TIMEOUT + ) ); } } @@ -690,8 +692,10 @@ Class Thread { * - 'kind': int, message kind, see Thread::KIND_* for details; * - 'created': int, unix timestamp when message was created; * - 'name': string, name of sender; - * - 'message': associative array with message data if kind equals to - * Thread::KIND_PLUGIN and message text string otherwise. + * - 'message': string, message text; + * - 'plugin': string, name of the plugin which sent the message or an + * empty string if message was not sent by a plugin. + * - 'data' array, arbitrary data attached to the message * @see Thread::postMessage() */ public function getMessages($is_user, &$last_id) { @@ -702,7 +706,7 @@ Class Thread { // Load messages $messages = $db->query( "select messageid as id, ikind as kind, dtmcreated as created, " . - " tname as name, tmessage as message " . + " tname as name, tmessage as message, plugin, data " . "from {chatmessage} " . "where threadid = :threadid and messageid > :lastid " . ($is_user ? "and ikind <> " . self::KIND_FOR_AGENT : "") . @@ -722,21 +726,22 @@ Class Thread { $msg['name'] ); - // Process message body - if ($messages[$key]['kind'] == self::KIND_PLUGIN) { - // Treat plugin message body as an associative array - $messages[$key]['message'] = unserialize( - $messages[$key]['message'] + // Process data attached to the message + if (! empty($messages[$key]['data'])) { + $messages[$key]['data'] = unserialize( + $messages[$key]['data'] ); } else { - // Change message body encoding for core messages kinds - $messages[$key]['message'] = myiconv( - $webim_encoding, - "utf-8", - $msg['message'] - ); + $messages[$key]['data'] = array(); } + // Change message body encoding + $messages[$key]['message'] = myiconv( + $webim_encoding, + "utf-8", + $msg['message'] + ); + // Get last message ID if ($msg['id'] > $last_id) { $last_id = $msg['id']; @@ -749,20 +754,30 @@ Class Thread { /** * Send the messsage * - * Use to send message with one of the core kinds(not Thread::KIND_PLUGIN). - * Trigger error with 'E_USER_WARNING' level if $kind equals to - * Thread::KIND_PLUGIN. + * One can attach arbitrary data to the message by setting 'data' item + * in the $options array. DO NOT serialize data manually - it will be + * automatically coverted to array and serialized before save in database + * and unserialized after retreive form database. * - * To send plugin message use Thread::postPluginMessage instead. + * One can also set plugin item of the $options array to indicate that + * message was sent by a plugin. * - * @param int $kind Message kind. One of the Thread::KIND_* but not - * Thread::KIND_PLUGIN + * @param int $kind Message kind. One of the Thread::KIND_* * @param string $message Message body - * @param string|null $from Sender name - * @param int|null $opid operator id. Use NULL for system messages - * @param int|null $time unix timestamp of the send time. Use NULL for - * current time. - * @return int|boolean Message ID or boolean false on failure. + * @param array $options List of additional options. It may contain + * following items: + * - 'name': string, name of the message sender. + * - 'operator_id': int, ID of the operator who sent the message. For + * system messages do not set this field. + * - 'created': int, unix timestamp of the send time. If you want to set + * current time do not set this field. + * - 'plugin': string, name of the plugin which sent the message. If + * message was not sent by a plugin do not set this field. + * - 'data': array with arbitrary data related with message. This value + * will be converted to array and serialized before save. If there is no + * such data do not set this field. + * + * @return int Message ID * * @see Thread::KIND_USER * @see Thread::KIND_AGENT @@ -774,39 +789,11 @@ Class Thread { * @see Thread::getMessages() * @see Thread::postPluginMessage() */ - public function postMessage($kind, $message, $from = null, $opid = null, $time = null) { - // Check message kind. It can not be equal to Thread::KIND_PLUGIN - if ($kind == self::KIND_PLUGIN) { - trigger_error( - 'Use Thread::postPluginMessage to send plugins messages', - E_USER_WARNING - ); - return false; - } + public function postMessage($kind, $message, $options = array()) { + $options = is_array($options) ? $options : array(); // Send message - return $this->saveMessage($kind, $message, $from, $opid, $time); - } - - /** - * Send plugin messsage - * - * @param string $plugin Plugin name. Use to determine which plugin sent - * the message. - * @param array $data Message data. Can contain arbitrary structure. - * @param int|null $time unix timestamp of the send time. Use NULL for - * current time. - * @return int Message ID - * - * @see Thread::getMessages() - */ - public function postPluginMessage($plugin, $data, $time = null) { - $message = serialize(array( - 'plugin' => $plugin, - 'data' => $data - )); - - return $this->saveMessage(self::KIND_PLUGIN, $message, null, null, $time); + return $this->saveMessage($kind, $message, $options); } /** @@ -814,10 +801,19 @@ Class Thread { * * @param int $kind Message kind. One of the Thread::KIND_* * @param string $message Message body - * @param string|null $from Sender name - * @param int|null $opid operator id. Use NULL for system messages - * @param int|null $time unix timestamp of the send time. Use NULL for - * current time. + * @param array $options List of additional options. It may contain + * following items: + * - 'name': string, name of the message sender. + * - 'operator_id': int, ID of the operator who sent the message. For + * system messages do not set this field. + * - 'created': int, unix timestamp of the send time. If you want to set + * current time do not set this field. + * - 'plugin': string, name of the plugin which sent the message. If + * message was not sent by a plugin do not set this field. + * - 'data': array with arbitrary data related with message. This value + * will be converted to array and serialized before save. If there is no + * such data do not set this field. + * * @return int Message ID * * @see Thread::KIND_USER @@ -829,22 +825,42 @@ Class Thread { * @see Thread::KIND_PLUGIN * @see Thread::getMessages() */ - protected function saveMessage($kind, $message, $from = null, $opid = null, $time = null) { + protected function saveMessage($kind, $message, $options = array()) { $db = Database::getInstance(); - $query = "INSERT INTO {chatmessage} " . - "(threadid,ikind,tmessage,tname,agentId,dtmcreated) " . - "VALUES (:threadid,:kind,:message,:name,:agentid,:created)"; + // Add default values to options + $options += array( + 'name' => null, + 'operator_id' => 0, + 'created' => time(), + 'plugin' => '', + 'data' => array() + ); + + // Prepare message data + $options['data'] = serialize((array)$options['data']); + + // Prepare query + $query = "INSERT INTO {chatmessage} (" . + "threadid, ikind, tmessage, tname, agentId, " . + "dtmcreated, plugin, data" . + ") VALUES (" . + ":threadid, :kind, :message, :name, :agentid, " . + ":created, :plugin, :data" . + ")"; $values = array( ':threadid' => $this->id, ':kind' => $kind, ':message' => $message, - ':name' => ($from ? $from : NULL), - ':agentid' => ($opid ? $opid : 0), - ':created' => ($time ? $time : time()) + ':name' => $options['name'], + ':agentid' => $options['operator_id'], + ':created' => $options['created'], + ':plugin' => $options['plugin'], + ':data' => $options['data'] ); + // Execute query $db->query($query, $values); return $db->insertedId(); } diff --git a/src/messenger/webim/libs/classes/thread_processor.php b/src/messenger/webim/libs/classes/thread_processor.php index 51a67b6e..c7a60b5b 100644 --- a/src/messenger/webim/libs/classes/thread_processor.php +++ b/src/messenger/webim/libs/classes/thread_processor.php @@ -326,11 +326,17 @@ class ThreadProcessor extends ClientSideProcessor { // Set fields $kind = $args['user'] ? Thread::KIND_USER : Thread::KIND_AGENT; - $from = $args['user'] ? $thread->userName : $thread->agentName; - $opid = $args['user'] ? null : $operator['operatorid']; + if ($args['user']) { + $msg_options = array('name' => $thread->userName); + } else { + $msg_options = array( + 'name' => $thread->agentName, + 'operator_id' => $operator['operatorid'] + ); + } // Post message - $posted_id = $thread->postMessage($kind, $args['message'], $from, $opid); + $posted_id = $thread->postMessage($kind, $args['message'], $msg_options); // Update shownMessageId if($args['user'] && $thread->shownMessageId == 0) { @@ -498,7 +504,7 @@ class ThreadProcessor extends ClientSideProcessor { $posted_id = $thread->postMessage( Thread::KIND_USER, $first_message, - $visitor['name'] + array('name' => $visitor['name']) ); $thread->shownMessageId = $posted_id; $thread->save(); @@ -621,7 +627,7 @@ class ThreadProcessor extends ClientSideProcessor { getstring2('chat.visitor.info', array($info)) ); } - $thread->postMessage(Thread::KIND_USER, $message, $name); + $thread->postMessage(Thread::KIND_USER, $message, array('name'=>$name)); // Get email for message $inbox_mail = get_group_email($group_id); diff --git a/src/messenger/webim/libs/invitation.php b/src/messenger/webim/libs/invitation.php index 0fd0f9c5..64592889 100644 --- a/src/messenger/webim/libs/invitation.php +++ b/src/messenger/webim/libs/invitation.php @@ -122,8 +122,10 @@ function invitation_invite($visitor_id, $operator) { $thread->postMessage( Thread::KIND_AGENT, getlocal("invitation.message"), - $operator_name, - $operator['operatorid'] + array( + 'name' => $operator_name, + 'operator_id' => $operator['operatorid'] + ) ); return $thread;