diff --git a/inc/command/cleanticketscommand.class.php b/inc/command/cleanticketscommand.class.php
index cbcd37702..b8c2a2371 100644
--- a/inc/command/cleanticketscommand.class.php
+++ b/inc/command/cleanticketscommand.class.php
@@ -31,13 +31,15 @@
namespace GlpiPlugin\Formcreator\Command;
+use ITILFollowup;
+use QuerySubQuery;
use Symfony\Component\Console\Command\Command;
+use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Ticket;
use Item_Ticket;
use PluginFormcreatorFormAnswer;
-use Glpi\Toolbox\Sanitizer;
class CleanTicketsCommand extends Command
{
@@ -48,66 +50,108 @@ protected function configure() {
}
protected function execute(InputInterface $input, OutputInterface $output) {
- $output->write("-> Search tickets to clean...");
- $output->writeln("");
+ $message = __("Searching for invalid items...", "formcreator");
+ $output->writeln("$message");
$this->fixBadForm_1($input, $output);
$this->fixBadForm_2($input, $output);
$this->fixBadForm_3($input, $output);
- $output->writeln('Done.');
- return 0;
+ $output->writeln("");
+ $message = __("Done.", "formcreator");
+ $output->writeln("$message");
+
+ return Command::SUCCESS;
}
/**
- * fix HTML tags double encoded
- *
=> <p> => <p>
+ * Get invalid data using a specific regex pattern to detect invalid content
*
- * @param InputInterface $input
- * @param OutputInterface $output
- * @return void
+ * @param string $invalid_content_pattern
+ *
+ * @return iterable
*/
- protected function fixBadForm_1(InputInterface $input, OutputInterface $output) {
+ protected function getInvalidData(string $invalid_content_pattern): iterable {
global $DB;
- // Search tickets having HTML tags in content in the following form
- // <p>Hello world</p>
- // Hello world is between
and
, but with wrong escaping
- $itemTicketTable = Item_Ticket::getTable();
- $ticketTable = Ticket::getTable();
- $pattern = '<';
- // $pattern = str_replace(';', '\\;', $pattern);
- $tickets = $DB->request([
- 'SELECT' => [$ticketTable => [Ticket::getIndexName(), 'content']],
- 'FROM' => $ticketTable,
+ $item_ticket_table = Item_Ticket::getTable();
+ $ticket_table = Ticket::getTable();
+ $followup_table = ITILFollowup::getTable();
+
+ // First source: tickets description
+ $tickets_query = new QuerySubQuery([
+ 'SELECT' => [
+ new \QueryExpression($DB->quoteValue(Ticket::getType()) . ' AS ' . $DB->quoteName('itemtype')),
+ $ticket_table => [Ticket::getIndexName(), 'content']
+ ],
+ 'FROM' => $ticket_table,
'INNER JOIN' => [
- $itemTicketTable => [
+ $item_ticket_table => [
'FKEY' => [
- $ticketTable => Ticket::getIndexName(),
- $itemTicketTable => Ticket::getForeignKeyField(),
+ $ticket_table => Ticket::getIndexName(),
+ $item_ticket_table => Ticket::getForeignKeyField(),
],
'AND' => [
- "$itemTicketTable.itemtype" => PluginFormcreatorFormAnswer::getType(),
+ "$item_ticket_table.itemtype" => PluginFormcreatorFormAnswer::getType(),
]
],
],
'WHERE' => [
- "$ticketTable.content" => ['LIKE', '%' . $pattern . '%'], // Matches bad encoding for '<'
+ "$ticket_table.content" => ['LIKE', '%' . $invalid_content_pattern . '%'],
],
]);
- $count = $tickets->count();
- if ($count < 1) {
- $output->writeln('-> No ticket to fix.');
- $output->writeln("");
- return 0;
- }
+ // Second source: tickets that where merged into other tickets as a followup
+ // These followups may have been a former ticket generated by formcreator
+ $followup_query = new QuerySubquery([
+ 'SELECT' => [
+ new \QueryExpression($DB->quoteValue(ITILFollowup::getType()) . ' AS ' . $DB->quoteName('itemtype')),
+ ITILFollowup::getIndexName(),
+ 'content'
+ ],
+ 'FROM' => $followup_table,
+ 'WHERE' => [
+ "sourceitems_id" => [">", 0], // Former tickets merged as followups
+ "$followup_table.content" => ['LIKE', '%' . $invalid_content_pattern . '%'],
+ ],
+ ]);
- $output->write("-> Found $count tickets to clean (double encoded < and > signs)");
- $output->writeln("");
- $output->write("-> Cleaning tickets...");
+ return $DB->request(new \QueryUnion([$tickets_query, $followup_query]));
+ }
+
+ /**
+ * fix HTML tags double encoded
+ * => <p> => <p>
+ *
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return void
+ */
+ protected function fixBadForm_1(InputInterface $input, OutputInterface $output) {
+ global $DB;
+
+ // Print step info
$output->writeln("");
- foreach ($tickets as $row) {
+ $message = __("Step 1: double encoded < and > signs.", "formcreator");
+ $output->writeln("$message");
+
+ // Search tickets having HTML tags in content in the following form
+ // <p>Hello world</p>
+ // Hello world is between
and
, but with wrong escaping
+ $items = $this->getInvalidData('<'); // Matches bad encoding for '<'
+
+ // No items found, nothing to do
+ $count = $items->count();
+ if ($count === 0) {
+ $output->writeln(__("No invalid items found.", "formcreator"));
+ return;
+ }
+
+ // Init progress bar
+ $output->writeln(__("Found $count item(s) to clean.", "formcreator"));
+ $progress_bar = new ProgressBar($output);
+
+ foreach ($progress_bar->iterate($items) as $item) {
$pattern = [
'/<([a-z0-9]+?)>/',
'/<(\/[a-z0-9]+?)>/',
@@ -116,18 +160,16 @@ protected function fixBadForm_1(InputInterface $input, OutputInterface $output)
'<$1>',
'<$1>',
];
- $row['content'] = preg_replace($pattern, $replace, $row['content']);
+ $item['content'] = preg_replace($pattern, $replace, $item['content']);
+
// Direct write to the table to avoid alteration of other fields
$DB->update(
- $ticketTable,
- [
- 'content' => $DB->escape($row['content'])
- ],
- [
- 'id' => $row['id'],
- ]
+ $item['itemtype']::getTable(),
+ ['content' => $DB->escape($item['content'])],
+ ['id' => $item['id']]
);
}
+ $output->writeln("");
}
/**
@@ -140,72 +182,56 @@ protected function fixBadForm_1(InputInterface $input, OutputInterface $output)
protected function fixBadForm_2(InputInterface $input, OutputInterface $output) {
global $DB;
+ // Print step info
+ $output->writeln("");
+ $message = __("Step 2: literal BR tag.", "formcreator");
+ $output->writeln("$message");
+
// Search tickets having HTML tags
- $itemTicketTable = Item_Ticket::getTable();
- $ticketTable = Ticket::getTable();
- $pattern = '
';
- $tickets = $DB->request([
- 'SELECT' => [$ticketTable => [Ticket::getIndexName(), 'content']],
- 'FROM' => $ticketTable,
- 'INNER JOIN' => [
- $itemTicketTable => [
- 'FKEY' => [
- $ticketTable => Ticket::getIndexName(),
- $itemTicketTable => Ticket::getForeignKeyField(),
- ],
- 'AND' => [
- "$itemTicketTable.itemtype" => PluginFormcreatorFormAnswer::getType(),
- ]
- ],
- ],
- 'WHERE' => [
- "$ticketTable.content" => ['LIKE', '%' . $pattern . '%'], // Matches bad encoding for 'br /'
- ],
- ]);
+ $items = $this->getInvalidData('
'); // Matches bad encoding for 'br /'
- $count = $tickets->count();
- if ($count < 1) {
- $output->writeln('-> No ticket to fix.');
- $output->writeln("");
- return 0;
+ // No items found, nothing to do
+ $count = $items->count();
+ if ($count === 0) {
+ $output->writeln(__("No invalid items found.", "formcreator"));
+ return;
}
- $output->write("-> Found $count tickets to clean (literal BR tag)");
- $output->writeln("");
- $output->write("-> Cleaning tickets...");
- $output->writeln("");
- foreach ($tickets as $row) {
+ // Init progress bar
+ $output->writeln(__("Found $count item(s) to clean.", "formcreator"));
+ $progress_bar = new ProgressBar($output);
+
+ foreach ($progress_bar->iterate($items) as $item) {
$pattern = [
'
',
];
// Determine if we must use legacy or new encoding
// @see Sanitizer::sanitize()
$replace = null;
- if (strpos($row['content'], '<') !== false && strpos($row['content'], '#60;') === false) {
+ if (strpos($item['content'], '<') !== false && strpos($item['content'], '#60;') === false) {
$replace = [
'<br />',
];
- } else if (strpos($row['content'], '#60') !== false && strpos($row['content'], '<') === false) {
+ } else if (strpos($item['content'], '#60') !== false && strpos($item['content'], '<') === false) {
$replace = [
'<br />',
];
}
if ($replace === null) {
- $output->write("-> Unable to determine the encoding type of ticket ID: " . $row['id']. "");
+ $message = __("Unable to determine the encoding type of item ID: %1$d", "formcreator");
+ $output->writeln("" . sprintf($message, $item['id']) . "");
continue;
}
- $row['content'] = str_replace($pattern, $replace, $row['content']);
+ $item['content'] = str_replace($pattern, $replace, $item['content']);
+
// Direct write to the table to avoid alteration of other fields
$DB->update(
- $ticketTable,
- [
- 'content' => $DB->escape($row['content'])
- ],
- [
- 'id' => $row['id'],
- ]
+ $item['itemtype']::getTable(),
+ ['content' => $DB->escape($item['content'])],
+ ['id' => $item['id']]
);
}
+ $output->writeln("");
}
/**
@@ -220,71 +246,55 @@ protected function fixBadForm_2(InputInterface $input, OutputInterface $output)
protected function fixBadForm_3(InputInterface $input, OutputInterface $output) {
global $DB;
+ // Print step info
+ $output->writeln("");
+ $message = __("Step 3: litteral > sign.", "formcreator");
+ $output->writeln("$message");
+
// Search tickets having HTML tags
- $itemTicketTable = Item_Ticket::getTable();
- $ticketTable = Ticket::getTable();
- $pattern = ' > '; // greater than sign with a space before and after
- $tickets = $DB->request([
- 'SELECT' => [$ticketTable => [Ticket::getIndexName(), 'content']],
- 'FROM' => $ticketTable,
- 'INNER JOIN' => [
- $itemTicketTable => [
- 'FKEY' => [
- $ticketTable => Ticket::getIndexName(),
- $itemTicketTable => Ticket::getForeignKeyField(),
- ],
- 'AND' => [
- "$itemTicketTable.itemtype" => PluginFormcreatorFormAnswer::getType(),
- ]
- ],
- ],
- 'WHERE' => [
- "$ticketTable.content" => ['LIKE', '%' . $pattern . '%'],
- ],
- ]);
+ $items = $this->getInvalidData(' > ');
- $count = $tickets->count();
- if ($count < 1) {
- $output->writeln('-> No ticket to fix.');
- $output->writeln("");
- return 0;
+ // No items found, nothing to do
+ $count = $items->count();
+ if ($count === 0) {
+ $output->writeln(__("No invalid items found.", "formcreator"));
+ return;
}
- $output->write("-> Found $count tickets to clean (litteral > sign)");
- $output->writeln("");
- $output->write("-> Cleaning tickets...");
- $output->writeln("");
- foreach ($tickets as $row) {
+ // Init progress bar
+ $output->writeln(__("Found $count item(s) to clean.", "formcreator"));
+ $progress_bar = new ProgressBar($output);
+
+ foreach ($progress_bar->iterate($items) as $item) {
$pattern = [
' > ',
];
// Determine if we must use legacy or new encoding
// @see Sanitizer::sanitize()
$replace = null;
- if (strpos($row['content'], '<') !== false && strpos($row['content'], '#60;') === false) {
+ if (strpos($item['content'], '<') !== false && strpos($item['content'], '#60;') === false) {
$replace = [
' > ',
];
- } else if (strpos($row['content'], '#60') !== false && strpos($row['content'], '<') === false) {
+ } else if (strpos($item['content'], '#60') !== false && strpos($item['content'], '<') === false) {
$replace = [
' & ',
];
}
if ($replace === null) {
- $output->write("-> Unable to determine the encoding type of ticket ID: " . $row['id']. "");
+ $message = __("Unable to determine the encoding type of item ID: %1$d", "formcreator");
+ $output->writeln("" . sprinf($message, $item['id']) . "");
continue;
}
- $row['content'] = str_replace($pattern, $replace, $row['content']);
+ $item['content'] = str_replace($pattern, $replace, $item['content']);
+
// Direct write to the table to avoid alteration of other fields
$DB->update(
- $ticketTable,
- [
- 'content' => $DB->escape($row['content'])
- ],
- [
- 'id' => $row['id'],
- ]
+ $item['itemtype']::getTable(),
+ ['content' => $DB->escape($item['content'])],
+ ['id' => $item['id']]
);
}
+ $output->writeln("");
}
}