External Ticket Search
From Cerb Wiki
Create a folder inside /storage/plugins: i.e.: user.externalsearches Put these 2 files into the folder:
Files
/storage/plugins/user.externalsearches/plugin.xml:
<!DOCTYPE plugin SYSTEM "../../libs/devblocks/plugin.dtd"> <plugin> <id>user.externalsearches</id> <name>[Cerb5] External Searches</name> <description>Allows ticket searches from other apps</description> <author>Gonzalo Lopez</author> <revision>0</revision> <dependencies> <require plugin_id="cerberusweb.core" version="5.0.0-beta" /> </dependencies> <extensions> <extension point="devblocks.controller"> <id>user.externalsearches.controller</id> <name>Forums Controller</name> <class> <file>api/App.php</file> <name>ExternalSearchController</name> </class> <params> <param key="uri" value="externalsearch" /> </params> </extension> </extensions> </plugin>
/storage/plugins/user.externalsearches/api/App.php:
<?php
class ExternalSearchController extends DevblocksControllerExtension {
const EXTENSION_ID = 'user.externalsearches.page';
/**
* These must be defined as DevblocksSearchCriteria class constants.
*
* @var array
* @access private
*/
private $_operators = array(
"OPER_EQ",
"OPER_EQ_OR_NULL",
"OPER_NEQ",
"OPER_IN",
"OPER_IS_NULL",
"OPER_NIN",
"OPER_FULLTEXT",
"OPER_LIKE",
"OPER_NOT_LIKE",
"OPER_GT",
"OPER_LT",
"OPER_GTE",
"OPER_LTE",
"OPER_BETWEEN"
);
/**
* Search fields and data types association
* Keys must be defined as SearchFields_Ticket class constants
*
* @param array $_fields;
*/
private $_fields = array(
"TICKET_ID",
"TICKET_MASK",
"TICKET_SUBJECT",
"TICKET_FIRST_WROTE",
"TICKET_LAST_WROTE",
"REQUESTER_ADDRESS",
"TICKET_INTERESTING_WORDS",
"ORG_NAME",
"TICKET_WAITING",
"TICKET_DELETED",
"TICKET_CLOSED",
"TICKET_FIRST_WROTE_SPAM",
"TICKET_FIRST_WROTE_NONSPAM",
"TICKET_CREATED_DATE",
"TICKET_UPDATED_DATE",
"TICKET_DUE_DATE",
"TICKET_SPAM_SCORE",
"TICKET_SPAM_TRAINING",
"TICKET_LAST_ACTION_CODE",
"TICKET_LAST_WORKER_ID",
"TICKET_NEXT_WORKER_ID",
"TICKET_TEAM_ID",
"TICKET_CATEGORY_ID",
"FULLTEXT_MESSAGE_CONTENT"
);
function __construct($manifest) {
parent::__construct($manifest);
}
public function handleRequest(DevblocksHttpRequest $request) {
$session = DevblocksPlatform::getSessionService();
$visit = $session->getVisit();
if (empty($visit)) {
DevblocksPlatform::redirect(new DevblocksHttpResponse(array('login')));
return;
}
$params = $request->path;
array_shift($params);
$view = C4_AbstractViewLoader::getView("search");
$filtered_criteria = $this->_parseParams($params);
if ($filtered_criteria) {
$view->params = array();
foreach ($filtered_criteria as $criteria) {
list ($field, $oper, $value) = $criteria;
$view->params[$field] = new DevblocksSearchCriteria($field, $oper, $value);
}
} else {
$view->doResetCriteria();
}
//$view->renderPage = 0;
C4_AbstractViewLoader::setView("search", $view);
DevblocksPlatform::redirect(new DevblocksHttpResponse(array('tickets', 'search')));
}
private function _parseParams($params) {
$filtered_criteria = array();
$criteria_regex = $this->_getCriteriaRegex();
foreach ($params as $param) {
$param = DevblocksPlatform::importGPC(urldecode($param),'string');
if (preg_match($criteria_regex, $param, $match)) {
array_shift($match);
list($field, $operator, $value) = $match;
if ($field_constant = constant("SearchFields_Ticket::" . $field)) {
$field = $field_constant;
}
if ($operator_constant = constant("DevblocksSearchCriteria::" . $operator)) {
$operator = $operator_constant;
}
if (strpos($value, "|") !== false) {
$value = explode("|", $value);
}
$filtered_criteria[] = array($field, $operator, $value);
}
}
return $filtered_criteria;
}
private function _getCriteriaRegex() {
$valid_operators_array = array();
foreach ($this->_operators as $operator_constant) {
$valid_operators_array[] = $operator_constant;
$valid_operators_array[] = constant("DevblocksSearchCriteria::$operator_constant");
}
$valid_operators = implode("|", $valid_operators_array);
$valid_fields_array = array();
foreach ($this->_fields as $field_constant) {
$valid_fields_array[] = $field_constant;
$valid_fields_array[] = constant("SearchFields_Ticket::" . $field_constant);
}
$valid_fields = implode("|", $valid_fields_array);
return "/($valid_fields)\s*($valid_operators)\s*(.+)$/";
}
}
Usage
The plugin activates a URL that receives search criteria via GET, and redirects the user to the ticket search tab, applying the specified criteria to the search.
The URLS are of the form:
http://cerberus.example.com/externalsearch/CRITERION_1/CRITERION_2/.../CRITERION_N
Where CRITERION is a string containing the FIELD, OPERATOR and VALUE.
- Fields may be specified by its constants or table column names (As defined at SearchFields_Ticket class).
- Operators may be specified directly, or by its constants (as defined at DevblocksSearchCriteria class).
- Criteria should be url-encoded if neccesary. Take care of encoding every criterion separately:
$url = "http://cerberus.example/externalseatch/".urlencode("TICKET_ID = 1")."/".urlencode("TICKET_TEAM_ID in 5|6|78");
- When specifying multiple values, separate them with | (pipe)
CRITERIA examples (every group of lines is equivalent):
TICKET_ID=1 t_ticket_id=1 TICKET_ID OPER_EQ 1 (must be url-encoded)
TICKET_IDOPER_IN1,2,3 t_ticket_id in 1,2,3 (must be url-encoded) TICKET_IDin1,2,3
TICKET_TEAM_ID>=260 t_team_idOPER_GT260
TICKET_TEAM_ID in (260,264,266) (must be url-encoded) t_team_idin260,264,266
Complete URL Examples:
http://cerberus.example.com/externalsearch/TICKET_ID=1
Notice how fields and operators are recognized even if there is no space characters between them, so you probably won't neeed to url-encode your URLS. This makes URLs hard to read, but allow to generate them more easily:
http://cerberus.example.com/externalsearch/TICKET_IDin1|2/TICKET_TEAM_IDOPERLT6
Examples (in these, criteria must be url-encoded):
http://cerberus.example.com/externalsearch/TICKET_IDin1|3|4
http://cerberus.example.com/externalsearch/TICKET_TEAM_IDOPER_GT56
TODO
If user is not logged in, redirect to login page passing URL.