From 52373364376f41e214bf414836150a0d6043e9d6 Mon Sep 17 00:00:00 2001 From: tomolimo Date: Tue, 6 Apr 2021 15:40:10 +0200 Subject: [PATCH] Compatible with GLPI 9.5 (#21) * Compatible with GLPI 9.5 * Added logo --- README.md | 81 ++++++----- front/filter.form.php | 21 ++- front/filter.php | 27 ++++ front/user.form.php | 12 +- hook.php | 302 +++++++++++++++++++++++++----------------- inc/filter.class.php | 32 ++++- inc/menu.class.php | 27 ++++ inc/user.class.php | 12 +- purgepictures.php | 52 +++++--- setup.php | 68 +++++++--- swipe.png | Bin 0 -> 45521 bytes ticketcleaner.xml | 20 ++- 12 files changed, 433 insertions(+), 221 deletions(-) create mode 100644 swipe.png diff --git a/README.md b/README.md index 4652284..ba56cf3 100644 --- a/README.md +++ b/README.md @@ -1,53 +1,66 @@ -# ticketcleaner -New home for Ticket Cleaner GLPi plugin +# Ticket Cleaner +Home for Ticket Cleaner GLPI plugin -Currently mirrors https://forge.glpi-project.org/projects/ticketcleaner +See wiki for filter explanations: https://github.com/tomolimo/ticketcleaner/wiki +## 3.0.0 +GLPI 9.5 compatible release -## 2.1.0 -Beware that, when upgrading from a version lower than 2.0.0, this new release will not keep your existing filters. You'll have to input them again with the new interface that permits to edit them directly into GLPi. -Your former filters will be copied into a backup table that you may edit via your preferred mySQL query editor (table name is `backup_glpi_plugin_ticketcleaner_filters`). -You'll have to combine your former filters to get the new ones that will be entered into the new table, or to create new one from scratch. +## 2.5.3 +Fixed issue with filter's name and comment -This version also brings the possibility to debug your regex using the GLPi debug mode (see wiki). - -## 2.0.1 -Extends 'regex' and 'replacement' size (instead of VARCHAR will use TEXT field type). +## 2.5.2 +Typo fix -## 2.0.2 -Added a test to prevent menu adding when not activated. -Added possibility to do online translation +## 2.5.0 +Compatibility with GLPI 9.4 -## 2.0.3 -Added 'UTF-8' as default charset for htmlentities and html_entity_decode, fixes #3 +## 2.4.0 +Compatibility with GLPI 9.3 -## 2.0.4 -Changed the internal mechanism to check and delete attached pictures when in the 'pictures' folder. Fixes #4 +## 2.4.2 +Fixed issue with filter's name and comment -## 2.0.5 -Added a filter to delete file tags from ticket content when files are deleted from list +## 2.4.1 +Typo fix -## 2.1.0 -Added arTableExists and arFieldExists to be compatible with 9.2 +## 2.3.5 +Fixed issue with filter's name and comment -## 2.3.1 -Remove functions for 9.1 compatibility +## 2.3.4 +Typo fix ## 2.3.3 Compatibility with GLPI 9.2 Fixed issue with the \r\n -## 2.3.4 -Typo fix +## 2.3.1 +Remove functions for 9.1 compatibility -## 2.4.0 -Compatibility with GLPI 9.3 +## 2.1.0 +Beware that, when upgrading from a version lower than 2.0.0, this new release will not keep your existing filters. You'll have to input them again with the new interface that permits to edit them directly into GLPi. +Your former filters will be copied into a backup table that you may edit via your preferred mySQL query editor (table name is `backup_glpi_plugin_ticketcleaner_filters`). +You'll have to combine your former filters to get the new ones that will be entered into the new table, or to create new one from scratch. -## 2.4.1 -Typo fix +This version also brings the possibility to debug your regex using the GLPi debug mode (see wiki). -## 2.5.0 -Compatibility with GLPI 9.4 +Added arTableExists and arFieldExists to be compatible with 9.2 -## 2.5.1 -Typo fix +## 2.0.5 +Added a filter to delete file tags from ticket content when files are deleted from list + +## 2.0.4 +Changed the internal mechanism to check and delete attached pictures when in the 'pictures' folder. Fixes #4 + +## 2.0.3 +Added 'UTF-8' as default charset for htmlentities and html_entity_decode, fixes #3 + +## 2.0.2 +Added a test to prevent menu adding when not activated. +Added possibility to do online translation + +## 2.0.1 +Extends 'regex' and 'replacement' size (instead of VARCHAR will use TEXT field type). + +## Older releases +Older releases are here: https://forge.glpi-project.org/projects/ticketcleaner diff --git a/front/filter.form.php b/front/filter.form.php index 401f2f1..67a912e 100644 --- a/front/filter.form.php +++ b/front/filter.form.php @@ -1,33 +1,28 @@ . +along with this plugin. If not, see . -------------------------------------------------------------------------- */ diff --git a/front/filter.php b/front/filter.php index 6b46821..0e6febb 100644 --- a/front/filter.php +++ b/front/filter.php @@ -1,4 +1,31 @@ . +-------------------------------------------------------------------------- + */ + include ("../../../inc/includes.php"); diff --git a/front/user.form.php b/front/user.form.php index 64d0d2d..a72164f 100644 --- a/front/user.form.php +++ b/front/user.form.php @@ -1,30 +1,30 @@ . +along with this plugin. If not, see . -------------------------------------------------------------------------- -*/ + */ define('GLPI_ROOT', '../../..'); include (GLPI_ROOT . "/inc/includes.php"); diff --git a/hook.php b/hook.php index 0b3379d..bf87f0d 100644 --- a/hook.php +++ b/hook.php @@ -1,4 +1,30 @@ . +-------------------------------------------------------------------------- + */ // ---------------------------------------------------------------------- // Original Author of file: Olivier Moron @@ -9,6 +35,7 @@ // It has been succesfully tested with plain TEXT and HTML emails // ---------------------------------------------------------------------- + /** * Summary of loadSha1IntoDB * This function checks if an update of SHA is mandatory @@ -19,34 +46,39 @@ * Will save the file name and SHA into DB, in table 'glpi_plugin_ticketcleaner_picturehashes' * for each file found in the 'pictures' folder */ - function loadSha1IntoDB() { - global $DB; - - // now fill the table - // get files from plugin pictures folder - $dir = GLPI_ROOT . "/plugins/ticketcleaner/pictures"; - $files = scandir( $dir ); - - $lastupdate =""; - $query = "SELECT * FROM `glpi_plugin_ticketcleaner_picturehashes_lastupdate`;"; - $res = $DB->query($query); - if ($DB->numrows($res) > 0) { - $row = $DB->fetch_array($res); - $lastupdate = $row['lastupdate']; + global $DB; + + // now fill the table + // get files from plugin pictures folder + $dir = GLPI_ROOT . "/plugins/ticketcleaner/pictures"; + $files = scandir( $dir ); + + $lastupdate =""; + $res = $DB->request('glpi_plugin_ticketcleaner_picturehashes_lastupdate'); + if ($res->numrows() > 0) { + //$row = $DB->fetch_array($res); + $row = $res->next(); + $lastupdate = $row['lastupdate']; } - $stats = stat($dir); - $datetime = date( "YmdHis", $stats['mtime'] ); + $stats = stat($dir); + $datetime = date( "YmdHis", $stats['mtime'] ); if ($datetime > $lastupdate) { // means picture folder has been modified since last update - $DB->query("TRUNCATE TABLE glpi_plugin_ticketcleaner_picturehashes"); //or die("error on 'truncate' glpi_plugin_ticketcleaner_picturehashes ". $DB->error()) ; - // compute hash for each file and then insert it in DB with REPLACE INTO to prvent double entries + $DB->query("TRUNCATE TABLE glpi_plugin_ticketcleaner_picturehashes"); //or die("error on 'truncate' glpi_plugin_ticketcleaner_picturehashes ". $DB->error()) ; + // compute hash for each file and then insert it in DB with REPLACE INTO to prvent double entries foreach ($files as $pict) { if ($pict <> "." && $pict <> "..") { $sha = sha1_file( $dir."/".$pict ); - $query = "INSERT INTO `glpi_plugin_ticketcleaner_picturehashes` (`hash`, `filename`) VALUES ('".$sha."', '".$pict."');"; - $DB->query($query) or die("error on 'insert' into glpi_plugin_ticketcleaner_picturehashes with ".$pict." hash: ". $DB->error()); + $DB->insertOrDie( + 'glpi_plugin_ticketcleaner_picturehashes', + [ + 'hash' => $sha, + 'filename' => $pict + ], + "error on 'insert' into glpi_plugin_ticketcleaner_picturehashes with ".$pict." hash: ". $DB->error() + ); } } @@ -56,13 +88,17 @@ function loadSha1IntoDB() { Toolbox::logInFile('TicketCleaner', "No files in '".$dir."'.\n" ); } - // update of lastupdate into DB, with $datetime - $query = "REPLACE INTO `glpi_plugin_ticketcleaner_picturehashes_lastupdate` SET lastupdate='".$datetime."', id=1;"; - $res = $DB->query($query); + // update of lastupdate into DB, with $datetime + $DB->update( + 'glpi_plugin_ticketcleaner_picturehashes_lastupdate', + ['lastupdate' => $datetime], + ['id=1'] + ); } } + /** * Summary of plugin_ticketcleaner_install * Installs plugin into current GLPI instance @@ -100,7 +136,7 @@ function plugin_ticketcleaner_install() { $DB->query($query) or die("error creating glpi_plugin_ticketcleaner_picturehashes " . $DB->error()); } - loadSha1IntoDB(); // also done on the fly + loadSha1IntoDB(); // also done on the fly if ($DB->tableExists("backup_glpi_plugin_ticketcleaner_filters")) { $query = "DROP TABLE `backup_glpi_plugin_ticketcleaner_filters`;"; @@ -133,10 +169,11 @@ function plugin_ticketcleaner_install() { ENGINE=InnoDB ;"; - $DB->query($query) or die("error creating glpi_plugin_ticketcleaner_filters " . $DB->error()); + $DB->query($query) or die("error creating glpi_plugin_ticketcleaner_filters " . $DB->error()); + } else { // change regex and replacement field type - $fields = $DB->list_fields( 'glpi_plugin_ticketcleaner_filters' ); + $fields = $DB->listFields( 'glpi_plugin_ticketcleaner_filters' ); if (strcasecmp( $fields['regex']['Type'], 'text' ) != 0) { $query = "ALTER TABLE `glpi_plugin_ticketcleaner_filters` @@ -149,10 +186,11 @@ function plugin_ticketcleaner_install() { CHANGE COLUMN `regex` `regex` TEXT NOT NULL AFTER `order` , CHANGE COLUMN `replacement` `replacement` TEXT NOT NULL AFTER `regex`;"; $DB->query($query) or die("error changing type of 'regex' and 'replacement' in glpi_plugin_ticketcleaner_filters " . $DB->error()); + } } - return true; + return true; } @@ -165,7 +203,7 @@ function plugin_ticketcleaner_install() { function plugin_ticketcleaner_uninstall() { global $DB; - // Current version tables + // Current version tables if ($DB->tableExists("glpi_plugin_ticketcleaner_picturehashes")) { $query = "DROP TABLE `glpi_plugin_ticketcleaner_picturehashes`"; $DB->query($query) or die("error deleting glpi_plugin_ticketcleaner_picturehashes"); @@ -176,7 +214,7 @@ function plugin_ticketcleaner_uninstall() { $DB->query($query) or die("error deleting glpi_plugin_ticketcleaner_picturehashes_lastupdate"); } - return true; + return true; } @@ -188,175 +226,203 @@ function plugin_ticketcleaner_uninstall() { */ class PluginTicketCleaner { - /** - * Summary of cleanText - * @param $parm contains current object (i.e. a Ticket or a TicketFollowup) - * loads filters from DB and applies them to object name and content. - * Filters are divided into a type and an order - * types (0 - 3): - * 0 - 1: filters of this type are used to delete any signature from content of ticket or content of follow-ups - * 0: regex for begin of signature - * 1: regex for end of signature - * 2 : filters of this type are used to delete (or replace) any text that will match a regex from content of Tickets or content of Followups - * 3 : filters of this type are used to delete (or replace) any text that will match a regex from name (=title) of Tickets - * orders (0 - n): used to apply filters in this defined order - * see filter examples in Plugin website - */ + /** + * Summary of cleanText + * @param $parm CommonDBTM contains current object (i.e. a Ticket or a TicketFollowup) + * loads filters from DB and applies them to object name and content. + * Filters are divided into a type and an order + * types (0 - 3): + * 0 - 1: filters of this type are used to delete any signature from content of ticket or content of follow-ups + * 0: regex for begin of signature + * 1: regex for end of signature + * 2 : filters of this type are used to delete (or replace) any text that will match a regex from content of Tickets or content of Followups + * 3 : filters of this type are used to delete (or replace) any text that will match a regex from name (=title) of Tickets + * orders (0 - n): used to apply filters in this defined order + * see filter examples in Plugin website + */ public static function cleanText($parm) { - global $DB; + global $DB; - $is_content = array_key_exists('content', $parm->input); - $is_name = array_key_exists('name', $parm->input); + $is_content = array_key_exists('content', $parm->input); + $is_name = array_key_exists('name', $parm->input); if ($is_content || $is_name) { - // load filters from DB - $filters = [ ]; - $query = "SELECT * FROM glpi_plugin_ticketcleaner_filters WHERE is_active=1 ORDER BY type, `order`;"; - - // preparation for starts of filter - foreach ($DB->request($query) as $filter) { + // load filters from DB + $filters = [ ]; + $res = $DB->request([ + 'FROM' => 'glpi_plugin_ticketcleaner_filters', + 'WHERE'=> [ + 'is_active' => 1 + ], + 'ORDER'=> ['type', 'order'] + ]); + + // preparation for starts of filter + //foreach ($DB->request($query) as $filter) { + foreach ($res as $filter) { $filters[ $filter['type'] ][] = $filter; } + $is_debug = isset($_SESSION['glpi_use_mode']) && ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE); + if ($is_content && isset($filters[ PluginTicketcleanerFilter::DESCRIPTION_TYPE ])) { $temp_content = $parm->input['content']; - if (isset($_SESSION['glpi_use_mode']) && ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE)) { + if ($is_debug) { Toolbox::logInFile('TicketCleaner', "\tInitial text content: " . $temp_content . "\n" ); } - //////////////////// - // GLPI fixes - // cases of the " that are converted into '; instead of " in GLPI 9.2, 9.3 and 9.4 - $temp_content = str_replace('\\\';', '\\"', $temp_content); - // End of GLPI fixes - //////////////////// // unsanitize doesn't exist, so reverse one by one the sanitize $temp_content = Toolbox::unclean_cross_side_scripting_deep($temp_content); $temp_content = Toolbox::stripslashes_deep($temp_content); - if (isset($_SESSION['glpi_use_mode']) && ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE)) { + if ($is_debug) { Toolbox::logInFile('TicketCleaner', "\tText content after un-sanitize: " . $temp_content . "\n" ); } + $did_something = false; foreach ($filters[ PluginTicketcleanerFilter::DESCRIPTION_TYPE ] as $ptn) { - $temp_content = preg_replace( $ptn['regex'], $ptn['replacement'], $temp_content ); - if (isset($_SESSION['glpi_use_mode']) && ($_SESSION['glpi_use_mode'] == Session::DEBUG_MODE)) { - Toolbox::logInFile('TicketCleaner', "\tAfter filter: " . $ptn['name'] . "\t text: " . $temp_content . "\n" ); + $temp_content_new = preg_replace( $ptn['regex'], $ptn['replacement'], $temp_content ); + if ($temp_content_new != $temp_content) { + $did_something = true; + $temp_content = $temp_content_new; + if ($is_debug) { + Toolbox::logInFile('TicketCleaner', "\tText content after filter: " . $ptn['name'] . "\t content: " . $temp_content . "\n" ); + } } } - $temp_content = Toolbox::sanitize([$temp_content]); // sanitize only accepts an array - $parm->input['content'] = $temp_content[0]; + if ($did_something) { + $temp_content = Toolbox::sanitize([$temp_content]); // sanitize only accepts an array + $parm->input['content'] = $temp_content[0]; + } } if ($is_name && isset($filters[ PluginTicketcleanerFilter::TITLE_TYPE ])) { + if ($is_debug) { + Toolbox::logInFile('TicketCleaner', "\tInitial text title: " . $parm->input['name'] . "\n" ); + } + $temp_title = $parm->input['name']; + $did_something = false; foreach ($filters[ PluginTicketcleanerFilter::TITLE_TYPE ] as $ptn) { - $parm->input['name'] = preg_replace( $ptn['regex'], $ptn['replacement'], $parm->input['name'] ); + $temp_title_new = preg_replace( $ptn['regex'], $ptn['replacement'], $temp_title ); + if ($temp_title_new != $temp_title) { + $temp_title = $temp_title_new; + $did_something = true; + if ($is_debug) { + Toolbox::logInFile('TicketCleaner', "\tText title after filter: " . $ptn['name'] . "\t title: " . $temp_title . "\n" ); + } + } + } + if ($did_something) { + $parm->input['name'] = $temp_title; } } } } - /** - * Summary of cleanImages - * @param $parm contains current object (i.e. a Ticket or a TicketFollowup) - * For each picture a log is written into TicketCleaner log file to indicate - * if it has been deleted or not - */ + + /** + * Summary of cleanImages + * @param $parm CommonDBTM contains current object (i.e. a Ticket or a TicketFollowup) + * For each picture a log is written into TicketCleaner log file to indicate + * if it has been deleted or not + */ public static function cleanImages($parm) { - global $DB; + global $DB; - // this ticket has been created via email receiver. - // has any FILE attached to it? + // this ticket has been created via email receiver. + // has any FILE attached to it? if (array_key_exists('name', $parm->input) && array_key_exists('_mailgate', $parm->input) && array_key_exists('_filename', $parm->input) && is_array($parm->input['_filename']) ) { - // if necessary will reload sha1 - loadSha1IntoDB(); + // if necessary will reload sha1 + loadSha1IntoDB(); - $msg_log = "Ticket: '".$parm->input['name']."'\n"; + $msg_log = "Ticket: '".$parm->input['name']."'\n"; - // signature FILES are deleted from array $parm->input['_filename'] + // signature FILES are deleted from array $parm->input['_filename'] - // load pictures signatures from DB - $files_hash = [ ]; - $query = "SELECT hash FROM glpi_plugin_ticketcleaner_picturehashes"; + // load pictures signatures from DB + $files_hash = [ ]; + $res = $DB->request([ + 'SELECT' => 'hash', + 'FROM' => 'glpi_plugin_ticketcleaner_picturehashes' + ]); - foreach ($DB->request($query) as $data) { + foreach ($res as $data) { $files_hash[] = $data['hash']; } foreach ($parm->input['_filename'] as $loc_key => $loc_file) { $loc_file = GLPI_TMP_DIR. "/$loc_file"; - $loc_type = Toolbox::getMime( $loc_file ); - $loc_sha = ""; - $loc_deleted = false; + $loc_type = Toolbox::getMime( $loc_file ); + $loc_sha = ""; + $loc_deleted = false; if (stripos( $loc_type, "IMAGE/") !== false) { - $loc_sha = sha1_file( $loc_file ); + $loc_sha = sha1_file( $loc_file ); if (in_array($loc_sha, $files_hash)) { - unset($parm->input['_filename'][$loc_key]); - unlink($loc_file); + unset($parm->input['_filename'][$loc_key]); + unlink($loc_file); if (isset( $parm->input['_tag'][$loc_key] )) { // remove the tag from content $parm->input['content'] = str_replace( "#".$parm->input['_tag'][$loc_key]."#", "", $parm->input['content'] ); unset($parm->input['_tag'][$loc_key]); } - $loc_deleted = true; + $loc_deleted = true; } } if ($loc_sha <> "") { - $msg_log .= "\tFile: '".$loc_file."'\ttype: '".$loc_type."'\tsha1: '".$loc_sha."'\tdeleted: '".($loc_deleted?"True":"False")."'\n"; + $msg_log .= "\tFile: '".$loc_file."'\ttype: '".$loc_type."'\tsha1: '".$loc_sha."'\tdeleted: '".($loc_deleted?"True":"False")."'\n"; } else { $msg_log .= "\tFile: '".$loc_file."'\ttype: '".$loc_type."'\n"; } } - Toolbox::logInFile('TicketCleaner', $msg_log ); + Toolbox::logInFile('TicketCleaner', $msg_log ); } } - /** - * Summary of plugin_pre_item_add_ticketcleaner - * @param $parm contains current object (i.e. a Ticket or a TicketFollowup) - */ - public static function plugin_pre_item_add_ticketcleaner($parm) { - global $DB, $GLOBALS; - PluginTicketCleaner::cleanText($parm); + /** + * Summary of plugin_pre_item_add_ticketcleaner + * @param $parm CommonDBTM contains current object (i.e. a Ticket or a TicketFollowup) + */ + public static function plugin_pre_item_add_ticketcleaner($parm) { + PluginTicketCleaner::cleanText($parm); - PluginTicketCleaner::cleanImages($parm); + PluginTicketCleaner::cleanImages($parm); } - /** - * Summary of plugin_pre_item_add_ticketcleaner_followup - * @param $parm contains current object (i.e. a Ticket or a TicketFollowup) - */ - public static function plugin_pre_item_add_ticketcleaner_followup($parm) { - global $DB; - PluginTicketCleaner::cleanText($parm); + /** + * Summary of plugin_pre_item_add_ticketcleaner_followup + * @param $parm CommonDBTM contains current object (i.e. a Ticket or a TicketFollowup) + */ + public static function plugin_pre_item_add_ticketcleaner_followup($parm) { + PluginTicketCleaner::cleanText($parm); - PluginTicketCleaner::cleanImages($parm); + PluginTicketCleaner::cleanImages($parm); } - /** - * Summary of plugin_pre_item_update_ticketcleaner - * @param $parm contains current object (i.e. a Ticket or a TicketFollowup) - */ + + /** + * Summary of plugin_pre_item_update_ticketcleaner + * @param $parm CommonDBTM contains current object (i.e. a Ticket or a TicketFollowup) + */ public static function plugin_pre_item_update_ticketcleaner($parm) { - PluginTicketCleaner::cleanText($parm); + PluginTicketCleaner::cleanText($parm); } - /** - * Summary of plugin_pre_item_update_ticketcleaner_followup - * @param $parm contains current object (i.e. a Ticket or a TicketFollowup) - */ + /** + * Summary of plugin_pre_item_update_ticketcleaner_followup + * @param $parm CommonDBTM contains current object (i.e. a Ticket or a TicketFollowup) + */ public static function plugin_pre_item_update_ticketcleaner_followup($parm) { - PluginTicketCleaner::cleanText($parm); + PluginTicketCleaner::cleanText($parm); } } diff --git a/inc/filter.class.php b/inc/filter.class.php index c5c80b2..9e37f8a 100644 --- a/inc/filter.class.php +++ b/inc/filter.class.php @@ -1,4 +1,30 @@ . +-------------------------------------------------------------------------- + */ if (!defined('GLPI_ROOT')) { die("Sorry. You can't access directly to this file"); @@ -282,9 +308,11 @@ function showForm ($ID, $options = ['candel'=>false]) { echo ""; echo "".__("Name")." :"; - echo ""; + // echo ""; + echo ""; echo "".__("Comments")." :"; - echo ""; + // echo ""; + echo ""; echo ""; echo ""; diff --git a/inc/menu.class.php b/inc/menu.class.php index 728066c..40c1ffb 100644 --- a/inc/menu.class.php +++ b/inc/menu.class.php @@ -1,4 +1,31 @@ . +-------------------------------------------------------------------------- + */ + class PluginTicketcleanerMenu extends CommonGLPI { static $rightname = 'entity'; diff --git a/inc/user.class.php b/inc/user.class.php index 11ac7d4..8a5036e 100644 --- a/inc/user.class.php +++ b/inc/user.class.php @@ -1,30 +1,30 @@ . +along with this plugin. If not, see . -------------------------------------------------------------------------- -*/ + */ /** * PluginTicketcleanerUser short summary. diff --git a/purgepictures.php b/purgepictures.php index 5ba29f9..e159faa 100644 --- a/purgepictures.php +++ b/purgepictures.php @@ -1,11 +1,34 @@ . +-------------------------------------------------------------------------- + */ // ---------------------------------------------------------------------- // Original Author of file: Olivier Moron -// Purpose of file: script to be used to purge logos from DB +// Purpose of file: script to be used to purge logos (or any images) from DB // ---------------------------------------------------------------------- // Ensure current directory as run command prompt @@ -20,20 +43,19 @@ loadSha1IntoDB(); // to be sure sha1 are up to date // get hashes from DB -$query = "SELECT * FROM `glpi_plugin_ticketcleaner_picturehashes` ;"; -$res = $DB->query($query); +$res = $DB->request('glpi_plugin_ticketcleaner_picturehashes'); -foreach ($DB->request($query) as $file_hash) { - // search if this document is already in the DB +foreach ($res as $file_hash) { + // search if this document is already in the DB - $doc = new Document(); + $doc = new Document(); - $criteria = ['sha1sum' => $file_hash['hash'] ]; + $criteria = ['sha1sum' => $file_hash['hash'] ]; foreach ($DB->request($doc->getTable(), $criteria) as $data) { - $doc->fields = $data; - echo "Document: ".$doc->fields['users_id']." - ".$doc->fields['id']." - ".$doc->fields['tickets_id']." - ".$doc->fields['name']." - ".$doc->fields['filename']." - ".$doc->fields['filepath']; - if ($doc->fields['users_id'] == 0) { // 0 means cron_mail_ate + $doc->fields = $data; + echo "Document: ".$doc->fields['users_id']." - ".$doc->fields['id']." - ".$doc->fields['tickets_id']." - ".$doc->fields['name']." - ".$doc->fields['filename']." - ".$doc->fields['filepath']; + if ($doc->fields['users_id'] == 0) { // 0 means cron_mailgate if ($doc->deleteFromDB(1)) { // logs history $changes[0] = 0; @@ -41,7 +63,7 @@ Log::history($doc->fields["id"], $doc->getType(), $changes, 0, Log::HISTORY_DELETE_ITEM); echo " --> Deleted\n"; } else { - echo " --> Not Deleted\n"; + echo " --> Not Deleted\n"; } } else { echo " --> Kept\n"; @@ -50,7 +72,3 @@ } } - - - - diff --git a/setup.php b/setup.php index a05faae..88e203a 100644 --- a/setup.php +++ b/setup.php @@ -1,4 +1,31 @@ . +-------------------------------------------------------------------------- + */ + // ---------------------------------------------------------------------- // Original Author of file: Olivier Moron @@ -8,14 +35,13 @@ // and it cleans attached pictures to emails // It has been succesfully tested with plain TEXT and HTML emails // ---------------------------------------------------------------------- -define ("PLUGIN_TICKETCLEANER_VERSION", "2.5.1"); +define ("PLUGIN_TICKETCLEANER_VERSION", "3.0.0"); /** * Summary of plugin_init_ticketcleaner * Initializes class, and plugin hooks */ function plugin_init_ticketcleaner() { - global $PLUGIN_HOOKS, $CFG_GLPI, $DEFAULT_PLURAL_NUMBER; if ((!isset($_SESSION["glpicronuserrunning"]) || (Session::getLoginUserID() != $_SESSION["glpicronuserrunning"])) && !isset($_SESSION['glpiticketcleanertranslationmode'])) { @@ -27,13 +53,13 @@ function plugin_init_ticketcleaner() { $PLUGIN_HOOKS['csrf_compliant']['ticketcleaner'] = true; $PLUGIN_HOOKS['pre_item_add']['ticketcleaner'] = [ - 'Ticket' => ['PluginTicketCleaner', 'plugin_pre_item_add_ticketcleaner'], - 'ITILFollowup' => ['PluginTicketCleaner', 'plugin_pre_item_add_ticketcleaner_followup'] - ]; + 'Ticket' => ['PluginTicketCleaner', 'plugin_pre_item_add_ticketcleaner'], + 'ITILFollowup' => ['PluginTicketCleaner', 'plugin_pre_item_add_ticketcleaner_followup'] + ]; $PLUGIN_HOOKS['pre_item_update']['ticketcleaner'] = [ - 'Ticket' => ['PluginTicketCleaner', 'plugin_pre_item_update_ticketcleaner'], - 'ITILFollowup' => ['PluginTicketCleaner', 'plugin_pre_item_update_ticketcleaner_followup'] - ]; + 'Ticket' => ['PluginTicketCleaner', 'plugin_pre_item_update_ticketcleaner'], + 'ITILFollowup' => ['PluginTicketCleaner', 'plugin_pre_item_update_ticketcleaner_followup'] + ]; $plugin = new Plugin(); if ($plugin->isInstalled('ticketcleaner') @@ -43,7 +69,7 @@ function plugin_init_ticketcleaner() { // show tab in user config to show translation switch Plugin::registerClass('PluginTicketcleanerUser', - ['addtabon' => ['Preference', 'User']]); + ['addtabon' => ['Preference', 'User']]); // Display a menu entry $PLUGIN_HOOKS['menu_toadd']['ticketcleaner'] = ['config' => 'PluginTicketcleanerMenu']; @@ -73,14 +99,20 @@ function plugin_init_ticketcleaner() { * @return name and version of the plugin */ function plugin_version_ticketcleaner() { - global $LANG; + //global $LANG; return ['name' => 'Ticket Cleaner', - 'version' => PLUGIN_TICKETCLEANER_VERSION, - 'author' => 'Olivier Moron', - 'license' => 'AGPLv3+', - 'homepage' => '', - 'minGlpiVersion' => '0.92']; + 'version' => PLUGIN_TICKETCLEANER_VERSION, + 'author' => 'Olivier Moron', + 'license' => 'GPLv3+', + 'homepage' => 'https://github.com/tomolimo/ticketcleaner', + 'requirements' => [ + 'glpi' => [ + 'min' => '9.5', + 'max' => '9.6' + ], + ] + ]; } @@ -89,8 +121,8 @@ function plugin_version_ticketcleaner() { * @return false when GLPI version is not ok! */ function plugin_ticketcleaner_check_prerequisites() { - if (version_compare(GLPI_VERSION, '9.2', 'lt')) { - echo "This plugin requires GLPI >= 9.2"; + if (version_compare(GLPI_VERSION, '9.5', 'lt') || version_compare(GLPI_VERSION, '9.6', 'ge')) { + echo "This plugin requires GLPI >= 9.5 and < 9.6"; return false; } return true; @@ -98,7 +130,7 @@ function plugin_ticketcleaner_check_prerequisites() { /** * Summary of plugin_ticketcleaner_check_config - * @return always true + * @return true */ function plugin_ticketcleaner_check_config() { return true; diff --git a/swipe.png b/swipe.png new file mode 100644 index 0000000000000000000000000000000000000000..6285b3e348993862e6b4417f7ea1a4cae3babd60 GIT binary patch literal 45521 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 literal 0 HcmV?d00001 diff --git a/ticketcleaner.xml b/ticketcleaner.xml index 806b3f3..03371b7 100644 --- a/ticketcleaner.xml +++ b/ticketcleaner.xml @@ -3,7 +3,7 @@ Ticket Cleaner ticketcleaner stable - + https://raw.githubusercontent.com/tomolimo/ticketcleaner/master/swipe.png @@ -53,17 +53,21 @@ This plugin adds the possibility to translate it 'inline', see wiki.]]> 9.1 - 2.3.4 + 2.3.5 9.2 - 2.4.1 + 2.4.2 9.3 - 2.5.1 + 2.5.3 9.4 + + 3.0.0 + 9.5 + Any @@ -71,12 +75,14 @@ This plugin adds the possibility to translate it 'inline', see wiki.]]> - Ticket - mail + Ticket + Filtre + mail Ticket - mail + Filter + eMail \ No newline at end of file