Commit 93dc02ef authored by lrargerich's avatar lrargerich

Live support system updated

parent 4420eb0c
......@@ -2410,9 +2410,9 @@ 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_chat_window.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
......@@ -2699,9 +2699,9 @@ 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_chat_window.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
......
### Live support chat system
### under construction
drop table if exists tiki_live_support_operators;
create table tiki_live_support_operators(
user varchar(200) not null,
accepted_requests integer(10),
status varchar(20),
longest_chat integer(10),
shortest_chat integer(10),
average_chat integer(10),
last_chat integer(14),
time_online integer(10),
votes integer(10),
points integer(10),
status_since integer(14),
primary key(user)
);
drop table if exists tiki_live_support_requests;
create table tiki_live_support_requests(
reqId char(32) not null,
......@@ -9,7 +26,7 @@ create table tiki_live_support_requests(
operator varchar(200),
operator_id char(32),
user_id char(32),
reason varchar(250),
reason text,
req_timestamp integer(14),
timestamp integer(14),
status varchar(40),
......
/*** Shared functions ***/
function foo() {
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?op_online=pepe');
var ret = msg('tiki-live_support_server.php?op_online=pepe');
alert(ret);
}
......@@ -38,7 +39,8 @@ function write_msg(txt,role,name) {
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);
window.chat_data.scrollTo(0,1000000);
var ret = msg('tiki-live_support_server.php?write=' + document.getElementById('reqId').value + '&msg=' + txt + '&senderId=' + document.getElementById('senderId').value + '&role=' + role + '&name=' + name);
}
function event_poll() {
......@@ -46,27 +48,32 @@ function event_poll() {
}
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);
var ret = msg('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);
var txt = msg('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 />');
}
}
window.chat_data.scrollTo(0,1000000);
}
}
function chat_close(role,user) {
write_msg('<i>' + user + ' has left the chat' + '</i>',role,user);
}
/*** 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);
var ret = msg('tiki-live_support_server.php?request_chat=1&reason=' + reason + '&user=' + user + '&tiki_user=' + tiki_user + '&email=' + email);
document.getElementById('reqId').value = ret;
client_poll();
}
......@@ -76,34 +83,31 @@ function client_poll() {
}
function pollForAccept() {
var ret = msg('http://localhost/tcvs/tiki/tiki-live_support_server.php?get_status=' + document.getElementById('reqId').value);
var ret = msg('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();
window.location.href='tiki-live_support_chat_window.php?reqId=' + document.getElementById('reqId').value + '&role=user';
}
}
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);
msg('tiki-live_support_server.php?client_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');
var last = msg('tiki-live_support_server.php?poll_requests=1');
if (last > last_req) {
window.location.reload();
last_req = last;
}
}
function set_operator_status(status) {
var ret = msg('tiki-live_support_server.php?set_operator_status=' + document.getElementById('user').value + '&status=' + status);
}
function console_poll() {
var ourInterval = setInterval("pollForRequests()", 10000);
}
......
......@@ -30,7 +30,20 @@ class Lslib {
die;
}
function new_user_request($user,$tiki_user,$email,$reason,$user_id)
function set_operator_id($reqId,$senderId)
{
$query = "update tiki_live_support_requests set operator_id = '$senderId' where reqId='$reqId'";
$this->query($query);
}
function set_user_id($reqId,$senderId)
{
$query = "update tiki_live_support_requests set user_id = '$senderId' where reqId='$reqId'";
$this->query($query);
}
function new_user_request($user,$tiki_user,$email,$reason)
{
$reqId = md5(uniqid('.'));
$user = addslashes($user);
......@@ -39,7 +52,7 @@ class Lslib {
$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')";
values('$reqId','$user','$tiki_user','$email','$reason',$now,'active',$now,'',0,0,'','')";
$this->query($query);
return $reqId;
}
......@@ -50,10 +63,18 @@ class Lslib {
if($x) return $x; else return 0;
}
function get_max_active_request()
{
return $this->getOne("select max(reqId) from tiki_live_support_requests where status='active'");
}
// Remove active requests
function purge_requests()
{
$now = date("U");
$min = $now - 60*2; // 1 minute = timeout.
$query = "update tiki_live_support_requests set status='timeout' where timestamp < $min";
$this->query($query);
}
// Get status for request
......@@ -61,6 +82,54 @@ class Lslib {
{
return $this->getOne("select status from tiki_live_support_requests where reqId='$reqId'");
}
function set_request_status($reqId,$status)
{
$query = "update tiki_live_support_requests set status='$status' where reqId='$reqId'";
$this->query($query);
}
// Get request information
function get_request($reqId)
{
$query = "select * from tiki_live_support_requests where reqId='$reqId'";
$result = $this->query($query);
$res = $result->fetchRow(DB_FETCHMODE_ASSOC);
return $res;
}
/*
accepted_requests integer(10),
status varchar(20),
longest_chat integer(10),
shortest_chat integer(10),
average_chat integer(10),
last_chat integer(14),
time_online integer(10),
votes integer(10),
points integer(10),
status_since integer(14),
primary key(user)
*/
function set_operator_status($user,$status)
{
$now = date("U");
// If switching to offline then sum online time for this operator
if($status == 'offline') {
$query = "update tiki_live_support_operators set time_online = $now - status_since where user='$user' and status='online'";
$this->query($query);
}
$query = "update tiki_live_support_operators set status='$status', status_since=$now where user='$user'";
$this->query($query);
}
function get_operator_status($user)
{
$status = $this->getOne("select status from tiki_live_support_operators where user='$user'");
if(!$status) $status = 'offline';
return $status;
}
// Accepts a request, change status to op_accepted
function operator_accept($reqId,$user,$operator_id)
......@@ -68,6 +137,7 @@ class Lslib {
$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);
$query = "update tiki_live_support_operators set accepted_requests = accepted_requests + 1 where operator='$user'";
}
......@@ -86,12 +156,11 @@ class Lslib {
$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()
function get_requests($status)
{
$this->purge_requests();
$query = "select * from tiki_live_support_requests where status='active'";
$query = "select * from tiki_live_support_requests where status='$status'";
$result = $this->query($query);
$ret = Array();
while($res = $result->fetchRow(DB_FETCHMODE_ASSOC)) {
......
{$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
<a class="pagetitle" href="tiki-live_support_admin.php">{tr}Live support system{/tr}</a>
<br/><br/>
[ <a class="link" {jspopup href="tiki-live_support_console.php"}>{tr}Open operator console{/tr}</a> |
<a class="link" {jspopup width="300" height="450" href="tiki-live_support_client.php"}>{tr} Open client window{/tr}</a> ]
<br/><br/>
{if count($online_operators) > 0}
<h3>{tr}Online operators{/tr}</h3>
{section name=ix loop=$online_operators}
{$online_operators[ix].user|avatarize}<br/>
{/section}
{/if}
{if count($offline_operators) > 0}
<h3>{tr}Offline operators{/tr}</h3>
{cycle values='odd,even' print=false}
<table class="normal">
<tr>
<td width="2%" class="heading" style="text-align:center;">
{tr}Operator{/tr}
</td>
<td class="heading" colspan='2'>
{tr}stats{/tr}
</td>
</tr>
{section name=ix loop=$offline_operators}
<tr>
<td width="2%" class="{cycle advance=false}" style="text-align:center;">
{$offline_operators[ix].user|avatarize}<br />
<b>{$offline_operators[ix].user}</b>
</td>
<td class="{cycle advance=false}">
<table width="100%">
<tr>
<td>{tr}Accepted requests{/tr}:</td>
<td>{$offline_operators[ix].accepted_requests}</td>
</tr>
<tr>
<td>{$offline_operators[ix].status} {tr}since{/tr}:</td>
<td>{$offline_operators[ix].status_since|tiki_short_datetime}</td>
</tr>
</table>
</td>
<td class="{cycle}" style="text-align:right;">
<a href='tiki-live_support_admin.php?removeuser={$offline_operators[ix].user}'><img src='img/icons/trash.gif' border='0' alt='{tr}del{/tr}' title='{tr}del{/tr}' /></a>
</td>
</tr>
{/section}
</table>
{/if}
<h3>{tr}Add an operator to the system{/tr}</h3>
<small>{tr}Operators must be tiki users{/tr}</small>
<form method="post" action="tiki-live_support_admin.php">
<table class="normal">
<tr>
<td class="formcolor">{tr}user{/tr}</td>
<td class="formcolor">
<select name="user">
{section name=ix loop=$users}
<option value="{$users[ix].user}">{$users[ix].user}</option>
{/section}
</select>
</td>
</tr>
<tr>
<td class="formcolor">&nbsp;</td>
<td class="formcolor">
<input type="submit" name="adduser" value="{tr}set as operator{/tr}" />
</td>
</tr>
</table>
</form>
......@@ -6,22 +6,45 @@
<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>
<title>Live support:{$role} window</title>
{literal}
<script type="text/javascript" src="lib/live_support/live-support.js">
</script>
{/literal}
{$trl}
</head>
<body onUnload="javascript:operator_close();">
<body onUnload="javascript:chat_close(document.getElementById('role').value,document.getElementById('username').value);">
<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/>
<input type="hidden" id="role" value="{$role}" />
<input type="hidden" id="username" value="{$username}" />
{if $role eq 'user'}
<table>
<tr>
<td style="text-align:center;">{$req_info.operator|avatarize}<br/>
<b>{$req_info.operator}</b>
</td>
<td>
{tr}Chat started{/tr}<br/>
<i>{$req_info.reason}</i>
</td>
</tr>
</table>
{elseif $role eq 'operator'}
{if $req_info.tiki_user}
{tr}Chatting with: {$req_info.tiki_user}{/tr}
{else}
{tr}Chatting with: {$req_info.user}{/tr}
{/if}
{else}
Observer: display operator and user
{/if}
<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);" />
{literal}
<input type="text" id="data" onKeyPress="javascript:if(event.keyCode == 13) {write_msg(document.getElementById('data').value,document.getElementById('role').value,document.getElementById('username').value);}" />
<input type="button" value="send" onClick="javascript:write_msg(document.getElementById('data').value,document.getElementById('role').value,document.getElementById('username').value);" />
{/literal}
<script>
/* Activate polling of requests */
var last_event=0;
......
......@@ -13,42 +13,61 @@
{/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" />
<body onUnload="client_close();">
<div id='request_chat' align="center">
<input type="hidden" id="reqId" />
<input type="hidden" id="user" value="{$user}" />
<input type="hidden" id="email" value="{$user_email}" />
<input type="hidden" id="tiki_user" value="{$user}" />
<h2>{tr}Request live support{/tr}</h2>
<table>
{if $user}
<tr>
<td>{tr}User{/tr}</td>
<td>
{$user}
</td>
</tr>
<tr>
<td>{tr}Email{/tr}</td>
<td>
{$user_email}
</td>
</tr>
{else}
<tr>
<td>{tr}User{/tr}</td>
<td>
<input type="text" id="user" />
</td>
</tr>
<tr>
<td>{tr}Email{/tr}</td>
<td>
<input type="text" id="email" />
</td>
</tr>
{/if}
<tr>
<td>{tr}Reason{/tr}</td>
<td>
<!--input id='reason' type="text" />-->
<textarea id='reason' cols='20' rows='3'></textarea>
</td>
</tr>
</table>
<br/><br/>
<input onClick="request_chat(document.getElementById('user').value,document.getElementById('tiki_user').value,document.getElementById('email').value,document.getElementById('reason').value);" type="button" value="{tr}Request support{/tr}" />
</div>
<div id='requesting_chat' style='display:none;'>
Requesting chat
<b>{tr}Your request is being processed{/tr}....</b>
<br/><br/>
<a onClick="javascript:client_close();window.close();" class="link">{tr}cancel request and exit{/tr}</a><br/>
<a href="tiki-live_support_message.php" class="link">{tr}cancel request and leave a message{/tr}</a></br>
</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
......@@ -14,29 +14,55 @@
{/literal}
{$trl}
</head>
{literal}
<body>
{$user}
{/literal}
<input type="hidden" id="user" value="{$user}" />
<input type="hidden" id="status" value="online" />
<table class="normal" width="100%">
<tr>
<td class="heading">{tr}Operator{/tr}: {$user}</td>
<td class="heading">{tr}Status{/tr}: <b>{$status}</b></td>
<td class="heading" style="text-align:right;">
{if $status eq 'offline'}
<a href="tiki-live_support_console.php?status=online" class="tableheading">{tr}be online{/tr}</a>
{else}
<a href="tiki-live_support_console.php?status=offline" class="tableheading">{tr}be offline{/tr}</a>
{/if}
</td>
</tr>
</table>
{if count($requests) > 0}
<h3>{tr}Support requests{/tr}</h3>
{if $new_requests eq 'y'}
NEW!
{/if}
<table id='reqs' class="normal">
<tr>
<td class="heading">Id</td>
<td class="heading">User</td>
<td class="heading">Reason</td>
<td class="heading">{tr}User{/tr}</td>
<td class="heading">{tr}Reason{/tr}</td>
<td class="heading">{tr}Requested{/tr}</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 advance=false}">{$requests[ix].timestamp|tiki_short_time}</td>
<td class="{cycle}">
<a class="link" {jspopup href="tiki-live_support_operator.php?reqId=$requests[ix].reqId" width="300" height="450"}>Accept</a>
{if $status eq 'online'}
<a class="link" {jspopup href="tiki-live_support_chat_window.php?reqId=$requests[ix].reqId&role=operator" width="300" height="450"}>{tr}Accept{/tr}</a>
{else}
&nbsp;
{/if}
</td>
</tr>
{/section}
</table>
{/if}
<script>
/* Activate polling of requests */
var last_req={$last};
console_poll();
</script>
......
<?php
// Initialization
require_once('tiki-setup.php');
include('lib/live_support/lsadminlib.php');
include('lib/live_support/lslib.php');
if($tiki_p_admin != 'y' && !$lsadminlib->user_is_operator($user)) {
$smarty->assign('msg',tra("You dont have permission to use this feature"));
$smarty->display("styles/$style_base/error.tpl");
die;
}
if(isset($_REQUEST['adduser'])) {
$lsadminlib->add_operator($_REQUEST['user']);
}
if(isset($_REQUEST['removeuser'])) {
$lsadminlib->remove_operator($_REQUEST['removeuser']);
}
// Get the list of operators
$online_operators = $lsadminlib->get_operators('online');
$offline_operators = $lsadminlib->get_operators('offline');
$smarty->assign_by_ref('online_operators',$online_operators);
$smarty->assign_by_ref('offline_operators',$offline_operators);
// Get the list of users
if(!isset($_REQUEST['find_users'])) $_REQUEST['find_users']='';
$users = $userlib->get_users(0,-1,'login_asc', $_REQUEST['find_users']);
$ok_users=Array();
for($i=0;$i<count($users['data']);$i++) {
foreach($online_operators as $op) {
if($op['user'] == $users['data'][$i]['user']) {
unset($users[$i]);
}
}
foreach($offline_operators as $op) {
if(isset($users['data'][$i]) && $op['user'] == $users['data'][$i]['user']) {
unset($users['data'][$i]);
}
}
if(isset($users['data'][$i])) {
$ok_users[]=$users['data'][$i];
}
}
$smarty->assign_by_ref('users',$ok_users);
// Display the template
$smarty->assign('mid','tiki-live_support_admin.tpl');
$smarty->display("styles/$style_base/tiki.tpl");
......
......@@ -6,7 +6,5 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="StyleSheet" href="styles/{$style}" type="text/css" />
</head>
<body>
foo
</body>
<body style="margin-left:4px;"></body>
</html>
\ No newline at end of file
<?php
// Initialization
require_once('tiki-setup.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