Compare commits

..

32 Commits

Author SHA1 Message Date
Denis Flaven
5a7c17b80a (retrofit from trunk) Properly sanitize the "switch_env" parameter and take it into account only if it contains a valid value.
SVN:2.0.3[4242]
2016-06-22 12:18:14 +00:00
Denis Flaven
0682f9f3b1 Use one-way encryption for storing the token used for the "Forgotten password" feature.
SVN:2.0.3[3924]
2016-02-19 18:23:00 +00:00
Denis Flaven
b2b0ab9eff Fixed a potential XSS vulnerability.
SVN:2.0.3[3665]
2015-07-30 09:14:51 +00:00
Denis Flaven
000dd3726d Enhancement: allow the API to create entries with a specified user_login.
SVN:2.0.3[3517]
2015-03-24 17:12:35 +00:00
Denis Flaven
0a8419c1d8 #594: properly display attachments inside "properties" by closing the span and the fieldset in non-edit mode.
SVN:2.0.3[3513]
2015-03-23 17:57:35 +00:00
Romain Quetiez
61fb800f23 #1060 Internal: improved the symptoms when calling MetaModel::GetAttributeDef with an invalid attribute code (feedback on the class name and no more FATAL errors) -retrofit from trunk
SVN:2.0.3[3494]
2015-02-09 13:16:30 +00:00
Romain Quetiez
ea7a8888e9 Partial retrofit of [3438]: fixes the helper RenameEnumValueInDB which did work only IF the values differ in case (ex. IpPhone to IPPhone)
SVN:2.0.3[3488]
2015-01-09 10:01:24 +00:00
Romain Quetiez
1e66220077 #1020 Restrict dashboard/shortcut refresh interval -retrofit from trunk
SVN:2.0.3[3449]
2014-12-03 14:18:16 +00:00
Romain Quetiez
ad3178d02e #1027 Regression introduced in [3148] thus in 2.0.3 (cache the reconciliation for external keys on the CSV import) a cache hit on an ambiguous external key was not correctly handled -retroffited from trunk
SVN:2.0.3[3441]
2014-12-01 19:21:19 +00:00
Romain Quetiez
028d4b52e4 #1007 Unexpected change of the case log when doing massive update of a User Request (+ hide the checkbox for the status because it makes no sense) -retrofit from trunk
SVN:2.0.3[3395]
2014-10-31 15:11:15 +00:00
Denis Flaven
6d4a78db20 #1011 Proper resizing of the dialog box for managing 1:n links - removed a trace - retrofit from trunk.
SVN:2.0.3[3391]
2014-10-30 08:56:15 +00:00
Denis Flaven
457ee5de64 Fixed the support of a non-default port for MySQL, thanks to theBigOne!
SVN:2.0.3[3369]
2014-10-16 14:34:25 +00:00
Denis Flaven
9bec433e94 #968 (continued) do not loose the "advanced mode" flag in the interactive display (retrofit from trunk).
SVN:2.0.3[3358]
2014-10-02 09:40:29 +00:00
Romain Quetiez
895a5fc5b0 #968 Interactive CSV Export truncated or missing characters (since 2.0.3) -reintegrated from trunk
SVN:2.0.3[3355]
2014-09-25 15:23:43 +00:00
Romain Quetiez
4c735a6dff #991 CSV export truncated (system dependent, since 2.0) due to a bug in iconv, the workaround is to do little by little -retrofit from trunk
SVN:2.0.3[3353]
2014-09-25 15:07:01 +00:00
Denis Flaven
5fd193885e #932: fixed a regression introduced by [r3319]... in case a criteria is present several times, retrofit from trunk.
SVN:2.0.3[3345]
2014-09-17 15:42:55 +00:00
Denis Flaven
9277184ba0 Bug fix: FetchAssoc was broken when dealing with in-memory sets, retrofit from trunk.
SVN:2.0.3[3341]
2014-09-16 09:47:03 +00:00
Romain Quetiez
aa0bd6c1ea #778 Issue on list sort order when editing an element - fixed a regression -reintegrated from trunk
SVN:2.0.3[3336]
2014-09-15 16:08:55 +00:00
Romain Quetiez
d8382a541c #778 Issue on list sort order when editing an element -reintegrated from trunk
SVN:2.0.3[3333]
2014-09-15 14:06:34 +00:00
Romain Quetiez
5e3eab90a6 #986 Search form: handle indirect external keys -reintegrated from trunk
SVN:2.0.3[3331]
2014-09-15 14:02:03 +00:00
Romain Quetiez
2c4c6a6690 #987 Usage login prevents from user deletion -reintegrated from trunk
SVN:2.0.3[3329]
2014-09-15 13:57:51 +00:00
Romain Quetiez
5e600c88a7 #932 Search form should be prefilled when running a search "shortcut" - very little progress: fixed the case when several criteria are given -reintegrated from trunk
SVN:2.0.3[3327]
2014-09-15 13:51:36 +00:00
Romain Quetiez
3c4057d546 #985 Shortcut auto refresh degrading table cosmetics -reintegrated from trunk
SVN:2.0.3[3325]
2014-09-15 13:48:28 +00:00
Romain Quetiez
9071f340a8 #984 Dashboard auto refresh degrading table functionalities like sorting -retrofit from trunk
SVN:2.0.3[3323]
2014-09-15 13:44:59 +00:00
Romain Quetiez
5cb9363cce #976 Fixed a typo introduced in the implementation of the fix -reintegrated from trunk
SVN:2.0.3[3316]
2014-09-11 08:26:08 +00:00
Romain Quetiez
9dd4b05866 Improved the processing of background task to enable more advanced functionalities like queuing (protection against reentrance) -reintegrated from trunk
SVN:2.0.3[3314]
2014-09-03 09:56:44 +00:00
Denis Flaven
4841738f01 Protect dashboards against invalid queries in "grouped by" dashlets.
SVN:2.0.3[3309]
2014-08-28 16:00:31 +00:00
Denis Flaven
8632d5597a #976: make sure that we do not bypass the method that computes the reference for newly created tickets.
SVN:2.0.3[3308]
2014-08-28 15:57:21 +00:00
Romain Quetiez
01e4f6af79 Improved the processing of background task to enable more advanced functionalities like queuing (factorized the error handling) -reintegrated from trunk
SVN:2.0.3[3303]
2014-08-21 08:55:57 +00:00
Romain Quetiez
0a2cdff528 Improved the processing of background task to enable more advanced functionalities like queuing -reintegrated from trunk
SVN:2.0.3[3301]
2014-08-19 10:10:18 +00:00
Romain Quetiez
b5166938df Legacy user rights management: allow the deletion of a profile in one step (it was nearly impossible because of the numerous related records, mainly of type URP_ActionGrant, for which iTop was requesting a manual deletion) -retrofit from trunk
SVN:2.0.3[3279]
2014-07-16 10:54:19 +00:00
Romain Quetiez
441b059581 Releasing 2.0.3
SVN:2.0.3[3276]
2014-07-15 13:36:53 +00:00
226 changed files with 7603 additions and 24273 deletions

View File

@@ -271,19 +271,6 @@ class URP_UserProfile extends UserRightsBaseClassGUI
{
return Dict::Format('UI:UserManagement:LinkBetween_User_And_Profile', $this->Get('userlogin'), $this->Get('profile'));
}
public function CheckToDelete(&$oDeletionPlan)
{
if (MetaModel::GetConfig()->Get('demo_mode'))
{
// Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults();
return false;
}
return parent::CheckToDelete($oDeletionPlan);
}
}
class URP_UserOrg extends UserRightsBaseClassGUI

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -225,8 +225,9 @@ EOF
EOF
);
}
$s_captured_output = $this->ob_get_clean_safe();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
$s_captured_output = ob_get_contents();
ob_end_clean();
if (($this->sContentType == 'text/html') && ($this->sContentDisposition == 'inline'))
{
// inline content != attachment && html => filter all scripts for malicious XSS scripts
echo self::FilterXSS($this->s_content);
@@ -392,3 +393,4 @@ EOF
}
}
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -781,12 +781,8 @@ class RestUtils
$oSearch = new DBObjectSearch($sClass);
foreach ($oCriteria as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value);
$realValue = self::MakeValue($sClass, $sAttCode, $value);
$oSearch->AddCondition($sAttCode, $realValue, '=');
if (is_object($value) || is_array($value))
{
$value = json_encode($value);
}
$aCriteriaReport[] = "$sAttCode: $value ($realValue)";
}
$oSet = new DBObjectSet($oSearch);
@@ -818,7 +814,7 @@ class RestUtils
{
if (is_object($key))
{
$res = static::FindObjectFromCriteria($sClass, $key);
$res = self::FindObjectFromCriteria($sClass, $key);
}
elseif (is_numeric($key))
{
@@ -882,7 +878,7 @@ class RestUtils
$oSearch = new DBObjectSearch($sClass);
foreach ($key as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value);
$realValue = self::MakeValue($sClass, $sAttCode, $value);
$oSearch->AddCondition($sAttCode, $realValue, '=');
}
}
@@ -926,7 +922,7 @@ class RestUtils
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
if ($oAttDef instanceof AttributeExternalKey)
{
$oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
$oExtKeyObject = self::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
$value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
}
elseif ($oAttDef instanceof AttributeLinkedSet)
@@ -939,7 +935,7 @@ class RestUtils
$aLinks = array();
foreach($value as $oValues)
{
$oLnk = static::MakeObjectFromFields($sLnkClass, $oValues);
$oLnk = self::MakeObjectFromFields($sLnkClass, $oValues);
$aLinks[] = $oLnk;
}
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
@@ -970,7 +966,7 @@ class RestUtils
$oObject = MetaModel::NewObject($sClass);
foreach ($aFields as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value);
$realValue = self::MakeValue($sClass, $sAttCode, $value);
try
{
$oObject->Set($sAttCode, $realValue);
@@ -997,7 +993,7 @@ class RestUtils
$sClass = get_class($oObject);
foreach ($aFields as $sAttCode => $value)
{
$realValue = static::MakeValue($sClass, $sAttCode, $value);
$realValue = self::MakeValue($sClass, $sAttCode, $value);
try
{
$oObject->Set($sAttCode, $realValue);

View File

@@ -125,29 +125,27 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
// Master data sources
$sSynchroIcon = '';
$oReplicaSet = $this->GetMasterReplica();
$bSynchronized = false;
$oCreatorTask = null;
$bCanBeDeletedByTask = false;
$bCanBeDeletedByUser = true;
$aMasterSources = array();
$aSyncData = $this->GetSynchroData();
if (count($aSyncData) > 0)
if ($oReplicaSet->Count() > 0)
{
$bSynchronized = true;
foreach ($aSyncData as $iSourceId => $aSourceData)
while($aData = $oReplicaSet->FetchAssoc())
{
$oDataSource = $aSourceData['source'];
$oReplica = reset($aSourceData['replica']); // Take the first one!
$sApplicationURL = $oDataSource->GetApplicationUrl($this, $oReplica);
$sLink = $oDataSource->GetName();
// Assumption: $aData['datasource'] will not be null because the data source id is always set...
$sApplicationURL = $aData['datasource']->GetApplicationUrl($this, $aData['replica']);
$sLink = $aData['datasource']->GetName();
if (!empty($sApplicationURL))
{
$sLink = "<a href=\"$sApplicationURL\" target=\"_blank\">".$oDataSource->GetName()."</a>";
$sLink = "<a href=\"$sApplicationURL\" target=\"_blank\">".$aData['datasource']->GetName()."</a>";
}
if ($oReplica->Get('status_dest_creator') == 1)
if ($aData['replica']->Get('status_dest_creator') == 1)
{
$oCreatorTask = $oDataSource;
$oCreatorTask = $aData['datasource'];
$bCreatedByTask = true;
}
else
@@ -156,12 +154,12 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
}
if ($bCreatedByTask)
{
$sDeletePolicy = $oDataSource->Get('delete_policy');
$sDeletePolicy = $aData['datasource']->Get('delete_policy');
if (($sDeletePolicy == 'delete') || ($sDeletePolicy == 'update_then_delete'))
{
$bCanBeDeletedByTask = true;
}
$sUserDeletePolicy = $oDataSource->Get('user_delete_policy');
$sUserDeletePolicy = $aData['datasource']->Get('user_delete_policy');
if ($sUserDeletePolicy == 'nobody')
{
$bCanBeDeletedByUser = false;
@@ -174,9 +172,9 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
}
}
$aMasterSources[$iSourceId]['datasource'] = $oDataSource;
$aMasterSources[$iSourceId]['url'] = $sLink;
$aMasterSources[$iSourceId]['last_synchro'] = $oReplica->Get('status_last_seen');
$aMasterSources[$aData['datasource']->GetKey()]['datasource'] = $aData['datasource'];
$aMasterSources[$aData['datasource']->GetKey()]['url'] = $sLink;
$aMasterSources[$aData['datasource']->GetKey()]['last_synchro'] = $aData['replica']->Get('status_last_seen');
}
if (is_object($oCreatorTask))
@@ -1404,8 +1402,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$sHtml .= "<p>\n";
$aFilterCriteria = $oSet->GetFilter()->GetCriteria();
$aMapCriteria = array();
// Todo: Investigate... The search criteria is an expression, i.e. a tree!
// I wonder if that code could work... cleanup required/recommended
foreach($aFilterCriteria as $aCriteria)
{
$aMapCriteria[$aCriteria['filtercode']][] = array('value' => $aCriteria['value'], 'opcode' => $aCriteria['opcode']);
@@ -1433,7 +1429,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
$sFilterValue = $aMapCriteria[$sFilterCode][0]['value'];
$sFilterOpCode = $aMapCriteria[$sFilterCode][0]['opcode'];
}
// Todo: Investigate...
if ($sFilterCode != 'company')
{
$oUnlimitedFilter->AddCondition($sFilterCode, $sFilterValue, $sFilterOpCode);
@@ -1522,7 +1517,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
if (is_scalar($sValue))
{
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"".htmlentities($sValue, ENT_QUOTES, 'UTF-8')."\" />\n";
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
}
}
$sHtml .= "<input type=\"hidden\" name=\"class\" value=\"$sClassName\" />\n";
@@ -1854,19 +1849,14 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
{
$sNullValue = "'$sNullValue'"; // Add quotes to turn this into a JS string if it's not a number
}
$sOriginalValue = ($iFlags & OPT_ATT_MUSTCHANGE) ? json_encode($value) : 'undefined';
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $bMandatory, sFormId, $sNullValue, $sOriginalValue) } );\n"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$iId').bind('".implode(' ', $aEventsList)."', function(evt, sFormId) { return ValidateField('$iId', '$sPattern', $bMandatory, sFormId, $sNullValue) } );\n"); // Bind to a custom event: validate
}
$aDependencies = MetaModel::GetDependentAttributes($sClass, $sAttCode); // List of attributes that depend on the current one
if (count($aDependencies) > 0)
{
// Unbind first to avoid duplicate event handlers in case of reload of the whole (or part of the) form
$oPage->add_ready_script("$('#$iId').unbind('change.dependencies').bind('change.dependencies', function(evt, sFormId) { return oWizardHelper{$sFormPrefix}.UpdateDependentFields(['".implode("','", $aDependencies)."']) } );\n"); // Bind to a custom event: validate
$oPage->add_ready_script("$('#$iId').bind('change', function(evt, sFormId) { return oWizardHelper{$sFormPrefix}.UpdateDependentFields(['".implode("','", $aDependencies)."']) } );\n"); // Bind to a custom event: validate
}
}
$oPage->add_dict_entry('UI:ValueMustBeSet');
$oPage->add_dict_entry('UI:ValueMustBeChanged');
$oPage->add_dict_entry('UI:ValueInvalidFormat');
return "<div>{$sHTMLValue}</div>";
}
@@ -2475,7 +2465,7 @@ EOF
{
// Possible return values are:
// HILIGHT_CLASS_CRITICAL, HILIGHT_CLASS_WARNING, HILIGHT_CLASS_OK, HILIGHT_CLASS_NONE
$current = parent::GetHilightClass(); // Default computation
$current = HILIGHT_CLASS_NONE; // Not hilighted by default
// Invoke extensions before the deletion (the deletion will do some cleanup and we might loose some information
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -39,11 +39,7 @@ class CSVPage extends WebPage
public function output()
{
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
$this->add_header("Content-Length: ".strlen(trim($this->s_content)));
foreach($this->a_headers as $s_header)
{
header($s_header);
@@ -109,3 +105,4 @@ class CSVPage extends WebPage
}
}
?>

View File

@@ -733,8 +733,7 @@ abstract class DashletGroupBy extends Dashlet
if (is_subclass_of($sAttType, 'AttributeFriendlyName')) continue;
if ($sAttType == 'AttributeExternalField') continue;
if (is_subclass_of($sAttType, 'AttributeExternalField')) continue;
if ($sAttType == 'AttributeOneWayPassword') continue;
$sLabel = $this->oModelReflection->GetLabel($sClass, $sAttCode);
$aGroupBy[$sAttCode] = $sLabel;

View File

@@ -393,7 +393,7 @@ class DisplayBlock
{
if (isset($aExtraParams['group_by_label']))
{
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
$sGroupByLabel = $aExtraParams['group_by_label'];
}
else
@@ -404,21 +404,6 @@ class DisplayBlock
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
}
// Security filtering
$aFields = $oGroupByExp->ListRequiredFields();
foreach($aFields as $sFieldAlias)
{
if (preg_match('/^([^.]+)\\.([^.]+)$/', $sFieldAlias, $aMatches))
{
$sFieldClass = $this->m_oFilter->GetClassName($aMatches[1]);
$oAttDef = MetaModel::GetAttributeDef($sFieldClass, $aMatches[2]);
if ($oAttDef instanceof AttributeOneWayPassword)
{
throw new Exception('Grouping on password fields is not supported.');
}
}
}
$aGroupBy = array();
$aGroupBy['grouped_by_1'] = $oGroupByExp;
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy, true);
@@ -780,7 +765,6 @@ class DisplayBlock
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
$sHtml .= '<div style="clear:both;"></div>';
break;
case 'csv':

View File

@@ -1,536 +0,0 @@
<?php
require_once('xlsxwriter.class.php');
class ExcelExporter
{
protected $sToken;
protected $aStatistics;
protected $sState;
protected $fStartTime;
protected $oSearch;
protected $aObjectsIDs;
protected $aTableHeaders;
protected $aAuthorizedClasses;
protected $iChunkSize = 1000;
protected $iPosition;
protected $sOutputFilePath;
protected $bAdvancedMode;
public function __construct($sToken = null)
{
$this->aStatistics = array(
'objects_count' => 0,
'total_duration' => 0,
'data_retrieval_duration' => 0,
'excel_build_duration' => 0,
'excel_write_duration' => 0,
'peak_memory_usage' => 0,
);
$this->fStartTime = microtime(true);
$this->oSearch = null;
$this->sState = 'new';
$this->aObjectsIDs = array();
$this->iPosition = 0;
$this->aAuthorizedClasses = null;
$this->aTableHeaders = null;
$this->sOutputFilePath = null;
$this->bAdvancedMode = false;
$this->CheckDataDir();
if ($sToken == null)
{
$this->sToken = $this->GetNewToken();
}
else
{
$this->sToken = $sToken;
$this->ReloadState();
}
}
public function __destruct()
{
if (($this->sState != 'done') && ($this->sState != 'error') && ($this->sToken != null))
{
// Operation in progress, save the state
$this->SaveState();
}
else
{
// Operation completed, cleanup the temp files
@unlink($this->GetStateFile());
@unlink($this->GetDataFile());
}
self::CleanupOldFiles();
}
public function SetChunkSize($iChunkSize)
{
$this->iChunkSize = $iChunkSize;
}
public function SetOutputFilePath($sDestFilePath)
{
$this->sOutputFilePath = $sDestFilePath;
}
public function SetAdvancedMode($bAdvanced)
{
$this->bAdvancedMode = $bAdvanced;
}
public function SaveState()
{
$aState = array(
'state' => $this->sState,
'statistics' => $this->aStatistics,
'filter' => $this->oSearch->serialize(),
'position' => $this->iPosition,
'chunk_size' => $this->iChunkSize,
'object_ids' => $this->aObjectsIDs,
'output_file_path' => $this->sOutputFilePath,
'advanced_mode' => $this->bAdvancedMode,
);
file_put_contents($this->GetStateFile(), json_encode($aState));
return $this->sToken;
}
public function ReloadState()
{
if ($this->sToken == null)
{
throw new Exception('ExcelExporter not initialized with a token, cannot reload state');
}
if (!file_exists($this->GetStateFile()))
{
throw new Exception("ExcelExporter: missing status file '".$this->GetStateFile()."', cannot reload state.");
}
$sJson = file_get_contents($this->GetStateFile());
$aState = json_decode($sJson, true);
if ($aState === null)
{
throw new Exception("ExcelExporter:corrupted status file '".$this->GetStateFile()."', not a JSON, cannot reload state.");
}
$this->sState = $aState['state'];
$this->aStatistics = $aState['statistics'];
$this->oSearch = DBObjectSearch::unserialize($aState['filter']);
$this->iPosition = $aState['position'];
$this->iChunkSize = $aState['chunk_size'];
$this->aObjectsIDs = $aState['object_ids'];
$this->sOutputFilePath = $aState['output_file_path'];
$this->bAdvancedMode = $aState['advanced_mode'];
}
public function SetObjectList($oSearch)
{
$this->oSearch = $oSearch;
}
public function Run()
{
$sCode = 'error';
$iPercentage = 100;
$sMessage = Dict::Format('ExcelExporter:ErrorUnexpected_State', $this->sState);
$fTime = microtime(true);
try
{
switch($this->sState)
{
case 'new':
$oIDSet = new DBObjectSet($this->oSearch);
$oIDSet->OptimizeColumnLoad(array('id'));
$this->aObjectsIDs = array();
while($oObj = $oIDSet->Fetch())
{
$this->aObjectsIDs[] = $oObj->GetKey();
}
$sCode = 'retrieving-data';
$iPercentage = 5;
$sMessage = Dict::S('ExcelExporter:RetrievingData');
$this->iPosition = 0;
$this->aStatistics['objects_count'] = count($this->aObjectsIDs);
$this->aStatistics['data_retrieval_duration'] += microtime(true) - $fTime;
// The first line of the file is the "headers" specifying the label and the type of each column
$this->GetFieldsList($oIDSet, $this->bAdvancedMode);
$sRow = json_encode($this->aTableHeaders);
$hFile = @fopen($this->GetDataFile(), 'ab');
if ($hFile === false)
{
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
}
fwrite($hFile, $sRow."\n");
fclose($hFile);
// Next state
$this->sState = 'retrieving-data';
break;
case 'retrieving-data':
$oCurrentSearch = clone $this->oSearch;
$aIDs = array_slice($this->aObjectsIDs, $this->iPosition, $this->iChunkSize);
$oCurrentSearch->AddCondition('id', $aIDs, 'IN');
$hFile = @fopen($this->GetDataFile(), 'ab');
if ($hFile === false)
{
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for writing.');
}
$oSet = new DBObjectSet($oCurrentSearch);
$this->GetFieldsList($oSet, $this->bAdvancedMode);
while($aObjects = $oSet->FetchAssoc())
{
$aRow = array();
foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
{
$oObj = $aObjects[$sAlias];
if ($this->bAdvancedMode)
{
$aRow[] = $oObj->GetKey();
}
foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
{
$value = $oObj->Get($sAttCodeEx);
if ($value instanceOf ormCaseLog)
{
// Extract the case log as text and remove the "===" which make Excel think that the cell contains a formula the next time you edit it!
$sExcelVal = trim(preg_replace('/========== ([^=]+) ============/', '********** $1 ************', $value->GetText()));
}
else
{
$sExcelVal = $oAttDef->GetEditValue($value, $oObj);
}
$aRow[] = $sExcelVal;
}
}
$sRow = json_encode($aRow);
fwrite($hFile, $sRow."\n");
}
fclose($hFile);
if (($this->iPosition + $this->iChunkSize) > count($this->aObjectsIDs))
{
// Next state
$this->sState = 'building-excel';
$sCode = 'building-excel';
$iPercentage = 80;
$sMessage = Dict::S('ExcelExporter:BuildingExcelFile');
}
else
{
$sCode = 'retrieving-data';
$this->iPosition += $this->iChunkSize;
$iPercentage = 5 + round(75 * ($this->iPosition / count($this->aObjectsIDs)));
$sMessage = Dict::S('ExcelExporter:RetrievingData');
}
break;
case 'building-excel':
$hFile = @fopen($this->GetDataFile(), 'rb');
if ($hFile === false)
{
throw new Exception('ExcelExporter: Failed to open temporary data file: "'.$this->GetDataFile().'" for reading.');
}
$sHeaders = fgets($hFile);
$aHeaders = json_decode($sHeaders, true);
$aData = array();
while($sLine = fgets($hFile))
{
$aRow = json_decode($sLine);
$aData[] = $aRow;
}
fclose($hFile);
@unlink($this->GetDataFile());
$fStartExcel = microtime(true);
$writer = new XLSXWriter();
$writer->setAuthor(UserRights::GetUserFriendlyName());
$writer->writeSheet($aData,'Sheet1', $aHeaders);
$fExcelTime = microtime(true) - $fStartExcel;
$this->aStatistics['excel_build_duration'] = $fExcelTime;
$fTime = microtime(true);
$writer->writeToFile($this->GetExcelFilePath());
$fExcelSaveTime = microtime(true) - $fTime;
$this->aStatistics['excel_write_duration'] = $fExcelSaveTime;
// Next state
$this->sState = 'done';
$sCode = 'done';
$iPercentage = 100;
$sMessage = Dict::S('ExcelExporter:Done');
break;
case 'done':
$this->sState = 'done';
$sCode = 'done';
$iPercentage = 100;
$sMessage = Dict::S('ExcelExporter:Done');
break;
}
}
catch(Exception $e)
{
$sCode = 'error';
$sMessage = $e->getMessage();
}
$this->aStatistics['total_duration'] += microtime(true) - $fTime;
$peak_memory = memory_get_peak_usage(true);
if ($peak_memory > $this->aStatistics['peak_memory_usage'])
{
$this->aStatistics['peak_memory_usage'] = $peak_memory;
}
return array(
'code' => $sCode,
'message' => $sMessage,
'percentage' => $iPercentage,
);
}
public function GetExcelFilePath()
{
if ($this->sOutputFilePath == null)
{
return APPROOT.'data/bulk_export/'.$this->sToken.'.xlsx';
}
else
{
return $this->sOutputFilePath;
}
}
public static function GetExcelFileFromToken($sToken)
{
return @file_get_contents(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
}
public static function CleanupFromToken($sToken)
{
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.status');
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.data');
@unlink(APPROOT.'data/bulk_export/'.$sToken.'.xlsx');
}
public function Cleanup()
{
self::CleanupFromToken($this->sToken);
}
/**
* Delete all files in the data/bulk_export directory which are older than 1 day
* unless a different delay is configured.
*/
public static function CleanupOldFiles()
{
$aFiles = glob(APPROOT.'data/bulk_export/*.*');
$iDelay = MetaModel::GetConfig()->Get('xlsx_exporter_cleanup_old_files_delay');
if($iDelay > 0)
{
foreach($aFiles as $sFile)
{
$iModificationTime = filemtime($sFile);
if($iModificationTime < (time() - $iDelay))
{
// Temporary files older than one day are deleted
//echo "Supposed to delete: '".$sFile." (Unix Modification Time: $iModificationTime)'\n";
@unlink($sFile);
}
}
}
}
public function DisplayStatistics(Page $oPage)
{
$aStats = array(
'Number of objects exported' => $this->aStatistics['objects_count'],
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
);
if ($oPage instanceof CLIPage)
{
$oPage->add($this->GetStatistics('text'));
}
else
{
$oPage->add($this->GetStatistics('html'));
}
}
public function GetStatistics($sFormat = 'html')
{
$sStats = '';
$aStats = array(
'Number of objects exported' => $this->aStatistics['objects_count'],
'Total export duration' => sprintf('%.3f s', $this->aStatistics['total_duration']),
'Data retrieval duration' => sprintf('%.3f s', $this->aStatistics['data_retrieval_duration']),
'Excel build duration' => sprintf('%.3f s', $this->aStatistics['excel_build_duration']),
'Excel write duration' => sprintf('%.3f s', $this->aStatistics['excel_write_duration']),
'Peak memory usage' => self::HumanDisplay($this->aStatistics['peak_memory_usage']),
);
if ($sFormat == 'text')
{
foreach($aStats as $sLabel => $sValue)
{
$sStats .= "+------------------------------+----------+\n";
$sStats .= sprintf("|%-30s|%10s|\n", $sLabel, $sValue);
}
$sStats .= "+------------------------------+----------+";
}
else
{
$sStats .= '<table><tbody>';
foreach($aStats as $sLabel => $sValue)
{
$sStats .= "<tr><td>$sLabel</td><td>$sValue</td></tr>";
}
$sStats .= '</tbody></table>';
}
return $sStats;
}
public static function HumanDisplay($iSize)
{
$aUnits = array('B','KB','MB','GB','TB','PB');
return @round($iSize/pow(1024,($i=floor(log($iSize,1024)))),2).' '.$aUnits[$i];
}
protected function CheckDataDir()
{
if(!is_dir(APPROOT."data/bulk_export"))
{
@mkdir(APPROOT."data/bulk_export", 0777, true /* recursive */);
clearstatcache();
}
if (!is_writable(APPROOT."data/bulk_export"))
{
throw new Exception('Data directory "'.APPROOT.'data/bulk_export" could not be written.');
}
}
protected function GetStateFile($sToken = null)
{
if ($sToken == null)
{
$sToken = $this->sToken;
}
return APPROOT."data/bulk_export/$sToken.status";
}
protected function GetDataFile()
{
return APPROOT.'data/bulk_export/'.$this->sToken.'.data';
}
protected function GetNewToken()
{
$iNum = rand();
do
{
$iNum++;
$sToken = sprintf("%08x", $iNum);
$sFileName = $this->GetStateFile($sToken);
$hFile = @fopen($sFileName, 'x');
}
while($hFile === false);
fclose($hFile);
return $sToken;
}
protected function GetFieldsList($oSet, $bFieldsAdvanced = false, $bLocalize = true, $aFields = null)
{
$this->aFieldsList = array();
$oAppContext = new ApplicationContext();
$aClasses = $oSet->GetFilter()->GetSelectedClasses();
$this->aAuthorizedClasses = array();
foreach($aClasses as $sAlias => $sClassName)
{
if (UserRights::IsActionAllowed($sClassName, UR_ACTION_READ, $oSet) && (UR_ALLOWED_YES || UR_ALLOWED_DEPENDS))
{
$this->aAuthorizedClasses[$sAlias] = $sClassName;
}
}
$aAttribs = array();
$this->aTableHeaders = array();
foreach($this->aAuthorizedClasses as $sAlias => $sClassName)
{
$aList[$sAlias] = array();
foreach(MetaModel::ListAttributeDefs($sClassName) as $sAttCode => $oAttDef)
{
if (is_null($aFields) || (count($aFields) == 0))
{
// Standard list of attributes (no link sets)
if ($oAttDef->IsScalar() && ($oAttDef->IsWritable() || $oAttDef->IsExternalField()))
{
$sAttCodeEx = $oAttDef->IsExternalField() ? $oAttDef->GetKeyAttCode().'->'.$oAttDef->GetExtAttCode() : $sAttCode;
if ($oAttDef->IsExternalKey(EXTKEY_ABSOLUTE))
{
if ($bFieldsAdvanced)
{
$aList[$sAlias][$sAttCodeEx] = $oAttDef;
if ($oAttDef->IsExternalKey(EXTKEY_RELATIVE))
{
$sRemoteClass = $oAttDef->GetTargetClass();
foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sRemoteAttCode)
{
$this->aFieldsList[$sAlias][$sAttCode.'->'.$sRemoteAttCode] = MetaModel::GetAttributeDef($sRemoteClass, $sRemoteAttCode);
}
}
}
}
else
{
// Any other attribute
$this->aFieldsList[$sAlias][$sAttCodeEx] = $oAttDef;
}
}
}
else
{
// User defined list of attributes
if (in_array($sAttCode, $aFields) || in_array($sAlias.'.'.$sAttCode, $aFields))
{
$this->aFieldsList[$sAlias][$sAttCode] = $oAttDef;
}
}
}
if ($bFieldsAdvanced)
{
$this->aTableHeaders['id'] = '0';
}
foreach($this->aFieldsList[$sAlias] as $sAttCodeEx => $oAttDef)
{
$sLabel = $bLocalize ? MetaModel::GetLabel($sClassName, $sAttCodeEx, isset($aParams['showMandatoryFields'])) : $sAttCodeEx;
if($oAttDef instanceof AttributeDateTime)
{
$this->aTableHeaders[$sLabel] = 'datetime';
}
else
{
$this->aTableHeaders[$sLabel] = 'string';
}
}
}
}
}

View File

@@ -38,10 +38,7 @@ class DesignerForm
protected $bReadOnly;
protected $sHierarchyPath; // Needed to manage the visibility of nested subform
protected $sHierarchyParent; // Needed to manage the visibility of nested subform
protected $sHierarchySelector; // Needed to manage the visibility of nested subform
protected $bDisplayed;
protected $aDefaultValues;
protected $sFieldsSuffix;
public function __construct()
{
@@ -50,17 +47,14 @@ class DesignerForm
$this->sScript = '';
$this->sReadyScript = '';
$this->sFormPrefix = '';
$this->sFieldsSuffix = '';
$this->sParamsContainer = '';
$this->sFormId = 'form_'.rand();
$this->oParentForm = null;
$this->bReadOnly = false;
$this->sHierarchyPath = '';
$this->sHierarchyParent = '';
$this->sHierarchySelector = '';
$this->StartFieldSet($this->sCurrentFieldSet);
$this->bDisplayed = true;
$this->aDefaultvalues = array();
}
public function AddField(DesignerFormField $oField)
@@ -84,14 +78,15 @@ class DesignerForm
public function Render($oP, $bReturnHTML = false)
{
$sFormId = $this->GetFormId();
if ($this->oParentForm == null)
{
$sFormId = $this->sFormId;
$sReturn = '<form id="'.$sFormId.'">';
}
else
{
$sReturn = '';
$sFormId = $this->oParentForm->sFormId;
}
$sHiddenFields = '';
foreach($this->aFieldSets as $sLabel => $aFields)
@@ -107,7 +102,7 @@ class DesignerForm
$aRow = $oField->Render($oP, $sFormId);
if ($oField->IsVisible())
{
$sValidation = '&nbsp;<span class="prop_apply">'.$this->GetValidationArea($oField->GetFieldId()).'</span>';
$sValidation = '&nbsp;<span class="prop_apply">'.$this->GetValidationArea($oField->GetCode()).'</span>';
$sField = $aRow['value'].$sValidation;
$aDetails[] = array('label' => $aRow['label'], 'value' => $sField);
}
@@ -145,11 +140,6 @@ class DesignerForm
$oP->add($sReturn);
}
}
public function GetFieldSets()
{
return $this->aFieldSets;
}
public function SetSubmitParams($sSubmitToUrl, $aSubmitParams)
{
@@ -163,11 +153,6 @@ class DesignerForm
$this->aSubmitParams = $oParentForm->aSubmitParams;
}
public function GetSubmitParams()
{
return array( 'url' => $this->sSubmitTo, 'params' => $this->aSubmitParams);
}
/**
* Helper to handle subforms hide/show
*/
@@ -183,7 +168,7 @@ class DesignerForm
{
return $this->sHierarchyPath;
}
/**
* Helper to handle subforms hide/show
*/
@@ -206,21 +191,24 @@ class DesignerForm
$sReturn = '';
$sActionUrl = addslashes($this->sSubmitTo);
$sJSSubmitParams = json_encode($this->aSubmitParams);
$sFormId = $this->GetFormId();
if ($this->oParentForm == null)
{
$sFormId = $this->sFormId;
$sReturn = '<form id="'.$sFormId.'" onsubmit="return false;">';
$sReturn .= '<table class="prop_table">';
$sReturn .= '<thead><tr><th class="prop_header">'.Dict::S('UI:Form:Property').'</th><th class="prop_header">'.Dict::S('UI:Form:Value').'</th><th colspan="2" class="prop_header">&nbsp;</th></tr></thead><tbody>';
}
else
{
$sFormId = $this->oParentForm->sFormId;
}
$sHiddenFields = '';
foreach($this->aFieldSets as $sLabel => $aFields)
{
$aDetails = array();
if ($sLabel != '')
{
$sReturn .= $this->StartRow().'<th colspan="4">'.$sLabel.'</th>'.$this->EndRow();
$sReturn .= '<tr><th colspan="4">'.$sLabel.'</th></tr>';
}
@@ -230,42 +218,18 @@ class DesignerForm
if ($oField->IsVisible())
{
$sFieldId = $this->GetFieldId($oField->GetCode());
$sValidation = $this->GetValidationArea($sFieldId, '<span title="Apply" class="ui-icon ui-icon-circle-check"/>');
$sValidationFields = '</td><td class="prop_icon prop_apply">'.$sValidation.'</td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td>'.$this->EndRow();
$sPath = $this->GetHierarchyPath().'/'.$oField->GetCode();
if (is_null($aRow['label']))
{
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_value" colspan="2">'.$aRow['value'];
}
else
{
$sReturn .= $this->StartRow($sFieldId).'<td class="prop_label">'.$aRow['label'].'</td><td class="prop_value">'.$aRow['value'];
}
if (!($oField instanceof DesignerFormSelectorField) && !($oField instanceof DesignerMultipleSubFormField))
$sValidation = $this->GetValidationArea($oField->GetCode(), '<span title="Apply" class="ui-icon ui-icon-circle-check"/>');
$sValidationFields = '</td><td class="prop_icon prop_apply">'.$sValidation.'</td><td class="prop_icon prop_cancel"><span title="Revert" class="ui-icon ui-icon-circle-close"/></td></tr>';
$sReturn .= '<tr id="row_'.$sFieldId.'"><td class="prop_label">'.$aRow['label'].'</td><td class="prop_value">'.$aRow['value'];
if (!($oField instanceof DesignerFormSelectorField))
{
$sReturn .= $sValidationFields;
}
$sNotifyParentSelectorJS = is_null($sNotifyParentSelector) ? 'null' : "'".addslashes($sNotifyParentSelector)."'";
$sAutoApply = $oField->IsAutoApply() ? 'true' : 'false';
$sHandlerEquals = $oField->GetHandlerEquals();
$sHandlerGetValue = $oField->GetHandlerGetValue();
$sWidgetClass = $oField->GetWidgetClass();
$sJSExtraParams = '';
if (count($oField->GetWidgetExtraParams()) > 0)
{
$aExtraParams = array();
foreach($oField->GetWidgetExtraParams() as $key=> $value)
{
$aExtraParams[] = "'$key': ".json_encode($value);
}
$sJSExtraParams = ', '.implode(', ', $aExtraParams);
}
$this->AddReadyScript(
<<<EOF
$('#row_$sFieldId').$sWidgetClass({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', equals: $sHandlerEquals, get_field_value: $sHandlerGetValue, auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams $sJSExtraParams });
$('#row_$sFieldId').property_field({parent_selector: $sNotifyParentSelectorJS, field_id: '$sFieldId', auto_apply: $sAutoApply, value: '', submit_to: '$sActionUrl', submit_parameters: $sJSSubmitParams });
EOF
);
}
@@ -283,7 +247,7 @@ EOF
$sReturn .= '</table>';
$sReturn .= $sHiddenFields;
$sReturn .= '</form>';
$sReturn .= '<div id="prop_submit_result"></div>'; // for the return of the submit operation
$sReturn .= '<div id="prop_submit_result"/>'; // for the return of the submit operation
}
else
{
@@ -323,26 +287,9 @@ EOF
{
$oP->add($sReturn);
}
}
public function StartRow($sFieldId = null)
{
if ($sFieldId != null)
{
return '<tr id="row_'.$sFieldId.'" data-path="'.$this->GetHierarchyPath().'" data-selector="'.$this->GetHierarchyParent().'">';
}
return '<tr data-path="'.$this->GetHierarchyPath().'" data-selector="'.$this->GetHierarchyParent().'">';
}
public function EndRow()
{
return '</tr>';
}
}
public function RenderAsDialog($oPage, $sDialogId, $sDialogTitle, $iDialogWidth, $sOkButtonLabel, $sIntroduction = null)
{
$this->SetPrefix('dlg_'); // To make sure that the controls have different IDs that the property sheet which may be displayed at the same time
$sDialogTitle = addslashes($sDialogTitle);
$sOkButtonLabel = addslashes($sOkButtonLabel);
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
@@ -359,21 +306,13 @@ EOF
<<<EOF
$('#$sDialogId').dialog({
height: 'auto',
width: $iDialogWidth,
width: 500,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sOkButtonLabel", click: function() {
var oForm = $(this).closest('.ui-dialog').find('form');
oForm.submit();
if (AnimateDlgButtons)
{
sFormId = oForm.attr('id');
if (oFormValidation[sFormId].length == 0)
{
AnimateDlgButtons(this);
}
}
} },
{ text: "$sCancelButtonLabel", click: function() { KillAllMenus(); $(this).dialog( "close" ); $(this).remove(); } },
],
@@ -405,29 +344,9 @@ EOF
public function GetPrefix()
{
$sPrefix = '';
if ($this->oParentForm != null)
{
$sPrefix = $this->oParentForm->GetPrefix();
}
return $sPrefix.$this->sFormPrefix;
}
public function SetSuffix($sSuffix)
{
$this->sFieldsSuffix = $sSuffix;
return $this->sFormPrefix;
}
public function GetSuffix()
{
$sSuffix = '';
if ($this->oParentForm != null)
{
$sSuffix = $this->oParentForm->GetSuffix();
}
return $sSuffix.$this->sFieldsSuffix;
}
public function SetReadOnly($bReadOnly = true)
{
$this->bReadOnly = $bReadOnly;
@@ -467,39 +386,11 @@ EOF
$this->oParentForm = $oParentForm;
}
public function SetDefaultValues($aDefaultValues)
{
if (!is_array($aDefaultValues)) return;
foreach($this->aFieldSets as $sLabel => $aFields)
{
foreach($aFields as $oField)
{
$oField->SetDefaultValueFrom($aDefaultValues);
}
}
}
public function GetDefaultValues()
{
return $this->aDefaultValues;
}
public function GetParentForm()
{
return $this->oParentForm;
}
public function GetFormId()
{
if ($this->oParentForm)
{
$this->oParentForm->GetFormId();
}
return $this->sFormId;
}
public function SetDisplayed($bDisplayed)
{
$this->bDisplayed = $bDisplayed;
@@ -529,42 +420,27 @@ EOF
public function GetFieldId($sCode)
{
return $this->GetPrefix().'attr_'.$sCode;
return $this->sFormPrefix.'attr_'.$sCode;
}
public function GetFieldName($sCode)
{
return 'attr_'.$sCode.$this->GetSuffix();
return 'attr_'.$sCode;
}
public function GetParamName($sCode)
{
return 'attr_'.$sCode.$this->GetSuffix();
return 'attr_'.$sCode;
}
public function GetValidationArea($sId, $sContent = '')
public function GetValidationArea($sCode, $sContent = '')
{
return "<span style=\"display:inline-block;width:20px;\" id=\"v_{$sId}\"><span class=\"ui-icon ui-icon-alert\"></span>$sContent</span>";
return "<span style=\"display:inline-block;width:20px;\" id=\"v_{$this->sFormPrefix}attr_$sCode\"><span class=\"ui-icon ui-icon-alert\"></span>$sContent</span>";
}
public function GetAsyncActionClass()
{
return $this->sAsyncActionClass;
}
public function FindField($sFieldCode)
{
$oFoundField = false;
foreach($this->aFieldSets as $sLabel => $aFields)
{
foreach($aFields as $oField)
{
$oFoundField = $oField->FindField($sFieldCode);
if ($oFoundField !== false) break;
}
if ($oFoundField !== false) break;
}
return $oFoundField;
}
}
class DesignerTabularForm extends DesignerForm
@@ -580,11 +456,6 @@ class DesignerTabularForm extends DesignerForm
{
$this->aTable[] = $aRow;
}
public function RenderAsPropertySheet($oP, $bReturnHTML = false, $sNotifyParentSelector = null)
{
return $this->Render($oP, $bReturnHTML);
}
public function Render($oP, $bReturnHTML = false)
{
@@ -685,7 +556,6 @@ class DesignerFormField
protected $bAutoApply;
protected $aCSSClasses;
protected $bDisplayed;
protected $aWidgetExtraParams;
public function __construct($sCode, $sLabel, $defaultValue)
{
@@ -697,7 +567,6 @@ class DesignerFormField
$this->bAutoApply = false;
$this->aCSSClasses = array();
$this->bDisplayed = true;
$this->aWidgetExtraParams = array();
}
public function GetCode()
@@ -746,21 +615,6 @@ class DesignerFormField
return $this->bDisplayed;
}
public function GetFieldId()
{
return $this->oForm->GetFieldId($this->sCode);
}
public function GetWidgetClass()
{
return 'property_field';
}
public function GetWidgetExtraParams()
{
return $this->aWidgetExtraParams;
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
@@ -804,36 +658,6 @@ class DesignerFormField
{
$this->aCSSClasses[] = $sCSSClass;
}
/**
* A way to set/change the default value after constructing the field
*/
public function SetDefaultValueFrom($aAllDefaultValue)
{
if (array_key_exists($this->GetCode(), $aAllDefaultValue))
{
$this->defaultValue = $aAllDefaultValue[$this->GetCode()];
}
}
public function FindField($sFieldCode)
{
if ($this->sCode == $sFieldCode)
{
return $this;
}
return false;
}
public function GetHandlerEquals()
{
return 'null';
}
public function GetHandlerGetValue()
{
return 'null';
}
}
class DesignerLabelField extends DesignerFormField
@@ -850,7 +674,7 @@ class DesignerLabelField extends DesignerFormField
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
return array('label' => $this->sLabel, 'value' => $this->sDescription);
return array('label' => $this->sLabel, 'value' => $sDescription);
}
public function ReadParam(&$aValues)
@@ -899,7 +723,6 @@ class DesignerTextField extends DesignerFormField
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
if ($this->IsReadOnly())
{
@@ -921,7 +744,7 @@ class DesignerTextField extends DesignerFormField
$sMandatory = $this->bMandatory ? 'true' : 'false';
$oP->add_ready_script(
<<<EOF
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues, '$sExplainForbiddenValues'); } );
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', '$sFormId', $sForbiddenValues, '$sExplainForbiddenValues'); } );
{
var myTimer = null;
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
@@ -975,7 +798,7 @@ class DesignerLongTextField extends DesignerTextField
$sReadOnly = $this->IsReadOnly() ? 'readonly' : '';
$oP->add_ready_script(
<<<EOF
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', $(this).closest('form').attr('id'), $sForbiddenValues, '$sExplainForbiddenValues'); } );
$('#$sId').bind('change keyup validate', function() { ValidateWithPattern('$sId', $sMandatory, '$sPattern', '$sFormId', $sForbiddenValues, '$sExplainForbiddenValues'); } );
{
var myTimer = null;
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
@@ -1025,7 +848,7 @@ class DesignerIntegerField extends DesignerFormField
$sMandatory = $this->bMandatory ? 'true' : 'false';
$oP->add_ready_script(
<<<EOF
$('#$sId').bind('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, $(this).closest('form').attr('id'), $sMin, $sMax); } );
$('#$sId').bind('change keyup validate', function() { ValidateInteger('$sId', $sMandatory, '$sFormId', $sMin, $sMax); } );
{
var myTimer = null;
$('#$sId').bind('keyup', function() { clearTimeout(myTimer); myTimer = setTimeout(function() { $('#$sId').trigger('change', {} ); }, 100); });
@@ -1064,7 +887,6 @@ class DesignerComboField extends DesignerFormField
protected $aAllowedValues;
protected $bMultipleSelection;
protected $bOtherChoices;
protected $sNullLabel;
public function __construct($sCode, $sLabel = '', $defaultValue = '')
{
@@ -1072,7 +894,6 @@ class DesignerComboField extends DesignerFormField
$this->aAllowedValues = array();
$this->bMultipleSelection = false;
$this->bOtherChoices = false;
$this->sNullLabel = Dict::S('UI:SelectOne');
$this->bAutoApply = true;
}
@@ -1091,17 +912,11 @@ class DesignerComboField extends DesignerFormField
{
$this->bOtherChoices = $bOtherChoices;
}
/**
* An empty label will disable the default empty value
*/
public function SetNullLabel($sLabel)
{
$this->sNullLabel = $sLabel;
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
$sId = $this->oForm->GetFieldId($this->sCode);
$sName = $this->oForm->GetFieldName($this->sCode);
$sChecked = $this->defaultValue ? 'checked' : '';
@@ -1146,10 +961,7 @@ class DesignerComboField extends DesignerFormField
else
{
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\">";
if ($this->sNullLabel != '')
{
$sHtml .= "<option value=\"\">".$this->sNullLabel."</option>";
}
$sHtml .= "<option value=\"\">".Dict::S('UI:SelectOne')."</option>";
}
foreach($this->aAllowedValues as $sKey => $sDisplayValue)
{
@@ -1172,7 +984,7 @@ class DesignerComboField extends DesignerFormField
}
$oP->add_ready_script(
<<<EOF
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', $(this).closest('form').attr('id'), null, null); } );
$('#$sId').bind('change validate', function() { ValidateWithPattern('$sId', $sMandatory, '', '$sFormId', null, null); } );
EOF
);
}
@@ -1249,6 +1061,7 @@ class DesignerBooleanField extends DesignerFormField
}
}
class DesignerHiddenField extends DesignerFormField
{
public function __construct($sCode, $sLabel = '', $defaultValue = '')
@@ -1310,19 +1123,14 @@ class DesignerIconSelectionField extends DesignerFormField
$sPostUploadTo = ($this->sUploadUrl == null) ? 'null' : "'{$this->sUploadUrl}'";
if (!$this->IsReadOnly())
{
$sValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$this->defaultValue}\"/>";
$oP->add_ready_script(
<<<EOF
$('#$sId').icon_select({current_idx: $idx, items: $sJSItems, post_upload_to: $sPostUploadTo});
EOF
);
}
else
{
$sValue = '<img src="'.$this->MakeFileUrl($this->defaultValue).'" />';
}
$sReadOnly = $this->IsReadOnly() ? 'disabled' : '';
return array('label' => $this->sLabel, 'value' => $sValue);
return array('label' =>$this->sLabel, 'value' => "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"{$this->defaultValue}\"/>");
}
}
@@ -1435,11 +1243,6 @@ class DesignerFormSelectorField extends DesignerFormField
$this->aSubForms = array();
}
public function GetWidgetClass()
{
return 'selector_property_field';
}
public function AddSubForm($oSubForm, $sLabel, $sValue)
{
$idx = count($this->aSubForms);
@@ -1457,8 +1260,6 @@ class DesignerFormSelectorField extends DesignerFormField
$sName = $this->oForm->GetFieldName($this->sCode);
$sReadOnly = $this->IsReadOnly() ? 'disabled="disabled"' : '';
$this->aCSSClasses[] = 'formSelector';
$sCSSClasses = '';
if (count($this->aCSSClasses) > 0)
{
@@ -1472,12 +1273,12 @@ class DesignerFormSelectorField extends DesignerFormField
$aHiddenValues = array();
$sDisplayValue = '';
$sHiddenValue = '';
foreach($this->aSubForms as $iKey => $aFormData)
foreach($this->aSubForms as $sKey => $aFormData)
{
if ($iKey == $this->defaultValue) // Default value is actually the index
if ($sKey == $this->defaultValue)
{
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');
$sHiddenValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($iKey, ENT_QUOTES, 'UTF-8')."\"/>";
$sHiddenValue = "<input type=\"hidden\" id=\"$sId\" name=\"$sName\" value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\"/>";
break;
}
}
@@ -1488,11 +1289,11 @@ class DesignerFormSelectorField extends DesignerFormField
$sHtml = "<select $sCSSClasses id=\"$sId\" name=\"$sName\" $sReadOnly>";
foreach($this->aSubForms as $iKey => $aFormData)
foreach($this->aSubForms as $sKey => $aFormData)
{
$sDisplayValue = htmlentities($aFormData['label'], ENT_QUOTES, 'UTF-8');;
$sSelected = ($iKey == $this->defaultValue) ? 'selected' : '';
$sHtml .= "<option value=\"$iKey\" $sSelected>".$sDisplayValue."</option>";
$sSelected = ($sKey == $this->defaultValue) ? 'selected' : '';
$sHtml .= "<option value=\"".htmlentities($sKey, ENT_QUOTES, 'UTF-8')."\" $sSelected>".$sDisplayValue."</option>";
}
$sHtml .= "</select>";
}
@@ -1521,21 +1322,19 @@ class DesignerFormSelectorField extends DesignerFormField
// - data-path : uniquely identifies the combination of users choices that must be made to show the node
// - data-state : records the state, depending on the user choice on the FormSelectorField just above the node, but indepentantly from the visibility in the page (can be visible in the form itself being in a hidden form)
// Then a series of actions are performed to hide and show the relevant nodes, depending on the user choice
$sSelector = $this->oForm->GetHierarchyPath().'/'.$this->sCode.$this->oForm->GetSuffix();
$sSelector = $this->oForm->GetHierarchyPath().'/'.$this->sCode;
$oSubForm->SetHierarchyParent($sSelector);
$sPath = $this->oForm->GetHierarchyPath().'/'.$this->sCode.$this->oForm->GetSuffix().'-'.$sKey;
$sPath = $this->oForm->GetHierarchyPath().'/'.$this->sCode.':'.$sKey;
$oSubForm->SetHierarchyPath($sPath);
$oSubForm->SetDisplayed($sKey == $this->defaultValue);
$sState = ($sKey == $this->defaultValue) ? 'visible' : 'hidden';
//$sHtml .= "</tbody><tbody data-selector=\"$sSelector\" data-path=\"$sPath\" data-state=\"$sState\" $sStyle>";
$sHtml .= "</tbody><tbody data-selector=\"$sSelector\" data-path=\"$sPath\" data-state=\"$sState\" $sStyle>";
$sHtml .= $oSubForm->RenderAsPropertySheet($oP, true);
$sState = $this->oForm->IsDisplayed() ? 'visible' : 'hidden';
$sParentStyle = '';
if ($oParent = $this->oForm->GetParentForm())
{
$sParentStyle = ($oParent->IsDisplayed()) ? '' : 'style="display:none"';
$sParentSelector = $oParent->GetHierarchyParent();
$sParentPath = $oParent->GetHierarchyPath();
}
@@ -1544,8 +1343,7 @@ class DesignerFormSelectorField extends DesignerFormField
$sParentSelector = '';
$sParentPath = '';
}
//$sHtml .= "</tbody><tbody data-selector=\"$sParentSelector\" data-path=\"$sParentPath\" data-state=\"$sState\" $sParentStyle>";
$sHtml .= "</tbody><tbody data-selector=\"$sParentSelector\" data-path=\"$sParentPath\" data-state=\"$sState\" $sStyle>";
}
else
{
@@ -1557,8 +1355,27 @@ class DesignerFormSelectorField extends DesignerFormField
if ($sRenderMode == 'property')
{
$sSelector = $this->oForm->GetHierarchyPath().'/'.$this->sCode.$this->oForm->GetSuffix();
$this->aWidgetExtraParams['data_selector'] = $sSelector;
$sSelector = $this->oForm->GetHierarchyPath().'/'.$this->sCode;
$oP->add_ready_script(
<<<EOF
$('#$sId').bind('change reverted', function() {
// Mark all the direct children as hidden
$('tbody[data-selector="$sSelector"]').attr('data-state', 'hidden');
// Mark the selected one as visible
var sSelectedHierarchy = '$sSelector:'+this.value;
$('tbody[data-path="'+sSelectedHierarchy+'"]').attr('data-state', 'visible');
// Show all items behind the current one
$('tbody[data-path^="$sSelector"]').show();
// Hide items behind the current one as soon as it is behind a hidden node (or itself is marked as hidden)
$('tbody[data-path^="$sSelector"][data-state="hidden"]').each(function(){
$(this).hide();
var sPath = $(this).attr('data-path');
$('tbody[data-path^="'+sPath+'/"]').hide();
});
});
EOF
);
}
else
{
@@ -1581,44 +1398,6 @@ EOF
$this->aSubForms[$sKey]['form']->SetParentForm($this->oForm);
$this->aSubForms[$sKey]['form']->ReadParams($aValues);
}
public function SetDefaultValueFrom($aAllDefaultValues)
{
if (array_key_exists($this->GetCode(), $aAllDefaultValues))
{
$selectedValue = $aAllDefaultValues[$this->GetCode()];
foreach($this->aSubForms as $iKey => $aFormData)
{
$sId = $this->oForm->GetFieldId($this->sCode);
if ($selectedValue == $aFormData['value'])
{
$this->defaultValue =$iKey;
$aDefaultValues = $this->oForm->GetDefaultValues();
$oSubForm = $aFormData['form'];
$oSubForm->SetDefaultValues($aAllDefaultValues);
}
}
}
}
public function FindField($sFieldCode)
{
$oField = parent::FindField($sFieldCode);
if ($oField === false)
{
// Look in the subforms
foreach($this->aSubForms as $sKey => $aFormData)
{
$oSubForm = $aFormData['form'];
$oField = $oSubForm->FindField($sFieldCode);
if ($oField !== false)
{
break;
}
}
}
return $oField;
}
}
class DesignerSubFormField extends DesignerFormField
@@ -1651,31 +1430,6 @@ class DesignerSubFormField extends DesignerFormField
$this->oSubForm->SetParentForm($this->oForm);
$this->oSubForm->ReadParams($aValues);
}
public function FindField($sFieldCode)
{
$oField = parent::FindField($sFieldCode);
if ($oField === false)
{
// Look in the subform
$oField = $this->oSubForm->FindField($sFieldCode);
}
return $oField;
}
}
class DesignerStaticTextField extends DesignerFormField
{
public function __construct($sCode, $sLabel = '', $defaultValue = '')
{
parent::__construct($sCode, $sLabel, $defaultValue);
}
public function Render(WebPage $oP, $sFormId, $sRenderMode='dialog')
{
return array('label' => $this->sLabel, 'value' => $this->defaultValue);
}
}
?>

View File

@@ -587,7 +587,8 @@ EOF
header($s_header);
}
}
$s_captured_output = $this->ob_get_clean_safe();
$s_captured_output = ob_get_contents();
ob_end_clean();
$sHtml = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
$sHtml .= "<html>\n";
$sHtml .= "<head>\n";
@@ -1038,3 +1039,4 @@ EOF
$this->m_sMessage = $sMessage;
}
}
?>

View File

@@ -90,8 +90,6 @@ class PortalWebPage extends NiceWebPage
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
$this->add_linked_script('../js/jquery.multiselect.min.js');
$this->add_linked_script("../js/ajaxfileupload.js");
$this->add_linked_script("../js/ckeditor/ckeditor.js");
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
$this->add_ready_script(
<<<EOF
try
@@ -233,20 +231,6 @@ EOF
var next_step = $('input[id=next_step]');
next_step.val(sStep);
}
// For disabling the CKEditor at init time when the corresponding textarea is disabled !
CKEDITOR.plugins.add( 'disabler',
{
init : function( editor )
{
editor.on( 'instanceReady', function(e)
{
e.removeListener();
$('#'+ editor.name).trigger('update');
});
}
});
EOF
);
@@ -842,7 +826,7 @@ EOF
}
$sStepHistory = implode(',', $aPreviousSteps);
$this->add("<input type=\"hidden\" id=\"step_history\" name=\"step_history\" value=\"".htmlentities($sStepHistory, ENT_QUOTES, 'UTF-8')."\">");
$this->add("<input type=\"hidden\" id=\"step_history\" name=\"step_history\" value=\"$sStepHistory\">");
if (!is_null($sNextStep))
{

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -19,8 +19,7 @@
/**
* This class records the pending "transactions" corresponding to forms that have not been
* submitted yet, in order to prevent double submissions. When created a transaction remains valid
* until the user's session expires. This class is actually a wrapper to the underlying implementation
* which choice is configured via the parameter 'transaction_storage'
* until the user's session expires
*
* @package iTop
* @copyright Copyright (C) 2010-2012 Combodo SARL
@@ -29,81 +28,6 @@
class privUITransaction
{
/**
* Create a new transaction id, store it in the session and return its id
* @param void
* @return int The identifier of the new transaction
*/
public static function GetNewTransactionId()
{
$bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled');
if (!$bTransactionsEnabled)
{
return 'notransactions'; // Any value will do
}
$sClass = 'privUITransaction'.MetaModel::GetConfig()->Get('transaction_storage');
if (!class_exists($sClass, false))
{
IssueLog::Error("Incorrect value '".MetaModel::GetConfig()->Get('transaction_storage')."' for 'transaction_storage', the class '$sClass' does not exists. Using privUITransactionSession instead for storing sessions.");
$sClass = 'privUITransactionSession';
}
return (string)$sClass::GetNewTransactionId();
}
/**
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
* the session so that another call to IsTransactionValid for the same transaction id
* will return false
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
* @param bool $bRemoveTransaction True if the transaction must be removed
* @return bool True if the transaction is valid, false otherwise
*/
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
$bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled');
if (!$bTransactionsEnabled)
{
return true; // All values are valid
}
$sClass = 'privUITransaction'.MetaModel::GetConfig()->Get('transaction_storage');
if (!class_exists($sClass, false))
{
$sClass = 'privUITransactionSession';
}
return $sClass::IsTransactionValid($id, $bRemoveTransaction);
}
/**
* Removes the transaction specified by its id
* @param int $id The Identifier (as returned by GetNewTranscationId) of the transaction to be removed.
* @return void
*/
public static function RemoveTransaction($id)
{
$bTransactionsEnabled = MetaModel::GetConfig()->Get('transactions_enabled');
if (!$bTransactionsEnabled)
{
return; // Nothing to do
}
$sClass = 'privUITransaction'.MetaModel::GetConfig()->Get('transaction_storage');
if (!class_exists($sClass, false))
{
$sClass = 'privUITransactionSession';
}
$sClass::RemoveTransaction($id);
}
}
/**
* The original (and by default) mechanism for storing transaction information
* as an array in the $_SESSION variable
*
*/
class privUITransactionSession
{
/**
* Create a new transaction id, store it in the session and return its id
@@ -175,178 +99,4 @@ class privUITransactionSession
}
}
}
/**
* An alternate implementation for storing the transactions as temporary files
* Useful when using an in-memory storage for the session which do not
* guarantee mutual exclusion for writing
*/
class privUITransactionFile
{
/**
* Create a new transaction id, store it in the session and return its id
* @param void
* @return int The identifier of the new transaction
*/
public static function GetNewTransactionId()
{
if (!is_dir(APPROOT.'data/transactions'))
{
if (!is_writable(APPROOT.'data'))
{
throw new Exception('The directory "'.APPROOT.'data" must be writable to the application.');
}
if (!@mkdir(APPROOT.'data/transactions'))
{
throw new Exception('Failed to create the directory "'.APPROOT.'data/transactions". Ajust the rights on the parent directory or let an administrator create the transactions directory and give the web sever enough rights to write into it.');
}
}
if (!is_writable(APPROOT.'data/transactions'))
{
throw new Exception('The directory "'.APPROOT.'data/transactions" must be writable to the application.');
}
self::CleanupOldTransactions();
$id = basename(tempnam(APPROOT.'data/transactions', self::GetUserPrefix()));
self::Info('GetNewTransactionId: Created transaction: '.$id);
return (string)$id;
}
/**
* Check whether a transaction is valid or not and (optionally) remove the valid transaction from
* the session so that another call to IsTransactionValid for the same transaction id
* will return false
* @param int $id Identifier of the transaction, as returned by GetNewTransactionId
* @param bool $bRemoveTransaction True if the transaction must be removed
* @return bool True if the transaction is valid, false otherwise
*/
public static function IsTransactionValid($id, $bRemoveTransaction = true)
{
$sFilepath = APPROOT.'data/transactions/'.$id;
clearstatcache(true, $sFilepath);
$bResult = file_exists($sFilepath);
if ($bResult)
{
if ($bRemoveTransaction)
{
$bResult = @unlink($sFilepath);
if (!$bResult)
{
self::Error('IsTransactionValid: FAILED to remove transaction '.$id);
}
else
{
self::Info('IsTransactionValid: OK. Removed transaction: '.$id);
}
}
}
else
{
self::Info("IsTransactionValid: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
}
return $bResult;
}
/**
* Removes the transaction specified by its id
* @param int $id The Identifier (as returned by GetNewTransactionId) of the transaction to be removed.
* @return void
*/
public static function RemoveTransaction($id)
{
$bSuccess = true;
$sFilepath = APPROOT.'data/transactions/'.$id;
clearstatcache(true, $sFilepath);
if(!file_exists($sFilepath))
{
$bSuccess = false;
self::Error("RemoveTransaction: Transaction '$id' not found. Pending transactions for this user:\n".implode("\n", self::GetPendingTransactions()));
}
$bSuccess = @unlink($sFilepath);
if (!$bSuccess)
{
self::Error('RemoveTransaction: FAILED to remove transaction '.$id);
}
else
{
self::Info('RemoveTransaction: OK '.$id);
}
return $bSuccess;
}
/**
* Cleanup old transactions which have been pending since more than 24 hours
* Use filemtime instead of filectime since filectime may be affected by operations on the directory (like changing the access rights)
*/
protected static function CleanupOldTransactions()
{
$iLimit = time() - 24*3600;
clearstatcache();
$aTransactions = glob(APPROOT.'data/transactions/*-*');
foreach($aTransactions as $sFileName)
{
if (filemtime($sFileName) < $iLimit)
{
@unlink($sFileName);
self::Info('CleanupOldTransactions: Deleted transaction: '.$sFileName);
}
}
}
/**
* For debugging purposes: gets the pending transactions of the current user
* as an array, with the date of the creation of the transaction file
*/
protected static function GetPendingTransactions()
{
clearstatcache();
$aResult = array();
$aTransactions = glob(APPROOT.'data/transactions/'.self::GetUserPrefix().'*');
foreach($aTransactions as $sFileName)
{
$aResult[] = date('Y-m-d H:i:s', filemtime($sFileName)).' - '.basename($sFileName);
}
sort($aResult);
return $aResult;
}
protected static function GetUserPrefix()
{
$sPrefix = substr(UserRights::GetUser(), 0, 10);
$sPrefix = preg_replace('/[^a-zA-Z0-9-_]/', '_', $sPrefix);
return $sPrefix.'-';
}
protected static function Info($sText)
{
self::Write('Info | '.$sText);
}
protected static function Warning($sText)
{
self::Write('Warning | '.$sText);
}
protected static function Error($sText)
{
self::Write('Error | '.$sText);
}
protected static function Write($sText)
{
$bLogEnabled = MetaModel::GetConfig()->Get('log_transactions');
if ($bLogEnabled)
{
$hLogFile = @fopen(APPROOT.'log/transactions.log', 'a');
if ($hLogFile !== false)
{
flock($hLogFile, LOCK_EX);
$sDate = date('Y-m-d H:i:s');
fwrite($hLogFile, "$sDate | $sText\n");
fflush($hLogFile);
flock($hLogFile, LOCK_UN);
fclose($hLogFile);
}
}
}
}
?>

View File

@@ -259,7 +259,7 @@ EOF
$sHTMLValue .= "<img id=\"mini_search_{$this->iId}\" style=\"border:0;vertical-align:middle;cursor:pointer;\" src=\"../images/mini_search.gif\" onClick=\"oACWidget_{$this->iId}.Search();\"/>&nbsp;";
// another hidden input to store & pass the object's Id
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" />\n";
$sHTMLValue .= "<input type=\"hidden\" id=\"$this->iId\" name=\"{$sAttrFieldPrefix}{$sFieldName}\" value=\"$value\" />\n";
$JSSearchMode = $this->bSearchMode ? 'true' : 'false';
// Scripts to start the autocomplete and bind some events to it

View File

@@ -80,7 +80,7 @@ class UIHTMLEditorWidget
// Could also be bound to 'instanceReady.ckeditor'
$oPage->add_ready_script("$('#$iId').bind('validate', function(evt, sFormId) { return ValidateCKEditField('$iId', '', {$this->m_sMandatory}, sFormId, '') } );\n");
$oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); $(this).data('ckeditorInstance').setReadOnly($(this).prop('disabled')); } );\n");
$oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); } );\n");
return $sHtmlValue;
}

View File

@@ -294,7 +294,7 @@ class UILinksWidgetDirect
$valuesDef = $oLinksetDef->GetValuesDef();
if ($valuesDef === null)
{
$oFilter = new DBObjectSearch($sRemoteClass);
$oFilter = new DBObjectSearch($this->sLinkedClass);
}
else
{

View File

@@ -130,7 +130,7 @@ class appUserPreferences extends DBObject
/**
* Call this function if the user has changed (like when doing a logoff...)
*/
static public function ResetPreferences()
static public function Reset()
{
self::$oUserPrefs = null;
}

View File

@@ -783,16 +783,11 @@ class utils
$sOQL = addslashes($param->GetFilter()->ToOQL(true));
$sFilter = urlencode($param->GetFilter()->serialize());
$sUrl = utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".$sFilter."&{$sContext}";
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/xlsx-export.js');
$sXlsxFilter = $param->GetFilter()->serialize();
$sXlsxJSFilter = addslashes($sXlsxFilter);
$aResult = array(
new SeparatorPopupMenuItem(),
// Static menus: Email this page, CSV Export & Add to Dashboard
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?body=".urlencode($sUrl).' '), // Add an extra space to make it work in Outlook
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), $sUrl."&format=csv"),
new JSPopupMenuItem('xlsx-export', Dict::S('ExcelExporter:ExportMenu'), "XlsxExportDialog('$sXlsxJSFilter');", array()),
new JSPopupMenuItem('UI:Menu:AddToDashboard', Dict::S('UI:Menu:AddToDashboard'), "DashletCreationDlg('$sOQL')"),
new JSPopupMenuItem('UI:Menu:ShortcutList', Dict::S('UI:Menu:ShortcutList'), "ShortcutListDlg('$sOQL', '$sDataTableId', '$sContext')"),
);
@@ -807,14 +802,11 @@ class utils
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage(get_class($oObj));
$oAppContext = new ApplicationContext();
$sContext = $oAppContext->GetForLink();
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/xlsx-export.js');
$sXlsxJSFilter = addslashes($sFilter);
$aResult = array(
new SeparatorPopupMenuItem(),
// Static menus: Email this page & CSV Export
new URLPopupMenuItem('UI:Menu:EMail', Dict::S('UI:Menu:EMail'), "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl).' '), // Add an extra space to make it work in Outlook
new URLPopupMenuItem('UI:Menu:CSVExport', Dict::S('UI:Menu:CSVExport'), utils::GetAbsoluteUrlAppRoot()."pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv&{$sContext}"),
new JSPopupMenuItem('xlsx-export', Dict::S('ExcelExporter:ExportMenu'), "XlsxExportDialog('$sXlsxJSFilter');", array()),
);
break;

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
@@ -68,7 +68,6 @@ class WebPage implements Page
protected $sContentType;
protected $sContentDisposition;
protected $sContentFileName;
protected $bTrashUnexpectedOutput;
protected $s_sOutputFormat;
protected $a_OutputOptions;
@@ -89,7 +88,6 @@ class WebPage implements Page
$this->sContentType = '';
$this->sContentDisposition = '';
$this->sContentFileName = '';
$this->bTrashUnexpectedOutput = false;
$this->s_OutputFormat = utils::ReadParam('output_format', 'html');
$this->a_OutputOptions = array();
ob_start(); // Start capturing the output
@@ -394,55 +392,22 @@ class WebPage implements Page
}
/**
* Discard unexpected output data (such as PHP warnings)
* Discard unexpected output data
* This is a MUST when the Page output is DATA (download of a document, download CSV export, download ...)
*/
public function TrashUnexpectedOutput()
{
$this->bTrashUnexpectedOutput = true;
}
/**
* Read the output buffer and deal with its contents:
* - trash unexpected output if the flag has been set
* - report unexpected behaviors such as the output buffering being stopped
*
* Possible improvement: I've noticed that several output buffers are stacked,
* if they are not empty, the output will be corrupted. The solution would
* consist in unstacking all of them (and concatenate the contents).
*/
protected function ob_get_clean_safe()
{
$sOutput = ob_get_contents();
if ($sOutput === false)
// This protection is redundant with a protection implemented in MetaModel::IncludeModule
// which detects such issues while loading module files
// Here, the purpose is to detect and discard characters produced by the code execution (echo)
$sPreviousContent = ob_get_clean();
if (trim($sPreviousContent) != '')
{
$sMsg = "Design/integration issue: No output buffer. Some piece of code has called ob_get_clean() or ob_end_clean() without calling ob_start()";
if ($this->bTrashUnexpectedOutput)
if (Utils::GetConfig() && Utils::GetConfig()->Get('debug_report_spurious_chars'))
{
IssueLog::Error($sMsg);
$sOutput = '';
}
else
{
$sOutput = $sMsg;
IssueLog::Error("Output already started before downloading file:\nContent was:'$sPreviousContent'\n");
}
}
else
{
ob_end_clean(); // on some versions of PHP doing so when the output buffering is stopped can cause a notice
if ($this->bTrashUnexpectedOutput)
{
if (trim($sOutput) != '')
{
if (Utils::GetConfig() && Utils::GetConfig()->Get('debug_report_spurious_chars'))
{
IssueLog::Error("Trashing unexpected output:'$s_captured_output'\n");
}
}
$sOutput = '';
}
}
return $sOutput;
}
/**
@@ -454,8 +419,8 @@ class WebPage implements Page
{
header($s_header);
}
$s_captured_output = $this->ob_get_clean_safe();
$s_captured_output = ob_get_contents();
ob_end_clean();
echo "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n";
echo "<html>\n";
echo "<head>\n";

View File

@@ -1,456 +0,0 @@
<?php
/* @author Mark Jones
* @license MIT License
* */
if (!class_exists('ZipArchive')) { throw new Exception('ZipArchive not found'); }
Class XLSXWriter
{
//------------------------------------------------------------------
protected $author ='Doc Author';
protected $sheets_meta = array();
protected $shared_strings = array();//unique set
protected $shared_string_count = 0;//count of non-unique references to the unique set
protected $temp_files = array();
public function __construct(){}
public function setAuthor($author='') { $this->author=$author; }
public function __destruct()
{
if (!empty($this->temp_files)) {
foreach($this->temp_files as $temp_file) {
@unlink($temp_file);
}
}
}
protected function tempFilename()
{
$filename = tempnam("/tmp", "xlsx_writer_");
$this->temp_files[] = $filename;
return $filename;
}
public function writeToStdOut()
{
$temp_file = $this->tempFilename();
self::writeToFile($temp_file);
readfile($temp_file);
}
public function writeToString()
{
$temp_file = $this->tempFilename();
self::writeToFile($temp_file);
$string = file_get_contents($temp_file);
return $string;
}
public function writeToFile($filename)
{
@unlink($filename);//if the zip already exists, overwrite it
$zip = new ZipArchive();
if (empty($this->sheets_meta)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", no worksheets defined."); return; }
if (!$zip->open($filename, ZipArchive::CREATE)) { self::log("Error in ".__CLASS__."::".__FUNCTION__.", unable to create zip."); return; }
$zip->addEmptyDir("docProps/");
$zip->addFromString("docProps/app.xml" , self::buildAppXML() );
$zip->addFromString("docProps/core.xml", self::buildCoreXML());
$zip->addEmptyDir("_rels/");
$zip->addFromString("_rels/.rels", self::buildRelationshipsXML());
$zip->addEmptyDir("xl/worksheets/");
foreach($this->sheets_meta as $sheet_meta) {
$zip->addFile($sheet_meta['filename'], "xl/worksheets/".$sheet_meta['xmlname'] );
}
if (!empty($this->shared_strings)) {
$zip->addFile($this->writeSharedStringsXML(), "xl/sharedStrings.xml" ); //$zip->addFromString("xl/sharedStrings.xml", self::buildSharedStringsXML() );
}
$zip->addFromString("xl/workbook.xml" , self::buildWorkbookXML() );
$zip->addFile($this->writeStylesXML(), "xl/styles.xml" ); //$zip->addFromString("xl/styles.xml" , self::buildStylesXML() );
$zip->addFromString("[Content_Types].xml" , self::buildContentTypesXML() );
$zip->addEmptyDir("xl/_rels/");
$zip->addFromString("xl/_rels/workbook.xml.rels", self::buildWorkbookRelsXML() );
$zip->close();
}
public function writeSheet(array $data, $sheet_name='', array $header_types=array() )
{
$data = empty($data) ? array( array('') ) : $data;
$sheet_filename = $this->tempFilename();
$sheet_default = 'Sheet'.(count($this->sheets_meta)+1);
$sheet_name = !empty($sheet_name) ? $sheet_name : $sheet_default;
$this->sheets_meta[] = array('filename'=>$sheet_filename, 'sheetname'=>$sheet_name ,'xmlname'=>strtolower($sheet_default).".xml" );
$header_offset = empty($header_types) ? 0 : 1;
$row_count = count($data) + $header_offset;
$column_count = count($data[self::array_first_key($data)]);
$max_cell = self::xlsCell( $row_count-1, $column_count-1 );
$tabselected = count($this->sheets_meta)==1 ? 'true' : 'false';//only first sheet is selected
$cell_formats_arr = empty($header_types) ? array_fill(0, $column_count, 'string') : array_values($header_types);
$header_row = empty($header_types) ? array() : array_keys($header_types);
$fd = fopen($sheet_filename, "w+");
if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; }
fwrite($fd,'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
fwrite($fd,'<worksheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">');
fwrite($fd, '<sheetPr filterMode="false">');
fwrite($fd, '<pageSetUpPr fitToPage="false"/>');
fwrite($fd, '</sheetPr>');
fwrite($fd, '<dimension ref="A1:'.$max_cell.'"/>');
fwrite($fd, '<sheetViews>');
fwrite($fd, '<sheetView colorId="64" defaultGridColor="true" rightToLeft="false" showFormulas="false" showGridLines="true" showOutlineSymbols="true" showRowColHeaders="true" showZeros="true" tabSelected="'.$tabselected.'" topLeftCell="A1" view="normal" windowProtection="false" workbookViewId="0" zoomScale="100" zoomScaleNormal="100" zoomScalePageLayoutView="100">');
fwrite($fd, '<selection activeCell="A1" activeCellId="0" pane="topLeft" sqref="A1"/>');
fwrite($fd, '</sheetView>');
fwrite($fd, '</sheetViews>');
fwrite($fd, '<cols>');
fwrite($fd, '<col collapsed="false" hidden="false" max="1025" min="1" style="0" width="19"/>');
fwrite($fd, '</cols>');
fwrite($fd, '<sheetData>');
if (!empty($header_row))
{
fwrite($fd, '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="'.(1).'">');
foreach($header_row as $k=>$v)
{
$this->writeCell($fd, 0, $k, $v, $cell_format='string');
}
fwrite($fd, '</row>');
}
foreach($data as $i=>$row)
{
fwrite($fd, '<row collapsed="false" customFormat="false" customHeight="false" hidden="false" ht="12.1" outlineLevel="0" r="'.($i+$header_offset+1).'">');
foreach($row as $k=>$v)
{
$this->writeCell($fd, $i+$header_offset, $k, $v, $cell_formats_arr[$k]);
}
fwrite($fd, '</row>');
}
fwrite($fd, '</sheetData>');
fwrite($fd, '<printOptions headings="false" gridLines="false" gridLinesSet="true" horizontalCentered="false" verticalCentered="false"/>');
fwrite($fd, '<pageMargins left="0.5" right="0.5" top="1.0" bottom="1.0" header="0.5" footer="0.5"/>');
fwrite($fd, '<pageSetup blackAndWhite="false" cellComments="none" copies="1" draft="false" firstPageNumber="1" fitToHeight="1" fitToWidth="1" horizontalDpi="300" orientation="portrait" pageOrder="downThenOver" paperSize="1" scale="100" useFirstPageNumber="true" usePrinterDefaults="false" verticalDpi="300"/>');
fwrite($fd, '<headerFooter differentFirst="false" differentOddEven="false">');
fwrite($fd, '<oddHeader>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12&amp;A</oddHeader>');
fwrite($fd, '<oddFooter>&amp;C&amp;&quot;Times New Roman,Regular&quot;&amp;12Page &amp;P</oddFooter>');
fwrite($fd, '</headerFooter>');
fwrite($fd,'</worksheet>');
fclose($fd);
}
protected function writeCell($fd, $row_number, $column_number, $value, $cell_format)
{
static $styles = array('money'=>1,'dollar'=>1,'datetime'=>2,'date'=>3,'string'=>0);
$cell = self::xlsCell($row_number, $column_number);
$s = isset($styles[$cell_format]) ? $styles[$cell_format] : '0';
if (is_numeric($value)) {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.($value*1).'</v></c>');//int,float, etc
} else if ($cell_format=='date') {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.intval(self::convert_date_time($value)).'</v></c>');
} else if ($cell_format=='datetime') {
if ($value === '') {
fwrite($fd,'<c r="'.$cell.'" s="0"/>');
} else {
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="n"><v>'.self::convert_date_time($value).'</v></c>');
}
} else if ($value==''){
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'"/>');
} else if ($value{0}=='='){
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><f>'.self::xmlspecialchars($value).'</f></c>');
} else if ($value!==''){
fwrite($fd,'<c r="'.$cell.'" s="'.$s.'" t="s"><v>'.self::xmlspecialchars($this->setSharedString($value)).'</v></c>');
}
}
protected function writeStylesXML()
{
$tempfile = $this->tempFilename();
$fd = fopen($tempfile, "w+");
if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; }
fwrite($fd, '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
fwrite($fd, '<styleSheet xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">');
fwrite($fd, '<numFmts count="4">');
fwrite($fd, '<numFmt formatCode="GENERAL" numFmtId="164"/>');
fwrite($fd, '<numFmt formatCode="[$$-1009]#,##0.00;[RED]\-[$$-1009]#,##0.00" numFmtId="165"/>');
fwrite($fd, '<numFmt formatCode="YYYY-MM-DD\ HH:MM:SS" numFmtId="166"/>');
fwrite($fd, '<numFmt formatCode="YYYY-MM-DD" numFmtId="167"/>');
fwrite($fd, '</numFmts>');
fwrite($fd, '<fonts count="4">');
fwrite($fd, '<font><name val="Arial"/><charset val="1"/><family val="2"/><sz val="10"/></font>');
fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
fwrite($fd, '<font><name val="Arial"/><family val="0"/><sz val="10"/></font>');
fwrite($fd, '</fonts>');
fwrite($fd, '<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
fwrite($fd, '<borders count="1"><border diagonalDown="false" diagonalUp="false"><left/><right/><top/><bottom/><diagonal/></border></borders>');
fwrite($fd, '<cellStyleXfs count="15">');
fwrite($fd, '<xf applyAlignment="true" applyBorder="true" applyFont="true" applyProtection="true" borderId="0" fillId="0" fontId="0" numFmtId="164">');
fwrite($fd, '<alignment horizontal="general" indent="0" shrinkToFit="false" textRotation="0" vertical="bottom" wrapText="false"/>');
fwrite($fd, '<protection hidden="false" locked="true"/>');
fwrite($fd, '</xf>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="2" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="0"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="43"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="41"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="44"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="42"/>');
//fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="true" applyProtection="false" borderId="0" fillId="0" fontId="1" numFmtId="9"/>');
fwrite($fd, '</cellStyleXfs>');
fwrite($fd, '<cellXfs count="4">');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="164" xfId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="165" xfId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="166" xfId="0"/>');
fwrite($fd, '<xf applyAlignment="false" applyBorder="false" applyFont="false" applyProtection="false" borderId="0" fillId="0" fontId="0" numFmtId="167" xfId="0"/>');
fwrite($fd, '</cellXfs>');
fwrite($fd, '<cellStyles count="1">');
fwrite($fd, '<cellStyle builtinId="0" customBuiltin="false" name="Normal" xfId="0"/>');
//fwrite($fd, '<cellStyle builtinId="3" customBuiltin="false" name="Comma" xfId="15"/>');
//fwrite($fd, '<cellStyle builtinId="6" customBuiltin="false" name="Comma [0]" xfId="16"/>');
//fwrite($fd, '<cellStyle builtinId="4" customBuiltin="false" name="Currency" xfId="17"/>');
//fwrite($fd, '<cellStyle builtinId="7" customBuiltin="false" name="Currency [0]" xfId="18"/>');
//fwrite($fd, '<cellStyle builtinId="5" customBuiltin="false" name="Percent" xfId="19"/>');
fwrite($fd, '</cellStyles>');
fwrite($fd, '</styleSheet>');
fclose($fd);
return $tempfile;
}
protected function setSharedString($v)
{
// Strip control characters which Excel does not seem to like...
$v = preg_replace('/[\x00-\x09\x0B\x0C\x0E-\x1F]/u', '', $v);
if (isset($this->shared_strings[$v]))
{
$string_value = $this->shared_strings[$v];
}
else
{
$string_value = count($this->shared_strings);
$this->shared_strings[$v] = $string_value;
}
$this->shared_string_count++;//non-unique count
return $string_value;
}
protected function writeSharedStringsXML()
{
$tempfile = $this->tempFilename();
$fd = fopen($tempfile, "w+");
if ($fd===false) { self::log("write failed in ".__CLASS__."::".__FUNCTION__."."); return; }
fwrite($fd,'<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n");
fwrite($fd,'<sst count="'.($this->shared_string_count).'" uniqueCount="'.count($this->shared_strings).'" xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main">');
foreach($this->shared_strings as $s=>$c)
{
fwrite($fd,'<si><t>'.self::xmlspecialchars($s).'</t></si>');
}
fwrite($fd, '</sst>');
fclose($fd);
return $tempfile;
}
protected function buildAppXML()
{
$app_xml="";
$app_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
$app_xml.='<Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/extended-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"><TotalTime>0</TotalTime></Properties>';
return $app_xml;
}
protected function buildCoreXML()
{
$core_xml="";
$core_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
$core_xml.='<cp:coreProperties xmlns:cp="http://schemas.openxmlformats.org/package/2006/metadata/core-properties" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dcmitype="http://purl.org/dc/dcmitype/" xmlns:dcterms="http://purl.org/dc/terms/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">';
$core_xml.='<dcterms:created xsi:type="dcterms:W3CDTF">'.date("Y-m-d\TH:i:s.00\Z").'</dcterms:created>';//$date_time = '2013-07-25T15:54:37.00Z';
$core_xml.='<dc:creator>'.self::xmlspecialchars($this->author).'</dc:creator>';
$core_xml.='<cp:revision>0</cp:revision>';
$core_xml.='</cp:coreProperties>';
return $core_xml;
}
protected function buildRelationshipsXML()
{
$rels_xml="";
$rels_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n";
$rels_xml.='<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
$rels_xml.='<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument" Target="xl/workbook.xml"/>';
$rels_xml.='<Relationship Id="rId2" Type="http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties" Target="docProps/core.xml"/>';
$rels_xml.='<Relationship Id="rId3" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties" Target="docProps/app.xml"/>';
$rels_xml.="\n";
$rels_xml.='</Relationships>';
return $rels_xml;
}
protected function buildWorkbookXML()
{
$workbook_xml="";
$workbook_xml.='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\n";
$workbook_xml.='<workbook xmlns="http://schemas.openxmlformats.org/spreadsheetml/2006/main" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">';
$workbook_xml.='<fileVersion appName="Calc"/><workbookPr backupFile="false" showObjects="all" date1904="false"/><workbookProtection/>';
$workbook_xml.='<bookViews><workbookView activeTab="0" firstSheet="0" showHorizontalScroll="true" showSheetTabs="true" showVerticalScroll="true" tabRatio="212" windowHeight="8192" windowWidth="16384" xWindow="0" yWindow="0"/></bookViews>';
$workbook_xml.='<sheets>';
foreach($this->sheets_meta as $i=>$sheet_meta) {
$workbook_xml.='<sheet name="'.self::xmlspecialchars($sheet_meta['sheetname']).'" sheetId="'.($i+1).'" state="visible" r:id="rId'.($i+2).'"/>';
}
$workbook_xml.='</sheets>';
$workbook_xml.='<calcPr iterateCount="100" refMode="A1" iterate="false" iterateDelta="0.001"/></workbook>';
return $workbook_xml;
}
protected function buildWorkbookRelsXML()
{
$wkbkrels_xml="";
$wkbkrels_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n";
$wkbkrels_xml.='<Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">';
$wkbkrels_xml.='<Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles" Target="styles.xml"/>';
foreach($this->sheets_meta as $i=>$sheet_meta) {
$wkbkrels_xml.='<Relationship Id="rId'.($i+2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet" Target="worksheets/'.($sheet_meta['xmlname']).'"/>';
}
if (!empty($this->shared_strings)) {
$wkbkrels_xml.='<Relationship Id="rId'.(count($this->sheets_meta)+2).'" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings" Target="sharedStrings.xml"/>';
}
$wkbkrels_xml.="\n";
$wkbkrels_xml.='</Relationships>';
return $wkbkrels_xml;
}
protected function buildContentTypesXML()
{
$content_types_xml="";
$content_types_xml.='<?xml version="1.0" encoding="UTF-8"?>'."\n";
$content_types_xml.='<Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">';
$content_types_xml.='<Override PartName="/_rels/.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>';
$content_types_xml.='<Override PartName="/xl/_rels/workbook.xml.rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>';
foreach($this->sheets_meta as $i=>$sheet_meta) {
$content_types_xml.='<Override PartName="/xl/worksheets/'.($sheet_meta['xmlname']).'" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml"/>';
}
if (!empty($this->shared_strings)) {
$content_types_xml.='<Override PartName="/xl/sharedStrings.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml"/>';
}
$content_types_xml.='<Override PartName="/xl/workbook.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml"/>';
$content_types_xml.='<Override PartName="/xl/styles.xml" ContentType="application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml"/>';
$content_types_xml.='<Override PartName="/docProps/app.xml" ContentType="application/vnd.openxmlformats-officedocument.extended-properties+xml"/>';
$content_types_xml.='<Override PartName="/docProps/core.xml" ContentType="application/vnd.openxmlformats-package.core-properties+xml"/>';
$content_types_xml.="\n";
$content_types_xml.='</Types>';
return $content_types_xml;
}
//------------------------------------------------------------------
/*
* @param $row_number int, zero based
* @param $column_number int, zero based
* @return Cell label/coordinates, ex: A1, C3, AA42
* */
public static function xlsCell($row_number, $column_number)
{
$n = $column_number;
for($r = ""; $n >= 0; $n = intval($n / 26) - 1) {
$r = chr($n%26 + 0x41) . $r;
}
return $r . ($row_number+1);
}
//------------------------------------------------------------------
public static function log($string)
{
file_put_contents("php://stderr", date("Y-m-d H:i:s:").rtrim(is_array($string) ? json_encode($string) : $string)."\n");
}
//------------------------------------------------------------------
public static function xmlspecialchars($val)
{
return str_replace("'", "&#39;", htmlspecialchars($val));
}
//------------------------------------------------------------------
public static function array_first_key(array $arr)
{
reset($arr);
$first_key = key($arr);
return $first_key;
}
//------------------------------------------------------------------
public static function convert_date_time($date_input) //thanks to Excel::Writer::XLSX::Worksheet.pm (perl)
{
$days = 0; # Number of days since epoch
$seconds = 0; # Time expressed as fraction of 24h hours in seconds
$year=$month=$day=0;
$hour=$min =$sec=0;
$date_time = $date_input;
if (preg_match("/(\d{4})\-(\d{2})\-(\d{2})/", $date_time, $matches))
{
list($junk,$year,$month,$day) = $matches;
}
if (preg_match("/(\d{2}):(\d{2}):(\d{2})/", $date_time, $matches))
{
list($junk,$hour,$min,$sec) = $matches;
$seconds = ( $hour * 60 * 60 + $min * 60 + $sec ) / ( 24 * 60 * 60 );
}
//using 1900 as epoch, not 1904, ignoring 1904 special case
# Special cases for Excel.
if ("$year-$month-$day"=='1899-12-31') return $seconds ; # Excel 1900 epoch
if ("$year-$month-$day"=='1900-01-00') return $seconds ; # Excel 1900 epoch
if ("$year-$month-$day"=='1900-02-29') return 60 + $seconds ; # Excel false leapday
# We calculate the date by calculating the number of days since the epoch
# and adjust for the number of leap days. We calculate the number of leap
# days by normalising the year in relation to the epoch. Thus the year 2000
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
$epoch = 1900;
$offset = 0;
$norm = 300;
$range = $year - $epoch;
# Set month days and check for leap year.
$leap = (($year % 400 == 0) || (($year % 4 == 0) && ($year % 100)) ) ? 1 : 0;
$mdays = array( 31, ($leap ? 29 : 28), 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 );
# Some boundary checks
if($year < $epoch || $year > 9999) return 0;
if($month < 1 || $month > 12) return 0;
if($day < 1 || $day > $mdays[ $month - 1 ]) return 0;
# Accumulate the number of days since the epoch.
$days = $day; # Add days for current month
$days += array_sum( array_slice($mdays, 0, $month-1 ) ); # Add days for past months
$days += $range * 365; # Add days for past years
$days += intval( ( $range ) / 4 ); # Add leapdays
$days -= intval( ( $range + $offset ) / 100 ); # Subtract 100 year leapdays
$days += intval( ( $range + $offset + $norm ) / 400 ); # Add 400 year leapdays
$days -= $leap; # Already counted above
# Adjust for Excel erroneously treating 1900 as a leap year.
if ($days > 59) { $days++;}
return $days + $seconds;
}
//------------------------------------------------------------------
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
@@ -51,9 +51,6 @@ class XMLPage extends WebPage
{
if (!$this->m_bPassThrough)
{
// Get the unexpected output but do nothing with it
$sTrash = $this->ob_get_clean_safe();
$this->s_content = "<?xml version=\"1.0\" encoding=\"UTF-8\"?".">\n".trim($this->s_content);
$this->add_header("Content-Length: ".strlen($this->s_content));
foreach($this->a_headers as $s_header)
@@ -82,7 +79,8 @@ class XMLPage extends WebPage
}
else
{
$s_captured_output = $this->ob_get_clean_safe();
$s_captured_output = ob_get_contents();
ob_end_clean();
foreach($this->a_headers as $s_header)
{
header($s_header);
@@ -103,4 +101,13 @@ class XMLPage extends WebPage
public function table($aConfig, $aData, $aParams = array())
{
}
public function TrashUnexpectedOutput()
{
if (!$this->m_bPassThrough)
{
parent::TrashUnexpectedOutput();
}
}
}
?>

View File

@@ -480,14 +480,6 @@ abstract class AttributeDefinition
return (string)$sValue;
}
/**
* Override to differentiate a value displayed in the UI or in the history
*/
public function GetAsHTMLForHistory($sValue, $oHostObject = null, $bLocalize = true)
{
return $this->GetAsHTML($sValue, $oHostObject, $bLocalize);
}
public function GetAllowedValues($aArgs = array(), $sContains = '')
{
$oValSetDef = $this->GetValuesDef();
@@ -495,18 +487,15 @@ abstract class AttributeDefinition
return $oValSetDef->GetValues($aArgs, $sContains);
}
/**
* Explain the change of the attribute (history)
*/
public function DescribeChangeAsHTML($sOldValue, $sNewValue, $sLabel = null)
public function GetAsHTMLForHistory($sOldValue, $sNewValue, $sLabel = null)
{
if (is_null($sLabel))
{
$sLabel = $this->GetLabel();
}
$sNewValueHtml = $this->GetAsHTMLForHistory($sNewValue);
$sOldValueHtml = $this->GetAsHTMLForHistory($sOldValue);
$sNewValueHtml = $this->GetAsHTML($sNewValue);
$sOldValueHtml = $this->GetAsHTML($sOldValue);
if($this->IsExternalKey())
{
@@ -892,106 +881,6 @@ class AttributeLinkedSet extends AttributeDefinition
return $oSet;
}
/**
* Helper to get a value that will be JSON encoded
* The operation is the opposite to FromJSONToValue
*/
public function GetForJSON($value)
{
$aRet = array();
if (is_object($value) && ($value instanceof DBObjectSet))
{
$value->Rewind();
while ($oObj = $value->Fetch())
{
$sObjClass = get_class($oObj);
// Show only relevant information (hide the external key to the current object)
$aAttributes = array();
foreach(MetaModel::ListAttributeDefs($sObjClass) as $sAttCode => $oAttDef)
{
if ($sAttCode == 'finalclass')
{
if ($sObjClass == $this->GetLinkedClass())
{
// Simplify the output if the exact class could be determined implicitely
continue;
}
}
if ($sAttCode == $this->GetExtKeyToMe()) continue;
if ($oAttDef->IsExternalField()) continue;
if (!$oAttDef->IsDirectField()) continue;
if (!$oAttDef->IsScalar()) continue;
$attValue = $oObj->Get($sAttCode);
$aAttributes[$sAttCode] = $oAttDef->GetForJSON($attValue);
}
$aRet[] = $aAttributes;
}
}
return $aRet;
}
/**
* Helper to form a value, given JSON decoded data
* The operation is the opposite to GetForJSON
*/
public function FromJSONToValue($json)
{
$sTargetClass = $this->Get('linked_class');
$aLinks = array();
foreach($json as $aValues)
{
if (isset($aValues['finalclass']))
{
$sLinkClass = $aValues['finalclass'];
if (!is_subclass_of($sLinkClass, $sTargetClass))
{
throw new CoreException('Wrong class for link attribute specification', array('requested_class' => $sLinkClass, 'expected_class' => $sTargetClass));
}
}
elseif (MetaModel::IsAbstract($sTargetClass))
{
throw new CoreException('Missing finalclass for link attribute specification');
}
else
{
$sLinkClass = $sTargetClass;
}
$oLink = MetaModel::NewObject($sLinkClass);
foreach ($aValues as $sAttCode => $sValue)
{
$oLink->Set($sAttCode, $sValue);
}
// Check (roughly) if such a link is valid
$aErrors = array();
foreach(MetaModel::ListAttributeDefs($sTargetClass) as $sAttCode => $oAttDef)
{
if ($oAttDef->IsExternalKey())
{
if (($oAttDef->GetTargetClass() == $this->GetHostClass()) || (is_subclass_of($this->GetHostClass(), $oAttDef->GetTargetClass())))
{
continue; // Don't check the key to self
}
}
if ($oAttDef->IsWritable() && $oAttDef->IsNull($oLink->Get($sAttCode)) && !$oAttDef->IsNullAllowed())
{
$aErrors[] = $sAttCode;
}
}
if (count($aErrors) > 0)
{
throw new CoreException("Missing value for mandatory attribute(s): ".implode(', ', $aErrors));
}
$aLinks[] = $oLink;
}
$oSet = DBObjectSet::FromArray($sTargetClass, $aLinks);
return $oSet;
}
public function Equals($val1, $val2)
{
if ($val1 === $val2) return true;
@@ -2093,7 +1982,7 @@ class AttributeCaseLog extends AttributeLongText
public function FromSQLToValue($aCols, $sPrefix = '')
{
if (!array_key_exists($sPrefix, $aCols))
if (!isset($aCols[$sPrefix]))
{
$sAvailable = implode(', ', array_keys($aCols));
throw new MissingColumnException("Missing column '$sPrefix' from {$sAvailable}");
@@ -3537,69 +3426,12 @@ class AttributeBlob extends AttributeDefinition
}
// Facilitate things: allow administrators to upload a document
// from a CSV by specifying its path/URL
// Facilitate things: allow the user to Set the value from a string
public function MakeRealValue($proposedValue, $oHostObj)
{
if (!is_object($proposedValue))
{
if (file_exists($proposedValue) && UserRights::IsAdministrator())
{
$sContent = file_get_contents($proposedValue);
$sExtension = strtolower(pathinfo($proposedValue, PATHINFO_EXTENSION));
$sMimeType = "application/x-octoet-stream";
$aKnownExtensions = array(
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12.xlsx',
'xltx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
'potx' => 'application/vnd.openxmlformats-officedocument.presentationml.template',
'ppsx' => 'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
'sldx' => 'application/vnd.openxmlformats-officedocument.presentationml.slide',
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
'dotx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
'xlam' => 'application/vnd.ms-excel.addin.macroEnabled.12',
'xlsb' => 'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
'jpg' => 'image/jpeg',
'jpeg' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'pdf' => 'application/pdf',
'doc' => 'application/msword',
'dot' => 'application/msword',
'xls' => 'application/vnd.ms-excel',
'ppt' => 'application/vnd.ms-powerpoint',
'vsd' => 'application/x-visio',
'vdx' => 'application/visio.drawing',
'odt' => 'application/vnd.oasis.opendocument.text',
'ods' => 'application/vnd.oasis.opendocument.spreadsheet',
'odp' => 'application/vnd.oasis.opendocument.presentation',
'zip' => 'application/zip',
'txt' => 'text/plain',
'htm' => 'text/html',
'html' => 'text/html',
'exe' => 'application/octet-stream'
);
if (!array_key_exists($sExtension, $aKnownExtensions) && extension_loaded('fileinfo'))
{
$finfo = new finfo(FILEINFO_MIME);
$sMimeType = $finfo->file($proposedValue);
}
return new ormDocument($sContent, $sMimeType);
}
else
{
return new ormDocument($proposedValue, 'text/plain');
}
return new ormDocument($proposedValue, 'text/plain');
}
return $proposedValue;
}
@@ -3885,7 +3717,7 @@ class AttributeStopWatch extends AttributeDefinition
);
$aThresholds = array();
foreach ($this->ListThresholds() as $iThreshold => $aDefinition)
foreach ($this->ListThresholds() as $iThreshold => $aFoo)
{
$sThPrefix = '_'.$iThreshold;
$value->DefineThreshold(
@@ -3893,8 +3725,7 @@ class AttributeStopWatch extends AttributeDefinition
self::DateToSeconds($aCols[$sPrefix.$sThPrefix.'_deadline']),
(bool)($aCols[$sPrefix.$sThPrefix.'_passed'] == 1),
(bool)($aCols[$sPrefix.$sThPrefix.'_triggered'] == 1),
$aCols[$sPrefix.$sThPrefix.'_overrun'],
array_key_exists('highlight', $aDefinition) ? $aDefinition['highlight'] : null
$aCols[$sPrefix.$sThPrefix.'_overrun']
);
}
@@ -4092,17 +3923,19 @@ class AttributeStopWatch extends AttributeDefinition
return Dict::S('BooleanLabel:'.$sDictKey, 'def:'.$sDictKey);
}
public function GetSubItemAsHTMLForHistory($sItemCode, $sValue)
public function GetSubItemAsHTMLForHistory($sItemCode, $sOldValue, $sNewValue, $sLabel)
{
switch($sItemCode)
{
case 'timespent':
$sHtml = (int)$sValue ? Str::pure2html(AttributeDuration::FormatDuration($sValue)) : null;
$sHtmlOld = (int)$sOldValue ? AttributeDuration::FormatDuration($sOldValue) : null;
$sHtmlNew = (int)$sNewValue ? AttributeDuration::FormatDuration($sNewValue) : null;
break;
case 'started':
case 'laststart':
case 'stopped':
$sHtml = (int)$sValue ? date(self::GetDateFormat(), (int)$sValue) : null;
$sHtmlOld = (int)$sOldValue ? date(self::GetDateFormat(), (int)$sOldValue) : null;
$sHtmlNew = (int)$sNewValue ? date(self::GetDateFormat(), (int)$sNewValue) : null;
break;
default:
@@ -4116,21 +3949,26 @@ class AttributeStopWatch extends AttributeDefinition
switch($sThresholdCode)
{
case 'deadline':
$sHtml = (int)$sValue ? date(self::GetDateFormat(true /*full*/), (int)$sValue) : null;
$sHtmlOld = (int)$sOldValue ? date(self::GetDateFormat(true /*full*/), (int)$sOldValue) : null;
$sHtmlNew = (int)$sNewValue ? date(self::GetDateFormat(true /*full*/), (int)$sNewValue) : null;
break;
case 'passed':
$sHtml = $this->GetBooleanLabel((int)$sValue);
$sHtmlOld = $this->GetBooleanLabel((int)$sOldValue);
$sHtmlNew = $this->GetBooleanLabel((int)$sNewValue);
break;
case 'triggered':
$sHtml = $this->GetBooleanLabel((int)$sValue);
$sHtmlOld = $this->GetBooleanLabel((int)$sOldValue);
$sHtmlNew = $this->GetBooleanLabel((int)$sNewValue);
break;
case 'overrun':
$sHtml = (int)$sValue > 0 ? Str::pure2html(AttributeDuration::FormatDuration((int)$sValue)) : '';
$sHtmlOld = (int)$sOldValue > 0 ? AttributeDuration::FormatDuration((int)$sOldValue) : '';
$sHtmlNew = (int)$sNewValue > 0 ? AttributeDuration::FormatDuration((int)$sNewValue) : '';
}
}
}
}
return $sHtml;
$sRes = parent::GetAsHTMLForHistory($sHtmlOld, $sHtmlNew, $sLabel);
return $sRes;
}
static protected function GetDateFormat($bFull = false)
@@ -4445,13 +4283,6 @@ class AttributeSubItem extends AttributeDefinition
return $res;
}
public function GetAsHTMLForHistory($value, $oHostObject = null, $bLocalize = true)
{
$oParent = $this->GetTargetAttDef();
$res = $oParent->GetSubItemAsHTMLForHistory($this->Get('item_code'), $value);
return $res;
}
public function GetAsCSV($value, $sSeparator = ',', $sTextQualifier = '"', $oHostObject = null, $bLocalize = true)
{
$oParent = $this->GetTargetAttDef();
@@ -4466,6 +4297,15 @@ class AttributeSubItem extends AttributeDefinition
return $res;
}
public function GetAsHTMLForHistory($sOldValue, $sNewValue, $sLabel = null)
{
$sLabel = $this->GetLabel();
$oParent = $this->GetTargetAttDef();
$sValue = $oParent->GetSubItemAsHTMLForHistory($this->Get('item_code'), $sOldValue, $sNewValue, $sLabel);
return $sValue;
}
/**
* As of now, this function must be implemented to have the value in spreadsheet format
*/
@@ -5025,7 +4865,7 @@ class AttributeFriendlyName extends AttributeComputedFieldVoid
}
// Do not display friendly names in the history of change
public function DescribeChangeAsHTML($sOldValue, $sNewValue, $sLabel = null)
public function GetAsHTMLForHistory($sOldValue, $sNewValue, $sLabel = null)
{
return '';
}

View File

@@ -55,7 +55,7 @@ class CMDBChangeOp extends DBObject
MetaModel::Init_AddAttribute(new AttributeExternalField("date", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"date")));
MetaModel::Init_AddAttribute(new AttributeExternalField("userinfo", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"userinfo")));
MetaModel::Init_AddAttribute(new AttributeString("objclass", array("allowed_values"=>null, "sql"=>"objclass", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeInteger("objkey", array("allowed_values"=>null, "sql"=>"objkey", "default_value"=>0, "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_AddAttribute(new AttributeString("objkey", array("allowed_values"=>null, "sql"=>"objkey", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
MetaModel::Init_SetZListItems('details', array('change', 'date', 'userinfo')); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', array('change', 'date', 'userinfo')); // Attributes to be displayed for the complete details
@@ -237,7 +237,7 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
$sAttName = $oAttDef->GetLabel();
$sNewValue = $this->Get('newvalue');
$sOldValue = $this->Get('oldvalue');
$sResult = $oAttDef->DescribeChangeAsHTML($sOldValue, $sNewValue);
$sResult = $oAttDef->GetAsHTMLForHistory($sOldValue, $sNewValue);
}
return $sResult;
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -96,19 +96,11 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
*/
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
// Default implementation: 24x7, no holidays: to compute the deadline, just add
// the specified duration to the given date/time
$oResult = clone $oStartDate;
$oResult->modify('+'.$iDuration.' seconds');
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oResult->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_END);
}
return $oResult;
}
@@ -121,17 +113,8 @@ class DefaultWorkingTimeComputer implements iWorkingTimeComputer
*/
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
{
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::Trace(WorkingTimeRecorder::TRACE_DEBUG, __class__.'::'.__function__);
}
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
$iDuration = abs($oEndDate->format('U') - $oStartDate->format('U'));
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::SetValues($oStartDate->format('U'), $oEndDate->format('U'), $iDuration, WorkingTimeRecorder::COMPUTED_DURATION);
}
return $iDuration;
return abs($oEndDate->format('U') - $oStartDate->format('U'));
}
}

View File

@@ -769,30 +769,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'user_rights_legacy' => array(
'type' => 'bool',
'description' => 'Set to true to restore the buggy algorithm for the computation of user rights (within the same profile, ALLOW on the class itself has precedence on DENY of a parent class)',
'default' => false,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'xlsx_exporter_cleanup_old_files_delay' => array(
'type' => 'int',
'description' => 'Delay (in seconds) for which to let the exported XLSX files on the server so that the user who initiated the export can download the result',
'default' => 86400,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'xlsx_exporter_memory_limit' => array(
'type' => 'string',
'description' => 'Memory limit to use when (interactively) exporting data to Excel',
'default' => '2048M', // Huuuuuuge 2GB!
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'min_reload_interval' => array(
'type' => 'integer',
'description' => 'Minimum refresh interval (seconds) for dashboards, shortcuts, etc. Even if the interval is set programmatically, it is forced to that minimum',
@@ -801,38 +777,6 @@ class Config
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'relations_max_depth' => array(
'type' => 'integer',
'description' => 'Maximum number of successive levels (depth) to explore when displaying the impact/depends on relations.',
'default' => 20, // In iTop 2.0.3, this was the hardcoded value
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'transaction_storage' => array(
'type' => 'string',
'description' => 'The type of mechanism to use for storing the unique identifiers for transactions (Session|File).',
'default' => 'Session',
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'transactions_enabled' => array(
'type' => 'bool',
'description' => 'Whether or not the whole mechanism to prevent multiple submissions of a page is enabled.',
'default' => true,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
'log_transactions' => array(
'type' => 'bool',
'description' => 'Whether or not to enable the debug log for the transactions.',
'default' => false,
'value' => '',
'source_of_value' => '',
'show_in_conf_sample' => false,
),
);
public function IsProperty($sPropCode)
@@ -1486,8 +1430,6 @@ class Config
$aSettings['log_notification'] = $this->m_bLogNotification;
$aSettings['log_issue'] = $this->m_bLogIssue;
$aSettings['log_web_service'] = $this->m_bLogWebService;
$aSettings['log_queries'] = $this->m_bLogQueries;
$aSettings['query_cache_enabled'] = $this->m_bQueryCacheEnabled;
$aSettings['min_display_limit'] = $this->m_iMinDisplayLimit;
$aSettings['max_display_limit'] = $this->m_iMaxDisplayLimit;
$aSettings['standard_reload_interval'] = $this->m_iStandardReloadInterval;
@@ -1495,7 +1437,6 @@ class Config
$aSettings['secure_connection_required'] = $this->m_bSecureConnectionRequired;
$aSettings['default_language'] = $this->m_sDefaultLanguage;
$aSettings['allowed_login_types'] = $this->m_sAllowedLoginTypes;
$aSettings['ext_auth_variable'] = $this->m_sExtAuthVariable;
$aSettings['encryption_key'] = $this->m_sEncryptionKey;
$aSettings['csv_import_charsets'] = $this->m_aCharsets;
@@ -1561,8 +1502,6 @@ class Config
'log_notification' => $this->m_bLogNotification,
'log_issue' => $this->m_bLogIssue,
'log_web_service' => $this->m_bLogWebService,
'log_queries' => $this->m_bLogQueries,
'query_cache_enabled' => $this->m_bQueryCacheEnabled,
'secure_connection_required' => $this->m_bSecureConnectionRequired,
);
foreach($aBoolValues as $sKey => $bValue)
@@ -1601,7 +1540,6 @@ class Config
'db_collation' => $this->m_sDBCollation,
'default_language' => $this->m_sDefaultLanguage,
'allowed_login_types' => $this->m_sAllowedLoginTypes,
'ext_auth_variable' => $this->m_sExtAuthVariable,
'encryption_key' => $this->m_sEncryptionKey,
'csv_import_charsets' => $this->m_aCharsets,
);

View File

@@ -94,9 +94,7 @@ abstract class DBObject implements iDisplay
private $m_bFullyLoaded = false; // Compound objects can be partially loaded
private $m_aLoadedAtt = array(); // Compound objects can be partially loaded, array of sAttCode
protected $m_aModifiedAtt = array(); // list of (potentially) modified sAttCodes
protected $m_aSynchroData = null; // Set of Synch data related to this object
protected $m_sHighlightCode = null;
protected $m_aCallbacks = array();
protected $m_oMasterReplicaSet = null; // Set of SynchroReplica related to this object
// Use the MetaModel::NewObject to build an object (do we have to force it?)
public function __construct($aRow = null, $sClassAlias = '', $aAttToLoad = null, $aExtendedDataSpec = null)
@@ -339,7 +337,7 @@ abstract class DBObject implements iDisplay
if ($sAttCode == 'finalclass')
{
// Ignore it - this attribute is set upon object creation and that's it
return false;
return;
}
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
@@ -417,9 +415,6 @@ abstract class DBObject implements iDisplay
// Make sure we do not reload it anymore... before saving it
$this->RegisterAsDirty();
// This function is eligible as a lifecycle action: returning true upon success is a must
return true;
}
public function GetLabel($sAttCode)
@@ -562,64 +557,6 @@ abstract class DBObject implements iDisplay
{
return $this->m_aExtendedData;
}
/**
* Set the HighlightCode if the given code has a greater rank than the current HilightCode
* @param string $sCode
* @return void
*/
protected function SetHighlightCode($sCode)
{
$aHighlightScale = MetaModel::GetHighlightScale(get_class($this));
$fCurrentRank = 0.0;
if (($this->m_sHighlightCode !== null) && array_key_exists($this->m_sHighlightCode, $aHighlightScale))
{
$fCurrentRank = $aHighlightScale[$this->m_sHighlightCode]['rank'];
}
if (array_key_exists($sCode, $aHighlightScale))
{
$fRank = $aHighlightScale[$sCode]['rank'];
if ($fRank > $fCurrentRank)
{
$this->m_sHighlightCode = $sCode;
}
}
}
/**
* Get the current HighlightCode
* @return string The Hightlight code (null if none set, meaning rank = 0)
*/
protected function GetHighlightCode()
{
return $this->m_sHighlightCode;
}
protected function ComputeHighlightCode()
{
// First if the state defines a HiglightCode, apply it
$sState = $this->GetState();
if ($sState != '')
{
$sCode = MetaModel::GetHighlightCode(get_class($this), $sState);
$this->SetHighlightCode($sCode);
}
// The check for each StopWatch if a HighlightCode is effective
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
{
if ($oAttDef instanceof AttributeStopWatch)
{
$oStopWatch = $this->Get($sAttCode);
$sCode = $oStopWatch->GetHighlightCode();
if ($sCode !== '')
{
$this->SetHighlightCode($sCode);
}
}
}
return $this->GetHighlightCode();
}
/**
* Updates the value of an external field by (re)loading the object
@@ -848,27 +785,10 @@ abstract class DBObject implements iDisplay
/**
* Get the icon representing this object
* @param boolean $bImgTag If true the result is a full IMG tag (or an emtpy string if no icon is defined)
* @return string Either the full IMG tag ($bImgTag == true) or just the URL to the icon file
* @return string Either the full IMG tag ($bImgTag == true) or just the path to the icon file
*/
public function GetIcon($bImgTag = true)
{
$sCode = $this->ComputeHighlightCode();
if($sCode != '')
{
$aHighlightScale = MetaModel::GetHighlightScale(get_class($this));
if (array_key_exists($sCode, $aHighlightScale))
{
$sIconUrl = $aHighlightScale[$sCode]['icon'];
if($bImgTag)
{
return "<img src=\"$sIconUrl\" style=\"vertical-align:middle\"/>";
}
else
{
return $sIconUrl;
}
}
}
return MetaModel::GetClassIcon(get_class($this), $bImgTag);
}
@@ -1182,51 +1102,54 @@ abstract class DBObject implements iDisplay
if ($this->InSyncScope())
{
foreach ($this->GetSynchroData() as $iSourceId => $aSourceData)
$oReplicaSet = $this->GetMasterReplica();
if ($oReplicaSet->Count() > 0)
{
foreach ($aSourceData['replica'] as $oReplica)
while($aData = $oReplicaSet->FetchAssoc())
{
$oDataSource = $aData['datasource'];
$oReplica = $aData['replica'];
$oDeletionPlan->AddToDelete($oReplica, DEL_SILENT);
}
$oDataSource = $aSourceData['source'];
if ($oDataSource->GetKey() == SynchroExecution::GetCurrentTaskId())
{
// The current task has the right to delete the object
continue;
}
$oReplica = reset($aSourceData['replica']); // Take the first one
if ($oReplica->Get('status_dest_creator') != 1)
{
// The object is not owned by the task
continue;
}
$sLink = $oDataSource->GetName();
$sUserDeletePolicy = $oDataSource->Get('user_delete_policy');
switch($sUserDeletePolicy)
{
case 'nobody':
$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
break;
case 'administrators':
if (!UserRights::IsAdministrator())
if ($oDataSource->GetKey() == SynchroExecution::GetCurrentTaskId())
{
$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
// The current task has the right to delete the object
continue;
}
if ($oReplica->Get('status_dest_creator') != 1)
{
// The object is not owned by the task
continue;
}
break;
case 'everybody':
default:
// Ok
break;
$sLink = $oDataSource->GetName();
$sUserDeletePolicy = $oDataSource->Get('user_delete_policy');
switch($sUserDeletePolicy)
{
case 'nobody':
$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
break;
case 'administrators':
if (!UserRights::IsAdministrator())
{
$this->m_aDeleteIssues[] = Dict::Format('Core:Synchro:TheObjectCannotBeDeletedByUser_Source', $sLink);
}
break;
case 'everybody':
default:
// Ok
break;
}
}
}
}
}
public function CheckToDelete(&$oDeletionPlan)
final public function CheckToDelete(&$oDeletionPlan)
{
$this->MakeDeletionPlan($oDeletionPlan);
$oDeletionPlan->ComputeResults();
@@ -1585,15 +1508,6 @@ abstract class DBObject implements iDisplay
$oTrigger->DoActivate($this->ToArgs('this'));
}
// Callbacks registered with RegisterCallback
if (isset($this->m_aCallbacks[self::CALLBACK_AFTERINSERT]))
{
foreach ($this->m_aCallbacks[self::CALLBACK_AFTERINSERT] as $aCallBackData)
{
call_user_func_array($aCallBackData['callback'], $aCallBackData['params']);
}
}
$this->RecordObjCreation();
return $this->m_iKey;
@@ -2084,55 +1998,17 @@ abstract class DBObject implements iDisplay
// array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD
$bSuccess = true;
foreach ($aTransitionDef['actions'] as $actionHandler)
foreach ($aTransitionDef['actions'] as $sActionHandler)
{
if (is_string($actionHandler))
// std PHP spec
$aActionCallSpec = array($this, $sActionHandler);
if (!is_callable($aActionCallSpec))
{
// Old (pre-2.1.0 modules) action definition without any parameter
$aActionCallSpec = array($this, $actionHandler);
if (!is_callable($aActionCallSpec))
{
throw new CoreException("Unable to call action: ".get_class($this)."::$actionHandler");
return;
}
$bRet = call_user_func($aActionCallSpec, $sStimulusCode);
}
else // if (is_array($actionHandler))
{
// New syntax: 'verb' and typed parameters
$sAction = $actionHandler['verb'];
$aParams = array();
foreach($actionHandler['params'] as $aDefinition)
{
$sParamType = array_key_exists('type', $aDefinition) ? $aDefinition['type'] : 'string';
switch($sParamType)
{
case 'int':
$value = (int)$aDefinition['value'];
break;
case 'float':
$value = (float)$aDefinition['value'];
break;
case 'bool':
$value = (bool)$aDefinition['value'];
break;
case 'reference':
$value = ${$aDefinition['value']};
break;
case 'string':
default:
$value = (string)$aDefinition['value'];
}
$aParams[] = $value;
}
$aCallSpec = array($this, $sAction);
$bRet = call_user_func_array($aCallSpec, $aParams);
throw new CoreException("Unable to call action: ".get_class($this)."::$sActionHandler");
return;
}
$bRet = call_user_func($aActionCallSpec, $sStimulusCode);
// if one call fails, the whole is considered as failed
if (!$bRet) $bSuccess = false;
}
@@ -2196,80 +2072,6 @@ abstract class DBObject implements iDisplay
$this->Set($sAttCode, $oSW);
}
/**
* Lifecycle action: Recover the default value (aka when an object is being created)
*/
public function Reset($sAttCode)
{
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
$this->Set($sAttCode, $oAttDef->GetDefaultValue());
return true;
}
/**
* Lifecycle action: Copy an attribute to another
*/
public function Copy($sDestAttCode, $sSourceAttCode)
{
$this->Set($sDestAttCode, $this->Get($sSourceAttCode));
return true;
}
/**
* Lifecycle action: Set the current date/time for the given attribute
*/
public function SetCurrentDate($sAttCode)
{
$this->Set($sAttCode, time());
return true;
}
/**
* Lifecycle action: Set the current logged in user for the given attribute
*/
public function SetCurrentUser($sAttCode)
{
$this->Set($sAttCode, UserRights::GetUserId());
return true;
}
/**
* Lifecycle action: Set the time elapsed since a reference point
*/
public function SetElapsedTime($sAttCode, $sRefAttCode, $sWorkingTimeComputer = null)
{
if (is_null($sWorkingTimeComputer))
{
$sWorkingTimeComputer = class_exists('SLAComputation') ? 'SLAComputation' : 'DefaultWorkingTimeComputer';
}
$oComputer = new $sWorkingTimeComputer();
$aCallSpec = array($oComputer, 'GetOpenDuration');
if (!is_callable($aCallSpec))
{
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetOpenDuration'");
}
$iStartTime = AttributeDateTime::GetAsUnixSeconds($this->Get($sRefAttCode));
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
$oEndDate = new DateTime(); // now
if (class_exists('WorkingTimeRecorder'))
{
$sClass = get_class($this);
WorkingTimeRecorder::Start($this, time(), "DBObject-SetElapsedTime-$sAttCode-$sRefAttCode", 'Core:ExplainWTC:ElapsedTime', array("Class:$sClass/Attribute:$sAttCode"));
}
$iElapsed = call_user_func($aCallSpec, $this, $oStartDate, $oEndDate);
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::End();
}
$this->Set($sAttCode, $iElapsed);
return true;
}
/*
* Create query parameters (SELECT ... WHERE service = :this->service_id)
* to be used with the APIs DBObjectSearch/DBObjectSet
@@ -2672,77 +2474,45 @@ abstract class DBObject implements iDisplay
}
/**
* WILL DEPRECATED SOON
* Caching relying on an object set is not efficient since 2.0.3
* Use GetSynchroData instead
*
* Get all the synchro replica related to this object
* @param none
* @return DBObjectSet Set with two columns: R=SynchroReplica S=SynchroDataSource
*/
public function GetMasterReplica()
{
$sOQL = "SELECT replica,datasource FROM SynchroReplica AS replica JOIN SynchroDataSource AS datasource ON replica.sync_source_id=datasource.id WHERE replica.dest_class = :dest_class AND replica.dest_id = :dest_id";
$oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array() /* order by*/, array('dest_class' => get_class($this), 'dest_id' => $this->GetKey()));
return $oReplicaSet;
}
/**
* Get all the synchro data related to this object
* @param none
* @return array of data_source_id => array
* 'source' => $oSource,
* 'attributes' => array of $oSynchroAttribute
* 'replica' => array of $oReplica (though only one should exist, misuse of the data sync can have this consequence)
*/
public function GetSynchroData()
{
if ($this->m_aSynchroData == null)
if ($this->m_oMasterReplicaSet == null)
{
//$aParentClasses = MetaModel::EnumParentClasses(get_class($this), ENUM_PARENT_CLASSES_ALL);
//$sClassesList = "'".implode("','", $aParentClasses)."'";
$sOQL = "SELECT replica,datasource FROM SynchroReplica AS replica JOIN SynchroDataSource AS datasource ON replica.sync_source_id=datasource.id WHERE replica.dest_class = :dest_class AND replica.dest_id = :dest_id";
$oReplicaSet = new DBObjectSet(DBObjectSearch::FromOQL($sOQL), array() /* order by*/, array('dest_class' => get_class($this), 'dest_id' => $this->GetKey()));
$this->m_aSynchroData = array();
while($aData = $oReplicaSet->FetchAssoc())
{
$iSourceId = $aData['datasource']->GetKey();
if (!array_key_exists($iSourceId, $this->m_aSynchroData))
{
$aAttributes = array();
$oAttrSet = $aData['datasource']->Get('attribute_list');
while($oSyncAttr = $oAttrSet->Fetch())
{
$aAttributes[$oSyncAttr->Get('attcode')] = $oSyncAttr;
}
$this->m_aSynchroData[$iSourceId] = array(
'source' => $aData['datasource'],
'attributes' => $aAttributes,
'replica' => array()
);
}
// Assumption: $aData['datasource'] will not be null because the data source id is always set...
$this->m_aSynchroData[$iSourceId]['replica'][] = $aData['replica'];
}
$this->m_oMasterReplicaSet = $oReplicaSet;
}
return $this->m_aSynchroData;
else
{
$this->m_oMasterReplicaSet->Rewind();
}
return $this->m_oMasterReplicaSet;
}
public function GetSynchroReplicaFlags($sAttCode, &$aReason)
{
$iFlags = OPT_ATT_NORMAL;
foreach ($this->GetSynchroData() as $iSourceId => $aSourceData)
$oSet = $this->GetMasterReplica();
while($aData = $oSet->FetchAssoc())
{
if ($iSourceId == SynchroExecution::GetCurrentTaskId())
if ($aData['datasource']->GetKey() == SynchroExecution::GetCurrentTaskId())
{
// Ignore the current task (check to write => ok)
continue;
}
// Assumption: one replica - take the first one!
$oReplica = reset($aSourceData['replica']);
$oSource = $aSourceData['source'];
if (array_key_exists($sAttCode, $aSourceData['attributes']))
// Assumption: $aData['datasource'] will not be null because the data source id is always set...
$oReplica = $aData['replica'];
$oSource = $aData['datasource'];
$oAttrSet = $oSource->Get('attribute_list');
while($oSyncAttr = $oAttrSet->Fetch())
{
$oSyncAttr = $aSourceData['attributes'][$sAttCode];
if (($oSyncAttr->Get('update') == 1) && ($oSyncAttr->Get('update_policy') == 'master_locked'))
if (($oSyncAttr->Get('attcode') == $sAttCode) && ($oSyncAttr->Get('update') == 1) && ($oSyncAttr->Get('update_policy') == 'master_locked'))
{
$iFlags |= OPT_ATT_SLAVE;
$sUrl = $oSource->GetApplicationUrl($this, $oReplica);
@@ -2793,15 +2563,6 @@ abstract class DBObject implements iDisplay
public function GetHilightClass()
{
$sCode = $this->ComputeHighlightCode();
if($sCode != '')
{
$aHighlightScale = MetaModel::GetHighlightScale(get_class($this));
if (array_key_exists($sCode, $aHighlightScale))
{
return $aHighlightScale[$sCode]['color'];
}
}
return HILIGHT_CLASS_NONE;
}
@@ -2820,28 +2581,6 @@ abstract class DBObject implements iDisplay
}
$oPage->details($aValues);
}
const CALLBACK_AFTERINSERT = 0;
/**
* Register a call back that will be called when some internal event happens
*
* @param $iType string Any of the CALLBACK_x constants
* @param $callback callable Call specification like a function name, or array('<class>', '<method>') or array($object, '<method>')
* @param $aParameters Array Values that will be passed to the callback, after $this
*/
public function RegisterCallback($iType, $callback, $aParameters = array())
{
$sCallBackName = '';
if (!is_callable($callback, false, $sCallBackName))
{
throw new Exception('Registering an unknown/protected function or wrong syntax for the call spec: '.$sCallBackName);
}
$this->m_aCallbacks[$iType][] = array(
'callback' => $callback,
'params' => $aParameters
);
}
}

View File

@@ -53,8 +53,9 @@ class DBObjectSearch
public function __construct($sClass, $sClassAlias = null)
{
if (is_null($sClassAlias)) $sClassAlias = $sClass;
if(!is_string($sClass)) throw new Exception('DBObjectSearch::__construct called with a non-string parameter: $sClass = '.print_r($sClass, true));
if(!MetaModel::IsValidClass($sClass)) throw new Exception('DBObjectSearch::__construct called for an invalid class: "'.$sClass.'"');
assert('is_string($sClass)');
assert('MetaModel::IsValidClass($sClass)'); // #@# could do better than an assert, or at least give the caller's reference
// => idee d'un assert avec call stack (autre utilisation = echec sur query SQL)
$this->m_aSelectedClasses = array($sClassAlias => $sClass);
$this->m_aClasses = array($sClassAlias => $sClass);
@@ -448,7 +449,7 @@ class DBObjectSearch
public function AddCondition($sFilterCode, $value, $sOpCode = null)
{
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
$oFilterDef = MetaModel::GetClassFilterDef($this->GetClass(), $sFilterCode);
$oField = new FieldExpression($sFilterCode, $this->GetClassAlias());
@@ -971,9 +972,6 @@ class DBObjectSearch
// Alternative to object mapping: the data are transfered directly into an array
// This is 10 times faster than creating a set of objects, and makes sense when optimization is required
/**
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
*/
public function ToDataArray($aColumns = array(), $aOrderBy = array(), $aArgs = array())
{
$sSQL = MetaModel::MakeSelectQuery($this, $aOrderBy, $aArgs);

View File

@@ -48,7 +48,7 @@ class DBObjectSet
* Create a new set based on a Search definition.
*
* @param DBObjectSearch $oFilter The search filter defining the objects which are part of the set (multiple columns/objects per row are supported)
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
* @param hash $aOrderBy
* @param hash $aArgs Values to substitute for the search/query parameters (if any). Format: param_name => value
* @param hash $aExtendedDataSpec
* @param int $iLimitCount Maximum number of rows to load (i.e. equivalent to MySQL's LIMIT start, count)
@@ -1156,3 +1156,5 @@ function HashCountComparison($a, $b) // Sort descending on 'count'
}
return ($a['count'] > $b['count']) ? -1 : 1;
}
?>

View File

@@ -177,15 +177,6 @@ class EMail
}
break;
case 'Null':
$oTransport = Swift_NullTransport::newInstance();
break;
case 'LogFile':
$oTransport = Swift_LogFileTransport::newInstance();
$oTransport->setLogFile(APPROOT.'log/mail.log');
break;
case 'PHPMail':
default:
$oTransport = Swift_MailTransport::newInstance();
@@ -405,75 +396,4 @@ class EMail
}
/////////////////////////////////////////////////////////////////////////////////////
/**
* Extension to SwiftMailer: "debug" transport that pretends messages have been sent,
* but just log them to a file.
*
* @package Swift
* @author Denis Flaven
*/
class Swift_Transport_LogFileTransport extends Swift_Transport_NullTransport
{
protected $sLogFile;
/**
* Sends the given message.
*
* @param Swift_Mime_Message $message
* @param string[] $failedRecipients An array of failures by-reference
*
* @return int The number of sent emails
*/
public function send(Swift_Mime_Message $message, &$failedRecipients = null)
{
$hFile = @fopen($this->sLogFile, 'a');
if ($hFile)
{
$sTxt = "================== ".date('Y-m-d H:i:s')." ==================\n";
$sTxt .= $message->toString()."\n";
@fwrite($hFile, $sTxt);
@fclose($hFile);
}
return parent::send($message, $failedRecipients);
}
public function setLogFile($sFilename)
{
$this->sLogFile = $sFilename;
}
}
/**
* Pretends messages have been sent, but just log them to a file.
*
* @package Swift
* @author Denis Flaven
*/
class Swift_LogFileTransport extends Swift_Transport_LogFileTransport
{
/**
* Create a new LogFileTransport.
*/
public function __construct()
{
call_user_func_array(
array($this, 'Swift_Transport_LogFileTransport::__construct'),
Swift_DependencyContainer::getInstance()
->createDependenciesFor('transport.null')
);
}
/**
* Create a new LogFileTransport instance.
*
* @return Swift_LogFileTransport
*/
public static function newInstance()
{
return new self();
}
}
?>

View File

@@ -59,11 +59,8 @@ class FileLog
$hLogFile = @fopen($this->m_sFile, 'a');
if ($hLogFile !== false)
{
flock($hLogFile, LOCK_EX);
$sDate = date('Y-m-d H:i:s');
fwrite($hLogFile, "$sDate | $sText\n");
fflush($hLogFile);
flock($hLogFile, LOCK_UN);
fclose($hLogFile);
}
}

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
@@ -279,7 +279,6 @@ abstract class MetaModel
private static $m_aChildClasses = array(); // array of ("classname" => array of "childclass")
private static $m_aClassParams = array(); // array of ("classname" => array of class information)
private static $m_aHighlightScales = array(); // array of ("classname" => array of highlightscale information)
static public function GetParentPersistentClass($sRefClass)
{
@@ -1913,50 +1912,6 @@ abstract class MetaModel
self::$m_aTransitions[$sTargetClass][$sStateCode] = array();
}
public static function Init_DefineHighlightScale($aHighlightScale)
{
$sTargetClass = self::GetCallersPHPClass("Init");
self::$m_aHighlightScales[$sTargetClass] = $aHighlightScale;
}
public static function GetHighlightScale($sTargetClass)
{
$aScale = array();
$aParentScale = array();
$sParentClass = self::GetParentPersistentClass($sTargetClass);
if (!empty($sParentClass))
{
// inherit the scale from the parent class
$aParentScale = self::GetHighlightScale($sParentClass);
}
if (array_key_exists($sTargetClass, self::$m_aHighlightScales))
{
$aScale = self::$m_aHighlightScales[$sTargetClass];
}
return array_merge($aParentScale, $aScale); // Merge both arrays, the values from the last one have precedence
}
public static function GetHighlightCode($sTargetClass, $sStateCode)
{
$sCode = '';
if ( array_key_exists($sTargetClass, self::$m_aStates)
&& array_key_exists($sStateCode, self::$m_aStates[$sTargetClass])
&& array_key_exists('highlight', self::$m_aStates[$sTargetClass][$sStateCode]) )
{
$sCode = self::$m_aStates[$sTargetClass][$sStateCode]['highlight']['code'];
}
else
{
// Check the parent's definition
$sParentClass = self::GetParentPersistentClass($sTargetClass);
if (!empty($sParentClass))
{
$sCode = self::GetHighlightCode($sParentClass, $sStateCode);
}
}
return $sCode;
}
public static function Init_OverloadStateAttribute($sStateCode, $sAttCode, $iFlags)
{
// Warning: this is not sufficient: the flags have to be copied to the states that are inheriting from this state
@@ -2171,10 +2126,6 @@ abstract class MetaModel
{
$aScalarArgs[$sArgName] = (string) $value;
}
elseif (is_null($value))
{
$aScalarArgs[$sArgName] = null;
}
}
}
// Add standard contextual arguments
@@ -2222,9 +2173,6 @@ abstract class MetaModel
}
/**
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
*/
public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false)
{
// Check the order by specification, and prefix with the class alias
@@ -2235,44 +2183,32 @@ abstract class MetaModel
$aOrderSpec = array();
foreach ($aOrderBy as $sFieldAlias => $bAscending)
{
if ($sFieldAlias != 'id')
{
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($sClass));
}
if (!is_bool($bAscending))
{
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
}
$iDotPos = strpos($sFieldAlias, '.');
if ($iDotPos === false)
if (self::IsValidAttCode($sClass, $sFieldAlias))
{
$sAttClass = $sClass;
$sAttClassAlias = $sClassAlias;
$sAttCode = $sFieldAlias;
}
else
{
$sAttClassAlias = substr($sFieldAlias, 0, $iDotPos);
$sAttClass = $oFilter->GetClassName($sAttClassAlias);
$sAttCode = substr($sFieldAlias, $iDotPos + 1);
}
if ($sAttCode != 'id')
{
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sAttCode, self::GetAttributesList($sAttClass));
$oAttDef = self::GetAttributeDef($sAttClass, $sAttCode);
foreach($oAttDef->GetOrderBySQLExpressions($sAttClassAlias) as $sSQLExpression)
$oAttDef = self::GetAttributeDef($sClass, $sFieldAlias);
foreach($oAttDef->GetOrderBySQLExpressions($sClassAlias) as $sSQLExpression)
{
$aOrderSpec[$sSQLExpression] = $bAscending;
}
}
else
{
$aOrderSpec['`'.$sAttClassAlias.$sAttCode.'`'] = $bAscending;
$aOrderSpec['`'.$sClassAlias.$sFieldAlias.'`'] = $bAscending;
}
// Make sure that the columns used for sorting are present in the loaded columns
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sAttClassAlias][$sAttCode]))
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sClassAlias][$sFieldAlias]))
{
$aAttToLoad[$sAttClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sAttClass, $sAttCode);
$aAttToLoad[$sClassAlias][$sFieldAlias] = MetaModel::GetAttributeDef($sClass, $sFieldAlias);
}
}
@@ -3079,7 +3015,7 @@ abstract class MetaModel
$sExtAttCode = $oAtt->GetExtAttCode();
// Translate mainclass.extfield => remoteclassalias.remotefieldcode
$oRemoteAttDef = self::GetAttributeDef($sKeyClass, $sExtAttCode);
foreach ($oRemoteAttDef->GetSQLExpressions() as $sColId => $sRemoteAttExpr)
foreach ($oRemoteAttDef->GetSQLExpressions() as $sColID => $sRemoteAttExpr)
{
$aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);
//echo "<p><b>aTranslateNow[$sTargetAlias][$sAttCode.$sColId] = new FieldExpression($sExtAttCode, $sKeyClassAlias);</b></p>\n";
@@ -3454,33 +3390,6 @@ abstract class MetaModel
{
// Do nothing...
}
else if ($oAttDef instanceof AttributeStopWatch)
{
$aThresholds = $oAttDef->ListThresholds();
if (is_array($aThresholds))
{
foreach($aThresholds as $iPercent => $aDef)
{
if (array_key_exists('highlight', $aDef))
{
if(!array_key_exists('code', $aDef['highlight']))
{
$aErrors[$sClass][] = "The 'code' element is missing for the 'highlight' property of the $iPercent% threshold in the attribute: '$sAttCode'.";
$aSugFix[$sClass][] = "Add a 'code' entry specifying the value of the highlight code for this threshold.";
}
else
{
$aScale = self::GetHighlightScale($sClass);
if (!array_key_exists($aDef['highlight']['code'], $aScale))
{
$aErrors[$sClass][] = "'{$aDef['highlight']['code']}' is not a valid value for the 'code' element of the $iPercent% threshold in the attribute: '$sAttCode'.";
$aSugFix[$sClass][] = "The possible highlight codes for this class are: ".implode(', ', array_keys($aScale)).".";
}
}
}
}
}
}
else // standard attributes
{
// Check that the default values definition is a valid object!
@@ -3578,46 +3487,17 @@ abstract class MetaModel
}
}
// Lifecycle - check that the action handlers are defined
// Lifcycle - check that the action handlers are defined
foreach (self::EnumStates($sClass) as $sStateCode => $aStateDef)
{
foreach(self::EnumTransitions($sClass, $sStateCode) as $sStimulusCode => $aTransitionDef)
{
foreach ($aTransitionDef['actions'] as $actionHandler)
foreach ($aTransitionDef['actions'] as $sActionHandler)
{
if (is_string($actionHandler))
if (!method_exists($sClass, $sActionHandler))
{
if (!method_exists($sClass, $actionHandler))
{
$aErrors[$sClass][] = "Unknown function '$sActionHandler' in transition [$sStateCode/$sStimulusCode] for state attribute '$sStateAttCode'";
$aSugFix[$sClass][] = "Specify a function which prototype is in the form [public function $sActionHandler(\$sStimulusCode){return true;}]";
}
}
else // if(is_array($actionHandler))
{
$sActionHandler = $actionHandler['verb'];
if (!method_exists($sClass, $sActionHandler))
{
$aErrors[$sClass][] = "Unknown function '$sActionHandler' in transition [$sStateCode/$sStimulusCode] for state attribute '$sStateAttCode'";
$aSugFix[$sClass][] = "Specify a function which prototype is in the form [public function $sActionHandler(...){return true;}]";
}
}
}
}
if (array_key_exists('highlight', $aStateDef))
{
if(!array_key_exists('code', $aStateDef['highlight']))
{
$aErrors[$sClass][] = "The 'code' element is missing for the 'highlight' property of state: '$sStateCode'.";
$aSugFix[$sClass][] = "Add a 'code' entry specifying the value of the highlight code for this state.";
}
else
{
$aScale = self::GetHighlightScale($sClass);
if (!array_key_exists($aStateDef['highlight']['code'], $aScale))
{
$aErrors[$sClass][] = "'{$aStateDef['highlight']['code']}' is not a valid value for the 'code' element in the 'highlight' property of state: '$sStateCode'.";
$aSugFix[$sClass][] = "The possible highlight codes for this class are: ".implode(', ', array_keys($aScale)).".";
$aErrors[$sClass][] = "Unknown function '$sActionHandler' in transition [$sStateCode/$sStimulusCode] for state attribute '$sStateAttCode'";
$aSugFix[$sClass][] = "Specify a function which prototype is in the form [public function $sActionHandler(\$sStimulusCode){return true;}]";
}
}
}
@@ -3805,7 +3685,7 @@ abstract class MetaModel
}
public static function DBCreate($aCallback = null)
public static function DBCreate()
{
// Note: we have to check if the DB does exist, because we may share the DB
// with other applications (in which case the DB does exist, not the tables with the given prefix)
@@ -3813,24 +3693,18 @@ abstract class MetaModel
{
CMDBSource::CreateDB(self::$m_sDBName);
}
self::DBCreateTables($aCallback);
self::DBCreateTables();
self::DBCreateViews();
}
protected static function DBCreateTables($aCallback = null)
protected static function DBCreateTables()
{
list($aErrors, $aSugFix, $aCondensedQueries) = self::DBCheckFormat();
//$sSQL = implode('; ', $aCondensedQueries); Does not work - multiple queries not allowed
foreach($aCondensedQueries as $sQuery)
{
$fStart = microtime(true);
CMDBSource::CreateTable($sQuery);
$fDuration = microtime(true) - $fStart;
if ($aCallback != null)
{
call_user_func($aCallback, $sQuery, $fDuration);
}
}
}
@@ -4848,7 +4722,6 @@ abstract class MetaModel
self::$m_aStates = $result['m_aStates'];
self::$m_aStimuli = $result['m_aStimuli'];
self::$m_aTransitions = $result['m_aTransitions'];
self::$m_aHighlightScales = $result['m_aHighlightScales'];
}
$oKPI->ComputeAndReport('Metamodel APC (fetch + read)');
}
@@ -4885,7 +4758,6 @@ abstract class MetaModel
$aCache['m_aStates'] = self::$m_aStates; // array of ("classname" => array of "statecode"=>array('label'=>..., attribute_inherit=> attribute_list=>...))
$aCache['m_aStimuli'] = self::$m_aStimuli; // array of ("classname" => array of ("stimuluscode"=>array('label'=>...)))
$aCache['m_aTransitions'] = self::$m_aTransitions; // array of ("classname" => array of ("statcode_from"=>array of ("stimuluscode" => array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD)))
$aCache['m_aHighlightScales'] = self::$m_aHighlightScales; // array of ("classname" => array of higlightcodes)))
apc_store($sOqlAPCCacheId, $aCache);
$oKPI->ComputeAndReport('Metamodel APC (store)');
}
@@ -4947,15 +4819,7 @@ abstract class MetaModel
if (!file_exists($sFile))
{
$sConfigFile = self::$m_oConfig->GetLoadedFile();
if (strlen($sConfigFile) > 0)
{
throw new CoreException('Include: wrong file name in configuration file', array('config file' => $sConfigFile, 'section' => $sModuleType, 'filename' => $sFile));
}
else
{
// The configuration is in memory only
throw new CoreException('Include: wrong file name in configuration file (in memory)', array('section' => $sModuleType, 'filename' => $sFile));
}
throw new CoreException('Wrong filename in configuration file', array('file' => $sConfigFile, 'module' => $sModuleType, 'filename' => $sFile));
}
// Note: We do not expect the modules to output characters while loading them.
@@ -5432,11 +5296,9 @@ abstract class MetaModel
{
// Some environment parameters are objects, we just need scalars
if (is_object($replace)) continue;
else
{
$aSearches[] = '$'.$sSearch.'$';
$aReplacements[] = (string) $replace;
}
$aSearches[] = '$'.$sSearch.'$';
$aReplacements[] = (string) $replace;
}
return str_replace($aSearches, $aReplacements, $aInput);
}
@@ -5536,3 +5398,5 @@ MetaModel::RegisterZList("preview", array("description"=>"All attributes visible
MetaModel::RegisterZList("standard_search", array("description"=>"List of criteria for the standard search", "type"=>"filters"));
MetaModel::RegisterZList("advanced_search", array("description"=>"List of criteria for the advanced search", "type"=>"filters"));
?>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2013-2016 Combodo SARL
// Copyright (C) 2013 Combodo SARL
//
// This file is part of iTop.
//
@@ -24,7 +24,7 @@
* Relies on MySQL locks because the API sem_get is not always present in the
* installed PHP.
*
* @copyright Copyright (C) 2013-2016 Combodo SARL
* @copyright Copyright (C) 2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class iTopMutex
@@ -37,19 +37,8 @@ class iTopMutex
public function __construct($sName, $sDBHost = null, $sDBUser = null, $sDBPwd = null)
{
// Compute the name of a lock for mysql
// Note: names are server-wide!!! So let's make the name specific to this iTop instance
$oConfig = utils::GetConfig(); // Will return an empty config when called during the setup
$sDBName = $oConfig->GetDBName();
$sDBSubname = $oConfig->GetDBSubname();
// Note: the name is server-wide!!!
$this->sName = 'itop.'.$sName;
if (substr($sName, -strlen($sDBName.$sDBSubname)) != $sDBName.$sDBSubname)
{
// If the name supplied already ends with the expected suffix
// don't add it twice, since the setup may try to detect an already
// running cron job by its mutex, without knowing if the config already exists or not
$this->sName .= $sDBName.$sDBSubname;
}
$this->bLocked = false; // Not yet locked
if (!array_key_exists($this->sName, self::$aAcquiredLocks))
@@ -59,6 +48,7 @@ class iTopMutex
// It is a MUST to create a dedicated session each time a lock is required, because
// using GET_LOCK anytime on the same session will RELEASE the current and unique session lock (known issue)
$oConfig = utils::GetConfig();
$sDBHost = is_null($sDBHost) ? $oConfig->GetDBHost() : $sDBHost;
$sDBUser = is_null($sDBUser) ? $oConfig->GetDBUser() : $sDBUser;
$sDBPwd = is_null($sDBPwd) ? $oConfig->GetDBPwd() : $sDBPwd;
@@ -131,43 +121,7 @@ class iTopMutex
$this->bLocked = true;
self::$aAcquiredLocks[$this->sName]++;
}
if (($res !== '1') && ($res !== '0'))
{
$sMsg = 'GET_LOCK('.$this->sName.', 0) returned: '.var_export($res, true).'. Expected values are: 0, 1 or null';
IssueLog::Error($sMsg);
throw new Exception($sMsg);
}
return ($res !== '0');
}
/**
* Check if the mutex is locked WITHOUT TRYING TO ACQUIRE IT
* @returns bool True if the mutex is in use, false otherwise
*/
public function IsLocked()
{
if ($this->bLocked)
{
return true; // Already acquired
}
if (self::$aAcquiredLocks[$this->sName] > 0)
{
return true;
}
$res = $this->QueryToScalar("SELECT IS_FREE_LOCK('".$this->sName."')"); // IS_FREE_LOCK detects some error cases that IS_USED_LOCK do not detect
if (is_null($res))
{
$sMsg = "MySQL Error, IS_FREE_LOCK('".$this->sName."') returned null. Error (".mysqli_errno($this->hDBLink).") = '".mysqli_error($this->hDBLink)."'";
IssueLog::Error($sMsg);
throw new Exception($sMsg);
}
else if ($res == '1')
{
// Lock is free
return false;
}
return true;
return ($res === '1');
}
/**

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -23,7 +23,7 @@ define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\
/**
* Class to store a "case log" in a structured way, keeping track of its successive entries
*
* @copyright Copyright (C) 2010-2015 Combodo SARL
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
class ormCaseLog {
@@ -394,7 +394,7 @@ class ormCaseLog {
{
throw new Exception("Only administrators can set the user id", RestResult::UNAUTHORIZED);
}
if ($bCheckUserId && ($oJson->user_id != 0))
if ($bCheckUserId)
{
try
{

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2014 Combodo SARL
// Copyright (C) 2010-2013 Combodo SARL
//
// This file is part of iTop.
//
@@ -62,13 +62,12 @@ class ormStopWatch
return (string) $this->iTimeSpent;
}
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $bTriggered = false, $iOverrun = null, $aHighlightDef = null)
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $bTriggered = false, $iOverrun = null)
{
$this->aThresholds[$iPercent] = array(
'deadline' => $tDeadline, // unix time (seconds)
'triggered' => $bTriggered,
'overrun' => $iOverrun,
'highlight' => $aHighlightDef, // array('code' => string, 'persistent' => boolean)
'overrun' => $iOverrun
);
}
@@ -82,26 +81,6 @@ class ormStopWatch
return $this->iTimeSpent;
}
/**
* Get the working elapsed time since the start of the stop watch
* even if it is currently running
* @param oAttDef AttributeDefinition Attribute hosting the stop watch
* @param oObject Hosting object (used for query parameters)
*/
public function GetElapsedTime($oAttDef, $oObject)
{
if (is_null($this->iLastStart))
{
return $this->GetTimeSpent();
}
else
{
$iElapsed = $this->ComputeDuration($oObject, $oAttDef, $this->iLastStart, time());
return $this->iTimeSpent + $iElapsed;
}
}
public function GetStartDate()
{
return $this->iStarted;
@@ -150,10 +129,6 @@ class ormStopWatch
{
$bRet = true;
}
if (isset($aThresholdData['overrun']) && ($aThresholdData['overrun'] > 0))
{
$bRet = true;
}
}
return $bRet;
}
@@ -168,31 +143,6 @@ class ormStopWatch
return false;
}
}
public function GetHighlightCode()
{
$sCode = '';
// Process the thresholds in ascending order
$aPercents = array();
foreach($this->aThresholds as $iPercent => $aDefs)
{
$aPercents[] = $iPercent;
}
sort($aPercents, SORT_NUMERIC);
foreach($aPercents as $iPercent)
{
$aDefs = $this->aThresholds[$iPercent];
if (array_key_exists('highlight', $aDefs) && is_array($aDefs['highlight']) && $this->IsThresholdPassed($iPercent))
{
// If persistant or SW running...
if (($aDefs['highlight']['persistent'] == true) || (($aDefs['highlight']['persistent'] == false) && !is_null($this->iLastStart)))
{
$sCode = $aDefs['highlight']['code'];
}
}
}
return $sCode;
}
public function GetAsHTML($oAttDef, $oHostObject = null)
{
@@ -331,7 +281,7 @@ class ormStopWatch
* It is the responsibility of the caller to compute the deadlines
* (to avoid computing twice for the same result)
*/
public function Start($oObject, $oAttDef, $iNow = null)
public function Start($oObject, $oAttDef)
{
if (!is_null($this->iLastStart))
{
@@ -339,16 +289,11 @@ class ormStopWatch
return false;
}
if (is_null($iNow))
{
$iNow = time();
}
if (is_null($this->iStarted))
{
$this->iStarted = $iNow;
$this->iStarted = time();
}
$this->iLastStart = $iNow;
$this->iLastStart = time();
$this->iStopped = null;
return true;
@@ -364,9 +309,8 @@ class ormStopWatch
// Currently stopped - do nothing
return false;
}
$iDurationGoal = $this->ComputeGoal($oObject, $oAttDef);
$iComputationRefTime = time();
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
if (is_null($iDurationGoal))
@@ -377,20 +321,9 @@ class ormStopWatch
else
{
$iThresholdDuration = round($iPercent * $iDurationGoal / 100);
if (class_exists('WorkingTimeRecorder'))
{
$sClass = get_class($oObject);
$sAttCode = $oAttDef->GetCode();
WorkingTimeRecorder::Start($oObject, $iComputationRefTime, "ormStopWatch-Deadline-$iPercent-$sAttCode", 'Core:ExplainWTC:StopWatch-Deadline', array("Class:$sClass/Attribute:$sAttCode", $iPercent));
}
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iStarted, $iThresholdDuration);
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::End();
}
}
if (is_null($aThresholdData['deadline']) || ($aThresholdData['deadline'] > time()))
{
@@ -420,18 +353,8 @@ class ormStopWatch
return false;
}
if (class_exists('WorkingTimeRecorder'))
{
$sClass = get_class($oObject);
$sAttCode = $oAttDef->GetCode();
WorkingTimeRecorder::Start($oObject, time(), "ormStopWatch-TimeSpent-$sAttCode", 'Core:ExplainWTC:StopWatch-TimeSpent', array("Class:$sClass/Attribute:$sAttCode"), true /*cumulative*/);
}
$iElapsed = $this->ComputeDuration($oObject, $oAttDef, $this->iLastStart, time());
$this->iTimeSpent = $this->iTimeSpent + $iElapsed;
if (class_exists('WorkingTimeRecorder'))
{
WorkingTimeRecorder::End();
}
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
{
@@ -501,44 +424,9 @@ class CheckStopWatchThresholds implements iBackgroundProcess
{
$sVerb = $aActionData['verb'];
$aParams = $aActionData['params'];
$aValues = array();
foreach($aParams as $def)
{
if (is_string($def))
{
// Old method (pre-2.1.0) non typed parameters
$aValues[] = $def;
}
else // if(is_array($def))
{
$sParamType = array_key_exists('type', $def) ? $def['type'] : 'string';
switch($sParamType)
{
case 'int':
$value = (int)$def['value'];
break;
case 'float':
$value = (float)$def['value'];
break;
case 'bool':
$value = (bool)$def['value'];
break;
case 'reference':
$value = ${$def['value']};
break;
case 'string':
default:
$value = (string)$def['value'];
}
$aValues[] = $value;
}
}
$sParams = implode(', ', $aParams);
$aCallSpec = array($oObj, $sVerb);
call_user_func_array($aCallSpec, $aValues);
call_user_func_array($aCallSpec, $aParams);
}
// Mark the threshold as "triggered"

View File

@@ -342,7 +342,6 @@ class lnkTriggerAction extends cmdbAbstractObject
"db_key_field" => "link_id",
"db_finalclass_field" => "",
"display_template" => "",
"is_link" => true,
);
MetaModel::Init_Params($aParams);
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "jointype"=> '', "allowed_values"=>null, "sql"=>"action_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));

View File

@@ -234,19 +234,12 @@ abstract class User extends cmdbAbstractObject
$aChanges = $this->ListChanges();
if (array_key_exists('login', $aChanges))
{
if (strcasecmp($this->Get('login'), $this->GetOriginal('login')) !== 0)
$sNewLogin = $aChanges['login'];
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT User WHERE login = :newlogin");
$oSet = new DBObjectSet($oSearch, array(), array('newlogin' => $sNewLogin));
if ($oSet->Count() > 0)
{
$sNewLogin = $aChanges['login'];
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT User WHERE login = :newlogin");
if (!$this->IsNew())
{
$oSearch->AddCondition('id', $this->GetKey(), '!=');
}
$oSet = new DBObjectSet($oSearch, array(), array('newlogin' => $sNewLogin));
if ($oSet->Count() > 0)
{
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:LoginMustBeUnique', $sNewLogin);
}
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:LoginMustBeUnique', $sNewLogin);
}
}
// Check that this user has at least one profile assigned
@@ -255,6 +248,7 @@ abstract class User extends cmdbAbstractObject
{
$this->m_aCheckIssues[] = Dict::Format('Class:User/Error:AtLeastOneProfileIsNeeded');
}
}
function GetGrantAsHtml($sClass, $iAction)
@@ -347,29 +341,6 @@ abstract class User extends cmdbAbstractObject
}
}
}
public function CheckToDelete(&$oDeletionPlan)
{
if (MetaModel::GetConfig()->Get('demo_mode'))
{
// Users deletion is NOT allowed in demo mode
$oDeletionPlan->AddToDelete($this, null);
$oDeletionPlan->SetDeletionIssues($this, array('deletion not allowed in demo mode.'), true);
$oDeletionPlan->ComputeResults();
return false;
}
return parent::CheckToDelete($oDeletionPlan);
}
protected function DBDeleteSingleObject()
{
if (MetaModel::GetConfig()->Get('demo_mode'))
{
// Users deletion is NOT allowed in demo mode
return;
}
parent::DBDeleteSingleObject();
}
}
/**
@@ -1303,9 +1274,8 @@ class CAS_SelfRegister implements iSelfRegister
}
else
{
// No membership: no way to create the user that should exist prior to authentication
phpCAS::log("User ".phpCAS::getUser().": missing user account in iTop (or iTop badly configured, Cf setting cas_memberof)");
$bFound = false;
// No membership required, anybody will pass
$bFound = true;
}
if (!$bFound)

View File

@@ -100,9 +100,6 @@ class ValueSetObjects extends ValueSetDefinition
private $m_bAllowAllData;
private $m_aModifierProperties;
/**
* @param hash $aOrderBy Array of '[<classalias>.]attcode' => bAscending
*/
public function __construct($sFilterExp, $sValueAttCode = '', $aOrderBy = array(), $bAllowAllData = false, $aModifierProperties = array())
{
$this->m_sContains = '';
@@ -418,3 +415,5 @@ class ValueSetEnumClasses extends ValueSetEnum
return true;
}
}
?>

View File

@@ -206,11 +206,6 @@ legend.transparent {
padding-left:14px;
background: url(../images/mini-arrow-orange.gif) no-repeat left;
}
.ui-widget-content td a.cke_toolbox_collapser {
padding-left: 0;
}
p a:hover, td a:hover {
text-decoration:underline;
color:#EB8F00;
@@ -1421,7 +1416,3 @@ div.ui-dialog-header {
padding-bottom: 10px;
padding-top: 7px;
}
.form_field_error {
border: 1px solid #933;
background: #fcc;
}

View File

@@ -22,6 +22,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s %2$s</format>
<attributes>
<attribute id="item_class"/>
<attribute id="temp_id"/>

View File

@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -456,7 +457,7 @@
<hidden/>
</attribute>
<attribute id="agent_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -465,13 +466,13 @@
<mandatory/>
</attribute>
<attribute id="supervisor_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="manager_group_id">
<mandatory/>
</attribute>
<attribute id="manager_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="outage">
<hidden/>
@@ -1204,6 +1205,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -1304,7 +1306,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions/>
@@ -1486,7 +1488,7 @@
<hidden/>
</attribute>
<attribute id="agent_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -1495,13 +1497,13 @@
<mandatory/>
</attribute>
<attribute id="supervisor_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="manager_group_id">
<mandatory/>
</attribute>
<attribute id="manager_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="outage">
<hidden/>
@@ -1511,7 +1513,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_plan">
<transition>
<stimulus>ev_plan</stimulus>
<target>plannedscheduled</target>
<actions/>
@@ -1587,7 +1589,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_implement">
<transition>
<stimulus>ev_implement</stimulus>
<target>implemented</target>
<actions/>
@@ -1794,12 +1796,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_monitor">
<transition>
<stimulus>ev_monitor</stimulus>
<target>monitored</target>
<actions/>
</transition>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>
@@ -1877,7 +1879,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>
@@ -2164,6 +2166,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -2462,7 +2465,7 @@
<hidden/>
</attribute>
<attribute id="agent_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -2471,13 +2474,13 @@
<mandatory/>
</attribute>
<attribute id="supervisor_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="manager_group_id">
<mandatory/>
</attribute>
<attribute id="manager_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="outage">
<hidden/>
@@ -3121,6 +3124,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -3244,12 +3248,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_validate">
<transition>
<stimulus>ev_validate</stimulus>
<target>validated</target>
<actions/>
</transition>
<transition id="ev_reject">
<transition>
<stimulus>ev_reject</stimulus>
<target>rejected</target>
<actions/>
@@ -3335,7 +3339,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions/>
@@ -3418,7 +3422,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reopen">
<transition>
<stimulus>ev_reopen</stimulus>
<target>new</target>
<actions/>
@@ -3467,7 +3471,7 @@
<hidden/>
</attribute>
<attribute id="agent_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -3476,13 +3480,13 @@
<mandatory/>
</attribute>
<attribute id="supervisor_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="manager_group_id">
<mandatory/>
</attribute>
<attribute id="manager_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="outage">
<hidden/>
@@ -3498,7 +3502,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_plan">
<transition>
<stimulus>ev_plan</stimulus>
<target>plannedscheduled</target>
<actions/>
@@ -3585,12 +3589,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_approve">
<transition>
<stimulus>ev_approve</stimulus>
<target>approved</target>
<actions/>
</transition>
<transition id="ev_notapprove">
<transition>
<stimulus>ev_notapprove</stimulus>
<target>notapproved</target>
<actions/>
@@ -3676,7 +3680,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_implement">
<transition>
<stimulus>ev_implement</stimulus>
<target>implemented</target>
<actions/>
@@ -3759,7 +3763,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_replan">
<transition>
<stimulus>ev_replan</stimulus>
<target>plannedscheduled</target>
<actions/>
@@ -3845,12 +3849,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_monitor">
<transition>
<stimulus>ev_monitor</stimulus>
<target>monitored</target>
<actions/>
</transition>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>
@@ -3940,7 +3944,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>
@@ -4242,6 +4246,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -4348,7 +4353,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions/>
@@ -4542,7 +4547,7 @@
<hidden/>
</attribute>
<attribute id="agent_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -4551,13 +4556,13 @@
<mandatory/>
</attribute>
<attribute id="supervisor_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="manager_group_id">
<mandatory/>
</attribute>
<attribute id="manager_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="outage">
<hidden/>
@@ -4573,7 +4578,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_plan">
<transition>
<stimulus>ev_plan</stimulus>
<target>plannedscheduled</target>
<actions/>
@@ -4655,12 +4660,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_approve">
<transition>
<stimulus>ev_approve</stimulus>
<target>approved</target>
<actions/>
</transition>
<transition id="ev_notapprove">
<transition>
<stimulus>ev_notapprove</stimulus>
<target>notapproved</target>
<actions/>
@@ -4741,7 +4746,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_implement">
<transition>
<stimulus>ev_implement</stimulus>
<target>implemented</target>
<actions/>
@@ -4818,7 +4823,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_replan">
<transition>
<stimulus>ev_replan</stimulus>
<target>plannedscheduled</target>
<actions/>
@@ -4898,12 +4903,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_monitor">
<transition>
<stimulus>ev_monitor</stimulus>
<target>monitored</target>
<actions/>
</transition>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>
@@ -4987,7 +4992,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>

View File

@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -115,6 +116,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -287,6 +289,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field>finalclass</db_final_class_field>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -484,6 +487,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s %2$s</format>
<attributes>
<attribute id="first_name"/>
<attribute id="name"/>
@@ -622,6 +626,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -740,6 +745,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="team_id"/>
</attributes>
@@ -859,6 +865,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field>finalclass</db_final_class_field>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1024,6 +1031,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1132,6 +1140,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1239,6 +1248,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1361,6 +1371,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1529,6 +1540,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s / %2$s</format>
<attributes>
<attribute id="ip"/>
<attribute id="ip_mask"/>
@@ -1688,6 +1700,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1808,6 +1821,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field>finalclass</db_final_class_field>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1873,6 +1887,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1937,6 +1952,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -2002,6 +2018,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="patch_id"/>
</attributes>
@@ -2093,6 +2110,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field>finalclass</db_final_class_field>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -2279,6 +2297,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s - %2$s</format>
<attributes>
<attribute id="name"/>
<attribute id="device_id_friendlyname"/>
@@ -2477,6 +2496,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s - %2$s</format>
<attributes>
<attribute id="name"/>
<attribute id="device_id_friendlyname"/>
@@ -2625,6 +2645,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s - %2$s</format>
<attributes>
<attribute id="name"/>
<attribute id="device_id_friendlyname"/>
@@ -2764,6 +2785,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s - %2$s</format>
<attributes>
<attribute id="name"/>
<attribute id="db_server_instance_id_friendlyname"/>
@@ -2923,6 +2945,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -3069,6 +3092,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -3198,6 +3222,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -3348,6 +3373,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s - %2$s</format>
<attributes>
<attribute id="device_id_friendlyname"/>
<attribute id="name"/>
@@ -3711,6 +3737,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -3878,6 +3905,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -4069,6 +4097,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -4191,6 +4220,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -4344,6 +4374,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -4531,6 +4562,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -4740,6 +4772,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -4960,6 +4993,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -5167,6 +5201,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -5310,6 +5345,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="group_id"/>
</attributes>
@@ -5416,6 +5452,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ci_id"/>
</attributes>
@@ -5528,6 +5565,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ci_id"/>
</attributes>
@@ -5644,6 +5682,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="solution_id"/>
</attributes>
@@ -5750,6 +5789,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="solution_id"/>
</attributes>

View File

@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -53,7 +54,7 @@
<read_only/>
</attribute>
<attribute id="description">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="start_date">
<read_only/>
@@ -62,28 +63,28 @@
<mandatory/>
</attribute>
<attribute id="org_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="service_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="servicesubcategory_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="product">
<must_prompt/>
</attribute>
<attribute id="impact">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="urgency">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="priority">
<read_only/>
</attribute>
<attribute id="workgroup_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -129,7 +130,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -138,7 +139,7 @@
</action>
</actions>
</transition>
<transition id="ev_timeout">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_tto</target>
<actions/>
@@ -203,7 +204,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -283,17 +284,17 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_reassign">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_reassign">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -376,12 +377,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -545,12 +546,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_close">
<transition>
<stimulus>ev_close</stimulus>
<target>closed</target>
<actions>
@@ -1041,6 +1042,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ticket_id"/>
</attributes>

View File

@@ -14,6 +14,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -223,6 +224,7 @@
<db_key_field>link_id</db_key_field>
<db_final_class_field/>
<naming>
<format>lnkInfraError</format>
<attributes/>
</naming>
<display_template/>
@@ -324,6 +326,7 @@
<db_key_field>link_id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="link_type"/>
</attributes>

View File

@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -212,7 +213,7 @@
<read_only/>
</attribute>
<attribute id="description">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="ticket_log">
<hidden/>
@@ -221,28 +222,28 @@
<read_only/>
</attribute>
<attribute id="org_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="service_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="servicesubcategory_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="product">
<must_prompt/>
</attribute>
<attribute id="impact">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="urgency">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="priority">
<read_only/>
</attribute>
<attribute id="workgroup_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_id">
<hidden/>
@@ -267,7 +268,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -323,12 +324,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -397,12 +398,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_close">
<transition>
<stimulus>ev_close</stimulus>
<target>closed</target>
<actions>
@@ -538,11 +539,7 @@
3 => 3,
),
);
$iPriority = 1;
if (isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')]))
{
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
return $iPriority;
}]]></code>
</method>
@@ -756,7 +753,7 @@
<parent>ProblemManagement</parent>
<definition>
<layout>DashboardLayoutTwoCols</layout>
<title/>
<title></title>
<cells>
<cell id="0">
<rank>0</rank>

View File

@@ -37,6 +37,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -90,7 +91,7 @@
<read_only/>
</attribute>
<attribute id="description">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="start_date">
<read_only/>
@@ -99,28 +100,28 @@
<mandatory/>
</attribute>
<attribute id="org_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="service_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="servicesubcategory_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="product">
<must_prompt/>
</attribute>
<attribute id="impact">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="urgency">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="priority">
<read_only/>
</attribute>
<attribute id="workgroup_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -172,7 +173,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -181,7 +182,7 @@
</action>
</actions>
</transition>
<transition id="ev_timeout">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_tto</target>
<actions/>
@@ -252,7 +253,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -338,17 +339,17 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_timeout">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -360,7 +361,7 @@
</action>
</actions>
</transition>
<transition id="ev_freeze">
<transition>
<stimulus>ev_freeze</stimulus>
<target>frozen</target>
<actions/>
@@ -442,12 +443,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -535,17 +536,17 @@
</attribute>
</flags>
<transitions>
<transition id="ev_timeout">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions/>
@@ -640,12 +641,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_close">
<transition>
<stimulus>ev_close</stimulus>
<target>closed</target>
<actions>

View File

@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field>finalclass</db_final_class_field>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -200,6 +201,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -374,6 +376,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -564,6 +567,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="customer_contract_id"/>
</attributes>
@@ -666,6 +670,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="contract_id"/>
</attributes>
@@ -772,6 +777,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="contract_id"/>
</attributes>
@@ -880,6 +886,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="contract_id"/>
</attributes>
@@ -989,6 +996,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="contract_id"/>
</attributes>
@@ -1083,6 +1091,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1262,6 +1271,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1362,6 +1372,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1444,6 +1455,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1576,6 +1588,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="sla_id"/>
</attributes>
@@ -1710,6 +1723,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="service_id"/>
</attributes>
@@ -1818,6 +1832,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="service_id"/>
</attributes>
@@ -1926,6 +1941,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="service_id"/>
</attributes>

View File

@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field>finalclass</db_final_class_field>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -161,6 +162,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -420,7 +422,7 @@
<read_only/>
</attribute>
<attribute id="description">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="start_date">
<read_only/>
@@ -429,28 +431,28 @@
<mandatory/>
</attribute>
<attribute id="org_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="service_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="servicesubcategory_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="product">
<must_prompt/>
</attribute>
<attribute id="impact">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="urgency">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="priority">
<read_only/>
</attribute>
<attribute id="workgroup_id">
<must_prompt/>
<must_change/>
</attribute>
<attribute id="agent_email">
<hidden/>
@@ -496,7 +498,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -505,7 +507,7 @@
</action>
</actions>
</transition>
<transition id="ev_timeout">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_tto</target>
<actions/>
@@ -570,7 +572,7 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions>
@@ -650,17 +652,17 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_timeout">
<transition>
<stimulus>ev_timeout</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -743,12 +745,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>escalated_ttr</target>
<actions/>
</transition>
<transition id="ev_resolve">
<transition>
<stimulus>ev_resolve</stimulus>
<target>resolved</target>
<actions>
@@ -912,12 +914,12 @@
</attribute>
</flags>
<transitions>
<transition id="ev_reassign">
<transition>
<stimulus>ev_reassign</stimulus>
<target>assigned</target>
<actions/>
</transition>
<transition id="ev_close">
<transition>
<stimulus>ev_close</stimulus>
<target>closed</target>
<actions>
@@ -1155,11 +1157,7 @@
3 => 3,
),
);
$iPriority = 1;
if (isset($aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')]))
{
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
}
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
return $iPriority;
}]]></code>
</method>
@@ -1486,6 +1484,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ticket_id"/>
</attributes>
@@ -1568,6 +1567,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ticket_id"/>
</attributes>
@@ -1677,6 +1677,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ticket_id"/>
</attributes>

View File

@@ -1,30 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:UserExternal' => 'Extern Bruger',
'Class:UserExternal+' => 'Bruger udenfor iTop',
));
?>

View File

@@ -1,32 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:UserLDAP' => 'LDAP-Bruger',
'Class:UserLDAP+' => 'Bruger der godkendes via LDAP',
'Class:UserLDAP/Attribute:password' => 'Password',
'Class:UserLDAP/Attribute:password+' => 'Brugerens password',
));
?>

View File

@@ -1,32 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:UserLocal' => 'iTop-Bruger',
'Class:UserLocal+' => 'Bruger der godkendes af iTop',
'Class:UserLocal/Attribute:password' => 'Password',
'Class:UserLocal/Attribute:password+' => 'Brugerens password',
));
?>

View File

@@ -1,40 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Attachments:TabTitle_Count' => 'Vedhæftninger (%1$d)',
'Attachments:EmptyTabTitle' => 'Vedhæftninger',
'Attachments:FieldsetTitle' => 'Vedhæftninger',
'Attachments:DeleteBtn' => 'Slet',
'Attachments:History_File_Added' => 'Vedhæftning %1$s tilføjet.',
'Attachments:History_File_Removed' => 'Vedhæftning %1$s fjernet.',
'Attachments:AddAttachment' => 'Vedhæft: ',
'Attachments:UploadNotAllowedOnThisSystem' => 'Upload IKKE tilladt i dette system.',
'Attachment:Max_Go' => '(Maksimal størrelse: %1$s GB)',
'Attachment:Max_Mo' => '(Maksimal størrelse: %1$s MB)',
'Attachment:Max_Ko' => '(Maksimal størrelse: %1$s KB)',
'Attachments:NoAttachment' => 'Intet vedhæftet. ',
));
?>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<classes>
<class id="Attachment" _delta="define">
<parent>DBObject</parent>
@@ -22,6 +22,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s %2$s</format>
<attributes>
<attribute id="item_class"/>
<attribute id="temp_id"/>
@@ -36,20 +37,20 @@
</reconciliation>
<indexes>
<index id="1">
<attributes>
<attribute id="temp_id"/>
</attributes>
<attributes>
<attribute id="temp_id"/>
</attributes>
</index>
<index id="2">
<attributes>
<attribute id="item_class"/>
<attribute id="item_id"/>
</attributes>
<attributes>
<attribute id="item_class"/>
<attribute id="item_id"/>
</attributes>
</index>
<index id="3">
<attributes>
<attribute id="item_org_id"/>
</attributes>
<attributes>
<attribute id="item_org_id"/>
</attributes>
</index>
</indexes>
</properties>

View File

@@ -1,5 +1,5 @@
<?php
// Copyright (C) 2010-2015 Combodo SARL
// Copyright (C) 2010-2012 Combodo SARL
//
// This file is part of iTop.
//
@@ -250,7 +250,6 @@ EOF
$('#attachment_plugin').trigger('remove_attachment', [att_id]);
return false; // Do not submit the form !
}
function ajaxFileUpload()
{
//starting setting some animation when the ajax starts and completes
@@ -348,7 +347,7 @@ EOF
$sIcon = utils::GetAbsoluteUrlAppRoot().AttachmentPlugIn::GetFileIcon($sFileName);
$sDownloadLink = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=download_document&class=Attachment&id='.$iAttId.'&field=contents';
$sPreview = $oDoc->IsPreviewAvailable() ? 'true' : 'false';
$oPage->add('<div class="attachment" id="display_attachment_'.$iAttId.'"><a data-preview="'.$sPreview.'" href="'.$sDownloadLink.'"><img src="'.$sIcon.'"><br/>'.$sFileName.'<input id="attachment_'.$iAttId.'" type="hidden" name="attachments[]" value="'.$iAttId.'"/></a><br/>&nbsp;<input id="btn_remove_'.$iAttId.'" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment('.$iAttId.');"/>&nbsp;</div>');
$oPage->add('<div class="attachment" id="display_attachment_'.$iAttId.'"><a data-preview="'.$sPreview.'" href="'.$sDownloadLink.'"><img src="'.$sIcon.'"><br/>'.$sFileName.'<input id="attachment_'+data.result.att_id+'" type="hidden" name="attachments[]" value="'.$iAttId.'"/></a><br/>&nbsp;<input id="btn_remove_'.$iAttId.'" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment('.$iAttId.');"/>&nbsp;</div>');
$oPage->add_ready_script("$('#attachment_plugin').trigger('add_attachment', [$iAttId, '".addslashes($sFileName)."']);");
}
}
@@ -369,7 +368,6 @@ $oPage->add_ready_script(
url: GetAbsoluteUrlModulesRoot()+'itop-attachments/ajax.attachment.php',
formData: { operation: 'add', temp_id: '$sTempId', obj_class: '$sClass' },
dataType: 'json',
pasteZone: null, // Don't accept files via Chrome's copy/paste
done: function (e, data) {
if(typeof(data.result.error) != 'undefined')
{
@@ -385,7 +383,7 @@ $oPage->add_ready_script(
{
$('#display_attachment_'+data.result.att_id).hover( function() { $(this).children(':button').toggleClass('btn_hidden'); } );
}
$('#attachment_plugin').trigger('add_attachment', [data.result.att_id, data.result.msg]);
$('#attachment_plugin').trigger('add_attachment', [data.result.att_id, data.msg]);
}
}
},
@@ -471,8 +469,7 @@ EOF
}
$oPage->add('</fieldset>');
$sPreviewNotAvailable = addslashes(Dict::S('Attachments:PreviewNotAvailable'));
$iMaxWidth = MetaModel::GetModuleSetting('itop-attachments', 'preview_max_width', 290);
$oPage->add_ready_script("$(document).tooltip({ items: '.attachment a', position: { my: 'left top', at: 'right top', using: function( position, feedback ) { $( this ).css( position ); }}, content: function() { if ($(this).attr('data-preview') == 'true') { return('<img style=\"max-width:{$iMaxWidth}px\" src=\"'+$(this).attr('href')+'\"></img>');} else { return '$sPreviewNotAvailable'; }}});");
$oPage->add_ready_script("$(document).tooltip({ items: '.attachment a', position: { my: 'left top', at: 'right top', using: function( position, feedback ) { $( this ).css( position ); }}, content: function() { if ($(this).attr('data-preview') == 'true') { return('<img style=\"max-width:290px\" src=\"'+$(this).attr('href')+'\"></img>');} else { return '$sPreviewNotAvailable'; }}});");
}
protected static function UpdateAttachments($oObject, $oChange = null)

View File

@@ -19,11 +19,11 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-attachments/2.1.0',
'itop-attachments/1.0.0',
array(
// Identification
//
'label' => 'Tickets Attachments',
'label' => 'Tickets attachments',
'category' => 'business',
// Setup
@@ -64,7 +64,6 @@ SetupWebPage::AddModule(
'settings' => array(
'allowed_classes' => array('Ticket'), // List of classes for which to manage "Attachments"
'position' => 'relations', // Where to display the attachments: relations | properties
'preview_max_width' => 290,
),
)
);

View File

@@ -1,48 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author LinProfs <info@linprofs.com>
*
* Linux & Open Source Professionals
* http://www.linprofs.com
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Attachments:TabTitle_Count' => 'Bijlagen (%1$d)',
'Attachments:EmptyTabTitle' => 'Bijlagen',
'Attachments:FieldsetTitle' => 'Bijlagen',
'Attachments:DeleteBtn' => 'Verwijder',
'Attachments:History_File_Added' => 'Bijlage %1$s toegevoegd.',
'Attachments:History_File_Removed' => 'Bijlage %1$s verwijderd.',
'Attachments:AddAttachment' => 'Voeg bijlage toe: ',
'Attachments:UploadNotAllowedOnThisSystem' => 'Bestand upload is NIET toegestaan op dit systeem.',
'Attachment:Max_Go' => '(Maximum bestandsgrootte: %1$s Go)',
'Attachment:Max_Mo' => '(Maximum bestandsgrootte: %1$s Mo)',
'Attachment:Max_Ko' => '(Maximum bestandsgrootte: %1$s Ko)',
'Attachments:NoAttachment' => 'Geen bijlage. ',
'Attachments:PreviewNotAvailable' => 'Een voorbeeld is niet beschikbaar voor dit type bijlage.',
'Class:Attachment' => 'Bijlage',
'Class:Attachment+' => '',
));
?>

View File

@@ -1,181 +0,0 @@
<?php
// Copyright (C) 2013-2016 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/>
/**
* Backup from an interactive session
*
* @copyright Copyright (C) 2013-2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
require_once(__DIR__.'/../../approot.inc.php');
require_once(APPROOT.'/application/application.inc.php');
require_once(APPROOT.'/application/webpage.class.inc.php');
require_once(APPROOT.'/application/ajaxwebpage.class.inc.php');
require_once(APPROOT.'core/mutex.class.inc.php');
try
{
$sOperation = utils::ReadParam('operation', '');
switch($sOperation)
{
case 'backup':
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$oPage = new ajax_page("");
$oPage->no_cache();
$oPage->SetContentType('text/html');
if (utils::GetConfig()->Get('demo_mode'))
{
$oPage->add("<div data-error-stimulus=\"Error\">Sorry, iTop is in <b>demonstration mode</b>: the feature is disabled.</div>");
}
else
{
try
{
set_time_limit(0);
$oBB = new BackupExec(APPROOT.'data/backups/manual/', 0 /*iRetentionCount*/);
$sRes = $oBB->Process(time() + 36000); // 10 hours to complete should be sufficient!
}
catch (Exception $e)
{
$oPage->p('Error: '.$e->getMessage());
}
}
$oPage->output();
break;
case 'restore_get_token':
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
$oPage = new ajax_page("");
$oPage->no_cache();
$oPage->SetContentType('text/html');
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
$oRestoreMutex = new iTopMutex('restore.'.$sEnvironment);
if (!$oRestoreMutex->IsLocked())
{
$sFile = utils::ReadParam('file', '', false, 'raw_data');
$sToken = str_replace(' ', '', (string)microtime());
$sTokenFile = APPROOT.'/data/restore.'.$sToken.'.tok';
file_put_contents($sTokenFile, $sFile);
$oPage->add_ready_script(
<<<EOF
$("#restore_token").val('$sToken');
EOF
);
}
else
{
$oPage->p(Dict::S('bkp-restore-running'));
}
$oPage->output();
break;
case 'restore_exec':
require_once(APPROOT."setup/runtimeenv.class.inc.php");
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/setup/backup.class.inc.php');
require_once(dirname(__FILE__).'/dbrestore.class.inc.php');
IssueLog::Enable(APPROOT.'log/error.log');
$oPage = new ajax_page("");
$oPage->no_cache();
$oPage->SetContentType('text/html');
if (utils::GetConfig()->Get('demo_mode'))
{
$oPage->add("<div data-error-stimulus=\"Error\">Sorry, iTop is in <b>demonstration mode</b>: the feature is disabled.</div>");
}
else
{
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
$oRestoreMutex = new iTopMutex('restore.'.$sEnvironment);
IssueLog::Info("Backup Restore - Acquiring the LOCK 'restore.$sEnvironment'");
$oRestoreMutex->Lock();
IssueLog::Info('Backup Restore - LOCK acquired, executing...');
try
{
set_time_limit(0);
// Get the file and destroy the token (single usage)
$sToken = utils::ReadParam('token', '', false, 'raw_data');
$sTokenFile = APPROOT.'/data/restore.'.$sToken.'.tok';
$sFile = file_get_contents($sTokenFile);
unlink($sTokenFile);
$sMySQLBinDir = utils::ReadParam('mysql_bindir', '', false, 'raw_data');
$sDBHost = utils::ReadParam('db_host', '', false, 'raw_data');
$sDBUser = utils::ReadParam('db_user', '', false, 'raw_data');
$sDBPwd = utils::ReadParam('db_pwd', '', false, 'raw_data');
$sDBName = utils::ReadParam('db_name', '', false, 'raw_data');
$sDBSubName = utils::ReadParam('db_subname', '', false, 'raw_data');
$oDBRS = new DBRestore($sDBHost, $sDBUser, $sDBPwd, $sDBName, $sDBSubName);
$oDBRS->SetMySQLBinDir($sMySQLBinDir);
$sBackupDir = APPROOT.'data/backups/';
$sBackupFile = $sBackupDir.$sFile;
$sRes = $oDBRS->RestoreFromZip($sBackupFile, $sEnvironment);
IssueLog::Info('Backup Restore - Done, releasing the LOCK');
$oRestoreMutex->Unlock();
}
catch (Exception $e)
{
$oRestoreMutex->Unlock();
$oPage->p('Error: '.$e->getMessage());
}
}
$oPage->output();
break;
case 'download':
require_once(APPROOT.'/application/startup.inc.php');
require_once(APPROOT.'/application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
if (utils::GetConfig()->Get('demo_mode'))
{
throw new Exception('iTop is in demonstration mode: the feature is disabled');
}
$sFile = utils::ReadParam('file', '', false, 'raw_data');
$oBackup = new DBBackupScheduled();
$sBackupDir = APPROOT.'data/backups/';
$oBackup->DownloadBackup($sBackupDir.$sFile);
break;
}
}
catch (Exception $e)
{
IssueLog::Error($e->getMessage());
}
?>

View File

@@ -1,54 +0,0 @@
# Parameters file for backup.php and check-backup.php
#
# Usage:
# backup.php --param_file=<this file>[,<another one>]
# or
# http://.../itop-backup/backup.php?param_file=<this file>[,<another one>]
#
# If a parameter is given both in the file and in the arguments,
# then the value given as argument is retained
#
# Note: most of the default values provided here should work fine
# if you have created sample data with the setup program
# MySQL coming with Easy PHP (Windows)
mysql_bindir = C:\Program Files\EasyPHP-5.3.6.0\mysql\bin
# Authentication
auth_user = admin
auth_pwd = admin
# Target file - path and filename (optional)
#
# Formatting rules:
# %Y-%m-%d => 2011-01-25... see PHP documentation of strftime()
# Placeholders:
# __HOST__ MySQL server
# __DB__ Database name
# __SUBNAME__ Tables prefix
#
backup_file = /var/log/__DB__-%Y-%m-%d
# Check thresholds (check-backup.php)
#
check_size_min = 20000 # bytes
check_size_reduction_max = 10 # percentage
# Ticket creation (check-backup.php)
#
# If the backup has failed, a ticket will be created
# This process relies on the SOAP service "CreateIncident"
#
# Root URL of an instance of iTop, into which the ticket will be created
check_ticket_itop = http://localhost/myiTop
# Any of the above paramaters are mandatory
check_ticket_login = admin # must have the right to create an Incident Ticket
check_ticket_pwd = admin
check_ticket_title = Backup check failed
check_ticket_customer = Demo
check_ticket_service = Computers and peripherals
check_ticket_service_subcategory = Repair
check_ticket_workgroup = Hardware support
check_ticket_impacted_server = dbserver1.demo.com

View File

@@ -1,200 +0,0 @@
<?php
// Copyright (C) 2014 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
require_once(__DIR__.'/../../approot.inc.php');
require_once(APPROOT.'application/application.inc.php');
require_once(APPROOT.'application/webpage.class.inc.php');
require_once(APPROOT.'application/csvpage.class.inc.php');
require_once(APPROOT.'application/clipage.class.inc.php');
require_once(APPROOT.'application/ajaxwebpage.class.inc.php');
require_once(APPROOT.'core/log.class.inc.php');
require_once(APPROOT.'application/startup.inc.php');
class MyDBBackup extends DBBackup
{
protected function LogInfo($sMsg)
{
$this->oPage->p($sMsg);
}
protected function LogError($sMsg)
{
$this->oPage->p('Error: '.$sMsg);
ToolsLog::Error($sMsg);
}
protected $oPage;
public function __construct($oPage)
{
$this->oPage = $oPage;
parent::__construct();
}
}
/**
* Checks if a parameter (possibly empty) was specified when calling this page
*/
function CheckParam($sParamName)
{
global $argv;
if (isset($_REQUEST[$sParamName])) return true; // HTTP parameter either GET or POST
if (!is_array($argv)) return false;
foreach($argv as $sArg)
{
if ($sArg == '--'.$sParamName) return true; // Empty command line parameter, long unix style
if ($sArg == $sParamName) return true; // Empty command line parameter, Windows style
if ($sArg == '-'.$sParamName) return true; // Empty command line parameter, short unix style
if (preg_match('/^--'.$sParamName.'=(.*)$/', $sArg, $aMatches)) return true; // Command parameter with a value
}
return false;
}
function Usage($oP)
{
$oP->p('Perform a backup of the iTop database by running mysqldump');
$oP->p('Parameters:');
if (utils::IsModeCLI())
{
$oP->p('auth_user: login, must be administrator');
$oP->p('auth_pwd: ...');
}
$oP->p('backup_file [optional]: name of the file to store the backup into. Follows the PHP strftime format spec. The following placeholders are available: __HOST__, __DB__, __SUBNAME__');
$oP->p('simulate [optional]: set to check the name of the file that would be created');
$oP->p('mysql_bindir [optional]: specify the path for mysqldump');
if (utils::IsModeCLI())
{
$oP->p('Example: php -q backup.php --auth_user=admin --auth_pwd=myPassw0rd');
$oP->p('Known limitation: the current directory must be the directory of backup.php');
}
else
{
$oP->p('Example: .../backup.php?backup_file=/tmp/backup.__DB__-__SUBNAME__.%Y-%m');
}
}
function ExitError($oP, $sMessage)
{
ToolsLog::Error($sMessage);
$oP->p($sMessage);
$oP->output();
exit;
}
function ReadMandatoryParam($oP, $sParam)
{
$sValue = utils::ReadParam($sParam, null, true /* Allow CLI */, 'raw_data');
if (is_null($sValue))
{
ExitError($oP, "ERROR: Missing argument '$sParam'");
}
return trim($sValue);
}
/////////////////////////////////
// Main program
set_time_limit(0);
if (utils::IsModeCLI())
{
$oP = new CLIPage("iTop - Database Backup");
}
else
{
$oP = new WebPage("iTop - Database Backup");
}
try
{
utils::UseParamFile();
}
catch(Exception $e)
{
ExitError($oP, $e->GetMessage());
}
if (utils::IsModeCLI())
{
$oP->p(date('Y-m-d H:i:s')." - running backup utility");
$sAuthUser = ReadMandatoryParam($oP, 'auth_user');
$sAuthPwd = ReadMandatoryParam($oP, 'auth_pwd');
$bDownloadBackup = false;
if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd))
{
UserRights::Login($sAuthUser); // Login & set the user's language
}
else
{
ExitError($oP, "Access restricted or wrong credentials ('$sAuthUser')");
}
}
else
{
require_once(APPROOT.'application/loginwebpage.class.inc.php');
LoginWebPage::DoLogin(); // Check user rights and prompt if needed
$bDownloadBackup = utils::ReadParam('download', false);
}
if (!UserRights::IsAdministrator())
{
ExitError($oP, "Access restricted to administors");
}
if (CheckParam('?') || CheckParam('h') || CheckParam('help'))
{
Usage($oP);
$oP->output();
exit;
}
$sDefaultBackupFileName = SetupUtils::GetTmpDir().'/'."__DB__-%Y-%m-%d";
$sBackupFile = utils::ReadParam('backup_file', $sDefaultBackupFileName, true, 'raw_data');
// Interpret strftime specifications (like %Y) and database placeholders
$oBackup = new MyDBBackup($oP);
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
$sBackupFile = $oBackup->MakeName($sBackupFile);
$sZipArchiveFile = $sBackupFile.'.zip';
$bSimulate = utils::ReadParam('simulate', false, true);
$res = false;
if ($bSimulate)
{
$oP->p("Simulate: would create file '$sZipArchiveFile'");
}
elseif (MetaModel::GetConfig()->Get('demo_mode'))
{
$oP->p("Sorry, iTop is in demonstration mode: the feature is disabled");
}
else
{
$oBackup->CreateZip($sZipArchiveFile);
}
if ($res && $bDownloadBackup)
{
$oBackup->DownloadBackup($sZipArchiveFile);
}
$oP->output();
?>

View File

@@ -1,267 +0,0 @@
<?php
// Copyright (C) 2014 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Purpose: check that the backup has been successfully executed
// this script is aimed at being invoked in CLI mode only
// Developer's notes:
// Duplicated code: sys_get_temp_dir, the computation of the target filename, etc.
// Recommended usage in CRON
// /usr/bin/php -q /var/www/combodo/modules/itop-backup/backup.php --backup_file=/home/backups/combodo-crm-%Y-%m-%d
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
require_once(__DIR__.'/../../approot.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/core/config.class.inc.php');
function ReadMandatoryParam($sParam)
{
$value = utils::ReadParam($sParam, null, true /* Allow CLI */, 'raw_data');
if (is_null($value))
{
throw new Exception("Missing argument '$sParam'");
}
return $value;
}
if (!function_exists('sys_get_temp_dir'))
{
// Based on http://www.phpit.net/
// article/creating-zip-tar-archives-dynamically-php/2/
function sys_get_temp_dir()
{
// Try to get from environment variable
if (!empty($_ENV['TMP']))
{
return realpath($_ENV['TMP']);
}
else if (!empty($_ENV['TMPDIR']))
{
return realpath($_ENV['TMPDIR']);
}
else if (!empty($_ENV['TEMP']))
{
return realpath($_ENV['TEMP']);
}
// Detect by creating a temporary file
else
{
// Try to use system's temporary directory
// as random name shouldn't exist
$temp_file = tempnam(md5(uniqid(rand(), TRUE)), '');
if ($temp_file)
{
$temp_dir = realpath(dirname($temp_file));
unlink($temp_file);
return $temp_dir;
}
else
{
return FALSE;
}
}
}
}
function MakeArchiveFileName($iRefTime = null)
{
$sDefaultBackupFileName = sys_get_temp_dir().'/'."__DB__-%Y-%m-%d";
$sBackupFile = utils::ReadParam('backup_file', $sDefaultBackupFileName, true, 'raw_data');
$oConfig = new Config(APPCONF.'production/config-itop.php');
$sBackupFile = str_replace('__HOST__', $oConfig->GetDBHost(), $sBackupFile);
$sBackupFile = str_replace('__DB__', $oConfig->GetDBName(), $sBackupFile);
$sBackupFile = str_replace('__SUBNAME__', $oConfig->GetDBSubName(), $sBackupFile);
if (is_null($iRefTime))
{
$sBackupFile = strftime($sBackupFile);
}
else
{
$sBackupFile = strftime($sBackupFile, $iRefTime);
}
return $sBackupFile.'.zip';
}
function RaiseAlarm($sMessage)
{
echo "$sMessage\n";
try
{
$sTicketLogin = ReadMandatoryParam('check_ticket_login');
$sTicketPwd = ReadMandatoryParam('check_ticket_pwd');
$sTicketTitle = ReadMandatoryParam('check_ticket_title');
$sTicketCustomer = ReadMandatoryParam('check_ticket_customer');
$sTicketService = ReadMandatoryParam('check_ticket_service');
$sTicketSubcategory = ReadMandatoryParam('check_ticket_service_subcategory');
$sTicketWorkgroup = ReadMandatoryParam('check_ticket_workgroup');
$sTicketImpactedServer = ReadMandatoryParam('check_ticket_impacted_server');
}
catch (Exception $e)
{
echo "The ticket could not be created: ".$e->GetMessage()."\n";
return;
}
$sMessage = "Server: [[Server:".$sTicketImpactedServer."]]\n".$sMessage;
require_once(APPROOT.'webservices/itopsoaptypes.class.inc.php');
//$sItopRootDefault = 'http'.((isset($_SERVER['HTTPS']) && ($_SERVER['HTTPS']!='off')) ? 's' : '').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/../..';
//$sItopRoot = utils::ReadParam('check_ticket_itop', $sItopRootDefault);
$sItopRoot = ReadMandatoryParam('check_ticket_itop');
$sWsdlUri = $sItopRoot.'/webservices/itop.wsdl.php';
//$sWsdlUri .= '?service_category=';
$aSOAPMapping = SOAPMapping::GetMapping();
ini_set("soap.wsdl_cache_enabled","0");
$oSoapClient = new SoapClient(
$sWsdlUri,
array(
'trace' => 1,
'classmap' => $aSOAPMapping, // defined in itopsoaptypes.class.inc.php
)
);
try
{
$oRes = $oSoapClient->CreateIncidentTicket
(
$sTicketLogin, /* login */
$sTicketPwd, /* password */
$sTicketTitle, /* title */
$sMessage, /* description */
null, /* caller */
new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', $sTicketCustomer))), /* customer */
new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', $sTicketService))), /* service */
new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', $sTicketSubcategory))), /* service subcategory */
'', /* product */
new SOAPExternalKeySearch(array(new SOAPSearchCondition('name', $sTicketWorkgroup))), /* workgroup */
array(
new SOAPLinkCreationSpec(
'Server',
array(new SOAPSearchCondition('name', $sTicketImpactedServer)),
array()
),
), /* impacted cis */
'1', /* impact */
'1' /* urgency */
);
}
catch(Exception $e)
{
echo "The ticket could not be created: SOAP Exception = '".$e->getMessage()."'\n";
}
//echo "<pre>\n";
//print_r($oRes);
//echo "</pre>\n";
if ($oRes->status)
{
$sTicketName = $oRes->result[0]->values[1]->value;
echo "Created ticket: $sTicketName\n";
}
else
{
echo "ERROR: Failed to create the ticket in target iTop ($sItopRoot)\n";
foreach ($oRes->errors->messages as $oMessage)
{
echo $oMessage->text."\n";
}
}
}
//////////
// Main
try
{
utils::UseParamFile();
}
catch(Exception $e)
{
echo "Error: ".$e->GetMessage()."\n";
exit;
}
$sZipArchiveFile = MakeArchiveFileName();
echo date('Y-m-d H:i:s')." - Checking file: $sZipArchiveFile\n";
if (file_exists($sZipArchiveFile))
{
if ($aStat = stat($sZipArchiveFile))
{
$iSize = (int) $aStat['size'];
$iMIN = utils::ReadParam('check_size_min', 0);
if ($iSize > $iMIN)
{
echo "Found the archive\n";
$sOldArchiveFile = MakeArchiveFileName(time() - 86400); // yesterday's archive
if (file_exists($sOldArchiveFile))
{
if ($aOldStat = stat($sOldArchiveFile))
{
echo "Comparing its size with older file: $sOldArchiveFile\n";
$iOldSize = (int) $aOldStat['size'];
$fVariationPercent = 100 * ($iSize - $iOldSize) / $iOldSize;
$sVariation = round($fVariationPercent, 2)." percent(s)";
$iREDUCTIONMAX = utils::ReadParam('check_size_reduction_max');
if ($fVariationPercent < -$iREDUCTIONMAX)
{
RaiseAlarm("Backup file '$sZipArchiveFile' changed by $sVariation, expecting a reduction limited to $iREDUCTIONMAX percents of the original size");
}
elseif ($fVariationPercent < 0)
{
echo "Size variation: $sVariation (the maximum allowed reduction is $iREDUCTIONMAX) \n";
}
else
{
echo "The archive grew by: $sVariation\n";
}
}
}
}
else
{
RaiseAlarm("Backup file '$sZipArchiveFile' too small (Found: $iSize, while expecting $iMIN bytes)");
}
}
else
{
RaiseAlarm("Failed to stat backup file '$sZipArchiveFile'");
}
}
else
{
RaiseAlarm("Missing backup file '$sZipArchiveFile'");
}
?>

View File

@@ -1,129 +0,0 @@
<?php
// Copyright (C) 2014 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 DBRestore extends DBBackup
{
protected function LogInfo($sMsg)
{
//IssueLog::Info('non juste info: '.$sMsg);
}
protected function LogError($sMsg)
{
IssueLog::Error($sMsg);
}
protected function LoadDatabase($sDataFile)
{
$this->LogInfo("Loading data onto $this->sDBHost/$this->sDBName(suffix:'$this->sDBSubName')");
// Just to check the connection to the DB (more accurate than getting the retcode of mysql)
$oMysqli = $this->DBConnect();
$sHost = self::EscapeShellArg($this->sDBHost);
$sUser = self::EscapeShellArg($this->sDBUser);
$sPwd = self::EscapeShellArg($this->sDBPwd);
$sDBName = self::EscapeShellArg($this->sDBName);
if (empty($this->sMySQLBinDir))
{
$sMySQLExe = 'mysql';
}
else
{
$sMySQLExe = '"'.$this->sMySQLBinDir.'/mysql"';
}
if (is_null($this->iDBPort))
{
$sPortOption = '';
}
else
{
$sPortOption = '--port='.$this->iDBPort.' ';
}
$sDataFileEscaped = self::EscapeShellArg($sDataFile);
$sCommand = "$sMySQLExe --default-character-set=utf8 --host=$sHost $sPortOption --user=$sUser --password=$sPwd $sDBName <$sDataFileEscaped 2>&1";
$sCommandDisplay = "$sMySQLExe --default-character-set=utf8 --host=$sHost $sPortOption --user=xxxx --password=xxxx $sDBName <$sDataFileEscaped 2>&1";
// Now run the command for real
$this->LogInfo("Executing command: $sCommandDisplay");
$aOutput = array();
$iRetCode = 0;
exec($sCommand, $aOutput, $iRetCode);
foreach($aOutput as $sLine)
{
$this->LogInfo("mysql said: $sLine");
}
if ($iRetCode != 0)
{
$this->LogError("Failed to execute: $sCommandDisplay. The command returned:$iRetCode");
foreach($aOutput as $sLine)
{
$this->LogError("mysql said: $sLine");
}
if (count($aOutput) == 1)
{
$sMoreInfo = trim($aOutput[0]);
}
else
{
$sMoreInfo = "Check the log file '".realpath(APPROOT.'/log/error.log')."' for more information.";
}
throw new BackupException("Failed to execute mysql: ".$sMoreInfo);
}
}
public function RestoreFromZip($sZipFile, $sEnvironment = 'production')
{
$this->LogInfo("Starting restore of ".basename($sZipFile));
$oZip = new ZipArchive();
$res = $oZip->open($sZipFile);
// Load the database
//
$sDataDir = tempnam(SetupUtils::GetTmpDir(), 'itop-');
unlink($sDataDir); // I need a directory, not a file...
SetupUtils::builddir($sDataDir); // Here is the directory
$oZip->extractTo($sDataDir, 'itop-dump.sql');
$sDataFile = $sDataDir.'/itop-dump.sql';
$this->LoadDatabase($sDataFile);
unlink($sDataFile);
// Update the code
//
$sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml';
if ($oZip->locateName('delta.xml') !== false)
{
// Extract and rename delta.xml => <env>.delta.xml;
file_put_contents($sDeltaFile, $oZip->getFromName('delta.xml'));
}
else
{
@unlink($sDeltaFile);
}
$sConfigFile = APPROOT.'conf/'.$sEnvironment.'/config-itop.php';
@chmod($sConfigFile, 0770); // Allow overwriting the file
$oZip->extractTo(APPROOT.'conf/'.$sEnvironment, 'config-itop.php');
@chmod($sConfigFile, 0444); // Read-only
$oEnvironment = new RunTimeEnvironment($sEnvironment);
$oEnvironment->CompileFrom($sEnvironment);
}
}

View File

@@ -1,48 +0,0 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 Combodo
* @license http://opensource.org/licenses/AGPL-3.0
* @author Robert Jaehne <robert.jaehne@itomig.de>
*/
Dict::Add('DE DE', 'German', 'Deutsch', array(
'bkp-backup-running' => 'Backup wird durchgeführt. Bitte warten ...',
'bkp-restore-running' => 'Wiederherstellung läuft. Bitte warten ...',
'Menu:BackupStatus' => 'Geplante Backups',
'bkp-status-title' => 'Geplante Backups',
'bkp-status-checks' => 'Einstellungen und Prüfungen',
'bkp-mysqldump-ok' => 'mysqldump ist vorhanden: %1$s',
'bkp-mysqldump-notfound' => 'mysqldump wurde nicht gefunden: %1$s - Stellen sie sicher, das er eingespielt und im Pfad verfügbar ist oder editieren sie die Konfigurationsdatei um das MySQL bindir anzupassen.',
'bkp-mysqldump-issue' => 'mysqldump konnte nicht eingespielt werden (retcode=%1$d): Stellen sie sicher, das er eingespielt und im Pfad verfügbar ist oder editieren sie die Konfigurationsdatei um das MySQL bindir anzupassen.',
'bkp-missing-dir' => 'Zielverzeichniss %1$s nicht gefunden',
'bkp-free-disk-space' => '<b>%1$s frei</b> in %2$s',
'bkp-dir-not-writeable' => '%1$s ist nicht schreibbar',
'bkp-wrong-format-spec' => 'Die verwendete Definition zur Formatierung von Dateinamen ist nicht korrekt (%1$s). Die Standard-Definition %2$s wird verwendet',
'bkp-name-sample' => 'Backup-Dateien werden abhängig von Datum, Zeit und Datenbank-Identifier erstellt. Beispiel: %1$s',
'bkp-week-days' => 'Backups werden <b>jeden %1$s um %2$s durchgeführt</b>',
'bkp-retention' => 'Mindestens <b>%1$d Backups werden im Zielverzeichniss vorgehalten</b>',
'bkp-next-to-delete' => 'Wird gelöscht, wenn das nächste Backup angelegt wird (unter Einstellungen "Menge vorhalten")',
'bkp-table-file' => 'Datei',
'bkp-table-file+' => 'Nur Dateien mit der Endung .zip werden als Backup-Dateien berücksichtigt.',
'bkp-table-size' => 'Grösse',
'bkp-table-size+' => '',
'bkp-table-actions' => 'Aktionen',
'bkp-table-actions+' => '',
'bkp-status-backups-auto' => 'Geplante Backups',
'bkp-status-backups-manual' => 'Manuelle Backups',
'bkp-status-backups-none' => 'Kein Backup vorhanden',
'bkp-next-backup' => 'Das nächste Backup wird am <b>%1$s</b> (%2$s) um %3$s durchgeführt',
'bkp-button-backup-now' => 'Backup läuft!',
'bkp-button-restore-now' => 'Wiederherstellen!',
'bkp-confirm-backup' => 'Bitte bestätigen sie, dass sie jetzt ein Backup erstellen wollen now.',
'bkp-confirm-restore' => 'Bitte bestätigen sie, dass sie mit Backup %1$s eine Wiederherstellung durchführen wollen.',
'bkp-wait-backup' => 'Bitte warten, bis das Backup abgeschlossen ist ...',
'bkp-wait-restore' => 'Bitte warten, bis die Wiederherstellung abgeschlossen ist ...',
'bkp-success-restore' => 'Wiederherstellung erfolgreich.',
));

View File

@@ -1,46 +0,0 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 Combodo
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('EN US', 'English', 'English', array(
'bkp-backup-running' => 'A backup is running. Please wait...',
'bkp-restore-running' => 'A restore is running. Please wait...',
'Menu:BackupStatus' => 'Scheduled Backups',
'bkp-status-title' => 'Scheduled Backups',
'bkp-status-checks' => 'Settings and checks',
'bkp-mysqldump-ok' => 'mysqldump is present: %1$s',
'bkp-mysqldump-notfound' => 'mysqldump could not be found: %1$s - Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir.',
'bkp-mysqldump-issue' => 'mysqldump could not be executed (retcode=%1$d): Please make sure it is installed and in the path, or edit the configuration file to tune mysql_bindir',
'bkp-missing-dir' => 'The target directory %1$s count not be found',
'bkp-free-disk-space' => '<b>%1$s free</b> in %2$s',
'bkp-dir-not-writeable' => '%1$s is not writeable',
'bkp-wrong-format-spec' => 'The current specification to format the file names is wrong (%1$s). A default specification will apply: %2$s',
'bkp-name-sample' => 'Backup files are named depending on DB identifiers, date and time. Example: %1$s',
'bkp-week-days' => 'Backups will occur <b>every %1$s at %2$s</b>',
'bkp-retention' => 'At most <b>%1$d backup files will be kept</b> in the target directory.',
'bkp-next-to-delete' => 'Will be deleted when the next backup occurs (see the setting "retention_count")',
'bkp-table-file' => 'File',
'bkp-table-file+' => 'Only files having the extension .zip are considered as being backup files',
'bkp-table-size' => 'Size',
'bkp-table-size+' => '',
'bkp-table-actions' => 'Actions',
'bkp-table-actions+' => '',
'bkp-status-backups-auto' => 'Scheduled backups',
'bkp-status-backups-manual' => 'Manual backups',
'bkp-status-backups-none' => 'No backup yet',
'bkp-next-backup' => 'The next backup will occur on <b>%1$s</b> (%2$s) at %3$s',
'bkp-button-backup-now' => 'Backup now!',
'bkp-button-restore-now' => 'Restore!',
'bkp-confirm-backup' => 'Please confirm that you do request the backup to occur right now.',
'bkp-confirm-restore' => 'Please confirm that you do want to restore the backup %1$s.',
'bkp-wait-backup' => 'Please wait for the backup to complete...',
'bkp-wait-restore' => 'Please wait for the restore to complete...',
'bkp-success-restore' => 'Restore successfully completed.',
));
?>

View File

@@ -1,46 +0,0 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 Combodo
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('FR FR', 'French', 'Français', array(
'bkp-backup-running' => 'Une sauvegarde est en cours. Veuillez patienter...',
'bkp-restore-running' => 'Une restauration des données est en cours. Veuillez patienter...',
'Menu:BackupStatus' => 'Sauvegarde automatique',
'bkp-status-title' => 'Sauvegarde automatique',
'bkp-status-checks' => 'Réglages et vérifications',
'bkp-mysqldump-ok' => 'mysqldump est installé: %1$s',
'bkp-mysqldump-notfound' => 'mysqldump n\'a pas été trouvé: %1$s - Veuillez vous assurer que les outils mysql sont installés et qu\'ils sont accessibles en ligne de commande, ou bien éditez le fichier de configuration pour en donner le chemin via mysql_bindir.',
'bkp-mysqldump-issue' => 'mysqldump n\'a pas pu être exécuté (code de retour: %1$d). Veuillez vérifier que les outils mysql sont installés et qu\'ils sont accessibles en ligne de commande, ou bien éditez le fichier de configuration pour en donner le chemin via mysql_bindir.',
'bkp-missing-dir' => 'Le répertoire cible \'%1$s\' n\'existe pas ou ne peut pas être lu.',
'bkp-free-disk-space' => 'Vous disposez de <b>%1$s d\'espace disque</b> sur %2$s',
'bkp-dir-not-writeable' => 'Le répertoire cible \'%1$s\' n\'est pas accessible en écriture.',
'bkp-wrong-format-spec' => 'La spécification de format pour le nom des sauvegarde est incorrecte (%1$s). La spécification par défaut sera appliquée: %2$s',
'bkp-name-sample' => 'Les fichiers de sauvegardes seront nommés en fonction de la base, la date et l\'heure. Par exemple: %1$s',
'bkp-week-days' => 'Les sauvegardes seront effectuées <b>tous les %1$s à %2$s</b>',
'bkp-retention' => 'Au plus <b>%1$d fichiers de sauvegardes seront conservés</b> dans le répertoire cible.',
'bkp-next-to-delete' => 'Sera effacé lors de la prochaine sauvegarde (Cf. réglage "retention_count")',
'bkp-table-file' => 'Fichier',
'bkp-table-file+' => 'Seuls les fichiers ayant l\'extension .zip sont considérés comme étant des fichiers de sauvegarde',
'bkp-table-size' => 'Taille',
'bkp-table-size+' => '',
'bkp-table-actions' => 'Actions',
'bkp-table-actions+' => '',
'bkp-status-backups-auto' => 'Sauvegardes automatiques',
'bkp-status-backups-manual' => 'Sauvegardes manuelles',
'bkp-status-backups-none' => 'Aucune sauvegarde n\'a été faite jusqu\' à présent.',
'bkp-next-backup' => 'La prochaine sauvegarde aura lieu <b>%1$s</b> (%2$s) à %3$s',
'bkp-button-backup-now' => 'Sauvegarder maintenant !',
'bkp-button-restore-now' => 'Restaurer !',
'bkp-confirm-backup' => 'Veuillez confirmer que vous souhaiter effectuer une sauvegarde maintenant.',
'bkp-confirm-restore' => 'Veuillez confirmer que vous souhaiter effectuer la restauration de \'%1$s\' maintenant.',
'bkp-wait-backup' => 'Sauvegarde en cours...',
'bkp-wait-restore' => 'Restauration des données en cours...',
'bkp-success-restore' => 'Restauration des données terminée.',
));
?>

View File

@@ -1,286 +0,0 @@
<?php
// Copyright (C) 2014-2016 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
require_once(APPROOT.'setup/setuputils.class.inc.php');
require_once(APPROOT.'setup/backup.class.inc.php');
require_once(APPROOT.'core/mutex.class.inc.php');
define('BACKUP_DEFAULT_FORMAT', '__DB__-%Y-%m-%d_%H_%M');
class BackupHandler extends ModuleHandlerAPI
{
public static function OnMetaModelStarted()
{
try
{
$oRestoreMutex = new iTopMutex('restore.'.utils::GetCurrentEnvironment());
if ($oRestoreMutex->IsLocked())
{
IssueLog::Info(__class__.'::'.__function__.' A user is trying to use iTop while a restore is running. The requested page is in read-only mode.');
MetaModel::GetConfig()->Set('access_mode', ACCESS_READONLY, 'itop-backup');
MetaModel::GetConfig()->Set('access_message', ' - '.dict::S('bkp-restore-running'), 'itop-backup');
}
}
catch(Exception $e)
{
IssueLog::Error(__class__.'::'.__function__.' Failed to check if a backup/restore is running: '.$e->getMessage());
}
}
}
class DBBackupScheduled extends DBBackup
{
protected function LogInfo($sMsg)
{
static $bDebug = null;
if ($bDebug == null)
{
$bDebug = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'debug', false);
}
if ($bDebug)
{
echo $sMsg."\n";
}
}
protected function LogError($sMsg)
{
static $bDebug = null;
if ($bDebug == null)
{
$bDebug = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'debug', false);
}
IssueLog::Error($sMsg);
if ($bDebug)
{
echo 'Error: '.$sMsg."\n";
}
}
/**
* List and order by date the backups in the given directory
* Note: the algorithm is currently based on the file modification date... because there is no "creation date" in general
*/
public function ListFiles($sBackupDir)
{
$aFiles = array();
$aTimes = array();
foreach(glob($sBackupDir.'*.zip') as $sFilePath)
{
$aFiles[] = $sFilePath;
$aTimes[] = filemtime($sFilePath); // unix time
}
array_multisort($aTimes, $aFiles);
return $aFiles;
}
}
class BackupExec implements iScheduledProcess
{
protected $sBackupDir;
protected $iRetentionCount;
/**
* Constructor
* @param sBackupDir string Target directory, defaults to APPROOT/data/backups/auto
* @param iRetentionCount int Rotation (default to the value given in the configuration file 'retentation_count') set to 0 to disable this feature
*/
public function __construct($sBackupDir = null, $iRetentionCount = null)
{
if (is_null($sBackupDir))
{
$this->sBackupDir = APPROOT.'data/backups/auto/';
}
else
{
$this->sBackupDir = $sBackupDir;
}
if (is_null($iRetentionCount))
{
$this->iRetentionCount = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'retention_count', 5);
}
else
{
$this->iRetentionCount = $iRetentionCount;
}
}
public function Process($iUnixTimeLimit)
{
$oMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
$oMutex->Lock();
try
{
// Make sure the target directory exists
SetupUtils::builddir($this->sBackupDir);
$oBackup = new DBBackupScheduled();
// Eliminate files exceeding the retention setting
//
if ($this->iRetentionCount > 0)
{
$aFiles = $oBackup->ListFiles($this->sBackupDir);
while (count($aFiles) >= $this->iRetentionCount)
{
$sFileToDelete = array_shift($aFiles);
unlink($sFileToDelete);
if (file_exists($sFileToDelete))
{
// Ok, do not loop indefinitely on this
break;
}
}
}
// Do execute the backup
//
$oBackup->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
$sBackupFile = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'file_name_format', '__DB__-%Y-%m-%d_%H_%M');
$sName = $oBackup->MakeName($sBackupFile);
if ($sName == '')
{
$sName = $oBackup->MakeName(BACKUP_DEFAULT_FORMAT);
}
$sZipFile = $this->sBackupDir.$sName.'.zip';
$sSourceConfigFile = APPCONF.utils::GetCurrentEnvironment().'/'.ITOP_CONFIG_FILE;
$oBackup->CreateZip($sZipFile, $sSourceConfigFile);
}
catch (Exception $e)
{
$oMutex->Unlock();
throw $e;
}
$oMutex->Unlock();
return "Created the backup: $sZipFile";
}
/*
Interpret current setting for the week days
@returns array of int (monday = 1)
*/
public function InterpretWeekDays()
{
static $aWEEKDAYTON = array('monday' => 1, 'tuesday' => 2, 'wednesday' => 3, 'thursday' => 4, 'friday' => 5, 'saturday' => 6, 'sunday' => 7);
$aDays = array();
$sWeekDays = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'week_days', 'monday, tuesday, wednesday, thursday, friday');
if ($sWeekDays != '')
{
$aWeekDaysRaw = explode(',', $sWeekDays);
foreach ($aWeekDaysRaw as $sWeekDay)
{
$sWeekDay = strtolower(trim($sWeekDay));
if (array_key_exists($sWeekDay, $aWEEKDAYTON))
{
$aDays[] = $aWEEKDAYTON[$sWeekDay];
}
else
{
throw new Exception("'itop-backup: wrong format for setting 'week_days' (found '$sWeekDay')");
}
}
}
if (count($aDays) == 0)
{
throw new Exception("'itop-backup: missing setting 'week_days'");
}
$aDays = array_unique($aDays);
sort($aDays);
return $aDays;
}
/*
Gives the exact time at which the process must be run next time
@returns DateTime
*/
public function GetNextOccurrence()
{
$bEnabled = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'enabled', true);
if (!$bEnabled)
{
$oRet = new DateTime('3000-01-01');
}
else
{
// 1st - Interpret the list of days as ordered numbers (monday = 1)
//
$aDays = $this->InterpretWeekDays();
// 2nd - Find the next active week day
//
$sBackupTime = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'time', '23:30');
if (!preg_match('/[0-2][0-9]:[0-5][0-9]/', $sBackupTime))
{
throw new Exception("'itop-backup: wrong format for setting 'time' (found '$sBackupTime')");
}
$oNow = new DateTime();
$iNextPos = false;
for ($iDay = $oNow->format('N') ; $iDay <= 7 ; $iDay++)
{
$iNextPos = array_search($iDay, $aDays);
if ($iNextPos !== false)
{
if (($iDay > $oNow->format('N')) || ($oNow->format('H:i') < $sBackupTime))
{
break;
}
}
}
// 3rd - Compute the result
//
if ($iNextPos === false)
{
// Jump to the first day within the next week
$iFirstDayOfWeek = $aDays[0];
$iDayMove = $oNow->format('N') - $iFirstDayOfWeek;
$oRet = clone $oNow;
$oRet->modify('-'.$iDayMove.' days');
$oRet->modify('+1 weeks');
}
else
{
$iNextDayOfWeek = $aDays[$iNextPos];
$iMove = $iNextDayOfWeek - $oNow->format('N');
$oRet = clone $oNow;
$oRet->modify('+'.$iMove.' days');
}
list($sHours, $sMinutes) = explode(':', $sBackupTime);
$oRet->setTime((int)$sHours, (int) $sMinutes);
}
return $oRet;
}
}
class ItopBackup extends ModuleHandlerAPI
{
public static function OnMenuCreation()
{
if (UserRights::IsAdministrator())
{
$oAdminMenu = new MenuGroup('AdminTools', 80 /* fRank */);
new WebPageMenuNode('BackupStatus', utils::GetAbsoluteUrlModulePage('itop-backup', 'status.php'), $oAdminMenu->GetIndex(), 15 /* fRank */);
}
}
}

View File

@@ -1,60 +0,0 @@
<?php
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-backup/2.1.1',
array(
// Identification
//
'label' => 'Backup utilities',
'category' => 'Application management',
// Setup
//
'dependencies' => array(
),
'mandatory' => true,
'visible' => false,
// Components
//
'datamodel' => array(
'main.itop-backup.php',
//'model.itop-backup.php',
),
'webservice' => array(
//'webservices.itop-backup.php',
),
'dictionary' => array(
'en.dict.itop-backup.php',
'fr.dict.itop-backup.php',
//'de.dict.itop-backup.php',
),
'data.struct' => array(
//'data.struct.itop-backup.xml',
),
'data.sample' => array(
//'data.sample.itop-backup.xml',
),
// Documentation
//
'doc.manual_setup' => '',
'doc.more_information' => '',
// Default settings
//
'settings' => array(
'mysql_bindir' => '',
'week_days' => 'monday, tuesday, wednesday, thursday, friday',
'time' => '23:30',
//'file_name_format' => '__DB__-%Y-%m-%d_%H_%M',
'retention_count' => 5,
'enabled' => true,
'debug' => false
),
)
);
?>

View File

@@ -1,401 +0,0 @@
<?php
// Copyright (C) 2016 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/>
/**
* Monitor the backup
*
* @copyright Copyright (C) 2016 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
require_once(__DIR__.'/../../approot.inc.php');
require_once(APPROOT.'application/application.inc.php');
require_once(APPROOT.'application/itopwebpage.class.inc.php');
require_once(APPROOT.'application/startup.inc.php');
require_once(APPROOT.'application/loginwebpage.class.inc.php');
/////////////////////////////////////////////////////////////////////
// Main program
//
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
//$sOperation = utils::ReadParam('operation', 'menu');
//$oAppContext = new ApplicationContext();
$oP = new iTopWebPage(Dict::S('bkp-status-title'));
$oP->set_base(utils::GetAbsoluteUrlAppRoot().'pages/');
try
{
$oP->add("<h1>".Dict::S('bkp-status-title')."</h1>");
if (MetaModel::GetConfig()->Get('demo_mode'))
{
$oP->add("<div class=\"header_message message_info\">iTop is in <b>demonstration mode</b>: the feature is disabled.</div>");
}
$sImgOk = '<img src="../images/validation_ok.png"> ';
$sImgError = '<img src="../images/validation_error.png"> ';
$oP->add("<fieldset>");
$oP->add("<legend>".Dict::S('bkp-status-checks')."</legend>");
// Availability of mysqldump
//
$sMySQLBinDir = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '');
$sMySQLBinDir = utils::ReadParam('mysql_bindir', $sMySQLBinDir, true);
if (empty($sMySQLBinDir))
{
$sMySQLDump = 'mysqldump';
}
else
{
//echo 'Info - Found mysql_bindir: '.$sMySQLBinDir;
$sMySQLDump = '"'.$sMySQLBinDir.'/mysqldump"';
}
$sCommand = "$sMySQLDump -V 2>&1";
$aOutput = array();
$iRetCode = 0;
exec($sCommand, $aOutput, $iRetCode);
if ($iRetCode == 0)
{
$sMySqlDump = $sImgOk.Dict::Format("bkp-mysqldump-ok", $aOutput[0]);
}
elseif ($iRetCode == 1)
{
$sMySqlDump = $sImgError.Dict::Format("bkp-mysqldump-notfound", implode(' ', $aOutput));
}
else
{
$sMySqlDump = $sImgError.Dict::Format("bkp-mysqldump-issue", $iRetCode);
}
foreach($aOutput as $sLine)
{
//echo 'Info - mysqldump -V said: '.$sLine;
}
$oP->p($sMySqlDump);
// Destination directory
//
// Make sure the target directory exists and is writeable
$sBackupDir = APPROOT.'data/backups/';
SetupUtils::builddir($sBackupDir);
if (!is_dir($sBackupDir))
{
$oP->p($sImgError.Dict::Format('bkp-missing-dir', $sBackupDir));
}
else
{
$oP->p(Dict::Format('bkp-free-disk-space', SetupUtils::HumanReadableSize(SetupUtils::CheckDiskSpace($sBackupDir)), $sBackupDir));
if (!is_writable($sBackupDir))
{
$oP->p($sImgError.Dict::Format('bkp-dir-not-writeable', $sBackupDir));
}
}
$sBackupDirAuto = $sBackupDir.'auto/';
SetupUtils::builddir($sBackupDirAuto);
$sBackupDirManual = $sBackupDir.'manual/';
SetupUtils::builddir($sBackupDirManual);
// Wrong format
//
$sBackupFile = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'file_name_format', BACKUP_DEFAULT_FORMAT);
$oBackup = new DBBackupScheduled();
$sZipName = $oBackup->MakeName($sBackupFile);
if ($sZipName == '')
{
$oP->p($sImgError.Dict::Format('bkp-wrong-format-spec', $sBackupFile, BACKUP_DEFAULT_FORMAT));
}
else
{
$oP->p(Dict::Format('bkp-name-sample', $sZipName));
}
// Week Days
//
$aWeekDayToString = array(
1 => Dict::S('DayOfWeek-Monday'),
2 => Dict::S('DayOfWeek-Tuesday'),
3 => Dict::S('DayOfWeek-Wednesday'),
4 => Dict::S('DayOfWeek-Thursday'),
5 => Dict::S('DayOfWeek-Friday'),
6 => Dict::S('DayOfWeek-Saturday'),
7 => Dict::S('DayOfWeek-Sunday')
);
$aDayLabels = array();
$oBackupExec = new BackupExec();
foreach ($oBackupExec->InterpretWeekDays() as $iDay)
{
$aDayLabels[] = $aWeekDayToString[$iDay];
}
$sDays = implode(', ', $aDayLabels);
$sBackupTime = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'time', '23:30');
$oP->p(Dict::Format('bkp-week-days', $sDays, $sBackupTime));
$iRetention = MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'retention_count', 5);
$oP->p(Dict::Format('bkp-retention', $iRetention));
$oP->add("</fieldset>");
// List of backups
//
$aFiles = $oBackup->ListFiles($sBackupDirAuto);
$aFilesToDelete = array();
while (count($aFiles) > $iRetention - 1)
{
$aFilesToDelete[] = array_shift($aFiles);
}
$oRestoreMutex = new iTopMutex('restore.'.utils::GetCurrentEnvironment());
if ($oRestoreMutex->IsLocked())
{
$sDisableRestore = 'disabled="disabled"';
}
else
{
$sDisableRestore = '';
}
// 1st table: list the backups made in the background
//
$aDetails = array();
foreach ($oBackup->ListFiles($sBackupDirAuto) as $sBackupFile)
{
$sFileName = basename($sBackupFile);
$sFilePath = 'auto/'.$sFileName;
if (MetaModel::GetConfig()->Get('demo_mode'))
{
$sName = $sFileName;
}
else
{
$sAjax = utils::GetAbsoluteUrlModulePage('itop-backup', 'ajax.backup.php', array('operation' => 'download', 'file' => $sFilePath));
$sName = "<a href=\"$sAjax\">".$sFileName.'</a>';
}
$sSize = SetupUtils::HumanReadableSize(filesize($sBackupFile));
$sConfirmRestore = addslashes(Dict::Format('bkp-confirm-restore', $sFileName));
$sFileEscaped = addslashes($sFilePath);
$sRestoreBtn = '<button class="restore" onclick="LaunchRestoreNow(\''.$sFileEscaped.'\', \''.$sConfirmRestore.'\');" '.$sDisableRestore.'>'.Dict::S('bkp-button-restore-now').'</button>';
if (in_array($sBackupFile, $aFilesToDelete))
{
$aDetails[] = array('file' => $sName.' <span class="next_to_delete" title="'.Dict::S('bkp-next-to-delete').'">*</span>', 'size' => $sSize, 'actions' => $sRestoreBtn);
}
else
{
$aDetails[] = array('file' => $sName, 'size' => $sSize, 'actions' => $sRestoreBtn);
}
}
$aConfig = array(
'file' => array('label' => Dict::S('bkp-table-file'), 'description' => Dict::S('bkp-table-file+')),
'size' => array('label' => Dict::S('bkp-table-size'), 'description' => Dict::S('bkp-table-size+')),
'actions' => array('label' => Dict::S('bkp-table-actions'), 'description' => Dict::S('bkp-table-actions+')),
);
$oP->add("<fieldset>");
$oP->add("<legend>".Dict::S('bkp-status-backups-auto')."</legend>");
if (count($aDetails) > 0)
{
$oP->add('<div style="max-height:400px; overflow: auto;">');
$oP->table($aConfig, array_reverse($aDetails));
$oP->add('</div>');
}
else
{
$oP->p(Dict::S('bkp-status-backups-none'));
}
$oP->add("</fieldset>");
// 2nd table: list the backups made manually
//
$aDetails = array();
foreach ($oBackup->ListFiles($sBackupDirManual) as $sBackupFile)
{
$sFileName = basename($sBackupFile);
$sFilePath = 'manual/'.$sFileName;
if (MetaModel::GetConfig()->Get('demo_mode'))
{
$sName = $sFileName;
}
else
{
$sAjax = utils::GetAbsoluteUrlModulePage('itop-backup', 'ajax.backup.php', array('operation' => 'download', 'file' => $sFilePath));
$sName = "<a href=\"$sAjax\">".$sFileName.'</a>';
}
$sSize = SetupUtils::HumanReadableSize(filesize($sBackupFile));
$sConfirmRestore = addslashes(Dict::Format('bkp-confirm-restore', $sFileName));
$sFileEscaped = addslashes($sFilePath);
$sRestoreBtn = '<button class="restore" onclick="LaunchRestoreNow(\''.$sFileEscaped.'\', \''.$sConfirmRestore.'\');" '.$sDisableRestore.'>'.Dict::S('bkp-button-restore-now').'</button>';
$aDetails[] = array('file' => $sName, 'size' => $sSize, 'actions' => $sRestoreBtn);
}
$aConfig = array(
'file' => array('label' => Dict::S('bkp-table-file'), 'description' => Dict::S('bkp-table-file+')),
'size' => array('label' => Dict::S('bkp-table-size'), 'description' => Dict::S('bkp-table-size+')),
'actions' => array('label' => Dict::S('bkp-table-actions'), 'description' => Dict::S('bkp-table-actions+')),
);
$oP->add("<fieldset>");
$oP->add("<legend>".Dict::S('bkp-status-backups-manual')."</legend>");
if (count($aDetails) > 0)
{
$oP->add('<div style="max-height:400px; overflow: auto;">');
$oP->table($aConfig, array_reverse($aDetails));
$oP->add('</div>');
}
else
{
$oP->p(Dict::S('bkp-status-backups-none'));
}
$oP->add("</fieldset>");
// Ongoing operation ?
//
$oBackupMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
if ($oBackupMutex->IsLocked())
{
$oP->p(Dict::S('bkp-backup-running'));
}
$oRestoreMutex = new iTopMutex('restore.'.utils::GetCurrentEnvironment());
if ($oRestoreMutex->IsLocked())
{
$oP->p(Dict::S('bkp-restore-running'));
}
// Do backup now
//
$oBackupExec = new BackupExec();
$oNext = $oBackupExec->GetNextOccurrence();
$oP->p(Dict::Format('bkp-next-backup', $aWeekDayToString[$oNext->Format('N')], $oNext->Format('Y-m-d'), $oNext->Format('H:i')));
$oP->p('<button onclick="LaunchBackupNow();">'.Dict::S('bkp-button-backup-now').'</button>');
$oP->add('<div id="backup_success" class="header_message message_ok" style="display: none;"></div>');
$oP->add('<div id="backup_errors" class="header_message message_error" style="display: none;"></div>');
$oP->add('<input type="hidden" name="restore_token" id="restore_token"/>');
$sConfirmBackup = addslashes(Dict::S('bkp-confirm-backup'));
$sPleaseWaitBackup = addslashes(Dict::S('bkp-wait-backup'));
$sPleaseWaitRestore = addslashes(Dict::S('bkp-wait-restore'));
$sRestoreDone = addslashes(Dict::S('bkp-success-restore'));
$sMySQLBinDir = addslashes(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', ''));
$sDBHost = addslashes(MetaModel::GetConfig()->GetDBHost());
$sDBUser = addslashes(MetaModel::GetConfig()->GetDBUser());
$sDBPwd = addslashes(MetaModel::GetConfig()->GetDBPwd());
$sDBName = addslashes(MetaModel::GetConfig()->GetDBName());
$sDBSubName = addslashes(MetaModel::GetConfig()->GetDBSubName());
$sEnvironment = addslashes(utils::GetCurrentEnvironment());
$oP->add_script(
<<<EOF
function LaunchBackupNow()
{
$('#backup_success').hide();
$('#backup_errors').hide();
if (confirm('$sConfirmBackup'))
{
$.blockUI({ message: '<h1><img src="../images/indicator.gif" /> $sPleaseWaitBackup</h1>' });
var oParams = {};
oParams.operation = 'backup';
$.post(GetAbsoluteUrlModulePage('itop-backup', 'ajax.backup.php'), oParams, function(data){
if (data.search(/error|exceptio|notice|warning/i) != -1)
{
$('#backup_errors').html(data);
$('#backup_errors').show();
}
else
{
window.location.reload();
}
$.unblockUI();
});
}
}
function LaunchRestoreNow(sBackupFile, sConfirmationMessage)
{
if (confirm(sConfirmationMessage))
{
$.blockUI({ message: '<h1><img src="../images/indicator.gif" /> $sPleaseWaitRestore</h1>' });
$('#backup_success').hide();
$('#backup_errors').hide();
var oParams = {};
oParams.operation = 'restore_get_token';
oParams.file = sBackupFile;
$.post(GetAbsoluteUrlModulePage('itop-backup', 'ajax.backup.php'), oParams, function(data){
// Get the value of restore_token
$('#backup_errors').append(data);
var oParams = {};
oParams.operation = 'restore_exec';
oParams.token = $("#restore_token").val();
oParams.mysql_bindir = '$sMySQLBinDir';
oParams.db_host = '$sDBHost';
oParams.db_user = '$sDBUser';
oParams.db_pwd = '$sDBPwd';
oParams.db_name = '$sDBName';
oParams.db_subname = '$sDBSubName';
oParams.environment = '$sEnvironment';
if (oParams.token.length > 0)
{
$.post(GetAbsoluteUrlModulePage('itop-backup', 'ajax.backup.php'), oParams, function(data){
if (data.search(/error|exceptio|notice|warning/i) != -1)
{
$('#backup_success').hide();
$('#backup_errors').html(data);
$('#backup_errors').show();
}
else
{
$('#backup_errors').hide();
$('#backup_success').html('$sRestoreDone');
$('#backup_success').show();
}
$.unblockUI();
});
}
else
{
$('button.restore').attr('disabled', 'disabled');
$.unblockUI();
}
});
}
}
EOF
);
if (MetaModel::GetConfig()->Get('demo_mode'))
{
$oP->add_ready_script("$('button').attr('disabled', 'disabled').attr('title', 'Disabled in demonstration mode')");
}
}
catch(Exception $e)
{
$oP->p('<b>'.$e->getMessage().'</b>');
}
$oP->output();
?>

View File

@@ -1,10 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<classes>
<class id="lnkVirtualDeviceToVolume" _delta="define">
<parent>cmdbAbstractObject</parent>
<properties>
<is_link>1</is_link>
<category>bizmodel,configmgmt</category>
<abstract>false</abstract>
<key_type>autoincrement</key_type>
@@ -12,6 +11,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="volume_id"/>
</attributes>
@@ -91,4 +91,4 @@
</presentation>
</class>
</classes>
</itop_design>
</itop_design>

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-bridge-virtualization-storage/2.1.0',
'itop-bridge-virtualization-storage/2.0.0',
array(
// Identification
//

View File

@@ -1,247 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:RoutineChange' => 'Rutine Ændring',
'Class:RoutineChange+' => '',
'Class:RoutineChange/Stimulus:ev_assign' => 'Tildel',
'Class:RoutineChange/Stimulus:ev_assign+' => '',
'Class:RoutineChange/Stimulus:ev_reopen' => 'Genåben',
'Class:RoutineChange/Stimulus:ev_reopen+' => '',
'Class:RoutineChange/Stimulus:ev_plan' => 'Planlæg',
'Class:RoutineChange/Stimulus:ev_plan+' => '',
'Class:RoutineChange/Stimulus:ev_approve' => 'Godkend',
'Class:RoutineChange/Stimulus:ev_approve+' => '',
'Class:RoutineChange/Stimulus:ev_replan' => 'Genplanlæg',
'Class:RoutineChange/Stimulus:ev_replan+' => '',
'Class:RoutineChange/Stimulus:ev_notapprove' => 'Godkend Ikke',
'Class:RoutineChange/Stimulus:ev_notapprove+' => '',
'Class:RoutineChange/Stimulus:ev_implement' => 'Implementer',
'Class:RoutineChange/Stimulus:ev_implement+' => '',
'Class:RoutineChange/Stimulus:ev_monitor' => 'Overvåg',
'Class:RoutineChange/Stimulus:ev_monitor+' => '',
'Class:RoutineChange/Stimulus:ev_finish' => 'Afslut',
'Class:RoutineChange/Stimulus:ev_finish+' => '',
'Class:NormalChange' => 'Normal Ændring',
'Class:NormalChange+' => '',
'Class:NormalChange/Attribute:acceptance_date' => 'Dato for accept',
'Class:NormalChange/Attribute:acceptance_date+' => '',
'Class:NormalChange/Attribute:acceptance_comment' => 'Kommentar til accept',
'Class:NormalChange/Attribute:acceptance_comment+' => '',
'Class:NormalChange/Stimulus:ev_validate' => 'Valider',
'Class:NormalChange/Stimulus:ev_validate+' => '',
'Class:NormalChange/Stimulus:ev_reject' => 'Afslå',
'Class:NormalChange/Stimulus:ev_reject+' => '',
'Class:NormalChange/Stimulus:ev_assign' => 'Tildel',
'Class:NormalChange/Stimulus:ev_assign+' => '',
'Class:NormalChange/Stimulus:ev_reopen' => 'Genåben',
'Class:NormalChange/Stimulus:ev_reopen+' => '',
'Class:NormalChange/Stimulus:ev_plan' => 'Planlæg',
'Class:NormalChange/Stimulus:ev_plan+' => '',
'Class:NormalChange/Stimulus:ev_approve' => 'Godkend',
'Class:NormalChange/Stimulus:ev_approve+' => '',
'Class:NormalChange/Stimulus:ev_replan' => 'Genplanlæg',
'Class:NormalChange/Stimulus:ev_replan+' => '',
'Class:NormalChange/Stimulus:ev_notapprove' => 'Godkent Ikke',
'Class:NormalChange/Stimulus:ev_notapprove+' => '',
'Class:NormalChange/Stimulus:ev_implement' => 'Implementer',
'Class:NormalChange/Stimulus:ev_implement+' => '',
'Class:NormalChange/Stimulus:ev_monitor' => 'Overvåg',
'Class:NormalChange/Stimulus:ev_monitor+' => '',
'Class:NormalChange/Stimulus:ev_finish' => 'Afslut',
'Class:NormalChange/Stimulus:ev_finish+' => '',
'Class:EmergencyChange' => 'Emergency Ændring',
'Class:EmergencyChange+' => '',
'Class:EmergencyChange/Stimulus:ev_assign' => 'Tildel',
'Class:EmergencyChange/Stimulus:ev_assign+' => '',
'Class:EmergencyChange/Stimulus:ev_reopen' => 'Genåben',
'Class:EmergencyChange/Stimulus:ev_reopen+' => '',
'Class:EmergencyChange/Stimulus:ev_plan' => 'Planlæg',
'Class:EmergencyChange/Stimulus:ev_plan+' => '',
'Class:EmergencyChange/Stimulus:ev_approve' => 'Godkend',
'Class:EmergencyChange/Stimulus:ev_approve+' => '',
'Class:EmergencyChange/Stimulus:ev_replan' => 'Genplanlæg',
'Class:EmergencyChange/Stimulus:ev_replan+' => '',
'Class:EmergencyChange/Stimulus:ev_notapprove' => 'Godkend Ikke',
'Class:EmergencyChange/Stimulus:ev_notapprove+' => '',
'Class:EmergencyChange/Stimulus:ev_implement' => 'Implementer',
'Class:EmergencyChange/Stimulus:ev_implement+' => '',
'Class:EmergencyChange/Stimulus:ev_monitor' => 'Overvåg',
'Class:EmergencyChange/Stimulus:ev_monitor+' => '',
'Class:EmergencyChange/Stimulus:ev_finish' => 'Afslut',
'Class:EmergencyChange/Stimulus:ev_finish+' => '',
'Menu:ChangeManagement' => 'Change Management',
'Menu:Change:Overview' => 'Oversigt',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'Ny Change',
'Menu:NewChange+' => 'Opret en ny Change ticket',
'Menu:SearchChanges' => 'Søg efter Changes',
'Menu:SearchChanges+' => 'Søg efter Change Tickets',
'Menu:Change:Shortcuts' => 'Genveje',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes, som afventer accept',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes, som afventer godkendelse',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Offene Changes',
'Menu:Changes+' => 'Alle åbne Changes',
'Menu:MyChanges' => 'Mine Changes',
'Menu:MyChanges+' => 'Changes som er tildelt mig',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes de sidste 7 dage, efter kategori',
'UI-ChangeManagementOverview-Last-7-days' => 'Antal Changes de sidste 7 dage',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes de sidste 7 dage efter type',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Changes de sidste 7 dage efter status',
'Class:Change' => 'Change',
'Class:Change+' => '',
'Class:Change/Attribute:status' => 'Status',
'Class:Change/Attribute:status+' => '',
'Class:Change/Attribute:status/Value:new' => 'Ny',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:validated' => 'Valideret',
'Class:Change/Attribute:status/Value:validated+' => '',
'Class:Change/Attribute:status/Value:rejected' => 'Afslået',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:assigned' => 'Tildelt',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:plannedscheduled' => 'Planlagt og tidssat',
'Class:Change/Attribute:status/Value:plannedscheduled+' => '',
'Class:Change/Attribute:status/Value:approved' => 'Godkendt',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:notapproved' => 'Ikke Godkendt',
'Class:Change/Attribute:status/Value:notapproved+' => '',
'Class:Change/Attribute:status/Value:implemented' => 'Implementeret',
'Class:Change/Attribute:status/Value:implemented+' => '',
'Class:Change/Attribute:status/Value:monitored' => 'Overvåget',
'Class:Change/Attribute:status/Value:monitored+' => '',
'Class:Change/Attribute:status/Value:closed' => 'Lukket',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:reason' => 'Årsag',
'Class:Change/Attribute:reason+' => '',
'Class:Change/Attribute:requestor_id' => 'Rekvirent',
'Class:Change/Attribute:requestor_id+' => '',
'Class:Change/Attribute:requestor_email' => 'Rekvirent e-mail',
'Class:Change/Attribute:requestor_email+' => '',
'Class:Change/Attribute:creation_date' => 'Oprettet dato',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:impact' => 'Indvirkning',
'Class:Change/Attribute:impact+' => '',
'Class:Change/Attribute:supervisor_group_id' => 'Supervisor-Team',
'Class:Change/Attribute:supervisor_group_id+' => '',
'Class:Change/Attribute:supervisor_group_name' => 'Supervisor-Teamnavn',
'Class:Change/Attribute:supervisor_group_name+' => '',
'Class:Change/Attribute:supervisor_id' => 'Supervisor',
'Class:Change/Attribute:supervisor_id+' => '',
'Class:Change/Attribute:supervisor_email' => 'Supervisor e-mail',
'Class:Change/Attribute:supervisor_email+' => '',
'Class:Change/Attribute:manager_group_id' => 'Manager-Team',
'Class:Change/Attribute:manager_group_id+' => '',
'Class:Change/Attribute:manager_group_name' => 'Manager-Team',
'Class:Change/Attribute:manager_group_name+' => '',
'Class:Change/Attribute:manager_id' => 'Manager',
'Class:Change/Attribute:manager_id+' => '',
'Class:Change/Attribute:manager_email' => 'Manager',
'Class:Change/Attribute:manager_email+' => '',
'Class:Change/Attribute:outage' => 'Nedetid',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => 'Nej',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => 'Ja',
'Class:Change/Attribute:outage/Value:yes+' => '',
'Class:Change/Attribute:fallback' => 'Fallback-Plan',
'Class:Change/Attribute:fallback+' => '',
'Class:Change/Attribute:parent_id' => 'Parent Change',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_name' => 'Parent Change Ref',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:related_request_list' => 'Relaterede Requests',
'Class:Change/Attribute:related_request_list+' => '',
'Class:Change/Attribute:related_problems_list' => 'Relaterede Problemer',
'Class:Change/Attribute:related_problems_list+' => '',
'Class:Change/Attribute:child_changes_list' => 'Afledte Changes',
'Class:Change/Attribute:child_changes_list+' => '',
'Class:Change/Attribute:parent_id_friendlyname' => 'Parent Friendly Name',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Attribute:parent_id_finalclass_recall' => 'Change-Type',
'Class:Change/Attribute:parent_id_finalclass_recall+' => '',
'Class:Change/Stimulus:ev_validate' => 'Valider',
'Class:Change/Stimulus:ev_validate+' => '',
'Class:Change/Stimulus:ev_reject' => 'Afslå',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_assign' => 'Tildel',
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_reopen' => 'Genåben',
'Class:Change/Stimulus:ev_reopen+' => '',
'Class:Change/Stimulus:ev_plan' => 'Planlæg',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_approve' => 'Godkend',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Stimulus:ev_replan' => 'Genplanlæg',
'Class:Change/Stimulus:ev_replan+' => '',
'Class:Change/Stimulus:ev_notapprove' => 'Afslå',
'Class:Change/Stimulus:ev_notapprove+' => '',
'Class:Change/Stimulus:ev_implement' => 'Implementer',
'Class:Change/Stimulus:ev_implement+' => '',
'Class:Change/Stimulus:ev_monitor' => 'Overvåg',
'Class:Change/Stimulus:ev_monitor+' => '',
'Class:Change/Stimulus:ev_finish' => 'Afslut',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:RoutineChange/Stimulus:ev_validate' => 'Valider',
'Class:RoutineChange/Stimulus:ev_validate+' => '',
'Class:RoutineChange/Stimulus:ev_reject' => 'Afslå',
'Class:RoutineChange/Stimulus:ev_reject+' => '',
'Class:ApprovedChange' => 'Godkendte Changes',
'Class:ApprovedChange+' => '',
'Class:ApprovedChange/Attribute:approval_date' => 'Dato for godkendelse',
'Class:ApprovedChange/Attribute:approval_date+' => '',
'Class:ApprovedChange/Attribute:approval_comment' => 'Kommentar til godkendelsen',
'Class:ApprovedChange/Attribute:approval_comment+' => '',
'Class:ApprovedChange/Stimulus:ev_validate' => 'Valider',
'Class:ApprovedChange/Stimulus:ev_validate+' => '',
'Class:ApprovedChange/Stimulus:ev_reject' => 'Afslå',
'Class:ApprovedChange/Stimulus:ev_reject+' => '',
'Class:ApprovedChange/Stimulus:ev_assign' => 'Tildel',
'Class:ApprovedChange/Stimulus:ev_assign+' => '',
'Class:ApprovedChange/Stimulus:ev_reopen' => 'Genåben',
'Class:ApprovedChange/Stimulus:ev_reopen+' => '',
'Class:ApprovedChange/Stimulus:ev_plan' => 'Planlæg',
'Class:ApprovedChange/Stimulus:ev_plan+' => '',
'Class:ApprovedChange/Stimulus:ev_approve' => 'Godkend',
'Class:ApprovedChange/Stimulus:ev_approve+' => '',
'Class:ApprovedChange/Stimulus:ev_replan' => 'Genplanlæg',
'Class:ApprovedChange/Stimulus:ev_replan+' => '',
'Class:ApprovedChange/Stimulus:ev_notapprove' => 'Tilbagekald godkendelse',
'Class:ApprovedChange/Stimulus:ev_notapprove+' => '',
'Class:ApprovedChange/Stimulus:ev_implement' => 'Implementer',
'Class:ApprovedChange/Stimulus:ev_implement+' => '',
'Class:ApprovedChange/Stimulus:ev_monitor' => 'Overvåg',
'Class:ApprovedChange/Stimulus:ev_monitor+' => '',
'Class:ApprovedChange/Stimulus:ev_finish' => 'Afslut',
'Class:ApprovedChange/Stimulus:ev_finish+' => '',
'Class:EmergencyChange/Stimulus:ev_validate' => 'Valider',
'Class:EmergencyChange/Stimulus:ev_validate+' => '',
'Class:EmergencyChange/Stimulus:ev_reject' => 'Afslå',
'Class:EmergencyChange/Stimulus:ev_reject+' => '',
));
?>

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-change-mgmt-itil/2.1.0',
'itop-change-mgmt-itil/2.0.0',
array(
// Identification
//

View File

@@ -1,115 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:Change' => 'Change',
'Class:Change+' => '',
'Class:Change/Attribute:status' => 'Status',
'Class:Change/Attribute:status+' => 'Status for emnet',
'Class:Change/Attribute:status/Value:new' => 'Ny',
'Class:Change/Attribute:status/Value:new+' => 'Opret ny',
'Class:Change/Attribute:status/Value:assigned' => 'Tildelt',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:planned' => 'Planlagt',
'Class:Change/Attribute:status/Value:planned+' => '',
'Class:Change/Attribute:status/Value:rejected' => 'Afslået',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:approved' => 'Godkendt',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:closed' => 'Lukket',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:category' => 'Kategori',
'Class:Change/Attribute:category+' => '',
'Class:Change/Attribute:category/Value:application' => 'Applikation',
'Class:Change/Attribute:category/Value:application+' => '',
'Class:Change/Attribute:category/Value:hardware' => 'Hardware',
'Class:Change/Attribute:category/Value:hardware+' => '',
'Class:Change/Attribute:category/Value:network' => 'Netværk',
'Class:Change/Attribute:category/Value:network+' => '',
'Class:Change/Attribute:category/Value:other' => 'Andet',
'Class:Change/Attribute:category/Value:other+' => '',
'Class:Change/Attribute:category/Value:software' => 'Software',
'Class:Change/Attribute:category/Value:software+' => '',
'Class:Change/Attribute:category/Value:system' => 'System',
'Class:Change/Attribute:category/Value:system+' => '',
'Class:Change/Attribute:reject_reason' => 'Årsag til afslag',
'Class:Change/Attribute:reject_reason+' => '',
'Class:Change/Attribute:changemanager_id' => 'Change Manager',
'Class:Change/Attribute:changemanager_id+' => '',
'Class:Change/Attribute:parent_id' => 'Parent Change',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:creation_date' => 'Oprettelsesdato',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:approval_date' => 'Godkendelsesdato',
'Class:Change/Attribute:approval_date+' => '',
'Class:Change/Attribute:fallback_plan' => 'Fallback-Plan',
'Class:Change/Attribute:fallback_plan+' => '',
'Class:Change/Attribute:related_request_list' => 'Relaterede Requests',
'Class:Change/Attribute:related_request_list+' => '',
'Class:Change/Attribute:child_changes_list' => 'Afledte Changes',
'Class:Change/Attribute:child_changes_list+' => '',
'Class:Change/Stimulus:ev_assign' => 'Tildel',
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_plan' => 'Planlæg',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_reject' => 'Afslåp',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_reopen' => 'Genåben',
'Class:Change/Stimulus:ev_reopen+' => '',
'Class:Change/Stimulus:ev_approve' => 'Godkend',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Stimulus:ev_finish' => 'Luk',
'Class:Change/Stimulus:ev_finish+' => '',
'Menu:ChangeManagement' => 'Change Management',
'Menu:Change:Overview' => 'Oversigt',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'Ny Change',
'Menu:NewChange+' => '',
'Menu:SearchChanges' => 'Søg efter Changes',
'Menu:SearchChanges+' => '',
'Menu:Change:Shortcuts' => 'Genveje',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes der afventer accept',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes der afventer godkendelse',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Åbne Changes',
'Menu:Changes+' => '',
'Menu:MyChanges' => 'Changes tildelt til mig',
'Menu:MyChanges+' => '',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes de sidste 7 dage efter kategori',
'UI-ChangeManagementOverview-Last-7-days' => 'Antal Changes i de sidste 7 dage',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes de sidste 7 dage efter type',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Changes de sidste 7 dage efter status',
'Class:Change/Attribute:changemanager_email' => 'Change Manager Email',
'Class:Change/Attribute:changemanager_email+' => '',
'Class:Change/Attribute:parent_name' => 'Parent Change ref',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:related_incident_list' => 'Relaterede Incidents',
'Class:Change/Attribute:related_incident_list+' => '',
'Class:Change/Attribute:parent_id_friendlyname' => 'Parent Change Friendly Name',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
));
?>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<classes>
<class id="Change" _delta="define">
<parent>Ticket</parent>
@@ -17,6 +17,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="ref"/>
</attributes>
@@ -37,12 +38,12 @@
<fields>
<field id="status" xsi:type="AttributeEnum">
<values>
<value id="new">new</value>
<value id="assigned">assigned</value>
<value id="planned">planned</value>
<value id="approved">approved</value>
<value id="closed">closed</value>
<value id="rejected">rejected</value>
<value>new</value>
<value>assigned</value>
<value>planned</value>
<value>approved</value>
<value>closed</value>
<value>rejected</value>
</values>
<sql>status</sql>
<default_value>new</default_value>
@@ -50,12 +51,12 @@
</field>
<field id="category" xsi:type="AttributeEnum">
<values>
<value id="hardware">hardware</value>
<value id="software">software</value>
<value id="system">system</value>
<value id="network">network</value>
<value id="application">application</value>
<value id="other">other</value>
<value>hardware</value>
<value>software</value>
<value>system</value>
<value>network</value>
<value>application</value>
<value>other</value>
</values>
<sql>category</sql>
<default_value>hardware</default_value>
@@ -106,8 +107,8 @@
</field>
<field id="outage" xsi:type="AttributeEnum">
<values>
<value id="yes">yes</value>
<value id="no">no</value>
<value>yes</value>
<value>no</value>
</values>
<sql>outage</sql>
<default_value>no</default_value>
@@ -144,23 +145,6 @@
</field>
</fields>
<lifecycle>
<highlight_scale>
<item id="approved">
<rank>1</rank>
<color>HIGHLIGHT_CLASS_NONE</color>
<icon>images/change-approved.png</icon>
</item>
<item id="rejected">
<rank>2</rank>
<color>HIGHLIGHT_CLASS_NONE</color>
<icon>images/change-rejected.png</icon>
</item>
<item id="closed">
<rank>3</rank>
<color>HIGHLIGHT_CLASS_NONE</color>
<icon>images/change-closed.png</icon>
</item>
</highlight_scale>
<attribute>status</attribute>
<stimuli>
<stimulus id="ev_assign" xsi:type="StimulusUserAction"/>
@@ -217,15 +201,21 @@
</attribute>
</flags>
<transitions>
<transition id="ev_assign">
<transition>
<stimulus>ev_assign</stimulus>
<target>assigned</target>
<actions/>
</transition>
</transitions>
</state>
<state id="assigned">
<inherit_flags_from>new</inherit_flags_from>
<flags>
<attribute id="ref">
<read_only/>
</attribute>
<attribute id="org_id">
<mandatory/>
</attribute>
<attribute id="team_id">
<mandatory/>
<must_prompt/>
@@ -234,22 +224,57 @@
<mandatory/>
<must_prompt/>
</attribute>
<attribute id="title">
<mandatory/>
</attribute>
<attribute id="description">
<mandatory/>
</attribute>
<attribute id="last_update">
<read_only/>
</attribute>
<attribute id="close_date">
<hidden/>
</attribute>
<attribute id="reject_reason">
<hidden/>
</attribute>
<attribute id="changemanager_id">
<mandatory/>
<must_prompt/>
</attribute>
<attribute id="caller_id"/>
<attribute id="creation_date">
<read_only/>
</attribute>
<attribute id="approval_date">
<hidden/>
</attribute>
<attribute id="outage">
<hidden/>
</attribute>
</flags>
<transitions>
<transition id="ev_plan">
<transition>
<stimulus>ev_plan</stimulus>
<target>planned</target>
<actions/>
</transition>
</transitions>
</state>
<state id="planned">
<inherit_flags_from>assigned</inherit_flags_from>
<flags>
<attribute id="ref">
<read_only/>
</attribute>
<attribute id="org_id">
<mandatory/>
</attribute>
<attribute id="title">
<mandatory/>
</attribute>
<attribute id="description">
<mandatory/>
</attribute>
<attribute id="start_date">
<mandatory/>
<must_prompt/>
@@ -258,6 +283,21 @@
<mandatory/>
<must_prompt/>
</attribute>
<attribute id="last_update">
<read_only/>
</attribute>
<attribute id="close_date">
<hidden/>
</attribute>
<attribute id="reject_reason">
<hidden/>
</attribute>
<attribute id="creation_date">
<read_only/>
</attribute>
<attribute id="approval_date">
<hidden/>
</attribute>
<attribute id="fallback_plan">
<mandatory/>
<must_prompt/>
@@ -265,41 +305,60 @@
<attribute id="caller_id">
<mandatory/>
</attribute>
<attribute id="team_id">
<mandatory/>
</attribute>
<attribute id="agent_id">
<mandatory/>
</attribute>
<attribute id="changemanager_id">
<mandatory/>
</attribute>
<attribute id="outage">
<mandatory/>
<must_prompt/>
</attribute>
</flags>
<transitions>
<transition id="ev_reject">
<transition>
<stimulus>ev_reject</stimulus>
<target>rejected</target>
<actions/>
</transition>
<transition id="ev_approve">
<transition>
<stimulus>ev_approve</stimulus>
<target>approved</target>
<actions>
<action>
<verb>SetCurrentDate</verb>
<params>
<param xsi:type="attcode">approval_date</param>
</params>
<verb>SetApprovalDate</verb>
</action>
<action>
<verb>Reset</verb>
<params>
<param xsi:type="attcode">reject_reason</param>
</params>
<verb>ResetRejectReason</verb>
</action>
</actions>
</transition>
</transitions>
</state>
<state id="rejected">
<highlight>
<code>rejected</code>
</highlight>
<inherit_flags_from>assigned</inherit_flags_from>
<flags>
<attribute id="ref">
<read_only/>
</attribute>
<attribute id="org_id">
<read_only/>
</attribute>
<attribute id="title">
<read_only/>
</attribute>
<attribute id="description">
<read_only/>
</attribute>
<attribute id="last_update">
<read_only/>
</attribute>
<attribute id="close_date">
<hidden/>
</attribute>
<attribute id="start_date">
<read_only/>
</attribute>
@@ -308,11 +367,32 @@
</attribute>
<attribute id="private_log">
<read_only/>
</attribute>
<attribute id="reject_reason">
<mandatory/>
<must_prompt/>
</attribute>
<attribute id="creation_date">
<read_only/>
</attribute>
<attribute id="approval_date">
<read_only/>
</attribute>
<attribute id="caller_id">
<read_only/>
</attribute>
<attribute id="team_id">
<read_only/>
</attribute>
<attribute id="agent_id">
<read_only/>
</attribute>
<attribute id="changemanager_id">
<read_only/>
</attribute>
<attribute id="private_log">
<read_only/>
</attribute>
<attribute id="fallback_plan">
<read_only/>
</attribute>
@@ -322,51 +402,23 @@
<attribute id="parent_id">
<read_only/>
</attribute>
<attribute id="org_id">
<read_only/>
</attribute>
<attribute id="title">
<read_only/>
</attribute>
<attribute id="description">
<read_only/>
</attribute>
<attribute id="reject_reason">
<mandatory/>
<must_prompt/>
</attribute>
<attribute id="approval_date">
<read_only/>
</attribute>
<attribute id="team_id">
<read_only/>
</attribute>
<attribute id="agent_id">
<read_only/>
</attribute>
<attribute id="changemanager_id">
<read_only/>
</attribute>
<attribute id="outage">
<read_only/>
</attribute>
</flags>
<transitions>
<transition id="ev_reopen">
<transition>
<stimulus>ev_reopen</stimulus>
<target>assigned</target>
<actions/>
</transition>
</transitions>
</state>
<state id="approved">
<highlight>
<code>approved</code>
</highlight>
<inherit_flags_from>planned</inherit_flags_from>
<flags>
<attribute id="private_log"/>
<attribute id="category"/>
<attribute id="parent_id"/>
<attribute id="ref">
<read_only/>
</attribute>
<attribute id="org_id">
<read_only/>
</attribute>
@@ -376,12 +428,21 @@
<attribute id="description">
<read_only/>
</attribute>
<attribute id="last_update">
<read_only/>
</attribute>
<attribute id="close_date">
<hidden/>
</attribute>
<attribute id="start_date">
<read_only/>
</attribute>
<attribute id="end_date">
<read_only/>
</attribute>
<attribute id="private_log">
<normal/>
</attribute>
<attribute id="reject_reason">
<read_only/>
</attribute>
@@ -403,37 +464,78 @@
<attribute id="changemanager_id">
<read_only/>
</attribute>
<attribute id="fallback_plan"/>
<attribute id="fallback_plan">
<normal/>
</attribute>
<attribute id="category">
<normal/>
</attribute>
<attribute id="parent_id">
<normal/>
</attribute>
<attribute id="outage">
<read_only/>
</attribute>
</flags>
<transitions>
<transition id="ev_finish">
<transition>
<stimulus>ev_finish</stimulus>
<target>closed</target>
<actions>
<action>
<verb>SetCurrentDate</verb>
<params>
<param xsi:type="attcode">close_date</param>
</params>
<verb>SetClosureDate</verb>
</action>
</actions>
</transition>
</transitions>
</state>
<state id="closed">
<highlight>
<code>closed</code>
</highlight>
<inherit_flags_from>approved</inherit_flags_from>
<flags>
<attribute id="ref">
<read_only/>
</attribute>
<attribute id="org_id">
<read_only/>
</attribute>
<attribute id="title">
<read_only/>
</attribute>
<attribute id="description">
<read_only/>
</attribute>
<attribute id="last_update">
<read_only/>
</attribute>
<attribute id="close_date">
<read_only/>
</attribute>
<attribute id="start_date">
<read_only/>
</attribute>
<attribute id="end_date">
<read_only/>
</attribute>
<attribute id="reject_reason">
<read_only/>
</attribute>
<attribute id="creation_date">
<read_only/>
</attribute>
<attribute id="approval_date">
<read_only/>
</attribute>
<attribute id="caller_id">
<read_only/>
</attribute>
<attribute id="team_id">
<read_only/>
</attribute>
<attribute id="agent_id">
<read_only/>
</attribute>
<attribute id="changemanager_id">
<read_only/>
</attribute>
<attribute id="private_log">
<read_only/>
</attribute>
@@ -446,6 +548,9 @@
<attribute id="parent_id">
<read_only/>
</attribute>
<attribute id="outage">
<read_only/>
</attribute>
</flags>
<transitions/>
</state>
@@ -453,10 +558,6 @@
</lifecycle>
<methods>
<method id="SetApprovalDate">
<comment><![CDATA[/**
* To be deprecated: use SetCurrentDate() instead
* @return void
*/]]></comment>
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
@@ -467,10 +568,6 @@
}]]></code>
</method>
<method id="ResetRejectReason">
<comment><![CDATA[/**
* To be deprecated: use SetCurrentDate() instead
* @return void
*/]]></comment>
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
@@ -481,10 +578,6 @@
}]]></code>
</method>
<method id="SetClosureDate">
<comment><![CDATA[/**
* To be deprecated: use SetCurrentDate() instead
* @return void
*/]]></comment>
<static>false</static>
<access>public</access>
<type>LifecycleAction</type>
@@ -540,6 +633,63 @@
$this->Set('last_update', time());
}]]></code>
</method>
<method id="GetIcon">
<comment>/**&#13;
* Get the icon representing this object&#13;
* @param boolean $bImgTag If true the result is a full IMG tag (or an emtpy string if no icon is defined)&#13;
* @return string Either the full IMG tag ($bImgTag == true) or just the path to the icon file&#13;
*/</comment>
<static>false</static>
<access>public</access>
<type>Overload-DBObject</type>
<code><![CDATA[ public function GetIcon($bImgTag = true)
{
$sStatus = $this->Get('status');
switch($this->GetState())
{
case 'approved':
case 'implemented':
case 'monitored':
$sIcon = self::MakeIconFromName('change-approved.png');
break;
case 'rejected':
case 'notapproved':
$sIcon = self::MakeIconFromName('change-rejected.png');
break;
case 'closed':
$sIcon = self::MakeIconFromName('change-closed.png');
break;
default:
$sIcon = MetaModel::GetClassIcon(get_class($this), $bImgTag);
}
return $sIcon;
}]]></code>
</method>
<method id="MakeIconFromName">
<static>true</static>
<access>protected</access>
<type>Overload-DBObject</type>
<code><![CDATA[ protected static function MakeIconFromName($sIconName, $bImgTag = true)
{
$sIcon = '';
if ($sIconName != '')
{
$sPath = '../env-'.utils::GetCurrentEnvironment().'/itop-change-mgmt/images/'.$sIconName;
if ($bImgTag)
{
$sIcon = "<img src=\"$sPath\" style=\"vertical-align:middle;\"/>";
}
else
{
$sIcon = $sPath;
}
}
return $sIcon;
}]]></code>
</method>
</methods>
<presentation>
<details>

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-change-mgmt/2.1.0',
'itop-change-mgmt/2.0.0',
array(
// Identification
//

View File

@@ -1,146 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author LinProfs <info@linprofs.com>
*
* Linux & Open Source Professionals
* http://www.linprofs.com
*
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
'Menu:ChangeManagement' => 'Change management',
'Menu:Change:Overview' => 'Overzicht',
'Menu:Change:Overview+' => '',
'Menu:NewChange' => 'Nieuwe change',
'Menu:NewChange+' => 'Maak een nieuwe change ticket aan',
'Menu:SearchChanges' => 'Zoek voor changes',
'Menu:SearchChanges+' => 'Zoek voor change tickets',
'Menu:Change:Shortcuts' => 'Snelkoppelingen',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes die nog acceptatie vereisen',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes die nog goedkeuring vereisen',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'Alle open changes',
'Menu:MyChanges' => 'Changes toegewezen aan mij',
'Menu:MyChanges+' => 'Changes toegewezen door mij (als Agent)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes per categorie van de afgelopen 7 dagen',
'UI-ChangeManagementOverview-Last-7-days' => 'Aantal changes van de afgelopen 7 dagen',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes per domein van de afgelopen 7 dagen',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Changes per status van de afgelopen 7 dagen',
));
// Dictionnay conventions
// Class:<class_name>
// Class:<class_name>+
// Class:<class_name>/Attribute:<attribute_code>
// Class:<class_name>/Attribute:<attribute_code>+
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
// Class:<class_name>/Stimulus:<stimulus_code>
// Class:<class_name>/Stimulus:<stimulus_code>+
//
// Class: Change
//
Dict::Add('NL NL', "Dutch", "Nederlands", array(
'Class:Change' => 'Change',
'Class:Change+' => '',
'Class:Change/Attribute:status' => 'Status',
'Class:Change/Attribute:status+' => '',
'Class:Change/Attribute:status/Value:new' => 'Nieuw',
'Class:Change/Attribute:status/Value:new+' => '',
'Class:Change/Attribute:status/Value:assigned' => 'Toegewezen',
'Class:Change/Attribute:status/Value:assigned+' => '',
'Class:Change/Attribute:status/Value:planned' => 'Gepland',
'Class:Change/Attribute:status/Value:planned+' => '',
'Class:Change/Attribute:status/Value:rejected' => 'Rejected',
'Class:Change/Attribute:status/Value:rejected+' => '',
'Class:Change/Attribute:status/Value:approved' => 'Goedgekeurd',
'Class:Change/Attribute:status/Value:approved+' => '',
'Class:Change/Attribute:status/Value:closed' => 'Gesloten',
'Class:Change/Attribute:status/Value:closed+' => '',
'Class:Change/Attribute:category' => 'Categorie',
'Class:Change/Attribute:category+' => '',
'Class:Change/Attribute:category/Value:application' => 'applicatie',
'Class:Change/Attribute:category/Value:application+' => 'applicatie',
'Class:Change/Attribute:category/Value:hardware' => 'hardware',
'Class:Change/Attribute:category/Value:hardware+' => 'hardware',
'Class:Change/Attribute:category/Value:network' => 'netwerk',
'Class:Change/Attribute:category/Value:network+' => 'netwerk',
'Class:Change/Attribute:category/Value:other' => 'anders',
'Class:Change/Attribute:category/Value:other+' => 'anders',
'Class:Change/Attribute:category/Value:software' => 'software',
'Class:Change/Attribute:category/Value:software+' => 'software',
'Class:Change/Attribute:category/Value:system' => 'systeem',
'Class:Change/Attribute:category/Value:system+' => 'systeem',
'Class:Change/Attribute:reject_reason' => 'Reden van afwijzing',
'Class:Change/Attribute:reject_reason+' => '',
'Class:Change/Attribute:changemanager_id' => 'Change manager',
'Class:Change/Attribute:changemanager_id+' => '',
'Class:Change/Attribute:changemanager_email' => 'Change manager email',
'Class:Change/Attribute:changemanager_email+' => '',
'Class:Change/Attribute:parent_id' => 'Hoofd change',
'Class:Change/Attribute:parent_id+' => '',
'Class:Change/Attribute:parent_name' => 'Hoofd change ref',
'Class:Change/Attribute:parent_name+' => '',
'Class:Change/Attribute:creation_date' => 'Creatie datum',
'Class:Change/Attribute:creation_date+' => '',
'Class:Change/Attribute:approval_date' => 'Goedkeuring datum',
'Class:Change/Attribute:approval_date+' => '',
'Class:Change/Attribute:fallback_plan' => 'Backup plan',
'Class:Change/Attribute:fallback_plan+' => '',
'Class:Change/Attribute:related_request_list' => 'Gerelateerde verzoeken',
'Class:Change/Attribute:related_request_list+' => 'Alle gebruikersverzoeken gelinkt aan deze change',
'Class:Change/Attribute:related_incident_list' => 'Gerelateerde incidenten',
'Class:Change/Attribute:related_incident_list+' => 'Alle incidenten die gelinkt zijn aan deze change',
'Class:Change/Attribute:related_problems_list' => 'Gerelateerde problemen',
'Class:Change/Attribute:related_problems_list+' => 'Alle problemen gelinkt aan deze change',
'Class:Change/Attribute:child_changes_list' => 'Sub changes',
'Class:Change/Attribute:child_changes_list+' => 'Alle sub changes gelinkt aan deze change',
'Class:Change/Attribute:parent_id_friendlyname' => 'Hoofd change friendly name',
'Class:Change/Attribute:parent_id_friendlyname+' => '',
'Class:Change/Stimulus:ev_assign' => 'Wijs toe',
'Class:Change/Stimulus:ev_assign+' => '',
'Class:Change/Stimulus:ev_plan' => 'Plan',
'Class:Change/Stimulus:ev_plan+' => '',
'Class:Change/Stimulus:ev_reject' => 'Wijs af',
'Class:Change/Stimulus:ev_reject+' => '',
'Class:Change/Stimulus:ev_reopen' => 'Heropen',
'Class:Change/Stimulus:ev_reopen+' => '',
'Class:Change/Stimulus:ev_approve' => 'Keur goed',
'Class:Change/Stimulus:ev_approve+' => '',
'Class:Change/Stimulus:ev_finish' => 'Sluit',
'Class:Change/Stimulus:ev_finish+' => '',
'Class:Change/Attribute:outage' => 'Storing',
'Class:Change/Attribute:outage+' => '',
'Class:Change/Attribute:outage/Value:no' => 'Nee',
'Class:Change/Attribute:outage/Value:no+' => '',
'Class:Change/Attribute:outage/Value:yes' => 'Yes',
'Class:Change/Attribute:outage/Value:yes+' => '',
));
?>

File diff suppressed because it is too large Load Diff

View File

@@ -289,8 +289,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:Model/Attribute:type/Value:Tablet+' => '',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'Tape-Library',
'Class:Model/Attribute:type/Value:TapeLibrary+' => '',
'Class:Model/Attribute:type/Value:Phone' => 'Telefon',
'Class:Model/Attribute:type/Value:Phone+' => '',
'Class:Model/Attribute:type/Value:Telephone' => 'Telefon',
'Class:Model/Attribute:type/Value:Telephone+' => '',
'Class:Model/Attribute:physicaldevices_list' => 'Phyische Geräte',
'Class:Model/Attribute:physicaldevices_list+' => '',
'Class:NetworkDeviceType' => 'Netzerkgerätetyp',
@@ -1019,14 +1019,10 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'Class:lnkGroupToCI/Attribute:group_name+' => '',
'Class:lnkGroupToCI/Attribute:ci_name' => 'Name',
'Class:lnkGroupToCI/Attribute:ci_name+' => '',
'Menu:DataAdministration' => 'Data Management',
'Menu:DataAdministration+' => 'Data Management',
'Menu:Catalogs' => 'Kataloge',
'Menu:Catalogs+' => 'Datentypen',
'Menu:Audit' => 'Audit',
'Menu:Audit+' => 'Audit',
'Menu:CSVImport' => 'CSV-Import',
'Menu:CSVImport+' => 'Massenerstellung oder -aktualisierung',
'Menu:Organization' => 'Organisationen',
'Menu:Organization+' => 'Alle Organisationen',
'Menu:Application' => 'Anwendungen',

View File

@@ -33,7 +33,7 @@ Dict::Add('EN US', 'English', 'English', array(
'Relation:impacts/Description' => 'Elements impacted by',
'Relation:impacts/VerbUp' => 'Impact...',
'Relation:impacts/VerbDown' => 'Elements impacted by...',
'Relation:depends on/Description' => 'Elements impacting',
'Relation:depends on/Description' => 'Elements this element depends on',
'Relation:depends on/VerbUp' => 'Depends on...',
'Relation:depends on/VerbDown' => 'Impacts...',
));
@@ -1327,8 +1327,8 @@ Dict::Add('EN US', 'English', 'English', array(
'Class:Model/Attribute:type/Value:Tablet+' => 'Tablet',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'Tape Library',
'Class:Model/Attribute:type/Value:TapeLibrary+' => 'Tape Library',
'Class:Model/Attribute:type/Value:Phone' => 'Telephone',
'Class:Model/Attribute:type/Value:Phone+' => 'Telephone',
'Class:Model/Attribute:type/Value:Telephone' => 'Telephone',
'Class:Model/Attribute:type/Value:Telephone+' => 'Telephone',
'Class:Model/Attribute:physicaldevices_list' => 'Physical devices',
'Class:Model/Attribute:physicaldevices_list+' => 'All the physical devices corresponding to this model',
));
@@ -1770,14 +1770,10 @@ Dict::Add('EN US', 'English', 'English', array(
//
Dict::Add('EN US', 'English', 'English', array(
'Menu:DataAdministration' => 'Data administration',
'Menu:DataAdministration+' => 'Data administration',
'Menu:Catalogs' => 'Catalogs',
'Menu:Catalogs+' => 'Data types',
'Menu:Audit' => 'Audit',
'Menu:Audit+' => 'Audit',
'Menu:CSVImport' => 'CSV import',
'Menu:CSVImport+' => 'Bulk creation or update',
'Menu:Organization' => 'Organizations',
'Menu:Organization+' => 'All organizations',
'Menu:Application' => 'Applications',

View File

@@ -1331,8 +1331,8 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Class:Model/Attribute:type/Value:Tablet+' => 'Tableta',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'Librería de Cinta',
'Class:Model/Attribute:type/Value:TapeLibrary+' => 'Librería de Cinta',
'Class:Model/Attribute:type/Value:Phone' => 'Teléfono',
'Class:Model/Attribute:type/Value:Phone+' => 'Teléfono',
'Class:Model/Attribute:type/Value:Telephone' => 'Teléfono',
'Class:Model/Attribute:type/Value:Telephone+' => 'Teléfono',
'Class:Model/Attribute:physicaldevices_list' => 'Dispositivo Físico',
'Class:Model/Attribute:physicaldevices_list+' => 'Dispositivo Físico',
));
@@ -1768,14 +1768,10 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
//
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
'Menu:DataAdministration' => 'Administración de Datos',
'Menu:DataAdministration+' => 'Administración de Datos',
'Menu:Catalogs' => 'Catálogos',
'Menu:Catalogs+' => 'Tipos de Datos',
'Menu:Audit' => 'Auditoría',
'Menu:Audit+' => 'Auditoría',
'Menu:CSVImport' => 'Importar CSV',
'Menu:CSVImport+' => 'Creación o Actualización Másiva',
'Menu:Organization' => 'Organizaciones',
'Menu:Organization+' => 'Organizaciones',
'Menu:Application' => 'Aplicaciones',

View File

@@ -1269,8 +1269,8 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Class:Model/Attribute:type/Value:Tablet+' => 'Tablette',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'Bandothèque',
'Class:Model/Attribute:type/Value:TapeLibrary+' => 'Bandothèque',
'Class:Model/Attribute:type/Value:Phone' => 'Téléphone',
'Class:Model/Attribute:type/Value:Phone+' => 'Téléphone',
'Class:Model/Attribute:type/Value:Telephone' => 'Téléphone',
'Class:Model/Attribute:type/Value:Telephone+' => 'Téléphone',
'Class:Model/Attribute:physicaldevices_list' => 'Matériels',
'Class:Model/Attribute:physicaldevices_list+' => '',
));
@@ -1717,14 +1717,10 @@ Dict::Add('FR FR', 'French', 'Français', array(
Dict::Add('FR FR', 'French', 'Français', array(
'Menu:DataAdministration' => 'Administration des données',
'Menu:DataAdministration+' => 'Administration des données',
'Menu:Catalogs' => 'Catalogues',
'Menu:Catalogs+' => 'Types de données',
'Menu:Audit' => 'Audit',
'Menu:Audit+' => 'Audit',
'Menu:CSVImport' => 'Import CSV',
'Menu:CSVImport+' => 'Import ou mise à jour en masse',
'Menu:Organization' => 'Organisations',
'Menu:Organization+' => 'Toutes les organisations',
'Menu:Application' => 'Logiciels',
@@ -1821,7 +1817,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
'Relation:impacts/Description' => 'Eléments impactés par',
'Relation:impacts/VerbUp' => 'Impacte...',
'Relation:impacts/VerbDown' => 'Dépend de...',
'Relation:depends on/Description' => 'Eléments dont dépend',
'Relation:depends on/Description' => 'Eléments dont dépend cet élément',
'Relation:depends on/VerbUp' => 'Dépend de...',
'Relation:depends on/VerbDown' => 'Impacte...',
'Menu:ConfigManagement:Typology' => 'Configuration des typologies',

View File

@@ -641,14 +641,10 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
'Class:Subnet/Tab:FreeIPs' => 'Szabad IP-k',
'Class:Subnet/Tab:FreeIPs-count' => 'Szabad IP-k: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => '10 szabad IP cím kivonata',
'Menu:DataAdministration' => 'Adat adminisztráció',
'Menu:DataAdministration+' => '',
'Menu:Catalogs' => 'Katalógusok',
'Menu:Catalogs+' => '',
'Menu:Audit' => 'Audit',
'Menu:Audit+' => '',
'Menu:CSVImport' => 'CSV import',
'Menu:CSVImport+' => '',
'Menu:Organization' => 'Szervezet',
'Menu:Organization+' => '',
'Menu:Application' => 'Alkalmazások',

View File

@@ -641,14 +641,10 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
'Class:Subnet/Tab:FreeIPs' => 'IP liberi',
'Class:Subnet/Tab:FreeIPs-count' => 'IP liberi: %1$s',
'Class:Subnet/Tab:FreeIPs-explain' => 'Qui c\'è un estratto di 10 indirizzi IP liberi',
'Menu:DataAdministration' => 'Dati di amministrazione',
'Menu:DataAdministration+' => '',
'Menu:Catalogs' => 'Cataloghi',
'Menu:Catalogs+' => 'Tipi di dato',
'Menu:Audit' => 'Audit',
'Menu:Audit+' => 'Audit',
'Menu:CSVImport' => 'Importazione CSV',
'Menu:CSVImport+' => '',
'Menu:Organization' => 'Organizzazioni',
'Menu:Organization+' => 'Tutte le organizzazioni',
'Menu:Application' => 'Applicazioni',

View File

@@ -294,8 +294,8 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:Model/Attribute:type/Value:Tablet+' => 'タブレット',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'テープライブラリ',
'Class:Model/Attribute:type/Value:TapeLibrary+' => 'テープライブラリ',
'Class:Model/Attribute:type/Value:Phone' => '電話',
'Class:Model/Attribute:type/Value:Phone+' => '電話',
'Class:Model/Attribute:type/Value:Telephone' => '電話',
'Class:Model/Attribute:type/Value:Telephone+' => '電話',
'Class:Model/Attribute:physicaldevices_list' => '物理デバイス',
'Class:Model/Attribute:physicaldevices_list+' => '',
'Class:NetworkDeviceType' => 'ネットワークデバイスタイプ',
@@ -1012,14 +1012,10 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Class:lnkGroupToCI/Attribute:group_name+' => '',
'Class:lnkGroupToCI/Attribute:ci_name' => '名前',
'Class:lnkGroupToCI/Attribute:ci_name+' => '',
'Menu:DataAdministration' => 'データ管理',
'Menu:DataAdministration+' => 'データ管理',
'Menu:Catalogs' => 'カタログ',
'Menu:Catalogs+' => 'データタイプ',
'Menu:Audit' => '監査',
'Menu:Audit+' => '監査',
'Menu:CSVImport' => 'CSV インポート',
'Menu:CSVImport+' => '一括作成/一括更新',
'Menu:Organization' => '組織',
'Menu:Organization+' => '全組織',
'Menu:Application' => 'アプリケーション',
@@ -1089,8 +1085,6 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
'Menu:Typology+' => 'トポロジー構成',
'Menu:Software' => 'ソフトウエアカタログ',
'Menu:Software+' => 'ソフトウエアカタログ',
'Menu:OSVersion' => 'OS バージョン',
'Menu:OSVersion+' => '',
'UI_WelcomeMenu_AllConfigItems' => 'サマリー',
'Menu:ConfigManagement:Typology' => '分類構成',
'Server:baseinfo' => '基本情報',

View File

@@ -3,7 +3,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-config-mgmt/2.1.0',
'itop-config-mgmt/2.0.0',
array(
// Identification
//
@@ -89,7 +89,6 @@ if (!class_exists('ConfigMgmtInstaller'))
self::RenameEnumValueInDB('Software', 'type', 'Webserver', 'WebServer');
self::RenameEnumValueInDB('Model', 'type', 'SANswitch', 'SANSwitch');
self::RenameEnumValueInDB('Model', 'type', 'IpPhone', 'IPPhone');
self::RenameEnumValueInDB('Model', 'type', 'Telephone', 'Phone');
self::RenameClassInDB('DBserver', 'DBServer');
self::RenameClassInDB('OSfamily', 'OSFamily');
self::RenameClassInDB('OSversion', 'OSVersion');

File diff suppressed because it is too large Load Diff

View File

@@ -1322,8 +1322,8 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Class:Model/Attribute:type/Value:Tablet+' => 'Tablet',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'Tape Library',
'Class:Model/Attribute:type/Value:TapeLibrary+' => 'Tape Library',
'Class:Model/Attribute:type/Value:Phone' => 'Telefone',
'Class:Model/Attribute:type/Value:Phone+' => 'Telefone',
'Class:Model/Attribute:type/Value:Telephone' => 'Telefone',
'Class:Model/Attribute:type/Value:Telephone+' => 'Telefone',
'Class:Model/Attribute:physicaldevices_list' => 'Dispositivo físico',
'Class:Model/Attribute:physicaldevices_list+' => 'Todos os dispositivos físicos correspondentes a esse modelo',
));
@@ -1764,20 +1764,17 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
//
Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
'Menu:DataAdministration' => 'Administração Dados',
'Menu:DataAdministration+' => 'Administração Dados',
'Menu:Catalogs' => 'Catálogos',
'Menu:Catalogs+' => 'Tipos dados',
'Menu:Audit' => 'Auditoria',
'Menu:Audit+' => 'Auditoria',
'Menu:CSVImport' => 'Importar CSV',
'Menu:CSVImport+' => 'Criação ou atualização em massa',
'Menu:Organization' => 'Organizações',
'Menu:Organization+' => 'Todas organizações',
'Menu:Application' => 'Applicações',
'Menu:Application+' => 'Todas aplicações',
'Menu:DBServer' => 'Serviços Banco de Dados',
'Menu:DBServer+' => 'Serviços Banco de Dados',
'Menu:Audit' => 'Auditoria',
'Menu:ConfigManagement' => 'Gerenciamento Configurações',
'Menu:ConfigManagement+' => 'Gerenciamento Configurações',
'Menu:ConfigManagementOverview' => 'Visão geral',

View File

@@ -1322,8 +1322,8 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
'Class:Model/Attribute:type/Value:Tablet+' => 'Планшет',
'Class:Model/Attribute:type/Value:TapeLibrary' => 'Ленточная библиотека',
'Class:Model/Attribute:type/Value:TapeLibrary+' => 'Ленточная библиотека',
'Class:Model/Attribute:type/Value:Phone' => 'Телефон',
'Class:Model/Attribute:type/Value:Phone+' => 'Телефон',
'Class:Model/Attribute:type/Value:Telephone' => 'Телефон',
'Class:Model/Attribute:type/Value:Telephone+' => 'Телефон',
'Class:Model/Attribute:physicaldevices_list' => 'Устройства',
'Class:Model/Attribute:physicaldevices_list+' => 'Устройства',
));
@@ -1765,14 +1765,10 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
//
Dict::Add('RU RU', 'Russian', 'Русский', array(
'Menu:DataAdministration' => 'Административные данные',
'Menu:DataAdministration+' => 'Административные данные',
'Menu:Catalogs' => 'Каталоги',
'Menu:Catalogs+' => 'Каталоги',
'Menu:Audit' => 'Аудит',
'Menu:Audit+' => 'Аудит',
'Menu:CSVImport' => 'Импорт CSV',
'Menu:CSVImport+' => 'Пакетное создание или обновление',
'Menu:Organization' => 'Организации',
'Menu:Organization+' => 'Все организации',
'Menu:Application' => 'Приложения',

View File

@@ -990,14 +990,10 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
//
Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
'Menu:DataAdministration' => 'Veri Yönetimi',
'Menu:DataAdministration+' => 'Veri Yönetimi',
'Menu:Catalogs' => 'Kataloglar',
'Menu:Catalogs+' => 'Veri tipleri',
'Menu:Audit' => 'Denetleme',
'Menu:Audit+' => 'Denetleme',
'Menu:CSVImport' => 'CSV dışardan al',
'Menu:CSVImport+' => 'Çoklu yaratım veya güncelleme',
'Menu:Organization' => 'Kurumlar',
'Menu:Organization+' => 'Tüm Kurumlar',
'Menu:Application' => 'Uygulamalar',

View File

@@ -992,14 +992,10 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
//
Dict::Add('ZH CN', 'Chinese', '简体中文', array(
'Menu:DataAdministration' => '数据管理',
'Menu:DataAdministration+' => '数据管理',
'Menu:Catalogs' => '目录',
'Menu:Catalogs+' => '数据类别',
'Menu:Audit' => '审计',
'Menu:Audit+' => '审计',
'Menu:CSVImport' => 'CSV 导入',
'Menu:CSVImport+' => '大批量创建或修改',
'Menu:Organization' => '组织',
'Menu:Organization+' => '所有组织',
'Menu:Application' => '应用程序',

View File

@@ -1,251 +0,0 @@
<?php
// Copyright (C) 2014-2016 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/>
/**
* Monitor the backup
*
* @copyright Copyright (C) 2013 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
require_once('../../approot.inc.php');
require_once(APPROOT.'application/application.inc.php');
require_once(APPROOT.'application/itopwebpage.class.inc.php');
require_once(APPROOT.'application/startup.inc.php');
require_once(APPROOT.'application/loginwebpage.class.inc.php');
function TestConfig($sContents, $oP)
{
try
{
ini_set('display_errors', 1);
ob_start();
eval('?'.'>'.trim($sContents));
$sNoise = trim(ob_get_contents());
ob_end_clean();
}
catch (Exception $e)
{
// well, never reach in case of parsing error :-(
throw new Exception('Error in configuration: '.$e->getMessage());
}
if (strlen($sNoise) > 0)
{
if (preg_match("/(Error|Parse error|Notice|Warning): (.+) in \S+ : eval\(\)'d code on line (\d+)/i", strip_tags($sNoise), $aMatches))
{
$sMessage = $aMatches[2];
$sLine = $aMatches[3];
$iLine = (int) $sLine;
// Highlight the line
$aLines = explode("\n", $sContents);
$iStart = 0;
for ($i = 0 ; $i < $iLine - 1; $i++) $iStart += strlen($aLines[$i]);
$iEnd = $iStart + strlen($aLines[$iLine - 1]);
$iTotalLines = count($aLines);
$oP->add_ready_script(
<<<EOF
setCursorPos($('#new_config')[0], $iStart, $iEnd);
$('#new_config')[0].focus();
var iScroll = Math.floor($('#new_config')[0].scrollHeight * ($iLine - 20) / $iTotalLines);
$('#new_config').scrollTop(iScroll);
EOF
);
$sMessage = Dict::Format('config-parse-error', $sMessage, $sLine);
throw new Exception($sMessage);
}
else
{
// Note: sNoise is an html output, but so far it was ok for me (e.g. showing the entire call stack)
throw new Exception('Syntax error in configuration file: <tt>'.$sNoise.'</tt>');
}
}
}
/////////////////////////////////////////////////////////////////////
// Main program
//
LoginWebPage::DoLogin(true); // Check user rights and prompt if needed (must be admin)
//$sOperation = utils::ReadParam('operation', 'menu');
//$oAppContext = new ApplicationContext();
$oP = new iTopWebPage(Dict::S('config-edit-title'));
$oP->set_base(utils::GetAbsoluteUrlAppRoot().'pages/');
try
{
$sOperation = utils::ReadParam('operation', '');
$oP->add("<h1>".Dict::S('config-edit-title')."</h1>");
if (MetaModel::GetConfig()->Get('demo_mode'))
{
$oP->add("<div class=\"header_message message_info\">Sorry, iTop is in <b>demonstration mode</b>: the configuration file cannot be edited.</div>");
}
if (MetaModel::GetModuleSetting('itop-config', 'config_editor', '') == 'disabled')
{
$oP->add("<div class=\"header_message message_info\">iTop interactive edition of the configuration as been disabled. See <tt>'config_editor' => 'disabled'</tt> in the configuration file.</div>");
}
else
{
$oP->add_style(
<<<EOF
textarea {
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
width: 100%;
height: 550px;
}
.current_line {
display: none;
margin-left: 20px;
}
EOF
);
$sConfigFile = APPROOT.'conf/'.utils::GetCurrentEnvironment().'/config-itop.php';
if ($sOperation == 'save')
{
$sConfig = utils::ReadParam('new_config', '', false, 'raw_data');
$sTransactionId = utils::ReadParam('transaction_id', '');
$sOrginalConfig = utils::ReadParam('prev_config', '', false, 'raw_data');
if (!utils::IsTransactionValid($sTransactionId, true))
{
$oP->add("<div class=\"header_message message_info\">Error: invalid Transaction ID. The configuration was <b>NOT</b> modified.</div>");
}
else
{
if ($sConfig == $sOrginalConfig)
{
$oP->add('<div id="save_result" class="header_message">'.Dict::S('config-no-change').'</div>');
}
else
{
try
{
TestConfig($sConfig, $oP); // throws exceptions
@chmod($sConfigFile, 0770); // Allow overwriting the file
$sTmpFile = tempnam(SetupUtils::GetTmpDir(), 'itop-cfg-');
// Don't write the file as-is since it would allow to inject any kind of PHP code.
// Instead write the interpreted version of the file
// Note:
// The actual raw PHP code will anyhow be interpreted exactly twice: once in TestConfig() above
// and a second time during the load of the Config object below.
// If you are really concerned about an iTop administrator crafting some malicious
// PHP code inside the config file, then turn off the interactive configuration
// editor by adding the configuration parameter:
// 'itop-config' => array(
// 'config_editor' => 'disabled',
// )
file_put_contents($sTmpFile, $sConfig);
$oTempConfig = new Config($sTmpFile, true);
$oTempConfig->WriteToFile($sConfigFile);
@unlink($sTmpFile);
@chmod($sConfigFile, 0444); // Read-only
$oP->p('<div id="save_result" class="header_message message_ok">'.Dict::S('Successfully recorded.').'</div>');
$sOrginalConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile));
}
catch (Exception $e)
{
$oP->p('<div id="save_result" class="header_message message_error">'.$e->getMessage().'</div>');
}
}
}
}
else
{
$sConfig = str_replace("\r\n", "\n", file_get_contents($sConfigFile));
$sOrginalConfig = $sConfig;
}
$sConfigEscaped = htmlentities($sConfig, ENT_QUOTES, 'UTF-8');
$sOriginalConfigEscaped = htmlentities($sOrginalConfig, ENT_QUOTES, 'UTF-8');
$oP->p(Dict::S('config-edit-intro'));
$oP->add("<form method=\"POST\">");
$oP->add("<input type=\"hidden\" name=\"operation\" value=\"save\">");
$oP->add("<input type=\"hidden\" name=\"transaction_id\" value=\"".utils::GetNewTransactionId()."\">");
$oP->add("<input type=\"submit\" value=\"".Dict::S('config-apply')."\"><button onclick=\"ResetConfig(); return false;\">".Dict::S('config-cancel')."</button>");
$oP->add("<span class=\"current_line\">".Dict::Format('config-current-line', "<span class=\"line_number\"></span>")."</span>");
$oP->add("<input type=\"hidden\" id=\"prev_config\" name=\"prev_config\" value=\"$sOriginalConfigEscaped\">");
$oP->add("<textarea id =\"new_config\" name=\"new_config\" onkeyup=\"UpdateLineNumber();\" onmouseup=\"UpdateLineNumber();\">$sConfigEscaped</textarea>");
$oP->add("<input type=\"submit\" value=\"".Dict::S('config-apply')."\"><button onclick=\"ResetConfig(); return false;\">".Dict::S('config-cancel')."</button>");
$oP->add("<span class=\"current_line\">".Dict::Format('config-current-line', "<span class=\"line_number\"></span>")."</span>");
$oP->add("</form>");
$sConfirmCancel = addslashes(Dict::S('config-confirm-cancel'));
$oP->add_script(
<<<EOF
function UpdateLineNumber()
{
var oTextArea = $('#new_config')[0];
$('.line_number').html(oTextArea.value.substr(0, oTextArea.selectionStart).split("\\n").length);
$('.current_line').show();
}
function ResetConfig()
{
if ($('#new_config').val() != $('#prev_config').val())
{
if (confirm('$sConfirmCancel'))
{
$('#new_config').val($('#prev_config').val());
}
}
$('.current_line').hide();
$('#save_result').hide();
return false;
}
function setCursorPos(input, start, end) {
if (arguments.length < 3) end = start;
if ("selectionStart" in input) {
setTimeout(function() {
input.selectionStart = start;
input.selectionEnd = end;
}, 1);
}
else if (input.createTextRange) {
var rng = input.createTextRange();
rng.moveStart("character", start);
rng.collapse();
rng.moveEnd("character", end - start);
rng.select();
}
}
EOF
);
}
}
catch(Exception $e)
{
$oP->p('<b>'.$e->getMessage().'</b>');
}
$oP->output();

View File

@@ -1,20 +0,0 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 Combodo
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DE DE', 'German', 'Deutsch', array(
'Menu:ConfigEditor' => 'Konfiguration',
'config-edit-title' => 'Konfigurations-Editor',
'config-edit-intro' => 'Seien sie bei der Bearbeitung der Konfigurationsdatei sehr vorsichtig. Normalerweise sollten es aureichen die Einträge im oberen Teil der Konfiguration zu bearbeiten (Bsp.: die globalen Konfigurations- und Moduleinstellungen).',
'config-apply' => 'Anwenden',
'config-cancel' => 'Zurücksetzen',
'config-confirm-cancel' => 'Ihre Änderungen werden nicht gespeichert.',
'config-no-change' => 'Keine Änderungen: Die Datei wurde nicht verändert.',
'config-parse-error' => 'Zeile %2$d: %1$s.<br/>Die Datei wurde nicht aktualisiert.',
'config-current-line' => 'Editiere Zeile: %1$s',
));

View File

@@ -1,21 +0,0 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 Combodo
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('EN US', 'English', 'English', array(
'Menu:ConfigEditor' => 'Configuration',
'config-edit-title' => 'Configuration File Editor',
'config-edit-intro' => 'Be very cautious when editing the configuration file. In particular, only the upper items (i.e. the global configuration and modules settings) should be edited.',
'config-apply' => 'Apply',
'config-cancel' => 'Reset',
'config-confirm-cancel' => 'Your changes will be lost.',
'config-no-change' => 'No change: the file has been left unchanged.',
'config-parse-error' => 'Line %2$d: %1$s.<br/>The file has NOT been updated.',
'config-current-line' => 'Editing line: %1$s',
));
?>

View File

@@ -1,21 +0,0 @@
<?php
/**
* Localized data
*
* @copyright Copyright (C) 2013 Combodo
* @license http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('FR FR', 'French', 'Français', array(
'Menu:ConfigEditor' => 'Configuration',
'config-edit-title' => 'Editeur du Fichier de Configuration',
'config-edit-intro' => 'Attention: une configuration incorrecte peut rendre iTop indisponible. En particulier, vous ne devriez éditer QUE les deux premiers éléments, à savoir la configuration globale et la configuration des modules.',
'config-save' => 'Appliquer',
'config-restore' => 'Réinitialiser',
'config-confirm-cancel' => 'Vos modifications seront perdues.',
'config-no-change' => 'Aucun changement : le fichier n\'a pas été altéré.',
'config-parse-error' => 'Ligne %2$d: %1$s.<br/>Le fichier n\'a PAS été modifié.',
'config-current-line' => 'Ligne en édition : %1$s',
));
?>

View File

@@ -1,30 +0,0 @@
<?php
// Copyright (C) 2013 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//require_once(APPROOT.'setup/setuputils.class.inc.php');
class ItopConfigEditor extends ModuleHandlerAPI
{
public static function OnMenuCreation()
{
if (UserRights::IsAdministrator())
{
$oAdminMenu = new MenuGroup('AdminTools', 80 /* fRank */);
new WebPageMenuNode('ConfigEditor', utils::GetAbsoluteUrlModulesRoot().'itop-config/config.php', $oAdminMenu->GetIndex(), 18 /* fRank */);
}
}
}

View File

@@ -1,53 +0,0 @@
<?php
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-config/1.0.2',
array(
// Identification
//
'label' => 'Configuration editor',
'category' => 'Application management',
// Setup
//
'dependencies' => array(
),
'mandatory' => true,
'visible' => false,
// Components
//
'datamodel' => array(
'main.itop-config.php',
//'model.itop-config.php',
),
'webservice' => array(
//'webservices.itop-config.php',
),
'dictionary' => array(
'en.dict.itop-config.php',
'fr.dict.itop-config.php',
//'de.dict.itop-config.php',
),
'data.struct' => array(
//'data.struct.itop-config.xml',
),
'data.sample' => array(
//'data.sample.itop-config.xml',
),
// Documentation
//
'doc.manual_setup' => '',
'doc.more_information' => '',
// Default settings
//
'settings' => array(
),
)
);
?>

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<classes>
<class id="Rack" _delta="define">
<parent>PhysicalDevice</parent>
@@ -11,6 +11,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -193,6 +194,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -397,6 +399,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -577,6 +580,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -740,6 +744,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -764,7 +769,7 @@
<target_class>Rack</target_class>
<is_null_allowed>false</is_null_allowed>
<on_target_delete>DEL_MANUAL</on_target_delete>
<allow_target_creation>false</allow_target_creation>
<allow_target_creation>false</allow_target_creation>
</field>
<field id="rack_name" xsi:type="AttributeExternalField">
<extkey_attcode>rack_id</extkey_attcode>
@@ -779,8 +784,8 @@
<target_class>PowerConnection</target_class>
<is_null_allowed>true</is_null_allowed>
<on_target_delete>DEL_MANUAL</on_target_delete>
<allow_target_creation>false</allow_target_creation>
<allow_target_creation>false</allow_target_creation>
<allow_target_creation>false</allow_target_creation>
<allow_target_creation>false</allow_target_creation>
</field>
<field id="powerstart_name" xsi:type="AttributeExternalField">
<extkey_attcode>powerstart_id</extkey_attcode>
@@ -953,25 +958,25 @@
</classes>
<menus>
<menu id="ConfigManagementOverview" xsi:type="DashboardMenuNode" _delta="must_exist">
<definition>
<cells>
<cell id="0" _delta="must_exist">
<dashlets>
<dashlet id="21" xsi:type="DashletBadge" _delta="define">
<rank>1</rank>
<class>Rack</class>
</dashlet>
<dashlet id="22" xsi:type="DashletBadge" _delta="define">
<rank>2</rank>
<class>Enclosure</class>
</dashlet>
<dashlet id="23" xsi:type="DashletBadge" _delta="define">
<rank>9</rank>
<class>PowerConnection</class>
</dashlet>
</dashlets>
</cell>
</cells>
<definition>
<cells>
<cell id="0" _delta="must_exist">
<dashlets>
<dashlet id="21" xsi:type="DashletBadge" _delta="define">
<rank>1</rank>
<class>Rack</class>
</dashlet>
<dashlet id="22" xsi:type="DashletBadge" _delta="define">
<rank>2</rank>
<class>Enclosure</class>
</dashlet>
<dashlet id="23" xsi:type="DashletBadge" _delta="define">
<rank>9</rank>
<class>PowerConnection</class>
</dashlet>
</dashlets>
</cell>
</cells>
</definition>
</menu>
</menus>

View File

@@ -18,7 +18,7 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-datacenter-mgmt/2.1.0',
'itop-datacenter-mgmt/2.0.0',
array(
// Identification
//

View File

@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.1">
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0">
<classes>
<class id="TelephonyCI" _delta="define">
<class id="TelephonyCI" _delta="define">
<parent>PhysicalDevice</parent>
<properties>
<category>bizmodel,searchable</category>
@@ -11,6 +11,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -163,6 +164,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -318,6 +320,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -496,6 +499,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -651,6 +655,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -803,6 +808,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -854,8 +860,8 @@
</field>
<field id="type" xsi:type="AttributeEnum">
<values>
<value id="laptop">laptop</value>
<value id="desktop">desktop</value>
<value>laptop</value>
<value>desktop</value>
</values>
<sql>type</sql>
<default_value/>
@@ -1057,6 +1063,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1235,6 +1242,7 @@
</list>
</presentation>
</class>
<class id="Peripheral" _delta="define">
<parent>PhysicalDevice</parent>
<properties>
@@ -1245,6 +1253,7 @@
<db_key_field>id</db_key_field>
<db_final_class_field/>
<naming>
<format>%1$s</format>
<attributes>
<attribute id="name"/>
</attributes>
@@ -1387,51 +1396,51 @@
</list>
</presentation>
</class>
</classes>
<menus>
<menu id="ConfigManagementOverview" xsi:type="DashboardMenuNode" _delta="must_exist">
<definition>
<cells>
<cell id="2" _delta="define">
<rank>2</rank>
<dashlets>
<dashlet id="25" xsi:type="DashletHeaderStatic">
<rank>0</rank>
<title>Menu:ConfigManagement:EndUsers</title>
<icon>itop-config-mgmt/images/team.png</icon>
</dashlet>
<dashlet id="26" xsi:type="DashletBadge">
<rank>1</rank>
<class>PC</class>
</dashlet>
<dashlet id="27" xsi:type="DashletBadge">
<rank>2</rank>
<class>Phone</class>
</dashlet>
<dashlet id="28" xsi:type="DashletBadge">
<rank>3</rank>
<class>IPPhone</class>
</dashlet>
<dashlet id="29" xsi:type="DashletBadge">
<rank>4</rank>
<class>MobilePhone</class>
</dashlet>
<dashlet id="30" xsi:type="DashletBadge">
<rank>5</rank>
<class>Tablet</class>
</dashlet>
<dashlet id="31" xsi:type="DashletBadge">
<rank>6</rank>
<class>Printer</class>
</dashlet>
<dashlet id="32" xsi:type="DashletBadge">
<rank>7</rank>
<class>Peripheral</class>
</dashlet>
</dashlets>
</cell>
</cells>
</definition>
</menu>
</menus>
</classes>
<menus>
<menu id="ConfigManagementOverview" xsi:type="DashboardMenuNode" _delta="must_exist">
<definition>
<cells>
<cell id="2" _delta="define">
<rank>2</rank>
<dashlets>
<dashlet id="25" xsi:type="DashletHeaderStatic">
<rank>0</rank>
<title>Menu:ConfigManagement:EndUsers</title>
<icon>itop-config-mgmt/images/team.png</icon>
</dashlet>
<dashlet id="26" xsi:type="DashletBadge">
<rank>1</rank>
<class>PC</class>
</dashlet>
<dashlet id="27" xsi:type="DashletBadge">
<rank>2</rank>
<class>Phone</class>
</dashlet>
<dashlet id="28" xsi:type="DashletBadge">
<rank>3</rank>
<class>IPPhone</class>
</dashlet>
<dashlet id="29" xsi:type="DashletBadge">
<rank>4</rank>
<class>MobilePhone</class>
</dashlet>
<dashlet id="30" xsi:type="DashletBadge">
<rank>5</rank>
<class>Tablet</class>
</dashlet>
<dashlet id="31" xsi:type="DashletBadge">
<rank>6</rank>
<class>Printer</class>
</dashlet>
<dashlet id="32" xsi:type="DashletBadge">
<rank>7</rank>
<class>Peripheral</class>
</dashlet>
</dashlets>
</cell>
</cells>
</definition>
</menu>
</menus>
</itop_design>

View File

@@ -25,11 +25,11 @@
SetupWebPage::AddModule(
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
'itop-endusers-devices/2.1.0',
'itop-endusers-devices/2.0.0',
array(
// Identification
//
'label' => 'End-user Devices Management',
'label' => 'End User Devices management',
'category' => 'business',
// Setup

View File

@@ -1,217 +0,0 @@
<?php
// Copyright (C) 2010-2012 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/>
/**
* @author Erik Bøg <erik@boegmoeller.dk>
* @copyright Copyright (C) 2010-2012 Combodo SARL
* @licence http://opensource.org/licenses/AGPL-3.0
*/
Dict::Add('DA DA', 'Danish', 'Dansk', array(
'Class:Incident' => 'Incident',
'Class:Incident+' => '',
'Class:Incident/Attribute:status' => 'Status',
'Class:Incident/Attribute:status+' => '',
'Class:Incident/Attribute:status/Value:new' => 'Ny',
'Class:Incident/Attribute:status/Value:new+' => '',
'Class:Incident/Attribute:status/Value:escalated_tto' => 'Eskaleret TTO',
'Class:Incident/Attribute:status/Value:escalated_tto+' => '',
'Class:Incident/Attribute:status/Value:assigned' => 'Tildelt',
'Class:Incident/Attribute:status/Value:assigned+' => '',
'Class:Incident/Attribute:status/Value:escalated_ttr' => 'Eskaleret TTR',
'Class:Incident/Attribute:status/Value:escalated_ttr+' => '',
'Class:Incident/Attribute:status/Value:pending' => 'Afventer',
'Class:Incident/Attribute:status/Value:pending+' => '',
'Class:Incident/Attribute:status/Value:resolved' => 'Løst',
'Class:Incident/Attribute:status/Value:resolved+' => '',
'Class:Incident/Attribute:status/Value:closed' => 'Lukket',
'Class:Incident/Attribute:status/Value:closed+' => '',
'Class:Incident/Attribute:impact' => 'Påvirkning',
'Class:Incident/Attribute:impact+' => '',
'Class:Incident/Attribute:impact/Value:1' => 'Afdeling',
'Class:Incident/Attribute:impact/Value:1+' => 'En afdeling er påvirket',
'Class:Incident/Attribute:impact/Value:2' => 'Service',
'Class:Incident/Attribute:impact/Value:2+' => 'En service er påvirket',
'Class:Incident/Attribute:impact/Value:3' => 'Person',
'Class:Incident/Attribute:impact/Value:3+' => 'En person er påvirket',
'Class:Incident/Attribute:priority' => 'Prioritet',
'Class:Incident/Attribute:priority+' => '',
'Class:Incident/Attribute:priority/Value:1' => 'Kritisk',
'Class:Incident/Attribute:priority/Value:1+' => '',
'Class:Incident/Attribute:priority/Value:2' => 'Høj',
'Class:Incident/Attribute:priority/Value:2+' => '',
'Class:Incident/Attribute:priority/Value:3' => 'Middel',
'Class:Incident/Attribute:priority/Value:3+' => '',
'Class:Incident/Attribute:priority/Value:4' => 'Lav',
'Class:Incident/Attribute:priority/Value:4+' => '',
'Class:Incident/Attribute:urgency' => 'Vigtighed',
'Class:Incident/Attribute:urgency+' => '',
'Class:Incident/Attribute:urgency/Value:1' => 'Kritisk',
'Class:Incident/Attribute:urgency/Value:1+' => '',
'Class:Incident/Attribute:urgency/Value:2' => 'Høj',
'Class:Incident/Attribute:urgency/Value:2+' => '',
'Class:Incident/Attribute:urgency/Value:3' => 'Middel',
'Class:Incident/Attribute:urgency/Value:3+' => '',
'Class:Incident/Attribute:urgency/Value:4' => 'Lav',
'Class:Incident/Attribute:urgency/Value:4+' => '',
'Class:Incident/Attribute:origin' => 'Oprindelse',
'Class:Incident/Attribute:origin+' => '',
'Class:Incident/Attribute:origin/Value:mail' => 'Mail',
'Class:Incident/Attribute:origin/Value:mail+' => '',
'Class:Incident/Attribute:origin/Value:monitoring' => 'Monitoring',
'Class:Incident/Attribute:origin/Value:monitoring+' => '',
'Class:Incident/Attribute:origin/Value:phone' => 'Telefon',
'Class:Incident/Attribute:origin/Value:phone+' => '',
'Class:Incident/Attribute:origin/Value:portal' => 'Portal',
'Class:Incident/Attribute:origin/Value:portal+' => '',
'Class:Incident/Attribute:service_id' => 'Ydelse',
'Class:Incident/Attribute:service_id+' => '',
'Class:Incident/Attribute:servicesubcategory_id' => 'Ydelse underkategori',
'Class:Incident/Attribute:servicesubcategory_id+' => '',
'Class:Incident/Attribute:escalation_flag' => 'Eskalations Flag',
'Class:Incident/Attribute:escalation_flag+' => '',
'Class:Incident/Attribute:escalation_flag/Value:no' => 'Nej',
'Class:Incident/Attribute:escalation_flag/Value:no+' => '',
'Class:Incident/Attribute:escalation_flag/Value:yes' => 'Ja',
'Class:Incident/Attribute:escalation_flag/Value:yes+' => '',
'Class:Incident/Attribute:escalation_reason' => 'Eskalationsgrund',
'Class:Incident/Attribute:escalation_reason+' => '',
'Class:Incident/Attribute:assignment_date' => 'Tildelt dato',
'Class:Incident/Attribute:assignment_date+' => '',
'Class:Incident/Attribute:resolution_date' => 'Løsnings dato',
'Class:Incident/Attribute:resolution_date+' => '',
'Class:Incident/Attribute:last_pending_date' => 'Sidste udsættelse dato',
'Class:Incident/Attribute:last_pending_date+' => '',
'Class:Incident/Attribute:cumulatedpending' => 'Akkumuleret ventetid',
'Class:Incident/Attribute:cumulatedpending+' => '',
'Class:Incident/Attribute:tto' => 'TTO (Time To Own)',
'Class:Incident/Attribute:tto+' => '',
'Class:Incident/Attribute:ttr' => 'TTR (Time To Resolve)',
'Class:Incident/Attribute:ttr+' => '',
'Class:Incident/Attribute:tto_escalation_deadline' => 'TTO-Deadline',
'Class:Incident/Attribute:tto_escalation_deadline+' => '',
'Class:Incident/Attribute:sla_tto_passed' => 'SLA TTO overskredet',
'Class:Incident/Attribute:sla_tto_passed+' => '',
'Class:Incident/Attribute:sla_tto_over' => 'Overskridelse SLA TTO',
'Class:Incident/Attribute:sla_tto_over+' => '',
'Class:Incident/Attribute:ttr_escalation_deadline' => 'TTR-Deadline',
'Class:Incident/Attribute:ttr_escalation_deadline+' => '',
'Class:Incident/Attribute:sla_ttr_passed' => 'SLA TTR overskredet',
'Class:Incident/Attribute:sla_ttr_passed+' => '',
'Class:Incident/Attribute:sla_ttr_over' => 'Overskridelse SLA TTR',
'Class:Incident/Attribute:sla_ttr_over+' => '',
'Class:Incident/Attribute:time_spent' => 'Tid forbrugt til løsning',
'Class:Incident/Attribute:time_spent+' => '',
'Class:Incident/Attribute:resolution_code' => 'Løsningskode',
'Class:Incident/Attribute:resolution_code+' => '',
'Class:Incident/Attribute:resolution_code/Value:assistance' => 'Assistance',
'Class:Incident/Attribute:resolution_code/Value:assistance+' => '',
'Class:Incident/Attribute:resolution_code/Value:bug fixed' => 'Bugfix',
'Class:Incident/Attribute:resolution_code/Value:bug fixed+' => '',
'Class:Incident/Attribute:resolution_code/Value:hardware repair' => 'Hardware Reparation',
'Class:Incident/Attribute:resolution_code/Value:hardware repair+' => '',
'Class:Incident/Attribute:resolution_code/Value:other' => 'Andet',
'Class:Incident/Attribute:resolution_code/Value:other+' => '',
'Class:Incident/Attribute:resolution_code/Value:software patch' => 'Software Patch',
'Class:Incident/Attribute:resolution_code/Value:software patch+' => '',
'Class:Incident/Attribute:resolution_code/Value:system update' => 'System Update',
'Class:Incident/Attribute:resolution_code/Value:system update+' => '',
'Class:Incident/Attribute:resolution_code/Value:training' => 'Uddannelse',
'Class:Incident/Attribute:resolution_code/Value:training+' => '',
'Class:Incident/Attribute:solution' => 'Løsning',
'Class:Incident/Attribute:solution+' => '',
'Class:Incident/Attribute:pending_reason' => 'Årsag til afventer',
'Class:Incident/Attribute:pending_reason+' => '',
'Class:Incident/Attribute:parent_incident_id' => 'Parent Incident',
'Class:Incident/Attribute:parent_incident_id+' => '',
'Class:Incident/Attribute:parent_change_id' => 'Parent Change',
'Class:Incident/Attribute:parent_change_id+' => '',
'Class:Incident/Attribute:child_incidents_list' => 'Afledte Incidents',
'Class:Incident/Attribute:child_incidents_list+' => '',
'Class:Incident/Attribute:public_log' => 'Offentlig Log',
'Class:Incident/Attribute:public_log+' => '',
'Class:Incident/Attribute:user_satisfaction' => 'Bruger tilfredshed',
'Class:Incident/Attribute:user_satisfaction+' => '',
'Class:Incident/Attribute:user_satisfaction/Value:1' => 'Meget tilfreds',
'Class:Incident/Attribute:user_satisfaction/Value:1+' => '',
'Class:Incident/Attribute:user_satisfaction/Value:2' => 'Tilfreds',
'Class:Incident/Attribute:user_satisfaction/Value:2+' => '',
'Class:Incident/Attribute:user_satisfaction/Value:3' => 'Nogenlunde tilfreds',
'Class:Incident/Attribute:user_satisfaction/Value:3+' => '',
'Class:Incident/Attribute:user_satisfaction/Value:4' => 'Meget utilfreds',
'Class:Incident/Attribute:user_satisfaction/Value:4+' => '',
'Class:Incident/Attribute:user_comment' => 'Bruger kommentar',
'Class:Incident/Attribute:user_comment+' => '',
'Class:Incident/Stimulus:ev_assign' => 'Tildelt',
'Class:Incident/Stimulus:ev_assign+' => '',
'Class:Incident/Stimulus:ev_reassign' => 'Forny tildeling',
'Class:Incident/Stimulus:ev_reassign+' => '',
'Class:Incident/Stimulus:ev_pending' => 'Afventer',
'Class:Incident/Stimulus:ev_pending+' => '',
'Class:Incident/Stimulus:ev_timeout' => 'Timeout',
'Class:Incident/Stimulus:ev_timeout+' => '',
'Class:Incident/Stimulus:ev_autoresolve' => 'Automatisk løst',
'Class:Incident/Stimulus:ev_autoresolve+' => '',
'Class:Incident/Stimulus:ev_autoclose' => 'Automatisk lukket',
'Class:Incident/Stimulus:ev_autoclose+' => '',
'Class:Incident/Stimulus:ev_resolve' => 'Marker som løst',
'Class:Incident/Stimulus:ev_resolve+' => '',
'Class:Incident/Stimulus:ev_close' => 'Luk denne Request',
'Class:Incident/Stimulus:ev_close+' => '',
'Class:Incident/Stimulus:ev_reopen' => 'Genåben',
'Class:Incident/Stimulus:ev_reopen+' => '',
'Menu:IncidentManagement' => 'Incident Management',
'Menu:IncidentManagement+' => '',
'Menu:Incident:Overview' => 'Oversigt',
'Menu:Incident:Overview+' => '',
'Menu:NewIncident' => 'Ny Incident',
'Menu:NewIncident+' => '',
'Menu:SearchIncidents' => 'Søg efter Incidents',
'Menu:SearchIncidents+' => '',
'Menu:Incident:Shortcuts' => 'Genveje',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Mine Incidents',
'Menu:Incident:MyIncidents+' => '',
'Menu:Incident:EscalatedIncidents' => 'Eskalerede Incidents',
'Menu:Incident:EscalatedIncidents+' => '',
'Menu:Incident:OpenIncidents' => 'Alle åbne Incidents',
'Menu:Incident:OpenIncidents+' => '',
'Menu:Incident:UnassignedIncidents' => 'Ikke tildelte Incidents',
'Menu:Incident:UnassignedIncidents+' => '',
'Menu:Incident:HelpdeskIncidents' => 'Level2 tildelte Incidents',
'Menu:Incident:HelpdeskIncidents+' => '',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => 'Incidents de sidste 14 dage efter prioritet',
'UI-IncidentManagementOverview-Last-14-days' => 'Antal Incidents de sidste 14 dage',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => 'Åbne Incidents efter status',
'UI-IncidentManagementOverview-OpenIncidentByAgent' => 'Åbne Incidents efter tildelt til',
'UI-IncidentManagementOverview-OpenIncidentByCustomer' => 'Åbne Incidents efter bruger',
'Class:Incident/Attribute:status/Value:waiting_for_approval' => 'Afventer godkendelse',
'Class:Incident/Attribute:status/Value:waiting_for_approval+' => '',
'Class:Incident/Attribute:service_name' => 'Ydelsesnavn',
'Class:Incident/Attribute:service_name+' => '',
'Class:Incident/Attribute:servicesubcategory_name' => 'Ydelses underkategorinavn',
'Class:Incident/Attribute:servicesubcategory_name+' => '',
'Class:Incident/Attribute:parent_incident_ref' => 'Parent-Incident-Reference',
'Class:Incident/Attribute:parent_incident_ref+' => '',
'Class:Incident/Attribute:parent_change_ref' => 'Parent-Change-Reference',
'Class:Incident/Attribute:parent_change_ref+' => '',
'Class:Incident/Attribute:parent_incident_id_friendlyname' => 'Parent-Incident-Friendly Name',
'Class:Incident/Attribute:parent_incident_id_friendlyname+' => '',
));
?>

Some files were not shown because too many files have changed in this diff Show More