Skip to content

Commit

Permalink
...
Browse files Browse the repository at this point in the history
  • Loading branch information
DonutsNL committed Jan 5, 2024
1 parent a290a84 commit 809380a
Show file tree
Hide file tree
Showing 5 changed files with 242 additions and 62 deletions.
28 changes: 27 additions & 1 deletion src/FilterPattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,8 @@ public function rawSearchOptions() : array

return $tab;
}



/**
* getFilterPatterns() : array -
* Get match patterns and config from dropdowns
Expand Down Expand Up @@ -362,4 +363,29 @@ public static function uninstall(Migration $migration) : void
$migration->displayMessage("Uninstalling $table");
$migration->dropTable($table);
}

/**
* Return dummy filterPattern for testing purposes
*
* @return array
*/
public static function getDummyPattern() : array
{
return [self::NAME => TestPattern,
self::ACTIVE => true,
self::DATE_CREATION => null,
self::DATE_MOD => null,
self::TICKETMATCHSTR => '/.*?(?<match>\(TESTMATCH-[0-9]{1,4}\)).*/',
self::TICKETMATCHSTRLEN => 16,
self::ASSETMATCHSTR => '/.*?(?<asset>\(TESTASSET-[0-9]{1,4}\)).*/',
self::ASSETMATCHSTRLEN => 16,
self::SOLVEDMATCHSTR => '/.*?(?<solved>\(TESTSOLVED-[0-9]{1,4}\)).*/',
self::SOLVEDMATCHSTRLEN => 18,
self::AUTOMERGE => true,
self::REOPENCLOSED => true,
self::SEARCHBODY => true,
self::MATCHSOURCE => true,
self::SUPPRESNOTIF => true];
}

}
152 changes: 95 additions & 57 deletions src/TicketHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,40 +48,45 @@ class TicketHandler{

private $ticket; // The referenced ticket object
private $pattern = false; // The pattern configuration
private $status = '-1'; // Status of this object, 1 if reference ticket is loaded.

// Not used
public function __construct() {}
private $status = false; // Status of this object

/**
* initHandler(int ticketId, array filterPattern) : bool -
* Loads a ticket from the database with provided ticket ID
* and populates used pattern config for various evals.
*
* @param int ticketId identity of the ticket that needs to be loaded
* @param int|Ticket ticket Either an testObject or ticket Id of the referenced ticket that needs to be loaded
* @param array pattern array holding the pattern used for the match.
* @return void Object is passed by reference, no return values required
* @since 1.1.0
*/
public function initHandler(int $ticketId, array $filterPattern) : bool
public function initHandler(int|Ticket $ticket, array $filterPattern) : bool
{
// Load the ticket we need to modify.
if(is_int($ticketId)){
if(is_int($ticket)){
if(is_array($filterPattern)){
$this->pattern = $filterPattern;
} else {
return false;
}

$this->ticket = new Ticket();
$this->ticket->getFromDB((integer) $ticketId);
$this->ticket->getFromDB((integer) $ticket);
// Check if we where able to fetch the correct ticket.
if($this->ticket->fields['id'] == $ticketId){
$this->status = '1';
if($this->ticket->fields['id'] == $ticket){
$this->status = true;
return true;
} else {
return false;
}
} else {
// Load ticket directly for testing purposes.
// Minimal validation to allow negative assertions
if(is_object($ticket)) {
$this->ticket = $ticket;
$this->pattern = $filterPattern;
$this->status = true;
}
}
}

Expand Down Expand Up @@ -226,56 +231,14 @@ public function addSolvedMessage($patternName = '') : bool
*/
public function processTicket(Ticket $item) : bool
{
// Match mailsender with ticket requester.
if($this->pattern[FilterPattern::MATCHSOURCE]) {
// https://github.com/DonutsNL/ticketfilter/issues/4
$succesfullUserMatch = false;

// Get all the users from the ticket Object received from the pre_item_add hook.
foreach($item->input['_actors']["requester"] as $null => $mailUser){
$usersToBeMatched[] = [
'userId' => $mailUser['items_id'],
'userEmail' => ($mailUser['default_email']) ? $mailUser['default_email'] : $mailUser['alternative_email']
];
}

// Fetch and match the requesters of the currently processed ticket.
// With the requesters in the ticket object received from the pre_item_add hook.
$usrObj = new $this->ticket->userlinkclass();
$actors = $usrObj->getActors($this->getId());
foreach ( $actors as $null => $ticketUsers) {
// Verify there are users assigned to process
if(is_array($ticketUsers) && count($ticketUsers) > 0) {
foreach($ticketUsers as $null => $userType) {
// Only evaluate user type requesters ignore watchers and technicians
if($userType['type'] == CommonITILActor::REQUESTER){
// First search alternative email because we dont want
// to match an users_id:int(0) that would match with all anonymous users
// assigned to the ticket.
if($userType['alternative_email']) {
if(array_search(($userType['alternative_email']), array_column($usersToBeMatched, 'userEmail'))){
$succesfullUserMatch = true;
}
} else {
// Try to match any non zero users_id in usersToBeMatched.
if(array_search($userType['users_id'], array_column($usersToBeMatched, 'userId'))){
$succesfullUserMatch = true;
}
}
} // Ignore the user that is either watcher or technician @see glpi/src/Ticket_User.php
} // foreach
}// No requesters assigned to ticket
}// foreach
// Process the followup.
if($this->status == '1') {

// We did not match any user from the email with the referenced ticket
// Per configuration do not merge the followup.
if(!$succesfullUserMatch){
// Evaluate the requesters of both tickets
if (!$this->verifyRequesters($item)) {
return false;
}
}

// Process the followup.
if($this->status == '1') {
// Do we need to reopen the closed ticket?
if($this->getStatus() == CommonITILObject::CLOSED) {
if($this->pattern[FilterPattern::REOPENCLOSED]) {
Expand Down Expand Up @@ -331,15 +294,23 @@ public function processTicket(Ticket $item) : bool
$this->addSolvedMessage($this->pattern[FilterPattern::NAME]);
// Set status to solved.
$this->setStatusToSolved();
print "Ticket updated to solved!<br>";
Session::addMessageAfterRedirect(__("<a href='".$this->getTicketURL()."'>New ticket was solved by the plugin!</a>"), true, INFO);
} else {
print "Solved Patern length issue <br>";
trigger_error('TicketFilter: Length of'.$matchArray['solved']['0'].' is longer then allowed by configured Ticket Match String Length', E_USER_WARNING);
}
} // Solved pattern not found
} else {// Solved pattern not found
print "Patern not found <br>";
}
} else {
print "Pregmatch failed <br>";
trigger_error("TicketFilter: PregMatch failed! please review the Solved pattern $p and correct it", E_USER_WARNING);
}
} else{
print "No solved string found!";
}
die();
return true;
} else {
return false;
Expand Down Expand Up @@ -392,4 +363,71 @@ public function searchTicketPool(string $searchString) : array
}
return $r;
}

/**
* verifyRequesters(Ticket $item) : bool -
* verify if the requesters in the 'to be created' ticket are present
* in the 'to be merged' ticket. Returns false if a match could not be made.
*
* @param Ticket $item Ticket object containing the mailgate uid
* @return bool Returns true on success and false on failure
* @since 1.0.0
*/
public function verifyRequesters(Ticket $item) : bool
{
// Match mailsender with ticket requester.
if(!$this->pattern[FilterPattern::MATCHSOURCE]) {
// Config does not require us to verify the users so we eval true.
return true;
} else {
// https://github.com/DonutsNL/ticketfilter/issues/4
$succesfullUserMatch = false;

// Get all the users from the ticket Object received from the pre_item_add hook.
foreach($item->input['_actors']["requester"] as $null => $mailUser){
$usersToBeMatched[] = [
'userId' => $mailUser['items_id'],
'userEmail' => ($mailUser['default_email']) ? $mailUser['default_email'] : $mailUser['alternative_email']
];
}

// Fetch and match the requesters of the currently processed ticket.
// With the requesters in the ticket object received from the pre_item_add hook.
$usrObj = new $this->ticket->userlinkclass();
$actors = $usrObj->getActors($this->getId());
foreach ( $actors as $null => $ticketUsers) {
// Verify there are users assigned to process
if(is_array($ticketUsers) && count($ticketUsers) > 0) {
foreach($ticketUsers as $null => $userType) {
// Only evaluate user type requesters ignore watchers and technicians
if($userType['type'] == CommonITILActor::REQUESTER){
// First search alternative email because we dont want
// to match an users_id:int(0) that would match with all anonymous users
// assigned to the ticket.
if(!empty($userType['alternative_email'])) {
if(array_search(($userType['alternative_email']), array_column($usersToBeMatched, 'userEmail')) === false){
echo "no match on email: {$userType['alternative_email']}<br>";
}else{
echo "match on email in: {$userType['users_id']}<br>";
$succesfullUserMatch = true;
}
} else {
// Try to match any non zero users_id in usersToBeMatched.
if(array_search($userType['users_id'], array_column($usersToBeMatched, 'userId')) === false){
echo "no match on userId: {$userType['users_id']}<br>";
}else{
echo "match on userId in: {$userType['users_id']}<br>";
$succesfullUserMatch = true;
}
}
} // Ignore the user that is either watcher or technician @see glpi/src/Ticket_User.php
} // foreach
}// No requesters assigned to ticket
}// foreach

// We did not match any user from the email with the referenced ticket
// Per configuration do not merge the followup.
return ($succesfullUserMatch) ? true : false;
}
}
}
6 changes: 2 additions & 4 deletions tests/TicketFilterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,5 @@ public function testTicketHandler()
);
}
}
// This plugin uses extensive database functions
// therefor we need to modify the classes to allow for more
// testing. This function is just preparations to allow
// phpunit testing. Simply run ./vendor/bin/phpunit ./tests

// phpunit testing Run ./vendor/bin/phpunit ./tests
32 changes: 32 additions & 0 deletions tests/UserValidationTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php
namespace tests;

use PHPUnit\Framework\MockObject\Exception;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;

use GlpiPlugin\Ticketfilter\TicketHandler;
use GlpiPlugin\Ticketfilter\FilterPattern;

// Needs more work.
// We need to work around the fact that the GLPI objects
// are not available in the plugin repository.
// Maybe create MOC objects instead.
/*
class UserValidationTest extends Testcase {
public function testUserValidation()
{
$ticket = new TestTicket();
$ticket->addToFields('status', 1);
$ticketHandler = new TicketHandler($ticket, FilterPattern::getDummyPattern());
//if(!$this->assertTrue()
}
}
class Ticket {
// Do stuff to represent a real ticket class.
}
*/
86 changes: 86 additions & 0 deletions tests/createTicketViaAPI.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
// User Params
$glpiUrl = 'https://your.glpi.url'; // Do not include closing slash '/'
$appToken = 'FOUND-IN-SETUP-GENERAL-API-ADD-API-CLIENT';
$userToken = 'REMOTE-ACCESS-KEY-GENERATED-IN-GLPI-USERTAB';
$ticketBody = json_encode([
"input" => [
"name" => "[TEST TICKET] CREATE TEST TICKET!", // Title
"content" => "Awsom ticket content!", // Content body
"_users_id_requester" => 523, // Match your user
"urgency" => 3,
"itilcategories_id" => 1, // Match your category
"type" => 2, // Request
"status" => 1 // Open.
],
]);

// Init Curl library;
// I just assume its present, else an fatal error will occur.
$ch = curl_init();

// Define HTTP headers to be send by Curl.
$initHeaders = ['Content-Type: application/json',
"Authorization: user_token $userToken",
"App-Token: $appToken",
];

// Initialize CURL params.
// See: https://www.php.net/manual/en/function.curl-setopt-array.php
$options = [
CURLOPT_URL => $glpiUrl.'/apirest.php/initSession', // What URL to open
CURLOPT_HEADER => false, // Do not return header information in response
CURLOPT_POST => true, // Use HTTP POST in the request
CURLOPT_TIMEOUT => 4, // Timeout after 4 attempts
CURLOPT_HTTPHEADER => $initHeaders, // Include de Init headers
CURLOPT_RETURNTRANSFER => true, // Put response in the returnvalue of curl_exec() for further processing
];

// perform Curl to receive valid session Token.
try {
curl_setopt_array($ch, $options);
if( ! $result = curl_exec($ch)) {
trigger_error(curl_error($ch));
}
}catch(Exception $e){ // Might also be ValueError :S
echo 'Caught exception: ', $e->getMessage(), "\n";
exit;
}

var_dump($result);

// A nice thing to do would be to catch the HTTP 200 (OK) here and validate the response.
// I assume the request is succesfull, else an error will be shown by var_dump;
// But im lazy in debugging scripts.

// Lets create our ticket;
$ticketHeaders = ['Content-Type: application/json',
'App-Token: $appToken',
"Session-Token: ".json_decode($result)->session_token,
];

// ReInitialize CURL params.
$options = [
CURLOPT_URL => $glpiUrl.'/apirest.php/Ticket',
CURLOPT_HEADER => false,
CURLOPT_POST => true,
CURLOPT_TIMEOUT => 4,
CURLOPT_HTTPHEADER => $ticketHeaders,
CURLOPT_POSTFIELDS => $ticketBody,
CURLOPT_RETURNTRANSFER => true,
];

// perform Curl to receive valid session Token.
try {
curl_setopt_array($ch, $options);
if( ! $result = curl_exec($ch)) {
trigger_error(curl_error($ch));
}
}catch(ValueError $e){
echo 'Caught exception: ', $e->getMessage(), "\n";
}

var_dump($result);

curl_close($ch);

0 comments on commit 809380a

Please sign in to comment.