Commit 4420eb0c authored by lrargerich's avatar lrargerich

Live support system experimental first version

parent affceb58
......@@ -1823,6 +1823,8 @@ tiki/lib/jpgraph/src/jpgraph_radar.php -text
tiki/lib/jpgraph/src/jpgraph_regstat.php -text
tiki/lib/jpgraph/src/jpgraph_scatter.php -text
tiki/lib/jpgraph/src/jpgraph_stock.php -text
tiki/lib/live_support/live-support.js -text svneol=unset#application/octet-stream
tiki/lib/live_support/lslib.php -text
tiki/lib/mailin/mailinlib.php -text
tiki/lib/md5.js -text
tiki/lib/menubuilder/menulib.php -text
......@@ -2407,6 +2409,10 @@ tiki/templates/tiki-list_submissions.tpl -text
tiki/templates/tiki-list_surveys.tpl -text
tiki/templates/tiki-list_trackers.tpl -text
tiki/templates/tiki-listpages.tpl -text
tiki/templates/tiki-live_support_admin.tpl -text
tiki/templates/tiki-live_support_client.tpl -text
tiki/templates/tiki-live_support_console.tpl -text
tiki/templates/tiki-live_support_operator.tpl -text svneol=unset#application/octet-stream
tiki/templates/tiki-login.tpl -text
tiki/templates/tiki-minical.tpl -text
tiki/templates/tiki-minical_prefs.tpl -text
......@@ -2691,6 +2697,12 @@ tiki/tiki-list_submissions.php -text
tiki/tiki-list_surveys.php -text
tiki/tiki-list_trackers.php -text
tiki/tiki-listpages.php -text
tiki/tiki-live_support_admin.php -text
tiki/tiki-live_support_chat_frame.php -text
tiki/tiki-live_support_client.php -text
tiki/tiki-live_support_console.php -text
tiki/tiki-live_support_operator.php -text
tiki/tiki-live_support_server.php -text
tiki/tiki-login.php -text
tiki/tiki-login_scr.php -text
tiki/tiki-login_validate.php -text
......
### Live support chat system
### under construction
drop table if exists tiki_live_support_requests;
create table tiki_live_support_requests(
reqId char(32) not null,
user varchar(200),
tiki_user varchar(200),
email varchar(200),
operator varchar(200),
operator_id char(32),
user_id char(32),
reason varchar(250),
req_timestamp integer(14),
timestamp integer(14),
status varchar(40),
resolution varchar(40),
chat_started integer(14),
chat_ended integer(14),
primary key(reqId)
);
drop table if exists tiki_live_support_events;
create table tiki_live_support_events(
eventId integer(14) not null auto_increment,
reqId char(32) not null,
type varchar(40),
seqId integer(14),
senderId varchar(32),
data text,
timestamp integer(14),
primary key(eventId)
);
### Live support chat system ends
INSERT INTO users_permissions(permName,type,permDesc,level) VALUES ('tiki_p_forum_autoapp','forums','Auto approve forum posts','admin');
drop table if exists tiki_user_postings;
......
/*** Shared functions ***/
function foo() {
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?op_online=pepe');
alert(ret);
}
function msg(msg) {
try {
// for Mozilla
req = new XMLHttpRequest();
req.overrideMimeType("text/xml");
} catch (e) {
// for IE5+
req = new ActiveXObject("Msxml2.XMLHTTP");
}
req.open("GET",msg,false);
req.send(null);
return req.responseText;
}
function msgxml(msg) {
try {
// for Mozilla
req = new XMLHttpRequest();
req.overrideMimeType("text/xml");
} catch (e) {
// for IE5+
req = new ActiveXObject("Msxml2.XMLHTTP");
}
req.open("GET",msg,false);
req.send(null);
return req.responseXML;
}
function write_msg(txt,role,name) {
window.chat_data.document.write(txt);
window.chat_data.document.write('<br />');
document.getElementById('data').value='';
/* And now send the message to the server */
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?write=' + document.getElementById('reqId').value + '&msg=' + txt + '&senderId=' + document.getElementById('senderId').value + '&role=' + role + '&name=' + name);
}
function event_poll() {
evpollInterval = setInterval("pollForEvents()", 5000);
}
function pollForEvents() {
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?get_last_event=' + document.getElementById('reqId').value + '&senderId=' + document.getElementById('senderId').value);
/* alert(ret);
alert(last_event); */
if(ret > last_event) {
while(last_event < ret) {
last_event = last_event + 1;
var txt = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?get_event=' + document.getElementById('reqId').value + '&last=' + last_event + '&senderId=' + document.getElementById('senderId').value);
if(txt) {
window.chat_data.document.write(txt);
window.chat_data.document.write('<br />');
}
}
}
}
/*** Client window functions ***/
function request_chat(user,tiki_user,email,reason) {
document.getElementById('username').value=document.getElementById('user').value;
document.getElementById('request_chat').style.display='none';
document.getElementById('requesting_chat').style.display='block';
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?request_chat=1&reason=' + reason + '&user=' + user + '&tiki_user=' + tiki_user + '&email=' + email + '&user_id=' + document.getElementById('senderId').value);
document.getElementById('reqId').value = ret;
client_poll();
}
function client_poll() {
clourInterval = setInterval("pollForAccept()", 5000);
}
function pollForAccept() {
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?get_status=' + document.getElementById('reqId').value);
if(ret == 'op_accepted') {
clearInterval(clourInterval);
document.getElementById('requesting_chat').style.display='none';
document.getElementById('chat').style.display='block';
event_poll();
}
}
function client_close() {
msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?client_close=' + document.getElementById('reqId').value);
}
/*** Operator window function ***/
function operator_close() {
msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?operator_close=' + document.getElementById('reqId').value);
}
/*** Operator console functions ***/
function pollForRequests() {
var last = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?poll_requests=1');
if (last > last_req) {
window.location.reload();
last_req = last;
}
}
function console_poll() {
var ourInterval = setInterval("pollForRequests()", 10000);
}
var clourInterval = null;
\ No newline at end of file
<?php
class Lslib {
function Lslib($db)
{
if(!$db) {
die("Invalid db object passed to Lslib constructor");
}
$this->db = $db;
}
// Queries the database reporting an error if detected
function query($query,$reporterrors=true) {
$result = $this->db->query($query);
if(DB::isError($result) && $reporterrors) $this->sql_error($query,$result);
return $result;
}
// Gets one column for the database.
function getOne($query,$reporterrors=true) {
$result = $this->db->getOne($query);
if(DB::isError($result) && $reporterrors) $this->sql_error($query,$result);
return $result;
}
// Reports SQL error from PEAR::db object.
function sql_error($query, $result)
{
trigger_error("MYSQL error: ".$result->getMessage()." in query:<br/>".$query."<br/>",E_USER_WARNING);
die;
}
function new_user_request($user,$tiki_user,$email,$reason,$user_id)
{
$reqId = md5(uniqid('.'));
$user = addslashes($user);
$tiki_user = addslashes($tiki_user);
$email = addslashes($email);
$reason = addslashes($reason);
$now = date("U");
$query = "insert into tiki_live_support_requests(reqId,user,tiki_user,email,reason,req_timestamp,status,timestamp,operator,chat_started,chat_ended,operator_id,user_id)
values('$reqId','$user','$tiki_user','$email','$reason',$now,'active',$now,'',0,0,'','$user_id')";
$this->query($query);
return $reqId;
}
function get_last_request()
{
$x = $this->getOne("select max(timestamp) from tiki_live_support_requests");
if($x) return $x; else return 0;
}
// Remove active requests
function purge_requests()
{
}
// Get status for request
function get_request_status($reqId)
{
return $this->getOne("select status from tiki_live_support_requests where reqId='$reqId'");
}
// Accepts a request, change status to op_accepted
function operator_accept($reqId,$user,$operator_id)
{
$now = date("U");
$query = "update tiki_live_support_requests set operator_id='$operator_id',operator='$user',status='op_accepted',timestamp=$now,chat_started=$now where reqId='$reqId'";
$this->query($query);
}
function user_close_request($reqId)
{
if(!$reqId) return;
$now = date("U");
$query = "update tiki_live_support_requests set status='user closed',timestamp=$now,chat_ended=$now where reqId='$reqId'";
$this->query($query);
}
function operator_close_request($reqId)
{
if(!$reqId) return;
$now = date("U");
$query = "update tiki_live_support_requests set status='operator closed',timestamp=$now,chat_ended=$now where reqId='$reqId'";
$this->query($query);
}
function get_active_requests()
{
$this->purge_requests();
$query = "select * from tiki_live_support_requests where status='active'";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
$ret[] = $res;
}
return $ret;
}
//EVENT HANDLING
function get_new_events($reqId,$senderId,$last)
{
$query = "select * from tiki_live_support_events where senderId='$senderId' and reqId='$reqId' and eventId>$last";
$result = $this->query($query);
$ret = '';
$ret='<?xml version="1.0" ?>';
$ret.='<events>';
while($res = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
$ret .= '<event>'.'<data>'.$res['data'].'</data></event>';
}
$ret.='</events>';
return $ret;
}
function get_last_event($reqId,$senderId)
{
return $this->getOne("select max(seqId) from tiki_live_support_events where senderId<>'$senderId' and reqId='$reqId'");
}
function get_event($reqId,$event,$senderId)
{
return $this->getOne("select data from tiki_live_support_events where senderId<>'$senderId' and reqId='$reqId' and seqId=$event");
}
function put_message($reqId,$msg,$senderId)
{
$now = date("U");
$seq = $this->getOne("select max(seqId) from tiki_live_support_events where reqId='$reqId'");
if(!$seq) $seq = 0;
$seq++;
$query = "insert into tiki_live_support_events(seqId,reqId,type,senderId,data,timestamp)
values($seq,'$reqId','msg','$senderId','$msg',$now)";
$this->query($query);
}
}
$lslib= new Lslib($dbTiki);
?>
{$user} foo<br/>
<a {jspopup href="tiki-live_support_console.php"}>operator console</a><br/>
<a {jspopup width="300" height="450" href="tiki-live_support_client.php"}>client window</a><br/>
\ No newline at end of file
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="StyleSheet" href="styles/{$style}" type="text/css" />
{include file="bidi.tpl"}
<title>Live support:User window</title>
{literal}
<script type="text/javascript" src="lib/live_support/live-support.js">
</script>
{/literal}
{$trl}
</head>
<body onUnload="javascript:client_close();">
<div id='request_chat'>
This is the client window<br/>
<input type="hidden" id="reqId" />
{if $user}
User: {$user} ({$user_email})<br/>
<input type="hidden" id="user" value="{$user}" />
<input type="hidden" id="email" value="{$user_email}" />
<input type="hidden" id="tiki_user" value="{$user}" />
{else}
User <input type="text" id="user" />
Email <input type="text" id="email" />
<input type="hidden" id="tiki_user" value="" />
{/if}
Reason: <input id='reason' type="text" />
<input onClick="request_chat(document.getElementById('user').value,document.getElementById('tiki_user').value,document.getElementById('email').value,document.getElementById('reason').value);" type="button" value="send" />
</div>
<div id='requesting_chat' style='display:none;'>
Requesting chat
</div>
<div id='chat' style='display:none;'>
User window {$senderId}<br/>
<input type="hidden" id="senderId" value="{$senderId}" />
<input type="hidden" id="username" />
<iframe name='chat_data' src='tiki-live_support_chat_frame.php' width="290" height="300" scrolling="yes">
</iframe>
<input type="text" id="data" />
<input type="button" name="send" onClick="javascript:write_msg(document.getElementById('data').value,'user',document.getElementById('username').value);" />
<script>
/* Activate polling of requests */
var last_event=0;
</script>
</div>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="StyleSheet" href="styles/{$style}" type="text/css" />
{include file="bidi.tpl"}
<title>Live support:Console</title>
{literal}
<script type="text/javascript" src="lib/live_support/live-support.js">
</script>
{/literal}
{$trl}
</head>
<body>
{$user}
<table id='reqs' class="normal">
<tr>
<td class="heading">Id</td>
<td class="heading">User</td>
<td class="heading">Reason</td>
<td class="heading">&nbsp;</td>
</tr>
{cycle values="odd,even" print=false}
{section loop=$requests name=ix}
<tr>
<td class="{cycle advance=false}">{$requests[ix].reqId}</td>
<td class="{cycle advance=false}">{$requests[ix].user}</td>
<td class="{cycle advance=false}">{$requests[ix].reason}</td>
<td class="{cycle}">
<a class="link" {jspopup href="tiki-live_support_operator.php?reqId=$requests[ix].reqId" width="300" height="450"}>Accept</a>
</td>
</tr>
{/section}
</table>
<script>
/* Activate polling of requests */
var last_req={$last};
console_poll();
</script>
</body>
</html>
\ No newline at end of file
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="StyleSheet" href="styles/{$style}" type="text/css" />
{include file="bidi.tpl"}
<title>Live support:Operator Window</title>
{literal}
<script type="text/javascript" src="lib/live_support/live-support.js">
</script>
{/literal}
{$trl}
</head>
<body onUnload="javascript:operator_close();">
<input type="hidden" id="reqId" value="{$reqId}" />
<input type="hidden" id="senderId" value="{$senderId}" />
<input type="hidden" id="username" value="{$user}" />
Operator window: {$senderId} in {$reqId}<br/>
<iframe name='chat_data' src='tiki-live_support_chat_frame.php' width="290" height="300" scrolling="yes">
</iframe>
<input type="text" id="data" />
<input type="button" name="send" onClick="javascript:write_msg(document.getElementById('data').value,'operator',document.getElementById('username').value);" />
<script>
/* Activate polling of requests */
var last_event=0;
event_poll();
</script>
</body>
</html>
\ No newline at end of file
<?php
// Initialization
require_once('tiki-setup.php');
// Display the template
$smarty->assign('mid','tiki-live_support_admin.tpl');
$smarty->display("styles/$style_base/tiki.tpl");
?>
\ No newline at end of file
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"DTD/xhtml1-transitional.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="StyleSheet" href="styles/{$style}" type="text/css" />
</head>
<body>
foo
</body>
</html>
\ No newline at end of file
<?php
// Initialization
require_once('tiki-setup.php');
include('lib/live_support/lslib.php');
$smarty->assign('senderId',md5(uniqid('.')));
if($user) {
$smarty->assign('user_email',$tikilib->get_user_email($user));
}
// Display the template
$smarty->display("tiki-live_support_client.tpl");
?>
\ No newline at end of file
<?php
// Initialization
require_once('tiki-setup.php');
include('lib/live_support/lslib.php');
$smarty->assign('requests',$lslib->get_active_requests());
$smarty->assign('last',$lslib->get_last_request());
// Display the template
$smarty->display("tiki-live_support_console.tpl");
?>
\ No newline at end of file
<?php
// Initialization
require_once('tiki-setup.php');
include('lib/live_support/lslib.php');
// We should receive the reqId here
// Accept the call (so the client polling for accept will be notified)
$senderId = md5(uniqId('.'));
$lslib->operator_accept($_REQUEST['reqId'],$user,$senderId);
$smarty->assign('reqId',$_REQUEST['reqId']);
$smarty->assign('senderId',$senderId);
// Display the template
$smarty->display("tiki-live_support_operator.tpl");
?>
\ No newline at end of file
<?php
// Live Support CHAT server.
// This PHP script handles all the messaging between the clients
// and the server (this script). Messaging is done using a REST
// model based on HTTP GET requests.
// Clients use Javascript to send messages to this server.
// clients of this server are:
// * The operator console
// * The operator chat window
// * The client chat window
// Long includes and heavy operations should be avoided to maximize the
// response time of this script which is critical.
include('db/tiki-db.php');
include('lib/live_support/lslib.php');
header("Expires: Mon, 26 Jul 1997 05:00:00 GMT"); // Date in the past
header("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT"); // always modified
header("Cache-Control: no-store, no-cache, must-revalidate"); // HTTP/1.1
header("Cache-Control: post-check=0, pre-check=0", false);
header("Pragma: no-cache"); // HTTP/1.0
// A user requests a chat
if(isset($_REQUEST['request_chat'])) {
// The server receives a chat request
// if then inserts a row in the support_requests table
// with the name of the user (or anonymous) and the reason for
// the request.
// Operator windows polling this server will be notified of current
// 'active' chat requests
header("Content-type: text/plain");
$id = $lslib->new_user_request($_REQUEST['user'],$_REQUEST['tiki_user'],$_REQUEST['email'],$_REQUEST['reason'],$_REQUEST['user_id']);
print($id);
}
if(isset($_REQUEST['write'])) {
if($_REQUEST['role']=='operator') {
}
if($_REQUEST['role']=='user') {
}
$_REQUEST['msg']='('.$_REQUEST['name'].')'.' '.$_REQUEST['msg'];
$lslib->put_message($_REQUEST['write'],$_REQUEST['msg'],$_REQUEST['senderId']);
}
if(isset($_REQUEST['get_last_event'])) {
header("Content-type: text/plain");
echo $lslib->get_last_event($_REQUEST['get_last_event'],$_REQUEST['senderId']);
}
if(isset($_REQUEST['get_event'])) {
header("Content-type: text/plain");
echo $lslib->get_event($_REQUEST['get_event'],$_REQUEST['last'],$_REQUEST['senderId']);
}
// A client closes its window
if(isset($_REQUEST['client_close'])) {
$lslib->user_close_request($_REQUEST['client_close']);
}
// An operator closes its window
if(isset($_REQUEST['operator_close'])) {
$lslib->operator_close_request($_REQUEST['operator_close']);
}
// A client polls for a connection
if(isset($_REQUEST['get_status'])) {
header("Content-type: text/plain");
echo $lslib->get_request_status($_REQUEST['get_status']);
}
// Operator console gets requests
if(isset($_REQUEST['poll_requests'])) {
// Now we can format this as XML
header("Content-type: text/plain");
echo $lslib->get_last_request();
}
?>
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment