Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ticket APIs (get ticket info, list agent or user tickets and post reply to ticket with new status) #4361

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 18 additions & 3 deletions api/http.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,24 @@

$dispatcher = patterns('',
url_post("^/tickets\.(?P<format>xml|json|email)$", array('api.tickets.php:TicketApiController','create')),
url('^/tasks/', patterns('',
url_post("^cron$", array('api.cron.php:CronApiController', 'execute'))
))


url_post("^/tickets/reply\.(?P<format>json)$", array('api.tickets.php:TicketApiController','postReply')),
// RESTful
url_get("^/tickets$", array('api.tickets.php:TicketApiController','restGetTickets')),
// url_get("^/tickets/(?P<ticket_number>\d{6})$", array('api.tickets.php:TicketApiController','restGetTicket')),
url_get("^/tickets/ticketInfo$", array('api.tickets.php:TicketApiController','getTicketInfo')),
url_get("^/tickets/staffTickets$", array('api.tickets.php:TicketApiController','getStaffTickets')),
url_get("^/tickets/clientTickets$", array('api.tickets.php:TicketApiController','getClientTickets')),
# Should stay disabled until there's an api key permission for ticket deletion
#url_delete("^/tickets/(?P<ticket_number>\d{6})$",
# array('api.tickets.php:TicketApiController','restDelete')),
url('^/tasks/', patterns('',
url_post("^cron$", array('api.cron.php:CronApiController', 'execute'))
))



);

Signal::send('api', $dispatcher);
Expand Down
228 changes: 227 additions & 1 deletion include/api.tickets.php
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,233 @@ function processEmail($data=false) {
return $this->createTicket($data);
}

}





function getTicketInfo() {
try{
if(!($key=$this->requireApiKey()))
return $this->exerr(401, __('API key not authorized'));


$ticket_number = $_REQUEST['ticketNumber'];
if (! ($ticket_number))
return $this->exerr(422, __('missing ticketNumber parameter '));

# Checks for valid ticket number
if (!is_numeric($ticket_number))
return $this->response(404, __("Invalid ticket number"));



# Checks for existing ticket with that number
$id = Ticket::getIdByNumber($ticket_number);


if ($id <= 0)
return $this->response(404, __("Ticket not found"));
# Load ticket and send response
$ticket = new Ticket(0);
//$ticket->load($id);
$ticket=Ticket::lookup($id);

$result = array('ticket'=> $ticket ,'status_code' => '0', 'status_msg' => 'ticket details retrieved successfully');
$result_code=200;
$this->response($result_code, json_encode($result ),
$contentType="application/json");

}
catch ( Throwable $e){
$msg = $e-> getMessage();
$result = array('ticket'=> array() ,'status_code' => 'FAILURE', 'status_msg' => $msg);
$this->response(500, json_encode($result),
$contentType="application/json");
}

}
/**
* RESTful GET ticket collection
*
* Pagination is made wit Range header.
* i.e.
* Range: items=0- <-- request all items
* Range: items=0-9 <-- request first 10 items
* Range: items 10-19 <-- request items 11 to 20
*
* Pagination status is given on Content-Range header.
* i.e.
* Content-Range items 0-9/100 <-- first 10 items retrieved, 100 total items.
*
* TODO: Add filtering support
*
*/
function restGetTickets() {
if(!($key=$this->requireApiKey()))
return $this->exerr(401, __('API key not authorized'));

# Build query
$qfields = array('number', 'created', 'updated', 'closed');
$q = 'SELECT ';
foreach ($qfields as $f) {
$q.=$f.',';
}
$q=rtrim($q, ',');
$qfrom = ' FROM '.TICKET_TABLE;
$q .= $qfrom;

$res = db_query($q);

header("TEST:".$q);

mysqli_free_result($res2);
unset($row);
$tickets = array();
$result_rows = $res->num_rows ;
// header("rowNum : ${result_rows}");
for ($row_no = 0; $row_no < $result_rows; $row_no++) {
$res->data_seek($row_no);
$row = $res->fetch_assoc();
$ticket = array();
foreach ($qfields as $f) {
array_push($ticket, array($f, $row[$f]));
}
array_push($ticket, array('href', '/api/tickets/'.$row['number']));
array_push($tickets, $ticket);
}

$result_code = 200;
$this->response($result_code, json_encode($tickets), $contentType = "application/json");
}

// staff tickets
function getStaffTickets()
{

try{
if (! ($key = $this->requireApiKey()))
return $this->exerr(401, __('API key not authorized'));

$staffUserName = $_REQUEST['staffUserName'];
if (! ($staffUserName))
return $this->exerr(422, __('missing staffUserName parameter '));
mysqli_set_charset('utf8mb4');
$staff = Staff::lookup(array(
'username' => $staffUserName
));

$myTickets = Ticket::objects()->filter(array(
'staff_id' => $staff->getId()
))
->all();


$tickets = array();
foreach ($myTickets as $ticket) {
array_push($tickets, $ticket);

}




$result_code = 200;
$result = array('tickets'=> $tickets ,'status_code' => '0', 'status_msg' => 'success');
$this->response($result_code, json_encode($result),
$contentType="application/json");

}
catch ( Throwable $e){
$msg = $e-> getMessage();
$result = array('tickets'=> array() ,'status_code' => 'FAILURE', 'status_msg' => $msg);
$this->response($result_code, json_encode($result),
$contentType="application/json");
}
}


//client tickets
function getClientTickets() {
try{
if(!($key=$this->requireApiKey()))
return $this->exerr(401, __('API key not authorized'));
mysqli_set_charset('utf8mb4');

$clientUserName = $_REQUEST['clientUserMail'];
if(!($clientUserName))
return $this->exerr(422, __('missing clientUserMail parameter '));
$user = TicketUser::lookupByEmail($clientUserName);

$myTickets = Ticket::objects()->filter(array('user_id' => $user->getId()))->all();

$tickets = array();
foreach ($myTickets as $ticket) {
array_push($tickets, $ticket);
}


$result_code = 200;
$result = array('tickets'=> $tickets ,'status_code' => '0', 'status_msg' => 'success');

$this->response($result_code, json_encode($result ),
$contentType="application/json");

}
catch ( Throwable $e){
$msg = $e-> getMessage();
$result = array('tickets'=> array() ,'status_code' => 'FAILURE', 'status_msg' => $msg);
$this->response(500, json_encode($result),
$contentType="application/json");
}
}


//staff replies to client ticket with the updated status
function postReply($format) {
try{
if(!($key=$this->requireApiKey()) || !$key->canCreateTickets())
return $this->exerr(401, __('API key not authorized'));

$data = $this->getRequest($format);

# Checks for existing ticket with that number
$id = Ticket::getIdByNumber($data['ticketNumber']);
if ($id <= 0)
return $this->response(404, __("Ticket not found"));

$data['id']=$id;
$staff = Staff::lookup(array('username'=>$data['staffUserName']));
$data['staffId']= $staff -> getId();
$data['poster'] = $staff;

$ticket=Ticket::lookup($id);
$errors = array();
$response = $ticket->postReply($data , $errors);


if(!$response)
return $this->exerr(500, __("Unable to reply to this ticket: unknown error"));

$location_base = '/api/tickets/';
// header('Location: '.$location_base.$ticket->getNumber());
// $this->response(201, $ticket->getNumber());
$result = array( 'status_code' => '0', 'status_msg' => 'reply posted successfully');
$result_code=200;
$this->response($result_code, json_encode($result ),
$contentType="application/json");

}
catch ( Throwable $e){
$msg = $e-> getMessage();
$result = array('tickets'=> array() ,'status_code' => 'FAILURE', 'status_msg' => $msg);
$this->response(500, json_encode($result),
$contentType="application/json");
}
}


}

//Local email piping controller - no API key required!
class PipeApiController extends TicketApiController {
Expand Down
45 changes: 44 additions & 1 deletion include/class.api.php
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,50 @@ function response($code, $resp) {
Http::response($code, $resp);
exit();
}
}
function response($code, $resp, $contentType="text/plain") {
Http::response($code, $resp, $contentType);
exit();
}


function getContentType() {
return strtolower($_SERVER['CONTENT-TYPE']);
}
function contentTypeToFormat($content_type) {
# Require a valid content-type (json, xml or rfc822) for POST and PUT
switch($content_type) {
case 'application/json':
return "json";
case 'application/xml':
return "xml";
case 'message/rfc822':
return "email";
default:
switch(strtolower($_SERVER['REQUEST_METHOD'])) {
case 'post':
case 'put':
$this->exerr(415, __('Unsupported data format'));
case 'get':
case 'delete':
return "";
}
}
}

/**
* Identifies request data format using content-type and passes it on to
* getRequest
*/
function getRequestAuto() {
$content_type = $this->getContentType();
$format = $this->contentTypeToFormat($content_type);
return $this->getRequest($format);
}




}

include_once "class.xml.php";
class ApiXmlDataParser extends XmlDataParser {
Expand Down
26 changes: 25 additions & 1 deletion include/class.thread.php
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ class ThreadEntryEmailInfo extends VerySimpleModel {
}

class ThreadEntry extends VerySimpleModel
implements TemplateVariable {
implements TemplateVariable , JsonSerializable {
static $meta = array(
'table' => THREAD_ENTRY_TABLE,
'pk' => array('id'),
Expand Down Expand Up @@ -1513,6 +1513,30 @@ static function registerAction($group, $action) {
static function getPermissions() {
return self::$perms;
}


public function jsonSerialize() {
return [
"id" => $this->getId(),
"pid" => $this->getPid(),
"thread_id" => $this->getThreadId(),
"staff_id" => $this->getStaffId() ,
"user_id" => $this->getUserId() ,
"type" => $this-> getType(),
"poster" => $this->getPoster(),
"editor" => $this-> getEditor(),
"source" => $this-> getSource(),
"title" => $this->getTitle(),
"body"=> $this->getBody()->getClean(),
"message"=>$this->getMessage(),
"format" => $this-> format,
"created"=> $this->created ,
"updated" => $this->updated,
"staff_name" => $this->getStaff() ? $this->getStaff()->getName(): null ,
"user_name" => $this->getUser() ? $this->getUser()->getName() : null

];
}
}

RolePermission::register(/* @trans */ 'Tickets', ThreadEntry::getPermissions());
Expand Down