Integrate database integrity module

This commit is contained in:
Eric
2019-12-13 17:28:08 +01:00
parent da3d886bd7
commit 2741a446ea
21 changed files with 2515 additions and 0 deletions

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('CS CZ', 'Czech', 'Čeština', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('DA DA', 'Danish', 'Dansk', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<menus>
<menu id="DBToolsMenu" xsi:type="WebPageMenuNode" _delta="define">
<rank>30</rank>
<parent>System</parent>
<url>$pages/exec.php?exec_module=combodo-db-tools&amp;exec_page=dbtools.php&amp;c[menu]=DBToolsMenu</url>
<enable_admin_only>1</enable_admin_only>
</menu>
</menus>
</itop_design>

View File

@@ -0,0 +1,476 @@
<?php
// Copyright (c) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
class DatabaseAnalyzer
{
var $iTimeLimitPerOperation;
public function __construct($iTimeLimitPerOperation = null)
{
$this->iTimeLimitPerOperation = $iTimeLimitPerOperation;
}
/**
* @param $sSelWrongRecs
* @param $sFixItRequest
* @param $sErrorDesc
* @param $sClass
* @param $aErrorsAndFixes
* @param array $aValueNames
*
* @throws \MySQLException
*/
private function ExecQuery($sSelWrongRecs, $sFixItRequest, $sErrorDesc, $sClass, &$aErrorsAndFixes, $aValueNames = array())
{
if (!is_null($this->iTimeLimitPerOperation))
{
set_time_limit($this->iTimeLimitPerOperation);
}
$aWrongRecords = CMDBSource::QueryToArray($sSelWrongRecs);
if (count($aWrongRecords) > 0)
{
foreach($aWrongRecords as $aRes)
{
if (!isset($aErrorsAndFixes[$sClass][$sErrorDesc]))
{
$aErrorsAndFixes[$sClass][$sErrorDesc] = array(
'count' => 1,
'query' => $sSelWrongRecs,
);
if (!empty($sFixItRequest))
{
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = array($sFixItRequest);
}
}
else
{
$aErrorsAndFixes[$sClass][$sErrorDesc]['count'] += 1;
}
if (empty($aValueNames))
{
$aValues = array('id' => $aRes['id']);
}
else
{
$aValues = array();
foreach ($aValueNames as $sValueName)
{
$aValues[$sValueName] = $aRes[$sValueName];
}
}
if (isset($aRes['value']))
{
$value = $aRes['value'];
$aValues['value'] = $value;
if (!isset($aErrorsAndFixes[$sClass][$sErrorDesc]['values'][$value]))
{
$aErrorsAndFixes[$sClass][$sErrorDesc]['values'][$value] = 1;
}
else
{
$aErrorsAndFixes[$sClass][$sErrorDesc]['values'][$value] += 1;
}
}
$aErrorsAndFixes[$sClass][$sErrorDesc]['res'][] = $aValues;
}
}
}
/**
* @param $aClassSelection
*
* @return array
* @throws \CoreException
* @throws \MySQLException
* @throws \Exception
*/
public function CheckIntegrity($aClassSelection)
{
// Getting and setting time limit are not symetric:
// www.php.net/manual/fr/function.set-time-limit.php#72305
$iPreviousTimeLimit = ini_get('max_execution_time');
$aErrorsAndFixes = array();
if (empty($aClassSelection))
{
$aClassSelection = MetaModel::GetClasses();
}
else
{
$aClasses = $aClassSelection;
foreach($aClasses as $sClass)
{
$aExpectedClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL);
$aClassSelection = array_merge($aClassSelection, $aExpectedClasses);
}
$aClassSelection = array_unique($aClassSelection);
}
foreach($aClassSelection as $sClass)
{
// Check uniqueness rules
if (method_exists('MetaModel', 'GetUniquenessRules'))
{
$this->CheckUniquenessRules($sClass, $aErrorsAndFixes);
}
if (!MetaModel::HasTable($sClass))
{
continue;
}
$sRootClass = MetaModel::GetRootClass($sClass);
$sTable = MetaModel::DBGetTable($sClass);
$sKeyField = MetaModel::DBGetKey($sClass);
if (!MetaModel::IsStandaloneClass($sClass))
{
if (!MetaModel::IsRootClass($sClass))
{
$sRootTable = MetaModel::DBGetTable($sRootClass);
$sRootKey = MetaModel::DBGetKey($sRootClass);
$this->CheckRecordsInRootTable($sTable, $sKeyField, $sRootTable, $sRootKey, $sClass, $aErrorsAndFixes);
$this->CheckRecordsInChildTable($sRootClass, $sClass, $sRootTable, $sRootKey, $sTable, $sKeyField, $aErrorsAndFixes);
}
}
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
{
// Skip this attribute if not defined in this table
if (!MetaModel::IsAttributeOrigin($sClass, $sAttCode))
{
continue;
}
if ($oAttDef->IsExternalKey())
{
$this->CheckExternalKeys($oAttDef, $sTable, $sKeyField, $sAttCode, $sClass, $aErrorsAndFixes);
}
elseif ($oAttDef->IsDirectField() && !($oAttDef instanceof AttributeTagSet))
{
$this->CheckEnums($sClass, $sAttCode, $oAttDef, $sTable, $sKeyField, $aErrorsAndFixes);
}
}
}
$this->CheckUsers($aErrorsAndFixes);
if (!is_null($this->iTimeLimitPerOperation))
{
set_time_limit($iPreviousTimeLimit);
}
return $aErrorsAndFixes;
}
/**
* @param $sClass
* @param $sUniquenessRuleId
* @param $aUniquenessRuleProperties
* @param $aErrorsAndFixes
*
* @throws \CoreException
* @throws \MissingQueryArgument
* @throws \MySQLException
* @throws \OQLException
* @throws \Exception
*/
private function CheckUniquenessRule($sClass, $sUniquenessRuleId, $aUniquenessRuleProperties, &$aErrorsAndFixes)
{
$sOqlUniquenessQuery = "SELECT $sClass";
if (!(empty($sUniquenessFilter = $aUniquenessRuleProperties['filter'])))
{
$sOqlUniquenessQuery .= ' WHERE '.$sUniquenessFilter;
}
$oUniquenessQuery = DBObjectSearch::FromOQL($sOqlUniquenessQuery);
$aValueNames = array();
$aGroupByExpr = array();
foreach ($aUniquenessRuleProperties['attributes'] as $sAttributeCode)
{
$oExpr = Expression::FromOQL("$sClass.$sAttributeCode");
$aGroupByExpr[$sAttributeCode] = $oExpr;
$aValueNames[] = $sAttributeCode;
}
$aSelectExpr = array();
$sSQLUniquenessQuery = $oUniquenessQuery->MakeGroupByQuery(array(), $aGroupByExpr, false, $aSelectExpr);
$sSQLUniquenessQuery .= ' having count(*) > 1';
$sErrorDesc = $this->GetUniquenessRuleMessage($sUniquenessRuleId);
$this->ExecQuery($sSQLUniquenessQuery, '', $sErrorDesc, $sClass, $aErrorsAndFixes, $aValueNames);
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['res']))
{
$aFixit = array("-- In order to get the duplicates, run the following queries:");
foreach ($aErrorsAndFixes[$sClass][$sErrorDesc]['res'] as $aValues)
{
$oFixSearch = new DBObjectSearch($sClass);
foreach ($aValues as $sAttCode => $sValue)
{
$oFixSearch->AddCondition($sAttCode, $sValue, '=');
}
$aFixit[] = $oFixSearch->MakeSelectQuery().';';
$aFixit[] = "";
}
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixit;
}
return;
}
private function GetUniquenessRuleMessage($sUniquenessRuleId)
{
// we could add also a specific message if user is admin ("dict key is missing")
return Dict::Format('Core:UniquenessDefaultError', $sUniquenessRuleId);
}
/**
* @param $sClass
* @param array $aErrorsAndFixes
*
* @throws \CoreException
*/
private function CheckUniquenessRules($sClass, &$aErrorsAndFixes)
{
if (method_exists('MetaModel', 'GetUniquenessRules'))
{
$aUniquenessRules = MetaModel::GetUniquenessRules($sClass);
foreach ($aUniquenessRules as $sUniquenessRuleId => $aUniquenessRuleProperties)
{
if ($aUniquenessRuleProperties['disabled'] === true)
{
continue;
}
$this->CheckUniquenessRule($sClass, $sUniquenessRuleId, $aUniquenessRuleProperties, $aErrorsAndFixes);
}
}
}
/**
* Check that any record found here has its counterpart in the root table
*
* @param $sTable
* @param $sKeyField
* @param $sRootTable
* @param $sRootKey
* @param $sClass
* @param array $aErrorsAndFixes
*
* @throws \MySQLException
*/
private function CheckRecordsInRootTable($sTable, $sKeyField, $sRootTable, $sRootKey, $sClass, &$aErrorsAndFixes)
{
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id";
$sDelete = "DELETE `$sTable`";
$sFilter = "FROM `$sTable` LEFT JOIN `$sRootTable` ON `$sTable`.`$sKeyField` = `$sRootTable`.`$sRootKey` WHERE `$sRootTable`.`$sRootKey` IS NULL";
$sSelectWrongRecs = "$sSelect $sFilter";
$sFixItRequest = "$sDelete $sFilter";
$this->ExecQuery($sSelectWrongRecs, $sFixItRequest, Dict::Format('DBAnalyzer-Integrity-OrphanRecord', $sTable, $sRootTable), $sClass, $aErrorsAndFixes);
}
/**
* Check that any record found in the root table and referring to a child class
* has its counterpart here (detect orphan nodes -root or in the middle of the hierarchy)
*
* @param $sRootClass
* @param $sClass
* @param $sRootTable
* @param $sRootKey
* @param $sTable
* @param $sKeyField
* @param array $aErrorsAndFixes
*
* @throws \CoreException
* @throws \MySQLException
*/
private function CheckRecordsInChildTable($sRootClass, $sClass, $sRootTable, $sRootKey, $sTable, $sKeyField, &$aErrorsAndFixes)
{
$sFinalClassField = MetaModel::DBGetClassField($sRootClass);
$aExpectedClasses = MetaModel::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL);
$sExpectedClasses = implode(",", CMDBSource::Quote($aExpectedClasses, true));
$sSelect = "SELECT DISTINCT `$sRootTable`.`$sRootKey` AS id";
$sDelete = "DELETE `$sRootTable`";
$sFilter = "FROM `$sRootTable` LEFT JOIN `$sTable` ON `$sRootTable`.`$sRootKey` = `$sTable`.`$sKeyField` WHERE `$sTable`.`$sKeyField` IS NULL AND `$sRootTable`.`$sFinalClassField` IN ($sExpectedClasses)";
$sSelWrongRecs = "$sSelect $sFilter";
$sFixItRequest = "$sDelete $sFilter";
$this->ExecQuery($sSelWrongRecs, $sFixItRequest, Dict::Format('DBAnalyzer-Integrity-OrphanRecord', $sRootTable, $sTable), $sRootClass, $aErrorsAndFixes);
}
/**
* Check that any external field is pointing to an existing object
*
* @param \AttributeDefinition $oAttDef
* @param $sTable
* @param $sKeyField
* @param $sAttCode
* @param $sClass
* @param array $aErrorsAndFixes
*
* @throws \CoreException
* @throws \MySQLException
*/
private function CheckExternalKeys(AttributeDefinition $oAttDef, $sTable, $sKeyField, $sAttCode, $sClass, &$aErrorsAndFixes)
{
$sRemoteClass = $oAttDef->GetTargetClass();
$sRemoteTable = MetaModel::DBGetTable($sRemoteClass);
$sRemoteKey = MetaModel::DBGetKey($sRemoteClass);
$aCols = $oAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
$sExtKeyField = current($aCols); // get the first column for an external key
// Note: a class/table may have an external key on itself
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id, `$sTable`.`$sExtKeyField` AS value";
$sFilter = "FROM `$sTable` LEFT JOIN `$sRemoteTable` AS `{$sRemoteTable}_1` ON `$sTable`.`$sExtKeyField` = `{$sRemoteTable}_1`.`$sRemoteKey`";
$sFilter = $sFilter." WHERE `{$sRemoteTable}_1`.`$sRemoteKey` IS NULL";
// Exclude the records pointing to 0/null from the errors (separate test below)
$sFilter .= " AND `$sTable`.`$sExtKeyField` IS NOT NULL";
$sFilter .= " AND `$sTable`.`$sExtKeyField` != 0";
$sSelWrongRecs = "$sSelect $sFilter";
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-InvalidExtKey', $sAttCode, $sTable, $sExtKeyField);
$this->ExecQuery($sSelWrongRecs, '', $sErrorDesc, $sClass, $aErrorsAndFixes);
// Fix it request needs the values of the enum to generate the requests
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['values']))
{
$aFixIt = array();
$aFixIt[] = "-- Remove inconsistant entries:";
$sIds = implode(', ', array_keys($aErrorsAndFixes[$sClass][$sErrorDesc]['values']));
$aFixIt[] = "DELETE `$sTable` FROM `$sTable` WHERE `$sTable`.`$sExtKeyField` IN ($sIds)";
$aFixIt[] = "";
$aFixIt[] = "-- Or fix inconsistant values: Replace XXX with the appropriate value";
foreach (array_keys($aErrorsAndFixes[$sClass][$sErrorDesc]['values']) as $sKey)
{
$aFixIt[] = "UPDATE `$sTable` SET `$sTable`.`$sExtKeyField` = XXX WHERE `$sTable`.`$sExtKeyField` = '$sKey'";
}
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixIt;
}
if (!$oAttDef->IsNullAllowed())
{
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id";
$sDelete = "DELETE `$sTable`";
$sFilter = "FROM `$sTable` WHERE `$sTable`.`$sExtKeyField` IS NULL OR `$sTable`.`$sExtKeyField` = 0";
$sSelWrongRecs = "$sSelect $sFilter";
$sFixItRequest = "$sDelete $sFilter";
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-MissingExtKey', $sAttCode, $sTable, $sExtKeyField);
$this->ExecQuery($sSelWrongRecs, $sFixItRequest, $sErrorDesc, $sClass, $aErrorsAndFixes);
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['count']) && ($aErrorsAndFixes[$sClass][$sErrorDesc]['count'] > 0))
{
$aFixIt = $aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'];
$aFixIt[] = "-- Alternate fix";
$aFixIt[] = "-- Replace XXX with the appropriate value";
$aFixIt[] = "UPDATE `$sTable` SET `$sTable`.`$sExtKeyField` = XXX WHERE `$sTable`.`$sExtKeyField` IS NULL OR `$sTable`.`$sExtKeyField` = 0";
$aAdditionalFixIt = $this->GetSpecificExternalKeysFixItForNull($sTable, $sExtKeyField);
foreach ($aAdditionalFixIt as $sFixIt)
{
$aFixIt[] = $sFixIt;
}
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixIt;
}
}
}
private function GetSpecificExternalKeysFixItForNull($sTable, $sExtKeyField)
{
$aFixIt = array();
if ($sTable == 'ticket' && $sExtKeyField == 'org_id')
{
$aFixIt[] = "-- Alternate fix: set the ticket org to the caller org";
$aFixIt[] = "UPDATE ticket AS t JOIN contact AS c ON t.caller_id=c.id SET t.org_id=c.org_id WHERE t.org_id IS NULL OR t.org_id = 0";
}
return $aFixIt;
}
/**
* Check that the values fit the allowed values
*
* @param $sClass
* @param $sAttCode
* @param \AttributeDefinition $oAttDef
* @param $sTable
* @param $sKeyField
* @param array $aErrorsAndFixes
*
* @throws \MySQLException
* @throws \Exception
*/
private function CheckEnums($sClass, $sAttCode, AttributeDefinition $oAttDef, $sTable, $sKeyField, &$aErrorsAndFixes)
{
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode);
if (!is_null($aAllowedValues) && count($aAllowedValues) > 0)
{
$sExpectedValues = implode(",", CMDBSource::Quote(array_keys($aAllowedValues), true));
$aCols = $oAttDef->GetSQLExpressions(); // Workaround a PHP bug: sometimes issuing a Notice if invoking current(somefunc())
$sMyAttributeField = current($aCols); // get the first column for the moment
$sFilter = "FROM `$sTable` WHERE `$sTable`.`$sMyAttributeField` NOT IN ($sExpectedValues)";
$sDelete = "DELETE `$sTable`";
$sSelect = "SELECT DISTINCT `$sTable`.`$sKeyField` AS id, `$sTable`.`$sMyAttributeField` AS value";
$sSelWrongRecs = "$sSelect $sFilter";
$sFixItRequest = "$sDelete $sFilter";
$sErrorDesc = Dict::Format('DBAnalyzer-Integrity-InvalidValue', $sAttCode, $sTable, $sMyAttributeField);
$this->ExecQuery($sSelWrongRecs, $sFixItRequest, $sErrorDesc, $sClass, $aErrorsAndFixes);
// Fix it request needs the values of the enum to generate the requests
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['values']))
{
if (isset($aErrorsAndFixes[$sClass][$sErrorDesc]['fixit']))
{
$aFixIt = $aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'];
$aFixIt[] = "-- Alternative: Replace 'XXX' with the appropriate value";
}
else
{
$aFixIt = array("-- Replace 'XXX' with the appropriate value");
}
foreach (array_keys($aErrorsAndFixes[$sClass][$sErrorDesc]['values']) as $sKey)
{
$aFixIt[] = "UPDATE `$sTable` SET `$sTable`.`$sMyAttributeField` = 'XXX' WHERE `$sTable`.`$sMyAttributeField` = '$sKey'";
}
$aErrorsAndFixes[$sClass][$sErrorDesc]['fixit'] = $aFixIt;
}
}
}
/**
* @param $aErrorsAndFixes
*
* @throws \CoreException
* @throws \MySQLException
*/
private function CheckUsers(&$aErrorsAndFixes)
{
// Check user accounts without profile
$sUserTable = MetaModel::DBGetTable('User');
$sLinkTable = MetaModel::DBGetTable('URP_UserProfile');
$sSelect = "SELECT DISTINCT u.id AS id, u.`login` AS value";
$sFilter = "FROM `$sUserTable` AS u LEFT JOIN `$sLinkTable` AS l ON l.userid = u.id WHERE l.id IS NULL";
$sSelWrongRecs = "$sSelect $sFilter";
$sFixit = "-- Remove the corresponding user(s)";
$this->ExecQuery($sSelWrongRecs, $sFixit, Dict::S('DBAnalyzer-Integrity-UsersWithoutProfile'), 'User', $aErrorsAndFixes);
}
}

View File

@@ -0,0 +1,536 @@
<?php
// Copyright (c) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
@include_once('../../approot.inc.php');
require_once(APPROOT.'application/startup.inc.php');
require_once('db_analyzer.class.inc.php');
const MAX_RESULTS = 10;
/**
* @param iTopWebPage $oP
* @param ApplicationContext $oAppContext
*
* @return \iTopWebPage
* @throws CoreException
* @throws DictExceptionMissingString
* @throws MySQLException
*/
function DisplayDBInconsistencies(iTopWebPage &$oP, ApplicationContext &$oAppContext)
{
$iShowId = intval(utils::ReadParam('show_id', '0'));
$sErrorLabelSelection = utils::ReadParam('error_selection', '');
$sClassSelection = utils::ReadParam('class_selection', '');
if (!empty($sClassSelection))
{
$aClassSelection = explode(",", $sClassSelection);
}
else
{
$aClassSelection = array();
}
$sClassSelection = utils::ReadParam('class_selection', '');
$oP->SetCurrentTab(Dict::S('DBTools:Inconsistencies'));
$bRunAnalysis = intval(utils::ReadParam('run_analysis', '0'));
if ($bRunAnalysis)
{
$oDBAnalyzer = new DatabaseAnalyzer();
$aResults = $oDBAnalyzer->CheckIntegrity($aClassSelection);
if (empty($aResults))
{
$oP->p('<div class="header_message message_ok">'.Dict::S('DBTools:NoError').'</div>');
}
}
$oP->add('<div style="padding: 15px; background: #ddd;">');
$oP->add("<form>");
$oP->add('<table style="border=0;">');
$oP->add("<tr><td>");
$sChecked = ($iShowId == 0) ? 'checked' : '';
$oP->add("<label><input type=\"radio\" $sChecked name=\"show_id\" value=\"0\">".Dict::S('DBTools:HideIds').'</label>');
$oP->add("</td><td>");
$sChecked = ($iShowId == 1) ? 'checked' : '';
$oP->add("<label><input type=\"radio\" $sChecked name=\"show_id\" value=\"1\">".Dict::S('DBTools:ShowIds').'</label>');
$oP->add("</td><td>");
$sChecked = ($iShowId == 3) ? 'checked' : '';
$oP->add("<label><input type=\"radio\" $sChecked name=\"show_id\" value=\"3\">".Dict::S('DBTools:ShowReport').'</label>');
$oP->add("</td></tr>\n");
$oP->add("</table><br>\n");
$oP->add("<input type=\"submit\" value=\"".Dict::S('DBTools:Analyze')."\">\n");
$oP->add('<input type="hidden" name="class_selection" value="'.$sClassSelection.'"/>');
$oP->add('<input type="hidden" name="error_selection" value="'.$sErrorLabelSelection.'"/>');
$oP->add('<input type="hidden" name="run_analysis" value="1"/>');
$oP->add('<input type="hidden" name="exec_module" value="combodo-db-tools"/>');
$oP->add('<input type="hidden" name="exec_page" value="dbtools.php"/>');
$oP->add($oAppContext->GetForForm());
$oP->add("</form>\n");
$oP->add('</div>');
if (!empty($sErrorLabelSelection) || !empty($sClassSelection))
{
$oP->add("<br>");
$oP->add("<form>");
$oP->add('<input type="hidden" name="show_id" value="0"/>');
$oP->add('<input type="hidden" name="class_selection" value=""/>');
$oP->add('<input type="hidden" name="error_selection" value=""/>');
$oP->add('<input type="hidden" name="exec_module" value="combodo-db-tools"/>');
$oP->add('<input type="hidden" name="exec_page" value="dbtools.php"/>');
$oP->add("<input type=\"submit\" value=\"".Dict::S('DBTools:ShowAll')."\">\n");
$oP->add("</form>\n");
}
if (!empty($aResults))
{
if ($iShowId == 3)
{
DisplayInconsistenciesReport($aResults);
}
$oP->p(Dict::S('DBTools:ErrorsFound'));
$oP->add('<table class="listResults"><tr><th>'.Dict::S('DBTools:Class').'</th><th>'.Dict::S('DBTools:Count').'</th><th>'.Dict::S('DBTools:Error').'</th></tr>');
$bTable = true;
foreach($aResults as $sClass => $aErrorList)
{
foreach($aErrorList as $sErrorLabel => $aError)
{
if (!empty($sErrorLabelSelection) && ($sErrorLabel != $sErrorLabelSelection))
{
continue;
}
if (!$bTable)
{
$oP->add('<br>');
$oP->add('<table class="listResults"><tr><th></th><th>Class</th><th>Count</th><th>Error</th></tr>');
$bTable = true;
}
$oP->add('<tr>');
$oP->add('<td>'.MetaModel::GetName($sClass).' ('.$sClass.')</td>');
$iCount = $aError['count'];
$oP->add('<td>'.$iCount.'</td>');
$oP->add('<td>'.$sErrorLabel.'</td>');
$oP->add('</tr>');
if ($iShowId > 0)
{
$oP->add('</table>');
$bTable = false;
$oP->p(Dict::S('DBTools:SQLquery'));
$sQuery = $aError['query'];
$oP->add('<div style="padding: 15px; background: #f1f1f1;">');
$oP->add('<code>'.$sQuery.'</code>');
$oP->add('</div>');
if (isset($aError['fixit']))
{
$oP->p(Dict::S('DBTools:FixitSQLquery'));
$aQueries = $aError['fixit'];
$oP->add('<div style="padding: 15px; background: #f1f1f1;">');
foreach($aQueries as $sFixQuery)
{
$oP->add('<pre>'.$sFixQuery.'</pre>');
}
$oP->add('<br></div>');
}
$oP->p(Dict::S('DBTools:SQLresult'));
$sQueryResult = '';
$iCount = count($aError['res']);
$iMaxCount = MAX_RESULTS;
foreach($aError['res'] as $aRes)
{
$iMaxCount--;
if ($iMaxCount < 0)
{
$sQueryResult .= 'Displayed '.MAX_RESULTS."/$iCount results.<br>";
break;
}
foreach($aRes as $sKey => $sValue)
{
$sQueryResult .= "'$sKey'='$sValue'&nbsp;";
}
$sQueryResult .= '<br>';
}
$oP->add('<div style="padding: 15px; background: #f1f1f1;">');
$oP->add('<code>'.$sQueryResult.'</code>');
$oP->add('</div>');
}
}
}
$oP->add('</table>');
}
return $oP;
}
/**
* @param $aResults
*
* @return mixed
* @throws CoreException
* @throws DictExceptionMissingString
*/
function DisplayInconsistenciesReport($aResults)
{
$sDBToolsFolder = str_replace("\\", '/', APPROOT.'log/');
$sReportFile = 'dbtools-report-'.date('Y-m-d-H-i-s');
$fReport = fopen($sDBToolsFolder.$sReportFile.'.txt', 'w');
fwrite($fReport, 'Database Maintenance tools: '.date('Y-m-d H:i:s')."\r\n");
foreach($aResults as $sClass => $aErrorList)
{
fwrite($fReport, '');
foreach($aErrorList as $sErrorLabel => $aError)
{
fwrite($fReport, "\r\n----------\r\n");
fwrite($fReport, 'Class: '.MetaModel::GetName($sClass).' ('.$sClass.")\r\n");
$iCount = $aError['count'];
fwrite($fReport, 'Count: '.$iCount."\r\n");
fwrite($fReport, 'Error: '.$sErrorLabel."\r\n");
$sQuery = $aError['query'];
fwrite($fReport, 'Query: '.$sQuery."\r\n");
if (isset($aError['fixit']))
{
fwrite($fReport, "\r\nFix it (indication):\r\n\r\n");
$aFixitQueries = $aError['fixit'];
foreach($aFixitQueries as $sFixitQuery)
{
fwrite($fReport, "$sFixitQuery\r\n");
}
fwrite($fReport, "\r\n");
}
$sQueryResult = '';
$aIdList = array();
foreach($aError['res'] as $aRes)
{
foreach($aRes as $sKey => $sValue)
{
$sQueryResult .= "'$sKey'='$sValue' ";
if ($sKey == 'id')
{
$aIdList[] = $sValue;
}
}
$sQueryResult .= "\r\n";
}
fwrite($fReport, "Result: \r\n".$sQueryResult);
$sIdList = '('.implode(',', $aIdList).')';
fwrite($fReport, 'Ids: '.$sIdList."\r\n");
}
}
fclose($fReport);
$oArchive = new ZipArchive();
$oArchive->open($sDBToolsFolder.$sReportFile.'.zip', ZipArchive::CREATE);
$oArchive->addFile($sDBToolsFolder.$sReportFile.'.txt', $sReportFile.'.txt');
$oArchive->close();
unlink($sDBToolsFolder.$sReportFile.'.txt');
$sReportFile = $sDBToolsFolder.$sReportFile.'.zip';
header('Content-Description: File Transfer');
header('Content-Type: multipart/x-zip');
header('Content-Disposition: inline; filename="'.basename($sReportFile).'"');
header('Expires: 0');
header('Cache-Control: must-revalidate');
header('Pragma: public');
header('Content-Length: '.filesize($sReportFile));
readfile($sReportFile);
unlink($sReportFile);
exit(0);
}
/**
* @param iTopWebPage $oP
* @param ApplicationContext $oAppContext
*
* @return \iTopWebPage
* @throws CoreException
* @throws MySQLException
* @throws \Exception
*/
function DisplayLostAttachments(iTopWebPage &$oP, ApplicationContext &$oAppContext)
{
// Retrieve parameters
$sStepName = utils::ReadParam('step_name');
$aRecordsToClean = utils::ReadParam('dbt-cbx', array(), false, 'raw_data');
$iRestoredItemsCount = 0;
$iRecordsToCleanCount = count($aRecordsToClean);
$aErrorsReport = array();
$bDoAnalyze = in_array($sStepName, array('analyze', 'restore'));
$bDoRestore = in_array($sStepName, array('restore'));
// Build HTML
$oP->SetCurrentTab(Dict::S('DBTools:LostAttachments'));
$oP->add('<div class="db-tools-tab-content">');
$oP->add('<div class="dbt-lostattachments">');
$oP->add('<div class="header_message message_info">'.Dict::S('DBTools:LostAttachments:Disclaimer').'</div>');
$oP->add('<div class="dbt-steps">');
$oP->add('<form>');
$oP->add('<input type="hidden" name="exec_module" value="combodo-db-tools"/>');
$oP->add('<input type="hidden" name="exec_page" value="dbtools.php"/>');
// Step 1: Analyze DB
$oP->add('<div class="dbt-step"><p class="dbt-step-description"><span class="dbt-step-number">1.</span><span>'.Dict::S('DBTools:LostAttachments:Step:Analyze').'</span></p><button type="submit" name="step_name" value="analyze">'.Dict::S('DBTools:LostAttachments:Button:Analyze') .'</button></div>');
// Step 2: Display results
if($bDoAnalyze)
{
// Check if we have to restore some items first
if($bDoRestore)
{
foreach($aRecordsToClean as $sRecordToClean)
{
utils::PushArchiveMode(false); // For iTop < 2.5, the application can be wrongly set to archive mode true when it fails from retrieving an object. See r5340.
try
{
// Retrieve attachment
$aLocationParts = explode('::', $sRecordToClean);
/** @var \DBObject $oOriginObject */
$oOriginObject = MetaModel::GetObject($aLocationParts[0], $aLocationParts[1], true, true);
/** @var \ormDocument $oOrmDocument */
$oOrmDocument = $oOriginObject->Get('contents');
// Retrieve target object
$sTargetClass = $oOriginObject->Get('item_class');
$sTargetId = $oOriginObject->Get('item_id');
/** @var \DBObject $oTargetObject */
$oTargetObject = MetaModel::GetObject($sTargetClass, $sTargetId, true, true);
// Put it on the target object
/** @var \Attachment $oAttachment */
$oAttachment = MetaModel::NewObject('Attachment');
$oAttachment->Set('item_class', $sTargetClass);
$oAttachment->Set('item_id', $sTargetId);
$oAttachment->Set('item_org_id', $oTargetObject->Get('org_id'));
$oAttachment->Set('contents', $oOrmDocument);
$oAttachment->DBInsert();
// Put history entry
$sHistoryEntry = Dict::Format('DBTools:LostAttachments:History', $oOrmDocument->GetFileName());
CMDBObject::SetTrackInfo(UserRights::GetUserFriendlyName());
$oChangeOp = MetaModel::NewObject('CMDBChangeOpPlugin');
/** @var \Change $oChange */
$oChange = CMDBObject::GetCurrentChange();
$oChangeOp->Set('change', $oChange->GetKey());
$oChangeOp->Set('objclass', $sTargetClass);
$oChangeOp->Set('objkey', $sTargetId);
$oChangeOp->Set('description', $sHistoryEntry);
$oChangeOp->DBInsert();
// Remove origin object (should only be done for InlineImage)
$oOriginObject->DBDelete();
$iRestoredItemsCount++;
}
catch(Exception $e)
{
$aErrorsReport[] = 'Could not restore attachment from '.$sRecordToClean.', cause: '.$e->getMessage();
}
utils::PopArchiveMode();
}
}
// Search attachments stored as inline images
$sInlineImageDBTable = MetaModel::DBGetTable('InlineImage');
$sSelWrongRecs = 'SELECT id, secret, "InlineImage" AS current_class, id AS current_id, item_class AS target_class, item_id AS target_id, contents_filename AS filename FROM '.$sInlineImageDBTable.' WHERE contents_mimetype NOT LIKE "image/%"';
$aWrongRecords = CMDBSource::QueryToArray($sSelWrongRecs);
$oP->add('<div class="dbt-step">');
$oP->add('<p class="dbt-step-description"><span class="dbt-step-number">2.</span><span>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults').'</span></p>');
if(empty($aWrongRecords))
{
$oP->add('<div class="header_message message_ok">'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:None').'</div>');
}
else
{
$oP->add('<div class="header_message message_error">'.Dict::Format('DBTools:LostAttachments:Step:AnalyzeResults:Some', count($aWrongRecords)).'</div>');
// Display errors as table
$oP->add('<table class="listResults">');
$oP->add('<tr><th><input type="checkbox" class="dbt-toggler-cbx" /></th><th>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename').'</th><th>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation').'</th><th>'.Dict::S('DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation').'</th></tr>');
foreach($aWrongRecords as $iIndex => $aWrongRecord)
{
$sCurrentClass = $aWrongRecord['current_class'];
$sCurrentId = $aWrongRecord['current_id'];
$sRecordToClean = Dict::S('DBTools:LostAttachments:StoredAsInlineImage');
$sTargetClass = $aWrongRecord['target_class'];
$sTargetId = $aWrongRecord['target_id'];
$sTargetLocation = '<a href="'.ApplicationContext::MakeObjectUrl($sTargetClass, $sTargetId).'" target="_blank">'.$sTargetClass.'::'.$sTargetId.'</a>';
$sFilename = '<a href="'.utils::GetAbsoluteUrlAppRoot().INLINEIMAGE_DOWNLOAD_URL.$aWrongRecord['id'].'&s='.$aWrongRecord['secret'].'" target="_blank">'.$aWrongRecord['filename'].'</a>';
$sRowClass = ($iIndex % 2 === 0) ? 'odd' : 'even'; // (Starts at 0, not 1)
$oP->add('<tr class="'.$sRowClass.'"><td><input type="checkbox" class="dbt-cbx" name="dbt-cbx[]" value="'.$sCurrentClass.'::'.$sCurrentId.'" /></td><td>'.$sFilename.'</td><td>'.$sRecordToClean.'</td><td>'.$sTargetLocation.'</td></tr>');
}
$oP->add('</table>');
$oP->add('<div><button type="submit" name="step_name" value="restore" disabled>'.Dict::S('DBTools:LostAttachments:Button:Restore').'</button></div>');
// JS to handle checkboxes and button
$oP->add_ready_script(
<<<EOF
// Check all / none checkboxes
$('.dbt-lostattachments .dbt-toggler-cbx').on('click', function(){
$('.dbt-lostattachments .dbt-cbx').prop('checked', $(this).prop('checked'));
// Disable restore button if at lest one checkbox clicked
var bDisableButton = ($('.dbt-lostattachments .dbt-cbx:checked').length === 0)
$('.dbt-lostattachments button[name="step_name"][value="restore"]').prop('disabled', bDisableButton);
});
// Click on a checkbox
$('.dbt-lostattachments .dbt-cbx').on('click', function(){
// Disable restore button if at lest one checkbox clicked
var bDisableButton = ($('.dbt-lostattachments .dbt-cbx:checked').length === 0)
$('.dbt-lostattachments button[name="step_name"][value="restore"]').prop('disabled', bDisableButton);
// Uncheck global checkbox
if( $('.dbt-lostattachments .dbt-cbx:not(:checked)').length > 0 )
{
$('.dbt-lostattachments .dbt-toggler-cbx').prop('checked', false);
}
});
EOF
);
}
$oP->add('</div>');
}
// Step 3: Restore results
if($bDoRestore)
{
$oP->add('<div class="dbt-step">');
$oP->add('<p class="dbt-step-description"><span class="dbt-step-number">3.</span><span>'.Dict::S('DBTools:LostAttachments:Step:RestoreResults').'</span></p>');
$oP->add('<div class="header_message message_info">'.Dict::Format('DBTools:LostAttachments:Step:RestoreResults:Results', $iRestoredItemsCount, $iRecordsToCleanCount).'</div>');
if(!empty($aErrorsReport))
{
foreach($aErrorsReport as $sErrorReport)
{
$oP->add('<div class="header_message message_error">'.$sErrorReport.'</div>');
}
}
$oP->add('</div>');
}
$oP->add($oAppContext->GetForForm());
$oP->add('</form>');
$oP->add('</div>');
$oP->add('</div>');
$oP->add('</div>');
// Buttons disabling on click
$sConfirmText = Dict::S('DBTools:LostAttachments:Button:Restore:Confirm');
$sButtonBusyText = Dict::S('DBTools:LostAttachments:Button:Busy');
$oP->add_ready_script(
<<<EOF
$('.dbt-lostattachments button[name="step_name"]').on('click', function(){
if($(this).val() === 'restore')
{
if(!confirm('{$sConfirmText}'))
{
return false;
}
}
//$(this).prop('disabled', true);
$(this).text('{$sButtonBusyText}');
});
EOF
);
return $oP;
}
/////////////////////////////////////////////////////////////////////
// Main program
//
try
{
if (method_exists('ApplicationMenu', 'CheckMenuIdEnabled'))
{
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
ApplicationMenu::CheckMenuIdEnabled('DBToolsMenu');
}
else
{
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed
}
$oAppContext = new ApplicationContext();
$sPageTitle = Dict::S('DBTools:Title');
$sPageId = 'db-tools';
$oP = new iTopWebPage($sPageTitle);
$oP->add_saas('env-'.utils::GetCurrentEnvironment().'/combodo-db-tools/default.scss');
$oP->add(
<<<EOF
<div class="page_header">
<h1>$sPageTitle</h1>
</div>
EOF
);
$oP->AddTabContainer('db-tools');
$oP->SetCurrentTabContainer('db-tools');
// DB Inconsistences
$oP = DisplayDBInconsistencies($oP, $oAppContext);
// Lost attachments
$oP = DisplayLostAttachments($oP, $oAppContext);
}
catch (Exception $e)
{
$oP->p('<b>'.$e->getMessage().'</b>');
}
if (isset($oP))
{
$oP->output();
}

View File

@@ -0,0 +1,84 @@
<?php
// Copyright (c) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
// Copyright 2018 David Gümbel, ITOMIG GmbH, david.guembel @ itomig DE
// Database inconsistencies
Dict::Add('DE DE', 'German', 'Deutsch', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools',
'DBTools:Class' => 'Klasse',
'DBTools:Title' => 'Datenbank-Pflege-Tools',
'DBTools:ErrorsFound' => 'Fehler gefunden',
'DBTools:Error' => 'Fehler',
'DBTools:Count' => 'Anzahl',
'DBTools:SQLquery' => 'SQL Query',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL Ergebnis',
'DBTools:NoError' => 'Die Datenbank ist OK',
'DBTools:HideIds' => 'Fehler',
'DBTools:ShowIds' => 'Fehler und Werte',
'DBTools:ShowReport' => 'Report',
'DBTools:IntegrityCheck' => 'Integritätscheck',
'DBTools:FetchCheck' => 'Fetch Check (dauert länger)',
'DBTools:Analyze' => 'Analysiere',
'DBTools:Details' => 'Details anzeigen',
'DBTools:ShowAll' => 'Alle Fehler anzeigen',
'DBTools:Inconsistencies' => 'Datenbank-Inkonsistenzen',
'DBAnalyzer-Integrity-OrphanRecord' => 'Verwaister Eintrag in `%1$s`, er sollte eine Entsprechung in Tabelle `%2$s` haben',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Ungültiger Externer Key %1$s (Spalte: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => 'Fehlender Externer Key %1$s (Spalte: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => 'Ungültiger Wert für %1$s (Spalte: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Manche Benutzerkonten haben keinerlei zugewiesenes Profi',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch-Count-Fehler in `%1$s`, %2$d Einträge geholt (fetched) / %3$d gezählt',
));
// Database Info
Dict::Add('DE DE', 'German', 'Deutsch', array(
'DBTools:DatabaseInfo' => 'Datenbank-Information',
'DBTools:Base' => 'Datenbank',
'DBTools:Size' => 'Größe',
));
// Lost attachments
Dict::Add('DE DE', 'German', 'Deutsch', array(
'DBTools:LostAttachments' => 'Verlorene Attachments',
'DBTools:LostAttachments:Disclaimer' => 'Hier können Sie Ihre Datenbank nach verlorenen oder falsch platzierten Attachments durchsuchen. Dies ist kein Recovery-Tool - es stellt keine gelöschten Daten wieder her.',
'DBTools:LostAttachments:Button:Analyze' => 'Analysieren',
'DBTools:LostAttachments:Button:Restore' => 'Wiederherstellen',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'Diese Aktion kann nicht rückgängig gemacht werden, bitte bestätigen Sie dass Sie die ausgewählten Dateien wiederherstellen möchten.',
'DBTools:LostAttachments:Button:Busy' => 'Bitte warten...',
'DBTools:LostAttachments:Step:Analyze' => 'Suche zunächst nach verlorenen / falsch platzierten Attachments, mittels einer Analyse der Datenbank',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyseergebnisse:',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Toll! Alles scheint am richtigen Ort zu sein.',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Manche Attachments scheinen am falschen Ort zu sein. Werfen Sie einen Blick auf die folgende Liste und wählen Sie diejenigen aus, die Sie gerne verschieben möchten.',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Dateiname',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Derzeitiger Ort',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Verschieben nach...',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore-Ergebnisse:',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d Attachments wurden wiederhergestellt.',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Als Inline-Bild gespeichert',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" mit DB-Tools wiederhergestellt'
));

View File

@@ -0,0 +1,18 @@
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step {
margin-top: 30px;
/* This is to avoid long exception message on restore errors */
}
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .dbt-step-description {
padding: 0;
margin: 0px 0px 5px 0px;
}
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .dbt-step-number {
margin-right: 0.3em;
}
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .listResults tr > *:first-child {
text-align: center;
}
.db-tools-tab-content .dbt-lostattachments .dbt-steps .dbt-step .message_error {
max-height: 150px;
overflow-y: auto;
}

View File

@@ -0,0 +1,30 @@
.db-tools-tab-content{
.dbt-lostattachments{
.dbt-steps{
.dbt-step{
margin-top: 30px;
.dbt-step-description{
padding: 0;
margin: 0px 0px 5px 0px;
}
.dbt-step-number{
margin-right: 0.3em;
}
.listResults{
tr>*:first-child{
text-align: center;
}
}
/* This is to avoid long exception message on restore errors */
.message_error{
max-height: 150px;
overflow-y: auto;
}
}
}
}
}

View File

@@ -0,0 +1,88 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('EN US', 'English', 'English', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'Database integrity',
'DBTools:Class' => 'Class',
'DBTools:Title' => 'Database Maintenance Tools',
'DBTools:ErrorsFound' => 'Errors Found',
'DBTools:Error' => 'Error',
'DBTools:Count' => 'Count',
'DBTools:SQLquery' => 'SQL query',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)',
'DBTools:SQLresult' => 'SQL result',
'DBTools:NoError' => 'The database is OK',
'DBTools:HideIds' => 'Error List',
'DBTools:ShowIds' => 'Detailed view',
'DBTools:ShowReport' => 'Report',
'DBTools:IntegrityCheck' => 'Integrity check',
'DBTools:FetchCheck' => 'Fetch Check (long)',
'DBTools:Analyze' => 'Analyze',
'DBTools:Details' => 'Show Details',
'DBTools:ShowAll' => 'Show All Errors',
'DBTools:Inconsistencies' => 'Database inconsistencies',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted',
));
// Database Info
Dict::Add('EN US', 'English', 'English', array(
'DBTools:DatabaseInfo' => 'Database Information',
'DBTools:Base' => 'Base',
'DBTools:Size' => 'Size',
));
// Lost attachments
Dict::Add('EN US', 'English', 'English', array(
'DBTools:LostAttachments' => 'Lost attachments',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze',
'DBTools:LostAttachments:Button:Restore' => 'Restore',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('ES CR', 'Spanish', 'Español, Castellaño', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,83 @@
<?php
// Copyright (c) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
// Database inconsistencies
Dict::Add('FR FR', 'French', 'Français', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'Intégrité base de données',
'DBTools:Class' => 'Classe',
'DBTools:Title' => 'Outils maintenance base de données',
'DBTools:ErrorsFound' => 'Erreurs trouvées',
'DBTools:Error' => 'Erreur',
'DBTools:Count' => 'Nombre',
'DBTools:SQLquery' => 'Requête SQL',
'DBTools:FixitSQLquery' => 'Requête SQL pour nettoyer la base (indication)',
'DBTools:SQLresult' => 'Résultat SQL',
'DBTools:NoError' => 'La base de données est OK',
'DBTools:HideIds' => 'Erreurs',
'DBTools:ShowIds' => 'Détails des erreurs',
'DBTools:ShowReport' => 'Rapport',
'DBTools:IntegrityCheck' => 'Contrôle d\'intégrité',
'DBTools:FetchCheck' => 'Contrôle de récupération (long)',
'DBTools:Analyze' => 'Analyser',
'DBTools:Details' => 'Afficher détails',
'DBTools:ShowAll' => 'Afficher toutes les erreurs',
'DBTools:Inconsistencies' => 'Incohérences de base de données',
'DBAnalyzer-Integrity-OrphanRecord' => 'Enregistrement orphelin dans `%1$s`, il devrait avoir son équivalent dans la tableit `%2$s`',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Clef externe invalide %1$s (colonne: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-MissingExtKey' => 'Clef externe manquante %1$s (colonne: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-InvalidValue' => 'Valeur invalide pour %1$s (colonne: `%2$s.%3$s`)',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Certains comptes utilisateurs n\'ont aucun profile',
'DBAnalyzer-Fetch-Count-Error' => 'Erreur de récupération dans `%1$s`, %2$d enregistrements récupérés / %3$d comptés',
));
// Database Info
Dict::Add('FR FR', 'French', 'Français', array(
'DBTools:DatabaseInfo' => 'Information Base de Données',
'DBTools:Base' => 'Base',
'DBTools:Size' => 'Taille',
));
// Lost attachments
Dict::Add('FR FR', 'French', 'Français', array(
'DBTools:LostAttachments' => 'Pièces jointes perdues',
'DBTools:LostAttachments:Disclaimer' => 'Ici vous pouvez retrouver des pièces jointes perdues ou égarées dans votre base de données. Ceci n\'est PAS un outil de récupération des données, il ne récupère pas les données effacées.',
'DBTools:LostAttachments:Button:Analyze' => 'Analyser',
'DBTools:LostAttachments:Button:Restore' => 'Restaurer',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'Cet action ne peut être annuler, veuillez confirmer que vous voulez restaurer les fichiers sélectionnés.',
'DBTools:LostAttachments:Button:Busy' => 'Patientez ...',
'DBTools:LostAttachments:Step:Analyze' => 'Tout d\'abord, scannez la base de données à la recherche de pièces jointes perdues/égarées.',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Résultat de l\'analyse :',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Parfait ! Il semble que tout soit en ordre.',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Certaines pièces jointes (%1$d) semblent être au mauvais endroit. Examinez la liste suivante et cochez celles que vous souhaitez déplacer.',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Nom de fichier',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Emplacement actuel',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Déplacer vers ...',
'DBTools:LostAttachments:Step:RestoreResults' => 'Résultats de la restauration :',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d pièces jointes ont été restaurées.',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stockée comme "InlineImage"',
'DBTools:LostAttachments:History' => 'Pièce jointe "%1$s" restaurée avec l\'outil de BDD'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('IT IT', 'Italian', 'Italiano', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('IT IT', 'Italian', 'Italiano', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('JA JP', 'Japanese', '日本語', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('JA JP', 'Japanese', '日本語', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('JA JP', 'Japanese', '日本語', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,59 @@
<?php
// Copyright (c) 2010-2018 Combodo SARL
//
// This file is part of iTop.
//
// iTop is free software; you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// iTop is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with iTop. If not, see <http://www.gnu.org/licenses/>
//
//
// iTop module definition file
//
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'combodo-db-tools/1.0.8',
array(
// Identification
//
'label' => 'Database maintenance tools',
'category' => 'business',
// Setup
//
'dependencies' => array(
),
'mandatory' => false,
'visible' => true,
// Components
//
'datamodel' => array(
'model.combodo-db-tools.php',
'src/Service/DBToolsUtils.php'
),
'webservice' => array(),
'data.struct' => array(),
'data.sample' => array(),
// Documentation
//
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
'doc.more_information' => '', // hyperlink to more information, if any
// Default settings
//
'settings' => array(),
)
);

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('RU RU', 'Russian', 'Русский', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('RU RU', 'Russian', 'Русский', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('RU RU', 'Russian', 'Русский', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,173 @@
<?php
/**
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DBTools\Service;
use CMDBSource;
use DBObjectSearch;
use DBObjectSet;
class DBToolsUtils
{
/**
* @return int
* @throws \CoreException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public final static function GetDatabaseSize()
{
$sSchema = CMDBSource::DBName();
$sReq = <<<EOF
SELECT sum(data_length+index_length) AS sz
FROM information_schema.tables
WHERE table_schema = '$sSchema';
EOF;
$oResult = CMDBSource::Query($sReq);
if ($oResult !== false)
{
$aRow = $oResult->fetch_assoc();
$sSize = $aRow['sz'];
return (int)$sSize;
}
return 0;
}
/**
* @return int
* @throws \CoreException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public final static function GetDBDataSize()
{
$sSchema = CMDBSource::DBName();
$sReq = <<<EOF
SELECT sum(data_length) AS sz
FROM information_schema.tables
WHERE table_schema = '$sSchema';
EOF;
$oResult = CMDBSource::Query($sReq);
if ($oResult !== false)
{
$aRow = $oResult->fetch_assoc();
$sSize = $aRow['sz'];
return (int)$sSize;
}
return 0;
}
/**
* @return int
* @throws \CoreException
* @throws \MySQLException
* @throws \MySQLHasGoneAwayException
*/
public final static function GetDBIndexSize()
{
$sSchema = CMDBSource::DBName();
$sReq = <<<EOF
SELECT sum(index_length) AS sz
FROM information_schema.tables
WHERE table_schema = '$sSchema';
EOF;
$oResult = CMDBSource::Query($sReq);
if ($oResult !== false)
{
$aRow = $oResult->fetch_assoc();
$sSize = $aRow['sz'];
return (int)$sSize;
}
return 0;
}
public final static function GetDatamodelVersion()
{
$oFilter = DBObjectSearch::FromOQL('SELECT ModuleInstallation AS mi WHERE mi.name="datamodel"');
$oSet = new DBObjectSet($oFilter, array('installed' => false)); // Most recent first
$oSet->SetLimit(1);
/** @var \DBObject $oModuleInstallation */
$oModuleInstallation = $oSet->Fetch();
return $oModuleInstallation->Get('version');
}
public static function GetPreviousInstallations($iLimitCount = 10)
{
$oFilter = DBObjectSearch::FromOQL('SELECT ModuleInstallation AS mi WHERE mi.parent_id=0 AND mi.name!="datamodel"');
$oSet = new DBObjectSet($oFilter, array('installed' => false)); // Most recent first
$oSet->SetLimit($iLimitCount);
$aRawValues = $oSet->ToArrayOfValues();
$aValues = array();
foreach ($aRawValues as $aRawValue)
{
$aValue = array();
foreach ($aRawValue as $sAliasAttCode => $sValue)
{
// remove 'mi.' from AttCode
$sAttCode = substr($sAliasAttCode, 3);
$aValue[$sAttCode] = $sValue;
}
$aValues[] = $aValue;
}
return $aValues;
}
public static function GetDBTablesInfo()
{
$sSchema = CMDBSource::DBName();
$sReq = <<<EOF
SELECT `table_name`,
table_rows,
data_length / 1024 / 1024 as data_length_mb,
index_length / 1024 / 1024 as index_length_mb,
(data_length + index_length) / 1024 / 1024 as total_length_mb
FROM information_schema.tables
WHERE table_schema = '$sSchema'
AND table_type = 'BASE TABLE';
EOF;
$oResult = CMDBSource::Query($sReq);
if ($oResult !== false)
{
return $oResult->fetch_all(MYSQLI_ASSOC);
}
return array();
}
public static function GetDBVariables()
{
$sReq = 'SHOW variables';
$oResult = CMDBSource::Query($sReq);
if ($oResult !== false)
{
return $oResult->fetch_all(MYSQLI_ASSOC);
}
return array();
}
public static function GetDBStatus()
{
$sReq = 'SHOW status';
$oResult = CMDBSource::Query($sReq);
if ($oResult !== false)
{
return $oResult->fetch_all(MYSQLI_ASSOC);
}
return array();
}
}

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));

View File

@@ -0,0 +1,87 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2010-2018 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*
* This file is part of iTop.
*
* iTop is free software; you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* iTop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with iTop. If not, see <http://www.gnu.org/licenses/>
*/
// Database inconsistencies
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
// Dictionary entries go here
'Menu:DBToolsMenu' => 'DB Tools~~',
'DBTools:Class' => 'Class~~',
'DBTools:Title' => 'Database Maintenance Tools~~',
'DBTools:ErrorsFound' => 'Errors Found~~',
'DBTools:Error' => 'Error~~',
'DBTools:Count' => 'Count~~',
'DBTools:SQLquery' => 'SQL query~~',
'DBTools:FixitSQLquery' => 'SQL query To Fix it (indication)~~',
'DBTools:SQLresult' => 'SQL result~~',
'DBTools:NoError' => 'The database is OK~~',
'DBTools:HideIds' => 'Error List~~',
'DBTools:ShowIds' => 'Detailed view~~',
'DBTools:ShowReport' => 'Report~~',
'DBTools:IntegrityCheck' => 'Integrity check~~',
'DBTools:FetchCheck' => 'Fetch Check (long)~~',
'DBTools:Analyze' => 'Analyze~~',
'DBTools:Details' => 'Show Details~~',
'DBTools:ShowAll' => 'Show All Errors~~',
'DBTools:Inconsistencies' => 'Database inconsistencies~~',
'DBAnalyzer-Integrity-OrphanRecord' => 'Orphan record in `%1$s`, it should have its counterpart in table `%2$s`~~',
'DBAnalyzer-Integrity-InvalidExtKey' => 'Invalid external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-MissingExtKey' => 'Missing external key %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-InvalidValue' => 'Invalid value for %1$s (column: `%2$s.%3$s`)~~',
'DBAnalyzer-Integrity-UsersWithoutProfile' => 'Some user accounts have no profile at all~~',
'DBAnalyzer-Fetch-Count-Error' => 'Fetch count error in `%1$s`, %2$d entries fetched / %3$d counted~~',
));
// Database Info
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:DatabaseInfo' => 'Database Information~~',
'DBTools:Base' => 'Base~~',
'DBTools:Size' => 'Size~~',
));
// Lost attachments
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'DBTools:LostAttachments' => 'Lost attachments~~',
'DBTools:LostAttachments:Disclaimer' => 'Here you can search your database for lost or misplaced attachments. This is NOT a data recovery tool, is does not retrieve deleted data.~~',
'DBTools:LostAttachments:Button:Analyze' => 'Analyze~~',
'DBTools:LostAttachments:Button:Restore' => 'Restore~~',
'DBTools:LostAttachments:Button:Restore:Confirm' => 'This action cannot be undone, please confirm that you want to restore the selected files.~~',
'DBTools:LostAttachments:Button:Busy' => 'Please wait...~~',
'DBTools:LostAttachments:Step:Analyze' => 'First, search for lost/misplaced attachments by analyzing the database.~~',
'DBTools:LostAttachments:Step:AnalyzeResults' => 'Analyze results:~~',
'DBTools:LostAttachments:Step:AnalyzeResults:None' => 'Great! Every thing seems to be at the right place.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Some' => 'Some attachments (%1$d) seem to be misplaced. Take a look at the following list and check the ones you would like to move.~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:Filename' => 'Filename~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:CurrentLocation' => 'Current location~~',
'DBTools:LostAttachments:Step:AnalyzeResults:Item:TargetLocation' => 'Move to...~~',
'DBTools:LostAttachments:Step:RestoreResults' => 'Restore results:~~',
'DBTools:LostAttachments:Step:RestoreResults:Results' => '%1$d/%2$d attachments were restored.~~',
'DBTools:LostAttachments:StoredAsInlineImage' => 'Stored as inline image~~',
'DBTools:LostAttachments:History' => 'Attachment "%1$s" restored with DB tools~~'
));