mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 23:44:11 +01:00
Compare commits
37 Commits
documentat
...
support/2.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89e98a4ad7 | ||
|
|
649a9833e9 | ||
|
|
b3c2396da8 | ||
|
|
5717ae1889 | ||
|
|
823b33b0f5 | ||
|
|
9561ae6292 | ||
|
|
e25a89dac1 | ||
|
|
cc7f3d46a6 | ||
|
|
95d6b640b1 | ||
|
|
4ee0c62701 | ||
|
|
15f521d470 | ||
|
|
86e6c8295f | ||
|
|
9f1338ee2a | ||
|
|
96c8ee5e4d | ||
|
|
8e863d4890 | ||
|
|
cd769d5e49 | ||
|
|
04677fc2c7 | ||
|
|
ed6a464d8b | ||
|
|
5794f7d1ca | ||
|
|
7d42aa48cd | ||
|
|
614dd21aa9 | ||
|
|
706e6c56ff | ||
|
|
f048c6cb1f | ||
|
|
1804903ee4 | ||
|
|
17a8a896dc | ||
|
|
ed85260bb3 | ||
|
|
3c7fac7504 | ||
|
|
93feb700e8 | ||
|
|
48456082a9 | ||
|
|
fbc0456496 | ||
|
|
0fc3ee12b1 | ||
|
|
ce5f8c93cd | ||
|
|
b38eb97323 | ||
|
|
e6eb32cd21 | ||
|
|
c2429f2d05 | ||
|
|
4e4f2b4db9 | ||
|
|
2d7f963316 |
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -781,8 +781,12 @@ class RestUtils
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
foreach ($oCriteria as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
$realValue = static::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);
|
||||
@@ -814,7 +818,7 @@ class RestUtils
|
||||
{
|
||||
if (is_object($key))
|
||||
{
|
||||
$res = self::FindObjectFromCriteria($sClass, $key);
|
||||
$res = static::FindObjectFromCriteria($sClass, $key);
|
||||
}
|
||||
elseif (is_numeric($key))
|
||||
{
|
||||
@@ -878,7 +882,7 @@ class RestUtils
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
foreach ($key as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
$oSearch->AddCondition($sAttCode, $realValue, '=');
|
||||
}
|
||||
}
|
||||
@@ -922,7 +926,7 @@ class RestUtils
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeExternalKey)
|
||||
{
|
||||
$oExtKeyObject = self::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
|
||||
$oExtKeyObject = static::FindObjectFromKey($oAttDef->GetTargetClass(), $value, true /* allow null */);
|
||||
$value = ($oExtKeyObject != null) ? $oExtKeyObject->GetKey() : 0;
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeLinkedSet)
|
||||
@@ -935,7 +939,7 @@ class RestUtils
|
||||
$aLinks = array();
|
||||
foreach($value as $oValues)
|
||||
{
|
||||
$oLnk = self::MakeObjectFromFields($sLnkClass, $oValues);
|
||||
$oLnk = static::MakeObjectFromFields($sLnkClass, $oValues);
|
||||
$aLinks[] = $oLnk;
|
||||
}
|
||||
$value = DBObjectSet::FromArray($sLnkClass, $aLinks);
|
||||
@@ -966,7 +970,7 @@ class RestUtils
|
||||
$oObject = MetaModel::NewObject($sClass);
|
||||
foreach ($aFields as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
try
|
||||
{
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
@@ -993,7 +997,7 @@ class RestUtils
|
||||
$sClass = get_class($oObject);
|
||||
foreach ($aFields as $sAttCode => $value)
|
||||
{
|
||||
$realValue = self::MakeValue($sClass, $sAttCode, $value);
|
||||
$realValue = static::MakeValue($sClass, $sAttCode, $value);
|
||||
try
|
||||
{
|
||||
$oObject->Set($sAttCode, $realValue);
|
||||
|
||||
@@ -312,7 +312,7 @@ abstract class Dashboard
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add('<h1>'.Dict::S($this->sTitle).'</h1>');
|
||||
$oPage->add('<h1>'.htmlentities(Dict::S($this->sTitle), ENT_QUOTES, 'UTF-8', false).'</h1>');
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
|
||||
@@ -733,7 +733,8 @@ 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;
|
||||
|
||||
|
||||
@@ -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,6 +404,21 @@ 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);
|
||||
|
||||
@@ -305,16 +305,20 @@ class LoginWebPage extends NiceWebPage
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser)."</p>\n");
|
||||
}
|
||||
elseif ($oUser->Get('reset_pwd_token') != $sToken)
|
||||
{
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Error-InvalidToken')."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-EnterPassword', $oUser->GetFriendlyName())."</p>\n");
|
||||
|
||||
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
|
||||
$this->add_script(
|
||||
$oEncryptedToken = $oUser->Get('reset_pwd_token');
|
||||
|
||||
if (!$oEncryptedToken->CheckPassword($sToken))
|
||||
{
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Error-InvalidToken')."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-EnterPassword', $oUser->GetFriendlyName())."</p>\n");
|
||||
|
||||
$sInconsistenPwdMsg = Dict::S('UI:Login:RetypePwdDoesNotMatch');
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function DoCheckPwd()
|
||||
{
|
||||
@@ -326,18 +330,19 @@ function DoCheckPwd()
|
||||
return true;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"new_pwd\">".Dict::S('UI:Login:NewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"new_pwd\" name=\"new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"retype_new_pwd\">".Dict::S('UI:Login:RetypeNewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"retype_new_pwd\" name=\"retype_new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"submit\" onClick=\"return DoCheckPwd();\" value=\"".Dict::S('UI:Button:ChangePassword')."\" /></span></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"do_reset_pwd\" />\n");
|
||||
$this->add("<input type=\"hidden\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" />\n");
|
||||
$this->add("<input type=\"hidden\" name=\"token\" value=\"".htmlentities($sToken, ENT_QUOTES, 'UTF-8')."\" />\n");
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div\n");
|
||||
);
|
||||
$this->add("<form method=\"post\">\n");
|
||||
$this->add("<table>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"new_pwd\">".Dict::S('UI:Login:NewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"new_pwd\" name=\"new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td style=\"text-align:right\"><label for=\"retype_new_pwd\">".Dict::S('UI:Login:RetypeNewPasswordPrompt').":</label></td><td style=\"text-align:left\"><input type=\"password\" id=\"retype_new_pwd\" name=\"retype_new_pwd\" value=\"\" /></td></tr>\n");
|
||||
$this->add("<tr><td colspan=\"2\" class=\"center v-spacer\"><span class=\"btn_border\"><input type=\"submit\" onClick=\"return DoCheckPwd();\" value=\"".Dict::S('UI:Button:ChangePassword')."\" /></span></td></tr>\n");
|
||||
$this->add("</table>\n");
|
||||
$this->add("<input type=\"hidden\" name=\"loginop\" value=\"do_reset_pwd\" />\n");
|
||||
$this->add("<input type=\"hidden\" name=\"auth_user\" value=\"".htmlentities($sAuthUser, ENT_QUOTES, 'UTF-8')."\" />\n");
|
||||
$this->add("<input type=\"hidden\" name=\"token\" value=\"".htmlentities($sToken, ENT_QUOTES, 'UTF-8')."\" />\n");
|
||||
$this->add("</form>\n");
|
||||
$this->add("</div\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,21 +362,25 @@ EOF
|
||||
{
|
||||
$this->add("<p>".Dict::Format('UI:ResetPwd-Error-WrongLogin', $sAuthUser)."</p>\n");
|
||||
}
|
||||
elseif ($oUser->Get('reset_pwd_token') != $sToken)
|
||||
{
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Error-InvalidToken')."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Trash the token and change the password
|
||||
$oUser->Set('reset_pwd_token', '');
|
||||
$oUser->SetPassword($sNewPwd); // Does record the change into the DB
|
||||
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Ready')."</p>");
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$this->add("<p><a href=\"$sUrl\">".Dict::S('UI:ResetPwd-Login')."</a></p>");
|
||||
$oEncryptedPassword = $oUser->Get('reset_pwd_token');
|
||||
if (!$oEncryptedPassword->CheckPassword($sToken))
|
||||
{
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Error-InvalidToken')."</p>\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Trash the token and change the password
|
||||
$oUser->Set('reset_pwd_token', '');
|
||||
$oUser->SetPassword($sNewPwd); // Does record the change into the DB
|
||||
|
||||
$this->add("<p>".Dict::S('UI:ResetPwd-Ready')."</p>");
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$this->add("<p><a href=\"$sUrl\">".Dict::S('UI:ResetPwd-Login')."</a></p>");
|
||||
}
|
||||
$this->add("</div\n");
|
||||
}
|
||||
$this->add("</div\n");
|
||||
}
|
||||
|
||||
public function DisplayChangePwdForm($bFailedLogin = false)
|
||||
|
||||
@@ -90,6 +90,8 @@ 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
|
||||
@@ -231,6 +233,20 @@ 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
|
||||
);
|
||||
|
||||
|
||||
@@ -28,10 +28,11 @@ require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
if (isset($_REQUEST['switch_env']))
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
if (($sSwitchEnv != null) && (file_exists(APPCONF.$sSwitchEnv.'/'.ITOP_CONFIG_FILE)))
|
||||
{
|
||||
$sEnv = $_REQUEST['switch_env'];
|
||||
$_SESSION['itop_env'] = $sEnv;
|
||||
$_SESSION['itop_env'] = $sSwitchEnv;
|
||||
$sEnv = $sSwitchEnv;
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (isset($_SESSION['itop_env']))
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,8 @@
|
||||
/**
|
||||
* 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
|
||||
* 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'
|
||||
*
|
||||
* @package iTop
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
@@ -28,6 +29,81 @@
|
||||
|
||||
|
||||
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
|
||||
@@ -99,4 +175,178 @@ class privUITransaction
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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')); } );\n");
|
||||
$oPage->add_ready_script("$('#$iId').bind('update', function() { BlockField('cke_$iId', $('#$iId').attr('disabled')); $(this).data('ckeditorInstance').setReadOnly($(this).prop('disabled')); } );\n");
|
||||
|
||||
return $sHtmlValue;
|
||||
}
|
||||
|
||||
@@ -294,7 +294,7 @@ class UILinksWidgetDirect
|
||||
$valuesDef = $oLinksetDef->GetValuesDef();
|
||||
if ($valuesDef === null)
|
||||
{
|
||||
$oFilter = new DBObjectSearch($this->sLinkedClass);
|
||||
$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -892,6 +892,106 @@ 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;
|
||||
|
||||
@@ -809,6 +809,30 @@ class Config
|
||||
'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)
|
||||
@@ -1462,6 +1486,8 @@ 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;
|
||||
@@ -1469,6 +1495,7 @@ 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;
|
||||
|
||||
@@ -1534,6 +1561,8 @@ 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)
|
||||
@@ -1572,6 +1601,7 @@ 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,
|
||||
);
|
||||
|
||||
@@ -2088,12 +2088,12 @@ abstract class DBObject implements iDisplay
|
||||
{
|
||||
if (is_string($actionHandler))
|
||||
{
|
||||
// Old (pre-2.1.0) action definition without any parameter
|
||||
$aActionCallSpec = array($this, $sActionHandler);
|
||||
// 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)."::$sActionHandler");
|
||||
throw new CoreException("Unable to call action: ".get_class($this)."::$actionHandler");
|
||||
return;
|
||||
}
|
||||
$bRet = call_user_func($aActionCallSpec, $sStimulusCode);
|
||||
|
||||
@@ -53,9 +53,8 @@ class DBObjectSearch
|
||||
public function __construct($sClass, $sClassAlias = null)
|
||||
{
|
||||
if (is_null($sClassAlias)) $sClassAlias = $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)
|
||||
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.'"');
|
||||
|
||||
$this->m_aSelectedClasses = array($sClassAlias => $sClass);
|
||||
$this->m_aClasses = array($sClassAlias => $sClass);
|
||||
@@ -449,7 +448,7 @@ class DBObjectSearch
|
||||
|
||||
public function AddCondition($sFilterCode, $value, $sOpCode = null)
|
||||
{
|
||||
MyHelpers::CheckKeyInArray('filter code', $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
|
||||
MyHelpers::CheckKeyInArray('filter code in class: '.$this->GetClass(), $sFilterCode, MetaModel::GetClassFilterDefs($this->GetClass()));
|
||||
$oFilterDef = MetaModel::GetClassFilterDef($this->GetClass(), $sFilterCode);
|
||||
|
||||
$oField = new FieldExpression($sFilterCode, $this->GetClassAlias());
|
||||
|
||||
@@ -59,8 +59,11 @@ 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -836,6 +836,10 @@ abstract class MetaModel
|
||||
final static public function GetAttributeDef($sClass, $sAttCode)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (!isset(self::$m_aAttribDefs[$sClass][$sAttCode]))
|
||||
{
|
||||
throw new Exception("Unknown attribute $sAttCode from class $sClass");
|
||||
}
|
||||
return self::$m_aAttribDefs[$sClass][$sAttCode];
|
||||
}
|
||||
|
||||
@@ -3075,7 +3079,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";
|
||||
@@ -5428,9 +5432,11 @@ abstract class MetaModel
|
||||
{
|
||||
// Some environment parameters are objects, we just need scalars
|
||||
if (is_object($replace)) continue;
|
||||
|
||||
$aSearches[] = '$'.$sSearch.'$';
|
||||
$aReplacements[] = (string) $replace;
|
||||
else
|
||||
{
|
||||
$aSearches[] = '$'.$sSearch.'$';
|
||||
$aReplacements[] = (string) $replace;
|
||||
}
|
||||
}
|
||||
return str_replace($aSearches, $aReplacements, $aInput);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2013 Combodo SARL
|
||||
// Copyright (C) 2013-2016 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 Combodo SARL
|
||||
* @copyright Copyright (C) 2013-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class iTopMutex
|
||||
@@ -37,8 +37,19 @@ class iTopMutex
|
||||
public function __construct($sName, $sDBHost = null, $sDBUser = null, $sDBPwd = null)
|
||||
{
|
||||
// Compute the name of a lock for mysql
|
||||
// Note: the name is server-wide!!!
|
||||
// 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();
|
||||
$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))
|
||||
@@ -48,7 +59,6 @@ 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;
|
||||
@@ -121,7 +131,43 @@ class iTopMutex
|
||||
$this->bLocked = true;
|
||||
self::$aAcquiredLocks[$this->sName]++;
|
||||
}
|
||||
return ($res === '1');
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2015 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-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2015 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class ormCaseLog {
|
||||
@@ -384,7 +384,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
|
||||
public function AddLogEntryFromJSON($oJson)
|
||||
public function AddLogEntryFromJSON($oJson, $bCheckUserId = true)
|
||||
{
|
||||
$sText = isset($oJson->message) ? $oJson->message : '';
|
||||
|
||||
@@ -394,16 +394,24 @@ class ormCaseLog {
|
||||
{
|
||||
throw new Exception("Only administrators can set the user id", RestResult::UNAUTHORIZED);
|
||||
}
|
||||
try
|
||||
if ($bCheckUserId && ($oJson->user_id != 0))
|
||||
{
|
||||
$oUser = RestUtils::FindObjectFromKey('User', $oJson->user_id);
|
||||
try
|
||||
{
|
||||
$oUser = RestUtils::FindObjectFromKey('User', $oJson->user_id);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new Exception('user_id: '.$e->getMessage(), $e->getCode());
|
||||
}
|
||||
$iUserId = $oUser->GetKey();
|
||||
$sOnBehalfOf = $oUser->GetFriendlyName();
|
||||
}
|
||||
catch(Exception $e)
|
||||
else
|
||||
{
|
||||
throw new Exception('user_id: '.$e->getMessage(), $e->getCode());
|
||||
$iUserId = $oJson->user_id;
|
||||
$sOnBehalfOf = $oJson->user_login;
|
||||
}
|
||||
$iUserId = $oUser->GetKey();
|
||||
$sOnBehalfOf = $oUser->GetFriendlyName();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -86,8 +86,9 @@ class ormStopWatch
|
||||
* 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)
|
||||
public function GetElapsedTime($oAttDef, $oObject)
|
||||
{
|
||||
if (is_null($this->iLastStart))
|
||||
{
|
||||
@@ -95,7 +96,7 @@ class ormStopWatch
|
||||
}
|
||||
else
|
||||
{
|
||||
$iElapsed = $this->ComputeDuration($this, $oAttDef, $this->iLastStart, time());
|
||||
$iElapsed = $this->ComputeDuration($oObject, $oAttDef, $this->iLastStart, time());
|
||||
return $this->iTimeSpent + $iElapsed;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,7 +400,7 @@ abstract class UserInternal extends User
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// When set, this token allows for password reset
|
||||
MetaModel::Init_AddAttribute(new AttributeString("reset_pwd_token", array("allowed_values"=>null, "sql"=>"reset_pwd_token", "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeOneWayPassword("reset_pwd_token", array("allowed_values"=>null, "default_value"=>null, "is_null_allowed"=>true, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('contactid', 'first_name', 'email', 'login', 'language', 'profile_list', 'allowed_org_list')); // Attributes to be displayed for the complete details
|
||||
@@ -1303,8 +1303,9 @@ class CAS_SelfRegister implements iSelfRegister
|
||||
}
|
||||
else
|
||||
{
|
||||
// No membership required, anybody will pass
|
||||
$bFound = true;
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (!$bFound)
|
||||
|
||||
@@ -206,6 +206,11 @@ 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;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -250,6 +250,7 @@ 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
|
||||
@@ -347,7 +348,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_'+data.result.att_id+'" type="hidden" name="attachments[]" value="'.$iAttId.'"/></a><br/> <input id="btn_remove_'.$iAttId.'" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment('.$iAttId.');"/> </div>');
|
||||
$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/> <input id="btn_remove_'.$iAttId.'" type="button" class="btn_hidden" value="Delete" onClick="RemoveAttachment('.$iAttId.');"/> </div>');
|
||||
$oPage->add_ready_script("$('#attachment_plugin').trigger('add_attachment', [$iAttId, '".addslashes($sFileName)."']);");
|
||||
}
|
||||
}
|
||||
@@ -368,6 +369,7 @@ $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')
|
||||
{
|
||||
@@ -383,7 +385,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.msg]);
|
||||
$('#attachment_plugin').trigger('add_attachment', [data.result.att_id, data.result.msg]);
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -440,7 +442,6 @@ EOF
|
||||
);
|
||||
$oPage->p('<span style="display:none;" id="attachment_loading">Loading, please wait...</span>');
|
||||
$oPage->p('<input type="hidden" id="attachment_plugin" name="attachment_plugin"/>');
|
||||
$oPage->add('</fieldset>');
|
||||
if ($this->m_bDeleteEnabled)
|
||||
{
|
||||
$oPage->add_ready_script('$(".attachment").hover( function() {$(this).children(":button").toggleClass("btn_hidden"); } );');
|
||||
@@ -466,7 +467,9 @@ EOF
|
||||
$oPage->add('<div class="attachment" id="attachment_'.$iAttId.'"><a data-preview="'.$sPreview.'" href="'.$sDownloadLink.'"><img src="'.$sIcon.'"><br/>'.$sFileName.'</a><input type="hidden" name="attachments[]" value="'.$iAttId.'"/><br/> </div>');
|
||||
}
|
||||
}
|
||||
$oPage->add('</span>');
|
||||
}
|
||||
$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'; }}});");
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2014 Combodo SARL
|
||||
// Copyright (C) 2013-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Backup from an interactive session
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2013-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -77,9 +77,8 @@ try
|
||||
|
||||
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
|
||||
$oRestoreMutex = new iTopMutex('restore.'.$sEnvironment);
|
||||
if ($oRestoreMutex->TryLock())
|
||||
if (!$oRestoreMutex->IsLocked())
|
||||
{
|
||||
$oRestoreMutex->Unlock();
|
||||
$sFile = utils::ReadParam('file', '', false, 'raw_data');
|
||||
$sToken = str_replace(' ', '', (string)microtime());
|
||||
$sTokenFile = APPROOT.'/data/restore.'.$sToken.'.tok';
|
||||
@@ -119,7 +118,9 @@ EOF
|
||||
{
|
||||
$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);
|
||||
@@ -144,6 +145,7 @@ EOF
|
||||
$sBackupFile = $sBackupDir.$sFile;
|
||||
$sRes = $oDBRS->RestoreFromZip($sBackupFile, $sEnvironment);
|
||||
|
||||
IssueLog::Info('Backup Restore - Done, releasing the LOCK');
|
||||
$oRestoreMutex->Unlock();
|
||||
}
|
||||
catch (Exception $e)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2014 Combodo SARL
|
||||
// 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
|
||||
@@ -26,35 +26,19 @@ class BackupHandler extends ModuleHandlerAPI
|
||||
{
|
||||
public static function OnMetaModelStarted()
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
$oBackupMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
|
||||
if ($oBackupMutex->TryLock())
|
||||
{
|
||||
$oBackupMutex->Unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not needed: the DB dump is done in a single transaction
|
||||
//MetaModel::GetConfig()->Set('access_mode', ACCESS_READONLY, 'itop-backup');
|
||||
//MetaModel::GetConfig()->Set('access_message', ' - '.dict::S('bkp-backup-running'), 'itop-backup');
|
||||
}
|
||||
|
||||
$oRestoreMutex = new iTopMutex('restore.'.utils::GetCurrentEnvironment());
|
||||
if ($oRestoreMutex->TryLock())
|
||||
{
|
||||
$oRestoreMutex->Unlock();
|
||||
}
|
||||
else
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2014 Combodo SARL
|
||||
// Copyright (C) 2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -20,7 +20,7 @@
|
||||
/**
|
||||
* Monitor the backup
|
||||
*
|
||||
* @copyright Copyright (C) 2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -169,14 +169,13 @@ try
|
||||
}
|
||||
|
||||
$oRestoreMutex = new iTopMutex('restore.'.utils::GetCurrentEnvironment());
|
||||
if ($oRestoreMutex->TryLock())
|
||||
if ($oRestoreMutex->IsLocked())
|
||||
{
|
||||
$oRestoreMutex->Unlock();
|
||||
$sDisableRestore = '';
|
||||
$sDisableRestore = 'disabled="disabled"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisableRestore = 'disabled="disabled"';
|
||||
$sDisableRestore = '';
|
||||
}
|
||||
|
||||
// 1st table: list the backups made in the background
|
||||
@@ -271,20 +270,12 @@ try
|
||||
// Ongoing operation ?
|
||||
//
|
||||
$oBackupMutex = new iTopMutex('backup.'.utils::GetCurrentEnvironment());
|
||||
if ($oBackupMutex->TryLock())
|
||||
{
|
||||
$oBackupMutex->Unlock();
|
||||
}
|
||||
else
|
||||
if ($oBackupMutex->IsLocked())
|
||||
{
|
||||
$oP->p(Dict::S('bkp-backup-running'));
|
||||
}
|
||||
$oRestoreMutex = new iTopMutex('restore.'.utils::GetCurrentEnvironment());
|
||||
if ($oRestoreMutex->TryLock())
|
||||
{
|
||||
$oRestoreMutex->Unlock();
|
||||
}
|
||||
else
|
||||
if ($oRestoreMutex->IsLocked())
|
||||
{
|
||||
$oP->p(Dict::S('bkp-restore-running'));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2014 Combodo SARL
|
||||
// Copyright (C) 2014-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -105,6 +105,10 @@ try
|
||||
{
|
||||
$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(
|
||||
@@ -129,27 +133,50 @@ EOF
|
||||
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 ($sConfig == $sOrginalConfig)
|
||||
if (!utils::IsTransactionValid($sTransactionId, true))
|
||||
{
|
||||
$oP->add('<div id="save_result" class="header_message">'.Dict::S('config-no-change').'</div>');
|
||||
$oP->add("<div class=\"header_message message_info\">Error: invalid Transaction ID. The configuration was <b>NOT</b> modified.</div>");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
if ($sConfig == $sOrginalConfig)
|
||||
{
|
||||
TestConfig($sConfig, $oP); // throws exceptions
|
||||
|
||||
@chmod($sConfigFile, 0770); // Allow overwriting the file
|
||||
file_put_contents($sConfigFile, $sConfig);
|
||||
@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));
|
||||
$oP->add('<div id="save_result" class="header_message">'.Dict::S('config-no-change').'</div>');
|
||||
}
|
||||
catch (Exception $e)
|
||||
else
|
||||
{
|
||||
$oP->p('<div id="save_result" class="header_message message_error">'.$e->getMessage().'</div>');
|
||||
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>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,6 +191,7 @@ EOF
|
||||
$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\">");
|
||||
|
||||
@@ -230,25 +230,32 @@ function ValidateCKEditField(sFieldId, sPattern, bMandatory, sFormId, nullValue)
|
||||
var bValid;
|
||||
var sTextContent;
|
||||
|
||||
// Get the contents without the tags
|
||||
var oFormattedContents = $("#cke_"+sFieldId+" iframe");
|
||||
if (oFormattedContents.length == 0)
|
||||
if ($('#'+sFieldId).attr('disabled'))
|
||||
{
|
||||
var oSourceContents = $("#cke_"+sFieldId+" textarea.cke_source");
|
||||
sTextContent = oSourceContents.val();
|
||||
bValid = true; // disabled fields are not checked
|
||||
}
|
||||
else
|
||||
{
|
||||
sTextContent = oFormattedContents.contents().find("body").text();
|
||||
}
|
||||
|
||||
if (bMandatory && (sTextContent == ''))
|
||||
{
|
||||
bValid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bValid = true;
|
||||
// Get the contents without the tags
|
||||
var oFormattedContents = $("#cke_"+sFieldId+" iframe");
|
||||
if (oFormattedContents.length == 0)
|
||||
{
|
||||
var oSourceContents = $("#cke_"+sFieldId+" textarea.cke_source");
|
||||
sTextContent = oSourceContents.val();
|
||||
}
|
||||
else
|
||||
{
|
||||
sTextContent = oFormattedContents.contents().find("body").text();
|
||||
}
|
||||
|
||||
if (bMandatory && (sTextContent == ''))
|
||||
{
|
||||
bValid = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
bValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
ReportFieldValidationStatus(sFieldId, sFormId, bValid, '');
|
||||
|
||||
@@ -238,8 +238,12 @@ $(function()
|
||||
}
|
||||
);
|
||||
oParams.operation = 'searchObjectsToAdd2';
|
||||
oParams['class'] = this.options.class_name;
|
||||
oParams.real_class = '';
|
||||
if ((oParams['class'] != undefined) && (oParams['class'] != ''))
|
||||
{
|
||||
oParams.real_class = oParams['class'];
|
||||
}
|
||||
oParams['class'] = this.options.class_name;
|
||||
oParams.att_code = this.options.att_code;
|
||||
oParams.iInputId = this.id;
|
||||
if (this.options.oWizardHelper)
|
||||
|
||||
@@ -200,13 +200,18 @@ function ReloadSearchForm(divId, sClassName, sBaseClass, sContext)
|
||||
for(var index = 0; index < aSubmit.length; index++)
|
||||
{
|
||||
// Restore the previously bound submit handlers
|
||||
var sEventName = 'submit';
|
||||
if ((aSubmit[index].namespace != undefined) && (aSubmit[index].namespace != ''))
|
||||
{
|
||||
sEventName += '.'+aSubmit[index].namespace;
|
||||
}
|
||||
if (aSubmit[index].data != undefined)
|
||||
{
|
||||
oForm.bind('submit.'+aSubmit[index].namespace, aSubmit[index].data, aSubmit[index].handler)
|
||||
oForm.bind(sEventName, aSubmit[index].data, aSubmit[index].handler)
|
||||
}
|
||||
else
|
||||
{
|
||||
oForm.bind('submit.'+aSubmit[index].namespace, aSubmit[index].handler)
|
||||
oForm.bind(sEventName, aSubmit[index].handler)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -601,6 +601,7 @@ try
|
||||
if ($iErrors == 0)
|
||||
{
|
||||
$oP->set_title(Dict::S('UI:SearchResultsPageTitle'));
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/xlsx-export.js'); // Since the results are loaded asynchronously they don't do this on their own
|
||||
$oP->add("<div style=\"padding: 10px;\">\n");
|
||||
$oP->add("<div class=\"header_message\" id=\"full_text_progress\" style=\"position: fixed; background-color: #cccccc; opacity: 0.7; padding: 1.5em;\">\n");
|
||||
$oP->add('<img id="full_text_indicator" src="../images/indicator.gif"> <span style="padding: 1.5em;">'.Dict::Format('UI:Search:Ongoing', htmlentities($sFullText, ENT_QUOTES, 'UTF-8')).'</span>');
|
||||
@@ -1654,4 +1655,4 @@ catch(Exception $e)
|
||||
IssueLog::Error($e->getMessage());
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1732,8 +1732,7 @@ catch (Exception $e)
|
||||
{
|
||||
// note: transform to cope with XSS attacks
|
||||
echo htmlentities($e->GetMessage(), ENT_QUOTES, 'utf-8');
|
||||
echo "<p>Debug trace: <pre>".$e->getTraceAsString()."</pre></p>\n";
|
||||
IssueLog::Error($e->getMessage());
|
||||
IssueLog::Error($e->getMessage()."\nDebug trace:\n".$e->getTraceAsString()); // Do NOT display the call stack since it may contain sensitive information
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -224,6 +224,12 @@ class DBBackup
|
||||
}
|
||||
if ($iRetCode != 0)
|
||||
{
|
||||
// Cleanup residual output (Happens with Error 2020: Got packet bigger than 'maxallowedpacket' bytes...)
|
||||
if (file_exists($sBackupFileName))
|
||||
{
|
||||
unlink($sBackupFileName);
|
||||
}
|
||||
|
||||
$this->LogError("Failed to execute: $sCommandDisplay. The command returned:$iRetCode");
|
||||
foreach($aOutput as $sLine)
|
||||
{
|
||||
|
||||
@@ -50,7 +50,7 @@ class CheckResult
|
||||
|
||||
class SetupUtils
|
||||
{
|
||||
const PHP_MIN_VERSION = '5.2.0';
|
||||
const PHP_MIN_VERSION = '5.3.0';
|
||||
const MYSQL_MIN_VERSION = '5.0.0';
|
||||
const MIN_MEMORY_LIMIT = 33554432; // = 32*1024*1024 Beware: Computations are not allowed in defining constants
|
||||
const SUHOSIN_GET_MAX_VALUE_LENGTH = 2048;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
/**
|
||||
* All the steps of the iTop installation wizard
|
||||
* @copyright Copyright (C) 2010-2012 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -618,16 +618,12 @@ EOF
|
||||
);
|
||||
|
||||
$oMutex = new iTopMutex(
|
||||
'cron.'.$this->oWizard->GetParameter('db_name', '').'_'.$this->oWizard->GetParameter('db_prefix', ''),
|
||||
'cron'.$this->oWizard->GetParameter('db_name', '').$this->oWizard->GetParameter('db_prefix', ''),
|
||||
$this->oWizard->GetParameter('db_server', ''),
|
||||
$this->oWizard->GetParameter('db_user', ''),
|
||||
$this->oWizard->GetParameter('db_pwd', '')
|
||||
);
|
||||
if ($oMutex->TryLock())
|
||||
{
|
||||
$oMutex->Unlock();
|
||||
}
|
||||
else
|
||||
if ($oMutex->IsLocked())
|
||||
{
|
||||
$oPage->p("<img src=\"../images/error.png\"/> An iTop CRON process is being executed on the target database. It is highly recommended to stop any iTop CRON process prior to running the setup program.");
|
||||
}
|
||||
|
||||
@@ -468,7 +468,7 @@ try
|
||||
// Prepare insert columns
|
||||
$sInsertColumns = '`'.implode('`, `', $aInputColumns).'`';
|
||||
|
||||
$oMutex = new iTopMutex('synchro_import_'.$oDataSource->GetKey().'_'.MetaModel::GetConfig()->GetDBName().'_'.MetaModel::GetConfig()->GetDBSubname());
|
||||
$oMutex = new iTopMutex('synchro_import_'.$oDataSource->GetKey());
|
||||
$oMutex->Lock();
|
||||
foreach($aData as $iRow => $aRow)
|
||||
{
|
||||
|
||||
@@ -2415,7 +2415,7 @@ class SynchroExecution
|
||||
|
||||
self::$m_oCurrentTask = $this->m_oDataSource;
|
||||
|
||||
$oMutex = new iTopMutex('synchro_process_'.$this->m_oDataSource->GetKey().'_'.MetaModel::GetConfig()->GetDBName().'_'.MetaModel::GetConfig()->GetDBSubname());
|
||||
$oMutex = new iTopMutex('synchro_process_'.$this->m_oDataSource->GetKey());
|
||||
try
|
||||
{
|
||||
$oMutex->Lock();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2013 Combodo SARL
|
||||
// Copyright (C) 2010-2016 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,7 +19,7 @@
|
||||
/**
|
||||
* Heart beat of the application (process asynchron tasks such as broadcasting email)
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2013 Combodo SARL
|
||||
* @copyright Copyright (C) 2010-2016 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@@ -71,49 +71,49 @@ function UsageAndExit($oP)
|
||||
|
||||
function RunTask($oProcess, BackgroundTask $oTask, $oStartDate, $iTimeLimit)
|
||||
{
|
||||
$oNow = new DateTime();
|
||||
$fStart = microtime(true);
|
||||
try
|
||||
{
|
||||
$oNow = new DateTime();
|
||||
$fStart = microtime(true);
|
||||
$sMessage = $oProcess->Process($iTimeLimit);
|
||||
$fDuration = microtime(true) - $fStart;
|
||||
if ($oTask->Get('total_exec_count') == 0)
|
||||
{
|
||||
// First execution
|
||||
$oTask->Set('first_run_date', $oNow->format('Y-m-d H:i:s'));
|
||||
}
|
||||
$oTask->ComputeDurations($fDuration); // does increment the counter and compute statistics
|
||||
$oTask->Set('latest_run_date', $oNow->format('Y-m-d H:i:s'));
|
||||
|
||||
$oRefClass = new ReflectionClass(get_class($oProcess));
|
||||
if ($oRefClass->implementsInterface('iScheduledProcess'))
|
||||
{
|
||||
// Schedules process do repeat at specific moments
|
||||
$oPlannedStart = $oProcess->GetNextOccurrence();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Background processes do repeat periodically
|
||||
$oPlannedStart = new DateTime($oTask->Get('latest_run_date'));
|
||||
// Let's assume that the task was started exactly when planned so that the schedule does no shift each time
|
||||
// this allows to schedule a task everyday "around" 11:30PM for example
|
||||
$oPlannedStart->modify('+'.$oProcess->GetPeriodicity().' seconds');
|
||||
$oEnd = new DateTime();
|
||||
if ($oPlannedStart->format('U') < $oEnd->format('U'))
|
||||
{
|
||||
// Huh, next planned start is already in the past, shift it of the periodicity !
|
||||
$oPlannedStart = $oEnd->modify('+'.$oProcess->GetPeriodicity().' seconds');
|
||||
}
|
||||
}
|
||||
|
||||
$oTask->Set('next_run_date', $oPlannedStart->format('Y-m-d H:i:s'));
|
||||
$oTask->DBUpdate();
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$sMessage = 'Processing failed, the following exception occured: '.$e->getMessage();
|
||||
$sMessage = 'Processing failed with message: '.$e->getMessage();
|
||||
}
|
||||
return $sMessage;
|
||||
$fDuration = microtime(true) - $fStart;
|
||||
if ($oTask->Get('total_exec_count') == 0)
|
||||
{
|
||||
// First execution
|
||||
$oTask->Set('first_run_date', $oNow->format('Y-m-d H:i:s'));
|
||||
}
|
||||
$oTask->ComputeDurations($fDuration); // does increment the counter and compute statistics
|
||||
$oTask->Set('latest_run_date', $oNow->format('Y-m-d H:i:s'));
|
||||
|
||||
$oRefClass = new ReflectionClass(get_class($oProcess));
|
||||
if ($oRefClass->implementsInterface('iScheduledProcess'))
|
||||
{
|
||||
// Schedules process do repeat at specific moments
|
||||
$oPlannedStart = $oProcess->GetNextOccurrence();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Background processes do repeat periodically
|
||||
$oPlannedStart = new DateTime($oTask->Get('latest_run_date'));
|
||||
// Let's assume that the task was started exactly when planned so that the schedule does no shift each time
|
||||
// this allows to schedule a task everyday "around" 11:30PM for example
|
||||
$oPlannedStart->modify('+'.$oProcess->GetPeriodicity().' seconds');
|
||||
$oEnd = new DateTime();
|
||||
if ($oPlannedStart->format('U') < $oEnd->format('U'))
|
||||
{
|
||||
// Huh, next planned start is already in the past, shift it of the periodicity !
|
||||
$oPlannedStart = $oEnd->modify('+'.$oProcess->GetPeriodicity().' seconds');
|
||||
}
|
||||
}
|
||||
|
||||
$oTask->Set('next_run_date', $oPlannedStart->format('Y-m-d H:i:s'));
|
||||
$oTask->DBUpdate();
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
function CronExec($oP, $aProcesses, $bVerbose)
|
||||
@@ -354,7 +354,7 @@ $oP->p("Starting: ".time().' ('.date('Y-m-d H:i:s').')');
|
||||
try
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$oMutex = new iTopMutex('cron.'.$oConfig->GetDBName().'_'.$oConfig->GetDBSubname());
|
||||
$oMutex = new iTopMutex('cron');
|
||||
if ($oMutex->TryLock())
|
||||
{
|
||||
// Note: testing this now in case some of the background processes forces the read-only mode for a while
|
||||
|
||||
@@ -66,7 +66,7 @@ else
|
||||
$sRawFile = WebServicesBase::GetWSDLContents();
|
||||
}
|
||||
|
||||
$sServerURI = 'http'.(utils::IsConnectionSecure() ? 's' : '').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/soapserver.php';
|
||||
$sServerURI = utils::GetAbsoluteUrlAppRoot().'webservices/soapserver.php';
|
||||
if (isset($_REQUEST['service_category']) && (!empty($_REQUEST['service_category'])))
|
||||
{
|
||||
$sServerURI .= "?service_category=".$_REQUEST['service_category'];
|
||||
|
||||
@@ -32,10 +32,10 @@ require_once(APPROOT.'/application/application.inc.php');
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
// this file is generated dynamically with location = here
|
||||
$sWsdlUri = 'http'.(utils::IsConnectionSecure() ? 's' : '').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/../webservices/itop.wsdl.php';
|
||||
$sWsdlUri = utils::GetAbsoluteUrlAppRoot().'webservices/itop.wsdl.php';
|
||||
if (isset($_REQUEST['service_category']) && (!empty($_REQUEST['service_category'])))
|
||||
{
|
||||
$sWsdlUri .= "soapserver.php?service_category=".$_REQUEST['service_category'];
|
||||
$sWsdlUri .= "?service_category=".$_REQUEST['service_category'];
|
||||
}
|
||||
|
||||
|
||||
@@ -99,7 +99,7 @@ else
|
||||
if (is_subclass_of($sPHPClass, 'WebServicesBase'))
|
||||
{
|
||||
$sServiceCategory = $sPHPClass;
|
||||
$sSoapServerUri = 'http'.(utils::IsConnectionSecure() ? 's' : '').'://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].dirname($_SERVER['SCRIPT_NAME']).'/../webservices/soapserver.php';
|
||||
$sSoapServerUri = utils::GetAbsoluteUrlAppRoot().'webservices/soapserver.php';
|
||||
$sSoapServerUri .= "?service_category=$sServiceCategory";
|
||||
echo "<li><a href=\"$sSoapServerUri\">$sServiceCategory</a></li>\n";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user